Angband.oook.cz
Angband.oook.cz
AboutVariantsLadderForumCompetitionComicScreenshotsFunniesLinks

Go Back   Angband Forums > Angband > Development

Reply
 
Thread Tools Display Modes
Old January 28, 2013, 21:33   #1
Narvius
Knight
 
Narvius's Avatar
 
Join Date: Dec 2007
Location: Poland, Katowice
Age: 27
Posts: 589
Narvius is on a distinguished road
Efficient drawing... wat.

I'm trying to write a roguelike (not based on Angband, per se, but peeking into its code from time to time, both to see how to do certain things and how NOT to do certain things).

Now, in Angband, when you start smashing random move buttons, everything gets updated immediately - no noticeable movement lag whatsoever.

My SDL-based mini-prototype, however... it's not anywhere near as fast. The screen isn't even 800x600, and redraws on keypresses (that's not entirely true, but a workable approximation). When I mash buttons, there is some really noticable lag - 20-40ms? Not sure.

Anyways. Due to this - since I couldn't find 'em in the code, so it's maybe better to ask the people who have a working understanding of it - I've been wondering:

1) ...what the hell is the underlying graphics-drawing thing? (I'm using the default Win7 binaries)
2) What triggers screen redraws?
3) How heavily is the screen-redrawing routine itself optimized?

Thanks in advance.
__________________
If you can convincingly pretend you're crazy, you probably are.
Narvius is offline   Reply With Quote
Old January 28, 2013, 21:45   #2
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,972
Derakon is on a distinguished road
I'd guess that your system is redrawing the entire screen every frame. Unfortunately, this is slow, especially with simple loops and software rendering (i.e. not relying on hardware acceleration). There are a few optimizations you can do without dipping into OpenGL, though.

First and foremost, you want to keep track of which tiles have been modified between one draw call and the next. These are your "dirty" tiles. Don't bother drawing any others. So for example, if a monster moves from tile A to tile B, then both tiles are now dirty and must be redrawn. Everything else can just stay put.

Secondly, map scrolling is fairly common. Since all of the tiles are "modified" by map scrolling, it doesn't work under the above mechanism. But what you can do is draw the current map to the screen, but offset by the scrolling amount. Then fill in dirty tiles as normal. So e.g. if you scroll the screen 1 tile to the right, then all you need to draw is the current map, offset 1 tile, plus a border of tiles (newly revealed by the scrolling), and any dirty tiles.

Thirdly, if you have overlays that can be shown and hidden, keep those on separate surfaces. For example, keep the map and the inventory displays on separate surfaces; when the inventory is hidden, just draw the map as it was, unmodified.

The bottom line is that each blit call you make exacts a constant cost in addition to the time it spends doing the actual drawing. Eliminating blit calls will save you a lot of time, therefore.

The actual drawing code Angband uses is going to be OS-dependent, so look at main-win or main-cocoa or whatever. But I'd wager you can get similar performance by a) doing the above, and b) possibly switching to OpenGL-based rendering. Stick every glyph you want to be able to render onto a texture, and then throw textured quads around. You can send entire arrays of coordinates to OpenGL as a stream of data, and then farm things off to hardware, which is very fast.
Derakon is offline   Reply With Quote
Old January 28, 2013, 21:52   #3
Narvius
Knight
 
Narvius's Avatar
 
Join Date: Dec 2007
Location: Poland, Katowice
Age: 27
Posts: 589
Narvius is on a distinguished road
Whoah - that was quick, many thanks.

