Переглянути джерело

Better implementation of the framerate manager, FPS timer added, minor improvements

beegee1 14 роки тому
батько
коміт
157002fe68

+ 8 - 0
client/CCursorHandler.cpp

@@ -183,6 +183,14 @@ void CCursorHandler::shiftPos( int &x, int &y )
 	}
 }
 
+void CCursorHandler::centerCursor()
+{
+	SDL_Surface *cursor = this->cursors[mode]->ourImages[number].bitmap;
+	this->xpos = (screen->w / 2.) - (cursor->w / 2.);
+	this->ypos = (screen->h / 2.) - (cursor->h / 2.);
+	SDL_WarpMouse(this->xpos, this->ypos);
+}
+
 CCursorHandler::~CCursorHandler()
 {
 	if(help)

+ 3 - 2
client/CCursorHandler.h

@@ -35,8 +35,9 @@ public:
 
 	void shiftPos( int &x, int &y );
 	void draw2();
-	void hide(){Show=0;};
-	void show(){Show=1;};
+	void hide() { Show=0; };
+	void show() { Show=1; };
+	void centerCursor();
 	~CCursorHandler();
 };
 

+ 1 - 1
client/CMT.cpp

@@ -266,7 +266,7 @@ int main(int argc, char** argv)
 		playIntro();
 
 	SDL_FillRect(screen,NULL,0);
-	SDL_Flip(screen);
+	CSDL_Ext::update(screen);
 	loading.join();
 	tlog0<<"Initialization of VCMI (together): "<<total.getDif()<<std::endl;
 

+ 2 - 11
client/CPlayerInterface.cpp

@@ -105,8 +105,6 @@ CPlayerInterface::CPlayerInterface(int Player)
 	makingTurn = false;
 	showingDialog = new CondSh<bool>(false);
 	sysOpts = GDefaultOptions;
-	//initializing framerate keeper
-	//framerate keeper initialized
 	cingconsole = new CInGameConsole;
 	terminate_cond.set(false);
 	firstCall = 1; //if loading will be overwritten in serialize
@@ -283,7 +281,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
 	initMovement(details, ho, hp);
 
 	//first initializing done
-	SDL_framerateDelay(GH.mainFPSmng); // after first move
+	GH.mainFPSmng->framerateDelay(); // after first move
 
 	//main moving
 	for(int i=1; i<32; i+=2*sysOpts.heroMoveSpeed)
@@ -292,7 +290,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
 		adventureInt->updateScreen = true;
 		adventureInt->show(screen);
 		CSDL_Ext::update(screen);
-		SDL_framerateDelay(GH.mainFPSmng); //for animation purposes
+		GH.mainFPSmng->framerateDelay(); //for animation purposes
 	} //for(int i=1; i<32; i+=4)
 	//main moving done
 
@@ -1330,18 +1328,11 @@ void CPlayerInterface::update()
 	if(adventureInt && !adventureInt->selection && GH.topInt() == adventureInt)
 		return;
 
-	GH.updateTime();
-	GH.handleEvents();
-
 	if(adventureInt && !adventureInt->isActive() && adventureInt->scrollingDir) //player forces map scrolling though interface is disabled
 		GH.totalRedraw();
 	else
 		GH.simpleRedraw();
 
-	CCS->curh->draw1();
-	CSDL_Ext::update(screen);
-	CCS->curh->draw2();
-
 	pim->unlock();
 }
 

+ 0 - 5
client/CPreGame.cpp

@@ -351,12 +351,7 @@ void CGPreGame::update()
 	if(SEL)
 		SEL->update();
 
-	CCS->curh->draw1();
-	SDL_Flip(screen);
-	CCS->curh->draw2();
 	GH.topInt()->show(screen);
-	GH.updateTime();
-	GH.handleEvents();
 }
 
 CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMultiMode MultiPlayer /*= CMenuScreen::SINGLE_PLAYER*/, const std::map<ui32, std::string> *Names /*= NULL*/)

