Immediate Mode Model/View/Controller

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Immediate Mode Model/View/Controller

Beitrag von CodingCat »

Pflichtlektüre für alle, die über die Entwicklung einer UI nachdenken: Immediate Mode Model/View/Controller
Zuletzt geändert von Krishty am 14.01.2014, 13:39, insgesamt 1-mal geändert.
Grund: Wir haben es jetzt lange genug falsch geschrieben.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Artikelempfehlungen, interessante Publikationen o.Ä.

Beitrag von Chromanoid »

Danke für den Link! Darüber bin ich auf diesen einleitenden Abschnitt gestoßen, dessen Wahrheiten man sich immer wieder vor Augen führen sollte:
OOPs - nasty traps in Object Oriented Programming

Zu IMGUI: Ich bin eigentlich MVVM Fan. Der IMGUI Weg erscheint mir nicht sehr skalierbar. Wenn man sowas sieht https://github.com/AdrienHerubel/imgui/ ... le_gl3.cpp juckt es doch in den Fingern, die Aufrufe in eigene Objekte zu packen. Die Parameter der Methoden werden zu Eigenschaften, man lädt die Objekte dann aus einer Datei und man möchte nur noch das Verhalten in der Anwendung beschreiben. *Zack* man ist wieder kurz davor Events zu verwenden... Vielleicht wäre ein Weg das ganze trotzdem direkt zu steuern, statt Events einfach aus der Liste die relevanten Elemente herauszusuchen und das besondere Verhalten pro Durchlauf per Methoden-Pointer einzufügen.
joeydee
Establishment
Beiträge: 1044
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Artikelempfehlungen, interessante Publikationen o.Ä.

Beitrag von joeydee »

Auch von mir ein Dank für den Link! Den Ansatz hätte ich wahrscheinlich nie als sinnvoll erachtet. Ich war sowieso auf der Suche nach einer eigenen, extrem schlanken Simple-Gui u.a. für schnelle Prototypen, aber auch skalierbar für eigene Designs. Mit meinem bisherigen Ansatz (klassisch mit Events) war ich mehr und mehr unzufrieden; das hier vereinfacht dagegen so einiges.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4854
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Artikelempfehlungen, interessante Publikationen o.Ä.

Beitrag von Schrompf »

Da ich schon einige Male mühsam interne States doppeln und deren Änderungen synchronisieren musste, gefällt mir das IMGUI-Konzept sehr gut. Ich mache mir allerdings Sorgen, ob man da auch die ganzen Produktivitätsmerkmale aktueller GUIs unterbekommt. Allen voran: eine InGame-GUI will ich auch mit Controller bedienen können. Eine Maus behält prinzipiell ihren State über mehrere Frames hinweg. Ein Controller dagegen gibt mit seinem eigenen State nur die erste Ableitung an. Wer aber berechnet daraus den neuen Zustand, also welches Widget als nächstes fokussiert ist, wenn der Button beim Zeichnen noch nicht weiß, welche Controls nach ihm noch kommen?

Animationen und sowas wären auch ein Problem, aber da könnte man noch argumentieren, dass das nur optischer Firlefanz sei. Automatisches Layout wäre das nächste Thema, das mit diesem Ansatz problematisch wird - da würde man dann wohl anfangen, alle Controls eines Frames mitzulisten und dann über mehrere Frames hinweg ein Layout dafür anzustreben. Es könnte funktionieren, aber dazu müsste man auf eine sehr nachsichtige Art die einzelnen Controls identifizieren können und Zusatzinformationen über mehrere Frames hinweg nachführen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Artikelempfehlungen, interessante Publikationen o.Ä.

Beitrag von CodingCat »

