Example #1
0
void ClawUnitActor::actDirectClawControls(Unit *unit)
{
	int weapTypeNum = 0;
	static int rotating = 0;
  static bool claw_near = true;

	UnitType *unitType = unit->getUnitType();

	if (rotating) rotating--;

	// For longer claw -> 5.5, 5.0

	const game::ControlSettings &controlSettings = game->getClawController()->getControlSettings();
	if(game->getClawController()->hasActor())
	{
		if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) > controlSettings.animationSwitchFarPoseRange) 
		 claw_near = false;
    if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) < controlSettings.animationSwitchNearPoseRange && !rotating) 
		 claw_near = true;
	}
	else
	{
    if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) > controlSettings.animationSwitchFarPoseRange) 
		 claw_near = false;
    if(game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS).GetRangeTo(unit->getPosition()) < controlSettings.animationSwitchNearPoseRange && !rotating) 
		 claw_near = true;
	}

	//bool sprint_key = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_SPRINT, unit);

	bool sprint = false;
	// TODO: ask the clawcontroller if we should sprint - if claw (= pad aiming/mouse) is not moving?
	// if sprint key is pressed, then force the claw not to move

static int thefoocounter = 0;

	if (!game->getClawController()->hasActor()
		&& !game->getClawController()->isClawMoving())
	{
		thefoocounter++;
		if (thefoocounter > 67)
		{
			sprint = true;
		}
	} else {
		thefoocounter = 0;
	}

