From 8b03acacbe6c4988a669fb108ae71e917a382e6e Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 24 Jul 2018 13:59:42 +0000 Subject: [PATCH] added env_cubemap support. doesn't currently render its own cubemaps yet. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5277 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_screen.c | 4 +- engine/client/m_options.c | 9 + engine/client/render.h | 3 +- engine/client/skin.c | 4 +- engine/common/cmd.c | 2 +- engine/common/gl_q2bsp.c | 10 +- engine/common/q1bsp.c | 594 ++++++++++++++++++++++++++++++++++++-- engine/d3d/d3d_backend.c | 1 + engine/gl/gl_alias.c | 1 + engine/gl/gl_backend.c | 7 +- engine/gl/gl_model.c | 48 +-- engine/gl/gl_model.h | 15 +- engine/gl/shader.h | 1 + 13 files changed, 649 insertions(+), 50 deletions(-) diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 534350f5b..cec33aef0 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -2641,7 +2641,7 @@ static void SCR_ScreenShot_f (void) Con_Printf (CON_ERROR "Couldn't write %s\n", sysname); } -static void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt) +void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt) { int width, height; void *buf; @@ -2997,7 +2997,7 @@ void SCR_ScreenShot_Cubemap_f(void) return; } - firstside = strcmp(Cmd_Argv(0), "envmap")?0:6; + firstside = (!strcmp(Cmd_Argv(0), "envmap"))?6:0; r_refdef.stereomethod = STEREO_OFF; Q_strncpyz(olddrawviewmodel, r_drawviewmodel.string, sizeof(olddrawviewmodel)); diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 9e1a74b70..30816a4e0 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -1002,6 +1002,15 @@ void FPS_Preset_f (void) return; } + if (!stricmp("hdr", arg)) + { + Cbuf_InsertText( + "set vid_srgb 2\n" + "set r_hdr_irisadaptation 1\n" + , RESTRICT_LOCAL, false); + return; + } + if (!stricmp("tenebrae", arg)) { //for the luls. combine with the tenebrae mod for maximum effect. Cbuf_InsertText( diff --git a/engine/client/render.h b/engine/client/render.h index ce30c69c1..332d601c5 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -517,7 +517,8 @@ typedef struct unsigned char *styles; unsigned char *shifts; } lightmapoverrides_t; -void Mod_LoadLighting (struct model_s *loadmodel, qbyte *mod_base, lump_t *l, qboolean interleaveddeluxe, lightmapoverrides_t *overrides); +typedef struct bspx_header_s bspx_header_t; +void Mod_LoadLighting (struct model_s *loadmodel, bspx_header_t *bspx, qbyte *mod_base, lump_t *l, qboolean interleaveddeluxe, lightmapoverrides_t *overrides); struct mleaf_s *Mod_PointInLeaf (struct model_s *model, float *p); diff --git a/engine/client/skin.c b/engine/client/skin.c index 29b18bb7b..caddf3b16 100644 --- a/engine/client/skin.c +++ b/engine/client/skin.c @@ -387,9 +387,9 @@ qbyte *Skin_Cache8 (qwskin_t *skin) skin->width = 320; skin->height = 200; - skin->skindata = out = BZ_Malloc(320*200); + skin->skindata = out = BZ_Malloc(skin->width*skin->height); - memset (out, bv, 320*200); + memset (out, bv, skin->width*skin->height); skin->loadstate = SKIN_LOADED; diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 173f15a1e..0432a9907 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -2733,7 +2733,7 @@ void Cmd_ExecuteString (const char *text, int level) if (MP_ConsoleCommand(text)) return; //let the csqc handle it if it wants. #endif -#if defined(MENU_NATIVECODE) +#if defined(MENU_NATIVECODE) && !defined(SERVERONLY) if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv)) return; #endif diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 7c896c6b3..26fb8925b 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -2555,12 +2555,12 @@ static qboolean CModQ3_LoadFogs (model_t *mod, qbyte *mod_base, lump_t *l) return true; } -texid_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org) +image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org) { int i; menvmap_t *e; float bestdist = FLT_MAX, dist; - texid_t *ret = NULL; + image_t *ret = NULL; vec3_t move; if (!wmodel || wmodel->loadstate != MLS_LOADED) return NULL; @@ -2974,7 +2974,6 @@ static qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l) out->fog = NULL; else out->fog = mod->fogs + LittleLong(in->fognum); - if (prv->surfaces[LittleLong(in->shadernum)].c.flags & (Q3SURF_NODRAW | Q3SURF_SKIP)) { out->mesh = &mesh[surfnum]; @@ -4017,6 +4016,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole model_t *wmod = mod; char loadname[32]; qbyte *mod_base = (qbyte *)filein; + bspx_header_t *bspx = NULL; #ifdef Q3BSPS extern cvar_t gl_overbright; #endif @@ -4147,7 +4147,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole prv->faces = NULL; - Q1BSPX_Setup(mod, mod_base, filelen, header.lumps, Q3LUMPS_TOTAL); + bspx = BSPX_Setup(mod, mod_base, filelen, header.lumps, Q3LUMPS_TOTAL); //q3 maps have built in 4-fold overbright. //if we're not rendering with that, we need to brighten the lightmaps in order to keep the darker parts the same brightness. we loose the 2 upper bits. those bright areas become uniform and indistinct. @@ -4440,6 +4440,8 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole #endif } + BSPX_LoadEnvmaps(mod, bspx, mod_base); + if (map_autoopenportals.value) memset (prv->portalopen, 1, sizeof(prv->portalopen)); //open them all. Used for progs that havn't got a clue. else diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 78e17e3ee..ad49596b0 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -1362,7 +1362,7 @@ unsigned int Q1BSP_PointContents(model_t *model, vec3_t axis[3], vec3_t point) return contents; } -void Q1BSP_LoadBrushes(model_t *model) +void Q1BSP_LoadBrushes(model_t *model, bspx_header_t *bspx, void *mod_base) { struct { unsigned int ver; @@ -1395,7 +1395,7 @@ void Q1BSP_LoadBrushes(model_t *model) model->engineflags &= ~MDLF_HASBRUSHES; - permodel = Q1BSPX_FindLump("BRUSHLIST", &lumpsizeremaining); + permodel = BSPX_FindLump(bspx, mod_base, "BRUSHLIST", &lumpsizeremaining); if (!permodel) return; @@ -2183,17 +2183,15 @@ typedef struct { int fileofs; // from file start int filelen; } bspx_lump_t; -typedef struct { +struct bspx_header_s { char id[4]; // 'BSPX' int numlumps; bspx_lump_t lumps[1]; -} bspx_header_t; -static char *bspxbase; -static bspx_header_t *bspxheader; +}; //supported lumps: //RGBLIGHTING (.lit) //LIGHTINGDIR (.lux) -void *Q1BSPX_FindLump(char *lumpname, int *lumpsize) +void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize) { int i; *lumpsize = 0; @@ -2205,28 +2203,25 @@ void *Q1BSPX_FindLump(char *lumpname, int *lumpsize) if (!strncmp(bspxheader->lumps[i].lumpname, lumpname, 24)) { *lumpsize = bspxheader->lumps[i].filelen; - return bspxbase + bspxheader->lumps[i].fileofs; + return (char*)mod_base + bspxheader->lumps[i].fileofs; } } return NULL; } -void Q1BSPX_Setup(model_t *mod, char *filebase, unsigned int filelen, lump_t *lumps, int numlumps) +bspx_header_t *BSPX_Setup(model_t *mod, char *filebase, unsigned int filelen, lump_t *lumps, int numlumps) { int i; int offs = 0; bspx_header_t *h; - bspxbase = filebase; - bspxheader = NULL; - for (i = 0; i < numlumps; i++, lumps++) { if (offs < lumps->fileofs + lumps->filelen) offs = lumps->fileofs + lumps->filelen; } offs = (offs + 3) & ~3; - if (offs + sizeof(*bspxheader) > filelen) - return; /*no space for it*/ + if (offs + sizeof(*h) > filelen) + return NULL; /*no space for it*/ h = (bspx_header_t*)(filebase + offs); i = LittleLong(h->numlumps); @@ -2234,15 +2229,580 @@ void Q1BSPX_Setup(model_t *mod, char *filebase, unsigned int filelen, lump_t *lu if (*(int*)h->id != (('B'<<0)|('S'<<8)|('P'<<16)|('X'<<24)) || i < 0 || offs + sizeof(*h) + sizeof(h->lumps[0])*(i-1) > filelen) - return; + return NULL; h->numlumps = i; while(i-->0) { h->lumps[i].fileofs = LittleLong(h->lumps[i].fileofs); h->lumps[i].filelen = LittleLong(h->lumps[i].filelen); if (h->lumps[i].fileofs + h->lumps[i].filelen > filelen) - return; + return NULL; } - bspxheader = h; + return h; } + +/* +void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum uploadfmt *fmt); +void BSPX_RenderEnvmaps(model_t *mod) +{ + int c, i; + + void *buffer; + int stride, cubesize; + uploadfmt_t fmt; + char filename[MAX_QPATH]; + char olddrawviewmodel[64]; //hack, so we can set r_drawviewmodel to 0 so that it doesn't appear in screenshots even if the csqc is generating new data. + vec3_t oldangles; + const struct + { + vec3_t angle; + const char *postfix; + qboolean verticalflip; + qboolean horizontalflip; + } sides[] = + { + {{0, 0, 90}, "_px", true}, + {{0, 180, -90}, "_nx", true}, + {{0, 90, 0}, "_py", true}, //upside down + {{0, 270, 0}, "_ny", false, true}, + {{-90, 0, 90}, "_pz", true}, + {{90, 0, 90}, "_nz", true}, + }; + char base[MAX_QPATH]; + COM_FileBase(cl.worldmodel->name, base, sizeof(base)); + + r_refdef.stereomethod = STEREO_OFF; + Q_strncpyz(olddrawviewmodel, r_drawviewmodel.string, sizeof(olddrawviewmodel)); + Cvar_Set(&r_drawviewmodel, "0"); + + VectorCopy(cl.playerview->viewangles, oldangles); + + for (c = 0; c < mod->numenvmaps; c++) + { + cubesize = mod->envmaps[c].cubesize; + if (cubesize < 1) + cubesize = 32; + + VectorCopy(mod->envmaps[c].origin, r_refdef.vieworg); + + for (i = 0; i < 6; i++) + { + Q_snprintfz(filename, sizeof(filename), "%s/%i_%i_%i%s.tga", base, (int)mod->envmaps[c].origin[0], (int)mod->envmaps[c].origin[1], (int)mod->envmaps[c].origin[2], sides[i].postfix); + + VectorCopy(sides[i].angle, cl.playerview->simangles); + VectorCopy(cl.playerview->simangles, cl.playerview->viewangles); + + buffer = SCR_ScreenShot_Capture(cubesize, cubesize, &stride, &fmt); + if (buffer) + { + char sysname[1024]; + if (sides[i].horizontalflip) + { + int y, x, p; + int pxsize; + char *bad = buffer; + char *in = buffer, *out; + switch(fmt) + { + case TF_RGBA32: + case TF_BGRA32: + case TF_RGBX32: + case TF_BGRX32: + pxsize = 4; + break; + case TF_RGB24: + case TF_BGR24: + pxsize = 3; + break; + case TF_RGBA16F: + pxsize = 8; + break; + case TF_RGBA32F: + pxsize = 16; + break; + default: //erk! + pxsize = 1; + break; + } + buffer = out = BZ_Malloc(cubesize*cubesize*pxsize); + for (y = 0; y < cubesize; y++, in += abs(stride), out += cubesize*pxsize) + { + for (x = 0; x < cubesize*pxsize; x+=pxsize) + { + for (p = 0; p < pxsize; p++) + out[x+p] = in[(cubesize-1)*pxsize-x+p]; + } + } + BZ_Free(bad); + if (stride < 0) + stride = -cubesize*pxsize; + else + stride = cubesize*pxsize; + } + if (sides[i].verticalflip) + stride = -stride; + if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, cubesize, cubesize, fmt)) + { + FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); + Con_Printf ("Wrote %s\n", sysname); + } + else + { + FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); + Con_Printf ("Failed to write %s\n", sysname); + } + BZ_Free(buffer); + } + } + } + Cvar_Set(&r_drawviewmodel, olddrawviewmodel); + + VectorCopy(oldangles, cl.playerview->viewangles); +} +*/ + +void BSPX_LoadEnvmaps(model_t *mod, bspx_header_t *bspx, void *mod_base) +{ + unsigned int *envidx, idx; + int i; + char base[MAX_QPATH]; + char imagename[MAX_QPATH]; + menvmap_t *out; + int count; + denvmap_t *in = BSPX_FindLump(bspx, mod_base, "ENVMAP", &count); + if (count%sizeof(*in)) + return; //erk + count /= sizeof(*in); + if (!count) + return; + out = ZG_Malloc(&mod->memgroup, sizeof(*out)*count); + + mod->envmaps = out; + mod->numenvmaps = count; + + COM_FileBase(mod->name, base, sizeof(base)); + for (i = 0; i < count; i++) + { + out[i].origin[0] = LittleFloat(in[i].origin[0]); + out[i].origin[1] = LittleFloat(in[i].origin[1]); + out[i].origin[2] = LittleFloat(in[i].origin[2]); + out[i].cubesize = LittleLong(in[i].cubesize); + + Q_snprintfz(imagename, sizeof(imagename), "%s/%i_%i_%i", base, (int)mod->envmaps[i].origin[0], (int)mod->envmaps[i].origin[1], (int)mod->envmaps[i].origin[2]); + out[i].image = Image_GetTexture(imagename, NULL, IF_CUBEMAP|IF_NOREPLACE, NULL, NULL, out[i].cubesize, out[i].cubesize, PTI_INVALID); + } + + + + //now update surface lists. + envidx = BSPX_FindLump(bspx, mod_base, "SURFENVMAP", &i); + if (i/sizeof(*envidx) == mod->numsurfaces) + { + for (i = 0; i < mod->numsurfaces; i++) + { + idx = LittleLong(envidx[i]); + if (idx < (unsigned int)count) + mod->surfaces[i].envmap = out[idx].image; + } + } +} + + +#if 1//ndef SERVERONLY + +struct bspxrw +{ + fromgame_t fg; + const char *fname; + char *origfile; + qofs_t origsize; + int lumpofs; + + size_t corelumps; + size_t totallumps; + + struct + { + char lumpname[24]; // up to 23 chars, zero-padded + void *data; // from file start + qofs_t filelen; + } *lumps; +}; +void Mod_BSPXRW_Free(struct bspxrw *ctx) +{ + FS_FreeFile(ctx->origfile); + Z_Free(ctx->lumps); + ctx->corelumps = ctx->totallumps = 0; + ctx->origfile = NULL; +} +void Mod_BSPXRW_Write(struct bspxrw *ctx) +{ +#if 1 + vfsfile_t *f = FS_OpenVFS(ctx->fname, "wb", FS_GAMEONLY); + if (f) + { + qofs_t bspxofs; + size_t i, j; + int pad, paddata = 0; + int nxlumps = ctx->totallumps-ctx->corelumps; + lump_t *lumps = alloca(sizeof(*lumps)*ctx->corelumps); + bspx_lump_t *xlumps = alloca(sizeof(*xlumps)*(ctx->totallumps-ctx->corelumps)); + //bsp header info + VFS_WRITE(f, ctx->origfile, ctx->lumpofs); + VFS_WRITE(f, lumps, sizeof(lumps[0])*ctx->corelumps); //placeholder + //orig lumps + for (i = 0; i < ctx->corelumps; i++) + { + lumps[i].fileofs = VFS_TELL(f); + lumps[i].filelen = ctx->lumps[i].filelen; + + VFS_WRITE(f, ctx->lumps[i].data, ctx->lumps[i].filelen); + //ALL lumps must be 4-aligned, so pad if needed. + pad = ((ctx->lumps[i].filelen+3)&~3)-ctx->lumps[i].filelen; + VFS_WRITE(f, &paddata, pad); + } + //bspx header + VFS_WRITE(f, "BSPX", 4); + VFS_WRITE(f, &nxlumps, sizeof(nxlumps)); + bspxofs = VFS_TELL(f); + VFS_WRITE(f, xlumps, sizeof(xlumps[0])*(ctx->totallumps-ctx->corelumps)); //placeholder + //bspx data + for (i = 0; i < nxlumps; i++) + { + j = ctx->corelumps+i; + xlumps[i].fileofs = VFS_TELL(f); + xlumps[i].filelen = ctx->lumps[j].filelen; + memcpy(xlumps[i].lumpname, ctx->lumps[j].lumpname, sizeof(xlumps[i].lumpname)); + + VFS_WRITE(f, ctx->lumps[j].data, ctx->lumps[j].filelen); + //ALL lumps must be 4-aligned, so pad if needed. + pad = ((ctx->lumps[j].filelen+3)&~3)-ctx->lumps[j].filelen; + VFS_WRITE(f, &paddata, pad); + } + + //now rewrite both sets of offsets. + VFS_SEEK(f, ctx->lumpofs); + VFS_WRITE(f, lumps, sizeof(lumps[0])*ctx->corelumps); + VFS_SEEK(f, bspxofs); + VFS_WRITE(f, xlumps, sizeof(xlumps[0])*(ctx->totallumps-ctx->corelumps)); + + VFS_CLOSE(f); + } +#endif + Mod_BSPXRW_Free(ctx); +} + +void Mod_BSPXRW_SetLump(struct bspxrw *ctx, const char *lumpname, void *data, size_t datasize) +{ + int i; + for (i = 0; i < ctx->totallumps; i++) + { + if (!strcmp(ctx->lumps[i].lumpname, lumpname)) + { //replace the existing lump + ctx->lumps[i].data = data; + ctx->lumps[i].filelen = datasize; + return; + } + } + + Z_ReallocElements(&ctx->lumps, &ctx->totallumps, ctx->totallumps+1, sizeof(*ctx->lumps)); + Q_strncpyz(ctx->lumps[i].lumpname, lumpname, sizeof(ctx->lumps[i].lumpname)); + ctx->lumps[i].data = data; + ctx->lumps[i].filelen = datasize; +} + +qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname) +{ + int i; + lump_t *l; + const char **corelumpnames = NULL; + bspx_header_t *bspxheader; +#ifdef Q3BSPS + static const char *q3corelumpnames[Q3LUMPS_TOTAL] = {"entities","shaders","planes","nodes","leafs","leafsurfs","leafbrushes","submodels","brushes","brushsides","verts","indexes","fogs","surfaces","lightmaps","lightgrid","visibility" + #ifdef RFBSPS + ,"lightgrididx" + #endif + }; +#endif + ctx->fname = fname; + ctx->origfile = FS_MallocFile(ctx->fname, FS_GAME, &ctx->origsize); + if (!ctx->origfile) + return false; + ctx->lumps = 0; + ctx->totallumps = 0; + + i = LittleLong(*(int*)ctx->origfile); + switch(i) + { + case 29: + case 30: + ctx->fg = ((i==30)?fg_halflife:fg_quake); + ctx->lumpofs = 4; + ctx->corelumps = 0; + break; + case IDBSPHEADER: + i = LittleLong(*(int*)(ctx->origfile+4)); + ctx->lumpofs = 8; + switch(i) + { +#ifdef Q2BSPS + case BSPVERSION_Q2: +// case BSPVERSION_Q2W: + ctx->fg = fg_quake2; + ctx->corelumps = Q2HEADER_LUMPS; + break; +#endif +#ifdef Q3BSPS + case BSPVERSION_Q3: + case BSPVERSION_RTCW: + ctx->fg = fg_quake3; + ctx->corelumps = 17; + corelumpnames = q3corelumpnames; + break; +#endif + default: + Mod_BSPXRW_Free(ctx); + return false; + } + break; +#ifdef RFBSPS + case ('R'<<0)+('B'<<8)+('S'<<16)+('P'<<24): + case ('F'<<0)+('B'<<8)+('S'<<16)+('P'<<24): + i = LittleLong(*(int*)(ctx->origfile+4)); + ctx->lumpofs = 8; + switch(i) + { + case BSPVERSION_RBSP: + ctx->fg = fg_quake3; + ctx->corelumps = 18; + corelumpnames = q3corelumpnames; + break; + default: + Mod_BSPXRW_Free(ctx); + return false; + } + break; +#endif + default: + Mod_BSPXRW_Free(ctx); + return false; + } + + l = (lump_t*)(ctx->origfile+ctx->lumpofs); + for (i = 0; i < ctx->corelumps; i++) + { + Z_ReallocElements(&ctx->lumps, &ctx->totallumps, ctx->totallumps+1, sizeof(*ctx->lumps)); + ctx->lumps[ctx->totallumps-1].data = ctx->origfile+l[i].fileofs; + ctx->lumps[ctx->totallumps-1].filelen = l[i].filelen; + if (corelumpnames) + Q_snprintfz(ctx->lumps[ctx->totallumps-1].lumpname, sizeof(ctx->lumps[0].lumpname), "%s", corelumpnames[i]); + else + Q_snprintfz(ctx->lumps[ctx->totallumps-1].lumpname, sizeof(ctx->lumps[0].lumpname), "lump%u", i); + } + + bspxheader = BSPX_Setup(NULL, ctx->origfile, ctx->origsize, l, ctx->corelumps); + if (bspxheader) + { + for (i = 0; i < bspxheader->numlumps; i++) + { + Z_ReallocElements(&ctx->lumps, &ctx->totallumps, ctx->totallumps+1, sizeof(*ctx->lumps)); + ctx->lumps[ctx->totallumps-1].data = ctx->origfile+bspxheader->lumps[i].fileofs; + ctx->lumps[ctx->totallumps-1].filelen = bspxheader->lumps[i].filelen; + memcpy(ctx->lumps[ctx->totallumps-1].lumpname, bspxheader->lumps[i].lumpname, sizeof(ctx->lumps[0].lumpname)); + } + } + return true; +} + +unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t nenvmap) +{ //this is slow, yes. + size_t n, v; + unsigned int best = ~0; + float bestdist = FLT_MAX, dist; + vec3_t diff, mid; + + if (surf->mesh) + { + VectorClear(mid); + for (v = 0; v < surf->mesh->numvertexes; v++) + VectorAdd(mid, surf->mesh->xyz_array[v], mid); + VectorScale(mid, 1.0/surf->mesh->numvertexes, mid); + + for (n = 0; n < nenvmap; n++) + { + VectorSubtract(mid, envmap[n].origin, diff); + dist = DotProduct(diff,diff); + if (bestdist > dist) + { + best = n; + bestdist = dist; + } + } + } + return best; +} + +int QDECL envmapsort(const void *av, const void *bv) +{ //sorts cubemaps in order of size, to make texturearrays easier, if ever. The loader can then just make runs. + const denvmap_t *a=av, *b=bv; + if (a->cubesize == b->cubesize) + return 0; + if (a->cubesize > b->cubesize) + return 1; + return -1; +} +void Mod_FindCubemaps_f(void) +{ + struct bspxrw bspctx; + if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name)) + { + const char *entlump = Mod_GetEntitiesString(cl.worldmodel), *lmp; + int nest; + char key[1024]; + char value[1024]; + + qboolean isenvmap; + float size; + vec3_t origin; + + denvmap_t *envmap = NULL; //*nenvmap + size_t nenvmap = 0; + unsigned int *envmapidx = NULL; //*numsurfaces + size_t nenvmapidx = 0, i; + + //find targetnames, and store their origins so that we can deal with spotlights. + for (lmp = entlump; ;) + { + lmp = COM_Parse(lmp); + if (com_token[0] != '{') + break; + + isenvmap = false; + size = 128; + VectorClear(origin); + + nest = 1; + while (1) + { + lmp = COM_ParseOut(lmp, key, sizeof(key)); + if (!lmp) + break; // error + if (key[0] == '{') + { + nest++; + continue; + } + if (key[0] == '}') + { + nest--; + if (!nest) + break; // end of entity + continue; + } + if (nest!=1) + continue; + if (key[0] == '_') + memmove(key, key+1, strlen(key)); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + lmp = COM_ParseOut(lmp, value, sizeof(value)); + if (!lmp) + break; // error + + // now that we have the key pair worked out... + if (!strcmp("classname", key) && !strcmp(value, "env_cubemap")) + isenvmap = true; + else if (!strcmp("origin", key)) + sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]); + else if (!strcmp("size", key)) + sscanf(value, "%f", &size); + } + + if (isenvmap) + { + int e = nenvmap; + if (ZF_ReallocElements(&envmap, &nenvmap, nenvmap+1, sizeof(*envmap))) + { + VectorCopy(origin, envmap[e].origin); + envmap[e].cubesize = size; + } + } + } + + if (nenvmap) + { + qsort(envmap, nenvmap, sizeof(*envmap), envmapsort); + if (ZF_ReallocElements(&envmapidx, &nenvmapidx, cl.worldmodel->numsurfaces, sizeof(*envmapidx))) + { + for(i = 0; i < cl.worldmodel->numsurfaces; i++) + envmapidx[i] = Mod_NearestCubeForSurf(cl.worldmodel->surfaces+i, envmap, nenvmap); + } + + Mod_BSPXRW_SetLump(&bspctx, "ENVMAP", envmap, nenvmap*sizeof(*envmap)); + Mod_BSPXRW_SetLump(&bspctx, "SURFENVMAP", envmapidx, cl.worldmodel->numsurfaces*sizeof(*envmapidx)); + Mod_BSPXRW_Write(&bspctx); + } + else + { + Con_Printf("No cubemaps found on map\n"); + Mod_BSPXRW_Free(&bspctx); + } + + Z_Free(envmapidx); + Z_Free(envmap); + } +} +void Mod_Realign_f(void) +{ + struct bspxrw bspctx; + if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name)) + Mod_BSPXRW_Write(&bspctx); +} +void Mod_BSPX_List_f(void) +{ + int i; + struct bspxrw ctx; + char *fname = Cmd_Argv(1); + if (!*fname && cl.worldmodel) + fname = cl.worldmodel->name; + if (Mod_BSPXRW_Read(&ctx, fname)) + { + for (i = 0; i < ctx.corelumps; i++) + { + Con_Printf("%s: %u\n", ctx.lumps[i].lumpname, ctx.lumps[i].filelen); + } + for ( ; i < ctx.totallumps; i++) + { + Con_Printf("%s: %u\n", ctx.lumps[i].lumpname, ctx.lumps[i].filelen); + } + Mod_BSPXRW_Free(&ctx); + } +} +void Mod_BSPX_Strip_f(void) +{ + int i; + struct bspxrw ctx; + qboolean found = false; + if (Cmd_Argc() != 3) + Con_Printf("%s FILENAME NAME: removes an extended lump from the named bsp file\n", Cmd_Argv(0)); + else if (Mod_BSPXRW_Read(&ctx, Cmd_Argv(1))) + { + for (i = ctx.corelumps; i < ctx.totallumps;) + { + if (!Q_strcasecmp(ctx.lumps[i].lumpname, Cmd_Argv(2))) + { + found = true; + memmove(&ctx.lumps[i], &ctx.lumps[i+1], sizeof(ctx.lumps[0])*(ctx.totallumps-(i+1))); + ctx.totallumps--; + } + else + i++; + } + if (found) + Mod_BSPXRW_Write(&ctx); + else + Mod_BSPXRW_Free(&ctx); + } +} +#endif \ No newline at end of file diff --git a/engine/d3d/d3d_backend.c b/engine/d3d/d3d_backend.c index 6f505bc26..5da6d555b 100644 --- a/engine/d3d/d3d_backend.c +++ b/engine/d3d/d3d_backend.c @@ -2060,6 +2060,7 @@ static void BE_ApplyUniforms(program_t *prog, int permu) case SP_LIGHTCUBEMATRIX: case SP_LIGHTSHADOWMAPPROJ: case SP_LIGHTSHADOWMAPSCALE: + case SP_LIGHTDIRECTION: case SP_RENDERTEXTURESCALE: diff --git a/engine/gl/gl_alias.c b/engine/gl/gl_alias.c index ba301014d..3cc021adb 100644 --- a/engine/gl/gl_alias.c +++ b/engine/gl/gl_alias.c @@ -1738,6 +1738,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches) b->buildmeshes = R_GAlias_DrawBatch; b->ent = e; + b->envmap = Mod_CubemapForOrigin(cl.worldmodel, e->origin); #if defined(Q3BSPS) || defined(RFBSPS) b->fog = Mod_FogForOrigin(cl.worldmodel, e->origin); #endif diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 83330818d..09683bb32 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1256,7 +1256,12 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass) t = shaderstate.curtexnums->fullbright; break; case T_GEN_REFLECTCUBE: - t = (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->reflectcube))?shaderstate.curtexnums->reflectcube:shaderstate.tex_reflectcube; + if (shaderstate.curtexnums && TEXLOADED(shaderstate.curtexnums->reflectcube)) + t = shaderstate.curtexnums->reflectcube; + else if (shaderstate.curbatch->envmap) + t = shaderstate.curbatch->envmap; + else + t = shaderstate.tex_reflectcube; GL_LazyBind(tmu, GL_TEXTURE_CUBE_MAP_ARB, t); return; case T_GEN_REFLECTMASK: diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index d1640c0eb..698116894 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -736,6 +736,11 @@ void Mod_Purge(enum mod_purge_e ptype) } } +void Mod_FindCubemaps_f(void); +void Mod_Realign_f(void); +void Mod_BSPX_List_f(void); +void Mod_BSPX_Strip_f(void); + /* =============== Mod_Init @@ -771,6 +776,11 @@ void Mod_Init (qboolean initial) Cvar_Register(&temp_lit2support, NULL); Cmd_AddCommand("sv_saveentfile", Mod_SaveEntFile_f); Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f); + + Cmd_AddCommandD("map_findcubemaps", Mod_FindCubemaps_f, "Scans the entities of a map to find reflection envmap sites and determines the nearest one to each surface."); + Cmd_AddCommandD("map_realign", Mod_Realign_f, "Reads the named bsp and writes it back out with only alignment changes."); + Cmd_AddCommandD("map_bspx_list", Mod_BSPX_List_f, "Lists all lumps (and their sizes) in the specified bsp."); + Cmd_AddCommandD("map_bspx_strip", Mod_BSPX_Strip_f, "Strips a named extension lump from a bsp file."); } if (initial) @@ -1677,7 +1687,7 @@ typedef struct Mod_LoadLighting ================= */ -void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean interleaveddeluxe, lightmapoverrides_t *overrides) +void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, lump_t *l, qboolean interleaveddeluxe, lightmapoverrides_t *overrides) { qboolean luxtmp = true; qboolean exptmp = true; @@ -1718,11 +1728,11 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean samples >>= 1; if (!samples) { - expdata = Q1BSPX_FindLump("LIGHTING_E5BGR9", &samples); //expressed as a big-endian packed int - 0xEBGR type thing, except misaligned and 32bit. + expdata = BSPX_FindLump(bspx, mod_base, "LIGHTING_E5BGR9", &samples); //expressed as a big-endian packed int - 0xEBGR type thing, except misaligned and 32bit. samples /= 4; if (!samples) { - litdata = Q1BSPX_FindLump("RGBLIGHTING", &samples); //RGB packed data + litdata = BSPX_FindLump(bspx, mod_base, "RGBLIGHTING", &samples); //RGB packed data samples /= 3; if (!samples) return; @@ -1853,13 +1863,13 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean { int size; /*FIXME: bspx support for extents+lmscale, may require style+offset lumps too, not sure what to do here*/ - expdata = Q1BSPX_FindLump("LIGHTING_E5BGR9", &size); + expdata = BSPX_FindLump(bspx, mod_base, "LIGHTING_E5BGR9", &size); exptmp = true; if (size != samples*4) { expdata = NULL; - litdata = Q1BSPX_FindLump("RGBLIGHTING", &size); + litdata = BSPX_FindLump(bspx, mod_base, "RGBLIGHTING", &size); littmp = true; if (size != samples*3) litdata = NULL; @@ -1944,7 +1954,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean if (!luxdata) { int size; - luxdata = Q1BSPX_FindLump("LIGHTINGDIR", &size); + luxdata = BSPX_FindLump(bspx, mod_base, "LIGHTINGDIR", &size); if (size != samples*3) luxdata = NULL; luxtmp = true; @@ -2024,7 +2034,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean if (overrides && !overrides->shifts) { int size; - overrides->shifts = Q1BSPX_FindLump("LMSHIFT", &size); + overrides->shifts = BSPX_FindLump(bspx, mod_base, "LMSHIFT", &size); if (size != loadmodel->numsurfaces) overrides->shifts = NULL; @@ -2032,14 +2042,14 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean if (!overrides->offsets) { int size; - overrides->offsets = Q1BSPX_FindLump("LMOFFSET", &size); + overrides->offsets = BSPX_FindLump(bspx, mod_base, "LMOFFSET", &size); if (size != loadmodel->numsurfaces * sizeof(int)) overrides->offsets = NULL; } if (!overrides->styles) { int size; - overrides->styles = Q1BSPX_FindLump("LMSTYLE", &size); + overrides->styles = BSPX_FindLump(bspx, mod_base, "LMSTYLE", &size); if (size != loadmodel->numsurfaces * sizeof(qbyte)*MAXQ1LIGHTMAPS) overrides->styles = NULL; } @@ -2305,7 +2315,7 @@ qboolean Mod_LoadVertexes (model_t *loadmodel, qbyte *mod_base, lump_t *l) return true; } -qboolean Mod_LoadVertexNormals (model_t *loadmodel, qbyte *mod_base, lump_t *l) +qboolean Mod_LoadVertexNormals (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, lump_t *l) { float *in; float *out; @@ -2323,7 +2333,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, qbyte *mod_base, lump_t *l) } else { - in = Q1BSPX_FindLump("VERTEXNORMALS", &count); + in = BSPX_FindLump(bspx, mod_base, "VERTEXNORMALS", &count); if (in) count /= sizeof(vec3_t); else @@ -3765,7 +3775,7 @@ void CalcSurfaceExtents (model_t *mod, msurface_t *s); Mod_LoadFaces ================= */ -static qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, lump_t *lightlump, qboolean lm) +static qboolean Mod_LoadFaces (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base, lump_t *l, lump_t *lightlump, qboolean lm) { dsface_t *ins; dlface_t *inl; @@ -3820,7 +3830,7 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, qbyte *mod_base, lump_t *l, l loadmodel->surfaces = out; loadmodel->numsurfaces = count; - Mod_LoadLighting (loadmodel, mod_base, lightlump, false, &overrides); + Mod_LoadLighting (loadmodel, bspx, mod_base, lightlump, false, &overrides); switch(loadmodel->lightmaps.fmt) { @@ -5075,6 +5085,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi qboolean isnotmap; qboolean using_rbe = true; qboolean misaligned = false; + bspx_header_t *bspx; COM_FileBase (mod->name, loadname, sizeof(loadname)); mod->type = mod_brush; @@ -5176,12 +5187,13 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi ofs += header.lumps[i].filelen; } BZ_Free(tmp); + bspx = NULL; } else { - Q1BSPX_Setup(mod, mod_base, fsize, header.lumps, HEADER_LUMPS); + bspx = BSPX_Setup(mod, mod_base, fsize, header.lumps, HEADER_LUMPS); - if (1)//mod_ebfs.value) + /*if (1)//mod_ebfs.value) { char *id; id = (char *)mod_base + sizeof(dheader_t); @@ -5189,7 +5201,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi { //EBFS detected. COM_LoadMapPackFile(mod->name, sizeof(dheader_t)); } - } + }*/ } noerrors = true; @@ -5229,7 +5241,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi TRACE(("Loading Texinfo\n")); noerrors = noerrors && Mod_LoadTexinfo (mod, mod_base, &header.lumps[LUMP_TEXINFO]); TRACE(("Loading Faces\n")); - noerrors = noerrors && Mod_LoadFaces (mod, mod_base, &header.lumps[LUMP_FACES], &header.lumps[LUMP_LIGHTING], longm); + noerrors = noerrors && Mod_LoadFaces (mod, bspx, mod_base, &header.lumps[LUMP_FACES], &header.lumps[LUMP_LIGHTING], longm); } if (!isDedicated) { @@ -5270,7 +5282,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi } TRACE(("LoadBrushModel %i\n", __LINE__)); - Q1BSP_LoadBrushes(mod); + Q1BSP_LoadBrushes(mod, bspx, mod_base); TRACE(("LoadBrushModel %i\n", __LINE__)); Q1BSP_SetModelFuncs(mod); TRACE(("LoadBrushModel %i\n", __LINE__)); diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index ab5332641..0b2bbd7b4 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -391,12 +391,17 @@ typedef struct mfog_s mplane_t **planes; } mfog_t; +typedef struct +{ + vec3_t origin; + int cubesize; //pixels +} denvmap_t; typedef struct { vec3_t origin; int cubesize; //pixels - texid_t *image; + texid_t image; } menvmap_t; #define LMSHIFT_DEFAULT 4 @@ -537,10 +542,12 @@ typedef struct hull_s void Q1BSP_CheckHullNodes(hull_t *hull); void Q1BSP_SetModelFuncs(struct model_s *mod); -void Q1BSP_LoadBrushes(struct model_s *model); +void Q1BSP_LoadBrushes(struct model_s *model, bspx_header_t *bspx, void *mod_base); void Q1BSP_Init(void); -void *Q1BSPX_FindLump(char *lumpname, int *lumpsize); -void Q1BSPX_Setup(struct model_s *mod, char *filebase, unsigned int filelen, lump_t *lumps, int numlumps); + +void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base); +void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize); +bspx_header_t *BSPX_Setup(struct model_s *mod, char *filebase, unsigned int filelen, lump_t *lumps, int numlumps); typedef struct fragmentdecal_s fragmentdecal_t; void Fragment_ClipPoly(fragmentdecal_t *dec, int numverts, float *inverts, shader_t *surfshader); diff --git a/engine/gl/shader.h b/engine/gl/shader.h index 37fba4941..6562e16a8 100644 --- a/engine/gl/shader.h +++ b/engine/gl/shader.h @@ -719,6 +719,7 @@ program_t *Shader_FindGeneric(char *name, int qrtype); const char *Shader_NameForGeneric(program_t *prog); void Shader_ReleaseGeneric(program_t *prog); +image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org); mfog_t *Mod_FogForOrigin(model_t *wmodel, vec3_t org); #define BEF_FORCEDEPTHWRITE 1