Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Mo Jul 07, 2025 18:18

Foren-Übersicht » Programmierung » OpenGL
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: glScissors
BeitragVerfasst: So Jun 10, 2007 13:19 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Hi, ich habe ein kleines Problem bei meiner GUI

Ich lasse mehrere Fenster zeichnen, die ineinander verschachtelt sind. Das Problem ist nun, dass ein Fenster 2, das in Fenster 1 steht, natuerlich nicht ueber den Rand von Fenster 1 hinausragen darf. Dazu wollte ich glScissors verwenden.

Mein Code dazu sieht folgendermaßen aus:
Code:
  1.   if Assigned(ParentObject) then
  2.   begin
  3.     glEnable(GL_SCISSOR_TEST);
  4.  
  5.     with ParentObject do
  6.     begin
  7.       glColor3f(1,0,0);
  8.       glBegin(GL_LINE_LOOP);
  9.         glVertex2f(Left, Top+Height);
  10.         glVertex2f(Left, Top);
  11.         glVertex2f(Left+Width, Top);
  12.         glVertex2f(Left+Width, Top+Height);
  13.       glEnd();
  14.       glScissor(Left, Top+Height, Width, Height);
  15.     end;
  16.   end;


Ich habe zwei Bilder, das erste zeigt, wie die Fenster ohne glScissors aussehen.
Das zweite zeigt, was bei glScissors passiert.

Bild
Bild


Wie man sieht, wird das Fenster 3 komplett weggeschnitten, habt ihr vielleicht ne Idee?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Jun 10, 2007 14:54 
Offline
DGL Member

Registriert: Do Mai 30, 2002 18:48
Beiträge: 1617
ist das 3. fenster kind des 2. fensters? dann ist der scissor nur auf das 2. fenster bezogen, missachtet aber, daß bereits das fenster 2 ne kind ist - du musst deinen scissor so bauen, daß er sich am ende rekursiv verhält und nicht immer nur die stufe oben drüber mit einbezieht, sondern alle darüber.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: So Jun 10, 2007 15:09 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Ja Fenster3 ist Kind von Fenster2.

Ich hatte es so schonmal aber funktionieren tut es trotz allem nicht.

Code:
  1. procedure TSE_GUI_Window_Custom.Draw;
  2. var i:Integer;
  3. begin
  4.   inherited;
  5.  
  6.   if Assigned(ParentObject) then
  7.   begin
  8.     if fText = 'Window2' then
  9.     begin
  10.     glEnable(GL_SCISSOR_TEST);
  11.  
  12.     with ParentObject do
  13.     begin
  14.       glColor3f(1,0,0);
  15.       glBegin(GL_LINE_LOOP);
  16.         glVertex2f(Left, Top+Height);
  17.         glVertex2f(Left, Top);
  18.         glVertex2f(Left+Width, Top);
  19.         glVertex2f(Left+Width, Top+Height);
  20.       glEnd();
  21.       glScissor(Left, Top+Height, Width, Height);
  22.     end;  end;
  23.   end;
  24.  
  25. //Window Zeichnen
  26.  
  27. // Hier werden alle Kinder gezeichnet
  28.   for i := 0 to fItems.Count - 1 do
  29.     (fItems.Objects[i] as TSE_GUI_Custom).Draw;
  30.  
  31.     glDisable(GL_BLEND);
  32.   if Assigned(ParentObject) then
  33.     glDisable(GL_SCISSOR_TEST);
  34.  
  35. end;


Problem ist, dass sich keinerlei aenderung zeigt.

Weiteres kuriosum: Beschränke ich die Beschneidung auf das Aeusserste Fenster (also das, das kein Parent hat) funktioniert es, allerdings wird dann innerhalb nicht abgeschnitten.
Bild dazu:
Bild

