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

Aktuelle Zeit: Fr Jul 18, 2025 14:53

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 6 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Sa Jan 30, 2010 14:14 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
So, meine GUI nimmt langsam (nebenbei will ja noch ein Chemiestudium bestritten werden ^^) aber sicher Form an. Die Grundklasse, von der ich alle Komponenten ableiten will, die in Interaktion mit dem Benutzer treten steht kurz vor der Fertigstellung - es fehlt nur noch eine Winzigkeit, um die es hier gehen soll.

Also, Erklärung zum Screenshot: Ihr seht da 4 Quadrate, rot, grün, blau und weiß. Die drei farbigen Quadrate sind "eigenständige" (nur dem GUI-Manager untergeordnete) Kontrollelemente. Sie reagieren auch korrekt auf die gängigen Mausereignisse (MouseMove, MouseEnter, MouseLeave, MouseClick, MouseDown, MouseUp). Das weiße Quadrat ist nicht direkt dem GUI-Manager untergeordnet, sondern dem roten Quadrat - hier wird mir von Mausereignissen als Sender dummerweise das rote Quadrat gemeldet...und das ist das Problem, der Sender sollte natürlich das weiße Quadrat sein.

Hier noch ein bisschen Quellcode:

1.: TglGUIManager.FindMouseEvent:
Diese Prozedur wird aufgerufen sobald in der Form, auf der sich der Rendercontext befindet ein Mausereignis stattfindet.
Code:
  1.  
  2. Function TglGUIManager.FindMouseEvent(MouseX: Integer; MouseY: Integer): TglControl;
  3. var
  4.   i:                  Integer;
  5.   PixelData:          LongInt;
  6.   Index:              Integer;
  7.   glMouseX, glMouseY: Integer;
  8. begin
  9. // 1. Mausposition OpenGL-konform umrechnen
  10. glMouseX := MouseX;
  11. glMouseY := Home.ClientHeight - MouseY;
  12.  
  13. // 2. Momentan gesetzte OpenGL-Attribute sichern und Buffer leeren
  14. glPushAttrib(GL_ALL_ATTRIB_BITS);
  15. glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  16.  
  17. // 3. Blending, Alpha und Texturierung deaktivieren, um Selektionsfarben nicht
  18. //    zu verfälschen, außerdem Scissor setzen.
  19. glDisable(GL_BLEND);
  20. glDisable(GL_ALPHA);
  21. glDisable(GL_TEXTURE_2D);
  22. glEnable(GL_SCISSOR_TEST);
  23. glScissor(glMouseX, glMouseY, 1, 1);
  24.  
  25. // 4. Alle untergeordneten Objekte, die auf Ereignisse reagieren können zeichnen
  26. for i := 0 to High(Children) do
  27.   if Children[i].InheritsFrom(TglControl) then
  28.     (Children[i] as TglControl).Render(True);
  29.  
  30. // 5. Farbinformationen auslesen und in Index umrechnen
  31. glReadPixels(glMouseX, glMouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, @PixelData);
  32. Index := ((PixelData and $FFFFFF) - 1);
  33. if Index <> -1 then Index := Index div 150;
  34.  
  35. // 6. Entweder kein Objekt getroffen, oder herausfinden ob ein Objekt selbst,
  36. //    oder eines der ihm untergeordneten Objekte getroffen wurde.
  37. if (Index = -1) or (Index > High(Children)) then
  38.   Result := nil
  39.   else
  40.   Result := (Children[Index] as TglControl).FindMouseEvent(glMouseX, glMouseY);
  41.  
  42. // 7. Attributen zurücksetzen
  43. glPopAttrib;
  44. end;
  45.  


2.: TglControl.Render
Kein Geheimnis: Die Renderprozedur der Kontrollelemente
Code:
  1.  
  2. procedure TglControl.Render(pSelection: Boolean = False);
  3. var
  4.   r, g, b:  Single;
  5.   i:        Longword;
  6.   iv:       Array[0..3] of Byte absolute i;
  7. const
  8.   fac = 1 / 255;
  9. begin
  10. // 1. Matrix sichern und "Position beziehen"
  11. glPushMatrix;
  12. glTranslatef(Left, Bottom, ZOrder);
  13.  
  14. if not pSelection then
  15.   // 2. Wenn keine Selektion durchgeführt wird: Einfach rendern.
  16.   begin
  17.   glColor4f(Red, Green, Blue, Alpha);
  18.   glBegin(GL_QUADS);
  19.     glVertex3f(0, 0, 0);
  20.     glVertex3f(Width, 0, 0);
  21.     glVertex3f(Width, Height, 0);
  22.     glVertex3f(0, Height, 0);
  23.   glEnd;
  24.  
  25.   if High(Children) <> -1 then
  26.     begin
  27.     glEnable(GL_SCISSOR_TEST);
  28.     glScissor(Trunc(Left), Trunc(Bottom), Trunc(Width), Trunc(Height));
  29.     for i := 0 to High(Children) do
  30.       if Children[i].InheritsFrom(TglControl) then
  31.         (Children[i] as TglControl).Render;
  32.     glDisable(GL_SCISSOR_TEST);
  33.     end;
  34.  
  35.   glPopMatrix;
  36.   end
  37.   else
  38.   // 3. Wenn doch:
  39.   begin
  40.   // 4. Selectionsfarbe berechnen
  41.   // Nur das sich keiner wundert: Ich kann im Editor einstellen, ob ich die
  42.   // "Szene" in Selektionsfarben sehen will. Damit ich da nicht nur schwarz sehe
  43.   // die Multiplikation mit 150.
  44.   i := (Index + 1) * 150;
  45.   r := iv[0] * fac; g := iv[1] * fac; b := iv[2] * fac;
  46.  
  47.   // 5. Farbe setzen, rendern.
  48.   glColor4f(r, g, b, 1);
  49.   glBegin(GL_QUADS);
  50.     glVertex3f(0, 0, 0);
  51.     glVertex3f(Width, 0, 0);
  52.     glVertex3f(Width, Height, 0);
  53.     glVertex3f(0, Height, 0);
  54.   glEnd;
  55.  
  56.   glPopMatrix;
  57.   end;
  58. end;
  59.  


