r3dux.org

A number-pimping side project from the valleys in *NEW* upside-down flavour.

  • Home
  • ABOUT
  • OLD SITE
  • SEARCH
  • FEEDBACK

How To: Transfer elements between vectors in C++

r3dux | January 16, 2013

Sometimes I end up needing to do this, so I re-implement the functionality… And it segfaults or behaves strangely. This time I’ll write it down somewhere I know where I can find it!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <string>
#include <vector>
 
using namespace std;
 
int main()
{
	// Create an empty vector of type string for our shopping list
	vector<string> shoppingList;
 
	// Add a few items to it
	shoppingList.push_back("Milk");
	shoppingList.push_back("Bread");
	shoppingList.push_back("Eggs");
 
	// Create an empty vector of type string for our purchases
	vector<string> purchases;
 
	// Create a string to hold the user's answer
	string answer;
 
	// Transfer items bought from the shopping list to the purchases list (includes removal from the shoppingList vector)
	vector<string>::iterator i = shoppingList.begin();
	while (i != shoppingList.end() )
	{
		cout << "Item: " << *i << endl;
		cout << "Purchase item? (y/n)" << endl;
 
		cin >> answer;
 
		// If we said yes...
		if (answer == "y")
		{
			// ...add the item to the purchases vector and...
			purchases.push_back(*i);
 
			// ...remove the item from the shoppingList vector. Erase returns an
			// iterator which points at the next element in the vector, so we need to
			// skip incrementing the iterator in this case or we might go out of bounds!
			i = shoppingList.erase(i);
		}
		else // Otherwise just move on to the next item!
		{
			i++;
		}
	}
 
	cout << endl;
 
	// Display both lists
	cout << "----- Shopping List ----" << endl;
	for (i = shoppingList.begin(); i != shoppingList.end(); i++)
	{
		cout << *i << endl;
	}
 
	cout << endl;
 
	cout << "----- Purchases ----" << endl;
	for (i = purchases.begin(); i != purchases.end(); i++)
	{
		cout << *i << endl;
	}
 
	cout << endl;
 
	return 0;
}

TLTB ;-)

Comments
No Comments »
Categories
Coding, How-To
Tags
C++, Elements, Transfer, Vector
Comments rss Comments rss
Trackback Trackback

How-To: Create A Simple OpenGL 2D Particle Fountain in C++

r3dux | January 12, 2013

I was recently asked about some particle systems I’d put together, so in response, this isn’t really a “look what I’ve coded” post – instead, it’s more of a “this is an easy way to set up a particle system framework” post.

To demonstrate the setup of a particle system using OpenGL, I’ve put together some simple starter code which displays a 2D particle fountain. I was going to just dump this code as a zipped project into a reply, but then (as my wife pointed out) it would be pretty much buried in the comments, so if other people starting OpenGL coding wanted to learn the basics of particle systems my code wouldn’t be as visible. As such, I’ve made this into a separate post – and all our example code does is this:

YouTube Preview Image

It’s a dirt-simple effect, but what it does isn’t so important right now – it’s deliberately simple. How it does what it does is what we’ll talk about.

Looking at particle systems from a high level – you generally have to choose between two different approaches to the system as a whole:

  1. You have a fixed number of particles (i.e. you have a fixed size array of however many particles) and you reset each particle to “recycle” it, or
  2. You have a dynamic number of particles (i.e. you have a dynamically resizable array) and you destroy each particle and create a new one as required.

I’ve gone with the latter approach for this code using a vector of particles (nothing to do with Vec2/Vec3 math – just the name of resizable array kinda construct). Admittedly, there’s more overhead in the creation and destruction of particles, but on the upside you don’t get that initial rush of particles you get when using fixed size arrays and as soon as you start the program BLAM! All your particles going at once.

To demonstrate what I mean, in the video below I’ve modified the code to instantiate ALL particles up to the particle limit at once, and then as soon as a particle goes off the bottom of the screen it gets destroyed and a new particle is created. The effect of which is that you get a single big burst of particles, and then as they all get destroyed and recreated at different times they turn into a smooth flow within a couple of seconds:

YouTube Preview Image