Habe hier nochmal ne Demo, wo Drag&Drop der Fenster funktioniert. Was da beim Ziehen passiert, versteh ich ueberhauptnicht...
http://shaddow89.sh.funpic.de/Desktop.rar


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mo Jun 25, 2007 19:26 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Tja nun habe ich noch einiges an meinem Programm umgestellt und bin bei Rekursionen gelandet.
Leider kann man ja immer nur eine Scissorbox initialisieren, sonst wäre mein Problem sehr viel einfacher zu beheben. Nun stehe ich aber vor dem folgenden:
Ich habe 3 Fenster:
Fenster1
Fenster2
Fenster3

Fenster3 ist Child von Fenster2
Fenster2 ist Child von Fenster1

Nun will ich im Fenster3 eine Scissorbox so setzen, dass das Fenster3 an den Grenzen von Fenster2 UND Fenster1 abgeschnitten wird. Logische Folge: Rekursion.
Ich gehe also immer weiter nach oben im Rekursionsbaum und vergleiche dann die einzelnen Werte der Fenster. Die Box die ich brauche, ist letztlich die kleinste, da sie sowohl von Fenster1 als auch Fenster2 beschnitten wird.
Das heisst effektiv:
Ich brauche den größsten Left und Topwert der Windows
und ich brauche den kleinsten Width und Heightwert der Windows

Die entstehende Box ist genau die, die durch beide Windows begrenzt wird

Der Code dazu also:
Code:
  1. procedure TSE_GUI_Custom.SetScissors;
  2. var InnerRect: TSE_Rect;
  3. begin
  4.   if Assigned(ParentObject) then
  5.     ParentObject.SetScissors
  6.   else
  7.   begin
  8.     InnerRect.Left  := 0;
  9.     InnerRect.Top   := 0;
  10.     InnerRect.Width := High(Word);
  11.     InnerRect.Height:= High(Word);
  12.  
  13.     InnerRect := GetInnerRect(InnerRect);
  14.  
  15.     glPushMatrix;
  16.     glLoadIdentity;
  17.  
  18.       glBegin(GL_LINE_LOOP);
  19.         glVertex2f(InnerRect.Left, InnerRect.Top+InnerRect.Height);
  20.         glVertex2f(InnerRect.Left, InnerRect.Top);
  21.         glVertex2f(InnerRect.Left+InnerRect.Width, InnerRect.Top);
  22.         glVertex2f(InnerRect.Left+InnerRect.Width, InnerRect.Top+InnerRect.Height);
  23.       glEnd();
  24.       WriteLn(InnerRect.Height);
  25.     glScissor(InnerRect.Left,InnerRect.Top+InnerRect.Height,InnerRect.Width,InnerRect.Height);
  26.     glPopMatrix;
  27.   end;
  28. end;
  29.  
  30. function TSE_GUI_Custom.GetInnerRect(InnerRect: TSE_Rect): TSE_Rect;
  31. begin      //ueberdenken
  32.   if Assigned(ParentObject) then
  33.     Result := ParentObject.GetInnerRect(InnerRect)
  34.   else
  35.   begin
  36.     if fLeft + GlobalCoords[0]  > InnerRect.Left    then InnerRect.Left   := fLeft  + GlobalCoords[0];
  37.     if fTop  + GlobalCoords[1]  > InnerRect.Top     then InnerRect.Top    := fTop   + GlobalCoords[1];
  38.     if fWidth                   < InnerRect.Width   then InnerRect.Width  := fWidth;
  39.     if fHeight                  < InnerRect.Height  then InnerRect.Height := fHeight;
  40.     Result := InnerRect;
  41.  
  42.   end;
  43. end;
  44.  


Die erste funktion erstellt nur die Variable. TSE_Rect ist ein Record aus Left, Top, Width und Height.
Diese Variable wird an die Rekusive Funktion GetInnerRect uebergeben. Da drin sollen nun die Werte verglichen. Alle Werte sind relativ zum uebergeordneten Objet, das heisst, Left und Top sind immer relative Werte. Width udn Height sind es ja sowieso da sie von Left und Top abhaengen. Da die resultierende Box aber nach globalen Koordinaten bestimmt werden muss, wird GlobalCoords addiert. Das sind jeweils die errechneten Globalen Koordinaten des Fensters.

