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
This commit is contained in:
Spoike 2018-07-24 13:59:42 +00:00
parent bb68e5c5cd
commit 8b03acacbe
13 changed files with 649 additions and 50 deletions

View file

@ -2641,7 +2641,7 @@ static void SCR_ScreenShot_f (void)
Con_Printf (CON_ERROR "Couldn't write %s\n", sysname); 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; int width, height;
void *buf; void *buf;
@ -2997,7 +2997,7 @@ void SCR_ScreenShot_Cubemap_f(void)
return; return;
} }
firstside = strcmp(Cmd_Argv(0), "envmap")?0:6; firstside = (!strcmp(Cmd_Argv(0), "envmap"))?6:0;
r_refdef.stereomethod = STEREO_OFF; r_refdef.stereomethod = STEREO_OFF;
Q_strncpyz(olddrawviewmodel, r_drawviewmodel.string, sizeof(olddrawviewmodel)); Q_strncpyz(olddrawviewmodel, r_drawviewmodel.string, sizeof(olddrawviewmodel));

View file

@ -1002,6 +1002,15 @@ void FPS_Preset_f (void)
return; 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)) if (!stricmp("tenebrae", arg))
{ //for the luls. combine with the tenebrae mod for maximum effect. { //for the luls. combine with the tenebrae mod for maximum effect.
Cbuf_InsertText( Cbuf_InsertText(

View file

@ -517,7 +517,8 @@ typedef struct
unsigned char *styles; unsigned char *styles;
unsigned char *shifts; unsigned char *shifts;
} lightmapoverrides_t; } 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); struct mleaf_s *Mod_PointInLeaf (struct model_s *model, float *p);

View file

@ -387,9 +387,9 @@ qbyte *Skin_Cache8 (qwskin_t *skin)
skin->width = 320; skin->width = 320;
skin->height = 200; 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; skin->loadstate = SKIN_LOADED;

View file

@ -2733,7 +2733,7 @@ void Cmd_ExecuteString (const char *text, int level)
if (MP_ConsoleCommand(text)) if (MP_ConsoleCommand(text))
return; //let the csqc handle it if it wants. return; //let the csqc handle it if it wants.
#endif #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)) if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv))
return; return;
#endif #endif

View file

@ -2555,12 +2555,12 @@ static qboolean CModQ3_LoadFogs (model_t *mod, qbyte *mod_base, lump_t *l)
return true; return true;
} }
texid_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org) image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org)
{ {
int i; int i;
menvmap_t *e; menvmap_t *e;
float bestdist = FLT_MAX, dist; float bestdist = FLT_MAX, dist;
texid_t *ret = NULL; image_t *ret = NULL;
vec3_t move; vec3_t move;
if (!wmodel || wmodel->loadstate != MLS_LOADED) if (!wmodel || wmodel->loadstate != MLS_LOADED)
return NULL; return NULL;
@ -2974,7 +2974,6 @@ static qboolean CModQ3_LoadRFaces (model_t *mod, qbyte *mod_base, lump_t *l)
out->fog = NULL; out->fog = NULL;
else else
out->fog = mod->fogs + LittleLong(in->fognum); out->fog = mod->fogs + LittleLong(in->fognum);
if (prv->surfaces[LittleLong(in->shadernum)].c.flags & (Q3SURF_NODRAW | Q3SURF_SKIP)) if (prv->surfaces[LittleLong(in->shadernum)].c.flags & (Q3SURF_NODRAW | Q3SURF_SKIP))
{ {
out->mesh = &mesh[surfnum]; 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; model_t *wmod = mod;
char loadname[32]; char loadname[32];
qbyte *mod_base = (qbyte *)filein; qbyte *mod_base = (qbyte *)filein;
bspx_header_t *bspx = NULL;
#ifdef Q3BSPS #ifdef Q3BSPS
extern cvar_t gl_overbright; extern cvar_t gl_overbright;
#endif #endif
@ -4147,7 +4147,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole
prv->faces = NULL; 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. //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. //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 #endif
} }
BSPX_LoadEnvmaps(mod, bspx, mod_base);
if (map_autoopenportals.value) if (map_autoopenportals.value)
memset (prv->portalopen, 1, sizeof(prv->portalopen)); //open them all. Used for progs that havn't got a clue. memset (prv->portalopen, 1, sizeof(prv->portalopen)); //open them all. Used for progs that havn't got a clue.
else else

View file

@ -1362,7 +1362,7 @@ unsigned int Q1BSP_PointContents(model_t *model, vec3_t axis[3], vec3_t point)
return contents; return contents;
} }
void Q1BSP_LoadBrushes(model_t *model) void Q1BSP_LoadBrushes(model_t *model, bspx_header_t *bspx, void *mod_base)
{ {
struct { struct {
unsigned int ver; unsigned int ver;
@ -1395,7 +1395,7 @@ void Q1BSP_LoadBrushes(model_t *model)
model->engineflags &= ~MDLF_HASBRUSHES; model->engineflags &= ~MDLF_HASBRUSHES;
permodel = Q1BSPX_FindLump("BRUSHLIST", &lumpsizeremaining); permodel = BSPX_FindLump(bspx, mod_base, "BRUSHLIST", &lumpsizeremaining);
if (!permodel) if (!permodel)
return; return;
@ -2183,17 +2183,15 @@ typedef struct {
int fileofs; // from file start int fileofs; // from file start
int filelen; int filelen;
} bspx_lump_t; } bspx_lump_t;
typedef struct { struct bspx_header_s {
char id[4]; // 'BSPX' char id[4]; // 'BSPX'
int numlumps; int numlumps;
bspx_lump_t lumps[1]; bspx_lump_t lumps[1];
} bspx_header_t; };
static char *bspxbase;
static bspx_header_t *bspxheader;
//supported lumps: //supported lumps:
//RGBLIGHTING (.lit) //RGBLIGHTING (.lit)
//LIGHTINGDIR (.lux) //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; int i;
*lumpsize = 0; *lumpsize = 0;
@ -2205,28 +2203,25 @@ void *Q1BSPX_FindLump(char *lumpname, int *lumpsize)
if (!strncmp(bspxheader->lumps[i].lumpname, lumpname, 24)) if (!strncmp(bspxheader->lumps[i].lumpname, lumpname, 24))
{ {
*lumpsize = bspxheader->lumps[i].filelen; *lumpsize = bspxheader->lumps[i].filelen;
return bspxbase + bspxheader->lumps[i].fileofs; return (char*)mod_base + bspxheader->lumps[i].fileofs;
} }
} }
return NULL; 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 i;
int offs = 0; int offs = 0;
bspx_header_t *h; bspx_header_t *h;
bspxbase = filebase;
bspxheader = NULL;
for (i = 0; i < numlumps; i++, lumps++) for (i = 0; i < numlumps; i++, lumps++)
{ {
if (offs < lumps->fileofs + lumps->filelen) if (offs < lumps->fileofs + lumps->filelen)
offs = lumps->fileofs + lumps->filelen; offs = lumps->fileofs + lumps->filelen;
} }
offs = (offs + 3) & ~3; offs = (offs + 3) & ~3;
if (offs + sizeof(*bspxheader) > filelen) if (offs + sizeof(*h) > filelen)
return; /*no space for it*/ return NULL; /*no space for it*/
h = (bspx_header_t*)(filebase + offs); h = (bspx_header_t*)(filebase + offs);
i = LittleLong(h->numlumps); 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)) || if (*(int*)h->id != (('B'<<0)|('S'<<8)|('P'<<16)|('X'<<24)) ||
i < 0 || i < 0 ||
offs + sizeof(*h) + sizeof(h->lumps[0])*(i-1) > filelen) offs + sizeof(*h) + sizeof(h->lumps[0])*(i-1) > filelen)
return; return NULL;
h->numlumps = i; h->numlumps = i;
while(i-->0) while(i-->0)
{ {
h->lumps[i].fileofs = LittleLong(h->lumps[i].fileofs); h->lumps[i].fileofs = LittleLong(h->lumps[i].fileofs);
h->lumps[i].filelen = LittleLong(h->lumps[i].filelen); h->lumps[i].filelen = LittleLong(h->lumps[i].filelen);
if (h->lumps[i].fileofs + h->lumps[i].filelen > 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

View file

@ -2060,6 +2060,7 @@ static void BE_ApplyUniforms(program_t *prog, int permu)
case SP_LIGHTCUBEMATRIX: case SP_LIGHTCUBEMATRIX:
case SP_LIGHTSHADOWMAPPROJ: case SP_LIGHTSHADOWMAPPROJ:
case SP_LIGHTSHADOWMAPSCALE: case SP_LIGHTSHADOWMAPSCALE:
case SP_LIGHTDIRECTION:
case SP_RENDERTEXTURESCALE: case SP_RENDERTEXTURESCALE:

View file

@ -1738,6 +1738,7 @@ void R_GAlias_GenerateBatches(entity_t *e, batch_t **batches)
b->buildmeshes = R_GAlias_DrawBatch; b->buildmeshes = R_GAlias_DrawBatch;
b->ent = e; b->ent = e;
b->envmap = Mod_CubemapForOrigin(cl.worldmodel, e->origin);
#if defined(Q3BSPS) || defined(RFBSPS) #if defined(Q3BSPS) || defined(RFBSPS)
b->fog = Mod_FogForOrigin(cl.worldmodel, e->origin); b->fog = Mod_FogForOrigin(cl.worldmodel, e->origin);
#endif #endif

View file

@ -1256,7 +1256,12 @@ static void Shader_BindTextureForPass(int tmu, const shaderpass_t *pass)
t = shaderstate.curtexnums->fullbright; t = shaderstate.curtexnums->fullbright;
break; break;
case T_GEN_REFLECTCUBE: 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); GL_LazyBind(tmu, GL_TEXTURE_CUBE_MAP_ARB, t);
return; return;
case T_GEN_REFLECTMASK: case T_GEN_REFLECTMASK:

View file

@ -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 Mod_Init
@ -771,6 +776,11 @@ void Mod_Init (qboolean initial)
Cvar_Register(&temp_lit2support, NULL); Cvar_Register(&temp_lit2support, NULL);
Cmd_AddCommand("sv_saveentfile", Mod_SaveEntFile_f); Cmd_AddCommand("sv_saveentfile", Mod_SaveEntFile_f);
Cmd_AddCommand("version_modelformats", Mod_PrintFormats_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) if (initial)
@ -1677,7 +1687,7 @@ typedef struct
Mod_LoadLighting 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 luxtmp = true;
qboolean exptmp = true; qboolean exptmp = true;
@ -1718,11 +1728,11 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
samples >>= 1; samples >>= 1;
if (!samples) 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; samples /= 4;
if (!samples) if (!samples)
{ {
litdata = Q1BSPX_FindLump("RGBLIGHTING", &samples); //RGB packed data litdata = BSPX_FindLump(bspx, mod_base, "RGBLIGHTING", &samples); //RGB packed data
samples /= 3; samples /= 3;
if (!samples) if (!samples)
return; return;
@ -1853,13 +1863,13 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
{ {
int size; int size;
/*FIXME: bspx support for extents+lmscale, may require style+offset lumps too, not sure what to do here*/ /*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; exptmp = true;
if (size != samples*4) if (size != samples*4)
{ {
expdata = NULL; expdata = NULL;
litdata = Q1BSPX_FindLump("RGBLIGHTING", &size); litdata = BSPX_FindLump(bspx, mod_base, "RGBLIGHTING", &size);
littmp = true; littmp = true;
if (size != samples*3) if (size != samples*3)
litdata = NULL; litdata = NULL;
@ -1944,7 +1954,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
if (!luxdata) if (!luxdata)
{ {
int size; int size;
luxdata = Q1BSPX_FindLump("LIGHTINGDIR", &size); luxdata = BSPX_FindLump(bspx, mod_base, "LIGHTINGDIR", &size);
if (size != samples*3) if (size != samples*3)
luxdata = NULL; luxdata = NULL;
luxtmp = true; luxtmp = true;
@ -2024,7 +2034,7 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
if (overrides && !overrides->shifts) if (overrides && !overrides->shifts)
{ {
int size; int size;
overrides->shifts = Q1BSPX_FindLump("LMSHIFT", &size); overrides->shifts = BSPX_FindLump(bspx, mod_base, "LMSHIFT", &size);
if (size != loadmodel->numsurfaces) if (size != loadmodel->numsurfaces)
overrides->shifts = NULL; overrides->shifts = NULL;
@ -2032,14 +2042,14 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean
if (!overrides->offsets) if (!overrides->offsets)
{ {
int size; int size;
overrides->offsets = Q1BSPX_FindLump("LMOFFSET", &size); overrides->offsets = BSPX_FindLump(bspx, mod_base, "LMOFFSET", &size);
if (size != loadmodel->numsurfaces * sizeof(int)) if (size != loadmodel->numsurfaces * sizeof(int))
overrides->offsets = NULL; overrides->offsets = NULL;
} }
if (!overrides->styles) if (!overrides->styles)
{ {
int size; int size;
overrides->styles = Q1BSPX_FindLump("LMSTYLE", &size); overrides->styles = BSPX_FindLump(bspx, mod_base, "LMSTYLE", &size);
if (size != loadmodel->numsurfaces * sizeof(qbyte)*MAXQ1LIGHTMAPS) if (size != loadmodel->numsurfaces * sizeof(qbyte)*MAXQ1LIGHTMAPS)
overrides->styles = NULL; overrides->styles = NULL;
} }
@ -2305,7 +2315,7 @@ qboolean Mod_LoadVertexes (model_t *loadmodel, qbyte *mod_base, lump_t *l)
return true; 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 *in;
float *out; float *out;
@ -2323,7 +2333,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, qbyte *mod_base, lump_t *l)
} }
else else
{ {
in = Q1BSPX_FindLump("VERTEXNORMALS", &count); in = BSPX_FindLump(bspx, mod_base, "VERTEXNORMALS", &count);
if (in) if (in)
count /= sizeof(vec3_t); count /= sizeof(vec3_t);
else else
@ -3765,7 +3775,7 @@ void CalcSurfaceExtents (model_t *mod, msurface_t *s);
Mod_LoadFaces 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; dsface_t *ins;
dlface_t *inl; 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->surfaces = out;
loadmodel->numsurfaces = count; loadmodel->numsurfaces = count;
Mod_LoadLighting (loadmodel, mod_base, lightlump, false, &overrides); Mod_LoadLighting (loadmodel, bspx, mod_base, lightlump, false, &overrides);
switch(loadmodel->lightmaps.fmt) switch(loadmodel->lightmaps.fmt)
{ {
@ -5075,6 +5085,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi
qboolean isnotmap; qboolean isnotmap;
qboolean using_rbe = true; qboolean using_rbe = true;
qboolean misaligned = false; qboolean misaligned = false;
bspx_header_t *bspx;
COM_FileBase (mod->name, loadname, sizeof(loadname)); COM_FileBase (mod->name, loadname, sizeof(loadname));
mod->type = mod_brush; 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; ofs += header.lumps[i].filelen;
} }
BZ_Free(tmp); BZ_Free(tmp);
bspx = NULL;
} }
else 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; char *id;
id = (char *)mod_base + sizeof(dheader_t); 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. { //EBFS detected.
COM_LoadMapPackFile(mod->name, sizeof(dheader_t)); COM_LoadMapPackFile(mod->name, sizeof(dheader_t));
} }
} }*/
} }
noerrors = true; noerrors = true;
@ -5229,7 +5241,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi
TRACE(("Loading Texinfo\n")); TRACE(("Loading Texinfo\n"));
noerrors = noerrors && Mod_LoadTexinfo (mod, mod_base, &header.lumps[LUMP_TEXINFO]); noerrors = noerrors && Mod_LoadTexinfo (mod, mod_base, &header.lumps[LUMP_TEXINFO]);
TRACE(("Loading Faces\n")); 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) if (!isDedicated)
{ {
@ -5270,7 +5282,7 @@ static qboolean QDECL Mod_LoadBrushModel (model_t *mod, void *buffer, size_t fsi
} }
TRACE(("LoadBrushModel %i\n", __LINE__)); TRACE(("LoadBrushModel %i\n", __LINE__));
Q1BSP_LoadBrushes(mod); Q1BSP_LoadBrushes(mod, bspx, mod_base);
TRACE(("LoadBrushModel %i\n", __LINE__)); TRACE(("LoadBrushModel %i\n", __LINE__));
Q1BSP_SetModelFuncs(mod); Q1BSP_SetModelFuncs(mod);
TRACE(("LoadBrushModel %i\n", __LINE__)); TRACE(("LoadBrushModel %i\n", __LINE__));

View file

@ -391,12 +391,17 @@ typedef struct mfog_s
mplane_t **planes; mplane_t **planes;
} mfog_t; } mfog_t;
typedef struct
{
vec3_t origin;
int cubesize; //pixels
} denvmap_t;
typedef struct typedef struct
{ {
vec3_t origin; vec3_t origin;
int cubesize; //pixels int cubesize; //pixels
texid_t *image; texid_t image;
} menvmap_t; } menvmap_t;
#define LMSHIFT_DEFAULT 4 #define LMSHIFT_DEFAULT 4
@ -537,10 +542,12 @@ typedef struct hull_s
void Q1BSP_CheckHullNodes(hull_t *hull); void Q1BSP_CheckHullNodes(hull_t *hull);
void Q1BSP_SetModelFuncs(struct model_s *mod); 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 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; typedef struct fragmentdecal_s fragmentdecal_t;
void Fragment_ClipPoly(fragmentdecal_t *dec, int numverts, float *inverts, shader_t *surfshader); void Fragment_ClipPoly(fragmentdecal_t *dec, int numverts, float *inverts, shader_t *surfshader);

View file

@ -719,6 +719,7 @@ program_t *Shader_FindGeneric(char *name, int qrtype);
const char *Shader_NameForGeneric(program_t *prog); const char *Shader_NameForGeneric(program_t *prog);
void Shader_ReleaseGeneric(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); mfog_t *Mod_FogForOrigin(model_t *wmodel, vec3_t org);
#define BEF_FORCEDEPTHWRITE 1 #define BEF_FORCEDEPTHWRITE 1