bool ETHScene::GenerateLightmaps(const int id) { if (!m_provider->IsRichLightingEnabled()) { return false; } // save current global scale and temporarily set it to 1 const ETHGlobalScaleManagerPtr& scaleManager = m_provider->GetGlobalScaleManager(); const float globalScale = scaleManager->GetScale(); scaleManager->SetScaleFactor(1.0f); const ETHSpriteEntity *pRender = (id >= 0) ? m_buckets.SeekEntity(id) : 0; const Vector2 v2Bucket = (pRender) ? ETHBucketManager::GetBucket(pRender->GetPositionXY(), GetBucketSize()) : Vector2(0,0); for (ETHBucketMap::iterator bucketIter = m_buckets.GetFirstBucket(); bucketIter != m_buckets.GetLastBucket(); ++bucketIter) { // if we're lighting only one entity and it is not in this bucket, skip it. // I know we could have used the find method to go directly to that bucket // but this function os not that critical to make the effort worth it. if (id >= 0) if (v2Bucket != bucketIter->first) continue; // iterate over all entities in this bucket ETHEntityList& entityList = bucketIter->second; ETHEntityList::const_iterator iEnd = entityList.end(); for (ETHEntityList::iterator iter = entityList.begin(); iter != iEnd; ++iter) { ETHRenderEntity* entity = (*iter); // if nID is valid, let's try to generate the lightmap for this one and only entity if (id >= 0) if (id != entity->GetID()) continue; Vector2 v2Size(1,1); Vector2 v2AbsoluteOrigin(0,0); if (entity->GetSprite()) { v2Size = entity->GetCurrentSize(); v2AbsoluteOrigin = entity->ComputeAbsoluteOrigin(v2Size); } // Place the current entity at the top-left corner to align // it to the render target const Vector3 oldPos = entity->GetPosition(); const Vector3 newPos = Vector3(v2AbsoluteOrigin.x, v2AbsoluteOrigin.y, 0); std::list<ETHLight> lights; // fill the light list for (ETHBucketMap::iterator lbucketIter = m_buckets.GetFirstBucket(); lbucketIter != m_buckets.GetLastBucket(); ++lbucketIter) { ETHEntityList& lEntityList = lbucketIter->second; ETHEntityList::const_iterator liEnd = lEntityList.end(); for (ETHEntityList::iterator liter = lEntityList.begin(); liter != liEnd; ++liter) { ETHRenderEntity* lightEntity = (*liter); if (lightEntity->IsStatic() && lightEntity->HasLightSource()) { lights.push_back( ETHEntityRenderingManager::BuildChildLight( *(lightEntity->GetLight()), newPos - oldPos + lightEntity->GetPosition(), lightEntity->GetScale())); } } } if (lights.size() > 0) { ETHLightmapGen((*iter), m_provider->GetShaderManager(), lights.begin(), lights.end(), m_buckets, oldPos, newPos, m_minSceneHeight, m_maxSceneHeight, m_sceneProps); } else { entity->ReleaseLightmap(); } entity->SetOrphanPosition(oldPos); lights.clear(); } } #if defined(_DEBUG) || defined(DEBUG) ETH_STREAM_DECL(ss) << GS_L("Lightmaps created... "); m_provider->Log(ss.str(), Platform::FileLogger::INFO); #endif // go back to the previous global scale scaleManager->SetScaleFactor(globalScale); return true; }
ETHLightmapGen::ETHLightmapGen( ETHRenderEntity* entity, boost::shared_ptr<ETHShaderManager> shaderManager, std::list<ETHLight>::iterator iBegin, std::list<ETHLight>::iterator iEnd, ETHBucketManager& buckets, const Vector3& oldPos, const Vector3& newPos, const float minHeight, const float maxHeight, const ETHSceneProperties &sceneProps) { entity->m_pLightmap.reset(); const SpritePtr& sprite = entity->m_pSprite; const ETHEntityProperties& props = entity->m_properties; if (!sprite || !props.staticEntity || !props.applyLight) { return; } const VideoPtr& video = entity->m_provider->GetVideo(); const Platform::FileLogger* logger = entity->m_provider->GetLogger(); if (video->Rendering()) { ETH_STREAM_DECL(ss) << GS_L("Entity ID #") << entity->GetID() << GS_L(": lightmaps can't be generated during application render."); logger->Log(ss.str(), Platform::FileLogger::ERROR); return; } const Vector2 v2Size = (sprite->GetNumRects() <= 1) ? sprite->GetBitmapSizeF() : sprite->GetRect().size; if (!(entity->m_pLightmap = video->CreateRenderTarget(static_cast<unsigned int>(v2Size.x), static_cast<unsigned int>(v2Size.y)))) { ETH_STREAM_DECL(ss) << GS_L("ETHRenderEntity::GenerateLightmap: coudn't create the render target."); logger->Log(ss.str(), Platform::FileLogger::ERROR); entity->m_pLightmap.reset(); return; } const bool zBuffer = video->GetZBuffer(); const bool zWrite = video->GetZWrite(); video->SetZBuffer(false); video->SetZWrite(false); // Paint it black video->SetRenderTarget(entity->m_pLightmap); if (!video->BeginTargetScene(gs2d::constant::BLACK, true)) { ETH_STREAM_DECL(ss) << GS_L("ETHRenderEntity::GenerateLightmap: coudn't render to target."); logger->Log(ss.str(), Platform::FileLogger::ERROR); entity->m_pLightmap.reset(); return; } video->EndTargetScene(); entity->m_controller->SetPos(newPos / Vector3(entity->GetScale(), 1)); Vector2 v2CamPos = video->GetCameraPos(); video->SetCameraPos(Vector2(0,0)); for (std::list<ETHLight>::iterator iter = iBegin; iter != iEnd; ++iter) { if (!iter->staticLight) continue; SpritePtr tempTarget; if (!(tempTarget = video->CreateRenderTarget(static_cast<unsigned int>(v2Size.x), static_cast<unsigned int>(v2Size.y)))) { ETH_STREAM_DECL(ss) << GS_L("ETHRenderEntity::GenerateLightmap: coudn't create temporary render target."); logger->Log(ss.str(), Platform::FileLogger::ERROR); entity->m_pLightmap.reset(); return; } if (!video->SetRenderTarget(tempTarget)) { ETH_STREAM_DECL(ss) << GS_L("ETHRenderEntity::GenerateLightmap: coudn't set render target."); logger->Log(ss.str(), Platform::FileLogger::ERROR); entity->m_pLightmap.reset(); return; } if (!video->BeginTargetScene(gs2d::constant::BLACK, true)) { ETH_STREAM_DECL(ss) << GS_L("ETHRenderEntity::GenerateLightmap: coudn't render to temporary target."); logger->Log(ss.str(), Platform::FileLogger::ERROR); entity->m_pLightmap.reset(); return; } // draw light const Vector2 tmpScale(entity->GetScale()); entity->SetScale(Vector2(1, 1)); iter->pos /= tmpScale.y; iter->range /= tmpScale.y; if (shaderManager->BeginLightPass(entity, &(*iter), video->GetScreenSizeF().y, 0.0f, sceneProps.lightIntensity, 0, true)) { entity->DrawLightPass(sceneProps.zAxisDirection, 0.0f, true); shaderManager->EndLightPass(); } // draw shadows if (entity->GetType() != ETHEntityProperties::ET_VERTICAL) { for (ETHBucketMap::iterator bucketIter = buckets.GetFirstBucket(); bucketIter != buckets.GetLastBucket(); ++bucketIter) { for (ETHEntityList::iterator entityIter = bucketIter->second.begin(); entityIter != bucketIter->second.end(); ++entityIter) { ETHRenderEntity* ent = (*entityIter); if (!ent->IsStatic()) continue; Vector3 oldPos2 = ent->GetPosition(); Vector3 newPos2 = oldPos2-(oldPos-newPos); ent->SetOrphanPosition(newPos2 / Vector3(ent->GetScale(), 1)); const Vector2 tmpScale(ent->GetScale()); ent->SetScale(Vector2(1, 1)); if (shaderManager->BeginShadowPass(ent, &(*iter), maxHeight, minHeight)) { ent->DrawShadow(maxHeight, minHeight, sceneProps, *iter, 0, true, true, entity->GetAngle(), entity->GetPosition()); shaderManager->EndShadowPass(); } ent->SetScale(tmpScale); ent->SetOrphanPosition(oldPos2); } } } video->EndTargetScene(); iter->pos *= tmpScale.y; iter->range *= tmpScale.y; entity->SetScale(tmpScale); // draw the shadowed light by adding it to the final lightmap video->SetRenderTarget(entity->m_pLightmap); video->BeginTargetScene(gs2d::constant::BLACK, false); const Video::ALPHA_MODE oldAM = video->GetAlphaMode(); video->SetAlphaMode(Video::AM_ADD); tempTarget->Draw(Vector2(0,0)); video->SetAlphaMode(oldAM); video->EndTargetScene(); } video->SetZBuffer(zBuffer); video->SetZWrite(zWrite); entity->m_pLightmap->GenerateBackup(); video->SetRenderTarget(SpritePtr()); video->SetCameraPos(v2CamPos); }