Leider funktioniert das nicht, die Scissorbox wird immer irgendwo in der Weltgeschichte initialisiert...


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Jun 26, 2007 15:50 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Eine wichtige sache Vorweg: Die Y-Koordinate der ScissorBox berechnet sich vom unteren Fensterrand, laut OpenGL-Spezifikation.

Des weiteren hatte ich selbst vor kurzem das Problem und es wie folgt gelöst:

Code:
  1.  
  2.  
  3. type
  4.   TguiRect = record
  5.     Top, Left, Width, Height: Integer;
  6.   end;
  7.  
  8. function TguiElement.GetChildScissorRect(ARect: TguiRect): TguiRect;
  9. var
  10.   I: Integer;
  11. begin
  12.   Result.Width := gglMin(ARect.Width, (FWidth - FClientMargins.RightBorder) - (ARect.Left + FClientMargins.LeftBorder));
  13.   Result.Height := gglMin(ARect.Height, (FHeight - FClientMargins.BottomBorder) - (ARect.Top + FClientMargins.TopBorder));
  14.   Result.Top := ARect.Top + FTop + FClientMargins.TopBorder;
  15.   Result.Left := ARect.Left + FLeft + FClientMargins.LeftBorder;
  16.  if FParent <> nil then
  17.     Result := FParent.GetChildScissorRect(Result);
  18. end;
  19.  
  20. function TguiElement.GetChildScissorRect: TguiRect;
  21. begin
  22.   Result.Top := FTop + FClientMargins.FTopBorder;
  23.   Result.Left := FLeft + FClientMargins.FLeftBorder;
  24.   Result.Width := FWidth - FClientMargins.FRightBorder;
  25.   Result.Height := FHeight - FClientMargins.FBottomBorder;
  26.   if FParent <> nil then
  27.     Result := FParent.GetChildScissorRect(Result);
  28. end;

(Die methoden sind überladen
gglMin gibt den kleineren der beiden übergebenen Werte zurück.)

Um die Scissor-Box zu erhalten, muss das untere Aufgerufen werden, also ohne Parameter. Dies ruft dann rekursiv die funktion mit Parameter des Eltern-Elementes auf. Das funktioniert soweit eigentlich ganz gut.
FClientMargins sind Ränder, die ein Offset bilden, sodass die Controls nicht immer direkt am Elternelementrand hängen, kannst du aber natürlich auch weglassen.

Dann habe ich noch folgende Funktion um das Y-Koordinaten-Problem zu lösen:
Code:
  1.  
  2. function ConvertGuiRectToOpenGLRect(ARect: TguiRect; ScreenHeight: Integer): TguiRect;
  3. begin
  4.   Result.Left := ARect.Left;
  5.   Result.Top := (ScreenHeight - ARect.Top) - ARect.Height;
  6.   Result.Width := ARect.Width;
  7.   Result.Height := ARect.Height;
  8. end;
  9.  

Damit wird der Y-Wert umgewandelt, sodass das Scissoring auch so funktioniert, allerdings braucht man dazu die höhe des Viewports (oder der Zeichenfläche?).

Du darfst die Sourcecodes ohne weiteres kopieren, wäre aber über eine nennung in den Credits (am besten mit Link) dankbar :wink:

Gruß Lord Horazont

//Edit: Ach ja, bitte verlink die Bilder das nächste mal, vielleicht auch mit Thumbnail. Das Seitwärtsscrollen um dann einen Beitrag zu lesen nervt ein wenig.

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Jun 26, 2007 18:01 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Mh naja ich muss nich scrollen ^^ deswegen isses mir vllt nicht aufgefallen

Also ich habe vorhin schonmal etwas weitergebastelt und im Grunde geht es jetzt. ich haette natuerlich nicht 'im Grunde' geschrieben, wenn jetzt nicht das Aber kaeme :)
Code:
  1.     procedure TSE_GUI_Custom.SetScissors;
  2. var InnerRect: TSE_Rect;
  3. begin
  4.  
  5.     InnerRect := GetInnerRect(InnerRect);
  6.  
  7.     glPushMatrix;
  8.     glLoadIdentity;
  9.       glColor3f(1,0,0);
  10.       glBegin(GL_LINE_LOOP);
  11.         glVertex2f(InnerRect.Left, InnerRect.Top+InnerRect.Height);
  12.         glVertex2f(InnerRect.Left, InnerRect.Top);
  13.         glVertex2f(InnerRect.Left+InnerRect.Width, InnerRect.Top);
  14.         glVertex2f(InnerRect.Left+InnerRect.Width, InnerRect.Top+InnerRect.Height);
  15.       glEnd();
  16.     // Zweiter Parameter: Screenheight - unterer Punkt
  17.     // glScissors geht von 0/0 unten links aus, ich habe 0/0 oben links
  18.     glScissor(InnerRect.Left,Window.ScreenHeight-InnerRect.Top-InnerRect.Height,InnerRect.Width+1,InnerRect.Height+1);
  19.     glPopMatrix;
  20. end;


Code:
  1. function TSE_GUI_Custom.GetInnerRect(InnerRect: TSE_Rect): TSE_Rect;
  2. begin  
  3.   if Assigned(ParentObject) then
  4.   begin
  5.     InnerRect := ParentObject.GetInnerRect(InnerRect);
  6.     InnerRect.Left  := InnerRect.Left   + fLeft;
  7.     InnerRect.Top   := InnerRect.Top    + fTop;
  8.     if fWidth       < InnerRect.Width   then InnerRect.Width  := fWidth;
  9.     if fHeight      < InnerRect.Height  then InnerRect.Height := fHeight;
  10.     Result := InnerRect;
  11.   end
  12.   else
  13.   begin
  14.     InnerRect.Left  := fLeft;
  15.     InnerRect.Top   := fTop;
  16.     InnerRect.Width := fWidth;
  17.     InnerRect.Height:= fHeight;
  18.     Result := InnerRect;
  19.   end;
  20. end;



Wenn cih nun im Fenster1 SetScissors aufrufe, wird alles wunderbar abgeschnitten.
Allerdings wird Fenster3 nur an den Raendern von Fenster1 und nicht von Fenster2 abgeschnitten.

Wenn ich jetzt aber (Achtung: Kuriosum) die Scissors nur um Fenster2 aktiviere, wird Fenster3 an den Raendern von Fenster2 wunderbar abgeschnitten (aber logischerweise wieder nichtmehr an den Raendern von Fenster1).

Im Grunde muesste aber Fenster3 an Fenster1 und Fenster2 abgeschnitten werden, zumal der Schnitt an Fenster2 ja durch den Test geht. Wenn ich Fenster1 zeichne, nutzt er eine Scissorbox in der Größe des gesamten SDLFensters, da Fenster1 ja das oberste Parentelement ist und daher keine Begrenzungen hat, ausser das SDLFenster selber.
Wenn Fenster1 fertig gezeichnet ist, dann geht er zu Fenster2 und nutzt die dort errechnete Scissorbox, und die ist jetzt mit den Größen von Fenster1 gefuellt. Bis dahin klappt die Rechnung. Ist Fenster2 fertig, gehts noch ein childelement tiefer zu fenster3 und nun muesste an den Grenzen von Fenster1 und Fenster2 abgeschnitten werden, aber nun wird nur an Fenster1 abgeschnitten...


Wenn ich mir deinen Code ansehe, ist es ja im Grunde beinahe das Gleiche. Nur meins geht halt nicht richtig ^^


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Jun 26, 2007 19:14 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ja, beinahe und ich glaube da haperts.

So wie ich das sehe, hast du ja ein problem mit höhe und breite. Das Problem hatte ich auch am Anfang und es lag an der Zeile mit gglMin. Du machst das nicht genauso wie ich. Versuch doch mal, meinen Code auf deine Klassenstruktur anzupassen.
Wenn es dann klappt, kann ich dir auch erklären weshalb, aber im Moment sitze ich an einem fremden Rechner, daher habe ich nicht so viel Zeit.

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Di Jun 26, 2007 21:18 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Also ich hab mal n bissel was durchgetestet und offenbar liegt es nicht an diesem Vergleich.
Mein Vorgehen ist ja beim Zeichnen wie folgt:

Die Scissorbox von Window1 wird gesetzt
Dann wird WIndow1 gezeichnet
Dann wird geht er in alle Childobjekte
Die Scissorbox von Window2 wird gesetzt
Dann wird Window2 gezeichnet

usw.

Im Grunde sollte es ja so gehen...

Code:
  1. procedure TSE_GUI_Window_Custom.Draw;
  2. var i:Integer;
  3. begin
  4.   inherited;
  5.  
  6.   glPushMatrix;
  7.  
  8.   glEnable(GL_SCISSOR_TEST);
  9.     SetScissors;
  10.  
  11.   // Setzt direkt von der oberen Linken Ecke
  12.   glTranslatef(Left,Top,0);
  13.  
  14. // Zeichnen
  15.  
  16.   glDisable(GL_SCISSOR_TEST);
  17.  
  18.   for i := 0 to fItems.Count - 1 do
  19.     (fItems.Objects[i] as TSE_GUI_Custom).Draw;
  20.  
  21.  
  22.   glPopMatrix;
  23. end;


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 27, 2007 14:28 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Ich habs mir nochmal angesehen..

Code:
  1.     if fWidth       < InnerRect.Width   then InnerRect.Width  := fWidth;
  2.     if fHeight      < InnerRect.Height  then InnerRect.Height := fHeight;
  3.  


und

Code:
  1.     InnerRect.Width := ReturnMin(InnerRect.Width,fWidth);
  2.     InnerRect.Height := ReturnMin(InnerRect.Height,fHeight);
  3.  


sind im Grunde das selbe.

Du machst aber praktisch das Folgende:
Code:
  1.     InnerRect.Width := ReturnMin(InnerRect.Width,fWidth-InnerRect.Left);
  2.     InnerRect.Height := ReturnMin(InnerRect.Height,fHeight-InnerRect.Top);
  3.  


Und ich verstehe nicht, warum du da hinten noch etwas subtrahierst. Zumal das bei mir eh nicht geht, weil dann Width und Height bei mir negative Werte annehmen.
Wenn meine Box bei 200,200 erzeugt wird und 50 breit und 50 hoch ist, dann würde nach deiner Rechnung die neue Breite und Hoehe bei -150 liegen. Versteh ich nicht


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Mi Jun 27, 2007 18:47 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Du musst aber eines Bedenken:
Die Left und Top-Koordinaten sind wegen der Rekursion und der Befehlsreihenfolge noch die des Child-Fensters. Daher kann das stimmen, weil so verhindert wird, dass dieses über den Rand zeichnet.

Gruß Lord Horazont

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Jun 28, 2007 09:09 
Offline
DGL Member

Registriert: So Aug 20, 2006 23:19
Beiträge: 564
Das versteh ich jetz nich ^^ Wozu rechnest du bei Width und Height Left und Top mit ein?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags:
BeitragVerfasst: Do Jun 28, 2007 13:29 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich musste zwar auch erstmal in meine alten Unterlagen schauen (ist schon etwas länger her, dass ich den Algo geschrieben habe) aber jetzt kann ich es dir anhand der beigefügen Grafik zeigen.

//Edit: Das gleiche Gilt für die Breite, aber natürlich alles auf der Y-Achse

Gruß Lord Horazont


Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 12 Beiträge ] 
Foren-Übersicht » Programmierung » OpenGL


Wer ist online?

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.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.015s | 15 Queries | GZIP : On ]