├── FontMap.png ├── Makefile ├── README.md ├── Smoke96.pbo ├── abstract.png ├── bstrlib.c ├── bstrlib.h ├── cloud.png ├── demo-ClipPlanes.c ├── demo-ClipPlanes.glsl ├── demo-DeepOpacity.c ├── demo-DeepOpacity.glsl ├── demo-DistancePicking.c ├── demo-DistancePicking.glsl ├── demo-GenCubeMap.c ├── demo-GenCubeMap.glsl ├── demo-Lava.c ├── demo-Lava.glsl ├── demo-Raycast.c ├── demo-Raycast.glsl ├── demo-SimpleText.c ├── demo-SimpleText.glsl ├── demo-TextGrid.c ├── demo-TextGrid.glsl ├── demo-ToonShading.c ├── demo-ToonShading.glsl ├── demo-VoronoiPicking.c ├── demo-VoronoiPicking.glsl ├── dev-FresnelGlass.c ├── dev-FresnelGlass.glsl ├── gl3.h ├── glew.c ├── glew.h ├── lavatile.png ├── lodepng.c ├── lodepng.h ├── pez.c ├── pez.h ├── pez.linux.c ├── verasansmono.png └── vmath.h /FontMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/recipes/34a5f6fa4109be03e180bc6839cbc0253b0cacea/FontMap.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-std=c99 -Wall -c -Wc++-compat -O3 3 | LIBS=-lX11 -lGL -lpng -lm 4 | DEMOS=\ 5 | GenCubeMap \ 6 | Lava \ 7 | SimpleText \ 8 | TextGrid \ 9 | ClipPlanes \ 10 | VoronoiPicking \ 11 | DistancePicking \ 12 | ToonShading \ 13 | DeepOpacity \ 14 | Raycast \ 15 | 16 | SHARED=pez.o bstrlib.o pez.linux.o lodepng.o 17 | PREFIX=demo- 18 | 19 | run: GenCubeMap 20 | ./GenCubeMap 21 | 22 | all: $(DEMOS) 23 | 24 | define DEMO_RULE 25 | $(1): $(PREFIX)$(1).o $(PREFIX)$(1).glsl $(SHARED) 26 | $(CC) $(PREFIX)$(1).o $(SHARED) -o $(1) $(LIBS) 27 | endef 28 | 29 | $(foreach demo,$(DEMOS),$(eval $(call DEMO_RULE,$(demo)))) 30 | 31 | .c.o: 32 | $(CC) $(CFLAGS) $< -o $@ 33 | 34 | clean: 35 | rm -rf *.o $(DEMOS) 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is my collection of tiny OpenGL demos for Linux. 2 | 3 | To build and run a single recipe, type this: 4 | 5 | make -j ClipPlanes 6 | ./ClipPlanes 7 | 8 | To build all the recipes, type this: 9 | 10 | make -j all 11 | -------------------------------------------------------------------------------- /Smoke96.pbo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/recipes/34a5f6fa4109be03e180bc6839cbc0253b0cacea/Smoke96.pbo -------------------------------------------------------------------------------- /abstract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/recipes/34a5f6fa4109be03e180bc6839cbc0253b0cacea/abstract.png -------------------------------------------------------------------------------- /bstrlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This source file is part of the bstring string library. This code was 3 | * written by Paul Hsieh in 2002-2010, and is covered by either the 3-clause 4 | * BSD open source license or GPL v2.0. Refer to the accompanying documentation 5 | * for details on usage and license. 6 | */ 7 | 8 | /* 9 | * bstrlib.h 10 | * 11 | * This file is the header file for the core module for implementing the 12 | * bstring functions. 13 | */ 14 | 15 | #ifndef BSTRLIB_INCLUDE 16 | #define BSTRLIB_INCLUDE 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #if !defined (BSTRLIB_VSNP_OK) && !defined (BSTRLIB_NOVSNP) 28 | # if defined (__TURBOC__) && !defined (__BORLANDC__) 29 | # define BSTRLIB_NOVSNP 30 | # endif 31 | #endif 32 | 33 | #define BSTR_ERR (-1) 34 | #define BSTR_OK (0) 35 | #define BSTR_BS_BUFF_LENGTH_GET (0) 36 | 37 | typedef struct tagbstring * bstring; 38 | typedef const struct tagbstring * const_bstring; 39 | 40 | /* Copy functions */ 41 | #define cstr2bstr bfromcstr 42 | extern bstring bfromcstr (const char * str); 43 | extern bstring bfromcstralloc (int mlen, const char * str); 44 | extern bstring blk2bstr (const void * blk, int len); 45 | extern char * bstr2cstr (const_bstring s, char z); 46 | extern int bcstrfree (char * s); 47 | extern bstring bstrcpy (const_bstring b1); 48 | extern int bassign (bstring a, const_bstring b); 49 | extern int bassignmidstr (bstring a, const_bstring b, int left, int len); 50 | extern int bassigncstr (bstring a, const char * str); 51 | extern int bassignblk (bstring a, const void * s, int len); 52 | 53 | /* Destroy function */ 54 | extern int bdestroy (bstring b); 55 | 56 | /* Space allocation hinting functions */ 57 | extern int balloc (bstring s, int len); 58 | extern int ballocmin (bstring b, int len); 59 | 60 | /* Substring extraction */ 61 | extern bstring bmidstr (const_bstring b, int left, int len); 62 | 63 | /* Various standard manipulations */ 64 | extern int bconcat (bstring b0, const_bstring b1); 65 | extern int bconchar (bstring b0, char c); 66 | extern int bcatcstr (bstring b, const char * s); 67 | extern int bcatblk (bstring b, const void * s, int len); 68 | extern int binsert (bstring s1, int pos, const_bstring s2, unsigned char fill); 69 | extern int binsertch (bstring s1, int pos, int len, unsigned char fill); 70 | extern int breplace (bstring b1, int pos, int len, const_bstring b2, unsigned char fill); 71 | extern int bdelete (bstring s1, int pos, int len); 72 | extern int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill); 73 | extern int btrunc (bstring b, int n); 74 | 75 | /* Scan/search functions */ 76 | extern int bstricmp (const_bstring b0, const_bstring b1); 77 | extern int bstrnicmp (const_bstring b0, const_bstring b1, int n); 78 | extern int biseqcaseless (const_bstring b0, const_bstring b1); 79 | extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); 80 | extern int biseq (const_bstring b0, const_bstring b1); 81 | extern int bisstemeqblk (const_bstring b0, const void * blk, int len); 82 | extern int biseqcstr (const_bstring b, const char * s); 83 | extern int biseqcstrcaseless (const_bstring b, const char * s); 84 | extern int bstrcmp (const_bstring b0, const_bstring b1); 85 | extern int bstrncmp (const_bstring b0, const_bstring b1, int n); 86 | extern int binstr (const_bstring s1, int pos, const_bstring s2); 87 | extern int binstrr (const_bstring s1, int pos, const_bstring s2); 88 | extern int binstrcaseless (const_bstring s1, int pos, const_bstring s2); 89 | extern int binstrrcaseless (const_bstring s1, int pos, const_bstring s2); 90 | extern int bstrchrp (const_bstring b, int c, int pos); 91 | extern int bstrrchrp (const_bstring b, int c, int pos); 92 | #define bstrchr(b,c) bstrchrp ((b), (c), 0) 93 | #define bstrrchr(b,c) bstrrchrp ((b), (c), blength(b)-1) 94 | extern int binchr (const_bstring b0, int pos, const_bstring b1); 95 | extern int binchrr (const_bstring b0, int pos, const_bstring b1); 96 | extern int bninchr (const_bstring b0, int pos, const_bstring b1); 97 | extern int bninchrr (const_bstring b0, int pos, const_bstring b1); 98 | extern int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos); 99 | extern int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos); 100 | 101 | /* List of string container functions */ 102 | struct bstrList { 103 | int qty, mlen; 104 | bstring * entry; 105 | }; 106 | extern struct bstrList * bstrListCreate (void); 107 | extern int bstrListDestroy (struct bstrList * sl); 108 | extern int bstrListAlloc (struct bstrList * sl, int msz); 109 | extern int bstrListAllocMin (struct bstrList * sl, int msz); 110 | 111 | /* String split and join functions */ 112 | extern struct bstrList * bsplit (const_bstring str, unsigned char splitChar); 113 | extern struct bstrList * bsplits (const_bstring str, const_bstring splitStr); 114 | extern struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr); 115 | extern bstring bjoin (const struct bstrList * bl, const_bstring sep); 116 | extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos, 117 | int (* cb) (void * parm, int ofs, int len), void * parm); 118 | extern int bsplitscb (const_bstring str, const_bstring splitStr, int pos, 119 | int (* cb) (void * parm, int ofs, int len), void * parm); 120 | extern int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos, 121 | int (* cb) (void * parm, int ofs, int len), void * parm); 122 | 123 | /* Miscellaneous functions */ 124 | extern int bpattern (bstring b, int len); 125 | extern int btoupper (bstring b); 126 | extern int btolower (bstring b); 127 | extern int bltrimws (bstring b); 128 | extern int brtrimws (bstring b); 129 | extern int btrimws (bstring b); 130 | 131 | /* <*>printf format functions */ 132 | #if !defined (BSTRLIB_NOVSNP) 133 | extern bstring bformat (const char * fmt, ...); 134 | extern int bformata (bstring b, const char * fmt, ...); 135 | extern int bassignformat (bstring b, const char * fmt, ...); 136 | extern int bvcformata (bstring b, int count, const char * fmt, va_list arglist); 137 | 138 | #define bvformata(ret, b, fmt, lastarg) { \ 139 | bstring bstrtmp_b = (b); \ 140 | const char * bstrtmp_fmt = (fmt); \ 141 | int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \ 142 | for (;;) { \ 143 | va_list bstrtmp_arglist; \ 144 | va_start (bstrtmp_arglist, lastarg); \ 145 | bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \ 146 | va_end (bstrtmp_arglist); \ 147 | if (bstrtmp_r >= 0) { /* Everything went ok */ \ 148 | bstrtmp_r = BSTR_OK; \ 149 | break; \ 150 | } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \ 151 | bstrtmp_r = BSTR_ERR; \ 152 | break; \ 153 | } \ 154 | bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \ 155 | } \ 156 | ret = bstrtmp_r; \ 157 | } 158 | 159 | #endif 160 | 161 | typedef int (*bNgetc) (void *parm); 162 | typedef size_t (* bNread) (void *buff, size_t elsize, size_t nelem, void *parm); 163 | 164 | /* Input functions */ 165 | extern bstring bgets (bNgetc getcPtr, void * parm, char terminator); 166 | extern bstring bread (bNread readPtr, void * parm); 167 | extern int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator); 168 | extern int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator); 169 | extern int breada (bstring b, bNread readPtr, void * parm); 170 | 171 | /* Stream functions */ 172 | extern struct bStream * bsopen (bNread readPtr, void * parm); 173 | extern void * bsclose (struct bStream * s); 174 | extern int bsbufflength (struct bStream * s, int sz); 175 | extern int bsreadln (bstring b, struct bStream * s, char terminator); 176 | extern int bsreadlns (bstring r, struct bStream * s, const_bstring term); 177 | extern int bsread (bstring b, struct bStream * s, int n); 178 | extern int bsreadlna (bstring b, struct bStream * s, char terminator); 179 | extern int bsreadlnsa (bstring r, struct bStream * s, const_bstring term); 180 | extern int bsreada (bstring b, struct bStream * s, int n); 181 | extern int bsunread (struct bStream * s, const_bstring b); 182 | extern int bspeek (bstring r, const struct bStream * s); 183 | extern int bssplitscb (struct bStream * s, const_bstring splitStr, 184 | int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); 185 | extern int bssplitstrcb (struct bStream * s, const_bstring splitStr, 186 | int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); 187 | extern int bseof (const struct bStream * s); 188 | 189 | struct tagbstring { 190 | int mlen; 191 | int slen; 192 | unsigned char * data; 193 | }; 194 | 195 | /* Accessor macros */ 196 | #define blengthe(b, e) (((b) == (void *)0 || (b)->slen < 0) ? (int)(e) : ((b)->slen)) 197 | #define blength(b) (blengthe ((b), 0)) 198 | #define bdataofse(b, o, e) (((b) == (void *)0 || (b)->data == (void*)0) ? (char *)(e) : ((char *)(b)->data) + (o)) 199 | #define bdataofs(b, o) (bdataofse ((b), (o), (void *)0)) 200 | #define bdatae(b, e) (bdataofse (b, 0, e)) 201 | #define bdata(b) (bdataofs (b, 0)) 202 | #define bchare(b, p, e) ((((unsigned)(p)) < (unsigned)blength(b)) ? ((b)->data[(p)]) : (e)) 203 | #define bchar(b, p) bchare ((b), (p), '\0') 204 | 205 | /* Static constant string initialization macro */ 206 | #define bsStaticMlen(q,m) {(m), (int) sizeof(q)-1, (unsigned char *) ("" q "")} 207 | #if defined(_MSC_VER) 208 | /* There are many versions of MSVC which emit __LINE__ as a non-constant. */ 209 | # define bsStatic(q) bsStaticMlen(q,-32) 210 | #endif 211 | #ifndef bsStatic 212 | # define bsStatic(q) bsStaticMlen(q,-__LINE__) 213 | #endif 214 | 215 | /* Static constant block parameter pair */ 216 | #define bsStaticBlkParms(q) ((void *)("" q "")), ((int) sizeof(q)-1) 217 | 218 | /* Reference building macros */ 219 | #define cstr2tbstr btfromcstr 220 | #define btfromcstr(t,s) { \ 221 | (t).data = (unsigned char *) (s); \ 222 | (t).slen = ((t).data) ? ((int) (strlen) ((char *)(t).data)) : 0; \ 223 | (t).mlen = -1; \ 224 | } 225 | #define blk2tbstr(t,s,l) { \ 226 | (t).data = (unsigned char *) (s); \ 227 | (t).slen = l; \ 228 | (t).mlen = -1; \ 229 | } 230 | #define btfromblk(t,s,l) blk2tbstr(t,s,l) 231 | #define bmid2tbstr(t,b,p,l) { \ 232 | const_bstring bstrtmp_s = (b); \ 233 | if (bstrtmp_s && bstrtmp_s->data && bstrtmp_s->slen >= 0) { \ 234 | int bstrtmp_left = (p); \ 235 | int bstrtmp_len = (l); \ 236 | if (bstrtmp_left < 0) { \ 237 | bstrtmp_len += bstrtmp_left; \ 238 | bstrtmp_left = 0; \ 239 | } \ 240 | if (bstrtmp_len > bstrtmp_s->slen - bstrtmp_left) \ 241 | bstrtmp_len = bstrtmp_s->slen - bstrtmp_left; \ 242 | if (bstrtmp_len <= 0) { \ 243 | (t).data = (unsigned char *)""; \ 244 | (t).slen = 0; \ 245 | } else { \ 246 | (t).data = bstrtmp_s->data + bstrtmp_left; \ 247 | (t).slen = bstrtmp_len; \ 248 | } \ 249 | } else { \ 250 | (t).data = (unsigned char *)""; \ 251 | (t).slen = 0; \ 252 | } \ 253 | (t).mlen = -__LINE__; \ 254 | } 255 | #define btfromblkltrimws(t,s,l) { \ 256 | int bstrtmp_idx = 0, bstrtmp_len = (l); \ 257 | unsigned char * bstrtmp_s = (s); \ 258 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 259 | for (; bstrtmp_idx < bstrtmp_len; bstrtmp_idx++) { \ 260 | if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ 261 | } \ 262 | } \ 263 | (t).data = bstrtmp_s + bstrtmp_idx; \ 264 | (t).slen = bstrtmp_len - bstrtmp_idx; \ 265 | (t).mlen = -__LINE__; \ 266 | } 267 | #define btfromblkrtrimws(t,s,l) { \ 268 | int bstrtmp_len = (l) - 1; \ 269 | unsigned char * bstrtmp_s = (s); \ 270 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 271 | for (; bstrtmp_len >= 0; bstrtmp_len--) { \ 272 | if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ 273 | } \ 274 | } \ 275 | (t).data = bstrtmp_s; \ 276 | (t).slen = bstrtmp_len + 1; \ 277 | (t).mlen = -__LINE__; \ 278 | } 279 | #define btfromblktrimws(t,s,l) { \ 280 | int bstrtmp_idx = 0, bstrtmp_len = (l) - 1; \ 281 | unsigned char * bstrtmp_s = (s); \ 282 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 283 | for (; bstrtmp_idx <= bstrtmp_len; bstrtmp_idx++) { \ 284 | if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ 285 | } \ 286 | for (; bstrtmp_len >= bstrtmp_idx; bstrtmp_len--) { \ 287 | if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ 288 | } \ 289 | } \ 290 | (t).data = bstrtmp_s + bstrtmp_idx; \ 291 | (t).slen = bstrtmp_len + 1 - bstrtmp_idx; \ 292 | (t).mlen = -__LINE__; \ 293 | } 294 | 295 | /* Write protection macros */ 296 | #define bwriteprotect(t) { if ((t).mlen >= 0) (t).mlen = -1; } 297 | #define bwriteallow(t) { if ((t).mlen == -1) (t).mlen = (t).slen + ((t).slen == 0); } 298 | #define biswriteprotected(t) ((t).mlen <= 0) 299 | 300 | #ifdef __cplusplus 301 | } 302 | #endif 303 | 304 | #endif 305 | -------------------------------------------------------------------------------- /cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/recipes/34a5f6fa4109be03e180bc6839cbc0253b0cacea/cloud.png -------------------------------------------------------------------------------- /demo-ClipPlanes.c: -------------------------------------------------------------------------------- 1 | // Clip Planes OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include 6 | #include "pez.h" 7 | #include "vmath.h" 8 | 9 | struct SceneParameters { 10 | int IndexCount; 11 | float Theta; 12 | Matrix4 Projection; 13 | Matrix4 Modelview; 14 | Matrix4 ViewMatrix; 15 | Matrix4 ModelMatrix; 16 | Matrix3 NormalMatrix; 17 | Vector4 ClipPlane; 18 | GLfloat PackedNormalMatrix[9]; 19 | } Scene; 20 | 21 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey); 22 | static GLuint CurrentProgram(); 23 | 24 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 25 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 26 | 27 | PezConfig PezGetConfig() 28 | { 29 | PezConfig config; 30 | config.Title = __FILE__; 31 | config.Width = 853; 32 | config.Height = 480; 33 | config.Multisampling = true; 34 | config.VerticalSync = false; 35 | return config; 36 | } 37 | 38 | static void CreateTorus(float major, float minor, int slices, int stacks) 39 | { 40 | GLuint vao; 41 | glGenVertexArrays(1, &vao); 42 | glBindVertexArray(vao); 43 | 44 | int vertexCount = slices * stacks * 3; 45 | int vertexStride = sizeof(float) * 3; 46 | GLsizeiptr size = vertexCount * vertexStride; 47 | GLfloat* positions = (GLfloat*) malloc(size); 48 | 49 | GLfloat* position = positions; 50 | for (int slice = 0; slice < slices; slice++) { 51 | float theta = slice * 2.0f * Pi / slices; 52 | for (int stack = 0; stack < stacks; stack++) { 53 | float phi = stack * 2.0f * Pi / stacks; 54 | float beta = major + minor * cos(phi); 55 | *position++ = cos(theta) * beta; 56 | *position++ = sin(theta) * beta; 57 | *position++ = sin(phi) * minor; 58 | } 59 | } 60 | 61 | GLuint handle; 62 | glGenBuffers(1, &handle); 63 | glBindBuffer(GL_ARRAY_BUFFER, handle); 64 | glBufferData(GL_ARRAY_BUFFER, size, positions, GL_STATIC_DRAW); 65 | glEnableVertexAttribArray(a("Position")); 66 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, 67 | vertexStride, 0); 68 | 69 | free(positions); 70 | 71 | Scene.IndexCount = slices * stacks * 6; 72 | size = Scene.IndexCount * sizeof(GLushort); 73 | GLushort* indices = (GLushort*) malloc(size); 74 | GLushort* index = indices; 75 | int v = 0; 76 | for (int i = 0; i < slices - 1; i++) { 77 | for (int j = 0; j < stacks; j++) { 78 | int next = (j + 1) % stacks; 79 | *index++ = v+next+stacks; *index++ = v+next; *index++ = v+j; 80 | *index++ = v+j; *index++ = v+j+stacks; *index++ = v+next+stacks; 81 | } 82 | v += stacks; 83 | } 84 | for (int j = 0; j < stacks; j++) { 85 | int next = (j + 1) % stacks; 86 | *index++ = next; *index++ = v+next; *index++ = v+j; 87 | *index++ = v+j; *index++ = j; *index++ = next; 88 | } 89 | 90 | glGenBuffers(1, &handle); 91 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); 92 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW); 93 | 94 | free(indices); 95 | } 96 | 97 | void PezInitialize() 98 | { 99 | LoadProgram("VS", "GS", "FS"); 100 | 101 | PezConfig cfg = PezGetConfig(); 102 | const float h = 5.0f; 103 | const float w = h * cfg.Width / cfg.Height; 104 | Scene.Projection = M4MakeFrustum(-w, w, // left & right planes 105 | -h, h, // bottom & top planes 106 | 65, 90); // near & far planes 107 | 108 | const float MajorRadius = 8.0f, MinorRadius = 2.0f; 109 | const int Slices = 40, Stacks = 10; 110 | CreateTorus(MajorRadius, MinorRadius, Slices, Stacks); 111 | Scene.Theta = 0; 112 | Scene.ClipPlane = (Vector4){0, 1, 0, 7}; 113 | 114 | glEnable(GL_DEPTH_TEST); 115 | glEnable(GL_CLIP_DISTANCE0); 116 | glClearColor(0.5f, 0.6f, 0.7f, 1.0f); 117 | } 118 | 119 | void PezUpdate(float seconds) 120 | { 121 | const float RadiansPerSecond = 0.5f; 122 | Scene.Theta += seconds * RadiansPerSecond; 123 | 124 | // Create the model-view matrix: 125 | Scene.ModelMatrix = M4MakeRotationZ(Scene.Theta); 126 | Point3 eye = {0, -75, 25}; 127 | Point3 target = {0, 0, 0}; 128 | Vector3 up = {0, 1, 0}; 129 | Scene.ViewMatrix = M4MakeLookAt(eye, target, up); 130 | Scene.Modelview = M4Mul(Scene.ViewMatrix, Scene.ModelMatrix); 131 | Scene.NormalMatrix = M4GetUpper3x3(Scene.Modelview); 132 | for (int i = 0; i < 9; ++i) 133 | Scene.PackedNormalMatrix[i] = M3GetElem(Scene.NormalMatrix, i/3, i%3); 134 | } 135 | 136 | void PezRender() 137 | { 138 | float* pModel = (float*) &Scene.ModelMatrix; 139 | float* pView = (float*) &Scene.ViewMatrix; 140 | float* pModelview = (float*) &Scene.Modelview; 141 | float* pProjection = (float*) &Scene.Projection; 142 | float* pNormalMatrix = &Scene.PackedNormalMatrix[0]; 143 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 144 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 145 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 146 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 147 | glUniformMatrix3fv(u("NormalMatrix"), 1, 0, pNormalMatrix); 148 | glUniform4fv(u("ClipPlane"), 1, &Scene.ClipPlane.x); 149 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 150 | glDrawElements(GL_TRIANGLES, Scene.IndexCount, GL_UNSIGNED_SHORT, 0); 151 | } 152 | 153 | void PezHandleMouse(int x, int y, int action) 154 | { 155 | } 156 | 157 | static GLuint CurrentProgram() 158 | { 159 | GLuint p; 160 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 161 | return p; 162 | } 163 | 164 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey) 165 | { 166 | GLchar spew[256]; 167 | GLint compileSuccess; 168 | GLuint programHandle = glCreateProgram(); 169 | 170 | const char* vsSource = pezGetShader(vsKey); 171 | pezCheck(vsSource != 0, "Can't find vshader: %s\n", vsKey); 172 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 173 | glShaderSource(vsHandle, 1, &vsSource, 0); 174 | glCompileShader(vsHandle); 175 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 176 | glGetShaderInfoLog(vsHandle, sizeof(spew), 0, spew); 177 | pezCheck(compileSuccess, "Can't compile vshader:\n%s", spew); 178 | glAttachShader(programHandle, vsHandle); 179 | 180 | const char* gsSource = pezGetShader(gsKey); 181 | pezCheck(gsSource != 0, "Can't find gshader: %s\n", gsKey); 182 | GLuint gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 183 | glShaderSource(gsHandle, 1, &gsSource, 0); 184 | glCompileShader(gsHandle); 185 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 186 | glGetShaderInfoLog(gsHandle, sizeof(spew), 0, spew); 187 | pezCheck(compileSuccess, "Can't compile gshader:\n%s", spew); 188 | glAttachShader(programHandle, gsHandle); 189 | 190 | const char* fsSource = pezGetShader(fsKey); 191 | pezCheck(fsSource != 0, "Can't find fshader: %s\n", fsKey); 192 | GLuint fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 193 | glShaderSource(fsHandle, 1, &fsSource, 0); 194 | glCompileShader(fsHandle); 195 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 196 | glGetShaderInfoLog(fsHandle, sizeof(spew), 0, spew); 197 | pezCheck(compileSuccess, "Can't compile fshader:\n%s", spew); 198 | glAttachShader(programHandle, fsHandle); 199 | 200 | glLinkProgram(programHandle); 201 | GLint linkSuccess; 202 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 203 | glGetProgramInfoLog(programHandle, sizeof(spew), 0, spew); 204 | pezCheck(linkSuccess, "Can't link shaders:\n%s", spew); 205 | glUseProgram(programHandle); 206 | return programHandle; 207 | } 208 | -------------------------------------------------------------------------------- /demo-ClipPlanes.glsl: -------------------------------------------------------------------------------- 1 | -- VS 2 | 3 | in vec4 Position; 4 | out vec3 vPosition; 5 | out float gl_ClipDistance[1]; 6 | 7 | uniform mat4 Projection; 8 | uniform mat4 Modelview; 9 | uniform mat4 ViewMatrix; 10 | uniform mat4 ModelMatrix; 11 | uniform vec4 ClipPlane; 12 | 13 | void main() 14 | { 15 | vPosition = Position.xyz; 16 | gl_Position = Projection * Modelview * Position; 17 | gl_ClipDistance[0] = dot(ModelMatrix * Position, ClipPlane); 18 | } 19 | 20 | -- GS 21 | 22 | out vec2 gDistance; 23 | out vec3 gNormal; 24 | in vec3 vPosition[3]; 25 | 26 | uniform mat3 NormalMatrix; 27 | layout(triangles) in; 28 | layout(triangle_strip, max_vertices = 3) out; 29 | 30 | void main() 31 | { 32 | vec3 A = vPosition[0]; 33 | vec3 B = vPosition[1]; 34 | vec3 C = vPosition[2]; 35 | 36 | gNormal = NormalMatrix * normalize(cross(B - A, C - A)); 37 | 38 | gDistance = vec2(1, 0); 39 | gl_Position = gl_in[0].gl_Position; 40 | gl_ClipDistance[0] = gl_in[0].gl_ClipDistance[0]; 41 | EmitVertex(); 42 | 43 | gDistance = vec2(0, 0); 44 | gl_Position = gl_in[1].gl_Position; 45 | gl_ClipDistance[0] = gl_in[1].gl_ClipDistance[0]; 46 | EmitVertex(); 47 | 48 | gDistance = vec2(0, 1); 49 | gl_Position = gl_in[2].gl_Position; 50 | gl_ClipDistance[0] = gl_in[2].gl_ClipDistance[0]; 51 | EmitVertex(); 52 | 53 | EndPrimitive(); 54 | } 55 | 56 | -- FS 57 | 58 | in vec2 gDistance; 59 | in vec3 gNormal; 60 | out vec4 FragColor; 61 | 62 | const float Scale = 20.0; 63 | const float Offset = -1.0; 64 | 65 | uniform vec3 LightPosition = vec3(0.25, 0.25, 1.0); 66 | uniform vec3 AmbientMaterial = vec3(0.04, 0.04, 0.04); 67 | uniform vec3 SpecularMaterial = vec3(0.5, 0.5, 0.5); 68 | uniform vec3 FrontMaterial = vec3(0.75, 0.75, 0.5); 69 | uniform vec3 BackMaterial = vec3(0.5, 0.5, 0.75); 70 | uniform float Shininess = 50; 71 | 72 | vec4 amplify(float d, vec3 color) 73 | { 74 | d = Scale * d + Offset + gl_FragCoord.z; 75 | d = clamp(d, 0, 1); 76 | d = 1 - exp2(-2*d*d); 77 | return vec4(d*color, 1); 78 | } 79 | 80 | void main() 81 | { 82 | vec3 N = normalize(gNormal); 83 | if (!gl_FrontFacing) 84 | N = -N; 85 | 86 | vec3 L = normalize(LightPosition); 87 | vec3 Eye = vec3(0, 0, 1); 88 | vec3 H = normalize(L + Eye); 89 | 90 | float df = max(0.0, dot(N, L)); 91 | float sf = max(0.0, dot(N, H)); 92 | sf = pow(sf, Shininess); 93 | 94 | vec3 color = gl_FrontFacing ? FrontMaterial : BackMaterial; 95 | vec3 lighting = AmbientMaterial + df * color; 96 | if (gl_FrontFacing) 97 | lighting += sf * SpecularMaterial; 98 | 99 | float d = min(gDistance.x, gDistance.y); 100 | FragColor = amplify(d, lighting); 101 | } 102 | -------------------------------------------------------------------------------- /demo-DeepOpacity.c: -------------------------------------------------------------------------------- 1 | // Deep Opacity OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include "pez.h" 6 | #include "vmath.h" 7 | 8 | static const Point3 EyePosition = {0, 0, 2}; 9 | static Point3 LightPosition = {1, 1, 2}; 10 | static const float FieldOfView = 0.7f; 11 | static const int GridSize = 96; 12 | static const int ViewSamples = 96 * 2; 13 | static const int LightSamples = 96; 14 | 15 | PezConfig PezGetConfig() 16 | { 17 | PezConfig config; 18 | config.Title = __FILE__; 19 | config.Width = 853; 20 | config.Height = 480; 21 | config.Multisampling = false; 22 | config.VerticalSync = false; 23 | return config; 24 | } 25 | 26 | typedef struct VolumeRec { 27 | GLuint FboHandle; 28 | GLuint TextureHandle; 29 | GLsizei Width; 30 | GLsizei Height; 31 | GLsizei Depth; 32 | } Volume; 33 | 34 | struct VolumesRec { 35 | Volume Density; 36 | Volume LightCache; 37 | } Volumes; 38 | 39 | struct MatricesRec { 40 | Matrix4 Projection; 41 | Matrix4 Modelview; 42 | Matrix4 ModelviewProjection; 43 | } Matrices; 44 | 45 | struct VbosRec { 46 | GLuint CubeCenter; 47 | GLuint FullscreenQuad; 48 | } Vbos; 49 | 50 | struct ProgramsRec { 51 | GLuint Raycast; 52 | GLuint Light; 53 | } Programs; 54 | 55 | static GLuint LoadProgram(char* vs, char* gs, char* fs); 56 | static Volume CreateVolume(GLsizei w, GLsizei h, GLsizei d, int numComponents); 57 | static GLuint CurrentProgram(); 58 | 59 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 60 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 61 | 62 | void PezInitialize() 63 | { 64 | Programs.Raycast = LoadProgram("VS", "GS", "FS"); 65 | Programs.Light = LoadProgram("Fluid.Vertex", "Fluid.PickLayer", "Light.Cache"); 66 | 67 | GLuint vao; 68 | glGenVertexArrays(1, &vao); 69 | glBindVertexArray(vao); 70 | 71 | float p[] = {0, 0, 0}; 72 | glGenBuffers(1, &Vbos.CubeCenter); 73 | glBindBuffer(GL_ARRAY_BUFFER, Vbos.CubeCenter); 74 | glBufferData(GL_ARRAY_BUFFER, sizeof(p), &p[0], GL_STATIC_DRAW); 75 | 76 | short q[] = { -1, -1, 1, -1, -1, 1, 1, 1 }; 77 | glGenBuffers(1, &Vbos.FullscreenQuad); 78 | glBindBuffer(GL_ARRAY_BUFFER, Vbos.FullscreenQuad); 79 | glBufferData(GL_ARRAY_BUFFER, sizeof(q), q, GL_STATIC_DRAW); 80 | 81 | Volumes.Density = CreateVolume(GridSize, GridSize, GridSize, 1); 82 | Volumes.LightCache = CreateVolume(GridSize, GridSize, GridSize, 1); 83 | 84 | PezPixels pixels = pezLoadPixels("Smoke96.pbo"); 85 | glBindTexture(GL_TEXTURE_3D, Volumes.Density.TextureHandle); 86 | glTexImage3D(GL_TEXTURE_3D, 0, pixels.InternalFormat, 87 | pixels.Width, pixels.Height, pixels.Depth, 88 | 0, pixels.Format, pixels.Type, pixels.Frames); 89 | pezFreePixels(pixels); 90 | 91 | glDisable(GL_DEPTH_TEST); 92 | glEnable(GL_CULL_FACE); 93 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 94 | 95 | glEnableVertexAttribArray(0); 96 | } 97 | 98 | void PezRender() 99 | { 100 | PezConfig cfg = PezGetConfig(); 101 | Vector3 rayOrigin = V4GetXYZ(M4MulP3(M4Transpose(Matrices.Modelview), EyePosition)); 102 | GLfloat* mvp = &Matrices.ModelviewProjection.col0.x; 103 | GLfloat* mv = &Matrices.Modelview.col0.x; 104 | GLfloat* proj = &Matrices.Projection.col0.x; 105 | 106 | // Generate the light cache: 107 | glDisable(GL_BLEND); 108 | glBindFramebuffer(GL_FRAMEBUFFER, Volumes.LightCache.FboHandle); 109 | glViewport(0, 0, Volumes.LightCache.Width, Volumes.LightCache.Height); 110 | glBindBuffer(GL_ARRAY_BUFFER, Vbos.FullscreenQuad); 111 | glVertexAttribPointer(0, 2, GL_SHORT, GL_FALSE, 2 * sizeof(short), 0); 112 | glBindTexture(GL_TEXTURE_3D, Volumes.Density.TextureHandle); 113 | glUseProgram(Programs.Light); 114 | glUniform3fv(u("LightPosition"), 1, &LightPosition.x); 115 | glUniform1f(u("LightStep"), sqrtf(2.0f) / LightSamples); 116 | glUniform1i(u("LightSamples"), LightSamples); 117 | glUniform1f(u("InverseSize"), 1.0f / GridSize); 118 | glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, GridSize); 119 | 120 | // Perform raycasting: 121 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 122 | glViewport(0, 0, cfg.Width, cfg.Height); 123 | glClearColor(0, 0, 0, 0); 124 | glClear(GL_COLOR_BUFFER_BIT); 125 | glEnable(GL_BLEND); 126 | glBindBuffer(GL_ARRAY_BUFFER, Vbos.CubeCenter); 127 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); 128 | glActiveTexture(GL_TEXTURE0); 129 | glBindTexture(GL_TEXTURE_3D, Volumes.Density.TextureHandle); 130 | glActiveTexture(GL_TEXTURE1); 131 | glBindTexture(GL_TEXTURE_3D, Volumes.LightCache.TextureHandle); 132 | glUseProgram(Programs.Raycast); 133 | glUniformMatrix4fv(u("ModelviewProjection"), 1, 0, mvp); 134 | glUniformMatrix4fv(u("Modelview"), 1, 0, mv); 135 | glUniformMatrix4fv(u("ProjectionMatrix"), 1, 0, proj); 136 | glUniform1i(u("ViewSamples"), ViewSamples); 137 | glUniform3fv(u("EyePosition"), 1, &EyePosition.x); 138 | glUniform1i(u("Density"), 0); 139 | glUniform1i(u("LightCache"), 1); 140 | glUniform3fv(u("RayOrigin"), 1, &rayOrigin.x); 141 | glUniform1f(u("FocalLength"), 1.0f / tanf(FieldOfView / 2)); 142 | glUniform2f(u("WindowSize"), (float) cfg.Width, (float) cfg.Height); 143 | glUniform1f(u("StepSize"), sqrtf(3.0f) / ViewSamples); // should be sqrt(2) 144 | glDrawArrays(GL_POINTS, 0, 1); 145 | glActiveTexture(GL_TEXTURE1); 146 | glBindTexture(GL_TEXTURE_3D, 0); 147 | glActiveTexture(GL_TEXTURE0); 148 | } 149 | 150 | void PezUpdate(float dt) 151 | { 152 | static float theta = 0; 153 | theta += dt / 2.0f; 154 | 155 | Vector3 up = {1, 0, 0}; Point3 target = {0, 0, 0}; 156 | Matrix4 view = M4MakeLookAt(EyePosition, target, up); 157 | Matrix4 spin = M4MakeRotationX(sin(theta / 4) * Pi / 2); 158 | Matrix4 model = M4Mul(spin, M4MakeRotationY(0.75)); 159 | Matrices.Modelview = M4Mul(view, model); 160 | 161 | Point3 p = {1, 1, 2}; 162 | LightPosition = T3MulP3(T3MakeRotationY(2 * theta), p); 163 | 164 | PezConfig cfg = PezGetConfig(); 165 | float aspectRatio = (float) cfg.Width / cfg.Height; 166 | Matrices.Projection = M4MakePerspective( 167 | FieldOfView, aspectRatio, 168 | 0.0f, 1.0f); 169 | 170 | Matrices.ModelviewProjection = M4Mul(Matrices.Projection, Matrices.Modelview); 171 | } 172 | 173 | void PezHandleMouse(int x, int y, int action) 174 | { 175 | } 176 | 177 | static GLuint LoadProgram(char* vsKey, char* gsKey, char* fsKey) 178 | { 179 | const char* vsSource = pezGetShader(vsKey); 180 | const char* gsSource = pezGetShader(gsKey); 181 | const char* fsSource = pezGetShader(fsKey); 182 | 183 | const char* msg = "Can't find %s shader: '%s'.\n"; 184 | pezCheck(vsSource != 0, msg, "vertex", vsKey); 185 | pezCheck(gsKey == 0 || gsSource != 0, msg, "geometry", gsKey); 186 | pezCheck(fsKey == 0 || fsSource != 0, msg, "fragment", fsKey); 187 | 188 | GLint compileSuccess; 189 | GLchar compilerSpew[256]; 190 | GLuint programHandle = glCreateProgram(); 191 | 192 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 193 | glShaderSource(vsHandle, 1, &vsSource, 0); 194 | glCompileShader(vsHandle); 195 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 196 | glGetShaderInfoLog(vsHandle, sizeof(compilerSpew), 0, compilerSpew); 197 | pezCheck(compileSuccess, "Can't compile %s:\n%s", vsKey, compilerSpew); 198 | glAttachShader(programHandle, vsHandle); 199 | 200 | GLuint gsHandle; 201 | if (gsKey) { 202 | gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 203 | glShaderSource(gsHandle, 1, &gsSource, 0); 204 | glCompileShader(gsHandle); 205 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 206 | glGetShaderInfoLog(gsHandle, sizeof(compilerSpew), 0, compilerSpew); 207 | pezCheck(compileSuccess, "Can't compile %s:\n%s", gsKey, compilerSpew); 208 | glAttachShader(programHandle, gsHandle); 209 | } 210 | 211 | GLuint fsHandle; 212 | if (fsKey) { 213 | fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 214 | glShaderSource(fsHandle, 1, &fsSource, 0); 215 | glCompileShader(fsHandle); 216 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 217 | glGetShaderInfoLog(fsHandle, sizeof(compilerSpew), 0, compilerSpew); 218 | pezCheck(compileSuccess, "Can't compile %s:\n%s", fsKey, compilerSpew); 219 | glAttachShader(programHandle, fsHandle); 220 | } 221 | 222 | glLinkProgram(programHandle); 223 | 224 | GLint linkSuccess; 225 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 226 | glGetProgramInfoLog(programHandle, sizeof(compilerSpew), 0, compilerSpew); 227 | 228 | if (!linkSuccess) { 229 | pezPrintString("Link error.\n"); 230 | if (vsKey) pezPrintString("Vertex Shader: %s\n", vsKey); 231 | if (gsKey) pezPrintString("Geometry Shader: %s\n", gsKey); 232 | if (fsKey) pezPrintString("Fragment Shader: %s\n", fsKey); 233 | pezPrintString("%s\n", compilerSpew); 234 | } 235 | 236 | return programHandle; 237 | } 238 | 239 | static Volume CreateVolume(GLsizei w, GLsizei h, GLsizei d, int numComponents) 240 | { 241 | GLuint fboHandle; 242 | glGenFramebuffers(1, &fboHandle); 243 | glBindFramebuffer(GL_FRAMEBUFFER, fboHandle); 244 | 245 | GLuint textureHandle; 246 | glGenTextures(1, &textureHandle); 247 | glBindTexture(GL_TEXTURE_3D, textureHandle); 248 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 249 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 250 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 251 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 252 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 253 | 254 | GLenum internalFmt, fmt; 255 | switch (numComponents) { 256 | case 1: internalFmt = GL_R16F; fmt = GL_RED; break; 257 | case 2: internalFmt = GL_RG16F; fmt = GL_RG; break; 258 | case 3: internalFmt = GL_RGB16F; fmt = GL_RGB; break; 259 | case 4: internalFmt = GL_RGBA16F; fmt = GL_RGBA; break; 260 | default: internalFmt = fmt = 0; pezFatal("%d components", numComponents); 261 | } 262 | 263 | GLenum type = GL_HALF_FLOAT; 264 | glTexImage3D(GL_TEXTURE_3D, 0, internalFmt, w, h, d, 0, fmt, type, 0); 265 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to create volume texture"); 266 | 267 | GLuint colorbuffer; 268 | glGenRenderbuffers(1, &colorbuffer); 269 | glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer); 270 | glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureHandle, 0); 271 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to attach color buffer"); 272 | 273 | GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); 274 | pezCheck(GL_FRAMEBUFFER_COMPLETE == fboStatus, "Unable to create FBO."); 275 | 276 | glClearColor(0, 0, 0, 0); 277 | glClear(GL_COLOR_BUFFER_BIT); 278 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 279 | 280 | Volume volume = { fboHandle, textureHandle, w, h, d }; 281 | return volume; 282 | } 283 | 284 | static GLuint CurrentProgram() 285 | { 286 | GLuint p; 287 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 288 | return p; 289 | } 290 | -------------------------------------------------------------------------------- /demo-DeepOpacity.glsl: -------------------------------------------------------------------------------- 1 | -- VS 2 | 3 | in vec4 Position; 4 | out vec4 vPosition; 5 | uniform mat4 ModelviewProjection; 6 | 7 | void main() 8 | { 9 | gl_Position = ModelviewProjection * Position; 10 | vPosition = Position; 11 | } 12 | 13 | -- GS 14 | 15 | layout(points) in; 16 | layout(triangle_strip, max_vertices = 24) out; 17 | 18 | in vec4 vPosition[1]; 19 | 20 | uniform mat4 ModelviewProjection; 21 | uniform mat4 ProjectionMatrix; 22 | uniform mat4 ViewMatrix; 23 | uniform mat4 Modelview; 24 | 25 | vec4 objCube[8]; // Object space coordinate of cube corner 26 | vec4 ndcCube[8]; // Normalized device coordinate of cube corner 27 | ivec4 faces[6]; // Vertex indices of the cube faces 28 | 29 | void emit_vert(int vert) 30 | { 31 | gl_Position = ndcCube[vert]; 32 | EmitVertex(); 33 | } 34 | 35 | void emit_face(int face) 36 | { 37 | emit_vert(faces[face][1]); emit_vert(faces[face][0]); 38 | emit_vert(faces[face][3]); emit_vert(faces[face][2]); 39 | EndPrimitive(); 40 | } 41 | 42 | void main() 43 | { 44 | faces[0] = ivec4(0,1,3,2); faces[1] = ivec4(5,4,6,7); 45 | faces[2] = ivec4(4,5,0,1); faces[3] = ivec4(3,2,7,6); 46 | faces[4] = ivec4(0,3,4,7); faces[5] = ivec4(2,1,6,5); 47 | 48 | vec4 P = vPosition[0]; 49 | vec4 I = vec4(1,0,0,0); 50 | vec4 J = vec4(0,1,0,0); 51 | vec4 K = vec4(0,0,1,0); 52 | 53 | objCube[0] = P+K+I+J; objCube[1] = P+K+I-J; 54 | objCube[2] = P+K-I-J; objCube[3] = P+K-I+J; 55 | objCube[4] = P-K+I+J; objCube[5] = P-K+I-J; 56 | objCube[6] = P-K-I-J; objCube[7] = P-K-I+J; 57 | 58 | // Transform the corners of the box: 59 | for (int vert = 0; vert < 8; vert++) 60 | ndcCube[vert] = ModelviewProjection * objCube[vert]; 61 | 62 | // Emit the six faces: 63 | for (int face = 0; face < 6; face++) 64 | emit_face(face); 65 | } 66 | 67 | -- FS 68 | 69 | out vec4 FragColor; 70 | 71 | uniform sampler3D Density; 72 | uniform sampler3D LightCache; 73 | 74 | uniform float Absorption = 10.0; 75 | uniform mat4 Modelview; 76 | uniform float FocalLength; 77 | uniform vec2 WindowSize; 78 | uniform vec3 RayOrigin; 79 | uniform vec3 Ambient = vec3(0.15, 0.15, 0.20); 80 | uniform float StepSize; 81 | uniform int ViewSamples; 82 | 83 | const bool Jitter = false; 84 | 85 | float GetDensity(vec3 pos) 86 | { 87 | return 2.0 * texture(Density, pos).x; 88 | } 89 | 90 | struct Ray { 91 | vec3 Origin; 92 | vec3 Dir; 93 | }; 94 | 95 | struct AABB { 96 | vec3 Min; 97 | vec3 Max; 98 | }; 99 | 100 | bool IntersectBox(Ray r, AABB aabb, out float t0, out float t1) 101 | { 102 | vec3 invR = 1.0 / r.Dir; 103 | vec3 tbot = invR * (aabb.Min-r.Origin); 104 | vec3 ttop = invR * (aabb.Max-r.Origin); 105 | vec3 tmin = min(ttop, tbot); 106 | vec3 tmax = max(ttop, tbot); 107 | vec2 t = max(tmin.xx, tmin.yz); 108 | t0 = max(t.x, t.y); 109 | t = min(tmax.xx, tmax.yz); 110 | t1 = min(t.x, t.y); 111 | return t0 <= t1; 112 | } 113 | 114 | float randhash(uint seed, float b) 115 | { 116 | const float InverseMaxInt = 1.0 / 4294967295.0; 117 | uint i=(seed^12345391u)*2654435769u; 118 | i^=(i<<6u)^(i>>26u); 119 | i*=2654435769u; 120 | i+=(i<<5u)^(i>>12u); 121 | return float(b * i) * InverseMaxInt; 122 | } 123 | 124 | void main() 125 | { 126 | vec3 rayDirection; 127 | rayDirection.xy = 2.0 * gl_FragCoord.xy / WindowSize - 1.0; 128 | rayDirection.x /= WindowSize.y / WindowSize.x; 129 | rayDirection.z = -FocalLength; 130 | rayDirection = (vec4(rayDirection, 0) * Modelview).xyz; 131 | 132 | Ray eye = Ray( RayOrigin, normalize(rayDirection) ); 133 | AABB aabb = AABB(vec3(-1), vec3(1)); 134 | 135 | float tnear, tfar; 136 | IntersectBox(eye, aabb, tnear, tfar); 137 | if (tnear < 0.0) tnear = 0.0; 138 | 139 | vec3 rayStart = eye.Origin + eye.Dir * tnear; 140 | vec3 rayStop = eye.Origin + eye.Dir * tfar; 141 | rayStart = 0.5 * (rayStart + 1.0); 142 | rayStop = 0.5 * (rayStop + 1.0); 143 | 144 | vec3 pos = rayStart; 145 | vec3 viewDir = normalize(rayStop-rayStart) * StepSize; 146 | float T = 1.0; 147 | vec3 Lo = Ambient; 148 | 149 | if (Jitter) { 150 | uint seed = uint(gl_FragCoord.x) * uint(gl_FragCoord.y); 151 | pos += viewDir * (-0.5 + randhash(seed, 1.0)); 152 | } 153 | 154 | float remainingLength = distance(rayStop, rayStart); 155 | 156 | for (int i=0; i < ViewSamples && remainingLength > 0.0; 157 | ++i, pos += viewDir, remainingLength -= StepSize) { 158 | 159 | float density = GetDensity(pos); 160 | vec3 lightColor = vec3(1); 161 | if (pos.z < 0.1) { 162 | density = 10; 163 | lightColor = 3*Ambient; 164 | } else if (density <= 0.01) { 165 | continue; 166 | } 167 | 168 | T *= 1.0 - density * StepSize * Absorption; 169 | if (T <= 0.01) 170 | break; 171 | 172 | vec3 Li = lightColor * texture(LightCache, pos).xxx; 173 | Lo += Li * T * density * StepSize; 174 | } 175 | 176 | //Lo = 1-Lo; 177 | 178 | FragColor.rgb = Lo; 179 | FragColor.a = 1-T; 180 | } 181 | 182 | -- Light.Cache 183 | 184 | in float gLayer; 185 | out float FragColor; 186 | 187 | uniform sampler3D Density; 188 | uniform vec3 LightPosition = vec3(1.0, 1.0, 2.0); 189 | uniform float LightIntensity = 10.0; 190 | uniform float Absorption = 10.0; 191 | uniform float LightStep; 192 | uniform int LightSamples; 193 | uniform float InverseSize; 194 | 195 | float GetDensity(vec3 pos) 196 | { 197 | return texture(Density, pos).x; 198 | } 199 | 200 | void main() 201 | { 202 | vec3 pos = vec3(InverseSize) * vec3(gl_FragCoord.xy, gLayer); 203 | vec3 lightDir = normalize(LightPosition-pos) * LightStep; 204 | float Tl = 1.0; 205 | vec3 lpos = pos + lightDir; 206 | 207 | for (int s = 0; s < LightSamples; ++s) { 208 | float ld = GetDensity(lpos); 209 | Tl *= 1.0 - Absorption * LightStep * ld; 210 | if (Tl <= 0.01) 211 | break; 212 | 213 | // Would be faster if this coniditional is replaced with a tighter loop 214 | if (lpos.x < 0 || lpos.y < 0 || lpos.z < 0 || 215 | lpos.x > 1 || lpos.y > 1 || lpos.z > 1) 216 | break; 217 | 218 | lpos += lightDir; 219 | } 220 | 221 | float Li = LightIntensity*Tl; 222 | FragColor = Li; 223 | } 224 | 225 | -- Light.Blur 226 | 227 | in float gLayer; 228 | out float FragColor; 229 | uniform sampler3D Density; 230 | uniform float InverseSize; 231 | uniform float StepSize; 232 | uniform float DensityScale; 233 | 234 | float GetDensity(vec3 pos) 235 | { 236 | return texture(Density, pos).x * DensityScale; 237 | } 238 | 239 | // This implements a super stupid filter in 3-Space that takes 7 samples. 240 | // A three-pass seperable Gaussian would be way better. 241 | 242 | void main() 243 | { 244 | vec3 pos = InverseSize * vec3(gl_FragCoord.xy, gLayer); 245 | float e = StepSize; 246 | float z = e; 247 | float density = GetDensity(pos); 248 | density += GetDensity(pos + vec3(e,e,0)); 249 | density += GetDensity(pos + vec3(-e,e,0)); 250 | density += GetDensity(pos + vec3(e,-e,0)); 251 | density += GetDensity(pos + vec3(-e,-e,0)); 252 | density += GetDensity(pos + vec3(0,0,-z)); 253 | density += GetDensity(pos + vec3(0,0,+z)); 254 | density /= 7; 255 | FragColor = density; 256 | } 257 | 258 | 259 | -- Fluid.Vertex 260 | 261 | in vec4 Position; 262 | out int vInstance; 263 | 264 | void main() 265 | { 266 | gl_Position = Position; 267 | vInstance = gl_InstanceID; 268 | } 269 | 270 | -- Fluid.PickLayer 271 | 272 | layout(triangles) in; 273 | layout(triangle_strip, max_vertices = 3) out; 274 | 275 | in int vInstance[3]; 276 | out float gLayer; 277 | 278 | uniform float InverseSize; 279 | 280 | void main() 281 | { 282 | gl_Layer = vInstance[0]; 283 | gLayer = float(gl_Layer) + 0.5; 284 | gl_Position = gl_in[0].gl_Position; 285 | EmitVertex(); 286 | gl_Position = gl_in[1].gl_Position; 287 | EmitVertex(); 288 | gl_Position = gl_in[2].gl_Position; 289 | EmitVertex(); 290 | EndPrimitive(); 291 | } 292 | -------------------------------------------------------------------------------- /demo-DistancePicking.glsl: -------------------------------------------------------------------------------- 1 | -- Quad.VS 2 | 3 | in vec2 Position; 4 | in vec2 TexCoord; 5 | out vec2 vTexCoord; 6 | 7 | void main() 8 | { 9 | vTexCoord = TexCoord; 10 | gl_Position = vec4(Position, 0, 1); 11 | } 12 | 13 | -- Quad.FS 14 | 15 | in vec2 vTexCoord; 16 | layout(location = 0) out vec4 FragColor; 17 | uniform sampler2D Sampler; 18 | uniform vec3 Scale; 19 | 20 | void main() 21 | { 22 | FragColor = vec4(Scale, 1) * texture(Sampler, vTexCoord); 23 | } 24 | 25 | -- Soft.FS 26 | 27 | in vec2 vTexCoord; 28 | layout(location = 0) out vec4 FragColor; 29 | uniform sampler2D ColorTexture; 30 | uniform sampler2D DistanceTexture; 31 | uniform vec2 InverseViewport; 32 | 33 | void main() 34 | { 35 | FragColor = texture(ColorTexture, vTexCoord); 36 | 37 | // White silhouette: 38 | float D = texture(DistanceTexture, vTexCoord).z; 39 | if (D != 0) { 40 | D /= 15.0; 41 | D = clamp(1 - D, 0, 1); 42 | vec3 L = vec3(1,1,1); 43 | vec3 C = L*D + vec3(0,0.25,0.5); 44 | FragColor = vec4(C, 1); 45 | } 46 | 47 | // Vignette dimming: 48 | float d = distance(vTexCoord, vec2(0.5,0.5)); 49 | FragColor *= 1-0.75*d; 50 | } 51 | 52 | -- Erode.FS 53 | 54 | layout(location = 1) out vec3 DistanceMap; 55 | 56 | in vec2 vTexCoord; 57 | 58 | uniform sampler2D Sampler; 59 | uniform float Beta; 60 | uniform vec2 Offset; 61 | 62 | void main() 63 | { 64 | vec3 A3 = texture(Sampler, vTexCoord).xyz; 65 | vec3 e3 = texture(Sampler, vTexCoord + Offset).xyz; 66 | vec3 w3 = texture(Sampler, vTexCoord - Offset).xyz; 67 | 68 | float A = A3.z; 69 | float e = Beta + e3.z; 70 | float w = Beta + w3.z; 71 | float B = min(min(A, e), w); 72 | 73 | if (A == B) { 74 | discard; 75 | } 76 | 77 | DistanceMap.xy = w3.xy; 78 | DistanceMap.z = B; 79 | 80 | if (A <= e && e <= w) DistanceMap.xy = A3.xy; 81 | if (A <= w && w <= e) DistanceMap.xy = A3.xy; 82 | if (e <= A && A <= w) DistanceMap.xy = e3.xy; 83 | if (e <= w && w <= A) DistanceMap.xy = e3.xy; 84 | } 85 | 86 | -- Lit.VS 87 | 88 | in vec4 Position; 89 | in vec3 Normal; 90 | 91 | out vec3 vPosition; 92 | out vec3 vNormal; 93 | 94 | uniform mat4 Projection; 95 | uniform mat4 Modelview; 96 | uniform mat4 ViewMatrix; 97 | uniform mat4 ModelMatrix; 98 | uniform mat3 NormalMatrix; 99 | 100 | void main() 101 | { 102 | vPosition = Position.xyz; 103 | gl_Position = Projection * Modelview * Position; 104 | vNormal = NormalMatrix * Normal; 105 | } 106 | 107 | -- Lit.FS 108 | 109 | in vec3 vNormal; 110 | 111 | layout(location = 0) out vec4 FragColor; 112 | layout(location = 1) out vec3 DistanceMap; 113 | 114 | uniform vec3 LightPosition = vec3(0.25, 0.25, 1.0); 115 | uniform vec3 AmbientMaterial = vec3(0.04, 0.04, 0.04); 116 | uniform vec3 SpecularMaterial = vec3(0.5, 0.5, 0.5); 117 | uniform vec3 FrontMaterial = vec3(0.75, 0.75, 0.5); 118 | uniform vec3 BackMaterial = vec3(0.5, 0.5, 0.75); 119 | uniform float Shininess = 50; 120 | 121 | void main() 122 | { 123 | vec3 N = normalize(vNormal); 124 | if (!gl_FrontFacing) 125 | N = -N; 126 | 127 | vec3 L = normalize(LightPosition); 128 | vec3 Eye = vec3(0, 0, 1); 129 | vec3 H = normalize(L + Eye); 130 | 131 | float df = max(0.0, dot(N, L)); 132 | float sf = max(0.0, dot(N, H)); 133 | sf = pow(sf, Shininess); 134 | 135 | vec3 color = gl_FrontFacing ? FrontMaterial : BackMaterial; 136 | vec3 lighting = AmbientMaterial + df * color; 137 | if (gl_FrontFacing) 138 | lighting += sf * SpecularMaterial; 139 | 140 | FragColor = vec4(lighting, 1); 141 | DistanceMap = vec3(gl_FragCoord.xy, 0); 142 | } 143 | 144 | -- Sprite.VS 145 | 146 | out vec3 vPosition; 147 | uniform vec2 MouseLocation; 148 | uniform mat4 Projection; 149 | uniform mat4 Modelview; 150 | uniform mat4 ViewMatrix; 151 | uniform mat4 ModelMatrix; 152 | 153 | uniform sampler2D Sampler; 154 | uniform vec2 InverseViewport; 155 | uniform float Height; 156 | 157 | void main() 158 | { 159 | vec2 distance = texture(Sampler, MouseLocation * InverseViewport).xy; 160 | vPosition = vec3(distance, 0); 161 | vPosition.y = Height - vPosition.y; 162 | gl_Position = Projection * Modelview * vec4(vPosition, 1); 163 | } 164 | 165 | -- Sprite.GS 166 | 167 | layout(points) in; 168 | layout(triangle_strip, max_vertices = 4) out; 169 | uniform vec2 SpriteSize; 170 | out vec2 gCenterCoord; 171 | uniform vec2 HalfViewport; 172 | uniform vec2 InverseViewport; 173 | 174 | vec2 toFragCoord(vec4 v) 175 | { 176 | return HalfViewport * (1.0 + v.xy / v.w); 177 | } 178 | 179 | void main() 180 | { 181 | vec4 P = gl_in[0].gl_Position; 182 | vec4 U = vec4(SpriteSize.x, 0, 0, 0) * InverseViewport.x; 183 | vec4 V = vec4(0, SpriteSize.y, 0, 0) * InverseViewport.y; 184 | gCenterCoord = toFragCoord(P); 185 | 186 | // Discard the cursor if it's not near anything 187 | if (gCenterCoord.x < 0.01 && gCenterCoord.y < 0.01) { 188 | return; 189 | } 190 | 191 | P.z = 0; 192 | P.xy /= P.w; 193 | P.w = 1; 194 | 195 | gl_Position = P - U - V; EmitVertex(); 196 | gl_Position = P + U - V; EmitVertex(); 197 | gl_Position = P - U + V; EmitVertex(); 198 | gl_Position = P + U + V; EmitVertex(); 199 | EndPrimitive(); 200 | } 201 | 202 | -- Sprite.FS 203 | 204 | out vec4 FragColor; 205 | in vec2 gCenterCoord; 206 | uniform vec2 SpriteSize; 207 | 208 | void main() 209 | { 210 | float L = distance(gl_FragCoord.xy, gCenterCoord); 211 | float D = 2.0 * L / SpriteSize.x; 212 | 213 | // Draw a circular mouse cursor 214 | float t = 0.125; // Border thickness 215 | float r = 0.75; // Inner radius 216 | float w = fwidth(D); // Antialiasing constant 217 | if (D < r - t) { 218 | float A = 1.0 - smoothstep(r-t-w, r-t, D); 219 | FragColor = vec4(A, A, A, 1); 220 | } else if (D < r + t) { 221 | FragColor = vec4(0, 0, 0, 1); 222 | } else { 223 | float A = 1.0 - smoothstep(r+t, r+t+w, D); 224 | FragColor = vec4(0, 0, 0, A); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /demo-GenCubeMap.c: -------------------------------------------------------------------------------- 1 | // CubeMap OpenGL Demo by Philip Rideout 2 | // Lava Shader by TheGameMaker 3 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 4 | // http://creativecommons.org/licenses/by/3.0/ 5 | 6 | #include 7 | #include 8 | #include "pez.h" 9 | #include "vmath.h" 10 | 11 | typedef struct { 12 | GLuint ColorTexture; 13 | GLuint DepthBuffer; 14 | GLuint Fbo; 15 | int Width; 16 | int Height; 17 | } RenderTarget; 18 | 19 | struct GlobalsParameters { 20 | int IndexCount; 21 | float Theta; 22 | float Time; 23 | Matrix4 Projection; 24 | Matrix4 Modelview; 25 | Matrix4 ViewMatrix; 26 | Matrix4 ModelMatrix; 27 | Matrix3 NormalMatrix; 28 | GLuint LavaTexture; 29 | GLuint CloudTexture; 30 | GLuint LavaProgram; 31 | GLuint ReflectionProgram; 32 | GLuint TorusVao; 33 | GLuint SphereVao; 34 | } Globals; 35 | 36 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey); 37 | static GLuint CurrentProgram(); 38 | static GLuint LoadTexture(const char* filename); 39 | static GLuint CreateTorus(float major, float minor, int slices, int stacks); 40 | static GLuint CreateSphere(float radius, int slices, int stacks); 41 | 42 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 43 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 44 | #define offset(x) ((const GLvoid*)x) 45 | #define OpenGLError GL_NO_ERROR == glGetError(), \ 46 | "%s:%d - OpenGL Error - %s", __FILE__, __LINE__, __FUNCTION__ \ 47 | 48 | PezConfig PezGetConfig() 49 | { 50 | PezConfig config; 51 | config.Title = __FILE__; 52 | config.Width = 1280; 53 | config.Height = 800; 54 | config.Multisampling = true; 55 | config.VerticalSync = true; 56 | return config; 57 | } 58 | 59 | static GLuint CreateTorus(float major, float minor, int slices, int stacks) 60 | { 61 | GLuint vao; 62 | glGenVertexArrays(1, &vao); 63 | glBindVertexArray(vao); 64 | 65 | int vertexCount = slices * stacks * 3; 66 | int vertexStride = sizeof(float) * 5; 67 | GLsizeiptr size = vertexCount * vertexStride; 68 | GLfloat* verts = (GLfloat*) malloc(size); 69 | 70 | GLfloat* vert = verts; 71 | for (int slice = 0; slice < slices; slice++) { 72 | float theta = slice * 2.0f * Pi / (slices - 1); 73 | for (int stack = 0; stack < stacks; stack++) { 74 | float phi = stack * 2.0f * Pi / (stacks - 1); 75 | float beta = major + minor * cos(phi); 76 | *vert++ = cos(theta) * beta; 77 | *vert++ = sin(theta) * beta; 78 | *vert++ = sin(phi) * minor; 79 | *vert++ = (float) slice / (slices-1); 80 | *vert++ = (float) stack / (stacks-1); 81 | } 82 | } 83 | 84 | GLuint handle; 85 | glGenBuffers(1, &handle); 86 | glBindBuffer(GL_ARRAY_BUFFER, handle); 87 | glBufferData(GL_ARRAY_BUFFER, size, verts, GL_STATIC_DRAW); 88 | glEnableVertexAttribArray(a("Position")); 89 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, vertexStride, 0); 90 | if (a("TexCoord") != -1) { 91 | glEnableVertexAttribArray(a("TexCoord")); 92 | glVertexAttribPointer(a("TexCoord"), 2, GL_FLOAT, GL_FALSE, vertexStride, offset(12)); 93 | } 94 | 95 | free(verts); 96 | 97 | Globals.IndexCount = (slices-1) * (stacks-1) * 6; 98 | size = Globals.IndexCount * sizeof(GLushort); 99 | GLushort* indices = (GLushort*) malloc(size); 100 | GLushort* index = indices; 101 | int v = 0; 102 | for (int i = 0; i < slices-1; i++) { 103 | for (int j = 0; j < stacks-1; j++) { 104 | int next = (j + 1) % stacks; 105 | *index++ = (v+next+stacks) % vertexCount; 106 | *index++ = (v+next) % vertexCount; 107 | *index++ = (v+j) % vertexCount; 108 | *index++ = (v+j) % vertexCount; 109 | *index++ = (v+j+stacks) % vertexCount; 110 | *index++ = (v+next+stacks) % vertexCount; 111 | } 112 | v += stacks; 113 | } 114 | glGenBuffers(1, &handle); 115 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); 116 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW); 117 | 118 | free(indices); 119 | return vao; 120 | } 121 | 122 | static GLuint CreateSphere(float radius, int slices, int stacks) 123 | { 124 | GLuint vao; 125 | glGenVertexArrays(1, &vao); 126 | glBindVertexArray(vao); 127 | 128 | int vertexCount = slices * stacks * 3; 129 | int vertexStride = sizeof(float) * 5; 130 | GLsizeiptr size = vertexCount * vertexStride; 131 | GLfloat* verts = (GLfloat*) malloc(size); 132 | 133 | GLfloat* vert = verts; 134 | for (int slice = 0; slice < slices; slice++) { 135 | float theta = slice * 2.0f * Pi / (slices - 1); 136 | for (int stack = 0; stack < stacks; stack++) { 137 | float phi = stack * 2.0f * Pi / (stacks - 1); 138 | *vert++ = sin(theta) * cos(phi); 139 | *vert++ = cos(theta); 140 | *vert++ = -sin(theta) * sin(phi); 141 | *vert++ = (float) slice / (slices-1); 142 | *vert++ = (float) stack / (stacks-1); 143 | } 144 | } 145 | 146 | GLuint handle; 147 | glGenBuffers(1, &handle); 148 | glBindBuffer(GL_ARRAY_BUFFER, handle); 149 | glBufferData(GL_ARRAY_BUFFER, size, verts, GL_STATIC_DRAW); 150 | glEnableVertexAttribArray(a("Position")); 151 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, vertexStride, 0); 152 | if (a("TexCoord") != -1) { 153 | glEnableVertexAttribArray(a("TexCoord")); 154 | glVertexAttribPointer(a("TexCoord"), 2, GL_FLOAT, GL_FALSE, vertexStride, offset(12)); 155 | } 156 | 157 | free(verts); 158 | 159 | Globals.IndexCount = (slices-1) * (stacks-1) * 6; 160 | size = Globals.IndexCount * sizeof(GLushort); 161 | GLushort* indices = (GLushort*) malloc(size); 162 | GLushort* index = indices; 163 | int v = 0; 164 | for (int i = 0; i < slices-1; i++) { 165 | for (int j = 0; j < stacks-1; j++) { 166 | int next = (j + 1) % stacks; 167 | *index++ = (v+next+stacks) % vertexCount; 168 | *index++ = (v+next) % vertexCount; 169 | *index++ = (v+j) % vertexCount; 170 | *index++ = (v+j) % vertexCount; 171 | *index++ = (v+j+stacks) % vertexCount; 172 | *index++ = (v+next+stacks) % vertexCount; 173 | } 174 | v += stacks; 175 | } 176 | glGenBuffers(1, &handle); 177 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); 178 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW); 179 | 180 | free(indices); 181 | return vao; 182 | } 183 | 184 | void PezInitialize() 185 | { 186 | PezConfig cfg = PezGetConfig(); 187 | 188 | float fovy = 170 * TwoPi / 180; 189 | float aspect = (float) cfg.Width / cfg.Height; 190 | float zNear = 65, zFar = 90; 191 | Globals.Projection = M4MakePerspective(fovy, aspect, zNear, zFar); 192 | Globals.Theta = 0; 193 | 194 | const float MajorRadius = 11.0f, MinorRadius = 1.5f; 195 | const float Radius = 5.0f; 196 | const int Slices = 60, Stacks = 30; 197 | 198 | Globals.LavaProgram = LoadProgram("TheGameMaker.VS", 0, "TheGameMaker.FS"); 199 | Globals.TorusVao = CreateTorus(MajorRadius, MinorRadius, Slices, Stacks); 200 | 201 | Globals.ReflectionProgram = LoadProgram("Reflection.VS", 0, "Reflection.FS"); 202 | Globals.SphereVao = CreateSphere(Radius, Slices, Stacks); 203 | 204 | // Load textures 205 | Globals.CloudTexture = LoadTexture("cloud.png"); 206 | Globals.LavaTexture = LoadTexture("lavatile.png"); 207 | 208 | glClearColor(0.1, 0.1, 0.1, 0); 209 | glBlendFunc(GL_ONE, GL_ONE); 210 | } 211 | 212 | void PezUpdate(float seconds) 213 | { 214 | const float RadiansPerSecond = 0.5f; 215 | Globals.Theta += seconds * RadiansPerSecond; 216 | Globals.Time += seconds; 217 | 218 | // Create the model-view matrix: 219 | Globals.ModelMatrix = M4MakeRotationZYX((Vector3){Globals.Theta, Globals.Theta, Globals.Theta}); 220 | Point3 eye = {0, 0, -80}; 221 | Point3 target = {0, 0, 0}; 222 | Vector3 up = {0, 1, 0}; 223 | Globals.ViewMatrix = M4MakeLookAt(eye, target, up); 224 | Globals.Modelview = M4Mul(Globals.ViewMatrix, Globals.ModelMatrix); 225 | Globals.NormalMatrix = M4GetUpper3x3(Globals.Modelview); 226 | } 227 | 228 | void PezRender() 229 | { 230 | float* pModel = (float*) &Globals.ModelMatrix; 231 | float* pView = (float*) &Globals.ViewMatrix; 232 | float* pModelview = (float*) &Globals.Modelview; 233 | float* pProjection = (float*) &Globals.Projection; 234 | 235 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 236 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 237 | 238 | glEnable(GL_DEPTH_TEST); 239 | glUseProgram(Globals.LavaProgram); 240 | glBindVertexArray(Globals.TorusVao); 241 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 242 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 243 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 244 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 245 | glUniform1f(u("time"), Globals.Time * 3); 246 | glActiveTexture(GL_TEXTURE0); 247 | glBindTexture(GL_TEXTURE_2D, Globals.CloudTexture); 248 | glActiveTexture(GL_TEXTURE1); 249 | glBindTexture(GL_TEXTURE_2D, Globals.LavaTexture); 250 | glDrawElements(GL_TRIANGLES, Globals.IndexCount, GL_UNSIGNED_SHORT, 0); 251 | glActiveTexture(GL_TEXTURE0); 252 | glDisable(GL_DEPTH_TEST); 253 | } 254 | 255 | void PezHandleMouse(int x, int y, int action) 256 | { 257 | } 258 | 259 | static GLuint CurrentProgram() 260 | { 261 | GLuint p; 262 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 263 | return p; 264 | } 265 | 266 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey) 267 | { 268 | GLchar spew[256]; 269 | GLint compileSuccess; 270 | GLuint programHandle = glCreateProgram(); 271 | 272 | const char* vsSource = pezGetShader(vsKey); 273 | pezCheck(vsSource != 0, "Can't find vshader: %s\n", vsKey); 274 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 275 | glShaderSource(vsHandle, 1, &vsSource, 0); 276 | glCompileShader(vsHandle); 277 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 278 | glGetShaderInfoLog(vsHandle, sizeof(spew), 0, spew); 279 | pezCheck(compileSuccess, "Can't compile vshader:\n%s", spew); 280 | glAttachShader(programHandle, vsHandle); 281 | 282 | if (gsKey) { 283 | const char* gsSource = pezGetShader(gsKey); 284 | pezCheck(gsSource != 0, "Can't find gshader: %s\n", gsKey); 285 | GLuint gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 286 | glShaderSource(gsHandle, 1, &gsSource, 0); 287 | glCompileShader(gsHandle); 288 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 289 | glGetShaderInfoLog(gsHandle, sizeof(spew), 0, spew); 290 | pezCheck(compileSuccess, "Can't compile gshader:\n%s", spew); 291 | glAttachShader(programHandle, gsHandle); 292 | } 293 | 294 | const char* fsSource = pezGetShader(fsKey); 295 | pezCheck(fsSource != 0, "Can't find fshader: %s\n", fsKey); 296 | GLuint fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 297 | glShaderSource(fsHandle, 1, &fsSource, 0); 298 | glCompileShader(fsHandle); 299 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 300 | glGetShaderInfoLog(fsHandle, sizeof(spew), 0, spew); 301 | pezCheck(compileSuccess, "Can't compile fshader:\n%s", spew); 302 | glAttachShader(programHandle, fsHandle); 303 | 304 | glLinkProgram(programHandle); 305 | GLint linkSuccess; 306 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 307 | glGetProgramInfoLog(programHandle, sizeof(spew), 0, spew); 308 | pezCheck(linkSuccess, "Can't link shaders:\n%s", spew); 309 | glUseProgram(programHandle); 310 | return programHandle; 311 | } 312 | 313 | static GLuint LoadTexture(const char* filename) 314 | { 315 | unsigned long w, h; 316 | int color_type, bit_depth, row_stride; 317 | png_bytep image; 318 | 319 | if (true) { 320 | FILE *fp = fopen(filename, "rb"); 321 | pezCheck(fp ? 1 : 0, "Can't find %s", filename); 322 | unsigned char header[8]; 323 | fread(header, 1, 8, fp); 324 | bool isPng = !png_sig_cmp(header, 0, 8); 325 | pezCheck(isPng, "%s is not a valid PNG file.", filename); 326 | png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 327 | pezCheckPointer(png_ptr, "PNG error line %d", __LINE__); 328 | png_infop info_ptr = png_create_info_struct(png_ptr); 329 | pezCheckPointer(info_ptr, "PNG error line %d", __LINE__); 330 | png_init_io(png_ptr, fp); 331 | png_set_sig_bytes(png_ptr, 8); 332 | png_read_info(png_ptr, info_ptr); 333 | w = png_get_image_width(png_ptr, info_ptr); 334 | h = png_get_image_height(png_ptr, info_ptr); 335 | color_type = png_get_color_type(png_ptr, info_ptr); 336 | bit_depth = png_get_bit_depth(png_ptr, info_ptr); 337 | pezPrintString("%s %dx%d bpp=%d ct=%d\n", filename, w, h, bit_depth, color_type); 338 | png_read_update_info(png_ptr, info_ptr); 339 | row_stride = png_get_rowbytes(png_ptr,info_ptr); 340 | image = (png_bytep) malloc(h * row_stride); 341 | png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * h); 342 | png_bytep row = image; 343 | for (int y = h-1; y >= 0; y--, row += row_stride) { 344 | row_pointers[y] = row; 345 | } 346 | png_read_image(png_ptr, row_pointers); 347 | free(row_pointers); 348 | fclose(fp); 349 | png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 350 | } 351 | 352 | pezCheck(bit_depth == 8, "Bit depth must be 8."); 353 | 354 | GLenum type = 0; 355 | switch (color_type) { 356 | case PNG_COLOR_TYPE_RGB: type = GL_RGB; break; 357 | case PNG_COLOR_TYPE_RGBA: type = GL_RGBA; break; 358 | case PNG_COLOR_TYPE_GRAY: type = GL_RED; break; 359 | default: pezFatal("Unknown color type: %d.", color_type); 360 | } 361 | 362 | GLuint handle; 363 | glGenTextures(1, &handle); 364 | glBindTexture(GL_TEXTURE_2D, handle); 365 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 366 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 367 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 368 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 369 | glTexImage2D(GL_TEXTURE_2D, 0, type, w, h, 0, type, GL_UNSIGNED_BYTE, image); 370 | glGenerateMipmap(GL_TEXTURE_2D); 371 | pezCheck(OpenGLError); 372 | 373 | free(image); 374 | return handle; 375 | } 376 | -------------------------------------------------------------------------------- /demo-GenCubeMap.glsl: -------------------------------------------------------------------------------- 1 | 2 | -- TheGameMaker.VS 3 | 4 | in vec4 Position; 5 | in vec2 TexCoord; 6 | 7 | uniform mat4 Projection; 8 | uniform mat4 Modelview; 9 | 10 | out vec2 vTexCoord; 11 | 12 | void main() 13 | { 14 | vTexCoord = vec2( 5.0, 1.0 ) * TexCoord; 15 | gl_Position = Projection * Modelview * Position; 16 | 17 | } 18 | 19 | -- TheGameMaker.FS 20 | 21 | uniform float time; 22 | 23 | uniform float fogDensity = 0.45; 24 | uniform vec3 fogColor = vec3(0, 0, 0); 25 | 26 | layout(binding=0) uniform sampler2D cloud; 27 | layout(binding=1) uniform sampler2D lava; 28 | 29 | in vec2 vTexCoord; 30 | out vec4 FragColor; 31 | 32 | void main( void ) { 33 | 34 | vec2 position = -1.0 + 2.0 * vTexCoord; 35 | 36 | vec4 noise = texture( cloud, vTexCoord ); 37 | vec2 T1 = vTexCoord + vec2( 1.5, -1.5 ) * time * 0.02; 38 | vec2 T2 = vTexCoord + vec2( -0.5, 2.0 ) * time * 0.01; 39 | 40 | T1.x += noise.x * 2.0; 41 | T1.y += noise.y * 2.0; 42 | T2.x -= noise.y * 0.2; 43 | T2.y += noise.z * 0.2; 44 | 45 | float p = texture( cloud, T1 * 2.0 ).a; 46 | 47 | vec4 color = texture( lava, T2 * 2.0 ).bgra; 48 | vec4 temp = color * ( vec4( p, p, p, p ) * 2.0 ) + ( color * color - 0.1 ); 49 | 50 | if( temp.r > 1.0 ){ temp.bg += clamp( temp.r - 2.0, 0.0, 100.0 ); } 51 | if( temp.g > 1.0 ){ temp.rb += temp.g - 1.0; } 52 | if( temp.b > 1.0 ){ temp.rg += temp.b - 1.0; } 53 | 54 | FragColor = temp; 55 | } 56 | 57 | -- Quad.VS 58 | 59 | in vec2 Position; 60 | in vec2 TexCoord; 61 | out vec2 vTexCoord; 62 | 63 | void main() 64 | { 65 | vTexCoord = TexCoord; 66 | gl_Position = vec4(Position, 0, 1); 67 | } 68 | 69 | -- Blur.FS 70 | 71 | in vec2 vTexCoord; 72 | layout(location = 0) out vec4 FragColor; 73 | uniform sampler2D Sampler; 74 | uniform vec2 Offsets[5]; 75 | uniform float Weights[5]; 76 | 77 | void main() 78 | { 79 | FragColor = vec4(0); 80 | for (int i = 0; i < 5; i++) { 81 | float w = Weights[i]; 82 | vec2 o = Offsets[i]; 83 | FragColor += w * texture(Sampler, vTexCoord + o); 84 | } 85 | } 86 | 87 | -- Quad.FS 88 | 89 | in vec2 vTexCoord; 90 | layout(location = 0) out vec4 FragColor; 91 | uniform sampler2D Sampler; 92 | uniform float Alpha = 1.0; 93 | 94 | void main() 95 | { 96 | FragColor = texture(Sampler, vTexCoord); 97 | if (gl_FragCoord.x < 1 || gl_FragCoord.x > 1279 || gl_FragCoord.y < 1 || gl_FragCoord.y > 799) { 98 | FragColor.rgb = vec3(0.5); 99 | } 100 | FragColor.a *= Alpha; 101 | } 102 | 103 | -- Hipass.FS 104 | 105 | in vec2 vTexCoord; 106 | layout(location = 0) out vec4 FragColor; 107 | uniform sampler2D Sampler; 108 | uniform float Threshold = 1.0; 109 | const vec3 Black = vec3(0, 0, 0); 110 | 111 | void main() 112 | { 113 | vec3 c = texture(Sampler, vTexCoord).rgb; 114 | float gray = dot(c,c); 115 | FragColor = vec4(gray > Threshold ? c : Black, 1); 116 | } 117 | 118 | 119 | -- Reflection.VS 120 | 121 | in vec4 Position; 122 | in vec2 TexCoord; 123 | 124 | uniform mat4 Projection; 125 | uniform mat4 Modelview; 126 | 127 | out vec2 vTexCoord; 128 | 129 | void main() 130 | { 131 | vTexCoord = vec2( 5.0, 1.0 ) * TexCoord; 132 | gl_Position = Projection * Modelview * Position; 133 | } 134 | 135 | -- Reflection.FS 136 | 137 | out vec4 FragColor; 138 | 139 | void main() 140 | { 141 | FragColor = vec4(1); 142 | } 143 | -------------------------------------------------------------------------------- /demo-Lava.c: -------------------------------------------------------------------------------- 1 | // Lava OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include 6 | #include 7 | #include "pez.h" 8 | #include "vmath.h" 9 | 10 | typedef struct { 11 | GLuint ColorTexture; 12 | GLuint DepthBuffer; 13 | GLuint Fbo; 14 | int Width; 15 | int Height; 16 | } RenderTarget; 17 | 18 | struct GlobalsParameters { 19 | int IndexCount; 20 | float Theta; 21 | float Time; 22 | Matrix4 Projection; 23 | Matrix4 Modelview; 24 | Matrix4 ViewMatrix; 25 | Matrix4 ModelMatrix; 26 | Matrix3 NormalMatrix; 27 | GLuint LavaTexture; 28 | GLuint CloudTexture; 29 | GLuint HipassProgram; 30 | GLuint QuadProgram; 31 | GLuint LavaProgram; 32 | GLuint BlurProgram; 33 | GLuint TorusVao; 34 | GLuint QuadVao; 35 | RenderTarget Scene; 36 | RenderTarget Small[2]; 37 | } Globals; 38 | 39 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey); 40 | static GLuint CurrentProgram(); 41 | static GLuint LoadTexture(const char* filename); 42 | static GLuint CreateTorus(float major, float minor, int slices, int stacks); 43 | static RenderTarget CreateRenderTarget(int width, int height, bool depth); 44 | 45 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 46 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 47 | #define offset(x) ((const GLvoid*)x) 48 | #define OpenGLError GL_NO_ERROR == glGetError(), \ 49 | "%s:%d - OpenGL Error - %s", __FILE__, __LINE__, __FUNCTION__ \ 50 | 51 | PezConfig PezGetConfig() 52 | { 53 | PezConfig config; 54 | config.Title = __FILE__; 55 | config.Width = 1280; 56 | config.Height = 800; 57 | config.Multisampling = true; 58 | config.VerticalSync = true; 59 | return config; 60 | } 61 | 62 | static GLuint CreateTorus(float major, float minor, int slices, int stacks) 63 | { 64 | GLuint vao; 65 | glGenVertexArrays(1, &vao); 66 | glBindVertexArray(vao); 67 | 68 | int vertexCount = slices * stacks * 3; 69 | int vertexStride = sizeof(float) * 5; 70 | GLsizeiptr size = vertexCount * vertexStride; 71 | GLfloat* verts = (GLfloat*) malloc(size); 72 | 73 | GLfloat* vert = verts; 74 | for (int slice = 0; slice < slices; slice++) { 75 | float theta = slice * 2.0f * Pi / (slices - 1); 76 | for (int stack = 0; stack < stacks; stack++) { 77 | float phi = stack * 2.0f * Pi / (stacks - 1); 78 | float beta = major + minor * cos(phi); 79 | *vert++ = cos(theta) * beta; 80 | *vert++ = sin(theta) * beta; 81 | *vert++ = sin(phi) * minor; 82 | *vert++ = (float) slice / (slices-1); 83 | *vert++ = (float) stack / (stacks-1); 84 | } 85 | } 86 | 87 | GLuint handle; 88 | glGenBuffers(1, &handle); 89 | glBindBuffer(GL_ARRAY_BUFFER, handle); 90 | glBufferData(GL_ARRAY_BUFFER, size, verts, GL_STATIC_DRAW); 91 | glEnableVertexAttribArray(a("Position")); 92 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, vertexStride, 0); 93 | if (a("TexCoord") != -1) { 94 | glEnableVertexAttribArray(a("TexCoord")); 95 | glVertexAttribPointer(a("TexCoord"), 2, GL_FLOAT, GL_FALSE, vertexStride, offset(12)); 96 | } 97 | 98 | free(verts); 99 | 100 | Globals.IndexCount = (slices-1) * (stacks-1) * 6; 101 | size = Globals.IndexCount * sizeof(GLushort); 102 | GLushort* indices = (GLushort*) malloc(size); 103 | GLushort* index = indices; 104 | int v = 0; 105 | for (int i = 0; i < slices-1; i++) { 106 | for (int j = 0; j < stacks-1; j++) { 107 | int next = (j + 1) % stacks; 108 | *index++ = (v+next+stacks) % vertexCount; 109 | *index++ = (v+next) % vertexCount; 110 | *index++ = (v+j) % vertexCount; 111 | *index++ = (v+j) % vertexCount; 112 | *index++ = (v+j+stacks) % vertexCount; 113 | *index++ = (v+next+stacks) % vertexCount; 114 | } 115 | v += stacks; 116 | } 117 | glGenBuffers(1, &handle); 118 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); 119 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, indices, GL_STATIC_DRAW); 120 | 121 | free(indices); 122 | return vao; 123 | } 124 | 125 | void PezInitialize() 126 | { 127 | Globals.HipassProgram = LoadProgram("Quad.VS", 0, "Hipass.FS"); 128 | Globals.QuadProgram = LoadProgram("Quad.VS", 0, "Quad.FS"); 129 | Globals.BlurProgram = LoadProgram("Quad.VS", 0, "Blur.FS"); 130 | Globals.LavaProgram = LoadProgram("TheGameMaker.VS", 0, "TheGameMaker.FS"); 131 | 132 | PezConfig cfg = PezGetConfig(); 133 | Globals.Scene = CreateRenderTarget(cfg.Width, cfg.Height, true); 134 | int d = 6; 135 | Globals.Small[0] = CreateRenderTarget(cfg.Width/d, cfg.Height/d, false); 136 | Globals.Small[1] = CreateRenderTarget(cfg.Width/d, cfg.Height/d, false); 137 | 138 | float fovy = 170 * TwoPi / 180; 139 | float aspect = (float) cfg.Width / cfg.Height; 140 | float zNear = 65, zFar = 90; 141 | Globals.Projection = M4MakePerspective(fovy, aspect, zNear, zFar); 142 | 143 | const float MajorRadius = 8.0f, MinorRadius = 4.0f; 144 | const int Slices = 60, Stacks = 30; 145 | Globals.TorusVao = CreateTorus(MajorRadius, MinorRadius, Slices, Stacks); 146 | 147 | glGenVertexArrays(1, &Globals.QuadVao); 148 | glBindVertexArray(Globals.QuadVao); 149 | 150 | Globals.Theta = 0; 151 | 152 | // Load textures 153 | Globals.CloudTexture = LoadTexture("cloud.png"); 154 | Globals.LavaTexture = LoadTexture("lavatile.png"); 155 | 156 | glClearColor(0, 0, 0, 0); 157 | glBlendFunc(GL_ONE, GL_ONE); 158 | } 159 | 160 | void PezUpdate(float seconds) 161 | { 162 | const float RadiansPerSecond = 0.5f; 163 | Globals.Theta += seconds * RadiansPerSecond; 164 | Globals.Time += seconds; 165 | 166 | // Create the model-view matrix: 167 | Globals.ModelMatrix = M4MakeRotationZYX((Vector3){Globals.Theta, Globals.Theta, Globals.Theta}); 168 | Point3 eye = {0, 0, -80}; 169 | Point3 target = {0, 0, 0}; 170 | Vector3 up = {0, 1, 0}; 171 | Globals.ViewMatrix = M4MakeLookAt(eye, target, up); 172 | Globals.Modelview = M4Mul(Globals.ViewMatrix, Globals.ModelMatrix); 173 | Globals.NormalMatrix = M4GetUpper3x3(Globals.Modelview); 174 | } 175 | 176 | void PezRender() 177 | { 178 | PezConfig cfg = PezGetConfig(); 179 | float* pModel = (float*) &Globals.ModelMatrix; 180 | float* pView = (float*) &Globals.ViewMatrix; 181 | float* pModelview = (float*) &Globals.Modelview; 182 | float* pProjection = (float*) &Globals.Projection; 183 | int w = Globals.Small[0].Width; 184 | int h = Globals.Small[0].Height; 185 | const float hoffsets[10] = { 186 | -2.0f / w, 0, 187 | -1.0f / w, 0, 188 | 0, 0, 189 | +1.0f / w, 0, 190 | +2.0f / w, 0, 191 | }; 192 | const float voffsets[10] = { 193 | 0, -2.0f / h, 194 | 0, -1.0f / h, 195 | 0, 0, 196 | 0, +1.0f / h, 197 | 0, +2.0f / h, 198 | }; 199 | const float weights[5] = { 200 | 1.0f / 16.0f, 201 | 4.0f / 16.0f, 202 | 6.0f / 16.0f, 203 | 4.0f / 16.0f, 204 | 1.0f / 16.0f, 205 | }; 206 | 207 | glBindFramebuffer(GL_FRAMEBUFFER, Globals.Scene.Fbo); 208 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 209 | 210 | glEnable(GL_DEPTH_TEST); 211 | glUseProgram(Globals.LavaProgram); 212 | glBindVertexArray(Globals.TorusVao); 213 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 214 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 215 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 216 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 217 | glUniform1f(u("time"), Globals.Time * 3); 218 | glActiveTexture(GL_TEXTURE0); 219 | glBindTexture(GL_TEXTURE_2D, Globals.CloudTexture); 220 | glActiveTexture(GL_TEXTURE1); 221 | glBindTexture(GL_TEXTURE_2D, Globals.LavaTexture); 222 | glDrawElements(GL_TRIANGLES, Globals.IndexCount, GL_UNSIGNED_SHORT, 0); 223 | glActiveTexture(GL_TEXTURE0); 224 | glDisable(GL_DEPTH_TEST); 225 | 226 | // Downsample 227 | glBindFramebuffer(GL_FRAMEBUFFER, Globals.Small[0].Fbo); 228 | glViewport(0, 0, w, h); 229 | glUseProgram(Globals.HipassProgram); 230 | glBindTexture(GL_TEXTURE_2D, Globals.Scene.ColorTexture); 231 | glBindVertexArray(Globals.QuadVao); 232 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 233 | glBindTexture(GL_TEXTURE_2D, 0); 234 | 235 | // Horizontal Pass 236 | glBindFramebuffer(GL_FRAMEBUFFER, Globals.Small[1].Fbo); 237 | glUseProgram(Globals.BlurProgram); 238 | glUniform2fv(u("Offsets"), 5, hoffsets); 239 | glUniform1fv(u("Weights"), 5, weights); 240 | glBindTexture(GL_TEXTURE_2D, Globals.Small[0].ColorTexture); 241 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 242 | glBindTexture(GL_TEXTURE_2D, 0); 243 | 244 | // Vertical Pass 245 | glBindFramebuffer(GL_FRAMEBUFFER, Globals.Small[0].Fbo); 246 | glUniform2fv(u("Offsets"), 5, voffsets); 247 | glBindTexture(GL_TEXTURE_2D, Globals.Small[1].ColorTexture); 248 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 249 | glBindTexture(GL_TEXTURE_2D, 0); 250 | 251 | // Blit full-res unprocessed scene to screen: 252 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 253 | glViewport(0, 0, cfg.Width, cfg.Height); 254 | glUseProgram(Globals.QuadProgram); 255 | glUniform1f(u("Alpha"), 1.0); 256 | glBindTexture(GL_TEXTURE_2D, Globals.Scene.ColorTexture); 257 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 258 | glBindTexture(GL_TEXTURE_2D, 0); 259 | 260 | // Additive blending with the blurred image: 261 | glEnable(GL_BLEND); 262 | glBindTexture(GL_TEXTURE_2D, Globals.Small[0].ColorTexture); 263 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 264 | glBindTexture(GL_TEXTURE_2D, 0); 265 | glDisable(GL_BLEND); 266 | } 267 | 268 | void PezHandleMouse(int x, int y, int action) 269 | { 270 | } 271 | 272 | static GLuint CurrentProgram() 273 | { 274 | GLuint p; 275 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 276 | return p; 277 | } 278 | 279 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey) 280 | { 281 | GLchar spew[256]; 282 | GLint compileSuccess; 283 | GLuint programHandle = glCreateProgram(); 284 | 285 | const char* vsSource = pezGetShader(vsKey); 286 | pezCheck(vsSource != 0, "Can't find vshader: %s\n", vsKey); 287 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 288 | glShaderSource(vsHandle, 1, &vsSource, 0); 289 | glCompileShader(vsHandle); 290 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 291 | glGetShaderInfoLog(vsHandle, sizeof(spew), 0, spew); 292 | pezCheck(compileSuccess, "Can't compile vshader:\n%s", spew); 293 | glAttachShader(programHandle, vsHandle); 294 | 295 | if (gsKey) { 296 | const char* gsSource = pezGetShader(gsKey); 297 | pezCheck(gsSource != 0, "Can't find gshader: %s\n", gsKey); 298 | GLuint gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 299 | glShaderSource(gsHandle, 1, &gsSource, 0); 300 | glCompileShader(gsHandle); 301 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 302 | glGetShaderInfoLog(gsHandle, sizeof(spew), 0, spew); 303 | pezCheck(compileSuccess, "Can't compile gshader:\n%s", spew); 304 | glAttachShader(programHandle, gsHandle); 305 | } 306 | 307 | const char* fsSource = pezGetShader(fsKey); 308 | pezCheck(fsSource != 0, "Can't find fshader: %s\n", fsKey); 309 | GLuint fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 310 | glShaderSource(fsHandle, 1, &fsSource, 0); 311 | glCompileShader(fsHandle); 312 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 313 | glGetShaderInfoLog(fsHandle, sizeof(spew), 0, spew); 314 | pezCheck(compileSuccess, "Can't compile fshader:\n%s", spew); 315 | glAttachShader(programHandle, fsHandle); 316 | 317 | glLinkProgram(programHandle); 318 | GLint linkSuccess; 319 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 320 | glGetProgramInfoLog(programHandle, sizeof(spew), 0, spew); 321 | pezCheck(linkSuccess, "Can't link shaders:\n%s", spew); 322 | glUseProgram(programHandle); 323 | return programHandle; 324 | } 325 | 326 | static GLuint LoadTexture(const char* filename) 327 | { 328 | unsigned long w, h; 329 | int color_type, bit_depth, row_stride; 330 | png_bytep image; 331 | 332 | if (true) { 333 | FILE *fp = fopen(filename, "rb"); 334 | pezCheck(fp ? 1 : 0, "Can't find %s", filename); 335 | unsigned char header[8]; 336 | fread(header, 1, 8, fp); 337 | bool isPng = !png_sig_cmp(header, 0, 8); 338 | pezCheck(isPng, "%s is not a valid PNG file.", filename); 339 | png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 340 | pezCheckPointer(png_ptr, "PNG error line %d", __LINE__); 341 | png_infop info_ptr = png_create_info_struct(png_ptr); 342 | pezCheckPointer(info_ptr, "PNG error line %d", __LINE__); 343 | png_init_io(png_ptr, fp); 344 | png_set_sig_bytes(png_ptr, 8); 345 | png_read_info(png_ptr, info_ptr); 346 | w = png_get_image_width(png_ptr, info_ptr); 347 | h = png_get_image_height(png_ptr, info_ptr); 348 | color_type = png_get_color_type(png_ptr, info_ptr); 349 | bit_depth = png_get_bit_depth(png_ptr, info_ptr); 350 | pezPrintString("%s %dx%d bpp=%d ct=%d\n", filename, w, h, bit_depth, color_type); 351 | png_read_update_info(png_ptr, info_ptr); 352 | row_stride = png_get_rowbytes(png_ptr,info_ptr); 353 | image = (png_bytep) malloc(h * row_stride); 354 | png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * h); 355 | png_bytep row = image; 356 | for (int y = h-1; y >= 0; y--, row += row_stride) { 357 | row_pointers[y] = row; 358 | } 359 | png_read_image(png_ptr, row_pointers); 360 | free(row_pointers); 361 | fclose(fp); 362 | png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 363 | } 364 | 365 | pezCheck(bit_depth == 8, "Bit depth must be 8."); 366 | 367 | GLenum type = 0; 368 | switch (color_type) { 369 | case PNG_COLOR_TYPE_RGB: type = GL_RGB; break; 370 | case PNG_COLOR_TYPE_RGBA: type = GL_RGBA; break; 371 | case PNG_COLOR_TYPE_GRAY: type = GL_RED; break; 372 | default: pezFatal("Unknown color type: %d.", color_type); 373 | } 374 | 375 | GLuint handle; 376 | glGenTextures(1, &handle); 377 | glBindTexture(GL_TEXTURE_2D, handle); 378 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 379 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 380 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 381 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 382 | glTexImage2D(GL_TEXTURE_2D, 0, type, w, h, 0, type, GL_UNSIGNED_BYTE, image); 383 | glGenerateMipmap(GL_TEXTURE_2D); 384 | pezCheck(OpenGLError); 385 | 386 | free(image); 387 | return handle; 388 | } 389 | 390 | static RenderTarget CreateRenderTarget(int width, int height, bool depth) 391 | { 392 | pezCheck(GL_NO_ERROR == glGetError(), "OpenGL error on line %d", __LINE__); 393 | 394 | RenderTarget rt; 395 | rt.Width = width; 396 | rt.Height = height; 397 | 398 | glGenTextures(1, &rt.ColorTexture); 399 | glBindTexture(GL_TEXTURE_2D, rt.ColorTexture); 400 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 401 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 402 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 403 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 404 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 405 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to create color texture."); 406 | 407 | glGenFramebuffers(1, &rt.Fbo); 408 | glBindFramebuffer(GL_FRAMEBUFFER, rt.Fbo); 409 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt.ColorTexture, 0); 410 | 411 | if (depth) { 412 | glGenRenderbuffers(1, &rt.DepthBuffer); 413 | glBindRenderbuffer(GL_RENDERBUFFER, rt.DepthBuffer); 414 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); 415 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt.DepthBuffer); 416 | } else { 417 | rt.DepthBuffer = 0; 418 | } 419 | 420 | pezCheck(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER), "Invalid FBO."); 421 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 422 | return rt; 423 | } 424 | -------------------------------------------------------------------------------- /demo-Lava.glsl: -------------------------------------------------------------------------------- 1 | 2 | -- TheGameMaker.VS 3 | 4 | in vec4 Position; 5 | in vec2 TexCoord; 6 | 7 | uniform mat4 Projection; 8 | uniform mat4 Modelview; 9 | 10 | out vec2 vTexCoord; 11 | 12 | void main() 13 | { 14 | vTexCoord = vec2( 3.0, 1.0 ) * TexCoord; 15 | gl_Position = Projection * Modelview * Position; 16 | 17 | } 18 | 19 | -- TheGameMaker.FS 20 | 21 | uniform float time; 22 | 23 | uniform float fogDensity = 0.45; 24 | uniform vec3 fogColor = vec3(0, 0, 0); 25 | 26 | layout(binding=0) uniform sampler2D cloud; 27 | layout(binding=1) uniform sampler2D lava; 28 | 29 | in vec2 vTexCoord; 30 | out vec4 FragColor; 31 | 32 | void main( void ) { 33 | 34 | vec2 position = -1.0 + 2.0 * vTexCoord; 35 | 36 | vec4 noise = texture( cloud, vTexCoord ); 37 | vec2 T1 = vTexCoord + vec2( 1.5, -1.5 ) * time * 0.02; 38 | vec2 T2 = vTexCoord + vec2( -0.5, 2.0 ) * time * 0.01; 39 | 40 | T1.x += noise.x * 2.0; 41 | T1.y += noise.y * 2.0; 42 | T2.x -= noise.y * 0.2; 43 | T2.y += noise.z * 0.2; 44 | 45 | float p = texture( cloud, T1 * 2.0 ).a; 46 | 47 | vec4 color = texture( lava, T2 * 2.0 ); 48 | vec4 temp = color * ( vec4( p, p, p, p ) * 2.0 ) + ( color * color - 0.1 ); 49 | 50 | if( temp.r > 1.0 ){ temp.bg += clamp( temp.r - 2.0, 0.0, 100.0 ); } 51 | if( temp.g > 1.0 ){ temp.rb += temp.g - 1.0; } 52 | if( temp.b > 1.0 ){ temp.rg += temp.b - 1.0; } 53 | 54 | FragColor = temp; 55 | 56 | float depth = gl_FragCoord.z * 4; // TODO some sort of auto-normalization? 57 | const float LOG2 = 1.442695; 58 | float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 ); 59 | fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 ); 60 | 61 | FragColor = mix( FragColor, vec4( fogColor, temp.a ), fogFactor ); 62 | } 63 | 64 | -- Quad.VS 65 | 66 | out vec2 vTexCoord; 67 | 68 | void main() 69 | { 70 | int i = gl_VertexID; 71 | vTexCoord = vec2(i%2,i/2); 72 | gl_Position = vec4(2*vTexCoord-1,0,1); 73 | } 74 | 75 | -- Blur.FS 76 | 77 | in vec2 vTexCoord; 78 | layout(location = 0) out vec4 FragColor; 79 | uniform sampler2D Sampler; 80 | uniform vec2 Offsets[5]; 81 | uniform float Weights[5]; 82 | 83 | void main() 84 | { 85 | FragColor = vec4(0); 86 | for (int i = 0; i < 5; i++) { 87 | float w = Weights[i]; 88 | vec2 o = Offsets[i]; 89 | FragColor += w * texture(Sampler, vTexCoord + o); 90 | } 91 | } 92 | 93 | -- Quad.FS 94 | 95 | in vec2 vTexCoord; 96 | layout(location = 0) out vec4 FragColor; 97 | uniform sampler2D Sampler; 98 | uniform float Alpha = 1.0; 99 | 100 | void main() 101 | { 102 | FragColor = texture(Sampler, vTexCoord); 103 | if (gl_FragCoord.x < 1 || gl_FragCoord.x > 1279 || gl_FragCoord.y < 1 || gl_FragCoord.y > 799) { 104 | FragColor.rgb = vec3(0.5); 105 | } 106 | FragColor.a *= Alpha; 107 | } 108 | 109 | -- Hipass.FS 110 | 111 | in vec2 vTexCoord; 112 | layout(location = 0) out vec4 FragColor; 113 | uniform sampler2D Sampler; 114 | uniform float Threshold = 1.0; 115 | const vec3 Black = vec3(0, 0, 0); 116 | 117 | void main() 118 | { 119 | vec3 c = texture(Sampler, vTexCoord).rgb; 120 | float gray = dot(c,c); 121 | FragColor = vec4(gray > Threshold ? c : Black, 1); 122 | } 123 | -------------------------------------------------------------------------------- /demo-Raycast.c: -------------------------------------------------------------------------------- 1 | // Raycast OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include "pez.h" 6 | #include "vmath.h" 7 | 8 | static const Point3 EyePosition = {0, 0, 2}; 9 | static Point3 LightPosition = {1, 1, 2}; 10 | static const float FieldOfView = 0.7f; 11 | static const int GridSize = 96; 12 | static const int ViewSamples = 96 * 2; 13 | 14 | PezConfig PezGetConfig() 15 | { 16 | PezConfig config; 17 | config.Title = __FILE__; 18 | config.Width = 853; 19 | config.Height = 480; 20 | config.Multisampling = false; 21 | config.VerticalSync = false; 22 | return config; 23 | } 24 | 25 | typedef struct VolumeRec { 26 | GLuint FboHandle; 27 | GLuint TextureHandle; 28 | GLsizei Width; 29 | GLsizei Height; 30 | GLsizei Depth; 31 | } Volume; 32 | 33 | struct VolumesRec { 34 | Volume Density; 35 | Volume LightCache; 36 | } Volumes; 37 | 38 | struct MatricesRec { 39 | Matrix4 Projection; 40 | Matrix4 Modelview; 41 | Matrix4 ModelviewProjection; 42 | } Matrices; 43 | 44 | struct VbosRec { 45 | GLuint CubeCenter; 46 | GLuint FullscreenQuad; 47 | } Vbos; 48 | 49 | struct ProgramsRec { 50 | GLuint Raycast; 51 | } Programs; 52 | 53 | static GLuint LoadProgram(char* vs, char* gs, char* fs); 54 | static Volume CreateVolume(GLsizei w, GLsizei h, GLsizei d, int numComponents); 55 | static GLuint CurrentProgram(); 56 | 57 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 58 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 59 | 60 | void PezInitialize() 61 | { 62 | PezGetConfig(); 63 | 64 | Programs.Raycast = LoadProgram("VS", "GS", "FS"); 65 | 66 | GLuint vao; 67 | glGenVertexArrays(1, &vao); 68 | glBindVertexArray(vao); 69 | 70 | float p[] = {0, 0, 0}; 71 | glGenBuffers(1, &Vbos.CubeCenter); 72 | glBindBuffer(GL_ARRAY_BUFFER, Vbos.CubeCenter); 73 | glBufferData(GL_ARRAY_BUFFER, sizeof(p), &p[0], GL_STATIC_DRAW); 74 | 75 | short q[] = { -1, -1, 1, -1, -1, 1, 1, 1 }; 76 | glGenBuffers(1, &Vbos.FullscreenQuad); 77 | glBindBuffer(GL_ARRAY_BUFFER, Vbos.FullscreenQuad); 78 | glBufferData(GL_ARRAY_BUFFER, sizeof(q), q, GL_STATIC_DRAW); 79 | 80 | Volumes.Density = CreateVolume(GridSize, GridSize, GridSize, 1); 81 | Volumes.LightCache = CreateVolume(GridSize, GridSize, GridSize, 1); 82 | 83 | PezPixels pixels = pezLoadPixels("Smoke96.pbo"); 84 | glBindTexture(GL_TEXTURE_3D, Volumes.Density.TextureHandle); 85 | glTexImage3D(GL_TEXTURE_3D, 0, pixels.InternalFormat, 86 | pixels.Width, pixels.Height, pixels.Depth, 87 | 0, pixels.Format, pixels.Type, pixels.Frames); 88 | pezFreePixels(pixels); 89 | 90 | glDisable(GL_DEPTH_TEST); 91 | glEnable(GL_CULL_FACE); 92 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 93 | 94 | glEnableVertexAttribArray(0); 95 | } 96 | 97 | void PezRender() 98 | { 99 | PezConfig cfg = PezGetConfig(); 100 | Vector3 rayOrigin = V4GetXYZ(M4MulP3(M4Transpose(Matrices.Modelview), EyePosition)); 101 | GLfloat* mvp = &Matrices.ModelviewProjection.col0.x; 102 | GLfloat* mv = &Matrices.Modelview.col0.x; 103 | GLfloat* proj = &Matrices.Projection.col0.x; 104 | 105 | // Perform raycasting: 106 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 107 | glViewport(0, 0, cfg.Width, cfg.Height); 108 | glClearColor(0, 0, 0, 0); 109 | glClear(GL_COLOR_BUFFER_BIT); 110 | glEnable(GL_BLEND); 111 | glBindBuffer(GL_ARRAY_BUFFER, Vbos.CubeCenter); 112 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0); 113 | glActiveTexture(GL_TEXTURE0); 114 | glBindTexture(GL_TEXTURE_3D, Volumes.Density.TextureHandle); 115 | glActiveTexture(GL_TEXTURE1); 116 | glBindTexture(GL_TEXTURE_3D, Volumes.LightCache.TextureHandle); 117 | glUseProgram(Programs.Raycast); 118 | glUniformMatrix4fv(u("ModelviewProjection"), 1, 0, mvp); 119 | glUniformMatrix4fv(u("Modelview"), 1, 0, mv); 120 | glUniformMatrix4fv(u("ProjectionMatrix"), 1, 0, proj); 121 | glUniform1i(u("ViewSamples"), ViewSamples); 122 | glUniform3fv(u("EyePosition"), 1, &EyePosition.x); 123 | glUniform3fv(u("LightPosition"), 1, &LightPosition.x); 124 | glUniform1i(u("Density"), 0); 125 | glUniform3fv(u("RayOrigin"), 1, &rayOrigin.x); 126 | glUniform1f(u("FocalLength"), 1.0f / tanf(FieldOfView / 2)); 127 | glUniform2f(u("WindowSize"), (float) cfg.Width, (float) cfg.Height); 128 | glUniform1f(u("StepSize"), sqrtf(3.0f) / ViewSamples); // should be sqrt(2) 129 | glDrawArrays(GL_POINTS, 0, 1); 130 | glActiveTexture(GL_TEXTURE1); 131 | glBindTexture(GL_TEXTURE_3D, 0); 132 | glActiveTexture(GL_TEXTURE0); 133 | } 134 | 135 | void PezUpdate(float dt) 136 | { 137 | static float theta = 0; 138 | theta += dt / 2.0f; 139 | 140 | Vector3 up = {1, 0, 0}; Point3 target = {0, 0, 0}; 141 | Matrix4 view = M4MakeLookAt(EyePosition, target, up); 142 | Matrix4 spin = M4MakeRotationX(sin(theta) * Pi / 2); 143 | Matrix4 model = M4Mul(spin, M4MakeRotationY(0.75)); 144 | Matrices.Modelview = M4Mul(view, model); 145 | 146 | Point3 p = {1, 1, 2}; 147 | LightPosition = T3MulP3(T3MakeRotationY(theta / 2), p); 148 | 149 | PezConfig cfg = PezGetConfig(); 150 | float aspectRatio = (float) cfg.Width / cfg.Height; 151 | Matrices.Projection = M4MakePerspective( 152 | FieldOfView, aspectRatio, 153 | 0.0f, 1.0f); 154 | 155 | Matrices.ModelviewProjection = M4Mul(Matrices.Projection, Matrices.Modelview); 156 | } 157 | 158 | void PezHandleMouse(int x, int y, int action) 159 | { 160 | } 161 | 162 | static GLuint LoadProgram(char* vsKey, char* gsKey, char* fsKey) 163 | { 164 | const char* vsSource = pezGetShader(vsKey); 165 | const char* gsSource = pezGetShader(gsKey); 166 | const char* fsSource = pezGetShader(fsKey); 167 | 168 | const char* msg = "Can't find %s shader: '%s'.\n"; 169 | pezCheck(vsSource != 0, msg, "vertex", vsKey); 170 | pezCheck(gsKey == 0 || gsSource != 0, msg, "geometry", gsKey); 171 | pezCheck(fsKey == 0 || fsSource != 0, msg, "fragment", fsKey); 172 | 173 | GLint compileSuccess; 174 | GLchar compilerSpew[256]; 175 | GLuint programHandle = glCreateProgram(); 176 | 177 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 178 | glShaderSource(vsHandle, 1, &vsSource, 0); 179 | glCompileShader(vsHandle); 180 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 181 | glGetShaderInfoLog(vsHandle, sizeof(compilerSpew), 0, compilerSpew); 182 | pezCheck(compileSuccess, "Can't compile %s:\n%s", vsKey, compilerSpew); 183 | glAttachShader(programHandle, vsHandle); 184 | 185 | GLuint gsHandle; 186 | if (gsKey) { 187 | gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 188 | glShaderSource(gsHandle, 1, &gsSource, 0); 189 | glCompileShader(gsHandle); 190 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 191 | glGetShaderInfoLog(gsHandle, sizeof(compilerSpew), 0, compilerSpew); 192 | pezCheck(compileSuccess, "Can't compile %s:\n%s", gsKey, compilerSpew); 193 | glAttachShader(programHandle, gsHandle); 194 | } 195 | 196 | GLuint fsHandle; 197 | if (fsKey) { 198 | fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 199 | glShaderSource(fsHandle, 1, &fsSource, 0); 200 | glCompileShader(fsHandle); 201 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 202 | glGetShaderInfoLog(fsHandle, sizeof(compilerSpew), 0, compilerSpew); 203 | pezCheck(compileSuccess, "Can't compile %s:\n%s", fsKey, compilerSpew); 204 | glAttachShader(programHandle, fsHandle); 205 | } 206 | 207 | glLinkProgram(programHandle); 208 | 209 | GLint linkSuccess; 210 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 211 | glGetProgramInfoLog(programHandle, sizeof(compilerSpew), 0, compilerSpew); 212 | 213 | if (!linkSuccess) { 214 | pezPrintString("Link error.\n"); 215 | if (vsKey) pezPrintString("Vertex Shader: %s\n", vsKey); 216 | if (gsKey) pezPrintString("Geometry Shader: %s\n", gsKey); 217 | if (fsKey) pezPrintString("Fragment Shader: %s\n", fsKey); 218 | pezPrintString("%s\n", compilerSpew); 219 | } 220 | 221 | return programHandle; 222 | } 223 | 224 | static Volume CreateVolume(GLsizei w, GLsizei h, GLsizei d, int numComponents) 225 | { 226 | GLuint fboHandle; 227 | glGenFramebuffers(1, &fboHandle); 228 | glBindFramebuffer(GL_FRAMEBUFFER, fboHandle); 229 | 230 | GLuint textureHandle; 231 | glGenTextures(1, &textureHandle); 232 | glBindTexture(GL_TEXTURE_3D, textureHandle); 233 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 234 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 235 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 236 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 237 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 238 | 239 | GLenum internalFmt, fmt; 240 | switch (numComponents) { 241 | case 1: internalFmt = GL_R16F; fmt = GL_RED; break; 242 | case 2: internalFmt = GL_RG16F; fmt = GL_RG; break; 243 | case 3: internalFmt = GL_RGB16F; fmt = GL_RGB; break; 244 | case 4: internalFmt = GL_RGBA16F; fmt = GL_RGBA; break; 245 | default: internalFmt = fmt = 0; pezFatal("%d components", numComponents); 246 | } 247 | 248 | GLenum type = GL_HALF_FLOAT; 249 | glTexImage3D(GL_TEXTURE_3D, 0, internalFmt, w, h, d, 0, fmt, type, 0); 250 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to create volume texture"); 251 | 252 | GLuint colorbuffer; 253 | glGenRenderbuffers(1, &colorbuffer); 254 | glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer); 255 | glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureHandle, 0); 256 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to attach color buffer"); 257 | 258 | GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); 259 | pezCheck(GL_FRAMEBUFFER_COMPLETE == fboStatus, "Unable to create FBO."); 260 | 261 | glClearColor(0, 0, 0, 0); 262 | glClear(GL_COLOR_BUFFER_BIT); 263 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 264 | 265 | Volume volume = { fboHandle, textureHandle, w, h, d }; 266 | return volume; 267 | } 268 | 269 | static GLuint CurrentProgram() 270 | { 271 | GLuint p; 272 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 273 | return p; 274 | } 275 | -------------------------------------------------------------------------------- /demo-Raycast.glsl: -------------------------------------------------------------------------------- 1 | -- VS 2 | 3 | in vec4 Position; 4 | out vec4 vPosition; 5 | uniform mat4 ModelviewProjection; 6 | 7 | void main() 8 | { 9 | gl_Position = ModelviewProjection * Position; 10 | vPosition = Position; 11 | } 12 | 13 | -- GS 14 | 15 | layout(points) in; 16 | layout(triangle_strip, max_vertices = 24) out; 17 | 18 | in vec4 vPosition[1]; 19 | 20 | uniform mat4 ModelviewProjection; 21 | uniform mat4 ProjectionMatrix; 22 | uniform mat4 ViewMatrix; 23 | uniform mat4 Modelview; 24 | 25 | vec4 objCube[8]; // Object space coordinate of cube corner 26 | vec4 ndcCube[8]; // Normalized device coordinate of cube corner 27 | ivec4 faces[6]; // Vertex indices of the cube faces 28 | 29 | void emit_vert(int vert) 30 | { 31 | gl_Position = ndcCube[vert]; 32 | EmitVertex(); 33 | } 34 | 35 | void emit_face(int face) 36 | { 37 | emit_vert(faces[face][1]); emit_vert(faces[face][0]); 38 | emit_vert(faces[face][3]); emit_vert(faces[face][2]); 39 | EndPrimitive(); 40 | } 41 | 42 | void main() 43 | { 44 | faces[0] = ivec4(0,1,3,2); faces[1] = ivec4(5,4,6,7); 45 | faces[2] = ivec4(4,5,0,1); faces[3] = ivec4(3,2,7,6); 46 | faces[4] = ivec4(0,3,4,7); faces[5] = ivec4(2,1,6,5); 47 | 48 | vec4 P = vPosition[0]; 49 | vec4 I = vec4(1,0,0,0); 50 | vec4 J = vec4(0,1,0,0); 51 | vec4 K = vec4(0,0,1,0); 52 | 53 | objCube[0] = P+K+I+J; objCube[1] = P+K+I-J; 54 | objCube[2] = P+K-I-J; objCube[3] = P+K-I+J; 55 | objCube[4] = P-K+I+J; objCube[5] = P-K+I-J; 56 | objCube[6] = P-K-I-J; objCube[7] = P-K-I+J; 57 | 58 | // Transform the corners of the box: 59 | for (int vert = 0; vert < 8; vert++) 60 | ndcCube[vert] = ModelviewProjection * objCube[vert]; 61 | 62 | // Emit the six faces: 63 | for (int face = 0; face < 6; face++) 64 | emit_face(face); 65 | } 66 | 67 | -- FS 68 | 69 | out vec4 FragColor; 70 | 71 | uniform sampler3D Density; 72 | 73 | uniform vec3 LightPosition = vec3(1.0, 1.0, 2.0); 74 | uniform vec3 LightIntensity = vec3(10.0); 75 | uniform float Absorption = 10.0; 76 | uniform mat4 Modelview; 77 | uniform float FocalLength; 78 | uniform vec2 WindowSize; 79 | uniform vec3 RayOrigin; 80 | uniform vec3 Ambient = vec3(0.15, 0.15, 0.20); 81 | uniform float StepSize; 82 | uniform int ViewSamples; 83 | 84 | const bool Jitter = false; 85 | 86 | float GetDensity(vec3 pos) 87 | { 88 | return 2.0 * texture(Density, pos).x; 89 | } 90 | 91 | struct Ray { 92 | vec3 Origin; 93 | vec3 Dir; 94 | }; 95 | 96 | struct AABB { 97 | vec3 Min; 98 | vec3 Max; 99 | }; 100 | 101 | bool IntersectBox(Ray r, AABB aabb, out float t0, out float t1) 102 | { 103 | vec3 invR = 1.0 / r.Dir; 104 | vec3 tbot = invR * (aabb.Min-r.Origin); 105 | vec3 ttop = invR * (aabb.Max-r.Origin); 106 | vec3 tmin = min(ttop, tbot); 107 | vec3 tmax = max(ttop, tbot); 108 | vec2 t = max(tmin.xx, tmin.yz); 109 | t0 = max(t.x, t.y); 110 | t = min(tmax.xx, tmax.yz); 111 | t1 = min(t.x, t.y); 112 | return t0 <= t1; 113 | } 114 | 115 | float randhash(uint seed, float b) 116 | { 117 | const float InverseMaxInt = 1.0 / 4294967295.0; 118 | uint i=(seed^12345391u)*2654435769u; 119 | i^=(i<<6u)^(i>>26u); 120 | i*=2654435769u; 121 | i+=(i<<5u)^(i>>12u); 122 | return float(b * i) * InverseMaxInt; 123 | } 124 | 125 | void main() 126 | { 127 | vec3 rayDirection; 128 | rayDirection.xy = 2.0 * gl_FragCoord.xy / WindowSize - 1.0; 129 | rayDirection.x /= WindowSize.y / WindowSize.x; 130 | rayDirection.z = -FocalLength; 131 | rayDirection = (vec4(rayDirection, 0) * Modelview).xyz; 132 | 133 | Ray eye = Ray( RayOrigin, normalize(rayDirection) ); 134 | AABB aabb = AABB(vec3(-1), vec3(1)); 135 | 136 | float tnear, tfar; 137 | IntersectBox(eye, aabb, tnear, tfar); 138 | if (tnear < 0.0) tnear = 0.0; 139 | 140 | vec3 rayStart = eye.Origin + eye.Dir * tnear; 141 | vec3 rayStop = eye.Origin + eye.Dir * tfar; 142 | rayStart = 0.5 * (rayStart + 1.0); 143 | rayStop = 0.5 * (rayStop + 1.0); 144 | 145 | vec3 pos = rayStart; 146 | vec3 viewDir = normalize(rayStop-rayStart) * StepSize; 147 | float T = 1.0; 148 | vec3 Lo = Ambient; 149 | 150 | if (Jitter) { 151 | uint seed = uint(gl_FragCoord.x) * uint(gl_FragCoord.y); 152 | pos += viewDir * (-0.5 + randhash(seed, 1.0)); 153 | } 154 | 155 | float remainingLength = distance(rayStop, rayStart); 156 | 157 | for (int i=0; i < ViewSamples && remainingLength > 0.0; 158 | ++i, pos += viewDir, remainingLength -= StepSize) { 159 | 160 | float density = GetDensity(pos); 161 | vec3 lightColor = vec3(1); 162 | if (pos.z < 0.1) { 163 | density = 10; 164 | lightColor = 3*Ambient; 165 | } else if (density <= 0.01) { 166 | continue; 167 | } 168 | 169 | T *= 1.0 - density * StepSize * Absorption; 170 | if (T <= 0.01) 171 | break; 172 | 173 | vec3 Li = lightColor * LightIntensity; 174 | Lo += Li * T * density * StepSize; 175 | } 176 | 177 | //Lo = 1-Lo; 178 | 179 | FragColor.rgb = Lo; 180 | FragColor.a = 1-T; 181 | } 182 | -------------------------------------------------------------------------------- /demo-SimpleText.c: -------------------------------------------------------------------------------- 1 | // Simple Text OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include 6 | #include 7 | #include 8 | #include "pez.h" 9 | #include "vmath.h" 10 | #include "lodepng.h" 11 | 12 | typedef struct { 13 | int VertexCount; 14 | int IndexCount; 15 | GLuint Vao; 16 | } MeshPod; 17 | 18 | typedef struct { 19 | Matrix4 Projection; 20 | Matrix4 Modelview; 21 | Matrix4 View; 22 | Matrix4 Model; 23 | Matrix3 Normal; 24 | GLfloat PackedNormal[9]; 25 | } TransformsPod; 26 | 27 | struct { 28 | float Theta; 29 | GLuint LitProgram; 30 | GLuint TextProgram; 31 | MeshPod TrefoilKnot; 32 | TransformsPod Transforms; 33 | GLuint FontMap; 34 | } Globals; 35 | 36 | typedef struct { 37 | Vector3 Position; 38 | Vector3 Normal; 39 | } Vertex; 40 | 41 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey); 42 | static GLuint CurrentProgram(); 43 | static MeshPod CreateTrefoil(); 44 | static GLuint LoadTexture(const char* filename); 45 | 46 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 47 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 48 | #define offset(x) ((const GLvoid*)x) 49 | #define OpenGLError GL_NO_ERROR == glGetError(), "%s:%d - OpenGL Error - %s", __FILE__, __LINE__, __FUNCTION__ 50 | 51 | PezConfig PezGetConfig() 52 | { 53 | PezConfig config; 54 | config.Title = __FILE__; 55 | config.Width = 1280/2; 56 | config.Height = 720/2; 57 | config.Multisampling = true; 58 | config.VerticalSync = true; 59 | return config; 60 | } 61 | 62 | void PezInitialize() 63 | { 64 | const PezConfig cfg = PezGetConfig(); 65 | 66 | // Compile shaders 67 | Globals.LitProgram = LoadProgram("Lit.VS", 0, "Lit.FS"); 68 | Globals.TextProgram = LoadProgram("Text.VS", "Text.GS", "Text.Smooth.FS"); 69 | 70 | // Set up viewport 71 | float fovy = 16 * TwoPi / 180; 72 | float aspect = (float) cfg.Width / cfg.Height; 73 | float zNear = 0.1, zFar = 300; 74 | Globals.Transforms.Projection = M4MakePerspective(fovy, aspect, zNear, zFar); 75 | 76 | // Create geometry 77 | glUseProgram(Globals.LitProgram); 78 | Globals.TrefoilKnot = CreateTrefoil(); 79 | 80 | // Load textures 81 | Globals.FontMap = LoadTexture("verasansmono.png"); 82 | 83 | // Load various constants 84 | glUseProgram(Globals.TextProgram); 85 | glUniform3f(u("TextColor"), 1, 1, 1); 86 | glUniform2f(u("CellSize"), 1.0f / 16, (300.0f / 384) / 6); 87 | glUniform2f(u("CellOffset"), 0.5 / 256.0, 0.5 / 256.0); 88 | glUniform2f(u("RenderSize"), 0.75 * 16 / cfg.Width, 0.75 * 33.33 / cfg.Height); 89 | glUniform2f(u("RenderOrigin"), -0.96, 0.9); 90 | 91 | // Misc Initialization 92 | Globals.Theta = 0; 93 | glClearColor(0.184, 0.310, 0.310, 1); 94 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 95 | pezCheck(OpenGLError); 96 | } 97 | 98 | void PezUpdate(float seconds) 99 | { 100 | const float RadiansPerSecond = 1.0f; 101 | Globals.Theta = fmod(Globals.Theta + seconds * RadiansPerSecond, TwoPi); 102 | 103 | // Create the model-view matrix: 104 | Globals.Transforms.Model = M4MakeRotationY(Globals.Theta); 105 | Point3 eye = {0, 0, 4}; 106 | Point3 target = {0, 0, 0}; 107 | Vector3 up = {0, 1, 0}; 108 | Globals.Transforms.View = M4MakeLookAt(eye, target, up); 109 | Globals.Transforms.Modelview = M4Mul(Globals.Transforms.View, Globals.Transforms.Model); 110 | Globals.Transforms.Normal = M4GetUpper3x3(Globals.Transforms.Modelview); 111 | for (int i = 0; i < 9; ++i) { 112 | Globals.Transforms.PackedNormal[i] = M3GetElem(Globals.Transforms.Normal, i/3, i%3); 113 | } 114 | } 115 | 116 | void PezRender() 117 | { 118 | float* pModel = (float*) &Globals.Transforms.Model; 119 | float* pView = (float*) &Globals.Transforms.View; 120 | float* pModelview = (float*) &Globals.Transforms.Modelview; 121 | float* pProjection = (float*) &Globals.Transforms.Projection; 122 | float* pNormalMatrix = &Globals.Transforms.PackedNormal[0]; 123 | MeshPod* mesh = &Globals.TrefoilKnot; 124 | 125 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 126 | glEnable(GL_DEPTH_TEST); 127 | glDisable(GL_BLEND); 128 | 129 | glUseProgram(Globals.LitProgram); 130 | glBindVertexArray(mesh->Vao); 131 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 132 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 133 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 134 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 135 | glUniformMatrix3fv(u("NormalMatrix"), 1, 0, pNormalMatrix); 136 | glDrawElements(GL_TRIANGLES, mesh->IndexCount, GL_UNSIGNED_SHORT, 0); 137 | pezCheck(OpenGLError); 138 | 139 | glEnable(GL_BLEND); 140 | glDisable(GL_DEPTH_TEST); 141 | glBindTexture(GL_TEXTURE_2D, Globals.FontMap); 142 | 143 | glUseProgram(Globals.TextProgram); 144 | glBindVertexArray(0); 145 | glBindBuffer(GL_ARRAY_BUFFER, 0); 146 | glEnableVertexAttribArray(a("Character")); 147 | 148 | char text[64]; 149 | sprintf(text, "theta = %3.1f", Globals.Theta * 180 / Pi); 150 | 151 | glVertexAttribIPointer(a("Character"), 1, GL_UNSIGNED_BYTE, 1, text); 152 | glDrawArrays(GL_POINTS, 0, strlen(text)); 153 | 154 | 155 | pezCheck(OpenGLError); 156 | } 157 | 158 | void PezHandleMouse(int x, int y, int action) 159 | { 160 | } 161 | 162 | static GLuint CurrentProgram() 163 | { 164 | GLuint p; 165 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 166 | return p; 167 | } 168 | 169 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey) 170 | { 171 | GLchar spew[256]; 172 | GLint compileSuccess; 173 | GLuint programHandle = glCreateProgram(); 174 | 175 | const char* vsSource = pezGetShader(vsKey); 176 | pezCheck(vsSource != 0, "Can't find vshader: %s\n", vsKey); 177 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 178 | glShaderSource(vsHandle, 1, &vsSource, 0); 179 | glCompileShader(vsHandle); 180 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 181 | glGetShaderInfoLog(vsHandle, sizeof(spew), 0, spew); 182 | pezCheck(compileSuccess, "Can't compile vshader:\n%s", spew); 183 | glAttachShader(programHandle, vsHandle); 184 | 185 | if (gsKey) { 186 | const char* gsSource = pezGetShader(gsKey); 187 | pezCheck(gsSource != 0, "Can't find gshader: %s\n", gsKey); 188 | GLuint gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 189 | glShaderSource(gsHandle, 1, &gsSource, 0); 190 | glCompileShader(gsHandle); 191 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 192 | glGetShaderInfoLog(gsHandle, sizeof(spew), 0, spew); 193 | pezCheck(compileSuccess, "Can't compile gshader:\n%s", spew); 194 | glAttachShader(programHandle, gsHandle); 195 | } 196 | 197 | const char* fsSource = pezGetShader(fsKey); 198 | pezCheck(fsSource != 0, "Can't find fshader: %s\n", fsKey); 199 | GLuint fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 200 | glShaderSource(fsHandle, 1, &fsSource, 0); 201 | glCompileShader(fsHandle); 202 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 203 | glGetShaderInfoLog(fsHandle, sizeof(spew), 0, spew); 204 | pezCheck(compileSuccess, "Can't compile fshader:\n%s", spew); 205 | glAttachShader(programHandle, fsHandle); 206 | 207 | glLinkProgram(programHandle); 208 | GLint linkSuccess; 209 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 210 | glGetProgramInfoLog(programHandle, sizeof(spew), 0, spew); 211 | pezCheck(linkSuccess, "Can't link shaders:\n%s", spew); 212 | glUseProgram(programHandle); 213 | 214 | pezCheck(OpenGLError); 215 | return programHandle; 216 | } 217 | 218 | static Vector3 EvaluateTrefoil(float s, float t) 219 | { 220 | const float a = 0.5f; 221 | const float b = 0.3f; 222 | const float c = 0.5f; 223 | const float d = 0.1f; 224 | const float u = (1 - s) * 2 * TwoPi; 225 | const float v = t * TwoPi; 226 | const float r = a + b * cos(1.5f * u); 227 | const float x = r * cos(u); 228 | const float y = r * sin(u); 229 | const float z = c * sin(1.5f * u); 230 | 231 | Vector3 dv; 232 | dv.x = -1.5f * b * sin(1.5f * u) * cos(u) - (a + b * cos(1.5f * u)) * sin(u); 233 | dv.y = -1.5f * b * sin(1.5f * u) * sin(u) + (a + b * cos(1.5f * u)) * cos(u); 234 | dv.z = 1.5f * c * cos(1.5f * u); 235 | 236 | Vector3 q = V3Normalize(dv); 237 | Vector3 qvn = V3Normalize((Vector3){q.y, -q.x, 0}); 238 | Vector3 ww = V3Cross(q, qvn); 239 | 240 | Vector3 range; 241 | range.x = x + d * (qvn.x * cos(v) + ww.x * sin(v)); 242 | range.y = y + d * (qvn.y * cos(v) + ww.y * sin(v)); 243 | range.z = z + d * ww.z * sin(v); 244 | return range; 245 | } 246 | 247 | static MeshPod CreateTrefoil() 248 | { 249 | const int Slices = 256; 250 | const int Stacks = 32; 251 | const int VertexCount = Slices * Stacks; 252 | const int IndexCount = VertexCount * 6; 253 | 254 | MeshPod mesh; 255 | glGenVertexArrays(1, &mesh.Vao); 256 | glBindVertexArray(mesh.Vao); 257 | 258 | // Create a buffer with interleaved positions and normals 259 | if (true) { 260 | Vertex verts[VertexCount]; 261 | Vertex* pVert = &verts[0]; 262 | float ds = 1.0f / Slices; 263 | float dt = 1.0f / Stacks; 264 | 265 | // The upper bounds in these loops are tweaked to reduce the 266 | // chance of precision error causing an incorrect # of iterations. 267 | for (float s = 0; s < 1 - ds / 2; s += ds) { 268 | for (float t = 0; t < 1 - dt / 2; t += dt) { 269 | const float E = 0.01f; 270 | Vector3 p = EvaluateTrefoil(s, t); 271 | Vector3 u = V3Sub(EvaluateTrefoil(s + E, t), p); 272 | Vector3 v = V3Sub(EvaluateTrefoil(s, t + E), p); 273 | Vector3 n = V3Normalize(V3Cross(u, v)); 274 | pVert->Position = p; 275 | pVert->Normal = n; 276 | ++pVert; 277 | } 278 | } 279 | 280 | pezCheck(pVert - &verts[0] == VertexCount, "Tessellation error."); 281 | 282 | GLuint vbo; 283 | GLsizeiptr size = sizeof(verts); 284 | const GLvoid* data = &verts[0].Position.x; 285 | GLenum usage = GL_STATIC_DRAW; 286 | glGenBuffers(1, &vbo); 287 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 288 | glBufferData(GL_ARRAY_BUFFER, size, data, usage); 289 | } 290 | 291 | // Create a buffer of 16-bit indices 292 | if (true) { 293 | GLushort inds[IndexCount]; 294 | GLushort* pIndex = &inds[0]; 295 | GLushort n = 0; 296 | for (GLushort i = 0; i < Slices; i++) { 297 | for (GLushort j = 0; j < Stacks; j++) { 298 | *pIndex++ = (n + j + Stacks) % VertexCount; 299 | *pIndex++ = n + (j + 1) % Stacks; 300 | *pIndex++ = n + j; 301 | 302 | *pIndex++ = (n + (j + 1) % Stacks + Stacks) % VertexCount; 303 | *pIndex++ = (n + (j + 1) % Stacks) % VertexCount; 304 | *pIndex++ = (n + j + Stacks) % VertexCount; 305 | } 306 | n += Stacks; 307 | } 308 | 309 | pezCheck(n == VertexCount, "Tessellation error."); 310 | pezCheck(pIndex - &inds[0] == IndexCount, "Tessellation error."); 311 | 312 | GLuint handle; 313 | GLsizeiptr size = sizeof(inds); 314 | const GLvoid* data = &inds[0]; 315 | GLenum usage = GL_STATIC_DRAW; 316 | glGenBuffers(1, &handle); 317 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); 318 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, usage); 319 | } 320 | 321 | mesh.VertexCount = VertexCount; 322 | mesh.IndexCount = IndexCount; 323 | 324 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, 24, 0); 325 | glVertexAttribPointer(a("Normal"), 3, GL_FLOAT, GL_FALSE, 24, offset(12)); 326 | glEnableVertexAttribArray(a("Position")); 327 | glEnableVertexAttribArray(a("Normal")); 328 | 329 | pezCheck(OpenGLError); 330 | return mesh; 331 | } 332 | 333 | static GLuint LoadTexture(const char* filename) 334 | { 335 | unsigned char* buffer; 336 | unsigned char* image; 337 | size_t buffersize, imagesize; 338 | LodePNG_Decoder decoder; 339 | LodePNG_loadFile(&buffer, &buffersize, filename); 340 | LodePNG_Decoder_init(&decoder); 341 | decoder.infoRaw.color.colorType = 0; 342 | decoder.infoRaw.color.bitDepth = 8; 343 | LodePNG_Decoder_decode(&decoder, &image, &imagesize, buffer, buffersize); 344 | pezCheck(!decoder.error, "error %u: %s\n", decoder.error, LodePNG_error_text(decoder.error)); 345 | int bpp = LodePNG_InfoColor_getBpp(&decoder.infoPng.color); 346 | int bitDepth = decoder.infoPng.color.bitDepth; 347 | int colorChannels = LodePNG_InfoColor_getChannels(&decoder.infoPng.color); 348 | pezCheck(bpp == 8 && bitDepth == 8 && colorChannels == 1); 349 | int w = decoder.infoPng.width; 350 | int h = decoder.infoPng.height; 351 | pezPrintString("Loaded %s (%d x %d) bufferSize = %d, imageSize = %d\n", filename, w, h, buffersize, imagesize); 352 | 353 | GLuint handle; 354 | glGenTextures(1, &handle); 355 | glBindTexture(GL_TEXTURE_2D, handle); 356 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 357 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 358 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 359 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 360 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, image); 361 | 362 | free(buffer); 363 | free(image); 364 | LodePNG_Decoder_cleanup(&decoder); 365 | 366 | pezCheck(OpenGLError); 367 | return handle; 368 | } 369 | -------------------------------------------------------------------------------- /demo-SimpleText.glsl: -------------------------------------------------------------------------------- 1 | -- Text.VS 2 | 3 | in int Character; 4 | out int vCharacter; 5 | out int vPosition; 6 | 7 | void main() 8 | { 9 | vCharacter = Character; 10 | vPosition = gl_VertexID; 11 | gl_Position = vec4(0, 0, 0, 1); 12 | } 13 | 14 | 15 | -- Text.GS 16 | 17 | layout(points) in; 18 | layout(triangle_strip, max_vertices = 4) out; 19 | 20 | in int vCharacter[1]; 21 | in int vPosition[1]; 22 | out vec2 gTexCoord; 23 | uniform sampler2D Sampler; 24 | 25 | uniform vec2 CellSize; 26 | uniform vec2 CellOffset; 27 | uniform vec2 RenderSize; 28 | uniform vec2 RenderOrigin; 29 | 30 | void main() 31 | { 32 | // Determine the final quad's position and size: 33 | float x = RenderOrigin.x + float(vPosition[0]) * RenderSize.x * 2; 34 | float y = RenderOrigin.y; 35 | vec4 P = vec4(x, y, 0, 1); 36 | vec4 U = vec4(1, 0, 0, 0) * RenderSize.x; 37 | vec4 V = vec4(0, 1, 0, 0) * RenderSize.y; 38 | 39 | // Determine the texture coordinates: 40 | int letter = vCharacter[0]; 41 | letter = clamp(letter - 32, 0, 96); 42 | int row = letter / 16 + 1; 43 | int col = letter % 16; 44 | float S0 = CellOffset.x + CellSize.x * col; 45 | float T0 = CellOffset.y + 1 - CellSize.y * row; 46 | float S1 = S0 + CellSize.x - CellOffset.x; 47 | float T1 = T0 + CellSize.y; 48 | 49 | // Output the quad's vertices: 50 | gTexCoord = vec2(S0, T1); gl_Position = P - U - V; EmitVertex(); 51 | gTexCoord = vec2(S1, T1); gl_Position = P + U - V; EmitVertex(); 52 | gTexCoord = vec2(S0, T0); gl_Position = P - U + V; EmitVertex(); 53 | gTexCoord = vec2(S1, T0); gl_Position = P + U + V; EmitVertex(); 54 | EndPrimitive(); 55 | } 56 | 57 | -- Text.Smooth.FS 58 | 59 | out vec4 FragColor; 60 | in vec2 gTexCoord; 61 | 62 | uniform sampler2D Sampler; 63 | uniform vec3 TextColor; 64 | 65 | void main() 66 | { 67 | float A = texture(Sampler, gTexCoord).r; 68 | FragColor = vec4(TextColor, A); 69 | } 70 | 71 | -- Lit.VS 72 | 73 | in vec4 Position; 74 | in vec3 Normal; 75 | 76 | out vec3 vPosition; 77 | out vec3 vNormal; 78 | 79 | uniform mat4 Projection; 80 | uniform mat4 Modelview; 81 | uniform mat4 ViewMatrix; 82 | uniform mat4 ModelMatrix; 83 | uniform mat3 NormalMatrix; 84 | 85 | void main() 86 | { 87 | vPosition = Position.xyz; 88 | gl_Position = Projection * Modelview * Position; 89 | vNormal = NormalMatrix * Normal; 90 | } 91 | 92 | -- Lit.FS 93 | 94 | in vec3 vNormal; 95 | out vec4 FragColor; 96 | 97 | uniform vec3 LightPosition = vec3(0.25, 0.25, 1.0); 98 | uniform vec3 AmbientMaterial = vec3(0.04, 0.04, 0.04); 99 | uniform vec3 SpecularMaterial = vec3(0.5, 0.5, 0.5); 100 | uniform vec3 FrontMaterial = vec3(0.75, 0.75, 0.5); 101 | uniform vec3 BackMaterial = vec3(0.5, 0.5, 0.75); 102 | uniform float Shininess = 50; 103 | 104 | const float A = 0.1; 105 | const float B = 0.3; 106 | const float C = 0.6; 107 | const float D = 1.0; 108 | 109 | void main() 110 | { 111 | vec3 N = normalize(vNormal); 112 | if (!gl_FrontFacing) 113 | N = -N; 114 | 115 | vec3 L = normalize(LightPosition); 116 | vec3 Eye = vec3(0, 0, 1); 117 | vec3 H = normalize(L + Eye); 118 | 119 | float df = max(0.0, dot(N, L)); 120 | float E = fwidth(df); 121 | if (df > A - E && df < A + E) 122 | df = mix(A, B, smoothstep(A - E, A + E, df)); 123 | else if (df > B - E && df < B + E) 124 | df = mix(B, C, smoothstep(B - E, B + E, df)); 125 | else if (df > C - E && df < C + E) 126 | df = mix(C, D, smoothstep(C - E, C + E, df)); 127 | else if (df < A) df = 0.0; 128 | else if (df < B) df = B; 129 | else if (df < C) df = C; 130 | else df = D; 131 | 132 | float sf = max(0.0, dot(N, H)); 133 | sf = pow(sf, Shininess); 134 | E = fwidth(sf); 135 | if (sf > 0.5 - E && sf < 0.5 + E) 136 | sf = clamp(0.5 * (sf - 0.5 + E) / E, 0.0, 1.0); 137 | else 138 | sf = step(0.5, sf); 139 | 140 | vec3 color = gl_FrontFacing ? FrontMaterial : BackMaterial; 141 | vec3 lighting = AmbientMaterial + df * color; 142 | if (gl_FrontFacing) 143 | lighting += sf * SpecularMaterial; 144 | 145 | FragColor = vec4(lighting, 1); 146 | } 147 | -------------------------------------------------------------------------------- /demo-TextGrid.c: -------------------------------------------------------------------------------- 1 | // Simple Text OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include 6 | #include 7 | #include "pez.h" 8 | #include "vmath.h" 9 | #include "lodepng.h" 10 | 11 | typedef struct { 12 | int VertexCount; 13 | int IndexCount; 14 | GLuint Vao; 15 | } MeshPod; 16 | 17 | typedef struct { 18 | Matrix4 Projection; 19 | Matrix4 Ortho; 20 | Matrix4 Modelview; 21 | Matrix4 View; 22 | Matrix4 Model; 23 | Matrix3 Normal; 24 | GLfloat PackedNormal[9]; 25 | } TransformsPod; 26 | 27 | struct { 28 | float Theta; 29 | GLuint LitProgram; 30 | GLuint QuadProgram; 31 | GLuint TextProgram; 32 | GLuint SinglePointVao; 33 | MeshPod TrefoilKnot; 34 | TransformsPod Transforms; 35 | GLuint QuadVao; 36 | GLuint TextVao; 37 | GLuint FontMap; 38 | char Message[256]; 39 | } Globals; 40 | 41 | typedef struct { 42 | Vector3 Position; 43 | Vector3 Normal; 44 | } Vertex; 45 | 46 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey); 47 | static GLuint CurrentProgram(); 48 | static MeshPod CreateTrefoil(); 49 | static GLuint LoadTexture(const char* filename); 50 | static GLuint CreateQuad(int sourceWidth, int sourceHeight, int destWidth, int destHeight); 51 | static GLuint CreateText(const char* text); 52 | 53 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 54 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 55 | #define offset(x) ((const GLvoid*)x) 56 | #define OpenGLError GL_NO_ERROR == glGetError(), "%s:%d - OpenGL Error - %s", __FILE__, __LINE__, __FUNCTION__ 57 | 58 | PezConfig PezGetConfig() 59 | { 60 | PezConfig config; 61 | config.Title = __FILE__; 62 | config.Width = 725;//853; 63 | config.Height = 231;//480; 64 | config.Multisampling = true; 65 | config.VerticalSync = true; 66 | return config; 67 | } 68 | 69 | void PezInitialize() 70 | { 71 | const PezConfig cfg = PezGetConfig(); 72 | pezSwAddDirective("*", "#extension GL_ARB_explicit_attrib_location : enable"); 73 | 74 | strcpy(Globals.Message, "Hello, world."); 75 | 76 | // Compile shaders 77 | Globals.QuadProgram = LoadProgram("Quad.VS", 0, "Quad.FS"); 78 | Globals.LitProgram = LoadProgram("Lit.VS", 0, "Lit.FS"); 79 | Globals.TextProgram = LoadProgram("Text.VS", "Text.GS", "Text.Smooth.FS"); 80 | 81 | // Set up viewport 82 | float fovy = 16 * TwoPi / 180; 83 | float aspect = (float) cfg.Width / cfg.Height; 84 | float zNear = 0.1, zFar = 300; 85 | Globals.Transforms.Projection = M4MakePerspective(fovy, aspect, zNear, zFar); 86 | Globals.Transforms.Ortho = M4MakeOrthographic(0, cfg.Width, cfg.Height, 0, 0, 1); 87 | 88 | // Create geometry 89 | glUseProgram(Globals.QuadProgram); 90 | Globals.QuadVao = CreateQuad(cfg.Width, -cfg.Height, cfg.Width, cfg.Height); 91 | glUseProgram(Globals.TextProgram); 92 | Globals.TextVao = CreateText(Globals.Message); 93 | glUseProgram(Globals.LitProgram); 94 | Globals.TrefoilKnot = CreateTrefoil(); 95 | 96 | // Load textures 97 | Globals.FontMap = LoadTexture("FontMap.png"); 98 | //Globals.FontMap = LoadTexture("Mona-EDT-Small.png"); 99 | 100 | // Misc Initialization 101 | Globals.Theta = 0; 102 | glClearColor(0.184, 0.310, 0.310, 1); 103 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 104 | pezCheck(OpenGLError); 105 | } 106 | 107 | void PezUpdate(float seconds) 108 | { 109 | const float RadiansPerSecond = 0.5f; 110 | Globals.Theta += seconds * RadiansPerSecond; 111 | 112 | // Create the model-view matrix: 113 | Globals.Transforms.Model = M4MakeRotationY(Globals.Theta); 114 | Point3 eye = {0, 0, 4}; 115 | Point3 target = {0, 0, 0}; 116 | Vector3 up = {0, 1, 0}; 117 | Globals.Transforms.View = M4MakeLookAt(eye, target, up); 118 | Globals.Transforms.Modelview = M4Mul(Globals.Transforms.View, Globals.Transforms.Model); 119 | Globals.Transforms.Normal = M4GetUpper3x3(Globals.Transforms.Modelview); 120 | for (int i = 0; i < 9; ++i) { 121 | Globals.Transforms.PackedNormal[i] = M3GetElem(Globals.Transforms.Normal, i/3, i%3); 122 | } 123 | } 124 | 125 | void PezRender() 126 | { 127 | float* pModel = (float*) &Globals.Transforms.Model; 128 | float* pView = (float*) &Globals.Transforms.View; 129 | float* pModelview = (float*) &Globals.Transforms.Modelview; 130 | float* pProjection = (float*) &Globals.Transforms.Projection; 131 | float* pNormalMatrix = &Globals.Transforms.PackedNormal[0]; 132 | MeshPod* mesh = &Globals.TrefoilKnot; 133 | 134 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 135 | glEnable(GL_DEPTH_TEST); 136 | 137 | glUseProgram(Globals.LitProgram); 138 | glBindVertexArray(mesh->Vao); 139 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 140 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 141 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 142 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 143 | glUniformMatrix3fv(u("NormalMatrix"), 1, 0, pNormalMatrix); 144 | glDrawElements(GL_TRIANGLES, mesh->IndexCount, GL_UNSIGNED_SHORT, 0); 145 | pezCheck(OpenGLError); 146 | 147 | glUseProgram(Globals.TextProgram); 148 | glEnable(GL_BLEND); 149 | glDisable(GL_DEPTH_TEST); 150 | glBindTexture(GL_TEXTURE_2D, Globals.FontMap); 151 | glDrawArrays(GL_POINTS, 0, 1); // strlen(Globals.Message)); 152 | glBindTexture(GL_TEXTURE_2D, 0); 153 | glDisable(GL_BLEND); 154 | 155 | pezCheck(OpenGLError); 156 | } 157 | 158 | void PezHandleMouse(int x, int y, int action) 159 | { 160 | } 161 | 162 | static GLuint CurrentProgram() 163 | { 164 | GLuint p; 165 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 166 | return p; 167 | } 168 | 169 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey) 170 | { 171 | GLchar spew[256]; 172 | GLint compileSuccess; 173 | GLuint programHandle = glCreateProgram(); 174 | 175 | const char* vsSource = pezGetShader(vsKey); 176 | pezCheck(vsSource != 0, "Can't find vshader: %s\n", vsKey); 177 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 178 | glShaderSource(vsHandle, 1, &vsSource, 0); 179 | glCompileShader(vsHandle); 180 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 181 | glGetShaderInfoLog(vsHandle, sizeof(spew), 0, spew); 182 | pezCheck(compileSuccess, "Can't compile vshader:\n%s", spew); 183 | glAttachShader(programHandle, vsHandle); 184 | 185 | if (gsKey) { 186 | const char* gsSource = pezGetShader(gsKey); 187 | pezCheck(gsSource != 0, "Can't find gshader: %s\n", gsKey); 188 | GLuint gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 189 | glShaderSource(gsHandle, 1, &gsSource, 0); 190 | glCompileShader(gsHandle); 191 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 192 | glGetShaderInfoLog(gsHandle, sizeof(spew), 0, spew); 193 | pezCheck(compileSuccess, "Can't compile gshader:\n%s", spew); 194 | glAttachShader(programHandle, gsHandle); 195 | } 196 | 197 | const char* fsSource = pezGetShader(fsKey); 198 | pezCheck(fsSource != 0, "Can't find fshader: %s\n", fsKey); 199 | GLuint fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 200 | glShaderSource(fsHandle, 1, &fsSource, 0); 201 | glCompileShader(fsHandle); 202 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 203 | glGetShaderInfoLog(fsHandle, sizeof(spew), 0, spew); 204 | pezCheck(compileSuccess, "Can't compile fshader:\n%s", spew); 205 | glAttachShader(programHandle, fsHandle); 206 | 207 | glLinkProgram(programHandle); 208 | GLint linkSuccess; 209 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 210 | glGetProgramInfoLog(programHandle, sizeof(spew), 0, spew); 211 | pezCheck(linkSuccess, "Can't link shaders:\n%s", spew); 212 | glUseProgram(programHandle); 213 | 214 | pezCheck(OpenGLError); 215 | return programHandle; 216 | } 217 | 218 | static Vector3 EvaluateTrefoil(float s, float t) 219 | { 220 | const float a = 0.5f; 221 | const float b = 0.3f; 222 | const float c = 0.5f; 223 | const float d = 0.1f; 224 | const float u = (1 - s) * 2 * TwoPi; 225 | const float v = t * TwoPi; 226 | const float r = a + b * cos(1.5f * u); 227 | const float x = r * cos(u); 228 | const float y = r * sin(u); 229 | const float z = c * sin(1.5f * u); 230 | 231 | Vector3 dv; 232 | dv.x = -1.5f * b * sin(1.5f * u) * cos(u) - (a + b * cos(1.5f * u)) * sin(u); 233 | dv.y = -1.5f * b * sin(1.5f * u) * sin(u) + (a + b * cos(1.5f * u)) * cos(u); 234 | dv.z = 1.5f * c * cos(1.5f * u); 235 | 236 | Vector3 q = V3Normalize(dv); 237 | Vector3 qvn = V3Normalize((Vector3){q.y, -q.x, 0}); 238 | Vector3 ww = V3Cross(q, qvn); 239 | 240 | Vector3 range; 241 | range.x = x + d * (qvn.x * cos(v) + ww.x * sin(v)); 242 | range.y = y + d * (qvn.y * cos(v) + ww.y * sin(v)); 243 | range.z = z + d * ww.z * sin(v); 244 | return range; 245 | } 246 | 247 | static MeshPod CreateTrefoil() 248 | { 249 | const int Slices = 256; 250 | const int Stacks = 32; 251 | const int VertexCount = Slices * Stacks; 252 | const int IndexCount = VertexCount * 6; 253 | 254 | MeshPod mesh; 255 | glGenVertexArrays(1, &mesh.Vao); 256 | glBindVertexArray(mesh.Vao); 257 | 258 | // Create a buffer with interleaved positions and normals 259 | if (true) { 260 | Vertex verts[VertexCount]; 261 | Vertex* pVert = &verts[0]; 262 | float ds = 1.0f / Slices; 263 | float dt = 1.0f / Stacks; 264 | 265 | // The upper bounds in these loops are tweaked to reduce the 266 | // chance of precision error causing an incorrect # of iterations. 267 | for (float s = 0; s < 1 - ds / 2; s += ds) { 268 | for (float t = 0; t < 1 - dt / 2; t += dt) { 269 | const float E = 0.01f; 270 | Vector3 p = EvaluateTrefoil(s, t); 271 | Vector3 u = V3Sub(EvaluateTrefoil(s + E, t), p); 272 | Vector3 v = V3Sub(EvaluateTrefoil(s, t + E), p); 273 | Vector3 n = V3Normalize(V3Cross(u, v)); 274 | pVert->Position = p; 275 | pVert->Normal = n; 276 | ++pVert; 277 | } 278 | } 279 | 280 | pezCheck(pVert - &verts[0] == VertexCount, "Tessellation error."); 281 | 282 | GLuint vbo; 283 | GLsizeiptr size = sizeof(verts); 284 | const GLvoid* data = &verts[0].Position.x; 285 | GLenum usage = GL_STATIC_DRAW; 286 | glGenBuffers(1, &vbo); 287 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 288 | glBufferData(GL_ARRAY_BUFFER, size, data, usage); 289 | } 290 | 291 | // Create a buffer of 16-bit indices 292 | if (true) { 293 | GLushort inds[IndexCount]; 294 | GLushort* pIndex = &inds[0]; 295 | GLushort n = 0; 296 | for (GLushort i = 0; i < Slices; i++) { 297 | for (GLushort j = 0; j < Stacks; j++) { 298 | *pIndex++ = (n + j + Stacks) % VertexCount; 299 | *pIndex++ = n + (j + 1) % Stacks; 300 | *pIndex++ = n + j; 301 | 302 | *pIndex++ = (n + (j + 1) % Stacks + Stacks) % VertexCount; 303 | *pIndex++ = (n + (j + 1) % Stacks) % VertexCount; 304 | *pIndex++ = (n + j + Stacks) % VertexCount; 305 | } 306 | n += Stacks; 307 | } 308 | 309 | pezCheck(n == VertexCount, "Tessellation error."); 310 | pezCheck(pIndex - &inds[0] == IndexCount, "Tessellation error."); 311 | 312 | GLuint handle; 313 | GLsizeiptr size = sizeof(inds); 314 | const GLvoid* data = &inds[0]; 315 | GLenum usage = GL_STATIC_DRAW; 316 | glGenBuffers(1, &handle); 317 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); 318 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, usage); 319 | } 320 | 321 | mesh.VertexCount = VertexCount; 322 | mesh.IndexCount = IndexCount; 323 | 324 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, 24, 0); 325 | glVertexAttribPointer(a("Normal"), 3, GL_FLOAT, GL_FALSE, 24, offset(12)); 326 | glEnableVertexAttribArray(a("Position")); 327 | glEnableVertexAttribArray(a("Normal")); 328 | 329 | pezCheck(OpenGLError); 330 | return mesh; 331 | } 332 | 333 | static GLuint LoadTexture(const char* filename) 334 | { 335 | unsigned char* buffer; 336 | unsigned char* image; 337 | size_t buffersize, imagesize; 338 | LodePNG_Decoder decoder; 339 | LodePNG_loadFile(&buffer, &buffersize, filename); 340 | LodePNG_Decoder_init(&decoder); 341 | decoder.infoRaw.color.colorType = 0; 342 | decoder.infoRaw.color.bitDepth = 8; 343 | LodePNG_Decoder_decode(&decoder, &image, &imagesize, buffer, buffersize); 344 | pezCheck(!decoder.error, "error %u: %s\n", decoder.error, LodePNG_error_text(decoder.error)); 345 | int bpp = LodePNG_InfoColor_getBpp(&decoder.infoPng.color); 346 | int bitDepth = decoder.infoPng.color.bitDepth; 347 | int colorChannels = LodePNG_InfoColor_getChannels(&decoder.infoPng.color); 348 | pezCheck(bpp == 8 && bitDepth == 8 && colorChannels == 1); 349 | int w = decoder.infoPng.width; 350 | int h = decoder.infoPng.height; 351 | pezPrintString("Loaded %s (%d x %d) bufferSize = %d, imageSize = %d\n", filename, w, h, buffersize, imagesize); 352 | 353 | GLuint handle; 354 | glGenTextures(1, &handle); 355 | glBindTexture(GL_TEXTURE_2D, handle); 356 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 357 | glPixelStorei(GL_PACK_ALIGNMENT, 1); 358 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 359 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 360 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 361 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 362 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, image); 363 | 364 | free(buffer); 365 | free(image); 366 | LodePNG_Decoder_cleanup(&decoder); 367 | 368 | pezCheck(OpenGLError); 369 | return handle; 370 | } 371 | /* 372 | static GLuint CreateRenderTarget() 373 | { 374 | GLuint* colorTexture = &Globals.ColorTexture; 375 | 376 | pezCheck(GL_NO_ERROR == glGetError(), "OpenGL error on line %d", __LINE__); 377 | PezConfig cfg = PezGetConfig(); 378 | 379 | glGenTextures(1, colorTexture); 380 | glBindTexture(GL_TEXTURE_2D, *colorTexture); 381 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 382 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 383 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 384 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 385 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cfg.Width, cfg.Height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 386 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to create color texture."); 387 | 388 | GLuint* distanceTexture = &Globals.DistanceTextures[0]; 389 | for (int i = 0; i < 2; i++) { 390 | glGenTextures(1, distanceTexture); 391 | glBindTexture(GL_TEXTURE_2D, *distanceTexture); 392 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 393 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 394 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 395 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 396 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, cfg.Width, cfg.Height, 0, GL_RGB, GL_HALF_FLOAT, 0); 397 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to create distance texture."); 398 | ++distanceTexture; 399 | } 400 | distanceTexture = &Globals.DistanceTextures[0]; 401 | 402 | Globals.ColorAttachment = GL_COLOR_ATTACHMENT0; 403 | Globals.DistanceAttachments[0] = GL_COLOR_ATTACHMENT1; 404 | Globals.DistanceAttachments[1] = GL_COLOR_ATTACHMENT2; 405 | 406 | GLuint fboHandle; 407 | glGenFramebuffers(1, &fboHandle); 408 | glBindFramebuffer(GL_FRAMEBUFFER, fboHandle); 409 | glFramebufferTexture2D(GL_FRAMEBUFFER, Globals.ColorAttachment, GL_TEXTURE_2D, *colorTexture, 0); 410 | glFramebufferTexture2D(GL_FRAMEBUFFER, Globals.DistanceAttachments[0], GL_TEXTURE_2D, distanceTexture[0], 0); 411 | glFramebufferTexture2D(GL_FRAMEBUFFER, Globals.DistanceAttachments[1], GL_TEXTURE_2D, distanceTexture[1], 0); 412 | 413 | GLuint depthBuffer; 414 | glGenRenderbuffers(1, &depthBuffer); 415 | glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); 416 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, cfg.Width, cfg.Height); 417 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer); 418 | 419 | pezCheck(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER), "Invalid FBO."); 420 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 421 | 422 | pezCheck(OpenGLError); 423 | return fboHandle; 424 | } 425 | */ 426 | static GLuint CreateQuad(int sourceWidth, int sourceHeight, int destWidth, int destHeight) 427 | { 428 | // Stretch to fit: 429 | float q[] = { 430 | -1, -1, 0, 1, 431 | +1, -1, 1, 1, 432 | -1, +1, 0, 0, 433 | +1, +1, 1, 0 }; 434 | 435 | if (sourceHeight < 0) { 436 | sourceHeight = -sourceHeight; 437 | q[3] = 1-q[3]; 438 | q[7] = 1-q[7]; 439 | q[11] = 1-q[11]; 440 | q[15] = 1-q[15]; 441 | } 442 | 443 | float sourceRatio = (float) sourceWidth / sourceHeight; 444 | float destRatio = (float) destWidth / destHeight; 445 | 446 | // Horizontal fit: 447 | if (sourceRatio > destRatio) { 448 | q[1] = q[5] = -destRatio / sourceRatio; 449 | q[9] = q[13] = destRatio / sourceRatio; 450 | 451 | // Vertical fit: 452 | } else { 453 | q[0] = q[8] = -sourceRatio / destRatio; 454 | q[4] = q[12] = sourceRatio / destRatio; 455 | } 456 | 457 | GLuint vbo, vao; 458 | glUseProgram(Globals.QuadProgram); 459 | glGenVertexArrays(1, &vao); 460 | glBindVertexArray(vao); 461 | glGenBuffers(1, &vbo); 462 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 463 | glBufferData(GL_ARRAY_BUFFER, sizeof(q), q, GL_STATIC_DRAW); 464 | glVertexAttribPointer(a("Position"), 2, GL_FLOAT, GL_FALSE, 16, 0); 465 | glVertexAttribPointer(a("TexCoord"), 2, GL_FLOAT, GL_FALSE, 16, offset(8)); 466 | glEnableVertexAttribArray(a("Position")); 467 | glEnableVertexAttribArray(a("TexCoord")); 468 | pezCheck(OpenGLError); 469 | return vao; 470 | } 471 | 472 | static GLuint CreateText(const char* text) 473 | { 474 | GLuint vbo, vao; 475 | glGenVertexArrays(1, &vao); 476 | glBindVertexArray(vao); 477 | glGenBuffers(1, &vbo); 478 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 479 | glBufferData(GL_ARRAY_BUFFER, strlen(text), text, GL_STATIC_DRAW); 480 | glVertexAttribPointer(a("Character"), 1, GL_UNSIGNED_BYTE, GL_FALSE, 8, 0); 481 | glEnableVertexAttribArray(a("Character")); 482 | pezCheck(OpenGLError); 483 | return vao; 484 | } 485 | -------------------------------------------------------------------------------- /demo-TextGrid.glsl: -------------------------------------------------------------------------------- 1 | -- Text.VS 2 | 3 | in uint Character; 4 | out uint vCharacter; 5 | uniform int GlyphWidth = 32; 6 | 7 | void main() 8 | { 9 | vec2 p; 10 | p.x = float(gl_VertexID) * GlyphWidth; 11 | p.y = 0; 12 | vCharacter = Character; 13 | gl_Position = vec4(p, 0, 1); 14 | } 15 | 16 | 17 | -- Text.GS 18 | 19 | layout(points) in; 20 | layout(triangle_strip, max_vertices = 4) out; 21 | 22 | in uint vCharacter[1]; 23 | out vec2 gTexCoord; 24 | uniform sampler2D Sampler; 25 | 26 | void main() 27 | { 28 | /* 29 | vec4 P = gl_in[0].gl_Position; 30 | vec4 U = vec4(SpriteSize.x, 0, 0, 0) * InverseViewport.x; 31 | vec4 V = vec4(0, SpriteSize.y, 0, 0) * InverseViewport.y; 32 | */ 33 | 34 | vec4 P = vec4(0, 0, 0, 1); 35 | vec4 U = vec4(1, 0, 0, 0); 36 | vec4 V = vec4(0, 1, 0, 0); 37 | 38 | // Letter 'H' is column 16, row 1. 39 | // Letter 'h' is column 0, row 3. 40 | // Columns and Rows increase Right-Down. 41 | float column = 8; 42 | float row = 3; 43 | 44 | float ColumnCount = 24; 45 | float RowCount = 4; 46 | 47 | ivec2 size = textureSize(Sampler, 0); 48 | 49 | ivec2 padding = ivec2(2, 16); 50 | vec2 offset = vec2(6, 0); 51 | int rowPadding = 2; // not yet used 52 | 53 | float GlyphWidth = float(size.x - padding.x) / ColumnCount; 54 | float GlyphHeight = float(size.y - padding.y) / RowCount; 55 | 56 | float S0 = (offset.x + (column+0) * GlyphWidth) / float(size.x); 57 | float S1 = (offset.x + (column+1) * GlyphWidth) / float(size.x); 58 | float T0 = (offset.y + (row+0) * GlyphHeight) / float(size.y); 59 | float T1 = (offset.y + (row+1) * GlyphHeight) / float(size.y); 60 | S0 = 0.0;S1 = 1.0;T0 = 0.0;T1 = 1.0; 61 | 62 | gTexCoord = vec2(S0, T1); 63 | gl_Position = P - U - V; 64 | EmitVertex(); 65 | 66 | gTexCoord = vec2(S1, T1); 67 | gl_Position = P + U - V; 68 | EmitVertex(); 69 | 70 | gTexCoord = vec2(S0, T0); 71 | gl_Position = P - U + V; 72 | EmitVertex(); 73 | 74 | gTexCoord = vec2(S1, T0); 75 | gl_Position = P + U + V; 76 | gl_Position.z += float(vCharacter[0]) * 0.00000000001; 77 | EmitVertex(); 78 | 79 | EndPrimitive(); 80 | } 81 | 82 | -- Text.Smooth.FS 83 | 84 | out vec4 FragColor; 85 | in vec2 gTexCoord; 86 | 87 | uniform sampler2D Sampler; 88 | //uniform vec3 TextColor = vec3(0.275, 0.510, 0.706); // SteelBlue 89 | uniform vec3 TextColor = vec3(0.686, 0.933, 0.933); // PaleTurquoise 90 | 91 | void main() 92 | { 93 | float D = texture(Sampler, gTexCoord).r; 94 | float width = fwidth(D); 95 | float T = 0.5; 96 | float A = 1.0 - smoothstep(T - width, T + width, D); 97 | 98 | FragColor = vec4(TextColor, A); 99 | 100 | int GlyphWidth = 29; 101 | int OffsetFromLeft = 11; 102 | int GlyphHeight = 52; 103 | int OffsetFromBottom = 14; 104 | 105 | if (int(gl_FragCoord.x - OffsetFromLeft) % GlyphWidth == 0) { 106 | FragColor = vec4(0,0,0,1); 107 | } 108 | 109 | if (int(gl_FragCoord.y - OffsetFromBottom) % GlyphHeight == 0) { 110 | FragColor = vec4(0,0,0,1); 111 | } 112 | } 113 | 114 | -- Text.Outline.FS 115 | 116 | out vec4 FragColor; 117 | in vec2 gTexCoord; 118 | 119 | uniform sampler2D Sampler; 120 | uniform float Thickness = 0.03; 121 | 122 | void main() 123 | { 124 | float D = texture(Sampler, gTexCoord).x; 125 | float width = fwidth(D); 126 | 127 | if (D < 0.5 - Thickness) { 128 | float A = 1.0 - smoothstep(0.5 - Thickness - width, 0.5 - Thickness, D); 129 | FragColor = vec4(A, A, A, 1); 130 | } else if (D < 0.5 + Thickness) { 131 | FragColor = vec4(0, 0, 0, 1); 132 | } else { 133 | float A = 1.0 - smoothstep(0.5 + Thickness, 0.5 + Thickness + width, D); 134 | FragColor = vec4(0, 0, 0, A); 135 | } 136 | } 137 | 138 | ---------------------------------------------------------------- 139 | 140 | -- Quad.VS 141 | 142 | in vec2 Position; 143 | in vec2 TexCoord; 144 | out vec2 vTexCoord; 145 | 146 | void main() 147 | { 148 | vTexCoord = TexCoord; 149 | gl_Position = vec4(Position, 0, 1); 150 | } 151 | 152 | -- Quad.FS 153 | 154 | in vec2 vTexCoord; 155 | layout(location = 0) out vec4 FragColor; 156 | uniform sampler2D Sampler; 157 | uniform vec3 Scale; 158 | 159 | void main() 160 | { 161 | FragColor = vec4(Scale, 1) * texture(Sampler, vTexCoord); 162 | } 163 | 164 | -- Lit.VS 165 | 166 | in vec4 Position; 167 | in vec3 Normal; 168 | 169 | out vec3 vPosition; 170 | out vec3 vNormal; 171 | 172 | uniform mat4 Projection; 173 | uniform mat4 Modelview; 174 | uniform mat4 ViewMatrix; 175 | uniform mat4 ModelMatrix; 176 | uniform mat3 NormalMatrix; 177 | 178 | void main() 179 | { 180 | vPosition = Position.xyz; 181 | gl_Position = Projection * Modelview * Position; 182 | vNormal = NormalMatrix * Normal; 183 | } 184 | 185 | -- Lit.FS 186 | 187 | in vec3 vNormal; 188 | out vec4 FragColor; 189 | 190 | uniform vec3 LightPosition = vec3(0.25, 0.25, 1.0); 191 | uniform vec3 AmbientMaterial = vec3(0.04, 0.04, 0.04); 192 | uniform vec3 SpecularMaterial = vec3(0.5, 0.5, 0.5); 193 | uniform vec3 FrontMaterial = vec3(0.75, 0.75, 0.5); 194 | uniform vec3 BackMaterial = vec3(0.5, 0.5, 0.75); 195 | uniform float Shininess = 50; 196 | 197 | const float A = 0.1; 198 | const float B = 0.3; 199 | const float C = 0.6; 200 | const float D = 1.0; 201 | 202 | void main() 203 | { 204 | vec3 N = normalize(vNormal); 205 | if (!gl_FrontFacing) 206 | N = -N; 207 | 208 | vec3 L = normalize(LightPosition); 209 | vec3 Eye = vec3(0, 0, 1); 210 | vec3 H = normalize(L + Eye); 211 | 212 | float df = max(0.0, dot(N, L)); 213 | float E = fwidth(df); 214 | if (df > A - E && df < A + E) 215 | df = mix(A, B, smoothstep(A - E, A + E, df)); 216 | else if (df > B - E && df < B + E) 217 | df = mix(B, C, smoothstep(B - E, B + E, df)); 218 | else if (df > C - E && df < C + E) 219 | df = mix(C, D, smoothstep(C - E, C + E, df)); 220 | else if (df < A) df = 0.0; 221 | else if (df < B) df = B; 222 | else if (df < C) df = C; 223 | else df = D; 224 | 225 | float sf = max(0.0, dot(N, H)); 226 | sf = pow(sf, Shininess); 227 | E = fwidth(sf); 228 | if (sf > 0.5 - E && sf < 0.5 + E) 229 | sf = clamp(0.5 * (sf - 0.5 + E) / E, 0.0, 1.0); 230 | else 231 | sf = step(0.5, sf); 232 | 233 | vec3 color = gl_FrontFacing ? FrontMaterial : BackMaterial; 234 | vec3 lighting = AmbientMaterial + df * color; 235 | if (gl_FrontFacing) 236 | lighting += sf * SpecularMaterial; 237 | 238 | FragColor = vec4(lighting, 1); 239 | } 240 | -------------------------------------------------------------------------------- /demo-ToonShading.c: -------------------------------------------------------------------------------- 1 | // Toon Shading OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include 6 | #include 7 | #include "pez.h" 8 | #include "vmath.h" 9 | 10 | typedef struct { 11 | int VertexCount; 12 | int IndexCount; 13 | GLuint Vao; 14 | } MeshPod; 15 | 16 | typedef struct { 17 | Matrix4 Projection; 18 | Matrix4 Ortho; 19 | Matrix4 Modelview; 20 | Matrix4 View; 21 | Matrix4 Model; 22 | Matrix3 Normal; 23 | GLfloat PackedNormal[9]; 24 | } TransformsPod; 25 | 26 | struct { 27 | float Theta; 28 | GLuint LitProgram; 29 | GLuint SinglePointVao; 30 | MeshPod TrefoilKnot; 31 | TransformsPod Transforms; 32 | } Globals; 33 | 34 | typedef struct { 35 | Vector3 Position; 36 | Vector3 Normal; 37 | } Vertex; 38 | 39 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey); 40 | static GLuint CurrentProgram(); 41 | static MeshPod CreateTrefoil(); 42 | 43 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 44 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 45 | #define offset(x) ((const GLvoid*)x) 46 | 47 | PezConfig PezGetConfig() 48 | { 49 | PezConfig config; 50 | config.Title = __FILE__; 51 | config.Width = 853; 52 | config.Height = 480; 53 | config.Multisampling = true; 54 | config.VerticalSync = true; 55 | return config; 56 | } 57 | 58 | void PezInitialize() 59 | { 60 | const PezConfig cfg = PezGetConfig(); 61 | 62 | // Compile shaders 63 | Globals.LitProgram = LoadProgram("Lit.VS", 0, "Lit.FS"); 64 | 65 | // Set up viewport 66 | float fovy = 16 * TwoPi / 180; 67 | float aspect = (float) cfg.Width / cfg.Height; 68 | float zNear = 0.1, zFar = 300; 69 | Globals.Transforms.Projection = M4MakePerspective(fovy, aspect, zNear, zFar); 70 | Globals.Transforms.Ortho = M4MakeOrthographic(0, cfg.Width, cfg.Height, 0, 0, 1); 71 | 72 | // Create geometry 73 | glUseProgram(Globals.LitProgram); 74 | Globals.TrefoilKnot = CreateTrefoil(); 75 | 76 | // Misc Initialization 77 | Globals.Theta = 0; 78 | glClearColor(0.5f, 0.6f, 0.7f, 1.0f); 79 | } 80 | 81 | void PezUpdate(float seconds) 82 | { 83 | const float RadiansPerSecond = 0.5f; 84 | Globals.Theta += seconds * RadiansPerSecond; 85 | 86 | // Create the model-view matrix: 87 | Globals.Transforms.Model = M4MakeRotationY(Globals.Theta); 88 | Point3 eye = {0, 0, 4}; 89 | Point3 target = {0, 0, 0}; 90 | Vector3 up = {0, 1, 0}; 91 | Globals.Transforms.View = M4MakeLookAt(eye, target, up); 92 | Globals.Transforms.Modelview = M4Mul(Globals.Transforms.View, Globals.Transforms.Model); 93 | Globals.Transforms.Normal = M4GetUpper3x3(Globals.Transforms.Modelview); 94 | for (int i = 0; i < 9; ++i) 95 | Globals.Transforms.PackedNormal[i] = M3GetElem(Globals.Transforms.Normal, i/3, i%3); 96 | } 97 | 98 | void PezRender() 99 | { 100 | float* pModel = (float*) &Globals.Transforms.Model; 101 | float* pView = (float*) &Globals.Transforms.View; 102 | float* pModelview = (float*) &Globals.Transforms.Modelview; 103 | float* pProjection = (float*) &Globals.Transforms.Projection; 104 | float* pNormalMatrix = &Globals.Transforms.PackedNormal[0]; 105 | MeshPod* mesh = &Globals.TrefoilKnot; 106 | 107 | glUseProgram(Globals.LitProgram); 108 | glBindVertexArray(mesh->Vao); 109 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 110 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 111 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 112 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 113 | glUniformMatrix3fv(u("NormalMatrix"), 1, 0, pNormalMatrix); 114 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 115 | glEnable(GL_DEPTH_TEST); 116 | glDrawElements(GL_TRIANGLES, mesh->IndexCount, GL_UNSIGNED_SHORT, 0); 117 | } 118 | 119 | void PezHandleMouse(int x, int y, int action) 120 | { 121 | } 122 | 123 | static GLuint CurrentProgram() 124 | { 125 | GLuint p; 126 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 127 | return p; 128 | } 129 | 130 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey) 131 | { 132 | GLchar spew[256]; 133 | GLint compileSuccess; 134 | GLuint programHandle = glCreateProgram(); 135 | 136 | const char* vsSource = pezGetShader(vsKey); 137 | pezCheck(vsSource != 0, "Can't find vshader: %s\n", vsKey); 138 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 139 | glShaderSource(vsHandle, 1, &vsSource, 0); 140 | glCompileShader(vsHandle); 141 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 142 | glGetShaderInfoLog(vsHandle, sizeof(spew), 0, spew); 143 | pezCheck(compileSuccess, "Can't compile vshader:\n%s", spew); 144 | glAttachShader(programHandle, vsHandle); 145 | 146 | if (gsKey) { 147 | const char* gsSource = pezGetShader(gsKey); 148 | pezCheck(gsSource != 0, "Can't find gshader: %s\n", gsKey); 149 | GLuint gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 150 | glShaderSource(gsHandle, 1, &gsSource, 0); 151 | glCompileShader(gsHandle); 152 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 153 | glGetShaderInfoLog(gsHandle, sizeof(spew), 0, spew); 154 | pezCheck(compileSuccess, "Can't compile gshader:\n%s", spew); 155 | glAttachShader(programHandle, gsHandle); 156 | } 157 | 158 | const char* fsSource = pezGetShader(fsKey); 159 | pezCheck(fsSource != 0, "Can't find fshader: %s\n", fsKey); 160 | GLuint fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 161 | glShaderSource(fsHandle, 1, &fsSource, 0); 162 | glCompileShader(fsHandle); 163 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 164 | glGetShaderInfoLog(fsHandle, sizeof(spew), 0, spew); 165 | pezCheck(compileSuccess, "Can't compile fshader:\n%s", spew); 166 | glAttachShader(programHandle, fsHandle); 167 | 168 | glLinkProgram(programHandle); 169 | GLint linkSuccess; 170 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 171 | glGetProgramInfoLog(programHandle, sizeof(spew), 0, spew); 172 | pezCheck(linkSuccess, "Can't link shaders:\n%s", spew); 173 | glUseProgram(programHandle); 174 | return programHandle; 175 | } 176 | 177 | static Vector3 EvaluateTrefoil(float s, float t) 178 | { 179 | const float a = 0.5f; 180 | const float b = 0.3f; 181 | const float c = 0.5f; 182 | const float d = 0.1f; 183 | const float u = (1 - s) * 2 * TwoPi; 184 | const float v = t * TwoPi; 185 | const float r = a + b * cos(1.5f * u); 186 | const float x = r * cos(u); 187 | const float y = r * sin(u); 188 | const float z = c * sin(1.5f * u); 189 | 190 | Vector3 dv; 191 | dv.x = -1.5f * b * sin(1.5f * u) * cos(u) - (a + b * cos(1.5f * u)) * sin(u); 192 | dv.y = -1.5f * b * sin(1.5f * u) * sin(u) + (a + b * cos(1.5f * u)) * cos(u); 193 | dv.z = 1.5f * c * cos(1.5f * u); 194 | 195 | Vector3 q = V3Normalize(dv); 196 | Vector3 qvn = V3Normalize((Vector3){q.y, -q.x, 0}); 197 | Vector3 ww = V3Cross(q, qvn); 198 | 199 | Vector3 range; 200 | range.x = x + d * (qvn.x * cos(v) + ww.x * sin(v)); 201 | range.y = y + d * (qvn.y * cos(v) + ww.y * sin(v)); 202 | range.z = z + d * ww.z * sin(v); 203 | return range; 204 | } 205 | 206 | static MeshPod CreateTrefoil() 207 | { 208 | const int Slices = 256; 209 | const int Stacks = 32; 210 | const int VertexCount = Slices * Stacks; 211 | const int IndexCount = VertexCount * 6; 212 | 213 | MeshPod mesh; 214 | glGenVertexArrays(1, &mesh.Vao); 215 | glBindVertexArray(mesh.Vao); 216 | 217 | // Create a buffer with interleaved positions and normals 218 | if (1) { 219 | Vertex verts[VertexCount]; 220 | Vertex* pVert = &verts[0]; 221 | float ds = 1.0f / Slices; 222 | float dt = 1.0f / Stacks; 223 | 224 | // The upper bounds in these loops are tweaked to reduce the 225 | // chance of precision error causing an incorrect # of iterations. 226 | for (float s = 0; s < 1 - ds / 2; s += ds) { 227 | for (float t = 0; t < 1 - dt / 2; t += dt) { 228 | const float E = 0.01f; 229 | Vector3 p = EvaluateTrefoil(s, t); 230 | Vector3 u = V3Sub(EvaluateTrefoil(s + E, t), p); 231 | Vector3 v = V3Sub(EvaluateTrefoil(s, t + E), p); 232 | Vector3 n = V3Normalize(V3Cross(u, v)); 233 | pVert->Position = p; 234 | pVert->Normal = n; 235 | ++pVert; 236 | } 237 | } 238 | 239 | pezCheck(pVert - &verts[0] == VertexCount, "Tessellation error."); 240 | 241 | GLuint vbo; 242 | GLsizeiptr size = sizeof(verts); 243 | const GLvoid* data = &verts[0].Position.x; 244 | GLenum usage = GL_STATIC_DRAW; 245 | glGenBuffers(1, &vbo); 246 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 247 | glBufferData(GL_ARRAY_BUFFER, size, data, usage); 248 | } 249 | 250 | // Create a buffer of 16-bit indices 251 | if (1) { 252 | GLushort inds[IndexCount]; 253 | GLushort* pIndex = &inds[0]; 254 | GLushort n = 0; 255 | for (GLushort i = 0; i < Slices; i++) { 256 | for (GLushort j = 0; j < Stacks; j++) { 257 | *pIndex++ = (n + j + Stacks) % VertexCount; 258 | *pIndex++ = n + (j + 1) % Stacks; 259 | *pIndex++ = n + j; 260 | 261 | *pIndex++ = (n + (j + 1) % Stacks + Stacks) % VertexCount; 262 | *pIndex++ = (n + (j + 1) % Stacks) % VertexCount; 263 | *pIndex++ = (n + j + Stacks) % VertexCount; 264 | } 265 | n += Stacks; 266 | } 267 | 268 | pezCheck(n == VertexCount, "Tessellation error."); 269 | pezCheck(pIndex - &inds[0] == IndexCount, "Tessellation error."); 270 | 271 | GLuint handle; 272 | GLsizeiptr size = sizeof(inds); 273 | const GLvoid* data = &inds[0]; 274 | GLenum usage = GL_STATIC_DRAW; 275 | glGenBuffers(1, &handle); 276 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle); 277 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, usage); 278 | } 279 | 280 | mesh.VertexCount = VertexCount; 281 | mesh.IndexCount = IndexCount; 282 | 283 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, 24, 0); 284 | glVertexAttribPointer(a("Normal"), 3, GL_FLOAT, GL_FALSE, 24, offset(12)); 285 | glEnableVertexAttribArray(a("Position")); 286 | glEnableVertexAttribArray(a("Normal")); 287 | 288 | return mesh; 289 | } 290 | -------------------------------------------------------------------------------- /demo-ToonShading.glsl: -------------------------------------------------------------------------------- 1 | 2 | -- Lit.VS 3 | 4 | in vec4 Position; 5 | in vec3 Normal; 6 | 7 | out vec3 vPosition; 8 | out vec3 vNormal; 9 | 10 | uniform mat4 Projection; 11 | uniform mat4 Modelview; 12 | uniform mat4 ViewMatrix; 13 | uniform mat4 ModelMatrix; 14 | uniform mat3 NormalMatrix; 15 | 16 | void main() 17 | { 18 | vPosition = Position.xyz; 19 | gl_Position = Projection * Modelview * Position; 20 | vNormal = NormalMatrix * Normal; 21 | } 22 | 23 | -- Lit.FS 24 | 25 | in vec3 vNormal; 26 | out vec4 FragColor; 27 | 28 | uniform vec3 LightPosition = vec3(0.25, 0.25, 1.0); 29 | uniform vec3 AmbientMaterial = vec3(0.04, 0.04, 0.04); 30 | uniform vec3 SpecularMaterial = vec3(0.5, 0.5, 0.5); 31 | uniform vec3 FrontMaterial = vec3(0.75, 0.75, 0.5); 32 | uniform vec3 BackMaterial = vec3(0.5, 0.5, 0.75); 33 | uniform float Shininess = 50; 34 | 35 | const float A = 0.1; 36 | const float B = 0.3; 37 | const float C = 0.6; 38 | const float D = 1.0; 39 | 40 | void main() 41 | { 42 | vec3 N = normalize(vNormal); 43 | if (!gl_FrontFacing) 44 | N = -N; 45 | 46 | vec3 L = normalize(LightPosition); 47 | vec3 Eye = vec3(0, 0, 1); 48 | vec3 H = normalize(L + Eye); 49 | 50 | float df = max(0.0, dot(N, L)); 51 | float E = fwidth(df); 52 | if (df > A - E && df < A + E) 53 | df = mix(A, B, smoothstep(A - E, A + E, df)); 54 | else if (df > B - E && df < B + E) 55 | df = mix(B, C, smoothstep(B - E, B + E, df)); 56 | else if (df > C - E && df < C + E) 57 | df = mix(C, D, smoothstep(C - E, C + E, df)); 58 | else if (df < A) df = 0.0; 59 | else if (df < B) df = B; 60 | else if (df < C) df = C; 61 | else df = D; 62 | 63 | float sf = max(0.0, dot(N, H)); 64 | sf = pow(sf, Shininess); 65 | E = fwidth(sf); 66 | if (sf > 0.5 - E && sf < 0.5 + E) 67 | sf = clamp(0.5 * (sf - 0.5 + E) / E, 0.0, 1.0); 68 | else 69 | sf = step(0.5, sf); 70 | 71 | vec3 color = gl_FrontFacing ? FrontMaterial : BackMaterial; 72 | vec3 lighting = AmbientMaterial + df * color; 73 | if (gl_FrontFacing) 74 | lighting += sf * SpecularMaterial; 75 | 76 | FragColor = vec4(lighting, 1); 77 | } 78 | -------------------------------------------------------------------------------- /demo-VoronoiPicking.c: -------------------------------------------------------------------------------- 1 | // Voronoi Picking OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include 6 | #include 7 | #include "pez.h" 8 | #include "vmath.h" 9 | 10 | struct { 11 | int VertexCount; 12 | bool IsDragging; 13 | float Theta; 14 | Matrix4 Projection; 15 | Matrix4 OrthoMatrix; 16 | Matrix4 Modelview; 17 | Matrix4 ViewMatrix; 18 | Matrix4 ModelMatrix; 19 | Vector3 Mouse; 20 | GLuint PointProgram; 21 | GLuint QuadProgram; 22 | GLuint SpriteProgram; 23 | GLuint QuadVao; 24 | GLuint CloudVao; 25 | GLuint SinglePointVao; 26 | GLuint OffscreenFbo, ColorTexture, IdTexture; 27 | } Globals; 28 | 29 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey); 30 | static GLuint CurrentProgram(); 31 | static GLuint CreateSinglePoint(); 32 | static void ModifySinglePoint(GLuint vao, Vector3 v); 33 | static GLuint CreatePointCloud(float radius, int count); 34 | static GLuint CreateRenderTarget(GLuint* colorTexture, GLuint* idTexture); 35 | static GLuint CreateQuad(int sourceWidth, int sourceHeight, int destWidth, int destHeight); 36 | 37 | #define u(x) glGetUniformLocation(CurrentProgram(), x) 38 | #define a(x) glGetAttribLocation(CurrentProgram(), x) 39 | #define offset(x) ((const GLvoid*)x) 40 | 41 | PezConfig PezGetConfig() 42 | { 43 | PezConfig config; 44 | config.Title = __FILE__; 45 | config.Width = 853; 46 | config.Height = 480; 47 | config.Multisampling = false; 48 | config.VerticalSync = true; 49 | return config; 50 | } 51 | 52 | void PezInitialize() 53 | { 54 | const float ViewHeight = 5.0f; 55 | const float ViewNear = 65, ViewFar = 90; 56 | const PezConfig cfg = PezGetConfig(); 57 | 58 | // Compile shaders 59 | Globals.QuadProgram = LoadProgram("Quad.VS", 0, "Quad.FS"); 60 | Globals.SpriteProgram = LoadProgram("VS", "Sprite.GS", "Sprite.FS"); 61 | Globals.PointProgram = LoadProgram("VS", 0, "Point.FS"); 62 | 63 | // Set up viewport 64 | const float w = ViewHeight * cfg.Width / cfg.Height; 65 | Globals.Projection = M4MakeFrustum(-w, w, 66 | -ViewHeight, ViewHeight, 67 | ViewNear, ViewFar); 68 | Globals.OrthoMatrix = M4MakeOrthographic(0, cfg.Width, cfg.Height, 0, 0, 1); 69 | 70 | // Create geometry 71 | Globals.SinglePointVao = CreateSinglePoint(); 72 | Globals.QuadVao = CreateQuad(cfg.Width, cfg.Height, cfg.Width, cfg.Height); 73 | Globals.CloudVao = CreatePointCloud(5.0f, 400); 74 | Globals.OffscreenFbo = CreateRenderTarget(&Globals.ColorTexture, &Globals.IdTexture); 75 | 76 | // Misc Initialization 77 | Globals.IsDragging = false; 78 | Globals.Theta = 0; 79 | Globals.Mouse.z = -1; 80 | glClearColor(0.5f, 0.6f, 0.7f, 1.0f); 81 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 82 | } 83 | 84 | void PezUpdate(float seconds) 85 | { 86 | const float RadiansPerSecond = 0.5f; 87 | Globals.Theta += seconds * RadiansPerSecond; 88 | 89 | // Create the model-view matrix: 90 | Globals.ModelMatrix = M4MakeRotationZ(Globals.Theta); 91 | Point3 eye = {0, -75, 25}; 92 | Point3 target = {0, 0, 0}; 93 | Vector3 up = {0, 1, 0}; 94 | Globals.ViewMatrix = M4MakeLookAt(eye, target, up); 95 | Globals.Modelview = M4Mul(Globals.ViewMatrix, Globals.ModelMatrix); 96 | } 97 | 98 | void PezRender() 99 | { 100 | float* pModel = (float*) &Globals.ModelMatrix; 101 | float* pView = (float*) &Globals.ViewMatrix; 102 | float* pModelview = (float*) &Globals.Modelview; 103 | float* pProjection = (float*) &Globals.Projection; 104 | 105 | glUseProgram(Globals.PointProgram); 106 | glBindVertexArray(Globals.CloudVao); 107 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 108 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 109 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 110 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 111 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 112 | glEnable(GL_DEPTH_TEST); 113 | glDrawArrays(GL_POINTS, 0, Globals.VertexCount); 114 | 115 | const float w = PezGetConfig().Width; 116 | const float h = PezGetConfig().Height; 117 | const float s = 64; 118 | 119 | glClear(GL_DEPTH_BUFFER_BIT); 120 | 121 | if (Globals.IsDragging) { 122 | glUseProgram(Globals.SpriteProgram); 123 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pView); 124 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pModel); 125 | glUniformMatrix4fv(u("Modelview"), 1, 0, pModelview); 126 | glUniformMatrix4fv(u("Projection"), 1, 0, pProjection); 127 | glUniform1i(u("Nailboard"), GL_TRUE); 128 | glUniform2f(u("SpriteSize"), s, s); 129 | glUniform2f(u("HalfViewport"), w / 2.0f, h / 2.0f); 130 | glUniform2f(u("InverseViewport"), 1.0f / w, 1.0f / h); 131 | glEnable(GL_BLEND); 132 | glDrawArrays(GL_POINTS, 0, Globals.VertexCount); 133 | glDisable(GL_BLEND); 134 | } 135 | 136 | if (Globals.Mouse.z < 0) { 137 | return; 138 | } 139 | 140 | glUseProgram(Globals.SpriteProgram); 141 | 142 | float x = Globals.Mouse.x; 143 | float y = Globals.Mouse.y; 144 | float z = 0; 145 | Vector3 p = {x, y, z}; 146 | ModifySinglePoint(Globals.SinglePointVao, p); 147 | 148 | Matrix4 i = M4MakeIdentity(); 149 | float* pIdentity = (float*) &i; 150 | float* pOrtho = (float*) &Globals.OrthoMatrix; 151 | 152 | glBindVertexArray(Globals.SinglePointVao); 153 | glUniformMatrix4fv(u("ViewMatrix"), 1, 0, pIdentity); 154 | glUniformMatrix4fv(u("ModelMatrix"), 1, 0, pIdentity); 155 | glUniformMatrix4fv(u("Modelview"), 1, 0, pIdentity); 156 | glUniformMatrix4fv(u("Projection"), 1, 0, pOrtho); 157 | glUniform1i(u("Nailboard"), GL_FALSE); 158 | glUniform2f(u("SpriteSize"), 32, 32); 159 | glUniform2f(u("HalfViewport"), w / 2.0f, h / 2.0f); 160 | glUniform2f(u("InverseViewport"), 1.0f / w, 1.0f / h); 161 | glDisable(GL_DEPTH_TEST); 162 | glEnable(GL_BLEND); 163 | glDrawArrays(GL_POINTS, 0, 1); 164 | glDisable(GL_BLEND); 165 | } 166 | 167 | void PezHandleMouse(int x, int y, int action) 168 | { 169 | Globals.Mouse.x = x; 170 | Globals.Mouse.y = y; 171 | Globals.Mouse.z = action; 172 | 173 | if (action == PEZ_DOWN) { 174 | Globals.IsDragging = true; 175 | } else if (action == PEZ_UP) { 176 | Globals.IsDragging = false; 177 | } 178 | } 179 | 180 | static GLuint CurrentProgram() 181 | { 182 | GLuint p; 183 | glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*) &p); 184 | return p; 185 | } 186 | 187 | static GLuint LoadProgram(const char* vsKey, const char* gsKey, const char* fsKey) 188 | { 189 | GLchar spew[256]; 190 | GLint compileSuccess; 191 | GLuint programHandle = glCreateProgram(); 192 | 193 | const char* vsSource = pezGetShader(vsKey); 194 | pezCheck(vsSource != 0, "Can't find vshader: %s\n", vsKey); 195 | GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER); 196 | glShaderSource(vsHandle, 1, &vsSource, 0); 197 | glCompileShader(vsHandle); 198 | glGetShaderiv(vsHandle, GL_COMPILE_STATUS, &compileSuccess); 199 | glGetShaderInfoLog(vsHandle, sizeof(spew), 0, spew); 200 | pezCheck(compileSuccess, "Can't compile vshader:\n%s", spew); 201 | glAttachShader(programHandle, vsHandle); 202 | 203 | if (gsKey) { 204 | const char* gsSource = pezGetShader(gsKey); 205 | pezCheck(gsSource != 0, "Can't find gshader: %s\n", gsKey); 206 | GLuint gsHandle = glCreateShader(GL_GEOMETRY_SHADER); 207 | glShaderSource(gsHandle, 1, &gsSource, 0); 208 | glCompileShader(gsHandle); 209 | glGetShaderiv(gsHandle, GL_COMPILE_STATUS, &compileSuccess); 210 | glGetShaderInfoLog(gsHandle, sizeof(spew), 0, spew); 211 | pezCheck(compileSuccess, "Can't compile gshader:\n%s", spew); 212 | glAttachShader(programHandle, gsHandle); 213 | } 214 | 215 | const char* fsSource = pezGetShader(fsKey); 216 | pezCheck(fsSource != 0, "Can't find fshader: %s\n", fsKey); 217 | GLuint fsHandle = glCreateShader(GL_FRAGMENT_SHADER); 218 | glShaderSource(fsHandle, 1, &fsSource, 0); 219 | glCompileShader(fsHandle); 220 | glGetShaderiv(fsHandle, GL_COMPILE_STATUS, &compileSuccess); 221 | glGetShaderInfoLog(fsHandle, sizeof(spew), 0, spew); 222 | pezCheck(compileSuccess, "Can't compile fshader:\n%s", spew); 223 | glAttachShader(programHandle, fsHandle); 224 | 225 | glLinkProgram(programHandle); 226 | GLint linkSuccess; 227 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 228 | glGetProgramInfoLog(programHandle, sizeof(spew), 0, spew); 229 | pezCheck(linkSuccess, "Can't link shaders:\n%s", spew); 230 | glUseProgram(programHandle); 231 | return programHandle; 232 | } 233 | 234 | static GLuint CreateSinglePoint() 235 | { 236 | GLuint vao; 237 | glGenVertexArrays(1, &vao); 238 | glBindVertexArray(vao); 239 | 240 | Vector3 v = {0, 0, 0}; 241 | GLsizeiptr size = sizeof(v); 242 | 243 | GLuint handle; 244 | glGenBuffers(1, &handle); 245 | glBindBuffer(GL_ARRAY_BUFFER, handle); 246 | glBufferData(GL_ARRAY_BUFFER, size, &v.x, GL_STATIC_DRAW); 247 | glEnableVertexAttribArray(a("Position")); 248 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, 249 | size, 0); 250 | 251 | return vao; 252 | } 253 | 254 | static void ModifySinglePoint(GLuint vao, Vector3 v) 255 | { 256 | glBindVertexArray(vao); 257 | 258 | GLuint handle; 259 | glGetVertexAttribiv(a("Position"), GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint*) &handle); 260 | glBindBuffer(GL_ARRAY_BUFFER, handle); 261 | 262 | GLsizeiptr size = sizeof(v); 263 | glBufferData(GL_ARRAY_BUFFER, size, &v.x, GL_STATIC_DRAW); 264 | } 265 | 266 | static GLuint CreatePointCloud(float r, int pointCount) 267 | { 268 | GLuint vao; 269 | glGenVertexArrays(1, &vao); 270 | glBindVertexArray(vao); 271 | 272 | Globals.VertexCount = pointCount; 273 | int vertexStride = sizeof(float) * 3; 274 | GLsizeiptr size = Globals.VertexCount * vertexStride; 275 | GLfloat* positions = (GLfloat*) malloc(size); 276 | 277 | GLfloat* position = positions; 278 | for (int slice = 0; slice < pointCount; slice++) { 279 | float x = r - 2 * r * rand() / RAND_MAX; 280 | float y = r - 2 * r * rand() / RAND_MAX; 281 | float z = r - 2 * r * rand() / RAND_MAX; 282 | if (x*x+y*y+z*z > r*r) { 283 | slice--; 284 | continue; 285 | } 286 | *position++ = x; 287 | *position++ = y; 288 | *position++ = z; 289 | } 290 | 291 | GLuint handle; 292 | glGenBuffers(1, &handle); 293 | glBindBuffer(GL_ARRAY_BUFFER, handle); 294 | glBufferData(GL_ARRAY_BUFFER, size, positions, GL_STATIC_DRAW); 295 | glEnableVertexAttribArray(a("Position")); 296 | glVertexAttribPointer(a("Position"), 3, GL_FLOAT, GL_FALSE, 297 | vertexStride, 0); 298 | 299 | free(positions); 300 | return vao; 301 | } 302 | 303 | static GLuint CreateRenderTarget(GLuint* colorTexture, GLuint* idTexture) 304 | { 305 | PezConfig cfg = PezGetConfig(); 306 | 307 | glGenTextures(1, colorTexture); 308 | glBindTexture(GL_TEXTURE_2D, *colorTexture); 309 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 310 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 311 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 312 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 313 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, cfg.Width, cfg.Height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 314 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to create color texture."); 315 | 316 | glGenTextures(1, idTexture); 317 | glBindTexture(GL_TEXTURE_2D, *idTexture); 318 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 319 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 320 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 321 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 322 | glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, cfg.Width, cfg.Height, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, 0); 323 | pezCheck(GL_NO_ERROR == glGetError(), "Unable to create id texture."); 324 | 325 | GLuint fboHandle; 326 | glGenFramebuffers(1, &fboHandle); 327 | glBindFramebuffer(GL_FRAMEBUFFER, fboHandle); 328 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *colorTexture, 0); 329 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, *idTexture, 0); 330 | 331 | GLuint depthBuffer; 332 | glGenRenderbuffers(1, &depthBuffer); 333 | glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); 334 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, cfg.Width, cfg.Height); 335 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer); 336 | 337 | pezCheck(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER), "Invalid FBO."); 338 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 339 | return fboHandle; 340 | } 341 | 342 | static GLuint CreateQuad(int sourceWidth, int sourceHeight, int destWidth, int destHeight) 343 | { 344 | // Stretch to fit: 345 | float q[] = { 346 | -1, -1, 0, 1, 347 | +1, -1, 1, 1, 348 | -1, +1, 0, 0, 349 | +1, +1, 1, 0 }; 350 | 351 | if (sourceHeight < 0) { 352 | sourceHeight = -sourceHeight; 353 | q[3] = 1-q[3]; 354 | q[7] = 1-q[7]; 355 | q[11] = 1-q[11]; 356 | q[15] = 1-q[15]; 357 | } 358 | 359 | float sourceRatio = (float) sourceWidth / sourceHeight; 360 | float destRatio = (float) destWidth / destHeight; 361 | 362 | // Horizontal fit: 363 | if (sourceRatio > destRatio) { 364 | q[1] = q[5] = -destRatio / sourceRatio; 365 | q[9] = q[13] = destRatio / sourceRatio; 366 | 367 | // Vertical fit: 368 | } else { 369 | q[0] = q[8] = -sourceRatio / destRatio; 370 | q[4] = q[12] = sourceRatio / destRatio; 371 | } 372 | 373 | GLuint vbo, vao; 374 | 375 | glUseProgram(Globals.QuadProgram); 376 | glGenVertexArrays(1, &vao); 377 | glBindVertexArray(vao); 378 | glGenBuffers(1, &vbo); 379 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 380 | glBufferData(GL_ARRAY_BUFFER, sizeof(q), q, GL_STATIC_DRAW); 381 | glVertexAttribPointer(a("Position"), 2, GL_FLOAT, GL_FALSE, 16, 0); 382 | glVertexAttribPointer(a("TexCoord"), 2, GL_FLOAT, GL_FALSE, 16, offset(8)); 383 | glEnableVertexAttribArray(a("Position")); 384 | glEnableVertexAttribArray(a("TexCoord")); 385 | 386 | return vao; 387 | } 388 | -------------------------------------------------------------------------------- /demo-VoronoiPicking.glsl: -------------------------------------------------------------------------------- 1 | -- Quad.VS 2 | 3 | in vec2 Position; 4 | in vec2 TexCoord; 5 | out vec2 vTexCoord; 6 | 7 | void main() 8 | { 9 | vTexCoord = TexCoord; 10 | gl_Position = vec4(Position, 0, 1); 11 | } 12 | 13 | -- Quad.FS 14 | 15 | in vec2 vTexCoord; 16 | out vec4 FragColor; 17 | uniform sampler2D Sampler; 18 | 19 | void main() 20 | { 21 | FragColor = texture(Sampler, vTexCoord); 22 | } 23 | 24 | -- VS 25 | 26 | in vec4 Position; 27 | out vec3 vPosition; 28 | out int vId; 29 | 30 | uniform mat4 Projection; 31 | uniform mat4 Modelview; 32 | uniform mat4 ViewMatrix; 33 | uniform mat4 ModelMatrix; 34 | 35 | void main() 36 | { 37 | vPosition = Position.xyz; 38 | vId = gl_VertexID; 39 | gl_Position = Projection * Modelview * Position; 40 | } 41 | 42 | ------------------------ 43 | 44 | ------------------------ 45 | 46 | -- Point.FS 47 | 48 | out vec4 FragColor; 49 | 50 | void main() 51 | { 52 | FragColor = vec4(0, 0, 0, 1); 53 | } 54 | 55 | ---------------------------------- 56 | ____ _ _ 57 | / ___| _ __ _ __ (_)| |_ ___ 58 | \___ \ | '_ \ | '__|| || __|/ _ \ 59 | ___) || |_) || | | || |_| __/ 60 | |____/ | .__/ |_| |_| \__|\___| 61 | |_| 62 | ----------------------------------- 63 | 64 | -- Sprite.GS 65 | 66 | layout(points) in; 67 | layout(triangle_strip, max_vertices = 4) out; 68 | uniform bool Nailboard; 69 | uniform vec2 SpriteSize; 70 | in int vId[1]; 71 | flat out int gId; 72 | out vec2 gCenterCoord; 73 | uniform vec2 HalfViewport; 74 | uniform vec2 InverseViewport; 75 | 76 | vec2 toFragCoord(vec4 v) 77 | { 78 | return HalfViewport * (1.0 + v.xy / v.w); 79 | } 80 | 81 | void main() 82 | { 83 | vec4 P = gl_in[0].gl_Position; 84 | vec4 U = vec4(SpriteSize.x, 0, 0, 0) * InverseViewport.x; 85 | vec4 V = vec4(0, SpriteSize.y, 0, 0) * InverseViewport.y; 86 | gId = vId[0]; 87 | gCenterCoord = toFragCoord(P); 88 | 89 | P.z = 0; 90 | P.xy /= P.w; 91 | P.w = 1; 92 | 93 | gl_Position = P - U - V; EmitVertex(); 94 | gl_Position = P + U - V; EmitVertex(); 95 | gl_Position = P - U + V; EmitVertex(); 96 | gl_Position = P + U + V; EmitVertex(); 97 | EndPrimitive(); 98 | } 99 | 100 | -- Sprite.FS 101 | 102 | flat in int gId; 103 | out vec4 FragColor; 104 | in vec2 gCenterCoord; 105 | uniform bool Nailboard; 106 | uniform vec2 SpriteSize; 107 | 108 | vec3 colorFromIndex(int i) 109 | { 110 | int r = i & 1; 111 | int g = i & 2; 112 | int b = i & 4; 113 | float x = (r == 0) ? 1.0 : 0.0; 114 | float y = (g == 0) ? 1.0 : 0.0; 115 | float z = (b == 0) ? 1.0 : 0.0; 116 | return vec3(x, y, z); 117 | } 118 | 119 | void main() 120 | { 121 | float L = distance(gl_FragCoord.xy, gCenterCoord); 122 | float D = 2.0 * L / SpriteSize.x; 123 | if (Nailboard) { 124 | 125 | // Draw a billboard with cone-shaped depth 126 | FragColor.rgb = colorFromIndex(gId); 127 | FragColor.rgb *= 1 - D; 128 | FragColor.a = 1; 129 | gl_FragDepth = D; 130 | 131 | } else { 132 | 133 | // Draw a circular mouse cursor 134 | float t = 0.125; // Border thickness 135 | float r = 0.75; // Inner radius 136 | float w = fwidth(D); // Antialiasing constant 137 | if (D < r - t) { 138 | float A = 1.0 - smoothstep(r-t-w, r-t, D); 139 | FragColor = vec4(A, A, A, 1); 140 | } else if (D < r + t) { 141 | FragColor = vec4(0, 0, 0, 1); 142 | } else { 143 | float A = 1.0 - smoothstep(r+t, r+t+w, D); 144 | FragColor = vec4(0, 0, 0, A); 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /dev-FresnelGlass.c: -------------------------------------------------------------------------------- 1 | // Fresnel Glass OpenGL Demo by Philip Rideout 2 | // Licensed under the Creative Commons Attribution 3.0 Unported License. 3 | // http://creativecommons.org/licenses/by/3.0/ 4 | 5 | #include "Platform.h" 6 | #include "Utility.h" 7 | #include 8 | #include 9 | 10 | //#define LIGHTING 11 | 12 | static GLuint DepthProgram; 13 | static GLuint AbsorptionProgram; 14 | static Matrix4 ProjectionMatrix; 15 | static Matrix4 ModelviewMatrix; 16 | static GLuint OffscreenFbo; 17 | static GLuint OffscreenTexture; 18 | static Mesh BuddhaMesh; 19 | static GLuint QuadVbo; 20 | 21 | static void LoadUniforms(GLuint program) 22 | { 23 | GLint modelview = glGetUniformLocation(program, "Modelview"); 24 | if (modelview > -1) 25 | { 26 | glUniformMatrix4fv(modelview, 1, 0, &ModelviewMatrix.col0.x); 27 | } 28 | 29 | GLint normalMatrix = glGetUniformLocation(program, "NormalMatrix"); 30 | if (normalMatrix > -1) 31 | { 32 | Matrix3 nm = M3Transpose(M4GetUpper3x3(ModelviewMatrix)); 33 | float packed[9] = { 34 | nm.col0.x, nm.col1.x, nm.col2.x, 35 | nm.col0.y, nm.col1.y, nm.col2.y, 36 | nm.col0.z, nm.col1.z, nm.col2.z }; 37 | glUniformMatrix3fv(normalMatrix, 1, 0, &packed[0]); 38 | } 39 | 40 | GLint projection = glGetUniformLocation(program, "Projection"); 41 | if (projection > -1) 42 | { 43 | glUniformMatrix4fv(projection, 1, 0, &ProjectionMatrix.col0.x); 44 | } 45 | 46 | GLint size = glGetUniformLocation(program, "Size"); 47 | if (size > -1) 48 | { 49 | glUniform2f(size, PEZ_VIEWPORT_WIDTH, PEZ_VIEWPORT_HEIGHT); 50 | } 51 | 52 | GLint diffuseMaterial = glGetUniformLocation(program, "DiffuseMaterial"); 53 | if (diffuseMaterial > -1) 54 | { 55 | glUniform3f(diffuseMaterial, 0, 0.75, 0.75); 56 | } 57 | 58 | GLint ambientMaterial = glGetUniformLocation(program, "AmbientMaterial"); 59 | if (ambientMaterial > -1) 60 | { 61 | glUniform3f(ambientMaterial, 0.04f, 0.04f, 0.04f); 62 | } 63 | 64 | GLint specularMaterial = glGetUniformLocation(program, "SpecularMaterial"); 65 | if (specularMaterial > -1) 66 | { 67 | glUniform3f(specularMaterial, 0.5f, 0.5f, 0.5f); 68 | } 69 | 70 | GLint shininess = glGetUniformLocation(program, "Shininess"); 71 | if (shininess > -1) 72 | { 73 | glUniform1f(shininess, 50); 74 | } 75 | 76 | GLint lightPosition = glGetUniformLocation(program, "LightPosition"); 77 | if (lightPosition > -1) 78 | { 79 | glUniform3f(lightPosition, 0.25, 0.25, 1); 80 | } 81 | } 82 | 83 | static void RenderBuddha() 84 | { 85 | glUseProgram(DepthProgram); 86 | LoadUniforms(DepthProgram); 87 | 88 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BuddhaMesh.Faces); 89 | 90 | glBindBuffer(GL_ARRAY_BUFFER, BuddhaMesh.Positions); 91 | int positionSlot = glGetAttribLocation(DepthProgram, "Position"); 92 | glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0); 93 | glEnableVertexAttribArray(positionSlot); 94 | 95 | glBindBuffer(GL_ARRAY_BUFFER, BuddhaMesh.Normals); 96 | int normalSlot = glGetAttribLocation(DepthProgram, "Normal"); 97 | glVertexAttribPointer(normalSlot, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0); 98 | glEnableVertexAttribArray(normalSlot); 99 | 100 | #ifdef LIGHTING 101 | glDisable(GL_CULL_FACE); 102 | glClear(GL_DEPTH_BUFFER_BIT); 103 | glEnable(GL_DEPTH_TEST); 104 | glDisable(GL_BLEND); 105 | glDrawElements(GL_TRIANGLES, BuddhaMesh.FaceCount * 3, GL_UNSIGNED_SHORT, 0); 106 | #else 107 | glEnable(GL_CULL_FACE); 108 | glEnable(GL_BLEND); 109 | glBlendFunc(GL_ONE, GL_ONE); 110 | GLint depthScale = glGetUniformLocation(DepthProgram, "DepthScale"); 111 | 112 | glUniform1f(depthScale, 1.0f); 113 | glCullFace(GL_FRONT); 114 | glDrawElements(GL_TRIANGLES, BuddhaMesh.FaceCount * 3, GL_UNSIGNED_SHORT, 0); 115 | 116 | glUniform1f(depthScale, -1.0f); 117 | glCullFace(GL_BACK); 118 | glDrawElements(GL_TRIANGLES, BuddhaMesh.FaceCount * 3, GL_UNSIGNED_SHORT, 0); 119 | #endif 120 | 121 | glDisable(GL_CULL_FACE); 122 | glDisable(GL_BLEND); 123 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 124 | glBindBuffer(GL_ARRAY_BUFFER, 0); 125 | glDisableVertexAttribArray(positionSlot); 126 | glDisableVertexAttribArray(normalSlot); 127 | 128 | #ifdef LIGHTING 129 | glDisable(GL_DEPTH_TEST); 130 | #endif 131 | } 132 | 133 | static void RenderQuad() 134 | { 135 | glUseProgram(AbsorptionProgram); 136 | LoadUniforms(AbsorptionProgram); 137 | 138 | glBindBuffer(GL_ARRAY_BUFFER, QuadVbo); 139 | int positionSlot = glGetAttribLocation(AbsorptionProgram, "Position"); 140 | glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0); 141 | glEnableVertexAttribArray(positionSlot); 142 | 143 | glBindTexture(GL_TEXTURE_2D, OffscreenTexture); 144 | glDrawArrays(GL_TRIANGLES, 0, 6); 145 | glBindTexture(GL_TEXTURE_2D, 0); 146 | 147 | glBindBuffer(GL_ARRAY_BUFFER, 0); 148 | glDisableVertexAttribArray(positionSlot); 149 | } 150 | 151 | void PezRender(GLuint windowFbo) 152 | { 153 | glBindFramebuffer(GL_FRAMEBUFFER, OffscreenFbo); 154 | glClearColor(0, 0, 0, 0); 155 | glClear(GL_COLOR_BUFFER_BIT); 156 | RenderBuddha(); 157 | 158 | glBindFramebuffer(GL_FRAMEBUFFER, windowFbo); 159 | glClearColor(1, 1, 1, 1); 160 | glClear(GL_COLOR_BUFFER_BIT); 161 | RenderQuad(); 162 | } 163 | 164 | const char* PezInitialize(int width, int height) 165 | { 166 | BuddhaMesh = CreateMesh("buddha.ctm"); 167 | QuadVbo = CreateQuad(-1, -1, 1, 1); 168 | 169 | #ifdef LIGHTING 170 | DepthProgram = CreateProgram("Glass.Vertex", "Glass.Fragment.Lighting" SUFFIX); 171 | AbsorptionProgram = CreateProgram("Glass.Vertex.Quad", "Glass.Fragment.Blit" SUFFIX); 172 | #else 173 | DepthProgram = CreateProgram("Glass.Vertex", "Glass.Fragment.Depth" SUFFIX); 174 | AbsorptionProgram = CreateProgram("Glass.Vertex.Quad", "Glass.Fragment.Absorption" SUFFIX); 175 | #endif 176 | 177 | // Create a floating-point render target: 178 | GLuint textureHandle; 179 | glGenTextures(1, &textureHandle); 180 | glBindTexture(GL_TEXTURE_2D, textureHandle); 181 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 182 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 183 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 184 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 185 | 186 | #ifdef LIGHTING 187 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 768, 1024, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 188 | #elif defined(__IPAD__) 189 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 768, 1024, 0, GL_LUMINANCE, GL_HALF_FLOAT_OES, 0); 190 | #else 191 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 768, 1024, 0, GL_RG, GL_FLOAT, 0); 192 | #endif 193 | 194 | PezCheckCondition(GL_NO_ERROR == glGetError(), "This passes on Mac OS X and iOS."); 195 | OffscreenTexture = textureHandle; 196 | 197 | GLuint fboHandle; 198 | glGenFramebuffers(1, &fboHandle); 199 | glBindFramebuffer(GL_FRAMEBUFFER, fboHandle); 200 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureHandle, 0); 201 | 202 | #ifdef LIGHTING 203 | GLuint depthRenderbuffer; 204 | glGenRenderbuffers(1, &depthRenderbuffer); 205 | glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); 206 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); 207 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); 208 | #endif 209 | 210 | PezCheckCondition(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER), "This asserts on iOS and passes on Mac OS X."); 211 | OffscreenFbo = fboHandle; 212 | 213 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 214 | glBindRenderbuffer(GL_RENDERBUFFER, 0); 215 | 216 | // Set up the projection matrix: 217 | const float HalfWidth = 0.5; 218 | const float HalfHeight = HalfWidth * PEZ_VIEWPORT_HEIGHT / PEZ_VIEWPORT_WIDTH; 219 | ProjectionMatrix = M4MakeFrustum(-HalfWidth, +HalfWidth, -HalfHeight, +HalfHeight, 5, 20); 220 | 221 | return "Glass Demo"; 222 | } 223 | 224 | void PezUpdate(unsigned int elapsedMicroseconds) 225 | { 226 | const float RadiansPerMicrosecond = 0.0000005f; 227 | static float Theta = 0; 228 | Theta += elapsedMicroseconds * RadiansPerMicrosecond; 229 | 230 | Vector3 offset = V3MakeFromElems(0, 0, 0); 231 | Matrix4 model = M4MakeRotationZ(Theta); 232 | model = M4Mul(M4MakeTranslation(offset), model); 233 | model = M4Mul(model, M4MakeTranslation(V3Neg(offset))); 234 | 235 | Point3 eyePosition = P3MakeFromElems(0, 10, 0); 236 | Point3 targetPosition = P3MakeFromElems(0, 0, 0); 237 | Vector3 upVector = V3MakeFromElems(0, 0, 1); 238 | Matrix4 view = M4MakeLookAt(eyePosition, targetPosition, upVector); 239 | 240 | ModelviewMatrix = M4Mul(view, model); 241 | } 242 | 243 | void PezHandleMouse(int x, int y, int action) 244 | { 245 | if (action == PEZ_UP) 246 | { 247 | exit(0); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /dev-FresnelGlass.glsl: -------------------------------------------------------------------------------- 1 | 2 | -- Vertex 3 | 4 | attribute vec4 Position; 5 | attribute vec3 Normal; 6 | 7 | varying vec3 vNormal; 8 | varying vec3 vPosition; 9 | 10 | uniform mat4 Projection; 11 | uniform mat4 Modelview; 12 | uniform mat3 NormalMatrix; 13 | 14 | void main() 15 | { 16 | vPosition = (Modelview * Position).xyz; 17 | vNormal = NormalMatrix * Normal; 18 | gl_Position = Projection * Modelview * Position; 19 | } 20 | 21 | -- Vertex.Quad 22 | 23 | attribute vec4 Position; 24 | 25 | void main() 26 | { 27 | gl_Position = Position; 28 | } 29 | 30 | -- Fragment.Depth 31 | 32 | uniform float DepthScale; 33 | varying vec3 vNormal; 34 | varying vec3 vPosition; 35 | 36 | void main() 37 | { 38 | vec3 N = normalize(vNormal); 39 | vec3 P = vPosition; 40 | vec3 I = normalize(P); 41 | float cosTheta = abs(dot(I, N)); 42 | float fresnel = pow(1.0 - cosTheta, 4.0); 43 | 44 | float depth = DepthScale * gl_FragCoord.z; 45 | 46 | gl_FragColor = vec4(depth, fresnel, 0, 0); 47 | } 48 | 49 | -- Fragment.Depth.ES2 50 | 51 | uniform highp float DepthScale; 52 | varying highp vec3 vNormal; 53 | varying highp vec3 vPosition; 54 | 55 | void main() 56 | { 57 | highp vec3 N = normalize(vNormal); 58 | highp vec3 P = vPosition; 59 | highp vec3 I = normalize(P); 60 | highp float cosTheta = abs(dot(I, N)); 61 | highp float fresnel = pow(1.0 - cosTheta, 4.0); 62 | 63 | highp float depth = DepthScale * gl_FragCoord.z; 64 | 65 | gl_FragColor = vec4(depth, fresnel, 0, 0); 66 | } 67 | 68 | -- Fragment.Absorption 69 | 70 | uniform sampler2D Sampler; 71 | uniform vec2 Size; 72 | uniform vec3 DiffuseMaterial; 73 | 74 | void main() 75 | { 76 | vec2 texCoord = gl_FragCoord.xy / Size; 77 | float thickness = abs(texture2D(Sampler, texCoord).r); 78 | if (thickness <= 0.0) 79 | { 80 | discard; 81 | } 82 | float sigma = 30.0; 83 | float fresnel = 1.0 - texture2D(Sampler, texCoord).g; 84 | float intensity = fresnel * exp(-sigma * thickness); 85 | gl_FragColor = vec4(intensity * DiffuseMaterial, 1); 86 | } 87 | 88 | -- Fragment.Blit 89 | 90 | uniform sampler2D Sampler; 91 | uniform vec2 Size; 92 | 93 | void main() 94 | { 95 | vec2 texCoord = gl_FragCoord.xy / Size; 96 | gl_FragColor = texture2D(Sampler, texCoord); 97 | } 98 | 99 | -- Fragment.Blit.ES2 100 | 101 | precision highp float; 102 | 103 | uniform sampler2D Sampler; 104 | uniform vec2 Size; 105 | 106 | void main() 107 | { 108 | vec2 texCoord = gl_FragCoord.xy / Size; 109 | gl_FragColor = texture2D(Sampler, texCoord); 110 | } 111 | 112 | -- Fragment.Absorption.ES2 113 | 114 | uniform sampler2D Sampler; 115 | uniform highp vec2 Size; 116 | 117 | void main() 118 | { 119 | highp vec2 texCoord = gl_FragCoord.xy / Size; 120 | gl_FragColor = texture2D(Sampler, texCoord); 121 | } 122 | 123 | -- Fragment.Lighting 124 | 125 | varying vec3 vNormal; 126 | 127 | uniform vec3 LightPosition; 128 | uniform vec3 DiffuseMaterial; 129 | uniform vec3 AmbientMaterial; 130 | uniform vec3 SpecularMaterial; 131 | uniform float Shininess; 132 | 133 | void main() 134 | { 135 | vec3 N = normalize(vNormal); 136 | vec3 L = normalize(LightPosition); 137 | vec3 E = vec3(0, 0, 1); 138 | vec3 H = normalize(L + E); 139 | 140 | float df = max(0.0, dot(N, L)); 141 | float sf = max(0.0, dot(N, H)); 142 | sf = pow(sf, Shininess); 143 | vec3 color = AmbientMaterial + df * DiffuseMaterial + sf * SpecularMaterial; 144 | 145 | gl_FragColor = vec4(color, 1.0); 146 | } 147 | 148 | -- Fragment.Lighting.ES2 149 | 150 | precision highp float; 151 | 152 | varying vec3 vNormal; 153 | 154 | uniform vec3 LightPosition; 155 | uniform vec3 DiffuseMaterial; 156 | uniform vec3 AmbientMaterial; 157 | uniform vec3 SpecularMaterial; 158 | uniform float Shininess; 159 | 160 | void main() 161 | { 162 | vec3 N = normalize(vNormal); 163 | vec3 L = normalize(LightPosition); 164 | vec3 E = vec3(0, 0, 1); 165 | vec3 H = normalize(L + E); 166 | 167 | float df = max(0.0, dot(N, L)); 168 | float sf = max(0.0, dot(N, H)); 169 | sf = pow(sf, Shininess); 170 | vec3 color = AmbientMaterial + df * DiffuseMaterial + sf * SpecularMaterial; 171 | 172 | gl_FragColor = vec4(color, 1.0); 173 | } 174 | -------------------------------------------------------------------------------- /lavatile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/recipes/34a5f6fa4109be03e180bc6839cbc0253b0cacea/lavatile.png -------------------------------------------------------------------------------- /pez.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #define PEZ_MAINLOOP 1 8 | #define PEZ_MOUSE_HANDLER 1 9 | #define PEZ_DROP_HANDLER 1 10 | #define GL3_PROTOTYPES 11 | 12 | #include "gl3.h" 13 | #include 14 | 15 | #define PEZ_FORWARD_COMPATIBLE_GL 1 16 | 17 | typedef struct PezConfigRec 18 | { 19 | const char* Title; 20 | int Width; 21 | int Height; 22 | bool Multisampling; 23 | bool VerticalSync; 24 | } PezConfig; 25 | 26 | #ifdef PEZ_MAINLOOP 27 | PezConfig PezGetConfig(); 28 | void PezInitialize(); 29 | void PezRender(); 30 | void PezUpdate(float seconds); 31 | 32 | #ifdef PEZ_MOUSE_HANDLER 33 | void PezHandleMouse(int x, int y, int action); 34 | #endif 35 | 36 | #ifdef PEZ_DROP_HANDLER 37 | void PezReceiveDrop(const char* filename); 38 | #endif 39 | 40 | #else 41 | void pezSwapBuffers(); 42 | #endif 43 | 44 | enum {PEZ_DOWN, PEZ_UP, PEZ_MOVE, PEZ_DOUBLECLICK}; 45 | #define TwoPi (6.28318531f) 46 | #define Pi (3.14159265f) 47 | #define countof(A) (sizeof(A) / sizeof(A[0])) 48 | 49 | void pezPrintString(const char* pStr, ...); 50 | void pezFatal(const char* pStr, ...); 51 | void pezCheck(int condition, ...); 52 | void pezCheckPointer(void* p, ...); 53 | int pezIsPressing(char key); 54 | const char* pezResourcePath(); 55 | const char* pezOpenFileDialog(); 56 | const char* pezGetDesktopFolder(); 57 | const char* pezGetShader(const char* effectKey); 58 | 59 | typedef struct PezAttribRec { 60 | const GLchar* Name; 61 | GLint Size; 62 | GLenum Type; 63 | GLsizei Stride; 64 | int FrameCount; 65 | GLvoid* Frames; 66 | } PezAttrib; 67 | 68 | typedef struct PezVertsRec { 69 | int AttribCount; 70 | int IndexCount; 71 | int VertexCount; 72 | GLenum IndexType; 73 | GLsizeiptr IndexBufferSize; 74 | PezAttrib* Attribs; 75 | GLvoid* Indices; 76 | void* RawHeader; 77 | } PezVerts; 78 | 79 | typedef struct PezPixelsRec { 80 | int FrameCount; 81 | GLsizei Width; 82 | GLsizei Height; 83 | GLsizei Depth; 84 | GLint MipLevels; 85 | GLenum Format; 86 | GLenum InternalFormat; 87 | GLenum Type; 88 | GLsizeiptr BytesPerFrame; 89 | GLvoid* Frames; 90 | void* RawHeader; 91 | } PezPixels; 92 | 93 | PezVerts pezLoadVerts(const char* filename); 94 | PezVerts pezGenQuad(float left, float top, float right, float bottom); 95 | void pezFreeVerts(PezVerts verts); 96 | void pezSaveVerts(PezVerts verts, const char* filename); 97 | 98 | PezPixels pezLoadPixels(const char* filename); 99 | void pezFreePixels(PezPixels pixels); 100 | void pezSavePixels(PezPixels pixels, const char* filename); 101 | void pezRenderText(PezPixels pixels, const char* message); 102 | PezPixels pezGenNoise(PezPixels desc, float alpha, float beta, int n); 103 | 104 | // For internal use, to support pezGetShader: 105 | int pezSwInit(const char* keyPrefix); 106 | int pezSwShutdown(); 107 | int pezSwAddPath(const char* pathPrefix, const char* pathSuffix); 108 | const char* pezSwGetError(); 109 | int pezSwAddDirective(const char* token, const char* directive); 110 | 111 | #ifdef __cplusplus 112 | } 113 | #endif 114 | -------------------------------------------------------------------------------- /pez.linux.c: -------------------------------------------------------------------------------- 1 | // Pez was developed by Philip Rideout and released under the MIT License. 2 | 3 | #include 4 | 5 | #include "pez.h" 6 | #include "gl3.h" 7 | #include "bstrlib.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 21 | #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 22 | #define GLX_CONTEXT_FLAGS_ARB 0x2094 23 | //#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 24 | //#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 25 | #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 26 | #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 27 | #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 28 | 29 | typedef struct PlatformContextRec 30 | { 31 | Display* MainDisplay; 32 | Window MainWindow; 33 | } PlatformContext; 34 | 35 | unsigned int GetMicroseconds() 36 | { 37 | struct timeval tp; 38 | gettimeofday(&tp, NULL); 39 | return tp.tv_sec * 1000000 + tp.tv_usec; 40 | } 41 | 42 | int main(int argc, char** argv) 43 | { 44 | int attrib[] = { 45 | GLX_RENDER_TYPE, GLX_RGBA_BIT, 46 | GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 47 | GLX_DOUBLEBUFFER, True, 48 | GLX_RED_SIZE, 8, 49 | GLX_GREEN_SIZE, 8, 50 | GLX_BLUE_SIZE, 8, 51 | GLX_ALPHA_SIZE, 8, 52 | GLX_DEPTH_SIZE, 24, 53 | None 54 | }; 55 | 56 | PlatformContext context; 57 | 58 | context.MainDisplay = XOpenDisplay(NULL); 59 | int screenIndex = DefaultScreen(context.MainDisplay); 60 | Window root = RootWindow(context.MainDisplay, screenIndex); 61 | 62 | int fbcount; 63 | PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddress((GLubyte*)"glXChooseFBConfig"); 64 | GLXFBConfig *fbc = glXChooseFBConfig(context.MainDisplay, screenIndex, attrib, &fbcount); 65 | if (!fbc) 66 | pezFatal("Failed to retrieve a framebuffer config\n"); 67 | 68 | PFNGLXGETVISUALFROMFBCONFIGPROC glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) glXGetProcAddress((GLubyte*)"glXGetVisualFromFBConfig"); 69 | if (!glXGetVisualFromFBConfig) 70 | pezFatal("Failed to get a GLX function pointer\n"); 71 | 72 | PFNGLXGETFBCONFIGATTRIBPROC glXGetFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) glXGetProcAddress((GLubyte*)"glXGetFBConfigAttrib"); 73 | if (!glXGetFBConfigAttrib) 74 | pezFatal("Failed to get a GLX function pointer\n"); 75 | 76 | if (PezGetConfig().Multisampling) { 77 | int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; 78 | for ( int i = 0; i < fbcount; i++ ) { 79 | XVisualInfo *vi = glXGetVisualFromFBConfig( context.MainDisplay, fbc[i] ); 80 | if (!vi) { 81 | continue; 82 | } 83 | int samp_buf, samples; 84 | glXGetFBConfigAttrib( context.MainDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); 85 | glXGetFBConfigAttrib( context.MainDisplay, fbc[i], GLX_SAMPLES , &samples ); 86 | //printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," 87 | // " SAMPLES = %d\n", 88 | // i, (unsigned int) vi->visualid, samp_buf, samples ); 89 | if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) ) 90 | best_fbc = i, best_num_samp = samples; 91 | if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) 92 | worst_fbc = i, worst_num_samp = samples; 93 | XFree( vi ); 94 | } 95 | fbc[0] = fbc[ best_fbc ]; 96 | } 97 | 98 | XVisualInfo *visinfo = glXGetVisualFromFBConfig(context.MainDisplay, fbc[0]); 99 | if (!visinfo) 100 | pezFatal("Error: couldn't create OpenGL window with this pixel format.\n"); 101 | 102 | XSetWindowAttributes attr; 103 | attr.background_pixel = 0; 104 | attr.border_pixel = 0; 105 | attr.colormap = XCreateColormap(context.MainDisplay, root, visinfo->visual, AllocNone); 106 | attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | 107 | PointerMotionMask | ButtonPressMask | ButtonReleaseMask; 108 | 109 | context.MainWindow = XCreateWindow( 110 | context.MainDisplay, 111 | root, 112 | 0, 0, 113 | PezGetConfig().Width, PezGetConfig().Height, 0, 114 | visinfo->depth, 115 | InputOutput, 116 | visinfo->visual, 117 | CWBackPixel | /*CWBorderPixel |*/ CWColormap | CWEventMask, 118 | &attr 119 | ); 120 | 121 | int borderless = 1; 122 | if (borderless) { 123 | Atom mwmHintsProperty = XInternAtom(context.MainDisplay, "_MOTIF_WM_HINTS", 0); 124 | MwmHints hints = {0}; 125 | hints.flags = MWM_HINTS_DECORATIONS; 126 | hints.decorations = 0; 127 | XChangeProperty(context.MainDisplay, context.MainWindow, mwmHintsProperty, mwmHintsProperty, 32, 128 | PropModeReplace, (unsigned char *)&hints, PROP_MWM_HINTS_ELEMENTS); 129 | } 130 | 131 | XMapWindow(context.MainDisplay, context.MainWindow); 132 | 133 | int centerWindow = 1; 134 | if (centerWindow) { 135 | Screen* pScreen = XScreenOfDisplay(context.MainDisplay, screenIndex); 136 | int left = XWidthOfScreen(pScreen)/2 - PezGetConfig().Width/2; 137 | int top = XHeightOfScreen(pScreen)/2 - PezGetConfig().Height/2; 138 | XMoveWindow(context.MainDisplay, context.MainWindow, left, top); 139 | } 140 | 141 | GLXContext glcontext = 0; 142 | if (PEZ_FORWARD_COMPATIBLE_GL) { 143 | PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribs = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((GLubyte*)"glXCreateContextAttribsARB"); 144 | if (!glXCreateContextAttribs) { 145 | pezFatal("Your platform does not support OpenGL 4.0.\n" 146 | "Try changing PEZ_FORWARD_COMPATIBLE_GL to 0.\n"); 147 | } 148 | int attribs[] = { 149 | GLX_CONTEXT_MAJOR_VERSION_ARB, 4, 150 | GLX_CONTEXT_MINOR_VERSION_ARB, 0, 151 | GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 152 | GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, 153 | 0 154 | }; 155 | glcontext = glXCreateContextAttribs(context.MainDisplay, fbc[0], NULL, True, attribs); 156 | } else { 157 | glcontext = glXCreateContext(context.MainDisplay, visinfo, NULL, True); 158 | } 159 | 160 | glXMakeCurrent(context.MainDisplay, context.MainWindow, glcontext); 161 | PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddress((GLubyte*)"glXSwapIntervalSGI"); 162 | if (glXSwapIntervalSGI) { 163 | glXSwapIntervalSGI(PezGetConfig().VerticalSync ? 1 : 0); 164 | } 165 | /* 166 | GLenum err = glewInit(); 167 | if (GLEW_OK != err) 168 | pezFatal("GLEW Error: %s\n", glewGetErrorString(err)); 169 | 170 | // Work around some GLEW issues: 171 | #define glewGetProcAddress(name) (*glXGetProcAddressARB)(name) 172 | glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)glewGetProcAddress((const GLubyte*)"glPatchParameteri"); 173 | glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)glewGetProcAddress((const GLubyte*)"glBindVertexArray"); 174 | glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)glewGetProcAddress((const GLubyte*)"glDeleteVertexArrays"); 175 | glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)glewGetProcAddress((const GLubyte*)"glGenVertexArrays"); 176 | glIsVertexArray = (PFNGLISVERTEXARRAYPROC)glewGetProcAddress((const GLubyte*)"glIsVertexArray"); 177 | */ 178 | // Reset OpenGL error state: 179 | glGetError(); 180 | 181 | // Lop off the trailing .c 182 | bstring name = bfromcstr(PezGetConfig().Title); 183 | bstring shaderPrefix = bmidstr(name, 0, blength(name) - 1); 184 | pezSwInit(bdata(shaderPrefix)); 185 | bdestroy(shaderPrefix); 186 | 187 | // Set up the Shader Wrangler 188 | pezSwAddPath("./", ".glsl"); 189 | pezSwAddPath("../", ".glsl"); 190 | char qualifiedPath[128]; 191 | strcpy(qualifiedPath, pezResourcePath()); 192 | strcat(qualifiedPath, "/"); 193 | pezSwAddPath(qualifiedPath, ".glsl"); 194 | pezSwAddDirective("*", "#version 420"); 195 | 196 | // Perform user-specified intialization 197 | pezPrintString("OpenGL Version: %s\n", glGetString(GL_VERSION)); 198 | PezInitialize(); 199 | bstring windowTitle = bmidstr(name, 5, blength(name) - 7); 200 | XStoreName(context.MainDisplay, context.MainWindow, bdata(windowTitle)); 201 | bdestroy(windowTitle); 202 | bdestroy(name); 203 | 204 | // ------------------- 205 | // Start the Game Loop 206 | // ------------------- 207 | 208 | unsigned int previousTime = GetMicroseconds(); 209 | int done = 0; 210 | while (!done) { 211 | 212 | if (glGetError() != GL_NO_ERROR) 213 | pezFatal("OpenGL error.\n"); 214 | 215 | if (XPending(context.MainDisplay)) { 216 | XEvent event; 217 | 218 | XNextEvent(context.MainDisplay, &event); 219 | switch (event.type) 220 | { 221 | case Expose: 222 | //redraw(display, event.xany.window); 223 | break; 224 | 225 | case ConfigureNotify: 226 | //resize(event.xconfigure.width, event.xconfigure.height); 227 | break; 228 | 229 | #ifdef PEZ_MOUSE_HANDLER 230 | case ButtonPress: 231 | PezHandleMouse(event.xbutton.x, event.xbutton.y, PEZ_DOWN); 232 | break; 233 | 234 | case ButtonRelease: 235 | PezHandleMouse(event.xbutton.x, event.xbutton.y, PEZ_UP); 236 | break; 237 | 238 | case MotionNotify: 239 | PezHandleMouse(event.xmotion.x, event.xmotion.y, PEZ_MOVE); 240 | break; 241 | #endif 242 | 243 | case KeyRelease: 244 | case KeyPress: { 245 | XComposeStatus composeStatus; 246 | char asciiCode[32]; 247 | KeySym keySym; 248 | int len; 249 | 250 | len = XLookupString(&event.xkey, asciiCode, sizeof(asciiCode), &keySym, &composeStatus); 251 | switch (asciiCode[0]) { 252 | case 'x': case 'X': case 'q': case 'Q': 253 | case 0x1b: 254 | done = 1; 255 | break; 256 | } 257 | } 258 | } 259 | } 260 | 261 | unsigned int currentTime = GetMicroseconds(); 262 | unsigned int deltaTime = currentTime - previousTime; 263 | previousTime = currentTime; 264 | 265 | PezUpdate((float) deltaTime / 1000000.0f); 266 | 267 | PezRender(0); 268 | glXSwapBuffers(context.MainDisplay, context.MainWindow); 269 | } 270 | 271 | pezSwShutdown(); 272 | 273 | return 0; 274 | } 275 | 276 | void pezPrintStringW(const wchar_t* pStr, ...) 277 | { 278 | va_list a; 279 | va_start(a, pStr); 280 | 281 | wchar_t msg[1024] = {0}; 282 | vswprintf(msg, countof(msg), pStr, a); 283 | fputws(msg, stderr); 284 | } 285 | 286 | void pezPrintString(const char* pStr, ...) 287 | { 288 | va_list a; 289 | va_start(a, pStr); 290 | 291 | char msg[1024] = {0}; 292 | vsnprintf(msg, countof(msg), pStr, a); 293 | fputs(msg, stderr); 294 | } 295 | 296 | void pezFatalW(const wchar_t* pStr, ...) 297 | { 298 | fwide(stderr, 1); 299 | 300 | va_list a; 301 | va_start(a, pStr); 302 | 303 | wchar_t msg[1024] = {0}; 304 | vswprintf(msg, countof(msg), pStr, a); 305 | fputws(msg, stderr); 306 | exit(1); 307 | } 308 | 309 | void _pezFatal(const char* pStr, va_list a) 310 | { 311 | char msg[1024] = {0}; 312 | vsnprintf(msg, countof(msg), pStr, a); 313 | fputs(msg, stderr); 314 | fputc('\n', stderr); 315 | exit(1); 316 | } 317 | 318 | void pezFatal(const char* pStr, ...) 319 | { 320 | va_list a; 321 | va_start(a, pStr); 322 | _pezFatal(pStr, a); 323 | } 324 | 325 | void pezCheck(int condition, ...) 326 | { 327 | va_list a; 328 | const char* pStr; 329 | 330 | if (condition) 331 | return; 332 | 333 | va_start(a, condition); 334 | pStr = va_arg(a, const char*); 335 | _pezFatal(pStr, a); 336 | } 337 | 338 | void pezCheckPointer(void* p, ...) 339 | { 340 | va_list a; 341 | const char* pStr; 342 | 343 | if (p != NULL) 344 | return; 345 | 346 | va_start(a, p); 347 | pStr = va_arg(a, const char*); 348 | _pezFatal(pStr, a); 349 | } 350 | 351 | int pezIsPressing(char key) 352 | { 353 | return 0; 354 | } 355 | 356 | const char* pezResourcePath() 357 | { 358 | return "."; 359 | } 360 | -------------------------------------------------------------------------------- /verasansmono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prideout/recipes/34a5f6fa4109be03e180bc6839cbc0253b0cacea/verasansmono.png --------------------------------------------------------------------------------