drop leftover unused code, headers for texture.cc and shader.cc

master
Daniel Kolesa 2020-04-30 22:50:35 +02:00
parent 768c588322
commit 949ec16cd7
34 changed files with 699 additions and 2164 deletions

View File

@ -1,4 +1,5 @@
#include "aa.hh"
#include "texture.hh"
#include "engine.hh"

View File

@ -1,3 +1,5 @@
#include "texture.hh"
#include "engine.hh"
extern vec hitsurface;

View File

@ -1,4 +1,10 @@
#ifndef ENGINE_BIH_HH
#define ENGINE_BIH_HH
#include <shared/geom.hh>
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

View File

@ -1,4 +1,5 @@
#include "blend.hh"
#include "texture.hh"
#include "engine.hh"

View File

@ -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();

View File

@ -1,4 +1,5 @@
#include "blend.hh"
#include "texture.hh"
#include "engine.hh"

View File

@ -1,4 +1,5 @@
#include "blend.hh"
#include "texture.hh"
#include "engine.hh"

View File

@ -1,6 +1,8 @@
// main.cpp: initialisation & main loop
#include "blend.hh"
#include "shader.hh"
#include "texture.hh"
#include "world.hh"
#include "engine.hh"

View File

@ -1,4 +1,5 @@
#include "material.hh"
#include "texture.hh"
#include "water.hh"
#include "engine.hh"

View File

@ -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;

View File

@ -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);

View File

@ -1,3 +1,5 @@
#include "texture.hh"
#include "engine.hh"
struct normalkey

View File

@ -1,5 +1,6 @@
#include "blend.hh"
#include "material.hh"
#include "texture.hh"
#include "world.hh"
#include "engine.hh"

View File

@ -2,6 +2,7 @@
#include "blend.hh"
#include "material.hh"
#include "texture.hh"
#include "world.hh"
#include "engine.hh"

View File

@ -3,6 +3,7 @@
#include "aa.hh"
#include "blend.hh"
#include "material.hh"
#include "texture.hh"
#include "water.hh"
#include "engine.hh"

View File

@ -2,6 +2,7 @@
#include "aa.hh"
#include "material.hh"
#include "texture.hh"
#include "world.hh"
#include "engine.hh"

View File

@ -1,4 +1,6 @@
#include "aa.hh"
#include "shader.hh"
#include "texture.hh"
#include "engine.hh"

View File

@ -1,5 +1,7 @@
// renderparticles.cpp
#include "shader.hh"
#include "texture.hh"
#include "water.hh"
#include "world.hh"

View File

@ -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 };

View File

@ -1,3 +1,5 @@
#include "texture.hh"
#include "engine.hh"
static hashnameset<font> fonts;

View File

@ -1,6 +1,7 @@
// renderva.cpp: handles the occlusion and rendering of vertex arrays
#include "blend.hh"
#include "texture.hh"
#include "engine.hh"

View File

@ -1,5 +1,8 @@
// shader.cpp: OpenGL GLSL shader management
#include "shader.hh"
#include "texture.hh"
#include "engine.hh"
Shader *Shader::lastshader = NULL;

View File

@ -0,0 +1,499 @@
#ifndef ENGINE_SHADER_HH
#define ENGINE_SHADER_HH
#include <shared/glexts.hh>
#include <shared/tools.hh>
#include <shared/geom.hh>
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<SlotShaderParamState> defaultparams;
vector<GlobalShaderParamUse> globalparams;
vector<LocalShaderParamState> localparams;
vector<uchar> localparamremap;
Shader *variantshader;
vector<Shader *> variants;
ushort *variantrows;
bool standard, forced, used;
Shader *reusevs, *reuseps;
vector<UniformLoc> uniformlocs;
vector<AttribLoc> attriblocs;
vector<FragDataLoc> 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<class T>
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<class T>
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<class T>
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<int>(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<uint>(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

View File

@ -1,4 +1,5 @@
#include "material.hh"
#include "texture.hh"
#include "engine.hh"

View File

@ -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<editline> &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<editline> 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 &currentline()
{
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<char> 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 &current = 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 &current = currentline();
if(ch == '\n')
{
if(maxy == -1 || cy < maxy-1)
{
editline newline(&current.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 &current = 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 &current = 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 &current = 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 <cx, cy> 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<editor *> 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<char> 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;
);

View File

@ -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<Texture> textures;
static hashnameset<Texture> 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<VSlot *> vslots;
vector<Slot *> slots;
MatSlot materialslots[(MATF_VOLUME|MATF_INDEX)+1];
Slot dummyslot;
VSlot dummyvslot(&dummyslot);
vector<DecalSlot *> decalslots;
DecalSlot dummydecalslot;
Slot *defslot = NULL;
static MatSlot materialslots[(MATF_VOLUME|MATF_INDEX)+1];
static vector<DecalSlot *> 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<envmap> 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<uint>(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;

View File

@ -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 <shared/gl.hh>
#include <shared/tools.hh>
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<SlotShaderParamState> defaultparams;
vector<GlobalShaderParamUse> globalparams;
vector<LocalShaderParamState> localparams;
vector<uchar> localparamremap;
Shader *variantshader;
vector<Shader *> variants;
ushort *variantrows;
bool standard, forced, used;
Shader *reusevs, *reuseps;
vector<UniformLoc> uniformlocs;
vector<AttribLoc> attriblocs;
vector<FragDataLoc> 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<class T>
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<class T>
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<class T>
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<int>(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<uint>(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<uchar> &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<Slot *> slots;
extern vector<VSlot *> 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<uchar> &buf, const VSlot &src);
void packvslot(vector<uchar> &buf, int index);
void packvslot(vector<uchar> &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

View File

@ -1,4 +1,5 @@
#include "material.hh"
#include "texture.hh"
#include "water.hh"
#include "engine.hh"

View File

@ -1,6 +1,7 @@
// world.cpp: core map management stuff
#include "blend.hh"
#include "texture.hh"
#include "worldio.hh"
#include "world.hh"

View File

@ -1,6 +1,7 @@
// worldio.cpp: loading & saving of maps and savegames
#include "blend.hh"
#include "texture.hh"
#include "world.hh"
#include "worldio.hh"

View File

@ -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 */

View File

@ -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 */

View File

@ -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<uchar> &buf, int index);
extern void packvslot(vector<uchar> &buf, const VSlot *vs);
// renderlights
enum { L_NOSHADOW = 1<<0, L_NODYNSHADOW = 1<<1, L_VOLUMETRIC = 1<<2, L_NOSPEC = 1<<3 };

View File

@ -1,764 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#include <zlib.h>
#include <ft2build.h>
#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), "<grey>%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;
}