1 struct GlobalShaderParamState
2 {
3     const char *name;
4     union
5     {
6         float fval[32];
7         int ival[32];
8         uint uval[32];
9         uchar buf[32*sizeof(float)];
10     };
11     int version;
12 
13     static int nextversion;
14 
15     void resetversions();
16 
changedGlobalShaderParamState17     void changed()
18     {
19         if(++nextversion < 0) resetversions();
20         version = nextversion;
21     }
22 };
23 
24 struct ShaderParamBinding
25 {
26     int loc, size;
27     GLenum format;
28 };
29 
30 struct GlobalShaderParamUse : ShaderParamBinding
31 {
32 
33     GlobalShaderParamState *param;
34     int version;
35 
flushGlobalShaderParamUse36     void flush()
37     {
38         if(version == param->version) return;
39         switch(format)
40         {
41             case GL_BOOL:
42             case GL_FLOAT:      glUniform1fv_(loc, size, param->fval); break;
43             case GL_BOOL_VEC2:
44             case GL_FLOAT_VEC2: glUniform2fv_(loc, size, param->fval); break;
45             case GL_BOOL_VEC3:
46             case GL_FLOAT_VEC3: glUniform3fv_(loc, size, param->fval); break;
47             case GL_BOOL_VEC4:
48             case GL_FLOAT_VEC4: glUniform4fv_(loc, size, param->fval); break;
49             case GL_INT:        glUniform1iv_(loc, size, param->ival); break;
50             case GL_INT_VEC2:   glUniform2iv_(loc, size, param->ival); break;
51             case GL_INT_VEC3:   glUniform3iv_(loc, size, param->ival); break;
52             case GL_INT_VEC4:   glUniform4iv_(loc, size, param->ival); break;
53             case GL_UNSIGNED_INT:      glUniform1uiv_(loc, size, param->uval); break;
54             case GL_UNSIGNED_INT_VEC2: glUniform2uiv_(loc, size, param->uval); break;
55             case GL_UNSIGNED_INT_VEC3: glUniform3uiv_(loc, size, param->uval); break;
56             case GL_UNSIGNED_INT_VEC4: glUniform4uiv_(loc, size, param->uval); break;
57             case GL_FLOAT_MAT2: glUniformMatrix2fv_(loc, 1, GL_FALSE, param->fval); break;
58             case GL_FLOAT_MAT3: glUniformMatrix3fv_(loc, 1, GL_FALSE, param->fval); break;
59             case GL_FLOAT_MAT4: glUniformMatrix4fv_(loc, 1, GL_FALSE, param->fval); break;
60         }
61         version = param->version;
62     }
63 };
64 
65 struct LocalShaderParamState : ShaderParamBinding
66 {
67     const char *name;
68 };
69 
70 struct SlotShaderParam
71 {
72     enum
73     {
74         REUSE = 1<<0
75     };
76 
77     const char *name;
78     int loc, flags, palette, palindex;
79     float val[4];
80 };
81 
82 struct SlotShaderParamState : LocalShaderParamState
83 {
84     int flags, palette, palindex;
85     float val[4];
86 
SlotShaderParamStateSlotShaderParamState87     SlotShaderParamState() : palette(0), palindex(0) {}
SlotShaderParamStateSlotShaderParamState88     SlotShaderParamState(const SlotShaderParam &p)
89     {
90         name = p.name;
91         loc = -1;
92         size = 1;
93         format = GL_FLOAT_VEC4;
94         flags = p.flags;
95         palette = p.palette;
96         palindex = p.palindex;
97         memcpy(val, p.val, sizeof(val));
98     }
99 };
100 
101 enum
102 {
103     SHADER_DEFAULT    = 0,
104     SHADER_WORLD      = 1<<0,
105     SHADER_ENVMAP     = 1<<1,
106     SHADER_REFRACT    = 1<<2,
107     SHADER_OPTION     = 1<<3,
108     SHADER_DYNAMIC    = 1<<4,
109     SHADER_TRIPLANAR  = 1<<5,
110 
111     SHADER_INVALID    = 1<<8,
112     SHADER_DEFERRED   = 1<<9
113 };
114 
115 #define MAXVARIANTROWS 32
116 
117 struct Slot;
118 struct VSlot;
119 
120 struct UniformLoc
121 {
122     const char *name, *blockname;
123     int loc, version, binding, stride, offset, size;
124     void *data;
nameUniformLoc125     UniformLoc(const char *name = NULL, const char *blockname = NULL, int binding = -1, int stride = -1) : name(name), blockname(blockname), loc(-1), version(-1), binding(binding), stride(stride), offset(-1), size(-1), data(NULL) {}
126 };
127 
128 struct AttribLoc
129 {
130     const char *name;
131     int loc;
nameAttribLoc132     AttribLoc(const char *name = NULL, int loc = -1) : name(name), loc(loc) {}
133 };
134 
135 struct FragDataLoc
136 {
137     const char *name;
138     int loc;
139     GLenum format;
140     int index;
nameFragDataLoc141     FragDataLoc(const char *name = NULL, int loc = -1, GLenum format = GL_FALSE, int index = 0) : name(name), loc(loc), format(format), index(index) {}
142 };
143 
144 struct Shader
145 {
146     static Shader *lastshader;
147 
148     char *name, *vsstr, *psstr, *defer;
149     int type;
150     GLuint program, vsobj, psobj;
151     vector<SlotShaderParamState> defaultparams;
152     vector<GlobalShaderParamUse> globalparams;
153     vector<LocalShaderParamState> localparams;
154     vector<uchar> localparamremap;
155     Shader *variantshader;
156     vector<Shader *> variants;
157     ushort *variantrows;
158     bool standard, forced, used;
159     Shader *reusevs, *reuseps;
160     vector<UniformLoc> uniformlocs;
161     vector<AttribLoc> attriblocs;
162     vector<FragDataLoc> fragdatalocs;
163     const void *owner;
164 
ShaderShader165     Shader() : name(NULL), vsstr(NULL), psstr(NULL), defer(NULL), type(SHADER_DEFAULT), program(0), vsobj(0), psobj(0), variantshader(NULL), variantrows(NULL), standard(false), forced(false), used(false), reusevs(NULL), reuseps(NULL), owner(NULL)
166     {
167     }
168 
~ShaderShader169     ~Shader()
170     {
171         DELETEA(name);
172         DELETEA(vsstr);
173         DELETEA(psstr);
174         DELETEA(defer);
175         DELETEA(variantrows);
176     }
177 
178     void allocparams(Slot *slot = NULL);
179     void setslotparams(Slot &slot);
180     void setslotparams(Slot &slot, VSlot &vslot);
181     void bindprograms();
182 
183     void flushparams(Slot *slot = NULL)
184     {
185         if(!used) { allocparams(slot); used = true; }
186         loopv(globalparams) globalparams[i].flush();
187     }
188 
189     void force();
190 
invalidShader191     bool invalid() const { return (type&SHADER_INVALID)!=0; }
deferredShader192     bool deferred() const { return (type&SHADER_DEFERRED)!=0; }
loadedShader193     bool loaded() const { return !(type&(SHADER_DEFERRED|SHADER_INVALID)); }
194 
hasoptionShader195     bool hasoption() const { return (type&SHADER_OPTION)!=0; }
196 
isdynamicShader197     bool isdynamic() const { return (type&SHADER_DYNAMIC)!=0; }
198 
isnullShader199     static inline bool isnull(const Shader *s) { return !s; }
200 
isnullShader201     bool isnull() const { return isnull(this); }
202 
numvariantsShader203     int numvariants(int row) const
204     {
205         if(row < 0 || row >= MAXVARIANTROWS || !variantrows) return 0;
206         return variantrows[row+1] - variantrows[row];
207     }
208 
getvariantShader209     Shader *getvariant(int col, int row) const
210     {
211         if(row < 0 || row >= MAXVARIANTROWS || col < 0 || !variantrows) return NULL;
212         int start = variantrows[row], end = variantrows[row+1];
213         return col < end - start ? variants[start + col] : NULL;
214     }
215 
addvariantShader216     void addvariant(int row, Shader *s)
217     {
218         if(row < 0 || row >= MAXVARIANTROWS || variants.length() >= USHRT_MAX) return;
219         if(!variantrows) { variantrows = new ushort[MAXVARIANTROWS+1]; memset(variantrows, 0, (MAXVARIANTROWS+1)*sizeof(ushort)); }
220         variants.insert(variantrows[row+1], s);
221         for(int i = row+1; i <= MAXVARIANTROWS; ++i) ++variantrows[i];
222     }
223 
setvariant_Shader224     void setvariant_(int col, int row)
225     {
226         Shader *s = this;
227         if(variantrows)
228         {
229             int start = variantrows[row], end = variantrows[row+1];
230             for(col = min(start + col, end-1); col >= start; --col) if(!variants[col]->invalid()) { s = variants[col]; break; }
231         }
232         if(lastshader!=s) s->bindprograms();
233     }
234 
setvariantShader235     void setvariant(int col, int row)
236     {
237         if(isnull() || !loaded()) return;
238         setvariant_(col, row);
239         lastshader->flushparams();
240     }
241 
setvariantShader242     void setvariant(int col, int row, Slot &slot)
243     {
244         if(isnull() || !loaded()) return;
245         setvariant_(col, row);
246         lastshader->flushparams(&slot);
247         lastshader->setslotparams(slot);
248     }
249 
setvariantShader250     void setvariant(int col, int row, Slot &slot, VSlot &vslot)
251     {
252         if(isnull() || !loaded()) return;
253         setvariant_(col, row);
254         lastshader->flushparams(&slot);
255         lastshader->setslotparams(slot, vslot);
256     }
257 
set_Shader258     void set_()
259     {
260         if(lastshader!=this) bindprograms();
261     }
262 
setShader263     void set()
264     {
265         if(isnull() || !loaded()) return;
266         set_();
267         lastshader->flushparams();
268     }
269 
setShader270     void set(Slot &slot)
271     {
272         if(isnull() || !loaded()) return;
273         set_();
274         lastshader->flushparams(&slot);
275         lastshader->setslotparams(slot);
276     }
277 
setShader278     void set(Slot &slot, VSlot &vslot)
279     {
280         if(isnull() || !loaded()) return;
281         set_();
282         lastshader->flushparams(&slot);
283         lastshader->setslotparams(slot, vslot);
284     }
285 
286     bool compile();
287     void cleanup(bool full = false);
288 
289     static int uniformlocversion();
290 };
291 
292 struct GlobalShaderParam
293 {
294     const char *name;
295     GlobalShaderParamState *param;
296 
GlobalShaderParamGlobalShaderParam297     GlobalShaderParam(const char *name) : name(name), param(NULL) {}
298 
resolveGlobalShaderParam299     GlobalShaderParamState *resolve()
300     {
301         extern GlobalShaderParamState *getglobalparam(const char *name);
302         if(!param) param = getglobalparam(name);
303         param->changed();
304         return param;
305     }
306 
307     void setf(float x = 0, float y = 0, float z = 0, float w = 0)
308     {
309         GlobalShaderParamState *g = resolve();
310         g->fval[0] = x;
311         g->fval[1] = y;
312         g->fval[2] = z;
313         g->fval[3] = w;
314     }
315     void set(const vec &v, float w = 0) { setf(v.x, v.y, v.z, w); }
316     void set(const vec2 &v, float z = 0, float w = 0) { setf(v.x, v.y, z, w); }
setGlobalShaderParam317     void set(const vec4 &v) { setf(v.x, v.y, v.z, v.w); }
setGlobalShaderParam318     void set(const plane &p) { setf(p.x, p.y, p.z, p.offset); }
setGlobalShaderParam319     void set(const matrix2 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); }
setGlobalShaderParam320     void set(const matrix3 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); }
setGlobalShaderParam321     void set(const matrix4 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); }
322 
323     template<class T>
324     void setv(const T *v, int n = 1) { memcpy(resolve()->buf, v, n*sizeof(T)); }
325 
326     void seti(int x = 0, int y = 0, int z = 0, int w = 0)
327     {
328         GlobalShaderParamState *g = resolve();
329         g->ival[0] = x;
330         g->ival[1] = y;
331         g->ival[2] = z;
332         g->ival[3] = w;
333     }
334     void set(const ivec &v, int w = 0) { seti(v.x, v.y, v.z, w); }
335     void set(const ivec2 &v, int z = 0, int w = 0) { seti(v.x, v.y, z, w); }
setGlobalShaderParam336     void set(const ivec4 &v) { seti(v.x, v.y, v.z, v.w); }
337 
338     void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0)
339     {
340         GlobalShaderParamState *g = resolve();
341         g->uval[0] = x;
342         g->uval[1] = y;
343         g->uval[2] = z;
344         g->uval[3] = w;
345     }
346 
347     template<class T>
348     T *reserve(int n = 1) { return (T *)resolve()->buf; }
349 };
350 
351 struct LocalShaderParam
352 {
353     const char *name;
354     int loc;
355 
LocalShaderParamLocalShaderParam356     LocalShaderParam(const char *name) : name(name), loc(-1) {}
357 
resolveLocalShaderParam358     LocalShaderParamState *resolve()
359     {
360         Shader *s = Shader::lastshader;
361         if(!s) return NULL;
362         if(!s->localparamremap.inrange(loc))
363         {
364             extern int getlocalparam(const char *name);
365             if(loc == -1) loc = getlocalparam(name);
366             if(!s->localparamremap.inrange(loc)) return NULL;
367         }
368         uchar remap = s->localparamremap[loc];
369         return s->localparams.inrange(remap) ? &s->localparams[remap] : NULL;
370     }
371 
372     void setf(float x = 0, float y = 0, float z = 0, float w = 0)
373     {
374         ShaderParamBinding *b = resolve();
375         if(b) switch(b->format)
376         {
377             case GL_BOOL:
378             case GL_FLOAT:      glUniform1f_(b->loc, x); break;
379             case GL_BOOL_VEC2:
380             case GL_FLOAT_VEC2: glUniform2f_(b->loc, x, y); break;
381             case GL_BOOL_VEC3:
382             case GL_FLOAT_VEC3: glUniform3f_(b->loc, x, y, z); break;
383             case GL_BOOL_VEC4:
384             case GL_FLOAT_VEC4: glUniform4f_(b->loc, x, y, z, w); break;
385             case GL_INT:        glUniform1i_(b->loc, int(x)); break;
386             case GL_INT_VEC2:   glUniform2i_(b->loc, int(x), int(y)); break;
387             case GL_INT_VEC3:   glUniform3i_(b->loc, int(x), int(y), int(z)); break;
388             case GL_INT_VEC4:   glUniform4i_(b->loc, int(x), int(y), int(z), int(w)); break;
389             case GL_UNSIGNED_INT:      glUniform1ui_(b->loc, uint(x)); break;
390             case GL_UNSIGNED_INT_VEC2: glUniform2ui_(b->loc, uint(x), uint(y)); break;
391             case GL_UNSIGNED_INT_VEC3: glUniform3ui_(b->loc, uint(x), uint(y), uint(z)); break;
392             case GL_UNSIGNED_INT_VEC4: glUniform4ui_(b->loc, uint(x), uint(y), uint(z), uint(w)); break;
393         }
394     }
395     void set(const vec &v, float w = 0) { setf(v.x, v.y, v.z, w); }
396     void set(const vec2 &v, float z = 0, float w = 0) { setf(v.x, v.y, z, w); }
setLocalShaderParam397     void set(const vec4 &v) { setf(v.x, v.y, v.z, v.w); }
setLocalShaderParam398     void set(const plane &p) { setf(p.x, p.y, p.z, p.offset); }
399     void setv(const float *f, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1fv_(b->loc, n, f); }
400     void setv(const vec *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform3fv_(b->loc, n, v->v); }
401     void setv(const vec2 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform2fv_(b->loc, n, v->v); }
402     void setv(const vec4 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4fv_(b->loc, n, v->v); }
403     void setv(const plane *p, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4fv_(b->loc, n, p->v); }
404     void setv(const matrix2 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix2fv_(b->loc, n, GL_FALSE, m->a.v); }
405     void setv(const matrix3 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix3fv_(b->loc, n, GL_FALSE, m->a.v); }
406     void setv(const matrix4 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix4fv_(b->loc, n, GL_FALSE, m->a.v); }
setLocalShaderParam407     void set(const matrix2 &m) { setv(&m); }
setLocalShaderParam408     void set(const matrix3 &m) { setv(&m); }
setLocalShaderParam409     void set(const matrix4 &m) { setv(&m); }
410 
411     template<class T>
settLocalShaderParam412     void sett(T x, T y, T z, T w)
413     {
414         ShaderParamBinding *b = resolve();
415         if(b) switch(b->format)
416         {
417             case GL_FLOAT:      glUniform1f_(b->loc, x); break;
418             case GL_FLOAT_VEC2: glUniform2f_(b->loc, x, y); break;
419             case GL_FLOAT_VEC3: glUniform3f_(b->loc, x, y, z); break;
420             case GL_FLOAT_VEC4: glUniform4f_(b->loc, x, y, z, w); break;
421             case GL_BOOL:
422             case GL_INT:        glUniform1i_(b->loc, x); break;
423             case GL_BOOL_VEC2:
424             case GL_INT_VEC2:   glUniform2i_(b->loc, x, y); break;
425             case GL_BOOL_VEC3:
426             case GL_INT_VEC3:   glUniform3i_(b->loc, x, y, z); break;
427             case GL_BOOL_VEC4:
428             case GL_INT_VEC4:   glUniform4i_(b->loc, x, y, z, w); break;
429             case GL_UNSIGNED_INT:      glUniform1ui_(b->loc, x); break;
430             case GL_UNSIGNED_INT_VEC2: glUniform2ui_(b->loc, x, y); break;
431             case GL_UNSIGNED_INT_VEC3: glUniform3ui_(b->loc, x, y, z); break;
432             case GL_UNSIGNED_INT_VEC4: glUniform4ui_(b->loc, x, y, z, w); break;
433         }
434     }
435     void seti(int x = 0, int y = 0, int z = 0, int w = 0) { sett<int>(x, y, z, w); }
436     void set(const ivec &v, int w = 0) { seti(v.x, v.y, v.z, w); }
437     void set(const ivec2 &v, int z = 0, int w = 0) { seti(v.x, v.y, z, w); }
setLocalShaderParam438     void set(const ivec4 &v) { seti(v.x, v.y, v.z, v.w); }
439     void setv(const int *i, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1iv_(b->loc, n, i); }
440     void setv(const ivec *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform3iv_(b->loc, n, v->v); }
441     void setv(const ivec2 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform2iv_(b->loc, n, v->v); }
442     void setv(const ivec4 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4iv_(b->loc, n, v->v); }
443 
444     void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0) { sett<uint>(x, y, z, w); }
445     void setv(const uint *u, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1uiv_(b->loc, n, u); }
446 };
447 
448 #define LOCALPARAM(name, vals) do { static LocalShaderParam param( #name ); param.set(vals); } while(0)
449 #define LOCALPARAMF(name, ...) do { static LocalShaderParam param( #name ); param.setf(__VA_ARGS__); } while(0)
450 #define LOCALPARAMI(name, ...) do { static LocalShaderParam param( #name ); param.seti(__VA_ARGS__); } while(0)
451 #define LOCALPARAMV(name, vals, num) do { static LocalShaderParam param( #name ); param.setv(vals, num); } while(0)
452 #define GLOBALPARAM(name, vals) do { static GlobalShaderParam param( #name ); param.set(vals); } while(0)
453 #define GLOBALPARAMF(name, ...) do { static GlobalShaderParam param( #name ); param.setf(__VA_ARGS__); } while(0)
454 #define GLOBALPARAMI(name, ...) do { static GlobalShaderParam param( #name ); param.seti(__VA_ARGS__); } while(0)
455 #define GLOBALPARAMV(name, vals, num) do { static GlobalShaderParam param( #name ); param.setv(vals, num); } while(0)
456 
457 #define SETSHADER(name, ...) \
458     do { \
459         static Shader *name##shader = NULL; \
460         if(!name##shader) name##shader = lookupshaderbyname(#name); \
461         name##shader->set(__VA_ARGS__); \
462     } while(0)
463 #define SETVARIANT(name, ...) \
464     do { \
465         static Shader *name##shader = NULL; \
466         if(!name##shader) name##shader = lookupshaderbyname(#name); \
467         name##shader->setvariant(__VA_ARGS__); \
468     } while(0)
469 
470 struct ImageData
471 {
472     int w, h, bpp, levels, align, pitch;
473     GLenum compressed;
474     uchar *data;
475     void *owner;
476     void (*freefunc)(void *);
477 
ImageDataImageData478     ImageData()
479         : data(NULL), owner(NULL), freefunc(NULL)
480     {}
481 
482 
483     ImageData(int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE)
484     {
485         setdata(NULL, nw, nh, nbpp, nlevels, nalign, ncompressed);
486     }
487 
ImageDataImageData488     ImageData(int nw, int nh, int nbpp, uchar *data)
489         : owner(NULL), freefunc(NULL)
490     {
491         setdata(data, nw, nh, nbpp);
492     }
493 
ImageDataImageData494     ImageData(SDL_Surface *s) { wrap(s); }
~ImageDataImageData495     ~ImageData() { cleanup(); }
496 
497     void setdata(uchar *ndata, int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE)
498     {
499         w = nw;
500         h = nh;
501         bpp = nbpp;
502         levels = nlevels;
503         align = nalign;
504         pitch = align ? 0 : w*bpp;
505         compressed = ncompressed;
506         data = ndata ? ndata : new uchar[calcsize()];
507         if(!ndata) { owner = this; freefunc = NULL; }
508     }
509 
calclevelsizeImageData510     int calclevelsize(int level) const { return ((max(w>>level, 1)+align-1)/align)*((max(h>>level, 1)+align-1)/align)*bpp; }
511 
calcsizeImageData512     int calcsize() const
513     {
514         if(!align) return w*h*bpp;
515         int lw = w, lh = h,
516             size = 0;
517         loopi(levels)
518         {
519             if(lw<=0) lw = 1;
520             if(lh<=0) lh = 1;
521             size += ((lw+align-1)/align)*((lh+align-1)/align)*bpp;
522             if(lw*lh==1) break;
523             lw >>= 1;
524             lh >>= 1;
525         }
526         return size;
527     }
528 
disownImageData529     void disown()
530     {
531         data = NULL;
532         owner = NULL;
533         freefunc = NULL;
534     }
535 
cleanupImageData536     void cleanup()
537     {
538         if(owner==this) delete[] data;
539         else if(freefunc) (*freefunc)(owner);
540         disown();
541     }
542 
replaceImageData543     void replace(ImageData &d)
544     {
545         cleanup();
546         *this = d;
547         if(owner == &d) owner = this;
548         d.disown();
549     }
550 
wrapImageData551     void wrap(SDL_Surface *s)
552     {
553         setdata((uchar *)s->pixels, s->w, s->h, s->format->BytesPerPixel);
554         pitch = s->pitch;
555         owner = s;
556         freefunc = (void (*)(void *))SDL_FreeSurface;
557     }
558 };
559 
560 // management of texture slots
561 // each texture slot can have multiple texture frames, of which currently only the first is used
562 // additional frames can be used for various shaders
563 
564 struct TextureAnim
565 {
566     int count, delay, x, y, w, h;
567     bool throb;
TextureAnimTextureAnim568     TextureAnim() : count(0), delay(0), throb(false) {}
569 };
570 
571 struct Texture
572 {
573     enum
574     {
575         IMAGE      = 0,
576         CUBEMAP    = 1,
577         TYPE       = 0xFF,
578 
579         STUB       = 1<<8,
580         TRANSIENT  = 1<<9,
581         COMPRESSED = 1<<10,
582         ALPHA      = 1<<11,
583         MIRROR     = 1<<12,
584         FLAGS      = 0xFF00
585     };
586 
587     char *name;
588     int type, w, h, xs, ys, bpp, clamp, frame, delay, last;
589     bool mipmap, canreduce, throb;
590     vector<GLuint> frames;
591     GLuint id;
592     uchar *alphamask;
593 
594 
TextureTexture595     Texture() : frame(0), delay(0), last(0), throb(false), alphamask(NULL)
596     {
597         frames.shrink(0);
598     }
599 
idframeTexture600     GLuint idframe(int id)
601     {
602         if(!frames.empty())
603             return frames[::clamp(id, 0, frames.length()-1)];
604         return id;
605     }
606 
getframeTexture607     GLuint getframe(float amt)
608     {
609         if(!frames.empty())
610             return frames[::clamp(int((frames.length()-1)*amt), 0, frames.length()-1)];
611         return id;
612     }
613 
retframeTexture614     GLuint retframe(int cur, int total)
615     {
616         if(!frames.empty())
617             return frames[::clamp((frames.length()-1)*cur/min(1, total), 0, frames.length()-1)];
618         return id;
619     }
620 };
621 
622 enum
623 {
624     TEX_DIFFUSE = 0,
625     TEX_NORMAL,
626     TEX_GLOW,
627     TEX_ENVMAP,
628     TEX_SPEC,
629     TEX_DEPTH,
630     TEX_UNKNOWN,
631     TEX_MAX,
632     TEX_DETAIL = TEX_SPEC
633 };
634 
635 enum
636 {
637     VSLOT_SHPARAM = 0,
638     VSLOT_SCALE,
639     VSLOT_ROTATION,
640     VSLOT_OFFSET,
641     VSLOT_SCROLL,
642     VSLOT_LAYER,
643     VSLOT_ALPHA,
644     VSLOT_COLOR,
645     VSLOT_PALETTE,
646     VSLOT_COAST,
647     VSLOT_REFRACT,
648     VSLOT_DETAIL,
649     VSLOT_NUM
650 };
651 
652 #define DEFAULT_ALPHA_FRONT 0.5f
653 #define DEFAULT_ALPHA_BACK 0.0f
654 
655 struct VSlot
656 {
657     Slot *slot;
658     VSlot *next;
659     int index, changed;
660     vector<SlotShaderParam> params;
661     bool linked;
662     float scale;
663     int rotation;
664     ivec2 offset;
665     vec2 scroll;
666     int layer, detail, palette, palindex;
667     float alphafront, alphaback;
668     vec colorscale, colorscalealt;
669     vec glowcolor;
670     float coastscale;
671     float refractscale;
672     vec refractcolor;
673 
674     Texture *loadthumbnail();
675 
slotVSlot676     VSlot(Slot *slot = NULL, int index = -1) : slot(slot), next(NULL), index(index), changed(0), palette(0), palindex(0)
677     {
678         reset();
679         if(slot) addvariant(slot);
680     }
681 
682     void addvariant(Slot *slot);
683 
resetVSlot684     void reset()
685     {
686         params.setsize(0);
687         linked = false;
688         scale = 1;
689         rotation = 0;
690         offset = ivec2(0, 0);
691         scroll = vec2(0, 0);
692         layer = detail = palette = palindex = 0;
693         alphafront = DEFAULT_ALPHA_FRONT;
694         alphaback = DEFAULT_ALPHA_BACK;
695         colorscale = vec(1, 1, 1);
696         glowcolor = vec(1, 1, 1);
697         coastscale = 1;
698         refractscale = 0;
699         refractcolor = vec(1, 1, 1);
700     }
701 
getcolorscaleVSlot702     vec getcolorscale() const { return palette || palindex ? vec(colorscale).mul(game::getpalette(palette, palindex)) : colorscale; }
getglowcolorVSlot703     vec getglowcolor() const { return vec(palette || palindex ? vec(glowcolor).mul(game::getpalette(palette, palindex)) : glowcolor).clamp(0.f, 1.f); }
704 
cleanupVSlot705     void cleanup()
706     {
707         linked = false;
708     }
709 
710     bool isdynamic() const;
711 };
712 
713 struct Slot
714 {
715     enum { OCTA, MATERIAL, DECAL };
716 
717     struct Tex
718     {
719         int type;
720         Texture *t;
721         string name;
722         int combined;
723 
TexSlot::Tex724         Tex() : t(NULL), combined(-1) {}
725     };
726 
727     int index, smooth;
728     vector<Tex> sts;
729     Shader *shader;
730     vector<SlotShaderParam> params;
731     VSlot *variants;
732     bool loaded;
733     uint texmask;
734     char *grass;
735     vec grasscolor;
736     float grassblend;
737     int grassscale, grassheight;
738     Texture *grasstex, *thumbnail;
739 
indexSlot740     Slot(int index = -1) : index(index), variants(NULL), grass(NULL) { reset(); }
~SlotSlot741     virtual ~Slot() {}
742 
typeSlot743     virtual int type() const { return OCTA; }
744     virtual const char *name() const;
745 
746     virtual VSlot &emptyvslot();
747 
748     virtual int cancombine(int type) const;
shouldpremulSlot749     virtual bool shouldpremul(int type) const { return false; }
750 
751     int findtextype(int type, int last = -1) const;
752 
753     void load(int index, Slot::Tex &t);
754     void load();
755 
756     Texture *loadthumbnail();
757 
resetSlot758     void reset()
759     {
760         smooth = -1;
761         sts.setsize(0);
762         shader = NULL;
763         params.setsize(0);
764         loaded = false;
765         texmask = 0;
766         DELETEA(grass);
767         grasscolor = vec(0, 0, 0);
768         grassblend = 0;
769         grassscale = grassheight = 0;
770         grasstex = NULL;
771         thumbnail = NULL;
772     }
773 
cleanupSlot774     void cleanup()
775     {
776         loaded = false;
777         grasstex = NULL;
778         thumbnail = NULL;
779         loopv(sts)
780         {
781             Tex &t = sts[i];
782             t.t = NULL;
783             t.combined = -1;
784         }
785     }
786 };
787 
addvariant(Slot * slot)788 inline void VSlot::addvariant(Slot *slot)
789 {
790     if(!slot->variants) slot->variants = this;
791     else
792     {
793         VSlot *prev = slot->variants;
794         while(prev->next) prev = prev->next;
795         prev->next = this;
796     }
797 }
798 
isdynamic()799 inline bool VSlot::isdynamic() const
800 {
801     return !scroll.iszero() || (slot->shader && slot->shader->isdynamic());
802 }
803 
804 struct MatSlot : Slot, VSlot
805 {
806     MatSlot();
807 
typeMatSlot808     int type() const { return MATERIAL; }
809     const char *name() const;
810 
emptyvslotMatSlot811     VSlot &emptyvslot() { return *this; }
812 
cancombineMatSlot813     int cancombine(int type) const { return -1; }
814 
resetMatSlot815     void reset()
816     {
817         Slot::reset();
818         VSlot::reset();
819     }
820 
cleanupMatSlot821     void cleanup()
822     {
823         Slot::cleanup();
824         VSlot::cleanup();
825     }
826 };
827 
828 #define DEFAULTDECALDEPTH 1.f
829 #define DEFAULTDECALFADE  0.5f
830 
831 struct DecalSlot : Slot, VSlot
832 {
833     float depth, fade;
834 
SlotDecalSlot835     DecalSlot(int index = -1) : Slot(index), VSlot(this), depth(DEFAULTDECALDEPTH), fade(DEFAULTDECALFADE) {}
836 
typeDecalSlot837     int type() const { return DECAL; }
838     const char *name() const;
839 
emptyvslotDecalSlot840     VSlot &emptyvslot() { return *this; }
841 
842     int cancombine(int type) const;
843     bool shouldpremul(int type) const;
844 
resetDecalSlot845     void reset()
846     {
847         Slot::reset();
848         VSlot::reset();
849         depth = DEFAULTDECALDEPTH;
850         fade = DEFAULTDECALFADE;
851     }
852 
cleanupDecalSlot853     void cleanup()
854     {
855         Slot::cleanup();
856         VSlot::cleanup();
857     }
858 };
859 
860 extern void scaleimage(ImageData &s, int w, int h);
861 extern void texcrop(ImageData &s, ImageData &d, int x, int y, int w, int h);
862 extern void texcrop(ImageData &s, int x, int y, int w, int h);
863 extern void updatetextures();
864 extern void preloadtextures(uint flags = IDF_PRELOAD);
865 
866 struct texrotation
867 {
868     bool flipx, flipy, swapxy;
869 };
870 
871 struct cubemapside
872 {
873     GLenum target;
874     const char *name;
875     bool flipx, flipy, swapxy;
876 };
877 
878 extern const texrotation texrotations[8];
879 extern const cubemapside cubemapsides[6];
880 extern Texture *notexture, *blanktexture;
881 extern Shader *nullshader, *hudshader, *hudtextshader, *hudnotextureshader, *hudbackgroundshader, *nocolorshader, *foggedshader, *foggednotextureshader, *ldrshader, *ldrnotextureshader, *stdworldshader;
882 extern int maxvsuniforms, maxfsuniforms;
883 
884 extern Shader *lookupshaderbyname(const char *name);
885 extern Shader *useshaderbyname(const char *name);
886 extern Shader *generateshader(const char *name, const char *cmd, ...);
887 extern void resetslotshader();
888 extern void setslotshader(Slot &s);
889 extern void linkslotshader(Slot &s, bool load = true);
890 extern void linkvslotshader(VSlot &s, bool load = true);
891 extern void linkslotshaders();
892 extern const char *getshaderparamname(const char *name, bool insert = true);
893 extern bool shouldreuseparams(Slot &s, VSlot &p);
894 extern void setupshaders();
895 extern void reloadshaders();
896 extern void cleanupshaders();
897 
898 #define MAXBLURRADIUS 7
899 extern float blursigma;
900 extern void setupblurkernel(int radius, float *weights, float *offsets);
901 extern void setblurshader(int pass, int size, int radius, float *weights, float *offsets, GLenum target = GL_TEXTURE_2D);
902 
903 enum
904 {
905     IFMT_NONE = 0,
906     IFMT_BMP,
907     IFMT_PNG,
908     IFMT_TGA,
909     IFMT_MAX,
910 };
911 extern const char *ifmtexts[IFMT_MAX];
912 extern char *notexturetex, *blanktex, *logotex, *emblemtex, *nothumbtex;
913 extern int imageformat;
914 
915 extern void savepng(const char *filename, ImageData &image, int compress = 9, bool flip = false);
916 extern void savetga(const char *filename, ImageData &image, int compress = 1, bool flip = false);
917 extern void saveimage(const char *name, ImageData &image, int format = IFMT_NONE, int compress = 9, bool flip = false, bool skip = false);
918 extern SDL_Surface *loadsurface(const char *name, bool noload = false);
919 extern bool loadimage(const char *name, ImageData &image);
920 extern bool loaddds(const char *filename, ImageData &image, int force = 0);
921 extern bool loadimage(const char *filename, ImageData &image);
922 
923 extern MatSlot materialslots[(MATF_VOLUME|MATF_INDEX)+1];
924 extern MatSlot &lookupmaterialslot(int slot, bool load = true);
925 extern Slot &lookupslot(int slot, bool load = true);
926 extern VSlot &lookupvslot(int slot, bool load = true);
927 extern DecalSlot &lookupdecalslot(int slot, bool load = true);
928 extern VSlot *findvslot(Slot &slot, const VSlot &src, const VSlot &delta);
929 extern VSlot *editvslot(const VSlot &src, const VSlot &delta);
930 extern void mergevslot(VSlot &dst, const VSlot &src, const VSlot &delta);
931 extern void packvslot(vector<uchar> &buf, const VSlot &src);
932 extern bool unpackvslot(ucharbuf &buf, VSlot &dst, bool delta);
933 
934 extern Slot dummyslot;
935 extern VSlot dummyvslot;
936 extern DecalSlot dummydecalslot;
937 extern vector<Slot *> slots;
938 extern vector<VSlot *> vslots;
939 extern vector<DecalSlot *> decalslots;
940 
941 #define _TVAR(f, n, c, m) _SVARF(n, n, c, { if(initing==NOT_INITING && n[0]) textureload(n, m, true); }, f|IDF_TEXTURE, 0)
942 #define TVAR(f, n, c, m)  _TVAR(f, n, c, m)
943 #define _TVARN(f, n, c, t, m) _SVARF(n, n, c, { if(initing==NOT_INITING) t = n[0] ? textureload(n, m, true) : notexture; }, f|IDF_TEXTURE, 0)
944 #define TVARN(f, n, c, t, m) _TVARN(f, n, c, t, m)
945 #define TVART(f, n, c, m) Texture *tex##n; _TVARN(f, n, c, tex##n, m)
946