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