-
Notifications
You must be signed in to change notification settings - Fork 2
GraphicsManager
#Graphics manager The graphics manager is your link to the 3D accelerated drawing surface. It has five major responsibilities, clear the screen, draw filled square, draw line, draw string and to swap buffers.
- Clear the screen - At the begening of every frame clear the screen to a solid color to avoid seeing the contents of the previous frame. This is optional. If you have a background that covers the whole screen you don't need to clear it.
- Draw square - Draw a solid colored rectangle on the screen.
- DrawLine - Draw a colored line on screen.
- DrawString - Draw a colored string on screen. This has only one hard coded font. It is very useful for debugging, it may not be appropriate for in game text.
- SwapBuffers - This is REQUIRED. Call at the end of every draw frame to make your back buffer into the new front buffer and get a new back buffer to draw into.
Let's explore how to actually use the graphics manager. Remember, the GraphicsManager is a singleton, you will only have one troughout the lifetime of your game! We are going to be starting from the skeleton created on the repository's front page.
#Initialize and shutdown
The first thing we need to do is initialize the GraphicsManager. This can be dont trought he classes Initialize member function. The function takes one argument of type OpenTK.GameWindow, which is the window that the manager is bound to. Luckly the main class already has a static GameWindow variable called Window . Replace the Initialize function in Program.cs with this:
public static void Initialize(object sender, EventArgs e) {
GraphicsManager.Instance.Initialize(Window);
}
That's all it takes to intialize the graphics manager. The Initialize function configures OpenGL for 2D rendering, sets our depth to 0 and loads in the debug font. A lot happens in this function, but it should execute pretty quick.
With all the managers you must manage allocated resources. It's best practice to free anything when you allocate, this is a good habit to get into. So, let's shutdown the GraphicsManager. To shutdown simply call the Shutdown member function of the GraphicsManager class. Replace the Shutdown function int Program.cs with this:
public static void Shutdown(object sender, EventArgs e) {
GraphicsManager.Instance.Shutdown();
}
#Render All rendering should take place between clearing the screen and swapping buffers. Let's add some code to make this happen.
To clear the screen call the ClearScreen member function of the GraphicsManager class. It takes as argument a System.Drawing.Color which represents the color to clear the screen to.
To swap buffers call the SwapBuffer member function of the GraphicsManager class. This function swaps the back bufer forward.
Replace the Render function in Program.cs with this:
public static void Render(object sender, FrameEventArgs e) {
GraphicsManager.Instance.ClearScreen(Color.CornflowerBlue);
// Add future render commands here
GraphicsManager.Instance.SwapBuffers();
}
At this point if you launch the game your application should have a nice blue background
#Draw Rect
Lets add some rendering code in-between the ClearScreen and SwapBuffers function calls. First we are going to explore the DrawRect member function of the GraphicsManager class. This function has the following signature:
public void DrawRect(Rectangle rect, Color c)
public void DrawRect(RectangleF rect, Color c)
Where rect is a rectangle in screen coordinates of where to draw the rectangle and c is the color to draw the rectangle in. Try to draw the following rectangles on screen:
- Red at x:0 y:0 with a width of 100 and height of 250
- Blue at x:50 y: 125 widht a width of 100 and a height of 250
- Green at x:100 y: 250 with a width of 100 and a height of 250
- Yellow at x: 400 y: 300 with a width of 400 and a height of 300
Running the game the window should look like this
If yours doesn't look like the above image, take a look at my implementation
#Draw Line
Keeping the previous code in place, lets try to draw some lines. You can draw lines with the DrawLine member function of the GraphicsManager class. The function has the following signature:
public void DrawLine(Point p1, Point p2, Color c)
public void DrawLine(PointF p1, PointF p2, Color c)
Where p1 is the start point of the line, p2 is the end point of the line and c is the color of the line. Try to draw a magenta cross (an X going accross) on the screen. Assume that the width of the screen is 800 and the height of the screen is 600.
Running the game the window should look like this
If yours doesn't look like the image above, take a look at my implementation
#Draw String
Keeping the previous code in place, lets draw a few strings to screen. Unlike the WinformGames framewrok the 2DOpenTK framework does not rasterize fonts in real time. Instead it has an embeded texture with every letter in can print. When you DrawString a bunch of rectangles are drawn on screen. Each rectangle has it's texture source set to a part of the font texture that represents the correct letter.
You can draw a string with the DrawString member function of the GraphicsManager class. The function has the following signature:
public void DrawString(string str, Point position, Color color)
public void DrawString(string str, PointF position, Color color)
Where str is the string you want to print, position is the screen space position of where you want to print it and color is the color you want to print it in. Try to write the following strings:
- "Hello World" at 600, 500 in green
- "Printing strings" at 315, 200 in black
Running the game the window should look like this
If yours doesn't look like the image above, take a look at my implementation
#Display Framerate
Lets use the above code to display something usefil, a framerate counter! Remember, deltaTime is 1/fps, which means that 1/deltaTime is fps. We have access to deltaTime in both the Render and Update functions in Program.cs. The FrameEventArgs argument contains a Time member, which is deltaTime.
Knowing this, adding a framerate should be as simple as adding:
GraphicsManager.Instance.DrawString("FPS: " + (1.0 / e.Time), new Point(10, 10), Color.Black);
Right before we call SwapBuffers. And indeed, it works. But if your computer works like mine the framerate is irradically jumping between 59 and 60. This is not a bug, two frames are rarley consistent! A few milliseconds of innacuracy are accepted. What we really want to display is the average frames per second.
To display the average FPS we're going to count how many frames take place during one second. We then divide the number of frames by how long it took to add them up (This might not be exactly one secong, it might be 1.02 seconds, or some other small error). And finally we're going to display the average. With this in mind, lets add 3 new static variables to our main class:
static int numFrames = 0;
static double framesTime = 0.0;
static int frameRate = 0;
And add some code to count the number of frames and calculate the average to the Update function
public static void Update(object sender, FrameEventArgs e) {
numFrames += 1;
framesTime += e.Time;
if (framesTime >= 1.0f) {
frameRate = (int)(System.Convert.ToDouble(numFrames) / framesTime);
framesTime = 0.0;
numFrames = 0;
}
}
Lastly, we're going to display the average FPS right under the real FPS
GraphicsManager.Instance.DrawString("FPS: " + (1.0 / e.Time), new Point(10, 10), Color.Black);
GraphicsManager.Instance.DrawString("Average FPS: " + frameRate, new Point(10, 30), Color.Black);
GraphicsManager.Instance.SwapBuffers();
As you can see even the average framerate is fluctuating. This is because we are not doing any heavy work. Once we start building a real game that framerate should stabolize.


