Author Topic: Rendering question  (Read 27115 times)

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #15 on: July 15, 2013, 09:44:52 PM »
Quote
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?

Change tracking is done by the console. Otherwise, yes.

Quote
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?

The Console should offer drawing short-cuts. I have 3 right now, draw_text, fill_rect, and plot_char. They all do the same thing in that they gather a list of drawing instructions and send them to the canvas.

I also have stack drawing methods so that a user can put many commands between a begin_draw() and an end_draw() without updating the canvas until the end_draw().
« Last Edit: July 16, 2013, 12:27:21 AM by requerent »

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #16 on: July 16, 2013, 12:12:14 AM »
Quote
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?

Change tracking is done by the console. Otherwise, yes.

So does this mean the console must contain a buffer or something of the sort that stores the state of the screen so it knows what characters have been changed? What do you do when dealing with tiles, where the screen is now single pixels and can also have non-tile objects like text?

Quote
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?

The Console should offer drawing short-cuts. I have 3 right now, draw_text, fill_rect, and plot_char. They all do the same thing in that they gather a list of drawing instructions and send them to the canvas.

OK, but how simple should the drawing instructions the canvas uses be? Considering that a lot of low-level libraries like Curses and SDL do provide some features for text drawing -- wouldn't these be more efficient, or what (and on libraries without it, could be faked anyway)?

Also, another question about panes: the area where the game world is drawn is a pane, no? But don't panes contain widgets? What kind of "widgets" does it have that allow it to represent the game world?
« Last Edit: July 16, 2013, 12:22:42 AM by mike3 »

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #17 on: July 16, 2013, 03:32:37 AM »
Quote
So does this mean the console must contain a buffer or something of the sort that stores the state of the screen so it knows what characters have been changed? What do you do when dealing with tiles, where the screen is now single pixels and can also have non-tile objects like text?

Yes, but I'm talking specifically about a console emulator. The Console doesn't even know what the resolution of the application is, so it can't represent pixels (unless you increase the logical resolution of the console in such a way that the canvas can only render each tile as a pixel-- but that violates the entire point of emulating a console).

How is text not tiled? Each character is a tile just as any sprite would be.

Quote
OK, but how simple should the drawing instructions the canvas uses be? Considering that a lot of low-level libraries like Curses and SDL do provide some features for text drawing -- wouldn't these be more efficient, or what (and on libraries without it, could be faked anyway)?

You will use those to draw characters into tiles.

Quote
Also, another question about panes: the area where the game world is drawn is a pane, no? But don't panes contain widgets? What kind of "widgets" does it have that allow it to represent the game world?

You could say that the Camera is a widget.



Here, consider the following example.

https://dl.dropboxusercontent.com/u/10791198/Rebrogue.swf

And here are the drawing instructions for the above example. This is in HaXe, which is a language with a number of meta-programming features, so some of it may not make sense, but you can see the correlation between method calls and their effect in the above .swf.

Code: [Select]
        var blueOnly = function(c:Int):Int
        {
        var t = c.toRGB();
        t[0] = t[1] = 0;
        return t.toHEX(); };


        var gradient = function(x:Int,y:Int):Int return x*0x110011+y*0x001111;
        var random = function(_,_,_):Int return Math.floor(Math.random() *0xffffff);
               
                       //colors may be an int or a function that takes up to 3 parameters- x, y and original color.
                       //this makes tinting and gradients a no-brainer


                console.setDimension([16,6]);
                console.clean();
                console.begin_draw();
                console.fill_rect([0,0],[16,6],random,random,"#");
                console.fill_rect([0,0],[16,6],null,gradient); //null preserves the original information
                console.plot_char([0,0],"X",0xffffff,0x0);
                console.draw_text([0,1],"Blah blah blah",null);
                console.fill_rect([0,0],[5,5],0xff00ff,0x0f0f0f);
                console.fill_rect([12,3],[16,6],null,blueOnly);
                console.fill_rect([12,0],[16,3],blueOnly);
                console.end_draw();

The value of having a logical console is that we can perform additive drawing without sending more information to the renderer than we need to. Many of the tiles in the above example get drawn upon multiple times, but only one draw call is made for each modified tile (in end_draw). Some of these draws are a function of the original color or only modify colors without modifying text or vice versa. This provides support for transparency, tinting, lighting effects, and other cool things in a way that is concise and flexible.

This isn't getting into a WM, panes, or widgets as I haven't quite finished that up yet, but maybe seeing an example of how it could work will help you rationalize how it should look on the back-end.