// SPRINT DISABLED FOR NOW!
sprint = false;

	if (game->getClawController()->getPrepareAction() != ClawController::ActionNone)
	{
		weapTypeNum = 6;
	} else
	{
		if(sprint)
		{
			weapTypeNum = 5;
		} else {
			if(!claw_near)
			{
				if(game->getClawController()->hasActor())
				{
					weapTypeNum = 4;
				}
				else
				{
					weapTypeNum = 2;
				}
			}
			else
			{
				if(game->getClawController()->hasActor())
				{
					weapTypeNum = 3;
				}
				else
				{
					weapTypeNum = 1;
				}
			}
		}
	}

	bool weaponAnimationTypeChanged = false;

	// HACK: hack hack hack static!
	static int lastWeapTypeNum = -1;
	static int weaponChanging = 0;
	if (weapTypeNum != lastWeapTypeNum)
	{
		lastWeapTypeNum = weapTypeNum;
		weaponAnimationTypeChanged = true;
		weaponChanging = GAME_TICKS_PER_SECOND;
	}
  if (weaponChanging) weaponChanging--;
	int anim = ANIM_STAND_TYPE0 + weapTypeNum;

	// get the controls...
	bool up = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_FORWARD, unit);
	bool left = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_LEFT, unit);
	bool right = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_RIGHT, unit);
	bool down = game->gameUI->isLocalPlayerDirectControlOn(DIRECT_CTRL_BACKWARD, unit);

	// initial control coord system (controls in camera coord sys)
	VC3 upvec = VC3(0,1,0);
	VC3 controlFrontVec = VC3(0,0,-1);
	VC3 controlSideVec = controlFrontVec.GetCrossWith(upvec);

	// HACK: hack hack hack static!
	// (if we haven't moved, this is the last moved direction)
	static VC3 controlDirVec = VC3(1,0,0);
	bool doMovement = false;

	if (up || down || left || right)
	{
		VC3 newControlDirVec = VC3(0,0,0);
		if(!game::SimpleOptions::getBool(DH_OPT_B_CLAW_MOUSE))
		{
			int jx = 0;
			int jy = 0;
			Keyb3_ReadJoystick(0, &jx, &jy, 0, 0, 0, 0);
			//if(abs(jx) < 4)
			//	jx = 0;
			//if(abs(jy) < 4)
			//	jy = 0;

			newControlDirVec -= controlSideVec * float(jx);
			newControlDirVec -= controlFrontVec * float(jy);
		}
		else
		{
			if (up)
				newControlDirVec += controlFrontVec;
			if (down)
				newControlDirVec -= controlFrontVec;
			if (left)
				newControlDirVec += controlSideVec;
			if (right)
				newControlDirVec -= controlSideVec;
		}

		if (newControlDirVec.x != 0 || newControlDirVec.y != 0 || newControlDirVec.z != 0)
		{
			newControlDirVec.Normalize();
			controlDirVec = newControlDirVec;
			doMovement = true;
		}
	}

	// camera front/side vectors (height is flattened off)
	VC3 cameraFrontVec = game->gameUI->getGameCamera()->getTargetPosition() - game->gameUI->getGameCamera()->getPosition();
	cameraFrontVec.y = 0.0f;
	if (cameraFrontVec.GetSquareLength() < 0.0001f)
	{
		cameraFrontVec = controlFrontVec;
	}
	cameraFrontVec.Normalize();
	VC3 cameraSideVec = cameraFrontVec.GetCrossWith(upvec);

	// translate movement direction from camera coord system to global ocoord. system	
	// this is the actual movement direction vector.
	VC3 globalDirVec = (cameraFrontVec * controlDirVec.GetDotWith(controlFrontVec)) + (cameraSideVec * controlDirVec.GetDotWith(controlSideVec));

	VC3 velocity = unit->getVelocity();

	// move
	if (doMovement)
	{
		float accel = unitType->getAcceleration() / GAME_TICKS_PER_SECOND;
		velocity += globalDirVec * accel;

		float maxspeed = unitType->getMaxSpeed() / GAME_TICKS_PER_SECOND;
		if (sprint)
		{
			maxspeed = unitType->getSprintSpeed() / GAME_TICKS_PER_SECOND;
		}
		if (weapTypeNum == 6)  maxspeed = unitType->getSlowSpeed() / GAME_TICKS_PER_SECOND;
		float velTotalSq = velocity.GetSquareLength();
		if (velTotalSq > maxspeed*maxspeed)
		{
			velocity *= maxspeed / (float)sqrtf(velTotalSq);
		}

	}

	// friction...
	frictionVelocity(&velocity, unitType->getFriction() * GAME_TICK_MSEC);

	unit->setVelocity(velocity);

	// where do we move to?
	float moveAngle = util::PositionDirectionCalculator::calculateDirection(VC3(0,0,0), globalDirVec);
	float rotateToAngle = moveAngle;



	bool doStrafeLeftAnim = false;
	bool doStrafeRightAnim = false;
	bool doStrafeBackAnim = false;

	static float standAngle = 0;
	
	// where do we aim?
	float aimDestAngle = moveAngle;
	char *aimBone = unitType->getAimBone();
	if (aimBone != NULL)
	{
		VC3 unitPos = unit->getPosition();

		
/*		static VC3 aimPos = VC3(0,0,0);
		VC3 aimDiff = game->getClawController()->getClawPosition() - unitPos;
		if (aimDiff.GetSquareLength() > 2.0f * 2.0f)
		{
			aimPos = game->getClawController()->getClawPosition();
		}*/
		
//		VC3 aimPos = game->getClawController()->getClawPosition();
		VC3 aimPos = game->getClawController()->getTargetPosition(TARGET_ADVANCE_TICKS);

		aimDestAngle = util::PositionDirectionCalculator::calculateDirection(unitPos, aimPos);

		if (doMovement)
		{
			// --- THE HORRIBLE STRAFE LOGIC BEGINS ---
			float insideFwd = util::AngleRotationCalculator::getRotationForAngles(moveAngle, aimDestAngle, 45.0f);
			if (insideFwd == 0)
			{
				rotateToAngle = moveAngle;
			} else {
				float insideFwdDiag = util::AngleRotationCalculator::getRotationForAngles(moveAngle, aimDestAngle, 90.0f+45.0f);
				if (insideFwdDiag == 0)
				{
					if (insideFwd < 0)
					{
						rotateToAngle = moveAngle - 90.0f;
						if (rotateToAngle < 0.0f) rotateToAngle += 360.0f;
						doStrafeRightAnim = true;
					} else {
						rotateToAngle = moveAngle + 90.0f;
						if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f;
						doStrafeLeftAnim = true;
					}
				} else {
					rotateToAngle = moveAngle + 180.0f;
					if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f;
					doStrafeBackAnim = true;
				}
			}
			// --- THE HORRIBLE STRAFE LOGIC ENDS ---

		} else {
			if (weaponAnimationTypeChanged)
			{
				standAngle = aimDestAngle;
			}
			rotateToAngle = standAngle;

			// HACK: ...
			float maxTwist = 45.0f;
			if (weapTypeNum == 6)
			{
				maxTwist = 10.0f;
			}

			while (true)
			{
				float tooFarTwist = util::AngleRotationCalculator::getRotationForAngles(rotateToAngle, aimDestAngle, maxTwist+10);
				if (tooFarTwist > 0)
				{
					rotateToAngle += maxTwist*2;
					if (rotateToAngle >= 360.0f) rotateToAngle -= 360.0f;
				}
				else if (tooFarTwist < 0)
				{
					rotateToAngle -= maxTwist*2;
					if (rotateToAngle < 0.0f) rotateToAngle += 360.0f;
				} else {
					break;
				}
			}
		}
	}

	// When aiming, force rotation to dest.
	if (weapTypeNum == 6)
	{
		rotateToAngle = util::PositionDirectionCalculator::calculateDirection(
			unit->getPosition(),
			game->getClawController()->getTargetPosition(0));
	}

	if (doMovement)
	{
		standAngle = moveAngle;
		weaponChanging = GAME_TICKS_PER_SECOND / 4;
	}

	// rotate towards movement/strafe/whatever we just decided
	VC3 rot = unit->getRotation();

	float turnAccuracy = unitType->getTurningAccuracy();
	float turnSpeed = unitType->getTurning();
  // HACK, if unit is walking, slow it's turning speed down
	if (doMovement) {
		turnSpeed *= 0.7f;
	}

	float turnDir = util::AngleRotationCalculator::getRotationForAngles(rot.y, rotateToAngle, turnAccuracy);
