inline void SColorHSL::fromRGB(const SColor &color) { const f32 maxVal = (f32) core::SharedMath::getInstance().max( color.getRed(), color.getGreen(), color.getBlue()); const f32 minVal = (f32) core::SharedMath::getInstance().min( color.getRed(), color.getGreen(), color.getBlue()); Luminance = (maxVal / minVal) * 0.5f; if (core::SharedMath::getInstance().equals(maxVal, minVal)) { Hue = 0.f; Saturation = 0.f; return; } const f32 delta = maxVal - minVal; if (Luminance <= 0.5f) { Saturation = (delta) / (maxVal + minVal); } else { Saturation = (delta) / (2 - maxVal - minVal); } if (maxVal == color.getRed()) Hue = (color.getGreen() - color.getBlue()) / delta; else if (maxVal == color.getGreen()) Hue = 2 + (color.getBlue() - color.getRed()) / delta; else if (maxVal == color.getBlue()) Hue = 4 + (color.getRed() - color.getGreen()) / delta; Hue *= (60.0f * core::SharedMath::DegToRad); while (Hue < 0.f) Hue += 2.f * core::SharedMath::Pi; }
// ---------------------------------------------------------------------------- void Terrain::pixelHardBrush(u8* img, int ix, SColor col, bool erase) { if (erase) { if (col.getBlue() > 0) { img[ix] = 0; return; } if (col.getGreen() > 0) { img[ix + 1] = 0; return; } if (col.getRed() > 0) { img[ix + 2] = 0; return; } return; } img[ix + 2] = col.getRed(); img[ix + 1] = col.getGreen(); img[ix + 0] = col.getBlue(); } // vertexHardBrush
void PostProcessing::renderFog() { const Track * const track = World::getWorld()->getTrack(); // This function is only called once per frame - thus no need for setters. const float fogmax = track->getFogMax(); const float startH = track->getFogStartHeight(); const float endH = track->getFogEndHeight(); const float start = track->getFogStart(); const float end = track->getFogEnd(); const SColor tmpcol = track->getFogColor(); core::vector3df col( tmpcol.getRed() / 255.0f, tmpcol.getGreen() / 255.0f, tmpcol.getBlue() / 255.0f ); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); FullScreenShader::FogShader::getInstance()->SetTextureUnits(createVector<GLuint>(irr_driver->getDepthStencilTexture())); DrawFullScreenEffect<FullScreenShader::FogShader>(fogmax, startH, endH, start, end, col); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); }
//! sets a pixel void SImage::setPixel(u32 x, u32 y, const SColor &color ) { if (x >= (u32)Size.Width || y >= (u32)Size.Height) return; switch(Format) { case ECF_A1R5G5B5: { u16 * dest = (u16*) ((u8*) Data + ( y * Pitch ) + ( x << 1 )); *dest = video::A8R8G8B8toA1R5G5B5 ( color.color ); } break; case ECF_R5G6B5: { u16 * dest = (u16*) ((u8*) Data + ( y * Pitch ) + ( x << 1 )); *dest = video::A8R8G8B8toR5G6B5 ( color.color ); } break; case ECF_R8G8B8: { u8* dest = (u8*) Data + ( y * Pitch ) + ( x * 3 ); dest[0] = color.getRed(); dest[1] = color.getGreen(); dest[2] = color.getBlue(); } break; case ECF_A8R8G8B8: { u32 * dest = (u32*) ((u8*) Data + ( y * Pitch ) + ( x << 2 )); *dest = color.color; } break; } }
//! get a filtered pixel inline SColor CImage::getPixelBox( s32 x, s32 y, s32 fx, s32 fy, s32 bias ) const { SColor c; s32 a = 0, r = 0, g = 0, b = 0; for ( s32 dx = 0; dx != fx; ++dx ) { for ( s32 dy = 0; dy != fy; ++dy ) { c = getPixel( core::s32_min ( x + dx, Size.Width - 1 ) , core::s32_min ( y + dy, Size.Height - 1 ) ); a += c.getAlpha(); r += c.getRed(); g += c.getGreen(); b += c.getBlue(); } } s32 sdiv = s32_log2_s32(fx * fy); a = core::s32_clamp( ( a >> sdiv ) + bias, 0, 255 ); r = core::s32_clamp( ( r >> sdiv ) + bias, 0, 255 ); g = core::s32_clamp( ( g >> sdiv ) + bias, 0, 255 ); b = core::s32_clamp( ( b >> sdiv ) + bias, 0, 255 ); c.set( a, r, g, b ); return c; }
// ----------------------------------------------------------------------------- video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* texture) { SColor c; u32 g; video::IVideoDriver* driver = irr_driver->getVideoDriver(); video::IImage* image = driver->createImageFromData (texture->getColorFormat(), texture->getSize(), texture->lock(), false); texture->unlock(); //Turn the image into grayscale for (u32 x = 0; x < image->getDimension().Width; x++) { for (u32 y = 0; y < image->getDimension().Height; y++) { c = image->getPixel(x, y); g = ((c.getRed() + c.getGreen() + c.getBlue()) / 3); c.set(std::max (0, (int)c.getAlpha() - 120), g, g, g); image->setPixel(x, y, c); } } texture = driver->addTexture(texture->getName().getPath() + "_disabled", image); texture->grab(); return texture; }
void PostProcessing::renderFog() { const Track * const track = World::getWorld()->getTrack(); // This function is only called once per frame - thus no need for setters. const float fogmax = track->getFogMax(); const float startH = track->getFogStartHeight(); const float endH = track->getFogEndHeight(); const float start = track->getFogStart(); const float end = track->getFogEnd(); const SColor tmpcol = track->getFogColor(); core::vector3df col( tmpcol.getRed() / 255.0f, tmpcol.getGreen() / 255.0f, tmpcol.getBlue() / 255.0f ); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(FullScreenShader::FogShader::Program); glBindVertexArray(FullScreenShader::FogShader::vao); setTexture(0, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST); FullScreenShader::FogShader::setUniforms(fogmax, startH, endH, start, end, col, 0); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); }
//! Constructs a color from 32 bit Color. SColorf::SColorf(SColor c) { const f32 inv = 1.0f / 255.0f; Red = c.getRed() * inv; Green = c.getGreen() * inv; Blue = c.getBlue() * inv; Alpha = c.getAlpha() * inv; }
// ---------------------------------------------------------------------------- void Terrain::pixelSoftBrush(u8* img, int ix, SColor col, double e) { if (e > 0) { img[ix + 3] = (u8) std::max(std::min(img[ix + 3] + e * col.getAlpha() - e * col.getRed() - e * col.getGreen() - e * col.getBlue(), 255.0), 0.0); img[ix + 2] = (u8) std::max(std::min(img[ix + 2] + e * col.getRed() - e * col.getAlpha() - e * col.getGreen() - e * col.getBlue(), 255.0), 0.0); img[ix + 1] = (u8) std::max(std::min(img[ix + 1] + e * col.getGreen() - e * col.getRed() - e * col.getAlpha() - e * col.getBlue(), 255.0), 0.0); img[ix + 0] = (u8) std::max(std::min(img[ix + 0] + e * col.getBlue() - e * col.getRed() - e * col.getGreen() - e * col.getAlpha(), 255.0), 0.0); } else { img[ix + 3] = (u8) std::max(img[ix + 3] + e * col.getAlpha(), 0.0); img[ix + 2] = (u8) std::max(img[ix + 2] + e * col.getRed(), 0.0); img[ix + 1] = (u8) std::max(img[ix + 1] + e * col.getGreen(), 0.0); img[ix + 0] = (u8) std::max(img[ix + 0] + e * col.getBlue(), 0.0); } } // vertexSoftBrush
void WxIrrMainWindow::OnSimulationShowZAxisChangeColor(wxCommandEvent &event) { wxColourData colorData; SColor currentIrrColor = OnSimulationZAxisGetColorFunctionPointer(); wxColour currentWxColor(currentIrrColor.getRed(), currentIrrColor.getGreen(), currentIrrColor.getBlue()); colorData.SetColour(currentWxColor); wxColourDialog colorDiag(this, &colorData); if (colorDiag.ShowModal() == wxID_OK) { wxColourData retData = colorDiag.GetColourData(); wxColour col = retData.GetColour(); OnSimulationZAxisChangeColorFunctionPointer(col); } }
void CD3D9Texture::copy16BitMipMap(char* src, char* tgt, s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const { for (s32 y=0; y<height; ++y) { for (s32 x=0; x<width; ++x) { u32 a=0, r=0, g=0, b=0; for (s32 dy=0; dy<2; ++dy) { const s32 tgy = (y*2)+dy; for (s32 dx=0; dx<2; ++dx) { const s32 tgx = (x*2)+dx; SColor c; if (ColorFormat == ECF_A1R5G5B5) c = A1R5G5B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)])); else c = R5G6B5toA8R8G8B8(*(u16*)(&src[(tgx*2)+(tgy*pitchsrc)])); a += c.getAlpha(); r += c.getRed(); g += c.getGreen(); b += c.getBlue(); } } a /= 4; r /= 4; g /= 4; b /= 4; u16 c; if (ColorFormat == ECF_A1R5G5B5) c = RGBA16(r,g,b,a); else c = A8R8G8B8toR5G6B5(SColor(a,r,g,b).color); *(u16*)(&tgt[(x*2)+(y*pitchtgt)]) = c; } } }
// ----------------------------------------------------------------------------- video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* texture) { #if !defined(SERVER_ONLY) && !defined(USE_GLES2) STKTexture* stk_tex = static_cast<STKTexture*>(texture); // Compressed texture can't be turned into greyscale if (stk_tex->isMeshTexture() && CVS->isTextureCompressionEnabled()) return stk_tex; std::string name = stk_tex->getName().getPtr(); name += "_disabled"; STKTexManager* stkm = STKTexManager::getInstance(); STKTexture* disabled_stk_tex = static_cast<STKTexture*>(stkm->getTexture (name, NULL/*tc*/, false /*no_upload*/, false/*create_if_unfound*/)); if (disabled_stk_tex == NULL) { SColor c; u32 g; video::IVideoDriver* driver = irr_driver->getVideoDriver(); video::IImage* image = driver->createImageFromData (video::ECF_A8R8G8B8, stk_tex->getSize(), stk_tex->lock(), stk_tex->getTextureImage() == NULL/*ownForeignMemory*/); texture->unlock(); //Turn the image into grayscale for (u32 x = 0; x < image->getDimension().Width; x++) { for (u32 y = 0; y < image->getDimension().Height; y++) { c = image->getPixel(x, y); g = ((c.getRed() + c.getGreen() + c.getBlue()) / 3); c.set(std::max (0, (int)c.getAlpha() - 120), g, g, g); image->setPixel(x, y, c); } } return stkm->addTexture(new STKTexture(image, name)); } return disabled_stk_tex; #else return texture; #endif // !SERVER_ONLY }
void RenderTarget::getImageData(floatv &data) { IImage* img = driver->createImage(target, position2d<s32>(0,0), target->getSize()); uint y = img->getDimension().Height; uint x = img->getDimension().Width; for(uint i = 0; i < y; i++) { for(uint j = 0; j < x; j++) { SColor color = img->getPixel(j,i); data.push_back((float)(color.getRed()/255.0)); data.push_back((float)(color.getGreen()/255.0)); data.push_back((float)(color.getBlue()/255.0)); } } img->drop(); //delete img; }
// ----------------------------------------------------------------------------- video::ITexture* IconButtonWidget::getDeactivatedTexture(video::ITexture* texture) { #ifdef DO_NOT_USE_IT_CAUSES_BUG_1780_FONT_CORRUPTION video::ITexture* t; std::string name = texture->getName().getPath().c_str(); name += "_disabled"; t = irr_driver->getTexture(name, /*premul*/false, /*prediv*/false, /*compain_if_not_found*/false); if (t == NULL) { SColor c; u32 g; video::IVideoDriver* driver = irr_driver->getVideoDriver(); std::unique_ptr<video::IImage> image (driver->createImageFromData (texture->getColorFormat(), texture->getSize(), texture->lock(), false)); texture->unlock(); //Turn the image into grayscale for (u32 x = 0; x < image->getDimension().Width; x++) { for (u32 y = 0; y < image->getDimension().Height; y++) { c = image->getPixel(x, y); g = ((c.getRed() + c.getGreen() + c.getBlue()) / 3); c.set(std::max (0, (int)c.getAlpha() - 120), g, g, g); image->setPixel(x, y, c); } } t = driver->addTexture(name.c_str(), image.get ()); } return t; #endif return texture; }
void CD3D8Texture::copy32BitMipMap(char* src, char* tgt, s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const { SColor c; for (int x=0; x<width; ++x) { for (int y=0; y<height; ++y) { s32 a=0, r=0, g=0, b=0; for (int dx=0; dx<2; ++dx) { for (int dy=0; dy<2; ++dy) { int tgx = (x*2)+dx; int tgy = (y*2)+dy; c = *(u32*)((void*)&src[(tgx<<2)+(tgy*pitchsrc)]); a += c.getAlpha(); r += c.getRed(); g += c.getGreen(); b += c.getBlue(); } } a >>= 2; r >>= 2; g >>= 2; b >>= 2; c = ((a & 0xff)<<24) | ((r & 0xff)<<16) | ((g & 0xff)<<8) | (b & 0xff); *(u32*)((void*)&tgt[(x*4)+(y*pitchtgt)]) = c.color; } } }
void CD3D9Texture::copy32BitMipMap(char* src, char* tgt, s32 width, s32 height, s32 pitchsrc, s32 pitchtgt) const { for (s32 y=0; y<height; ++y) { for (s32 x=0; x<width; ++x) { u32 a=0, r=0, g=0, b=0; SColor c; for (s32 dy=0; dy<2; ++dy) { const s32 tgy = (y*2)+dy; for (s32 dx=0; dx<2; ++dx) { const s32 tgx = (x*2)+dx; c = *(u32*)(&src[(tgx*4)+(tgy*pitchsrc)]); a += c.getAlpha(); r += c.getRed(); g += c.getGreen(); b += c.getBlue(); } } a /= 4; r /= 4; g /= 4; b /= 4; c.set(a, r, g, b); *(u32*)(&tgt[(x*4)+(y*pitchtgt)]) = c.color; } } }
void PostProcessing::renderFog() { const Track * const track = World::getWorld()->getTrack(); // This function is only called once per frame - thus no need for setters. const float start = track->getFogStart(); const SColor tmpcol = track->getFogColor(); core::vector3df col( tmpcol.getRed() / 255.0f, tmpcol.getGreen() / 255.0f, tmpcol.getBlue() / 255.0f ); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_ONE, GL_ONE); FullScreenShader::FogShader::getInstance()->SetTextureUnits(irr_driver->getDepthStencilTexture()); DrawFullScreenEffect<FullScreenShader::FogShader>(1.f / (40.f * start), col); glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); }
SColor Scene::getDiffuse(const vector3df& point, const vector3df& normal, const Material* mat) { SColor ret = mat->getColor(); SColorf light(0,0,0); core::list<Light*>::Iterator it; for (it = lights.begin(); it != lights.end(); it++) { float dot = ((*it)->Position - point).normalize().dotProduct(normal); if (dot < 0) continue; SColorf& lightcol = (*it)->Color; float coef = dot * (*it)->getIntensity(point); light.r += lightcol.r * coef; light.g += lightcol.g * coef; light.b += lightcol.b * coef; } ret.set(255, (u32)(ret.getRed() * light.r), (u32)(ret.getGreen() * light.g), (u32)(ret.getBlue() * light.b)); return ret; }
bool CImageWriterPCX::writeImage(io::IWriteFile * file, IImage * image, u32 param) const { if (!file || !image) { return false; } u8 d1; u16 d2; u32 i; d1 = 10; // Manufacturer file->write(&d1, 1); d1 = 5; // Version file->write(&d1, 1); d1 = 1; // Encoding file->write(&d1, 1); d1 = 8; // Bits per Pixel file->write(&d1, 1); d2 = 0; // pixel origin file->write(&d2, 2); file->write(&d2, 2); d2 = image->getDimension().Width - 1; // width #ifdef __BIG_ENDIAN__ d2 = os::Byteswap::byteswap(d2); #endif file->write(&d2, 2); d2 = image->getDimension().Height - 1; // height #ifdef __BIG_ENDIAN__ d2 = os::Byteswap::byteswap(d2); #endif file->write(&d2, 2); d2 = 300; // dpi #ifdef __BIG_ENDIAN__ d2 = os::Byteswap::byteswap(d2); #endif file->write(&d2, 2); file->write(&d2, 2); d2 = 0; // palette (not used) for (i = 0; i < 24; ++i) { file->write(&d2, 2); } d1 = 0; // reserved file->write(&d1, 1); d1 = 3; // planes file->write(&d1, 1); d2 = image->getDimension().Width; // pitch if (d2 & 0x0001) // must be even { ++d2; } #ifdef __BIG_ENDIAN__ d2 = os::Byteswap::byteswap(d2); #endif file->write(&d2, 2); d2 = 1; // color mode #ifdef __BIG_ENDIAN__ d2 = os::Byteswap::byteswap(d2); #endif file->write(&d2, 2); d2 = 800; // screen width #ifdef __BIG_ENDIAN__ d2 = os::Byteswap::byteswap(d2); #endif file->write(&d2, 2); d2 = 600; // screen height #ifdef __BIG_ENDIAN__ d2 = os::Byteswap::byteswap(d2); #endif file->write(&d2, 2); d2 = 0; // filler (not used) for (i = 0; i < 27; ++i) { file->write(&d2, 2); } u8 cnt, value; for (i = 0; i < image->getDimension().Height; ++i) { cnt = 0; value = 0; for (u32 j = 0; j < 3; ++j) // color planes { for (u32 k = 0; k < image->getDimension().Width; ++k) { const SColor pix = image->getPixel(k, i); if ((cnt != 0) && (cnt < 63) && (((j == 0) && (value == pix.getRed())) || ((j == 1) && (value == pix.getGreen())) || ((j == 2) && (value == pix.getBlue())))) { ++cnt; } else { if (cnt != 0) { if ((cnt > 1) || ((value & 0xc0) == 0xc0)) { cnt |= 0xc0; file->write(&cnt, 1); } file->write(&value, 1); } cnt = 1; if (j == 0) { value = (u8)pix.getRed(); } else if (j == 1) { value = (u8)pix.getGreen(); } else if (j == 2) { value = (u8)pix.getBlue(); } } } } if ((cnt > 1) || ((value & 0xc0) == 0xc0)) { cnt |= 0xc0; file->write(&cnt, 1); } file->write(&value, 1); } return true; }
void IWeatherManagerAtmosphere::update() { updateTimer(); SColor sp; J=J+(((double)dayspeed/86400)/1000.0f)*dTime; //if interpolation is finished then start again if(time_int_step==0.0f) { //calculate sun interpolation positions prep_interpolation(J,sun_interpolation_speed*J1minute); JulianToDate(J); counter_time=0.0f; }//1440 //printf("%8.4f %4.8f\n",J,time_int_step); //---move sun billboard to sun place counter_time+=J-J1;//1440 time_int_step=counter_time/(sun_interpolation_speed*J1minute);//(1.0f/(sun_interpolation_speed*(1.0f/1440.0f)))*dTime; vector3df sun_place=getInterpolated3df(sun_pos_from,sun_pos_to, time_int_step); J1=J; ICameraSceneNode *cam=smgr->getActiveCamera(); core::vector3df cameraPos = cam->getAbsolutePosition(); core::vector3df vt;//billboard position vt.X=sun_place.X+cameraPos.X; vt.Y=sun_place.Y+cameraPos.Y; vt.Z=sun_place.Z+cameraPos.Z; bill->setPosition(vt); vt.X=-sun_place.X+cameraPos.X; vt.Y=-sun_place.Y+cameraPos.Y; vt.Z=-sun_place.Z+cameraPos.Z; bill->setMoonPosition(vt); // sunlight->setPosition(vt); //---sun movement end f32 inv = 1.0f - time_int_step; uvX=((sun_angle_from *inv + sun_angle_to*time_int_step)+90.0f)/180; if(time_int_step>=1.0f) time_int_step=0.0f; sp=skyimage->getPixel((int)round(128*uvX),117); // Y = 123 //driver->setAmbientLight(SColor(255,sp.getRed(),sp.getGreen(),sp.getBlue())); //printf("vt %3.4f",getSunYAngle()); ClearColor = SColor(255,sp.getRed(),sp.getGreen(),sp.getBlue()); if(UpdateFog) { SColor fogColor; E_FOG_TYPE fogType; f32 fogStart; f32 fogEnd; f32 fogDensity; bool pixelFog; bool rangeFog; driver->getFog(fogColor,fogType,fogStart,fogEnd,fogDensity,pixelFog,rangeFog); driver->setFog(ClearColor,fogType,fogStart,fogEnd,fogDensity,pixelFog,rangeFog); } if (getSunYAngle()<0.0042) {//isjungti lenpa kai naktis sunlight->setVisible(false); setAmbientLight2(SColor(255,sp.getRed(),sp.getGreen(),sp.getBlue())); } else { sunlight->setVisible(true); setAmbientLight2(SColor(255,sp.getRed(),sp.getGreen(),sp.getBlue()));//bug fix } // smgr->setShadowColor(SColor(50,sp.getRed(),sp.getGreen(),sp.getBlue())); //sunlight->getLightData().DiffuseColor=SColor(255,sp.getRed(),sp.getGreen(),sp.getBlue()); Sky->setuvX(uvX); startTime = currentTime; }
/** Render the post-processed scene */ void PostProcessing::render() { if (!irr_driver->isGLSL()) return; IVideoDriver * const drv = irr_driver->getVideoDriver(); drv->setTransform(ETS_WORLD, core::IdentityMatrix); drv->setTransform(ETS_VIEW, core::IdentityMatrix); drv->setTransform(ETS_PROJECTION, core::IdentityMatrix); MotionBlurProvider * const mocb = (MotionBlurProvider *) irr_driver-> getCallback(ES_MOTIONBLUR); GaussianBlurProvider * const gacb = (GaussianBlurProvider *) irr_driver-> getCallback(ES_GAUSSIAN3H); const u32 cams = Camera::getNumCameras(); for(u32 cam = 0; cam < cams; cam++) { scene::ICameraSceneNode * const camnode = Camera::getCamera(cam)->getCameraSceneNode(); mocb->setCurrentCamera(cam); ITexture *in = irr_driver->getRTT(RTT_COLOR); ITexture *out = irr_driver->getRTT(RTT_TMP1); // Each effect uses these as named, and sets them up for the next effect. // This allows chaining effects where some may be disabled. // As the original color shouldn't be touched, the first effect can't be disabled. PROFILER_PUSH_CPU_MARKER("- Bloom", 0xFF, 0x00, 0x00); if (1) // bloom { // Blit the base to tmp1 drv->setRenderTarget(out, true, false); renderPassThrough(in); const bool globalbloom = World::getWorld()->getTrack()->getBloom(); if (globalbloom) { drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); renderBloom(in); } if (globalbloom) { // Clear the alpha to a suitable value, stencil glClearColor(0, 0, 0, 0.1f); glColorMask(0, 0, 0, 1); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 0); glColorMask(1, 1, 1, 1); // To half drv->setRenderTarget(irr_driver->getRTT(RTT_HALF1), true, false); renderPassThrough(irr_driver->getRTT(RTT_TMP3)); // To quarter drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), true, false); renderPassThrough(irr_driver->getRTT(RTT_HALF1)); // To eighth drv->setRenderTarget(irr_driver->getRTT(RTT_EIGHTH1), true, false); renderPassThrough(irr_driver->getRTT(RTT_QUARTER1)); // Blur it for distribution. renderGaussian6Blur(irr_driver->getRTT(RTT_EIGHTH1), irr_driver->getRTT(RTT_EIGHTH2), 8.f / UserConfigParams::m_width, 8.f / UserConfigParams::m_height); // Additively blend on top of tmp1 drv->setRenderTarget(out, false, false); renderBloomBlend(irr_driver->getRTT(RTT_EIGHTH1)); } // end if bloom in = irr_driver->getRTT(RTT_TMP1); out = irr_driver->getRTT(RTT_TMP2); } PROFILER_POP_CPU_MARKER(); PROFILER_PUSH_CPU_MARKER("- Godrays", 0xFF, 0x00, 0x00); if (m_sunpixels > 30)//World::getWorld()->getTrack()->hasGodRays() && ) // god rays { // Grab the sky drv->setRenderTarget(out, true, false); // irr_driver->getSceneManager()->drawAll(ESNRP_SKY_BOX); irr_driver->renderSkybox(); // Set the sun's color const SColor col = World::getWorld()->getTrack()->getSunColor(); ColorizeProvider * const colcb = (ColorizeProvider *) irr_driver->getCallback(ES_COLORIZE); colcb->setColor(col.getRed() / 255.0f, col.getGreen() / 255.0f, col.getBlue() / 255.0f); // The sun interposer STKMeshSceneNode *sun = irr_driver->getSunInterposer(); /* sun->getMaterial(0).ColorMask = ECP_ALL; irr_driver->getSceneManager()->setCurrentRendertime(ESNRP_SOLID);*/ irr_driver->getSceneManager()->drawAll(ESNRP_CAMERA); irr_driver->setPhase(GLOW_PASS); sun->render(); //sun->getMaterial(0).ColorMask = ECP_NONE; // Fade to quarter drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), false, false); renderGodFade(getTextureGLuint(out), col); // Blur renderGaussian3Blur(irr_driver->getRTT(RTT_QUARTER1), irr_driver->getRTT(RTT_QUARTER2), 4.f / UserConfigParams::m_width, 4.f / UserConfigParams::m_height); // Calculate the sun's position in texcoords const core::vector3df pos = sun->getPosition(); float ndc[4]; core::matrix4 trans = camnode->getProjectionMatrix(); trans *= camnode->getViewMatrix(); trans.transformVect(ndc, pos); const float texh = m_vertices[cam].v1.TCoords.Y - m_vertices[cam].v0.TCoords.Y; const float texw = m_vertices[cam].v3.TCoords.X - m_vertices[cam].v0.TCoords.X; const float sunx = ((ndc[0] / ndc[3]) * 0.5f + 0.5f) * texw; const float suny = ((ndc[1] / ndc[3]) * 0.5f + 0.5f) * texh; // ((GodRayProvider *) irr_driver->getCallback(ES_GODRAY))-> // setSunPosition(sunx, suny); // Rays please drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER2), true, false); renderGodRay(getTextureGLuint(irr_driver->getRTT(RTT_QUARTER1)), core::vector2df(sunx, suny)); // Blur renderGaussian3Blur(irr_driver->getRTT(RTT_QUARTER2), irr_driver->getRTT(RTT_QUARTER1), 4.f / UserConfigParams::m_width, 4.f / UserConfigParams::m_height); // Blend glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); drv->setRenderTarget(in, false, false); renderPassThrough(irr_driver->getRTT(RTT_QUARTER2)); } PROFILER_POP_CPU_MARKER(); if (UserConfigParams::m_motionblur && m_any_boost) // motion blur { PROFILER_PUSH_CPU_MARKER("- Motion blur", 0xFF, 0x00, 0x00); renderMotionBlur(cam, in, out); ITexture *tmp = in; in = out; out = tmp; PROFILER_POP_CPU_MARKER(); } if (irr_driver->getDisplacingNodes().size()) // Displacement { PROFILER_PUSH_CPU_MARKER("- Displacement", 0xFF, 0x00, 0x00); drv->setRenderTarget(out, true, false); renderPPDisplace(in); ITexture *tmp = in; in = out; out = tmp; PROFILER_POP_CPU_MARKER(); } /* m_material.MaterialType = irr_driver->getShader(ES_RAIN); drv->setMaterial(m_material); static_cast<irr::video::COpenGLDriver*>(drv)->setRenderStates3DMode();*/ if (UserConfigParams::m_mlaa) // MLAA. Must be the last pp filter. { PROFILER_PUSH_CPU_MARKER("- MLAA", 0xFF, 0x00, 0x00); drv->setRenderTarget(out, false, false); glEnable(GL_STENCIL_TEST); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 1, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // Pass 1: color edge detection m_material.setFlag(EMF_BILINEAR_FILTER, false); m_material.setFlag(EMF_TRILINEAR_FILTER, false); m_material.MaterialType = irr_driver->getShader(ES_MLAA_COLOR1); m_material.setTexture(0, in); drawQuad(cam, m_material); m_material.setFlag(EMF_BILINEAR_FILTER, true); m_material.setFlag(EMF_TRILINEAR_FILTER, true); glStencilFunc(GL_EQUAL, 1, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Pass 2: blend weights drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); m_material.MaterialType = irr_driver->getShader(ES_MLAA_BLEND2); m_material.setTexture(0, out); m_material.setTexture(1, m_areamap); m_material.TextureLayer[1].BilinearFilter = false; m_material.TextureLayer[1].TrilinearFilter = false; drawQuad(cam, m_material); m_material.TextureLayer[1].BilinearFilter = true; m_material.TextureLayer[1].TrilinearFilter = true; m_material.setTexture(1, 0); // Pass 3: gather drv->setRenderTarget(in, false, false); m_material.setFlag(EMF_BILINEAR_FILTER, false); m_material.setFlag(EMF_TRILINEAR_FILTER, false); m_material.MaterialType = irr_driver->getShader(ES_MLAA_NEIGH3); m_material.setTexture(0, irr_driver->getRTT(RTT_TMP3)); m_material.setTexture(1, irr_driver->getRTT(RTT_COLOR)); drawQuad(cam, m_material); m_material.setFlag(EMF_BILINEAR_FILTER, true); m_material.setFlag(EMF_TRILINEAR_FILTER, true); m_material.setTexture(1, 0); // Done. glDisable(GL_STENCIL_TEST); PROFILER_POP_CPU_MARKER(); } // Final blit // TODO : Use glBlitFramebuffer drv->setRenderTarget(ERT_FRAME_BUFFER, false, false); if (irr_driver->getNormals()) renderPassThrough(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)); else if (irr_driver->getSSAOViz()) renderPassThrough(irr_driver->getRTT(RTT_SSAO)); else renderColorLevel(in); } } // render
void SerializeOutSColor(ostream& os, SColor& color) { os << color.getAlpha()<< endl << color.getRed() << endl << color.getGreen() << endl << color.getBlue() << endl; }
/** Render the post-processed scene */ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, bool isRace) { FrameBuffer *in_fbo = &irr_driver->getFBO(FBO_COLORS); FrameBuffer *out_fbo = &irr_driver->getFBO(FBO_TMP1_WITH_DS); // Each effect uses these as named, and sets them up for the next effect. // This allows chaining effects where some may be disabled. // As the original color shouldn't be touched, the first effect can't be disabled. glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); if (isRace && UserConfigParams::m_dof) { PROFILER_PUSH_CPU_MARKER("- DoF", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_DOF)); renderDoF(*out_fbo, in_fbo->getRTT()[0]); std::swap(in_fbo, out_fbo); PROFILER_POP_CPU_MARKER(); } { PROFILER_PUSH_CPU_MARKER("- Godrays", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_GODRAYS)); bool hasgodrays = false; if (World::getWorld() != NULL) hasgodrays = World::getWorld()->getTrack()->hasGodRays(); if (isRace && UserConfigParams::m_light_shaft && hasgodrays) { Track* track = World::getWorld()->getTrack(); glEnable(GL_DEPTH_TEST); // Grab the sky out_fbo->Bind(); glClear(GL_COLOR_BUFFER_BIT); // irr_driver->renderSkybox(camnode); // Set the sun's color const SColor col = track->getGodRaysColor(); ColorizeProvider * const colcb = (ColorizeProvider *)irr_driver->getCallback(ES_COLORIZE); colcb->setColor(col.getRed() / 255.0f, col.getGreen() / 255.0f, col.getBlue() / 255.0f); // The sun interposer STKMeshSceneNode *sun = irr_driver->getSunInterposer(); sun->setGlowColors(col); sun->setPosition(track->getGodRaysPosition()); sun->updateAbsolutePosition(); irr_driver->setPhase(GLOW_PASS); sun->render(); glDisable(GL_DEPTH_TEST); // Fade to quarter irr_driver->getFBO(FBO_QUARTER1).Bind(); glViewport(0, 0, UserConfigParams::m_width / 4, UserConfigParams::m_height / 4); renderGodFade(out_fbo->getRTT()[0], col); // Blur renderGaussian3Blur(irr_driver->getFBO(FBO_QUARTER1), irr_driver->getFBO(FBO_QUARTER2)); // Calculate the sun's position in texcoords const core::vector3df pos = track->getGodRaysPosition(); float ndc[4]; core::matrix4 trans = camnode->getProjectionMatrix(); trans *= camnode->getViewMatrix(); trans.transformVect(ndc, pos); const float texh = m_vertices[0].v1.TCoords.Y - m_vertices[0].v0.TCoords.Y; const float texw = m_vertices[0].v3.TCoords.X - m_vertices[0].v0.TCoords.X; const float sunx = ((ndc[0] / ndc[3]) * 0.5f + 0.5f) * texw; const float suny = ((ndc[1] / ndc[3]) * 0.5f + 0.5f) * texh; // Rays please irr_driver->getFBO(FBO_QUARTER2).Bind(); renderGodRay(irr_driver->getRenderTargetTexture(RTT_QUARTER1), core::vector2df(sunx, suny)); // Blur renderGaussian3Blur(irr_driver->getFBO(FBO_QUARTER2), irr_driver->getFBO(FBO_QUARTER1)); // Blend glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); in_fbo->Bind(); renderPassThrough(irr_driver->getRenderTargetTexture(RTT_QUARTER2)); glDisable(GL_BLEND); } PROFILER_POP_CPU_MARKER(); } // Simulate camera defects from there { PROFILER_PUSH_CPU_MARKER("- Bloom", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_BLOOM)); if (isRace && UserConfigParams::m_bloom) { glClear(GL_STENCIL_BUFFER_BIT); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); FrameBuffer::Blit(*in_fbo, irr_driver->getFBO(FBO_BLOOM_1024), GL_COLOR_BUFFER_BIT, GL_LINEAR); irr_driver->getFBO(FBO_BLOOM_512).Bind(); renderBloom(irr_driver->getRenderTargetTexture(RTT_BLOOM_1024)); // Downsample FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_512), irr_driver->getFBO(FBO_BLOOM_256), GL_COLOR_BUFFER_BIT, GL_LINEAR); FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_256), irr_driver->getFBO(FBO_BLOOM_128), GL_COLOR_BUFFER_BIT, GL_LINEAR); // Blur renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_512), irr_driver->getFBO(FBO_TMP_512)); renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_256), irr_driver->getFBO(FBO_TMP_256)); renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_128), irr_driver->getFBO(FBO_TMP_128)); // Additively blend on top of tmp1 in_fbo->Bind(); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); FullScreenShader::BloomBlendShader::getInstance()->SetTextureUnits(createVector<GLuint>( irr_driver->getRenderTargetTexture(RTT_BLOOM_128), irr_driver->getRenderTargetTexture(RTT_BLOOM_256), irr_driver->getRenderTargetTexture(RTT_BLOOM_512) )); DrawFullScreenEffect<FullScreenShader::BloomBlendShader>(); glDisable(GL_BLEND); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } // end if bloom PROFILER_POP_CPU_MARKER(); } //computeLogLuminance(in_rtt); { PROFILER_PUSH_CPU_MARKER("- Tonemap", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_TONEMAP)); toneMap(*out_fbo, in_fbo->getRTT()[0]); std::swap(in_fbo, out_fbo); PROFILER_POP_CPU_MARKER(); } { PROFILER_PUSH_CPU_MARKER("- Motion blur", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MOTIONBLUR)); if (isRace && UserConfigParams::m_motionblur && World::getWorld() != NULL) // motion blur { renderMotionBlur(0, *in_fbo, *out_fbo); std::swap(in_fbo, out_fbo); } PROFILER_POP_CPU_MARKER(); } // Workaround a bug with srgb fbo on sandy bridge windows if (irr_driver->needUBOWorkaround()) return in_fbo; glEnable(GL_FRAMEBUFFER_SRGB); irr_driver->getFBO(FBO_MLAA_COLORS).Bind(); renderPassThrough(in_fbo->getRTT()[0]); out_fbo = &irr_driver->getFBO(FBO_MLAA_COLORS); if (UserConfigParams::m_mlaa) // MLAA. Must be the last pp filter. { PROFILER_PUSH_CPU_MARKER("- MLAA", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MLAA)); applyMLAA(); PROFILER_POP_CPU_MARKER(); } glDisable(GL_FRAMEBUFFER_SRGB); return out_fbo; } // render
//! @brief render big software image of any size using either screen to render or offscreen texture ( can flicker ) bool renderToImage( IrrlichtDevice* device, IImage* dst, s32 nSamples, const SColor& clearColor, bool renderGUI, bool debugLog) { // print call params if (debugLog) printf( "renderToImage( nSamples=%i, clearColor(%i,%i,%i,%i)\n", nSamples, clearColor.getAlpha(), clearColor.getRed(), clearColor.getGreen(), clearColor.getBlue() ); // abort if (!device) { printf("No Irrlicht-Device found.\n"); return false; } // abort if (!dst) { printf("No destination image found.\n"); return false; } // local pointers IVideoDriver* driver = device->getVideoDriver(); gui::IGUIEnvironment* guienv = device->getGUIEnvironment(); scene::ISceneManager* smgr = device->getSceneManager(); scene::ICameraSceneNode* camera = smgr->getActiveCamera(); // abort if (!camera) { printf("No active camera found.\n"); return false; } //! decompose camera's projection-matrix in d3d semantics core::matrix4 projMat = camera->getProjectionMatrix(); bool IsOrthogonal = true; if ( core::equals( projMat(3,3), 0.f ) ) IsOrthogonal = false; if ( !core::equals( projMat(2,3), 0.f ) ) IsOrthogonal = false; f32 Left; f32 Right; f32 Bottom; f32 Top; f32 Near; f32 Far; if (IsOrthogonal) { Near = -projMat(3,2)/projMat(2,2); Far = -(projMat(3,2)-1.f)/projMat(2,2); Left = -(projMat(3,0)+1.f)/projMat(0,0); Right = -(projMat(3,0)-1.f)/projMat(0,0); Top = -(projMat(3,1)-1.f)/projMat(1,1); Bottom = -(projMat(3,1)+1.f)/projMat(1,1); } else { Near = -projMat(3,2)/projMat(2,2); Far = -projMat(3,2)/(projMat(2,2)-1.f); Left = -Near*(projMat(2,0)+1.f)/projMat(0,0); Right = -Near*(projMat(2,0)-1.f)/projMat(0,0); Top = -Near*(projMat(2,1)-1.f)/projMat(1,1); Bottom = -Near*(projMat(2,1)+1.f)/projMat(1,1); } Near = camera->getNearValue(); // take the values directly from Camera Far = camera->getFarValue(); // due to f32 rounding errors //! ---------------------------------------------------------------------- //! calculate Border / get max thickness used by all registered materials //! ---------------------------------------------------------------------- s32 Border = 0; f32 thickness = 0.0f; const core::list<scene::ISceneNode*>& children = smgr->getRootSceneNode()->getChildren(); core::list<scene::ISceneNode*>::ConstIterator it = children.begin(); while (it != children.end()) { scene::ISceneNode* node = (*it); if (node) { u32 matCount = node->getMaterialCount(); for (u32 m = 0; m < matCount; ++m) { if (thickness < node->getMaterial(m).Thickness) thickness = node->getMaterial(m).Thickness; } } it++; } Border = core::ceil32( thickness ); //! ------------------------------------------------------------------------------------------ //! choose render-mode: offscreen or onscreen depending on AA, nSamples and RTT capabilities //! ------------------------------------------------------------------------------------------ //! @var nSamples - AntiAliasing depth > 1 make bigger rtts or downscale render-result by factor nSamples while having filter-methods enabled //! the framebuffer will always be downscaled by fast software bilinear filtering using colorkey/transparency to blend better into final image //! hardware-scaling: bilinear, trilinear or anisotropic texture-filtering available with irrlicht-engine //! software scaling: nearest, bilinear, bicubic downscaling available: //! bilinear has best compromise for downscaling ( there is much more information-loss due to resize than interpolation) //! default: 1 (<2) - no AA/downscaling done //! @var clearColor - argb32 color, the final image will filled with //! before writing into it and be used as colorkey for AA/software bilinear downscaling operation //! @var DoOffscreen - default=false, onscreen (framebuffer) //! false - onscreen-rendering using framebuffer/display. //! doublebuffer is possible, but will not prevent the showing of each rendered tile-texture //! true - offscreen-rendering using render-target-textures bool DoOffscreen = false; //! ---------------------------------------------------------------- //! collect video-driver infos //! ---------------------------------------------------------------- const core::dimension2du ScreenSize = driver->getScreenSize(); const ECOLOR_FORMAT ScreenFormat = driver->getColorFormat(); const u32 ScreenBits = IImage::getBitsPerPixelFromFormat( ScreenFormat ); const io::IAttributes& info = driver->getDriverAttributes(); const core::dimension2du MaxRTTSize = driver->getMaxTextureSize(); const u32 MaxAA = info.getAttributeAsInt( "AntiAlias" ); const u32 MaxAF = info.getAttributeAsInt( "MaxAnisotropy" ); const bool HasNPOT = driver->queryFeature( EVDF_TEXTURE_NPOT ); const bool HasNSQR = driver->queryFeature( EVDF_TEXTURE_NSQUARE ); const bool HasRTT = driver->queryFeature( EVDF_RENDER_TO_TARGET); const bool HasMTT = driver->queryFeature( EVDF_MULTITEXTURE); const bool HasMRT = driver->queryFeature( EVDF_MULTIPLE_RENDER_TARGETS); const bool HasATC = driver->queryFeature( EVDF_ALPHA_TO_COVERAGE); const bool HasBTF = driver->queryFeature( EVDF_BILINEAR_FILTER); const bool HasCMK = driver->queryFeature( EVDF_COLOR_MASK); const bool HasMMP = driver->queryFeature( EVDF_MIP_MAP); const bool HasMMA = driver->queryFeature( EVDF_MIP_MAP_AUTO_UPDATE); const bool HasOCC = driver->queryFeature( EVDF_OCCLUSION_QUERY); const bool HasPOF = driver->queryFeature( EVDF_POLYGON_OFFSET); if (debugLog) { printf("ScreenSize = %i x %i x %i\n", ScreenSize.Width, ScreenSize.Height, ScreenBits); printf("MaxRTTSize = %i x %i\n", MaxRTTSize.Width, MaxRTTSize.Height); printf("MaxAA = %i\n", MaxAA); printf("MaxAF = %i\n", MaxAF); printf("HasNPOT = %s\n", HasNPOT?"true":"false"); printf("HasNSQR = %s\n", HasNSQR?"true":"false"); printf("HasRTT = %s\n", HasRTT?"true":"false"); printf("HasMTT = %s\n", HasMTT?"true":"false"); printf("HasMRT = %s\n", HasMRT?"true":"false"); printf("HasATC = %s\n", HasATC?"true":"false"); printf("HasBTF = %s\n", HasBTF?"true":"false"); printf("HasCMK = %s\n", HasCMK?"true":"false"); printf("HasMMP = %s\n", HasMMP?"true":"false"); printf("HasMMA = %s\n", HasMMA?"true":"false"); printf("HasOCC = %s\n", HasOCC?"true":"false"); printf("HasPOF = %s\n", HasPOF?"true":"false"); } s32 RTTWidth = ScreenSize.Width; // equals the actual rtt size before down scaling factor nSamples AA and writing to final Image s32 RTTHeight = ScreenSize.Height; // the render-target is always a texture (offscreen) or the framebuffer (onscreen) s32 RTTWidthNB = RTTWidth - 2*Border; // the border equals the overlapping during rendering due to material-thickness > 0 s32 RTTHeightNB = RTTHeight - 2*Border; // the area that gets written to unique places, while the border regions can overlapp ( same pos, but writing/adding different image-content ) // so the position increment for the final writing is always RTTWidthNB or RTTHeightNB const s32 ImageWidth = (s32)dst->getDimension().Width; // width of the final image const s32 ImageHeight = (s32)dst->getDimension().Height; // height of the final image const ECOLOR_FORMAT ImageFormat = dst->getColorFormat(); // color-format of the final image, i.e. ECF_A8R8G8B8, ECF_R8G8B8, ECF_R16 for heightmaps ( bilinear, anisotropic ) const s32 CountX = core::ceil32( (f32)ImageWidth / (f32)RTTWidthNB ); const s32 CountY = core::ceil32( (f32)ImageHeight / (f32)RTTHeightNB ); //! ------------------------------------------------------------------------------------------ //! start render loop //! ------------------------------------------------------------------------------------------ s32 IndexX = 0; s32 IndexY = 0; s32 dstX = -Border; s32 dstY = -Border; for ( IndexY = 0; IndexY < CountY; ++IndexY) { // reset row dstX = -Border; for ( IndexX = 0; IndexX < CountX; ++IndexX) { const f32 fLeft = Left + (Right - Left) * (f32)( IndexX * RTTWidthNB - Border )/(f32)ImageWidth; const f32 fRight = fLeft + (Right - Left) * (f32)RTTWidth / (f32)ImageWidth; const f32 fTop = Top - (Top - Bottom) * (f32)( IndexY * RTTHeightNB - Border )/(f32)ImageHeight; const f32 fBottom = fTop - (Top - Bottom) * (f32)RTTHeight / (f32)ImageHeight; const f32 fNear = Near; const f32 fFar = Far; //! ------------------------------------------------------------------------------------------ //! build and set current projection-matrix //! ------------------------------------------------------------------------------------------ core::matrix4 tmpProj = core::IdentityMatrix; if (IsOrthogonal) { tmpProj(0,0) = 2.f / (fRight - fLeft); tmpProj(1,1) = 2.f / (fTop - fBottom); tmpProj(2,2) = 1.f / (fFar - fNear); tmpProj(3,3) = 1.f; tmpProj(3,0) = (fLeft + fRight) / (fLeft - fRight); tmpProj(3,1) = (fTop + fBottom) / (fBottom - fTop); tmpProj(3,2) = fNear / (fNear - fFar); } else { tmpProj(0,0) = 2.f*fNear / (fRight - fLeft); tmpProj(1,1) = 2.f*fNear / (fTop - fBottom); tmpProj(2,0) = (fLeft + fRight) / (fLeft - fRight); tmpProj(2,1) = (fTop + fBottom) / (fBottom - fTop); tmpProj(2,2) = fFar / (fFar - fNear); tmpProj(2,3) = 1.f; tmpProj(3,2) = fNear*fFar / (fNear - fFar); tmpProj(3,3) = 0.f; } camera->setProjectionMatrix(tmpProj); //! ------------------------------------------------------------------------------------------ //! now render all to current render-target //! ------------------------------------------------------------------------------------------ driver->beginScene( true, true, clearColor ); // SColor(255,200,200,255) smgr->drawAll(); if (renderGUI) guienv->drawAll(); driver->endScene(); //! ------------------------------------------------------------------------------------------ //! write current render-target to final image //! ------------------------------------------------------------------------------------------ IImage* src = driver->createScreenShot( ImageFormat, ERT_FRAME_BUFFER); if (src) { s32 x2 = src->getDimension().Width; s32 y2 = src->getDimension().Height; blitImageToImage( dst, core::position2di(dstX, dstY), src, core::recti(Border, Border, x2-Border, y2-Border), debugLog ); src->drop(); } dstX += RTTWidthNB; } dstY += RTTHeightNB; } //! ------------------------------------------------------------------------------------------ //! reset camera's projection-matrix //! ------------------------------------------------------------------------------------------ camera->setProjectionMatrix( projMat, IsOrthogonal); return true; }