Author Topic: Rendering question  (Read 27446 times)

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Rendering question
« on: July 14, 2013, 06:39:02 AM »
Hi.

I was wondering about this: When drawing the level map in a roguelike, there seems to be two things one can do:

1. draw the entire map every frame

2. draw only what's "changed".

In the case of a simple text-based one, which is better? It would seem 2) would be faster, but also at the cost of added code complexity (you need to notify the rendering system of any and all changes to the map somehow). Does this matter on modern machines or is it just not worth the added complexity now? How do you do this in your games?

And what happens when you get up to graphics like with tiles and animated tiles? Or with "chase" (is that the right term?) scrolling where the scrolling follows the player as they move around (which'd seem to necessitate a full redraw anyways since everything on the screen moves)?

Trystan

  • Rogueliker
  • ***
  • Posts: 164
  • Karma: +0/-0
    • View Profile
    • my blog
Re: Rendering question
« Reply #1 on: July 14, 2013, 06:51:34 AM »
In general, only deal with performance when it becomes a problem and only add code complexity when absolutely necessary.

Krice

  • (Banned)
  • Rogueliker
  • ***
  • Posts: 2316
  • Karma: +0/-2
    • View Profile
    • Email
Re: Rendering question
« Reply #2 on: July 14, 2013, 09:31:13 AM »
How do you do this in your games

I'm using SDL with software drawing mode so it's useful to draw and update only areas that are changed. I'm dividing update areas in few main ones like gameview, side stats and message output. When something is changed the GUI gets a note on the update area and it's updated per turn or flushing when needed. For me this simple technique also came a bit late, since I was just happily drawing stuff without realizing that some stats gets updated frequently and can trigger multiple updates on the same area which is slow.

With SDL's software drawing it's still good not to update the entire screen per turn, because it is noticeably slower. It can be different with opengl or other hardware drawing though.

Endorya

  • Rogueliker
  • ***
  • Posts: 513
  • Karma: +0/-0
  • The non-purist roguelike lover
    • View Profile
    • Email
Re: Rendering question
« Reply #3 on: July 14, 2013, 10:56:09 AM »
It really depends on how heavy your rendering work becomes but it is good practice in general to render only what is needed. If you have real time animated tiles you will probably have to render the whole scene constantly. If your world only changes when the player ends a turn, you will probably render the whole world just once per turn.

In any case, I advise you to first see how performance plays while rendering everything and you should do this in a computer bellow average in terms of processing power. As Trystan advised, roam only towards code complexity when really necessary.
« Last Edit: July 14, 2013, 03:55:03 PM by Endorya »
"You are never alone. Death is always near watching you."

miki151

  • Rogueliker
  • ***
  • Posts: 264
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #4 on: July 14, 2013, 04:41:09 PM »
In most games there are situations when there are a lot of changes and you are basically updating everything, so you need to handle that anyway. It's best to optimize the worst case scenarios, if you're at it.
KeeperRL, Dungeon Keeper in roguelike style:
http://keeperrl.com

Anvilfolk

  • Rogueliker
  • ***
  • Posts: 374
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #5 on: July 14, 2013, 05:20:37 PM »
Just pick something that supports hardware acceleration. All 3d games redraw the entire screen every single frame, so graphics cards are used to it - and we're talking millions of triangles. I'm pretty sure you won't quite get there with roguelikes :)

Krice: Perhaps check out SFML instead of SDL. It supports windowed hardware acceleration, and is also a little more high level and easy to use.

Overall, make sure you're working with the right tools and libraries, and it shouldn't be a problem!
"Get it hot! Hit it harder!!!"
 - The tutor warcry

One of They Who Are Too Busy

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #6 on: July 14, 2013, 07:37:05 PM »
Quote
Just pick something that supports hardware acceleration. All 3d games redraw the entire screen every single frame, so graphics cards are used to it - and we're talking millions of triangles. I'm pretty sure you won't quite get there with roguelikes

You might be surprised how fast poorly written rendering code will bog a card down. Also, how well you write your rendering logic will determine how portable your application is.

Quote
Krice: Perhaps check out SFML instead of SDL. It supports windowed hardware acceleration, and is also a little more high level and easy to use.

I think he's using software drawing mode on purpose, as SDL can use opengl for hardware acceleration just as well as SFML.



@OP,

I'm working on a cross-platform console emulator right now, and I make a distinction between the logical console and a canvas. The logical console is a container that stores a buffer of all the drawing cells and provides drawing methods. The canvas is an interface that represents the rendering context. The drawing methods of the console send instructions on only what has changed to the canvas, so only new drawing updates take place. The canvas also obviously takes care of resizing and analyzing font metrics to determine how to best fill the screen.

A separate asset manager can parse a file that contains a mapping of keys to assets that will serve as a library for the canvas. This way you can make it easy to modify the graphics with a simple set of instructions. Instead of passing characters, you pass keys through which the canvas looks up the appropriate glyph. You can then do animations logically by simply swapping out the appropriate glyph. You don't even need much foresight here- simply have a key for every action you implement. The animation won't get used unless it exists.


miki151

  • Rogueliker
  • ***
  • Posts: 264
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #7 on: July 14, 2013, 07:57:02 PM »
You might be surprised how fast poorly written rendering code will bog a card down. Also, how well you write your rendering logic will determine how portable your application is.
This is very true, 3d action games were here way before hardware acceleration. Preparation for rendering is where costly mistakes are easy to make, by copying and/or constructing a lot of short-lived objects.
KeeperRL, Dungeon Keeper in roguelike style:
http://keeperrl.com

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #8 on: July 14, 2013, 09:13:06 PM »
@OP,

I'm working on a cross-platform console emulator right now, and I make a distinction between the logical console and a canvas. The logical console is a container that stores a buffer of all the drawing cells and provides drawing methods. The canvas is an interface that represents the rendering context. The drawing methods of the console send instructions on only what has changed to the canvas, so only new drawing updates take place. The canvas also obviously takes care of resizing and analyzing font metrics to determine how to best fill the screen.

A separate asset manager can parse a file that contains a mapping of keys to assets that will serve as a library for the canvas. This way you can make it easy to modify the graphics with a simple set of instructions. Instead of passing characters, you pass keys through which the canvas looks up the appropriate glyph. You can then do animations logically by simply swapping out the appropriate glyph. You don't even need much foresight here- simply have a key for every action you implement. The animation won't get used unless it exists.

Hmm. However, when one is using the console, does one call the drawing methods for every tile in the world that is visible on the screen each render, or only those that have changed? As the latter means the game logic then needs to inform the rendering system every time something is done to the map. Is that an entanglement of game logic and rendering?

And if one wants to do "chase" scrolling (which I mentioned earlier), where the view always scrolls as the player moves, doesn't this require every character on the console to be changed anyway? So how much benefit is there from adding the extra code complexity (as opposed to a simple every-tile redraw loop)?
« Last Edit: July 14, 2013, 09:32:14 PM by mike3 »

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #9 on: July 14, 2013, 11:08:41 PM »
@OP,

I'm working on a cross-platform console emulator right now, and I make a distinction between the logical console and a canvas. The logical console is a container that stores a buffer of all the drawing cells and provides drawing methods. The canvas is an interface that represents the rendering context. The drawing methods of the console send instructions on only what has changed to the canvas, so only new drawing updates take place. The canvas also obviously takes care of resizing and analyzing font metrics to determine how to best fill the screen.

A separate asset manager can parse a file that contains a mapping of keys to assets that will serve as a library for the canvas. This way you can make it easy to modify the graphics with a simple set of instructions. Instead of passing characters, you pass keys through which the canvas looks up the appropriate glyph. You can then do animations logically by simply swapping out the appropriate glyph. You don't even need much foresight here- simply have a key for every action you implement. The animation won't get used unless it exists.

Hmm. However, when one is using the console, does one call the drawing methods for every tile in the world that is visible on the screen each render, or only those that have changed? As the latter means the game logic then needs to inform the rendering system every time something is done to the map. Is that an entanglement of game logic and rendering?


No. That's the responsibility of your canvas. The console represents the graphical state, whereas the canvas is the rendering context. For a Roguelike, you don't really need to use double-buffering, so you aren't redrawing the scene every frame-- instead, you just pass changes to the canvas and the canvas makes adjustments accordingly. Regardless, it's the canvas's responsibility to determine how to handle changes to its own state.

Correct- the Console should not be called in game logic, See below.

Quote
And if one wants to do "chase" scrolling (which I mentioned earlier), where the view always scrolls as the player moves, doesn't this require every character on the console to be changed anyway? So how much benefit is there from adding the extra code complexity (as opposed to a simple every-tile redraw loop)?

The Console is a logical object but it's part of the application logic, not the game logic. The other half of it is a window manager. The WM divvies up console regions to different panes and manages the focus pane (the one that gets input). Panes contain widgets and represent pop-up messages, the information log, any UI element, and the game Camera. The WM and its panes could be completely static and super simple, but the abstraction will be valuable regardless.

The Camera is a logical object that describes what drawing information will get sent to its containing pane. Basically, you have a map of the game. The camera describes what region of that map to draw-- in the case of a scrolling game, it will be centered on the player character (and most likely collide with the edge of the map). In this way, the pane can be moved around without affecting what the player sees. You could also have multiple panes with cameras focusing on different things. This is kind of the basics of MVC (model, view, controller).

Oh-- and you will have things that don't get updated on your screen every frame-- UI elements, some duplicate adjacent tiles, etc. It's good practice and should be trivial to implement.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #10 on: July 14, 2013, 11:27:28 PM »
Hmm. However, when one is using the console, does one call the drawing methods for every tile in the world that is visible on the screen each render, or only those that have changed? As the latter means the game logic then needs to inform the rendering system every time something is done to the map. Is that an entanglement of game logic and rendering?

No. That's the responsibility of your canvas. The console represents the graphical state, whereas the canvas is the rendering context. For a Roguelike, you don't really need to use double-buffering, so you aren't redrawing the scene every frame-- instead, you just pass changes to the canvas and the canvas makes adjustments accordingly. Regardless, it's the canvas's responsibility to determine how to handle changes to its own state.

Correct- the Console should not be called in game logic, See below.

So what does the game logic do when it makes a change to the map? Also, isn't the canvas inside the console? Where are these drawing methods exposed to? What calls them? I thought that the canvas was behind the drawing methods, buried inside the console, and thought the drawing methods are then called by some outer render/update routine. So what calls the drawing methods and how?

Quote
And if one wants to do "chase" scrolling (which I mentioned earlier), where the view always scrolls as the player moves, doesn't this require every character on the console to be changed anyway? So how much benefit is there from adding the extra code complexity (as opposed to a simple every-tile redraw loop)?

The Console is a logical object but it's part of the application logic, not the game logic. The other half of it is a window manager. The WM divvies up console regions to different panes and manages the focus pane (the one that gets input). Panes contain widgets and represent pop-up messages, the information log, any UI element, and the game Camera. The WM and its panes could be completely static and super simple, but the abstraction will be valuable regardless.

The Camera is a logical object that describes what drawing information will get sent to its containing pane. Basically, you have a map of the game. The camera describes what region of that map to draw-- in the case of a scrolling game, it will be centered on the player character (and most likely collide with the edge of the map). In this way, the pane can be moved around without affecting what the player sees. You could also have multiple panes with cameras focusing on different things. This is kind of the basics of MVC (model, view, controller).

Oh-- and you will have things that don't get updated on your screen every frame-- UI elements, some duplicate adjacent tiles, etc. It's good practice and should be trivial to implement.

How is the pane-handling done with regards to the console object? How does the WM stand in relation to the console object? What provides the features to draw to the panes? What draws to them -- i.e. if there's a pane for the game area, what draws to this?

Also, does this console/canvas/WM thing also work when considering a tile-based game? What if you want to make it flexible so one can add both a tile and text version?
« Last Edit: July 14, 2013, 11:35:04 PM by mike3 »

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #11 on: July 15, 2013, 01:02:14 AM »
Quote
How is the pane-handling done with regards to the console object? How does the WM stand in relation to the console object? What provides the features to draw to the panes? What draws to them -- i.e. if there's a pane for the game area, what draws to this?

A WM arranges Panes on the screen in a logical manner and sets which pane has focus (gets input).

A pane is a managed area of the console. Each pane draws to an area of the console that is provided by the WM. Typically , a pane will contain widgets. A widget is managed GUI feature-- a widget could be a line of text, a checkbox, a button, or a paragraph of scrollable text. A pane will likely contain many widgets, each with their own descriptions of how they should be drawn.

As mentioned before, a Camera draws to the pane for the game area. The current game area consists of a logical map of objects (your game grid). The Camera is a logical object that describes what area of the map to render to the pane. If the offset of the camera is consistent with the player's avatar, then it will be a 'chase'-camera (the camera could just be a location and then the pane just draws as much as it can). The camera doesn't really do anything but look at the state of the game (which is the map) and send information.

Now-- if you want to add fancy animations or effects and such, you can use some looping update calls to the map (like, to draw a colorful effect or something), which should cascade through your camera to tell the pane to update the console.

Quote
Also, does this console/canvas/WM thing also work when considering a tile-based game? What if you want to make it flexible so one can add both a tile and text version?

Anytime you want flexibility, you just make an abstraction. The difference between a tile and text version is nothing more than how assets are managed. The asset tied to a goblin, for example, isn't 'g,' but a unique-identifier. Then you can have a config file that lists mappings of unique-ids to assets. When the canvas gets text, it draws text, when it gets a unique-id, it looks up the appropriate asset, caches it, and draws that. It could be either a text or a tile- doesn't matter.

If the sprite/tile is animated, then the canvas will need a way to manage that on its end.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #12 on: July 15, 2013, 02:19:45 AM »
Quote
How is the pane-handling done with regards to the console object? How does the WM stand in relation to the console object? What provides the features to draw to the panes? What draws to them -- i.e. if there's a pane for the game area, what draws to this?

A WM arranges Panes on the screen in a logical manner and sets which pane has focus (gets input).

A pane is a managed area of the console. Each pane draws to an area of the console that is provided by the WM. Typically , a pane will contain widgets. A widget is managed GUI feature-- a widget could be a line of text, a checkbox, a button, or a paragraph of scrollable text. A pane will likely contain many widgets, each with their own descriptions of how they should be drawn.

As mentioned before, a Camera draws to the pane for the game area. The current game area consists of a logical map of objects (your game grid). The Camera is a logical object that describes what area of the map to render to the pane. If the offset of the camera is consistent with the player's avatar, then it will be a 'chase'-camera (the camera could just be a location and then the pane just draws as much as it can). The camera doesn't really do anything but look at the state of the game (which is the map) and send information.

Now-- if you want to add fancy animations or effects and such, you can use some looping update calls to the map (like, to draw a colorful effect or something), which should cascade through your camera to tell the pane to update the console.

Quote
Also, does this console/canvas/WM thing also work when considering a tile-based game? What if you want to make it flexible so one can add both a tile and text version?

Anytime you want flexibility, you just make an abstraction. The difference between a tile and text version is nothing more than how assets are managed. The asset tied to a goblin, for example, isn't 'g,' but a unique-identifier. Then you can have a config file that lists mappings of unique-ids to assets. When the canvas gets text, it draws text, when it gets a unique-id, it looks up the appropriate asset, caches it, and draws that. It could be either a text or a tile- doesn't matter.

If the sprite/tile is animated, then the canvas will need a way to manage that on its end.

So then I think of something like this:

Canvas object:
    has methods to "receive a change" (what does that mean?)
    actually draws to the screen (??)

Console object:
   has a Canvas object inside it.
   has drawing methods
   has methods to get input from the keyboard (yes? or no?)
   has a method to designate an area as a pane

Pane:
   Has drawing methods too(?)
   Has event handlers to trap on input(?)

Widget:
   Has drawing function
   Has event handlers to trap input

Window manager:
   Holds panes and associated UI widgets. Manages
   which one has "focus".
   Takes in input events and passes them to the widget and pane with focus

Camera:
   Has a position, map reference, and function to draw the map to its associated Pane. (how much of the map does this tell the lower facilities to draw?)

Is this about right? What about the spots where I'm still unclear (marked with "?"s)
« Last Edit: July 15, 2013, 04:22:59 AM by mike3 »

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #13 on: July 15, 2013, 07:00:48 AM »
Sorta.

Canvas is an interface that gets filled out by platform dependent code. Essentially, you would put a wrapper for ie. Flash, OpenGL, or Curses here. My canvas interface really only has one method, that is to commit an array of drawing instructions. In this case, each instruction contains a glyph (either a character or a key), a position, foreground color, and background color (I have everything nullable so that we can only pass what information we want).

Console is a logical object that describes the state of the canvas. Drawing information sent to the console is cached and propagated to the canvas for actual rendering. While the Console/Canvas CAN be rationalized as a single interface, I personally prefer composition over inheritance here. The Console does NOT take input. It's purely an obfuscation of the platform rendering library (curses, opengl, flash, html5, etc). We'll have another object that handles the input and mapping, but I don't think that should be bundled with the console (though it could be). "You might say- wait a minute! Any platform rendering library is also going to have a way to get input- shouldn't the console also handle that information?" It's too monolithic for my taste. I want the console to be a one-way object for writing data to the screen. I'd prefer to have some other object deal with the I/O, even if it uses the same reference to the platform that the console does.


The WM->Pane->Widget relationship could be thought of as a tree. The WM is a relative root node, a Pane is a sibling, and a widget is a leaf. The WM is really just a special Pane that caches what child pane is getting input. Any pane could contain any number of other panes, using the same logic as the WM. A widget is an actual drawing object. While a pane may have a background color (or even just a tint), it isn't sending very many drawing instructions (though it could have a title and scroll-bars)- just telling the widgets when they need to send theirs. The purpose of the Pane is to manage the local drawing context-- That is, the relative origin that it's children are being drawn to. In this sense, each widget/pane has a local and global position- where a pane inherently describes a rendering depth.

The Camera should be pretty straightforward. Your logical map stores spatial information. The camera just starts from one corner and iterates through to the next grabbing the asset key of each entity in the map (an empty space or floor tile is also an entity).

Asset Manager - Is a mapping of glyph-codes (an array key/index) to assets. You can ensure clarity by using strings as keys but an enumeration or consts might be more to your liking. The Canvas will receive a drawing instruction in the form of a glyph-code and color information, it will then pass the glyph-code into the asset manager to fetch which asset it is supposed to use, and then draw accordingly. The Asset Manager will likely read a configuration file that describes this mapping. Strings are cool because you can use no-brainer concatenations to  describe different animations if you want. You can even encode information into the key to allow the Asset Manager to parse for and composite a group of glyphs-- such as if you want to show equipment and stuff. That sort of thing should be an afterthought though- as long as you keep things modular it should be easy to implement later.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #14 on: July 15, 2013, 08:58:49 AM »
So if I get this right, then the Camera loops through every tile/entity within its field of view each frame, while the actual rendering, which is done by the Canvas, only invokes the actual business-end platform-dependent draw calls for whatever tiles have actually changed? Or is that change-tracking done by the Console?

How simple should the "drawing instructions" be? Just one glyph per instruction? Does this mean that when drawing text (for example), we need a whole heap of drawing instructions for each and every character in the text?

Now I have another question with regards to the input thing: some low-level libraries like Curses have the input as bound up with the display in interesting ways. In particular, in Curses, one gets input with the wgetch() function, which takes a window as parameter, which is a display concept. Yet in our code we keep display and input separate. Does this mean that when using Curses, we should simply not use the Curses window mechanism at all, and just use the getch() and other non-"w" functions (which use the default window, "stdscr")?