Exemple #1
0
// convert HSV [0..1] to RGB [0..1]
static void HSV2RGB(float h, float s, float v, float &r, float &g, float &b)
{
#if 1
	// convert hue to index and fraction
	const int bits = 20;
	int scaled = (xs_FloorToInt(h * (1 << bits)) & ((1 << bits) - 1)) * 6;
	int i = scaled >> bits;
	float f = scaled * (1.0f / (1 << bits)) - i;

	// generate components
	float p = v * (1 - s);
	float q = v * (1 - f * s);
	float t = v * (1 - (1 - f) * s);

	switch (i)
	{
	case 0: r = v; g = t; b = p; break;
	case 1: r = q; g = v; b = p; break;
	case 2: r = p; g = v; b = t; break;
	case 3: r = p; g = q; b = v; break;
	case 4: r = t; g = p; b = v; break;
	case 5: r = v; g = p; b = q; break;
	}
#else
	// http://www.xmission.com/~trevin/atari/video_notes.html
	const float Y = 0.7f, S = 0.7f, theta = float(M_PI) - float(M_PI) * (sim_turn & 63) / 32.0f;
	float R = Clamp(Y + S * sin(theta), 0.0f, 1.0f);
	float G = Clamp(Y - (27/53) * S * sin(theta) - (10/53) * S * cos(theta), 0.0f, 1.0f);
	float B = Clamp(Y + S * cos(theta), 0.0f, 1.0f);
#endif
}
// render
void PlayerOverlaySpecial::Render(unsigned int aId, float aTime, const Transform2 &aTransform)
{
	// get the player
	Player *player = Database::player.Get(aId);

	// get the player entity (HACK)
	unsigned int id = player->GetId();

	// get "special" ammo resource (HACK)
	Resource *specialresource = Database::resource.Get(id).Get(0xd940d530 /* "special" */);
	if (!specialresource)
		return;
	int new_special = xs_FloorToInt(specialresource->GetValue());

	// if the special has not changed...
	if (new_special == cur_special && !wasreset)
	{
		// call the existing draw list
		glCallList(special_handle);
		return;
	}

	// update special
	cur_special = new_special;

	// start a new draw list list
	glNewList(special_handle, GL_COMPILE_AND_EXECUTE);

	// draw the special ammo icon
	glColor4f(0.4f, 0.5f, 1.0f, 1.0f);
	glPushMatrix();
	glTranslatef(specialpos.x, specialpos.y, 0.0f);
	glScalef(4, 4, 1);
	glCallList(Database::drawlist.Get(0x8cdedbba /* "circle16" */));
	glPopMatrix();

	// draw remaining special ammo
	char special[16];
	sprintf(special, "x%d", cur_special);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, OGLCONSOLE_glFontHandle);

	glColor4f(0.4f, 0.5f, 1.0f, 1.0f);

	glBegin(GL_QUADS);
	float w = 8;
	float h = -8;
	float x = specialpos.x + 8;
	float y = specialpos.y - 0.5f * h;
	float z = 0;
	OGLCONSOLE_DrawString(special, x, y, w, h, z);

	glEnd();

	glDisable(GL_TEXTURE_2D);

	glEndList();
}
void gl_RenderModel(GLSprite * spr)
{
	FSpriteModelFrame * smf = spr->modelframe;


	// Setup transformation.
	glDepthFunc(GL_LEQUAL);
	gl_RenderState.EnableTexture(true);
	// [BB] In case the model should be rendered translucent, do back face culling.
	// This solves a few of the problems caused by the lack of depth sorting.
	// TO-DO: Implement proper depth sorting.
	if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
	{
		glEnable(GL_CULL_FACE);
		glFrontFace(GL_CW);
	}

	int translation = 0;
	if ( !(smf->flags & MDL_IGNORETRANSLATION) )
		translation = spr->actor->Translation;


	// y scale for a sprite means height, i.e. z in the world!
	float scaleFactorX = spr->actor->Scale.X * smf->xscale;
	float scaleFactorY = spr->actor->Scale.X * smf->yscale;
	float scaleFactorZ = spr->actor->Scale.Y * smf->zscale;
	float pitch = 0;
	float roll = 0;
	float rotateOffset = 0;
	float angle = spr->actor->Angles.Yaw.Degrees;

	// [BB] Workaround for the missing pitch information.
	if ( (smf->flags & MDL_PITCHFROMMOMENTUM) )
	{
		const double x = spr->actor->Vel.X;
		const double y = spr->actor->Vel.Y;
		const double z = spr->actor->Vel.Z;

		if (spr->actor->Vel.LengthSquared() > EQUAL_EPSILON)
		{
			// [BB] Calculate the pitch using spherical coordinates.
			if (z || x || y) pitch = float(atan(z / sqrt(x*x + y*y)) / M_PI * 180);

			// Correcting pitch if model is moving backwards
			if (fabs(x) > EQUAL_EPSILON || fabs(y) > EQUAL_EPSILON)
			{
				if ((x * cos(angle * M_PI / 180) + y * sin(angle * M_PI / 180)) / sqrt(x * x + y * y) < 0) pitch *= -1;
			}
			else pitch = fabs(pitch);
		}
	}

	if( smf->flags & MDL_ROTATING )
	{
		const float time = smf->rotationSpeed*GetTimeFloat()/200.f;
		rotateOffset = float((time - xs_FloorToInt(time)) *360.f );
	}

	// Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing.
	// If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the momentum vector pitch.
	if (smf->flags & MDL_USEACTORPITCH)
	{
		double d = spr->actor->Angles.Pitch.Degrees;
		if (smf->flags & MDL_BADROTATION) pitch -= d;
		else pitch += d;
	}
	if(smf->flags & MDL_USEACTORROLL) roll += spr->actor->Angles.Roll.Degrees;

	gl_RenderState.mModelMatrix.loadIdentity();

	// Model space => World space
	gl_RenderState.mModelMatrix.translate(spr->x, spr->z, spr->y );	
	
	// Applying model transformations:
	// 1) Applying actor angle, pitch and roll to the model
	gl_RenderState.mModelMatrix.rotate(-angle, 0, 1, 0);
	gl_RenderState.mModelMatrix.rotate(pitch, 0, 0, 1);
	gl_RenderState.mModelMatrix.rotate(-roll, 1, 0, 0);
	
	// 2) Applying Doomsday like rotation of the weapon pickup models
	// The rotation angle is based on the elapsed time.
	
	if( smf->flags & MDL_ROTATING )
	{
		gl_RenderState.mModelMatrix.translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ);
		gl_RenderState.mModelMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate);
		gl_RenderState.mModelMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ);
	}

	// 3) Scaling model.
	gl_RenderState.mModelMatrix.scale(scaleFactorX, scaleFactorZ, scaleFactorY);

	// 4) Aplying model offsets (model offsets do not depend on model scalings).
	gl_RenderState.mModelMatrix.translate(smf->xoffset / smf->xscale, smf->zoffset / smf->zscale, smf->yoffset / smf->yscale);
	
	// 5) Applying model rotations.
	gl_RenderState.mModelMatrix.rotate(-smf->angleoffset, 0, 1, 0);
	gl_RenderState.mModelMatrix.rotate(smf->pitchoffset, 0, 0, 1);
	gl_RenderState.mModelMatrix.rotate(-smf->rolloffset, 1, 0, 0);

	// consider the pixel stretching. For non-voxels this must be factored out here
	float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / glset.pixelstretch;
	gl_RenderState.mModelMatrix.scale(1, stretch, 1);


	gl_RenderState.EnableModelMatrix(true);
	gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, spr->actor->GetClass(), nullptr, translation );
	gl_RenderState.EnableModelMatrix(false);

	glDepthFunc(GL_LESS);
	if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
		glDisable(GL_CULL_FACE);
}
Exemple #4
0
 operator int() const {
     return xs_FloorToInt(X) + 65536 * xs_FloorToInt(Y);
 }
