diff --git a/src/engine/aa.cc b/src/engine/aa.cc index 3c700a3..be7a507 100644 --- a/src/engine/aa.cc +++ b/src/engine/aa.cc @@ -1,4 +1,5 @@ #include "aa.hh" +#include "texture.hh" #include "engine.hh" diff --git a/src/engine/bih.cc b/src/engine/bih.cc index 9532288..f1f225b 100644 --- a/src/engine/bih.cc +++ b/src/engine/bih.cc @@ -1,3 +1,5 @@ +#include "texture.hh" + #include "engine.hh" extern vec hitsurface; diff --git a/src/engine/bih.hh b/src/engine/bih.hh index fb05115..f656b91 100644 --- a/src/engine/bih.hh +++ b/src/engine/bih.hh @@ -1,4 +1,10 @@ +#ifndef ENGINE_BIH_HH +#define ENGINE_BIH_HH + +#include + struct stainrenderer; +struct Texture; struct BIH { @@ -91,3 +97,4 @@ struct BIH extern bool mmintersect(const extentity &e, const vec &o, const vec &ray, float maxdist, int mode, float &dist); +#endif diff --git a/src/engine/blend.cc b/src/engine/blend.cc index 53f64bc..c09c0ef 100644 --- a/src/engine/blend.cc +++ b/src/engine/blend.cc @@ -1,4 +1,5 @@ #include "blend.hh" +#include "texture.hh" #include "engine.hh" diff --git a/src/engine/engine.hh b/src/engine/engine.hh index df039f1..71ea28d 100644 --- a/src/engine/engine.hh +++ b/src/engine/engine.hh @@ -7,7 +7,6 @@ #ifndef STANDALONE #include "light.hh" -#include "texture.hh" #include "bih.hh" #include "model.hh" @@ -53,6 +52,8 @@ struct font #define MINRESW 640 #define MINRESH 480 +struct Shader; + extern font *curfont; extern Shader *textshader; extern const matrix4x3 *textmatrix; @@ -64,42 +65,11 @@ extern void reloadfonts(); static inline void setfont(font *f) { if(f) curfont = f; } // texture -extern int hwtexsize, hwcubetexsize, hwmaxaniso, maxtexsize, hwtexunits, hwvtexunits; +struct cubemapside; -extern Texture *textureload(const char *name, int clamp = 0, bool mipit = true, bool msg = true); -extern int texalign(const void *data, int w, int bpp); -extern bool floatformat(GLenum format); -extern void cleanuptexture(Texture *t); -extern uchar *loadalphamask(Texture *t); -extern Texture *cubemapload(const char *name, bool mipit = true, bool msg = true, bool transient = false); extern void drawcubemap(int size, const vec &o, float yaw, float pitch, const cubemapside &side, bool onlysky = false); -extern void loadshaders(); -extern void setuptexparameters(int tnum, const void *pixels, int clamp, int filter, GLenum format = GL_RGB, GLenum target = GL_TEXTURE_2D, bool swizzle = false); -extern void createtexture(int tnum, int w, int h, const void *pixels, int clamp, int filter, GLenum component = GL_RGB, GLenum target = GL_TEXTURE_2D, int pw = 0, int ph = 0, int pitch = 0, bool resize = true, GLenum format = GL_FALSE, bool swizzle = false); -extern void create3dtexture(int tnum, int w, int h, int d, const void *pixels, int clamp, int filter, GLenum component = GL_RGB, GLenum target = GL_TEXTURE_3D, bool swizzle = false); -extern void blurtexture(int n, int bpp, int w, int h, uchar *dst, const uchar *src, int margin = 0); -extern void blurnormals(int n, int w, int h, bvec *dst, const bvec *src, int margin = 0); -extern GLuint setuppostfx(int w, int h, GLuint outfbo = 0); -extern void cleanuppostfx(bool fullclean = false); -extern void renderpostfx(GLuint outfbo = 0); -extern void initenvmaps(); -extern void genenvmaps(); -extern ushort closestenvmap(const vec &o); -extern ushort closestenvmap(int orient, const ivec &o, int size); -extern GLuint lookupenvmap(ushort emid); -extern GLuint lookupenvmap(Slot &slot); -extern bool reloadtexture(Texture &tex); -extern bool reloadtexture(const char *name); -extern void setuptexcompress(); -extern void clearslots(); extern void compacteditvslots(); extern void compactmruvslots(); -extern void compactvslots(cube *c, int n = 8); -extern void compactvslot(int &index); -extern void compactvslot(VSlot &vs); -extern int compactvslots(bool cull = false); -extern void reloadtextures(); -extern void cleanuptextures(); // pvs extern void clearpvs(); diff --git a/src/engine/grass.cc b/src/engine/grass.cc index 439b118..c34a7eb 100644 --- a/src/engine/grass.cc +++ b/src/engine/grass.cc @@ -1,4 +1,5 @@ #include "blend.hh" +#include "texture.hh" #include "engine.hh" diff --git a/src/engine/light.cc b/src/engine/light.cc index 576b00f..acbcc80 100644 --- a/src/engine/light.cc +++ b/src/engine/light.cc @@ -1,4 +1,5 @@ #include "blend.hh" +#include "texture.hh" #include "engine.hh" diff --git a/src/engine/main.cc b/src/engine/main.cc index 94fd5f5..7fcfcf1 100644 --- a/src/engine/main.cc +++ b/src/engine/main.cc @@ -1,6 +1,8 @@ // main.cpp: initialisation & main loop #include "blend.hh" +#include "shader.hh" +#include "texture.hh" #include "world.hh" #include "engine.hh" diff --git a/src/engine/material.cc b/src/engine/material.cc index 73af957..a5fd8db 100644 --- a/src/engine/material.cc +++ b/src/engine/material.cc @@ -1,4 +1,5 @@ #include "material.hh" +#include "texture.hh" #include "water.hh" #include "engine.hh" diff --git a/src/engine/model.hh b/src/engine/model.hh index b46e761..837b0e8 100644 --- a/src/engine/model.hh +++ b/src/engine/model.hh @@ -1,5 +1,7 @@ enum { MDL_MD2 = 0, MDL_MD3, MDL_MD5, MDL_OBJ, MDL_SMD, MDL_IQM, NUMMODELTYPES }; +struct Shader; + struct model { char *name; diff --git a/src/engine/movie.cc b/src/engine/movie.cc index e30d9eb..e8fb0d0 100644 --- a/src/engine/movie.cc +++ b/src/engine/movie.cc @@ -7,6 +7,8 @@ // avidemux - ok - 3Apr09-RockKeyman:had to swap UV channels as it showed up blue // kino - ok +#include "texture.hh" + #include "engine.hh" VAR(dbgmovie, 0, 0, 1); diff --git a/src/engine/normal.cc b/src/engine/normal.cc index 44002c5..6529b96 100644 --- a/src/engine/normal.cc +++ b/src/engine/normal.cc @@ -1,3 +1,5 @@ +#include "texture.hh" + #include "engine.hh" struct normalkey diff --git a/src/engine/octaedit.cc b/src/engine/octaedit.cc index d63f7f1..a1491d3 100644 --- a/src/engine/octaedit.cc +++ b/src/engine/octaedit.cc @@ -1,5 +1,6 @@ #include "blend.hh" #include "material.hh" +#include "texture.hh" #include "world.hh" #include "engine.hh" diff --git a/src/engine/octarender.cc b/src/engine/octarender.cc index f902ffb..6ecba7c 100644 --- a/src/engine/octarender.cc +++ b/src/engine/octarender.cc @@ -2,6 +2,7 @@ #include "blend.hh" #include "material.hh" +#include "texture.hh" #include "world.hh" #include "engine.hh" diff --git a/src/engine/rendergl.cc b/src/engine/rendergl.cc index c5f968d..8b89127 100644 --- a/src/engine/rendergl.cc +++ b/src/engine/rendergl.cc @@ -3,6 +3,7 @@ #include "aa.hh" #include "blend.hh" #include "material.hh" +#include "texture.hh" #include "water.hh" #include "engine.hh" diff --git a/src/engine/renderlights.cc b/src/engine/renderlights.cc index c04a006..59e480e 100644 --- a/src/engine/renderlights.cc +++ b/src/engine/renderlights.cc @@ -2,6 +2,7 @@ #include "aa.hh" #include "material.hh" +#include "texture.hh" #include "world.hh" #include "engine.hh" diff --git a/src/engine/rendermodel.cc b/src/engine/rendermodel.cc index ac60078..3139c58 100644 --- a/src/engine/rendermodel.cc +++ b/src/engine/rendermodel.cc @@ -1,4 +1,6 @@ #include "aa.hh" +#include "shader.hh" +#include "texture.hh" #include "engine.hh" diff --git a/src/engine/renderparticles.cc b/src/engine/renderparticles.cc index 59e7422..8fadc37 100644 --- a/src/engine/renderparticles.cc +++ b/src/engine/renderparticles.cc @@ -1,5 +1,7 @@ // renderparticles.cpp +#include "shader.hh" +#include "texture.hh" #include "water.hh" #include "world.hh" diff --git a/src/engine/rendersky.cc b/src/engine/rendersky.cc index 91b34ca..39496c4 100644 --- a/src/engine/rendersky.cc +++ b/src/engine/rendersky.cc @@ -1,3 +1,5 @@ +#include "texture.hh" + #include "engine.hh" Texture *sky[6] = { 0, 0, 0, 0, 0, 0 }, *clouds[6] = { 0, 0, 0, 0, 0, 0 }; diff --git a/src/engine/rendertext.cc b/src/engine/rendertext.cc index 0322f6e..6e9150b 100644 --- a/src/engine/rendertext.cc +++ b/src/engine/rendertext.cc @@ -1,3 +1,5 @@ +#include "texture.hh" + #include "engine.hh" static hashnameset fonts; diff --git a/src/engine/renderva.cc b/src/engine/renderva.cc index 8b45974..de64ba9 100644 --- a/src/engine/renderva.cc +++ b/src/engine/renderva.cc @@ -1,6 +1,7 @@ // renderva.cpp: handles the occlusion and rendering of vertex arrays #include "blend.hh" +#include "texture.hh" #include "engine.hh" diff --git a/src/engine/shader.cc b/src/engine/shader.cc index 4e4072d..abc517f 100644 --- a/src/engine/shader.cc +++ b/src/engine/shader.cc @@ -1,5 +1,8 @@ // shader.cpp: OpenGL GLSL shader management +#include "shader.hh" +#include "texture.hh" + #include "engine.hh" Shader *Shader::lastshader = NULL; diff --git a/src/engine/shader.hh b/src/engine/shader.hh new file mode 100644 index 0000000..fdaa618 --- /dev/null +++ b/src/engine/shader.hh @@ -0,0 +1,499 @@ +#ifndef ENGINE_SHADER_HH +#define ENGINE_SHADER_HH + +#include +#include +#include + +struct Slot; +struct VSlot; + +struct GlobalShaderParamState +{ + const char *name; + union + { + float fval[32]; + int ival[32]; + uint uval[32]; + uchar buf[32*sizeof(float)]; + }; + int version; + + static int nextversion; + + void resetversions(); + + void changed() + { + if(++nextversion < 0) resetversions(); + version = nextversion; + } +}; + +struct ShaderParamBinding +{ + int loc, size; + GLenum format; +}; + +struct GlobalShaderParamUse : ShaderParamBinding +{ + + GlobalShaderParamState *param; + int version; + + void flush() + { + if(version == param->version) return; + switch(format) + { + case GL_BOOL: + case GL_FLOAT: glUniform1fv_(loc, size, param->fval); break; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: glUniform2fv_(loc, size, param->fval); break; + case GL_BOOL_VEC3: + case GL_FLOAT_VEC3: glUniform3fv_(loc, size, param->fval); break; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: glUniform4fv_(loc, size, param->fval); break; + case GL_INT: glUniform1iv_(loc, size, param->ival); break; + case GL_INT_VEC2: glUniform2iv_(loc, size, param->ival); break; + case GL_INT_VEC3: glUniform3iv_(loc, size, param->ival); break; + case GL_INT_VEC4: glUniform4iv_(loc, size, param->ival); break; + case GL_UNSIGNED_INT: glUniform1uiv_(loc, size, param->uval); break; + case GL_UNSIGNED_INT_VEC2: glUniform2uiv_(loc, size, param->uval); break; + case GL_UNSIGNED_INT_VEC3: glUniform3uiv_(loc, size, param->uval); break; + case GL_UNSIGNED_INT_VEC4: glUniform4uiv_(loc, size, param->uval); break; + case GL_FLOAT_MAT2: glUniformMatrix2fv_(loc, 1, GL_FALSE, param->fval); break; + case GL_FLOAT_MAT3: glUniformMatrix3fv_(loc, 1, GL_FALSE, param->fval); break; + case GL_FLOAT_MAT4: glUniformMatrix4fv_(loc, 1, GL_FALSE, param->fval); break; + } + version = param->version; + } +}; + +struct LocalShaderParamState : ShaderParamBinding +{ + const char *name; +}; + +struct SlotShaderParam +{ + enum + { + REUSE = 1<<0 + }; + + const char *name; + int loc, flags; + float val[4]; +}; + +struct SlotShaderParamState : LocalShaderParamState +{ + int flags; + float val[4]; + + SlotShaderParamState() {} + SlotShaderParamState(const SlotShaderParam &p) + { + name = p.name; + loc = -1; + size = 1; + format = GL_FLOAT_VEC4; + flags = p.flags; + memcpy(val, p.val, sizeof(val)); + } +}; + +enum +{ + SHADER_DEFAULT = 0, + SHADER_WORLD = 1<<0, + SHADER_ENVMAP = 1<<1, + SHADER_REFRACT = 1<<2, + SHADER_OPTION = 1<<3, + SHADER_DYNAMIC = 1<<4, + SHADER_TRIPLANAR = 1<<5, + + SHADER_INVALID = 1<<8, + SHADER_DEFERRED = 1<<9 +}; + +#define MAXVARIANTROWS 32 + +struct UniformLoc +{ + const char *name, *blockname; + int loc, version, binding, stride, offset, size; + void *data; + 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) {} +}; + +struct AttribLoc +{ + const char *name; + int loc; + AttribLoc(const char *name = NULL, int loc = -1) : name(name), loc(loc) {} +}; + +struct FragDataLoc +{ + const char *name; + int loc; + GLenum format; + int index; + FragDataLoc(const char *name = NULL, int loc = -1, GLenum format = GL_FALSE, int index = 0) : name(name), loc(loc), format(format), index(index) {} +}; + +struct Shader +{ + static Shader *lastshader; + + char *name, *vsstr, *psstr, *defer; + int type; + GLuint program, vsobj, psobj; + vector defaultparams; + vector globalparams; + vector localparams; + vector localparamremap; + Shader *variantshader; + vector variants; + ushort *variantrows; + bool standard, forced, used; + Shader *reusevs, *reuseps; + vector uniformlocs; + vector attriblocs; + vector fragdatalocs; + const void *owner; + + 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) + { + } + + ~Shader() + { + DELETEA(name); + DELETEA(vsstr); + DELETEA(psstr); + DELETEA(defer); + DELETEA(variantrows); + } + + void allocparams(Slot *slot = NULL); + void setslotparams(Slot &slot); + void setslotparams(Slot &slot, VSlot &vslot); + void bindprograms(); + + void flushparams(Slot *slot = NULL) + { + if(!used) { allocparams(slot); used = true; } + loopv(globalparams) globalparams[i].flush(); + } + + void force(); + + bool invalid() const { return (type&SHADER_INVALID)!=0; } + bool deferred() const { return (type&SHADER_DEFERRED)!=0; } + bool loaded() const { return !(type&(SHADER_DEFERRED|SHADER_INVALID)); } + + bool hasoption() const { return (type&SHADER_OPTION)!=0; } + + bool isdynamic() const { return (type&SHADER_DYNAMIC)!=0; } + + static inline bool isnull(const Shader *s) { return !s; } + + bool isnull() const { return isnull(this); } + + int numvariants(int row) const + { + if(row < 0 || row >= MAXVARIANTROWS || !variantrows) return 0; + return variantrows[row+1] - variantrows[row]; + } + + Shader *getvariant(int col, int row) const + { + if(row < 0 || row >= MAXVARIANTROWS || col < 0 || !variantrows) return NULL; + int start = variantrows[row], end = variantrows[row+1]; + return col < end - start ? variants[start + col] : NULL; + } + + void addvariant(int row, Shader *s) + { + if(row < 0 || row >= MAXVARIANTROWS || variants.length() >= USHRT_MAX) return; + if(!variantrows) { variantrows = new ushort[MAXVARIANTROWS+1]; memset(variantrows, 0, (MAXVARIANTROWS+1)*sizeof(ushort)); } + variants.insert(variantrows[row+1], s); + for(int i = row+1; i <= MAXVARIANTROWS; ++i) ++variantrows[i]; + } + + void setvariant_(int col, int row) + { + Shader *s = this; + if(variantrows) + { + int start = variantrows[row], end = variantrows[row+1]; + for(col = min(start + col, end-1); col >= start; --col) if(!variants[col]->invalid()) { s = variants[col]; break; } + } + if(lastshader!=s) s->bindprograms(); + } + + void setvariant(int col, int row) + { + if(isnull() || !loaded()) return; + setvariant_(col, row); + lastshader->flushparams(); + } + + void setvariant(int col, int row, Slot &slot) + { + if(isnull() || !loaded()) return; + setvariant_(col, row); + lastshader->flushparams(&slot); + lastshader->setslotparams(slot); + } + + void setvariant(int col, int row, Slot &slot, VSlot &vslot) + { + if(isnull() || !loaded()) return; + setvariant_(col, row); + lastshader->flushparams(&slot); + lastshader->setslotparams(slot, vslot); + } + + void set_() + { + if(lastshader!=this) bindprograms(); + } + + void set() + { + if(isnull() || !loaded()) return; + set_(); + lastshader->flushparams(); + } + + void set(Slot &slot) + { + if(isnull() || !loaded()) return; + set_(); + lastshader->flushparams(&slot); + lastshader->setslotparams(slot); + } + + void set(Slot &slot, VSlot &vslot) + { + if(isnull() || !loaded()) return; + set_(); + lastshader->flushparams(&slot); + lastshader->setslotparams(slot, vslot); + } + + bool compile(); + void cleanup(bool full = false); + + static int uniformlocversion(); +}; + +struct GlobalShaderParam +{ + const char *name; + GlobalShaderParamState *param; + + GlobalShaderParam(const char *name) : name(name), param(NULL) {} + + GlobalShaderParamState *resolve() + { + extern GlobalShaderParamState *getglobalparam(const char *name); + if(!param) param = getglobalparam(name); + param->changed(); + return param; + } + + void setf(float x = 0, float y = 0, float z = 0, float w = 0) + { + GlobalShaderParamState *g = resolve(); + g->fval[0] = x; + g->fval[1] = y; + g->fval[2] = z; + g->fval[3] = w; + } + void set(const vec &v, float w = 0) { setf(v.x, v.y, v.z, w); } + void set(const vec2 &v, float z = 0, float w = 0) { setf(v.x, v.y, z, w); } + void set(const vec4 &v) { setf(v.x, v.y, v.z, v.w); } + void set(const plane &p) { setf(p.x, p.y, p.z, p.offset); } + void set(const matrix2 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); } + void set(const matrix3 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); } + void set(const matrix4 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); } + + template + void setv(const T *v, int n = 1) { memcpy(resolve()->buf, v, n*sizeof(T)); } + + void seti(int x = 0, int y = 0, int z = 0, int w = 0) + { + GlobalShaderParamState *g = resolve(); + g->ival[0] = x; + g->ival[1] = y; + g->ival[2] = z; + g->ival[3] = w; + } + void set(const ivec &v, int w = 0) { seti(v.x, v.y, v.z, w); } + void set(const ivec2 &v, int z = 0, int w = 0) { seti(v.x, v.y, z, w); } + void set(const ivec4 &v) { seti(v.x, v.y, v.z, v.w); } + + void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0) + { + GlobalShaderParamState *g = resolve(); + g->uval[0] = x; + g->uval[1] = y; + g->uval[2] = z; + g->uval[3] = w; + } + + template + T *reserve(int n = 1) { return (T *)resolve()->buf; } +}; + +struct LocalShaderParam +{ + const char *name; + int loc; + + LocalShaderParam(const char *name) : name(name), loc(-1) {} + + LocalShaderParamState *resolve() + { + Shader *s = Shader::lastshader; + if(!s) return NULL; + if(!s->localparamremap.inrange(loc)) + { + extern int getlocalparam(const char *name); + if(loc == -1) loc = getlocalparam(name); + if(!s->localparamremap.inrange(loc)) return NULL; + } + uchar remap = s->localparamremap[loc]; + return s->localparams.inrange(remap) ? &s->localparams[remap] : NULL; + } + + void setf(float x = 0, float y = 0, float z = 0, float w = 0) + { + ShaderParamBinding *b = resolve(); + if(b) switch(b->format) + { + case GL_BOOL: + case GL_FLOAT: glUniform1f_(b->loc, x); break; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: glUniform2f_(b->loc, x, y); break; + case GL_BOOL_VEC3: + case GL_FLOAT_VEC3: glUniform3f_(b->loc, x, y, z); break; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: glUniform4f_(b->loc, x, y, z, w); break; + case GL_INT: glUniform1i_(b->loc, int(x)); break; + case GL_INT_VEC2: glUniform2i_(b->loc, int(x), int(y)); break; + case GL_INT_VEC3: glUniform3i_(b->loc, int(x), int(y), int(z)); break; + case GL_INT_VEC4: glUniform4i_(b->loc, int(x), int(y), int(z), int(w)); break; + case GL_UNSIGNED_INT: glUniform1ui_(b->loc, uint(x)); break; + case GL_UNSIGNED_INT_VEC2: glUniform2ui_(b->loc, uint(x), uint(y)); break; + case GL_UNSIGNED_INT_VEC3: glUniform3ui_(b->loc, uint(x), uint(y), uint(z)); break; + case GL_UNSIGNED_INT_VEC4: glUniform4ui_(b->loc, uint(x), uint(y), uint(z), uint(w)); break; + } + } + void set(const vec &v, float w = 0) { setf(v.x, v.y, v.z, w); } + void set(const vec2 &v, float z = 0, float w = 0) { setf(v.x, v.y, z, w); } + void set(const vec4 &v) { setf(v.x, v.y, v.z, v.w); } + void set(const plane &p) { setf(p.x, p.y, p.z, p.offset); } + void setv(const float *f, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1fv_(b->loc, n, f); } + void setv(const vec *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform3fv_(b->loc, n, v->v); } + void setv(const vec2 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform2fv_(b->loc, n, v->v); } + void setv(const vec4 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4fv_(b->loc, n, v->v); } + void setv(const plane *p, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4fv_(b->loc, n, p->v); } + void setv(const matrix2 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix2fv_(b->loc, n, GL_FALSE, m->a.v); } + void setv(const matrix3 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix3fv_(b->loc, n, GL_FALSE, m->a.v); } + void setv(const matrix4 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix4fv_(b->loc, n, GL_FALSE, m->a.v); } + void set(const matrix2 &m) { setv(&m); } + void set(const matrix3 &m) { setv(&m); } + void set(const matrix4 &m) { setv(&m); } + + template + void sett(T x, T y, T z, T w) + { + ShaderParamBinding *b = resolve(); + if(b) switch(b->format) + { + case GL_FLOAT: glUniform1f_(b->loc, x); break; + case GL_FLOAT_VEC2: glUniform2f_(b->loc, x, y); break; + case GL_FLOAT_VEC3: glUniform3f_(b->loc, x, y, z); break; + case GL_FLOAT_VEC4: glUniform4f_(b->loc, x, y, z, w); break; + case GL_BOOL: + case GL_INT: glUniform1i_(b->loc, x); break; + case GL_BOOL_VEC2: + case GL_INT_VEC2: glUniform2i_(b->loc, x, y); break; + case GL_BOOL_VEC3: + case GL_INT_VEC3: glUniform3i_(b->loc, x, y, z); break; + case GL_BOOL_VEC4: + case GL_INT_VEC4: glUniform4i_(b->loc, x, y, z, w); break; + case GL_UNSIGNED_INT: glUniform1ui_(b->loc, x); break; + case GL_UNSIGNED_INT_VEC2: glUniform2ui_(b->loc, x, y); break; + case GL_UNSIGNED_INT_VEC3: glUniform3ui_(b->loc, x, y, z); break; + case GL_UNSIGNED_INT_VEC4: glUniform4ui_(b->loc, x, y, z, w); break; + } + } + void seti(int x = 0, int y = 0, int z = 0, int w = 0) { sett(x, y, z, w); } + void set(const ivec &v, int w = 0) { seti(v.x, v.y, v.z, w); } + void set(const ivec2 &v, int z = 0, int w = 0) { seti(v.x, v.y, z, w); } + void set(const ivec4 &v) { seti(v.x, v.y, v.z, v.w); } + void setv(const int *i, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1iv_(b->loc, n, i); } + void setv(const ivec *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform3iv_(b->loc, n, v->v); } + void setv(const ivec2 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform2iv_(b->loc, n, v->v); } + void setv(const ivec4 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4iv_(b->loc, n, v->v); } + + void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0) { sett(x, y, z, w); } + void setv(const uint *u, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1uiv_(b->loc, n, u); } +}; + +#define LOCALPARAM(name, vals) do { static LocalShaderParam param( #name ); param.set(vals); } while(0) +#define LOCALPARAMF(name, ...) do { static LocalShaderParam param( #name ); param.setf(__VA_ARGS__); } while(0) +#define LOCALPARAMI(name, ...) do { static LocalShaderParam param( #name ); param.seti(__VA_ARGS__); } while(0) +#define LOCALPARAMV(name, vals, num) do { static LocalShaderParam param( #name ); param.setv(vals, num); } while(0) +#define GLOBALPARAM(name, vals) do { static GlobalShaderParam param( #name ); param.set(vals); } while(0) +#define GLOBALPARAMF(name, ...) do { static GlobalShaderParam param( #name ); param.setf(__VA_ARGS__); } while(0) +#define GLOBALPARAMI(name, ...) do { static GlobalShaderParam param( #name ); param.seti(__VA_ARGS__); } while(0) +#define GLOBALPARAMV(name, vals, num) do { static GlobalShaderParam param( #name ); param.setv(vals, num); } while(0) + +#define SETSHADER(name, ...) \ + do { \ + static Shader *name##shader = NULL; \ + if(!name##shader) name##shader = lookupshaderbyname(#name); \ + name##shader->set(__VA_ARGS__); \ + } while(0) +#define SETVARIANT(name, ...) \ + do { \ + static Shader *name##shader = NULL; \ + if(!name##shader) name##shader = lookupshaderbyname(#name); \ + name##shader->setvariant(__VA_ARGS__); \ + } while(0) + +void resetslotshader(); +void setslotshader(Slot &s); +void linkslotshader(Slot &s, bool load = true); +void linkvslotshader(VSlot &s, bool load = true); + +bool shouldreuseparams(Slot &s, VSlot &p); +void setupshaders(); +void loadshaders(); +void reloadshaders(); +void cleanupshaders(); + +extern int maxvsuniforms, maxfsuniforms; + +extern Shader *nullshader, *hudshader, *hudtextshader, *hudnotextureshader, *nocolorshader, *foggedshader, *foggednotextureshader, *ldrshader, *ldrnotextureshader, *stdworldshader; + +const char *getshaderparamname(const char *name, bool insert = true); +Shader *lookupshaderbyname(const char *name); +Shader *useshaderbyname(const char *name); +Shader *generateshader(const char *name, const char *cmd, ...); + +GLuint setuppostfx(int w, int h, GLuint outfbo = 0); +void cleanuppostfx(bool fullclean = false); +void renderpostfx(GLuint outfbo = 0); + +#endif diff --git a/src/engine/stain.cc b/src/engine/stain.cc index 41555a1..ef571a4 100644 --- a/src/engine/stain.cc +++ b/src/engine/stain.cc @@ -1,4 +1,5 @@ #include "material.hh" +#include "texture.hh" #include "engine.hh" diff --git a/src/engine/textedit.hh b/src/engine/textedit.hh deleted file mode 100644 index d97c9ab..0000000 --- a/src/engine/textedit.hh +++ /dev/null @@ -1,790 +0,0 @@ - -struct editline -{ - enum { CHUNKSIZE = 256 }; - - char *text; - int len, maxlen; - - editline() : text(NULL), len(0), maxlen(0) {} - editline(const char *init) : text(NULL), len(0), maxlen(0) - { - set(init); - } - - bool empty() { return len <= 0; } - - void clear() - { - DELETEA(text); - len = maxlen = 0; - } - - bool grow(int total, const char *fmt = "", ...) - { - if(total + 1 <= maxlen) return false; - maxlen = (total + CHUNKSIZE) - total%CHUNKSIZE; - char *newtext = new char[maxlen]; - if(fmt) - { - va_list args; - va_start(args, fmt); - vformatstring(newtext, fmt, args, maxlen); - va_end(args); - } - else newtext[0] = '\0'; - DELETEA(text); - text = newtext; - return true; - } - - void set(const char *str, int slen = -1) - { - if(slen < 0) - { - slen = strlen(str); - if(!grow(slen, "%s", str)) memcpy(text, str, slen + 1); - } - else - { - grow(slen); - memcpy(text, str, slen); - text[slen] = '\0'; - } - len = slen; - } - - void prepend(const char *str) - { - int slen = strlen(str); - if(!grow(slen + len, "%s%s", str, text ? text : "")) - { - memmove(&text[slen], text, len + 1); - memcpy(text, str, slen + 1); - } - len += slen; - } - - void append(const char *str) - { - int slen = strlen(str); - if(!grow(len + slen, "%s%s", text ? text : "", str)) memcpy(&text[len], str, slen + 1); - len += slen; - } - - bool read(stream *f, int chop = -1) - { - if(chop < 0) chop = INT_MAX; else chop++; - set(""); - while(len + 1 < chop && f->getline(&text[len], min(maxlen, chop) - len)) - { - len += strlen(&text[len]); - if(len > 0 && text[len-1] == '\n') - { - text[--len] = '\0'; - return true; - } - if(len + 1 >= maxlen && len + 1 < chop) grow(len + CHUNKSIZE, "%s", text); - } - if(len + 1 >= chop) - { - char buf[CHUNKSIZE]; - while(f->getline(buf, sizeof(buf))) - { - int blen = strlen(buf); - if(blen > 0 && buf[blen-1] == '\n') return true; - } - } - return len > 0; - } - - void del(int start, int count) - { - if(!text) return; - if(start < 0) { count += start; start = 0; } - if(count <= 0 || start >= len) return; - if(start + count > len) count = len - start - 1; - memmove(&text[start], &text[start+count], len + 1 - (start + count)); - len -= count; - } - - void chop(int newlen) - { - if(!text) return; - len = clamp(newlen, 0, len); - text[len] = '\0'; - } - - void insert(char *str, int start, int count = 0) - { - if(count <= 0) count = strlen(str); - start = clamp(start, 0, len); - grow(len + count, "%s", text ? text : ""); - memmove(&text[start + count], &text[start], len - start + 1); - memcpy(&text[start], str, count); - len += count; - } - - void combinelines(vector &src) - { - if(src.empty()) set(""); - else loopv(src) - { - if(i) append("\n"); - if(!i) set(src[i].text, src[i].len); - else insert(src[i].text, len, src[i].len); - } - } -}; - -enum { EDITORFOCUSED = 1, EDITORUSED, EDITORFOREVER }; - -struct editor -{ - int mode; //editor mode - 1= keep while focused, 2= keep while used in gui, 3= keep forever (i.e. until mode changes) - bool active, rendered; - const char *name; - const char *filename; - - int cx, cy; // cursor position - ensured to be valid after a region() or currentline() - int mx, my; // selection mark, mx=-1 if following cursor - avoid direct access, instead use region() - int maxx, maxy; // maxy=-1 if unlimited lines, 1 if single line editor - - int scrolly; // vertical scroll offset - - bool linewrap; - int pixelwidth; // required for up/down/hit/draw/bounds - int pixelheight; // -1 for variable sized, i.e. from bounds() - - vector lines; // MUST always contain at least one line! - - editor(const char *name, int mode, const char *initval) : - mode(mode), active(true), rendered(false), name(newstring(name)), filename(NULL), - cx(0), cy(0), mx(-1), maxx(-1), maxy(-1), scrolly(0), linewrap(false), pixelwidth(-1), pixelheight(-1) - { - //printf("editor %08x '%s'\n", this, name); - lines.add().set(initval ? initval : ""); - } - - ~editor() - { - //printf("~editor %08x '%s'\n", this, name); - DELETEA(name); - DELETEA(filename); - clear(NULL); - } - - bool empty() { return lines.length() == 1 && lines[0].empty(); } - - void clear(const char *init = "") - { - cx = cy = 0; - mark(false); - loopv(lines) lines[i].clear(); - lines.shrink(0); - if(init) lines.add().set(init); - } - - void init(const char *inittext) - { - if(strcmp(lines[0].text, inittext)) clear(inittext); - } - - void updateheight() - { - int width; - text_bounds(lines[0].text, width, pixelheight, pixelwidth); - } - - void setfile(const char *fname) - { - DELETEA(filename); - if(fname) filename = newstring(fname); - } - - void load() - { - if(!filename) return; - clear(NULL); - stream *file = openutf8file(filename, "r"); - if(file) - { - while(lines.add().read(file, maxx) && (maxy < 0 || lines.length() <= maxy)); - lines.pop().clear(); - delete file; - } - if(lines.empty()) lines.add().set(""); - } - - void save() - { - if(!filename) return; - stream *file = openutf8file(filename, "w"); - if(!file) return; - loopv(lines) file->putline(lines[i].text); - delete file; - } - - void mark(bool enable) - { - mx = (enable) ? cx : -1; - my = cy; - } - - void selectall() - { - mx = my = INT_MAX; - cx = cy = 0; - } - - // constrain results to within buffer - s=start, e=end, return true if a selection range - // also ensures that cy is always within lines[] and cx is valid - bool region(int &sx, int &sy, int &ex, int &ey) - { - int n = lines.length(); - ASSERT(n != 0); - if(cy < 0) cy = 0; else if(cy >= n) cy = n-1; - int len = lines[cy].len; - if(cx < 0) cx = 0; else if(cx > len) cx = len; - if(mx >= 0) - { - if(my < 0) my = 0; else if(my >= n) my = n-1; - len = lines[my].len; - if(mx > len) mx = len; - sx = mx; sy = my; - } - else { sx = cx; sy = cy; } - ex = cx; - ey = cy; - if(sy > ey) { swap(sy, ey); swap(sx, ex); } - else if(sy==ey && sx > ex) swap(sx, ex); - if(mx >= 0) ex++; - return (sx != ex) || (sy != ey); - } - - bool region() { int sx, sy, ex, ey; return region(sx, sy, ex, ey); } - - // also ensures that cy is always within lines[] and cx is valid - editline ¤tline() - { - int n = lines.length(); - ASSERT(n != 0); - if(cy < 0) cy = 0; else if(cy >= n) cy = n-1; - if(cx < 0) cx = 0; else if(cx > lines[cy].len) cx = lines[cy].len; - return lines[cy]; - } - - void copyselectionto(editor *b) - { - if(b==this) return; - - b->clear(NULL); - int sx, sy, ex, ey; - region(sx, sy, ex, ey); - loopi(1+ey-sy) - { - if(b->maxy != -1 && b->lines.length() >= b->maxy) break; - int y = sy+i; - char *line = lines[y].text; - int len = lines[y].len; - if(y == sy && y == ey) - { - line += sx; - len = ex - sx; - } - else if(y == sy) line += sx; - else if(y == ey) len = ex; - b->lines.add().set(line, len); - } - if(b->lines.empty()) b->lines.add().set(""); - } - - char *tostring() - { - int len = 0; - loopv(lines) len += lines[i].len + 1; - char *str = newstring(len); - int offset = 0; - loopv(lines) - { - editline &l = lines[i]; - memcpy(&str[offset], l.text, l.len); - offset += l.len; - str[offset++] = '\n'; - } - str[offset] = '\0'; - return str; - } - - char *selectiontostring() - { - vector buf; - int sx, sy, ex, ey; - region(sx, sy, ex, ey); - loopi(1+ey-sy) - { - int y = sy+i; - char *line = lines[y].text; - int len = lines[y].len; - if(y == sy && y == ey) - { - line += sx; - len = ex - sx; - } - else if(y == sy) line += sx; - else if(y == ey) len = ex; - buf.put(line, len); - buf.add('\n'); - } - buf.add('\0'); - return newstring(buf.getbuf(), buf.length()-1); - } - - void removelines(int start, int count) - { - loopi(count) lines[start+i].clear(); - lines.remove(start, count); - } - - bool del() // removes the current selection (if any) - { - int sx, sy, ex, ey; - if(!region(sx, sy, ex, ey)) - { - mark(false); - return false; - } - if(sy == ey) - { - if(sx == 0 && ex == lines[ey].len) removelines(sy, 1); - else lines[sy].del(sx, ex - sx); - } - else - { - if(ey > sy+1) { removelines(sy+1, ey-(sy+1)); ey = sy+1; } - if(ex == lines[ey].len) removelines(ey, 1); else lines[ey].del(0, ex); - if(sx == 0) removelines(sy, 1); else lines[sy].del(sx, lines[sy].len - sx); - } - if(lines.empty()) lines.add().set(""); - mark(false); - cx = sx; - cy = sy; - editline ¤t = currentline(); - if(cx >= current.len && cy < lines.length() - 1) - { - current.append(lines[cy+1].text); - removelines(cy + 1, 1); - } - return true; - } - - void insert(char ch) - { - del(); - editline ¤t = currentline(); - if(ch == '\n') - { - if(maxy == -1 || cy < maxy-1) - { - editline newline(¤t.text[cx]); - current.chop(cx); - cy = min(lines.length(), cy+1); - lines.insert(cy, newline); - } - else current.chop(cx); - cx = 0; - } - else - { - int len = current.len; - if(maxx >= 0 && len > maxx-1) len = maxx-1; - if(cx <= len) current.insert(&ch, cx++, 1); - } - } - - void insert(const char *s) - { - while(*s) insert(*s++); - } - - void insertallfrom(editor *b) - { - if(b==this) return; - - del(); - - if(b->lines.length() == 1 || maxy == 1) - { - editline ¤t = currentline(); - char *str = b->lines[0].text; - int slen = b->lines[0].len; - if(maxx >= 0 && b->lines[0].len + cx > maxx) slen = maxx-cx; - if(slen > 0) - { - int len = current.len; - if(maxx >= 0 && slen + cx + len > maxx) len = max(0, maxx-(cx+slen)); - current.insert(str, cx, slen); - cx += slen; - } - } - else - { - loopv(b->lines) - { - if(!i) - { - lines[cy++].append(b->lines[i].text); - } - else if(i >= b->lines.length()) - { - cx = b->lines[i].len; - lines[cy].prepend(b->lines[i].text); - } - else if(maxy < 0 || lines.length() < maxy) lines.insert(cy++, editline(b->lines[i].text)); - } - } - } - - void scrollup() - { - cy--; - } - - void scrolldown() - { - cy++; - } - - void key(int code) - { - switch(code) - { - case SDLK_UP: - if(linewrap) - { - int x, y; - char *str = currentline().text; - text_pos(str, cx+1, x, y, pixelwidth); - if(y > 0) { cx = text_visible(str, x, y-FONTH, pixelwidth); break; } - } - cy--; - break; - case SDLK_DOWN: - if(linewrap) - { - int x, y, width, height; - char *str = currentline().text; - text_pos(str, cx, x, y, pixelwidth); - text_bounds(str, width, height, pixelwidth); - y += FONTH; - if(y < height) { cx = text_visible(str, x, y, pixelwidth); break; } - } - cy++; - break; - case SDLK_PAGEUP: - cy-=pixelheight/FONTH; - break; - case SDLK_PAGEDOWN: - cy+=pixelheight/FONTH; - break; - case SDLK_HOME: - cx = cy = 0; - break; - case SDLK_END: - cx = cy = INT_MAX; - break; - case SDLK_LEFT: - cx--; - break; - case SDLK_RIGHT: - cx++; - break; - case SDLK_DELETE: - if(!del()) - { - editline ¤t = currentline(); - if(cx < current.len) current.del(cx, 1); - else if(cy < lines.length()-1) - { //combine with next line - current.append(lines[cy+1].text); - removelines(cy+1, 1); - } - } - break; - case SDLK_BACKSPACE: - if(!del()) - { - editline ¤t = currentline(); - if(cx > 0) current.del(--cx, 1); - else if(cy > 0) - { //combine with previous line - cx = lines[cy-1].len; - lines[cy-1].append(current.text); - removelines(cy--, 1); - } - } - break; - case SDLK_LSHIFT: - case SDLK_RSHIFT: - break; - case SDLK_RETURN: - insert('\n'); - break; - case SDLK_TAB: - insert('\t'); - break; - } - } - - void input(const char *str, int len) - { - loopi(len) insert(str[i]); - } - - void hit(int hitx, int hity, bool dragged) - { - int maxwidth = linewrap?pixelwidth:-1; - int h = 0; - for(int i = scrolly; i < lines.length(); i++) - { - int width, height; - text_bounds(lines[i].text, width, height, maxwidth); - if(h + height > pixelheight) break; - - if(hity >= h && hity <= h+height) - { - int x = text_visible(lines[i].text, hitx, hity-h, maxwidth); - if(dragged) { mx = x; my = i; } else { cx = x; cy = i; }; - break; - } - h+=height; - } - } - - int limitscrolly() - { - int maxwidth = linewrap?pixelwidth:-1; - int slines = lines.length(); - for(int ph = pixelheight; slines > 0 && ph > 0;) - { - int width, height; - text_bounds(lines[slines-1].text, width, height, maxwidth); - if(height > ph) break; - ph -= height; - slines--; - } - return slines; - } - - void draw(int x, int y, int color, bool hit) - { - int maxwidth = linewrap?pixelwidth:-1; - - int sx, sy, ex, ey; - bool selection = region(sx, sy, ex, ey); - - // fix scrolly so that is always on screen - if(cy < scrolly) scrolly = cy; - else - { - if(scrolly < 0) scrolly = 0; - int h = 0; - for(int i = cy; i >= scrolly; i--) - { - int width, height; - text_bounds(lines[i].text, width, height, maxwidth); - if(h + height > pixelheight) { scrolly = i+1; break; } - h += height; - } - } - - if(selection) - { - // convert from cursor coords into pixel coords - int psx, psy, pex, pey; - text_pos(lines[sy].text, sx, psx, psy, maxwidth); - text_pos(lines[ey].text, ex, pex, pey, maxwidth); - int maxy = lines.length(); - int h = 0; - for(int i = scrolly; i < maxy; i++) - { - int width, height; - text_bounds(lines[i].text, width, height, maxwidth); - if(h + height > pixelheight) { maxy = i; break; } - if(i == sy) psy += h; - if(i == ey) { pey += h; break; } - h += height; - } - maxy--; - - if(ey >= scrolly && sy <= maxy) - { - // crop top/bottom within window - if(sy < scrolly) { sy = scrolly; psy = 0; psx = 0; } - if(ey > maxy) { ey = maxy; pey = pixelheight - FONTH; pex = pixelwidth; } - - hudnotextureshader->set(); - gle::colorub(0xA0, 0x80, 0x80); - gle::defvertex(2); - gle::begin(GL_QUADS); - if(psy == pey) - { - gle::attribf(x+psx, y+psy); - gle::attribf(x+pex, y+psy); - gle::attribf(x+pex, y+pey+FONTH); - gle::attribf(x+psx, y+pey+FONTH); - } - else - { gle::attribf(x+psx, y+psy); - gle::attribf(x+psx, y+psy+FONTH); - gle::attribf(x+pixelwidth, y+psy+FONTH); - gle::attribf(x+pixelwidth, y+psy); - if(pey-psy > FONTH) - { - gle::attribf(x, y+psy+FONTH); - gle::attribf(x+pixelwidth, y+psy+FONTH); - gle::attribf(x+pixelwidth, y+pey); - gle::attribf(x, y+pey); - } - gle::attribf(x, y+pey); - gle::attribf(x, y+pey+FONTH); - gle::attribf(x+pex, y+pey+FONTH); - gle::attribf(x+pex, y+pey); - } - gle::end(); - } - } - - int h = 0; - for(int i = scrolly; i < lines.length(); i++) - { - int width, height; - text_bounds(lines[i].text, width, height, maxwidth); - if(h + height > pixelheight) break; - - draw_text(lines[i].text, x, y+h, color>>16, (color>>8)&0xFF, color&0xFF, 0xFF, hit&&(cy==i)?cx:-1, maxwidth); - if(linewrap && height > FONTH) // line wrap indicator - { - hudnotextureshader->set(); - gle::colorub(0x80, 0xA0, 0x80); - gle::defvertex(2); - gle::begin(GL_TRIANGLE_STRIP); - gle::attribf(x, y+h+FONTH); - gle::attribf(x, y+h+height); - gle::attribf(x-FONTW/2, y+h+FONTH); - gle::attribf(x-FONTW/2, y+h+height); - gle::end(); - } - h+=height; - } - } -}; - -static vector editors; -static editor *textfocus = NULL; - -static void readyeditors() -{ - loopv(editors) editors[i]->active = (editors[i]->mode==EDITORFOREVER); -} - -static void flusheditors() -{ - loopvrev(editors) if(!editors[i]->active) - { - editor *e = editors.remove(i); - if(e == textfocus) textfocus = NULL; - delete e; - } -} - -static editor *useeditor(const char *name, int mode, bool focus, const char *initval = NULL) -{ - loopv(editors) if(!strcmp(editors[i]->name, name)) - { - editor *e = editors[i]; - if(focus) textfocus = e; - e->active = true; - return e; - } - if(mode < 0) return NULL; - editor *e = new editor(name, mode, initval); - editors.add(e); - if(focus) textfocus = e; - return e; -} - - -#define TEXTCOMMAND(f, s, d, body) ICOMMAND(f, s, d,\ - if(!textfocus || identflags&IDF_OVERRIDDEN) return;\ - body\ -) - -ICOMMAND(textlist, "", (), // @DEBUG return list of all the editors - vector s; - loopv(editors) - { - if(i > 0) s.put(", ", 2); - s.put(editors[i]->name, strlen(editors[i]->name)); - } - s.add('\0'); - result(s.getbuf()); -); -TEXTCOMMAND(textshow, "", (), // @DEBUG return the start of the buffer - editline line; - line.combinelines(textfocus->lines); - result(line.text); - line.clear(); -); -ICOMMAND(textfocus, "si", (char *name, int *mode), // focus on a (or create a persistent) specific editor, else returns current name - if(identflags&IDF_OVERRIDDEN) return; - if(*name) useeditor(name, *mode<=0 ? EDITORFOREVER : *mode, true); - else if(editors.length() > 0) result(editors.last()->name); -); -TEXTCOMMAND(textprev, "", (), editors.insert(0, textfocus); editors.pop();); // return to the previous editor -TEXTCOMMAND(textmode, "i", (int *m), // (1= keep while focused, 2= keep while used in gui, 3= keep forever (i.e. until mode changes)) topmost editor, return current setting if no args - if(*m) textfocus->mode = *m; - else intret(textfocus->mode); -); -TEXTCOMMAND(textsave, "s", (char *file), // saves the topmost (filename is optional) - if(*file) textfocus->setfile(path(file, true)); - textfocus->save(); -); -TEXTCOMMAND(textload, "s", (char *file), // loads into the textfocusmost editor, returns filename if no args - if(*file) - { - textfocus->setfile(path(file, true)); - textfocus->load(); - } - else if(textfocus->filename) result(textfocus->filename); -); -ICOMMAND(textinit, "sss", (char *name, char *file, char *initval), // loads into named editor if no file assigned and editor has been rendered -{ - if(identflags&IDF_OVERRIDDEN) return; - editor *e = NULL; - loopv(editors) if(!strcmp(editors[i]->name, name)) { e = editors[i]; break; } - if(e && e->rendered && !e->filename && *file && (e->lines.empty() || (e->lines.length() == 1 && !strcmp(e->lines[0].text, initval)))) - { - e->setfile(path(file, true)); - e->load(); - } -}); - -#define PASTEBUFFER "#pastebuffer" - -TEXTCOMMAND(textcopy, "", (), editor *b = useeditor(PASTEBUFFER, EDITORFOREVER, false); textfocus->copyselectionto(b);); -TEXTCOMMAND(textpaste, "", (), editor *b = useeditor(PASTEBUFFER, EDITORFOREVER, false); textfocus->insertallfrom(b);); -TEXTCOMMAND(textmark, "i", (int *m), // (1=mark, 2=unmark), return current mark setting if no args - if(*m) textfocus->mark(*m==1); - else intret(textfocus->region() ? 1 : 2); -); -TEXTCOMMAND(textselectall, "", (), textfocus->selectall();); -TEXTCOMMAND(textclear, "", (), textfocus->clear();); -TEXTCOMMAND(textcurrentline, "", (), result(textfocus->currentline().text);); - -TEXTCOMMAND(textexec, "i", (int *selected), // execute script commands from the buffer (0=all, 1=selected region only) - char *script = *selected ? textfocus->selectiontostring() : textfocus->tostring(); - execute(script); - delete[] script; -); - diff --git a/src/engine/texture.cc b/src/engine/texture.cc index 59296df..eced773 100644 --- a/src/engine/texture.cc +++ b/src/engine/texture.cc @@ -1,6 +1,8 @@ // texture.cpp: texture slot management #include "material.hh" +#include "shader.hh" +#include "texture.hh" #include "engine.hh" @@ -10,6 +12,8 @@ #include "SDL_image.h" #endif +static bool loaddds(const char *filename, ImageData &image, int force = 0); + #ifndef SDL_IMAGE_VERSION_ATLEAST #define SDL_IMAGE_VERSION_ATLEAST(X, Y, Z) \ (SDL_VERSIONNUM(SDL_IMAGE_MAJOR_VERSION, SDL_IMAGE_MINOR_VERSION, SDL_IMAGE_PATCHLEVEL) >= SDL_VERSIONNUM(X, Y, Z)) @@ -359,7 +363,7 @@ static void reorientrgtc(GLenum format, int blocksize, int w, int h, uchar *src, } \ } -void forcergbimage(ImageData &s) +static void forcergbimage(ImageData &s) { if(s.bpp >= 3) return; ImageData d(s.w, s.h, 3); @@ -379,7 +383,8 @@ void forcergbimage(ImageData &s) } \ } -void forcergbaimage(ImageData &s) +#if 0 +static void forcergbaimage(ImageData &s) { if(s.bpp >= 4) return; ImageData d(s.w, s.h, 4); @@ -387,8 +392,9 @@ void forcergbaimage(ImageData &s) else readwritetex(d, s, { dst[0] = dst[1] = dst[2] = src[0]; }); s.replace(d); } +#endif -void swizzleimage(ImageData &s) +static void swizzleimage(ImageData &s) { if(s.bpp==2) { @@ -404,14 +410,14 @@ void swizzleimage(ImageData &s) } } -void scaleimage(ImageData &s, int w, int h) +static void scaleimage(ImageData &s, int w, int h) { ImageData d(w, h, s.bpp); scaletexture(s.data, s.w, s.h, s.bpp, s.pitch, d.data, w, h); s.replace(d); } -void texreorient(ImageData &s, bool flipx, bool flipy, bool swapxy, int type = TEX_DIFFUSE) +static void texreorient(ImageData &s, bool flipx, bool flipy, bool swapxy, int type = TEX_DIFFUSE) { ImageData d(swapxy ? s.h : s.w, swapxy ? s.w : s.h, s.bpp, s.levels, s.align, s.compressed); switch(s.compressed) @@ -464,7 +470,7 @@ extern const texrotation texrotations[8] = { true, true, true }, // 7: flipped transpose }; -void texrotate(ImageData &s, int numrots, int type = TEX_DIFFUSE) +static void texrotate(ImageData &s, int numrots, int type = TEX_DIFFUSE) { if(numrots>=1 && numrots<=7) { @@ -473,7 +479,7 @@ void texrotate(ImageData &s, int numrots, int type = TEX_DIFFUSE) } } -void texoffset(ImageData &s, int xoffset, int yoffset) +static void texoffset(ImageData &s, int xoffset, int yoffset) { xoffset = max(xoffset, 0); xoffset %= s.w; @@ -492,7 +498,7 @@ void texoffset(ImageData &s, int xoffset, int yoffset) s.replace(d); } -void texcrop(ImageData &s, int x, int y, int w, int h) +static void texcrop(ImageData &s, int x, int y, int w, int h) { x = clamp(x, 0, s.w); y = clamp(y, 0, s.h); @@ -510,7 +516,7 @@ void texcrop(ImageData &s, int x, int y, int w, int h) s.replace(d); } -void texmad(ImageData &s, const vec &mul, const vec &add) +static void texmad(ImageData &s, const vec &mul, const vec &add) { if(s.bpp < 3 && (mul.x != mul.y || mul.y != mul.z || add.x != add.y || add.y != add.z)) swizzleimage(s); @@ -520,7 +526,7 @@ void texmad(ImageData &s, const vec &mul, const vec &add) ); } -void texcolorify(ImageData &s, const vec &color, vec weights) +static void texcolorify(ImageData &s, const vec &color, vec weights) { if(s.bpp < 3) return; if(weights.iszero()) weights = vec(0.21f, 0.72f, 0.07f); @@ -530,7 +536,7 @@ void texcolorify(ImageData &s, const vec &color, vec weights) ); } -void texcolormask(ImageData &s, const vec &color1, const vec &color2) +static void texcolormask(ImageData &s, const vec &color1, const vec &color2) { if(s.bpp < 4) return; ImageData d(s.w, s.h, 3); @@ -542,13 +548,13 @@ void texcolormask(ImageData &s, const vec &color1, const vec &color2) s.replace(d); } -void texdup(ImageData &s, int srcchan, int dstchan) +static void texdup(ImageData &s, int srcchan, int dstchan) { if(srcchan==dstchan || max(srcchan, dstchan) >= s.bpp) return; writetex(s, dst[dstchan] = dst[srcchan]); } -void texmix(ImageData &s, int c1, int c2, int c3, int c4) +static void texmix(ImageData &s, int c1, int c2, int c3, int c4) { int numchans = c1 < 0 ? 0 : (c2 < 0 ? 1 : (c3 < 0 ? 2 : (c4 < 0 ? 3 : 4))); if(numchans <= 0) return; @@ -565,7 +571,7 @@ void texmix(ImageData &s, int c1, int c2, int c3, int c4) s.replace(d); } -void texgrey(ImageData &s) +static void texgrey(ImageData &s) { if(s.bpp <= 2) return; ImageData d(s.w, s.h, s.bpp >= 4 ? 2 : 1); @@ -583,7 +589,7 @@ void texgrey(ImageData &s) s.replace(d); } -void texpremul(ImageData &s) +static void texpremul(ImageData &s) { switch(s.bpp) { @@ -603,7 +609,7 @@ void texpremul(ImageData &s) } } -void texagrad(ImageData &s, float x2, float y2, float x1, float y1) +static void texagrad(ImageData &s, float x2, float y2, float x1, float y1) { if(s.bpp != 2 && s.bpp != 4) return; y1 = 1 - y1; @@ -634,7 +640,7 @@ void texagrad(ImageData &s, float x2, float y2, float x1, float y1) } } -void texblend(ImageData &d, ImageData &s, ImageData &m) +static void texblend(ImageData &d, ImageData &s, ImageData &m) { if(s.w != d.w || s.h != d.h) scaleimage(s, d.w, d.h); if(m.w != d.w || m.h != d.h) scaleimage(m, d.w, d.h); @@ -713,7 +719,7 @@ void setuptexcompress() glHint(GL_TEXTURE_COMPRESSION_HINT, hint); } -GLenum compressedformat(GLenum format, int w, int h, int force = 0) +static GLenum compressedformat(GLenum format, int w, int h, int force = 0) { if(usetexcompress && texcompress && force >= 0 && (force || max(w, h) >= texcompress)) switch(format) { @@ -734,7 +740,7 @@ GLenum compressedformat(GLenum format, int w, int h, int force = 0) return format; } -int formatsize(GLenum format) +static int formatsize(GLenum format) { switch(format) { @@ -751,7 +757,7 @@ int formatsize(GLenum format) VARFP(usenp2, 0, 1, 1, initwarning("texture quality", INIT_LOAD)); -void resizetexture(int w, int h, bool mipmap, bool canreduce, GLenum target, int compress, int &tw, int &th) +static void resizetexture(int w, int h, bool mipmap, bool canreduce, GLenum target, int compress, int &tw, int &th) { int hwlimit = target==GL_TEXTURE_CUBE_MAP ? hwcubetexsize : hwtexsize, sizelimit = mipmap && maxtexsize ? min(maxtexsize, hwlimit) : hwlimit; @@ -782,7 +788,7 @@ void resizetexture(int w, int h, bool mipmap, bool canreduce, GLenum target, int } } -void uploadtexture(GLenum target, GLenum internal, int tw, int th, GLenum format, GLenum type, const void *pixels, int pw, int ph, int pitch, bool mipmap) +static void uploadtexture(GLenum target, GLenum internal, int tw, int th, GLenum format, GLenum type, const void *pixels, int pw, int ph, int pitch, bool mipmap) { int bpp = formatsize(format), row = 0, rowalign = 0; if(!pitch) pitch = pw*bpp; @@ -827,7 +833,7 @@ void uploadtexture(GLenum target, GLenum internal, int tw, int th, GLenum format if(buf) delete[] buf; } -void uploadcompressedtexture(GLenum target, GLenum subtarget, GLenum format, int w, int h, const uchar *data, int align, int blocksize, int levels, bool mipmap) +static void uploadcompressedtexture(GLenum target, GLenum subtarget, GLenum format, int w, int h, const uchar *data, int align, int blocksize, int levels, bool mipmap) { int hwlimit = target==GL_TEXTURE_CUBE_MAP ? hwcubetexsize : hwtexsize, sizelimit = levels > 1 && maxtexsize ? min(maxtexsize, hwlimit) : hwlimit; @@ -849,7 +855,7 @@ void uploadcompressedtexture(GLenum target, GLenum subtarget, GLenum format, int } } -GLenum textarget(GLenum subtarget) +static GLenum textarget(GLenum subtarget) { switch(subtarget) { @@ -864,7 +870,7 @@ GLenum textarget(GLenum subtarget) return subtarget; } -GLenum uncompressedformat(GLenum format) +static GLenum uncompressedformat(GLenum format) { switch(format) { @@ -894,7 +900,7 @@ GLenum uncompressedformat(GLenum format) return GL_FALSE; } -const GLint *swizzlemask(GLenum format) +static const GLint *swizzlemask(GLenum format) { static const GLint luminance[4] = { GL_RED, GL_RED, GL_RED, GL_ONE }; static const GLint luminancealpha[4] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; @@ -906,7 +912,7 @@ const GLint *swizzlemask(GLenum format) return NULL; } -void setuptexparameters(int tnum, const void *pixels, int clamp, int filter, GLenum format, GLenum target, bool swizzle) +static void setuptexparameters(int tnum, const void *pixels, int clamp, int filter, GLenum format, GLenum target, bool swizzle) { glBindTexture(target, tnum); glTexParameteri(target, GL_TEXTURE_WRAP_S, clamp&1 ? GL_CLAMP_TO_EDGE : (clamp&0x100 ? GL_MIRRORED_REPEAT : GL_REPEAT)); @@ -1079,7 +1085,7 @@ void createtexture(int tnum, int w, int h, const void *pixels, int clamp, int fi uploadtexture(subtarget, component, tw, th, format, type, pixels, pw, ph, pitch, mipmap); } -void createcompressedtexture(int tnum, int w, int h, const uchar *data, int align, int blocksize, int levels, int clamp, int filter, GLenum format, GLenum subtarget, bool swizzle = false) +static void createcompressedtexture(int tnum, int w, int h, const uchar *data, int align, int blocksize, int levels, int clamp, int filter, GLenum format, GLenum subtarget, bool swizzle = false) { GLenum target = textarget(subtarget); if(tnum) setuptexparameters(tnum, data, clamp, filter, format, target, swizzle); @@ -1094,7 +1100,7 @@ void create3dtexture(int tnum, int w, int h, int d, const void *pixels, int clam } -hashnameset textures; +static hashnameset textures; Texture *notexture = NULL; // used as default, ensured to be loaded @@ -1235,7 +1241,7 @@ static Texture *newtexture(Texture *t, const char *rname, ImageData &s, int clam #define RGBMASKS 0x0000ff, 0x00ff00, 0xff0000, 0 #endif -SDL_Surface *wrapsurface(void *data, int width, int height, int bpp) +static SDL_Surface *wrapsurface(void *data, int width, int height, int bpp) { switch(bpp) { @@ -1245,7 +1251,7 @@ SDL_Surface *wrapsurface(void *data, int width, int height, int bpp) return NULL; } -SDL_Surface *creatergbsurface(SDL_Surface *os) +static SDL_Surface *creatergbsurface(SDL_Surface *os) { SDL_Surface *ns = SDL_CreateRGBSurface(SDL_SWSURFACE, os->w, os->h, 24, RGBMASKS); if(ns) SDL_BlitSurface(os, NULL, ns, NULL); @@ -1253,7 +1259,7 @@ SDL_Surface *creatergbsurface(SDL_Surface *os) return ns; } -SDL_Surface *creatergbasurface(SDL_Surface *os) +static SDL_Surface *creatergbasurface(SDL_Surface *os) { SDL_Surface *ns = SDL_CreateRGBSurface(SDL_SWSURFACE, os->w, os->h, 32, RGBAMASKS); if(ns) @@ -1265,7 +1271,7 @@ SDL_Surface *creatergbasurface(SDL_Surface *os) return ns; } -bool checkgrayscale(SDL_Surface *s) +static bool checkgrayscale(SDL_Surface *s) { // gray scale images have 256 levels, no colorkey, and the palette is a ramp if(s->format->palette) @@ -1277,7 +1283,7 @@ bool checkgrayscale(SDL_Surface *s) return true; } -SDL_Surface *fixsurfaceformat(SDL_Surface *s) +static SDL_Surface *fixsurfaceformat(SDL_Surface *s) { if(!s) return NULL; if(!s->pixels || min(s->w, s->h) <= 0 || s->format->BytesPerPixel <= 0) @@ -1303,7 +1309,7 @@ SDL_Surface *fixsurfaceformat(SDL_Surface *s) return s; } -void texflip(ImageData &s) +static void texflip(ImageData &s) { ImageData d(s.w, s.h, s.bpp); uchar *dst = d.data, *src = &s.data[s.pitch*s.h]; @@ -1316,7 +1322,7 @@ void texflip(ImageData &s) s.replace(d); } -void texnormal(ImageData &s, int emphasis) +static void texnormal(ImageData &s, int emphasis) { ImageData d(s.w, s.h, 3); uchar *src = s.data, *dst = d.data; @@ -1411,7 +1417,7 @@ static void blurtexture(int w, int h, uchar *dst, const uchar *src, int margin) } } -void blurtexture(int n, int bpp, int w, int h, uchar *dst, const uchar *src, int margin) +static void blurtexture(int n, int bpp, int w, int h, uchar *dst, const uchar *src, int margin = 0) { switch((clamp(n, 1, 2)<<4) | bpp) { @@ -1422,7 +1428,8 @@ void blurtexture(int n, int bpp, int w, int h, uchar *dst, const uchar *src, int } } -void blurnormals(int n, int w, int h, bvec *dst, const bvec *src, int margin) +#if 0 +static void blurnormals(int n, int w, int h, bvec *dst, const bvec *src, int margin = 0) { switch(clamp(n, 1, 2)) { @@ -1430,8 +1437,9 @@ void blurnormals(int n, int w, int h, bvec *dst, const bvec *src, int margin) case 2: blurtexture<2, 3, true>(w, h, dst->v, src->v, margin); break; } } +#endif -void texblur(ImageData &s, int n, int r) +static void texblur(ImageData &s, int n, int r) { if(s.bpp < 3) return; loopi(r) @@ -1442,7 +1450,7 @@ void texblur(ImageData &s, int n, int r) } } -bool canloadsurface(const char *name) +static bool canloadsurface(const char *name) { stream *f = openfile(name, "rb"); if(!f) return false; @@ -1450,7 +1458,7 @@ bool canloadsurface(const char *name) return true; } -SDL_Surface *loadsurface(const char *name) +static SDL_Surface *loadsurface(const char *name) { SDL_Surface *s = NULL; stream *z = openzipfile(name, "rb"); @@ -1669,12 +1677,13 @@ bool settexture(const char *name, int clamp) vector vslots; vector slots; -MatSlot materialslots[(MATF_VOLUME|MATF_INDEX)+1]; Slot dummyslot; VSlot dummyvslot(&dummyslot); -vector decalslots; DecalSlot dummydecalslot; -Slot *defslot = NULL; + +static MatSlot materialslots[(MATF_VOLUME|MATF_INDEX)+1]; +static vector decalslots; +static Slot *defslot = NULL; const char *Slot::name() const { return tempformatstring("slot %d", index); } @@ -1683,7 +1692,7 @@ const char *MatSlot::name() const { return tempformatstring("material slot %s", const char *DecalSlot::name() const { return tempformatstring("decal slot %d", Slot::index); } -void texturereset(int *n) +static void texturereset(int *n) { if(!(identflags&IDF_OVERRIDDEN) && !game::allowedittoggle()) return; defslot = NULL; @@ -1706,7 +1715,7 @@ void texturereset(int *n) COMMAND(texturereset, "i"); -void materialreset() +static void materialreset() { if(!(identflags&IDF_OVERRIDDEN) && !game::allowedittoggle()) return; defslot = NULL; @@ -1715,7 +1724,7 @@ void materialreset() COMMAND(materialreset, ""); -void decalreset(int *n) +static void decalreset(int *n) { if(!(identflags&IDF_OVERRIDDEN) && !game::allowedittoggle()) return; defslot = NULL; @@ -2265,7 +2274,7 @@ const struct slottex {"e", TEX_ENVMAP} }; -int findslottex(const char *name) +static int findslottex(const char *name) { loopi(sizeof(slottexs)/sizeof(slottex)) { @@ -2274,7 +2283,7 @@ int findslottex(const char *name) return -1; } -void texture(char *type, char *name, int *rot, int *xoffset, int *yoffset, float *scale) +static void texture(char *type, char *name, int *rot, int *xoffset, int *yoffset, float *scale) { int tnum = findslottex(type), matslot; if(tnum==TEX_DIFFUSE) @@ -2317,7 +2326,7 @@ void texture(char *type, char *name, int *rot, int *xoffset, int *yoffset, float COMMAND(texture, "ssiiif"); -void texgrass(char *name) +static void texgrass(char *name) { if(!defslot) return; Slot &s = *defslot; @@ -2326,7 +2335,7 @@ void texgrass(char *name) } COMMAND(texgrass, "s"); -void texscroll(float *scrollS, float *scrollT) +static void texscroll(float *scrollS, float *scrollT) { if(!defslot) return; Slot &s = *defslot; @@ -2335,7 +2344,7 @@ void texscroll(float *scrollS, float *scrollT) } COMMAND(texscroll, "ff"); -void texoffset_(int *xoffset, int *yoffset) +static void texoffset_(int *xoffset, int *yoffset) { if(!defslot) return; Slot &s = *defslot; @@ -2344,7 +2353,7 @@ void texoffset_(int *xoffset, int *yoffset) } COMMANDN(texoffset, texoffset_, "ii"); -void texrotate_(int *rot) +static void texrotate_(int *rot) { if(!defslot) return; Slot &s = *defslot; @@ -2353,7 +2362,7 @@ void texrotate_(int *rot) } COMMANDN(texrotate, texrotate_, "i"); -void texscale(float *scale) +static void texscale(float *scale) { if(!defslot) return; Slot &s = *defslot; @@ -2362,7 +2371,7 @@ void texscale(float *scale) } COMMAND(texscale, "f"); -void texlayer(int *layer) +static void texlayer(int *layer) { if(!defslot) return; Slot &s = *defslot; @@ -2371,7 +2380,7 @@ void texlayer(int *layer) } COMMAND(texlayer, "i"); -void texdetail(int *detail) +static void texdetail(int *detail) { if(!defslot) return; Slot &s = *defslot; @@ -2380,7 +2389,7 @@ void texdetail(int *detail) } COMMAND(texdetail, "i"); -void texalpha(float *front, float *back) +static void texalpha(float *front, float *back) { if(!defslot) return; Slot &s = *defslot; @@ -2390,7 +2399,7 @@ void texalpha(float *front, float *back) } COMMAND(texalpha, "ff"); -void texcolor(float *r, float *g, float *b) +static void texcolor(float *r, float *g, float *b) { if(!defslot) return; Slot &s = *defslot; @@ -2399,7 +2408,7 @@ void texcolor(float *r, float *g, float *b) } COMMAND(texcolor, "fff"); -void texrefract(float *k, float *r, float *g, float *b) +static void texrefract(float *k, float *r, float *g, float *b) { if(!defslot) return; Slot &s = *defslot; @@ -2412,7 +2421,7 @@ void texrefract(float *k, float *r, float *g, float *b) } COMMAND(texrefract, "ffff"); -void texsmooth(int *id, int *angle) +static void texsmooth(int *id, int *angle) { if(!defslot) return; Slot &s = *defslot; @@ -2420,7 +2429,7 @@ void texsmooth(int *id, int *angle) } COMMAND(texsmooth, "ib"); -void decaldepth(float *depth, float *fade) +static void decaldepth(float *depth, float *fade) { if(!defslot || defslot->type() != Slot::DECAL) return; DecalSlot &s = *(DecalSlot *)defslot; @@ -2787,7 +2796,7 @@ extern const cubemapside cubemapsides[6] = VARFP(envmapsize, 4, 7, 10, setupmaterials()); -Texture *cubemaploadwildcard(Texture *t, const char *name, bool mipit, bool msg, bool transient = false) +static Texture *cubemaploadwildcard(Texture *t, const char *name, bool mipit, bool msg, bool transient = false) { string tname; if(!name) copystring(tname, t->name); @@ -2938,7 +2947,7 @@ struct envmap static vector envmaps; -void clearenvmaps() +static void clearenvmaps() { loopv(envmaps) envmaps[i].clear(); envmaps.shrink(0); @@ -2947,7 +2956,7 @@ void clearenvmaps() static GLuint emfbo[3] = { 0, 0, 0 }, emtex[2] = { 0, 0 }; static int emtexsize = -1; -GLuint genenvmap(const vec &o, int envmapsize, int blur, bool onlysky) +static GLuint genenvmap(const vec &o, int envmapsize, int blur, bool onlysky) { int rendersize = 1<<(envmapsize+aaenvmap), sizelimit = min(hwcubetexsize, min(gw, gh)); if(maxtexsize) sizelimit = min(sizelimit, maxtexsize); @@ -3147,7 +3156,7 @@ GLuint lookupenvmap(ushort emid) return tex ? tex : lookupskyenvmap(); } -void cleanuptexture(Texture *t) +static void cleanuptexture(Texture *t) { DELETEA(t->alphamask); if(t->id) { glDeleteTextures(1, &t->id); t->id = 0; } @@ -3191,7 +3200,7 @@ bool reloadtexture(Texture &tex) return true; } -void reloadtex(char *name) +static void reloadtex(char *name) { Texture *t = textures.access(path(name, true)); if(!t) { conoutf(CON_ERROR, "texture %s is not loaded", name); return; } @@ -3424,7 +3433,7 @@ DECODEDDS(decodergtc2, 2, greenbits >>= 3; ); -bool loaddds(const char *filename, ImageData &image, int force) +static bool loaddds(const char *filename, ImageData &image, int force) { stream *f = openfile(filename, "rb"); if(!f) return false; @@ -3504,7 +3513,7 @@ bool loaddds(const char *filename, ImageData &image, int force) return true; } -void gendds(char *infile, char *outfile) +static void gendds(char *infile, char *outfile) { if(!hasS3TC || usetexcompress <= 1) { conoutf(CON_ERROR, "OpenGL driver does not support S3TC texture compression"); return; } @@ -3604,7 +3613,7 @@ void gendds(char *infile, char *outfile) } COMMAND(gendds, "ss"); -void writepngchunk(stream *f, const char *type, uchar *data = NULL, uint len = 0) +static void writepngchunk(stream *f, const char *type, uchar *data = NULL, uint len = 0) { f->putbig(len); f->write(type, 4); @@ -3813,9 +3822,9 @@ enum VARP(screenshotquality, 0, 97, 100); VARP(screenshotformat, 0, IMG_PNG, NUMIMG-1); -const char *imageexts[NUMIMG] = { ".bmp", ".tga", ".png", ".jpg" }; +static const char *imageexts[NUMIMG] = { ".bmp", ".tga", ".png", ".jpg" }; -int guessimageformat(const char *filename, int format = IMG_BMP) +static int guessimageformat(const char *filename, int format = IMG_BMP) { int len = strlen(filename); loopi(NUMIMG) @@ -3826,7 +3835,7 @@ int guessimageformat(const char *filename, int format = IMG_BMP) return format; } -void saveimage(const char *filename, int format, ImageData &image, bool flip = false) +static void saveimage(const char *filename, int format, ImageData &image, bool flip = false) { switch(format) { @@ -3869,7 +3878,7 @@ bool loadimage(const char *filename, ImageData &image) SVARP(screenshotdir, "screenshot"); -void screenshot(char *filename) +static void screenshot(char *filename) { static string buf; int format = -1, dirlen = 0; @@ -3922,7 +3931,7 @@ void screenshot(char *filename) COMMAND(screenshot, "s"); -void flipnormalmapy(char *destfile, char *normalfile) // jpg/png/tga-> tga +static void flipnormalmapy(char *destfile, char *normalfile) // jpg/png/tga-> tga { ImageData ns; if(!loadimage(normalfile, ns)) return; @@ -3935,7 +3944,7 @@ void flipnormalmapy(char *destfile, char *normalfile) // jpg/png/tga-> tga saveimage(destfile, guessimageformat(destfile, IMG_TGA), d); } -void mergenormalmaps(char *heightfile, char *normalfile) // jpg/png/tga + tga -> tga +static void mergenormalmaps(char *heightfile, char *normalfile) // jpg/png/tga + tga -> tga { ImageData hs, ns; if(!loadimage(heightfile, hs) || !loadimage(normalfile, ns) || hs.w != ns.w || hs.h != ns.h) return; @@ -3946,7 +3955,7 @@ void mergenormalmaps(char *heightfile, char *normalfile) // jpg/png/tga + tga -> saveimage(normalfile, guessimageformat(normalfile, IMG_TGA), d); } -void normalizenormalmap(char *destfile, char *normalfile) // jpg/png/tga-> tga +static void normalizenormalmap(char *destfile, char *normalfile) // jpg/png/tga-> tga { ImageData ns; if(!loadimage(normalfile, ns)) return; @@ -3957,7 +3966,7 @@ void normalizenormalmap(char *destfile, char *normalfile) // jpg/png/tga-> tga saveimage(destfile, guessimageformat(destfile, IMG_TGA), d); } -void removealphachannel(char *destfile, char *rgbafile) +static void removealphachannel(char *destfile, char *rgbafile) { ImageData ns; if(!loadimage(rgbafile, ns)) return; diff --git a/src/engine/texture.hh b/src/engine/texture.hh index 6ae4c6c..1bc66b0 100644 --- a/src/engine/texture.hh +++ b/src/engine/texture.hh @@ -1,469 +1,10 @@ -struct GlobalShaderParamState -{ - const char *name; - union - { - float fval[32]; - int ival[32]; - uint uval[32]; - uchar buf[32*sizeof(float)]; - }; - int version; +#ifndef ENGINE_TEXTURE_HH +#define ENGINE_TEXTURE_HH - static int nextversion; +#include +#include - void resetversions(); - - void changed() - { - if(++nextversion < 0) resetversions(); - version = nextversion; - } -}; - -struct ShaderParamBinding -{ - int loc, size; - GLenum format; -}; - -struct GlobalShaderParamUse : ShaderParamBinding -{ - - GlobalShaderParamState *param; - int version; - - void flush() - { - if(version == param->version) return; - switch(format) - { - case GL_BOOL: - case GL_FLOAT: glUniform1fv_(loc, size, param->fval); break; - case GL_BOOL_VEC2: - case GL_FLOAT_VEC2: glUniform2fv_(loc, size, param->fval); break; - case GL_BOOL_VEC3: - case GL_FLOAT_VEC3: glUniform3fv_(loc, size, param->fval); break; - case GL_BOOL_VEC4: - case GL_FLOAT_VEC4: glUniform4fv_(loc, size, param->fval); break; - case GL_INT: glUniform1iv_(loc, size, param->ival); break; - case GL_INT_VEC2: glUniform2iv_(loc, size, param->ival); break; - case GL_INT_VEC3: glUniform3iv_(loc, size, param->ival); break; - case GL_INT_VEC4: glUniform4iv_(loc, size, param->ival); break; - case GL_UNSIGNED_INT: glUniform1uiv_(loc, size, param->uval); break; - case GL_UNSIGNED_INT_VEC2: glUniform2uiv_(loc, size, param->uval); break; - case GL_UNSIGNED_INT_VEC3: glUniform3uiv_(loc, size, param->uval); break; - case GL_UNSIGNED_INT_VEC4: glUniform4uiv_(loc, size, param->uval); break; - case GL_FLOAT_MAT2: glUniformMatrix2fv_(loc, 1, GL_FALSE, param->fval); break; - case GL_FLOAT_MAT3: glUniformMatrix3fv_(loc, 1, GL_FALSE, param->fval); break; - case GL_FLOAT_MAT4: glUniformMatrix4fv_(loc, 1, GL_FALSE, param->fval); break; - } - version = param->version; - } -}; - -struct LocalShaderParamState : ShaderParamBinding -{ - const char *name; -}; - -struct SlotShaderParam -{ - enum - { - REUSE = 1<<0 - }; - - const char *name; - int loc, flags; - float val[4]; -}; - -struct SlotShaderParamState : LocalShaderParamState -{ - int flags; - float val[4]; - - SlotShaderParamState() {} - SlotShaderParamState(const SlotShaderParam &p) - { - name = p.name; - loc = -1; - size = 1; - format = GL_FLOAT_VEC4; - flags = p.flags; - memcpy(val, p.val, sizeof(val)); - } -}; - -enum -{ - SHADER_DEFAULT = 0, - SHADER_WORLD = 1<<0, - SHADER_ENVMAP = 1<<1, - SHADER_REFRACT = 1<<2, - SHADER_OPTION = 1<<3, - SHADER_DYNAMIC = 1<<4, - SHADER_TRIPLANAR = 1<<5, - - SHADER_INVALID = 1<<8, - SHADER_DEFERRED = 1<<9 -}; - -#define MAXVARIANTROWS 32 - -struct Slot; -struct VSlot; - -struct UniformLoc -{ - const char *name, *blockname; - int loc, version, binding, stride, offset, size; - void *data; - 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) {} -}; - -struct AttribLoc -{ - const char *name; - int loc; - AttribLoc(const char *name = NULL, int loc = -1) : name(name), loc(loc) {} -}; - -struct FragDataLoc -{ - const char *name; - int loc; - GLenum format; - int index; - FragDataLoc(const char *name = NULL, int loc = -1, GLenum format = GL_FALSE, int index = 0) : name(name), loc(loc), format(format), index(index) {} -}; - -struct Shader -{ - static Shader *lastshader; - - char *name, *vsstr, *psstr, *defer; - int type; - GLuint program, vsobj, psobj; - vector defaultparams; - vector globalparams; - vector localparams; - vector localparamremap; - Shader *variantshader; - vector variants; - ushort *variantrows; - bool standard, forced, used; - Shader *reusevs, *reuseps; - vector uniformlocs; - vector attriblocs; - vector fragdatalocs; - const void *owner; - - 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) - { - } - - ~Shader() - { - DELETEA(name); - DELETEA(vsstr); - DELETEA(psstr); - DELETEA(defer); - DELETEA(variantrows); - } - - void allocparams(Slot *slot = NULL); - void setslotparams(Slot &slot); - void setslotparams(Slot &slot, VSlot &vslot); - void bindprograms(); - - void flushparams(Slot *slot = NULL) - { - if(!used) { allocparams(slot); used = true; } - loopv(globalparams) globalparams[i].flush(); - } - - void force(); - - bool invalid() const { return (type&SHADER_INVALID)!=0; } - bool deferred() const { return (type&SHADER_DEFERRED)!=0; } - bool loaded() const { return !(type&(SHADER_DEFERRED|SHADER_INVALID)); } - - bool hasoption() const { return (type&SHADER_OPTION)!=0; } - - bool isdynamic() const { return (type&SHADER_DYNAMIC)!=0; } - - static inline bool isnull(const Shader *s) { return !s; } - - bool isnull() const { return isnull(this); } - - int numvariants(int row) const - { - if(row < 0 || row >= MAXVARIANTROWS || !variantrows) return 0; - return variantrows[row+1] - variantrows[row]; - } - - Shader *getvariant(int col, int row) const - { - if(row < 0 || row >= MAXVARIANTROWS || col < 0 || !variantrows) return NULL; - int start = variantrows[row], end = variantrows[row+1]; - return col < end - start ? variants[start + col] : NULL; - } - - void addvariant(int row, Shader *s) - { - if(row < 0 || row >= MAXVARIANTROWS || variants.length() >= USHRT_MAX) return; - if(!variantrows) { variantrows = new ushort[MAXVARIANTROWS+1]; memset(variantrows, 0, (MAXVARIANTROWS+1)*sizeof(ushort)); } - variants.insert(variantrows[row+1], s); - for(int i = row+1; i <= MAXVARIANTROWS; ++i) ++variantrows[i]; - } - - void setvariant_(int col, int row) - { - Shader *s = this; - if(variantrows) - { - int start = variantrows[row], end = variantrows[row+1]; - for(col = min(start + col, end-1); col >= start; --col) if(!variants[col]->invalid()) { s = variants[col]; break; } - } - if(lastshader!=s) s->bindprograms(); - } - - void setvariant(int col, int row) - { - if(isnull() || !loaded()) return; - setvariant_(col, row); - lastshader->flushparams(); - } - - void setvariant(int col, int row, Slot &slot) - { - if(isnull() || !loaded()) return; - setvariant_(col, row); - lastshader->flushparams(&slot); - lastshader->setslotparams(slot); - } - - void setvariant(int col, int row, Slot &slot, VSlot &vslot) - { - if(isnull() || !loaded()) return; - setvariant_(col, row); - lastshader->flushparams(&slot); - lastshader->setslotparams(slot, vslot); - } - - void set_() - { - if(lastshader!=this) bindprograms(); - } - - void set() - { - if(isnull() || !loaded()) return; - set_(); - lastshader->flushparams(); - } - - void set(Slot &slot) - { - if(isnull() || !loaded()) return; - set_(); - lastshader->flushparams(&slot); - lastshader->setslotparams(slot); - } - - void set(Slot &slot, VSlot &vslot) - { - if(isnull() || !loaded()) return; - set_(); - lastshader->flushparams(&slot); - lastshader->setslotparams(slot, vslot); - } - - bool compile(); - void cleanup(bool full = false); - - static int uniformlocversion(); -}; - -struct GlobalShaderParam -{ - const char *name; - GlobalShaderParamState *param; - - GlobalShaderParam(const char *name) : name(name), param(NULL) {} - - GlobalShaderParamState *resolve() - { - extern GlobalShaderParamState *getglobalparam(const char *name); - if(!param) param = getglobalparam(name); - param->changed(); - return param; - } - - void setf(float x = 0, float y = 0, float z = 0, float w = 0) - { - GlobalShaderParamState *g = resolve(); - g->fval[0] = x; - g->fval[1] = y; - g->fval[2] = z; - g->fval[3] = w; - } - void set(const vec &v, float w = 0) { setf(v.x, v.y, v.z, w); } - void set(const vec2 &v, float z = 0, float w = 0) { setf(v.x, v.y, z, w); } - void set(const vec4 &v) { setf(v.x, v.y, v.z, v.w); } - void set(const plane &p) { setf(p.x, p.y, p.z, p.offset); } - void set(const matrix2 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); } - void set(const matrix3 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); } - void set(const matrix4 &m) { memcpy(resolve()->fval, m.a.v, sizeof(m)); } - - template - void setv(const T *v, int n = 1) { memcpy(resolve()->buf, v, n*sizeof(T)); } - - void seti(int x = 0, int y = 0, int z = 0, int w = 0) - { - GlobalShaderParamState *g = resolve(); - g->ival[0] = x; - g->ival[1] = y; - g->ival[2] = z; - g->ival[3] = w; - } - void set(const ivec &v, int w = 0) { seti(v.x, v.y, v.z, w); } - void set(const ivec2 &v, int z = 0, int w = 0) { seti(v.x, v.y, z, w); } - void set(const ivec4 &v) { seti(v.x, v.y, v.z, v.w); } - - void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0) - { - GlobalShaderParamState *g = resolve(); - g->uval[0] = x; - g->uval[1] = y; - g->uval[2] = z; - g->uval[3] = w; - } - - template - T *reserve(int n = 1) { return (T *)resolve()->buf; } -}; - -struct LocalShaderParam -{ - const char *name; - int loc; - - LocalShaderParam(const char *name) : name(name), loc(-1) {} - - LocalShaderParamState *resolve() - { - Shader *s = Shader::lastshader; - if(!s) return NULL; - if(!s->localparamremap.inrange(loc)) - { - extern int getlocalparam(const char *name); - if(loc == -1) loc = getlocalparam(name); - if(!s->localparamremap.inrange(loc)) return NULL; - } - uchar remap = s->localparamremap[loc]; - return s->localparams.inrange(remap) ? &s->localparams[remap] : NULL; - } - - void setf(float x = 0, float y = 0, float z = 0, float w = 0) - { - ShaderParamBinding *b = resolve(); - if(b) switch(b->format) - { - case GL_BOOL: - case GL_FLOAT: glUniform1f_(b->loc, x); break; - case GL_BOOL_VEC2: - case GL_FLOAT_VEC2: glUniform2f_(b->loc, x, y); break; - case GL_BOOL_VEC3: - case GL_FLOAT_VEC3: glUniform3f_(b->loc, x, y, z); break; - case GL_BOOL_VEC4: - case GL_FLOAT_VEC4: glUniform4f_(b->loc, x, y, z, w); break; - case GL_INT: glUniform1i_(b->loc, int(x)); break; - case GL_INT_VEC2: glUniform2i_(b->loc, int(x), int(y)); break; - case GL_INT_VEC3: glUniform3i_(b->loc, int(x), int(y), int(z)); break; - case GL_INT_VEC4: glUniform4i_(b->loc, int(x), int(y), int(z), int(w)); break; - case GL_UNSIGNED_INT: glUniform1ui_(b->loc, uint(x)); break; - case GL_UNSIGNED_INT_VEC2: glUniform2ui_(b->loc, uint(x), uint(y)); break; - case GL_UNSIGNED_INT_VEC3: glUniform3ui_(b->loc, uint(x), uint(y), uint(z)); break; - case GL_UNSIGNED_INT_VEC4: glUniform4ui_(b->loc, uint(x), uint(y), uint(z), uint(w)); break; - } - } - void set(const vec &v, float w = 0) { setf(v.x, v.y, v.z, w); } - void set(const vec2 &v, float z = 0, float w = 0) { setf(v.x, v.y, z, w); } - void set(const vec4 &v) { setf(v.x, v.y, v.z, v.w); } - void set(const plane &p) { setf(p.x, p.y, p.z, p.offset); } - void setv(const float *f, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1fv_(b->loc, n, f); } - void setv(const vec *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform3fv_(b->loc, n, v->v); } - void setv(const vec2 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform2fv_(b->loc, n, v->v); } - void setv(const vec4 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4fv_(b->loc, n, v->v); } - void setv(const plane *p, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4fv_(b->loc, n, p->v); } - void setv(const matrix2 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix2fv_(b->loc, n, GL_FALSE, m->a.v); } - void setv(const matrix3 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix3fv_(b->loc, n, GL_FALSE, m->a.v); } - void setv(const matrix4 *m, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniformMatrix4fv_(b->loc, n, GL_FALSE, m->a.v); } - void set(const matrix2 &m) { setv(&m); } - void set(const matrix3 &m) { setv(&m); } - void set(const matrix4 &m) { setv(&m); } - - template - void sett(T x, T y, T z, T w) - { - ShaderParamBinding *b = resolve(); - if(b) switch(b->format) - { - case GL_FLOAT: glUniform1f_(b->loc, x); break; - case GL_FLOAT_VEC2: glUniform2f_(b->loc, x, y); break; - case GL_FLOAT_VEC3: glUniform3f_(b->loc, x, y, z); break; - case GL_FLOAT_VEC4: glUniform4f_(b->loc, x, y, z, w); break; - case GL_BOOL: - case GL_INT: glUniform1i_(b->loc, x); break; - case GL_BOOL_VEC2: - case GL_INT_VEC2: glUniform2i_(b->loc, x, y); break; - case GL_BOOL_VEC3: - case GL_INT_VEC3: glUniform3i_(b->loc, x, y, z); break; - case GL_BOOL_VEC4: - case GL_INT_VEC4: glUniform4i_(b->loc, x, y, z, w); break; - case GL_UNSIGNED_INT: glUniform1ui_(b->loc, x); break; - case GL_UNSIGNED_INT_VEC2: glUniform2ui_(b->loc, x, y); break; - case GL_UNSIGNED_INT_VEC3: glUniform3ui_(b->loc, x, y, z); break; - case GL_UNSIGNED_INT_VEC4: glUniform4ui_(b->loc, x, y, z, w); break; - } - } - void seti(int x = 0, int y = 0, int z = 0, int w = 0) { sett(x, y, z, w); } - void set(const ivec &v, int w = 0) { seti(v.x, v.y, v.z, w); } - void set(const ivec2 &v, int z = 0, int w = 0) { seti(v.x, v.y, z, w); } - void set(const ivec4 &v) { seti(v.x, v.y, v.z, v.w); } - void setv(const int *i, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1iv_(b->loc, n, i); } - void setv(const ivec *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform3iv_(b->loc, n, v->v); } - void setv(const ivec2 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform2iv_(b->loc, n, v->v); } - void setv(const ivec4 *v, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform4iv_(b->loc, n, v->v); } - - void setu(uint x = 0, uint y = 0, uint z = 0, uint w = 0) { sett(x, y, z, w); } - void setv(const uint *u, int n = 1) { ShaderParamBinding *b = resolve(); if(b) glUniform1uiv_(b->loc, n, u); } -}; - -#define LOCALPARAM(name, vals) do { static LocalShaderParam param( #name ); param.set(vals); } while(0) -#define LOCALPARAMF(name, ...) do { static LocalShaderParam param( #name ); param.setf(__VA_ARGS__); } while(0) -#define LOCALPARAMI(name, ...) do { static LocalShaderParam param( #name ); param.seti(__VA_ARGS__); } while(0) -#define LOCALPARAMV(name, vals, num) do { static LocalShaderParam param( #name ); param.setv(vals, num); } while(0) -#define GLOBALPARAM(name, vals) do { static GlobalShaderParam param( #name ); param.set(vals); } while(0) -#define GLOBALPARAMF(name, ...) do { static GlobalShaderParam param( #name ); param.setf(__VA_ARGS__); } while(0) -#define GLOBALPARAMI(name, ...) do { static GlobalShaderParam param( #name ); param.seti(__VA_ARGS__); } while(0) -#define GLOBALPARAMV(name, vals, num) do { static GlobalShaderParam param( #name ); param.setv(vals, num); } while(0) - -#define SETSHADER(name, ...) \ - do { \ - static Shader *name##shader = NULL; \ - if(!name##shader) name##shader = lookupshaderbyname(#name); \ - name##shader->set(__VA_ARGS__); \ - } while(0) -#define SETVARIANT(name, ...) \ - do { \ - static Shader *name##shader = NULL; \ - if(!name##shader) name##shader = lookupshaderbyname(#name); \ - name##shader->setvariant(__VA_ARGS__); \ - } while(0) +#include "shader.hh" struct ImageData { @@ -820,43 +361,17 @@ struct cubemapside extern const texrotation texrotations[8]; extern const cubemapside cubemapsides[6]; -extern Texture *notexture; -extern Shader *nullshader, *hudshader, *hudtextshader, *hudnotextureshader, *nocolorshader, *foggedshader, *foggednotextureshader, *ldrshader, *ldrnotextureshader, *stdworldshader; -extern int maxvsuniforms, maxfsuniforms; -extern Shader *lookupshaderbyname(const char *name); -extern Shader *useshaderbyname(const char *name); -extern Shader *generateshader(const char *name, const char *cmd, ...); -extern void resetslotshader(); -extern void setslotshader(Slot &s); -extern void linkslotshader(Slot &s, bool load = true); -extern void linkvslotshader(VSlot &s, bool load = true); -extern void linkslotshaders(); -extern const char *getshaderparamname(const char *name, bool insert = true); -extern bool shouldreuseparams(Slot &s, VSlot &p); -extern void setupshaders(); -extern void reloadshaders(); -extern void cleanupshaders(); +extern int hwtexsize, hwcubetexsize, hwmaxaniso, maxtexsize, hwtexunits, hwvtexunits; #define MAXBLURRADIUS 7 extern float blursigma; -extern void setupblurkernel(int radius, float *weights, float *offsets); -extern void setblurshader(int pass, int size, int radius, float *weights, float *offsets, GLenum target = GL_TEXTURE_2D); +void setupblurkernel(int radius, float *weights, float *offsets); +void setblurshader(int pass, int size, int radius, float *weights, float *offsets, GLenum target = GL_TEXTURE_2D); -extern void savepng(const char *filename, ImageData &image, bool flip = false); -extern void savetga(const char *filename, ImageData &image, bool flip = false); -extern bool loaddds(const char *filename, ImageData &image, int force = 0); -extern bool loadimage(const char *filename, ImageData &image); - -extern MatSlot &lookupmaterialslot(int slot, bool load = true); -extern Slot &lookupslot(int slot, bool load = true); -extern VSlot &lookupvslot(int slot, bool load = true); -extern DecalSlot &lookupdecalslot(int slot, bool load = true); -extern VSlot *findvslot(Slot &slot, const VSlot &src, const VSlot &delta); -extern VSlot *editvslot(const VSlot &src, const VSlot &delta); -extern void mergevslot(VSlot &dst, const VSlot &src, const VSlot &delta); -extern void packvslot(vector &buf, const VSlot &src); -extern bool unpackvslot(ucharbuf &buf, VSlot &dst, bool delta); +void savepng(const char *filename, ImageData &image, bool flip = false); +void savetga(const char *filename, ImageData &image, bool flip = false); +bool loadimage(const char *filename, ImageData &image); extern Slot dummyslot; extern VSlot dummyvslot; @@ -864,3 +379,50 @@ extern DecalSlot dummydecalslot; extern vector slots; extern vector vslots; +MatSlot &lookupmaterialslot(int slot, bool load = true); +Slot &lookupslot(int slot, bool load = true); +VSlot &lookupvslot(int slot, bool load = true); +DecalSlot &lookupdecalslot(int slot, bool load = true); +VSlot *findvslot(Slot &slot, const VSlot &src, const VSlot &delta); +VSlot *editvslot(const VSlot &src, const VSlot &delta); +void mergevslot(VSlot &dst, const VSlot &src, const VSlot &delta); +void packvslot(vector &buf, const VSlot &src); +void packvslot(vector &buf, int index); +void packvslot(vector &buf, const VSlot *vs); +bool unpackvslot(ucharbuf &buf, VSlot &dst, bool delta); + +struct cube; + +void compactvslots(cube *c, int n = 8); +void compactvslot(int &index); +void compactvslot(VSlot &vs); +int compactvslots(bool cull = false); + +void clearslots(); + +void linkslotshaders(); + +extern Texture *notexture; + +int texalign(const void *data, int w, int bpp); +bool floatformat(GLenum format); +uchar *loadalphamask(Texture *t); +void setuptexcompress(); +void createtexture(int tnum, int w, int h, const void *pixels, int clamp, int filter, GLenum component = GL_RGB, GLenum target = GL_TEXTURE_2D, int pw = 0, int ph = 0, int pitch = 0, bool resize = true, GLenum format = GL_FALSE, bool swizzle = false); +void create3dtexture(int tnum, int w, int h, int d, const void *pixels, int clamp, int filter, GLenum component = GL_RGB, GLenum target = GL_TEXTURE_3D, bool swizzle = false); +Texture *textureload(const char *name, int clamp = 0, bool mipit = true, bool msg = true); +bool settexture(const char *name, int clamp = 0); +bool reloadtexture(Texture &tex); +bool reloadtexture(const char *name); +void reloadtextures(); +void cleanuptextures(); + +Texture *cubemapload(const char *name, bool mipit = true, bool msg = true, bool transient = false); +void initenvmaps(); +void genenvmaps(); +ushort closestenvmap(const vec &o); +ushort closestenvmap(int orient, const ivec &o, int size); +GLuint lookupenvmap(ushort emid); +GLuint lookupenvmap(Slot &slot); + +#endif \ No newline at end of file diff --git a/src/engine/water.cc b/src/engine/water.cc index e915618..14b1afd 100644 --- a/src/engine/water.cc +++ b/src/engine/water.cc @@ -1,4 +1,5 @@ #include "material.hh" +#include "texture.hh" #include "water.hh" #include "engine.hh" diff --git a/src/engine/world.cc b/src/engine/world.cc index 4d924d7..b97b1ae 100644 --- a/src/engine/world.cc +++ b/src/engine/world.cc @@ -1,6 +1,7 @@ // world.cpp: core map management stuff #include "blend.hh" +#include "texture.hh" #include "worldio.hh" #include "world.hh" diff --git a/src/engine/worldio.cc b/src/engine/worldio.cc index 7b6cbc5..c7755d8 100644 --- a/src/engine/worldio.cc +++ b/src/engine/worldio.cc @@ -1,6 +1,7 @@ // worldio.cpp: loading & saving of maps and savegames #include "blend.hh" +#include "texture.hh" #include "world.hh" #include "worldio.hh" diff --git a/src/shared/glemu.hh b/src/shared/glemu.hh index 7c3c6d0..7442697 100644 --- a/src/shared/glemu.hh +++ b/src/shared/glemu.hh @@ -1,3 +1,8 @@ +#ifndef SHARED_GLEMU_HH +#define SHARED_GLEMU_HH + +#include "glexts.hh" + namespace gle { enum @@ -178,3 +183,4 @@ namespace gle extern void cleanup(); } +#endif /* SHARED_GLEMU_HH */ diff --git a/src/shared/glexts.hh b/src/shared/glexts.hh index 4df8e26..4aa119a 100644 --- a/src/shared/glexts.hh +++ b/src/shared/glexts.hh @@ -1,3 +1,8 @@ +#ifndef SHARED_GLEXTS_HH +#define SHARED_GLEXTS_HH + +#include "gl.hh" + #ifndef APIENTRY #define APIENTRY #endif @@ -830,3 +835,4 @@ extern PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog_; // GL_ARB_copy_image extern PFNGLCOPYIMAGESUBDATAPROC glCopyImageSubData_; +#endif /* SHARED_GLEXTS_HH */ diff --git a/src/shared/iengine.hh b/src/shared/iengine.hh index 90d6658..3d9c77f 100644 --- a/src/shared/iengine.hh +++ b/src/shared/iengine.hh @@ -52,8 +52,6 @@ extern bool raycubelos(const vec &o, const vec &dest, vec &hitpos); extern int thirdperson; extern bool isthirdperson(); -extern bool settexture(const char *name, int clamp = 0); - // octaedit enum { EDIT_FACE = 0, EDIT_TEX, EDIT_MAT, EDIT_FLIP, EDIT_COPY, EDIT_PASTE, EDIT_ROTATE, EDIT_REPLACE, EDIT_DELCUBE, EDIT_CALCLIGHT, EDIT_REMIP, EDIT_VSLOT, EDIT_UNDO, EDIT_REDO }; @@ -226,9 +224,6 @@ static inline void text_pos(const char *str, int cursor, int &cx, int &cy, int m struct VSlot; -extern void packvslot(vector &buf, int index); -extern void packvslot(vector &buf, const VSlot *vs); - // renderlights enum { L_NOSHADOW = 1<<0, L_NODYNSHADOW = 1<<1, L_VOLUMETRIC = 1<<2, L_NOSPEC = 1<<3 }; diff --git a/src/shared/tessfont.c b/src/shared/tessfont.c deleted file mode 100644 index 9934a93..0000000 --- a/src/shared/tessfont.c +++ /dev/null @@ -1,764 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include FT_FREETYPE_H -#include FT_STROKER_H -#include FT_GLYPH_H - -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; - -static inline int imin(int a, int b) { return a < b ? a : b; } -static inline int imax(int a, int b) { return a > b ? a : b; } -static inline int iclamp(int n, int l, int h) { return imax(l, imin(n, h)); } -static inline float fclamp(float n, float l, float h) { return fmax(l, fmin(n, h)); } - -void fatal(const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - vfprintf(stderr, fmt, v); - va_end(v); - fputc('\n', stderr); - - exit(EXIT_FAILURE); -} - -uint bigswap(uint n) -{ - const int islittleendian = 1; - return *(const uchar *)&islittleendian ? (n<<24) | (n>>24) | ((n>>8)&0xFF00) | ((n<<8)&0xFF0000) : n; -} - -size_t writebig(FILE *f, uint n) -{ - n = bigswap(n); - return fwrite(&n, 1, sizeof(n), f); -} - -void writepngchunk(FILE *f, const char *type, uchar *data, uint len) -{ - uint crc; - writebig(f, len); - fwrite(type, 1, 4, f); - fwrite(data, 1, len, f); - - crc = crc32(0, Z_NULL, 0); - crc = crc32(crc, (const Bytef *)type, 4); - if(data) crc = crc32(crc, data, len); - writebig(f, crc); -} - -struct pngihdr -{ - uint width, height; - uchar bitdepth, colortype, compress, filter, interlace; -}; - -void savepng(const char *filename, uchar *data, int w, int h, int bpp, int flip) -{ - const uchar signature[] = { 137, 80, 78, 71, 13, 10, 26, 10 }; - struct pngihdr ihdr; - FILE *f; - long idat; - uint len, crc; - z_stream z; - uchar buf[1<<12]; - int i, j; - - memset(&ihdr, 0, sizeof(ihdr)); - ihdr.width = bigswap(w); - ihdr.height = bigswap(h); - ihdr.bitdepth = 8; - switch(bpp) - { - case 1: ihdr.colortype = 0; break; - case 2: ihdr.colortype = 4; break; - case 3: ihdr.colortype = 2; break; - case 4: ihdr.colortype = 6; break; - default: fatal("tessfont: invalid PNG bpp"); return; - } - f = fopen(filename, "wb"); - if(!f) { fatal("tessfont: could not write to %s", filename); return; } - - fwrite(signature, 1, sizeof(signature), f); - - writepngchunk(f, "IHDR", (uchar *)&ihdr, 13); - - idat = ftell(f); - len = 0; - fwrite("\0\0\0\0IDAT", 1, 8, f); - crc = crc32(0, Z_NULL, 0); - crc = crc32(crc, (const Bytef *)"IDAT", 4); - - z.zalloc = NULL; - z.zfree = NULL; - z.opaque = NULL; - - if(deflateInit(&z, Z_BEST_COMPRESSION) != Z_OK) - goto error; - - z.next_out = (Bytef *)buf; - z.avail_out = sizeof(buf); - - for(i = 0; i < h; i++) - { - uchar filter = 0; - for(j = 0; j < 2; j++) - { - z.next_in = j ? (Bytef *)data + (flip ? h-i-1 : i)*w*bpp : (Bytef *)&filter; - z.avail_in = j ? w*bpp : 1; - while(z.avail_in > 0) - { - if(deflate(&z, Z_NO_FLUSH) != Z_OK) goto cleanuperror; - #define FLUSHZ do { \ - int flush = sizeof(buf) - z.avail_out; \ - crc = crc32(crc, buf, flush); \ - len += flush; \ - fwrite(buf, 1, flush, f); \ - z.next_out = (Bytef *)buf; \ - z.avail_out = sizeof(buf); \ - } while(0) - FLUSHZ; - } - } - } - - for(;;) - { - int err = deflate(&z, Z_FINISH); - if(err != Z_OK && err != Z_STREAM_END) goto cleanuperror; - FLUSHZ; - if(err == Z_STREAM_END) break; - } - - deflateEnd(&z); - - fseek(f, idat, SEEK_SET); - writebig(f, len); - fseek(f, 0, SEEK_END); - writebig(f, crc); - - writepngchunk(f, "IEND", NULL, 0); - - fclose(f); - return; - -cleanuperror: - deflateEnd(&z); - -error: - fclose(f); - - fatal("tessfont: failed saving PNG to %s", filename); -} - -enum -{ - CT_PRINT = 1<<0, - CT_SPACE = 1<<1, - CT_DIGIT = 1<<2, - CT_ALPHA = 1<<3, - CT_LOWER = 1<<4, - CT_UPPER = 1<<5, - CT_UNICODE = 1<<6 -}; -#define CUBECTYPE(s, p, d, a, A, u, U) \ - 0, U, U, U, U, U, U, U, U, s, s, s, s, s, U, U, \ - U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, \ - s, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, \ - d, d, d, d, d, d, d, d, d, d, p, p, p, p, p, p, \ - p, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, \ - A, A, A, A, A, A, A, A, A, A, A, p, p, p, p, p, \ - p, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, \ - a, a, a, a, a, a, a, a, a, a, a, p, p, p, p, U, \ - U, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, \ - u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, U, \ - u, U, u, U, u, U, u, U, u, U, u, U, u, U, u, U, \ - u, U, u, U, u, U, u, U, u, U, u, U, u, U, u, U, \ - u, U, u, U, u, U, u, U, U, u, U, u, U, u, U, U, \ - U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, \ - U, U, U, U, u, u, u, u, u, u, u, u, u, u, u, u, \ - u, u, u, u, u, u, u, u, u, u, u, u, u, u, U, u -const uchar cubectype[256] = -{ - CUBECTYPE(CT_SPACE, - CT_PRINT, - CT_PRINT|CT_DIGIT, - CT_PRINT|CT_ALPHA|CT_LOWER, - CT_PRINT|CT_ALPHA|CT_UPPER, - CT_PRINT|CT_UNICODE|CT_ALPHA|CT_LOWER, - CT_PRINT|CT_UNICODE|CT_ALPHA|CT_UPPER) -}; -int iscubeprint(uchar c) { return cubectype[c]&CT_PRINT; } -int iscubespace(uchar c) { return cubectype[c]&CT_SPACE; } -int iscubealpha(uchar c) { return cubectype[c]&CT_ALPHA; } -int iscubealnum(uchar c) { return cubectype[c]&(CT_ALPHA|CT_DIGIT); } -int iscubelower(uchar c) { return cubectype[c]&CT_LOWER; } -int iscubeupper(uchar c) { return cubectype[c]&CT_UPPER; } -const int cube2unichars[256] = -{ - 0, 192, 193, 194, 195, 196, 197, 198, 199, 9, 10, 11, 12, 13, 200, 201, - 202, 203, 204, 205, 206, 207, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 220, - 221, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 241, 242, 243, 244, 245, 246, 248, 249, 250, 251, 252, 253, 255, 0x104, - 0x105, 0x106, 0x107, 0x10C, 0x10D, 0x10E, 0x10F, 0x118, 0x119, 0x11A, 0x11B, 0x11E, 0x11F, 0x130, 0x131, 0x141, - 0x142, 0x143, 0x144, 0x147, 0x148, 0x150, 0x151, 0x152, 0x153, 0x158, 0x159, 0x15A, 0x15B, 0x15E, 0x15F, 0x160, - 0x161, 0x164, 0x165, 0x16E, 0x16F, 0x170, 0x171, 0x178, 0x179, 0x17A, 0x17B, 0x17C, 0x17D, 0x17E, 0x404, 0x411, - 0x413, 0x414, 0x416, 0x417, 0x418, 0x419, 0x41B, 0x41F, 0x423, 0x424, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, - 0x42C, 0x42D, 0x42E, 0x42F, 0x431, 0x432, 0x433, 0x434, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, - 0x43F, 0x442, 0x444, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x454, 0x490, 0x491 -}; -int cube2uni(uchar c) -{ - return cube2unichars[c]; -} - -const char *encodeutf8(int uni) -{ - static char buf[7]; - char *dst = buf; - if(uni <= 0x7F) { *dst++ = uni; goto uni1; } - else if(uni <= 0x7FF) { *dst++ = 0xC0 | (uni>>6); goto uni2; } - else if(uni <= 0xFFFF) { *dst++ = 0xE0 | (uni>>12); goto uni3; } - else if(uni <= 0x1FFFFF) { *dst++ = 0xF0 | (uni>>18); goto uni4; } - else if(uni <= 0x3FFFFFF) { *dst++ = 0xF8 | (uni>>24); goto uni5; } - else if(uni <= 0x7FFFFFFF) { *dst++ = 0xFC | (uni>>30); goto uni6; } - else goto uni1; -uni6: *dst++ = 0x80 | ((uni>>24)&0x3F); -uni5: *dst++ = 0x80 | ((uni>>18)&0x3F); -uni4: *dst++ = 0x80 | ((uni>>12)&0x3F); -uni3: *dst++ = 0x80 | ((uni>>6)&0x3F); -uni2: *dst++ = 0x80 | (uni&0x3F); -uni1: *dst++ = '\0'; - return buf; -} - -struct fontchar { int code, uni, tex, x, y, sdfradius, sdfpitch, sdfx, sdfy, sdfw, sdfh; float w, h, left, top, advance; FT_BitmapGlyph glyph; uchar *sdf; }; - -const char *texdir = ""; - -const char *texfilename(const char *name, int texnum) -{ - static char file[256]; - snprintf(file, sizeof(file), "%s%d.png", name, texnum); - return file; -} - -const char *texname(const char *name, int texnum) -{ - static char file[512]; - snprintf(file, sizeof(file), "%s%s", texdir, texfilename(name, texnum)); - return file; -} - -static int sdist; -static inline void searchdist(int x, int y, int cx, int cy) -{ - int dx = cx - x, dy = cy - y, dist = dx*dx + dy*dy; - if(dist < sdist) sdist = dist; -} - -static int sx1, ex1; -static inline int search1(int x, int y, int w, int radius, int cy, uchar *src) -{ - int cx = imin(ex1, x)-1; - if(cx >= sx1) - { - uchar *bsrc = &src[cx>>3]; - int bx = cx&~7, bits = *bsrc; - if(bits==0xFF) cx = bx-1; - else - { - bits >>= 7-(cx&7); - if(bx <= sx1) - { - for(; cx >= sx1; cx--, bits >>= 1) if(!(bits&1)) { sx1 = cx+1; searchdist(x, y, cx, cy); goto foundbelow1; } - goto foundbelow1; - } - else for(; cx >= bx; cx--, bits >>= 1) if(!(bits&1)) { sx1 = cx+1; searchdist(x, y, cx, cy); goto foundbelow1; } - } - while(cx >= sx1) - { - bits = *--bsrc; - if(bits==0xFF) cx -= 8; - else if((bx = cx - 7) <= sx1) - { - for(; cx >= sx1; cx--, bits >>= 1) if(!(bits&1)) { sx1 = cx+1; searchdist(x, y, cx, cy); goto foundbelow1; } - goto foundbelow1; - } - else for(; cx >= bx; cx--, bits >>= 1) if(!(bits&1)) { sx1 = cx+1; searchdist(x, y, cx, cy); goto foundbelow1; } - - } - } -foundbelow1: - cx = imax(sx1, x); - if(cx < ex1) - { - uchar *bsrc = &src[cx>>3]; - int bx = (cx&~7) + 8, bits = *bsrc; - if(bits==0xFF) cx = bx; - else - { - bits <<= cx&7; - if(bx >= ex1) - { - for(; cx < ex1; cx++, bits <<= 1) if(!(bits&0x80)) { ex1 = cx-1; searchdist(x, y, cx, cy); goto foundabove1; } - goto foundabove1; - } - else for(; cx < bx; cx++, bits <<= 1) if(!(bits&0x80)) { ex1 = cx-1; searchdist(x, y, cx, cy); goto foundabove1; } - } - while(cx < ex1) - { - bits = *++bsrc; - if(bits==0xFF) cx += 8; - else if((bx = cx + 8) >= ex1) - { - for(; cx < ex1; cx++, bits <<= 1) if(!(bits&0x80)) { ex1 = cx-1; searchdist(x, y, cx, cy); goto foundabove1; } - goto foundabove1; - } - else for(; cx < bx; cx++, bits <<= 1) if(!(bits&0x80)) { ex1 = cx-1; searchdist(x, y, cx, cy); goto foundabove1; } - } - } -foundabove1: - if(x - radius < 0) searchdist(x, y, -1, cy); - if(x + radius > w) searchdist(x, y, w, cy); - return sx1 < ex1; -} - -static int sx0, ex0; -static inline int search0(int x, int y, int w, int radius, int cy, uchar *src) -{ - int cx = imin(ex0, x)-1; - if(cx >= sx0) - { - uchar *bsrc = &src[cx>>3]; - int bx = cx&~7, bits = *bsrc; - if(!bits) cx = bx-1; - else - { - bits >>= 7-(cx&7); - if(bx <= sx0) - { - for(; cx >= sx0; cx--, bits >>= 1) if(bits&1) { sx0 = cx+1; searchdist(x, y, cx, cy); goto foundbelow0; } - goto foundbelow0; - } - else for(; cx >= bx; cx--, bits >>= 1) if(bits&1) { sx0 = cx+1; searchdist(x, y, cx, cy); goto foundbelow0; } - } - while(cx >= sx0) - { - bits = *--bsrc; - if(!bits) cx -= 8; - else if((bx = cx - 7) <= sx0) - { - for(; cx >= sx0; cx--, bits >>= 1) if(bits&1) { sx0 = cx+1; searchdist(x, y, cx, cy); goto foundbelow0; } - goto foundbelow0; - } - else for(; cx >= bx; cx--, bits >>= 1) if(bits&1) { sx0 = cx+1; searchdist(x, y, cx, cy); goto foundbelow0; } - } - } -foundbelow0: - cx = imax(sx0, x); - if(cx < ex0) - { - uchar *bsrc = &src[cx>>3]; - int bx = (cx&~7) + 8, bits = *bsrc; - if(!bits) cx = bx; - else - { - bits <<= cx&7; - if(bx >= ex0) - { - for(; cx < ex0; cx++, bits <<= 1) if(bits&0x80) { ex0 = cx-1; searchdist(x, y, cx, cy); goto foundabove0; } - goto foundabove0; - } - else for(; cx < bx; cx++, bits <<= 1) if(bits&0x80) { ex0 = cx-1; searchdist(x, y, cx, cy); goto foundabove0; } - } - while(cx < ex0) - { - bits = *++bsrc; - if(!bits) cx += 8; - else if((bx = cx + 8) >= ex0) - { - for(; cx < ex0; cx++, bits <<= 1) if(bits&0x80) { ex0 = cx-1; searchdist(x, y, cx, cy); goto foundabove0; } - goto foundabove0; - } - else for(; cx < bx; cx++, bits <<= 1) if(bits&0x80) { ex0 = cx-1; searchdist(x, y, cx, cy); goto foundabove0; } - } - } -foundabove0: - return sx0 < ex0; -} - -#define SUPERSAMPLE_MIN 1 -#define SUPERSAMPLE_MAX 32 -static int supersample = SUPERSAMPLE_MIN; - -void gensdf(struct fontchar *c) -{ - int w = c->glyph->bitmap.width, h = c->glyph->bitmap.rows, radius = c->sdfradius*supersample; - int dx, dy, dw = (w + 2*radius + supersample-1)/supersample, dh = (h + 2*radius + supersample-1)/supersample; - int x, y, x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN; - uchar *dst = (uchar *)malloc(dw*dh), *src; - if(!dst) fatal("tessfont: failed allocating signed distance field"); - c->sdfpitch = dw; - c->sdf = dst; - for(dy = 0; dy < dh; dy++) - for(dx = 0; dx < dw; dx++) - { - double total = 0; - for(y = dy*supersample - radius; y < (dy+1)*supersample - radius; y++) - for(x = dx*supersample - radius; x < (dx+1)*supersample - radius; x++) - { - int sx = imax(x - radius, 0), sy = imax(y - radius, 0), ex = imin(x + radius, w), ey = imin(y + radius, h), cy, val = 0; - if(y >= 0 && y < h && x >= 0 && x < w) - { - uchar *center = (uchar *)c->glyph->bitmap.buffer + y*c->glyph->bitmap.pitch; - val = (center[x>>3]<<(x&7))&0x80; - } - sdist = INT_MAX; - if(val) - { - for(cy = imin(ey, y)-1, sx1 = sx, ex1 = ex, src = (uchar *)c->glyph->bitmap.buffer + cy*c->glyph->bitmap.pitch; - cy >= sy && search1(x, y, w, radius, cy, src); - cy--, src -= c->glyph->bitmap.pitch); - for(cy = imax(sy, y), sx1 = sx, ex1 = ex, src = (uchar *)c->glyph->bitmap.buffer + cy*c->glyph->bitmap.pitch; - cy < ey && search1(x, y, w, radius, cy, src); - cy++, src += c->glyph->bitmap.pitch); - if(y - radius < 0) searchdist(x, y, x, -1); - if(y + radius > h) searchdist(x, y, x, h); - } - else - { - for(cy = imin(ey, y)-1, sx0 = sx, ex0 = ex, src = (uchar *)c->glyph->bitmap.buffer + cy*c->glyph->bitmap.pitch; - cy >= sy && search0(x, y, w, radius, cy, src); - cy--, src -= c->glyph->bitmap.pitch); - for(cy = imax(sy, y), sx0 = sx, ex0 = ex, src = (uchar *)c->glyph->bitmap.buffer + cy*c->glyph->bitmap.pitch; - cy < ey && search0(x, y, w, radius, cy, src); - cy++, src += c->glyph->bitmap.pitch); - } - if(val) total += sqrt(sdist); - else total -= sqrt(sdist); - } - *dst = (uchar)iclamp((int)round(127.5 + (127.5/(supersample*supersample))*total/radius), 0, 255); - if(*dst) - { - x1 = imin(x1, dx); - y1 = imin(y1, dy); - x2 = imax(x2, dx); - y2 = imax(y2, dy); - } - dst++; - } - if(x1 <= x2 && y1 <= y2) - { - c->sdfx = x1; - c->sdfy = y1; - c->sdfw = x2 - x1 + 1; - c->sdfh = y2 - y1 + 1; - } -} - -void writetexs(const char *name, struct fontchar *chars, int numchars, int numtexs, int tw, int th) -{ - int tex; - uchar *pixels = (uchar *)malloc(tw*th); - if(!pixels) fatal("tessfont: failed allocating textures"); - for(tex = 0; tex < numtexs; tex++) - { - const char *file = texfilename(name, tex); - int texchars = 0, i; - uchar *dst, *src; - memset(pixels, 0, tw*th); - for(i = 0; i < numchars; i++) - { - struct fontchar *c = &chars[i]; - int y; - if(c->tex != tex) continue; - texchars++; - dst = &pixels[c->y*tw + c->x]; - src = c->sdf + c->sdfy*c->sdfpitch + c->sdfx; - for(y = 0; y < c->sdfh; y++) - { - memcpy(dst, src, c->sdfw); - dst += tw; - src += c->sdfpitch; - } - } - printf("tessfont: writing %d chars to %s\n", texchars, file); - savepng(file, pixels, tw, th, 1, 0); - } - free(pixels); -} - -static float offsetx = 0, offsety = 0, border = 0, border2 = 0, outline = 0, outline2 = 0; -static int scale = 0; - -void writecfg(const char *name, struct fontchar *chars, int numchars, float x1, float y1, float x2, float y2, int sw, int sh, int argc, char **argv) -{ - FILE *f; - char file[256]; - int i, lastcode = 0, lasttex = 0; - snprintf(file, sizeof(file), "%s.cfg", name); - f = fopen(file, "w"); - if(!f) fatal("tessfont: failed writing %s", file); - printf("tessfont: writing %d chars to %s\n", numchars, file); - fprintf(f, "//"); - for(i = 1; i < argc; i++) - fprintf(f, " %s", argv[i]); - fprintf(f, "\n"); - fprintf(f, "font \"%s\" \"%s\" %d %d\n", name, texname(name, 0), sw, sh); - if(scale > 0) fprintf(f, "fontscale %d\n", scale); - if(border2) fprintf(f, "fontborder %g %g\n", border, border2); - else if(border) fprintf(f, "fontborder %g\n", border); - if(outline2) fprintf(f, "fontoutline %g %g\n", outline, outline2); - else if(outline) fprintf(f, "fontoutline %g\n", outline); - for(i = 0; i < numchars; i++) - { - struct fontchar *c = &chars[i]; - if(!lastcode && lastcode < c->code) - { - fprintf(f, "fontoffset \"%s\"\n", encodeutf8(c->uni)); - lastcode = c->code; - } - else if(lastcode < c->code) - { - if(lastcode + 1 == c->code) - fprintf(f, "fontskip // %d\n", lastcode); - else - fprintf(f, "fontskip %d // %d .. %d\n", c->code - lastcode, lastcode, c->code-1); - lastcode = c->code; - } - if(lasttex != c->tex) - { - fprintf(f, "\nfonttex \"%s\"\n", texname(name, c->tex)); - lasttex = c->tex; - } - float offx = c->sdfx-c->sdfradius + c->left + offsetx, offy = c->sdfy-c->sdfradius + y2-c->top + offsety; - if(c->code != c->uni) - fprintf(f, "fontchar %d %d %d %d %g %g %g // %s (%d -> 0x%X)\n", c->x, c->y, c->sdfw, c->sdfh, offx, offy, c->advance, encodeutf8(c->uni), c->code, c->uni); - else - fprintf(f, "fontchar %d %d %d %d %g %g %g // %s (%d)\n", c->x, c->y, c->sdfw, c->sdfh, offx, offy, c->advance, encodeutf8(c->uni), c->code); - lastcode++; - } - fclose(f); -} - -int groupchar(int c) -{ - switch(c) - { - case 0x152: case 0x153: case 0x178: return 1; - } - if(c < 127 || c >= 0x2000) return 0; - if(c < 0x100) return 1; - if(c < 0x400) return 2; - return 3; -} - -int sortchars(const void *x, const void *y) -{ - const struct fontchar *xc = *(const struct fontchar **)x, *yc = *(const struct fontchar **)y; - int xg = groupchar(xc->uni), yg = groupchar(yc->uni); - if(xg < yg) return -1; - if(xg > yg) return 1; - if(xc->sdfh != yc->sdfh) return yc->sdfh - xc->sdfh; - if(xc->sdfw != yc->sdfw) return yc->sdfw - xc->sdfw; - return yc->uni - xc->uni; -} - -int scorechar(struct fontchar *f, int pad, int tw, int th, int rw, int rh, int ry) -{ - int score = 0; - if(rw + f->sdfw > tw) { ry += rh + pad; score = 1; } - if(ry + f->sdfh > th) score = 2; - return score; -} - -int main(int argc, char **argv) -{ - FT_Library l; - FT_Face f; - int i, radius, pad, w, h, tw, th, c, numgen = 0, trial = -2, rw = 0, rh = 0, ry = 0, sw = 0, sh = 0; - float advance, x1 = INT_MAX, x2 = INT_MIN, y1 = INT_MAX, y2 = INT_MIN, w2 = 0, h2 = 0; - time_t starttime, endtime; - struct fontchar chars[256]; - struct fontchar *order[256]; - int numchars = 0, numtex = 0; - if(argc < 13) - fatal("Usage: tessfont infile outfile supersample border[:border2[:outline:outline2]] radius pad offsetx[:offsety] advance charwidth charheight texwidth texheight [spacewidth spaceheight scale texdir]"); - supersample = iclamp(atoi(argv[3]), SUPERSAMPLE_MIN, SUPERSAMPLE_MAX); - sscanf(argv[4], "%f:%f:%f:%f", &border, &border2, &outline, &outline2); - radius = atoi(argv[5]); - pad = atoi(argv[6]); - sscanf(argv[7], "%f:%f", &offsetx, &offsety); - advance = atof(argv[8]); - w = atoi(argv[9]); - h = atoi(argv[10]); - tw = atoi(argv[11]); - th = atoi(argv[12]); - if(argc > 13) sw = atoi(argv[13]); - if(argc > 14) sh = atoi(argv[14]); - if(argc > 15) scale = atoi(argv[15]); - if(argc > 16) texdir = argv[16]; - if(FT_Init_FreeType(&l)) - fatal("tessfont: failed initing freetype"); - if(FT_New_Face(l, argv[1], 0, &f) || - FT_Set_Charmap(f, f->charmaps[0]) || - FT_Set_Pixel_Sizes(f, w*supersample, h*supersample)) - fatal("tessfont: failed loading font %s", argv[1]); - setbuf(stdout, NULL); - starttime = time(NULL); - for(c = 0; c < 256; c++) if(iscubeprint(c)) - { - FT_Glyph p; - FT_BitmapGlyph b; - struct fontchar *dst = &chars[numchars]; - dst->code = c; - dst->uni = cube2uni(c); - if(FT_Load_Char(f, dst->uni, FT_LOAD_TARGET_MONO)) - fatal("tessfont: failed loading character %s", encodeutf8(dst->uni)); - FT_Get_Glyph(f->glyph, &p); - FT_Glyph_To_Bitmap(&p, FT_RENDER_MODE_MONO, 0, 1); - b = (FT_BitmapGlyph)p; - dst->tex = -1; - dst->x = INT_MIN; - dst->y = INT_MIN; - dst->w = b->bitmap.width/(float)supersample; - dst->h = b->bitmap.rows/(float)supersample; - dst->left = b->left/(float)supersample; - dst->top = b->top/(float)supersample; - dst->advance = offsetx + p->advance.x/(float)(supersample<<16) + advance; - dst->glyph = b; - dst->sdfradius = radius; - dst->sdf = NULL; - dst->sdfpitch = 0; - dst->sdfx = 0; - dst->sdfy = 0; - dst->sdfw = 0; - dst->sdfh = 0; - order[numchars++] = dst; - if(!numgen) printf("tessfont: generating %d", dst->code); - else printf(" %d", dst->code); - numgen += dst->code >= 100 ? 4 : (dst->code >= 10 ? 3 : 2); - if(numgen > 50) { printf("\n"); numgen = 0; } - gensdf(dst); - } - if(numgen) printf("\n"); - qsort(order, numchars, sizeof(order[0]), sortchars); - for(i = 0; i < numchars;) - { - struct fontchar *dst; - int j, k, trial0, prevscore, dstscore, fitscore; - for(trial0 = trial, prevscore = -1; (trial -= 2) >= trial0-512;) - { - int g, fw = rw, fh = rh, fy = ry, curscore = 0, reused = 0; - for(j = i; j < numchars; j++) - { - dst = order[j]; - if(dst->tex >= 0 || dst->tex <= trial) continue; - g = groupchar(dst->uni); - dstscore = scorechar(dst, pad, tw, th, fw, fh, fy); - for(k = j; k < numchars; k++) - { - struct fontchar *fit = order[k]; - if(fit->tex >= 0 || fit->tex <= trial) continue; - if(fit->tex >= trial0 && groupchar(fit->uni) != g) break; - fitscore = scorechar(fit, pad, tw, th, fw, fh, fy); - if(fitscore < dstscore || (fitscore == dstscore && fit->sdfh > dst->sdfh)) - { - dst = fit; - dstscore = fitscore; - } - } - if(fw + dst->sdfw > tw) - { - fy += fh + pad; - fw = fh = 0; - } - if(fy + dst->sdfh > th) - { - fy = fw = fh = 0; - if(curscore > 0) break; - } - if(dst->tex >= trial+1 && dst->tex <= trial+2) { dst->tex = trial; reused++; } - else dst->tex = trial; - fw += dst->sdfw + pad; - fh = imax(fh, dst->sdfh); - if(dst != order[j]) --j; - curscore++; - } - if(reused < prevscore || curscore <= prevscore) break; - prevscore = curscore; - } - for(; i < numchars; i++) - { - dst = order[i]; - if(dst->tex >= 0) continue; - dstscore = scorechar(dst, pad, tw, th, rw, rh, ry); - for(j = i; j < numchars; j++) - { - struct fontchar *fit = order[j]; - if(fit->tex < trial || fit->tex > trial+2) continue; - fitscore = scorechar(fit, pad, tw, th, rw, rh, ry); - if(fitscore < dstscore || (fitscore == dstscore && fit->sdfh > dst->sdfh)) - { - dst = fit; - dstscore = fitscore; - } - } - if(dst->tex < trial || dst->tex > trial+2) break; - if(rw + dst->sdfw > tw) - { - ry += rh + pad; - rw = rh = 0; - } - if(ry + dst->sdfh > th) - { - ry = rw = rh = 0; - numtex++; - } - dst->tex = numtex; - dst->x = rw; - dst->y = ry; - rw += dst->sdfw + pad; - rh = imax(rh, dst->sdfh); - y1 = fmin(y1, dst->top - dst->h); - y2 = fmax(y2, dst->top); - x1 = fmin(x1, dst->left); - x2 = fmax(x2, dst->left + dst->w); - w2 = fmax(w2, dst->w); - h2 = fmax(h2, dst->h); - if(dst != order[i]) --i; - } - } - if(rh > 0) numtex++; - if(sh <= 0) sh = (int)ceil(y2 - y1); - if(sw <= 0) sw = sh/3; - endtime = time(NULL); - writetexs(argv[2], chars, numchars, numtex, tw, th); - writecfg(argv[2], chars, numchars, x1, y1, x2, y2, sw, sh, argc, argv); - for(i = 0; i < numchars; i++) - { - struct fontchar *c = &chars[i]; - FT_Done_Glyph((FT_Glyph)c->glyph); - if(c->sdf) free(c->sdf); - } - FT_Done_FreeType(l); - printf("tessfont: (%g, %g) .. (%g, %g) = (%g, %g) / (%g, %g), %d texs, %d secs\n", x1, y1, x2, y2, x2 - x1, y2 - y1, w2, h2, numtex, (int)(endtime - starttime)); - return EXIT_SUCCESS; -} -