Where would tiles fit in here?
In plot_char or fill_rect, if the string passed is length > 1, then the canvas can perform a library look-up to see if there is a corresponding sprite for that string.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #18 on: July 16, 2013, 06:39:48 AM »
"How is text not tiled? Each character is a tile just as any sprite would be."

Well, when I think of a game with graphical tiles (which is what I mean), I imagine a screen divided up by pixels. And graphical tiles and text characters need not be the same size, and may even overlap. This would seem to require pixel-level coordinates. So how then do you detect changes?


requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #19 on: July 16, 2013, 08:42:04 AM »
"How is text not tiled? Each character is a tile just as any sprite would be."

Well, when I think of a game with graphical tiles (which is what I mean), I imagine a screen divided up by pixels. And graphical tiles and text characters need not be the same size, and may even overlap. This would seem to require pixel-level coordinates. So how then do you detect changes?

I have been talking solely about console emulation. That means a discrete grid occupied by a single glyph- either a sprite (animated or not) or a text character. If you want to take full advantage of 2D rendering (and have floating text), then you're no longer emulating a console and just doing standard 2D graphics. Things like WMs and Panes still apply, and you may still want to emulate a console but have extra drawing effects, in which case you would just use your canvas to circumvent the console emulation.

There are a few techniques for optimizing 2D graphics, but if you're going all floaty text, then there are likely going to be additional graphical elements that could dirty your screen in unpredictable ways. In this case, you should blit and buffer, which your rendering library will probably do for you as long as you use it correctly.


mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #20 on: July 16, 2013, 09:19:06 AM »
Thanks again.

I have one more question, related to "panes": if "panes" get the input, does this mean that one would have a trap handler or something on the main game "pane" that runs the game logic (i.e. the logic routine is called from a "pane" trap handler) when a key is depressed and said pane has focus? This would seem to differ from the "game state object" approach mentioned in another thread of mine here, as here it seems all menus and what not can simply be implemented via trap handlers and focus-switching and so dispensing with the need for the dedicated game state object mechanism.

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #21 on: July 16, 2013, 02:05:04 PM »
The WM can be the input handler-- all you do is pass the input down to the focused pane and let it decide. A pane will have its own keymap for whatever actions it can perform.

edit: Well-- your input handler will convert input into 'keys', which the pane will map to an action. Basics of keymapping.
« Last Edit: July 16, 2013, 04:32:53 PM by requerent »

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #22 on: July 16, 2013, 10:41:57 PM »
The WM can be the input handler-- all you do is pass the input down to the focused pane and let it decide. A pane will have its own keymap for whatever actions it can perform.

edit: Well-- your input handler will convert input into 'keys', which the pane will map to an action. Basics of keymapping.

So am I right in my conclusion that it dispenses with the need for the "game state mechanism" for handling menus and so forth that I just mentioned?

Also, what about what I asked here about using Curses, with its "windows" and how they're tied up with the getting of input?:
http://forums.roguetemple.com/index.php?topic=3497.msg29553#msg29553
« Last Edit: July 16, 2013, 11:34:39 PM by mike3 »

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #23 on: July 17, 2013, 03:21:23 AM »
The WM can be the input handler-- all you do is pass the input down to the focused pane and let it decide. A pane will have its own keymap for whatever actions it can perform.

edit: Well-- your input handler will convert input into 'keys', which the pane will map to an action. Basics of keymapping.

So am I right in my conclusion that it dispenses with the need for the "game state mechanism" for handling menus and so forth that I just mentioned?

Also, what about what I asked here about using Curses, with its "windows" and how they're tied up with the getting of input?:
http://forums.roguetemple.com/index.php?topic=3497.msg29553#msg29553

I would likely make the input handler a separate logical object. All it does is handle the platform specific code for receiving input. It would then send meaningful interpretations of that input to the WM, who would then pass it on to a specific pane, from whence that pane's mapping of that input to some action would take effect.

A WM IS a state machine. the current state is the focused pane that receives input... Ah- I should clarify a little bit. A pane doesn't necessarily have to be nested within the logical boundaries of its parent pane-- for example, you may have a tiled pane open a floating pop-up menu. In this case, the menu would be registered with the WM instead of the parent pane, but the menu would still pass focus/data to its parent after its function has been served.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #24 on: July 17, 2013, 05:17:55 AM »
I would likely make the input handler a separate logical object. All it does is handle the platform specific code for receiving input. It would then send meaningful interpretations of that input to the WM, who would then pass it on to a specific pane, from whence that pane's mapping of that input to some action would take effect.

The thing I was wondering about though was that in Curses, the "window" mechanism seems like a natural one for implementing panes (especially with the Curses panel library), but Curses doesn't maintain that input/window separation, in fact it joins the two together. So it seems like to keep logical separation, you can't use the Curses window mechanism.