// render
void PlayerOverlayLevel::Render(unsigned int aId, float aTime, const Transform2 &aTransform)
{
	// get the player
	Player *player = Database::player.Get(aId);

	// get the attached entity identifier
	unsigned int id = player->mAttach;

	// get level resource
	Resource *levelresource = Database::resource.Get(id).Get(0x9b99e7dd /* "level" */);
	if (!levelresource)
		return;
	int new_level = xs_FloorToInt(levelresource->GetValue());
	float new_part = levelresource->GetValue() - new_level;

	// if the level has not changed...
	if (new_part == cur_part && new_level == cur_level && !wasreset)
	{
		// call the existing draw list
		glCallList(level_handle);
		return;
	}

	// update level
	cur_level = new_level;
	cur_part = new_part;

	// start a new draw list list
	glNewList(level_handle, GL_COMPILE_AND_EXECUTE);

	// draw level gauge
	glBegin(GL_QUADS);

	// background
	glColor4fv(levelcolor[cur_level]);
	glVertex2f(levelrect.x, levelrect.y);
	glVertex2f(levelrect.x + levelrect.w, levelrect.y);
	glVertex2f(levelrect.x + levelrect.w, levelrect.y + levelrect.h);
	glVertex2f(levelrect.x, levelrect.y + levelrect.h);

	// fill gauge
	glColor4fv(levelcolor[cur_level+1]);
	glVertex2f(levelrect.x, levelrect.y);
	glVertex2f(levelrect.x + levelrect.w * cur_part, levelrect.y);
	glVertex2f(levelrect.x + levelrect.w * cur_part, levelrect.y + levelrect.h);
	glVertex2f(levelrect.x, levelrect.y + levelrect.h);

	glEnd();

	// draw the level icon
	glColor4f(0.4f, 0.5f, 1.0f, 1.0f);
	glPushMatrix();
	glTranslatef(levelpos.x, levelpos.y, 0.0f);
	glScalef(4, 4, 1);
	glCallList(Database::drawlist.Get(0x8cdedbba /* "circle16" */));
	glPopMatrix();

	// draw level number
	char level[16];
	sprintf(level, "x%d", cur_level);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, OGLCONSOLE_glFontHandle);

	glColor4f(0.4f, 0.5f, 1.0f, 1.0f);

	glBegin(GL_QUADS);
	float w = 8;
	float h = -8;
	float x = levelpos.x + 8;
	float y = levelpos.y - 0.5f * h;
	float z = 0;
	OGLCONSOLE_DrawString(level, x, y, w, h, z);

	glEnd();

	glDisable(GL_TEXTURE_2D);

	glEndList();
}
// render
void PlayerOverlayAmmo::Render(unsigned int aId, float aTime, const Transform2 &aTransform)
{
	// get the player
	Player *player = Database::player.Get(aId);

	// get the attached entity identifier
	unsigned int id = player->mAttach;

	// draw player ammo (HACK)
	Resource *ammoresource = Database::resource.Get(id).Get(0x5b9b0daf /* "ammo" */);
	if (!ammoresource)
		return;

	// get ammo ratio
	float new_ammo = 0.0f;
	const ResourceTemplate &ammoresourcetemplate = Database::resourcetemplate.Get(id).Get(0x5b9b0daf /* "ammo" */);
	if (ammoresourcetemplate.mMaximum > 0)
	{
		new_ammo = ammoresource->GetValue() / ammoresourcetemplate.mMaximum;
	}
	
	// get level
	int new_level = 1;
	Resource *levelresource = Database::resource.Get(id).Get(0x9b99e7dd /* "level" */);
	if (levelresource)
	{
		new_level = xs_FloorToInt(levelresource->GetValue());
	}

	// if the lives count has not changed...
	if (new_ammo == cur_ammo && new_level == cur_level && glIsList(ammo_handle))
	{
		// call the existing draw list
		glCallList(ammo_handle);
		return;
	}

	// update ammo
	cur_ammo = new_ammo;
	cur_level = new_level;

	// start a new draw list list
	glNewList(ammo_handle, GL_COMPILE_AND_EXECUTE);

	glBegin(GL_QUADS);

	// background
	glColor4fv(ammocolor[cur_level]);
	glVertex2f(ammorect.x, ammorect.y);
	glVertex2f(ammorect.x + ammorect.w, ammorect.y);
	glVertex2f(ammorect.x + ammorect.w, ammorect.y + ammorect.h);
	glVertex2f(ammorect.x, ammorect.y + ammorect.h);

	// fill gauge
	glColor4fv(ammocolor[cur_level+1]);
	glVertex2f(ammorect.x, ammorect.y);
	glVertex2f(ammorect.x + ammorect.w * cur_ammo, ammorect.y);
	glVertex2f(ammorect.x + ammorect.w * cur_ammo, ammorect.y + ammorect.h);
	glVertex2f(ammorect.x, ammorect.y + ammorect.h);

	glEnd();

	glEndList();
}
Exemple #7
0
void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1, int color2, double maxdiff, int flags, PClassActor *spawnclass, DAngle angle, int duration, double sparsity, double drift, int SpiralOffset, DAngle pitch)
{
	double length = 0;
	int steps, i;
	TArray<TrailSegment> trail;
	TAngle<double> deg;
	DVector3 pos;
	bool fullbright;
	unsigned segment;
	double lencount;

	for (unsigned i = 0; i < portalhits.Size() - 1; i++)
	{
		TrailSegment seg;

		seg.start = portalhits[i].ContPos;
		seg.dir = portalhits[i].OutDir;
		seg.length = (portalhits[i + 1].HitPos - seg.start).Length();

		//Calculate PerpendicularVector (extend, dir):
		double minelem = 1;
		int epos;
		int ii;
		for (epos = 0, ii = 0; ii < 3; ++ii)
		{
			if (fabs(seg.dir[ii]) < minelem)
			{
				epos = ii;
				minelem = fabs(seg.dir[ii]);
			}
		}
		DVector3 tempvec(0, 0, 0);
		tempvec[epos] = 1;
		seg.extend = (tempvec - (seg.dir | tempvec) * seg.dir) * 3;
		length += seg.length;

		auto player = source->Level->GetConsolePlayer();
		if (player)
		{
			// Only consider sound in 2D (for now, anyway)
			// [BB] You have to divide by lengthsquared here, not multiply with it.
			AActor *mo = player->camera;
			double r = ((seg.start.Y - mo->Y()) * (-seg.dir.Y) - (seg.start.X - mo->X()) * (seg.dir.X)) / (seg.length * seg.length);
			r = clamp<double>(r, 0., 1.);
			seg.soundpos = seg.start + r * seg.dir;
			seg.sounddist = (seg.soundpos - mo->Pos()).LengthSquared();
		}
		else
		{
			// Set to invalid for secondary levels.
			seg.soundpos = {0,0};
			seg.sounddist = -1;
		}
		trail.Push(seg);
	}

	steps = xs_FloorToInt(length / 3);
	fullbright = !!(flags & RAF_FULLBRIGHT);

	if (steps)
	{
		if (!(flags & RAF_SILENT))
		{
			auto player = source->Level->GetConsolePlayer();
			if (player)
			{
				FSoundID sound;
				
				// Allow other sounds than 'weapons/railgf'!
				if (!source->player) sound = source->AttackSound;
				else if (source->player->ReadyWeapon) sound = source->player->ReadyWeapon->AttackSound;
				else sound = 0;
				if (!sound) sound = "weapons/railgf";
				
				// The railgun's sound is special. It gets played from the
				// point on the slug's trail that is closest to the hearing player.
				AActor *mo = player->camera;
				
				if (fabs(mo->X() - trail[0].start.X) < 20 && fabs(mo->Y() - trail[0].start.Y) < 20)
				{ // This player (probably) fired the railgun
					S_Sound (mo, CHAN_WEAPON, sound, 1, ATTN_NORM);
				}
				else
				{
					TrailSegment *shortest = NULL;
					for (auto &seg : trail)
					{
						if (shortest == NULL || shortest->sounddist > seg.sounddist) shortest = &seg;
					}
					S_Sound (source->Level, DVector3(shortest->soundpos, r_viewpoint.Pos.Z), CHAN_WEAPON, sound, 1, ATTN_NORM);
				}
			}
		}
	}
	else
	{
		// line is 0 length, so nothing to do
		return;
	}

	// Create the outer spiral.
	if (color1 != -1 && (!r_rail_smartspiral || color2 == -1) && r_rail_spiralsparsity > 0 && (spawnclass == NULL))
	{
		double stepsize = 3 * r_rail_spiralsparsity * sparsity;
		int spiral_steps = (int)(steps * r_rail_spiralsparsity / sparsity);
		segment = 0;
		lencount = trail[0].length;
		
		color1 = color1 == 0 ? -1 : ParticleColor(color1);
		pos = trail[0].start;
		deg = (double)SpiralOffset;
		for (i = spiral_steps; i; i--)
		{
			FParticle *p = NewParticle (source->Level);
			DVector3 tempvec;

			if (!p)
				return;

			int spiralduration = (duration == 0) ? 35 : duration;

			p->alpha = 1.f;
			p->ttl = spiralduration;
			p->fadestep = FADEFROMTTL(spiralduration);
			p->size = 3;
			p->bright = fullbright;

			tempvec = DMatrix3x3(trail[segment].dir, deg) * trail[segment].extend;
			p->Vel = tempvec * drift / 16.;
			p->Pos = tempvec + pos;
			pos += trail[segment].dir * stepsize;
			deg += double(r_rail_spiralsparsity * 14);
			lencount -= stepsize;
			if (color1 == -1)
			{
				int rand = M_Random();

				if (rand < 155)
					p->color = rblue2;
				else if (rand < 188)
					p->color = rblue1;
				else if (rand < 222)
					p->color = rblue3;
				else
					p->color = rblue4;
			}
			else 
			{
				p->color = color1;
			}

			p->renderstyle = STYLE_Translucent;

			if (lencount <= 0)
			{
				segment++;
				if (segment < trail.Size())
				{
					pos = trail[segment].start - trail[segment].dir * lencount;
					lencount += trail[segment].length;
				}
				else
				{
					// should never happen but if something goes wrong, just terminate the loop.
					break;
				}
			}
		}
	}

	// Create the inner trail.
	if (color2 != -1 && r_rail_trailsparsity > 0 && spawnclass == NULL)
	{
		double stepsize = 3 * r_rail_trailsparsity * sparsity;
		int trail_steps = xs_FloorToInt(steps * r_rail_trailsparsity / sparsity);

		color2 = color2 == 0 ? -1 : ParticleColor(color2);
		DVector3 diff(0, 0, 0);

		pos = trail[0].start;
		lencount = trail[0].length;
		segment = 0;
		for (i = trail_steps; i; i--)
		{
			// [XA] inner trail uses a different default duration (33).
			int innerduration = (duration == 0) ? 33 : duration;
			FParticle *p = JitterParticle (source->Level, innerduration, (float)drift);

			if (!p)
				return;

			if (maxdiff > 0)
			{
				int rnd = M_Random ();
				if (rnd & 1)
					diff.X = clamp<double>(diff.X + ((rnd & 8) ? 1 : -1), -maxdiff, maxdiff);
				if (rnd & 2)
					diff.Y = clamp<double>(diff.Y + ((rnd & 16) ? 1 : -1), -maxdiff, maxdiff);
				if (rnd & 4)
					diff.Z = clamp<double>(diff.Z + ((rnd & 32) ? 1 : -1), -maxdiff, maxdiff);
			}

			DVector3 postmp = pos + diff;

			p->size = 2;
			p->Pos = postmp;
			if (color1 != -1)
				p->Acc.Z -= 1./4096;
			pos += trail[segment].dir * stepsize;
			lencount -= stepsize;
			p->bright = fullbright;

			if (color2 == -1)
			{
				int rand = M_Random();

				if (rand < 85)
					p->color = grey4;
				else if (rand < 170)
					p->color = grey2;
				else
					p->color = grey1;
			}
			else 
			{
				p->color = color2;
			}
			if (lencount <= 0)
			{
				segment++;
				if (segment < trail.Size())
				{
					pos = trail[segment].start - trail[segment].dir * lencount;
					lencount += trail[segment].length;
				}
				else
				{
					// should never happen but if something goes wrong, just terminate the loop.
					break;
				}
			}

		}
	}
	// create actors
	if (spawnclass != NULL)
	{
		if (sparsity < 1)
			sparsity = 32;

		double stepsize = sparsity;
		int trail_steps = (int)((steps * 3) / sparsity);
		DVector3 diff(0, 0, 0);

		pos = trail[0].start;
		lencount = trail[0].length;
		segment = 0;

		for (i = trail_steps; i; i--)
		{
			if (maxdiff > 0)
			{
				int rnd = pr_railtrail();
				if (rnd & 1)
					diff.X = clamp<double>(diff.X + ((rnd & 8) ? 1 : -1), -maxdiff, maxdiff);
				if (rnd & 2)
					diff.Y = clamp<double>(diff.Y + ((rnd & 16) ? 1 : -1), -maxdiff, maxdiff);
				if (rnd & 4)
					diff.Z = clamp<double>(diff.Z + ((rnd & 32) ? 1 : -1), -maxdiff, maxdiff);
			}			
			AActor *thing = Spawn (source->Level, spawnclass, pos + diff, ALLOW_REPLACE);
			if (thing)
			{
				if (source)	thing->target = source;
				thing->Angles.Pitch = pitch;
				thing->Angles.Yaw = angle;
			}
			pos += trail[segment].dir * stepsize;
			lencount -= stepsize;
			if (lencount <= 0)
			{
				segment++;
				if (segment < trail.Size())
				{
					pos = trail[segment].start - trail[segment].dir * lencount;
					lencount += trail[segment].length;
				}
				else
				{
					// should never happen but if something goes wrong, just terminate the loop.
					break;
				}
			}
		}
	}
}
Exemple #8
0
void gl_RenderModel(GLSprite * spr, int cm)
{
	// [BB/EP] Take care of gl_fogmode and ZADF_FORCE_GL_DEFAULTS.
	OVERRIDE_FOGMODE_IF_NECESSARY

	FSpriteModelFrame * smf = spr->modelframe;


	// Setup transformation.
	gl.MatrixMode(GL_MODELVIEW);
	gl.PushMatrix();
	gl.DepthFunc(GL_LEQUAL);
	// [BB] In case the model should be rendered translucent, do back face culling.
	// This solves a few of the problems caused by the lack of depth sorting.
	// TO-DO: Implement proper depth sorting.
	if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
	{
		gl.Enable(GL_CULL_FACE);
		glFrontFace(GL_CW);
	}

	int translation = 0;
	if ( !(smf->flags & MDL_IGNORETRANSLATION) )
		translation = spr->actor->Translation;


	// y scale for a sprite means height, i.e. z in the world!
	float scaleFactorX = FIXED2FLOAT(spr->actor->scaleX) * smf->xscale;
	float scaleFactorY = FIXED2FLOAT(spr->actor->scaleX) * smf->yscale;
	float scaleFactorZ = FIXED2FLOAT(spr->actor->scaleY) * smf->zscale;
	float pitch = 0;
	float rotateOffset = 0;
	float angle = ANGLE_TO_FLOAT(spr->actor->angle);

	// [BB] Workaround for the missing pitch information.
	if ( (smf->flags & MDL_PITCHFROMMOMENTUM) )
	{
		const double x = static_cast<double>(spr->actor->velx);
		const double y = static_cast<double>(spr->actor->vely);
		const double z = static_cast<double>(spr->actor->velz);
		// [BB] Calculate the pitch using spherical coordinates.
		
		pitch = float(atan( z/sqrt(x*x+y*y) ) / M_PI * 180);
	}

	if( smf->flags & MDL_ROTATING )
	{
		const float time = smf->rotationSpeed*GetTimeFloat()/200.f;
		rotateOffset = float((time - xs_FloorToInt(time)) *360.f );
	}

	if (gl_fogmode != 2 && (GLRenderer->mLightCount == 0 || !gl_light_models))
	{
		// Model space => World space
		gl.Translatef(spr->x, spr->z, spr->y );

		if ( !(smf->flags & MDL_ALIGNANGLE) )
			gl.Rotatef(-angle, 0, 1, 0);
		// [BB] Change the angle so that the object is exactly facing the camera in the x/y plane.
		else
			gl.Rotatef( -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ), 0, 1, 0);

		// [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE).
		if ( (smf->flags & MDL_ALIGNPITCH) )
		{
			const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy );
			const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) );
			gl.Rotatef(pitch, 0, 0, 1);
		}

		// [BB] Workaround for the missing pitch information.
		if (pitch != 0)	gl.Rotatef(pitch, 0, 0, 1);

		// [BB] Special flag for flat, beam like models.
		if ( (smf->flags & MDL_ROLLAGAINSTANGLE) )
			gl.Rotatef( gl_RollAgainstAngleHelper ( spr->actor ), 1, 0, 0);

		// Model rotation.
		// [BB] Added Doomsday like rotation of the weapon pickup models.
		// The rotation angle is based on the elapsed time.

		if( smf->flags & MDL_ROTATING )
		{
			gl.Translatef(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ);
			gl.Rotatef(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate);
			gl.Translatef(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ);
		} 		

		// Scaling and model space offset.
		gl.Scalef(scaleFactorX, scaleFactorZ, scaleFactorY);

		// [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling.
		gl.Translatef(0., smf->zoffset / smf->zscale, 0.);

		gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, NULL, NULL, translation );
	}
	else
	{
		Matrix3x4 ModelToWorld;
		Matrix3x4 NormalTransform;

		// For radial fog we need to pass coordinates in world space in order to calculate distances.
		// That means that the local transformations cannot be part of the modelview matrix

		ModelToWorld.MakeIdentity();

		// Model space => World space
		ModelToWorld.Translate(spr->x, spr->z, spr->y);

		if ( !(smf->flags & MDL_ALIGNANGLE) )
			ModelToWorld.Rotate(0,1,0, -angle);
		// [BB] Change the angle so that the object is exactly facing the camera in the x/y plane.
		else
			ModelToWorld.Rotate(0,1,0, -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ) );

		// [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE).
		if ( (smf->flags & MDL_ALIGNPITCH) )
		{
			const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy );
			const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) );
			ModelToWorld.Rotate(0,0,1,pitch);
		}

		// [BB] Workaround for the missing pitch information.
		if (pitch != 0) ModelToWorld.Rotate(0,0,1,pitch);

		// [BB] Special flag for flat, beam like models.
		if ( (smf->flags & MDL_ROLLAGAINSTANGLE) )
			ModelToWorld.Rotate(1, 0, 0, gl_RollAgainstAngleHelper ( spr->actor ));

		// Model rotation.
		// [BB] Added Doomsday like rotation of the weapon pickup models.
		// The rotation angle is based on the elapsed time.

		if( smf->flags & MDL_ROTATING )
		{
			ModelToWorld.Translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ);
			ModelToWorld.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, rotateOffset);
			ModelToWorld.Translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ);
		}

		ModelToWorld.Scale(scaleFactorX, scaleFactorZ, scaleFactorY);

		// [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling.
		ModelToWorld.Translate(0., smf->zoffset / smf->zscale, 0.);

		if (!gl_light_models)
		{
			gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, NULL, translation );
		}
		else
		{
			// The normal transform matrix only contains the inverse rotations and scalings but not the translations
			NormalTransform.MakeIdentity();

			NormalTransform.Scale(1.f/scaleFactorX, 1.f/scaleFactorZ, 1.f/scaleFactorY);
			if( smf->flags & MDL_ROTATING ) NormalTransform.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, -rotateOffset);
			if (pitch != 0) NormalTransform.Rotate(0,0,1,-pitch);
			if (angle != 0) NormalTransform.Rotate(0,1,0, angle);

			gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, &NormalTransform, translation );
		}

	}

	gl.MatrixMode(GL_MODELVIEW);
	gl.PopMatrix();
	gl.DepthFunc(GL_LESS);
	if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] ))
		gl.Disable(GL_CULL_FACE);
}
Exemple #9
0
void BuildPathingGrid(const int aZoneSize, const int aCellSize)
{
	if (grid_handle)
	{
		glCallList(grid_handle);
		return;
	}

	// create a new grid handle
	grid_handle = glGenLists(1);

	// create a new list
	glNewList(grid_handle, GL_COMPILE);

	// get world boundary
	const b2AABB &boundary = Collidable::GetBoundary();

	// get zone extents
	int zx0 = xs_FloorToInt(boundary.lowerBound.x / aZoneSize);
	int zx1 = xs_CeilToInt(boundary.upperBound.x / aZoneSize);
	int zy0 = xs_FloorToInt(boundary.lowerBound.y / aZoneSize);
	int zy1 = xs_CeilToInt(boundary.upperBound.y / aZoneSize);

	// cells per zone
	int cell_side = aZoneSize / aCellSize;
	int cell_count = cell_side * cell_side;

	// get the collision world
	b2World *world = Collidable::GetWorld();

	// create a probe fixture
	b2PolygonShape probeshape;
	probeshape.SetAsBox(aCellSize * 0.5f, aCellSize * 0.5f, b2Vec2(aCellSize * 0.5f, aCellSize * 0.5f), 0.0f);
	b2BodyDef probebodydef;
	b2Body *probebody = world->CreateBody(&probebodydef);
	b2FixtureDef probefixturedef;
	probefixturedef.shape = &probeshape;
	probefixturedef.isSensor = true;
	probebody->CreateFixture(&probefixturedef);

	// for each zone row...
	for (int zy = zy0; zy < zy1; ++zy)
	{
		// for each zone column...
		for (int zx = zx0; zx < zx1; ++zx)
		{
			// get zone boundary
			b2AABB zone_aabb;
			zone_aabb.lowerBound.x = float((zx) * aZoneSize);
			zone_aabb.lowerBound.y = float((zy) * aZoneSize);
			zone_aabb.upperBound.x = float((zx + 1) * aZoneSize);
			zone_aabb.upperBound.y = float((zy + 1) * aZoneSize);

			// draw zone boundary
			glBegin(GL_LINE_LOOP);
			glColor4f(1, 1, 1, 1);
			glVertex2f(zone_aabb.lowerBound.x, zone_aabb.lowerBound.y);
			glVertex2f(zone_aabb.upperBound.x, zone_aabb.lowerBound.y);
			glVertex2f(zone_aabb.upperBound.x, zone_aabb.upperBound.y);
			glVertex2f(zone_aabb.lowerBound.x, zone_aabb.upperBound.y);
			glEnd();

			// initialize cell map
			unsigned char *cell_map = static_cast<unsigned char *>(_alloca(cell_count));
			memset(cell_map, 0xFF, cell_count);

			// for each cell row
			for (int row = 0; row < cell_side; ++row)
			{
				// for each cell column...
				for (int col = 0; col < cell_side; ++col)
				{
					// probe filter
					static const b2Filter aFilter;

					// get fixtures intersecting the cell
					b2AABB cell_aabb;
					cell_aabb.lowerBound.x = zone_aabb.lowerBound.x + (col) * aCellSize;
					cell_aabb.lowerBound.y = zone_aabb.lowerBound.y + (row) * aCellSize;
					cell_aabb.upperBound.x = zone_aabb.lowerBound.x + (col + 1) * aCellSize;
					cell_aabb.upperBound.y = zone_aabb.lowerBound.y + (row + 1) * aCellSize;
					GridQueryCallback callback(aFilter);
					world->QueryAABB(&callback, cell_aabb);

					// cell type (0=empty, 1=blocked)
					cell_map[row * cell_side + col] = callback.mBlocker != NULL;
				}
			}

			// initialize slab map
			unsigned char *slab_map = static_cast<unsigned char *>(_alloca(cell_count));
			memset(slab_map, 0xFF, cell_count);
			int slab_count = 0;

			// for each cell row
			for (int row = 0; row < cell_side; ++row)
			{
				// for each cell column...
				for (int col = 0; col < cell_side; ++col)
				{
					// skip assigned spaces
					if (slab_map[row * cell_side + col] != 0xFF)
						continue;

					// cell type
					unsigned char cell = cell_map[row * cell_side + col];

					// allocate a new index
					unsigned char index = unsigned char(slab_count++);
					assert(index < 0xFF);

					// find horizontal extent
					int c0 = col;
					int c1 = cell_side;
					for (int c = c0; c < c1; ++c)
					{
						if ((cell_map[row * cell_side + c] != cell) || ((slab_map[row * cell_side + c] != 0xFF) && (slab_map[row * cell_side + c] != index)))
						{
							c1 = c;
							break;
						}
					}

					// find vertical extent
					int r0 = row;
					int r1 = cell_side;
					for (int r = r0; r < r1; ++r)
					{
						for (int c = c0; c < c1; ++c)
						{
							if ((cell_map[r * cell_side + c] != cell) || ((slab_map[r * cell_side + c] != 0xFF) && (slab_map[r * cell_side + c] != index)))
							{
								r1 = r;
								break;
							}
						}
					}
					
					// fill slab
					for (int r = r0; r < r1; ++r)
					{
						for (int c = c0; c < c1; ++c)
						{
							slab_map[r * cell_side + c] = index;
						}
					}

					assert(c0 < c1 && r0 < r1);

					// set slab extents
					//titleslab[index][0] = c0;
					//titleslab[index][1] = c1;
					//titleslab[index][2] = r0;
					//titleslab[index][3] = r1;
					b2AABB slab_aabb;
					slab_aabb.lowerBound.x = zone_aabb.lowerBound.x + c0 * aCellSize;
					slab_aabb.lowerBound.y = zone_aabb.lowerBound.y + r0 * aCellSize;
					slab_aabb.upperBound.x = zone_aabb.lowerBound.x + c1 * aCellSize;
					slab_aabb.upperBound.y = zone_aabb.lowerBound.y + r1 * aCellSize;
					AddGridSlab(slab_aabb, cell_color[cell]);

					// skip visited columns
					col = c1 - 1;
				}
			}

			DebugPrint("zone %d %d slabs %d\n", zx, zy, slab_count);
		}
	}

	// destroy the probe fixture
	world->DestroyBody(probebody);

	glEndList();
}