void Storm3D_Spotlight::testVisibility(Storm3D_Camera &camera)
{
	// Simple hack, skip visibility check if camera has orthogonal projection on (practically when mapview is enabled)
	if(!(data->spotlightAlwaysVisible || camera.GetForcedOrthogonalProjectionEnabled() ) )
	{
		data->visible = camera.TestSphereVisibility(data->properties.position, data->properties.range);
		data->coneUpdated = false;
	}
	else
	{
		data->visible = true;
		data->coneUpdated = false;
	}
}
	void updateMatrices(const float *cameraView)
	{
		float bias = getBias();
		if(shadowMap)
			properties.targetPos = shadowMap->pos;

		properties.resolutionX = 2 * SHADOW_WIDTH;
		properties.resolutionY = 2 * SHADOW_HEIGHT;
		properties.updateMatrices(cameraView, bias);

		camera.SetPosition(properties.position);
		camera.SetTarget(properties.position + properties.direction);
		camera.SetFieldOfView(D3DXToRadian(properties.fov));
		camera.SetVisibilityRange(properties.range);
	}
	void findDecals(Storm3D_Scene &scene)
	{
		decals.clear();

		// Find decals
		{
			IStorm3D_Camera *camera = scene.GetCamera();
			Storm3D_Camera *stormCamera = reinterpret_cast<Storm3D_Camera *> (camera);

			Frustum frustum = stormCamera->getFrustum();
			Tree::FrustumIterator itf(*tree, frustum);
			for(; !itf.end(); itf.next())
				decals.push_back(*itf);

			std::sort(decals.begin(), decals.end(), DecalSorter());
		}
	}
/*!
	\param camera camera to which test visibility
*/
void Storm3D_FakeSpotlight::testVisibility(Storm3D_Camera &camera)
{
//	data->visible = camera.TestSphereVisibility(data->properties.position, data->properties.range);
//	data->visible = true;

	// Frustum vs. AABB
	VC2 min, max;
	float planeY = data->properties.position.y - data->plane.height;
	getPlane(min, max);
	AABB clipBox ( VC3( min.x, planeY - 0.1f, min.y ), VC3( max.x, planeY + 0.1f, max.y ) );
	data->visible = camera.TestBoxVisibility ( clipBox.mmin, clipBox.mmax );

}
	void renderShadows(Storm3D_Scene &scene)
	{
		// this is BROKEN
		// FIXME
		// just clear the list
		shadowDecals.clear();
		return;

		createIndexBuffers();

		int renderAmount = 0;
		if(!shadowDecals.empty())
		{
			IStorm3D_Camera *camera = scene.GetCamera();
			Storm3D_Camera *stormCamera = reinterpret_cast<Storm3D_Camera *> (camera);
			Frustum frustum = stormCamera->getFrustum();

			shadowVertices.create(shadowDecals.size() * 4, VERTEX_SIZE, true);

			int rawSize = shadowDecals.size() * 4 * VERTEX_SIZE;
			void *ramBuffer = malloc(rawSize);
			void *lockPointer = shadowVertices.lock();
			VXFORMAT_DECAL *buffer = reinterpret_cast<VXFORMAT_DECAL *> (ramBuffer);

			float inverseRange =1.f / fogRange;
			for(unsigned int i = 0; i < shadowDecals.size(); ++i)
			{
				const StormDecal &decal = shadowDecals[i];
				Sphere sphere(decal.position, decal.getRadius());
				if(frustum.visibility(sphere))
				{
					float factor = decal.position.y - fogEnd;
					factor *= inverseRange;
					if(factor < 0.f)
						factor = 0.f;
					if(factor > 1.f)
						factor = 1.f;
					factor = 1.f - factor;

					COL color = decal.light;
					color.r += factor * (1.f - color.r);
					color.g += factor * (1.f - color.g);
					color.b += factor * (1.f - color.b);

					DWORD vertexColor = color.GetAsD3DCompatibleARGB() & 0x00FFFFFF;

					DWORD oldColor = decal.vertexColor;
					decal.vertexColor = vertexColor;
					decal.insert(buffer);
					decal.vertexColor = oldColor;

					buffer += 4;
					++renderAmount;
				}
			}

			if(renderAmount)
			{
				if(renderAmount > STORM_MAX_DECAL_AMOUNT)
					renderAmount = STORM_MAX_DECAL_AMOUNT;
				memcpy(lockPointer, ramBuffer, renderAmount * 4 * VERTEX_SIZE);
			}

			free(ramBuffer);
			shadowVertices.unlock();
		}

		D3DXMATRIX tm;

		frozenbyte::storm::VertexShader::disable();
		frozenbyte::storm::PixelShader::disable();
		Storm3D_ShaderManager::GetSingleton()->SetWorldTransform(tm);

		applyFVF(DECAL_FVF, VERTEX_SIZE);
		glActiveTexture(GL_TEXTURE0);
		glClientActiveTexture(GL_TEXTURE0);
		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
		glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
		glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
		glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
		glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PRIMARY_COLOR);
		glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
		glActiveTexture(GL_TEXTURE1);
		glClientActiveTexture(GL_TEXTURE1);
		glDisable(GL_TEXTURE_2D);
		glDisable(GL_TEXTURE_3D);
		glDisable(GL_TEXTURE_CUBE_MAP);

		glDepthMask(GL_FALSE);
		glEnable(GL_BLEND);
		glDisable(GL_ALPHA_TEST);
		glBlendFunc(GL_ZERO, GL_SRC_COLOR);

		if(renderAmount && shadowMaterial)
		{
			shadowVertices.apply(0);
			shadowMaterial->applyShadow();

			indices.render(renderAmount * 2, renderAmount * 4);
			scene.AddPolyCounter(renderAmount * 2);
		}

		glDepthMask(GL_TRUE);
		glDisable(GL_BLEND);
		shadowDecals.clear();
	}
