Return to “Dev Logs”

Post

Re: [Josh] Friday, August 17, 2018

#16
vector67 wrote:
Sat Aug 18, 2018 9:34 am
This may seem like a stupid question to those of you au fait with games programming, but as a web developer I have to ask why HTML/CSS is not the solution here. It's a very mature design with more than a decade of competent people working on it in order to do exactly this, create aesthetically pleasing and functional UIs. Instead of JavaScript, you could just use lua. I understand that now you probably won't go back and change this, but I'd like to know why this wasn't an option when you began your search for a solution.

I am very glad that you're getting back to gameplay again, and that this problem is done and partially dusted.
1. As you've correctly pointed out: HTML and CSS is just that: a design, not a technology. To implement HTML/CSS based UI in your game you would have to use something like CEF, I'll talk on that later.

2. HTML and CSS is not tailored for application UI design. It was initially created to display static documents. So it naturally uses a retained model, all the cons of which are outlined in Josh's own post.

3. HTML and CSS was made for people who can't program which brings in many limitations and takeaways, Josh isn't such a person.

4. "just use lua" means taking away one of the biggest benefits of web development: community. You wouldn't be able to use any of the libraries created for the actual web unless you used javascript.

5. Being "mature" does not mean being good. In fact both HTML and CSS are terrible, because they carry a terrible burden of having to support their own legacy. They kinda resemble C++ in that.

6. Performance. Take chrome (and CEF is just embedded chrome), state of the art web browser, run a profiler and try clicking around a few modern websites which use react or angular. You'll quickly see what I mean. Switching from one page to another can take as much as 100ms (that's one of the better cases, in practice a lot of websites have ~400ms CPU-bound page switches), that's 6 frames dropped on a 60Hz display, and 15 frames dropped on a 144Hz one. That is absolutely unacceptable for any realtime application, especially for a game. Opening a default bootstrap modal has frames where repainting takes up to 50ms on my MBP2015, this is pure CSS at work.

Also most AAA games use Scaleform for UI which is basically flash, not HTML.
Post

Re: [Josh] Friday, August 17, 2018

#17
DoctorGester wrote:
Tue Aug 21, 2018 8:07 am
6. Performance. Take chrome (and CEF is just embedded chrome), state of the art web browser, run a profiler and try clicking around a few modern websites which use react or angular. You'll quickly see what I mean. Switching from one page to another can take as much as 100ms (that's one of the better cases, in practice a lot of websites have ~400ms CPU-bound page switches), that's 6 frames dropped on a 60Hz display, and 15 frames dropped on a 144Hz one. That is absolutely unacceptable for any realtime application, especially for a game. Opening a default bootstrap modal has frames where repainting takes up to 50ms on my MBP2015, this is pure CSS at work.
This.

To have the same performance of a game UI as I get from websites would be unacceptable. HTML/CSS can be quite heavy, especially if you're trying to embed a large amount of images in the page.

Frankly, I think it's slightly ridiculous how resource intensive some webpages are.
I am literally and wholly in love with myself.
Post

Re: [Josh] Friday, August 17, 2018

#18
DoctorGester wrote:
Tue Aug 21, 2018 7:55 am
Great post as usual, Josh!

I just wanted to share my opinion on the whole RM vs IM debacle since I have recently implemented a somewhat complex and fully responsive UI using dear imgui internal framework (only using dear imgui behaviors and fully custom styling and layouting). Basically, not to take away from your achievement, but you've implemented what dear imgui already had from the beginning. Dear imgui retains a fair bunch of info about windows so you can query their sizes before laying out your elements. Regarding to a frame delay: I'm sure there are many cases where this is a problem, but in a common case where, for example, you have a button drawn last which is supposed to toggle visibility of an element drawn first what you could do is discard the whole UI on click and recompose it again all within the same frame. My UI takes about 0.5ms of CPU time per frame so it's not a huge deal.

Thanks for the interesting feedback DoctorGester!