If you’re using a fixed size particle array, you’ll need to implement some mechanism to delay the instantiation or “launch” of the particles – for example, you might give each particle a random framesUntilLaunch value and decrease it by 1 each frame until it gets to 0 and you can let the particle do its thing. I wrote such a delay system for some fireworks code I did a while back if you’d like to see a concrete example.

Anyways, back at this code, our main is using three main classes to encapsulate data and provide methods to manipulate it:

  • Colour4f.hpp – A class to store a colour as red/green/blue/alpha floating point values and manipulate ‘em (including interpolation of colours),
  • Vec2.hpp – A templatised class to store two values as a vector (Not a resizable array this time! An actually “euclidian vector” – i.e. two values which represent a direction and magnitude). It also includes lots of overloaded operators so you can add two vectors together (“up” + “right” gives you “up-right” etc.), multiply a vector by a scalar (i.e. moving “up-right” multiplied by 10 means you’re now moving up-right ten times as fast). By templatised, I mean that you can create a Vec2 of ints, or floats, or doubles, or shorts, or whatever numeric type makes sense for your application – take a look at the source below if you want examples, and finally
  • Particle2D.hpp – A particle class which uses the above Colour4f and Vec2 classes to provide powerful movement and colour modification options in a small & easy to use package.

You can download the complete source code as a Code::Blocks project here, if you’d like: PointSprite_Particle_Fountain_2D.zip.

Note: As my OS of choice is GNU/Linux (LMDE, to be specific), the source files provided will have Linux line-endings – so you’ll need to open them with a good text editor like Notepad++ if you’re in in Windows, otherwise each file will look like a single massive block of noise!

Or, if you’d prefer to just browse the source code so you can copy and paste sections, you’ll find it all laid out below.

I love particle systems – you can do some visually stunning things with really simple code, or you can do amazing things if you take it further. Either way, I hope you have a lot of fun with them (there’s lots more particle stuff on this site if you’re looking for inspiration – try Actionscript tag for a start!) – and if you make anything cool or pretty using and you think I’ve helped – please do show me or let me know – I’ve love to see or hear about what you’ve done! =D

Also – if you make this – show me how, okay?

YouTube Preview Image

Cheers!

Read the rest of this entry »

Comments
1 Comment »
Categories
Coding, OpenGL
Tags
C++, Fountain, How-To, OpenGL, Particle, Vector
Comments rss Comments rss
Trackback Trackback

OpenGL Particle Emitters and Waypoints with Colour Interpolation

r3dux | December 30, 2012

I thought the particles would look nicer being coloured as an interpolation of the colours of the waypoints they’re travelling between…

YouTube Preview Image

And you know what? I’m thinking I was right! ;-)

Comments
4 Comments »
Categories
Coding, Imagery
Tags
C++, Emitters, Interpolation, OpenGL, Particle. Systems, Particles, Waypoints
Comments rss Comments rss
Trackback Trackback

Vec3: A Simple Vector Class in C++

r3dux | December 8, 2012

This is really the second post of three updating an earlier post on how to write some simple FPS-type controls for OpenGL – last post we looked at a FpsManager class so we could get frame timings to implement framerate independent movement. This time, we’re looking at a simple Vec3 class which stores 3D coordinates and helps to perform some operations on them. This is going to form part of the Camera class in the final part, but I thought I’d put it here on its own so it can be re-used.

There’s probably about ten million different vector classes out there, but I really wanted to write my own so I understood exactly how it worked, and I’ve commented it pretty heavily in the process – so hopefully if you’re looking for a vector class you might be able to look at this one, see how it works and what it does, and take and modify it for your own work.

Before skipping to the code, let’s just take a quick look at what it does – it packages up 3 values called x, y and z, and allows us to easily manipulate them. Quite what you store in these values is up to you, it could be a vertex position, or a direction vector, or a RGB colour – anything that has three values, really.

