// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "progress.h" #include "time_client.h" #include "global.h" #include "nel/misc/events.h" #include "nel/3d/u_texture.h" #include "game_share/ryzom_version.h" #include "nel/misc/i18n.h" #include "continent.h" #include "weather.h" #include "weather_manager_client.h" #include "interface_v3/input_handler_manager.h" #include "interface_v3/interface_manager.h" #include "release.h" #include "net_manager.h" #include "client_cfg.h" #include "bg_downloader_access.h" #include "nel/misc/system_utils.h" #include "nel/3d/stereo_hmd.h" using namespace std; using namespace NLMISC; using namespace NL3D; extern void selectTipsOfTheDay (uint tips); extern NL3D::UMaterial LoadingMaterial; extern NL3D::UMaterial LoadingMaterialFull; extern std::vector LogoBitmaps; extern uint TipsOfTheDayIndex; extern ucstring TipsOfTheDay; extern bool UseEscapeDuringLoading; CProgress::CProgress () { _LastUpdate = ryzomGetLocalTime (); _FontFactor = 1.0f; pushCropedValues (0, 1); ApplyTextCommands = false; _TPCancelFlag = false; } CProgress::~CProgress () { } void CProgress::setFontFactor(float temp) { _FontFactor = temp; } void CProgress::newMessage (const ucstring& message) { popCropedValues (); _CurrentRootStep++; pushCropedValues ((float)_CurrentRootStep/(float)_RootStepCount, (float)(_CurrentRootStep+1)/(float)_RootStepCount); // New message _ProgressMessage = message; // Force call to progress internalProgress (0); } void CProgress::reset (uint rootNodeCount) { _CurrentRootStep = 0; _RootStepCount = rootNodeCount; popCropedValues (); pushCropedValues (0, 1/(float)_RootStepCount); ApplyTextCommands = false; finish(); } void CProgress::progress (float value) { // Timer sint64 newTime = ryzomGetLocalTime (); if (newTime - _LastUpdate > PROGRESS_BAR_UPDATE) { internalProgress (value); _LastUpdate = newTime; } } float nextLine (uint fontHeight, uint windowHeight, float previousY) { if (windowHeight > 0) { return previousY-(float)fontHeight/(float)windowHeight; } return previousY; } void drawLoadingBitmap (float progress) { if (!LoadingMaterial.empty() && !LoadingMaterialFull.empty()) { Driver->setMatrixMode2D11(); LoadingMaterialFull.setAlphaTestThreshold (1.f-progress); CQuadUV quad; uint wh = Driver->getWindowHeight(); uint ww = Driver->getWindowWidth(); float x1 = 0; float y1 = 0; float x2 = 1; float y2 = 1; if ((ww > 1024) || (wh > 768)) { if ((ww - 1024) > (wh - 768)) x1 = ((ww - (wh * 1024.f) / 768.f) / 2.f) / ww; else y1 = ((wh - (ww * 768.f) / 1024.f) / 2.f) / wh; } if (x1 != 0) x2 = 1 - x1; if (y1 != 0) y2 = 1 - y1; quad.V0.set (x1,y1,0); quad.V1.set (x2,y1,0); quad.V2.set (x2,y2,0); quad.V3.set (x1,y2,0); quad.Uv0.U= 0; quad.Uv0.V= 0.75f; quad.Uv1.U= 1; quad.Uv1.V= 0.75f; quad.Uv2.U= 1; quad.Uv2.V= 0; quad.Uv3.U= 0; quad.Uv3.V= 0; Driver->drawQuad(0, 0, 1, 1, CRGBA(0, 0, 0, 255)); Driver->drawQuad(quad, LoadingMaterial); Driver->drawQuad(quad, LoadingMaterialFull); } } void CProgress::internalProgress (float value) { // Get croped value value = getCropedValue (value); // can't do anything if no driver if (Driver == NULL) return; if (Driver->AsyncListener.isKeyPushed (KeyDOWN)) selectTipsOfTheDay (TipsOfTheDayIndex-1); if (Driver->AsyncListener.isKeyPushed (KeyUP)) selectTipsOfTheDay (TipsOfTheDayIndex+1); // Create camera for stereo mode bool stereoHMD = StereoHMD && !MainCam.empty() && (MainCam.getTransformMode() == UCamera::RotQuat); CVector oldPos; CQuat oldQuat; if (stereoHMD) { MainCam.getPos(oldPos); MainCam.getRotQuat(oldQuat); StereoHMD->setInterfaceMatrix(CMatrix()); // identity NLMISC::CQuat hmdOrient = StereoHMD->getOrientation(); NLMISC::CMatrix camMatrix; camMatrix.identity(); NLMISC::CMatrix hmdMatrix; hmdMatrix.setRot(hmdOrient); NLMISC::CMatrix posMatrix; // minimal head modeling, will be changed in the future posMatrix.translate(StereoHMD->getEyePosition()); NLMISC::CMatrix mat = ((camMatrix * hmdMatrix) * posMatrix); MainCam.setPos(mat.getPos()); MainCam.setRotQuat(mat.getRot()); StereoDisplay->updateCamera(0, &MainCam); } uint i = 0; while ((!stereoHMD && i == 0) || (stereoHMD && StereoDisplay->nextPass())) { ++i; if (stereoHMD) { // modify cameras for stereo display const CViewport &vp = StereoDisplay->getCurrentViewport(); Driver->setViewport(vp); StereoDisplay->getCurrentMatrix(0, &MainCam); StereoDisplay->getCurrentFrustum(0, &MainCam); // begin current pass StereoDisplay->beginRenderTarget(); nldebug("Cam pos: %f, %f, %f", MainCam.getPos().x, MainCam.getPos().y, MainCam.getPos().z); } if (!stereoHMD || StereoDisplay->wantClear()) { Driver->clearBuffers(CRGBA(0, 0, 0, 0)); } if (stereoHMD && StereoDisplay->wantScene()) { Driver->setMatrixMode3D(MainCam); } if (!stereoHMD || StereoDisplay->wantInterface2D()) { nldebug("Draw progress 2D"); // Font factor float fontFactor = 1; if (Driver->getWindowHeight() > 0) fontFactor = (float)Driver->getWindowHeight() / 600.f; fontFactor *= _FontFactor; // Set 2d view. Driver->setMatrixMode2D11(); // Display the loading background. drawLoadingBitmap(value); // temporary values for conversions float x, y, width, height; for(uint i = 0; i < ClientCfg.Logos.size(); i++) { std::vector res; explode(ClientCfg.Logos[i], std::string(":"), res); if(res.size()==9 && idrawBitmap(x/(float)ClientCfg.Width, y/(float)ClientCfg.Height, width/(float)ClientCfg.Width, height/(float)ClientCfg.Height, *LogoBitmaps[i]); } } if (TextContext != NULL) { // Init the Pen. TextContext->setKeep800x600Ratio(false); TextContext->setColor(CRGBA(255,255,255)); TextContext->setFontSize((uint)(12.f * fontFactor)); TextContext->setHotSpot(UTextContext::TopRight); #if !FINAL_VERSION // Display the Text. TextContext->printAt(1, 0.98f, _ProgressMessage); #else if( ClientCfg.LoadingStringCount > 0 ) { TextContext->printAt(1, 0.98f, _ProgressMessage); } #endif // FINAL_VERSION // Display the build version. TextContext->setFontSize((uint)(12.f * fontFactor)); TextContext->setHotSpot(UTextContext::TopRight); string str; #if FINAL_VERSION str = "FV "; #else str = "DEV "; #endif str += RYZOM_VERSION; TextContext->printfAt(1.0f,1.0f, str.c_str()); // Display the tips of the day. TextContext->setFontSize((uint)(16.f * fontFactor)); TextContext->setHotSpot(UTextContext::MiddleTop); ucstring::size_type index = 0; ucstring::size_type end = TipsOfTheDay.find((ucchar)'\n'); if (end == string::npos) end = TipsOfTheDay.size(); float fY = ClientCfg.TipsY; if (!TipsOfTheDay.empty()) { while (index < end) { // Get the line ucstring line = TipsOfTheDay.substr (index, end-index); // Draw the line TextContext->printAt(0.5f, fY, line); fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); index=end+1; end = TipsOfTheDay.find((ucchar)'\n', index); if (end == ucstring::npos) end = TipsOfTheDay.size(); } // More help TextContext->setFontSize((uint)(12.f * fontFactor)); /* todo tips of the day uncomment ucstring ucstr = CI18N::get ("uiTipsEnd"); TextContext->printAt(0.5f, fY, ucstr); */ fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); fY = nextLine (TextContext->getFontSize(), Driver->getWindowHeight(), fY); } if (!_TPReason.empty()) { TextContext->setHotSpot(UTextContext::MiddleMiddle); TextContext->setFontSize((uint)(14.f * fontFactor)); TextContext->printAt(0.5f, 0.5f, _TPReason); TextContext->setHotSpot(UTextContext::BottomLeft); TextContext->setColor(NLMISC::CRGBA::White); } if (!_TPCancelText.empty()) { if (ClientCfg.Width != 0 && ClientCfg.Height != 0) { TextContext->setFontSize((uint)(15.f * fontFactor)); TextContext->setHotSpot(UTextContext::BottomLeft); ucstring uc = CI18N::get("uiR2EDTPEscapeToInteruptLoading") + " (" + _TPCancelText + ") - " + CI18N::get("uiDelayedTPCancel"); UTextContext::CStringInfo info = TextContext->getStringInfo(uc); float stringX = 0.5f - info.StringWidth/(ClientCfg.Width*2); TextContext->printAt(stringX, 7.f / ClientCfg.Height, uc); } } // Teleport help //fY = ClientCfg.TeleportInfoY; if (!ApplyTextCommands && LoadingContinent && !LoadingContinent->Indoor) { TextContext->setFontSize((uint)(13.f * fontFactor)); // Print some more info uint32 day = RT.getRyzomDay(); str = toString (CI18N::get ("uiTipsTeleport").toUtf8().c_str(), CI18N::get (LoadingContinent->LocalizedName).toUtf8().c_str(), day, (uint)RT.getRyzomTime(), CI18N::get ("uiSeason"+toStringEnum(CRyzomTime::getSeasonByDay(day))).toUtf8().c_str(), CI18N::get (WeatherManager.getCurrWeatherState().LocalizedName).toUtf8().c_str()); ucstring ucstr; ucstr.fromUtf8 (str); TextContext->setHotSpot(UTextContext::MiddleBottom); TextContext->setColor(CRGBA(186, 179, 163, 255)); TextContext->printAt(0.5f, 25/768.f, ucstr); } // apply text commands if( ApplyTextCommands ) { std::vector printfCommands = ClientCfg.PrintfCommands; if(FreeTrial) printfCommands = ClientCfg.PrintfCommandsFreeTrial; if( !printfCommands.empty() ) { TextContext->setHotSpot(UTextContext::MiddleBottom); vector::iterator itpc; for( itpc = printfCommands.begin(); itpc != printfCommands.end(); ++itpc ) { float x = 0.5f;//((*itpc).X / 1024.f); float y = ((*itpc).Y / 768.f); TextContext->setColor( (*itpc).Color ); TextContext->setFontSize( (uint)(16.f * fontFactor)); // build the ucstr(s) ucstring ucstr = CI18N::get((*itpc).Text); vector vucstr; ucstring sep("\n"); splitUCString(ucstr,sep,vucstr); // Letter size UTextContext::CStringInfo si = TextContext->getStringInfo(ucstring("|")); uint fontHeight = (uint) si.StringHeight + 2; // we add 2 pixels for the gap uint i; float newy = y; for( i=0; iprintAt(x,newy, vucstr[i]); newy = nextLine(fontHeight, Driver->getWindowHeight(), newy); } } } } } } if (stereoHMD) { StereoDisplay->endRenderTarget(); } } /* stereo loop */ if (stereoHMD) { MainCam.setPos(oldPos); MainCam.setRotQuat(oldQuat); } // Clamp clamp (value, 0.f, 1.f); // Set matrix Driver->setMatrixMode2D11 (); // want to receive the 'mouse down' event to deal with the 'cancel tp button' Driver->EventServer.addListener(EventMouseDownId, this); // Update messages CInputHandlerManager::getInstance()->pumpEventsNoIM(); Driver->EventServer.removeListener(EventMouseDownId, this); // Exit ? bool activeDriver = Driver->isActive(); if ((UseEscapeDuringLoading && Driver->AsyncListener.isKeyPushed (KeyESCAPE)) || !activeDriver) { // Release the application releaseMainLoop(true); release(); // Leave the application extern void quitCrashReport (); quitCrashReport (); exit(EXIT_SUCCESS); } if(!_TPCancelText.empty() && Driver->AsyncListener.isKeyPushed(KeySHIFT) && Driver->AsyncListener.isKeyPushed(KeyESCAPE)) { _TPCancelFlag = true; } CBGDownloaderAccess::getInstance().update(); // Display to screen. Driver->swapBuffers(); // \todo GUIGUI : Remove this when possible. NetMngr.update(); IngameDbMngr.flushObserverCalls(); NLGUI::CDBManager::getInstance()->flushObserverCalls(); // update system dependent progress bar static uint previousValue = 0; uint currentValue = (uint)(value*100.0f); if (currentValue != previousValue) { CSystemUtils::updateProgressBar(currentValue, 100); previousValue = currentValue; } } void CProgress::setTPMessages(const ucstring &tpReason,const ucstring &tpCancelText, const std::string &/* iconName */) { _TPReason = tpReason; _TPCancelText = tpCancelText; } void CProgress::operator ()(const CEvent& /* event */) { } bool CProgress::getTPCancelFlag(bool clearFlag /*=true*/) { bool flag = _TPCancelFlag; if (clearFlag) { _TPCancelFlag = false; } return flag; } void CProgress::release() { setTPMessages(ucstring(), ucstring(), ""); _TPCancelFlag = false; } void CProgress::finish() { // stop system dependent progress bar CSystemUtils::updateProgressBar(1, 0); }