Chromanoid hat geschrieben:Zu IMGUI: Ich bin eigentlich MVVM Fan. Der IMGUI Weg erscheint mir nicht sehr skalierbar. Wenn man sowas sieht https://github.com/AdrienHerubel/imgui/ ... le_gl3.cpp juckt es doch in den Fingern, die Aufrufe in eigene Objekte zu packen. Die Parameter der Methoden werden zu Eigenschaften, man lädt die Objekte dann aus einer Datei und man möchte nur noch das Verhalten in der Anwendung beschreiben. *Zack* man ist wieder kurz davor Events zu verwenden... Vielleicht wäre ein Weg das ganze trotzdem direkt zu steuern, statt Events einfach aus der Liste die relevanten Elemente herauszusuchen und das besondere Verhalten pro Durchlauf per Methoden-Pointer einzufügen.
Ich kann mich nicht an Einzelheiten des Artikels erinnern (ich glaube gar, ich habe nur den Titel gelesen und Code überflogen), aber aus meiner Sicht verfehlst du den Punkt: Es geht genau um den Aufruf pro Control - also Code statt Daten/Objekte - egal ob die Parameter als struct oder direkt reingehen - insbesondere keine persistenten Objekte für angezeigte UI-Elemente: Das ist essenziell, da in einem großen Baum von Daten auch ganze Unterbäume von UI-Elementen von einem Frame zum anderen verschwinden können, ohne dass du Add/Remove-Events behandeln willst. Davon abgesehen bist du frei zu tun und zu lassen was du willst, ob du das Layout von Teilbäumen deiner UI im Voraus erstellst und in wie auch immer gearteten Objekten vorhälst, damit du es jedes Frame der UI füttern kannst, ist deine Sache. Der bedeutendste Anwendungsfall, der mir einfällt, ist aber ein einfaches Tree Layout, wo derartige manuelle Layouting-Features wenig nütze sind und nur unnötig Komplexität einführen.

Nebenbemerkung: Das Beispiel auf github kannte ich gar nicht, aber mein UI-Prototyp war dem nach 2 Tagen bereits haushoch überlegen. :P
Schrompf hat geschrieben:Ich mache mir allerdings Sorgen, ob man da auch die ganzen Produktivitätsmerkmale aktueller GUIs unterbekommt.
Die Zuordnung von Controls über die Frames hinweg ist tatsächlich bisweilen eine Herausforderung. Ich konstruiere mir für jedes Control einen eindeutigen Pfad von Objektzeigern und speichere diesen bei Notwendigkeit einer solchen Zuordnung für die nachfolgenden Frames. Da der Pfad in den nachfolgenden Frames immer nur zum Vergleich herangezogen wird, macht es nichts, wenn die darin enthaltenen Zeiger ungültig werden - findet sich im nächsten Frame das Control nicht mehr, wird der Pfad einfach gelöscht. Darüber kriegst du schonmal Fokus, Mouse Capture, gepufferte Eingabe etc.

Automatisches Layout ist kein Problem, solange es einfach fortlaufend ist. ;-) Ich betone nochmal, dass der wichtigste Anwendungsfall für mich die Bearbeitung von tiefen heterogenen Datenbäumen im Rahmen von Content Creation erscheint, wo die UI in erster Linie sehr gut zugänglich sein muss, ohne fancy Layout, und wo Implementierung umfassender Event-Systeme der Alptraum wäre.
Schrompf hat geschrieben:Ein Controller dagegen gibt mit seinem eigenen State nur die erste Ableitung an. Wer aber berechnet daraus den neuen Zustand, also welches Widget als nächstes fokussiert ist, wenn der Button beim Zeichnen noch nicht weiß, welche Controls nach ihm noch kommen?
Prinzipiell lasse ich im Moment tatsächlich einfach immer das betroffene Control Eingaben verarbeiten, das funktioniert für Fokus/Texteingabe soweit sehr gut. Tab-Fokus kannst du genauso umsetzen, indem du immer den Pfad des vorangegangene Objekts pufferst (Fokus zurück) bzw. ein Flag einführst, womit du dem nachfolgenden Element Fokus signalisierst (Fokus weiter).
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Intermediate Mode Model/View/Controller

Beitrag von dot »

