View Single Post
Re: code to get the illumination at any point on the map
Old
  (#5)
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 - 06-02-2012

It was a simple example.

And now about the actual fall
Now I have understood, why the Valve haven't changed structure which I posted.
The reason is that the structures which are currently in HLSDK intended for a dedicated server (swds.dll), and those structures that I have posted are used in the listen server (hw.dll) to work with openGL.

Well now that in this situation will have to take into account the type of server (listen/dedicated) and on the basis of it to choose structure....

So modified code is here (The prefix "GL_" for names of structures is added, has replaced 'GL_texture_t::UNKNOWN[2u]' to original members, fixed offset for 'GL_mnode_t::numsurfaces', function RecursiveLightPoint() now a template, added function ActualRecursiveLightPoint(), the call in function 'R_LightPoint' of function 'RecursiveLightPoint' has been changed to a call 'ActualRecursiveLightPoint')

Code:
struct GL_texture_t	// NOT USED BY LIGHTING CODE, BUT STILL AS BONUS
{
/*! Off=0(0)*/	char		name[16];
/*! Off=16(4)*/	unsigned int	width, height;
/*! Off=24(6)*/	int			gl_texturenum;
/*! Off=28(7)*/	msurface_t	*texturechain;	// for gl_texsort drawing
/*! Off=32(8)*/	int			anim_total;				// total tenths in sequence (0 = no)
/*! Off=36(9)*/	int			anim_min, anim_max;		// time for this frame min <=time< max
/*! Off=44(11)*/	texture_t *anim_next;		// in the animation sequence
/*! Off=48(12)*/	texture_t *alternate_anims;	// bmodels in frame 1 use these
/*! Off=52(13)*/	unsigned int	offsets[MIPLEVELS];		// four mip maps stored
/*! Off=68(17)*/	unsigned int	paloffset;
};	// sizeof (GL_texture_t) == 72 (18)
struct GL_mleaf_t	// NOT USED BY LIGHTING CODE, BUT STILL HERE AS A BONUS
{
// common with node
/*! Off=0(0)*/	int			contents;		// wil be a negative contents number
/*! 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;

// leaf specific
/*! Off=36(9)*/	unsigned char		*compressed_vis;
/*! Off=40(10)*/	efrag_t	*efrags;

/*! Off=44(11)*/	msurface_t	**firstmarksurface;
/*! Off=48(12)*/	int			nummarksurfaces;
/*! Off=52(13)*/	int			key;			// BSP sequence number for leaf's contents
/*! Off=56(14)*/	unsigned char		ambient_sound_level[NUM_AMBIENTS];
};	// sizeof (GL_mleaf_t) == 60 (15)
struct GL_msurface_t
{
/*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)*/	BOOL	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.length = 0u;
		cl_lightstyle.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.ServerPrintf ("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, BOOL 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 = (start | plane->normal) - plane->dist;
	back = (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> ((mid | Vector (tex->vecs[0])) + tex->vecs[0][3]);
		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...
		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);
}
const bool ActualRecursiveLightPoint (const Math::Vector3D &start, const Math::Vector3D &end)
{
	return IS_DEDICATED_SERVER () ?
		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.
	assert (sv_worldmodel != NULL);

	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 ());
}
}

static inline const char *const FormatBuffer (const char *const format, ...)
{
	static char string[4096u];

	va_list argumentPointer;

	// Concatenate all the arguments in one string....
	va_start (argumentPointer, format);
		vsnprintf (string, sizeof (string), format, argumentPointer);
	va_end (argumentPointer);

	return string;
}

inline void ShowMagic (void)
{
	const edict_t *const hostPlayerEdict (INDEXENT (1u));

	if (hostPlayerEdict == NULL || hostPlayerEdict->free)
		return;

	CLIENT_PRINTF (hostPlayerEdict, print_chat, FormatBuffer ("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)));
}
P.S. Excuse if that and also sorry for bad english
  
Reply With Quote