If we were dealing with two vertexes, we can do stuff like this:

    // Define two initial vectors
    Vec3<double> vector1(1, 2, 3); // A coordinate +1 on the X axis (horiz), +2 on the Y axis (vert), and +3 on the Z axis (depth)
    Vec3<double> vector2(4, 5, 6); // A coordinate +4 on the X axis (horiz), +5 on the Y axis (vert), and +6 on the Z axis (depth)
 
    // Create a new vector which is the sum of these two vectors added together
    Vec3<double>result = vector1 + vector2;
    result.display();           // (5, 7, 9)
 
    // Add the first vector to our result vector
    result += vector1;
    result.display();           // 6, 9, 12
 
    // Subtract the second vector from our result vector
    result -= vector2;
    result.display();           // 2, 4, 6
 
    // Divide our result vector by the scalar value 2
    result /= 2;
    result.display();           // 1, 2, 3
 
    // Multiply both vectors together and assign to our result vector (this is a dot-product
    // operation, but we have specific dot product functions we can use, too)
    result = vector1 * vector2;
    result.display();           // 4, 10, 18
 
    // Multiply our result vector by 2
    result *= 2;
    result.display();           // 8, 20, 36
 
    // Normalise our result vector so that all values fall within the range -1 to +1
    result.normalise();
    result.display();           // 0.190693, 0.476731, 0.858116
 
     // Calculate the distance between two points in 3D space
    double distance = Vec3<double>::getDistance(vector1, vector2);
    cout << "Distance between points: " << distance << endl; // 5.19615
 
    // Dot products only work on normalised values (i.e. each x/y/z value in the vector must be in the range -1 to +1)
    // So remember to normalise your vectors before computing the dot product!
    vector1.normalise();
    vector2.normalise();
    double dotProduct = Vec3<double>::dotProduct(vector1, vector2);
    cout << "Dot product: " << dotProduct << endl;           // 0.974632
 
    // Define some vectors pointing up, down, left, and right
    Vec3<double> up(   0,  1, 0);
    Vec3<double> down( 0, -1, 0);
    Vec3<double> left(-1,  0, 0);
    Vec3<double> right(1,  0, 0);
 
    // ------------ Dot Product Tests ------------
 
    // The dot product of two vectors pointing the same direction is 1
    dotProduct = Vec3<double>::dotProduct(up, up);
    cout << "Dot product of up and up: " << dotProduct << endl;
 
    // The dot product of two vectors which are perpendicular to each other is is 0
    dotProduct = Vec3<double>::dotProduct(up, right);
    cout << "Dot product of up and right: " << dotProduct << endl;
 
    // The dot product of two vectors pointing in opposite directions is -1
    dotProduct = Vec3<double>::dotProduct(up, down);
    cout << "Dot product of up and down: " << dotProduct << endl;
 
    // ------------ Cross Product Tests ------------
 
    // The cross product of a vector is the vector which is perpendicular to the plane made
    // by the two vectors specified. Whether it points "up" or "down" depends on the
    // handedness of the coordinate system and/or the order of vectors provided.
 
    // Test 1
    Vec3<double> crossProduct = Vec3<double>::crossProduct(up, right);
 
    // x = 0, y = 0, z = -1 (i.e. the vector perpendicular to up and right points INTO the screen)
    crossProduct.display(); 
 
    // Test 2
    crossProduct = Vec3<double>::crossProduct(right, up);
 
    // x = 0, y = 0, z = 1 (i.e. the vector perpendicular to right and up points OUT from screen)
    crossProduct.display();

Seems pretty easy to work with to me…

Here’s the code for the Vec3 class itself as a templatised, header-only C++ .hpp file – just include the Vec3.hpp class and you’re good to go:

#ifndef VEC3_HPP
#define VEC3_HPP
 
#include <iostream>
 
template <class T> class Vec3
{
    private:
        // A Vec3 simply has three properties called x, y and z
        T x, y, z;
 
    public:
        // ------------ Constructors ------------
 
        // Default constructor
        Vec3() { x = y = z = 0; };
 
        // Three parameter constructor
        Vec3(T xValue, T yValue, T zValue)
        {
            x = xValue;
            y = yValue;
            z = zValue;
        }
 
        // ------------ Getters and setters ------------
 
        void set(const T &xValue, const T &yValue, const T &zValue)
        {
            x = xValue;
            y = yValue;
            z = zValue;
        }
 
        T getX() const { return x; }
        T getY() const { return y; }
        T getZ() const { return z; }
 
        void setX(const T &xValue) { x = xValue; }
        void setY(const T &yValue) { y = yValue; }
        void setZ(const T &zValue) { z = zValue; }
 
        // ------------ Helper methods ------------
 
        // Method to reset a vector to zero
        void zero()
        {
            x = y = z = 0;
        }
 
        // Method to normalise a vector
        void normalise()
        {
            // Calculate the magnitude of our vector
            T magnitude = sqrt((x * x) + (y * y) + (z * z));
 
            // As long as the magnitude isn't zero, divide each element by the magnitude
            // to get the normalised value between -1 and +1
            if (magnitude != 0)
            {
                x /= magnitude;
                y /= magnitude;
                z /= magnitude;
            }
        }
 
        // Static method to calculate and return the scalar dot product of two vectors
        //
        // Note: The dot product of two vectors tell us things about the angle between
        // the vectors. That is, it tells us if they are pointing in the same direction
        // (i.e. are they parallel? If so, the dot product will be 1), or if they're
        // perpendicular (i.e. at 90 degrees to each other) the dot product will be 0,
        // or if they're pointing in opposite directions then the dot product will be -1.
        //
        // Usage example: double foo = Vec3<double>::dotProduct(vectorA, vectorB);
        static T dotProduct(const Vec3 &vec1, const Vec3 &vec2)
        {
            return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
        }
 
        // Non-static method to calculate and return the scalar dot product of this vector and another vector
        //
        // Usage example: double foo = vectorA.dotProduct(vectorB);
        T dotProduct(const Vec3 &vec) const
        {
            return x * vec.x + y * vec.y + z * vec.z;
        }
 
        // Static method to calculate and return a vector which is the cross product of two vectors
        //
        // Note: The cross product is simply a vector which is perpendicular to the plane formed by
        // the first two vectors. Think of a desk like the one your laptop or keyboard is sitting on.
        // If you put one pencil pointing directly away from you, and then another pencil pointing to the
        // right so they form a "L" shape, the vector perpendicular to the plane made by these two pencils
        // points directly upwards.
        //
        // Whether the vector is perpendicularly pointing "up" or "down" depends on the "handedness" of the
        // coordinate system that you're using.
        //
        // Further reading: http://en.wikipedia.org/wiki/Cross_product
        //
        // Usage example: Vec3<double> crossVect = Vec3<double>::crossProduct(vectorA, vectorB);
        static Vec3 crossProduct(const Vec3 &vec1, const Vec3 &vec2)
        {
            return Vec3(vec1.y * vec2.z - vec1.z * vec2.y, vec1.z * vec2.x - vec1.x * vec2.z, vec1.x * vec2.y - vec1.y * vec2.x);
        }
 
        // Easy adders
        void addX(T value) { x += value; }
        void addY(T value) { y += value; }
        void addZ(T value) { z += value; }
 
        // Method to return the distance between two vectors in 3D space
        //
        // Note: This is accurate, but not especially fast - depending on your needs you might
        // like to use the Manhattan Distance instead: http://en.wikipedia.org/wiki/Taxicab_geometry
        // There's a good discussion of it here: http://stackoverflow.com/questions/3693514/very-fast-3d-distance-check
        // The gist is, to find if we're within a given distance between two vectors you can use:
        //
        // bool within3DManhattanDistance(Vec3 c1, Vec3 c2, float distance)
        // {
        //      float dx = abs(c2.x - c1.x);
        //      if (dx > distance) return false; // too far in x direction
        //
        //      float dy = abs(c2.y - c1.y);
        //      if (dy > distance) return false; // too far in y direction
        //
        //      float dz = abs(c2.z - c1.z);
        //      if (dz > distance) return false; // too far in z direction
        //
        //      return true; // we're within the cube
        // }
        //
        // Or to just calculate the straight Manhattan distance you could use:
        //
        // float getManhattanDistance(Vec3 c1, Vec3 c2)
        // {
        //      float dx = abs(c2.x - c1.x);
        //      float dy = abs(c2.y - c1.y);
        //      float dz = abs(c2.z - c1.z);
        //      return dx+dy+dz;
        // }
        //
        static T getDistance(const Vec3 &v1, const Vec3 &v2)
        {
            T dx = v2.x - v1.x;
            T dy = v2.y - v1.y;
            T dz = v2.z - v1.z;
 
            return sqrt(dx * dx + dy * dy + dz * dz);
        }
 
        // Method to display the vector so you can easily check the values
        void display()
        {
            std::cout << "X: " << x << "\t Y: " << y << "\t Z: " << z << std::endl;
        }
 
        // ------------ Overloaded operators ------------
 
        // Overloaded addition operator to add Vec3s together
        Vec3 operator+(const Vec3 &vector) const
        {
            return Vec3<T>(x + vector.x, y + vector.y, z + vector.z);
        }
 
        // Overloaded add and asssign operator to add Vec3s together
        void operator+=(const Vec3 &vector)
        {
            x += vector.x;
            y += vector.y;
            z += vector.z;
        }
 
        // Overloaded subtraction operator to subtract a Vec3 from another Vec3
        Vec3 operator-(const Vec3 &vector) const
        {
            return Vec3<T>(x - vector.x, y - vector.y, z - vector.z);
        }
 
        // Overloaded subtract and asssign operator to subtract a Vec3 from another Vec3
        void operator-=(const Vec3 &vector)
        {
            x -= vector.x;
            y -= vector.y;
            z -= vector.z;
        }
 
        // Overloaded multiplication operator to multiply two Vec3s together
        Vec3 operator*(const Vec3 &vector) const
        {
            return Vec3<T>(x * vector.x, y * vector.y, z * vector.z);
        }
 
        // Overloaded multiply operator to multiply a vector by a scalar
        Vec3 operator*(const T &value) const
        {
            return Vec3<T>(x * value, y * value, z * value);
        }
 
        // Overloaded multiply and assign operator to multiply a vector by a scalar
        void operator*=(const T &value)
        {
            x *= value;
            y *= value;
            z *= value;
        }
 
        // Overloaded multiply operator to multiply a vector by a scalar
        Vec3 operator/(const T &value) const
        {
            return Vec3<T>(x / value, y / value, z / value);
        }
 
        // Overloaded multiply and assign operator to multiply a vector by a scalar
        void operator/=(const T &value)
        {
            x /= value;
            y /= value;
            z /= value;
        }
};
 