+ 51 - 6
client/GUIBase.cpp

@@ -103,6 +103,11 @@ IShowActivable * CGuiHandler::topInt()
 }
 
 void CGuiHandler::totalRedraw()
+{
+	this->invalidateTotalRedraw = true;
+}
+
+void CGuiHandler::internalTotalRedraw()
 {
 	for(int i=0;i<objsToBlit.size();i++)
 		objsToBlit[i]->showAll(screen2);
@@ -111,6 +116,9 @@ void CGuiHandler::totalRedraw()
 
 	if(objsToBlit.size())
 		objsToBlit.back()->showAll(screen);
+
+	this->invalidateTotalRedraw = false;
+	this->invalidateSimpleRedraw = false;
 }
 
 void CGuiHandler::updateTime()
@@ -303,11 +311,18 @@ void CGuiHandler::handleMouseMotion(SDL_Event *sEvent)
 }
 
 void CGuiHandler::simpleRedraw()
+{
+	this->invalidateSimpleRedraw = true;
+}
+
+void CGuiHandler::internalSimpleRedraw()
 {
 	//update only top interface and draw background
 	if(objsToBlit.size() > 1)
 		blitAt(screen2,0,0,screen); //blit background
 	objsToBlit.back()->show(screen); //blit active interface/window
+	
+	this->invalidateSimpleRedraw = false;
 }
 
 void CGuiHandler::handleMoveInterested( const SDL_MouseMotionEvent & motion )
@@ -343,14 +358,33 @@ void CGuiHandler::run()
 	setThreadName(-1, "CGuiHandler::run");
 	try
 	{
-		SDL_initFramerate(mainFPSmng);
+		CCS->curh->centerCursor();
+		mainFPSmng->init(); // resets internal clock, needed for FPS manager
 		while(!terminate)
 		{
 			if(curInt)
-				curInt->update();
+				curInt->update(); // calls a update and drawing process of the loaded game interface object at the moment
+
+			// Handles mouse and key input
+			GH.updateTime();
+			GH.handleEvents();
 
-			SDL_framerateDelay(mainFPSmng);
-			//SDL_Delay(20); //give time for other apps
+			// Redraws the GUI only once during rendering
+			if (this->invalidateTotalRedraw == true)
+				internalTotalRedraw();
+			if (this->invalidateSimpleRedraw == true)
+				internalSimpleRedraw();
+
+			if (SHOW_FPS)
+				drawFPSCounter();
+
+			mainFPSmng->framerateDelay(); // holds a constant FPS
+			
+			// draw the mouse cursor and update the screen
+			// todo: bad way of updating the cursor, update screen should be the last statement of the rendering process
+			CCS->curh->draw1();
+			CSDL_Ext::update(screen);
+			CCS->curh->draw2();
 		}
 	} HANDLE_EXCEPTION
 }
@@ -363,8 +397,8 @@ CGuiHandler::CGuiHandler()
 	terminate = false;
 	statusbar = NULL;
 
-	mainFPSmng = new FPSmanager;
-	SDL_setFramerate(mainFPSmng, 48);
+	// Creates the FPS manager and sets the framerate to 48 which is doubled the value of the original Heroes 3 FPS rate
+	mainFPSmng = new FPSManager(48);
 }
 
 CGuiHandler::~CGuiHandler()
@@ -377,6 +411,17 @@ void CGuiHandler::breakEventHandling()
 	current = NULL;
 }
 
