Immortal_BLG |
16-03-2012 01:33 |
Re: code to get the illumination at any point on the map
Quote:
Originally Posted by KWo
(Post 64319)
It would be much more easy if You could post a working code instead just examples... :)
[EDIT]
If You want to see my code - send me a pm with Your email address, I can send it You that way. I wanted to upload it at the mirror of the filebase (CFE server), but it looks like Ancient has changed some access rights and nobody can browse my files there. :(
[/EDIT]
|
Eventually I decided to compile the project podbot_mm (in MSVC 2010) yourself, pre-inserting my code in order to eliminate all errors at the building.
So KWo HERE you can take the project (the source code and DLL), and below I present the corrected code:
Code:
#include <com_model.h>
#include <pm_defs.h>
#define SURF_PLANEBACK 2
#define SURF_DRAWSKY 4
#define SURF_DRAWSPRITE 8
#define SURF_DRAWTURB 0x10
#define SURF_DRAWTILED 0x20
#define SURF_DRAWBACKGROUND 0x40
struct GL_msurface_t
{
#define SURF_UNDERWATER 0x80 // ONLY FOR OpenGL!!!
//#define SURF_DONTWARP 0x100 // ONLY FOR OpenGL!!! (EXISTS?!?!?!?!?!??!?!?!?!?!?!??!)
/*off=0(0)*/ int visframe; // should be drawn when node is crossed
/*off=4(1)*/ mplane_t *plane; // pointer to shared plane
/*off=8(2)*/ int flags; // see SURF_* #defines
/*off=12(3)*/ int firstedge; // look up in model->surfedges[], negative numbers are backwards edges
/*off=16(4)*/ int numedges;
/*off=20(5)*/ short texturemins[2]; // smallest s/t position on the surface.
/*off=24(6)*/ short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces
/*off=28(7)*/ int light_s, light_t; // gl lightmap coordinates
/*off=36(9)*/ struct glpoly_t *polys; // multiple if warped
/*off=40(10)*/ msurface_t *texturechain;
/*off=44(11)*/ mtexinfo_t *texinfo;
// lighting info
/*off=48(12)*/ int dlightframe; // last frame the surface was checked by an animated light
/*off=52(13)*/ int dlightbits; // dynamically generated. Indicates if the surface illumination
// is modified by an animated light.
/*off=56(14)*/ int lightmaptexturenum;
/*off=60(15)*/ unsigned char styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights
// no one surface can be effected by more than 4
// animated lights.
/*off=64(16)*/ int cached_light[MAXLIGHTMAPS]; // values currently used in lightmap
/*off=80(20)*/ qboolean cached_dlight; // true if dynamic light in cache
/*off=84(21)*/ color24 *samples; // [numstyles*surfsize]
/*off=88(22)*/ decal_t *pdecals;
}; // sizeof (GL_msurface_t) == 92 (23)
struct GL_mnode_t
{
enum ChildrenType_t
{
ChildrenType_Front,
ChildrenType_Back,
ChildrenType_Total
};
// common with leaf
/*! Off=0(0)*/ int contents; // 0, to differentiate from leafs
/*! Off=4(1)*/ int visframe; // node needs to be traversed if current
/*! Off=8(2)*/ Vector mins, maxs; // for bounding box culling
/*! Off=32(8)*/ mnode_t *parent;
// node specific
/*! Off=36(9)*/ mplane_t *plane;
/*! Off=40(10)*/ mnode_t *children[ChildrenType_Total];
/*! Off=48(12)*/ unsigned short firstsurface;
/*! Off=50(12.5)*/ unsigned short numsurfaces;
}; // sizeof (GL_mnode_t) == 52 (13)
#define MAX_LIGHTSTYLES 64
#define MAX_LIGHTSTYLEVALUE 256
struct lightstyle_t
{
int length;
char map[MAX_LIGHTSTYLES];
};
lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
int d_lightstylevalue[MAX_LIGHTSTYLEVALUE]; // 8.8 fraction of base light value
model_t *sv_worldmodel (NULL); // Analog of sv.worldmodel.
static inline void SetupLightStyles (void)
{
// Setup lighting information....
// reset all light styles
for (unsigned char index (0u); index < MAX_LIGHTSTYLES; ++index)
{
cl_lightstyle[index].length = 0u;
cl_lightstyle[index].map[0u] = '\0';
}
for (unsigned short index (0u); index < MAX_LIGHTSTYLEVALUE; ++index)
d_lightstylevalue[index] = 264; // normal light value
}
static inline void R_AnimateLight (void)
{
// light animations
// 'm' is normal light, 'a' is no light, 'z' is double bright
const int i (static_cast <int> (gpGlobals->time * 10.0f));
int k;
for (unsigned char j (0u); j < MAX_LIGHTSTYLES; ++j)
{
if (cl_lightstyle[j].length == 0u)
{
d_lightstylevalue[j] = 256;
continue;
}
k = cl_lightstyle[j].map[i % cl_lightstyle[j].length] - 'a';
k *= 22;
d_lightstylevalue[j] = k;
}
}
static inline void CallbackLightStyle (const unsigned char style, char *const value)
{
if (style >= MAX_LIGHTSTYLES)
{
g_engfuncs.pfnServerPrint ("SVC_LIGHTSTYLE > MAX_LIGHTSTYLES\n");
return;
}
// OCCURS!
if (value == NULL)
{
cl_lightstyle[style].length = 0u;
cl_lightstyle[style].map[0u] = '\0';
return;
}
const unsigned short maximumCopyAmount (sizeof (cl_lightstyle[style].map) - sizeof ('\0'));
strncpy (cl_lightstyle[style].map, value, maximumCopyAmount);
cl_lightstyle[style].map[maximumCopyAmount] = '\0';
cl_lightstyle[style].length = strlen (cl_lightstyle[style].map);
}
static inline void CallbackStartFrame (void)
{
R_AnimateLight ();
inline void ShowMagic (void);
ShowMagic ();
}
static inline void CallbackPM_Move (playermove_t *const playerMove, const bool server)
{
// Reliability checks.
assert (playerMove != NULL);
assert (server == true); // ALWAYS SHOULD BE TRUE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Honestly this is need only once per changelevel, but....
sv_worldmodel = playerMove->physents[0u].model; // Always point at sv.worldmodel!
// Reliability check.
assert (sv_worldmodel != NULL);
}
static WINAPI GiveFnptrsToDll (enginefuncs_t *pengfuncsFromEngine, globalvars_t *pGlobals)
{
// get the engine functions from the engine...
memcpy (&g_engfuncs, pengfuncsFromEngine, sizeof (g_engfuncs));
gpGlobals = pGlobals;
SetupLightStyles ();
}
static void pfnLightStyle (int style, char *value)
{
LIGHT_STYLE (style, value);
or ->>---------->>------------->>---------------------->>-------------------|
|
// Update light style for fake clients.... |
CallbackLightStyle (static_cast <const unsigned char> (style), value); |
|
RETURN_META (MRES_IGNORED); <------------------<<------------<<-------------|
}
static void pfnStartFrame (void)
{
// this function starts a video frame. It is called once per video frame by the engine. If
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
// placing a hook on it, we have a good place to do things that should be done continuously
// during the game, for example making the bots think (yes, because no Think() function exists
// for the bots by the MOD side, remember). Also here we have control on the bot population,
// for example if a new player joins the server, we should disconnect a bot, and if the
// player population decreases, we should fill the server with other bots.
CallbackStartFrame ();
(*g_engfuncs.pfnStartFrame) ();
or
RETURN_META (MRES_IGNORED);
}
static void PM_Move (playermove_t *playerMove, qboolean 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...)
CallbackPM_Move (playerMove, server == TRUE);
(*g_engfuncs.pfnPM_Move) (playerMove, server);
or
RETURN_META (MRES_IGNORED);
}
struct Color
{
int red;
int green;
int blue;
inline void Reset (void) { red = green = blue = 0; }
inline const unsigned int GetAvg (void) const { return (red + green + blue) / (sizeof (Color) / sizeof (int)); }
};
/*
=============================================================================
LIGHT SAMPLING
=============================================================================
*/
namespace Light
{
//static const mplane_t *lightplane (NULL);
//static Vector lightspot;
static Color g_pointColor;
template <typename nodeType, typename surfaceType> static const bool RecursiveLightPoint (const nodeType *const node, const Vector &start, const Vector &end)
{
float front, back, frac;
int side;
mplane_t *plane;
Vector mid;
surfaceType *surf;
int s, t, ds, dt;
int i;
mtexinfo_t *tex;
color24 *lightmap;
unsigned int scale;
unsigned char maps;
// Reliability check.
assert (node != NULL);
if (node->contents < 0)
return false; // didn't hit anything
// Determine which side of the node plane our points are on
// FIXME: optimize for axial
plane = node->plane;
front = DotProduct (start, plane->normal) - plane->dist;
back = DotProduct (end, plane->normal) - plane->dist;
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 <nodeType, surfaceType> (reinterpret_cast <nodeType *> (node->children[side]), start, end);
// calculate mid point
frac = front / (front - back);
mid = start + (end - start) * frac;
// go down front side
if (RecursiveLightPoint <nodeType, surfaceType> (reinterpret_cast <nodeType *> (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;
surf = reinterpret_cast <surfaceType *> (sv_worldmodel->surfaces) + node->firstsurface;
for (i = 0; i < node->numsurfaces; ++i, ++surf)
{
if (surf->flags & SURF_DRAWTILED)
continue; // no lightmaps
tex = surf->texinfo;
// See where in lightmap space our intersection point is
s = static_cast <int> (DotProduct (mid, Vector (tex->vecs[0])) + tex->vecs[0][3]);
t = static_cast <int> (DotProduct (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...
ds = s - surf->texturemins[0];
dt = t - surf->texturemins[1];
if (ds > surf->extents[0] || dt > surf->extents[1])
continue;
if (surf->samples == NULL)
return true;
ds >>= 4;
dt >>= 4;
g_pointColor.Reset (); // Reset point color.
const int smax ((surf->extents[0] >> 4) + 1);
const int tmax ((surf->extents[1] >> 4) + 1);
const int size (smax * tmax);
lightmap = surf->samples + dt * smax + ds;
// Compute the lightmap color at a particular point
for (maps = 0u; maps < MAXLIGHTMAPS && surf->styles[maps] != 255u; ++maps)
{
scale = d_lightstylevalue[surf->styles[maps]];
g_pointColor.red += lightmap->r * scale;
g_pointColor.green += lightmap->g * scale;
g_pointColor.blue += lightmap->b * scale;
lightmap += size; // skip to next lightmap
}
g_pointColor.red >>= 8u;
g_pointColor.green >>= 8u;
g_pointColor.blue >>= 8u;
return true;
}
// go down back side
return RecursiveLightPoint <nodeType, surfaceType> (reinterpret_cast <nodeType *> (node->children[!side]), mid, end);
}
inline const bool IsSoftwareDrawingMode (void)
{
static const bool isSoftwareDrawingMode (IS_DEDICATED_SERVER () || GetModuleHandle ("sw.dll") != NULL);
return isSoftwareDrawingMode;
}
const bool ActualRecursiveLightPoint (const Vector &start, const Vector &end)
{
return IsSoftwareDrawingMode () ?
RecursiveLightPoint <mnode_t, msurface_t> (sv_worldmodel->nodes, start, end) :
RecursiveLightPoint <GL_mnode_t, GL_msurface_t> (reinterpret_cast <GL_mnode_t *> (sv_worldmodel->nodes), start, end);
}
static inline const unsigned char R_LightPoint (const Vector &p)
{
// Reliability check.
if (sv_worldmodel == NULL)
return 0u;
if (sv_worldmodel->lightdata == NULL)
return 255u;
Vector end (p);
end.z -= 2048.0f;
return ActualRecursiveLightPoint (p, end) == false ? 0u : static_cast <unsigned char> (g_pointColor.GetAvg ());
}
}
inline void ShowMagic (void)
{
edict_t *const hostPlayerEdict (INDEXENT (1u));
if (hostPlayerEdict == NULL || hostPlayerEdict->free || hostPlayerEdict->pvPrivateData == NULL || (hostPlayerEdict->v.flags & FL_FAKECLIENT))
return;
char message[192];
_snprintf (message, sizeof (message), "ShowMagic(): \"%s\"->v.light_level=%i, R_LightPoint(hostOrg)=%i\n", STRING (hostPlayerEdict->v.netname), hostPlayerEdict->v.light_level, Light::R_LightPoint (hostPlayerEdict->v.origin));
CLIENT_PRINTF (hostPlayerEdict, print_chat, message);
}
Changes:
1) add the required headers from HLSDK;
2) added definitions of 'SURF_*' constants;
3) type 'BOOL' is changed to 'qboolean';
4) type 'Math::Vector3D' is changed to HLSDK 'Vector';
5) added check "hostPlayerEdict->pvPrivateData == NULL" in a function 'ShowMagic';
6) in a function 'SetupLightStyles' fixed bug related to 'cl_lightstyle' array.
7) changed the name of the function 'g_engfuncs.ServerPrintf' to 'g_engfuncs.pfnServerPrint'
8) function 'DotProduct' is used instead of the overloaded operator logical OR for calculation of scalar product of vectors.
Excuse me. It all is simply a consequence of the porting of code from my bot, and also because of that that I this code up until that time didn't compile/not checked properly....
|