Angband Forums

Angband Forums (http://angband.oook.cz/forum/index.php)
-   ToME (http://angband.oook.cz/forum/forumdisplay.php?f=9)
-   -   ToME 2.4.0-ah released (http://angband.oook.cz/forum/showthread.php?t=8541)

Gwarl August 11, 2018 23:58

It is indeed the gcu port, that's my universal point of compatibility for all the variants. It would be a nightmare patching in the code to do anything else for each variant individually.

I have vague plans for some angband-specific javascript version of noteye in the future, which would then also solve graphics for every variant at once.

AnonymousHero August 12, 2018 08:31

Quote:

Originally Posted by Gwarl (Post 132745)
It is indeed the gcu port, that's my universal point of compatibility for all the variants. It would be a nightmare patching in the code to do anything else for each variant individually.

Yeah, that was what I was afraid of... :(

(What I've been experimenting with is basically completely gutting the Term subsystem and going towards supporting only an Allegro5-based frontend -- and hopefully Windows via cross-compilation, but that's a bit further off. The whole UI/keyboard subsystem is so unbelievably hackish and broken... :/ )

Quote:

Originally Posted by Gwarl (Post 132745)
I have vague plans for some angband-specific javascript version of noteye in the future, which would then also solve graphics for every variant at once.

I've actually been thinking of just doing away with the native GUI programming wholesale and changing T2 to just be a RESTful server and have a little bit of Javascript in the browser instead. It would be soooo much less painful.

(Just had a look at NotEye and it looks like even more hacks piled on top... it's kind of miraculous that such a monstrosity could even be made to work.)

t4nk August 12, 2018 20:28

Quote:

Originally Posted by AnonymousHero (Post 132750)
Yeah, that was what I was afraid of... :(

(What I've been experimenting with is basically completely gutting the Term subsystem and going towards supporting only an Allegro5-based frontend -- and hopefully Windows via cross-compilation, but that's a bit further off.

Why gut the Term, though?

Quote:

The whole UI/keyboard subsystem is so unbelievably hackish and broken... :/ )
IMO, there is nothing wrong with it conceptually. It's just a quality-of-implementation issue.

AnonymousHero August 13, 2018 17:09

Quote:

Originally Posted by t4nk (Post 132781)
Why gut the Term, though?


IMO, there is nothing wrong with it conceptually. It's just a quality-of-implementation issue.

I suppose most things could be argued to be quality-of-implementation, but it's a stretch in the T2 code base, at least. (No idea what you're using as a reference? Perhaps Vanilla...? I haven't actually looked into the vanilla code base, so these might not apply there. I'm guessing that it's at least vastly improved over T2 when the code base was modernized.)

Still, I'd argue that these are design problems:
  • The term code has one key queue per term, but requires that the active term be set to the first term (angband_term[0]) when 'interacting' with the keyboard queue, etc. The keyboard queue (singleton) should never have been tied to a term (multiple).
  • The handling of the UI event loop (singleton) is intermingled with the handling of each individual term. Again there's some nonsense where the current term must be set to the 0th one.
  • Generally speaking the "current term" is horrifically tangled into the code base all over the place. There should never have been such a thing as the "current term". (The concept doesn't really make sense.). This is the one that closest to a QoI issue, but I think it could be argued either way.

(I'm sure there's more that I'm forgetting right now.)

t4nk August 13, 2018 22:47

Quote:

Originally Posted by AnonymousHero (Post 132825)
I suppose most things could be argued to be quality-of-implementation, but it's a stretch in the T2 code base, at least. (No idea what you're using as a reference? Perhaps Vanilla...? I haven't actually looked into the vanilla code base, so these might not apply there. I'm guessing that it's at least vastly improved over T2 when the code base was modernized.)

Vanilla's ui-term.c is the same thing... To my knowledge, I was the only person since Ben Harrison to substantially change this thing :) The Term is indeed horribly written, but I think its fundamental ideas are sound.

Quote:

The term code has one key queue per term, but requires that the active term be set to the first term (angband_term[0]) when 'interacting' with the keyboard queue, etc. The keyboard queue (singleton) should never have been tied to a term (multiple).
True, and there is no reason why it must be like that. This is very easy to change, though.

Quote:

Generally speaking the "current term" is horrifically tangled into the code base all over the place. There should never have been such a thing as the "current term". (The concept doesn't really make sense.). This is the one that closest to a QoI issue, but I think it could be argued either way.
I'm not familiar with Allegro, but a quick look at the documentation suggests the standard pattern:
Code:

void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap);
"This function selects the bitmap to which all subsequent drawing operations in the calling thread will draw to. To return to drawing to a display, set the backbuffer of the display as the target bitmap, using al_get_backbuffer. As a convenience, you may also use al_set_target_backbuffer."
That's how it's done in low level APIs (OpenGL, DirectX). Of course, it's not the only possible way of doing things, but it's pretty standard and it doesn't seem overly crazy to me.

When working on textui2, I came to the conclusion that it's useful to divide the Terms into two kinds; permanent (map, messages, sidebar, monster list) and temporary (inventory, options, knowledge menu - the stuff that goes away when the user presses ESC). Organizing temporary terms as a stack, with the top of the stack being the current target of rendering operations, is very convenient (and there were no problems with using this architecture while writing ncurses frontend). OTOH, permanent terms don't need to be on the stack.

I'm actually (very slowly) writing an Angband-insired roguelike (in D :)). So I've been thinking quite a bit about the architecture of the IO subsistem lately. The Term as an ADT (a two dimensional array of colored characters that keeps track of their updates since the last render) is surely worth keeping, and so is the stack of Terms. Anyway, hopefully you'll proceed with your ideas - I'm adding your TOME repo to bookmarks :)

AnonymousHero August 14, 2018 15:42

Quote:

Originally Posted by t4nk (Post 132834)
Code:

void al_set_target_bitmap(ALLEGRO_BITMAP *bitmap);
"This function selects the bitmap to which all subsequent drawing operations in the calling thread will draw to. To return to drawing to a display, set the backbuffer of the display as the target bitmap, using al_get_backbuffer. As a convenience, you may also use al_set_target_backbuffer."
That's how it's done in low level APIs (OpenGL, DirectX). Of course, it's not the only possible way of doing things, but it's pretty standard and it doesn't seem overly crazy to me.

... but in e.g. Allegro (which is obviously built on top of whatever the platform supports, in my case OpenGL) they do kind of the same, but there's actually a good reason for it, namely that all high-performance graphics APIs are done that way. Why? Well, graphics hardware functions very differently to a regular computer and you (the programmer) really need to be aware of that and think in terms of the underlying mechanism -- if you e.g. try to blit from several hundred character-sized textures to the display, then you're going to have a bad time. (What you must do is create a "font atlas" which contains all the characters and use that for blitting from. Etc. Generally speaking 'switching states' is slow on GPUs because of very high latency. You really just want to fill the pipeline.)

The problem is much lesser in programming graphics because the "display list" only sticks around for a single frame and then you start over. (Also known as "immediate mode".) For a game like Angband, that's pretty simple to manage because the scope is very limited -- I think the entirety of the code which does this in my T2 branch is about 50-100 lines? I'm pretty sure I can eventually get rid of the "damage" tracking that the term structure does -- leaving me with a simple 2D array of char+attribute... which might as well be inside the frontend code. (In fact the frontend code already has such a structure because I want it to be able to redraw without having to call back into the term code.)

Just to be clear: There are much better ways to manage the global drawing context which al_set_target_bitmap or whatever just hide under the carpet, such that you could actually have the compiler check your work, but they require pretty advanced type systems which C in the very least doesn't really support. They'd also get pretty hairy in C++, I imagine. Since most of the graphics APIs target C or C++, that's what we get.

Quote:

Originally Posted by t4nk (Post 132834)
When working on textui2, I came to the conclusion that it's useful to divide the Terms into two kinds; permanent (map, messages, sidebar, monster list) and temporary (inventory, options, knowledge menu - the stuff that goes away when the user presses ESC). Organizing temporary terms as a stack, with the top of the stack being the current target of rendering operations, is very convenient (and there were no problems with using this architecture while writing ncurses frontend). OTOH, permanent terms don't need to be on the stack.

Interesting -- I hadn't thought of doing it this way, but I think I'm going for a design where there's no "current target". All drawing methods must have an explicit target term where they will draw. (That will usually come from a formal function parameter, but obviously there will a top-level dispatching coming from the "window options", e.g. "what do I draw in which window".)

Quote:

Originally Posted by t4nk (Post 132834)
I'm actually (very slowly) writing an Angband-insired roguelike (in D :)). So I've been thinking quite a bit about the architecture of the IO subsistem lately. The Term as an ADT (a two dimensional array of colored characters that keeps track of their updates since the last render) is surely worth keeping, and so is the stack of Terms. Anyway, hopefully you'll proceed with your ideas - I'm adding your TOME repo to bookmarks :)

I'm not saying that the "2D grid" is a bad abstraction -- it's the intermingling of concerns of the event loop, drawing to the screen and keyboard input into one big ball of mud where it's really unclear what's responsible for what (and how 'many' there are of each).

I'm not convinced in any way that tracking "damage" at a single-character level is a useful thing -- just redraw from scratch for every frame[1]. An even reasonably modern GPU should be able to draw Angband at several hundred (if not thousands) of FPS.

(The exceptions here would be old frameworks where this type of drawing is not really supported very well. My experiences in SDL2.x and Allegro 5 suggest that at least there's no problem there.)

[1] Here's another mismatch between that UI code and the modern world. You really want do just draw on every frame (if there have been any changes) and the Angband/T2 code contains sleep, etc. in various places in the code. These could end up being pretty non-trivial to avoid because changing the structure around an event loop might end up being difficult... I'm not quite giving up yet because it might be reasonable to with coroutines or similar.

EDIT: Anyway, this is ranting at this point... :).

Nick August 14, 2018 23:17

Quote:

Originally Posted by t4nk (Post 132834)
When working on textui2,

Veering temporarily off-topic (sorry AH), I'm really sorry that is not incorporated in V yet - both takkaria and I have thought about it and got no further than that. I'm tempted to say I'll add that to the list of things for the next version...

AnonymousHero August 15, 2018 12:52

@Nick Heh, I think it's just descended into ranting at this point, so a break from that is nice :).

I definitely agree about textui2, btw. It looked really nice.

t4nk August 15, 2018 21:44

Quote:

I'm not saying that the "2D grid" is a bad abstraction -- it's the intermingling of concerns of the event loop, drawing to the screen and keyboard input into one big ball of mud where it's really unclear what's responsible for what (and how 'many' there are of each).
Well, one thing to note is that there are only two situations when the screen must be redrawn:
1) When the game is waiting for user input (so the user should see the latest state of the game)
2) When some animation is played

Overly frequent screen redraws is the number one cause of slowdowns in textui1 (and requires hacks to work around), since most displays can be redrawn no more than 60 times per second. Thus, there is some synchronization between handling events and drawing to the screen.

Quote:

I'm not convinced in any way that tracking "damage" at a single-character level is a useful thing -- just redraw from scratch for every frame[1]. An even reasonably modern GPU should be able to draw Angband at several hundred (if not thousands) of FPS.
It depends. SDL2's high-level API is too slow for that (and I did use font atlases - see main2-sdl2:make_font_cache()). You might also want to (eventually) write a frontend for terminal emulator using termbox or some such... Anyway, z-term.c's approach to that is a bit too complicated, I currently use
Code:


struct TermCell
{
    dchar codepoint = 0;
    RGBA foreground = Color.white;

    // Hack - the biggest codepoint is 0x10_FFFF, which is 21 bits;
    // that leaves 11 more bits in a dchar, which we use for bitflags.
    // The flags are used only in this module; don't forget to clear them.

private:

    enum _Mask : uint
    {
        dirty = 1 << 31,
        clear = 0x1F_FFFF,
    }

    TermCell dirty() const pure
    {
        return TermCell(this.codepoint | _Mask.dirty,
                        this.foreground);
    }

    TermCell clear() const pure
    {
        return TermCell(this.codepoint & _Mask.clear,
                        this.foreground);
    }

    bool isDirty() const pure { return this.codepoint & _Mask.dirty; }
    bool isClear() const pure { return (this.codepoint & _Mask.clear) == this.codepoint; }
}

Quote:

Veering temporarily off-topic (sorry AH), I'm really sorry that is not incorporated in V yet - both takkaria and I have thought about it and got no further than that. I'm tempted to say I'll add that to the list of things for the next version...
Well, ping me if you decide to do that :) I recall there were some updates to ui-display.c and some other things. Anyway, textui2 didn't go to waste after all - I'm now finding it useful for remembering how SDL2 works :)

Gwarl September 25, 2018 16:52

Bump. If we can get user directory command line arguments back this week, we'll have a competition next month.


All times are GMT +1. The time now is 03:57.

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