3.: TglControl.FindMouseEvent
Siehe TglGUIManager.FindMouseEvent: Wird aufgerufen um rauszufinden, ob ein "Kind" des zunächst als getroffen festgestellten Objekt getroffen wurde.
Code:
  1.  
  2. Function TglControl.FindMouseEvent(glMouseX: Integer; glMouseY: Integer): TglControl;
  3. var
  4.   i:          Integer;
  5.   PixelData:  Longword;
  6.   Index:      Integer;
  7. begin
  8. // 1. Buffer wieder löschen (Tiefenpuffer ist testweise auskommentiert,
  9. //    Selektion funktioniert auch mit gelöschtem Tiefenpuffer nicht)
  10. glClear(GL_COLOR_BUFFER_BIT{ or GL_DEPTH_BUFFER_BIT});
  11.  
  12. // 2. Alle untergeordneten Kontrollelemente in Selektionsfarben zeichnen
  13. for i := 0 to High(Children) do
  14.   if Children[i].InheritsFrom(TglControl) then
  15.     (Children[i] as TglControl).Render(True);
  16.  
  17. // 3. Pixelfarbe an Mausposition auslesen, Index ausrechnen
  18. glReadPixels(glMouseX, glMouseY, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, @PixelData);
  19. Index := ((PixelData and $FFFFFF) - 1);
  20. if Index <> -1 then Index := Index div 150;
  21.  
  22. // 4. Wenn kein Objekt getroffen wurde, wurde das Hauptobjekt getroffen, sonst...
  23. if Index = -1 then
  24.   Result := Self
  25.   else
  26.   Result := (Children[Index] as TglControl).FindMouseEvent(glMouseX, glMouseY);
  27. end;
  28.  


Da die Selektion auf "Rootebene", also der Ebene gleich über dem Manager funktioniert, scheint der Fehler irgendwo in 3. zu liegen, aber ich finde ihn einfach nicht...vielleicht (hoffentlich) kann mir hier ja jemand helfen.


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


Zuletzt geändert von zoiX am Sa Jan 30, 2010 17:41, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 30, 2010 14:54 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Peinlich....20 Minuten nach dem ich den Thread erstellt hatte bringt ein Einkauf und das damit verbundene Sinnieren über ein völlig anderes Problem (Was esse ich heute?) die Erleuchtung...

Hatte schlichtweg vergessen, wenn ich die "Kinder" in Selektionsfarben zeichne, vorher den Ursprung auf den Ursprung des übergeordneten Objektes zu setzen.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 30, 2010 15:04 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2623
Wohnort: Berlin
Programmiersprache: Go, C/C++
Colorpicking ist eine recht langsame variante GUI picks zu machen und meiner meinung nach garnicht notwendig.
Die meisten Spiele nutzen entweder 2d Boxed intersection oder 2d/3d vectorbased intersection.
Ich kann dir 2D Boxed intersection empfehlen, da es so ziemlich das schnellste ist und für die meisten Projekte völlig ausreichend ist.
Code:
  1. If (Mouse.X>Elmt.Position.X && Mouse.X<Elmt.Position.X+Elmt.Position.Width && Mouse.Y>Elmt.Position.Y && Mouse.Y<Elmt.Position.Y+Elmt.Position.Height)
  2.   return true;
  3. else
  4.   return false;

Vector intersection wird im Professionellen Bereich oft verwendet.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 30, 2010 17:40 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Ich hab mir schon fast gedacht das sowas kommt, und mir auch selbst schon Gedanken gemacht, ob ein "geometriebasiertes" Picking für mich nicht besser wäre, aber ich will auch nicht-rechteckige (und nichtmal zwingend viereckige) Kontrollelemente "verbauen", und weiß nicht genau, wie ich Treffer da basierend auf der Geometrie finden soll. Ich bin nicht besonders fit in Geometrie, und die Frage, ob ein Punkt innerhalb eines Dreiecks liegt stellt mich schon vor eine große Hürde, wenn ich sie mittels eines Algorithmus beantworten soll.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 30, 2010 17:59 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2623
Wohnort: Berlin
Programmiersprache: Go, C/C++
Schau z.B. mal hier rein.
http://www.gamedev.net/community/forums/topic.asp?topic_id=295943

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jan 30, 2010 19:24 
Offline
DGL Member

Registriert: Mo Aug 31, 2009 13:19
Beiträge: 151
Ja....schaut ja denkbar einfach aus o.O Das man auf sowas nicht selber kommt...
Hatte gerade eben auch noch gegoogelt und auch ne Methode, die nicht allzu kompliziert klang gefunden, aber die Methode über die Flächen ist einfach großartig. Und auch auf höhere n-Ecke verallgemeinerbar, ohne sie auf Dreiecke zu vereinfachen, wenn ich mich recht entsinne.

Da wird meine Geometrie-Unit heute abend wohl noch ein paar Prozeduren lernen...


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


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 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:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.008s | 14 Queries | GZIP : On ]