View Single Post
Re: code to get the illumination at any point on the map
Old
  (#13)
Immortal_BLG
Member
 
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
Default Re: code to get the illumination at any point on the map - 16-03-2012

Quote:
Originally Posted by KWo View Post
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....
  
Reply With Quote