irrlicht/source/Irrlicht/CLightSceneNode.cpp
engineer_apple 2340f9b849 Changes in 1.6 TA
- PixelBlend16 and PixelBlend16_simd are working for the new rules.
	- bugfix. CLightSceneNode didn't correctly update it's attributes
	
		Lighting Linear Attenuation.	= 1.f / radius
		
		The Example loadirr files set the lightscene radius to 1000.f but
		stays on the previous default attentuation with the older radius 100 -> 1.f / 100
		so the examples looks golden-brown.
		
		Now the radius is correctly!! set to the attenuation of 1.f/1000.f because the
		file doesn't have special attenuation. and now it looks more yellow.
		can anybody show me a correct screenshot for this file;-)? Niko?
		
		Or is this behavior the default lighting?. then it would be
		a fixed constant linear attenuation of 0.01f;-). Please clearify
		For now i didn't fixed it
		
		
		I encountered this behavior because i ( burning video ) used the original radius
		for calculations and so i've found that radius != 1.f / linearAttenuation but
		in the LightSceneNode this formula was used.. confused;-)
		

	- vector template and equals tests
		as working with the test suits i cleaned the template behavior (mixed types are
		used in the templates) and added all missing special math function with their coressponding type
		I also set the equal test for s32 to behave like the f32 routine.

		The function equals always implements a weak test.		
		that means a tolerance MUST always be used if you use the equal function. default is 1.
		you can set it to zero a==b-> equals ( a, b, 0 ) but do it explicit like you have to
		for floating compare. This is important when irrlicht is going to use special hardware
		math acceleration on a per function base, like sse2, or the other way round fixpoint.
	
	- VideoDriver drawPixel
		The HW renderes are using the alpha components for blending.
		The Software Renderes and image loaders are using CImage::setPixel copy. 
		so setPixel is engaged to either blends or copy the pixel
		default: false
	- Burningvideo
		added RenderMaterial EMT_SPHERE_MAP
			pushed burningsvideo to 0.43
		added RenderMaterial EMT_REFLECTION_2_LAYER
			pushed burningsvideo to 0.44
		set	EMT_TRANSPARENT_ALPHA_CHANNEL_REF
			to use AlphaRef 0.5 like Direct3D
			
		One Note: in OpenGL there is know difference between sphere_map and reflection layer
		both using GL_TEXTURE_GEN_MODE GL_SPHERE_MAP, whereas in d3d one time using camera_normal
		on sphere and reflection on refletcion_layer.
		
		The visual difference is that on sphere map the "image is not moving" when you rotate the 
		viewer. For Buring i took the opengl visual. always moving
				

	- rename quake3 SEntity to IEntity to be confom with IShader
		even IShader and IEntity are none pure virtual interfaces
		like most irrlicht objects


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2207 dfc29bdd-3216-0410-991c-e03cc46cb475
2009-02-10 15:08:23 +00:00

272 lines
7.5 KiB
C++

