Beispiel #1
0
void CTexturedLineRData::CreateLineCap(const SOverlayTexturedLine& line, const CVector3D& corner1, const CVector3D& corner2,
	const CVector3D& lineDirectionNormal, SOverlayTexturedLine::LineCapType endCapType, std::vector<SVertex>& verticesOut,
	std::vector<u16>& indicesOut)
{
	if (endCapType == SOverlayTexturedLine::LINECAP_FLAT)
		return; // no action needed, this is the default

	// When not in closed mode, we've created artificial points for the start- and endpoints that extend the line in the
	// direction of the first and the last segment, respectively. Thus, we know both the start and endpoints have perpendicular
	// butt endings, i.e. the end corner vertices on either side of the line extend perpendicularly from the segment direction.
	// That is to say, when viewed from the top, we will have something like
	//                                                 .
	//  this:                     and not like this:  /|
	//         ----+                                 / |
	//             |                                /  .
	//             |                                  /
	//         ----+                                 /
	//

	int roundCapPoints = 8; // amount of points to sample along the semicircle for rounded caps (including corner points)
	float radius = line.m_Thickness;

	CVector3D centerPoint = (corner1 + corner2) * 0.5f;
	SVertex centerVertex(centerPoint, 0.5f, 0.5f);
	u16 indexOffset = verticesOut.size(); // index offset in verticesOut from where we start adding our vertices

	switch (endCapType)
	{
	case SOverlayTexturedLine::LINECAP_SHARP:
		{
			roundCapPoints = 3; // creates only one point directly ahead
			radius *= 1.5f; // make it a bit sharper (note that we don't use the radius for the butt-end corner points so it should be ok)
			centerVertex.m_UVs[0] = 0.480f; // slight visual correction to make the texture match up better at the corner points
		}
		// fall-through
	case SOverlayTexturedLine::LINECAP_ROUND:
		{
			// Draw a rounded line cap in the 3D plane of the line specified by the two corner points and the normal vector of the 
			// line's direction. The terrain normal at the centroid between the two corner points is perpendicular to this plane.
			// The way this works is by taking a vector from the corner points' centroid to one of the corner points (which is then 
			// of radius length), and rotate it around the terrain normal vector in that centroid. This will rotate the vector in 
			// the line's plane, producing the desired rounded cap.

			// To please OpenGL's winding order, this angle needs to be negated depending on whether we start rotating from 
			// the (center -> corner1) or (center -> corner2) vector. For the (center -> corner2) vector, we apparently need to use 
			// the negated angle.
			float stepAngle = -(float)(M_PI/(roundCapPoints-1));

			// Push the vertices in triangle fan order (easy to generate GL_TRIANGLES indices for afterwards)
			// Note that we're manually adding the corner vertices instead of having them be generated by the rotating vector. 
			// This is because we want to support an overly large radius to make the sharp line ending look sharper.
			verticesOut.push_back(centerVertex); 
			verticesOut.push_back(SVertex(corner2, 0.f, 0.f));

			// Get the base vector that we will incrementally rotate in the cap plane to produce the radial sample points.
			// Normally corner2 - centerPoint would suffice for this since it is of radius length, but we want to support custom 
			// radii to support tuning the 'sharpness' of sharp end caps (see above)
			CVector3D rotationBaseVector = (corner2 - centerPoint).Normalized() * radius;
			// Calculate the normal vector of the plane in which we're going to be drawing the line cap. This is the vector that
			// is perpendicular to both baseVector and the 'lineDirectionNormal' vector indicating the direction of the line.
			// Note that we shouldn't use terrain->CalcExactNormal() here because if the line is being rendered on top of water,
			// then CalcExactNormal will return the normal vector of the terrain that's underwater (which can be quite funky).
			CVector3D capPlaneNormal = lineDirectionNormal.Cross(rotationBaseVector).Normalized();

			for (int i = 1; i < roundCapPoints - 1; ++i)
			{
				// Rotate the centerPoint -> corner vector by i*stepAngle radians around the cap plane normal at the center point.
				CQuaternion quatRotation;
				quatRotation.FromAxisAngle(capPlaneNormal, i * stepAngle);
				CVector3D worldPos3D = centerPoint + quatRotation.Rotate(rotationBaseVector);

				// Let v range from 0 to 1 as we move along the semi-circle, keep u fixed at 0 (i.e. curve the left vertical edge 
				// of the texture around the edge of the semicircle)
				float u = 0.f;
				float v = clamp((i/(float)(roundCapPoints-1)), 0.f, 1.f); // pos, u, v
				verticesOut.push_back(SVertex(worldPos3D, u, v));
			}

			// connect back to the other butt-end corner point to complete the semicircle 
			verticesOut.push_back(SVertex(corner1, 0.f, 1.f)); 

			// now push indices in GL_TRIANGLES order; vertices[indexOffset] is the center vertex, vertices[indexOffset + 1] is the 
			// first corner point, then a bunch of radial samples, and then at the end we have the other corner point again. So: 
			for (int i=1; i < roundCapPoints; ++i)
			{
				indicesOut.push_back(indexOffset); // center vertex 
				indicesOut.push_back(indexOffset + i); 
				indicesOut.push_back(indexOffset + i + 1); 
			}
		}
		break;

	case SOverlayTexturedLine::LINECAP_SQUARE:
		{
			// Extend the (corner1 -> corner2) vector along the direction normal and draw a square line ending consisting of 
			// three triangles (sort of like a triangle fan)
			// NOTE: The order in which the vertices are pushed out determines the visibility, as they
			// are rendered only one-sided; the wrong order of vertices will make the cap visible only from the bottom.
			verticesOut.push_back(centerVertex);
			verticesOut.push_back(SVertex(corner2, 0.f, 0.f));
			verticesOut.push_back(SVertex(corner2 + (lineDirectionNormal * (line.m_Thickness)), 0.f, 0.33333f)); // extend butt corner point 2 along the normal vector 
			verticesOut.push_back(SVertex(corner1 + (lineDirectionNormal * (line.m_Thickness)), 0.f, 0.66666f)); // extend butt corner point 1 along the normal vector 
			verticesOut.push_back(SVertex(corner1, 0.f, 1.0f)); // push butt corner point 1 

			for (int i=1; i < 4; ++i) 
			{ 
				indicesOut.push_back(indexOffset); // center point 
				indicesOut.push_back(indexOffset + i); 
				indicesOut.push_back(indexOffset + i + 1);
			} 
		}
		break;

	default:
		break;
	}

}
Beispiel #2
0
void CGameView::Update(const float deltaRealTime)
{
	// If camera movement is being handled by the touch-input system,
	// then we should stop to avoid conflicting with it
	if (g_TouchInput.IsEnabled())
		return;

	if (!g_app_has_focus)
		return;

	if (m->CinemaManager.GetEnabled())
	{
		m->CinemaManager.Update(deltaRealTime);
		return;
	}

	// Calculate mouse movement
	static int mouse_last_x = 0;
	static int mouse_last_y = 0;
	int mouse_dx = g_mouse_x - mouse_last_x;
	int mouse_dy = g_mouse_y - mouse_last_y;
	mouse_last_x = g_mouse_x;
	mouse_last_y = g_mouse_y;

	if (HotkeyIsPressed("camera.rotate.cw"))
		m->RotateY.AddSmoothly(m->ViewRotateYSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.ccw"))
		m->RotateY.AddSmoothly(-m->ViewRotateYSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.up"))
		m->RotateX.AddSmoothly(-m->ViewRotateXSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.down"))
		m->RotateX.AddSmoothly(m->ViewRotateXSpeed * deltaRealTime);

	float moveRightward = 0.f;
	float moveForward = 0.f;

	if (HotkeyIsPressed("camera.pan"))
	{
		moveRightward += m->ViewDragSpeed * mouse_dx;
		moveForward += m->ViewDragSpeed * -mouse_dy;
	}

	if (g_mouse_active)
	{
		if (g_mouse_x >= g_xres - 2 && g_mouse_x < g_xres)
			moveRightward += m->ViewScrollSpeed * deltaRealTime;
		else if (g_mouse_x <= 3 && g_mouse_x >= 0)
			moveRightward -= m->ViewScrollSpeed * deltaRealTime;

		if (g_mouse_y >= g_yres - 2 && g_mouse_y < g_yres)
			moveForward -= m->ViewScrollSpeed * deltaRealTime;
		else if (g_mouse_y <= 3 && g_mouse_y >= 0)
			moveForward += m->ViewScrollSpeed * deltaRealTime;
	}

	if (HotkeyIsPressed("camera.right"))
		moveRightward += m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.left"))
		moveRightward -= m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.up"))
		moveForward += m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.down"))
		moveForward -= m->ViewScrollSpeed * deltaRealTime;

	if (g_Joystick.IsEnabled())
	{
		// This could all be improved with extra speed and sensitivity settings
		// (maybe use pow to allow finer control?), and inversion settings

		moveRightward += g_Joystick.GetAxisValue(m->JoystickPanX) * m->ViewScrollSpeed * deltaRealTime;
		moveForward -= g_Joystick.GetAxisValue(m->JoystickPanY) * m->ViewScrollSpeed * deltaRealTime;

		m->RotateX.AddSmoothly(g_Joystick.GetAxisValue(m->JoystickRotateX) * m->ViewRotateXSpeed * deltaRealTime);
		m->RotateY.AddSmoothly(-g_Joystick.GetAxisValue(m->JoystickRotateY) * m->ViewRotateYSpeed * deltaRealTime);

		// Use a +1 bias for zoom because I want this to work with trigger buttons that default to -1
		m->Zoom.AddSmoothly((g_Joystick.GetAxisValue(m->JoystickZoomIn) + 1.0f) / 2.0f * m->ViewZoomSpeed * deltaRealTime);
		m->Zoom.AddSmoothly(-(g_Joystick.GetAxisValue(m->JoystickZoomOut) + 1.0f) / 2.0f * m->ViewZoomSpeed * deltaRealTime);
	}

	if (moveRightward || moveForward)
	{
		// Break out of following mode when the user starts scrolling
		m->FollowEntity = INVALID_ENTITY;

		float s = sin(m->RotateY.GetSmoothedValue());
		float c = cos(m->RotateY.GetSmoothedValue());
		m->PosX.AddSmoothly(c * moveRightward);
		m->PosZ.AddSmoothly(-s * moveRightward);
		m->PosX.AddSmoothly(s * moveForward);
		m->PosZ.AddSmoothly(c * moveForward);
	}

	if (m->FollowEntity)
	{
		CmpPtr<ICmpPosition> cmpPosition(*(m->Game->GetSimulation2()), m->FollowEntity);
		CmpPtr<ICmpRangeManager> cmpRangeManager(*(m->Game->GetSimulation2()), SYSTEM_ENTITY);
		if (cmpPosition && cmpPosition->IsInWorld() &&
		    cmpRangeManager && cmpRangeManager->GetLosVisibility(m->FollowEntity, m->Game->GetViewedPlayerID()) == ICmpRangeManager::VIS_VISIBLE)
		{
			// Get the most recent interpolated position
			float frameOffset = m->Game->GetSimulation2()->GetLastFrameOffset();
			CMatrix3D transform = cmpPosition->GetInterpolatedTransform(frameOffset);
			CVector3D pos = transform.GetTranslation();

			if (m->FollowFirstPerson)
			{
				float x, z, angle;
				cmpPosition->GetInterpolatedPosition2D(frameOffset, x, z, angle);
				float height = 4.f;
				m->ViewCamera.m_Orientation.SetIdentity();
				m->ViewCamera.m_Orientation.RotateX((float)M_PI/24.f);
				m->ViewCamera.m_Orientation.RotateY(angle);
				m->ViewCamera.m_Orientation.Translate(pos.X, pos.Y + height, pos.Z);

				m->ViewCamera.UpdateFrustum();
				return;
			}
			else
			{
				// Move the camera to match the unit
				CCamera targetCam = m->ViewCamera;
				SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);

				CVector3D pivot = GetSmoothPivot(targetCam);
				CVector3D delta = pos - pivot;
				m->PosX.AddSmoothly(delta.X);
				m->PosY.AddSmoothly(delta.Y);
				m->PosZ.AddSmoothly(delta.Z);
			}
		}
		else
		{
			// The unit disappeared (died or garrisoned etc), so stop following it
			m->FollowEntity = INVALID_ENTITY;
		}
	}

	if (HotkeyIsPressed("camera.zoom.in"))
		m->Zoom.AddSmoothly(-m->ViewZoomSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.zoom.out"))
		m->Zoom.AddSmoothly(m->ViewZoomSpeed * deltaRealTime);

	if (m->ConstrainCamera)
		m->Zoom.ClampSmoothly(m->ViewZoomMin, m->ViewZoomMax);

	float zoomDelta = -m->Zoom.Update(deltaRealTime);
	if (zoomDelta)
	{
		CVector3D forwards = m->ViewCamera.m_Orientation.GetIn();
		m->PosX.AddSmoothly(forwards.X * zoomDelta);
		m->PosY.AddSmoothly(forwards.Y * zoomDelta);
		m->PosZ.AddSmoothly(forwards.Z * zoomDelta);
	}

	if (m->ConstrainCamera)
		m->RotateX.ClampSmoothly(DEGTORAD(m->ViewRotateXMin), DEGTORAD(m->ViewRotateXMax));

	FocusHeight(m, true);

	// Ensure the ViewCamera focus is inside the map with the chosen margins
	// if not so - apply margins to the camera
	if (m->ConstrainCamera)
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);

		CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();

		CVector3D pivot = GetSmoothPivot(targetCam);
		CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

		CVector3D desiredPivot = pivot;

		CmpPtr<ICmpRangeManager> cmpRangeManager(*(m->Game->GetSimulation2()), SYSTEM_ENTITY);
		if (cmpRangeManager && cmpRangeManager->GetLosCircular())
		{
			// Clamp to a circular region around the center of the map
			float r = pTerrain->GetMaxX() / 2;
			CVector3D center(r, desiredPivot.Y, r);
			float dist = (desiredPivot - center).Length();
			if (dist > r - CAMERA_EDGE_MARGIN)
				desiredPivot = center + (desiredPivot - center).Normalized() * (r - CAMERA_EDGE_MARGIN);
		}
		else
		{
			// Clamp to the square edges of the map
			desiredPivot.X = Clamp(desiredPivot.X, pTerrain->GetMinX() + CAMERA_EDGE_MARGIN, pTerrain->GetMaxX() - CAMERA_EDGE_MARGIN);
			desiredPivot.Z = Clamp(desiredPivot.Z, pTerrain->GetMinZ() + CAMERA_EDGE_MARGIN, pTerrain->GetMaxZ() - CAMERA_EDGE_MARGIN);
		}

		// Update the position so that pivot is within the margin
		m->PosX.SetValueSmoothly(desiredPivot.X + delta.X);
		m->PosZ.SetValueSmoothly(desiredPivot.Z + delta.Z);
	}

	m->PosX.Update(deltaRealTime);
	m->PosY.Update(deltaRealTime);
	m->PosZ.Update(deltaRealTime);

	// Handle rotation around the Y (vertical) axis
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);

		float rotateYDelta = m->RotateY.Update(deltaRealTime);
		if (rotateYDelta)
		{
			// We've updated RotateY, and need to adjust Pos so that it's still
			// facing towards the original focus point (the terrain in the center
			// of the screen).

			CVector3D upwards(0.0f, 1.0f, 0.0f);

			CVector3D pivot = GetSmoothPivot(targetCam);
			CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

			CQuaternion q;
			q.FromAxisAngle(upwards, rotateYDelta);
			CVector3D d = q.Rotate(delta) - delta;

			m->PosX.Add(d.X);
			m->PosY.Add(d.Y);
			m->PosZ.Add(d.Z);
		}
	}

	// Handle rotation around the X (sideways, relative to camera) axis
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);

		float rotateXDelta = m->RotateX.Update(deltaRealTime);
		if (rotateXDelta)
		{
			CVector3D rightwards = targetCam.m_Orientation.GetLeft() * -1.0f;

			CVector3D pivot = GetSmoothPivot(targetCam);
			CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

			CQuaternion q;
			q.FromAxisAngle(rightwards, rotateXDelta);
			CVector3D d = q.Rotate(delta) - delta;

			m->PosX.Add(d.X);
			m->PosY.Add(d.Y);
			m->PosZ.Add(d.Z);
		}
	}

	/* This is disabled since it doesn't seem necessary:

	// Ensure the camera's near point is never inside the terrain
	if (m->ConstrainCamera)
	{
		CMatrix3D target;
		target.SetIdentity();
		target.RotateX(m->RotateX.GetValue());
		target.RotateY(m->RotateY.GetValue());
		target.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());

		CVector3D nearPoint = target.GetTranslation() + target.GetIn() * defaultNear;
		float ground = m->Game->GetWorld()->GetTerrain()->GetExactGroundLevel(nearPoint.X, nearPoint.Z);
		float limit = ground + 16.f;
		if (nearPoint.Y < limit)
			m->PosY.AddSmoothly(limit - nearPoint.Y);
	}
	*/

	m->RotateY.Wrap(-(float)M_PI, (float)M_PI);

	// Update the camera matrix
	m->ViewCamera.SetProjection(m->ViewNear, m->ViewFar, m->ViewFOV);
	SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
	m->ViewCamera.UpdateFrustum();
}
Beispiel #3
0
bool CManipRot::UIEventHandler( const ui::Event& EV )
{	
	int ex = EV.miX;
	int ey = EV.miY;
	
	CVector2 posubp = EV.GetUnitCoordBP();

	CCamera *pcam = mManager.GetActiveCamera();
	
	bool brval = false;
			
	bool isshift = false; //CSystem::IsKeyDepressed(VK_SHIFT );
	bool isctrl = false; //CSystem::IsKeyDepressed(VK_CONTROL );
	
	switch( EV.miEventCode )
	{
		case ui::UIEV_PUSH:
		{	
			mManager.mManipHandler.Init(posubp, pcam->mCameraData.GetIVPMatrix(), pcam->QuatC );
			mBaseTransform = mManager.mCurTransform;

			SelectBestPlane(posubp);

			brval = true;
		}
		break;

		case ui::UIEV_RELEASE:
		{
			mManager.DisableManip();

			brval = true;
		}
		break;

		case ui::UIEV_DRAG:
		{
			IntersectWithPlanes( posubp );

			if ( CheckIntersect() )
			{	
				///////////////////////////////////////////
				// calc normalvectors from base:origin to point on activeintersection plane (in world space)
				const CVector3 & Origin = mBaseTransform.GetTransform().GetPosition();
				CVector3 D1 = (Origin-mActiveIntersection->mIntersectionPoint).Normal();
				CVector3 D0 = (Origin-mActiveIntersection->mBaseIntersectionPoint).Normal();
				///////////////////////////////////////////
				// calc matrix to put worldspace vector into plane local space
				CMatrix4 MatWldToObj = mBaseTransform.GetTransform().GetMatrix(); //GetRotation();
				MatWldToObj.Inverse();
				CVector4 bAxisAngle = mLocalRotationAxis; 
				CQuaternion brq;
				brq.FromAxisAngle(bAxisAngle);
				CMatrix4 MatObjToPln = brq.ToMatrix();
				MatObjToPln.Inverse();
				CMatrix4 MatWldToPln = MatObjToPln*MatWldToObj;
				//CMatrix4 MatInvRot = InvQuat.ToMatrix();
				///////////////////////////////////////////
				// calc plane local rotation
				CVector4 AxisAngle = mLocalRotationAxis; 
				CVector4 D0I = CVector4(D0,CReal(0.0f)).Transform(MatWldToPln);
				CVector4 D1I = CVector4(D1,CReal(0.0f)).Transform(MatWldToPln);
				//orkprintf( "D0 <%f %f %f>\n", float(D0.GetX()), float(D0.GetY()), float(D0.GetZ()) );
				//orkprintf( "D1 <%f %f %f>\n", float(D1.GetX()), float(D1.GetY()), float(D1.GetZ()) );
				//orkprintf( "D0I <%f %f %f>\n", float(D0I.GetX()), float(D0I.GetY()), float(D0I.GetZ()) );
				//orkprintf( "D1I <%f %f %f>\n", float(D1I.GetX()), float(D1I.GetY()), float(D1I.GetZ()) );
				AxisAngle.SetW( CalcAngle(D0I,D1I) );
				CQuaternion RotQ;
				RotQ.FromAxisAngle( AxisAngle );
				///////////////////
				// Rot Snap
				if( isshift )
				{	CReal SnapAngleVal( PI2/16.0f );
					CVector4 NewAxisAngle = RotQ.ToAxisAngle();
					CReal Angle = NewAxisAngle.GetW();
					Angle = SnapReal( Angle, SnapAngleVal );
					NewAxisAngle.SetW( Angle );
					RotQ.FromAxisAngle( NewAxisAngle );
				}
				///////////////////
				// accum rotation
				CQuaternion oq = mBaseTransform.GetTransform().GetRotation();
				CQuaternion NewQ = RotQ.Multiply(oq);
				///////////////////
				// Rot Reset To Identity
				if( isctrl && isshift )
				{
					NewQ.FromAxisAngle( CVector4( CReal(0.0f), CReal(1.0f), CReal(0.0f), CReal(0.0f) ) );
				}
				///////////////////
				TransformNode mset = mManager.mCurTransform;
				mset.GetTransform().SetRotation( NewQ );
				mManager.ApplyTransform( mset );
				///////////////////
			}

			brval = true;
		}
		break;

		default:
			break;
	}

	return brval;
}