OctaCore/src/engine/texture.hh

428 lines
9.8 KiB
C++

#ifndef ENGINE_TEXTURE_HH
#define ENGINE_TEXTURE_HH
#include <shared/gl.hh>
#include <shared/tools.hh>
#include "shader.hh"
struct ImageData
{
int w, h, bpp, levels, align, pitch;
GLenum compressed;
uchar *data;
void *owner;
void (*freefunc)(void *);
ImageData()
: data(nullptr), owner(nullptr), freefunc(nullptr)
{}
ImageData(int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE)
{
setdata(nullptr, nw, nh, nbpp, nlevels, nalign, ncompressed);
}
ImageData(int nw, int nh, int nbpp, uchar *data)
: owner(nullptr), freefunc(nullptr)
{
setdata(data, nw, nh, nbpp);
}
ImageData(SDL_Surface *s) { wrap(s); }
~ImageData() { cleanup(); }
void setdata(uchar *ndata, int nw, int nh, int nbpp, int nlevels = 1, int nalign = 0, GLenum ncompressed = GL_FALSE)
{
w = nw;
h = nh;
bpp = nbpp;
levels = nlevels;
align = nalign;
pitch = align ? 0 : w*bpp;
compressed = ncompressed;
data = ndata ? ndata : new uchar[calcsize()];
if(!ndata) { owner = this; freefunc = nullptr; }
}
int calclevelsize(int level) const { return ((max(w>>level, 1)+align-1)/align)*((max(h>>level, 1)+align-1)/align)*bpp; }
int calcsize() const
{
if(!align) return w*h*bpp;
int lw = w, lh = h,
size = 0;
loopi(levels)
{
if(lw<=0) lw = 1;
if(lh<=0) lh = 1;
size += ((lw+align-1)/align)*((lh+align-1)/align)*bpp;
if(lw*lh==1) break;
lw >>= 1;
lh >>= 1;
}
return size;
}
void disown()
{
data = nullptr;
owner = nullptr;
freefunc = nullptr;
}
void cleanup()
{
if(owner==this) delete[] data;
else if(freefunc) (*freefunc)(owner);
disown();
}
void replace(ImageData &d)
{
cleanup();
*this = d;
if(owner == &d) owner = this;
d.disown();
}
void wrap(SDL_Surface *s)
{
setdata((uchar *)s->pixels, s->w, s->h, s->format->BytesPerPixel);
pitch = s->pitch;
owner = s;
freefunc = (void (*)(void *))SDL_FreeSurface;
}
};
// management of texture slots
// each texture slot can have multiple texture frames, of which currently only the first is used
// additional frames can be used for various shaders
struct Texture
{
enum
{
IMAGE = 0,
CUBEMAP = 1,
TYPE = 0xFF,
STUB = 1<<8,
TRANSIENT = 1<<9,
COMPRESSED = 1<<10,
ALPHA = 1<<11,
MIRROR = 1<<12,
FLAGS = 0xFF00
};
char *name;
int type, w, h, xs, ys, bpp, clamp;
bool mipmap, canreduce;
GLuint id;
uchar *alphamask;
Texture() : alphamask(nullptr) {}
};
enum
{
TEX_DIFFUSE = 0,
TEX_NORMAL,
TEX_GLOW,
TEX_ENVMAP,
TEX_SPEC,
TEX_DEPTH,
TEX_ALPHA,
TEX_UNKNOWN,
TEX_DETAIL = TEX_SPEC
};
enum
{
VSLOT_SHPARAM = 0,
VSLOT_SCALE,
VSLOT_ROTATION,
VSLOT_OFFSET,
VSLOT_SCROLL,
VSLOT_LAYER,
VSLOT_ALPHA,
VSLOT_COLOR,
VSLOT_RESERVED, // used by RE
VSLOT_REFRACT,
VSLOT_DETAIL,
VSLOT_NUM
};
struct VSlot
{
Slot *slot;
VSlot *next;
int index, changed;
vector<SlotShaderParam> params;
bool linked;
float scale;
int rotation;
ivec2 offset;
vec2 scroll;
int layer, detail;
float alphafront, alphaback;
vec colorscale;
vec glowcolor;
float refractscale;
vec refractcolor;
VSlot(Slot *slot = nullptr, int index = -1) : slot(slot), next(nullptr), index(index), changed(0)
{
reset();
if(slot) addvariant(slot);
}
void addvariant(Slot *slot);
void reset()
{
params.setsize(0);
linked = false;
scale = 1;
rotation = 0;
offset = ivec2(0, 0);
scroll = vec2(0, 0);
layer = detail = 0;
alphafront = 0.5f;
alphaback = 0;
colorscale = vec(1, 1, 1);
glowcolor = vec(1, 1, 1);
refractscale = 0;
refractcolor = vec(1, 1, 1);
}
void cleanup()
{
linked = false;
}
bool isdynamic() const;
};
struct Slot
{
enum { OCTA, MATERIAL, DECAL };
struct Tex
{
int type;
Texture *t;
string name;
int combined;
Tex() : t(nullptr), combined(-1) {}
};
int index, smooth;
vector<Tex> sts;
Shader *shader;
vector<SlotShaderParam> params;
VSlot *variants;
bool loaded;
uint texmask;
char *grass;
Texture *grasstex, *thumbnail;
Slot(int index = -1) : index(index), variants(nullptr), grass(nullptr) { reset(); }
virtual ~Slot() {}
virtual int type() const { return OCTA; }
virtual const char *name() const;
virtual const char *texturedir() const { return "media/texture"; }
virtual VSlot &emptyvslot();
virtual int cancombine(int type) const;
virtual bool shouldpremul(int type) const { return false; }
int findtextype(int type, int last = -1) const;
void load(int index, Slot::Tex &t);
void load();
Texture *loadthumbnail();
void reset()
{
smooth = -1;
sts.setsize(0);
shader = nullptr;
params.setsize(0);
loaded = false;
texmask = 0;
DELETEA(grass);
grasstex = nullptr;
thumbnail = nullptr;
}
void cleanup()
{
loaded = false;
grasstex = nullptr;
thumbnail = nullptr;
loopv(sts)
{
Tex &t = sts[i];
t.t = nullptr;
t.combined = -1;
}
}
};
inline void VSlot::addvariant(Slot *slot)
{
if(!slot->variants) slot->variants = this;
else
{
VSlot *prev = slot->variants;
while(prev->next) prev = prev->next;
prev->next = this;
}
}
inline bool VSlot::isdynamic() const
{
return !scroll.iszero() || slot->shader->isdynamic();
}
struct MatSlot : Slot, VSlot
{
MatSlot();
int type() const { return MATERIAL; }
const char *name() const;
VSlot &emptyvslot() { return *this; }
int cancombine(int type) const { return -1; }
void reset()
{
Slot::reset();
VSlot::reset();
}
void cleanup()
{
Slot::cleanup();
VSlot::cleanup();
}
};
struct DecalSlot : Slot, VSlot
{
float depth, fade;
DecalSlot(int index = -1) : Slot(index), VSlot(this), depth(1), fade(0.5f) {}
int type() const { return DECAL; }
const char *name() const;
const char *texturedir() const { return "media/decal"; }
VSlot &emptyvslot() { return *this; }
int cancombine(int type) const;
bool shouldpremul(int type) const;
void reset()
{
Slot::reset();
VSlot::reset();
depth = 1;
fade = 0.5f;
}
void cleanup()
{
Slot::cleanup();
VSlot::cleanup();
}
};
struct texrotation
{
bool flipx, flipy, swapxy;
};
struct cubemapside
{
GLenum target;
const char *name;
bool flipx, flipy, swapxy;
};
extern const texrotation texrotations[8];
extern const cubemapside cubemapsides[6];
extern int hwtexsize, hwcubetexsize, hwmaxaniso, maxtexsize, hwtexunits, hwvtexunits;
#define MAXBLURRADIUS 7
extern float blursigma;
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);
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;
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