Exemple #6
0
bool Storm3D_SpotlightShared::setScissorRect(Storm3D_Camera &camera, const VC2I &screenSize, Storm3D_Scene *scene)
{
	D3DXMATRIX light;
	D3DXVECTOR3 lightPosition(position.x, position.y, position.z);
	D3DXVECTOR3 up(0, 1.f, 0);
	D3DXVECTOR3 lookAt = lightPosition;
	lookAt += D3DXVECTOR3(direction.x, direction.y, direction.z);
	D3DXMatrixLookAtLH(&light, &lightPosition, &lookAt, &up);

	// Create frustum vertices

	D3DXVECTOR3 v[5];
	v[0] = D3DXVECTOR3(0, 0, 0);
	v[1] = D3DXVECTOR3(0, 0, 1.f);
	v[2] = D3DXVECTOR3(0, 0, 1.f);
	v[3] = D3DXVECTOR3(0, 0, 1.f);
	v[4] = D3DXVECTOR3(0, 0, 1.f);

	float det = D3DXMatrixDeterminant(&light);
	D3DXMatrixInverse(&light, &det, &light);
	float angle = D3DXToRadian(fov) * .5f;
	for(int i = 0; i <= 4; ++i)
	{
		if(i > 0)
		{
			float z = v[i].z;
			if(i == 1 || i == 2)
			{
				v[i].x = z * sinf(angle);
				v[i].z = z * cosf(angle);
			}
			else
			{
				v[i].x = z * sinf(-angle);
				v[i].z = z * cosf(-angle);
			}

			if(i == 1 || i == 3)
				v[i].y = z * sinf(angle);
			else
				v[i].y = z * sinf(-angle);

			float scale = range / cosf(angle);
			v[i] *= scale;
		}

		D3DXVec3TransformCoord(&v[i], &v[i], &light);
	}

	// Create area

	const Frustum &frustum = camera.getFrustum();
	int minX = screenSize.x;
	int minY = screenSize.y;
	int maxX = 0;
	int maxY = 0;

	for(int i = 0; i < 6; ++i)
	{
		VC3 v1;
		VC3 v2;
		VC3 v3;

		if(i == 0)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[1]);
			v3 = toVC3(v[2]);
		}
		else if(i == 1)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[2]);
			v3 = toVC3(v[4]);
		}
		else if(i == 2)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[3]);
			v3 = toVC3(v[4]);
		}
		else if(i == 3)
		{
			v1 = toVC3(v[0]);
			v2 = toVC3(v[1]);
			v3 = toVC3(v[3]);
		}
		else if(i == 4)
		{
			v1 = toVC3(v[1]);
			v2 = toVC3(v[2]);
			v3 = toVC3(v[3]);
		}
		else if(i == 5)
		{
			v1 = toVC3(v[4]);
			v2 = toVC3(v[2]);
			v3 = toVC3(v[3]);
		}

		const ClipPolygon &clipPolygon = clipTriangleToFrustum(v1, v2, v3, frustum);
		for(int j = 0; j < clipPolygon.vertexAmount; ++j)
		{
			VC3 result;
			float rhw = 0.f;
			float real_z = 0.f;
			camera.GetTransformedToScreen(clipPolygon.vertices[j], result, rhw, real_z);

			int x = int(result.x * screenSize.x);
			int y = int(result.y * screenSize.y);
			//if(x < -1 || x > screenSize.x)
			//	continue;
			//if(y < -1 || x > screenSize.y)
			//	continue;

			x = max(x, 0);
			y = max(y, 0);
			x = min(x, screenSize.x - 1);
			y = min(y, screenSize.y - 1);

			maxX = max(x, maxX);
			maxY = max(y, maxY);
			minX = min(x, minX);
			minY = min(y, minY);

			/*
			// Visualize clipped polygons
			if(scene)
			{
				VC3 p1 = clipPolygon.vertices[j];
				VC3 p2 = clipPolygon.vertices[(j + 1) % clipPolygon.vertexAmount];


				for(int k = 0; k < 5; ++k)
				{
					const VC3 &planeNormal = frustum.planeNormals[k];
					PLANE plane;

					if(k == 0)
						plane.MakeFromNormalAndPosition(planeNormal, frustum.position + planeNormal);
					else
						plane.MakeFromNormalAndPosition(planeNormal, frustum.position);
	
					float d1 = plane.GetPointRange(p1);
					float d2 = plane.GetPointRange(p2);

					if(d1 < .25f)
						p1 += planeNormal * (.25f - d1);
					if(d2 < .25f)
						p2 += planeNormal * (.25f - d2);
				}

				scene->AddLine(p1, p2, COL(1.f, 1.f, 1.f));
			}
			*/
		}
	}

	RECT rc;
	bool visible = false;

	if(maxX > minX && maxY > minY)
	{
		visible = true;
		rc.left = minX;
		rc.top = minY;
		rc.right = maxX;
		rc.bottom = maxY;
	}
	else
	{
		visible = false;
		rc.left = 0;
		rc.top = 0;
		rc.right = 1;
		rc.bottom = 1;
	}
