OctaCore/src/engine/water.cc

698 lines
23 KiB
C++

#include "water.hh"
#include "material.hh"
#include "octarender.hh"
#include "rendergl.hh"
#include "texture.hh"
#include "world.hh"
#include <shared/cube.hh>
extern const vec matnormals[6];
extern vector<materialsurface> watersurfs[4], waterfallsurfs[4], lavasurfs[4], lavafallsurfs[4];
#define NUMCAUSTICS 32
VARFR(causticscale, 0, 50, 10000, preloadwatershaders());
VARFR(causticmillis, 0, 75, 1000, preloadwatershaders());
FVARR(causticcontrast, 0, 0.6f, 2);
FVARR(causticoffset, 0, 0.7f, 1);
VARFP(caustics, 0, 1, 1, { loadcaustics(); preloadwatershaders(); });
#define WATERVARS(name) \
CVAR0R(name##colour, 0x01212C); \
CVAR0R(name##deepcolour, 0x010A10); \
CVAR0R(name##deepfade, 0x60BFFF); \
CVAR0R(name##refractcolour, 0xFFFFFF); \
VARR(name##fog, 0, 30, 10000); \
VARR(name##deep, 0, 50, 10000); \
VARR(name##spec, 0, 150, 200); \
FVARR(name##refract, 0, 0.1f, 1e3f); \
CVARR(name##fallcolour, 0); \
CVARR(name##fallrefractcolour, 0); \
VARR(name##fallspec, 0, 150, 200); \
FVARR(name##fallrefract, 0, 0.1f, 1e3f);
WATERVARS(water)
WATERVARS(water2)
WATERVARS(water3)
WATERVARS(water4)
GETMATIDXVAR(water, colour, const bvec &)
GETMATIDXVAR(water, deepcolour, const bvec &)
GETMATIDXVAR(water, deepfade, const bvec &)
GETMATIDXVAR(water, refractcolour, const bvec &)
GETMATIDXVAR(water, fallcolour, const bvec &)
GETMATIDXVAR(water, fallrefractcolour, const bvec &)
GETMATIDXVAR(water, fog, int)
GETMATIDXVAR(water, deep, int)
GETMATIDXVAR(water, spec, int)
GETMATIDXVAR(water, refract, float)
GETMATIDXVAR(water, fallspec, int)
GETMATIDXVAR(water, fallrefract, float)
#define LAVAVARS(name) \
CVAR0R(name##colour, 0xFF4000); \
VARR(name##fog, 0, 50, 10000); \
FVARR(name##glowmin, 0, 0.25f, 2); \
FVARR(name##glowmax, 0, 1.0f, 2); \
VARR(name##spec, 0, 25, 200);
LAVAVARS(lava)
LAVAVARS(lava2)
LAVAVARS(lava3)
LAVAVARS(lava4)
GETMATIDXVAR(lava, colour, const bvec &)
GETMATIDXVAR(lava, fog, int)
GETMATIDXVAR(lava, glowmin, float)
GETMATIDXVAR(lava, glowmax, float)
GETMATIDXVAR(lava, spec, int)
VARFP(waterreflect, 0, 1, 1, { preloadwatershaders(); });
VARR(waterreflectstep, 1, 32, 10000);
VARFP(waterenvmap, 0, 1, 1, { preloadwatershaders(); });
VARFP(waterfallenv, 0, 1, 1, preloadwatershaders());
VARFP(vertwater, 0, 1, 1, allchanged());
static Texture *caustictex[NUMCAUSTICS] = { NULL };
void loadcaustics(bool force)
{
static bool needcaustics = false;
if(force) needcaustics = true;
if(!caustics || !needcaustics) return;
useshaderbyname("caustics");
if(caustictex[0]) return;
loopi(NUMCAUSTICS)
{
defformatstring(name, "<grey><noswizzle>media/texture/mat_water/caustic/caust%.2d.png", i);
caustictex[i] = textureload(name);
}
}
#if 0
static void cleanupcaustics()
{
loopi(NUMCAUSTICS) caustictex[i] = NULL;
}
#endif
static void setupcaustics(int tmu, float surface = -1e16f)
{
if(!caustictex[0]) loadcaustics(true);
vec s = vec(0.011f, 0, 0.0066f).mul(100.0f/causticscale), t = vec(0, 0.011f, 0.0066f).mul(100.0f/causticscale);
int tex = (lastmillis/causticmillis)%NUMCAUSTICS;
float frac = float(lastmillis%causticmillis)/causticmillis;
loopi(2)
{
glActiveTexture_(GL_TEXTURE0+tmu+i);
glBindTexture(GL_TEXTURE_2D, caustictex[(tex+i)%NUMCAUSTICS]->id);
}
glActiveTexture_(GL_TEXTURE0);
float blendscale = causticcontrast, blendoffset = 1;
if(surface > -1e15f)
{
float bz = surface + camera1->o.z + (vertwater ? WATER_AMPLITUDE : 0);
matrix4 m(vec4(s.x, t.x, 0, 0),
vec4(s.y, t.y, 0, 0),
vec4(s.z, t.z, -1, 0),
vec4( 0, 0, bz, 1));
m.mul(worldmatrix);
GLOBALPARAM(causticsmatrix, m);
blendscale *= 0.5f;
blendoffset = 0;
}
else
{
GLOBALPARAM(causticsS, s);
GLOBALPARAM(causticsT, t);
}
GLOBALPARAMF(causticsblend, blendscale*(1-frac), blendscale*frac, blendoffset - causticoffset*blendscale);
}
static void rendercaustics(float surface, float syl, float syr)
{
if(!caustics || !causticscale || !causticmillis) return;
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
setupcaustics(0, surface);
SETSHADER(caustics);
gle::defvertex(2);
gle::begin(GL_TRIANGLE_STRIP);
gle::attribf(1, -1);
gle::attribf(-1, -1);
gle::attribf(1, syr);
gle::attribf(-1, syl);
gle::end();
}
void renderwaterfog(int mat, float surface)
{
glDepthFunc(GL_NOTEQUAL);
glDepthMask(GL_FALSE);
glDepthRange(1, 1);
glEnable(GL_BLEND);
glActiveTexture_(GL_TEXTURE9);
if(msaalight) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msdepthtex);
else glBindTexture(GL_TEXTURE_RECTANGLE, gdepthtex);
glActiveTexture_(GL_TEXTURE0);
vec p[4] =
{
invcamprojmatrix.perspectivetransform(vec(-1, -1, -1)),
invcamprojmatrix.perspectivetransform(vec(-1, 1, -1)),
invcamprojmatrix.perspectivetransform(vec(1, -1, -1)),
invcamprojmatrix.perspectivetransform(vec(1, 1, -1))
};
float bz = surface + camera1->o.z + (vertwater ? WATER_AMPLITUDE : 0),
syl = p[1].z > p[0].z ? 2*(bz - p[0].z)/(p[1].z - p[0].z) - 1 : 1,
syr = p[3].z > p[2].z ? 2*(bz - p[2].z)/(p[3].z - p[2].z) - 1 : 1;
if((mat&MATF_VOLUME) == MAT_WATER)
{
const bvec &deepcolor = getwaterdeepcolour(mat);
int deep = getwaterdeep(mat);
GLOBALPARAMF(waterdeepcolor, deepcolor.x*ldrscaleb, deepcolor.y*ldrscaleb, deepcolor.z*ldrscaleb);
vec deepfade = getwaterdeepfade(mat).tocolor().mul(deep);
GLOBALPARAMF(waterdeepfade,
deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
deep ? calcfogdensity(deep) : -1e4f);
rendercaustics(surface, syl, syr);
}
else
{
GLOBALPARAMF(waterdeepcolor, 0, 0, 0);
GLOBALPARAMF(waterdeepfade, -1e4f, -1e4f, -1e4f, -1e4f);
}
GLOBALPARAMF(waterheight, bz);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
SETSHADER(waterfog);
gle::defvertex(3);
gle::begin(GL_TRIANGLE_STRIP);
gle::attribf(1, -1, 1);
gle::attribf(-1, -1, 1);
gle::attribf(1, syr, 1);
gle::attribf(-1, syl, 1);
gle::end();
glDisable(GL_BLEND);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glDepthRange(0, 1);
}
/* vertex water */
VARP(watersubdiv, 0, 2, 3);
VARP(waterlod, 0, 1, 3);
static int wx1, wy1, wx2, wy2, wsize;
static float whscale, whoffset;
#define VERTW(vertw, defbody, body) \
static inline void def##vertw() \
{ \
gle::defvertex(); \
defbody; \
} \
static inline void vertw(float v1, float v2, float v3) \
{ \
float angle = (v1-wx1)*(v2-wy1)*(v1-wx2)*(v2-wy2)*whscale+whoffset; \
float s = angle - int(angle) - 0.5f; \
s *= 8 - fabs(s)*16; \
float h = WATER_AMPLITUDE*s-WATER_OFFSET; \
gle::attribf(v1, v2, v3+h); \
body; \
}
#define VERTWN(vertw, defbody, body) \
static inline void def##vertw() \
{ \
gle::defvertex(); \
defbody; \
} \
static inline void vertw(float v1, float v2, float v3) \
{ \
float h = -WATER_OFFSET; \
gle::attribf(v1, v2, v3+h); \
body; \
}
#define VERTWT(vertwt, defbody, body) \
VERTW(vertwt, defbody, { \
float v = angle - int(angle+0.25f) - 0.25f; \
v *= 8 - fabs(v)*16; \
float duv = 0.5f*v; \
body; \
})
static float wxscale = 1.0f, wyscale = 1.0f, wscroll = 0.0f;
VERTW(vertwt, {
gle::deftexcoord0();
}, {
gle::attribf(wxscale*v1, wyscale*v2);
})
VERTWN(vertwtn, {
gle::deftexcoord0();
}, {
gle::attribf(wxscale*v1, wyscale*v2);
})
VERTW(vertl, {
gle::deftexcoord0();
}, {
gle::attribf(wxscale*(v1+wscroll), wyscale*(v2+wscroll));
})
VERTWN(vertln, {
gle::deftexcoord0();
}, {
gle::attribf(wxscale*(v1+wscroll), wyscale*(v2+wscroll));
})
#define renderwaterstrips(vertw, z) { \
def##vertw(); \
gle::begin(GL_TRIANGLE_STRIP, 2*(wy2-wy1 + 1)*(wx2-wx1)/subdiv); \
for(int x = wx1; x<wx2; x += subdiv) \
{ \
vertw(x, wy1, z); \
vertw(x+subdiv, wy1, z); \
for(int y = wy1; y<wy2; y += subdiv) \
{ \
vertw(x, y+subdiv, z); \
vertw(x+subdiv, y+subdiv, z); \
} \
gle::multidraw(); \
} \
xtraverts += gle::end(); \
}
static void rendervertwater(int subdiv, int xo, int yo, int z, int size, int mat)
{
wx1 = xo;
wy1 = yo;
wx2 = wx1 + size,
wy2 = wy1 + size;
wsize = size;
whscale = 59.0f/(23.0f*wsize*wsize)/(2*M_PI);
ASSERT((wx1 & (subdiv - 1)) == 0);
ASSERT((wy1 & (subdiv - 1)) == 0);
switch(mat)
{
case MAT_WATER:
{
whoffset = fmod(float(lastmillis/600.0f/(2*M_PI)), 1.0f);
renderwaterstrips(vertwt, z);
break;
}
case MAT_LAVA:
{
whoffset = fmod(float(lastmillis/2000.0f/(2*M_PI)), 1.0f);
renderwaterstrips(vertl, z);
break;
}
}
}
static int calcwatersubdiv(int x, int y, int z, int size)
{
float dist;
if(camera1->o.x >= x && camera1->o.x < x + size &&
camera1->o.y >= y && camera1->o.y < y + size)
dist = fabs(camera1->o.z - float(z));
else
dist = vec(x + size/2, y + size/2, z + size/2).dist(camera1->o) - size*1.42f/2;
int subdiv = watersubdiv + int(dist) / (32 << waterlod);
return subdiv >= 31 ? INT_MAX : 1<<subdiv;
}
static int renderwaterlod(int x, int y, int z, int size, int mat)
{
if(size <= (32 << waterlod))
{
int subdiv = calcwatersubdiv(x, y, z, size);
if(subdiv < size * 2) rendervertwater(min(subdiv, size), x, y, z, size, mat);
return subdiv;
}
else
{
int subdiv = calcwatersubdiv(x, y, z, size);
if(subdiv >= size)
{
if(subdiv < size * 2) rendervertwater(size, x, y, z, size, mat);
return subdiv;
}
int childsize = size / 2,
subdiv1 = renderwaterlod(x, y, z, childsize, mat),
subdiv2 = renderwaterlod(x + childsize, y, z, childsize, mat),
subdiv3 = renderwaterlod(x + childsize, y + childsize, z, childsize, mat),
subdiv4 = renderwaterlod(x, y + childsize, z, childsize, mat),
minsubdiv = subdiv1;
minsubdiv = min(minsubdiv, subdiv2);
minsubdiv = min(minsubdiv, subdiv3);
minsubdiv = min(minsubdiv, subdiv4);
if(minsubdiv < size * 2)
{
if(minsubdiv >= size) rendervertwater(size, x, y, z, size, mat);
else
{
if(subdiv1 >= size) rendervertwater(childsize, x, y, z, childsize, mat);
if(subdiv2 >= size) rendervertwater(childsize, x + childsize, y, z, childsize, mat);
if(subdiv3 >= size) rendervertwater(childsize, x + childsize, y + childsize, z, childsize, mat);
if(subdiv4 >= size) rendervertwater(childsize, x, y + childsize, z, childsize, mat);
}
}
return minsubdiv;
}
}
#define renderwaterquad(vertwn, z) \
{ \
if(gle::attribbuf.empty()) { def##vertwn(); gle::begin(GL_QUADS); } \
vertwn(x, y, z); \
vertwn(x+rsize, y, z); \
vertwn(x+rsize, y+csize, z); \
vertwn(x, y+csize, z); \
xtraverts += 4; \
}
static void renderflatwater(int x, int y, int z, int rsize, int csize, int mat)
{
switch(mat)
{
case MAT_WATER:
renderwaterquad(vertwtn, z);
break;
case MAT_LAVA:
renderwaterquad(vertln, z);
break;
}
}
static inline void renderwater(const materialsurface &m, int mat = MAT_WATER)
{
if(!vertwater || drawtex == DRAWTEX_MINIMAP) renderflatwater(m.o.x, m.o.y, m.o.z, m.rsize, m.csize, mat);
else if(renderwaterlod(m.o.x, m.o.y, m.o.z, m.csize, mat) >= int(m.csize) * 2)
rendervertwater(m.csize, m.o.x, m.o.y, m.o.z, m.csize, mat);
}
void preloadwatershaders(bool force)
{
static bool needwater = false;
if(force) needwater = true;
if(!needwater) return;
if(caustics && causticscale && causticmillis)
{
if(waterreflect) useshaderbyname("waterreflectcaustics");
else if(waterenvmap) useshaderbyname("waterenvcaustics");
else useshaderbyname("watercaustics");
}
else
{
if(waterreflect) useshaderbyname("waterreflect");
else if(waterenvmap) useshaderbyname("waterenv");
else useshaderbyname("water");
}
useshaderbyname("underwater");
if(waterfallenv) useshaderbyname("waterfallenv");
useshaderbyname("waterfall");
useshaderbyname("waterfog");
useshaderbyname("waterminimap");
}
static float wfwave = 0.0f, wfscroll = 0.0f, wfxscale = 1.0f, wfyscale = 1.0f;
static void renderwaterfall(const materialsurface &m, float offset, const vec *normal = NULL)
{
if(gle::attribbuf.empty())
{
gle::defvertex();
if(normal) gle::defnormal();
gle::deftexcoord0();
gle::begin(GL_QUADS);
}
float x = m.o.x, y = m.o.y, zmin = m.o.z, zmax = zmin;
if(m.ends&1) zmin += -WATER_OFFSET-WATER_AMPLITUDE;
if(m.ends&2) zmax += wfwave;
int csize = m.csize, rsize = m.rsize;
#define GENFACEORIENT(orient, v0, v1, v2, v3) \
case orient: v0 v1 v2 v3 break;
#undef GENFACEVERTX
#define GENFACEVERTX(orient, vert, mx,my,mz, sx,sy,sz) \
{ \
vec v(mx sx, my sy, mz sz); \
gle::attribf(v.x, v.y, v.z); \
GENFACENORMAL \
gle::attribf(wfxscale*v.y, -wfyscale*(v.z+wfscroll)); \
}
#undef GENFACEVERTY
#define GENFACEVERTY(orient, vert, mx,my,mz, sx,sy,sz) \
{ \
vec v(mx sx, my sy, mz sz); \
gle::attribf(v.x, v.y, v.z); \
GENFACENORMAL \
gle::attribf(wfxscale*v.x, -wfyscale*(v.z+wfscroll)); \
}
#define GENFACENORMAL gle::attribf(n.x, n.y, n.z);
if(normal)
{
vec n = *normal;
switch(m.orient) { GENFACEVERTSXY(x, x, y, y, zmin, zmax, /**/, + csize, /**/, + rsize, + offset, - offset) }
}
#undef GENFACENORMAL
#define GENFACENORMAL
else switch(m.orient) { GENFACEVERTSXY(x, x, y, y, zmin, zmax, /**/, + csize, /**/, + rsize, + offset, - offset) }
#undef GENFACENORMAL
#undef GENFACEORIENT
#undef GENFACEVERTX
#define GENFACEVERTX(o,n, x,y,z, xv,yv,zv) GENFACEVERT(o,n, x,y,z, xv,yv,zv)
#undef GENFACEVERTY
#define GENFACEVERTY(o,n, x,y,z, xv,yv,zv) GENFACEVERT(o,n, x,y,z, xv,yv,zv)
}
void renderlava()
{
loopk(4)
{
if(lavasurfs[k].empty() && (drawtex == DRAWTEX_MINIMAP || lavafallsurfs[k].empty())) continue;
MatSlot &lslot = lookupmaterialslot(MAT_LAVA+k);
SETSHADER(lava);
float t = lastmillis/2000.0f;
t -= floor(t);
t = 1.0f - 2*fabs(t-0.5f);
t = 0.5f + 0.5f*t;
float glowmin = getlavaglowmin(k), glowmax = getlavaglowmax(k);
int spec = getlavaspec(k);
LOCALPARAMF(lavaglow, 0.5f*(glowmin + (glowmax-glowmin)*t));
LOCALPARAMF(lavaspec, spec/100.0f);
if(lavasurfs[k].length())
{
Texture *tex = lslot.sts.inrange(0) ? lslot.sts[0].t: notexture;
wxscale = TEX_SCALE/(tex->xs*lslot.scale);
wyscale = TEX_SCALE/(tex->ys*lslot.scale);
wscroll = lastmillis/1000.0f;
glBindTexture(GL_TEXTURE_2D, tex->id);
glActiveTexture_(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, lslot.sts.inrange(1) ? lslot.sts[1].t->id : notexture->id);
glActiveTexture_(GL_TEXTURE0);
gle::normal(vec(0, 0, 1));
vector<materialsurface> &surfs = lavasurfs[k];
loopv(surfs) renderwater(surfs[i], MAT_LAVA);
xtraverts += gle::end();
}
if(drawtex != DRAWTEX_MINIMAP && lavafallsurfs[k].length())
{
Texture *tex = lslot.sts.inrange(2) ? lslot.sts[2].t : (lslot.sts.inrange(0) ? lslot.sts[0].t : notexture);
float angle = fmod(float(lastmillis/2000.0f/(2*M_PI)), 1.0f),
s = angle - int(angle) - 0.5f;
s *= 8 - fabs(s)*16;
wfwave = vertwater ? WATER_AMPLITUDE*s-WATER_OFFSET : -WATER_OFFSET;
wfscroll = 16.0f*lastmillis/3000.0f;
wfxscale = TEX_SCALE/(tex->xs*lslot.scale);
wfyscale = TEX_SCALE/(tex->ys*lslot.scale);
glBindTexture(GL_TEXTURE_2D, tex->id);
glActiveTexture_(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, lslot.sts.inrange(2) ? (lslot.sts.inrange(3) ? lslot.sts[3].t->id : notexture->id) : (lslot.sts.inrange(1) ? lslot.sts[1].t->id : notexture->id));
glActiveTexture_(GL_TEXTURE0);
vector<materialsurface> &surfs = lavafallsurfs[k];
loopv(surfs)
{
materialsurface &m = surfs[i];
renderwaterfall(m, 0.1f, &matnormals[m.orient]);
}
xtraverts += gle::end();
}
}
}
void renderwaterfalls()
{
loopk(4)
{
vector<materialsurface> &surfs = waterfallsurfs[k];
if(surfs.empty()) continue;
MatSlot &wslot = lookupmaterialslot(MAT_WATER+k);
Texture *tex = wslot.sts.inrange(2) ? wslot.sts[2].t : (wslot.sts.inrange(0) ? wslot.sts[0].t : notexture);
float angle = fmod(float(lastmillis/600.0f/(2*M_PI)), 1.0f),
s = angle - int(angle) - 0.5f;
s *= 8 - fabs(s)*16;
wfwave = vertwater ? WATER_AMPLITUDE*s-WATER_OFFSET : -WATER_OFFSET;
wfscroll = 16.0f*lastmillis/1000.0f;
wfxscale = TEX_SCALE/(tex->xs*wslot.scale);
wfyscale = TEX_SCALE/(tex->ys*wslot.scale);
bvec color = getwaterfallcolour(k), refractcolor = getwaterfallrefractcolour(k);
if(color.iszero()) color = getwatercolour(k);
if(refractcolor.iszero()) refractcolor = getwaterrefractcolour(k);
float colorscale = (0.5f/255), refractscale = colorscale/ldrscale;
float refract = getwaterfallrefract(k);
int spec = getwaterfallspec(k);
GLOBALPARAMF(waterfallcolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
GLOBALPARAMF(waterfallrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
GLOBALPARAMF(waterfallspec, spec/100.0f);
if(waterfallenv) SETSHADER(waterfallenv);
else SETSHADER(waterfall);
glBindTexture(GL_TEXTURE_2D, tex->id);
glActiveTexture_(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, wslot.sts.inrange(2) ? (wslot.sts.inrange(3) ? wslot.sts[3].t->id : notexture->id) : (wslot.sts.inrange(1) ? wslot.sts[1].t->id : notexture->id));
if(waterfallenv)
{
glActiveTexture_(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(wslot));
}
glActiveTexture_(GL_TEXTURE0);
loopv(surfs)
{
materialsurface &m = surfs[i];
renderwaterfall(m, 0.1f, &matnormals[m.orient]);
}
xtraverts += gle::end();
}
}
void renderwater()
{
loopk(4)
{
vector<materialsurface> &surfs = watersurfs[k];
if(surfs.empty()) continue;
MatSlot &wslot = lookupmaterialslot(MAT_WATER+k);
Texture *tex = wslot.sts.inrange(0) ? wslot.sts[0].t: notexture;
wxscale = TEX_SCALE/(tex->xs*wslot.scale);
wyscale = TEX_SCALE/(tex->ys*wslot.scale);
wscroll = 0.0f;
glBindTexture(GL_TEXTURE_2D, tex->id);
glActiveTexture_(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, wslot.sts.inrange(1) ? wslot.sts[1].t->id : notexture->id);
if(caustics && causticscale && causticmillis) setupcaustics(2);
if(waterenvmap && !waterreflect && drawtex != DRAWTEX_MINIMAP)
{
glActiveTexture_(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_CUBE_MAP, lookupenvmap(wslot));
}
glActiveTexture_(GL_TEXTURE0);
float colorscale = 0.5f/255, refractscale = colorscale/ldrscale, reflectscale = 0.5f/ldrscale;
const bvec &color = getwatercolour(k);
const bvec &deepcolor = getwaterdeepcolour(k);
const bvec &refractcolor = getwaterrefractcolour(k);
int fog = getwaterfog(k), deep = getwaterdeep(k), spec = getwaterspec(k);
float refract = getwaterrefract(k);
GLOBALPARAMF(watercolor, color.x*colorscale, color.y*colorscale, color.z*colorscale);
GLOBALPARAMF(waterdeepcolor, deepcolor.x*colorscale, deepcolor.y*colorscale, deepcolor.z*colorscale);
float fogdensity = fog ? calcfogdensity(fog) : -1e4f;
GLOBALPARAMF(waterfog, fogdensity);
vec deepfade = getwaterdeepfade(k).tocolor().mul(deep);
GLOBALPARAMF(waterdeepfade,
deepfade.x ? calcfogdensity(deepfade.x) : -1e4f,
deepfade.y ? calcfogdensity(deepfade.y) : -1e4f,
deepfade.z ? calcfogdensity(deepfade.z) : -1e4f,
deep ? calcfogdensity(deep) : -1e4f);
GLOBALPARAMF(waterspec, spec/100.0f);
GLOBALPARAMF(waterreflect, reflectscale, reflectscale, reflectscale, waterreflectstep);
GLOBALPARAMF(waterrefract, refractcolor.x*refractscale, refractcolor.y*refractscale, refractcolor.z*refractscale, refract*viewh);
#define SETWATERSHADER(which, name) \
do { \
static Shader *name##shader = NULL; \
if(!name##shader) name##shader = lookupshaderbyname(#name); \
which##shader = name##shader; \
} while(0)
Shader *aboveshader = NULL;
if(drawtex == DRAWTEX_MINIMAP) SETWATERSHADER(above, waterminimap);
else if(caustics && causticscale && causticmillis)
{
if(waterreflect) SETWATERSHADER(above, waterreflectcaustics);
else if(waterenvmap) SETWATERSHADER(above, waterenvcaustics);
else SETWATERSHADER(above, watercaustics);
}
else
{
if(waterreflect) SETWATERSHADER(above, waterreflect);
else if(waterenvmap) SETWATERSHADER(above, waterenv);
else SETWATERSHADER(above, water);
}
Shader *belowshader = NULL;
if(drawtex != DRAWTEX_MINIMAP) SETWATERSHADER(below, underwater);
aboveshader->set();
loopv(surfs)
{
materialsurface &m = surfs[i];
if(camera1->o.z < m.o.z - WATER_OFFSET) continue;
renderwater(m);
}
xtraverts += gle::end();
if(belowshader)
{
belowshader->set();
loopv(surfs)
{
materialsurface &m = surfs[i];
if(camera1->o.z >= m.o.z - WATER_OFFSET) continue;
renderwater(m);
}
xtraverts += gle::end();
}
}
}