#include "CSkyDomeSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ICameraSceneNode.h"
#include "IAnimatedMesh.h"
#include "os.h"
namespace irr
{
namespace scene
{
CSkyDomeSceneNode::CSkyDomeSceneNode(video::ITexture* sky, u32 horiRes, u32 vertRes,
f32 texturePercentage, f32 spherePercentage, f32 radius,
ISceneNode* parent, ISceneManager* mgr, s32 id)
: ISceneNode(parent, mgr, id), Buffer(0),
HorizontalResolution(horiRes), VerticalResolution(vertRes),
TexturePercentage(texturePercentage),
SpherePercentage(spherePercentage), Radius(radius)
{
#ifdef _DEBUG
setDebugName("CSkyDomeSceneNode");
#endif
setAutomaticCulling(scene::EAC_OFF);
Buffer = new SMeshBuffer();
Buffer->Material.Lighting = false;
Buffer->Material.ZBuffer = video::ECFN_NEVER;
Buffer->Material.ZWriteEnable = false;
Buffer->Material.AntiAliasing = video::EAAM_OFF;
Buffer->Material.setTexture(0, sky);
Buffer->BoundingBox.MaxEdge.set(0,0,0);
Buffer->BoundingBox.MinEdge.set(0,0,0);
generateMesh();
}
CSkyDomeSceneNode::~CSkyDomeSceneNode()
{
if (Buffer)
Buffer->drop();
}
void CSkyDomeSceneNode::generateMesh()
{
f32 azimuth;
u32 k;
Buffer->Vertices.clear();
Buffer->Indices.clear();
const f32 azimuth_step = (core::PI * 2.f) / HorizontalResolution;
if (SpherePercentage < 0.f)
SpherePercentage = -SpherePercentage;
if (SpherePercentage > 2.f)
SpherePercentage = 2.f;
const f32 elevation_step = SpherePercentage * core::HALF_PI / (f32)VerticalResolution;
Buffer->Vertices.reallocate( (HorizontalResolution + 1) * (VerticalResolution + 1) );
Buffer->Indices.reallocate(3 * (2*VerticalResolution - 1) * HorizontalResolution);
video::S3DVertex vtx;
vtx.Color.set(255,255,255,255);
vtx.Normal.set(0.0f,-1.f,0.0f);
const f32 tcV = TexturePercentage / VerticalResolution;
for (k = 0, azimuth = 0; k <= HorizontalResolution; ++k)
{
f32 elevation = core::HALF_PI;
const f32 tcU = (f32)k / (f32)HorizontalResolution;
const f32 sinA = sinf(azimuth);
const f32 cosA = cosf(azimuth);
for (u32 j = 0; j <= VerticalResolution; ++j)
{
const f32 cosEr = Radius * cosf(elevation);
vtx.Pos.set(cosEr*sinA, Radius*sinf(elevation), cosEr*cosA);
vtx.TCoords.set(tcU, j*tcV);
vtx.Normal = -vtx.Pos;
vtx.Normal.normalize();
Buffer->Vertices.push_back(vtx);
elevation -= elevation_step;
}
azimuth += azimuth_step;
}
for (k = 0; k < HorizontalResolution; ++k)
{
Buffer->Indices.push_back(VerticalResolution + 2 + (VerticalResolution + 1)*k);
Buffer->Indices.push_back(1 + (VerticalResolution + 1)*k);
Buffer->Indices.push_back(0 + (VerticalResolution + 1)*k);
for (u32 j = 1; j < VerticalResolution; ++j)
{
Buffer->Indices.push_back(VerticalResolution + 2 + (VerticalResolution + 1)*k + j);
Buffer->Indices.push_back(1 + (VerticalResolution + 1)*k + j);
Buffer->Indices.push_back(0 + (VerticalResolution + 1)*k + j);
Buffer->Indices.push_back(VerticalResolution + 1 + (VerticalResolution + 1)*k + j);
Buffer->Indices.push_back(VerticalResolution + 2 + (VerticalResolution + 1)*k + j);
Buffer->Indices.push_back(0 + (VerticalResolution + 1)*k + j);
}
}
Buffer->setHardwareMappingHint(scene::EHM_STATIC);
}
void CSkyDomeSceneNode::render()
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
if (!camera || !driver)
return;
if ( !camera->isOrthogonal() )
{
core::matrix4 mat(AbsoluteTransformation);
mat.setTranslation(camera->getAbsolutePosition());
driver->setTransform(video::ETS_WORLD, mat);
driver->setMaterial(Buffer->Material);
driver->drawMeshBuffer(Buffer);
}
if ( DebugDataVisible )
{
video::SMaterial m;
m.Lighting = false;
driver->setMaterial(m);
if ( DebugDataVisible & scene::EDS_NORMALS )
{
IAnimatedMesh * arrow = SceneManager->addArrowMesh (
"__debugnormal2", 0xFFECEC00,
0xFF999900, 4, 8, 1.f * 40.f, 0.6f * 40.f, 0.05f * 40.f, 0.3f * 40.f);
if ( 0 == arrow )
{
arrow = SceneManager->getMesh ( "__debugnormal2" );
}
IMesh *mesh = arrow->getMesh(0);
core::matrix4 m2;
const scene::IMeshBuffer* mb = Buffer;
const u32 vSize = video::getVertexPitchFromType(mb->getVertexType());
const video::S3DVertex* v = ( const video::S3DVertex*)mb->getVertices();
for ( u32 i=0; i != mb->getVertexCount(); ++i )
{
core::quaternion quatRot(v->Normal.X, 0.f, -v->Normal.X, 1+v->Normal.Y);
quatRot.normalize();
quatRot.getMatrix(m2, v->Pos);
m2 = AbsoluteTransformation * m2;
driver->setTransform(video::ETS_WORLD, m2);
for (u32 a = 0; a != mesh->getMeshBufferCount(); ++a)
driver->drawMeshBuffer(mesh->getMeshBuffer(a));
v = (const video::S3DVertex*) ( (u8*) v + vSize );
}
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
}
if ( DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY )
{
m.Wireframe = true;
driver->setMaterial(m);
driver->drawMeshBuffer(Buffer);
}
}
}
const core::aabbox3d<f32>& CSkyDomeSceneNode::getBoundingBox() const
{
return Buffer->BoundingBox;
}
void CSkyDomeSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
{
SceneManager->registerNodeForRendering(this, ESNRP_SKY_BOX );
}
ISceneNode::OnRegisterSceneNode();
}
video::SMaterial& CSkyDomeSceneNode::getMaterial(u32 i)
{
return Buffer->Material;
}
u32 CSkyDomeSceneNode::getMaterialCount() const
{
return 1;
}
void CSkyDomeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ISceneNode::serializeAttributes(out, options);
out->addInt ("HorizontalResolution", HorizontalResolution);
out->addInt ("VerticalResolution", VerticalResolution);
out->addFloat("TexturePercentage", TexturePercentage);
out->addFloat("SpherePercentage", SpherePercentage);
out->addFloat("Radius", Radius);
}
void CSkyDomeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
HorizontalResolution = in->getAttributeAsInt ("HorizontalResolution");
VerticalResolution = in->getAttributeAsInt ("VerticalResolution");
TexturePercentage = in->getAttributeAsFloat("TexturePercentage");
SpherePercentage = in->getAttributeAsFloat("SpherePercentage");
Radius = in->getAttributeAsFloat("Radius");
ISceneNode::deserializeAttributes(in, options);
generateMesh();
}
ISceneNode* CSkyDomeSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CSkyDomeSceneNode* nb = new CSkyDomeSceneNode(Buffer->Material.TextureLayer[0].Texture, HorizontalResolution, VerticalResolution, TexturePercentage,
SpherePercentage, Radius, newParent, newManager, ID);
nb->cloneMembers(this, newManager);
if ( newParent )
nb->drop();
return nb;
}
}
}