Honestly, if embedding Dear ImGui in our engine had been feasible, it's possible that I would have gone that route. I have the utmost respect for that library, as mentioned in this log! After some attempts, however, it became clear that embedding it in our engine would take a prohibitive amount of work due to the fact that it leverages C++ extensively. That's not too much of an issue for libraries that we can keep isolated to engine-level (Bullet, for instance), but it's quite a problem for libraries that we need to access from script. All script->engine access is via LuaJIT's FFI, which, due to the unfortunate state of the (lack of a standard) C++ ABI, requires a C API. So yes, in some sense implementing a subset of Dear ImGui is not far off from what I was attempting to do.

That being said, I know from experience that the layout issue does matter. Yes, we can query content regions in DImGui, however, to achieve adaptive layouts we still essentially have to do all the work ourselves. Consider the second screenshot of the HmGui demo that I showed. The DImGui code to produce that is rough!! While using DImGui to implement the LT Editor, I ended up doing most of the layout work myself in Lua (sounds like you may be doing something similar as you mention custom layout). Honestly, this work does add up quickly when trying to build game interfaces.

So, yes, Dear ImGui is excellent and if the embedding work were easier we probably could have made it work. That being said, it's definitely the case that HmGui retains significantly more layout information than Dear ImGui, and this adds up to significant savings in code complexity.

Interestingly, the code complexity savings even pay off at the implementation level. For example, Dear ImGui's checkbox function:

Code: Select all

bool ImGui::Checkbox(const char* label, bool* v)
{
    ImGuiWindow* window = GetCurrentWindow();
    if (window->SkipItems)
        return false;

    ImGuiContext& g = *GImGui;
    const ImGuiStyle& style = g.Style;
    const ImGuiID id = window->GetID(label);
    const ImVec2 label_size = CalcTextSize(label, NULL, true);

    const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); // We want a square shape to we use Y twice
    ItemSize(check_bb, style.FramePadding.y);

    ImRect total_bb = check_bb;
    if (label_size.x > 0)
        SameLine(0, style.ItemInnerSpacing.x);
    const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size);
    if (label_size.x > 0)
    {
        ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
        total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
    }

    if (!ItemAdd(total_bb, id))
        return false;

    bool hovered, held;
    bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
    if (pressed)
        *v = !(*v);

    RenderNavHighlight(total_bb, id);
    RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
    if (*v)
    {
        const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
        const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
        RenderCheckMark(check_bb.Min + ImVec2(pad,pad), GetColorU32(ImGuiCol_CheckMark), check_bb.GetWidth() - pad*2.0f);
    }

    if (g.LogEnabled)
        LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]");
    if (label_size.x > 0.0f)
        RenderText(text_bb.Min, label);

    return pressed;
}

HmGui's checkbox function:

Code: Select all

bool HmGui_Checkbox (cstr label, bool value) {
  HmGui_BeginGroupX();
  self.group->focusStyle = FocusStyle_Underline;
  if (HmGui_GroupHasFocus(FocusType_Mouse) && self.activate)
    value = !value;
  HmGui_SetPadding(4, 4);
  HmGui_SetSpacing(8);
  HmGui_SetStretch(1, 0);

  HmGui_Text(label);
  HmGui_SetAlign(0.0f, 0.5f);
  HmGui_SetStretch(1, 0);

  HmGui_BeginGroupStack();
  HmGui_Rect(16, 16, self.style->colorFrame);
  if (value) {
    HmGui_Rect(10, 10, self.style->colorPrimary);
    HmGui_SetAlign(0.5f, 0.5f);
  }
  HmGui_EndGroup();
  HmGui_SetStretch(0, 0);
  HmGui_EndGroup();
  return value;
}

Obviously not a fair comparison, as there's more going on in the Dear ImGui implementation. But the thing to note is how much of the ImGui code is concerned with low-level layout. HmGui, on the other hand, is able to use higher-level layout primitives, cutting complexity quite a bit.

It would be really interesting to see in the future if Omar adds these kinds of retained layout features to Dear ImGui :geek: Frankly I suspect Dear ImGui may one day take over the world :lol:

