diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 886c6db2..25e9a4bf 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -2757,7 +2757,6 @@ void CL_LinkPacketEntities (void) ent->externalmodelview = 0; ent->forcedshader = NULL; - ent->visframe = 0; ent->keynum = state->number; diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index edee50dc..3ad4e9db 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -1094,7 +1094,7 @@ fixedorg: cl.pmovetype[pnum] = to->playerstate[cl.playernum[pnum]].pm_type; stepheight = to->playerstate[cl.playernum[pnum]].origin[2] - from->playerstate[cl.playernum[pnum]].origin[2]; - if (cl.nolocalplayer[pnum]) + if (cl.nolocalplayer[pnum] && cl.maxlerpents > cl.playernum[pnum]+1) { //keep the entity tracking the prediction position, so mirrors don't go all weird VectorCopy(to->playerstate[cl.playernum[pnum]].origin, cl.lerpents[cl.playernum[pnum]+1].origin); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index e6c8ed81..4209604e 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1755,7 +1755,11 @@ void SCR_SetUpToDrawConsole (void) scr_conlines = scr_con_current = vid.height * fullscreenpercent; } else if ((key_dest == key_console || key_dest == key_game) && SCR_GetLoadingStage() == LS_NONE && cls.state < ca_active) + { + if (cls.state < ca_demostart) + key_dest = key_console; scr_con_current = scr_conlines = vid.height * fullscreenpercent; + } else if (key_dest == key_console || scr_chatmode) { scr_conlines = vid.height*scr_consize.value; // half screen diff --git a/engine/client/console.c b/engine/client/console.c index f78806c5..f6b36f6b 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -831,7 +831,7 @@ int Con_DrawInput (int left, int right, int y) y -= Font_CharHeight(); - if (key_dest != key_console && con_current->vislines != vid.height) + if (key_dest != key_console)// && con_current->vislines != vid.height) return y; // don't draw anything (always draw if not active) if (!con_current->linebuffered) diff --git a/engine/client/image.c b/engine/client/image.c index 1d26c251..ce5ddcf6 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -2377,13 +2377,13 @@ texid_t R_LoadHiResTexture(char *name, char *subpath, unsigned int flags) snprintf(fname, sizeof(fname)-1, "%s/%s", subpath, name); /*should be safe if its null*/ if (subpath && *subpath && !(flags & IF_REPLACE)) { - tex = R_FindTexture(fname); + tex = R_FindTexture(fname, flags); if (TEXVALID(tex)) //don't bother if it already exists. return tex; } if (!(flags & IF_SUBDIRONLY) && !(flags & IF_REPLACE)) { - tex = R_FindTexture(name); + tex = R_FindTexture(name, flags); if (TEXVALID(tex)) //don't bother if it already exists. return tex; } @@ -2614,7 +2614,7 @@ texid_t R_LoadBumpmapTexture(char *name, char *subpath) COM_StripExtension(name, nicename, sizeof(nicename)); - tex = R_FindTexture(name); + tex = R_FindTexture(name, 0); if (TEXVALID(tex)) //don't bother if it already exists. return tex; diff --git a/engine/client/merged.h b/engine/client/merged.h index a69400eb..9f718ee1 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -236,7 +236,7 @@ typedef struct rendererinfo_s { texid_tf (*IMG_LoadTexture8Pal24) (char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags); texid_tf (*IMG_LoadTexture8Pal32) (char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags); texid_tf (*IMG_LoadCompressed) (char *name); - texid_tf (*IMG_FindTexture) (char *identifier); + texid_tf (*IMG_FindTexture) (char *identifier, unsigned int flags); texid_tf (*IMG_AllocNewTexture) (char *identifier, int w, int h); void (*IMG_Upload) (texid_t tex, char *name, uploadfmt_t fmt, void *data, void *palette, int width, int height, unsigned int flags); void (*IMG_DestroyTexture) (texid_t tex); diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 418c718e..5c46f415 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -4768,6 +4768,7 @@ void CSQC_Event_Touch(world_t *w, wedict_t *s, wedict_t *o) *csqcg.self = EDICT_TO_PROG(w->progs, (edict_t*)s); *csqcg.other = EDICT_TO_PROG(w->progs, (edict_t*)o); + *csqcg.svtime = w->physicstime; PR_ExecuteProgram (w->progs, s->v->touch); @@ -4779,6 +4780,7 @@ void CSQC_Event_Think(world_t *w, wedict_t *s) { *csqcg.self = EDICT_TO_PROG(w->progs, (edict_t*)s); *csqcg.other = EDICT_TO_PROG(w->progs, (edict_t*)w->edicts); + *csqcg.svtime = w->physicstime; PR_ExecuteProgram (w->progs, s->v->think); } @@ -4806,7 +4808,7 @@ qboolean CSQC_Event_ContentsTransition(world_t *w, wedict_t *ent, int oldwaterty { void *pr_globals = PR_globals(w->progs, PR_CURRENT); *csqcg.self = EDICT_TO_PROG(w->progs, ent); - *csqcg.cltime = w->physicstime; + *csqcg.svtime = w->physicstime; G_FLOAT(OFS_PARM0) = oldwatertype; G_FLOAT(OFS_PARM1) = newwatertype; PR_ExecuteProgram (w->progs, ent->xv->contentstransition); diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 6c29a1cd..502cc744 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2018,6 +2018,13 @@ void Surf_SetupFrame(void) } } +#ifdef TERRAIN + if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL) && cl.worldmodel && cl.worldmodel->terrain) + { + r_viewcontents |= Heightmap_PointContents(cl.worldmodel, NULL, r_origin); + } +#endif + /*pick up any extra water entities*/ { extern vec3_t player_maxs, player_mins; diff --git a/engine/client/render.h b/engine/client/render.h index 4201ad77..a3246ed9 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -100,17 +100,17 @@ typedef struct entity_s struct player_info_s *scoreboard; // identify player - struct efrag_s *efrag; // linked list of efrags (FIXME) - int visframe; // last frame this entity was +// struct efrag_s *efrag; // linked list of efrags (FIXME) +// int visframe; // last frame this entity was // found in an active leaf // only used for static objects - int dlightframe; // dynamic lighting - int dlightbits; +// int dlightframe; // dynamic lighting +// int dlightbits; // FIXME: could turn these into a union - int trivial_accept; - struct mnode_s *topnode; // for bmodels, first world node +// int trivial_accept; +// struct mnode_s *topnode; // for bmodels, first world node // that splits bmodel, or NULL if // not split @@ -301,7 +301,7 @@ texid_t D3D9_LoadTexture (char *identifier, int width, int height, enum uploadfm texid_t D3D9_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *data, qbyte *palette24, unsigned int flags); texid_t D3D9_LoadTexture8Pal32 (char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags); texid_t D3D9_LoadCompressed (char *name); -texid_t D3D9_FindTexture (char *identifier); +texid_t D3D9_FindTexture (char *identifier, unsigned int flags); texid_t D3D9_AllocNewTexture(char *ident, int width, int height); void D3D9_Upload (texid_t tex, char *name, enum uploadfmt fmt, void *data, void *palette, int width, int height, unsigned int flags); void D3D9_DestroyTexture (texid_t tex); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 8fdfceec..863253f8 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -163,8 +163,13 @@ cvar_t scr_viewsize = CVARFC("viewsize", "100", CVAR_ARCHIVE, SCR_Viewsize_Callback); +#ifdef ANDROID +cvar_t vid_conautoscale = CVARF ("vid_conautoscale", "2", + CVAR_ARCHIVE | CVAR_RENDERERCALLBACK); +#else cvar_t vid_conautoscale = CVARF ("vid_conautoscale", "0", CVAR_ARCHIVE | CVAR_RENDERERCALLBACK); +#endif cvar_t vid_conheight = CVARF ("vid_conheight", "0", CVAR_ARCHIVE); cvar_t vid_conwidth = CVARF ("vid_conwidth", "0", @@ -2064,14 +2069,14 @@ qboolean R_CullEntityBox(entity_t *e, vec3_t modmins, vec3_t modmaxs) #if 1 float mrad = 0, v; - if (e->axis[0][0]==1 && e->axis[0][1]==0 && e->axis[0][1]==0 && - e->axis[1][0]==0 && e->axis[1][1]==1 && e->axis[1][1]==0 && - e->axis[2][0]==0 && e->axis[2][1]==0 && e->axis[2][1]==1) + if (e->axis[0][0]==1 && e->axis[0][1]==0 && e->axis[0][2]==0 && + e->axis[1][0]==0 && e->axis[1][1]==1 && e->axis[1][2]==0 && + e->axis[2][0]==0 && e->axis[2][1]==0 && e->axis[2][2]==1) { for (i = 0; i < 3; i++) { - wmin[i] = e->origin[i]+modmins[i]; - wmax[i] = e->origin[i]+modmaxs[i]; + wmin[i] = e->origin[i]+modmins[i]*e->scale; + wmax[i] = e->origin[i]+modmaxs[i]*e->scale; } } else @@ -2085,6 +2090,7 @@ qboolean R_CullEntityBox(entity_t *e, vec3_t modmins, vec3_t modmaxs) if (mrad < v) mrad = v; } + mrad *= e->scale; for (i = 0; i < 3; i++) { wmin[i] = e->origin[i]-mrad; diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 888fa389..e59103b0 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -3543,19 +3543,19 @@ void CMQ3_CalcPHS (void) int rowbytes, rowwords; int i, j, k, l, index; int bitbyte; - unsigned *dest, *src; + unsigned int *dest, *src; qbyte *scan; int count, vcount; int numclusters; Con_DPrintf ("Building PHS...\n"); - map_q3phs = Hunk_Alloc(sizeof(*map_q3phs) + (map_q3pvs->numclusters+7)/8 * map_q3pvs->numclusters); + map_q3phs = Hunk_Alloc(sizeof(*map_q3phs) + (map_q3pvs->numclusters+sizeof(int)*8-1)/8 * map_q3pvs->numclusters); - rowwords = map_q3pvs->rowsize / sizeof(long); + rowwords = map_q3pvs->rowsize / sizeof(int); rowbytes = map_q3pvs->rowsize; - memset ( map_q3phs, 0, sizeof(*map_q3phs) + (map_q3pvs->numclusters+7)/8 * map_q3pvs->numclusters ); + memset ( map_q3phs, 0, sizeof(*map_q3phs) + (map_q3pvs->numclusters+sizeof(int)*8-1)/8 * map_q3pvs->numclusters ); map_q3phs->rowsize = map_q3pvs->rowsize; map_q3phs->numclusters = numclusters = map_q3pvs->numclusters; @@ -3577,11 +3577,12 @@ void CMQ3_CalcPHS (void) count = 0; scan = (qbyte *)map_q3pvs->data; - dest = (unsigned *)((qbyte *)map_q3phs + 8); + dest = (unsigned int *)(map_q3phs->data); for (i=0 ; i= numclusters) // Host_Error ("CM_CalcPHS: Bad bit in PVS"); // pad bits should be 0 - src = (unsigned *)((qbyte*)map_q3pvs->data) + index*rowwords; + src = (unsigned int *)(map_q3pvs->data) + index*rowwords; for (l=0 ; lfromgame = fg_quake3; for (i=0 ; i com_filesize) + { + Con_Printf (CON_ERROR "WARNING: q3bsp %s truncated (lump %i, %i+%i > %i)\n", name, i, header.lumps[i].fileofs, header.lumps[i].filelen, com_filesize); + header.lumps[i].filelen = com_filesize - header.lumps[i].fileofs; + if (header.lumps[i].filelen < 0) + header.lumps[i].filelen = 0; + } + } } /* #ifndef SERVERONLY @@ -3852,24 +3870,33 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c #endif case QR_NONE: //dedicated only mapisq3 = true; +Hunk_Check(); noerrors = noerrors && CModQ3_LoadShaders (&header.lumps[Q3LUMP_SHADERS]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadPlanes (&header.lumps[Q3LUMP_PLANES]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadLeafBrushes (&header.lumps[Q3LUMP_LEAFBRUSHES]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadBrushes (&header.lumps[Q3LUMP_BRUSHES]); +Hunk_Check(); if (header.version == 1) { noerrors = noerrors && CModRBSP_LoadBrushSides (&header.lumps[Q3LUMP_BRUSHSIDES]); +Hunk_Check(); noerrors = noerrors && CModRBSP_LoadVertexes (&header.lumps[Q3LUMP_DRAWVERTS]); } else { noerrors = noerrors && CModQ3_LoadBrushSides (&header.lumps[Q3LUMP_BRUSHSIDES]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadVertexes (&header.lumps[Q3LUMP_DRAWVERTS]); } +Hunk_Check(); if (header.version == 1) noerrors = noerrors && CModRBSP_LoadFaces (&header.lumps[Q3LUMP_SURFACES]); else noerrors = noerrors && CModQ3_LoadFaces (&header.lumps[Q3LUMP_SURFACES]); +Hunk_Check(); #if defined(GLQUAKE) || defined(D3DQUAKE) if (qrenderer != QR_NONE) { @@ -3907,13 +3934,20 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c } } #endif +Hunk_Check(); noerrors = noerrors && CModQ3_LoadLeafFaces (&header.lumps[Q3LUMP_LEAFSURFACES]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadLeafs (&header.lumps[Q3LUMP_LEAFS]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadNodes (&header.lumps[Q3LUMP_NODES]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadSubmodels (&header.lumps[Q3LUMP_MODELS]); +Hunk_Check(); noerrors = noerrors && CModQ3_LoadVisibility (&header.lumps[Q3LUMP_VISIBILITY]); +Hunk_Check(); if (noerrors) CMod_LoadEntityString (&header.lumps[Q3LUMP_ENTITIES]); +Hunk_Check(); if (!noerrors) { @@ -3974,15 +4008,15 @@ cmodel_t *CM_LoadMap (char *name, char *filein, qboolean clientload, unsigned *c Hunk_FreeToLowMark(start); return NULL; } - +Hunk_Check(); #ifndef CLIENTONLY CMQ3_CalcPHS(); #endif - +Hunk_Check(); // BZ_Free(map_verts); BZ_Free(map_faces); BZ_Free(map_leaffaces); - +Hunk_Check(); break; default: #ifdef SERVERONLY diff --git a/engine/d3d/d3d_image.c b/engine/d3d/d3d_image.c index d74ccd5f..594b4d62 100644 --- a/engine/d3d/d3d_image.c +++ b/engine/d3d/d3d_image.c @@ -426,7 +426,7 @@ texid_t D3D9_LoadCompressed (char *name) return r_nulltex; } -texid_t D3D9_FindTexture (char *identifier) +texid_t D3D9_FindTexture (char *identifier, unsigned int flags) { d3dtexture_t *tex = d3d_lookup_texture(identifier); if (tex->tex.ptr) diff --git a/engine/droid/src/com/fteqw/FTEDroidActivity.java b/engine/droid/src/com/fteqw/FTEDroidActivity.java index 6fa22fff..586d41f4 100644 --- a/engine/droid/src/com/fteqw/FTEDroidActivity.java +++ b/engine/droid/src/com/fteqw/FTEDroidActivity.java @@ -95,7 +95,7 @@ public class FTEDroidActivity extends Activity if ((fl & 1) != 0) { // getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - im.showSoftInput(theview, InputMethodManager.SHOW_FORCED); + im.showSoftInput(theview, 0);//InputMethodManager.SHOW_FORCED); } else { diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index c39d880a..888d0dcd 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -1949,7 +1949,7 @@ void BE_GenModelBatches(batch_t **batches) if (ent->model->needload) continue; - if (cl.lerpents && (cls.allow_anyparticles || ent->visframe)) //allowed or static + if (cl.lerpents && (cls.allow_anyparticles)) //allowed or static { if (gl_part_flame.value) { diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index 0ead0521..9a9e19a5 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -598,13 +598,19 @@ void GL_Set2D (qboolean flipped) GL_FindTexture ================ */ -texid_t GL_FindTexture (char *identifier) +texid_t GL_FindTexture (char *identifier, unsigned int flags) { gltexture_t *glt; glt = Hash_Get(&gltexturetable, identifier); - if (glt) + while(glt) { + if ((glt->flags ^ flags) & IF_CLAMP) + { + glt = Hash_GetNext(&gltexturetable, identifier, glt); + continue; + } + image_width = glt->width; image_height = glt->height; return glt->texnum; @@ -613,14 +619,14 @@ texid_t GL_FindTexture (char *identifier) return r_nulltex; } -gltexture_t *GL_MatchTexture (char *identifier, int bits, int width, int height) +gltexture_t *GL_MatchTexture (char *identifier, unsigned int flags, int bits, int width, int height) { gltexture_t *glt; glt = Hash_Get(&gltexturetable, identifier); while(glt) { - if (glt->bpp == bits && width == glt->width && height == glt->height) + if (glt->bpp == bits && width == glt->width && height == glt->height && !((glt->flags ^ flags) & IF_CLAMP)) return glt; glt = Hash_GetNext(&gltexturetable, identifier, glt); @@ -2145,7 +2151,7 @@ texid_t GL_LoadTexture (char *identifier, int width, int height, qbyte *data, un if (identifier[0]) { - glt = GL_MatchTexture(identifier, 8, width, height); + glt = GL_MatchTexture(identifier, flags, 8, width, height); if (glt && !(flags & IF_REPLACE)) return glt->texnum; } @@ -2171,7 +2177,7 @@ texid_t GL_LoadTextureFB (char *identifier, int width, int height, qbyte *data, // see if the texture is already present if (identifier[0]) { - glt = GL_MatchTexture(identifier, 8, width, height); + glt = GL_MatchTexture(identifier, flags, 8, width, height); if (glt) return glt->texnum; } @@ -2201,7 +2207,7 @@ texid_t GL_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *da // see if the texture is already present if (identifier[0]) { - glt = GL_MatchTexture(identifier, 24, width, height); + glt = GL_MatchTexture(identifier, flags, 24, width, height); if (glt) return glt->texnum; } @@ -2223,7 +2229,7 @@ texid_t GL_LoadTexture8Pal32 (char *identifier, int width, int height, qbyte *da // see if the texture is already present if (identifier[0]) { - glt = GL_MatchTexture(identifier, 32, width, height); + glt = GL_MatchTexture(identifier, flags, 32, width, height); if (glt) return glt->texnum; } @@ -2248,7 +2254,7 @@ texid_t GL_LoadTexture32 (char *identifier, int width, int height, void *data, u // see if the texture is already present if (identifier[0]) { - glt = GL_MatchTexture(identifier, 32, width, height); + glt = GL_MatchTexture(identifier, flags, 32, width, height); if (glt && !(flags & IF_REPLACE)) return glt->texnum; } @@ -2284,7 +2290,7 @@ texid_t GL_LoadTexture32_BGRA (char *identifier, int width, int height, unsigned // see if the texture is already present if (identifier[0]) { - glt = GL_MatchTexture(identifier, 32, width, height); + glt = GL_MatchTexture(identifier, flags, 32, width, height); if (glt) return glt->texnum; } @@ -2313,7 +2319,7 @@ texid_t GL_LoadCompressed(char *name) // see if the texture is already present if (name[0]) { - texid_t num = GL_FindTexture(name); + texid_t num = GL_FindTexture(name, 0); if (TEXVALID(num)) return num; } @@ -2347,7 +2353,7 @@ texid_t GL_LoadTexture8Grey (char *identifier, int width, int height, unsigned c // see if the texture is already present if (identifier[0]) { - glt = GL_MatchTexture(identifier, 8, width, height); + glt = GL_MatchTexture(identifier, flags, 8, width, height); if (glt) return glt->texnum; } @@ -2374,7 +2380,7 @@ texid_t GL_LoadTexture8Bump (char *identifier, int width, int height, unsigned c // see if the texture is already present if (identifier[0]) { - glt = GL_MatchTexture(identifier, 8, width, height); + glt = GL_MatchTexture(identifier, flags, 8, width, height); if (glt) { TRACE(("dbg: GL_LoadTexture8Bump: duplicated %s\n", identifier)); diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 8f9a5ce4..ef78c105 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -34,9 +34,27 @@ int Surf_NewLightmaps(int count, int width, int height); enum { - SECTION_HASWATER = 1, + //these flags can be found on disk + TSF_HASWATER = 1u<<0, + + //these flags should not be found on disk + TSF_RELIGHT = 1u<<29, //height edited, needs relighting. + TSF_DIRTY = 1u<<30, //its heightmap has changed, the mesh needs rebuilding + TSF_EDITED = 1u<<31 //says it needs to be written if saved + +#define TSF_INTERNAL (TSF_RELIGHT|TSF_DIRTY|TSF_EDITED) }; +typedef struct +{ + int size; + vec3_t axisorg[4]; + float scale; + int reserved3; + int reserved2; + int reserved1; + //char modelname[1+]; +} dsmesh_t; typedef struct { int magic; @@ -49,6 +67,11 @@ typedef struct float waterheight; float minh; float maxh; + int numents; + int entsofs; + int reserved3; + int reserved2; + int reserved1; } dsection_t; typedef struct { @@ -68,7 +91,10 @@ typedef struct vbo_t vbo; mesh_t mesh; mesh_t *amesh; - qboolean modified:1; + + int numents; + int maxents; + entity_t *ents; #endif } hmsection_t; typedef struct @@ -94,8 +120,22 @@ typedef struct heightmap_s { int lm, x, y; } *unusedlmsects; #endif + +#ifndef SERVERONLY + //I'm putting this here because we might have some quite expensive lighting routines going on + //and that'll make editing the terrain jerky as fook, so relighting it a few texels at a time will help maintain a framerate while editing + hmsection_t *relight; + unsigned int relightidx; + vec2_t relightmin; +#endif } heightmap_t; + +static void ted_dorelight(heightmap_t *hm); + + + + static void Terr_LoadSectionTextures(hmsection_t *s) { #ifndef SERVERONLY @@ -159,6 +199,7 @@ static char *Terr_DiskSectionName(heightmap_t *hm, int sx, int sy) static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy) { dsection_t *ds = NULL; + dsmesh_t *dm; int i; #ifndef SERVERONLY unsigned char *lm; @@ -203,7 +244,7 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in s->hmmod = hm; #ifndef SERVERONLY - s->modified = true; + s->flags |= TSF_DIRTY; if (s->lightmap < 0 && qrenderer != QR_NONE) Terr_InitLightmap(s); @@ -211,7 +252,7 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in if (ds) { - s->flags = ds->flags; + s->flags = ds->flags | TSF_DIRTY; #ifndef SERVERONLY Q_strncpyz(s->texname[0], ds->texname[0], sizeof(s->texname[0])); Q_strncpyz(s->texname[1], ds->texname[1], sizeof(s->texname[1])); @@ -249,10 +290,61 @@ static hmsection_t *Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, in s->maxh = ds->maxh; s->waterheight = ds->waterheight; + s->numents = ds->numents; + s->maxents = s->numents; + s->ents = malloc(sizeof(*s->ents) * s->maxents); + if (!s->ents) + s->numents = s->maxents = 0; + memset(s->ents, 0, sizeof(*s->ents) * s->maxents); + for (i = 0, dm = (dsmesh_t*)((qbyte*)ds + ds->entsofs); i < s->numents; i++, dm = (dsmesh_t*)((qbyte*)dm + dm->size)) + { + s->ents[i].model = Mod_ForName((char*)(dm + 1), false); + if (!s->ents[i].model || s->ents[i].model->type == mod_dummy) + { + s->numents--; + i--; + continue; + } + s->ents[i].scale = dm->scale; + VectorCopy(dm->axisorg[0], s->ents[i].axis[0]); + VectorCopy(dm->axisorg[1], s->ents[i].axis[1]); + VectorCopy(dm->axisorg[2], s->ents[i].axis[2]); + VectorCopy(dm->axisorg[3], s->ents[i].origin); + s->ents[i].origin[0] += (sx-CHUNKBIAS)*hm->sectionsize; + s->ents[i].origin[1] += (sy-CHUNKBIAS)*hm->sectionsize; + s->ents[i].shaderRGBAf[0] = 1; + s->ents[i].shaderRGBAf[1] = 1; + s->ents[i].shaderRGBAf[2] = 1; + s->ents[i].shaderRGBAf[3] = 1; + } + FS_FreeFile(ds); } else { + if (s->lightmap >= 0) + { + int j; + lm = lightmap[s->lightmap]->lightmaps; + lm += (s->lmx * HMLMSTRIDE + s->lmy) * lightmap_bytes; + for (i = 0; i < SECTTEXSIZE; i++) + { + for (j = 0; j < SECTTEXSIZE; j++, lm+=4) + { + lm[0] = 0; + lm[1] = 0; + lm[2] = 0; + lm[3] = 255; + } + lm += (HMLMSTRIDE - SECTTEXSIZE)*lightmap_bytes; + } + lightmap[s->lightmap]->modified = true; + lightmap[s->lightmap]->rectchange.l = 0; + lightmap[s->lightmap]->rectchange.t = 0; + lightmap[s->lightmap]->rectchange.w = HMLMSTRIDE; + lightmap[s->lightmap]->rectchange.h = HMLMSTRIDE; + } + #if 0//def DEBUG void *f; if (lightmap_bytes == 4 && lightmap_bgra && FS_LoadFile(va("maps/%s/splatt.png", hm->path), &f) >= 0) @@ -348,15 +440,26 @@ static void Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy) { #ifndef SERVERONLY dsection_t ds; + dsmesh_t dm; unsigned char *lm; + vfsfile_t *f; + int nothing = 0; int i; //if its invalid or doesn't contain all the data... if (!s || s->lightmap < 0) return; + memset(&ds, 0, sizeof(ds)); + memset(&dm, 0, sizeof(dm)); + ds.magic = SECTION_MAGIC; ds.ver = SECTION_VER; - ds.flags = 0; + //mask off the flags which are only valid in memory + ds.flags = s->flags & ~(TSF_INTERNAL); + + //kill the haswater flag if its entirely above any possible water anyway. + if (s->waterheight < s->minh) + ds.flags &= ~TSF_HASWATER; Q_strncpyz(ds.texname[0], s->texname[0], sizeof(ds.texname[0])); Q_strncpyz(ds.texname[1], s->texname[1], sizeof(ds.texname[1])); @@ -375,11 +478,37 @@ static void Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy) { ds.heights[i] = LittleFloat(s->heights[i]); } + ds.waterheight = s->waterheight; ds.holes = s->holes; ds.minh = s->minh; ds.maxh = s->maxh; + ds.numents = s->numents; + ds.entsofs = sizeof(ds); - FS_WriteFile(Terr_DiskSectionName(hm, sx, sy), &ds, sizeof(ds), FS_GAMEONLY); + f = FS_OpenVFS(Terr_DiskSectionName(hm, sx, sy), "wb", FS_GAMEONLY); + VFS_WRITE(f, &ds, sizeof(ds)); + for (i = 0; i < s->numents; i++) + { + int pad; + dm.scale = s->ents[i].scale; + VectorCopy(s->ents[i].axis[0], dm.axisorg[0]); + VectorCopy(s->ents[i].axis[1], dm.axisorg[1]); + VectorCopy(s->ents[i].axis[2], dm.axisorg[2]); + VectorCopy(s->ents[i].origin, dm.axisorg[3]); + dm.axisorg[3][0] += (CHUNKBIAS-sx)*hm->sectionsize; + dm.axisorg[3][1] += (CHUNKBIAS-sy)*hm->sectionsize; + dm.size = sizeof(dm) + strlen(s->ents[i].model->name) + 1; + if (dm.size & 3) + pad = 4 - (dm.size&3); + else + pad = 0; + dm.size += pad; + VFS_WRITE(f, &dm, sizeof(dm)); + VFS_WRITE(f, s->ents[i].model->name, strlen(s->ents[i].model->name)+1); + if (pad) + VFS_WRITE(f, ¬hing, pad); + } + VFS_CLOSE(f); #endif } @@ -398,6 +527,8 @@ static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean dolo if (doload) { cluster = malloc(sizeof(*cluster)); + if (!cluster) + return NULL; memset(cluster, 0, sizeof(*cluster)); hm->cluster[cx + cy*MAXSECTIONS] = cluster; } @@ -416,10 +547,11 @@ static hmsection_t *Terr_GetSection(heightmap_t *hm, int x, int y, qboolean dolo } /*save all currently loaded sections*/ -void HeightMap_Save(heightmap_t *hm) +int HeightMap_Save(heightmap_t *hm) { hmsection_t *s; int x, y; + int sectionssaved = 0; for (x = hm->firstsegx; x < hm->maxsegx; x++) { for (y = hm->firstsegy; y < hm->maxsegy; y++) @@ -427,9 +559,16 @@ void HeightMap_Save(heightmap_t *hm) s = Terr_GetSection(hm, x, y, false); if (!s) continue; - Terr_SaveSection(hm, s, x, y); + if (s->flags & TSF_EDITED) + { + s->flags &= ~TSF_EDITED; + Terr_SaveSection(hm, s, x, y); + sectionssaved++; + } } } + + return sectionssaved; } void Terr_DestroySection(heightmap_t *hm, hmsection_t *s) @@ -518,6 +657,233 @@ void Terr_PurgeTerrainModel(model_t *mod, qboolean lightmapsonly) #endif } #ifndef SERVERONLY +void Terr_DrawTerrainWater(float *mins, float *maxs, float waterz, float r, float g, float b, float a) +{ + scenetris_t *t; + shader_t *s = R_RegisterCustom ("warp/terrain", Shader_DefaultBSPQ2, NULL); + + if (!TEXVALID(s->defaulttextures.base)) + s->defaulttextures.base = R_LoadHiResTexture("terwater", NULL, IF_NOALPHA); + if (!TEXVALID(s->defaulttextures.bump)) + s->defaulttextures.bump = R_LoadBumpmapTexture("terwater_bump", NULL); + if (!TEXVALID(s->defaulttextures.bump)) + { + unsigned char dat[64*64] = {0}; + int i; + for (i = 0; i < 64*64; i++) + dat[i] = rand()&15; + s->defaulttextures.bump = R_LoadTexture8BumpPal("terwater_bump", 64, 64, dat, 0); + } + + + if (cl_numstris && cl_stris[cl_numstris-1].shader == s) + { + t = &cl_stris[cl_numstris-1]; + } + else + { + if (cl_numstris == cl_maxstris) + { + cl_maxstris+=8; + cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + } + t = &cl_stris[cl_numstris++]; + t->shader = s; + t->firstidx = cl_numstrisidx; + t->firstvert = cl_numstrisvert; + t->numvert = 0; + t->numidx = 0; + } + + if (cl_numstrisidx+12 > cl_maxstrisidx) + { + cl_maxstrisidx=cl_numstrisidx+12 + 64; + cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); + } + if (cl_numstrisvert+4 > cl_maxstrisvert) + { + cl_maxstrisvert+=64; + cl_strisvertv = BZ_Realloc(cl_strisvertv, sizeof(*cl_strisvertv)*cl_maxstrisvert); + cl_strisvertt = BZ_Realloc(cl_strisvertt, sizeof(*cl_strisvertt)*cl_maxstrisvert); + cl_strisvertc = BZ_Realloc(cl_strisvertc, sizeof(*cl_strisvertc)*cl_maxstrisvert); + } + + { + VectorSet(cl_strisvertv[cl_numstrisvert], mins[0], mins[1], waterz); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, a); + Vector2Set(cl_strisvertt[cl_numstrisvert], mins[0]/64, mins[1]/64); + cl_numstrisvert++; + + VectorSet(cl_strisvertv[cl_numstrisvert], mins[0], maxs[1], waterz); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, a); + Vector2Set(cl_strisvertt[cl_numstrisvert], mins[0]/64, maxs[1]/64); + cl_numstrisvert++; + + VectorSet(cl_strisvertv[cl_numstrisvert], maxs[0], maxs[1], waterz); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, a); + Vector2Set(cl_strisvertt[cl_numstrisvert], maxs[0]/64, maxs[1]/64); + cl_numstrisvert++; + + VectorSet(cl_strisvertv[cl_numstrisvert], maxs[0], mins[1], waterz); + Vector4Set(cl_strisvertc[cl_numstrisvert], r, g, b, a); + Vector2Set(cl_strisvertt[cl_numstrisvert], maxs[0]/64, mins[1]/64); + cl_numstrisvert++; + } + + + + + /*build the triangles*/ + cl_strisidx[cl_numstrisidx++] = t->numvert + 0; + cl_strisidx[cl_numstrisidx++] = t->numvert + 1; + cl_strisidx[cl_numstrisidx++] = t->numvert + 2; + + cl_strisidx[cl_numstrisidx++] = t->numvert + 0; + cl_strisidx[cl_numstrisidx++] = t->numvert + 2; + cl_strisidx[cl_numstrisidx++] = t->numvert + 3; + + cl_strisidx[cl_numstrisidx++] = t->numvert + 3; + cl_strisidx[cl_numstrisidx++] = t->numvert + 2; + cl_strisidx[cl_numstrisidx++] = t->numvert + 1; + + cl_strisidx[cl_numstrisidx++] = t->numvert + 3; + cl_strisidx[cl_numstrisidx++] = t->numvert + 1; + cl_strisidx[cl_numstrisidx++] = t->numvert + 0; + + + t->numidx = cl_numstrisidx - t->firstidx; + t->numvert += 4; +} + +void Terr_RebuildMesh(hmsection_t *s, int x, int y) +{ + int vx, vy; + int v; + mesh_t *mesh = &s->mesh; + heightmap_t *hm = s->hmmod; + + if (s->lightmap < 0) + { + Terr_InitLightmap(s); + } + + s->minh = 9999999999999999.f; + s->maxh = -9999999999999999.f; + + if (!mesh->xyz_array) + { + mesh->xyz_array = BZ_Malloc((sizeof(vecV_t)+sizeof(vec2_t)+sizeof(vec2_t)) * (SECTHEIGHTSIZE)*(SECTHEIGHTSIZE)); + mesh->st_array = (void*) (mesh->xyz_array + (SECTHEIGHTSIZE)*(SECTHEIGHTSIZE)); + mesh->lmst_array[0] = (void*) (mesh->st_array + (SECTHEIGHTSIZE)*(SECTHEIGHTSIZE)); + } + mesh->numvertexes = 0; + /*64 quads across requires 65 verticies*/ + for (vx = 0; vx < SECTHEIGHTSIZE; vx++) + { + for (vy = 0; vy < SECTHEIGHTSIZE; vy++) + { + v = mesh->numvertexes++; + mesh->xyz_array[v][0] = (x-CHUNKBIAS + vx/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; + mesh->xyz_array[v][1] = (y-CHUNKBIAS + vy/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; + mesh->xyz_array[v][2] = s->heights[vx + vy*SECTHEIGHTSIZE]; + + if (s->maxh < mesh->xyz_array[v][2]) + s->maxh = mesh->xyz_array[v][2]; + if (s->minh > mesh->xyz_array[v][2]) + s->minh = mesh->xyz_array[v][2]; + + mesh->st_array[v][0] = mesh->xyz_array[v][0] / 128; + mesh->st_array[v][1] = mesh->xyz_array[v][1] / 128; + + //calc the position in the range -0.5 to 0.5 + mesh->lmst_array[0][v][0] = (((float)vx / (SECTHEIGHTSIZE-1))-0.5); + mesh->lmst_array[0][v][1] = (((float)vy / (SECTHEIGHTSIZE-1))-0.5); + //scale down to a half-texel + mesh->lmst_array[0][v][0] *= (SECTTEXSIZE-1.0f)/HMLMSTRIDE; + mesh->lmst_array[0][v][1] *= (SECTTEXSIZE-1.0f)/HMLMSTRIDE; + //bias it + mesh->lmst_array[0][v][0] += ((float)SECTTEXSIZE/(HMLMSTRIDE*2)) + ((float)(s->lmy) / HMLMSTRIDE); + mesh->lmst_array[0][v][1] += ((float)SECTTEXSIZE/(HMLMSTRIDE*2)) + ((float)(s->lmx) / HMLMSTRIDE); + + //TODO: include colour tints + } + } + + if (!mesh->indexes) + mesh->indexes = BZ_Malloc(sizeof(index_t) * SECTHEIGHTSIZE*SECTHEIGHTSIZE*6); + + mesh->numindexes = 0; + for (vx = 0; vx < SECTHEIGHTSIZE-1; vx++) + { + for (vy = 0; vy < SECTHEIGHTSIZE-1; vy++) + { + float d1,d2; +#if SECTHEIGHTSIZE >= 4 + int holebit; + + //skip generation of the mesh above holes + holebit = (vy / (SECTHEIGHTSIZE/4))+(vx / (SECTHEIGHTSIZE/4))*4; + holebit = 1u<holes & holebit) + continue; +#endif + v = vx + vy*(SECTHEIGHTSIZE); + + d1 = fabs(mesh->xyz_array[v][2] - mesh->xyz_array[v+1+SECTHEIGHTSIZE][2]); + d2 = fabs(mesh->xyz_array[v+1][2] - mesh->xyz_array[v+SECTHEIGHTSIZE][2]); +#if 1 + if (d1 < d2) + { + mesh->indexes[mesh->numindexes++] = v+0; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+0; + mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; + } +#endif + else + { + mesh->indexes[mesh->numindexes++] = v+0; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+1; + mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; + mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; + } + } + } + +#ifdef GLQUAKE + if (qrenderer == QR_OPENGL) + { + if (!s->vbo.coord.gl.vbo) + qglGenBuffersARB(1, &s->vbo.coord.gl.vbo); + s->vbo.coord.gl.addr = 0; + GL_SelectVBO(s->vbo.coord.gl.vbo); + qglBufferDataARB(GL_ARRAY_BUFFER_ARB, (sizeof(vecV_t)+sizeof(vec2_t)+sizeof(vec2_t)) * (mesh->numvertexes), mesh->xyz_array, GL_STATIC_DRAW_ARB); + GL_SelectVBO(0); + s->vbo.texcoord.gl.addr = (void*)((char*)mesh->st_array - (char*)mesh->xyz_array); + s->vbo.texcoord.gl.vbo = s->vbo.coord.gl.vbo; + s->vbo.lmcoord[0].gl.addr = (void*)((char*)mesh->lmst_array[0] - (char*)mesh->xyz_array); + s->vbo.lmcoord[0].gl.vbo = s->vbo.coord.gl.vbo; +// Z_Free(mesh->xyz_array); +// mesh->xyz_array = NULL; +// mesh->st_array = NULL; +// mesh->lmst_array = NULL; + + if (!s->vbo.indicies.gl.vbo) + qglGenBuffersARB(1, &s->vbo.indicies.gl.vbo); + s->vbo.indicies.gl.addr = 0; + GL_SelectEBO(s->vbo.indicies.gl.vbo); + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(index_t) * mesh->numindexes, mesh->indexes, GL_STATIC_DRAW_ARB); + GL_SelectEBO(0); +// Z_Free(mesh->indexes); +// mesh->indexes = NULL; + } +#endif +} + void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) { //a 512*512 heightmap @@ -525,7 +891,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) //so a million triangles per frame if the whole thing is visible. //with 130 to 180fps, display lists rule! - int x, y, vx, vy, v; + int x, y, i; vec3_t mins, maxs; model_t *m = e->model; heightmap_t *hm = m->terrain; @@ -533,6 +899,9 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) batch_t *b; hmsection_t *s; int bounds[4]; + + if (hm->relight) + ted_dorelight(hm); if (e->model == cl.worldmodel) { @@ -560,6 +929,7 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) } } + if (r_refdef.gfog_rgbd[3] || gl_maxdist.value>0) { float culldist; @@ -610,130 +980,43 @@ void Terr_DrawTerrainModel (batch_t **batches, entity_t *e) if (s->lightmap < 0) Terr_LoadSection(hm, s, x, y); - mesh = &s->mesh; - if (s->modified) + if (s->flags & TSF_RELIGHT) { -// minx = x*SECTHEIGHTSIZE; -// miny = y*SECTHEIGHTSIZE; - - s->modified = false; - - if (s->lightmap < 0) + if (!hm->relight) { - Terr_InitLightmap(s); + s->flags &= ~TSF_RELIGHT; + hm->relight = s; + hm->relightidx = 0; + hm->relightmin[0] = mins[0]; + hm->relightmin[1] = mins[1]; } + } - s->minh = 9999999999999999.f; - s->maxh = -9999999999999999.f; + mesh = &s->mesh; + if (s->flags & TSF_DIRTY) + { + s->flags &= ~TSF_DIRTY; - if (!mesh->xyz_array) + Terr_RebuildMesh(s, x, y); + } + + //chuck out any batches for models in this section + for (i = 0; i < s->numents; i++) + { + if (s->ents[i].model && s->ents[i].model->type == mod_alias) { - mesh->xyz_array = BZ_Malloc((sizeof(vecV_t)+sizeof(vec2_t)+sizeof(vec2_t)) * (SECTHEIGHTSIZE)*(SECTHEIGHTSIZE)); - mesh->st_array = (void*) (mesh->xyz_array + (SECTHEIGHTSIZE)*(SECTHEIGHTSIZE)); - mesh->lmst_array[0] = (void*) (mesh->st_array + (SECTHEIGHTSIZE)*(SECTHEIGHTSIZE)); + R_GAlias_GenerateBatches(&s->ents[i], batches); } - mesh->numvertexes = 0; - /*64 quads across requires 65 verticies*/ - for (vx = 0; vx < SECTHEIGHTSIZE; vx++) + } + + if (s->flags & TSF_HASWATER) + { + mins[2] = s->waterheight; + maxs[2] = s->waterheight; + if (!R_CullBox(mins, maxs)) { - for (vy = 0; vy < SECTHEIGHTSIZE; vy++) - { - v = mesh->numvertexes++; - mesh->xyz_array[v][0] = (x-CHUNKBIAS + vx/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; - mesh->xyz_array[v][1] = (y-CHUNKBIAS + vy/(SECTHEIGHTSIZE-1.0f)) * hm->sectionsize; - mesh->xyz_array[v][2] = s->heights[vx + vy*SECTHEIGHTSIZE]; - - if (s->maxh < mesh->xyz_array[v][2]) - s->maxh = mesh->xyz_array[v][2]; - if (s->minh > mesh->xyz_array[v][2]) - s->minh = mesh->xyz_array[v][2]; - - mesh->st_array[v][0] = mesh->xyz_array[v][0] / 128; - mesh->st_array[v][1] = mesh->xyz_array[v][1] / 128; - - //calc the position in the range -0.5 to 0.5 - mesh->lmst_array[0][v][0] = (((float)vx / (SECTHEIGHTSIZE-1))-0.5); - mesh->lmst_array[0][v][1] = (((float)vy / (SECTHEIGHTSIZE-1))-0.5); - //scale down to a half-texel - mesh->lmst_array[0][v][0] *= (SECTTEXSIZE-1.0f)/HMLMSTRIDE; - mesh->lmst_array[0][v][1] *= (SECTTEXSIZE-1.0f)/HMLMSTRIDE; - //bias it - mesh->lmst_array[0][v][0] += ((float)SECTTEXSIZE/(HMLMSTRIDE*2)) + ((float)(s->lmy) / HMLMSTRIDE); - mesh->lmst_array[0][v][1] += ((float)SECTTEXSIZE/(HMLMSTRIDE*2)) + ((float)(s->lmx) / HMLMSTRIDE); - - //TODO: include colour tints - } + Terr_DrawTerrainWater(mins, maxs, s->waterheight, 1, 1, 1, 1); } - - if (!mesh->indexes) - mesh->indexes = BZ_Malloc(sizeof(index_t) * SECTHEIGHTSIZE*SECTHEIGHTSIZE*6); - - mesh->numindexes = 0; - for (vx = 0; vx < SECTHEIGHTSIZE-1; vx++) - { - for (vy = 0; vy < SECTHEIGHTSIZE-1; vy++) - { - float d1,d2; - int holebit; - - //skip generation of the mesh above holes - holebit = (vy / (SECTHEIGHTSIZE/4))+(vx / (SECTHEIGHTSIZE/4))*4; - holebit = 1u<holes & holebit) - continue; - v = vx + vy*(SECTHEIGHTSIZE); - - d1 = fabs(mesh->xyz_array[v][2] - mesh->xyz_array[v+1+SECTHEIGHTSIZE][2]); - d2 = fabs(mesh->xyz_array[v+1][2] - mesh->xyz_array[v+SECTHEIGHTSIZE][2]); - if (d1 > d2) - { - mesh->indexes[mesh->numindexes++] = v+0; - mesh->indexes[mesh->numindexes++] = v+1; - mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; - mesh->indexes[mesh->numindexes++] = v+1; - mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; - mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; - } - else - { - mesh->indexes[mesh->numindexes++] = v+0; - mesh->indexes[mesh->numindexes++] = v+1; - mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; - mesh->indexes[mesh->numindexes++] = v+0; - mesh->indexes[mesh->numindexes++] = v+1+SECTHEIGHTSIZE; - mesh->indexes[mesh->numindexes++] = v+SECTHEIGHTSIZE; - } - } - } - -#ifdef GLQUAKE - if (qrenderer == QR_OPENGL) - { - if (!s->vbo.coord.gl.vbo) - qglGenBuffersARB(1, &s->vbo.coord.gl.vbo); - s->vbo.coord.gl.addr = 0; - GL_SelectVBO(s->vbo.coord.gl.vbo); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, (sizeof(vecV_t)+sizeof(vec2_t)+sizeof(vec2_t)) * (mesh->numvertexes), mesh->xyz_array, GL_STATIC_DRAW_ARB); - GL_SelectVBO(0); - s->vbo.texcoord.gl.addr = (void*)((char*)mesh->st_array - (char*)mesh->xyz_array); - s->vbo.texcoord.gl.vbo = s->vbo.coord.gl.vbo; - s->vbo.lmcoord[0].gl.addr = (void*)((char*)mesh->lmst_array[0] - (char*)mesh->xyz_array); - s->vbo.lmcoord[0].gl.vbo = s->vbo.coord.gl.vbo; -// Z_Free(mesh->xyz_array); -// mesh->xyz_array = NULL; -// mesh->st_array = NULL; -// mesh->lmst_array = NULL; - - if (!s->vbo.indicies.gl.vbo) - qglGenBuffersARB(1, &s->vbo.indicies.gl.vbo); - s->vbo.indicies.gl.addr = 0; - GL_SelectEBO(s->vbo.indicies.gl.vbo); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(index_t) * mesh->numindexes, mesh->indexes, GL_STATIC_DRAW_ARB); - GL_SelectEBO(0); -// Z_Free(mesh->indexes); -// mesh->indexes = NULL; - } -#endif } mins[2] = s->minh; @@ -833,7 +1116,7 @@ unsigned int Heightmap_PointContentsHM(heightmap_t *hm, float clipmipsz, vec3_t } if (z <= tz) return FTECONTENTS_SOLID; //contained within - if (s->flags & SECTION_HASWATER) + if (s->flags & TSF_HASWATER) if (z < s->waterheight) return FTECONTENTS_WATER; return FTECONTENTS_EMPTY; @@ -852,28 +1135,43 @@ unsigned int Heightmap_NativeBoxContents(model_t *model, int hulloverride, int f void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm) { +#if 0 norm[0] = 0; norm[1] = 0; norm[2] = 1; -/* +#else float x, y; - float z; int sx, sy; vec3_t d1, d2; + const float wbias = CHUNKBIAS * hm->sectionsize; + hmsection_t *s; - x = org[0]/(SECTHEIGHTSIZE * hm->sectionsize); - y = org[1]/(SECTHEIGHTSIZE * hm->sectionsize); - z = org[2]; + norm[0] = 0; + norm[1] = 0; + norm[2] = 1; + sx = (org[0]+wbias)/hm->sectionsize; + sy = (org[1]+wbias)/hm->sectionsize; + if (sx < hm->firstsegx || sy < hm->firstsegy) + return; + if (sx >= hm->maxsegx || sy >= hm->maxsegy) + return; + s = Terr_GetSection(hm, sx, sy, true); + if (!s) + return; + + x = (org[0]+wbias - (sx*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; + y = (org[1]+wbias - (sy*hm->sectionsize))*(SECTHEIGHTSIZE-1)/hm->sectionsize; +/* if (x < 0) x = 0; if (y < 0) y = 0; - if (x > hm->tilesx-1) - x = hm->tilesx-1; - if (y > hm->tilesy-1) - y = hm->tilesy-1; - + if (x > hm->maxsegx-1) + x = hm->maxsegx-1; + if (y > hm->maxsegy-1) + y = hm->maxsegy-1; +*/ sx = x; x-=sx; sy = y; y-=sy; @@ -882,118 +1180,134 @@ void Heightmap_Normal(heightmap_t *hm, vec3_t org, vec3_t norm) //0, 1 //1, 1 //1, 0 - d1[0] = (SECTHEIGHTSIZE * hm->sectionsize); + d1[0] = (hm->sectionsize / SECTHEIGHTSIZE); d1[1] = 0; - d1[2] = (hm->heights[(sx+1)+(sy+1)*hm->tilesx] - hm->heights[(sx+0)+(sy+1)*hm->tilesx]); + d1[2] = (s->heights[(sx+1)+(sy+1)*SECTHEIGHTSIZE] - s->heights[(sx+0)+(sy+1)*SECTHEIGHTSIZE]); d2[0] = 0; - d2[1] = (SECTHEIGHTSIZE * hm->sectionsize); - d2[2] = (hm->heights[(sx+1)+(sy+1)*hm->tilesx] - hm->heights[(sx+1)+(sy+0)*hm->tilesx]); + d2[1] = (hm->sectionsize / SECTHEIGHTSIZE); + d2[2] = (s->heights[(sx+1)+(sy+1)*SECTHEIGHTSIZE] - s->heights[(sx+1)+(sy+0)*SECTHEIGHTSIZE]); } else { //the 0,0 triangle //0, 1 //1, 0 //0, 0 - d1[0] = (SECTHEIGHTSIZE * hm->sectionsize); + d1[0] = (hm->sectionsize / SECTHEIGHTSIZE); d1[1] = 0; - d1[2] = (hm->heights[(sx+0)+(sy+1)*hm->tilesx] - hm->heights[(sx+0)+(sy+0)*hm->tilesx]); + d1[2] = (s->heights[(sx+1)+(sy+0)*SECTHEIGHTSIZE] - s->heights[(sx+0)+(sy+0)*SECTHEIGHTSIZE]); d2[0] = 0; - d2[1] = (SECTHEIGHTSIZE * hm->sectionsize); - d2[2] = (hm->heights[(sx+1)+(sy+0)*hm->tilesx] - hm->heights[(sx+0)+(sy+0)*hm->tilesx]); + d2[1] = (hm->sectionsize / SECTHEIGHTSIZE); + d2[2] = (s->heights[(sx+0)+(sy+1)*SECTHEIGHTSIZE] - s->heights[(sx+0)+(sy+0)*SECTHEIGHTSIZE]); } VectorNormalize(d1); VectorNormalize(d2); CrossProduct(d1, d2, norm); VectorNormalize(norm); -*/ +#endif } -#if 0 typedef struct { vec3_t start; vec3_t end; vec3_t impact; vec4_t plane; float frac; + float htilesize; heightmap_t *hm; int contents; } hmtrace_t; -#define Closestf(res,n,min,max) res = ((n>0)?min:max) -#define Closest(res,n,min,max) Closestf(res[0],n[0],min[0],max[0]);Closestf(res[1],n[1],min[1],max[1]);Closestf(res[2],n[2],min[2],max[2]) -void Heightmap_Trace_Square(hmtrace_t *tr, int sx, int sy) + +//sx,sy are the tile coord +//note that tile SECTHEIGHTSIZE-1 does not exist, as the last sample overlaps the first sample of the next section +void Heightmap_Trace_Square(hmtrace_t *tr, int tx, int ty) { vec3_t d[2]; - vec3_t p[3]; + vec3_t p[4]; vec4_t n[5]; int t, i; qboolean startout, endout; float *enterplane; - float enterfrac, exitfrac; + float enterfrac, exitfrac, nearfrac=0; float enterdist=0; float dist, d1, d2, f; + int sx, sy; + hmsection_t *s; - if (sx < 0 || sx > tr->hm->tilesx) + if (tx < 0 || tx >= CHUNKLIMIT*(SECTHEIGHTSIZE-1)) return; - if (sy < 0 || sy > tr->hm->tilesy) + if (ty < 0 || ty >= CHUNKLIMIT*(SECTHEIGHTSIZE-1)) return; + s = Terr_GetSection(tr->hm, tx/(SECTHEIGHTSIZE-1), ty/(SECTHEIGHTSIZE-1), true); + + sx = tx; + sy = ty; + + tx = tx % (SECTHEIGHTSIZE-1); + ty = ty % (SECTHEIGHTSIZE-1); + + VectorSet(p[0], tr->htilesize*(sx+0), tr->htilesize*(sy+0), s->heights[(tx+0)+(ty+0)*SECTHEIGHTSIZE]); + VectorSet(p[1], tr->htilesize*(sx+1), tr->htilesize*(sy+0), s->heights[(tx+1)+(ty+0)*SECTHEIGHTSIZE]); + VectorSet(p[2], tr->htilesize*(sx+0), tr->htilesize*(sy+1), s->heights[(tx+0)+(ty+1)*SECTHEIGHTSIZE]); + VectorSet(p[3], tr->htilesize*(sx+1), tr->htilesize*(sy+1), s->heights[(tx+1)+(ty+1)*SECTHEIGHTSIZE]); +// DebugDrawQuadH(p[0][0], p[0][1], p[3][0], p[3][1], p[0][2], 0, 0, 0.2); for (t = 0; t < 2; t++) { - /*generate the brush*/ + /*generate the brush (in world space*/ if (t == 0) { - VectorSet(p[0], tr->hm->terrainscale*(sx+0), tr->hm->terrainscale*(sy+0), tr->hm->heights[(sx+0)+(sy+0)*tr->hm->tilesx]); - VectorSet(p[1], tr->hm->terrainscale*(sx+1), tr->hm->terrainscale*(sy+0), tr->hm->heights[(sx+1)+(sy+0)*tr->hm->tilesx]); - VectorSet(p[2], tr->hm->terrainscale*(sx+0), tr->hm->terrainscale*(sy+1), tr->hm->heights[(sx+0)+(sy+1)*tr->hm->tilesx]); +// continue; VectorSubtract(p[1], p[0], d[0]); VectorSubtract(p[2], p[0], d[1]); //left-most - Vector4Set(n[0], -1, 0, 0, tr->hm->terrainscale*(sx+0)); + Vector4Set(n[0], -1, 0, 0, -tr->htilesize*(sx+0)); //top-most - Vector4Set(n[1], 0, -1, 0, tr->hm->terrainscale*(sy+0)); + Vector4Set(n[1], 0, -1, 0, -tr->htilesize*(sy+0)); //bottom-right VectorSet(n[2], 0.70710678118654752440084436210485, 0.70710678118654752440084436210485, 0); - n[2][3] = -DotProduct(n[2], p[1]); + n[2][3] = DotProduct(n[2], p[1]); //top + VectorNormalize(d[0]); + VectorNormalize(d[1]); CrossProduct(d[0], d[1], n[3]); VectorNormalize(n[3]); - n[3][3] = -DotProduct(n[3], p[1]); + n[3][3] = DotProduct(n[3], p[1]); //down - Vector4Set(n[4], 0, 0, 1, 0); + Vector4Set(n[4], 0, 0, -1, 0); + n[4][3] = DotProduct(n[3], p[1]); } else { - VectorSet(p[0], tr->hm->terrainscale*(sx+1), tr->hm->terrainscale*(sy+1), tr->hm->heights[(sx+1)+(sy+1)*tr->hm->tilesx]); - VectorSet(p[1], tr->hm->terrainscale*(sx+1), tr->hm->terrainscale*(sy+0), tr->hm->heights[(sx+1)+(sy+0)*tr->hm->tilesx]); - VectorSet(p[2], tr->hm->terrainscale*(sx+0), tr->hm->terrainscale*(sy+1), tr->hm->heights[(sx+0)+(sy+1)*tr->hm->tilesx]); - VectorSubtract(p[1], p[0], d[0]); - VectorSubtract(p[2], p[0], d[1]); +// continue; + VectorSubtract(p[3], p[2], d[0]); + VectorSubtract(p[3], p[1], d[1]); + //right-most - Vector4Set(n[0], 1, 0, 0, tr->hm->terrainscale*(sx+1)); + Vector4Set(n[0], 1, 0, 0, tr->htilesize*(sx+1)); //bottom-most - Vector4Set(n[1], 0, 1, 0, tr->hm->terrainscale*(sy+1)); - //bottom-right + Vector4Set(n[1], 0, 1, 0, tr->htilesize*(sy+1)); + //top-left VectorSet(n[2], -0.70710678118654752440084436210485, -0.70710678118654752440084436210485, 0); - n[2][3] = -DotProduct(n[2], p[1]); + n[2][3] = DotProduct(n[2], p[1]); //top + VectorNormalize(d[0]); + VectorNormalize(d[1]); CrossProduct(d[0], d[1], n[3]); VectorNormalize(n[3]); - n[3][3] = -DotProduct(n[3], p[1]); + n[3][3] = DotProduct(n[3], p[1]); //down - Vector4Set(n[4], 0, 0, 1, 0); + Vector4Set(n[4], 0, 0, -1, 0); + n[4][3] = DotProduct(n[3], p[1]); } - - - startout = false; endout = false; enterplane= NULL; enterfrac = -1; exitfrac = 10; - for (i = 0; i < 5; i++) + for (i = 0; i < 4; i++) { /*calculate the distance based upon the shape of the object we're tracing for*/ dist = n[i][3]; @@ -1002,7 +1316,7 @@ void Heightmap_Trace_Square(hmtrace_t *tr, int sx, int sy) d1 = DotProduct (tr->start, n[i]) - dist; d2 = DotProduct (tr->end, n[i]) - dist; - if (d1 >= 0) + if (d1 > 0) startout = true; if (d2 > 0) endout = true; @@ -1015,13 +1329,14 @@ void Heightmap_Trace_Square(hmtrace_t *tr, int sx, int sy) if (d1 < 0 && d2 <= 0) continue; - f = d1 / (d1-d2); + f = (d1) / (d1-d2); if (d1 > d2) { //entered the brush. favour the furthest fraction to avoid extended edges (yay for convex shapes) if (enterfrac < f) { enterfrac = f; + nearfrac = (d1 - (0.03125)) / (d1-d2); enterplane = n[i]; enterdist = dist; } @@ -1046,7 +1361,9 @@ void Heightmap_Trace_Square(hmtrace_t *tr, int sx, int sy) //impact! if (enterfrac < tr->frac) { - tr->frac = enterfrac; + if (nearfrac < 0) + nearfrac = 0; + tr->frac = nearfrac;//enterfrac; tr->plane[3] = enterdist; VectorCopy(enterplane, tr->plane); } @@ -1076,7 +1393,7 @@ nextbrush: point[0] = sx+1; point[1] = sy; - point[2] = tr->hm->heights[sx+1+sy*tr->hm->terrainsize]; + point[2] = s->heights[sx+1+sy*tr->hm->terrainsize]; if (tris & 1) { //triangle with 0, 0 @@ -1132,42 +1449,8 @@ nextbrush: } #endif } + #define DIST_EPSILON 0 -void Heightmap_RecurseTrace(hmtrace_t *tr, float p1[2], float p2[2]) -{ - float newv[2]; - float frac; - int mid; - int axis; - //FIXME: expand the trace somehow - if ((int)p1[0] == (int)p2[0] && (int)p1[1] == (int)p2[1]) - { //end - Heightmap_Trace_Square(tr, p1[0], p2[1]); - return; - } - /*decide the plane axis*/ - axis = abs(p2[1] - p1[1]) > abs(p2[0] - p1[0]); - /*figure out the index to split the trace at*/ - mid = (p1[axis] + p2[axis])*0.5; - if (!mid)/*make sure we make progress*/ - mid = (p2[axis] > p1[axis])?1:-1; - - //it crosses somewhere, it must do. - if (p2[axis] > p1[axis]) - frac = ((p1[axis] - mid) - DIST_EPSILON)/(p1[axis]-p2[axis]); - else - frac = ((p1[axis] - mid) + DIST_EPSILON)/(p1[axis]-p2[axis]); - - newv[axis] = mid; - newv[!axis] = (p2[!axis] * frac) + (p1[!axis] * (1-frac)); - if ((int)p1[axis] != (int)newv[axis]) - Heightmap_RecurseTrace(tr, p1, newv); - if (!tr->contents) - { - Heightmap_RecurseTrace(tr, newv, p2); - } -} - /* Heightmap_TraceRecurse Traces an arbitary box through a heightmap. (interface with outside) @@ -1179,25 +1462,108 @@ Why is recursion good? Obviously, we don't care all that much about 1 */ -qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace) +qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec3_t mataxis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int against, struct trace_s *trace) { - float p1[2], p2[2]; + vec2_t pos, npos; + qboolean nudge[2]; + vec2_t dir; + vec2_t frac; + vec2_t emins; + vec2_t emaxs; + int x, y; + int axis; + int breaklimit = 1000; hmtrace_t hmtrace; hmtrace.hm = model->terrain; + hmtrace.htilesize = hmtrace.hm->sectionsize / (SECTHEIGHTSIZE-1); + hmtrace.frac = 1; + hmtrace.contents = 0; - hmtrace.start[0] = start[0]/hmtrace.hm->terrainscale; - hmtrace.start[1] = start[1]/hmtrace.hm->terrainscale; + hmtrace.plane[0] = 0; + hmtrace.plane[1] = 0; + hmtrace.plane[2] = 1; + hmtrace.plane[3] = 0; + + memset(trace, 0, sizeof(*trace)); + trace->fraction = 1; + + //to tile space + hmtrace.start[0] = (start[0] + CHUNKBIAS*hmtrace.hm->sectionsize); + hmtrace.start[1] = (start[1] + CHUNKBIAS*hmtrace.hm->sectionsize); hmtrace.start[2] = (start[2] + mins[2]); - hmtrace.end[0] = end[0]/hmtrace.hm->terrainscale; - hmtrace.end[1] = end[1]/hmtrace.hm->terrainscale; + hmtrace.end[0] = (end[0] + CHUNKBIAS*hmtrace.hm->sectionsize); + hmtrace.end[1] = (end[1] + CHUNKBIAS*hmtrace.hm->sectionsize); hmtrace.end[2] = (end[2] + mins[2]); - p1[0] = (start[0])/hmtrace.hm->terrainscale; - p1[1] = (start[1])/hmtrace.hm->terrainscale; - p2[0] = (end[0])/hmtrace.hm->terrainscale; - p2[1] = (end[1])/hmtrace.hm->terrainscale; + dir[0] = (hmtrace.end[0] - hmtrace.start[0])/hmtrace.htilesize; + dir[1] = (hmtrace.end[1] - hmtrace.start[1])/hmtrace.htilesize; + pos[0] = hmtrace.start[0]/hmtrace.htilesize; + pos[1] = hmtrace.start[1]/hmtrace.htilesize; - Heightmap_RecurseTrace(&hmtrace, p1, p2); + emins[0] = (mins[0]-1)/hmtrace.htilesize; + emins[1] = (mins[1]-1)/hmtrace.htilesize; + emaxs[0] = (maxs[0]+1)/hmtrace.htilesize; + emaxs[1] = (maxs[1]+1)/hmtrace.htilesize; + + /*fixme: + set pos to the leading corner instead + on boundary changes, scan across multiple blocks + */ + + //make sure the start tile is valid + for (y = pos[1] + emins[1]; y <= pos[1] + emaxs[1]; y++) + for (x = pos[0] + emins[0]; x <= pos[0] + emaxs[0]; x++) + Heightmap_Trace_Square(&hmtrace, x, y); + for(;;) + { + if (breaklimit--< 0) + break; + for (axis = 0; axis < 2; axis++) + { + if (dir[axis] > 0) + { + nudge[axis] = false; + npos[axis] = pos[axis] + 1-(pos[axis]-(int)pos[axis]); + frac[axis] = (npos[axis]*hmtrace.htilesize - hmtrace.start[axis])/(hmtrace.end[axis]-hmtrace.start[axis]); + } + else if (dir[axis] < 0) + { + npos[axis] = pos[axis]; + nudge[axis] = (float)(int)pos[axis] == pos[axis]; + npos[axis] = (int)npos[axis]; + frac[axis] = (npos[axis]*hmtrace.htilesize - hmtrace.start[axis])/(hmtrace.end[axis]-hmtrace.start[axis]); + npos[axis] -= nudge[axis]; + } + else + frac[axis] = 1000000000000000; + } + + //which side are we going down? + if (frac[0] < frac[1]) + axis = 0; + else + axis = 1; + + if (frac[axis] >= 1) + break; + + //touch the neighbour(s) + if (dir[axis] > 0) + { + pos[axis] = (int)pos[axis] + 1; + pos[axis] = npos[axis]; + Heightmap_Trace_Square(&hmtrace, pos[0], pos[1]); + } + else + { + pos[axis] = npos[axis]; + Heightmap_Trace_Square(&hmtrace, pos[0], pos[1]); + } + //and make sure our position on the other axis is correct, for the next time around the loop + if (frac[axis] > hmtrace.frac) + break; + pos[!axis] = ((hmtrace.end[!axis] * frac[axis]) + (hmtrace.start[!axis] * (1-frac[axis])))/hmtrace.htilesize; + } trace->plane.dist = hmtrace.plane[3]; trace->plane.normal[0] = hmtrace.plane[0]; @@ -1209,83 +1575,18 @@ qboolean Heightmap_Trace(struct model_s *model, int hulloverride, int frame, vec trace->fraction = 0; trace->startsolid = true; trace->allsolid = true; + VectorCopy(start, trace->endpos); } else { + if (hmtrace.frac < 0) + hmtrace.frac = 0; trace->fraction = hmtrace.frac; VectorInterpolate(start, hmtrace.frac, end, trace->endpos); } return trace->fraction < 1; } -#else -/* -Heightmap_Trace -Traces a line through a heightmap, sampling the terrain at various different positions. -This is inprecise, only supports points (or vertical lines), and can often travel though sticky out bits of terrain. -*/ -qboolean Heightmap_Trace(model_t *model, int forcehullnum, int frame, vec3_t axis[3], vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, unsigned int contentmask, trace_t *trace) -{ - vec3_t org; - vec3_t dir; - float distleft; - float dist; - heightmap_t *hm = model->terrain; - memset(trace, 0, sizeof(trace_t)); - if (Heightmap_PointContentsHM(hm, mins[2], start) == FTECONTENTS_SOLID) - { - trace->fraction = 0; - trace->startsolid = true; - trace->allsolid = true; - VectorCopy(start, trace->endpos); - return true; - } - VectorCopy(start, org); - VectorSubtract(end, start, dir); - dist = VectorNormalize(dir); - if (dist < 10 && dist) - { //if less than 10 units, do at least 10 steps - VectorScale(dir, 1/10.0f, dir); - dist = 10; - } - distleft = dist; - - while(distleft>0) - { - VectorAdd(org, dir, org); - if (Heightmap_PointContentsHM(hm, mins[2], org) == FTECONTENTS_SOLID) - { //go back to the previous safe spot - VectorSubtract(org, dir, org); - break; - } - distleft--; - } - - trace->contents = Heightmap_PointContentsHM(hm, mins[2], end); - - if (distleft <= 0 && trace->contents != FTECONTENTS_SOLID) - { //all the way - trace->fraction = 1; - VectorCopy(end, trace->endpos); - } - else - { //we didn't get all the way there. :( - VectorSubtract(org, start, dir); - trace->fraction = Length(dir)/dist; - if (trace->fraction > 1) - trace->fraction = 1; - VectorCopy(org, trace->endpos); - } - - trace->plane.normal[0] = 0; - trace->plane.normal[1] = 0; - trace->plane.normal[2] = 1; - Heightmap_Normal(model->terrain, trace->endpos, trace->plane.normal); - - return trace->fraction != 1; -} - -#endif unsigned int Heightmap_FatPVS (model_t *mod, vec3_t org, qbyte *pvsbuffer, unsigned int pvssize, qboolean add) { return 0; @@ -1341,9 +1642,13 @@ static unsigned char *ted_getlightmap(hmsection_t *s, int idx) int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE; if (s->lightmap < 0) { - Terr_InitLightmap(s); + Terr_LoadSection(s->hmmod, s, x, y); + if (s->lightmap < 0) + Terr_InitLightmap(s); } + s->flags |= TSF_EDITED; + lightmap[s->lightmap]->modified = true; lightmap[s->lightmap]->rectchange.l = 0; lightmap[s->lightmap]->rectchange.t = 0; @@ -1353,6 +1658,54 @@ static unsigned char *ted_getlightmap(hmsection_t *s, int idx) lm += ((s->lmx+y) * HMLMSTRIDE + (s->lmy+x)) * lightmap_bytes; return lm; } +static void ted_dorelight(heightmap_t *hm) +{ + unsigned char *lm = ted_getlightmap(hm->relight, 0); + int x, y; +#define EXPAND 2 + vec3_t surfnorms[(SECTTEXSIZE+EXPAND*2)*(SECTTEXSIZE+EXPAND*2)]; +// float scaletab[EXPAND*2*EXPAND*2]; + vec3_t ldir = {0.4, 0.7, 2}; + hmsection_t *s = hm->relight; + + hm->relight = NULL; + + for (y = -EXPAND; y < SECTTEXSIZE+EXPAND; y++) + for (x = -EXPAND; x < SECTTEXSIZE+EXPAND; x++) + { + vec3_t pos; + pos[0] = hm->relightmin[0] + (x*hm->sectionsize/(SECTTEXSIZE-1)); + pos[1] = hm->relightmin[1] + (y*hm->sectionsize/(SECTTEXSIZE-1)); + pos[2] = 0; + Heightmap_Normal(s->hmmod, pos, surfnorms[x+EXPAND + (y+EXPAND)*(SECTTEXSIZE+EXPAND*2)]); + } + + VectorNormalize(ldir); + + for (y = 0; y < SECTTEXSIZE; y++, lm += (HMLMSTRIDE-SECTTEXSIZE)*4) + for (x = 0; x < SECTTEXSIZE; x++, lm += 4) + { + vec3_t norm; + float d; + int sx,sy; + VectorClear(norm); + for (sy = -EXPAND; sy <= EXPAND; sy++) + for (sx = -EXPAND; sx <= EXPAND; sx++) + { + d = sqrt((EXPAND*2+1)*(EXPAND*2+1) - sx*sx+sy*sy); + VectorMA(norm, d, surfnorms[x+sx+EXPAND + (y+sy+EXPAND)*(SECTTEXSIZE+EXPAND*2)], norm); + } + + VectorNormalize(norm); + d = DotProduct(ldir, norm); + if (d < 0) + d = 0; +// lm[0] = norm[0]*127 + 128; +// lm[1] = norm[1]*127 + 128; +// lm[2] = norm[2]*127 + 128; + lm[3] = d*255; + } +} static void ted_sethole(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) { unsigned int bit; @@ -1362,7 +1715,7 @@ static void ted_sethole(void *ctx, hmsection_t *s, int idx, float wx, float wy, bit = mask; else bit = 0; - s->modified = true; + s->flags |= TSF_DIRTY|TSF_EDITED; s->holes = (s->holes & ~mask) | bit; } static void ted_heighttally(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) @@ -1373,7 +1726,7 @@ static void ted_heighttally(void *ctx, hmsection_t *s, int idx, float wx, float } static void ted_heightsmooth(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) { - s->modified = true; + s->flags |= TSF_DIRTY|TSF_EDITED|TSF_RELIGHT; /*interpolate the terrain towards a certain value*/ if (IS_NAN(s->heights[idx])) @@ -1383,13 +1736,13 @@ static void ted_heightsmooth(void *ctx, hmsection_t *s, int idx, float wx, float } static void ted_heightraise(void *ctx, hmsection_t *s, int idx, float wx, float wy, float strength) { - s->modified = true; + s->flags |= TSF_DIRTY|TSF_EDITED|TSF_RELIGHT; /*raise the terrain*/ s->heights[idx] += strength; } static void ted_heightset(void *ctx, hmsection_t *s, int idx, float wx, float wy, float strength) { - s->modified = true; + s->flags |= TSF_DIRTY|TSF_EDITED|TSF_RELIGHT; /*set the terrain to a specific value*/ s->heights[idx] = *(float*)ctx; } @@ -1482,6 +1835,45 @@ static void ted_mixpaint(void *ctx, hmsection_t *s, int idx, float wx, float wy, } } } + +/* +static void ted_mixlight(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) +{ + unsigned char *lm = ted_getlightmap(s, idx); + vec3_t pos, pos2; + vec3_t norm, tnorm; + vec3_t ldir = {0.4, 0.7, 2}; + float d; + int x,y; + trace_t tr; + VectorClear(norm); + for (y = -4; y < 4; y++) + for (x = -4; x < 4; x++) + { + pos[0] = wx - (CHUNKBIAS + x/64.0) * s->hmmod->sectionsize; + pos[1] = wy - (CHUNKBIAS + y/64.0) * s->hmmod->sectionsize; +#if 0 + pos[2] = 10000; + pos2[0] = wx - (CHUNKBIAS + x/64.0) * s->hmmod->sectionsize; + pos2[1] = wy - (CHUNKBIAS + y/64.0) * s->hmmod->sectionsize; + pos2[2] = -10000; + Heightmap_Trace(cl.worldmodel, 0, 0, NULL, pos, pos2, vec3_origin, vec3_origin, FTECONTENTS_SOLID, &tr); + VectorCopy(tr.plane.normal, tnorm); +#else + Heightmap_Normal(s->hmmod, pos, tnorm); +#endif + d = sqrt(32 - x*x+y*y); + VectorMA(norm, d, tnorm, norm); + } + + VectorNormalize(ldir); + VectorNormalize(norm); + d = DotProduct(ldir, norm); + if (d < 0) + d = 0; + lm[3] = d*255; +} +*/ static void ted_mixset(void *ctx, hmsection_t *s, int idx, float wx, float wy, float w) { unsigned char *lm = ted_getlightmap(s, idx); @@ -1570,13 +1962,16 @@ enum ter_mixpaint, ter_mixconcentrate, ter_mixnoise, - ter_mixblur + ter_mixblur, + ter_water_set, + ter_mesh_add, + ter_mesh_kill }; void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_globals) { world_t *vmw = prinst->parms->user; int action = G_FLOAT(OFS_PARM0); - float *pos = G_VECTOR(OFS_PARM1); + vec3_t pos;// G_VECTOR(OFS_PARM1); float radius = G_FLOAT(OFS_PARM2); float quant = G_FLOAT(OFS_PARM3); // G_FLOAT(OFS_RETURN) = Heightmap_Edit(w->worldmodel, action, pos, radius, quant); @@ -1591,8 +1986,9 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob return; hm = mod->terrain; - pos[0] += hm->sectionsize * CHUNKBIAS; - pos[1] += hm->sectionsize * CHUNKBIAS; + pos[0] = G_FLOAT(OFS_PARM1+0) + hm->sectionsize * CHUNKBIAS; + pos[1] = G_FLOAT(OFS_PARM1+1) + hm->sectionsize * CHUNKBIAS; + pos[2] = G_FLOAT(OFS_PARM1+2); switch(action) { @@ -1600,7 +1996,7 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob Terr_PurgeTerrainModel(mod, false); break; case ter_save: - HeightMap_Save(hm); + Con_Printf("%i sections saved\n", HeightMap_Save(hm)); break; case ter_sethole: { @@ -1638,6 +2034,22 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob tally[0] = 0; ted_itterate(hm, pos, radius, 1, SECTHEIGHTSIZE, ted_heightsmooth, &tally); break; + case ter_water_set: + { + int x, y; + hmsection_t *s; + x = pos[0] / hm->sectionsize; + y = pos[1] / hm->sectionsize; + x = bound(hm->firstsegx, x, hm->maxsegy-1); + y = bound(hm->firstsegy, y, hm->maxsegy-1); + + s = Terr_GetSection(hm, x, y, true); + if (!s) + return; + s->flags |= TSF_HASWATER|TSF_EDITED; + s->waterheight = quant; + } + break; case ter_lower: quant *= -1; case ter_raise: @@ -1690,6 +2102,7 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob s = Terr_GetSection(hm, x, y, true); if (!s) return; + s->flags |= TSF_EDITED; for (t = 0; t < 4; t++) { if (!strcmp(s->texname[t], killtex)) @@ -1732,6 +2145,67 @@ void QCBUILTIN PF_terrain_edit(progfuncs_t *prinst, struct globalvars_s *pr_glob } } break; + case ter_mesh_add: + { + entity_t *e; + float *epos; + int x, y; + hmsection_t *s; + epos = ((wedict_t *)G_EDICT(prinst, OFS_PARM1))->v->origin; + x = (epos[0] / hm->sectionsize) + CHUNKBIAS; + y = (epos[1] / hm->sectionsize) + CHUNKBIAS; + x = bound(hm->firstsegx, x, hm->maxsegy-1); + y = bound(hm->firstsegy, y, hm->maxsegy-1); + + s = Terr_GetSection(hm, x, y, true); + if (!s) + return; + + s->flags |= TSF_EDITED; + + if (s->maxents == s->numents) + { + s->maxents++; + s->ents = realloc(s->ents, sizeof(*s->ents)*(s->maxents)); + } + e = &s->ents[s->numents++]; + + memset(e, 0, sizeof(*e)); + e->scale = ((wedict_t *)G_EDICT(prinst, OFS_PARM1))->xv->scale; + e->shaderRGBAf[0] = 1; + e->shaderRGBAf[1] = 1; + e->shaderRGBAf[2] = 1; + e->shaderRGBAf[3] = 1; + VectorCopy(epos, e->origin); + AngleVectorsFLU(((wedict_t *)G_EDICT(prinst, OFS_PARM1))->v->angles, e->axis[0], e->axis[1], e->axis[2]); + e->model = vmw->Get_CModel(vmw, ((wedict_t *)G_EDICT(prinst, OFS_PARM1))->v->modelindex); + } + break; + case ter_mesh_kill: + { +// int i; +// entity_t *e; + int x, y; +// float r; + hmsection_t *s; + x = pos[0] / hm->sectionsize; + y = pos[1] / hm->sectionsize; + x = bound(hm->firstsegx, x, hm->maxsegy-1); + y = bound(hm->firstsegy, y, hm->maxsegy-1); + + s = Terr_GetSection(hm, x, y, true); + if (!s) + return; + + s->numents = 0; + s->flags |= TSF_EDITED; + + /*for (i = 0; i < s->numents; i++) + { + + }*/ + } + break; } } #else @@ -1760,7 +2234,7 @@ void Terr_ParseEntityLump(char *data, float *scale, int *minx, int *maxx, int *m strcpy(key, com_token); if (!((data=COM_Parse(data)))) break; // error - if (!strcmp("segmentsize", key)) // for HalfLife maps + if (!strcmp("segmentsize", key)) *scale = atof(com_token); else if (!strcmp("minxsegment", key)) *minx = atoi(com_token) + CHUNKBIAS; @@ -1815,9 +2289,9 @@ qboolean Terr_LoadTerrainModel (model_t *mod, void *buffer) hm->firstsegy = CHUNKBIAS - 1; hm->maxsegx = CHUNKBIAS + 1; hm->maxsegy = CHUNKBIAS + 1; - hm->exteriorcontents = FTECONTENTS_SKY|FTECONTENTS_SOLID; //sky outside the map + hm->exteriorcontents = FTECONTENTS_SOLID; //sky outside the map -// Terr_ParseEntityLump(hm, mod->entities); + Terr_ParseEntityLump(mod->entities, &hm->sectionsize, &hm->firstsegx, &hm->maxsegx, &hm->firstsegy, &hm->maxsegy); if (hm->firstsegx < 0) hm->firstsegx = 0; @@ -1828,6 +2302,13 @@ qboolean Terr_LoadTerrainModel (model_t *mod, void *buffer) if (hm->maxsegy > CHUNKLIMIT) hm->maxsegy = CHUNKLIMIT; + mod->mins[0] = (hm->firstsegx - CHUNKBIAS) * hm->sectionsize; + mod->mins[1] = (hm->firstsegy - CHUNKBIAS) * hm->sectionsize; + mod->mins[2] = -999999999999999999999999.f; + mod->maxs[0] = (hm->maxsegy - CHUNKBIAS) * hm->sectionsize; + mod->maxs[1] = (hm->maxsegy - CHUNKBIAS) * hm->sectionsize; + mod->maxs[2] = 999999999999999999999999.f; + #ifndef SERVERONLY if (qrenderer != QR_NONE) { diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 0555e6d6..7d489842 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -406,7 +406,7 @@ void R_SetupGL (void) fov_x = r_refdef.fov_x;//+sin(cl.time)*5; fov_y = r_refdef.fov_y;//-sin(cl.time+1)*5; - if (r_waterwarp.value<0 && r_viewleaf && (r_viewcontents & FTECONTENTS_FLUID)) + if (r_waterwarp.value<0 && (r_viewcontents & FTECONTENTS_FLUID)) { fov_x *= 1 + (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); fov_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); @@ -651,7 +651,14 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, int portaltype) if (r_refdef.recurse) return; - VectorCopy(mesh->normals_array[0], plane.normal); + if (!mesh->normals_array) + { + VectorSet(plane.normal, 0, 0, 1); + } + else + { + VectorCopy(mesh->normals_array[0], plane.normal); + } plane.dist = DotProduct(mesh->xyz_array[0], plane.normal); //if we're too far away from the surface, don't draw anything @@ -1248,7 +1255,7 @@ void GLR_RenderView (void) // SCENE POST PROCESSING // we check if we need to use any shaders - currently it's just waterwarp - if ((r_waterwarp.value>0 && r_viewleaf && (r_viewcontents & FTECONTENTS_WATER))) + if ((r_waterwarp.value>0 && (r_viewcontents & FTECONTENTS_WATER))) { if (scenepp_waterwarp) { diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 240b805e..f33247f3 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -2347,7 +2347,7 @@ static void Sh_DrawStencilLightShadows(dlight_t *dl, qbyte *lvis, qbyte *vvis, q if (!ent->model) continue; - if (cls.allow_anyparticles || ent->visframe) //allowed or static + if (cls.allow_anyparticles) //allowed or static { if (ent->model->engineflags & MDLF_ENGULPHS) { diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index f4c9f8e1..50dabce4 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -224,7 +224,7 @@ texid_tf GL_LoadTexture8Pal24 (char *identifier, int width, int height, qbyte *d texid_tf GL_LoadTexture8Pal32 (char *identifier, int width, int height, qbyte *data, qbyte *palette32, unsigned int flags); texid_tf GL_LoadTexture32 (char *identifier, int width, int height, void *data, unsigned int flags); texid_tf GL_LoadCompressed(char *name); -texid_tf GL_FindTexture (char *identifier); +texid_tf GL_FindTexture (char *identifier, unsigned int flags); texid_tf GL_LoadTextureFB (char *identifier, int width, int height, qbyte *data, unsigned int flags); void GL_Upload8Pal24 (qbyte *data, qbyte *pal, int width, int height, unsigned int flags); diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index bd84123c..ef653f1b 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -1137,12 +1137,12 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "{\n" "vec4 m = texture2D(s_t4, lm);\n" -"gl_FragColor = fog4(\n" +"gl_FragColor = fog4(vec4(m.aaa,1.0)*(\n" "texture2D(s_t0, tc)*m.r\n" "+ texture2D(s_t1, tc)*m.g\n" "+ texture2D(s_t2, tc)*m.b\n" "+ texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b))\n" -");\n" +"));\n" "}\n" "#endif\n" }, diff --git a/engine/shaders/glsl/terrain.glsl b/engine/shaders/glsl/terrain.glsl index 73c5f3aa..031e1e64 100644 --- a/engine/shaders/glsl/terrain.glsl +++ b/engine/shaders/glsl/terrain.glsl @@ -32,11 +32,11 @@ void main (void) { vec4 m = texture2D(s_t4, lm); - gl_FragColor = fog4( + gl_FragColor = fog4(vec4(m.aaa,1.0)*( texture2D(s_t0, tc)*m.r + texture2D(s_t1, tc)*m.g + texture2D(s_t2, tc)*m.b + texture2D(s_t3, tc)*(1.0 - (m.r + m.g + m.b)) - ); + )); } #endif \ No newline at end of file