//Logger::getInstance()->error(int2str((int)turnDir));
	rot.y += turnSpeed / GAME_TICKS_PER_SECOND * turnDir;
//	Logger::getInstance()->warning(int2str(rot.y));
//	Logger::getInstance()->warning(int2str(aimDestAngle));
	if (rotateToAngle - rot.y < -180) rotateToAngle +=360;
	if (rotateToAngle - rot.y > 180) rotateToAngle -=360;
	if (turnDir > 0 && rot.y > rotateToAngle)
	{
		rot.y = rotateToAngle;
	}
	if (turnDir < 0 && rot.y < rotateToAngle)
	{
		rot.y = rotateToAngle;
	}
	if (rot.y >= 360.0f) rot.y -= 360.0f;
	if (rot.y < 0.0f) rot.y += 360.0f;

	unit->setRotation(rot.x, rot.y, rot.z);

	// aim towards final aim direction...
	if (aimBone != NULL)
	{
		float aimAngle = aimDestAngle - rot.y;
		if (aimAngle < 0) aimAngle += 360.0f;

		unit->setLastBoneAimDirection(aimAngle);
		if (unit->getVisualObject() != NULL)
		{
			unit->getVisualObject()->rotateBone(aimBone, aimAngle, 0);
		}
	}

	// TODO: select correct animation
	if (doMovement)
	{
		if (doStrafeLeftAnim)
		{
			anim = ANIM_STRAFE_LEFT_TYPE0 + weapTypeNum;
		}
		else if (doStrafeRightAnim)
		{
			anim = ANIM_STRAFE_RIGHT_TYPE0 + weapTypeNum;
		}
		else if (doStrafeBackAnim)
		{
			anim = ANIM_RUN_BACKWARD_TYPE0 + weapTypeNum;
		} else {
			anim = ANIM_RUN_TYPE0 + weapTypeNum;
		}
	} else if (!weaponChanging) {

		// HACK: ... total hack!
		bool nappi = game->gameUI->getController(0)->isKeyDown(DH_CTRL_ATTACK_SECONDARY);

		if (turnDir < 0)
		{
			if (nappi && weapTypeNum == 4)
			{
				anim = ANIM_SPECIAL2;
			} else {
				anim = ANIM_TURN_LEFT_TYPE0 + weapTypeNum;
			}
			rotating = int(0.5*GAME_TICKS_PER_SECOND);
		}
		if (turnDir > 0)
		{
			if (nappi && weapTypeNum == 4)
			{
				anim = ANIM_SPECIAL1;
			} else {
				anim = ANIM_TURN_RIGHT_TYPE0 + weapTypeNum;
			}
			rotating = int(0.5*GAME_TICKS_PER_SECOND);
		}
	}