A WM IS a state machine. the current state is the focused pane that receives input... Ah- I should clarify a little bit. A pane doesn't necessarily have to be nested within the logical boundaries of its parent pane-- for example, you may have a tiled pane open a floating pop-up menu. In this case, the menu would be registered with the WM instead of the parent pane, but the menu would still pass focus/data to its parent after its function has been served.

However, should a pane "crop" whatever is drawn inside it (as opposed to floating on top)? Doesn't this require additional functionality/computations in the underlying Console or 2D graphics system?

Anyway, this seems neater than my original game state object system, it looks to resolve some of the various conundrums with that better. I like it and I think I might use it :)

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #25 on: July 17, 2013, 05:41:26 AM »
Quote
The thing I was wondering about though was that in Curses, the "window" mechanism seems like a natural one for implementing panes (especially with the Curses panel library), but Curses doesn't maintain that input/window separation, in fact it joins the two together. So it seems like to keep logical separation, you can't use the Curses window mechanism.

Unfortunately, I'm not that familiar with curses. If you want to be able to swap out the renderer, I'm not sure if you can rely on a platform specific implementation of windows, unless it's possible to logically abstract the entire curses drawing interface. If you want to use curses specifically and don't have an interest in another drawing methodology, go for it. The I/O handling of panes is more conceptual-- if what curses does is intuitive and makes sense to you, go for it. I only prefer a top-level I/O mechanism so that I can modify raw input data if needs be (like if we want to catch shift/ctrl at the application level instead of the pane level).

Quote
However, should a pane "crop" whatever is drawn inside it (as opposed to floating on top)? Doesn't this require additional functionality/computations in the underlying Console or 2D graphics system?

It's up to you. In most cases, you will have a clear understanding of how you want your UI to look, so you don't need any special logic. You could crop or not-- just depends on what you want to do. The rules with which a pane renders its widgets depends on the pane. A pane is just the base container for widgets and should not set very hard restrictions on what can be done with them. In most cases a pane will represent a partition of the screen that you render specific objects to, but the way in which those objects are rendered might not limit their drawing instructions to within that pane. The pane is basically a local coordinate system for drawing groups of widgets.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #26 on: July 17, 2013, 07:33:26 AM »
I think I've got it figured out now. Thanks! Hopefully I'll be able to get this working.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #27 on: July 21, 2013, 04:18:05 AM »
I just wondered another thing: where would one put the various "higher-level" rendering functions, like to render boxes and other more complex shapes used to make widgets?

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #28 on: July 21, 2013, 07:58:36 PM »
If we're still talking about a console emulator (that is, the ONLY BASIC drawing method we have is plot_char), some drawing utilities could be in the logical console. Every complex drawing method, in a console, is just an aggregation of plot_chars. So, to draw a widget, that widget will send the instructions necessary to draw itself.


This is oftentimes called a display list. You have a tree of drawable objects that contain other drawable objects that we traverse when drawing the scene (also called a scenegraph). Each node in the graph represents a coordinate (relative to the parent) and possibly drawing instructions (and transformations).

When we draw a widget, we've already scoped to a local point, we just need instructions to draw. We would probably make a library of common methods, like draw_circle and daw_rect, to make things simpler-- though, more importantly, we would try to make sure similar widgets use the same drawing instructions whenever possible or make it so that a widget is a composition of components-- like scrollbars, textfields, etc. At this point though it's just semantics.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #29 on: July 21, 2013, 09:10:35 PM »
If we're still talking about a console emulator (that is, the ONLY BASIC drawing method we have is plot_char), some drawing utilities could be in the logical console. Every complex drawing method, in a console, is just an aggregation of plot_chars. So, to draw a widget, that widget will send the instructions necessary to draw itself.


This is oftentimes called a display list. You have a tree of drawable objects that contain other drawable objects that we traverse when drawing the scene (also called a scenegraph). Each node in the graph represents a coordinate (relative to the parent) and possibly drawing instructions (and transformations).

When we draw a widget, we've already scoped to a local point, we just need instructions to draw. We would probably make a library of common methods, like draw_circle and daw_rect, to make things simpler-- though, more importantly, we would try to make sure similar widgets use the same drawing instructions whenever possible or make it so that a widget is a composition of components-- like scrollbars, textfields, etc. At this point though it's just semantics.

So would this "tree of drawable objects" be a separate data structure from the pane/widget one (even though, say, panes contain widgets -- doesn't this already form such a "tree"?) or not?

And would those "circle" ,"rect", etc. drawing methods in that "library" be just "free floating" functions and not class members? If members, what would they be members of? The console, as you seem to hint in the first part of the message?