Ich bin auch überhaupt kein Fan von retained mode. Allerdings seh ich da, insbesondere bei komplexen GUIs, mindestens ein fundamentales Problem, das imo leider nicht so leicht überspielt werden kann, wie die Diskussion des obigen immediate mode Ansatz es gerne versuchen würde: Layout. Layout computations können aufwendig werden. Mit einem immediate mode GUI habe ich, soweit ich das sehe, zwei Möglichkeiten: Entweder, ich berechne in jedem Frame das komplette Layout ständig neu, oder ich bau mir im Hintergrund selbst eine komplette retained mode Struktur und die "GUI Library" degradiert effektiv zur Rendering Library. Beides ist imo weit von einer zufriedenstellenden Lösung entfernt. Ersteres outsourced einen großen Teil der Arbeit zum User und verfehlt damit imo einen ganz wesentlichen Aspekt einer GUI Library, zweiteres ist dagegen erst wieder retained mode. Ein extrem wichtiger Spezialfall von Layout versteckt sich hinter Text Rendering. Text Layout ist extrem komplex (Unicode auf und ab, Spacing, Kerning, Justification, Text Directionality ...). Anzunehmen, dass man eben mal drawString("hello world!") macht und gut ist, ist nett, ab einem gewissen Punkt aber leider auch einfach nur noch realitätsfremd. Standardinteraktionen mit dem User wie z.B. Resizen von Controls müssten wohl durchgehend selbst implementiert werden, es kann ja nichtmal sowas wie z.B. das Konzept eines Inputfokus geben. Außerdem will ich nicht in jedem Frame für alle 223 Buttons testen müssen, ob der Mauszeiger im Button liegt oder nicht, wenn gerade mal 3 davon auch nur in der Nähe wären. Klar, natürlich kann man auch hier eine bessere Lösung dem User überlassen. Langsam stellt sich dann aber unweigerlich die Frage, inwiefern sowas nützlich ist und sich "GUI Library" nennen darf, wenn alle möglichen Dinge, die eigentlich Implementierungsdetails sein sollten, dem User nicht nur überlassen, sondern für den User schon überhaupt auch nur sichtbar werden. Auch im Hinblick auf Energieeffizienz möge so ein Ansatz in einem Spiel vielleicht gerade noch vertretbar sein, in einer normalen Anwendung ist es imo aber ein absolutes No-Go, die ganze GUI ständig neu zu rendern.

Ich hab auch schon länger drüber nachgedacht; ich denke, dass GUI vermutlich einfach von Natur aus untrennbar mit gewissem State verbunden ist, weswegen es eine völlig zustandslose Lösung rein prinzipiell gar nicht geben kann. State duplication allerdings, lässt sich wohl vermeiden. Ich denk im Moment über einen Ansatz nach, der rein presentation-spezifischen Zustand in einer retained mode Struktur hält, sich content-spezifischen Zustand wie z.B. den Text auf einem Label aber, wann immer benötigt, per Callback vom User holt. Genau in dieser Unterscheidung zwischen Presentation und Content liegt imo der eigentliche Knackpunkt; obige immediate mode Lösung setzt implizit gewissermaßen ja ebenfalls genau dort an...
Zuletzt geändert von dot am 14.01.2014, 15:32, insgesamt 11-mal geändert.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Artikelempfehlungen, interessante Publikationen o.Ä.

Beitrag von Chromanoid »

CodingCat hat geschrieben:
Chromanoid hat geschrieben:Wenn man sowas sieht https://github.com/AdrienHerubel/imgui/ ... le_gl3.cpp juckt es doch in den Fingern, die Aufrufe in eigene Objekte zu packen. Die Parameter der Methoden werden zu Eigenschaften, man lädt die Objekte dann aus einer Datei und man möchte nur noch das Verhalten in der Anwendung beschreiben. *Zack* man ist wieder kurz davor Events zu verwenden...
Ich kann mich nicht an Einzelheiten des Artikels erinnern (ich glaube gar, ich habe nur den Titel gelesen und Code überflogen), aber aus meiner Sicht verfehlst du den Punkt
Mir ging es genau darum, dass man eben schnell den Punkt verfehlt, weil es mir doch einen eher unpraktischen Eindruck macht. Das hat dot ja auch schon geschrieben. Sehr gute Ergänzung zum Thema findet man IMO auch in der verlinkten Präsentation: http://sol.gfxile.net/files/Assembly07_IMGUI.pdf Am Ende wird die Entkopplung von Design und Code angesprochen.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Intermediate Mode Model/View/Controller

Beitrag von CodingCat »

