ent->state_current.active = true;
ent->render.model = cl.worldmodel = NULL; // no world model yet
ent->render.alpha = 1;
- ent->render.colormap = -1; // no special coloring
ent->render.flags = RENDER_SHADOW | RENDER_LIGHT;
Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
CL_UpdateRenderEntity(&ent->render);
}
}
+static void CL_UpdateRenderEntity_Lighting(entity_render_t *ent)
+{
+ vec3_t tempdiffusenormal;
+
+ // fetch the lighting from the worldmodel data
+ VectorSet(ent->modellight_ambient, r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f));
+ VectorClear(ent->modellight_diffuse);
+ VectorClear(tempdiffusenormal);
+ if ((ent->flags & RENDER_LIGHT) && cl.worldmodel && cl.worldmodel->brush.LightPoint)
+ {
+ vec3_t org;
+ Matrix4x4_OriginFromMatrix(&ent->matrix, org);
+ cl.worldmodel->brush.LightPoint(cl.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
+ }
+ else // highly rare
+ VectorSet(ent->modellight_ambient, 1, 1, 1);
+
+ // move the light direction into modelspace coordinates for lighting code
+ Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
+ if(VectorLength2(ent->modellight_lightdir) <= 0)
+ VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
+ VectorNormalize(ent->modellight_lightdir);
+}
+
//static const vec3_t nomodelmins = {-16, -16, -16};
//static const vec3_t nomodelmaxs = {16, 16, 16};
void CL_UpdateRenderEntity(entity_render_t *ent)
ent->maxs[1] = org[1] + 16;
ent->maxs[2] = org[2] + 16;
}
+ CL_UpdateRenderEntity_Lighting(ent);
}
/*
memset (ent, 0, sizeof(*ent));
r_refdef.entities[r_refdef.numentities++] = &ent->render;
- ent->render.colormap = -1; // no special coloring
ent->render.alpha = 1;
VectorSet(ent->render.colormod, 1, 1, 1);
return ent;
flag->render.model = cl.model_precache[cl.qw_modelindex_flag];
flag->render.skinnum = skin;
- flag->render.colormap = -1; // no special coloring
flag->render.alpha = 1;
VectorSet(flag->render.colormod, 1, 1, 1);
// attach the flag to the player matrix
extern void V_CalcViewBlend(void);
extern void V_CalcRefdef(void);
+void CL_SetEntityColormapColors(entity_render_t *ent, int colormap)
+{
+ const unsigned char *cbcolor;
+ if (colormap >= 0)
+ {
+ cbcolor = palette_rgb_pantscolormap[colormap & 0xF];
+ VectorScale(cbcolor, (1.0f / 255.0f), ent->colormap_pantscolor);
+ cbcolor = palette_rgb_shirtcolormap[(colormap & 0xF0) >> 4];
+ VectorScale(cbcolor, (1.0f / 255.0f), ent->colormap_shirtcolor);
+ }
+ else
+ {
+ VectorClear(ent->colormap_pantscolor);
+ VectorClear(ent->colormap_shirtcolor);
+ }
+}
+
// note this is a recursive function, recursionlimit should be 32 or so on the initial call
void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolate)
{
VectorScale(e->state_current.colormod, (1.0f / 32.0f), e->render.colormod);
e->render.entitynumber = e - cl.entities;
if (e->state_current.flags & RENDER_COLORMAPPED)
- {
- unsigned char *cbcolor;
- e->render.colormap = e->state_current.colormap;
- cbcolor = palette_rgb_pantscolormap[e->render.colormap & 0xF];
- e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f);
- e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f);
- e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f);
- cbcolor = palette_rgb_shirtcolormap[(e->render.colormap & 0xF0) >> 4];
- e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f);
- e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f);
- e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f);
- }
- else if (e->state_current.colormap && cl.scores != NULL && e->state_current.colormap <= cl.maxclients)
- {
- unsigned char *cbcolor;
- e->render.colormap = cl.scores[e->state_current.colormap - 1].colors; // color it
- cbcolor = palette_rgb_pantscolormap[e->render.colormap & 0xF];
- e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f);
- e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f);
- e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f);
- cbcolor = palette_rgb_shirtcolormap[(e->render.colormap & 0xF0) >> 4];
- e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f);
- e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f);
- e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f);
- }
+ CL_SetEntityColormapColors(&e->render, e->state_current.colormap);
+ else if (e->state_current.colormap > 0 && e->state_current.colormap <= cl.maxclients && cl.scores != NULL)
+ CL_SetEntityColormapColors(&e->render, cl.scores[e->state_current.colormap-1].colors);
else
- {
- e->render.colormap = -1; // no special coloring
- VectorClear(e->render.colormap_pantscolor);
- VectorClear(e->render.colormap_shirtcolor);
- }
+ CL_SetEntityColormapColors(&e->render, -1);
e->render.skinnum = e->state_current.skin;
if (e->state_current.tagentity)
{
Matrix4x4_CreateFromQuakeEntity(&e->render.matrix, origin[0], origin[1], origin[2], angles[0], angles[1], angles[2], e->render.scale);
}
- // make the other useful stuff
- CL_UpdateRenderEntity(&e->render);
-
// tenebrae's sprites are all additive mode (weird)
if (gamemode == GAME_TENEBRAE && e->render.model && e->render.model->type == mod_sprite)
e->render.effects |= EF_ADDITIVE;
e->render.flags |= RENDER_SHADOW;
if (e->render.flags & RENDER_VIEWMODEL)
e->render.flags |= RENDER_NOSELFSHADOW;
+
+ // make the other useful stuff
+ CL_UpdateRenderEntity(&e->render);
}
// creates light and trails from an entity
entity_t *ent = &cl.entities[0];
// FIXME: this should be done at load
ent->render.matrix = identitymatrix;
- CL_UpdateRenderEntity(&ent->render);
ent->render.flags = RENDER_SHADOW;
if (!r_fullbright.integer)
ent->render.flags |= RENDER_LIGHT;
VectorSet(ent->render.colormod, 1, 1, 1);
+ CL_UpdateRenderEntity(&ent->render);
r_refdef.worldentity = &ent->render;
r_refdef.worldmodel = cl.worldmodel;
}
// if the model was not loaded when the static entity was created we
// need to re-fetch the model pointer
e->render.model = cl.model_precache[e->state_baseline.modelindex];
- CL_UpdateRenderEntity(&e->render);
// either fullbright or lit
if (!(e->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
e->render.flags |= RENDER_LIGHT;
e->render.flags |= RENDER_SHADOW;
VectorSet(e->render.colormod, 1, 1, 1);
R_LerpAnimation(&e->render);
+ CL_UpdateRenderEntity(&e->render);
r_refdef.entities[r_refdef.numentities++] = &e->render;
}
}
ent->render.model = cl.model_precache[e->modelindex];
else
ent->render.model = cl.csqc_model_precache[-(e->modelindex+1)];
- ent->render.colormap = -1; // no special coloring
ent->render.alpha = 1;
VectorSet(ent->render.colormod, 1, 1, 1);
// normal stuff
ent->render.model = cl.model_precache[cl.qw_modelindex_spike];
- ent->render.colormap = -1; // no special coloring
ent->render.alpha = 1;
VectorSet(ent->render.colormod, 1, 1, 1);
ent->render.framelerp = 0;
// make torchs play out of sync
ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
- ent->render.colormap = -1; // no special coloring
ent->render.skinnum = ent->state_baseline.skin;
ent->render.effects = ent->state_baseline.effects;
ent->render.alpha = 1;
// LordHavoc: this struct is intended for the renderer but some fields are
// used by the client.
+//
+// The renderer should not rely on any changes to this struct to be persistent
+// across multiple frames because temp entities are wiped every frame, but it
+// is acceptable to cache things in this struct that are not critical.
+//
+// For example the r_cullentities_trace code does such caching.
typedef struct entity_render_s
{
// location
model_t *model;
// number of the entity represents, or 0 for non-network entities
int entitynumber;
- // entity shirt and pants colors (-1 if not colormapped)
- int colormap;
- // literal colors for renderer
+ // literal colormap colors for renderer, if both are 0 0 0 it is not colormapped
vec3_t colormap_pantscolor;
vec3_t colormap_shirtcolor;
// light, particles, etc
// 4 frame numbers (-1 if not used) and their blending scalers (0-1), if interpolation is not desired, use frame instead
frameblend_t frameblend[4];
- // current lighting from map
+ // current lighting from map (updated ONLY by client code, not renderer)
vec3_t modellight_ambient;
vec3_t modellight_diffuse; // q3bsp
vec3_t modellight_lightdir; // q3bsp
+ // FIELDS UPDATED BY RENDERER:
// last time visible during trace culling
double last_trace_visibility;
}
void CL_Disconnect_f (void);
void CL_UpdateRenderEntity(entity_render_t *ent);
+void CL_SetEntityColormapColors(entity_render_t *ent, int colormap);
void CL_UpdateViewEntities(void);
//
entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
// copy it to the current state
+ memset(staticent, 0, sizeof(*staticent));
staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
staticent->render.framelerp = 0;
// make torchs play out of sync
staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
- staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
staticent->render.skinnum = (int)ent->fields.client->skin;
staticent->render.effects = (int)ent->fields.client->effects;
staticent->render.alpha = 1;
}
else
Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], staticent->render.scale);
- CL_UpdateRenderEntity(&staticent->render);
// either fullbright or lit
if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
// turn off shadows from transparent objects
if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
staticent->render.flags |= RENDER_SHADOW;
+
+ CL_UpdateRenderEntity(&staticent->render);
}
else
Con_Printf("Too many static entities");
qboolean CSQC_AddRenderEdict(prvm_edict_t *ed)
{
int renderflags;
+ int c;
float scale;
prvm_eval_t *val;
entity_t *e;
return false;
e->render.model = model;
- e->render.colormap = (int)ed->fields.client->colormap;
e->render.skinnum = (int)ed->fields.client->skin;
e->render.effects |= e->render.model->effects;
scale = 1;
// concat the matrices to make the entity relative to its tag
Matrix4x4_Concat(&e->render.matrix, &tagmatrix, &matrix2);
- // make the other useful stuff
- CL_UpdateRenderEntity(&e->render);
if(renderflags)
{
if(renderflags & RF_ADDITIVE) e->render.effects |= EF_ADDITIVE;
}
- if ((e->render.colormap > 0 && e->render.colormap <= cl.maxclients) || e->render.colormap >= 1024)
- {
- unsigned char *cbcolor;
- int palcol;
- if (e->render.colormap >= 1024)
- palcol = (unsigned char)(e->render.colormap-1024);
- else
- palcol = cl.scores[e->render.colormap-1].colors;
-
- cbcolor = palette_rgb_pantscolormap[palcol & 0xF];
- e->render.colormap_pantscolor[0] = cbcolor[0] * (1.0f / 255.0f);
- e->render.colormap_pantscolor[1] = cbcolor[1] * (1.0f / 255.0f);
- e->render.colormap_pantscolor[2] = cbcolor[2] * (1.0f / 255.0f);
- cbcolor = palette_rgb_shirtcolormap[(palcol & 0xF0) >> 4];
- e->render.colormap_shirtcolor[0] = cbcolor[0] * (1.0f / 255.0f);
- e->render.colormap_shirtcolor[1] = cbcolor[1] * (1.0f / 255.0f);
- e->render.colormap_shirtcolor[2] = cbcolor[2] * (1.0f / 255.0f);
- }
+ c = (int)ed->fields.client->colormap;
+ if (c <= 0)
+ CL_SetEntityColormapColors(&e->render, -1);
+ else if (c <= cl.maxclients && cl.scores != NULL)
+ CL_SetEntityColormapColors(&e->render, cl.scores[c-1].colors);
+ else
+ CL_SetEntityColormapColors(&e->render, c);
// either fullbright or lit
if (!(e->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
if (e->render.flags & RENDER_VIEWMODEL)
e->render.flags |= RENDER_NOSELFSHADOW;
+ // make the other useful stuff
+ CL_UpdateRenderEntity(&e->render);
+
return true;
}
else if (mode == SHADERMODE_LIGHTDIRECTION)
{
if (r_glsl_permutation->loc_AmbientColor >= 0)
- qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale, rsurface.modellight_ambient[1] * ambientscale, rsurface.modellight_ambient[2] * ambientscale);
+ qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale * r_refdef.lightmapintensity, rsurface.modellight_ambient[1] * ambientscale * r_refdef.lightmapintensity, rsurface.modellight_ambient[2] * ambientscale * r_refdef.lightmapintensity);
if (r_glsl_permutation->loc_DiffuseColor >= 0)
- qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale, rsurface.modellight_diffuse[1] * diffusescale, rsurface.modellight_diffuse[2] * diffusescale);
+ qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale * r_refdef.lightmapintensity, rsurface.modellight_diffuse[1] * diffusescale * r_refdef.lightmapintensity, rsurface.modellight_diffuse[2] * diffusescale * r_refdef.lightmapintensity);
if (r_glsl_permutation->loc_SpecularColor >= 0)
- qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale, rsurface.modellight_diffuse[1] * specularscale, rsurface.modellight_diffuse[2] * specularscale);
+ qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale * r_refdef.lightmapintensity, rsurface.modellight_diffuse[1] * specularscale * r_refdef.lightmapintensity, rsurface.modellight_diffuse[2] * specularscale * r_refdef.lightmapintensity);
if (r_glsl_permutation->loc_LightDir >= 0)
qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
}
//==================================================================================
-static void R_UpdateEntityLighting(entity_render_t *ent)
-{
- vec3_t tempdiffusenormal;
-
- // fetch the lighting from the worldmodel data
- VectorSet(ent->modellight_ambient, r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f));
- VectorClear(ent->modellight_diffuse);
- VectorClear(tempdiffusenormal);
- if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
- {
- vec3_t org;
- Matrix4x4_OriginFromMatrix(&ent->matrix, org);
- r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
- }
- else // highly rare
- VectorSet(ent->modellight_ambient, 1, 1, 1);
-
- // move the light direction into modelspace coordinates for lighting code
- Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
- if(VectorLength2(ent->modellight_lightdir) > 0)
- {
- VectorNormalize(ent->modellight_lightdir);
- }
- else
- {
- VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
- }
-
- // scale ambient and directional light contributions according to rendering variables
- ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
- ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
- ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
- ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
- ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
- ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
-}
-
static void R_View_UpdateEntityVisible (void)
{
int i, renderimask;
r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs));
}
}
-
- // update entity lighting (even on hidden entities for r_shadows)
- for (i = 0;i < r_refdef.numentities;i++)
- R_UpdateEntityLighting(r_refdef.entities[i]);
}
// only used if skyrendermasked, and normally returns false
// TODO: optimize
// model lighting
VectorCopy(rsurface.modellight_lightdir, lightdir);
- ambientcolor[0] = rsurface.modellight_ambient[0] * r * 0.5f;
- ambientcolor[1] = rsurface.modellight_ambient[1] * g * 0.5f;
- ambientcolor[2] = rsurface.modellight_ambient[2] * b * 0.5f;
- diffusecolor[0] = rsurface.modellight_diffuse[0] * r * 0.5f;
- diffusecolor[1] = rsurface.modellight_diffuse[1] * g * 0.5f;
- diffusecolor[2] = rsurface.modellight_diffuse[2] * b * 0.5f;
+ f = 0.5f * r_refdef.lightmapintensity;
+ ambientcolor[0] = rsurface.modellight_ambient[0] * r * f;
+ ambientcolor[1] = rsurface.modellight_ambient[1] * g * f;
+ ambientcolor[2] = rsurface.modellight_ambient[2] * b * f;
+ diffusecolor[0] = rsurface.modellight_diffuse[0] * r * f;
+ diffusecolor[1] = rsurface.modellight_diffuse[1] * g * f;
+ diffusecolor[2] = rsurface.modellight_diffuse[2] * b * f;
if (VectorLength2(diffusecolor) > 0)
{
// generate color arrays for the surfaces in this list
if (loadmodel->brush.numsubmodels)
loadmodel->brush.submodels = (model_t **)Mem_Alloc(loadmodel->mempool, loadmodel->brush.numsubmodels * sizeof(model_t *));
- if (loadmodel->isworldmodel)
- {
- // clear out any stale submodels or worldmodels lying around
- // if we did this clear before now, an error might abort loading and
- // leave things in a bad state
- Mod_RemoveStaleWorldModels(loadmodel);
- }
-
// LordHavoc: to clear the fog around the original quake submodel code, I
// will explain:
// first of all, some background info on the submodels:
loadmodel->brush.num_leafs = 0;
Mod_Q3BSP_RecursiveFindNumLeafs(loadmodel->brush.data_nodes);
- if (loadmodel->isworldmodel)
- {
- // clear out any stale submodels or worldmodels lying around
- // if we did this clear before now, an error might abort loading and
- // leave things in a bad state
- Mod_RemoveStaleWorldModels(loadmodel);
- }
-
mod = loadmodel;
for (i = 0;i < loadmodel->brush.numsubmodels;i++)
{
VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius);
VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius);
- // if we're loading a worldmodel, then this is a level change, and we
- // should reload all q3 shaders to make sure they are current (which will
- // also be used by any other models loaded after this world model)
+ // if we're loading a worldmodel, then this is a level change
if (mod->isworldmodel)
+ {
+ // clear out any stale submodels or worldmodels lying around
+ // if we did this clear before now, an error might abort loading and
+ // leave things in a bad state
+ Mod_RemoveStaleWorldModels(mod);
+ // reload q3 shaders, to make sure they are ready to go for this level
+ // (including any models loaded for this level)
Mod_LoadQ3Shaders();
+ }
if (buf)
{
// John Carmack said the quake palette.lmp can be considered public domain because it is not an important asset to id, so I include it here as a fallback if no external palette file is found.
unsigned char host_quakepal[768] =
{
-// marked: colormap colors: cb = (e->render.colormap & 0xF0);cb += (cb >= 128 && cb < 224) ? 4 : 12;
+// marked: colormap colors: cb = (colormap & 0xF0);cb += (cb >= 128 && cb < 224) ? 4 : 12;
// 0x0*
0,0,0, 15,15,15, 31,31,31, 47,47,47, 63,63,63, 75,75,75, 91,91,91, 107,107,107,
123,123,123, 139,139,139, 155,155,155, 171,171,171, 187,187,187, 203,203,203, 219,219,219, 235,235,235,