It seems I'll be spending some of them hours on my drawing code then.
__________________
If you can convincingly pretend you're crazy, you probably are.
Narvius is offline   Reply With Quote
Old January 29, 2013, 20:06   #4
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
In short: Use double buffering and always draw into an in-memory bitmap/texture. (Regardless of whether you're using 2D or OpenGL.)

If you're using X11, avoid X11 calls at all costs -- they synchronous and at least two orders of magnitude slower than in-memory operations. Use Cairo (or something similar) to draw in-memory and then blit the surface to screen in a single X11 operation. All Angband variants that I know of disobey this rule (they issue one X11 operation per "cell" on screen) and fail miserably when scrolling or using "Center screen on player".
AnonymousHero is offline   Reply With Quote
Old January 29, 2013, 21:20   #5
takkaria
Veteran
 
takkaria's Avatar
 
Join Date: Apr 2007
Posts: 1,941
Donated: $40
takkaria is on a distinguished road
Quote:
Originally Posted by AnonymousHero View Post
In short: Use double buffering and always draw into an in-memory bitmap/texture. (Regardless of whether you're using 2D or OpenGL.)

If you're using X11, avoid X11 calls at all costs -- they synchronous and at least two orders of magnitude slower than in-memory operations. Use Cairo (or something similar) to draw in-memory and then blit the surface to screen in a single X11 operation. All Angband variants that I know of disobey this rule (they issue one X11 operation per "cell" on screen) and fail miserably when scrolling or using "Center screen on player".
The X11 port is explicitly designed to use no external libraries except Xlib. If you want more, I'd suggest SDL.
__________________
takkaria whispers something about options. -more-
takkaria is offline   Reply With Quote
Old January 29, 2013, 21:36   #6
Derakon
Prophet
 
Derakon's Avatar
 
Join Date: Dec 2009
Posts: 8,972
Derakon is on a distinguished road
For what it's worth, Pyrel uses widget libraries (Qt / wxWidgets) to handle its drawing. In my opinion, they're superior to SDL in that you can have multiple traditional windows, each with a canvas you can draw anything to. You can also use standard OS dialogs easily. SDL can only kind of fake multiple windows and you have to code every UI widget yourself; it's doable, but there's no real reason to force yourself to go that route.

However, this does mean that you have to use the library's drawing code, or else switch to OpenGL rendering, which is not especially newbie-friendly.
Derakon is offline   Reply With Quote
Old January 30, 2013, 06:26   #7
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by takkaria View Post
The X11 port is explicitly designed to use no external libraries except Xlib. If you want more, I'd suggest SDL.
AFAIUI, using the XImage type functions in Xlib, it should be possible to draw everything in-memory and then blit the whole final bitmap in one go(*). AFAICT it is the "blit a single character at a time" thing which completely destroys performance on X11/Xlib (because it's synchronous and requires a round-trip to the X server).

SDL is a non-starter for me (at least) because it only supports a single terminal window. (At least 1.2.x doesn't support more, and it seems 2.x still hasn't made it into very many distributions.) It supports splitting that single window, but that won't let me use mulitple physical screens the way I want.

(*) I don't know if Xlib supports all drawing operations on XImages -- I'm guessing no -- so I'm not suggesting that this is trivial endeavor if all you can use is Xlib. However, it is the right way to do it if you're writing from scratch. If you use something like Cairo it should be pretty trivial.
AnonymousHero is offline   Reply With Quote
Old January 31, 2013, 11:35   #8
LostTemplar
Knight
 
Join Date: Aug 2009
Posts: 670
LostTemplar is on a distinguished road
Use OS default bitmap drawing routines, or just normal ASCII text, again with default drawing, e.g. if you want just text under windows create console application. Use another 'frame buffer' for your 'game engine' to draw to.
E.g. for a tile based roguelike your game should mogify some array of tile indexes, then call a rendering function, that get images for individual tiles and forms a bitmap, then use standard OS bitmap display function. You can update frames, based on time (for background animation), or after every player turn.

Partial updates also work, are faster, but somewhat less universal, and may be more buggy.
LostTemplar is offline   Reply With Quote
Old January 31, 2013, 19:05   #9
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by LostTemplar View Post
Partial updates also work, are faster, but somewhat less universal, and may be more buggy.
The sentence is a bit ambiguous, but I take it that you're referring to partial updates from the bitmap, right? (Otherwise round-tripping will probably kill performance because of syscall overhead.)
AnonymousHero is offline   Reply With Quote
Old January 31, 2013, 19:27   #10
LostTemplar
Knight
 
Join Date: Aug 2009
Posts: 670
LostTemplar is on a distinguished road
I thought about creating and then drawing the bitmap, just not full window size, if it is not needed, I would still prefer to limit partial updates to some kind of rectangular area, not like individual tiles or character. Yes I am very concerned about system call overhead cost, it is often very high.
LostTemplar is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 04:09.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.