openclonk/src/game/C4GraphicsSystem.cpp

453 lines
14 KiB
C++
Raw Normal View History

2009-05-08 13:28:41 +00:00
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 1998-2000, 2004, 2008 Matthes Bender
* Copyright (c) 2001-2003, 2005-2009 Sven Eberhardt
* Copyright (c) 2001 Michael Käser
* Copyright (c) 2005-2006, 2008-2010 Günther Brammer
2009-05-08 13:28:41 +00:00
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
/* Operates viewports, message board and draws the game */
#include <C4Include.h>
#include <C4GraphicsSystem.h>
#include <C4Viewport.h>
#include <C4ViewportWindow.h>
2009-05-08 13:28:41 +00:00
#include <C4Application.h>
#include <C4Console.h>
#include <C4Random.h>
#include <C4FullScreen.h>
#include <C4Gui.h>
#include <C4LoaderScreen.h>
#include <C4Player.h>
#include <C4SoundSystem.h>
#include <C4MouseControl.h>
#include <C4GraphicsResource.h>
#include <C4Landscape.h>
#include <C4Network2.h>
#include <C4Game.h>
2009-06-12 23:09:32 +00:00
#include <C4PlayerList.h>
#include <C4GameObjects.h>
2009-05-08 13:28:41 +00:00
#include <StdPNG.h>
C4GraphicsSystem::C4GraphicsSystem()
{
2009-05-08 13:28:41 +00:00
Default();
}
2009-05-08 13:28:41 +00:00
C4GraphicsSystem::~C4GraphicsSystem()
{
2009-05-08 13:28:41 +00:00
Clear();
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::Init()
{
2009-05-08 13:28:41 +00:00
// Init video module
if (Config.Graphics.VideoModule)
Video.Init(FullScreen.pSurface);
2009-05-08 13:28:41 +00:00
// Success
return true;
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::Clear()
{
2009-05-08 13:28:41 +00:00
// Clear message board
MessageBoard.Clear();
// Clear upper board
UpperBoard.Clear();
// clear loader
if (pLoaderScreen) { delete pLoaderScreen; pLoaderScreen=NULL; }
// Close viewports
::Viewports.Clear();
2009-05-08 13:28:41 +00:00
// Clear video system
Video.Clear();
// No debug stuff
DeactivateDebugOutput();
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::StartDrawing()
{
2009-05-08 13:28:41 +00:00
// only if ddraw is ready
2011-10-03 14:30:18 +00:00
if (!pDraw) return false;
if (!pDraw->Active) return false;
2009-05-08 13:28:41 +00:00
// only if application is active or windowed (if config allows)
2010-09-28 18:16:33 +00:00
if (!Application.Active && (!Application.isEditor || !Config.Graphics.RenderInactiveEM)) return false;
2009-05-08 13:28:41 +00:00
// drawing OK
return true;
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::FinishDrawing()
{
2010-09-28 18:16:33 +00:00
if (!Application.isEditor) FullScreen.pSurface->PageFlip();
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::Execute()
{
2009-05-08 13:28:41 +00:00
// activity check
if (!StartDrawing()) return;
bool fBGDrawn = false;
// If lobby running, message board only (page flip done by startup message board)
if (!::pGUI->HasFullscreenDialog(true)) // allow for message board behind GUI
if (::Network.isLobbyActive() || !Game.IsRunning)
2010-09-28 18:16:33 +00:00
if (!Application.isEditor)
{
2009-05-08 13:28:41 +00:00
// Message board
if (iRedrawBackground) ClearFullscreenBackground();
MessageBoard.Execute();
if (!C4GUI::IsActive())
2009-05-08 13:28:41 +00:00
{ FinishDrawing(); return; }
fBGDrawn = true;
}
2009-05-08 13:28:41 +00:00
// fullscreen GUI?
if (!Application.isEditor && C4GUI::IsActive() && (::pGUI->HasFullscreenDialog(false) || !Game.IsRunning))
{
2009-05-08 13:28:41 +00:00
if (!fBGDrawn && iRedrawBackground) ClearFullscreenBackground();
2009-06-05 16:53:56 +00:00
::pGUI->Render(!fBGDrawn);
2009-05-08 13:28:41 +00:00
FinishDrawing();
return;
}
2009-05-08 13:28:41 +00:00
2009-05-08 13:28:41 +00:00
// Reset object audibility
::Objects.ResetAudibility();
2009-05-08 13:28:41 +00:00
// some hack to ensure the mouse is drawn after a dialog close and before any
// movement messages
if (!C4GUI::IsActive())
::pGUI->SetMouseInGUI(false, false);
2009-05-08 13:28:41 +00:00
// Viewports
::Viewports.Execute(!Application.isEditor && iRedrawBackground);
if (iRedrawBackground) --iRedrawBackground;
2009-05-08 13:28:41 +00:00
2010-09-28 18:16:33 +00:00
if (!Application.isEditor)
{
2009-05-08 13:28:41 +00:00
// Upper board
UpperBoard.Execute();
// Message board
MessageBoard.Execute();
// Help & Messages
DrawHelp();
DrawHoldMessages();
DrawFlashMessage();
}
2009-05-08 13:28:41 +00:00
// InGame-GUI
if (C4GUI::IsActive())
{
2009-06-05 16:53:56 +00:00
::pGUI->Render(false);
}
2009-05-08 13:28:41 +00:00
// gamma update
2011-10-03 14:30:18 +00:00
pDraw->ApplyGamma();
2009-05-08 13:28:41 +00:00
// Video record & status (fullsrceen)
2010-09-28 18:16:33 +00:00
if (!Application.isEditor)
2009-05-08 13:28:41 +00:00
Video.Execute();
// done
FinishDrawing();
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::Default()
{
2009-05-08 13:28:41 +00:00
UpperBoard.Default();
MessageBoard.Default();
InvalidateBg();
ShowVertices=false;
ShowAction=false;
ShowCommand=false;
ShowEntrance=false;
ShowPathfinder=false;
ShowNetstatus=false;
ShowSolidMask=false;
ShowHelp=false;
2009-05-08 13:28:41 +00:00
FlashMessageText[0]=0;
FlashMessageTime=0; FlashMessageX=FlashMessageY=0;
Video.Default();
pLoaderScreen=NULL;
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::ClearFullscreenBackground()
{
2011-10-03 14:30:18 +00:00
pDraw->FillBG(0);
2009-05-08 13:28:41 +00:00
--iRedrawBackground;
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::InitLoaderScreen(const char *szLoaderSpec, bool fDrawBlackScreenFirst)
{
2009-05-08 13:28:41 +00:00
// create new loader; overwrite current only if successful
C4LoaderScreen *pNewLoader = new C4LoaderScreen();
pNewLoader->SetBlackScreen(fDrawBlackScreenFirst);
if (!pNewLoader->Init(szLoaderSpec)) { delete pNewLoader; return false; }
2009-05-08 13:28:41 +00:00
if (pLoaderScreen) delete pLoaderScreen;
pLoaderScreen = pNewLoader;
// apply user gamma for loader
2011-10-03 14:30:18 +00:00
pDraw->ApplyGamma();
2009-05-08 13:28:41 +00:00
// done, success
return true;
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::EnableLoaderDrawing()
{
2009-05-08 13:28:41 +00:00
// reset black screen loader flag
if (pLoaderScreen) pLoaderScreen->SetBlackScreen(false);
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::SaveScreenshot(bool fSaveAll)
{
2009-05-08 13:28:41 +00:00
// Filename
char szFilename[_MAX_PATH+1];
int32_t iScreenshotIndex=1;
const char *strFilePath = NULL;
do
sprintf(szFilename,"Screenshot%03i.png",iScreenshotIndex++);
while (FileExists(strFilePath = Config.AtScreenshotPath(szFilename)));
bool fSuccess=DoSaveScreenshot(fSaveAll, strFilePath);
2009-05-08 13:28:41 +00:00
// log if successful/where it has been stored
if (!fSuccess)
2009-05-11 13:09:53 +00:00
LogF(LoadResStr("IDS_PRC_SCREENSHOTERROR"), Config.AtUserDataRelativePath(Config.AtScreenshotPath(szFilename)));
2009-05-08 13:28:41 +00:00
else
2009-05-11 13:09:53 +00:00
LogF(LoadResStr("IDS_PRC_SCREENSHOT"), Config.AtUserDataRelativePath(Config.AtScreenshotPath(szFilename)));
2009-05-08 13:28:41 +00:00
// return success
return !!fSuccess;
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::DoSaveScreenshot(bool fSaveAll, const char *szFilename)
{
2009-05-08 13:28:41 +00:00
// Fullscreen only
2010-09-28 18:16:33 +00:00
if (Application.isEditor) return false;
2009-05-08 13:28:41 +00:00
// back surface must be present
if (!FullScreen.pSurface) return false;
2009-05-08 13:28:41 +00:00
// save landscape
if (fSaveAll)
{
2009-05-08 13:28:41 +00:00
// get viewport to draw in
C4Viewport *pVP=::Viewports.GetFirstViewport(); if (!pVP) return false;
2009-05-08 13:28:41 +00:00
// create image large enough to hold the landcape
CPNGFile png; int32_t lWdt=GBackWdt,lHgt=GBackHgt;
if (!png.Create(lWdt, lHgt, false)) return false;
2009-05-08 13:28:41 +00:00
// get backbuffer size
int32_t bkWdt=C4GUI::GetScreenWdt(), bkHgt=C4GUI::GetScreenHgt();
if (!bkWdt || !bkHgt) return false;
2009-05-08 13:28:41 +00:00
// facet for blitting
C4TargetFacet bkFct;
// mark background to be redrawn
InvalidateBg();
// backup and clear sky parallaxity
2009-06-05 15:20:41 +00:00
int32_t iParX=::Landscape.Sky.ParX; ::Landscape.Sky.ParX=10;
int32_t iParY=::Landscape.Sky.ParY; ::Landscape.Sky.ParY=10;
2009-05-08 13:28:41 +00:00
// temporarily change viewport player
int32_t iVpPlr=pVP->Player; pVP->Player=NO_OWNER;
// blit all tiles needed
for (int32_t iY=0; iY<lHgt; iY+=bkHgt) for (int32_t iX=0; iX<lWdt; iX+=bkWdt)
{
// get max width/height
int32_t bkWdt2=bkWdt,bkHgt2=bkHgt;
if (iX+bkWdt2>lWdt) bkWdt2-=iX+bkWdt2-lWdt;
if (iY+bkHgt2>lHgt) bkHgt2-=iY+bkHgt2-lHgt;
// update facet
bkFct.Set(FullScreen.pSurface, 0, 0, bkWdt2, bkHgt2, iX, iY);
// draw there
pVP->Draw(bkFct, false);
// render
FullScreen.pSurface->PageFlip(); FullScreen.pSurface->PageFlip();
// get output (locking primary!)
if (FullScreen.pSurface->Lock())
2009-05-08 13:28:41 +00:00
{
// transfer each pixel - slooow...
for (int32_t iY2=0; iY2<bkHgt2; ++iY2)
for (int32_t iX2=0; iX2<bkWdt2; ++iX2)
2011-10-03 14:30:18 +00:00
png.SetPix(iX+iX2, iY+iY2, pDraw->ApplyGammaTo(FullScreen.pSurface->GetPixDw(iX2, iY2, false)));
// done; unlock
FullScreen.pSurface->Unlock();
2009-05-08 13:28:41 +00:00
}
}
// restore viewport player
pVP->Player=iVpPlr;
// restore parallaxity
2009-06-05 15:20:41 +00:00
::Landscape.Sky.ParX=iParX;
::Landscape.Sky.ParY=iParY;
2009-05-08 13:28:41 +00:00
// save!
return png.Save(szFilename);
}
2009-05-08 13:28:41 +00:00
// Save primary surface
return FullScreen.pSurface->SavePNG(szFilename, false, true, false);
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::DeactivateDebugOutput()
{
ShowVertices=false;
ShowAction=false;
ShowCommand=false;
ShowEntrance=false;
ShowPathfinder=false; // allow pathfinder! - why this??
ShowSolidMask=false;
ShowNetstatus=false;
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::DrawHoldMessages()
{
2010-09-28 18:16:33 +00:00
if (!Application.isEditor && Game.HaltCount)
{
2011-10-03 14:30:18 +00:00
pDraw->TextOut("Pause", ::GraphicsResource.FontRegular,1.0,
FullScreen.pSurface, C4GUI::GetScreenWdt()/2,
C4GUI::GetScreenHgt()/2 - ::GraphicsResource.FontRegular.iLineHgt*2,
2011-10-03 14:34:08 +00:00
C4Draw::DEFAULT_MESSAGE_COLOR, ACenter);
::GraphicsSystem.OverwriteBg();
2009-05-08 13:28:41 +00:00
}
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::FlashMessage(const char *szMessage)
{
2009-05-08 13:28:41 +00:00
// Store message
SCopy(szMessage, FlashMessageText, C4MaxTitle);
// Calculate message time
FlashMessageTime = SLen(FlashMessageText) * 2;
// Initial position
FlashMessageX = -1;
FlashMessageY = 10;
// Upper board active: stay below upper board
if (Config.Graphics.UpperBoard)
FlashMessageY += C4UpperBoardHeight;
// More than one viewport: try to stay below portraits etc.
if (::Viewports.GetViewportCount() > 1)
2009-05-08 13:28:41 +00:00
FlashMessageY += 64;
// New flash message: redraw background (might be drawing one message on top of another)
InvalidateBg();
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::FlashMessageOnOff(const char *strWhat, bool fOn)
{
2009-05-08 13:28:41 +00:00
StdStrBuf strMessage;
strMessage.Format("%s: %s", strWhat, LoadResStr(fOn ? "IDS_CTL_ON" : "IDS_CTL_OFF"));
FlashMessage(strMessage.getData());
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::DrawFlashMessage()
{
2009-05-08 13:28:41 +00:00
if (!FlashMessageTime) return;
2010-09-28 18:16:33 +00:00
if (Application.isEditor) return;
2011-10-03 14:30:18 +00:00
pDraw->TextOut(FlashMessageText, ::GraphicsResource.FontRegular, 1.0, FullScreen.pSurface,
(FlashMessageX==-1) ? C4GUI::GetScreenWdt()/2 : FlashMessageX,
(FlashMessageY==-1) ? C4GUI::GetScreenHgt()/2 : FlashMessageY,
2011-10-03 14:34:08 +00:00
C4Draw::DEFAULT_MESSAGE_COLOR,
(FlashMessageX==-1) ? ACenter : ALeft);
2009-05-08 13:28:41 +00:00
FlashMessageTime--;
// Flash message timed out: redraw background
if (!FlashMessageTime) InvalidateBg();
}
2009-05-08 13:28:41 +00:00
void C4GraphicsSystem::DrawHelp()
{
2009-05-08 13:28:41 +00:00
if (!ShowHelp) return;
2010-09-28 18:16:33 +00:00
if (Application.isEditor) return;
int32_t iX = ::Viewports.ViewportArea.X, iY = ::Viewports.ViewportArea.Y;
int32_t iWdt = ::Viewports.ViewportArea.Wdt;
2009-05-08 13:28:41 +00:00
StdStrBuf strText;
// left coloumn
strText.AppendFormat("[%s]\n\n", LoadResStr("IDS_CTL_GAMEFUNCTIONS"));
// main functions
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("ToggleShowHelp").getData(), LoadResStr("IDS_CON_HELP"));
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("MusicToggle").getData(), LoadResStr("IDS_CTL_MUSIC"));
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("NetClientListDlgToggle").getData(), LoadResStr("IDS_DLG_NETWORK"));
// messages
StdCopyStrBuf strAltChatKey(GetKeyboardInputName("ChatOpen", false, 0));
strText.AppendFormat("\n<c ffff00>%s/%s</c> - %s\n", GetKeyboardInputName("ChatOpen", false, 1).getData(), strAltChatKey.getData(), LoadResStr("IDS_CTL_SENDMESSAGE"));
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("MsgBoardScrollUp").getData(), LoadResStr("IDS_CTL_MESSAGEBOARDBACK"));
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("MsgBoardScrollDown").getData(), LoadResStr("IDS_CTL_MESSAGEBOARDFORWARD"));
// irc chat
strText.AppendFormat("\n<c ffff00>%s</c> - %s\n", GetKeyboardInputName("ToggleChat").getData(), LoadResStr("IDS_CTL_IRCCHAT"));
// scoreboard
strText.AppendFormat("\n<c ffff00>%s</c> - %s\n", GetKeyboardInputName("ScoreboardToggle").getData(), LoadResStr("IDS_CTL_SCOREBOARD"));
// screenshots
strText.AppendFormat("\n<c ffff00>%s</c> - %s\n", GetKeyboardInputName("Screenshot").getData(), LoadResStr("IDS_CTL_SCREENSHOT"));
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("ScreenshotEx").getData(), LoadResStr("IDS_CTL_SCREENSHOTEX"));
2011-10-03 14:30:18 +00:00
pDraw->TextOut(strText.getData(), ::GraphicsResource.FontRegular, 1.0, FullScreen.pSurface,
2011-10-03 14:34:08 +00:00
iX + 128, iY + 64, C4Draw::DEFAULT_MESSAGE_COLOR, ALeft);
2009-05-08 13:28:41 +00:00
// right coloumn
strText.Clear();
// game speed
strText.AppendFormat("\n\n<c ffff00>%s</c> - %s\n", GetKeyboardInputName("GameSpeedUp").getData(), LoadResStr("IDS_CTL_GAMESPEEDUP"));
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("GameSlowDown").getData(), LoadResStr("IDS_CTL_GAMESPEEDDOWN"));
// debug
strText.AppendFormat("\n\n[%s]\n\n", "Debug");
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("DbgModeToggle").getData(), LoadResStr("IDS_CTL_DEBUGMODE"));
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("DbgShowVtxToggle").getData(), "Entrance+Vertices");
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("DbgShowActionToggle").getData(), "Actions/Commands/Pathfinder");
strText.AppendFormat("<c ffff00>%s</c> - %s\n", GetKeyboardInputName("DbgShowSolidMaskToggle").getData(), "SolidMasks");
2011-10-03 14:30:18 +00:00
pDraw->TextOut(strText.getData(), ::GraphicsResource.FontRegular, 1.0, FullScreen.pSurface,
2011-10-03 14:34:08 +00:00
iX + iWdt/2 + 64, iY + 64, C4Draw::DEFAULT_MESSAGE_COLOR, ALeft);
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::ToggleShowNetStatus()
{
2009-05-08 13:28:41 +00:00
ShowNetstatus = !ShowNetstatus;
return true;
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::ToggleShowVertices()
{
2009-05-08 13:28:41 +00:00
if (!Game.DebugMode && !Console.Active) { FlashMessage(LoadResStr("IDS_MSG_NODEBUGMODE")); return false; }
Toggle(ShowVertices);
Toggle(ShowEntrance); // vertices and entrance now toggled together
FlashMessageOnOff("Entrance+Vertices", ShowVertices || ShowEntrance);
return true;
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::ToggleShowAction()
{
2009-05-08 13:28:41 +00:00
if (!Game.DebugMode && !Console.Active) { FlashMessage(LoadResStr("IDS_MSG_NODEBUGMODE")); return false; }
if (!(ShowAction || ShowCommand || ShowPathfinder))
{ ShowAction = true; FlashMessage("Actions"); }
2009-05-08 13:28:41 +00:00
else if (ShowAction)
{ ShowAction = false; ShowCommand = true; FlashMessage("Commands"); }
2009-05-08 13:28:41 +00:00
else if (ShowCommand)
{ ShowCommand = false; ShowPathfinder = true; FlashMessage("Pathfinder"); }
2009-05-08 13:28:41 +00:00
else if (ShowPathfinder)
{ ShowPathfinder = false; FlashMessageOnOff("Actions/Commands/Pathfinder", false); }
2009-05-08 13:28:41 +00:00
return true;
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::ToggleShowSolidMask()
{
2009-05-08 13:28:41 +00:00
if (!Game.DebugMode && !Console.Active) { FlashMessage(LoadResStr("IDS_MSG_NODEBUGMODE")); return false; }
Toggle(ShowSolidMask);
FlashMessageOnOff("SolidMasks", !!ShowSolidMask);
return true;
}
2009-05-08 13:28:41 +00:00
bool C4GraphicsSystem::ToggleShowHelp()
{
2009-05-08 13:28:41 +00:00
Toggle(ShowHelp);
// Turned off? Invalidate background.
if (!ShowHelp) InvalidateBg();
return true;
}
2009-05-08 13:28:41 +00:00
C4GraphicsSystem GraphicsSystem;