#endif

Next post, we’re going to be implementing a FPS-style camera class using this Vec3 class to move around a 3D scene – and because of all our hard work in getting this vector class together, it’s going to make moving the camera around a doddle =D

Cheers!

Comments
1 Comment »
Categories
Coding, OpenGL
Tags
C++, Camera, Direction, Math, OpenGL, position, Vec3, Vector, Vertex
Comments rss Comments rss
Trackback Trackback

FpsManager – A C++ helper class for framerate independent movement

r3dux | December 1, 2012

I wrote only a few months back that I didn’t want to write another piece of FPS code, ever. But this was before I started taking framerate independent movement seriously. In my past coding I’ve just enabled VSync and been done with it – as long as the machine had enough processing capacity to perform at 60fps everything was fine, and nearly everything I wrote was so simple that it didn’t task the box too much.

However, as I’ve been working on a lot of Android code recently where the processing capacity of the device can easily vary by orders of magnitude, I’ve started thinking more that I really need to be able to cater to framerate changes gracefully. And for this, I’ve reinvented the wheel – if only to be absolutely sure in no uncertain terms about how the wheel frickn’ works.

So to put this to the test, I wrote the FpsManager class, and rewrote the camera from my old post on Simple OpenGL FPS Controls into a proper class suitable for reuse in multiple projects and capable of working in a framerate independent manner. That’s the next post…

…first things first: The FpsManager! ;-)

FpsManager.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#include <string>
#include <sstream>
 
#ifndef __glfw_h_
    #include <GL/glfw.h> // We need GLFW for this, so let's check for it- although it'd be a doddle to convert to non-GLFW using code.
#endif
 