/*
	// Visualize scissor area
	if(scene && visible)
	{
		static DWORD foo = GetTickCount();
		int dif = (GetTickCount() - foo) % 2000;
		if(dif < 1000)
			scene->Render2D_Picture(0, VC2(float(minX), float(minY)), VC2(float(maxX - minX), float(maxY - minY)), 0.5f, 0.f, 0, 0, 0, 0, false);
	}
*/
	device.SetScissorRect(&rc);
	device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);

	return visible;
}
Exemple #7
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);
	}
}
/*!
	\param present
	\return polygon count
*/
int Storm3D_Scene::RenderScene(bool present)
{
	// Reset polygon counter
	poly_counter = 0;
	
	{
		static int haxValue = 0;
		++haxValue;

		IStorm3D_Texture *target = Storm3D2->getReflectionTexture();
		if(target /*&& haxValue > 1*/) 
		{
			haxValue = 0;

			enableLocalReflection = true;
			frozenbyte::storm::setInverseCulling(true);
			active_visibility = 1;

			Storm3D_Camera camback = camera;
			camback.Apply();

			Storm3D_Texture *render_target = (Storm3D_Texture *) target;
			if (!render_target->IsCube())
			{
				bool renderHalved = true;
				bool renderDistortion = true;
				bool renderGlow = true;
				bool renderGlowImproved = true;
				bool renderFakes = true;
				bool renderFakeShadows = true;
				bool renderSpotShadows = true;
				bool renderParticles = true;

				if(!terrains.empty())
				{
					IStorm3D_TerrainRenderer &renderer = (*terrains.begin())->getRenderer();
					bool shouldRenderHalved = Storm3D2->halfReflection;
					bool shouldRenderDistortion = false;
					bool shouldRenderGlow = false;
					bool shouldRenderGlowImproved = false;
					bool shouldRenderFakes = false;
					bool shouldRenderFakeShadows = false;
					bool shouldRenderSpotShadows = false;

					// Particle reflection hacky
					bool shouldRenderParticleReflection = false;
					shouldRenderParticleReflection = renderer.enableFeature(IStorm3D_TerrainRenderer::ParticleReflection, false);
					renderer.enableFeature(IStorm3D_TerrainRenderer::ParticleReflection, shouldRenderParticleReflection);
					renderParticles = renderer.enableFeature(IStorm3D_TerrainRenderer::Particles, shouldRenderParticleReflection);

					if(Storm3D2->reflectionQuality >= 100)
					{
						shouldRenderDistortion = true;
						shouldRenderGlow = true;
					}

					renderHalved = renderer.enableFeature(IStorm3D_TerrainRenderer::HalfRendering, shouldRenderHalved);
					renderDistortion = renderer.enableFeature(IStorm3D_TerrainRenderer::Distortion, shouldRenderDistortion);
					renderGlow = renderer.enableFeature(IStorm3D_TerrainRenderer::Glow, shouldRenderGlow);
					renderGlowImproved = renderer.enableFeature(IStorm3D_TerrainRenderer::BetterGlowSampling, shouldRenderGlowImproved);
					renderFakes = renderer.enableFeature(IStorm3D_TerrainRenderer::FakeLights, shouldRenderFakes);
					renderFakeShadows = renderer.enableFeature(IStorm3D_TerrainRenderer::FakeShadows, shouldRenderFakeShadows);
					renderSpotShadows = renderer.enableFeature(IStorm3D_TerrainRenderer::SpotShadows, shouldRenderSpotShadows);

					// If we already have features disabled, don't enable them for reflection
					if(renderHalved)
						renderer.enableFeature(IStorm3D_TerrainRenderer::HalfRendering, true);
					if(!renderDistortion)
						renderer.enableFeature(IStorm3D_TerrainRenderer::Distortion, false);
					if(!renderGlowImproved)
						renderer.enableFeature(IStorm3D_TerrainRenderer::BetterGlowSampling, false);
					if(!renderGlow)
						renderer.enableFeature(IStorm3D_TerrainRenderer::Glow, false);
					if(!renderFakes)
						renderer.enableFeature(IStorm3D_TerrainRenderer::FakeLights, false);
					if(!renderFakeShadows)
						renderer.enableFeature(IStorm3D_TerrainRenderer::FakeShadows, false);
					if(!renderSpotShadows)
						renderer.enableFeature(IStorm3D_TerrainRenderer::SpotShadows, false);
				}

				VC3 position = camera.GetPosition();
				VC3 target = camera.GetTarget();

				// Mirror relative to reflection plane
				position.y = reflection_height - (position.y - reflection_height);
				target.y = reflection_height - (target.y - reflection_height);

				camera.SetPosition(position);
				camera.SetTarget(target);
				camera.ForceViewProjection(&camback);
				RenderSceneWithParams(false,false,false,true,render_target);

				igios_unimplemented();

				if(!terrains.empty())
				{
					IStorm3D_TerrainRenderer &renderer = (*terrains.begin())->getRenderer();

					renderer.enableFeature(IStorm3D_TerrainRenderer::HalfRendering, renderHalved);
					renderer.enableFeature(IStorm3D_TerrainRenderer::Distortion, renderDistortion);
					renderer.enableFeature(IStorm3D_TerrainRenderer::Glow, renderGlow);
					renderer.enableFeature(IStorm3D_TerrainRenderer::BetterGlowSampling, renderGlowImproved);
					renderer.enableFeature(IStorm3D_TerrainRenderer::FakeLights, renderFakes);
					renderer.enableFeature(IStorm3D_TerrainRenderer::FakeShadows, renderFakeShadows);
					renderer.enableFeature(IStorm3D_TerrainRenderer::SpotShadows, renderSpotShadows);
					renderer.enableFeature(IStorm3D_TerrainRenderer::Particles, renderParticles);
				}

				// debugging code
				if(false){
					static IStorm3D_Material *hax = this->Storm3D2->CreateNewMaterial("..");
					hax->SetBaseTexture(render_target);
					this->Render2D_Picture(hax, VC2(300,10), VC2(512,512), 1.f, 0.f, 0.f, 0.f, 1.f, 1.f, false);
				}
			}

			active_visibility = 0;
			enableLocalReflection = false;
			frozenbyte::storm::setInverseCulling(false);

			camera = camback;
		}
	}

	// Render with flip
	RenderSceneWithParams(present, false);

	// Return polygon count
	return poly_counter;
}
bool Storm3D_SpotlightShared::setScissorRect(Storm3D_Camera &camera, const VC2I &screenSize)
{
	D3DXMATRIX light;
	D3DXVECTOR3 lightPosition(position.x, position.y, position.z);
	D3DXVECTOR3 up(0, 1.f, 0);
	D3DXVECTOR3 lookAt = lightPosition;
	lookAt += D3DXVECTOR3(direction.x, direction.y, direction.z);
	D3DXMatrixLookAtLH(&light, &lightPosition, &lookAt, &up);

	D3DXVECTOR3 v[5];
	v[0] = D3DXVECTOR3(0, 0, 0);
	v[1] = D3DXVECTOR3(0, 0, 1.f);
	v[2] = D3DXVECTOR3(0, 0, 1.f);
	v[3] = D3DXVECTOR3(0, 0, 1.f);
	v[4] = D3DXVECTOR3(0, 0, 1.f);

	int minX = screenSize.x;
	int minY = screenSize.y;
	int maxX = 0;
	int maxY = 0;

	float det = D3DXMatrixDeterminant(&light);
	D3DXMatrixInverse(&light, &det, &light);

	float angle = D3DXToRadian(fov) * .5f;
	for(int i = 0; i <= 4; ++i)
	{
		if(i > 0)
		{
			float z = v[i].z;
			if(i == 1 || i == 2)
			{
				v[i].x = z * sinf(angle);
				v[i].z = z * cosf(angle);
			}
			else
			{
				v[i].x = z * sinf(-angle);
				v[i].z = z * cosf(-angle);
			}

			if(i == 1 || i == 3)
				v[i].y = z * sinf(angle);
			else
				v[i].y = z * sinf(-angle);

			float scale = range / cosf(angle);
			v[i] *= scale;
		}

		D3DXVec3TransformCoord(&v[i], &v[i], &light);
	}

	const Frustum &frustum = camera.getFrustum();
	calculateLineToScissor(toVC3(v[0]), toVC3(v[1]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[0]), toVC3(v[2]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[0]), toVC3(v[3]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[0]), toVC3(v[4]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[1]), toVC3(v[2]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[2]), toVC3(v[3]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[3]), toVC3(v[4]), frustum, camera, screenSize, minX, minY, maxX, maxY);
	calculateLineToScissor(toVC3(v[4]), toVC3(v[1]), frustum, camera, screenSize, minX, minY, maxX, maxY);

	/*
	VC3 cameraPos = camera.GetPosition();
	VC3 cameraPosResult;
	float cameraRhw = 0, cameraRealZ = 0;
	bool cameraVisible = camera.GetTransformedToScreen(cameraPos, cameraPosResult, cameraRhw, cameraRealZ);

	for(i = 0; i <= 4; ++i)
	{
		VC3 source(v[i].x, v[i].y, v[i].z);
		VC3 result;
		float rhw = 0, realZ = 0;
		bool inFront = camera.GetTransformedToScreen(source, result, rhw, realZ);

		// HAX HAX!

		result.x = std::max(0.f, result.x);
		result.y = std::max(0.f, result.y);
		result.x = std::min(1.f, result.x);
		result.y = std::min(1.f, result.y);

		//if(fabsf(rhw) < 0.0001f)
		//	continue;

		bool flip = false;
		if(realZ < cameraRealZ)
			flip = true;

		if(flip)
		{
			result.x = 1.f - result.x;
			result.y = 1.f - result.y;

			//minX = 0;
			//minY = 0;
			//maxX = screenSize.x;
			//maxY = screenSize.y;
		}

		int x = int(result.x * screenSize.x);
		int y = int(result.y * screenSize.y);

		maxX = std::max(x, maxX);
		maxY = std::max(y, maxY);
		minX = std::min(x, minX);
		minY = std::min(y, minY);
	}
	*/

	if(maxX > screenSize.x)
		maxX = screenSize.x;
	if(maxY > screenSize.y)
		maxY = screenSize.y;
	if(minX < 0)
		minX = 0;
	if(minY < 0)
		minY = 0;

	RECT rc;
	rc.left = minX;
	rc.top = minY;
	rc.right = maxX;
	rc.bottom = maxY;

	if(rc.left < rc.right && rc.top < rc.bottom)
	{
		device.SetScissorRect(&rc);
		device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
	}
	else
	{
		RECT rc;
		rc.left = 0;
		rc.top = 0;
		rc.right = 1;
		rc.bottom = 1;

		device.SetScissorRect(&rc);
		device.SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);

		return false;
	}

	return true;
}
void Storm3D_Spotlight::renderCone(Storm3D_Camera &camera, float timeFactor, bool renderGlows)
{
	if(!data->hasCone || !data->hasShadows || !data->shadowMap)
		return;

	bool normalPass = !data->coneUpdated;
	if(data->hasCone && data->updateCone && !data->coneUpdated)
	{
		data->createCone();
		data->coneUpdated = true;
	}

	D3DXVECTOR3 lightPosition(data->properties.position.x, data->properties.position.y, data->properties.position.z);
	D3DXVECTOR3 up(0, 1.f, 0);
	D3DXVECTOR3 lookAt = lightPosition;
	lookAt += D3DXVECTOR3(data->properties.direction.x, data->properties.direction.y, data->properties.direction.z);

	D3DXMATRIX tm;
	D3DXMatrixLookAtLH(&tm, &lightPosition, &lookAt, &up);

	VC3 cameraDir = camera.GetDirection();
	cameraDir.Normalize();
	D3DXVECTOR3 direction(cameraDir.x, cameraDir.y, cameraDir.z);
	D3DXVec3TransformNormal(&direction, &direction, &tm);

	Storm3D_ShaderManager::GetSingleton()->setSpot(data->properties.color, data->properties.position, data->properties.direction, data->properties.range, .1f);
	Storm3D_ShaderManager::GetSingleton()->setTextureTm(data->properties.shaderProjection[0]);
	Storm3D_ShaderManager::GetSingleton()->setSpotTarget(data->properties.targetProjection);

	float det = D3DXMatrixDeterminant(&tm);
	D3DXMatrixInverse(&tm, &det, &tm);
	Storm3D_ShaderManager::GetSingleton()->SetWorldTransform(data->device, tm, true);

	if(data->shadowMap && data->shadowMap->hasInitialized())
		data->shadowMap->apply(0);
	if(data->coneTexture)
	{
		data->coneTexture->AnimateVideo();
		data->coneTexture->Apply(3);

		if(type == AtiBuffer || type == AtiFloatBuffer)
			data->coneTexture->Apply(4);
		else
			data->coneTexture->Apply(1);
	}

	if(type == AtiBuffer)
	{
		if(data->coneTexture)
			data->coneAtiPixelShader_Texture->apply();
		else
			data->coneAtiPixelShader_NoTexture->apply();

	}
	else if(type == AtiFloatBuffer)
	{
		if(data->coneTexture)
			data->coneAtiFloatPixelShader_Texture->apply();
		else
			data->coneAtiFloatPixelShader_NoTexture->apply();
	}
	else
	{
		if(data->coneTexture)
			data->coneNvPixelShader_Texture->apply();
		else
			data->coneNvPixelShader_NoTexture->apply();
	}

	float colorMul = data->coneColorMultiplier;
	float colorData[4] = { data->properties.color.r * colorMul, data->properties.color.g * colorMul, data->properties.color.b * colorMul, 1.f };
	if(renderGlows)
	{
		if(normalPass)
		{
			colorData[0] *= 0.2f;
			colorData[1] *= 0.2f;
			colorData[2] *= 0.2f;
			colorData[3] *= 0.2f;
		}
		else
		{
			colorData[0] *= 0.4f;
			colorData[1] *= 0.4f;
			colorData[2] *= 0.4f;
			colorData[3] *= 0.4f;
		}
	}

	data->device.SetVertexShaderConstantF(9, colorData, 1);

	float bias = 0.005f;
	float directionData[4] = { -direction.x, -direction.y, -direction.z, bias };
	data->device.SetVertexShaderConstantF(10, directionData, 1);

	for(int i = 0; i < 2; ++i)
	{
		data->angle[i] += data->speed[i] * timeFactor;
		D3DXVECTOR3 center(0.5f, 0.5f, 0.f);
		D3DXQUATERNION quat1;
		D3DXQuaternionRotationYawPitchRoll(&quat1, 0, 0, data->angle[i]);
		D3DXMATRIX rot1;
		D3DXMatrixAffineTransformation(&rot1, 1.f, &center, &quat1, 0);
		D3DXMatrixTranspose(&rot1, &rot1);
		
		if(i == 0)
			data->device.SetVertexShaderConstantF(16, rot1, 3);
		else
			data->device.SetVertexShaderConstantF(19, rot1, 3);
	}

	frozenbyte::storm::enableMipFiltering(data->device, 0, 0, false);
	data->coneVertexBuffer.apply(data->device, 0);
	data->coneIndexBuffer.render(data->device, CONE_FACES, CONE_VERTICES);
	frozenbyte::storm::enableMipFiltering(data->device, 0, 0, true);
}
    void renderShadows(Storm3D_Scene &scene)
    {
        gfx::Renderer& renderer = storm.renderer;
        gfx::Device& device = renderer.device;
        gfx::ProgramManager& programManager = renderer.programManager;

        if (shadowDecals.empty() || !shadowMaterial)
            return;

        int renderAmount = 0;

        IStorm3D_Camera *camera = scene.GetCamera();
        Storm3D_Camera *stormCamera = reinterpret_cast<Storm3D_Camera *> (camera);
        Frustum frustum = stormCamera->getFrustum();

        uint32_t baseVertex = 0;
        Vertex_P3DUV *buffer = 0;;
        renderer.lockDynVtx<Vertex_P3DUV>(shadowDecals.size() * 4, &buffer, &baseVertex);

        float inverseRange = 1.f / fogRange;
        for (unsigned int i = 0; i < shadowDecals.size() && renderAmount < MAX_DECAL_AMOUNT; ++i)
        {
            const Decal &decal = shadowDecals[i];
            Sphere sphere(decal.position, decal.getRadius());
            if (frustum.visibility(sphere))
            {
                float factor = decal.position.y - fogEnd;
                factor *= inverseRange;
                factor = std::max(0.0f, factor);
                factor = std::min(1.0f, factor);
                factor = 1.f - factor;

                COL color = decal.light;
                color.r += factor * (1.f - color.r);
                color.g += factor * (1.f - color.g);
                color.b += factor * (1.f - color.b);

                uint32_t vertexColor = color.as_u32_D3D_ARGB(decal.alpha);
                decal.insert(buffer, vertexColor);

                buffer += 4;
                ++renderAmount;
            }
        }

        renderer.unlockDynVtx();

        if (renderAmount == 0)
            return;

        D3DXMATRIX tm;
        D3DXMatrixIdentity(&tm);

        programManager.setProgram( gfx::ProgramManager::DECAL_SHADOW);
        programManager.setWorldMatrix(tm);
        programManager.applyState(device);

        device.SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
        device.SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
        device.SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
        device.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
        device.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);

        if (shadowMaterial->baseTexture)
            shadowMaterial->baseTexture->Apply(0);

        renderer.setFVF(FVF_P3DUV);
        renderer.setDynVtxBuffer<Vertex_P3DUV>();
        renderer.drawQuads(baseVertex, renderAmount);

        device.SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
        device.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

        shadowDecals.clear();
    }