Exemplo n.º 1
0
/*
==================
SV_CheckTimeouts

If a packet has not been received from a client for timeout->value
seconds, drop the conneciton.  Server frames are used instead of
realtime to avoid dropping the local client while debugging.

When a client is normally dropped, the client_t goes into a zombie state
for a few seconds to make sure any final reliable message gets resent
if necessary
==================
*/
void SV_CheckTimeouts()
{
	guard(SV_CheckTimeouts);
	int droppoint = svs.realtime - appRound(timeout->value * 1000);
	int zombiepoint = svs.realtime - appRound(zombietime->value * 1000);

	int		i;
	client_t *cl;
	for (i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++)
	{
		// message times may be wrong across a changelevel
		if (cl->lastmessage > svs.realtime)
			cl->lastmessage = svs.realtime;

		if (cl->state == cs_zombie && cl->lastmessage < zombiepoint)
		{
			cl->state = cs_free;	// can now be reused
			continue;
		}
		if ((cl->state == cs_connected || cl->state == cs_spawned) && cl->lastmessage < droppoint)
		{
			SV_DropClient(cl, "timed out");
			cl->state = cs_free;	// don't bother with zombie state
		}
	}
	unguard;
}
Exemplo n.º 2
0
static void CalcVrect()
{
	float frac = scr_viewsize->Clamp(40, 100) / 100.0f;

	scr_vrect.width = appRound(viddef.width * frac);
	scr_vrect.height = appRound(viddef.height * frac);

	scr_vrect.width  &= ~1;		// align(2)
	scr_vrect.height &= ~1;		// align(2)

	scr_vrect.x = (viddef.width - scr_vrect.width) / 2;
	scr_vrect.y = (viddef.height - scr_vrect.height) / 2;
}
Exemplo n.º 3
0
// Used for spatializing channels and autosounds
static void S_SpatializeOrigin(const CVec3 &origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
{
	if (cls.state != ca_active)
	{
		*left_vol = *right_vol = 255;
		return;
	}

	// calculate stereo seperation and distance attenuation
	CVec3 source_vec;
	VectorSubtract(origin, listener_origin, source_vec);

	float dist = source_vec.NormalizeFast();
	dist -= SOUND_FULLVOLUME;
	if (dist < 0)
		dist = 0;			// close enough to be at full volume
	dist *= dist_mult;		// different attenuation levels

	float d = dot(listener_right, source_vec);

	float lscale, rscale;
	if (dma.channels == 1 || !dist_mult)
	{	// no attenuation = no spatialization
		rscale = 1.0f;
		lscale = 1.0f;
	}
	else
	{
		rscale = 0.5f * (1.0f + d);
		lscale = 0.5f * (1.0f - d);
	}

	// swap left and right volumes
	if (s_reverse_stereo->integer)
		Exchange(lscale, rscale);

	float scale;
	// add in distance effect
	scale = (1.0f - dist) * rscale;
	*right_vol = appRound(master_vol * scale);
	if (*right_vol < 0)
		*right_vol = 0;

	scale = (1.0f - dist) * lscale;
	*left_vol = appRound(master_vol * scale);
	if (*left_vol < 0)
		*left_vol = 0;
}
Exemplo n.º 4
0
void S_Update_()
{
	guard(S_Update_);

	if (!sound_started) return;

	SNDDMA_BeginPainting();

	if (!dma.buffer) return;

	// Updates DMA time
	GetSoundtime();

	// check to make sure that we haven't overshot
	if (paintedtime < soundtime)
	{
		Com_DPrintf("S_Update_ : overflow\n");
		paintedtime = soundtime;
	}

	// mix ahead of current position
	unsigned endtime = soundtime + appRound(s_mixahead->value * dma.speed);

	// mix to an even submission block size
	endtime = Align(endtime, dma.submission_chunk);
	int samps = dma.samples >> (dma.channels-1);
	if (endtime - soundtime > samps)
		endtime = soundtime + samps;

	S_PaintChannels(endtime);

	SNDDMA_Submit();
	unguard;
}
Exemplo n.º 5
0
void SaturateColor4b(color_t *c)
{
	float sat = r_saturation->value;
	if (sat != 1.0f)
	{
		float r = c->c[0];
		float g = c->c[1];
		float b = c->c[2];
		float light = (r + g + b) / 3;
		SATURATE(r,light,sat);
		SATURATE(g,light,sat);
		SATURATE(b,light,sat);
		c->c[0] = appRound(r);
		c->c[1] = appRound(g);
		c->c[2] = appRound(b);
	}
}
Exemplo n.º 6
0
// Project 3D point to screen coordinates; return false when not in view frustum
bool ProjectToScreen(const CVec3 &pos, int scr[2])
{
	CVec3	vec;
	VectorSubtract(pos, vp.view.origin, vec);

	float z = dot(vec, vp.view.axis[0]);
	if (z <= gl_znear->value) return false;			// not visible

	float x = dot(vec, vp.view.axis[1]) / z / vp.t_fov_x;
	if (x < -1 || x > 1) return false;

	float y = dot(vec, vp.view.axis[2]) / z / vp.t_fov_y;
	if (y < -1 || y > 1) return false;

	scr[0] = appRound(vp.x + vp.w * (0.5 - x / 2));
	scr[1] = appRound(vp.y + vp.h * (0.5 - y / 2));

	return true;
}
Exemplo n.º 7
0
static void SetLight_f(bool usage, int argc, char **argv)
{
	if (usage || argc != 3)
	{
		appPrintf("Usage: setlight <style> <value=0..2>\n");
		return;
	}
	if (!cls.cheatsEnabled)
		return;
	int style = atoi(argv[1]);
	if (style < 0 || style > 255)
	{
		appWPrintf("bad style: %d\n", style);
		return;
	}
	char str[2];
	str[0] = appRound(atof(argv[2]) * ('m' - 'a')) + 'a';
	str[1] = 0;
	CL_SetLightstyle(style, str);
}
Exemplo n.º 8
0
void USkeletalMesh::ConvertWedges(CSkelMeshLod &Lod, const TArray<FVector> &MeshPoints, const TArray<FMeshWedge> &MeshWedges, const TArray<FVertInfluence> &VertInfluences)
{
	guard(USkeletalMesh::ConvertWedges);

	struct CVertInfo
	{
		int		NumInfs;		// may be higher than NUM_INFLUENCES
		int		Bone[NUM_INFLUENCES];
		float	Weight[NUM_INFLUENCES];
	};

	int i, j;

	CVertInfo *Verts = new CVertInfo[MeshPoints.Num()];
	memset(Verts, 0, MeshPoints.Num() * sizeof(CVertInfo));

	// collect influences per vertex
	for (i = 0; i < VertInfluences.Num(); i++)
	{
		const FVertInfluence &Inf = VertInfluences[i];
		CVertInfo &V = Verts[Inf.PointIndex];
		int NumInfs = V.NumInfs++;
		int idx = NumInfs;
		if (NumInfs >= NUM_INFLUENCES)
		{
			// overflow
			// find smallest weight smaller than current
			float w = Inf.Weight;
			idx = -1;
			for (j = 0; j < NUM_INFLUENCES; j++)
			{
				if (V.Weight[j] < w)
				{
					w = V.Weight[j];
					idx = j;
					// continue - may be other weight will be even smaller
				}
			}
			if (idx < 0) continue;	// this weight is smaller than other
		}
		// add influence
		V.Bone[idx]   = Inf.BoneIndex;
		V.Weight[idx] = Inf.Weight;
	}

	// normalize influences
	for (i = 0; i < MeshPoints.Num(); i++)
	{
		CVertInfo &V = Verts[i];
		if (V.NumInfs == 0)
		{
			appPrintf("WARNING: Vertex %d has 0 influences\n", i);
			V.NumInfs = 1;
			V.Bone[0] = 0;
			V.Weight[0] = 1.0f;
			continue;
		}
		if (V.NumInfs <= NUM_INFLUENCES) continue;	// no normalization is required
		float s = 0;
		for (j = 0; j < NUM_INFLUENCES; j++)		// count sum
			s += V.Weight[j];
		s = 1.0f / s;
		for (j = 0; j < NUM_INFLUENCES; j++)		// adjust weights
			V.Weight[j] *= s;
	}

	// create vertices
	Lod.AllocateVerts(MeshWedges.Num());
	for (i = 0; i < MeshWedges.Num(); i++)
	{
		const FMeshWedge &SW = MeshWedges[i];
		CSkelMeshVertex  &DW = Lod.Verts[i];
		DW.Position = CVT(MeshPoints[SW.iVertex]);
		DW.UV = CVT(SW.TexUV);
		// DW.Normal and DW.Tangent are unset
		// setup Bone[] and Weight[]
		const CVertInfo &V = Verts[SW.iVertex];
		unsigned PackedWeights = 0;
		for (j = 0; j < V.NumInfs; j++)
		{
			DW.Bone[j]   = V.Bone[j];
			PackedWeights |= appRound(V.Weight[j] * 255) << (j * 8);
		}
		DW.PackedWeights = PackedWeights;
		for (/* continue */; j < NUM_INFLUENCES; j++)	// place end marker and zero weight
		{
			DW.Bone[j] = -1;
		}
	}

	delete Verts;

	unguard;
}
Exemplo n.º 9
0
void UVertMesh::BuildNormals()
{
	// UE1 meshes have no stored normals, should build them
	// This function is similar to BuildNormals() from SkelMeshInstance.cpp
	int numVerts = Verts.Num();
	int i;
	Normals.Empty(numVerts);
	Normals.AddZeroed(numVerts);
	TArray<CVec3> tmpVerts, tmpNormals;
	tmpVerts.AddZeroed(numVerts);
	tmpNormals.AddZeroed(numVerts);
	// convert verts
	for (i = 0; i < numVerts; i++)
	{
		const FMeshVert &SV = Verts[i];
		CVec3           &DV = tmpVerts[i];
		DV[0] = SV.X * MeshScale.X;
		DV[1] = SV.Y * MeshScale.Y;
		DV[2] = SV.Z * MeshScale.Z;
	}
	// iterate faces
	for (i = 0; i < Faces.Num(); i++)
	{
		const FMeshFace &F = Faces[i];
		// get vertex indices
		int i1 = Wedges[F.iWedge[0]].iVertex;
		int i2 = Wedges[F.iWedge[2]].iVertex;		// note: reverse order in comparison with SkeletalMesh
		int i3 = Wedges[F.iWedge[1]].iVertex;
		// iterate all frames
		for (int j = 0; j < FrameCount; j++)
		{
			int base = VertexCount * j;
			// compute edges
			const CVec3 &V1 = tmpVerts[base + i1];
			const CVec3 &V2 = tmpVerts[base + i2];
			const CVec3 &V3 = tmpVerts[base + i3];
			CVec3 D1, D2, D3;
			VectorSubtract(V2, V1, D1);
			VectorSubtract(V3, V2, D2);
			VectorSubtract(V1, V3, D3);
			// compute normal
			CVec3 norm;
			cross(D2, D1, norm);
			norm.Normalize();
			// compute angles
			D1.Normalize();
			D2.Normalize();
			D3.Normalize();
			float angle1 = acos(-dot(D1, D3));
			float angle2 = acos(-dot(D1, D2));
			float angle3 = acos(-dot(D2, D3));
			// add normals for triangle verts
			VectorMA(tmpNormals[base + i1], angle1, norm);
			VectorMA(tmpNormals[base + i2], angle2, norm);
			VectorMA(tmpNormals[base + i3], angle3, norm);
		}
	}
	// normalize and convert computed normals
	for (i = 0; i < numVerts; i++)
	{
		CVec3 &SN     = tmpNormals[i];
		FMeshNorm &DN = Normals[i];
		SN.Normalize();
		DN.X = appRound(SN[0] * 511 + 512);
		DN.Y = appRound(SN[1] * 511 + 512);
		DN.Z = appRound(SN[2] * 511 + 512);
	}
}
Exemplo n.º 10
0
// Cinematic streaming and voice over network
void S_RawSamples(int samples, int rate, int width, int channels, byte *data)
{
	int		i;
	int		src, dst;

	if (!sound_started)
		return;

	if (s_rawend < paintedtime)
		s_rawend = paintedtime;
	float scale = (float)rate / dma.speed;

	if (channels == 2 && width == 2)
	{
		if (scale == 1.0)
		{	// optimized case
			for (i=0 ; i<samples ; i++)
			{
				dst = s_rawend&(MAX_RAW_SAMPLES-1);
				s_rawend++;
				s_rawsamples[dst].left  = ((short *)data)[i*2]   << 8;
				s_rawsamples[dst].right = ((short *)data)[i*2+1] << 8;
			}
		}
		else
		{
			for (i=0 ; ; i++)
			{
				src = appRound(i*scale);
				if (src >= samples)
					break;
				dst = s_rawend&(MAX_RAW_SAMPLES-1);
				s_rawend++;
				s_rawsamples[dst].left  = ((short *)data)[src*2]   << 8;
				s_rawsamples[dst].right = ((short *)data)[src*2+1] << 8;
			}
		}
	}
	else if (channels == 1 && width == 2)
	{
		for (i=0 ; ; i++)
		{
			src = appRound(i*scale);
			if (src >= samples)
				break;
			dst = s_rawend&(MAX_RAW_SAMPLES-1);
			s_rawend++;
			s_rawsamples[dst].left  = ((short *)data)[src] << 8;
			s_rawsamples[dst].right = ((short *)data)[src] << 8;
		}
	}
	else if (channels == 2 && width == 1)
	{
		for (i=0 ; ; i++)
		{
			src = appRound(i*scale);
			if (src >= samples)
				break;
			dst = s_rawend&(MAX_RAW_SAMPLES-1);
			s_rawend++;
			s_rawsamples[dst].left  = ((char *)data)[src*2]   << 16;
			s_rawsamples[dst].right = ((char *)data)[src*2+1] << 16;
		}
	}
	else if (channels == 1 && width == 1)
	{
		for (i=0 ; ; i++)
		{
			src = appRound(i*scale);
			if (src >= samples)
				break;
			dst = s_rawend&(MAX_RAW_SAMPLES-1);
			s_rawend++;
			s_rawsamples[dst].left  = (((byte *)data)[src]-128) << 16;
			s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
		}
	}
}
Exemplo n.º 11
0
/*
====================
S_StartSound

Validates the parms and ques the sound up
if pos is NULL, the sound will be dynamically sourced from the entity
Entchannel 0 will never override a playing sound
====================
*/
void S_StartSound(const CVec3 *origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs)
{
	if (!sound_started) return;
	if (!sfx) return;

	if (sfx->Name[0] == '*')
		sfx = GetPlayerSound(&cl_entities[entnum].current, sfx->Name);

	// make sure the sound is loaded
	sfxcache_t *sc = S_LoadSound(sfx);
	if (!sc)
		return;		// couldn't load the sound's data

	int vol = appRound(fvol*255);

	// make the playsound_t
	playsound_t *ps = S_AllocPlaysound();
	if (!ps) return;

	if (origin)
	{
		ps->origin = *origin;
		ps->fixed_origin = true;
	}
	else
		ps->fixed_origin = false;

	ps->entnum      = entnum;
	ps->entchannel  = entchannel;
	ps->attenuation = attenuation;
	ps->volume      = vol;
	ps->sfx         = sfx;

	// drift s_beginofs
	int start = appRound(cl.frame.servertime / 1000.0f * dma.speed + s_beginofs);
	if (start < paintedtime)
	{
		start = paintedtime;
		s_beginofs = start - appRound(cl.frame.servertime / 1000.0f * dma.speed);
	}
	else if (start > paintedtime + 0.3 * dma.speed)
	{
		start = appRound(paintedtime + 0.1 * dma.speed);
		s_beginofs = start - appRound(cl.frame.servertime / 1000.0f * dma.speed);
	}
	else
	{
		s_beginofs-=10;
	}

	if (!timeofs)
		ps->begin = paintedtime;
	else
		ps->begin = appRound(start + timeofs * dma.speed);

	// sort into the pending sound list
	playsound_t *sort;
	for (sort = s_pendingplays.next; sort != &s_pendingplays && sort->begin < ps->begin; sort = sort->next)
		; // empty

	ps->next = sort;
	ps->prev = sort->prev;

	ps->next->prev = ps;
	ps->prev->next = ps;
}
Exemplo n.º 12
0
void SV_LinkEdict(edict_t *ent)
{
	guard(SV_LinkEdict);

	int		i, j, k;

	//!! HOOK - move outside ?
	if (bspfile.type != map_q2)
	{
		if (ent->s.modelindex >= 0 && ent->s.modelindex < MAX_MODELS)
		{
			// link model hook
			const char *modelName = sv.configstrings[CS_MODELS + ent->s.modelindex];
			if (!strcmp(modelName, "models/objects/dmspot/tris.md2"))
			{
				// teleporter (source+target) was found
//				appPrintf(S_CYAN"teleport: %g %g %g\n", VECTOR_ARG(ent->s.origin));
				return;			// simply do not link model; trigger entity will be added anyway
			}
		}
	}

	if (ent->area.prev)
		SV_UnlinkEdict(ent);	// unlink from old position (i.e. relink edict)

	if (ent == ge->edicts)
		return;					// don't add the world

	if (!ent->inuse)
		return;

	entityHull_t &ex = ents[NUM_FOR_EDICT(ent)];
	memset(&ex, 0, sizeof(entityHull_t));
	ex.owner = ent;
	ex.axis.FromEuler(ent->s.angles);

	// set the size
	VectorSubtract(ent->bounds.maxs, ent->bounds.mins, ent->size);

	// encode the size into the entity_state for client prediction
	if (ent->solid == SOLID_BBOX)
	{
		// assume that x/y are equal and symetric
		i = appRound(ent->bounds.maxs[0] / 8);
		// z is not symetric
		j = appRound(-ent->bounds.mins[2] / 8);
		// and z maxs can be negative...
		k = appRound((ent->bounds.maxs[2] + 32) / 8);
		// original Q2 have bounded i/j/k/ with lower margin==1 (for client prediction only); this will
		// produce incorrect collision test when bbox mins/maxs is (0,0,0)
		i = bound(i, 0, 31);		// mins/maxs[0,1] range is -248..0/0..248
		j = bound(j, 0, 31);		// mins[2] range is [-248..0]
		k = bound(k, 0, 63);		// maxs[2] range is [-32..472]

		// if SVF_DEADMONSTER, s.solid should be 0
		ent->s.solid = (ent->svflags & SVF_DEADMONSTER) ? 0 : (k<<10) | (j<<5) | i;

		i *= 8;
		j *= 8;
		k *= 8;
		ex.bounds.mins.Set(-i, -i, -j);
		ex.bounds.maxs.Set(i, i, k - 32);
		ex.bounds.GetCenter(ex.center);
		ex.center.Add(ent->s.origin);
		ex.model  = NULL;
		ex.radius = VectorDistance(ex.bounds.maxs, ex.bounds.mins) / 2;
	}
	else if (ent->solid == SOLID_BSP)
	{
		ex.model = sv.models[ent->s.modelindex];
		if (!ex.model) Com_DropError("MOVETYPE_PUSH with a non bsp model");
		CVec3	v;
		ex.model->bounds.GetCenter(v);
		UnTransformPoint(ent->s.origin, ex.axis, v, ex.center);
		ex.radius = ex.model->radius;

		ent->s.solid = 31;		// a SOLID_BBOX will never create this value (mins=(-248,-248,0) maxs=(248,248,-32))
	}
	else if (ent->solid == SOLID_TRIGGER)
	{
		ent->s.solid = 0;
		// check for model link
		ex.model = sv.models[ent->s.modelindex];
		if (!ex.model)
		{
			// model not attached by game, check entstring
			//?? can optimize: add 'bool spawningEnts', set to 'true' before SpawnEntities()
			//?? and 'false' after; skip code below when 'false'
			for (triggerModelLink_t *link = bspfile.modelLinks; link; link = link->next)
#define CMP(n)	(fabs(ent->s.origin[n] - link->origin[n]) < 0.5f)
				if (CMP(0) && CMP(1) && CMP(2))
				{
					CBspModel *model = CM_InlineModel(link->modelIdx);
					VectorSubtract(model->bounds.maxs, ent->s.origin, ent->bounds.maxs);
					VectorSubtract(model->bounds.mins, ent->s.origin, ent->bounds.mins);
					break;
				}
#undef CMP
		}
	}
	else
		ent->s.solid = 0;

	// set the abs box
	if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]))
	{
		// expand for rotation
		for (i = 0; i < 3 ; i++)
		{
			ent->absBounds.mins[i] = ex.center[i] - ex.radius;
			ent->absBounds.maxs[i] = ex.center[i] + ex.radius;
		}
	}
	else
	{	// normal
		VectorAdd(ent->s.origin, ent->bounds.mins, ent->absBounds.mins);
		VectorAdd(ent->s.origin, ent->bounds.maxs, ent->absBounds.maxs);
	}

	// because movement is clipped an epsilon away from an actual edge,
	// we must fully check even when bounding boxes don't quite touch
	for (i = 0; i < 3; i++)
	{
		ent->absBounds.mins[i] -= 1;
		ent->absBounds.maxs[i] += 1;
	}

	// link to PVS leafs
	ent->num_clusters = 0;
	ent->zonenum      = 0;
	ent->zonenum2     = 0;

	// get all leafs, including solids
	CBspLeaf *leafs[MAX_TOTAL_ENT_LEAFS];
	int topnode;
	int num_leafs = CM_BoxLeafs(ent->absBounds, ARRAY_ARG(leafs), &topnode);

	// set zones
	int clusters[MAX_TOTAL_ENT_LEAFS];
	for (i = 0; i < num_leafs; i++)
	{
		clusters[i] = leafs[i]->cluster;
		int zone = leafs[i]->zone;
		if (zone)
		{	// doors may legally straggle two zones,
			// but nothing should evern need more than that
			if (ent->zonenum && ent->zonenum != zone)
			{
				if (ent->zonenum2 && ent->zonenum2 != zone && sv.state == ss_loading)
					Com_DPrintf("Object touching 3 zones at %g %g %g\n", VECTOR_ARG(ent->absBounds.mins));
				ent->zonenum2 = zone;
			}
			else
				ent->zonenum = zone;
		}
	}

	if (num_leafs >= MAX_TOTAL_ENT_LEAFS)
	{	// assume we missed some leafs, and mark by headnode
		ent->num_clusters = -1;
		ent->headnode     = topnode;
	}
	else
	{
		ent->num_clusters = 0;
		for (i = 0; i < num_leafs; i++)
		{
			if (clusters[i] == -1)
				continue;		// not a visible leaf
			for (j = 0; j < i; j++)
				if (clusters[j] == clusters[i])
					break;
			if (j == i)
			{
				if (ent->num_clusters == MAX_ENT_CLUSTERS)
				{	// assume we missed some leafs, and mark by headnode
					ent->num_clusters = -1;
					ent->headnode     = topnode;
					break;
				}

				ent->clusternums[ent->num_clusters++] = clusters[i];
			}
		}
	}

	// if first time, make sure old_origin is valid
	if (!ent->linkcount)
		ent->s.old_origin = ent->s.origin;
	ent->linkcount++;

	if (ent->solid == SOLID_NOT)
		return;

	// find the first node that the ent's box crosses
	areanode_t *node = areaNodes;
	while (node->axis != -1)
	{
		if (ent->absBounds.mins[node->axis] > node->dist)
			node = node->children[0];
		else if (ent->absBounds.maxs[node->axis] < node->dist)
			node = node->children[1];
		else
			break;		// crosses the node
	}

	// link it in
	areanode_t *node2 = node;
	if (ent->solid == SOLID_TRIGGER)
	{
		InsertLinkBefore(ent->area, node->trigEdicts);
		for ( ; node2; node2 = node2->parent)
			node2->numTrigEdicts++;
	}
	else
	{
		InsertLinkBefore(ent->area, node->solidEdicts);
		for ( ; node2; node2 = node2->parent)
			node2->numSolidEdicts++;
	}
	ex.area = node;

	unguard;
}
Exemplo n.º 13
0
void GLimp_SetGamma(float gamma)
{
#if FIND_GAMMA
	EXEC_ONCE(appWPrintf("Find gamma mode!\n"));
	float	a, b;			// y = ax + b
	a = Cvar_Get("a","1")->value;
#	if !FIND_GAMMA2
	b = Cvar_Get("b","0.5")->value;
#	else
	b = Cvar_Get("b","-0.5")->value;
#	endif
#endif

	if (!gammaStored) return;

	gamma = bound(gamma, 0.5, 3);
	float contr = bound(r_contrast->value, 0.1, 2);
	float bright = bound(r_brightness->value, 0.1, 2);
	float invGamma = 1.0f / gamma;
	float overbright = gl_config.overbright + 1;

	for (int i = 0; i < 256; i++)
	{
#if 0
		float tmp = (i / 255.0f * overbright - 0.5f) * contr + 0.5f;
		if (tmp < 0) tmp = 0;					// without this, can get semi-negative picture when r_gamma=0.5 (invGamma=2, sqr func)
		int v = appRound(65535.0f * (pow(tmp, invGamma) + bright - 1));
#else
		// taken from UT2003
		// note: ut_br = br-0.5, ut_contr = contr-0.5 (replace later: norm. bright=0.5, contr=0.5) !!
		float tmp = pow(i * overbright / 255.0f, invGamma) * contr * 65535;
		tmp = tmp + (bright - 1) * 32768 - (contr - 0.5) * 32768 + 16384;
		int v = appRound(tmp);
#endif

		if (GIsWin2K)
		{
			// Win2K/XP performs checking of gamma ramp and may reject it
#if !FIND_GAMMA
			// clamp gamma curve with line 'y=x*GAMMA_ANGLE+GAMMA_OFFSET'
#define GAMMA_ANGLE		1
#define GAMMA_OFFSET	0.5
			int m = i * (GAMMA_ANGLE*256) + (int)(GAMMA_OFFSET*65536);
			if (v > m) v = m;
#define GAMMA_ANGLE2	1
#define GAMMA_OFFSET2	-0.5
			m = i * (GAMMA_ANGLE2*256) + (int)(GAMMA_OFFSET2*65536);
			if (v < m) v = m;
#else // FIND_GAMMA
#	if !FIND_GAMMA2
			int m = appRound(i * a * 256 + b * 65535);
			if (v > m) v = m;
#	else
			int m = appRound(i * a * 256 + b * 65535);
			if (v < m) v = m;
#	endif
#endif // FIND_GAMMA
		}
		v = bound(v, 0, 65535);
		newGamma[i] = newGamma[i+256] = newGamma[i+512] = v;
	}

	gammaValid = true;
	UpdateGamma();
}
Exemplo n.º 14
0
static void LoadAnimationCfg(clientInfo_t &ci, const char *filename)
{
	char *buf = (char*) GFileSystem->LoadFile(filename);
	gci = &ci;
	int animNumber = 0;
	animation_t *anims = ci.animations;
	int frameSkip = 0;

	ci.modelGender = 'm';						// male; default

	CSimpleParser text;
	text.InitFromBuf(buf);

	while (const char *line = text.GetLine())
	{
		// execute line
		if (line[0] >= '0' && line[0] <= '9')	// numbers => frame numbers
		{
			if (animNumber >= MAX_ANIMATIONS)
			{
				appWPrintf("Too much animations in \"%s\"\n", filename);
				break;
			}
			int firstFrame, numFrames, loopFrames;
			float fps;
			if (sscanf(line, "%d %d %d %f", &firstFrame, &numFrames, &loopFrames, &fps) != 4)
			{
				appWPrintf("Invalid frame info [%s] in \"%s\"\n", line, filename);
				break;
			}
			// some processing on acquired data + store info
			if (animNumber == LEGS_WALKCR)
			{
				frameSkip = firstFrame - anims[TORSO_GESTURE].firstFrame;
				firstFrame = anims[TORSO_GESTURE].firstFrame;
			}
			else if (animNumber > LEGS_WALKCR && animNumber < TORSO_GETFLAG)
				firstFrame -= frameSkip;
			if (numFrames < 0)
			{
				numFrames = -numFrames;
				anims[animNumber].reversed = true;
			}
			anims[animNumber].firstFrame = firstFrame;
			anims[animNumber].numFrames  = numFrames;
			anims[animNumber].loopFrames = loopFrames;
			if (fps < 1) fps = 1;
			anims[animNumber].frameLerp = appRound(1000.0f / fps);
			animNumber++;
		}
		else if (!ExecuteCommand(line, ARRAY_ARG(animCommands)))
		{
			appWPrintf("Invalid line [%s] in \"%s\"\n", line, filename);
			break;
		}
	}

	// copy gestures when absent
	if (animNumber >= TORSO_GETFLAG && animNumber <= TORSO_NEGATIVE)
		for (int i = animNumber; i <= TORSO_NEGATIVE; i++)
		{
			anims[i] = anims[TORSO_GESTURE];
			anims[i].reversed = false;
		}

	// crouch backward animation
	anims[LEGS_BACKCR] = anims[LEGS_WALKCR];
	anims[LEGS_BACKCR].reversed = true;
	// walk backward animation
	anims[LEGS_BACKWALK] = anims[LEGS_WALK];
	anims[LEGS_BACKWALK].reversed = true;
	// Q3 have some processing of flag animations ...

	for (int i = 0; i < MAX_TOTALANIMATIONS; i++)
		if (anims[i].frameLerp == 0) anims[i].frameLerp = 100;	// just in case

	delete buf;
}