/** The FpsManager class is designed to work with GLFW and enforces a specified framerate on an application.
  * It can also display the current framerate at user-specified intervals, and in addition returns the time
  * duration since the last frame, which can be used to implement framerate independent movement.
  *
  * Author: r3dux
  * Revision: 0.1
  * Date: 1st December 2012
  *
  * ---- Creation examples (it's most useful to create your fpsManager object globally in your Main.cpp file): ----
  *
  *     FpsManager fpsManager(60.0);                    // Lock to 60fps, no reporting of framerate
  *
  *     FpsManager fpsManager(85.0, 3.0);               // Lock to 85fps, output FPS to console once every three seconds
  *
  *     FpsManager fpsManager(30.0, 0.5, "My App");     // Lock to 30fps, output FPS to console & window title every half second
  *
  *
  * ---- Using the fpsManager in your main loop: ----
  *
  * bool running     = true;
  * double deltaTime = 0.0;
  *
  * while (running)
  * {
  *     // Calculate our camera movement
  *     cam->move(deltaTime);
  *
  *     // Draw our scene
  *     drawScene();
  *
  *     // Exit if ESC was pressed or window was closed
  *     running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED);
  *
  *     // Call our fpsManager to limit the FPS and get the frame duration to pass to the cam->move method
  *     deltaTime = fpsManager.enforceFPS();
  * }
  *
  * That's it! =D
  */
 
class FpsManager
{
 
    private:
        double frameStartTime;         // Frame start time
        double frameEndTime;           // Frame end time
        double frameDuration;          // How many milliseconds between the last frame and this frame
 
        double targetFps;              // The desired FPS to run at (i.e. maxFPS)
        double currentFps;             // The current FPS value
        int    frameCount;             // How many frames have been drawn s
 
        double targetFrameDuration;    // How many milliseconds each frame should take to hit a target FPS value (i.e. 60fps = 1.0 / 60 = 0.016ms)
        double sleepDuration;          // How long to sleep if we're exceeding the target frame rate duration
 
        double lastReportTime;         // The timestamp of when we last reported
        double reportInterval;         // How often to update the FPS value
 
        std::string windowTitle;       // Window title to update view GLFW
 
        bool verbose;                  // Whether or not to output FPS details to the console or update the window
 
        // Limit the minimum and maximum target FPS value to relatively sane values
        static const double MIN_TARGET_FPS = 20.0;
        static const double MAX_TARGET_FPS = 60.0; // If you set this above the refresh of your monitor and enable VSync it'll break! Be aware!
 
        // Private method to set relatively sane defaults. Called by constructors before overwriting with more specific values as required.
        void init(double theTargetFps, bool theVerboseSetting)
        {
            setTargetFps(theTargetFps);
 
            frameCount     = 0;
 
            currentFps     = 0.0;
 
            sleepDuration  = 0.0;
 
            frameStartTime = glfwGetTime();
            frameEndTime   = frameStartTime + 1;
            frameDuration  = 1;
 
            lastReportTime = frameStartTime;
            reportInterval = 1.0f;
 
            windowTitle    = "NONE";
 
            verbose        = theVerboseSetting;
        }
 
    public:
 
        // Single parameter constructor - just set a desired framerate and let it go.
        // Note: No FPS reporting by default, although you can turn it on or off later with the setVerbose(true/false) method
        FpsManager(int theTargetFps)
        {
            init(theTargetFps, false);
        }
 
        // Two parameter constructor which sets a desired framerate and a reporting interval in seconds
        FpsManager(int theTargetFps, double theReportInterval)
        {
            init(theTargetFps, true);
 
            setReportInterval(theReportInterval);
        }
 
        // Three parameter constructor which sets a desired framerate, how often to report, and the window title to append the FPS to
        FpsManager(int theTargetFps, float theReportInterval, std::string theWindowTitle)
        {
            init(theTargetFps, true); // If you specify a window title it's safe to say you want the FPS to update there ;)
 
            setReportInterval(theReportInterval);
 
            windowTitle = theWindowTitle;
        }
 
        // Getter and setter for the verbose property
        bool getVerbose()
        {
            return verbose;
        }
        void setVerbose(bool theVerboseValue)
        {
            verbose = theVerboseValue;
        }
 
        // Getter and setter for the targetFps property
        int getTargetFps()
        {
            return targetFps;
        }
        void setTargetFps(int theFpsLimit)
        {
            // Make at least some attempt to sanitise the target FPS...
            if (theFpsLimit < MIN_TARGET_FPS)
            {
                theFpsLimit = MIN_TARGET_FPS;
                std::cout << "Limiting FPS rate to legal minimum of " << MIN_TARGET_FPS << " frames per second." << std::endl;
            }
            if (theFpsLimit > MAX_TARGET_FPS)
            {
                theFpsLimit = MAX_TARGET_FPS;
                std::cout << "Limiting FPS rate to legal maximum of " << MAX_TARGET_FPS << " frames per second." << std::endl;
            }
 
            // ...then set it and calculate the target duration of each frame at this framerate
            targetFps = theFpsLimit;
            targetFrameDuration = 1.0 / targetFps;
        }
 