Na dann muss ich wohl mal fleißig widersprechen ... :P
dot hat geschrieben:Entweder, ich berechne in jedem Frame das komplette Layout ständig neu
Ja, genau das tue ich in meinem Prototyp, und genau das erachte ich im Kontext von Content Creation Tools als gangbar und sinnvoll ...
dot hat geschrieben:Ein extrem wichtiger Spezialfall von Layout versteckt sich hinter Text Rendering. Text Layout ist extrem komplex (Unicode auf und ab, Spacing, Kerning, Justification, Text Directionality ...). Anzunehmen, dass man eben mal drawString("hello world!") macht und gut ist, ist nett, ab einem gewissen Punkt aber leider auch einfach nur noch realitätsfremd.
... nein, im Allgemeinen ist das eigentlich nicht realitätsfremd, es sei denn du entwickelst einen WYSIWYG Text-Editor. Einfaches Alignment an festen Grenzen ist kein Problem, Kerning lässt sich genau wie Glyphzuordnung seitens UI-Bibliothek in entsprechenden Datenstrukturen sehr schnell nachschlagen, wenn notwendig kannst du auch noch problemlos eine UTF-8-Dekodierung voranstellen.
dot hat geschrieben:Standardinteraktionen mit dem User wie z.B. Resizen von Controls müssten wohl durchgehend selbst implementiert werden, es kann ja nichtmal sowas wie z.B. das Konzept eines Inputfokus geben.
Input-Fokus sowie Mouse Capture habe ich bereits wie oben skizziert implementiert, das ist kein Problem. Persistentes Resize auf Control-granularer Ebene passt tatsächlich schlecht ins zustandslose Konzept, ich sehe aber dafür im von mir angestrebten Zielkontext der Zugänglichmachung und Bearbeitung großer Datenbäume auch keine Notwendigkeit. Mittelfristiger Zustand während der Bearbeitung einer konkreten Untermenge der Daten ist hingegen kein Problem, analog zu Input-Fokus lässt sich auch gepufferte Text-Eingabe, Resize etc. für gerade aktive Controls implementieren.
dot hat geschrieben:Außerdem will ich nicht in jedem Frame für alle 223 Buttons testen müssen, ob der Mauszeiger im Button liegt oder nicht, wenn gerade mal 3 davon auch nur in der Nähe wären. Klar, natürlich kann man auch hier eine bessere Lösung dem User überlassen. Langsam stellt sich dann aber unweigerlich die Frage, inwiefern sowas nützlich ist und sich "GUI Library" nennen darf, wenn alle möglichen Dinge, die eigentlich Implementierungsdetails sein sollten, dem User nicht nur überlassen, sondern für den User schon überhaupt auch nur sichtbar werden.
Culling/Tree Pruning ist bei großen Datenmengen definitiv ein Muss, aber genau Aufgabe der UI-Bibliothek und nicht des Benutzers. Auch dies lässt sich über versteckten Zustand und eindeutige Control-Pfad-Identifier lösen - der Trick ist abermals, den Zustand ohne Rückabhängigkeiten zu den Daten zu speichern, um in nachfolgenden Frames fehlende/neue Teile im Rahmen des Aufbaus der UI erkennen zu können, ohne dass Benachrichtigung/Synchronisation seitens der Daten erforderlich wird.
dot hat geschrieben:Auch im Hinblick auf Energieeffizienz möge so ein Ansatz in einem Spiel vielleicht gerade noch vertretbar sein, in einer normalen Anwendung ist es imo aber ein absolutes No-Go, die ganze GUI ständig neu zu rendern.
Das ist ein wichtiger Punkt und ich sehe für diese radikale Art von UI tatsächlich nur ein begrenztes Einsatzgebiet, dort spart es aber meines Erachtens einen riesen Haufen Arbeit verglichen mit unzähligen UI-Bindings bzw. ganzen Ports von Engines in andere Sprachen (C#), wo Frameworks mehr Unterstützung für automatisierte Bindings auf Kosten von Speicher- und Laufzeiteffizienz bieten.
dot hat geschrieben:Ich hab auch schon länger drüber nachgedacht; ich denke, dass GUI vermutlich einfach von Natur aus untrennbar mit gewissem State verbunden ist, weswegen es eine völlig zustandslose Lösung rein prinzipiell gar nicht geben kann. State duplication allerdings, lässt sich wohl vermeiden. Ich denk im Moment über einen Ansatz nach, der rein presentation-spezifischen Zustand in einer retained mode Struktur hält, sich content-spezifischen Zustand wie z.B. den Text auf einem Label aber, wann immer benötigt, per Callback vom User holt. Genau in dieser Unterscheidung zwischen Presentation und Content liegt imo der eigentliche Knackpunkt; obige immediate mode Lösung setzt implizit gewissermaßen ja ebenfalls genau dort an...
Soweit ich weiß arbeiten einige Frameworks (Android?) bereits genau so. Das eigentliche Problem von nicht-Immediate UIs bleibt aber bestehen: Sobald nicht konsequent die ganze Zeit Updates durchgeführt werden, brauchst du Benachrichtigung über Veränderung bzw. Invalidierung von Teilbereichen deiner UI. Deshalb funktioniert das IMGUI-Konzept überhaupt nur in dieser radikalen Form.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Intermediate Mode Model/View/Controller

Beitrag von dot »

CodingCat hat geschrieben:
dot hat geschrieben:Entweder, ich berechne in jedem Frame das komplette Layout ständig neu
Ja, genau das tue ich in meinem Prototyp, und genau das erachte ich im Kontext von Content Creation Tools als gangbar und sinnvoll ...
CodingCat hat geschrieben:
dot hat geschrieben:Ein extrem wichtiger Spezialfall von Layout versteckt sich hinter Text Rendering. Text Layout ist extrem komplex (Unicode auf und ab, Spacing, Kerning, Justification, Text Directionality ...). Anzunehmen, dass man eben mal drawString("hello world!") macht und gut ist, ist nett, ab einem gewissen Punkt aber leider auch einfach nur noch realitätsfremd.
... nein, im Allgemeinen ist das eigentlich nicht realitätsfremd, es sei denn du entwickelst einen WYSIWYG Text-Editor. Einfaches Alignment an festen Grenzen ist kein Problem, Kerning lässt sich genau wie Glyphzuordnung seitens UI-Bibliothek in entsprechenden Datenstrukturen sehr schnell nachschlagen, wenn notwendig kannst du auch noch problemlos eine UTF-8-Dekodierung voranstellen.
Der Punkt ist: It adds up...

Natürlich, bis zu einem gewissen Grad kann man alles machen. Aber es ist imo einfach dermaßen verschwenderisch, dass ich nichtmehr ruhig schlafen könnte, wenn ich wüsste, dass mein UI tatsächlich in jedem Frame rekursiv das komplette two-pass Layout durchrechnet und jeden einzelnen Buchstaben neu platziert... ;)