+void CGuiHandler::drawFPSCounter()
+{
+	const static SDL_Color yellow = {255, 255, 0, 0};
+	static SDL_Rect overlay = { 0, 0, 64, 32};
+	Uint32 black = SDL_MapRGB(screen->format, 10, 10, 10);
+	SDL_FillRect(screen, &overlay, black);
+	std::string fps = toString(mainFPSmng->fps);
+	CSDL_Ext::printAt(fps, 10, 10, FONT_BIG, yellow, screen);
+}
+
+
 void CIntObject::activateLClick()
 {
 	GH.lclickable.push_front(this);

+ 16 - 4
client/GUIBase.h

@@ -511,8 +511,16 @@ public:
 /// Handles GUI logic and drawing
 class CGuiHandler
 {
+private:
+	bool invalidateTotalRedraw;
+	bool invalidateSimpleRedraw;
+
+	void internalTotalRedraw();
+	void internalSimpleRedraw();
+
 public:
-	FPSmanager * mainFPSmng; //to keep const framerate
+	const static bool SHOW_FPS = false; // shows a fps counter when set to true
+	FPSManager *mainFPSmng; //to keep const framerate
 	timeHandler th;
 	std::list<IShowActivable *> listInt; //list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on)
 	IStatusBar * statusbar;
@@ -539,14 +547,17 @@ public:
 
 	CGuiHandler();
 	~CGuiHandler();
-	void run();
-	void totalRedraw(); //forces total redraw (using showAll)
-	void simpleRedraw(); //update only top interface and draw background from buffer
+	void run(); // holds the main loop for the whole program after initialization and manages the update/rendering system
+	
+	void totalRedraw(); //forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering
+	void simpleRedraw(); //update only top interface and draw background from buffer, sets a flag, method gets called at the end of the rendering
+	
 	void popInt(IShowActivable *top); //removes given interface from the top and activates next
 	void popIntTotally(IShowActivable *top); //deactivates, deletes, removes given interface from the top and activates next
 	void pushInt(IShowActivable *newInt); //deactivate old top interface, activates this one and pushes to the top
 	void popInts(int howMany); //pops one or more interfaces - deactivates top, deletes and removes given number of interfaces, activates new front
 	IShowActivable *topInt(); //returns top interface
+	
 	void updateTime(); //handles timeInterested
 	void handleEvents(); //takes events from queue and calls interested objects
 	void handleEvent(SDL_Event *sEvent);
@@ -554,6 +565,7 @@ public:
 	void handleMoveInterested( const SDL_MouseMotionEvent & motion );
 	void fakeMouseMove();
 	void breakEventHandling(); //current event won't be propagated anymore
+	void CGuiHandler::drawFPSCounter(); // draws the FPS to the upper left corner of the screen
 	ui8 defActionsDef; //default auto actions
 	ui8 captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
 	std::list<CIntObject *> createdObj; //stack of objs being created

+ 25 - 68
client/SDL_framerate.cpp

@@ -1,84 +1,41 @@
 
-/*
-
- SDL_framerate: framerate manager
-
- LGPL (c) A. Schiffler
- 
+/*
+ * SDL_framerate.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
  */
+
 #include "../stdafx.h"
 #include "SDL_framerate.h"
+#include <SDL.h>
 
-/* 
-   Initialize the framerate manager
-*/
-
-void SDL_initFramerate(FPSmanager * manager)
-{
-    /*
-     * Store some sane values 
-     */
-    manager->framecount = 0;
-    manager->rate = FPS_DEFAULT;
-    manager->rateticks = (1000.0 / (float) FPS_DEFAULT);
-    manager->lastticks = SDL_GetTicks();
-}
-
-/* 
-   Set the framerate in Hz 
-*/
 
-int SDL_setFramerate(FPSmanager * manager, int rate)
+FPSManager::FPSManager(int rate)
 {
-    if ((rate >= FPS_LOWER_LIMIT) && (rate <= FPS_UPPER_LIMIT)) {
-	manager->framecount = 0;
-	manager->rate = rate;
-	manager->rateticks = (1000.0 / (float) rate);
-	return (0);
-    } else {
-	return (-1);
-    }
+	this->rate = rate;
+	this->rateticks = (1000.0 / (double) rate);
+	this->fps = 0;
 }
 
-/* 
-  Return the current target framerate in Hz 
-*/
-
-int SDL_getFramerate(FPSmanager * manager)
+void FPSManager::init()
 {
-    if (manager == NULL) {
-	return (-1);
-    } else {
-	return (manager->rate);
-    }
+	this->lastticks = SDL_GetTicks();
 }
 
-/* 
-  Delay execution to maintain a constant framerate. Calculate fps.
-*/
-
-void SDL_framerateDelay(FPSmanager * manager)
+void FPSManager::framerateDelay()
 {
-    Uint32 current_ticks;
-    Uint32 target_ticks;
-    Uint32 the_delay;
-
-    /*
-     * Next frame 
-     */
-    manager->framecount++;
+    Uint32 currentTicks = SDL_GetTicks();
+	double diff = currentTicks - this->lastticks;
 
-    /*
-     * Get/calc ticks 
-     */
-    current_ticks = SDL_GetTicks();
-    target_ticks = manager->lastticks + (Uint32) ((float) manager->framecount * manager->rateticks);
+	if (diff < this->rateticks) // FPS is higher than it should be, then wait some time
+	{
+		SDL_Delay(ceil(this->rateticks) - diff);
+	}
 
-    if (current_ticks <= target_ticks) {
-	the_delay = target_ticks - current_ticks;
-	SDL_Delay(the_delay);
-    } else {
-	manager->framecount = 0;
-	manager->lastticks = SDL_GetTicks();
-    }
+	this->fps = ceil(1000. / (SDL_GetTicks() - this->lastticks));
+	this->lastticks = SDL_GetTicks();
 }

+ 21 - 53
client/SDL_framerate.h

@@ -1,65 +1,33 @@
 
-/*
-
- SDL_framerate: framerate manager
- 
- LGPL (c) A. Schiffler
- 
+/*
+ * timeHandler.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
  */
 
 #ifndef _SDL_framerate_h
 #define _SDL_framerate_h
 
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* --- */
-
-#include "SDL.h"
 
-/* --------- Definitions */
+/// A fps manager which holds game updates at a constant rate
+class FPSManager
+{
+private:
+	double rateticks;
+	unsigned int lastticks;
+	int rate;
 
-/* Some rates in Hz */
+public:
+	int fps; // the actual fps value
 
-#define FPS_UPPER_LIMIT		200
-#define FPS_LOWER_LIMIT		1
-#define FPS_DEFAULT		30
+	FPSManager(int rate); // initializes the manager with a given fps rate
+	void FPSManager::init(); // needs to be called directly before the main game loop to reset the internal timer
+	void framerateDelay(); // needs to be called every game update cycle
+};
 
-/* --------- Structure variables */
 
-	typedef struct {
-	Uint32 framecount;
-	float rateticks;
-	Uint32 lastticks;
-	Uint32 rate;
-	} FPSmanager;
-
-/* --------- Function prototypes */
-
-#ifdef WIN32
-#ifdef BUILD_DLL
-#define DLLINTERFACE __declspec(dllexport)
-#else
-#define DLLINTERFACE __declspec(dllimport)
-#endif
-#else
-#define DLLINTERFACE
 #endif
-
-/* Functions return 0 or value for sucess and -1 for error */
-
-	void SDL_initFramerate(FPSmanager * manager);
-	int SDL_setFramerate(FPSmanager * manager, int rate);
-	int SDL_getFramerate(FPSmanager * manager);
-	void SDL_framerateDelay(FPSmanager * manager);
-
-/* --- */
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-
-#endif				/* _SDL_framerate_h */

+ 11 - 1
global.h

@@ -135,7 +135,6 @@ const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT;
 
 const int SPELLBOOK_GOLD_COST = 500;
 
-
 //for battle stacks' positions
 struct THex
 {
@@ -348,6 +347,17 @@ enum EAlignment
 {
 	GOOD, EVIL, NEUTRAL
 };
+
+// Converts an int/double or any data type you wish to a string
+template<typename T>
+std::string toString(const T& value)
+{
+    std::ostringstream oss;
+    oss << value;
+    return oss.str();
+}
+
+
 //uncomment to make it work
 //#define MARK_BLOCKED_POSITIONS
 //#define MARK_VISITABLE_POSITIONS