// Copyright (C) 2002-2009 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CLightSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "os.h"
namespace irr
{
namespace scene
{
//! constructor
CLightSceneNode::CLightSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, video::SColorf color, f32 radius)
: ILightSceneNode(parent, mgr, id, position), DriverLightIndex(-1), LightIsOn(true)
{
#ifdef _DEBUG
setDebugName("CLightSceneNode");
#endif
LightData.DiffuseColor = color;
// set some useful specular color
LightData.SpecularColor = color.getInterpolated(video::SColor(255,255,255,255),0.7f);
setRadius(radius);
}
//! pre render event
void CLightSceneNode::OnRegisterSceneNode()
{
doLightRecalc();
if (IsVisible)
SceneManager->registerNodeForRendering(this, ESNRP_LIGHT);
ISceneNode::OnRegisterSceneNode();
}
//! render
void CLightSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if (!driver)
return;
if ( DebugDataVisible & scene::EDS_BBOX )
{
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
switch ( LightData.Type )
{
case video::ELT_POINT:
case video::ELT_SPOT:
driver->draw3DBox(BBox, LightData.DiffuseColor.toSColor());
break;
case video::ELT_DIRECTIONAL:
driver->draw3DLine(core::vector3df(0.f, 0.f, 0.f),
LightData.Direction * LightData.Radius,
LightData.DiffuseColor.toSColor());
break;
}
}
DriverLightIndex = driver->addDynamicLight(LightData);
setVisible(LightIsOn);
}
//! sets the light data
void CLightSceneNode::setLightData(const video::SLight& light)
{
LightData = light;
}
//! \return Returns the light data.
const video::SLight& CLightSceneNode::getLightData() const
{
return LightData;
}
//! \return Returns the light data.
video::SLight& CLightSceneNode::getLightData()
{
return LightData;
}
void CLightSceneNode::setVisible(bool isVisible)
{
ISceneNode::setVisible(isVisible);
if(DriverLightIndex < 0)
return;
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if (!driver)
return;
LightIsOn = isVisible;
driver->turnLightOn((u32)DriverLightIndex, LightIsOn);
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CLightSceneNode::getBoundingBox() const
{
return BBox;
}
//! Sets the light's radius of influence.
/** Outside this radius the light won't lighten geometry and cast no
shadows. Setting the radius will also influence the attenuation, setting
it to (0,1/radius,0). If you want to override this behavior, set the
attenuation after the radius.
\param radius The new radius. */
void CLightSceneNode::setRadius(f32 radius)
{
LightData.Radius=radius;
LightData.Attenuation.set(0.f, 1.f/radius, 0.f);
doLightRecalc();
}
//! Gets the light's radius of influence.
/** \return The current radius. */
f32 CLightSceneNode::getRadius() const
{
return LightData.Radius;
}
//! Sets the light type.
/** \param type The new type. */
void CLightSceneNode::setLightType(video::E_LIGHT_TYPE type)
{
LightData.Type=type;
}
//! Gets the light type.
/** \return The current light type. */
video::E_LIGHT_TYPE CLightSceneNode::getLightType() const
{
return LightData.Type;
}
//! Sets whether this light casts shadows.
/** Enabling this flag won't automatically cast shadows, the meshes
will still need shadow scene nodes attached. But one can enable or
disable distinct lights for shadow casting for performance reasons.
\param shadow True if this light shall cast shadows. */
void CLightSceneNode::enableCastShadow(bool shadow)
{
LightData.CastShadows=shadow;
}
//! Check whether this light casts shadows.
/** \return True if light would cast shadows, else false. */
bool CLightSceneNode::getCastShadow() const
{
return LightData.CastShadows;
}
void CLightSceneNode::doLightRecalc()
{
if ((LightData.Type == video::ELT_SPOT) || (LightData.Type == video::ELT_DIRECTIONAL))
{
LightData.Direction = core::vector3df(.0f,.0f,1.0f);
getAbsoluteTransformation().rotateVect(LightData.Direction);
LightData.Direction.normalize();
}
if ((LightData.Type == video::ELT_SPOT) || (LightData.Type == video::ELT_POINT))
{
const f32 r = LightData.Radius * LightData.Radius * 0.5f;
BBox.MaxEdge.set( r, r, r );
BBox.MinEdge.set( -r, -r, -r );
setAutomaticCulling( scene::EAC_BOX );
LightData.Position = getAbsolutePosition();
}
if (LightData.Type == video::ELT_DIRECTIONAL)
{
BBox.reset( 0, 0, 0 );
setAutomaticCulling( scene::EAC_OFF );
}
}
//! Writes attributes of the scene node.
void CLightSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ILightSceneNode::serializeAttributes(out, options);
out->addColorf ("AmbientColor", LightData.AmbientColor);
out->addColorf ("DiffuseColor", LightData.DiffuseColor);
out->addColorf ("SpecularColor", LightData.SpecularColor);
out->addVector3d("Attenuation", LightData.Attenuation);
out->addFloat ("Radius", LightData.Radius);
out->addFloat ("OuterCone", LightData.OuterCone);
out->addFloat ("InnerCone", LightData.InnerCone);
out->addFloat ("Falloff", LightData.Falloff);
out->addBool ("CastShadows", LightData.CastShadows);
out->addEnum ("LightType", LightData.Type, video::LightTypeNames);
}
//! Reads attributes of the scene node.
void CLightSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
LightData.AmbientColor = in->getAttributeAsColorf("AmbientColor");
LightData.DiffuseColor = in->getAttributeAsColorf("DiffuseColor");
LightData.SpecularColor = in->getAttributeAsColorf("SpecularColor");
//TODO: clearify Radius and Linear Attenuation
#if 0
setRadius ( in->getAttributeAsFloat("Radius") );
#else
LightData.Radius = in->getAttributeAsFloat("Radius");
#endif
if (in->existsAttribute("Attenuation")) // might not exist in older files
LightData.Attenuation = in->getAttributeAsVector3d("Attenuation");
if (in->existsAttribute("OuterCone")) // might not exist in older files
LightData.OuterCone = in->getAttributeAsFloat("OuterCone");
if (in->existsAttribute("InnerCone")) // might not exist in older files
LightData.InnerCone = in->getAttributeAsFloat("InnerCone");
if (in->existsAttribute("Falloff")) // might not exist in older files
LightData.Falloff = in->getAttributeAsFloat("Falloff");
LightData.CastShadows = in->getAttributeAsBool("CastShadows");
LightData.Type = (video::E_LIGHT_TYPE)in->getAttributeAsEnumeration("LightType", video::LightTypeNames);
doLightRecalc ();
ILightSceneNode::deserializeAttributes(in, options);
}
//! Creates a clone of this scene node and its children.
ISceneNode* CLightSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CLightSceneNode* nb = new CLightSceneNode(newParent,
newManager, ID, RelativeTranslation, LightData.DiffuseColor, LightData.Radius);
nb->cloneMembers(this, newManager);
nb->LightData = LightData;
nb->BBox = BBox;
nb->drop();
return nb;
}
} // end namespace scene
} // end namespace irr