Wait...ich glaub two-pass Layout wär sowieso schon wieder ein Problem!? :P

CodingCat hat geschrieben:
dot hat geschrieben:Standardinteraktionen mit dem User wie z.B. Resizen von Controls müssten wohl durchgehend selbst implementiert werden, es kann ja nichtmal sowas wie z.B. das Konzept eines Inputfokus geben.
Input-Fokus sowie Mouse Capture habe ich bereits wie oben skizziert implementiert, das ist kein Problem. Persistentes Resize auf Control-granularer Ebene passt tatsächlich schlecht ins zustandslose Konzept, ich sehe aber dafür im von mir angestrebten Zielkontext der Zugänglichmachung und Bearbeitung großer Datenbäume auch keine Notwendigkeit. Mittelfristiger Zustand während der Bearbeitung einer konkreten Untermenge der Daten ist hingegen kein Problem, analog zu Input-Fokus lässt sich auch gepufferte Text-Eingabe, Resize etc. für gerade aktive Controls implementieren.
CodingCat hat geschrieben:
dot hat geschrieben:Außerdem will ich nicht in jedem Frame für alle 223 Buttons testen müssen, ob der Mauszeiger im Button liegt oder nicht, wenn gerade mal 3 davon auch nur in der Nähe wären. Klar, natürlich kann man auch hier eine bessere Lösung dem User überlassen. Langsam stellt sich dann aber unweigerlich die Frage, inwiefern sowas nützlich ist und sich "GUI Library" nennen darf, wenn alle möglichen Dinge, die eigentlich Implementierungsdetails sein sollten, dem User nicht nur überlassen, sondern für den User schon überhaupt auch nur sichtbar werden.
Culling/Tree Pruning ist bei großen Datenmengen definitiv ein Muss, aber genau Aufgabe der UI-Bibliothek und nicht des Benutzers. Auch dies lässt sich über versteckten Zustand und eindeutige Control-Pfad-Identifier lösen - der Trick ist abermals, den Zustand ohne Rückabhängigkeiten zu den Daten zu speichern, um in nachfolgenden Frames fehlende/neue Teile im Rahmen des Aufbaus der UI erkennen zu können, ohne dass Benachrichtigung/Synchronisation seitens der Daten erforderlich wird.
Naja, dieser Trick funktioniert wohl in der Praxis ganz gut, ich empfinde ihn aber als ein wenig unsauber. Egal ob man jetzt Pointer oder sonst irgendwelche IDs verwendet. Wenn ich einen Button lösche und gleich drauf einen neuen mach, hab ich zumindest bei Pointern das Problem, dass mein neuer Button potentiell die selbe Adresse hat und das GUI niemals mitbekommt, dass das jetzt plötzlich ein anderer Button ist. Insbesondere bei generierten IDs kann man dies zwar bis zu einem gewissen Grad beeinflussen, aber es ist irgendwie dennoch ein Hack um ein prinzipielles Problem eher auszugleichen als zu lösen. Auch brauch ich natürlich wieder einen weiteren Lookup und mein User muss für jedes Control nun auf einmal eine ID bereitstellen... ;)