---
Victor Tombs wrote:
Sat Aug 18, 2018 12:42 am
I doubt if you will be surprised to read that after skimming through the bulk of your dev log, Josh, I tended to concentrate on your "Conclusion". I understand that what you've done with the GUI will make a worthwhile contribution to the game I will eventually be playing, and I thank you for that. :)

I am not surprised Victor, I'm glad you found the nugget that I left in there for readers like yourself :D

jonathanredden wrote:
Fri Aug 17, 2018 10:33 pm
Oh, thank you for saving me from my most miserable week at ups as a package handler(SO MANY ENVELOPES AND IREGS)!
-50 stress

It makes me happy to know that I can relieve a bit of stress with my dev toils. I hope you're having a better week :(
“Whether you think you can, or you think you can't--you're right.” ~ Henry Ford
Post

Re: [Josh] Friday, August 17, 2018

#20
Hi,

I am not a player of your game, but I just wanted to reply to the conceptual GUI model. For the past 6 months, I've worked on the Azul GUI framework (https://azul.rs/). Azul is mostly immediate mode but it doesn't redraw at 60fps, so it's "retained mode", if you want to call it that. It uses a HTML-like DOM and CSS, while it's not production-ready, it might be worth a look for the conceptual theme. I created this framework to solve my problems in Rust (a competitor to C / C++), a speciality about Rust is that it has no inheritance, so any OOP-like approach like in many retained-mode GUI frameworks doesn't work because they heavily rely on inheritance. And it doesn't allow mutable pointers to be aliased. I set out to solve that problem with azul.

The problem with IMGUI-like frameworks is the layout. One component can't know about the size of the other components, because that would inflict on the purity of "one component = one function" rule. On the other hand, you have OOP-style GUIs where essentially the root window contains and knows about all of its contents. This creates two problems: first, the graphical details and resources are stored inside of the data model, conflating the application data with the GUI data. Second, communicating between two visually seperate components requires advance shenanigans, like child widgets having pointers to their parent widgets or relying on static data - and once you put threads into that mix, you have race conditions galore.

So to solve the layout problem, I disallow users to directly render-to-the-screen, but rather render into a tree-like data structure (a document object model or DOM). This tree structure provides me with enough information about the hierarchy of elements that I can use a constraint solver to position elements relatively to each other.

GUIs (or at least display lists) are tree-like datastructures, from a rendering standpoint. A root window contains some rectangles, which in turn contain other rectangles or text or images and so on. So it isn't too surprising on why I picked a HTML-like tree approach: It fits the problem nicely - even a retained mode GUI data model will eventually become a tree-like data structure if you view inheritance as a tree model (class A deriving from class B is similar to a parent node A having a child node B).

In your GUI, you highly rely on some global mutable renderer state, like the current text color. The reason I don't like this approach is because it's hard to debug which function set what state, it's easy to forget the cleanup (i.e. forgetting to set text_color back to black after you're done rendering the object) and it is generally thread-unsafe, unless you use mutexes to protect your global state, (which would decrease performance).

So for styling I went for an immutable CSS stylesheet. Immutable because it is only parsed and loaded once at startup and then never changed again. If you look at the web today, the major performance bottleneck isn't CSS or HTML. It's the massive amount of JavaScript on each page. CSS in itself is a decent solution because you can hot-reload it from a file for quick changes, you can easily share properties between components without buying into an entire OOP inheritance model and it can withstand API changes very easily - at one point I changed the entire underlying architecture of the CSS rendering with a huge decrease in memory, but without changing one single line of CSS.

Next "immediate mode" often gets conflated with 60fps game-style UIs, which is wrong - you can write things in an immediate mode way, but only redraw the screen when necessary. I do this by requiring the user to give me an `UpdateScreen` enum back so that I can see if the callback that was called changes the UI (so then the framework needs to re-render the screen). At max, azul consumes 1 - 4 % CPU and if the user does nothing, it uses 0% - so just because it's immediate mode doesn't mean it has to redraw itself at 60fps.

