void CAddCameraController::onLMouseUp(int x, int y) { IView *pView = getIView(); ICameraSceneNode *cam = pView->getSceneMgr()->getActiveCamera(); // get position core::vector3df hit; bool b = getPickPosition( &hit ); if ( b ) { core::vector3df camPos = cam->getAbsolutePosition(); core::line3df camRay( camPos, hit ); if ( camRay.getLength() < 5000 ) { CGameCamera *pObj = pView->getCurrentZone()->createCamera(); pObj->setPosition( hit ); pObj->setVisible( true ); // add history CHistoryManager::getInstance()->beginHistory(); CHistoryManager::getInstance()->addHistoryCreateObj( pObj ); CHistoryManager::getInstance()->endHistory(); } else pView->alertError( L"Can not create object because is too far" ); } else pView->alertError( L"Can not create object because is too far" ); }
//! render void CBillboardSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera || !driver) return; // make billboard look to camera core::vector3df pos = getAbsolutePosition(); core::vector3df campos = camera->getAbsolutePosition(); core::vector3df target = camera->getTarget(); core::vector3df up = camera->getUpVector(); core::vector3df view = target - campos; view.normalize(); core::vector3df horizontal = up.crossProduct(view); if ( horizontal.getLength() == 0 ) { horizontal.set(up.Y,up.X,up.Z); } horizontal.normalize(); horizontal *= 0.5f * Size.Width; core::vector3df vertical = horizontal.crossProduct(view); vertical.normalize(); vertical *= 0.5f * Size.Height; view *= -1.0f; for (s32 i=0; i<4; ++i) vertices[i].Normal = view; vertices[0].Pos = pos + horizontal + vertical; vertices[1].Pos = pos + horizontal - vertical; vertices[2].Pos = pos - horizontal - vertical; vertices[3].Pos = pos - horizontal + vertical; // draw if (DebugDataVisible) { driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); video::SMaterial m; m.Lighting = false; driver->setMaterial(m); driver->draw3DBox(BBox, video::SColor(0,208,195,152)); } core::matrix4 mat; driver->setTransform(video::ETS_WORLD, mat); driver->setMaterial(Material); driver->drawIndexedTriangleList(vertices, 4, indices, 2); }
bool CBaseAddController::getPickPosition( core::vector3df *pos ) { IView *pView = getIView(); // move object core::line3df ray = pView->getSelectRay(); // check hit on terrain CDocument *pDoc = (CDocument*) pView->getDocument(); ArrayZone* zones = pDoc->getAllZone(); ArrayZoneIter i = zones->begin(), end = zones->end(); while ( i != end ) { core::vector3df colPoint; core::triangle3df colTri; float maxDistance = ray.getLengthSQ(); if ( (*i)->getTerrainCollision( ray, maxDistance, colPoint, colTri ) == true ) { *pos = colPoint; return true; } i++; } core::plane3df plane( core::vector3df(0.0f, 0.0f, 0.0f), core::vector3df(0.0f, 1.0f, 0.0f) ); // get position core::vector3df hit; bool b = plane.getIntersectionWithLine( ray.start, ray.getVector(), hit ); if ( b ) { ICameraSceneNode *cam = pView->getSceneMgr()->getActiveCamera(); core::vector3df camPos = cam->getAbsolutePosition(); core::line3df camRay( camPos, hit ); if ( camRay.getLength() < 5000 ) { *pos = hit; return true; } } return false; }
void CAddWaypointController::onLMouseUp (int x, int y) { IView *pView = getIView(); ICameraSceneNode *cam = pView->getSceneMgr()->getActiveCamera(); // get position core::vector3df hit; bool b = getPickPosition( &hit ); if ( b ) { core::vector3df camPos = cam->getAbsolutePosition(); core::line3df camRay( camPos, hit ); if ( camRay.getLength() < 5000 ) { CWayPoint *pObj = pView->getCurrentZone()->createWaypoint(); pObj->setPosition( hit ); pObj->setVisible( true ); // add history CHistoryManager* pHistory = CHistoryManager::createGetInstance(); pHistory->beginHistory(); pHistory->addHistoryCreateObj( pObj ); if ( m_connect ) { pHistory->addHistoryBeginModifyObj( m_connect ); m_connect->setNext( pObj ); pHistory->addHistoryEndModifyObj( m_connect ); pHistory->addHistoryBeginModifyObj( pObj ); pObj->setBack( m_connect ); pHistory->addHistoryEndModifyObj( pObj ); } pHistory->endHistory(); m_connect = pObj; } else pView->alertError( L"Can not create object because is too far" ); } else pView->alertError( L"Can not create object because is too far" ); }
//! pre render event void CBillboardTextSceneNode::OnAnimate(u32 timeMs) { if (!IsVisible || !Font || !Mesh) return; ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera) return; // get text width f32 textLength = 0.f; u32 i; for(i=0; i!=Symbol.size(); ++i) { SSymbolInfo &info = Symbol[i]; textLength += info.Kerning + info.Width; } if (textLength<0.0f) textLength=1.0f; //const core::matrix4 &m = camera->getViewFrustum()->Matrices[ video::ETS_VIEW ]; // make billboard look to camera core::vector3df pos = getAbsolutePosition(); core::vector3df campos = camera->getAbsolutePosition(); core::vector3df target = camera->getTarget(); core::vector3df up = camera->getUpVector(); core::vector3df view = target - campos; view.normalize(); core::vector3df horizontal = up.crossProduct(view); if ( horizontal.getLength() == 0 ) { horizontal.set(up.Y,up.X,up.Z); } horizontal.normalize(); core::vector3df space = horizontal; horizontal *= 0.5f * Size.Width; core::vector3df vertical = horizontal.crossProduct(view); vertical.normalize(); vertical *= 0.5f * Size.Height; view *= -1.0f; // center text pos += space * (Size.Width * -0.5f); for ( i = 0; i!= Symbol.size(); ++i ) { SSymbolInfo &info = Symbol[i]; f32 infw = info.Width / textLength; f32 infk = info.Kerning / textLength; f32 w = (Size.Width * infw * 0.5f); pos += space * w; SMeshBuffer* buf = (SMeshBuffer*)Mesh->getMeshBuffer(info.bufNo); buf->Vertices[info.firstVert+0].Normal = view; buf->Vertices[info.firstVert+1].Normal = view; buf->Vertices[info.firstVert+2].Normal = view; buf->Vertices[info.firstVert+3].Normal = view; buf->Vertices[info.firstVert+0].Pos = pos + (space * w) + vertical; buf->Vertices[info.firstVert+1].Pos = pos + (space * w) - vertical; buf->Vertices[info.firstVert+2].Pos = pos - (space * w) - vertical; buf->Vertices[info.firstVert+3].Pos = pos - (space * w) + vertical; pos += space * (Size.Width*infk + w); } // make bounding box for (i=0; i< Mesh->getMeshBufferCount() ; ++i) Mesh->getMeshBuffer(i)->recalculateBoundingBox(); Mesh->recalculateBoundingBox(); BBox = Mesh->getBoundingBox(); core::matrix4 mat( getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE ); mat.transformBoxEx(BBox); }
void CSSceneNodeAnimatorFPS::animateNode(ISceneNode* node, u32 timeMs) { if (!node || node->getType() != ESNT_CAMERA) return; ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); if (firstUpdate) { camera->updateAbsolutePosition(); if (CursorControl) { CursorControl->setPosition(m_CursorOffsetX, m_CursorOffsetY); CursorPos = CenterCursor = CursorControl->getRelativePosition(); } LastAnimationTime = timeMs; firstUpdate = false; } // If the camera isn't the active camera, and receiving input, then don't process it. if (!camera->isInputReceiverEnabled()) { firstInput = true; return; } if (firstInput) { allKeysUp(); firstInput = false; } scene::ISceneManager * smgr = camera->getSceneManager(); if (smgr && smgr->getActiveCamera() != camera) return; // get time f32 timeDiff = (f32)(timeMs - LastAnimationTime); LastAnimationTime = timeMs; // update position core::vector3df pos = camera->getPosition(); // Update rotation core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition()); core::vector3df relativeRotation = target.getHorizontalAngle(); if (CursorControl) { if (CursorPos != CenterCursor) { relativeRotation.Y -= (m_CursorOffsetX - CursorPos.X) * RotateSpeed; relativeRotation.X -= (m_CursorOffsetY - CursorPos.Y) * RotateSpeed * MouseYDirection; // X < MaxVerticalAngle or X > 360-MaxVerticalAngle if (relativeRotation.X > MaxVerticalAngle * 2 && relativeRotation.X < 360.0f - MaxVerticalAngle) { relativeRotation.X = 360.0f - MaxVerticalAngle; } else if (relativeRotation.X > MaxVerticalAngle && relativeRotation.X < 360.0f - MaxVerticalAngle) { relativeRotation.X = MaxVerticalAngle; } // Do the fix as normal, special case below // reset cursor position to the centre of the window. CursorControl->setPosition(m_CursorOffsetX, m_CursorOffsetY); CenterCursor = CursorControl->getRelativePosition(); // needed to avoid problems when the event receiver is disabled CursorPos = CenterCursor; } // Special case, mouse is whipped outside of window before it can update. video::IVideoDriver* driver = smgr->getVideoDriver(); core::vector2d<u32> mousepos(u32(CursorControl->getPosition().X), u32(CursorControl->getPosition().Y)); core::rect<u32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height); // Only if we are moving outside quickly. bool reset = !screenRect.isPointInside(mousepos); if (reset) { // Force a reset. CursorControl->setPosition(m_CursorOffsetX, m_CursorOffsetY); CenterCursor = CursorControl->getRelativePosition(); CursorPos = CenterCursor; } } // set target target.set(0, 0, core::max_(1.f, pos.getLength())); core::vector3df movedir = target; core::matrix4 mat; mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0)); mat.transformVect(target); if (NoVerticalMovement) { mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0)); mat.transformVect(movedir); } else { movedir = target; } movedir.normalize(); if (CursorKeys[EKA_MOVE_FORWARD]) pos += movedir * timeDiff * MoveSpeed; if (CursorKeys[EKA_MOVE_BACKWARD]) pos -= movedir * timeDiff * MoveSpeed; // strafing core::vector3df strafevect = target; strafevect = strafevect.crossProduct(camera->getUpVector()); if (NoVerticalMovement) strafevect.Y = 0.0f; strafevect.normalize(); if (CursorKeys[EKA_STRAFE_LEFT]) pos += strafevect * timeDiff * MoveSpeed; if (CursorKeys[EKA_STRAFE_RIGHT]) pos -= strafevect * timeDiff * MoveSpeed; // For jumping, we find the collision response animator attached to our camera // and if it's not falling, we tell it to jump. if (CursorKeys[EKA_JUMP_UP]) { const ISceneNodeAnimatorList& animators = camera->getAnimators(); ISceneNodeAnimatorList::ConstIterator it = animators.begin(); while (it != animators.end()) { if (ESNAT_COLLISION_RESPONSE == (*it)->getType()) { ISceneNodeAnimatorCollisionResponse * collisionResponse = static_cast<ISceneNodeAnimatorCollisionResponse *>(*it); if (!collisionResponse->isFalling()) collisionResponse->jump(JumpSpeed); } it++; } } // write translation camera->setPosition(pos); // write right target target += pos; camera->setTarget(target); }
//! render void CParticleSystemSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera || !driver) return; #if 0 // calculate vectors for letting particles look to camera core::vector3df view(camera->getTarget() - camera->getAbsolutePosition()); view.normalize(); view *= -1.0f; #else const core::matrix4 &m = camera->getViewFrustum()->getTransform( video::ETS_VIEW ); const core::vector3df view ( -m[2], -m[6] , -m[10] ); #endif // reallocate arrays, if they are too small reallocateBuffers(); // create particle vertex data s32 idx = 0; for (u32 i=0; i<Particles.size(); ++i) { const SParticle& particle = Particles[i]; #if 0 core::vector3df horizontal = camera->getUpVector().crossProduct(view); horizontal.normalize(); horizontal *= 0.5f * particle.size.Width; core::vector3df vertical = horizontal.crossProduct(view); vertical.normalize(); vertical *= 0.5f * particle.size.Height; #else f32 f; f = 0.5f * particle.size.Width; const core::vector3df horizontal ( m[0] * f, m[4] * f, m[8] * f ); f = -0.5f * particle.size.Height; const core::vector3df vertical ( m[1] * f, m[5] * f, m[9] * f ); #endif Buffer->Vertices[0+idx].Pos = particle.pos + horizontal + vertical; Buffer->Vertices[0+idx].Color = particle.color; Buffer->Vertices[0+idx].Normal = view; Buffer->Vertices[1+idx].Pos = particle.pos + horizontal - vertical; Buffer->Vertices[1+idx].Color = particle.color; Buffer->Vertices[1+idx].Normal = view; Buffer->Vertices[2+idx].Pos = particle.pos - horizontal - vertical; Buffer->Vertices[2+idx].Color = particle.color; Buffer->Vertices[2+idx].Normal = view; Buffer->Vertices[3+idx].Pos = particle.pos - horizontal + vertical; Buffer->Vertices[3+idx].Color = particle.color; Buffer->Vertices[3+idx].Normal = view; idx +=4; } // render all core::matrix4 mat; if (!ParticlesAreGlobal) mat.setTranslation(AbsoluteTransformation.getTranslation()); driver->setTransform(video::ETS_WORLD, mat); driver->setMaterial(Buffer->Material); driver->drawVertexPrimitiveList(Buffer->getVertices(), Particles.size()*4, Buffer->getIndices(), Particles.size()*2, video::EVT_STANDARD, EPT_TRIANGLES,Buffer->getIndexType()); // for debug purposes only: if ( DebugDataVisible & scene::EDS_BBOX ) { driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); video::SMaterial deb_m; deb_m.Lighting = false; driver->setMaterial(deb_m); driver->draw3DBox(Buffer->BoundingBox, video::SColor(0,255,255,255)); } }
void CSceneNodeAnimatorCameraFPS::animateNode(IDummyTransformationSceneNode* node, uint32_t timeMs) { if (!node || node->getType() != ESNT_CAMERA) return; ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); if (firstUpdate) { camera->updateAbsolutePosition(); if (CursorControl ) { CursorControl->setPosition(0.5f, 0.5f); CursorPos = CenterCursor = CursorControl->getRelativePosition(); } LastAnimationTime = timeMs; firstUpdate = false; } // If the camera isn't the active camera, and receiving input, then don't process it. if(!camera->isInputReceiverEnabled()) { firstInput = true; return; } if ( firstInput ) { allKeysUp(); firstInput = false; } scene::ISceneManager * smgr = camera->getSceneManager(); if(smgr && smgr->getActiveCamera() != camera) return; // get time float timeDiff = (float) ( timeMs - LastAnimationTime ); LastAnimationTime = timeMs; // update position core::vector3df pos = camera->getPosition(); // Update rotation core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition()); core::vector3df relativeRotation = target.getHorizontalAngle(); if (CursorControl) { if (CursorPos != CenterCursor) { relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed; relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed * MouseYDirection; // X < MaxVerticalAngle or X > 360-MaxVerticalAngle if (relativeRotation.X > MaxVerticalAngle*2 && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = 360.0f-MaxVerticalAngle; } else if (relativeRotation.X > MaxVerticalAngle && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = MaxVerticalAngle; } // Do the fix as normal, special case below // reset cursor position to the centre of the window. CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); // needed to avoid problems when the event receiver is disabled CursorPos = CenterCursor; } // Special case, mouse is whipped outside of window before it can update. video::IVideoDriver* driver = smgr->getVideoDriver(); core::vector2d<uint32_t> mousepos(uint32_t(CursorControl->getPosition().X), uint32_t(CursorControl->getPosition().Y)); core::rect<uint32_t> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height); // Only if we are moving outside quickly. bool reset = !screenRect.isPointInside(mousepos); if(reset) { // Force a reset. CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); CursorPos = CenterCursor; } } // set target target.set(0,0, core::max_(1.f, pos.getLength())); core::vector3df movedir = target; core::matrix4x3 mat; mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0)); mat.transformVect(&target.X); if (NoVerticalMovement) { mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0)); mat.transformVect(&movedir.X); } else { movedir = target; } movedir.normalize(); if (CursorKeys[EKA_MOVE_FORWARD]) pos += movedir * timeDiff * MoveSpeed; if (CursorKeys[EKA_MOVE_BACKWARD]) pos -= movedir * timeDiff * MoveSpeed; // strafing core::vector3df strafevect = target; strafevect = strafevect.crossProduct(camera->getUpVector()); if (NoVerticalMovement) strafevect.Y = 0.0f; strafevect.normalize(); if (CursorKeys[EKA_STRAFE_LEFT]) pos += strafevect * timeDiff * MoveSpeed; if (CursorKeys[EKA_STRAFE_RIGHT]) pos -= strafevect * timeDiff * MoveSpeed; // write translation camera->setPosition(pos); // write right target target += pos; camera->setTarget(target); }
// registering the scene node for rendering, here we take the opportunity // to make LOD adjustments to child nodes void CLODSceneNode::OnRegisterSceneNode() { //if this node is invisible forget any child nodes if (!IsVisible) return; // get a timer to calculate the amount to fade objects u32 time = device->getTimer()->getTime(); // get the camera position ICameraSceneNode* cam = smgr->getActiveCamera(); core::vector3df vectorCam = cam->getAbsolutePosition(); // loop through all child nodes u32 i,j; u32 lod, fade; SMaterial * material; for (i=0; i < children.size(); ++i) { // get the node associated with this link SChildLink &child = children[i]; IAnimatedMeshSceneNode *node = (IAnimatedMeshSceneNode *)child.node; // calculate the distance to the node. at the moment we do this the // slow linear way instead of using the distance squared method core::vector3df vectorNode = node->getAbsolutePosition(); float distance = vectorNode.getDistanceFrom( vectorCam ); // itterate through all of the LOD levels and find the lod distance // that is appropriate for this distance lod = 0xFFFFFFFF; for (j=0; j < lods.size(); ++j) { if ( distance >= lods[j].distance ) { lod = j; } } // if a LOD level was found if ( lod != 0xFFFFFFFF ) { // if this lod is associated with a mesh if ( lods[lod].mesh ) { // if this lod differs from the child lod if ( lod != children[i].lod ) { children[i].lod = lod; // if the node is an animated mesh node if ( ( node->getType()) == ESNT_ANIMATED_MESH ) { // set the new mesh to be used node->setMeshClean( lods[lod].mesh ); } } // handle instances where the node is faded switch ( children[i].mode ) { case LOD_INVISIBLE: // make the node visible node->setVisible( true ); children[i].mode = LOD_FADE_IN; children[i].fade = time; break; // we are partially faded we need to fade back in case LOD_FADE_IN: // fade the node in by 1 multiplied by the time passed fade = (time - children[i].fade) / fadeScale; if ( fade > 0xFF ) fade = 0xFF; // if the node is fully opaque again if ( fade == 0xFF ) { // restore the origonal material type node->setMaterialType(children[i].matType); children[i].mode = LOD_OPAQUE; if ( callback ) callback( true, node ); } // fade the node through its materials fade *= 0x01010101; material = &node->getMaterial( 0 ); if ( useAlpha ) { material->DiffuseColor.set( fade ); material->AmbientColor.set( fade ); } else { material->DiffuseColor.set( fade & 0xFFFFFF ); material->AmbientColor.set( fade & 0xFFFFFF ); } break; // we were in the process of fading out case LOD_FADE_OUT: children[i].fade = time - ( 0xFF * fadeScale - ( time - children[i].fade )); children[i].mode = LOD_FADE_IN; break; } } else { // we have a lod without a mesh, this is an instruction to fade switch ( children[i].mode ) { // the node is fully opaque start fading case LOD_OPAQUE: children[i].mode = LOD_FADE_OUT; children[i].fade = time; // note the material type children[i].matType = node->getMaterial(0).MaterialType; // set the material type based on mapping node->setMaterialType( matmap[children[i].matType] ); //break; // the node is in the process of fading case LOD_FADE_OUT: // fade the node out by 1 multiplied by the time passed fade = (time - children[i].fade) / fadeScale; if ( fade > 0xFF ) fade = 0xFF; // if the node is fully transparent if ( fade == 0xFF ) { // make it completely invisible node->setVisible( false ); children[i].mode = LOD_INVISIBLE; if ( callback ) callback( false, node ); } // fade the node through its materials fade *= 0x01010101; fade = 0xFFFFFFFF - fade; material = &node->getMaterial( 0 ); if ( useAlpha ) { material->DiffuseColor.set( fade ); material->AmbientColor.set( fade ); } else { material->DiffuseColor.set( fade & 0xFFFFFF ); material->AmbientColor.set( fade & 0xFFFFFF ); } break; // we were in the process of fading in case LOD_FADE_IN: children[i].fade = time - ( 0xFF * fadeScale - ( time - children[i].fade )); children[i].mode = LOD_FADE_OUT; break; } // switch } } else { // handle instances where the node is faded switch ( children[i].mode ) { case LOD_INVISIBLE: // make the node visible node->setVisible( true ); children[i].mode = LOD_FADE_IN; children[i].fade = time; if ( callback ) callback( true, node ); break; // we are partially faded we need to fade back in case LOD_FADE_IN: // fade the node in by 1 multiplied by the time passed fade = (time - children[i].fade) / fadeScale; if ( fade > 255 ) fade = 255; // if the node is fully opaque again if ( fade == 0xFF ) { // restore the origonal material type node->setMaterialType(children[i].matType); children[i].mode = LOD_OPAQUE; } // fade the node through its materials fade *= 0x01010101; material = &node->getMaterial( 0 ); if ( useAlpha ) { material->DiffuseColor.set( fade ); material->AmbientColor.set( fade ); } else { material->DiffuseColor.set( fade & 0xFFFFFF ); material->AmbientColor.set( fade & 0xFFFFFF ); } break; // we were in the process of fading out case LOD_FADE_OUT: children[i].fade = time - ( 0xFF * fadeScale - ( time - children[i].fade )); children[i].mode = LOD_FADE_IN; break; } } } ISceneNode::OnRegisterSceneNode(); }
void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) { if (node->getType() != ESNT_CAMERA) return; ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node); if (firstUpdate) { camera->updateAbsolutePosition(); if (CursorControl && camera) { CursorControl->setPosition(0.5f, 0.5f); CursorPos = CenterCursor = CursorControl->getRelativePosition(); } LastAnimationTime = timeMs; firstUpdate = false; } // get time f32 timeDiff = (f32) ( timeMs - LastAnimationTime ); LastAnimationTime = timeMs; // update position core::vector3df pos = camera->getPosition(); // Update rotation core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition()); core::vector3df relativeRotation = target.getHorizontalAngle(); if (CursorControl) { if (CursorPos != CenterCursor) { relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed; relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed; // X < MaxVerticalAngle or X > 360-MaxVerticalAngle if (relativeRotation.X > MaxVerticalAngle*2 && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = 360.0f-MaxVerticalAngle; } else if (relativeRotation.X > MaxVerticalAngle && relativeRotation.X < 360.0f-MaxVerticalAngle) { relativeRotation.X = MaxVerticalAngle; } // reset cursor position CursorControl->setPosition(0.5f, 0.5f); CenterCursor = CursorControl->getRelativePosition(); // needed to avoid problems when the ecent receiver is // disabled CursorPos = CenterCursor; } } // set target target.set(0,0, core::max_(1.f, pos.getLength())); core::vector3df movedir = target; core::matrix4 mat; mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0)); mat.transformVect(target); if (NoVerticalMovement) { mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0)); mat.transformVect(movedir); } else { movedir = target; } movedir.normalize(); if (CursorKeys[EKA_MOVE_FORWARD]) pos += movedir * timeDiff * MoveSpeed; if (CursorKeys[EKA_MOVE_BACKWARD]) pos -= movedir * timeDiff * MoveSpeed; // strafing core::vector3df strafevect = target; strafevect = strafevect.crossProduct(camera->getUpVector()); if (NoVerticalMovement) strafevect.Y = 0.0f; strafevect.normalize(); if (CursorKeys[EKA_STRAFE_LEFT]) pos += strafevect * timeDiff * MoveSpeed; if (CursorKeys[EKA_STRAFE_RIGHT]) pos -= strafevect * timeDiff * MoveSpeed; // For jumping, we find the collision response animator attached to our camera // and if it's not falling, we tell it to jump. if (CursorKeys[EKA_JUMP_UP]) { const core::list<ISceneNodeAnimator*> & animators = camera->getAnimators(); core::list<ISceneNodeAnimator*>::ConstIterator it = animators.begin(); while(it != animators.end()) { if(ESNAT_COLLISION_RESPONSE == (*it)->getType()) { ISceneNodeAnimatorCollisionResponse * collisionResponse = static_cast<ISceneNodeAnimatorCollisionResponse *>(*it); if(!collisionResponse->isFalling()) collisionResponse->jump(JumpSpeed); } it++; } } // write translation camera->setPosition(pos); // write right target TargetVector = target; target += pos; camera->setTarget(target); }
/* Every time it gets drawn, this function gets called */ void CLensFlareSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); ICameraSceneNode* camera = SceneManager->getActiveCamera(); // Bail out if function dosn't have enough info // Will fail here if no textures supplied if (!camera || !driver || !Material.getTexture(0)) return; driver->setTransform(video::ETS_WORLD, core::matrix4()); const core::vector3df campos = camera->getAbsolutePosition(); const core::dimension2d<u32> sz = SceneManager->getVideoDriver()->getScreenSize(); const core::vector2df mid = core::vector2df((f32)sz.Width, (f32)sz.Height) * 0.5f; const core::position2di lp = SceneManager->getSceneCollisionManager()-> getScreenCoordinatesFrom3DPosition(getAbsolutePosition(), camera); const core::vector2df lightpos = core::vector2df((f32)lp.X, (f32)lp.Y); const u32 nframes = Material.getTexture(0)->getOriginalSize().Width / Material.getTexture(0)->getOriginalSize().Height; int texw = 8; float texp = 1.0f / nframes; core::vector3df target = camera->getTarget(); core::vector3df up = camera->getUpVector(); core::vector3df view = target - campos; view.normalize(); core::vector3df horizontal = up.crossProduct(view); horizontal.normalize(); core::vector3df vertical; vertical = horizontal.crossProduct(view); vertical.normalize(); view *= -1.0f; for (u32 i=0; i<4; ++i) vertices[i].Normal = view; driver->setMaterial(Material); core::vector3df pos; core::vector3df hor; core::vector3df ver; for (u32 ax = 0; ax < nframes; ++ax) { if (ax == 0 ) { pos = getAbsolutePosition(); texw = Material.getTexture(0)->getSize().Height; hor = horizontal * (sourceScale * texw); ver = vertical * (sourceScale * texw); } else { core::vector2df ipos = mid.getInterpolated(lightpos, (2.0f / nframes) * ax); pos = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates( core::position2d<s32>(int(ipos.X ), int(ipos.Y ) ), camera).end; core::vector3df dir = core::vector3df(campos - pos).normalize(); pos = campos + (dir * -10.0f); texw = 4; hor = horizontal * (opticsScale * texw); ver = vertical * (opticsScale * texw); } vertices[0].TCoords.set( ax * texp, 1.0f); vertices[1].TCoords.set( ax * texp, 0.0f); vertices[2].TCoords.set((ax+1) * texp, 0.0f); vertices[3].TCoords.set((ax+1) * texp, 1.0f); vertices[0].Pos = pos + hor + ver; vertices[1].Pos = pos + hor - ver; vertices[2].Pos = pos - hor - ver; vertices[3].Pos = pos - hor + ver; driver->drawIndexedTriangleList(vertices, 4, indices, 2); } }
//! render void CParticleSystemSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); ICameraSceneNode* camera = SceneManager->getActiveCamera(); if (!camera || !driver) return; // calculate vectors for letting particles look to camera core::vector3df campos = camera->getAbsolutePosition(); core::vector3df target = camera->getTarget(); core::vector3df up = camera->getUpVector(); core::vector3df view = target - campos; view.normalize(); core::vector3df horizontal = up.crossProduct(view); horizontal.normalize(); core::vector3df vertical = horizontal.crossProduct(view); vertical.normalize(); horizontal *= 0.5f * ParticleSize.Width; vertical *= 0.5f * ParticleSize.Height; view *= -1.0f; // reallocate arrays, if they are too small reallocateBuffers(); // create particle vertex data for (u32 i=0; i<Particles.size(); ++i) { const SParticle& particle = Particles[i]; s32 idx = i*4; Vertices[0+idx].Pos = particle.pos + horizontal + vertical; Vertices[0+idx].Color = particle.color; Vertices[0+idx].Normal = view; Vertices[1+idx].Pos = particle.pos + horizontal - vertical; Vertices[1+idx].Color = particle.color; Vertices[1+idx].Normal = view; Vertices[2+idx].Pos = particle.pos - horizontal - vertical; Vertices[2+idx].Color = particle.color; Vertices[2+idx].Normal = view; Vertices[3+idx].Pos = particle.pos - horizontal + vertical; Vertices[3+idx].Color = particle.color; Vertices[3+idx].Normal = view; } // render all core::matrix4 mat; if (!ParticlesAreGlobal) mat.setTranslation(AbsoluteTransformation.getTranslation()); driver->setTransform(video::ETS_WORLD, mat); driver->setMaterial(Material); driver->drawIndexedTriangleList(Vertices.pointer(), Particles.size()*4, Indices.pointer(), Particles.size()*2); // for debug purposes only: if (DebugDataVisible) { driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); video::SMaterial m; m.Lighting = false; driver->setMaterial(m); driver->draw3DBox(Box, video::SColor(0,255,255,255)); } }
void CImpostorSceneNode::renderNode(SNodeLink& Imp) { ISceneNode* n = Imp.Node; updatePosAndVector(Imp); // remember old viewport and render target core::rect<s32> oldView = SceneManager->getVideoDriver()->getViewPort(); if (!oldView.isRectCollided(Imp.NewPos)) return; ICameraSceneNode* cam = SceneManager->getActiveCamera(); cam->updateAbsolutePosition(); core::vector3df camP = cam->getAbsolutePosition(); f32 distance = camP.getDistanceFrom(n->getTransformedBoundingBox().getCenter()); // project into screen core::vector3df pUL = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(Imp.NewPos.UpperLeftCorner, cam).getVector(); pUL.setLength(distance); core::vector3df pLR = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(Imp.NewPos.LowerRightCorner, cam).getVector(); pLR.setLength(distance); core::vector3df pUR = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(core::position2di(Imp.NewPos.LowerRightCorner.X, Imp.NewPos.UpperLeftCorner.Y), cam).getVector(); pUR.setLength(distance); core::vector3df pLL = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates(core::position2di(Imp.NewPos.UpperLeftCorner.X, Imp.NewPos.LowerRightCorner.Y), cam).getVector(); pLL.setLength(distance); Imp.BilPos1 = camP + pUL; Imp.BilPos2 = camP + pLR; Imp.BilPos3 = camP + pUR; Imp.BilPos4 = camP + pLL; // translate and scale, but don't rotate core::matrix4 invMat = n->getAbsoluteTransformation(); invMat.makeInverse(); Imp.BilPos1 *= invMat.getScale(); invMat.translateVect(Imp.BilPos1); Imp.BilPos2 *= invMat.getScale(); invMat.translateVect(Imp.BilPos2); Imp.BilPos3 *= invMat.getScale(); invMat.translateVect(Imp.BilPos3); Imp.BilPos4 *= invMat.getScale(); invMat.translateVect(Imp.BilPos4); Imp.ScreenPos = Imp.NewPos; Imp.RotVec = Imp.NewVec; video::ITexture* rt = 0; // SceneManager->getVideoDriver()->getRenderTarget(); // set up the camera and viewport for rendering ISceneManager* oldManager = n->getSceneManager(); // set up the camera ICameraSceneNode* cam2= LocalManager->getActiveCamera(); cam2->setPosition(cam->getAbsolutePosition()); core::vector3df v = n->getTransformedBoundingBox().getCenter(); cam2->setUpVector(cam->getUpVector()); cam2->setTarget(cam->getTarget()); cam2->updateAbsolutePosition(); f32 scaleW = f32(oldView.getWidth()) / f32(Imp.ScreenPos.getWidth()); f32 scaleH = f32(oldView.getHeight()) / f32(Imp.ScreenPos.getHeight()); //f32 transW = f32(Impostors[i].ScreenPos.getWidth()/2) / (f32(oldView.getWidth()) - f32(Impostors[i].ScreenPos.getCenter().X)); //f32 transH = f32(Impostors[i].ScreenPos.getHeight()/2) / (f32(oldView.getHeight()) - f32(Impostors[i].ScreenPos.getCenter().X)); f32 transW = (f32(oldView.getCenter().X) - f32(Imp.ScreenPos.getCenter().X)) / f32(Imp.ScreenPos.getWidth()); f32 transH = (f32(oldView.getCenter().Y) - f32(Imp.ScreenPos.getCenter().Y)) / f32(Imp.ScreenPos.getHeight()); core::matrix4 proj(cam->getProjectionMatrix()); core::matrix4 zoom, trans; Imp.Time = Timer->getRealTime(); zoom.setScale(core::vector3df(scaleW, scaleH, 1.0)); trans.setTranslation(core::vector3df(transW*2,-transH*2,0.0)); proj = zoom * proj; #if defined(GENERATE_METHOD_1) proj = trans * proj; #endif // set the correct render target and viewport setTarget(Imp); // draw the scene cam2->setProjectionMatrix(proj); E_CULLING_TYPE culltype = EAC_FRUSTUM_BOX; n->setAutomaticCulling(EAC_OFF); //cam2->render(); // n->setSceneManager(LocalManager); n->OnRegisterSceneNode(); LocalManager->drawAll(); n->setAutomaticCulling(culltype); //s32 numberzzz = LocalManager->getParameters()->getAttributeAsInt("culled"); // copy work buffer back s32 slot = Buffers[Imp.BufferID].SlotSize; //SceneManager->getGUIEnvironment()->getBuiltInFont()->draw(L"HI THERE!", core::rect<s32>(0, 0, slot, slot), video::SColor(), true, true); SceneManager->getVideoDriver()->setRenderTarget(Buffers[ Imp.BufferID].Texture, false, true); //SceneManager->getVideoDriver()->setRenderTarget(0); //LocalManager->getVideoDriver()->setViewPort( core::rect<s32>(0,0,TextureWidth,TextureWidth) ); s32 d = TextureWidth / slot; s32 x = (Imp.SlotID % d) * slot; s32 y = (Imp.SlotID / d) * slot; //LocalManager->getVideoDriver()->setViewPort( core::rect<s32>(0,0,TextureWidth,TextureWidth) ); /* SceneManager->getVideoDriver()->draw2DRectangle( video::SColor(127,0,0,0), core::rect<s32>(x,y,x+slot,y+slot)); SceneManager->getVideoDriver()->draw2DRectangle( video::SColor(100,0,0,0), core::rect<s32>(x,y,x+slot,y+slot)); SceneManager->getVideoDriver()->draw2DRectangle( video::SColor(100,0,0,0), core::rect<s32>(x,y,x+slot,y+slot)); */ //SceneManager->getVideoDriver()->setTransform core::rect<s32> clipRect(x,y, x+slot,y+slot); video::SMaterial m; m.MaterialTypeParam =video::pack_texureBlendFunc(video::EBF_ONE, video::EBF_ONE_MINUS_DST_ALPHA, video::EMFN_MODULATE_1X); m.MaterialType = video::EMT_ONETEXTURE_BLEND; m.Lighting=false; m.ZBuffer = false; m.ZWriteEnable = false; m.TextureLayer[0].TextureWrapU = video::ETC_CLAMP; m.setTexture(0, WorkTexture); video::S3DVertex Vertices[6]; Vertices[0] = video::S3DVertex(-1.0f, -1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 0.0f, YDirection); Vertices[1] = video::S3DVertex(-1.0f, 1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 0.0f, 0.0f); Vertices[2] = video::S3DVertex( 1.0f, 1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 1.0f, 0.0f); Vertices[3] = video::S3DVertex( 1.0f, -1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 1.0f, YDirection); Vertices[4] = video::S3DVertex(-1.0f, -1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 0.0f, YDirection); Vertices[5] = video::S3DVertex( 1.0f, 1.0f, 0.0f,1,1,0, video::SColor(255,255,255,255), 1.0f, 0.0f); const u16 i1[] = {0,1,2,3,4,5}; const u16 i2[] = {0,2,1,3,5,4}; const u16* indices = i1; core::matrix4 matrix, matrix2; if (YDirection == -1.0f) { matrix2.setScale(core::vector3df(1.0f,-1.0f,1.0f)); indices = i2; } LocalManager->getVideoDriver()->setViewPort( clipRect ); LocalManager->getVideoDriver()->setMaterial(m); SceneManager->getVideoDriver()->setTransform(video::ETS_WORLD, matrix); SceneManager->getVideoDriver()->setTransform(video::ETS_PROJECTION, matrix2); SceneManager->getVideoDriver()->setTransform(video::ETS_VIEW, matrix); SceneManager->getVideoDriver()->drawIndexedTriangleList(&Vertices[0], 6, &indices[0], 2); LocalManager->getVideoDriver()->setViewPort(core::rect<s32>(0,0,TextureWidth, TextureWidth)); //SceneManager->getVideoDriver()->draw2DImage( // WorkTexture, // core::position2di(x,y), // core::rect<s32>(0,0,slot, slot), // &clipRect, // video::SColor(255,255,255,255),true); if (DebugDataVisible & EDS_IMPOSTOR_INFO && DebugFont) { core::stringw text; video::SColor col(255,255,0,0); core::rect<s32> clip(x, y, x+slot, 0); s32 third = s32(f32(slot)*0.5f); text=L"Buf: "; text+=Imp.BufferID; clip.UpperLeftCorner.Y = y+third; clip.LowerRightCorner.Y = y+ third*2; DebugFont->draw(text.c_str(), clip, col, true, true, &clip); text=L"Region: "; text+=Imp.SlotID; clip.UpperLeftCorner.Y = y+third*2; clip.LowerRightCorner.Y = y+slot; DebugFont->draw(text.c_str(), clip, col, true, true, &clip); } //core::rect<s32> blaView = SceneManager->getVideoDriver()->getViewPort(); //SceneManager->getVideoDriver()->setTransform(video::ETS_WORLD, n->getAbsoluteTransformation()); //SceneManager->getVideoDriver()->draw3DBox(n->getBoundingBox()); // restore states SceneManager->getVideoDriver()->setRenderTarget(0, false, false); LocalManager->getVideoDriver()->setViewPort(oldView); // n->setSceneManager(oldManager); }
void CImpostorSceneNode::OnRegisterSceneNode() { if (!IsVisible) return; RenderCount++; // in here we: // decide which nodes need updates, add them to the queue // process the render queue // allocate textures and mesh buffers if required // perform clean up tasks: // garbage collection- free up spaces // reorganise // get collision manager ISceneCollisionManager* colmgr = SceneManager->getSceneCollisionManager(); // and the active camera ICameraSceneNode* cam = SceneManager->getActiveCamera(); core::aabbox3df camBB = cam->getViewFrustum()->getBoundingBox(); u32 now = Timer->getRealTime(); // loop through all impostor nodes u32 i; for (i=0; i < Impostors.size(); ++i) { SNodeLink &Imp = Impostors[i]; ISceneNode *n = Imp.Node; // skip invisible and culled nodes if (!n->isVisible() || !camBB.intersectsWithBox(n->getTransformedBoundingBox())) { //Culled++; Imp.IsActive = false; continue; } updatePosAndVector(Imp); // now we have the screen position... core::rect<s32> r = SceneManager->getVideoDriver()->getViewPort(); if (!Imp.NewPos.isValid() || !r.isRectCollided(Imp.NewPos) ) { // culled // Culled++; continue; } core::dimension2di newSize = Imp.NewPos.getSize(); // Change in rotation: a.length >= a.dotProduct(b) <= -a.length f32 diff = 0; // far plane = never update, near plane = always update f32 far = cam->getFarValue(); far *= far; f32 dist = Imp.Node->getAbsolutePosition().getDistanceFromSQ(cam->getAbsolutePosition()); dist = 1.0 - (far/dist); // value between 0 and 1 diff = dist; Imp.Score = dist; //s32 a = core::max_<s32>(Imp.NewPos.getWidth(), Imp.NewPos.getHeight()); //diff *= f32(a); bool reRender = diff > Threshold; //reRender =true; reRender = reRender || ( !Imp.IsQueued && Imp.BufferID != -1 && Buffers[Imp.BufferID].SlotSize < getTextureSizeFromSurfaceSize(core::max_<s32>(newSize.Width, newSize.Height))); // so small that we don't care about it if (newSize.Width < 4 || newSize.Height < 4) { Imp.IsActive = false; // object was culled //Culled++; continue; } // too large to fit in a texture slot if (newSize.Width > MaxSize || newSize.Height > MaxSize) { // get rid releaseSlot(Imp); Imp.IsActive = false; } else { Imp.IsActive = true; } if (Imp.IsActive && Imp.BufferID == -1 && !Imp.IsQueued ) reRender = true; if (Imp.IsActive) { // impostor replaces the node if (reRender && now > Imp.Time + MinTime) { if (!Imp.IsQueued) { CacheMisses++; Imp.IsQueued = true; SRenderQueueItem q; q.Node = &Imp; //q.Value = val; RenderQueue.push_back(q); } else { //QueueHits++; } } else { // don't re-render the impostor texture, only draw it CacheHits++; } } if (!Imp.IsActive) // || ( Imp.BufferID == -1 && Imp.IsQueued)) { // original node is visible n->OnRegisterSceneNode(); // cache miss CacheMisses++; } } SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT); }
void CLensFlareSceneNode::render() { video::IVideoDriver* driver = SceneManager->getVideoDriver(); ICameraSceneNode* camera = SceneManager->getActiveCamera(); if ( !camera || !driver || !material.Texture1 ) { return; } driver->setTransform( video::ETS_WORLD, core::matrix4() ); core::vector3df campos = camera->getAbsolutePosition(); core::dimension2d<s32> sz = SceneManager->getVideoDriver()->getScreenSize(); core::vector2df mid = core::vector2df( sz.Width, sz.Height ); mid /= 2; core::position2d<s32> lp = SceneManager->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition( getAbsolutePosition(), camera ); core::vector2df lightpos = core::vector2df( lp.X, lp.Y ); core::vector2df ipos; int nframes = material.Texture1->getOriginalSize().Width / material.Texture1->getOriginalSize().Height; int imageheight = material.Texture1->getSize().Height; int texw = 8; // fix height of lens flares to 32 pixels float texp = 1.0f / nframes; // calc billboard rotation to face camera core::vector3df target = camera->getTarget(); core::vector3df up = camera->getUpVector(); core::vector3df view = target - campos; view.normalize(); core::vector3df horizontal = up.crossProduct( view ); horizontal.normalize(); core::vector3df vertical; vertical = horizontal.crossProduct( view ); vertical.normalize(); view *= -1.0f; for ( s32 i = 0; i < 4; ++i ) { vertices[i].Normal = view; } core::vector3df hor; core::vector3df ver; // set material driver->setMaterial( material ); core::vector3df pos; for ( int ax = 0; ax < nframes; ax++ ) { if ( ax == 0 ) { // first burst is 3d pos = getAbsolutePosition(); texw = imageheight * 10; } else { // calc screen position for each flare ipos = mid.getInterpolated( lightpos, ( 2.0f / nframes ) * ax ); // try to find the correspondent world coordinate for screen position pos = SceneManager->getSceneCollisionManager()->getRayFromScreenCoordinates( core::position2d<s32>( int( ipos.X ), int( ipos.Y ) ), camera ).end; // try to put this position vetor near in front of camera core::vector3df dir = core::vector3df( campos - pos ).normalize(); pos = campos + ( dir * -10.0f );// put 10 units in front texw = 4; } // render flares // move texcoords to next flare in texture vertices[0].TCoords.set( ax * texp, 1.0f ); vertices[1].TCoords.set( ax * texp, 0.0f ); vertices[2].TCoords.set( ( ax + 1 ) * texp, 0.0f ); vertices[3].TCoords.set( ( ax + 1 ) * texp, 1.0f ); hor = horizontal * ( 0.5f * texw ); ver = vertical * ( 0.5f * texw ); vertices[0].Pos = pos + hor + ver; vertices[1].Pos = pos + hor - ver; vertices[2].Pos = pos - hor - ver; vertices[3].Pos = pos - hor + ver; // draw image part driver->drawIndexedTriangleList( vertices, 4, indices, 2 ); } }
void CBillboardGroupSceneNode::updateBillboards() { ICameraSceneNode* camera = SceneManager->getActiveCamera(); if ( !camera ) return; core::vector3df camPos = camera->getAbsolutePosition(); core::vector3df ref = core::vector3df(0,1,0); camera->getAbsoluteTransformation().rotateVect(ref); core::vector3df view, right, up; bool farAway = false; core::vector3df center = BoundingBox.getCenter(); AbsoluteTransformation.transformVect(center); core::vector3df camDir = camPos - center; if ( camDir.getLengthSQ() >= (FarDistance + Radius)*(FarDistance + Radius) ) { farAway = true; view = center - camPos; view.normalize(); right = ref.crossProduct( view ); up = view.crossProduct( right ); } core::vector3df rotatedCamDir = camDir; AbsoluteTransformation.inverseRotateVect( rotatedCamDir ); if ( farAway && (rotatedCamDir - LastCamDir).getLengthSQ() < 1000.0f ) { return; } LastCamDir = rotatedCamDir; // Update the position of every billboard for ( s32 i=0; i<Billboards.size(); i++ ) { if ( !farAway ) { core::vector3df pos = Billboards[i].Position; AbsoluteTransformation.transformVect( pos ); view = pos - camPos; view.normalize(); } core::vector3df thisRight = right; core::vector3df thisUp = up; if ( Billboards[i].HasAxis ) { core::vector3df axis = Billboards[i].Axis; AbsoluteTransformation.rotateVect(axis); thisRight = axis.crossProduct( view ); thisUp = axis; } else if ( !farAway ) { thisRight = ref.crossProduct( view ); thisUp = view.crossProduct( thisRight ); } f32 rollrad = Billboards[i].Roll * core::DEGTORAD; f32 cos_roll = cos( rollrad ); f32 sin_roll = sin( rollrad ); core::vector3df a = cos_roll * thisRight + sin_roll * thisUp; core::vector3df b = -sin_roll * thisRight + cos_roll * thisUp; a *= Billboards[i].Size.Width / 2.0f; b *= Billboards[i].Size.Height / 2.0f; s32 vertexIndex = 4 * i; // 4 vertices per billboard core::vector3df billPos = Billboards[i].Position; AbsoluteTransformation.transformVect(billPos); MeshBuffer.Vertices[vertexIndex ].Pos = billPos - a + b; MeshBuffer.Vertices[vertexIndex+1].Pos = billPos + a + b; MeshBuffer.Vertices[vertexIndex+2].Pos = billPos + a - b; MeshBuffer.Vertices[vertexIndex+3].Pos = billPos - a - b; } }