Support for getting correct light-level for waypoints. Thanks to Immortal_BLG for light-level calculation code.
This commit is contained in:
parent
7b3b80354d
commit
7ebf1b6ef4
10 changed files with 500 additions and 17 deletions
|
|
@ -1102,4 +1102,146 @@ void Engine::processMessages (void *ptr) {
|
|||
logEntry (true, LL_FATAL, "Network message handler error. Call to unrecognized message id (%d).\n", m_msgBlock.msg);
|
||||
}
|
||||
m_msgBlock.state++; // and finally update network message state
|
||||
}
|
||||
|
||||
void LightMeasure::initializeLightstyles (void) {
|
||||
// this function initializes lighting information...
|
||||
|
||||
// reset all light styles
|
||||
for (int i = 0; i < MAX_LIGHTSTYLES; i++) {
|
||||
m_lightstyle[i].length = 0;
|
||||
m_lightstyle[i].map[0] = 0x0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTSTYLEVALUE; i++) {
|
||||
m_lightstyleValue[i] = 264;
|
||||
}
|
||||
}
|
||||
|
||||
void LightMeasure::animateLight (void) {
|
||||
// this function performs light animations
|
||||
|
||||
if (!m_doAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 'm' is normal light, 'a' is no light, 'z' is double bright
|
||||
const int index = static_cast <int> (engine.timebase () * 10.0f);
|
||||
|
||||
for (int j = 0; j < MAX_LIGHTSTYLES; j++) {
|
||||
if (!m_lightstyle[j].length) {
|
||||
m_lightstyleValue[j] = 256;
|
||||
continue;
|
||||
}
|
||||
int value = m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a';
|
||||
m_lightstyleValue[j] = value * 22;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool LightMeasure::recursiveLightPoint (const mnode_t *node, const Vector &start, const Vector &end) {
|
||||
if (node->contents < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// determine which side of the node plane our points are on, fixme: optimize for axial
|
||||
auto plane = node->plane;
|
||||
|
||||
float front = (start | plane->normal) - plane->dist;
|
||||
float back = (end | plane->normal) - plane->dist;
|
||||
|
||||
int side = front < 0.0f;
|
||||
|
||||
// if they're both on the same side of the plane, don't bother to split just check the appropriate child
|
||||
if ((back < 0.0f) == side) {
|
||||
return recursiveLightPoint (node->children[side], start, end);
|
||||
}
|
||||
|
||||
// calculate mid point
|
||||
float frac = front / (front - back);
|
||||
auto mid = start + (end - start) * frac;
|
||||
|
||||
// go down front side
|
||||
if (recursiveLightPoint (node->children[side], start, mid)) {
|
||||
return true; // hit something
|
||||
}
|
||||
|
||||
// blow it off if it doesn't split the plane...
|
||||
if ((back < 0.0f) == side) {
|
||||
return false; // didn't hit anything
|
||||
}
|
||||
|
||||
// check for impact on this node
|
||||
// lightspot = mid;
|
||||
// lightplane = plane;
|
||||
auto surf = reinterpret_cast <msurface_t *> (m_worldModel->surfaces) + node->firstsurface;
|
||||
|
||||
for (int i = 0; i < node->numsurfaces; i++, surf++) {
|
||||
if (surf->flags & SURF_DRAWTILED) {
|
||||
continue; // no lightmaps
|
||||
}
|
||||
auto tex = surf->texinfo;
|
||||
|
||||
// see where in lightmap space our intersection point is
|
||||
int s = static_cast <int> ((mid | Vector (tex->vecs[0])) + tex->vecs[0][3]);
|
||||
int t = static_cast <int> ((mid | Vector (tex->vecs[1])) + tex->vecs[1][3]);
|
||||
|
||||
// not in the bounds of our lightmap? punt...
|
||||
if (s < surf->texturemins[0] || t < surf->texturemins[1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// assuming a square lightmap (fixme: which ain't always the case), lets see if it lies in that rectangle. if not, punt...
|
||||
int ds = s - surf->texturemins[0];
|
||||
int dt = t - surf->texturemins[1];
|
||||
|
||||
if (ds > surf->extents[0] || dt > surf->extents[1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!surf->samples) {
|
||||
return true;
|
||||
}
|
||||
ds >>= 4;
|
||||
dt >>= 4;
|
||||
|
||||
m_point.reset (); // reset point color.
|
||||
|
||||
int smax = (surf->extents[0] >> 4) + 1;
|
||||
int tmax = (surf->extents[1] >> 4) + 1;
|
||||
int size = smax * tmax;
|
||||
|
||||
auto lightmap = surf->samples + dt * smax + ds;
|
||||
|
||||
// compute the lightmap color at a particular point
|
||||
for (int maps = 0u; maps < MAXLIGHTMAPS && surf->styles[maps] != 255u; ++maps) {
|
||||
uint32 scale = m_lightstyleValue[surf->styles[maps]];
|
||||
|
||||
m_point.red += lightmap->r * scale;
|
||||
m_point.green += lightmap->g * scale;
|
||||
m_point.blue += lightmap->b * scale;
|
||||
|
||||
lightmap += size; // skip to next lightmap
|
||||
}
|
||||
m_point.red >>= 8u;
|
||||
m_point.green >>= 8u;
|
||||
m_point.blue >>= 8u;
|
||||
|
||||
return true;
|
||||
}
|
||||
return recursiveLightPoint (node->children[!side], mid, end); // go down back side
|
||||
}
|
||||
|
||||
float LightMeasure::getLightLevel (const Vector &point) {
|
||||
if (!m_worldModel) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (!m_worldModel->lightdata) {
|
||||
return 255.0f;
|
||||
}
|
||||
|
||||
Vector endPoint (point);
|
||||
endPoint.z -= 2048.0f;
|
||||
|
||||
return recursiveLightPoint (m_worldModel->nodes, point, endPoint) == false ? 0.0f : 100 * cr::sqrtf (cr::min (75.0f, static_cast <float> (m_point.avg ())) / 75.0f);
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ ConVar yb_version ("yb_version", PRODUCT_VERSION, VT_READONLY);
|
|||
ConVar mp_startmoney ("mp_startmoney", nullptr, VT_NOREGISTER, true, "800");
|
||||
|
||||
int handleBotCommands (edict_t *ent, const char *arg0, const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *arg5, const char *self) {
|
||||
|
||||
// adding one bot with random parameters to random team
|
||||
if (stricmp (arg0, "addbot") == 0 || stricmp (arg0, "add") == 0) {
|
||||
bots.addbot (arg4, arg1, arg2, arg3, arg5, true);
|
||||
|
|
@ -352,6 +353,18 @@ int handleBotCommands (edict_t *ent, const char *arg0, const char *arg1, const c
|
|||
waypoints.cachePoint ();
|
||||
}
|
||||
|
||||
else if (stricmp (arg1, "glp") == 0) {
|
||||
|
||||
|
||||
for (int i = 0; i < waypoints.length (); i++) {
|
||||
|
||||
|
||||
engine.print ("%d - %f", i, waypoints.getLightLevel (i));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// do a cleanup
|
||||
else if (stricmp (arg1, "clean") == 0) {
|
||||
if (!isEmptyStr (arg2)) {
|
||||
|
|
@ -2097,6 +2110,9 @@ void ServerActivate (edict_t *pentEdictList, int edictCount, int clientMax) {
|
|||
// do a level initialization
|
||||
engine.levelInitialize ();
|
||||
|
||||
// update worldmodel
|
||||
illum.resetWorldModel ();
|
||||
|
||||
// do level initialization stuff here...
|
||||
waypoints.init ();
|
||||
waypoints.load ();
|
||||
|
|
@ -2139,6 +2155,9 @@ void ServerDeactivate (void) {
|
|||
// set state to unprecached
|
||||
engine.setUnprecached ();
|
||||
|
||||
// enable lightstyle animations on level change
|
||||
illum.enableAnimation (true);
|
||||
|
||||
// xash is not kicking fakeclients on changelevel
|
||||
if (g_gameFlags & GAME_XASH_ENGINE) {
|
||||
bots.kickEveryone (true, false);
|
||||
|
|
@ -2164,6 +2183,9 @@ void StartFrame (void) {
|
|||
// run periodic update of bot states
|
||||
bots.frame ();
|
||||
|
||||
// update lightstyle animations
|
||||
illum.animateLight ();
|
||||
|
||||
// record some stats of all players on the server
|
||||
for (int i = 0; i < engine.maxClients (); i++) {
|
||||
edict_t *player = engine.entityOfIndex (i + 1);
|
||||
|
|
@ -2229,6 +2251,9 @@ void StartFrame (void) {
|
|||
}
|
||||
bots.calculatePingOffsets ();
|
||||
|
||||
// calculate light levels for all waypoints if needed
|
||||
waypoints.initLightLevels ();
|
||||
|
||||
if (g_gameFlags & GAME_METAMOD) {
|
||||
static auto dmActive = g_engfuncs.pfnCVarGetPointer ("csdm_active");
|
||||
static auto freeForAll = g_engfuncs.pfnCVarGetPointer ("mp_freeforall");
|
||||
|
|
@ -2786,7 +2811,7 @@ typedef void (*entity_func_t) (entvars_t *);
|
|||
gamedll_funcs_t gameDLLFunc;
|
||||
|
||||
SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||
// this function is called right after FuncPointers_t() by the engine in the game DLL (or
|
||||
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
||||
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
||||
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
||||
// that is passed into this function (explanation comes straight from botman). This allows
|
||||
|
|
@ -2824,6 +2849,19 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
|||
functionTable->pfnStartFrame = StartFrame;
|
||||
functionTable->pfnUpdateClientData = UpdateClientData;
|
||||
|
||||
functionTable->pfnPM_Move = [] (playermove_t *playerMove, int server) {
|
||||
// this is the player movement code clients run to predict things when the server can't update
|
||||
// them often enough (or doesn't want to). The server runs exactly the same function for
|
||||
// moving players. There is normally no distinction between them, else client-side prediction
|
||||
// wouldn't work properly (and it doesn't work that well, already...)
|
||||
|
||||
illum.setWorldModel (playerMove->physents[0u].model);
|
||||
|
||||
if (g_gameFlags & GAME_METAMOD) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
}
|
||||
g_functionTable.pfnPM_Move (playerMove, server);
|
||||
};
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -2861,7 +2899,7 @@ SHARED_LIBRARAY_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, in
|
|||
}
|
||||
|
||||
if (!api_GetNewDLLFunctions (functionTable, interfaceVersion)) {
|
||||
logEntry (true, LL_FATAL, "GetNewDLLFunctions: ERROR - Not Initialized.");
|
||||
logEntry (true, LL_ERROR, "GetNewDLLFunctions: ERROR - Not Initialized.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1367,6 +1367,22 @@ void Waypoint::initVisibility (void) {
|
|||
fp.close ();
|
||||
}
|
||||
|
||||
void Waypoint::initLightLevels (void) {
|
||||
// this function get's the light level for each waypoin on the map
|
||||
|
||||
// no waypoints ? no light levels, and only one-time init
|
||||
if (!m_numWaypoints || !cr::fzero (m_waypointLightLevel[0])) {
|
||||
return;
|
||||
}
|
||||
engine.print ("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1");
|
||||
// update light levels for all waypoints
|
||||
for (int i = 0; i < m_numWaypoints; i++) {
|
||||
m_waypointLightLevel[i] = illum.getLightLevel (m_paths[i]->origin);
|
||||
}
|
||||
// disable lightstyle animations on finish (will be auto-enabled on mapchange)
|
||||
illum.enableAnimation (false);
|
||||
}
|
||||
|
||||
void Waypoint::initTypes (void) {
|
||||
m_terrorPoints.clear ();
|
||||
m_ctPoints.clear ();
|
||||
|
|
@ -1506,7 +1522,8 @@ bool Waypoint::load (void) {
|
|||
}
|
||||
|
||||
for (int i = 0; i < m_numWaypoints; i++) {
|
||||
m_waypointDisplayTime[i] = 0.0;
|
||||
m_waypointDisplayTime[i] = 0.0f;
|
||||
m_waypointLightLevel[i] = 0.0f;
|
||||
}
|
||||
|
||||
initPathMatrix ();
|
||||
|
|
@ -2679,6 +2696,7 @@ Waypoint::Waypoint (void) {
|
|||
|
||||
memset (m_visLUT, 0, sizeof (m_visLUT));
|
||||
memset (m_waypointDisplayTime, 0, sizeof (m_waypointDisplayTime));
|
||||
memset (m_waypointLightLevel, 0, sizeof (m_waypointLightLevel));
|
||||
memset (m_infoBuffer, 0, sizeof (m_infoBuffer));
|
||||
|
||||
m_waypointPaths = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue