Blinking was good visible and annoying in edit mode, for example for alpha=255. Backport from Sauerbraten. Thanks BrutalSystem
355 lines
8.8 KiB
C++
355 lines
8.8 KiB
C++
#include "cube.h"
|
|
|
|
int wx1, wy1, wx2, wy2;
|
|
float wsx1, wsy1, wsx2, wsy2;
|
|
|
|
VARP(watersubdiv, 1, 4, 64);
|
|
FVARF(waterlevel, -10000, -10000, 127,
|
|
{
|
|
if(!noteditmode("waterlevel"))
|
|
{
|
|
hdr.waterlevel = waterlevel * WATERLEVELSCALING;
|
|
unsavededits++;
|
|
}
|
|
waterlevel = float(hdr.waterlevel) / WATERLEVELSCALING; // waterlevel and hdr.waterlevel need to be kept in sync
|
|
});
|
|
|
|
void setwatercolor(const char *r, const char *g, const char *b, const char *a)
|
|
{
|
|
if(r[0])
|
|
{
|
|
hdr.watercolor[0] = ATOI(r);
|
|
hdr.watercolor[1] = ATOI(g);
|
|
hdr.watercolor[2] = ATOI(b);
|
|
hdr.watercolor[3] = a[0] ? ATOI(a) : 178;
|
|
}
|
|
else
|
|
{
|
|
hdr.watercolor[0] = 20;
|
|
hdr.watercolor[1] = 25;
|
|
hdr.watercolor[2] = 20;
|
|
hdr.watercolor[3] = 178;
|
|
}
|
|
if(editmode) unsavededits++;
|
|
}
|
|
|
|
COMMANDF(watercolour, "ssss", (char *r, char *g, char *b, char *a) { if(editmode) setwatercolor(r, g, b, a); });
|
|
|
|
FVAR(waveheight, 0, 0.3f, 1.0f);
|
|
VARP(ignoreoverride_limitwaveheight, 0, 0, 1);
|
|
float effective_waveheight = 0.3f;
|
|
|
|
void getwatercolour()
|
|
{
|
|
defformatstring(res)("%d %d %d %d", hdr.watercolor[0], hdr.watercolor[1], hdr.watercolor[2], hdr.watercolor[3]);
|
|
result(res);
|
|
}
|
|
COMMAND(getwatercolour, "");
|
|
|
|
const char *componentnames[] = { "red", "green", "blue", "alpha", "" };
|
|
|
|
void setwatercolour(char *what, int *v)
|
|
{
|
|
int t = getlistindex(what, componentnames, true, -1);
|
|
if(t >= 0 && t < 4 && editmode)
|
|
{
|
|
hdr.watercolor[t] = *v;
|
|
unsavededits++;
|
|
}
|
|
}
|
|
COMMAND(setwatercolour, "si");
|
|
|
|
// renders water for bounding rect area that contains water... simple but very inefficient
|
|
|
|
#define VERTW(vertw, defbody, body) \
|
|
static inline void def##vertw() \
|
|
{ \
|
|
varray::defattrib(varray::ATTRIB_VERTEX, 3, GL_FLOAT); \
|
|
defbody; \
|
|
} \
|
|
inline void vertw(float v1, float v2, float v3, float t) \
|
|
{ \
|
|
float angle = v1*v2*0.1f/PI2 + t; \
|
|
float s = angle - int(angle) - 0.5f; \
|
|
s *= 8 - fabs(s)*16; \
|
|
float h = effective_waveheight*0.5f*s; \
|
|
varray::attrib<float>(v1, v2, v3+h); \
|
|
body; \
|
|
}
|
|
#define VERTWC(vertwc, defbody, body) \
|
|
VERTW(vertwc, defbody, { \
|
|
float v = angle - int(angle+0.25) - 0.25; \
|
|
v *= 8 - fabs(v)*16; \
|
|
body; \
|
|
})
|
|
#define VERTWT(vertwt, defbody, body) \
|
|
VERTWC(vertwt, defbody, { \
|
|
float duv = effective_waveheight*0.5f*v; \
|
|
body; \
|
|
})
|
|
|
|
VERTW(vertw, {}, {})
|
|
VERTWC(vertwc, {
|
|
varray::defattrib(varray::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE);
|
|
}, {
|
|
varray::attrib<uchar>(hdr.watercolor[0], hdr.watercolor[1], hdr.watercolor[2], clamp(int(hdr.watercolor[3] + fabs(s)*0x18), 0, 255));
|
|
})
|
|
VERTWT(vertwt, {
|
|
varray::defattrib(varray::ATTRIB_TEXCOORD0, 3, GL_FLOAT);
|
|
}, {
|
|
varray::attrib<float>(v1+duv, v2+duv, v3+h);
|
|
})
|
|
VERTWT(vertwtc, {
|
|
varray::defattrib(varray::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE);
|
|
varray::defattrib(varray::ATTRIB_TEXCOORD0, 3, GL_FLOAT);
|
|
}, {
|
|
varray::attrib<uchar>(255, 255, 255, int(0x33 + fabs(s)*0x18));
|
|
varray::attrib<float>(v1+duv, v2+duv, v3+h);
|
|
})
|
|
VERTWT(vertwmtc, {
|
|
varray::defattrib(varray::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE);
|
|
varray::defattrib(varray::ATTRIB_TEXCOORD0, 3, GL_FLOAT);
|
|
varray::defattrib(varray::ATTRIB_TEXCOORD1, 3, GL_FLOAT);
|
|
}, {
|
|
varray::attrib<uchar>(255, 255, 255, int(0x33 + fabs(s)*0x18));
|
|
varray::attrib<float>(v1-duv, v2+duv, v3+h);
|
|
varray::attrib<float>(v1+duv, v2+duv, v3+h);
|
|
})
|
|
|
|
extern int nquads;
|
|
|
|
#define renderwaterstrips(vertw, hf, t) \
|
|
def##vertw(); \
|
|
for(int x = wx1; x<wx2; x += watersubdiv) \
|
|
{ \
|
|
varray::begin(GL_TRIANGLE_STRIP); \
|
|
vertw(x, wy1, hf, t); \
|
|
vertw(x+watersubdiv, wy1, hf, t); \
|
|
for(int y = wy1; y<wy2; y += watersubdiv) \
|
|
{ \
|
|
vertw(x, y+watersubdiv, hf, t); \
|
|
vertw(x+watersubdiv, y+watersubdiv, hf, t); \
|
|
} \
|
|
nquads += varray::end()/4; \
|
|
}
|
|
|
|
void setprojtexmatrix()
|
|
{
|
|
glmatrixf projtex = mvpmatrix;
|
|
projtex.projective();
|
|
|
|
glMatrixMode(GL_TEXTURE);
|
|
glLoadMatrixf(projtex.v);
|
|
}
|
|
|
|
void setupmultitexrefract(GLuint reflecttex, GLuint refracttex)
|
|
{
|
|
setuptmu(0, "K , T @ Ka");
|
|
|
|
colortmu(0, hdr.watercolor[0]/255.0f, hdr.watercolor[1]/255.0f, hdr.watercolor[2]/255.0f, hdr.watercolor[3]/255.0f);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, refracttex);
|
|
setprojtexmatrix();
|
|
|
|
glActiveTexture_(GL_TEXTURE1_ARB);
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
setuptmu(1, "P , T @ C~a");
|
|
|
|
glBindTexture(GL_TEXTURE_2D, reflecttex);
|
|
setprojtexmatrix();
|
|
|
|
glActiveTexture_(GL_TEXTURE0_ARB);
|
|
}
|
|
|
|
void setupmultitexreflect(GLuint reflecttex)
|
|
{
|
|
setuptmu(0, "T , K @ Ca", "Ka * P~a");
|
|
|
|
float a = hdr.watercolor[3]/255.0f;
|
|
colortmu(0, hdr.watercolor[0]/255.0f*a, hdr.watercolor[1]/255.0f*a, hdr.watercolor[2]/255.0f*a, 1.0f-a);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, reflecttex);
|
|
setprojtexmatrix();
|
|
}
|
|
|
|
void cleanupmultitex(GLuint reflecttex, GLuint refracttex)
|
|
{
|
|
resettmu(0);
|
|
glLoadIdentity();
|
|
|
|
if(refracttex)
|
|
{
|
|
glActiveTexture_(GL_TEXTURE1_ARB);
|
|
glDisable(GL_TEXTURE_2D);
|
|
resettmu(1);
|
|
glLoadIdentity();
|
|
glActiveTexture_(GL_TEXTURE0_ARB);
|
|
}
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
|
|
VARP(mtwater, 0, 1, 1);
|
|
|
|
int renderwater(float hf, GLuint reflecttex, GLuint refracttex)
|
|
{
|
|
if(wx1<0) return nquads;
|
|
|
|
extern int mapoverride_limitwaveheight;
|
|
effective_waveheight = mapoverride_limitwaveheight && !ignoreoverride_limitwaveheight ? 0.1f : waveheight;
|
|
|
|
wx1 -= wx1%watersubdiv;
|
|
wy1 -= wy1%watersubdiv;
|
|
|
|
float t = fmod(float(lastmillis/300.0f/PI2), 1.0f);
|
|
|
|
if(mtwater && maxtmus>=2 && reflecttex)
|
|
{
|
|
varray::enable();
|
|
|
|
if(refracttex)
|
|
{
|
|
setupmultitexrefract(reflecttex, refracttex);
|
|
renderwaterstrips(vertwmtc, hf, t);
|
|
}
|
|
else
|
|
{
|
|
setupmultitexreflect(reflecttex);
|
|
glDepthMask(GL_FALSE);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_ONE, GL_SRC_ALPHA);
|
|
renderwaterstrips(vertwtc, hf, t);
|
|
glDisable(GL_BLEND);
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
cleanupmultitex(reflecttex, refracttex);
|
|
|
|
varray::disable();
|
|
|
|
return nquads;
|
|
}
|
|
|
|
if(!refracttex)
|
|
{
|
|
glDisable(GL_TEXTURE_2D);
|
|
glEnable(GL_BLEND);
|
|
}
|
|
glDepthMask(GL_FALSE);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
varray::enable();
|
|
|
|
if(reflecttex)
|
|
{
|
|
if(!refracttex)
|
|
{
|
|
glColor4ubv(hdr.watercolor);
|
|
renderwaterstrips(vertw, hf, t);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
setprojtexmatrix();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, refracttex ? refracttex : reflecttex);
|
|
}
|
|
|
|
if(refracttex)
|
|
{
|
|
glColor3f(1, 1, 1);
|
|
renderwaterstrips(vertwt, hf, t);
|
|
glEnable(GL_BLEND);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, reflecttex);
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
if(reflecttex) { renderwaterstrips(vertwtc, hf, t); }
|
|
else { renderwaterstrips(vertwc, hf, t); }
|
|
|
|
varray::disable();
|
|
|
|
if(reflecttex)
|
|
{
|
|
glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
else glEnable(GL_TEXTURE_2D);
|
|
|
|
glDisable(GL_BLEND);
|
|
if(!refracttex) glDepthMask(GL_TRUE);
|
|
|
|
return nquads;
|
|
}
|
|
|
|
void addwaterquad(int x, int y, int size) // update bounding rect that contains water
|
|
{
|
|
int x2 = x+size;
|
|
int y2 = y+size;
|
|
if(wx1<0)
|
|
{
|
|
wx1 = x;
|
|
wy1 = y;
|
|
wx2 = x2;
|
|
wy2 = y2;
|
|
}
|
|
else
|
|
{
|
|
if(x<wx1) wx1 = x;
|
|
if(y<wy1) wy1 = y;
|
|
if(x2>wx2) wx2 = x2;
|
|
if(y2>wy2) wy2 = y2;
|
|
}
|
|
}
|
|
|
|
void calcwaterscissor()
|
|
{
|
|
vec4 v[4];
|
|
float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1;
|
|
loopi(4)
|
|
{
|
|
vec4 &p = v[i];
|
|
mvpmatrix.transform(vec(i&1 ? wx2 : wx1, i&2 ? wy2 : wy1, waterlevel - 0.3f), p);
|
|
if(p.z >= 0)
|
|
{
|
|
float x = p.x / p.w, y = p.y / p.w;
|
|
sx1 = min(sx1, x);
|
|
sy1 = min(sy1, y);
|
|
sx2 = max(sx2, x);
|
|
sy2 = max(sy2, y);
|
|
}
|
|
}
|
|
if(sx1 >= sx2 || sy1 >= sy2)
|
|
{
|
|
sx1 = sy1 = -1;
|
|
sx2 = sy2 = 1;
|
|
}
|
|
else loopi(4)
|
|
{
|
|
const vec4 &p = v[i];
|
|
if(p.z >= 0) continue;
|
|
loopj(2)
|
|
{
|
|
const vec4 &o = v[i^(1<<j)];
|
|
if(o.z <= 0) continue;
|
|
float t = p.z/(p.z - o.z),
|
|
w = p.w + t*(o.w - p.w),
|
|
x = (p.x + t*(o.x - p.x))/w,
|
|
y = (p.y + t*(o.y - p.y))/w;
|
|
sx1 = min(sx1, x);
|
|
sy1 = min(sy1, y);
|
|
sx2 = max(sx2, x);
|
|
sy2 = max(sy2, y);
|
|
}
|
|
}
|
|
wsx1 = max(sx1, -1.0f);
|
|
wsy1 = max(sy1, -1.0f);
|
|
wsx2 = min(sx2, 1.0f);
|
|
wsy2 = min(sy2, 1.0f);
|
|
}
|
|
|
|
void resetwater()
|
|
{
|
|
if(!reflecting) wx1 = -1;
|
|
}
|
|
|