Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Warum denn nicht? OK, ich habe es bei dieser Anwendung nicht so gemacht, aber bei TinyGUI habe ich das Verschieben und Skalieren eines Controls über glTranslate/glScale realisiert, das bedeutet, dass seine wahren Koordinaten völlig gleichgültig waren, und das kann ich mir z.B. gut mit DisplayListen vorstellen.
@edit: Für VBO's kann ich es nicht sagen, weil ich mich damit nicht auskenne.
Registriert: Sa Jan 01, 2005 17:11 Beiträge: 2068
Programmiersprache: C++
Stimmt, im Prinzip hast du recht.
Wenn die GUI anfängt zu Zeichnen starte ich die Displayliste und am Ende des Zeichnen compiliere ich sie.
Das funktioniert mit dem Konzept soweit.
Als einzige was Probleme machen könnten wären Kleinigkeiten:
Es muss eine spezielle Funktion am Anfang des Zeichnens sowie am Ende aufgerufen werden, damit man weiss, dass man dort ist.
Und man müsste die Draw-Funktion der GUI überschreiben können. Sodass dort einfach nur geschaut wurde ob sich was am "Aussehen" der GUI geändert hat und dann die Displayliste neuerstellen, ansonsten die Displayliste einfach rendert.
Somit ist das Konzept des Graphictools soweit in Ordnung, es muss nur ein Defaultgraphictool existieren was unter OpenGL funktioniert.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Was die Displaylisten betrifft: ich hab es jetzt ohnehin einfach mit den vier Werten Links/Oben/Breite/Höhe gemacht (das "viereckige Plätzchen"). Ich zwinge mich, immer den einfachsten Weg zu nehmen, der gerade noch das erforderliche Ergebnis bringt. Und wenn ich ehrlich bin, ist das mit Links/Oben/Breite/Höhe der einfachere Weg.
Wie das DGL Default GraphTool auszusehen hat bzw. welche Objekte es in Betrieb nimmt, kannst Du Dir (bzw. die Community) aussuchen, insbesondere was das Schrift- und Texturobjekt betrifft. Darum wollte ich das Ganze thematisieren.
EIN VORSCHLAG: man könnte ein EasySDL-Schriftobjekt nehmen und ein EINFACHES Texturobjekt, das sich an Lossys Standard orientiert, aber plattformübergreifend ist, z.B. auch mit SDL (weiß jetzt nicht obs sowas schon gibt). Wenn wir uns geeinigt haben, kann man die Klassendefinition vorgeben. ***)
Für das Einrichten der Applikation nehme ich deshalb nicht SDL, weil ich das nicht darf - Du weißt schon, es muss multiwindow-fähig sein, deshalb die WIN-API. Zum Portieren nach Linux braucht nur ein Include-File (bei mir ist das derzeit eine Unit namens OSSupport) ersetzt zu werden.
***) EDIT: Achtung, ein paar Voraussetzungen hab ich allerdings schon: Die Objekte müssen
--- einen Namen (eine Identity) haben
--- public Properties haben, mit denen man einen Mindeststandard an Manipulationsmöglichkeiten hat
Wenn ich es recht überlege, müssen sie NICHT RTTI-fähig sein, da sie ohnehin mit Hilfe ihres Namens per Theme geladen werden, und nicht direkt von den Widgets per RTTI.
EDIT2: Seufz. Ich schaff es nicht, die nötigen Eigenschaften der Objekte auf die Schnelle zu definieren. Ich brauch dafür ein wenig Zeit.
1) Gib mir ein Bild namens "OpenFile" 2) Gib mir eine Farbe "Hellblau" 3) Gib mir eine Zeichenprozedur "Ellipse" 4) Gib mir eine Schrift "Arial" 5) Gib mir was auch immer
Na das nenn ich mal 'das Pferd von hinten aufzäumen' . Wenn das Widget die GraphTool instanz kennt (und das tut sie offensichtlich), dann brauch es die ganzen prozedurpointer garnicht, sondern kann direkt z.B. DrawEllipse rufen. Dann kannst Du auch problemlos die Parametersets unterschiedlich machen. Das würde dann beim Zeichnen so aussehen:
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Das wäre sehr schlecht für die Performance, denn das Widget müßte dann die Textur oder die Farbe namens "OpenFile" oder "Hellblau" heraussuchen, und zwar über eine Stringsuchfunktion. Wenn das einmal passiert, OK, aber wenn alle Widgets das bei jedem Renderpass so machen müssen, ist das ziemlich langsam, darum verwende ich einen schnellen direkten Zeiger.
Und das:
Code:
GraphTool.DrawEllipse(X1,Y1,X2,Y1,R);
ist auch langsam, denn die Widgets bekommen ihre Zeichenprozeduren über Themes. Und da kriegen sie einen String. Die Zeichenprozedur (=prozedurale Variable) wird für jede Widget-Klasse über eine Stringsuchfunktion geholt, wenn Themes geladen wird. Ab dann benutzt das Widget nur mehr den Methodenzeiger. Ich lasse mich überzeugen, wenn Du eine schnelle Alternative zu folgendem Code weißt (der auch bei jedem Renderpass jedes Widgets ablaufen müsste):
Spontan würde ich sagen, leg einen enum an für DrawProcName. Wenn der eine published property ist, dann kann man sie über SetEnumProp aus einem String heraus setzen:
Code:
TDrawProcName=(TRIANGLE,RECTANGLE,ROUNDRECT,...);
Setzen:
Code:
SetEnumProp(MyWidget,'DrawProcName','TRIANGLE');
oder:
MyWidget.DrawProcName=TRIANGLE;
In der Zeichenroutine:
Code:
Case DrawProcName Of
TRIANGLE:Begin
GraphTool.DrawTriangle(X1,Y1,X2,Y2,X3,Y3);
End;
....
End;
Das hat ausserdem den Vorteil, dass man schon beim Setzen feststellen kann, obs die Zeicenprozedur überhaupt gibt. Im Else-Zweig der Case-Anweisung kommt dann ne exception rein, dass dieser Enum-Member noch nicht implementiert ist, dann findet man bei Erweiterungen auch leichter die Stellen.
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Noch ne Idee: nicht so schön, dafür aber seltener:
Code:
Case DrawProcName[1]Of
'E': GraphTool.DrawEllipse(X1,Y1,X2,Y1,R);
'H': GraphTool.DrawHexagon(X1,Y1,X2,Y1,R);
'T': GraphTool.DrawTriangle(X1,Y1,X2,Y1,R);
'R':Begin
Case DrawProcName[2]Of
'E': GraphTool.DrawRectangle(X1,Y1,X2,Y1,R);
'O': GraphTool.DrawRoundRectangle(X1,Y1,X2,Y1,R);
End;
End;
End;
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Was wären die Unterschiede der von Dir vorgeschlagenen Version:
1) Die Enum-Abfrage ist schneller aber bleibt mir beim Rendern nicht erspart: das sehe ich als Nachteil, den Prozedurzeiger kann ich einfach losschicken
2) Ich spare mir ein Standard-Theme, das wäre eine relativ kleine Textdatei, ist das wirklich so ein Vorteil?
3) Die Variable "DrawProcName" müsste ein Published Property sein: sehe weder Vorteil noch Nachteil, ist eher egal
4) Man muss die Widgets immer per RTTI laden oder das Anwendungsprogramm muss "DrawProcName" für jedes Widget zu Beginn "zu Fuß" bestücken: das gefällt mir weniger; ein Vorteil beim zu Fuß bestücken wäre, dass man im Quelltext sieht, um welche Zeichenprozedur es sich handelt, gefällt mir eigentlich aber immer noch nicht
5) Themes vergibt die Theme-Eigenschaften klassenweise; das ist beim Laden über RTTI nicht wirklich so gewährleistet, dh. es besteht die Gefahr, dass es zu "Kraut und Rüben"-Design kommt (das heißt nicht, dass der Anwender nach dem Laden des Themes nicht Eigenschaften neu setzen kann); Themes ist daher weniger Arbeit für den Programmierer
6) Methodenzeiger kann man ja auch über RTTI laden, wenns bloß darum geht; Nach dem Create des Root-Widgets steht das GraphTool zur Verfügung. Es ist zwar derzeit nicht RTTI-fähig, aber das kann man ja nachholen. Die VCL holt ja auch ihre Eventhandler aus dem Root (=TForm) heraus.
Anmerkung: jetzt in der Testphase habe ich den Dataprovider noch nicht eingehängt. Da müsste ich das jedenfalls "zu Fuss" bestücken.
zu 1) die Case bildet sich je Fall auf SUB und JE ab. das sind die beiden schnellsten Assembler-befehle und brauchen einen Prozessor-Takt. Das Argument zieht nicht.
zu 2) Finde ich schon.. je weniger Datei desto gut, ist aber Geschmackssache.
zu 3) muss sie nur, wenn du das wirklich über RTTI setzen willst, es gibt da auch andere Möglichkeiten, siehe zu 4)
zu 4) Das Theme- Objekt bekommt Methoden, Widgets zu generieren. Damit must Du sie nicht 'von Hand' initialisieren. Das Theme Objekt weiss, welche Zeichenmethode z.B.: ein Knopf rufen muss und weißt ihm diesen Enum-Member zu.
Das Theme-Objekt läd diese Informationen aus der Theme-Datei. Hier steht das natürlich in Textform drin und beim ersten Laden kann man sich den Stringvergleich leisten und für jeden Widget-Typen (Knopf, edit, panel...) einen 'Prototypen' anlegen, der dann als Blaupause fürd Widgetkreieren dient.
Wenn man nun einen speziellen Knopf will, dann kann man ihm nach dem Kreieren einfach nen anderen Zeichen-Enum verpassen, dann hat man einen sechseckigen Knopf, der sich ausser der Form von einem viereckigen nicht unterscheidet.
zu 5) Klassenweises Vergeben erreichst Du auch mit 4), allerdings sollten unbedingt hinterher gaaanz viele Eigenschaften änderbar sein (roter Knopf zum quit usw.).
zu 6) stimmt, aber speichern würde ich eher die Events, die den Windowmanager interesieren (on Click usw) aber das geht nicht wirklich, da die ja extern sind und demzufolge immer über Code gesetzt werden müssen.
7) Wenn Du sowas wie DFMs laden willst (und ich glaub das steht im Pflichtenheft) kommst Du um einen Parser nicht herum und da bietet sich die RTTI einfach an, weil die gibts schon.
_________________ Manchmal sehen Dinge, die wie Dinge aussehen wollen, mehr wie Dinge aus, als Dinge.
<Esmerelda Wetterwax>
Es kann vorkommen, dass die Nachkommen trotz Abkommen mit ihrem Einkommen nicht auskommen und umkommen.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo Sidorion,
Irgendwo hab ich den Satz aufgeschnappt: Bitte entschuldigt meinen langen Beitrag. Ich hatte keine Zeit, einen kurzen zu schreiben. In diesem Sinne
Zitat:
zu 1) die Case bildet sich je Fall auf SUB und JE ab. das sind die beiden schnellsten Assembler-befehle und brauchen einen Prozessor-Takt. Das Argument zieht nicht.
OK, wenn das so ist, hast Du recht (Assembler,..... Puh). Allerdings ist dann der Code, mit dem die visuellen Eigenschaften zugewiesen werden, nicht mehr einheitlich (weiß schon, ist ein schwächliches Argument, aber wer mag schon gern seinen mit Herzblut geschriebenen Code umschreiben?).
Zitat:
zu 4) Das Theme- Objekt bekommt Methoden, Widgets zu generieren. Damit must Du sie nicht 'von Hand' initialisieren. Das Theme Objekt weiss, welche Zeichenmethode z.B.: ein Knopf rufen muss und weißt ihm diesen Enum-Member zu.
Hier werde ich Schwierigkeiten bekommen. Wir hatten den Punkt, auf welche Weise Widgets zu erzeugen sind, schon mal abgehandelt. Die Community-Mitglieder hatten mein
Code:
AddButton(....)
verworfen, weil es ihnen nicht gefallen hat. Sie wollten lieber
Code:
MyButton:= TButton.Create(.........
Das ist auch eine Geschmacksfrage. Aber ich gebe zu, wenn man es so im Code stehen sieht, ist es wirklich sehr aussagekräftig. Diese Diskussion würde ich nur dann noch mal beginnen, wenn es WIRKLICH notwendig ist.
Aber ich habe da offenbar etwas nicht verstanden. Wir sind bei der Initialisierung des Programms, OK? Angenommen wir laden jetzt unsere Widgets per RTTI (ja, das ist im Pflichtenheft so vorgesehen, aber mit XML), oder der Programmierer erzeugt sie mit "MyButton:= TButton.Create(.....". Dann sind die Widgets schon vorhanden. Das Theme ist meiner Meinung nach nicht ermächtigt, Widgets zu erzeugen, es darf nur vorhandene Widgets "bekleiden". Und das kann es doch - ohne weitere Informationen aus einer Datei - nur mit Standardwerten tun. Dann ist das doch überflüssig, denn den Standardwert sollte der TButton schon selbst haben (ein graues Rectangle vermutlich).
Zitat:
zu 2) Finde ich schon.. je weniger Datei desto gut, ist aber Geschmackssache.
Siehe oben: Wir müssten uns daher entscheiden, ob die Widgets selbst ein Standardaussehen haben (das wäre mein Vorschlag) oder ob Themes das für Sie tun soll. Dann könnte man sich die Standard-Themesdatei ersparen. Und der Benutzer müßte ein Theme explizit laden (auch möglich während der Laufzeit). Such Dir was aus.
Zitat:
zu 3) muss sie nur, wenn du das wirklich über RTTI setzen willst, es gibt da auch andere Möglichkeiten, siehe zu 4)
Nein, das wollte ich nicht über RTTI verwirklichen. Es ist ganz teuflisch, die Properties in die richtige Sektion zu setzen.: was Published und was Public ist, ist eigentlich dadurch total festgelegt. Ich frag mich, ob das nicht ein schwerer Fehler ist, wenn ich hier auf den Objektinspektor schiele, ich meine im Hinblick auf eine IDE, bei der man alle/viele Widget-Eigenschaften Published braucht.....(Auweia, und was mir gerade eben einfällt: was ist mit dem Skript? Warum sagt eigentlich nie jemand was dazu? Ich muss hier "ins Blaue" programmieren, und glaubt mir, dabei kommt nix Gutes raus)
Zitat:
Wenn man nun einen speziellen Knopf will, dann kann man ihm nach dem Kreieren einfach nen anderen Zeichen-Enum verpassen, dann hat man einen sechseckigen Knopf, der sich ausser der Form von einem viereckigen nicht unterscheidet.
So funktioniert es jetzt auch: das GraphTool hat alle seine Zeichenutensilien in speziellen Listen und rückt diese auf Anforderung heraus. Man ändert die visuellen Eigenschaften, aber nicht das Verhalten (das müsste ein TBehavior machen). Themes tut ja eigentlich auch nichts anderes, nur gibt es das Aussehen für Klassen vor.
Zitat:
zu 5) Klassenweises Vergeben erreichst Du auch mit 4), allerdings sollten unbedingt hinterher gaaanz viele Eigenschaften änderbar sein (roter Knopf zum quit usw.).
Das Theme setzt bei mir bloß ganz bestimmte Eigenschaften. Damit tut es das, was ein Programmierer auch tun kann. Die Eigenschaften werden nicht gesperrt, dh. man kann sie jederzeit wieder anders setzen, NACHDEM Theme "drübergefahren" ist. (Ich finde, wenn jemand irgendwo einen roten/grünen/blauen Knopf haben will, dann bin ich nicht berechtigt, ihn dran zu hindern - ich bin ja nicht Microsoft).
Zitat:
zu 6) stimmt, aber speichern würde ich eher die Events, die den Windowmanager interesieren (on Click usw) aber das geht nicht wirklich, da die ja extern sind und demzufolge immer über Code gesetzt werden müssen.
Mumpf - nein das geht im Augenblick nicht wirklich. Es sind allerdings Konstellationen in einem Anwendungsprogramm denkbar, wo das geht (siehe VCL). Aber so bleibt das jedem selbst überlassen. Und SO eine Diskussion fange ich ganz bestimmt nicht mehr an (ich habe derzeit meine Events published, konsequenterweise müsste ich sie public definieren).
Zitat:
7) Wenn Du sowas wie DFMs laden willst (und ich glaub das steht im Pflichtenheft) kommst Du um einen Parser nicht herum und da bietet sich die RTTI einfach an, weil die gibts schon.
Ja, muss ich so machen,siehe oben, und haben wir schon abgehandelt. Ich habs auch schon geschrieben (hängt weiter oben im Thread, hab seither nichts verändert).
Traude
EDIT: Zum Thema roter Knopf trotz Theme: Der User kann ja jederzeit ein Theme laden, damit würde er alle Sonderdefinitionen von Eigenschaften zunichte machen. Das schreit nach einem Event "AfterLoadTheme", wo der Programmierer wieder alle seine roten Knöpfe setzen kann.
Warum macht ihr das so kompliziert über den Namen und nicht ein Klasse TRenderer die verschiedene Funktionen bietet, die man dann überschreiben kann. Diese Klasse kann selber wieder eine GUI Komponente sein, so dass sie automatisch mit geladen und gespeichert wird.
Wenn so eine Komponente im Formular liegt, dann rendert sich z.B. ein Button oder eine Textbox darüber und nicht selber.
Die Abstraktion der Zeichenfläche ist dann noch speziell über einen Canvas zu regeln, der jeweils beim Paint Erreignis übergeben wird und sehr einfach gestaltet werden kann:
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Öhm, weils mir nicht eingefallen ist.
Wie willst Du mit dem TRenderer von außerhalb des Programms die Zeichenmittel verändern? Das muss man als Programmbenutzer tun können, der den Code nicht verändern kann.
Aber ich muss mir Dein Konzept gründlich ansehen. Das braucht ein bisschen. (Mein GraphTool ist übrigens etwas ziemlich Ähnliches wie Dein Canvas, geht ja gar nicht anders. Die Freiheitsgrade sind hier schon ziemlich reduziert. Aber der Renderer ist was Neues für mich.)
EDIT:
Soweit ich das beurteilen kann, ist bei mir das GraphTool eine Zusammenfassung Deines Renderers und Deines Canvas. Du hast also die Rendering Maschine herausgenommen, um den Vorteil der Vererbung auszunutzen. Das ist raffiniert.
Du müsstest so viele Ableitungen davon haben, wie Du Zeichenroutinen hast. Und das Widget kriegt diejenige Anbeitung, die für es vorgesehen ist. Wenn eine andere Zeichenroutine gewünscht ist, weist Du dem Widget eine andere Ableitung zu. Aber wer bestimmt bei Dir, welche Widget-Klasse welche Zeichenroutine erhält? Anders gefragt, wer stöpselt die verschiedenen Renderer ins Widget ein?
Zuletzt geändert von Traude am Fr Mär 30, 2007 13:06, insgesamt 1-mal geändert.
procedure TButton.Paint(canvas:TCanvas);
var
r:TRenderer;
begin
r:=GetRenderer(); // Render Komponente suchen oder Default Renderer erstellen und cachen
r.DrawFrame(canvas,...);
r.DrawString(canvas,...);
end;
procedure TRenderer.DrawFrame(canvas:TCanvas,rect:TRect);
begin
// hier könnte auch ein runder Rahmen mit Farbverlauf gezeichnet werden
with canvas do
begin
Begin(LineLoop);
Vertex(rect.Left,rect.Top);
Vertex(rect.Right,rect.Top);
Vertex(rect.Right,rect.Bottom);
Vertex(rect.Left,rect.Bottom);
End;
end;
end;
OpenGL spezifisch:
procedure TCanvas.Begin(...);
begin
glBegin(...)
end;
Mitglieder in diesem Forum: 0 Mitglieder und 4 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.