CodingCat hat geschrieben:
dot hat geschrieben:Auch im Hinblick auf Energieeffizienz möge so ein Ansatz in einem Spiel vielleicht gerade noch vertretbar sein, in einer normalen Anwendung ist es imo aber ein absolutes No-Go, die ganze GUI ständig neu zu rendern.
Das ist ein wichtiger Punkt und ich sehe für diese radikale Art von UI tatsächlich nur ein begrenztes Einsatzgebiet, dort spart es aber meines Erachtens einen riesen Haufen Arbeit verglichen mit unzähligen UI-Bindings bzw. ganzen Ports von Engines in andere Sprachen (C#), wo Frameworks mehr Unterstützung für automatisierte Bindings auf Kosten von Speicher- und Laufzeiteffizienz bieten.
CodingCat hat geschrieben:
dot hat geschrieben:Ich hab auch schon länger drüber nachgedacht; ich denke, dass GUI vermutlich einfach von Natur aus untrennbar mit gewissem State verbunden ist, weswegen es eine völlig zustandslose Lösung rein prinzipiell gar nicht geben kann. State duplication allerdings, lässt sich wohl vermeiden. Ich denk im Moment über einen Ansatz nach, der rein presentation-spezifischen Zustand in einer retained mode Struktur hält, sich content-spezifischen Zustand wie z.B. den Text auf einem Label aber, wann immer benötigt, per Callback vom User holt. Genau in dieser Unterscheidung zwischen Presentation und Content liegt imo der eigentliche Knackpunkt; obige immediate mode Lösung setzt implizit gewissermaßen ja ebenfalls genau dort an...
Soweit ich weiß arbeiten einige Frameworks (Android?) bereits genau so. Das eigentliche Problem von nicht-Immediate UIs bleibt aber bestehen: Sobald nicht konsequent die ganze Zeit Updates durchgeführt werden, brauchst du Benachrichtigung über Veränderung bzw. Invalidierung von Teilbereichen deiner UI. Deshalb funktioniert das IMGUI-Konzept überhaupt nur in dieser radikalen Form.
Ich sage ja nicht, dass ich die Vorteile des immediate mode Ansatzes nicht sehe. Leider ist er aber wohl doch eher recht ineffizient und funktioniert überhaupt nur unter sehr speziellen Voraussetzungen, die viele Dinge, die man von einem modernen UI erwarten würde, von vornherein ausschließen oder nur in beschränktem Umfang erlauben. Die meisten UI Toolkits sind in der Tat furchtbar, Events ein direkter Pfad in die Hölle, ich wünschte, es gäbe bessere Lösungen...
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Immediate Mode Model/View/Controller

Beitrag von CodingCat »

dot hat geschrieben:Natürlich, bis zu einem gewissen Grad kann man alles machen. Aber es ist imo einfach dermaßen verschwenderisch, dass ich nichtmehr ruhig schlafen könnte, wenn ich wüsste, dass mein UI tatsächlich in jedem Frame rekursiv das komplette two-pass Layout durchrechnet und jeden einzelnen Buchstaben neu platziert... ;)
Genau hier sehe ich aber in einer Anwendung, die jedes Frame mehrere Millionen Dreiecke rendert, nicht das Problem. :P
dot hat geschrieben:Naja, dieser Trick funktioniert wohl in der Praxis ganz gut, ich empfinde ihn aber als ein wenig unsauber. Egal ob man jetzt Pointer oder sonst irgendwelche IDs verwendet. Wenn ich einen Button lösche und gleich drauf einen neuen mach, hab ich zumindest bei Pointern das Problem, dass mein neuer Button potentiell die selbe Adresse hat und das GUI niemals mitbekommt, dass das jetzt plötzlich ein anderer Button ist. Insbesondere bei generierten IDs kann man dies zwar bis zu einem gewissen Grad beeinflussen, aber es ist irgendwie dennoch ein Hack um ein prinzipielles Problem eher auszugleichen als zu lösen. Auch brauch ich natürlich wieder einen weiteren Lookup und mein User muss für jedes Control nun auf einmal eine ID bereitstellen... ;)
ID muss in der Tat bereitgestellt werden. Dass IDs unbemerkt den Besitzer wechseln ist in der Tat möglich, aber nach meiner aktuellen Einschätzung nicht störend. In Fällen, in denen so viele Aktionen aufeinander treffen, dass so ein Fall eintritt, gibt meiner Erfahrung nach bis heute jede nicht auf Datenverwaltung spezialisierte Event-basierte Applikation über kurz oder lang den Geist auf, weil so viel Zustand mit indirekter Daten-Abhängigkeit vorliegt, dass sich ungültige Zustände und Crash-Möglichkeiten schon in Anzahl überhaupt nicht mehr überblicken lassen. In der Immediate Mode UI hingegen wird schlimmstenfalls der Fokus ungefragt auf ein anderes Control übertragen und ggf. gepufferte Eingabe auf das falsche Datenelement angewandt - und auch das nur, wenn ohne Benutzerinteraktion unerwarteterweise die gerade in der Bearbeitung befindlichen Daten verschwinden. Es ist klar, dass solches Verhalten in vielen Anwendungen inakzeptabel wäre, dort wäre der UI-Zustand dann jedoch eine gewollte Kopie eines vergangenen Datenzustandes und die Synchronisation nebenläufig bearbeiteter Daten wäre ohnehin ein entscheidender Teil der Programmlogik.
dot hat geschrieben:Ich sage ja nicht, dass ich die Vorteile des immediate mode Ansatzes nicht sehe. Leider ist er aber wohl doch eher recht ineffizient und funktioniert überhaupt nur unter sehr speziellen Voraussetzungen, die viele Dinge, die man von einem modernen UI erwarten würde, von vornherein ausschließen oder nur in beschränktem Umfang erlauben. Die meisten UI Toolkits sind in der Tat furchtbar, Events ein direkter Pfad in die Hölle, ich wünschte, es gäbe bessere Lösungen...
Geht mir genauso :-/ Letztlich ist die UI-Zustandsproblematik leider äquivalent mit der Cache-Kohärenz-Problematik, entsprechend schlecht sieht es mit optimalen allgemeinen Lösungsmöglichkeiten aus.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: Immediate Mode Model/View/Controller