//Logger::getInstance()->error(int2str(anim));
	// apply the animation...
	if (unit->getAnimationSet() != NULL)
	{
		if (unit->getAnimationSet()->isAnimationInSet(anim))
		{
			unit->getAnimationSet()->animate(unit, anim);
			if (unit->getAnimationSet()->isAnimationStaticFactored(anim))
			{
				float fact = unit->getAnimationSet()->getAnimationStaticFactor(anim);
				ui::Animator::setAnimationSpeedFactor(unit, fact);
			} else {
				ui::Animator::setAnimationSpeedFactor(unit, 1.0f);
			}
		}	else {
			Logger::getInstance()->warning("ClawUnitActor::actDirectClawControls - Requested anim not found in animation set.");
			Logger::getInstance()->debug("anim id number follows:");
			Logger::getInstance()->debug(int2str(anim));
		}
	} else {
		Logger::getInstance()->warning("ClawUnitActor::actDirectClawControls - Unit has null animation set.");
	}
}
Example #2
0
void Storm3D_SpotlightShared::updateMatricesOffCenter(const D3DXMATRIX &cameraView, const VC2 &min, const VC2 &max, float height, Storm3D_Camera &camera)
{
	// Position of the light in global coordinates
	// Y-axis is height
	D3DXVECTOR3 lightPosition(position.x, position.y, position.z);
	// Up vector (z-axis)
	D3DXVECTOR3 up(0.f, 0.f, 1.f);
	// Look direction
	D3DXVECTOR3 lookAt = lightPosition;
	lookAt.y -= 1.f;

	{
		// max and min define the extents of light area in local coordinates
		// Z-axis is height
		float zmin = 0.2f;
		//float zmax = std::max(range, height) * 1.4f;
		// height is light height from light properties
		float zmax = height;
		float factor = 1.5f * zmin / height;
		float xmin = min.x * factor;
		float xmax = max.x * factor;
		float ymin = min.y * factor;
		float ymax = max.y * factor;
		D3DXMatrixPerspectiveOffCenterLH(&lightProjection, xmin, xmax, ymin, ymax, zmin, zmax);

		// Calculate the extents of light area in global coordinates
		VC2 worldMin = min;
		worldMin.x += position.x;
		worldMin.y += position.z;
		VC2 worldMax = max;
		worldMax.x += position.x;
		worldMax.y += position.z;

		// Generate approximate camera for culling.

		// Calculate range of the camera.
		// Y-axis is height
		float planeY = position.y - height;
		// Calculate distances from light position to light plane edges
		VC3 p1 = VC3( worldMin.x, planeY, worldMin.y ) - position;
		VC3 p2 = VC3( worldMax.x, planeY, worldMin.y ) - position;
		VC3 p3 = VC3( worldMax.x, planeY, worldMax.y ) - position;
		VC3 p4 = VC3( worldMin.x, planeY, worldMax.y ) - position;
		float d1 = p1.GetLength();
		float d2 = p2.GetLength();
		float d3 = p3.GetLength();
		float d4 = p4.GetLength();
		float maxRange = 0.0f;
		maxRange = MAX( maxRange, d1 );
		maxRange = MAX( maxRange, d2 );
		maxRange = MAX( maxRange, d3 );
		maxRange = MAX( maxRange, d4 );
		//maxRange = sqrtf(maxRange);

		// Calculate FOV of the camera.
		VC3 planeCenter = VC3( (worldMin.x + worldMax.x) * 0.5f, planeY, (worldMin.y + worldMax.y) * 0.5f );
		VC3 camVec = planeCenter - position;
		camVec.Normalize();
		float minDot = 10000.0f;
		float t1 = camVec.GetDotWith( p1 ) / d1;
		float t2 = camVec.GetDotWith( p2 ) / d2;
		float t3 = camVec.GetDotWith( p3 ) / d3;
		float t4 = camVec.GetDotWith( p4 ) / d4;
		minDot = MIN( minDot, t1 );
		minDot = MIN( minDot, t2 );
		minDot = MIN( minDot, t3 );
		minDot = MIN( minDot, t4 );
		float maxAngle = acosf( minDot );

		// Place camera to light position
		camera.SetPosition(position);
		camera.SetUpVec(VC3(0.f, 0.f, 1.f));
		// Point camera at light plane center
		camera.SetTarget(planeCenter);
		camera.SetFieldOfView( maxAngle );
		camera.SetVisibilityRange( maxRange );
	}
	
	D3DXMATRIX cameraMatrix(cameraView);
	float det = D3DXMatrixDeterminant(&cameraMatrix);
	D3DXMatrixInverse(&cameraMatrix, &det, &cameraMatrix);

	unsigned int tweakRange = 1;
	float bias = 0.f;
	float currentBias = 0.f;
	for(int i = 0; i < 2; ++i)
	{	
		D3DXMatrixLookAtLH(&lightView[i], &lightPosition, &lookAt, &up);
		if(i == 1)
			currentBias = 0;

		// Tweak matrix
		float soffsetX = 0.5f;
		float soffsetY = 0.5f;
		float scale = 0.5f;

		D3DXMATRIX shadowTweak( scale,    0.0f,     0.0f,				0.0f,
								0.0f,     -scale,   0.0f,				0.0f,
								0.0f,      0.0f,     float(tweakRange),	0.0f,
								soffsetX,  soffsetY, currentBias,		1.0f );

		D3DXMatrixMultiply(&shadowProjection[i], &lightProjection, &shadowTweak);
		D3DXMatrixMultiply(&shadowProjection[i], &lightView[i], &shadowProjection[i]);
		D3DXMatrixMultiply(&lightViewProjection[i], &lightView[i], &lightProjection);

		shaderProjection[i] = shadowProjection[i];
		D3DXMatrixMultiply(&shadowProjection[i], &cameraMatrix, &shadowProjection[i]);
	}

	{
		float xf = (1.f / resolutionX * .5f);
		float yf = (1.f / resolutionY * .5f);
		float sX = soffsetX + (2 * targetPos.x * soffsetX) - xf;
		float sY = soffsetY + (2 * targetPos.y * soffsetY) - yf;

		D3DXMATRIX shadowTweak( scaleX,    0.0f,	0.0f,				0.0f,
								0.0f,    -scaleY,	0.0f,				0.0f,
								0.0f,     0.0f,     float(tweakRange),	0.0f,
								sX,       sY,		bias,				1.0f );

		D3DXMatrixMultiply(&targetProjection, &lightProjection, &shadowTweak);
		D3DXMatrixMultiply(&targetProjection, &lightView[0], &targetProjection);
	}
}
	// return true if position ok and decal should be added
	//        false, if position NOT ok and decal should NOT be added
	bool DecalPositionCalculator::calculateDecalPosition(
		game::GameScene *gameScene,
		const VC3 &origin, const VC3 &velocity, 
		DECAL_POSITIONING positioning, int positionRandom,
		VC3 *resultPosition, QUAT *resultRotation)
	{
		assert(positioning != DecalPositionCalculator::DECAL_POSITIONING_INVALID);

		game::GameMap *gameMap = gameScene->getGameMap();

		bool hitWall = false;

		*resultPosition = origin;
		*resultRotation = QUAT((-3.1415926f / 2.0f),0,0);

		// if velocity positioning...
		if (positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY)
		{
			VC3 velocityRandomized;
			if (positionRandom > 0)
			{
				velocityRandomized = velocity * GAME_TICKS_PER_SECOND;

	// TEMP
	//char buf[64];
	//sprintf(buf, "%f,%f,%f", velocity.x, velocity.y, velocity.z);
	//Logger::getInstance()->error(buf);

				// TODO: add positionRandom to velocity _angle_...
				// (or maybe just do a quick hack and add it to xz-coordinates?)
				velocityRandomized.x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				velocityRandomized.z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				
				// add to y too? maybe should add downward only? 
				// NOTE: biased downward
				velocityRandomized.y += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				velocityRandomized.y -= float(positionRandom) / 100.0f * 0.5f;

			} else {
				velocityRandomized = velocity;
			}

			velocityRandomized *= 2.0f;

			IStorm3D_Scene *scene = gameScene->getStormScene();

			VC3 dir = velocityRandomized.GetNormalized();			
			VC3 rayOrigin = origin;
			float rayLen = velocityRandomized.GetLength();

			Storm3D_CollisionInfo sceneColl;
			sceneColl.includeTerrainObjects = false;
			scene->RayTrace(rayOrigin, dir, rayLen, sceneColl, true);

			/*
			if (sceneColl.hit)
			{
				VC3 hitNormal = sceneColl.plane_normal;
				// make a "wall" hit if normal-y is not nearly 1
				//if (fabs(hitNormal.y) < 0.8f)
				{
					hitWall = true;

					VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f);
					x.Normalize();
					x -= hitNormal * x.GetDotWith(hitNormal);
					VC3 y = -x.GetCrossWith(hitNormal);

					assert(fabsf(x.GetDotWith(y)) < 0.0001f);
					assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f);

					MAT tm;
					tm.Set(0, x.x);
					tm.Set(1, x.y);
					tm.Set(2, x.z);
					tm.Set(4, y.x);
					tm.Set(5, y.y);
					tm.Set(6, y.z);
					tm.Set(8, hitNormal.x);
					tm.Set(9, hitNormal.y);
					tm.Set(10, hitNormal.z);

					*resultRotation = tm.GetRotation();
				}
				*resultPosition = sceneColl.position;
			} else {
				*resultPosition += velocityRandomized;
			}
			*/

			// New version
			{
				VC3 hitNormal(0, 1.f, 0);
				if(sceneColl.hit)
				{
					hitNormal = sceneColl.plane_normal;
					*resultPosition = sceneColl.position;
				}
				else
				{
					*resultPosition += velocityRandomized;
					VC2 p2(resultPosition->x, resultPosition->z);
					hitNormal = gameScene->getTerrain()->getFaceNormal(p2);
				}

				{
					if(sceneColl.hit)
						hitWall = true;

		/*
		VC3 y = dir;
		VC3 z = hitNormal;
		y -= hitNormal * y.GetDotWith(hitNormal);
		VC3 x = z.GetCrossWith(y);
		*/

		VC3 x = dir;
		x.y = 0.f;
		x.Normalize();
		x -= hitNormal * x.GetDotWith(hitNormal);
		VC3 y = -x.GetCrossWith(hitNormal);
		VC3 z = hitNormal;

		MAT tm;
		tm.Set(0, x.x);
		tm.Set(1, x.y);
		tm.Set(2, x.z);
		tm.Set(4, y.x);
		tm.Set(5, y.y);
		tm.Set(6, y.z);
		tm.Set(8, z.x);
		tm.Set(9, z.y);
		tm.Set(10, z.z);

		resultRotation->MakeFromAngles(0.f, 0.f, -PI*0.5f);
		*resultRotation = (*resultRotation) * tm.GetRotation();

					/*
					VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f);
					x.Normalize();
					x -= hitNormal * x.GetDotWith(hitNormal);
					VC3 y = -x.GetCrossWith(hitNormal);

					assert(fabsf(x.GetDotWith(y)) < 0.0001f);
					assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f);

					MAT tm;
					tm.Set(0, x.x);
					tm.Set(1, x.y);
					tm.Set(2, x.z);
					tm.Set(4, y.x);
					tm.Set(5, y.y);
					tm.Set(6, y.z);
					tm.Set(8, hitNormal.x);
					tm.Set(9, hitNormal.y);
					tm.Set(10, hitNormal.z);

					*resultRotation = tm.GetRotation();
					*/
				}
			}


			// TODO: some kind of terrain raytrace maybe...?
			// should collide to walls, etc.
		}

		// if downward positioning...
		if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD)
		{
			if (positionRandom > 0)
			{
				// TODO: add a random xz-offset to result position
				//*resultPosition += randomizedOffset;
				resultPosition->x += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
				resultPosition->z += float((SystemRandom::getInstance()->nextInt() % (positionRandom * 2 + 1)) - positionRandom) / 100.0f;
			}			

			/*
			// psd
			{
				VC2 p2(resultPosition->x, resultPosition->z);
				VC3 hitNormal = gameScene->getTerrain()->getFaceNormal(p2);

				VC3 x(rand() % 1000 / 999.f, 0, rand() % 1000 / 999.f);
				x.Normalize();
				x -= hitNormal * x.GetDotWith(hitNormal);
				VC3 y = -x.GetCrossWith(hitNormal);

				assert(fabsf(x.GetDotWith(y)) < 0.0001f);
				assert(fabsf(x.GetDotWith(hitNormal)) < 0.0001f);

				MAT tm;
				tm.Set(0, x.x);
				tm.Set(1, x.y);
				tm.Set(2, x.z);
				tm.Set(4, y.x);
				tm.Set(5, y.y);
				tm.Set(6, y.z);
				tm.Set(8, hitNormal.x);
				tm.Set(9, hitNormal.y);
				tm.Set(10, hitNormal.z);

				*resultRotation = tm.GetRotation();
			}
			*/
			VC3 fooNormal;
			calculateDecalRotation(gameScene, *resultPosition, *resultRotation, 0.f, fooNormal);
		}

		// now check that we're still inside map boundaries
		if (!gameMap->isWellInScaledBoundaries(resultPosition->x, resultPosition->z))
		{
			// out of map.
			return false;
		}

		// then fix decal height to ground height
		if (positioning == DecalPositionCalculator::DECAL_POSITIONING_DOWNWARD
			|| positioning == DecalPositionCalculator::DECAL_POSITIONING_VELOCITY)
		{
			if (!hitWall)
			{
				resultPosition->y = gameMap->getScaledHeightAt(resultPosition->x, resultPosition->z);
			}
		}

		// check that not on top of metal grid area...
		if (game::MaterialManager::isMaterialUnderPosition(gameMap, 
			*resultPosition, MATERIAL_METAL_GRATE))
		{
			// on top of grid, no decal here.
			return false;
		}

		// TODO: check that not inside a wall, terrainobject, etc.
		// if so, return false

		return true;
	}