Author Topic: Rendering question  (Read 18641 times)

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #30 on: July 21, 2013, 10:38:49 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?

Yes, it's the same thing. 3D rendering works the same way, if you're curious. The position of an object is just an offset from its parent-- same idea for windows/panes/widgets etc. It's a little different with compositing, but that doesn't matter in this case.

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

Doesn't matter really.

A good way to do it is to make it so that the Console accepts a 2D array of glyphs (struct representing character, foreground and background color) and a starting position. Then you could have a static class produce graphs to be passed into the Console. Alternatively, you could have these functions work directly with the console or be a part of the console-- it's up to you. Whatever makes most OOP sense. Since we're working with a logical console, it doesn't hurt to have advanced drawing operations there. However, proper OOP would put these methods in a helper object.

You could define a typedef for 2d glyphs called a Graph (or shape or whatever) and use that as the parameter for a console method "draw_graph." Then you can produce as many drawing libraries that you want, so long as they have methods that produce graph objects.


IE.
Code: [Select]
draw_rect(console, rect) //call drawing functions internally by passing the console
Library.draw_rect(console,rect) //for better organization put function in static object (most recommended)
Console.draw_rect(rect) //or for simpler libraries put directly in console (least recommended)

plot_rect(rect):graph //pass rectangle information and return a graph object
Library.plot_rect(rect):graph //from static class
Console.draw_graph(graph) // pass graph object into console drawing method.

The top set is faster, but gives you less flexibility. While the second set is a bit more memory intensive but will allow you to work directly with the graph object. Since the console acts as a logical buffer, it really isn't necessary to have a graph object at all, but you might find it useful-- especially for caching certain drawing methods-- IE, a circle of a particular radius could be easier to draw if you cache it as a graph after calculating it once.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #31 on: July 21, 2013, 10:56:35 PM »
Thanks again.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Window manager question (was Re: Rendering question)
« Reply #32 on: July 23, 2013, 02:09:10 AM »
I now have another question, related to window managers: If a bunch of things happen during the turn logic (which would be triggered by keypresses going to the pane showing the game world) that require updating the screen, e.g. displaying text messages, or an explosion appears, or something -- should one mix calls to the window manager's redraw function with the logic like that, or handle that separately, like by passing events to the window manager to be handled later in some main message/event loop where all getting of input and redraws are centralized? If separate, then how does one preserve the ordering and sequentiality of those things? Note that just having an event queue with "redraw events" added to it wouldn't seem to work, since the windows' states would be changing, which means that by the time that queue is finally handled after the logic completes, the windows have changed state several times and the redraws would only redraw to their last state at the time control returns to the event loop.

I suppose this ties in with the "separating render and logic" concern I mentioned in another thread here, but am curious as to how it's done in the context of this window manager-based system.

requerent

  • Rogueliker
  • ***
  • Posts: 355
  • Karma: +0/-0
    • View Profile
Re: Rendering question
« Reply #33 on: July 23, 2013, 10:54:22 PM »
I now have another question, related to window managers: If a bunch of things happen during the turn logic (which would be triggered by keypresses going to the pane showing the game world) that require updating the screen, e.g. displaying text messages, or an explosion appears, or something -- should one mix calls to the window manager's redraw function with the logic like that, or handle that separately, like by passing events to the window manager to be handled later in some main message/event loop where all getting of input and redraws are centralized? If separate, then how does one preserve the ordering and sequentiality of those things?[/quote]

If you are not using real-time rendering, then a change to the game state should inform a window that it needs to redraw (nothing else will!). In real-time rendering, the window is either checking the game state each frame to see if it needs to redraw, or it waits to receive incoming events and redraws.

Each window just reads the state of the game and draws that information in a way that is pertinent to that particular window (status bars, maps, text notifications- etc). You either need to tell a window to update or have the window always updating.

Quote
Note that just having an event queue with "redraw events" added to it wouldn't seem to work, since the windows' states would be changing, which means that by the time that queue is finally handled after the logic completes, the windows have changed state several times and the redraws would only redraw to their last state at the time control returns to the event loop.

You don't need an event queue. You simply tell a window when it is dirty and that it needs to redraw.

Quote
I suppose this ties in with the "separating render and logic" concern I mentioned in another thread here, but am curious as to how it's done in the context of this window manager-based system.

Separation of rendering and logic has more to do with calling drawing instructions within the logic of the game. Telling a graphical object to redraw is fine. The purpose of keeping them separate is so that we can rewrite either one without effecting the other.

In real-time games, it's common to update the rendering at 60 HZ and update the logic a little faster, say, 100 HZ. The idea is that the logic is always updating slightly faster than rendering, so that you get a more fluid visual experience. If logic updated slower, objects would appear to move in a choppy manner. To optimize render and logical updates, their code needs to be in separate places. The Logical side of the application acts upon the game state, modifying and updating it in various ways, contingent upon input. The Rendering side reads the game state, in an agnostic way, and prints the output. This is a basic I/O relationship.

In a roguelike, this is a complete non-issue, but I think the example may help to illustrate why you want to keep it separate. After all, in the text messages, we need to send explicit information to the text message window (game log). That means calling something like "tmWindow.log(myEnum.combat,combatInfo,whatever)" for each game interaction that occurs. The Window does the drawing, but the logic tells it what to draw. The main point is that the Logic isn't deciding how that information is drawn.

mike3

  • Rogueliker
  • ***
  • Posts: 125
  • Karma: +0/-0
    • View Profile
    • Email
Re: Rendering question
« Reply #34 on: July 24, 2013, 08:53:07 PM »
Thanks. Now I understand the "separation" part better.