Lastly, you have the application data modeling, i.e. how do we store the data, how do we go about modifying and re-rendering it. This is where many frameworks go (in my opinion) the wrong way. Many retained-mode GUI frameworks do this:

Code: Select all

int main() {
      auto my_gui = Window();
      window.add_button("Hello world");
      window.run();
}
The problem with this is that it doesn't scale to more complex UIs, it's what I call "optimizing for your Hello-World line count". Why is that? Well, essentially, these frameworks think that you just set up your UI once (in the main loop) and then display it and boom, done. But that's not the case, you often have dynamic content that changes state based on user interaction, like a user selecting different screens. This approach leads to very static UIs, i.e. UIs where changing the content of a window is a pain in the ass.

So in order to solve that I allow users to pass function pointers in the rendering (the `layout` method) that have unique mutable access to the entire application state. Meaning, one callback can change the entire app state - so you have the problem of mutable-pointer-to-parent-widget solved and two visual components can communicate with each other because they both know about the same data model, but they don't know about each other (i.e. the button doesn't know that it increases a labels content, it just knows that it increases a number - and the label just knows that it should re-render itself with that number, but it doesn't know about the button itself).

Azul does not have the problem of 1 frame delays, because it's essentially: user input -> callback is run -> callback updates data model (your business logic goes here) -> rerender data model if necessary -> update screen with new rendered UI. Right now, azul has a frame time of 1 - 4 ms and I realize that this is too slow for games. But who knows, maybe someone can come up with a different implementation.

This model has drawbacks, especially regarding default methods (i.e. a text input that updates itself without the application programmer needing to explicitly write the updating code) and positioning elements based on dynamic positioning (something like JavaScripts `div.getComputedStyle()`). But both of these problems are solvable, but this post is already long enough. So yeah, those were my thoughts on the current state of GUI concepts. In practice (I use azul for an 2d rendering application of my own), it works very well. Of course it's in the early stages, but I thought it may be a good inspiration on how to (conceptually) build hybrid UIs.

Cheers
Post

Re: [Josh] Friday, August 17, 2018

#21
Hi fschutt.
Welcome on the forum!

Thanks for the insightful post. Learning everyday something here...
I agree that the UI should not have to redraw from scratch every frame. In order to be an interface with a human and allow interaction, it must be fairly static. So not sure I understand why it must be sooo fast, but I never programmed games, so there is that...
Image
Post

Re: [Josh] Friday, August 17, 2018

#24
jonathanredden wrote:
Tue Sep 04, 2018 11:13 pm
we need that devlog. Now!

"Soon" works for me, but OK. ;)

I do have some things I'm wondering, though:

* What gameplay got prioritized for implementation over the past couple of weeks? I'm personally looking forward to hearing about AI that works across multiple star systems with good LOD simulation, as that's a critical milestone. But I could totally get behind Josh relaxing a little by building some more specific, fun systems like dogfighting or trading or faction management. (What? Yes, all those can be fun!)

* Is there any intention of bringing aboard a new intern?

* What tasks remain on the burndown list, has their scope (which translates to time to design/build/test) been estimated, and what's the total time remaining before Minimum Viable Product (pre-polish) is achieved?

Anyway, I'll be happy to see the next "here's what's new" whenever that happens.
Post

Re: [Josh] Friday, August 17, 2018

#26
jonathanredden wrote:
Tue Sep 04, 2018 11:13 pm
we need that devlog. Now!
Hold ye thine horses and grow thine self a pair of patience :p
Flatfingers wrote:
Wed Sep 05, 2018 12:41 am
I could totally get behind Josh relaxing a little by building some more specific, fun systems like dogfighting

Oh god, please no. Save for maybe some basic UI, I'd hope we'd been ready to go to beta with dogfighting since PAX.