        double getFrameDuration() { return frameDuration; } // Returns the time it took to complete the last frame in milliseconds
 
        // Setter for the report interval (how often the FPS is reported) - santises input.
        void setReportInterval(float theReportInterval)
        {
            // Ensure the time interval between FPS checks is sane (low cap = 0.1s, high-cap = 10.0s)
            // Negative numbers are invalid, 10 fps checks per second at most, 1 every 10 secs at least.
            if (theReportInterval < 0.1)
            {
                theReportInterval = 0.1;
            }
            if (theReportInterval > 10.0)
            {
                theReportInterval = 10.0;
            }
            reportInterval = theReportInterval;
        }
 
        // Method to force our application to stick to a given frame rate and return how long it took to process a frame
        double enforceFPS()
        {
            // Get the current time
            frameEndTime = glfwGetTime();
 
            // Calculate how long it's been since the frameStartTime was set (at the end of this method)
            frameDuration = frameEndTime - frameStartTime;
 
            if (reportInterval != 0.0f)
            {
 
                // Calculate and display the FPS every specified time interval
                if ((frameEndTime - lastReportTime) > reportInterval)
                {
                    // Update the last report time to be now
                    lastReportTime = frameEndTime;
 
                    // Calculate the FPS as the number of frames divided by the interval in seconds
                    currentFps =  (double)frameCount / reportInterval;
 
                    // Reset the frame counter to 1 (and not zero - which would make our FPS values off)
                    frameCount = 1;
 
                    if (verbose)
                    {
                        std::cout << "FPS: " << currentFps << std::endl;
 
                        // If the user specified a window title to append the FPS value to...
                        if (windowTitle != "NONE")
                        {
                            // Convert the fps value into a string using an output stringstream
                            std::ostringstream stream;
                            stream << currentFps;
                            std::string fpsString = stream.str();
 
                            // Append the FPS value to the window title details
                            std::string tempWindowTitle = windowTitle + " | FPS: " + fpsString;
 
                            // Convert the new window title to a c_str and set it
                            const char* pszConstString = tempWindowTitle.c_str();
                            glfwSetWindowTitle(pszConstString);
                        }
 
                    } // End of if verbose section
 
                }
                else // FPS calculation time interval hasn't elapsed yet? Simply increment the FPS frame counter
                {
                    ++frameCount;
                }
 
            } // End of if we specified a report interval section
 
            // Calculate how long we should sleep for to stick to our target frame rate
            sleepDuration = targetFrameDuration - frameDuration;
 
            // If we're running faster than our target duration, sleep until we catch up!
            if (sleepDuration > 0.0)
                glfwSleep(targetFrameDuration - frameDuration);
 
            // Reset the frame start time to be now - this means we only need put a single call into the main loop
            frameStartTime = glfwGetTime();
 
            // Pass back our total frame duration (including any sleep) to be used as our deltaTime value in the game loop (to allow for framerate independant speeds)
            return glfwGetTime() - frameEndTime;
 
        } // End of our enforceFPS method
 
};

Comments? Suggestions? Think I’ve designed it badly, or quite well? Know why it works just fine (from a usability standpoint) but provides a framerate just under that requested?

Feel free to let me know in the comments below! Cheers! =D

Comments
4 Comments »
Categories
Coding
Tags
C++, deltaTIme, FPS, Framerate, Frames Per Second, GLFW, Manager, Movement
Comments rss Comments rss
Trackback Trackback

« Previous Entries

Translate

Categories

Archives

Tags

3D ActionScript ActionScript 3.0 Adobe AI Ballarat Bash C++ Class Convert CS4 Effect Error Film Flash FPS GLFW Glitch GLSL Hack How-To install Java Kinect Linux Live Mash-Up Microsoft Motion mount OpenGL Particle Problem PS3 Remix Retro script Slides Sound Ubuntu Video VirtualBox Wii Windows XBox

Gamercard

OpenR3dux

Misc.

Flattr this

RSS Feed

r3dux twitter feed



“Taming the lion tamers”

rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox