mirror of
https://github.com/yquake2/ref_vk.git
synced 2025-02-22 19:51:49 +00:00
Add LIGHTGRID_OCTREE support
This commit is contained in:
parent
352fc5328f
commit
1d3679584e
7 changed files with 304 additions and 15 deletions
|
@ -176,6 +176,50 @@ typedef struct mleaf_s
|
|||
int key; /* BSP sequence number for leaf's contents */
|
||||
} mleaf_t;
|
||||
|
||||
/* BSPX Light octtree */
|
||||
#define LGNODE_LEAF (1u<<31)
|
||||
#define LGNODE_MISSING (1u<<30)
|
||||
|
||||
/* this uses an octtree to trim samples. */
|
||||
typedef struct bspxlgnode_s
|
||||
{
|
||||
int mid[3];
|
||||
unsigned int child[8];
|
||||
} bspxlgnode_t;
|
||||
|
||||
typedef struct bspxlglightstyle_s
|
||||
{
|
||||
byte style;
|
||||
byte rgb[3];
|
||||
} bspxlglightstyle_t;
|
||||
|
||||
typedef struct bspxlgsamp_s
|
||||
{
|
||||
bspxlglightstyle_t map[4];
|
||||
} bspxlgsamp_t;
|
||||
|
||||
typedef struct bspxlgleaf_s
|
||||
{
|
||||
int mins[3];
|
||||
int size[3];
|
||||
bspxlgsamp_t *rgbvalues;
|
||||
} bspxlgleaf_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t gridscale;
|
||||
unsigned int count[3];
|
||||
vec3_t mins;
|
||||
unsigned int styles;
|
||||
|
||||
unsigned int rootnode;
|
||||
|
||||
unsigned int numnodes;
|
||||
bspxlgnode_t *nodes;
|
||||
unsigned int numleafs;
|
||||
bspxlgleaf_t *leafs;
|
||||
} bspxlightgrid_t;
|
||||
|
||||
/* Shared models func */
|
||||
typedef struct image_s* (*findimage_t)(const char *name, imagetype_t type);
|
||||
extern void *Mod_LoadAliasModel (const char *mod_name, const void *buffer, int modfilelen,
|
||||
|
|
|
@ -183,7 +183,7 @@ extern float r_viewproj_matrix[16];
|
|||
|
||||
extern float *s_blocklights, *s_blocklights_max;
|
||||
|
||||
void R_LightPoint (vec3_t p, vec3_t color, entity_t *currententity);
|
||||
void R_LightPoint (const bspxlightgrid_t *grid, vec3_t p, vec3_t color, entity_t *currententity);
|
||||
void R_PushDlights (void);
|
||||
|
||||
//====================================================================
|
||||
|
|
|
@ -171,6 +171,9 @@ typedef struct model_s
|
|||
|
||||
// submodules
|
||||
vec3_t origin; // for sounds or lights
|
||||
|
||||
/* octree */
|
||||
bspxlightgrid_t *grid;
|
||||
} model_t;
|
||||
|
||||
void Mod_Init(void);
|
||||
|
|
|
@ -283,8 +283,77 @@ RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end, vec3_t pointcolor)
|
|||
return RecursiveLightPoint(node->children[!side], mid, end, pointcolor);
|
||||
}
|
||||
|
||||
static int
|
||||
BSPX_LightGridSingleValue(const bspxlightgrid_t *grid, const lightstyle_t *lightstyles, int x, int y, int z, vec3_t res_diffuse)
|
||||
{
|
||||
unsigned int node;
|
||||
|
||||
node = grid->rootnode;
|
||||
while (!(node & LGNODE_LEAF))
|
||||
{
|
||||
struct bspxlgnode_s *n;
|
||||
if (node & LGNODE_MISSING)
|
||||
return 0; //failure
|
||||
n = grid->nodes + node;
|
||||
node = n->child[
|
||||
((x>=n->mid[0])<<2)|
|
||||
((y>=n->mid[1])<<1)|
|
||||
((z>=n->mid[2])<<0)];
|
||||
}
|
||||
|
||||
{
|
||||
struct bspxlgleaf_s *leaf = &grid->leafs[node & ~LGNODE_LEAF];
|
||||
struct bspxlgsamp_s *samp;
|
||||
int i;
|
||||
|
||||
x -= leaf->mins[0];
|
||||
y -= leaf->mins[1];
|
||||
z -= leaf->mins[2];
|
||||
if (x >= leaf->size[0] ||
|
||||
y >= leaf->size[1] ||
|
||||
z >= leaf->size[2])
|
||||
return 0; //sample we're after is out of bounds...
|
||||
|
||||
i = x + leaf->size[0]*(y + leaf->size[1]*z);
|
||||
samp = leaf->rgbvalues + i;
|
||||
|
||||
//no hdr support
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (samp->map[i].style == ((byte)(~0u)))
|
||||
break; //no more
|
||||
res_diffuse[0] += samp->map[i].rgb[0] * lightstyles[samp->map[i].style].rgb[0] / 255.0;
|
||||
res_diffuse[1] += samp->map[i].rgb[1] * lightstyles[samp->map[i].style].rgb[1] / 255.0;
|
||||
res_diffuse[2] += samp->map[i].rgb[2] * lightstyles[samp->map[i].style].rgb[2] / 255.0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
BSPX_LightGridValue(const bspxlightgrid_t *grid, const lightstyle_t *lightstyles,
|
||||
const vec3_t point, vec3_t res_diffuse)
|
||||
{
|
||||
int tile[3];
|
||||
int i;
|
||||
int s;
|
||||
|
||||
VectorSet(res_diffuse, 0, 0, 0); //assume worst
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
tile[i] = (point[i] - grid->mins[i]) * grid->gridscale[i];
|
||||
|
||||
for (i = 0, s = 0; i < 8; i++)
|
||||
s += BSPX_LightGridSingleValue(grid, lightstyles,
|
||||
tile[0]+!!(i&1),
|
||||
tile[1]+!!(i&2),
|
||||
tile[2]+!!(i&4), res_diffuse);
|
||||
|
||||
VectorScale(res_diffuse, 1.0/s, res_diffuse); //average the successful ones
|
||||
}
|
||||
|
||||
void
|
||||
R_LightPoint(vec3_t p, vec3_t color, entity_t *currententity)
|
||||
R_LightPoint(const bspxlightgrid_t *grid, vec3_t p, vec3_t color, entity_t *currententity)
|
||||
{
|
||||
vec3_t end, pointcolor, dist;
|
||||
float r;
|
||||
|
@ -297,6 +366,13 @@ R_LightPoint(vec3_t p, vec3_t color, entity_t *currententity)
|
|||
return;
|
||||
}
|
||||
|
||||
if (grid)
|
||||
{
|
||||
BSPX_LightGridValue(grid, r_newrefdef.lightstyles,
|
||||
currententity->origin, color);
|
||||
return;
|
||||
}
|
||||
|
||||
end[0] = p[0];
|
||||
end[1] = p[1];
|
||||
end[2] = p[2] - 2048;
|
||||
|
|
|
@ -243,7 +243,7 @@ R_DrawNullModel(entity_t *currententity)
|
|||
}
|
||||
else
|
||||
{
|
||||
R_LightPoint(currententity->origin, shadelight, currententity);
|
||||
R_LightPoint(r_worldmodel->grid, currententity->origin, shadelight, currententity);
|
||||
}
|
||||
|
||||
float model[16];
|
||||
|
@ -1071,7 +1071,7 @@ R_SetLightLevel (void)
|
|||
}
|
||||
|
||||
/* save off light value for server to look at */
|
||||
R_LightPoint(r_newrefdef.vieworg, shadelight, NULL);
|
||||
R_LightPoint(r_worldmodel->grid, r_newrefdef.vieworg, shadelight, NULL);
|
||||
|
||||
/* pick the greatest component, which should be the
|
||||
* same as the mono value returned by software */
|
||||
|
|
|
@ -853,7 +853,7 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
|
|||
}
|
||||
else
|
||||
{
|
||||
R_LightPoint(currententity->origin, shadelight, currententity);
|
||||
R_LightPoint(r_worldmodel->grid, currententity->origin, shadelight, currententity);
|
||||
|
||||
// player lighting hack for communication back to server
|
||||
// big hack!
|
||||
|
|
|
@ -376,7 +376,8 @@ Mod_LoadDecoupledLM(const dlminfo_t* lminfos, int surfnum, msurface_t *out)
|
|||
}
|
||||
|
||||
const void *
|
||||
Mod_BSPX_FindLump(bspx_header_t* bspx_header, char* lumpname, int* plumpsize, const byte* mod_base)
|
||||
Mod_LoadBSPXFindLump(const bspx_header_t* bspx_header, char* lumpname, int* plumpsize,
|
||||
const byte* mod_base)
|
||||
{
|
||||
int i;
|
||||
bspx_lump_t* lump;
|
||||
|
@ -475,7 +476,7 @@ Mod_LoadFaces
|
|||
=================
|
||||
*/
|
||||
static void
|
||||
Mod_LoadFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, bspx_header_t *bspx_header)
|
||||
Mod_LoadFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, const bspx_header_t *bspx_header)
|
||||
{
|
||||
int i, count, surfnum, lminfosize, lightofs;
|
||||
const dlminfo_t *lminfos;
|
||||
|
@ -496,7 +497,7 @@ Mod_LoadFaces(model_t *loadmodel, const byte *mod_base, const lump_t *l, bspx_he
|
|||
loadmodel->surfaces = out;
|
||||
loadmodel->numsurfaces = count;
|
||||
|
||||
lminfos = Mod_BSPX_FindLump(bspx_header, "DECOUPLED_LM", &lminfosize, mod_base);
|
||||
lminfos = Mod_LoadBSPXFindLump(bspx_header, "DECOUPLED_LM", &lminfosize, mod_base);
|
||||
if (lminfos != NULL && lminfosize / sizeof(dlminfo_t) != loadmodel->numsurfaces) {
|
||||
R_Printf(PRINT_ALL, "%s: [%s] decoupled_lm size %ld does not match surface count %d\n",
|
||||
__func__, loadmodel->name, lminfosize / sizeof(dlminfo_t), loadmodel->numsurfaces);
|
||||
|
@ -703,6 +704,157 @@ static int calcLumpHunkSize(const lump_t *l, int inSize, int outSize)
|
|||
return size;
|
||||
}
|
||||
|
||||
/* Need to clean */
|
||||
struct rctx_s {
|
||||
const byte *data;
|
||||
int ofs, size;
|
||||
};
|
||||
|
||||
static byte ReadByte(struct rctx_s *ctx)
|
||||
{
|
||||
if (ctx->ofs >= ctx->size)
|
||||
{
|
||||
ctx->ofs++;
|
||||
return 0;
|
||||
}
|
||||
return ctx->data[ctx->ofs++];
|
||||
}
|
||||
|
||||
static int ReadInt(struct rctx_s *ctx)
|
||||
{
|
||||
int r = (int)ReadByte(ctx)<<0;
|
||||
r|= (int)ReadByte(ctx)<<8;
|
||||
r|= (int)ReadByte(ctx)<<16;
|
||||
r|= (int)ReadByte(ctx)<<24;
|
||||
return r;
|
||||
}
|
||||
|
||||
static float ReadFloat(struct rctx_s *ctx)
|
||||
{
|
||||
union {float f; int i;} u;
|
||||
u.i = ReadInt(ctx);
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static bspxlightgrid_t*
|
||||
Mod_LoadBSPXLightGrid(const bspx_header_t *bspx_header, const byte *mod_base)
|
||||
{
|
||||
vec3_t step, mins;
|
||||
int size[3];
|
||||
bspxlightgrid_t *grid;
|
||||
unsigned int numstyles, numnodes, numleafs, rootnode;
|
||||
unsigned int nodestart, leafsamps = 0, i, j, k, s;
|
||||
struct bspxlgsamp_s *samp;
|
||||
struct rctx_s ctx = {0};
|
||||
|
||||
ctx.data = Mod_LoadBSPXFindLump(bspx_header, "LIGHTGRID_OCTREE", &ctx.size, mod_base);
|
||||
if (!ctx.data)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
step[j] = ReadFloat(&ctx);
|
||||
for (j = 0; j < 3; j++)
|
||||
size[j] = ReadInt(&ctx);
|
||||
for (j = 0; j < 3; j++)
|
||||
mins[j] = ReadFloat(&ctx);
|
||||
|
||||
numstyles = ReadByte(&ctx); //urgh, misaligned the entire thing
|
||||
rootnode = ReadInt(&ctx);
|
||||
numnodes = ReadInt(&ctx);
|
||||
nodestart = ctx.ofs;
|
||||
ctx.ofs += (3+8)*4*numnodes;
|
||||
numleafs = ReadInt(&ctx);
|
||||
for (i = 0; i < numleafs; i++)
|
||||
{
|
||||
unsigned int lsz[3];
|
||||
ctx.ofs += 3*4;
|
||||
for (j = 0; j < 3; j++)
|
||||
lsz[j] = ReadInt(&ctx);
|
||||
j = lsz[0]*lsz[1]*lsz[2];
|
||||
leafsamps += j;
|
||||
while (j --> 0)
|
||||
{ //this loop is annonying, memcpy dreams...
|
||||
s = ReadByte(&ctx);
|
||||
if (s == 255)
|
||||
continue;
|
||||
ctx.ofs += s*4;
|
||||
}
|
||||
}
|
||||
|
||||
grid = Hunk_Alloc(sizeof(*grid) + sizeof(*grid->leafs)*numleafs + sizeof(*grid->nodes)*numnodes + sizeof(struct bspxlgsamp_s)*leafsamps);
|
||||
memset(grid, 0xcc, sizeof(*grid) + sizeof(*grid->leafs)*numleafs + sizeof(*grid->nodes)*numnodes + sizeof(struct bspxlgsamp_s)*leafsamps);
|
||||
grid->leafs = (void*)(grid+1);
|
||||
grid->nodes = (void*)(grid->leafs + numleafs);
|
||||
samp = (void*)(grid->nodes+numnodes);
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
grid->gridscale[j] = 1/step[j]; //prefer it as a multiply
|
||||
VectorCopy(mins, grid->mins);
|
||||
VectorCopy(size, grid->count);
|
||||
grid->numnodes = numnodes;
|
||||
grid->numleafs = numleafs;
|
||||
grid->rootnode = rootnode;
|
||||
(void)numstyles;
|
||||
|
||||
//rewind to the nodes. *sigh*
|
||||
ctx.ofs = nodestart;
|
||||
for (i = 0; i < numnodes; i++)
|
||||
{
|
||||
for (j = 0; j < 3; j++)
|
||||
grid->nodes[i].mid[j] = ReadInt(&ctx);
|
||||
for (j = 0; j < 8; j++)
|
||||
grid->nodes[i].child[j] = ReadInt(&ctx);
|
||||
}
|
||||
ctx.ofs += 4;
|
||||
for (i = 0; i < numleafs; i++)
|
||||
{
|
||||
for (j = 0; j < 3; j++)
|
||||
grid->leafs[i].mins[j] = ReadInt(&ctx);
|
||||
for (j = 0; j < 3; j++)
|
||||
grid->leafs[i].size[j] = ReadInt(&ctx);
|
||||
|
||||
grid->leafs[i].rgbvalues = samp;
|
||||
|
||||
j = grid->leafs[i].size[0]*grid->leafs[i].size[1]*grid->leafs[i].size[2];
|
||||
while (j --> 0)
|
||||
{
|
||||
s = ReadByte(&ctx);
|
||||
if (s == 0xff)
|
||||
memset(samp, 0xff, sizeof(*samp));
|
||||
else
|
||||
{
|
||||
for (k = 0; k < s; k++)
|
||||
{
|
||||
if (k >= 4)
|
||||
ReadInt(&ctx);
|
||||
else
|
||||
{
|
||||
samp->map[k].style = ReadByte(&ctx);
|
||||
samp->map[k].rgb[0] = ReadByte(&ctx);
|
||||
samp->map[k].rgb[1] = ReadByte(&ctx);
|
||||
samp->map[k].rgb[2] = ReadByte(&ctx);
|
||||
}
|
||||
}
|
||||
for (; k < 4; k++)
|
||||
{
|
||||
samp->map[k].style = (byte)~0u;
|
||||
samp->map[k].rgb[0] =
|
||||
samp->map[k].rgb[1] =
|
||||
samp->map[k].rgb[2] = 0;
|
||||
}
|
||||
}
|
||||
samp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.ofs != ctx.size)
|
||||
grid = NULL;
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_LoadBrushModel
|
||||
|
@ -711,10 +863,10 @@ Mod_LoadBrushModel
|
|||
static void
|
||||
Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen)
|
||||
{
|
||||
bspx_header_t* bspx_header;
|
||||
byte *mod_base;
|
||||
dheader_t *header;
|
||||
int i;
|
||||
const bspx_header_t* bspx_header;
|
||||
int i, lightgridsize = 0;
|
||||
dheader_t *header;
|
||||
byte *mod_base;
|
||||
|
||||
header = (dheader_t *)buffer;
|
||||
|
||||
|
@ -734,6 +886,9 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen)
|
|||
((int *)header)[i] = LittleLong(((int *)header)[i]);
|
||||
}
|
||||
|
||||
/* check for BSPX extensions */
|
||||
bspx_header = Mod_LoadBSPX(modfilelen, (byte*)header);
|
||||
|
||||
// calculate the needed hunksize from the lumps
|
||||
int hunkSize = 0;
|
||||
hunkSize += calcLumpHunkSize(&header->lumps[LUMP_VERTEXES], sizeof(dvertex_t), sizeof(mvertex_t));
|
||||
|
@ -751,12 +906,23 @@ Mod_LoadBrushModel (model_t *mod, const void *buffer, int modfilelen)
|
|||
hunkSize += calcLumpHunkSize(&header->lumps[LUMP_NODES], sizeof(dnode_t), sizeof(mnode_t));
|
||||
hunkSize += calcLumpHunkSize(&header->lumps[LUMP_MODELS], sizeof(dmodel_t), sizeof(model_t));
|
||||
|
||||
/* Get size of octree on disk, need to recheck real size */
|
||||
if (Mod_LoadBSPXFindLump(bspx_header, "LIGHTGRID_OCTREE", &lightgridsize, mod_base))
|
||||
{
|
||||
hunkSize += lightgridsize * 4;
|
||||
}
|
||||
|
||||
mod->extradata = Hunk_Begin(hunkSize);
|
||||
mod->type = mod_brush;
|
||||
|
||||
|
||||
/* check for BSPX extensions */
|
||||
bspx_header = Mod_LoadBSPX(modfilelen, (byte*)header);
|
||||
if (bspx_header)
|
||||
{
|
||||
mod->grid = Mod_LoadBSPXLightGrid(bspx_header, mod_base);
|
||||
}
|
||||
else
|
||||
{
|
||||
mod->grid = NULL;
|
||||
}
|
||||
|
||||
/* load into heap */
|
||||
Mod_LoadVertexes(mod->name, &mod->vertexes, &mod->numvertexes, mod_base,
|
||||
|
|
Loading…
Reference in a new issue