/** * \brief Implementing callback from AbstractTopLevelContainer */ virtual int getWidth() { return m_area.getWidth(); }
// this function was written by Lonesome Ducky // modified to add clipping // taken from http://irrlicht.sourceforge.net/forum/viewtopic.php?f=9&t=32388&start=15 void engine::draw2DImage(irr::video::IVideoDriver *driver, irr::video::ITexture* texture , irr::core::rect<irr::s32> sourceRect, irr::core::position2d<irr::s32> position, irr::core::position2d<irr::s32> rotationPoint, irr::f32 rotation, irr::core::vector2df scale, bool useAlphaChannel, irr::video::SColor color, irr::core::rect<irr::s32> clipRect) { irr::video::SMaterial material; // Store and clear the projection matrix irr::core::matrix4 oldProjMat = driver->getTransform(irr::video::ETS_PROJECTION); driver->setTransform(irr::video::ETS_PROJECTION,irr::core::matrix4()); // Store and clear the view matrix irr::core::matrix4 oldViewMat = driver->getTransform(irr::video::ETS_VIEW); driver->setTransform(irr::video::ETS_VIEW,irr::core::matrix4()); // Find the positions of corners irr::core::vector2df corner[8]; float px = (irr::f32)position.X; float py = (irr::f32)position.Y; float pw = (irr::f32)sourceRect.getWidth(); float ph = (irr::f32)sourceRect.getHeight(); corner[0] = irr::core::vector2df(px,py); corner[1] = irr::core::vector2df(px + (pw * scale.X)/2,py); corner[2] = irr::core::vector2df(px+pw*scale.X,py); corner[3] = irr::core::vector2df(px,py+(ph * scale.Y)/2); corner[4] = irr::core::vector2df(px + pw*scale.X,py+(ph*scale.Y)/2); corner[5] = irr::core::vector2df(px,py+ph*scale.Y); corner[6] = irr::core::vector2df(px + (pw*scale.X)/2, py + ph*scale.Y); corner[7] = irr::core::vector2df(px+pw*scale.X,py+ph*scale.Y); // Rotate corners if (rotation != 0.0f) for (int x = 0; x < 8; x++) corner[x].rotateBy((irr::f32)rotation,irr::core::vector2df((irr::f32)rotationPoint.X, (irr::f32)rotationPoint.Y)); irr::core::vector2df source_corners[8]; source_corners[0] = irr::core::vector2df(0,0); source_corners[1] = irr::core::vector2df((float)sourceRect.getWidth()/2,0); source_corners[2] = irr::core::vector2df((float)sourceRect.getWidth(),0); source_corners[3] = irr::core::vector2df(0,(float)sourceRect.getHeight()/2); source_corners[4] = irr::core::vector2df((float)sourceRect.getWidth(),(float)sourceRect.getHeight()/2); source_corners[5] = irr::core::vector2df(0,(float)sourceRect.getHeight()); source_corners[6] = irr::core::vector2df((float)sourceRect.getWidth()/2,(float)sourceRect.getHeight()); source_corners[7] = irr::core::vector2df((float)sourceRect.getWidth(),(float)sourceRect.getHeight()); // note: this assumes the rotation point is the actually center of the image float source_center_x = (float)sourceRect.getWidth()/2; float source_center_y = (float)sourceRect.getHeight()/2; // because there isn't a true to form clipping method available, I do this cludgy clipping method // first, I make the shape an octogon, then I clip the points of the rotated shape // then I find out what the source image ought to look like when clipped from those dimensions // 1. Find what the rotation the source rect corners would be if (rotation != 0.0f) for (int x = 0; x < 8; x++) source_corners[x].rotateBy((irr::f32)rotation,irr::core::vector2df(source_center_x, source_center_y)); // 2. Clip the rotated shape for(int x=0; x < 8; x++){ // these translations aren't correct for rotations that aren't vertical or horizontal. need to translate the points on the correct axis if(!clipRect.isPointInside(irr::core::vector2d<irr::s32>((irr::s32)source_corners[x].X + position.X, (irr::s32)source_corners[x].Y + position.Y))){ if((source_corners[x].X + position.X) < clipRect.UpperLeftCorner.X){ source_corners[x].X = (float)((float)clipRect.UpperLeftCorner.X - (float)position.X); } if((source_corners[x].X + position.X) > clipRect.LowerRightCorner.X){ source_corners[x].X = (float)((float)clipRect.LowerRightCorner.X - (float)position.X); } if((source_corners[x].Y + position.Y) < clipRect.UpperLeftCorner.Y){ source_corners[x].Y = (float)((float)clipRect.UpperLeftCorner.Y - (float)position.Y); } if((source_corners[x].Y + position.Y) > clipRect.LowerRightCorner.Y){ source_corners[x].Y = (float)((float)clipRect.LowerRightCorner.Y - (float)position.Y); } } if(!clipRect.isPointInside(irr::core::vector2d<irr::s32>((irr::s32)corner[x].X, (irr::s32)corner[x].Y))){ if(corner[x].X < clipRect.UpperLeftCorner.X){ corner[x].X = (float)clipRect.UpperLeftCorner.X; } if(corner[x].X > clipRect.LowerRightCorner.X){ corner[x].X = (float)clipRect.LowerRightCorner.X; } if(corner[x].Y < clipRect.UpperLeftCorner.Y){ corner[x].Y = (float)clipRect.UpperLeftCorner.Y; } if(corner[x].Y > clipRect.LowerRightCorner.Y){ corner[x].Y = (float)clipRect.LowerRightCorner.Y; } } } // 3. Rotate it back if (rotation != 0.0f) for (int x = 0; x < 8; x++) source_corners[x].rotateBy((irr::f32)rotation*-1,irr::core::vector2df(source_center_x, source_center_y)); // 4. Use the UV Coordinates of the resulting shape irr::core::vector2df uvCorner[8]; for (int x = 0; x < 8; x++) uvCorner[x] = source_corners[x]; for (int x = 0; x < 8; x++) { float uvX = uvCorner[x].X/(float)texture->getSize().Width; float uvY = uvCorner[x].Y/(float)texture->getSize().Height; uvCorner[x] = irr::core::vector2df(uvX,uvY); } irr::video::S3DVertex vertices[8]; // each indices is a point of a triangle to render // put them in the wrong order, and the triangle won't render right // I solved this puzzle one triangle at a time, to come up with this list irr::u16 indices[18] = { 0, 1, 3, 0, 2, 3, 3, 2, 4, 3, 4, 7, 3, 7, 6, 3, 6, 5 }; // Convert pixels to world coordinates float screenWidth = (float)driver->getScreenSize().Width; float screenHeight = (float)driver->getScreenSize().Height; for (int x = 0; x < 8; x++) { float screenPosX = ((corner[x].X/screenWidth)-0.5f)*2.0f; float screenPosY = ((corner[x].Y/screenHeight)-0.5f)*-2.0f; vertices[x].Pos = irr::core::vector3df(screenPosX,screenPosY,1); vertices[x].TCoords = uvCorner[x]; vertices[x].Color = color; } material.Lighting = false; material.ZWriteEnable = false; material.ZBuffer = false; material.TextureLayer[0].Texture = texture; material.MaterialTypeParam = irr::video::pack_texureBlendFunc(irr::video::EBF_SRC_ALPHA, irr::video::EBF_ONE_MINUS_SRC_ALPHA, irr::video::EMFN_MODULATE_1X, irr::video::EAS_TEXTURE | irr::video::EAS_VERTEX_COLOR); if (useAlphaChannel) material.MaterialType = irr::video::EMT_ONETEXTURE_BLEND; else material.MaterialType = irr::video::EMT_SOLID; driver->setMaterial(material); driver->drawIndexedTriangleList(&vertices[0],8,&indices[0],6); // Restore projection and view matrices driver->setTransform(irr::video::ETS_PROJECTION,oldProjMat); driver->setTransform(irr::video::ETS_VIEW,oldViewMat); }
/** * \brief Implementing callback from AbstractTopLevelContainer */ virtual int getHeight() { return m_area.getHeight(); }
//----------------------------------------------------------------------------// void IrrlichtGeometryBuffer::draw() const { // Set up clipping for this buffer // // NB: This is done via viewport & projection manipulation because Irrlicht // does not expose scissoring facilities of underlying APIs. This has the // unfortunate side effect of being much more expensive to set up. const irr::core::rect<irr::s32> target_vp(d_driver.getViewPort()); const irr::core::matrix4 proj (d_driver.getTransform(irr::video::ETS_PROJECTION)); const Size csz(d_clipRect.getSize()); const Size tsz(static_cast<float>(target_vp.getWidth()), static_cast<float>(target_vp.getHeight())); // set modified projection 'scissor' matix that negates scale and // translation that would be done by setting the viewport to the clip area. irr::core::matrix4 scsr(irr::core::matrix4::EM4CONST_IDENTITY); scsr(0, 0) = tsz.d_width / csz.d_width; scsr(1, 1) = tsz.d_height / csz.d_height; scsr(3, 0) = d_xViewDir * (tsz.d_width + 2.0f * (target_vp.UpperLeftCorner.X - (d_clipRect.d_left + csz.d_width * 0.5f))) / csz.d_width; scsr(3, 1) = -(tsz.d_height + 2.0f * (target_vp.UpperLeftCorner.Y - (d_clipRect.d_top + csz.d_height * 0.5f))) / csz.d_height; scsr *= proj; d_driver.setTransform(irr::video::ETS_PROJECTION, scsr); // set new viewport for the clipping area const irr::core::rect<irr::s32> vp( static_cast<irr::s32>(d_clipRect.d_left), static_cast<irr::s32>(d_clipRect.d_top), static_cast<irr::s32>(d_clipRect.d_right), static_cast<irr::s32>(d_clipRect.d_bottom)); d_driver.setViewPort(vp); if (!d_matrixValid) updateMatrix(); d_driver.setTransform(irr::video::ETS_WORLD, d_matrix); const int pass_count = d_effect ? d_effect->getPassCount() : 1; for (int pass = 0; pass < pass_count; ++pass) { // set up RenderEffect if (d_effect) d_effect->performPreRenderFunctions(pass); // draw the batches size_t pos = 0; BatchList::const_iterator i = d_batches.begin(); for ( ; i != d_batches.end(); ++i) { d_material.setTexture(0, (*i).first); d_driver.setMaterial(d_material); d_driver.drawIndexedTriangleList(&d_vertices[pos], (*i).second, &d_indices[pos], (*i).second / 3); pos += (*i).second; } } // clean up RenderEffect if (d_effect) d_effect->performPostRenderFunctions(); // restore original projection matrix and viewport. d_driver.setTransform(irr::video::ETS_PROJECTION, proj); d_driver.setViewPort(target_vp); }