As for faction management, I'm totally okay with something skeletal. In depth faction management is supposed to be a post 1.0 feature anyway, so laying the groundwork is good, getting a reputation system going is good, but being able to fiddle with organizational details and account for non-player parity, can wait for later imho.
Trading probably still requires he tackle the pricing problem he wracked his head against. It's definitely a major and important feature, and maybe giving a day each week or an hour each day to work on it would probably be a good idea, but there's so many other things that need doing, I imagine it will have to be on the back burner until a mental break through on the issue occurs. But again, that's just me.

* What tasks remain on the burndown list, has their scope (which translates to time to design/build/test) been estimated, and what's the total time remaining before Minimum Viable Product (pre-polish) is achieved?
I'd also like to have at least a rough estimate of what what remains before beta, or heck, what remains before we can get some videos/screenshots to show the people we've been telling about LT for years (I showed a couple people the PAX video and they were kind of amazed it was a real thing. That it looked really cool and they wanted to see moar).
Image
Challenging your assumptions is good for your health, good for your business, and good for your future. Stay skeptical but never undervalue the importance of a new and unfamiliar perspective.
Imagination Fertilizer
Beauty may not save the world, but it's the only thing that can
Post

Re: [Josh] Friday, August 17, 2018

#27
The specific examples I suggested of "relatively small (but necessary) gameplay systems" that Josh could implement shouldn't be taken too literally. The idea I was trying to convey is that I think it would be OK, if he felt like it, for Josh to work on something low-stress (but still a meaningful part of the game) for a while before hunkering down for one of the Big Systems.

Other possibilities are mining, or sensors (including assigning emission types to game objects), or ship class generation algorithms -- basically any feature that's relatively small, is a valuable part of the overall game, and is guaranteed to be something that can be implemented successfully (even if not perfectly). Let the guy have a break if he wants one!

As for a task list with estimates, I'm not expecting Josh to show us his full Trello list. :D Again, the point isn't "I demand to see your specific tasks!"; it's that it would be nice to know that there is a list, it's still being updated, tasks have scope estimates equivalent to time durations, the whole thing rolls up to yield a tentative MVP date, and so far Josh is still on track to achieve a MVP version of Limit Theory within some reasonable delta of that date (or, if not, will occasionally do a re-estimation pass to produce a new "OMG it's actually done" date).

And the point of this is not to artificially impose some kind of "I must hit that arbitrary date" pressure; that's unhelpful. The point is to have some way to see that you're making progress along a timeline to completion of a project, because that's a great tool for remaining motivated. You may not see progress every day. You might go backwards some days! But over weeks and months, you can see real and satisfying motion toward the finish line... if you list and track your tasks.

Anyway, some kind of reassurance here would be nice, not only because I'm aching to play LT as imagined but because I look forward to Josh being able to point to a playable LT and say, "I made that, and it's good."

That's going to be a great day.
Post

Re: [Josh] Friday, August 17, 2018

#28
And on the 6th anniversary, Josh said "Let there be Beta!" And there was Beta. And Josh looked upon the Beta and said it was good enough to ship... To the beta tier backers... :geek: ;)
Image
Challenging your assumptions is good for your health, good for your business, and good for your future. Stay skeptical but never undervalue the importance of a new and unfamiliar perspective.
Imagination Fertilizer
Beauty may not save the world, but it's the only thing that can
Post

Re: [Josh] Friday, August 17, 2018

#29
Hyperion wrote:
Thu Sep 06, 2018 12:56 am
And on the 6th anniversary, Josh said "Let there be Beta!" And there was Beta. And Josh looked upon the Beta and said it was good enough to ship... To the beta tier backers... :geek: ;)
Two more days until that September 8th arbitrary deadline is up. I do wonder what progress will be shared with us tomorrow and how it might influence the feature list which Talvieno made. I hope that sensor code is largely complete, along with dog fighting code and mining. We've seen mining and combat since the first LT Kickstarter video. If those systems aren't in place by now I'd be seriously concerned about how long it might take to implement something like the full working economy and ship-station construction. It'll be 2019 in just a few months, I would like to know what progress we have made since 2012 in a bullet list format.

7 years of development, wow.
Image

Online Now

Users browsing this forum: Damocles and 2 guests

cron