diff --git a/source/src/cube.h b/source/src/cube.h index f604d882..8a27e751 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -82,7 +82,7 @@ extern int lastmillis; // last time extern int curtime; // current frame time extern int gamemode, nextmode; extern int xtraverts; -extern bool minimap; +extern bool minimap, reflecting; extern bool demoplayback; extern bool intermission; extern bool arenajoin; diff --git a/source/src/main.cpp b/source/src/main.cpp index 41fdaa89..5b452a81 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -45,22 +45,22 @@ void screenshot(char *imagepath) { SDL_Surface *image; SDL_Surface *temp; - int idx; if((image = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0))) { - if((temp = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0))) + if((temp = SDL_CreateRGBSurface(SDL_SWSURFACE, scr_w, scr_h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0))) { glReadPixels(0, 0, scr_w, scr_h, GL_RGB, GL_UNSIGNED_BYTE, image->pixels); - for (idx = 0; idxpixels+temp->pitch*idx; - memcpy(dest, (char *)image->pixels+image->pitch*(scr_h-1-idx), 3*scr_w); + char *dest = (char *)temp->pixels+temp->pitch*i; + memcpy(dest, (char *)image->pixels+image->pitch*(scr_h-1-i), 3*scr_w); endianswap(dest, 3, scr_w); } - if(!imagepath) + if(!imagepath[0]) { - imagepath = new string; - s_sprintf(imagepath)("screenshots/screenshot_%d.bmp", lastmillis); + static string buf; + s_sprintf(buf)("screenshots/screenshot_%d.bmp", lastmillis); + imagepath = buf; } SDL_SaveBMP(temp, path(imagepath)); SDL_FreeSurface(temp); @@ -69,7 +69,7 @@ void screenshot(char *imagepath) } } -COMMAND(screenshot, ARG_NONE); +COMMAND(screenshot, ARG_1STR); COMMAND(quit, ARG_NONE); SDL_Surface *screen = NULL; diff --git a/source/src/protos.h b/source/src/protos.h index 35dcbcc8..e94acd7e 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -75,8 +75,9 @@ extern void render_flat(int tex, int x, int y, int size, int h, sqr *l1, sqr *l2 extern void render_flatdelta(int wtex, int x, int y, int size, float h1, float h2, float h3, float h4, sqr *l1, sqr *l2, sqr *l3, sqr *l4, bool isceil); extern void render_square(int wtex, float floor1, float floor2, float ceil1, float ceil2, int x1, int y1, int x2, int y2, int size, sqr *l1, sqr *l2, bool topleft); extern void render_tris(int x, int y, int size, bool topleft, sqr *h1, sqr *h2, sqr *s, sqr *t, sqr *u, sqr *v); +extern void setwatercolor(char *r = "", char *g = "", char *b = "", char *a = ""); extern void addwaterquad(int x, int y, int size); -extern int renderwater(float hf); +extern int renderwater(float hf, GLuint tex); extern void resetcubes(); extern void setupstrips(); extern void renderstripssky(); diff --git a/source/src/rendercubes.cpp b/source/src/rendercubes.cpp index 92bfbeea..7cb213e6 100644 --- a/source/src/rendercubes.cpp +++ b/source/src/rendercubes.cpp @@ -358,60 +358,108 @@ int wx1, wy1, wx2, wy2; VARP(watersubdiv, 1, 4, 64); VARF(waterlevel, -128, -128, 127, if(!noteditmode()) hdr.waterlevel = waterlevel); -inline void vertw(int v1, float v2, int v3, float t1, float t2, float t) +void setwatercolor(char *r, char *g, char *b, char *a) { - glTexCoord2f(t1, t2); - glVertex3f((float)v1, v2-sinf(v1*v3*0.1+t)*0.2f, (float)v3); + 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] = 25; + hdr.watercolor[1] = 76; + hdr.watercolor[2] = 102; + hdr.watercolor[3] = 178; + } } -inline float dx(float x) { return x+sinf(x*2+lastmillis/1000.0f)*0.04f; } -inline float dy(float x) { return x+sinf(x*2+lastmillis/900.0f+PI/5)*0.05f; } +COMMANDN(watercolour, setwatercolor, ARG_4STR); + +inline void vertw(int v1, float v2, int v3, float t, int tex) +{ + float h = sinf(v1*v3*0.1f+t); + if(tex>0) + { + glColor4f(1, 1, 1, 0.2f - h*0.1f); + float xoff = (v1%2 ? h : -h)*0.2f, yoff = ((v3+1)%2 ? -h : h)*0.2f; + glTexCoord3f(v1+xoff, v2, v3+yoff); + } + else if(tex<0) glColor4ub(hdr.watercolor[0], hdr.watercolor[1], hdr.watercolor[2], (uchar)(hdr.watercolor[3] - h*25.5f)); + + glVertex3f((float)v1, v2 + h*0.2f, (float)v3); +} // renders water for bounding rect area that contains water... simple but very inefficient -int renderwater(float hf) +void renderwaterstrips(float hf, int tex, float t) +{ + for(int x = wx1; xpitch = (float)i; } @@ -231,6 +235,112 @@ void transplayer() glTranslatef(-camera1->o.x, -camera1->o.z, -camera1->o.y); } +void genclipmatrix(float a, float b, float c, float d, GLfloat matrix[16]) +{ + // transform the clip plane into camera space + GLdouble clip[4] = {a, b, c, d}; + glClipPlane(GL_CLIP_PLANE0, clip); + glGetClipPlane(GL_CLIP_PLANE0, clip); + + glGetFloatv(GL_PROJECTION_MATRIX, matrix); + float x = ((clip[0]<0 ? -1 : (clip[0]>0 ? 1 : 0)) + matrix[8]) / matrix[0], + y = ((clip[1]<0 ? -1 : (clip[1]>0 ? 1 : 0)) + matrix[9]) / matrix[5], + w = (1 + matrix[10]) / matrix[14], + scale = 2 / (x*clip[0] + y*clip[1] - clip[2] + w*clip[3]); + matrix[2] = clip[0]*scale; + matrix[6] = clip[1]*scale; + matrix[10] = clip[2]*scale + 1.0f; + matrix[14] = clip[3]*scale; +} + +bool reflecting = false; +GLuint reflecttex = 0; +int reflectlastsize = 0; + +VARP(reflectres, 6, 7, 10); +VARP(waterreflect, 0, 1, 1); + +void drawreflection(float hf, int w, int h, float changelod) +{ + reflecting = true; + + int size = 1< w || size > h) size /= 2; + if(size!=reflectlastsize) + { + glDeleteTextures(1, &reflecttex); + reflecttex = 0; + } + if(!reflecttex) + { + glGenTextures(1, &reflecttex); + createtexture(reflecttex, size, size, NULL, 3, false, GL_RGB); + reflectlastsize = size; + } + + resetcubes(); + + render_world(camera1->o.x, camera1->o.y, hf, changelod, + (int)camera1->yaw, -(int)camera1->pitch, (float)fov, size, size); + + setupstrips(); + + glCullFace(GL_BACK); + glViewport(0, 0, size, size); + glClear(GL_DEPTH_BUFFER_BIT); + + glEnable(GL_TEXTURE_2D); + + transplayer(); + glTranslatef(0, 2*hf, 0); + glScalef(1, -1, 1); + + GLfloat clipmat[16]; + genclipmatrix(0, 1, 0, 0.1f-hf, clipmat); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadMatrixf(clipmat); + glMatrixMode(GL_MODELVIEW); + + renderstripssky(); + + glPushMatrix(); + glLoadIdentity(); + glRotatef(camera1->pitch, -1, 0, 0); + glRotatef(camera1->yaw, 0, 1, 0); + glRotatef(90, 1, 0, 0); + glScalef(1, 1, -1); + glColor3f(1, 1, 1); + glDisable(GL_FOG); + glDepthFunc(GL_GREATER); + draw_envbox(fog*4/3); + glDepthFunc(GL_LESS); + glEnable(GL_FOG); + glPopMatrix(); + + overbright(2); + + renderstrips(); + renderentities(); + renderclients(); + + overbright(1); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + glCullFace(GL_FRONT); + glViewport(0, 0, w, h); + + glBindTexture(GL_TEXTURE_2D, reflecttex); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size, size); + + glDisable(GL_TEXTURE_2D); + + reflecting = false; +} + bool minimap = false, minimapdirty = true; int minimaplastsize = 0; GLuint minimaptex = 0; @@ -244,13 +354,12 @@ COMMAND(clearminimap, ARG_NONE); VARFP(minimapres, 7, 9, 10, clearminimap()); -void drawminimap() +void drawminimap(int w, int h) { if(!minimapdirty) return; - extern int scr_w, scr_h; int size = 1< scr_w || size > scr_h) size /= 2; + while(size > w || size > h) size /= 2; if(size!=minimaplastsize) { glDeleteTextures(1, &minimaptex); @@ -304,7 +413,7 @@ void drawminimap() overbright(1); float hf = hdr.waterlevel-0.3f; - renderwater(hf); + renderwater(hf, 0); minimap = false; @@ -316,17 +425,12 @@ void drawminimap() glEnable(GL_FOG); glDisable(GL_TEXTURE_2D); - glViewport(0, 0, scr_w, scr_h); + glViewport(0, 0, w, h); glClearDepth(1.0); } -VARP(fov, 90, 100, 120); - int xtraverts; -VAR(fog, 64, 180, 1024); -VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); - void drawhudgun(int w, int h, float aspect, int farplane) { if(scoped && player1->gunselect==GUN_SNIPER) return; @@ -391,24 +495,9 @@ void readdepth(int w, int h, vec &pos) pos.z = (float)worldz; } -void invertperspective() -{ - // This only generates a valid inverse matrix for matrices generated by gluPerspective() - GLdouble inv[16]; - memset(inv, 0, sizeof(inv)); - - inv[0*4+0] = 1.0/pm[0*4+0]; - inv[1*4+1] = 1.0/pm[1*4+1]; - inv[2*4+3] = 1.0/pm[3*4+2]; - inv[3*4+2] = -1.0; - inv[3*4+3] = pm[2*4+2]/pm[3*4+2]; - - glLoadMatrixd(inv); -} - void gl_drawframe(int w, int h, float changelod, float curfps) { - drawminimap(); + drawminimap(w, h); recomputecamera(); @@ -423,22 +512,29 @@ void gl_drawframe(int w, int h, float changelod, float curfps) glFogfv(GL_FOG_COLOR, fogc); glClearColor(fogc[0], fogc[1], fogc[2], 1.0f); - if(underwater) - { - fovy += sinf(lastmillis/1000.0f)*2.0f; - aspect += sinf(lastmillis/1000.0f+PI)*0.1f; - glFogi(GL_FOG_START, 0); - glFogi(GL_FOG_END, (fog+96)/8); - } - - glClear((outsidemap(camera1) ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); glLoadIdentity(); int farplane = fog*5/2; gluPerspective(fovy, aspect, 0.15f, farplane); glMatrixMode(GL_MODELVIEW); + if(underwater) + { + fovy += sinf(lastmillis/1000.0f)*2.0f; + aspect += sinf(lastmillis/1000.0f+PI)*0.1f; + float wfogc[4] = { hdr.watercolor[0]/255.0f, hdr.watercolor[1]/255.0f, hdr.watercolor[2]/255.0f, 1.0f }; + glFogfv(GL_FOG_COLOR, wfogc); + glFogi(GL_FOG_START, 0); + glFogi(GL_FOG_END, (fog+96)/8); + } + else if(waterreflect) + { + extern int wx1; + if(wx1>=0) drawreflection(hf, w, h, changelod); + } + + glClear((outsidemap(camera1) ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT); + transplayer(); glEnable(GL_TEXTURE_2D); @@ -495,7 +591,7 @@ void gl_drawframe(int w, int h, float changelod, float curfps) render_particles(curtime); glDisable(GL_CULL_FACE); - int nquads = renderwater(hf); + int nquads = renderwater(hf, !waterreflect || underwater ? 0 : reflecttex); glDisable(GL_FOG); glDisable(GL_TEXTURE_2D); @@ -508,7 +604,6 @@ void gl_drawframe(int w, int h, float changelod, float curfps) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } - invertperspective(); extern vector verts; gl_drawhud(w, h, (int)curfps, nquads, verts.length(), underwater); diff --git a/source/src/renderhud.cpp b/source/src/renderhud.cpp index 912e5ca7..06c4db20 100644 --- a/source/src/renderhud.cpp +++ b/source/src/renderhud.cpp @@ -145,8 +145,6 @@ bool insideradar(const vec ¢erpos, float radius, const vec &o) return o.distxy(centerpos)<=radius; } -VAR(foop, 0, 10, 1000); - void drawradar(int w, int h) { vec center = showmap ? vec(ssize/2, ssize/2, 0) : player1->o; @@ -227,17 +225,28 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat { glDisable(GL_DEPTH_TEST); - glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); glOrtho(0, VIRTW, VIRTH, 0, -1, 1); glEnable(GL_BLEND); if(dblend || underwater) { glDepthMask(GL_FALSE); - glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + if(dblend) + { + glBlendFunc(GL_ZERO, GL_SRC_COLOR); + glColor3f(1.0f, 0.1f, 0.1f); + } + else + { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4ub(hdr.watercolor[0], hdr.watercolor[1], hdr.watercolor[2], 102); + } glBegin(GL_QUADS); - if(dblend) glColor3f(0.0f, 0.9f, 0.9f); - else glColor3f(0.9f, 0.5f, 0.0f); glVertex2i(0, 0); glVertex2i(VIRTW, 0); glVertex2i(VIRTW, VIRTH); @@ -263,16 +272,19 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat drawequipicons(); - if(!hideradar) drawradar(w, h); + if(!hideradar) + { + glMatrixMode(GL_MODELVIEW); + drawradar(w, h); + glMatrixMode(GL_PROJECTION); + } char *infostr = editinfo(); if(getcurcommand()) rendercommand(20, 1570); else if(infostr) draw_text(infostr, 20, 1570); else if(targetplayer) draw_text(targetplayer->name, 20, 1570); - glPopMatrix(); - - glPushMatrix(); + glLoadIdentity(); glOrtho(0, VIRTW*2, VIRTH*2, 0, -1, 1); renderconsole(); @@ -285,11 +297,10 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat draw_textf("wvt %d", left, top+240, curvert); draw_textf("evt %d", left, top+320, xtraverts); } - glPopMatrix(); if(player1->state==CS_ALIVE) { - glPushMatrix(); + glLoadIdentity(); glOrtho(0, VIRTW/2, VIRTH/2, 0, -1, 1); draw_textf("%d", 90, 827, player1->health); if(player1->armour) draw_textf("%d", 390, 827, player1->armour); @@ -300,30 +311,27 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat else sprintf(gunstats,"%i",player1->mag[player1->gunselect]); draw_text(gunstats, 690, 827); } - glPopMatrix(); if(m_teammode && !hideteamhud) { - glPushMatrix(); + glLoadIdentity(); glOrtho(0, VIRTW, VIRTH, 0, -1, 1); glDisable(GL_BLEND); drawctficon(VIRTW-120-10, VIRTH/6+10+10, 120, team_int(player1->team), 1, 1/4.0f); // local players team glEnable(GL_BLEND); draw_textf(player1->team, VIRTW-VIRTH/6-10, VIRTH/6+10+10+120/2); - glPopMatrix(); } if(didteamkill) { - glPushMatrix(); + glLoadIdentity(); glOrtho(0, VIRTW/3, VIRTH/3, 0, -1, 1); draw_text("\f3you killed a teammate", VIRTW/3/40, VIRTH/3/2); - glPopMatrix(); } if(m_ctf && !hidectfhud) { - glPushMatrix(); + glLoadIdentity(); glOrtho(0, VIRTW, VIRTH, 0, -1, 1); glColor4f(1.0f, 1.0f, 1.0f, 0.2f); glBlendFunc(GL_SRC_ALPHA, GL_ONE); @@ -343,13 +351,14 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat drawctficon(VIRTW-225-10, VIRTH*5/8, 225, team_opposite(team_int(player1->team)), 1, 1/2.0f); glDisable(GL_BLEND); } - glPopMatrix(); } } glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); + + glMatrixMode(GL_MODELVIEW); } void loadingscreen(const char *fmt, ...) diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 2822825f..22765a5a 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -259,6 +259,6 @@ void renderclients() { playerent *d; loopv(players) if((d = players[i]) && (!demoplayback || i!=democlientnum)) renderclient(d); - if(player1->state==CS_DEAD) renderclient(player1); + if(player1->state==CS_DEAD || reflecting) renderclient(player1); } diff --git a/source/src/texture.cpp b/source/src/texture.cpp index 7690f8bc..31c4d6d3 100644 --- a/source/src/texture.cpp +++ b/source/src/texture.cpp @@ -120,7 +120,7 @@ int lookuptexture(int tex, int &xs, int &ys) return t->id; } -static Texture *sky[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; +Texture *sky[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; void loadsky(char *basename) { diff --git a/source/src/world.cpp b/source/src/world.cpp index e66185d7..b566cd91 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -311,7 +311,8 @@ void empty_world(int factor, bool force) // main empty world creation routine { s_strncpy(hdr.maptitle, "Untitled Map by Unknown", 128); hdr.waterlevel = -100000; - loopi(15) hdr.reserved[i] = 0; + setwatercolor(); + loopi(sizeof(hdr.reserved)/sizeof(hdr.reserved[0])) hdr.reserved[i] = 0; loopk(3) loopi(256) hdr.texlists[k][i] = i; ents.setsize(0); block b = { 8, 8, ssize-16, ssize-16 }; diff --git a/source/src/world.h b/source/src/world.h index 6db0246e..ff428b13 100644 --- a/source/src/world.h +++ b/source/src/world.h @@ -43,7 +43,8 @@ struct header // map file format header char maptitle[128]; uchar texlists[3][256]; int waterlevel; - int reserved[15]; + uchar watercolor[4]; + int reserved[14]; }; #define SWS(w,x,y,s) (&(w)[(y)*(s)+(x)]) diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index 1e6877fb..06d393fe 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -225,6 +225,7 @@ void load_world(char *mname) // still supports all map formats that have { gzread(f, &hdr.waterlevel, sizeof(int)*16); endianswap(&hdr.waterlevel, sizeof(int), 16); + if(!hdr.watercolor[3]) setwatercolor(); } else { diff --git a/source/src/worldrender.cpp b/source/src/worldrender.cpp index 0112dd6e..a08130d3 100644 --- a/source/src/worldrender.cpp +++ b/source/src/worldrender.cpp @@ -158,12 +158,12 @@ void render_seg_new(float vx, float vy, float vh, int mip, int x, int y, int xs, if((s->type==SPACE || s->type==CHF) && s->floor<=vh && render_floor) { render_flat(s->ftex, xx<floor, s, t, u, v, false); - if(s->floorfloortype==FHF) { render_flatdelta(s->ftex, xx<floor-s->vdelta/4.0ffloor-s->vdelta/4.0f