Beitrag von dot »

CodingCat hat geschrieben:
dot hat geschrieben:Natürlich, bis zu einem gewissen Grad kann man alles machen. Aber es ist imo einfach dermaßen verschwenderisch, dass ich nichtmehr ruhig schlafen könnte, wenn ich wüsste, dass mein UI tatsächlich in jedem Frame rekursiv das komplette two-pass Layout durchrechnet und jeden einzelnen Buchstaben neu platziert... ;)
Genau hier sehe ich aber in einer Anwendung, die jedes Frame mehrere Millionen Dreiecke rendert, nicht das Problem. :P
Also zumindest bei mir macht das mit dem Millionen-Dreiecke-Rendern die GPU und nicht die CPU... :P
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: Immediate Mode Model/View/Controller

Beitrag von CodingCat »

Und wer schickt die 1000 Draw Calls? Wer cullt die 10000 Objekte? Mein Punkt ist: Solange ich keinen Texteditor schreibe, ist der Aufwand für das bisschen Bildschirmtext verschwindend gering.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Immediate Mode Model/View/Controller

Beitrag von Chromanoid »

Ich zitiere mal aus der Präsentation:
The good..
● No object creation
● No cleanup either
● No queries for information
● No message passing
● Data owned by application, not the widget
● Everything is “immediate” - one call per widget, each frame, handles behavior and rendering.

..the bad..
● Requires different kind of thinking
● Wastes CPU time
– But in games you're re-rendering stuff 50+ fps anyway..
● UI generated from code; No designer-friendly tools.
– Unless you make some...

