Bladeren bron

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

beegee1 14 jaren geleden
bovenliggende
commit
157002fe68
10 gewijzigde bestanden met toevoegingen van 138 en 151 verwijderingen
  1. 8 0
      client/CCursorHandler.cpp
  2. 3 2
      client/CCursorHandler.h
  3. 1 1
      client/CMT.cpp
  4. 2 11
      client/CPlayerInterface.cpp
  5. 0 5
      client/CPreGame.cpp
  6. 51 6
      client/GUIBase.cpp
  7. 16 4
      client/GUIBase.h
  8. 25 68
      client/SDL_framerate.cpp
  9. 21 53
      client/SDL_framerate.h
  10. 11 1
      global.h

+ 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