..and the ugly.
● While making easy things dead easy, makes complicated things very complicated.
– The UI system internals may become even more complex than in “traditional” GUI library!
● UI logic interleaved to rendering
– Can be overcome by more complex internals.
● Pretty “anti-OOP” (although this is debatable)
Not a silver bullet.
So sehe ich das eigentlich auch. Für größere Spiele scheint mir Scaleform das Tool der Wahl zu sein, da merkt man ja schon wie wichtig die Designer sind (Tweening und Co. sind bestimmt ein herrlicher Spaß mit IMGUI, oder nicht?). Für andere Dinge sollte HTML5 immer interessanter werden.
NytroX
Establishment
Beiträge: 363
Registriert: 03.10.2003, 12:47

Re: Immediate Mode Model/View/Controller

Beitrag von NytroX »

Für andere Dinge sollte HTML5 immer interessanter werden
Uuh, nur mal als Einwurf, aber ist eine IMGUI nicht einfach quasi genau das gleiche wie HTML?

Um das nochmal näher auszuführen, nach meinem Verständnis geht es darum, anstatt Controls zu erzeugen, einfach die Sachen direkt zu rendern, also:

Code: Alles auswählen

//anstatt
//1.Frame
Label = new Label(xpos, ypos, width,height,"Hello");
//2.Frame
label.setText("Hello2"); //greift auf den Zustand zu, ist meist wesentlich komplexer

//machen wir
//1. Frame
gui.clear();
gui.CreateLabel(xpos,ypos, width,height,"Hello");
gui.render();
//2. Frame
gui.clear();
gui.CreateLabel(xpos,ypos, width,height,"Hello2");
gui.render();

Letzteres kommt mir relativ bekannt vor, wenn ich JSP oder PHP sehe.
Da macht man nämlich:

Code: Alles auswählen

//Ausgabe bei aufruf der index.html
echo("<b class="label">Hello</b>");
//Ausgabe nach POST
echo("<b class="label">Hello2</b>");
Mit dem einzigen Unterschied, dass meine "Frames" einfach HTTP Requests sind...
Man kann sich das so vorstellen, dass die GUI-Calls einfach den HTML-Code generieren, der dann am Ende mit gui.render() o.ä. auf den Bildschirm gebracht wird.

Und wenn ich jetzt z.B. an ein Spiel denke, würde ich die GUI in eine Textur rendern, und diese Textur später als Layer über den Rest legen.
Also z.B.
RenderToTexture1 -> 3D Welt
RenderToTexture2 -> GUI
Und dann beides übereinander in den Backbuffer (nachdem eh quasi jeder einen deferred renderer hat ist das auch kein großer Aufwand für die GPU mehr)

Man muss die GUI Textur auch nur neu rendern, wenn sich am Datenmodell was geändert hat, die muss man nicht mit 200fps updaten.
Und man kann das GUI Update sogar parallelisieren, weil es in eine unabhängige Textur gerendert wird.

Und wenn man jetzt noch ganz was tolles will, kann man die Aufrufe auch verschachteln:

Code: Alles auswählen

gui.CreateButton(xpos,ypos, width,height,gui.CreateLabel("Yeah"));
//erzeugt dann sowas wie:
//<p class="button"><b class="label">Yeah</b></p>
Damit gehen dann auch Tabellen, Layouts, uvm.

Aber wirklich neu ist das alles irgendwie nicht, oder?
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Immediate Mode Model/View/Controller

Beitrag von Chromanoid »

Man baut doch bei JSP/PHP und Co. i.d.R. ein Formular o.Ä. auf, das dann ganz traditionell mit Zustand, Events und Pipapo im Browser auf dem Client angezeigt wird. In der Betrachtung von HTML für eine GUI würde genau dieser clientseitige Teil das wichtige sein. Das Formular an sich würde man nach Möglichkeit als Template schon vorher haben. Das sollte nämlich vom Designer angefertigt werden können. Ich stelle mir das dann eher so vor: http://handlebarsjs.com/ und als Ergänzung mal Adobe Profukte fürs Editieren animierter "GUIs" http://html.adobe.com/edge/animate/, https://creative.adobe.com/products/reflow usw. HTML5 ist da IMO deshalb so interessant, weil es eine Auszeichnungssprache ist, die genau auf ein großes Problem bei der GUI Entwicklung, nämlich unterschiedliche Auflösungen, ausgelegt ist.
Antworten