(6) Polygon Clipping Vorlesung „Computergraphik I“ S. Müller UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 1 - Wiederholung I Clipping Berechnung eines Ausschnitts Test der Gültigkeit der Parameter bei Putpixel zu teuer, daher Clipping z.B. mit Bildschirmfenster 2-Stufiges Vorgehen: • Schneller Test, ob Linie innerhalb/außerhalb des Bildschirms liegt • Berechnung des Schnittpunkts nur, wenn unbedingt nötig. Cohen-Sutherland UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 2 - Wiederholung II 1001 Durch einfache Bit-Operationen (und, oder) lässt sich schnell erkennen, ob eine Linie vollständig innerhalb bzw. außerhalb des Bereichs liegt. 1. 2. 3. 4. 5. B E 0001 0101 Linie vollständig außerhalb, fertig. Linie vollständig innerhalb, alles zeichnen. Sonst: neue Punkte bestimmen bis 3) erreicht ist UNIVERSITÄT KOBLENZ · LANDAU 1010 A c1 & c2 ≠ 0 c1 | c2 == 0 1000 H 0000 C F D G 0010 0110 0100 cA&cB 1000 cC&cD 0000 cC | cD 0100 cut cE&cF 0000 cE | cF 0000 draw cG&cH 0000 cG | cH 0110 cut ignore S. Müller - 3 - Wiederholung III { c1 = outcode( a); c2 = outcode( b); A (Oben, Links) A (Oben, Rechts) while((c1 | c2) != 0) { if ((c1 & c2) != 0) return ; n.x = a.y-b.y; n.y = b.x-a.x; d = a.x*b.y-a.y*b.x; A‘ (Oben) A‘‘ (0000) if (c1 == 0) c = c2; else c = c1; A‘ (0000) B (0000) if ((c & C_LEFT) != 0) { p.x = xmin; p.y = -(n.x*p.x+d)/n.y;} else if ((c & C_RIGHT) != 0) { p.x = xmax; p.y = -(n.x*p.x+d)/n.y;} else if ((c & C_TOP) != 0) { p.y = ymax; p.x = -(n.y*p.y+d)/n.x;} else if ((c & C_BOTTOM) != 0) { p.y = ymin; p.x = -(n.y*p.y+d)/n.x;} B (0000) B (Rechts) A‘ (Rechts) if (c == c1) { a = p; c1 = outcode( a);} else { b = p; c2 = outcode( b);} A (Unten) } draw_line( a, b); } UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 4 - Wiederholung IV: Cohen-Sutherland Dieser Algorithmus arbeitet sehr effizient Er findet vor allem für Clipping an Bildschirmkanten Verwendung Nachteil: er funktioniert nur für rechteckige Ausschnitte für beliebige Ausschnittsfenster ist der Bereichscode so nicht mehr einsetzbar; das gleiche gilt für die einfache Berechnung der Schnittpunkte zwischen den Kanten der Ausschnittsfenster und den Linien Erweiterung für beliebige Ausschnittsfenster: CyrusBeck UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 5 - Wiederholung V: Cyrus-Beck Clipping von Linien, an beliebigen, konvexen Polygonzügen Eckpunkte des Clip-Objekts müssen gegen den Uhrzeigersinn definiert werden („counterclockwise“) Degenerierte Kanten (identische Eckpunkte) müssen vorher abgefangen werden Berechnung der Normalen auf die Kanten des Clip-Objekts, wobei Normalen nach außen zeigen UNIVERSITÄT KOBLENZ · LANDAU Start- und Endpunkt der zu zeichnenden Linie werden für jede Kante mit Hilfe eines In/Out-Tests klassifiziert Skalarprodukt zwischen Normale und Verbindung Kante-Linienpunkt Beiden innen: weitermachen ohne SP Berechnung Beide außen: aufhören. Falls SP berechnet wird, wird dieser ebenfalls als In/OutPunkt klassifiziert. S. Müller - 6 - Wiederholung VI: Cyrus-Beck void clip_and_draw( glm::ivec2 a, glm::ivec2 b) { float t, t_in, t_out, c0, c1, nenner; c0 = glm::dot( w0, n); c1 = glm::dot( w1, n); if (c0 > 0 && c1 > 0) // alles außerhalb, fertig return; if (c0 <= 0 && c1 <= 0) // innerhalb, weitertesten continue; nenner = glm::dot( v, n); t = -c0/nenner; glm::vec2 v; glm::vec2 w0, w1, n; v.x = b.x - a.x; v.y = b.y - a.y; t_in = 0.0; t_out = 1.0; for ( { int n.x n.y int i = 0; i < 4; i++) if (nenner < 0 && t > t_in) t_in = t; if (nenner > 0 && t < t_out) t_out = t; iNext = (i+1) % 4; = P[iNext].y-P[i].y; = -(P[iNext].x-P[i].x); } if (t_in > t_out) return; w0 = a - P[i]; w1 = b - P[i]; b.x b.y a.x a.y 04_Clipping.sln UNIVERSITÄT KOBLENZ · LANDAU = = = = a.x a.y a.x a.y + + + + t_out t_out t_in t_in * * * * v.x; v.y; v.x; v.y; draw_line( a, b); } S. Müller - 7 - Wiederholung VII: Cyrus-Beck B In B Out Out Out A In A In Die klassifizierten Schnittpunkte (In/Out) werden entlang von t sortiert. Ist t_in (t für äußersten In-Punkt) größer als t_out (t für innersten Out-Punkt), dann liegt die Linie außerhalb und muss nicht gezeichnet werden. UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 8 - Polygon Clipping UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 9 - Ausgangspunkt Wir haben gesagt, dass die „Applikation“ sicherstellen muss, dass put_pixel(x,y) nur für gültige Pixel aufgerufen wird. Bisher Clipping von Linien: Cohen-Sutherland: Clippen von Linien an rechteckigen Objekten mit Hilfe von Bereichscodes. Cyrus-Beck: Clippen von Linien an beliebigen, konvexen Polygonzügen Clipping von Polygon gegen Polygon: Sutherland-Hodgman UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 10 - Sutherland-Hodgman Clipping eines Polygonzugs gegen ein konvexes ClipPolygon (z.B. Bildschirm); der Polygonzug darf konkav sein. Polygonzug (4 Punkte) Ergebnis (9 Punkte) Bildschirm UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 11 - Vorgehen Der Polygonzug wird der Reihe nach an den Clip-Kanten geschnitten. UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 12 - Vorgehen Das Ergebnis muss wieder ein geschlossener Polygonzug sein. Als Eingabe dient die Liste der Eckpunkte in der richtigen Reihenfolge (gegen den Uhrzeigersinn). Die Routine gibt – nach dem Schnitt mit der jeweiligen Clip-Kante - eine neue Liste von Eckpunkten zurück. Wichtig: die Reihenfolge muss stimmen. UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 13 - 4 Fälle Annahme: der Startpunkt A wurde bereits behandelt B S B A S B Beide Punkte drinnen: Output B A Linie „zeigt“ nach außen: Output S B A A Linie „zeigt“ nach innen: Output S, B UNIVERSITÄT KOBLENZ · LANDAU Beide Punkte draußen: Output (nichts) S. Müller - 14 - D Beispiel 1 S1 S2 A Input: Output: C A B C D S1 A B C S 2 B Man beginnt mit der Kante letzter Punkt (D) – erster Punkt (A) UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 15 - Beispiel 2 S1 S3 S2 S6 A C S5 Input: S1 A B C S 2 Output: S3 S1 A S 4 S5 C S 6 UNIVERSITÄT KOBLENZ · LANDAU S4 B S. Müller - 16 - PseudoCode Diese Routine wird der Reihe nach für jede Clip-Kante aufgerufen. „Innerhalb/Außerhalb“: hier wird wieder die Normale auf die Kante berechnet und mit Hilfe des Vorzeichens des Skalarproduktes entschieden. „Output“: stellt ein neues Polygon zusammen, das am Ende zurückgegeben wird. „Schnittpunkt“ berechnet den Schnittpunkt mit der Clipkante, wobei nur Punkte zw. A und B berechnet werden dürfen. UNIVERSITÄT KOBLENZ · LANDAU Polygon SutherlandHodgman(Polygon poly, Edge clipedge) { A ist letzter Punkt des Polygons; Schleife über alle Ecken B des Polygons { if B innerhalb von clipedge if A innerhalb von clipedge Output (B); else { S = Schnittpunkt (A,B,edge); Output(S), Output(B); } else if A innerhalb von clipedge { S = Schnittpunkt (A,B,edge); Output(S); } A = B; } Ergebnis von Output zurückgeben. } S. Müller - 17 - Beispiel D A C B Problem: unnötige Kanten mit Fläche Null… UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 18 - Sutherland-Hodgman Clipping eines Polygonzugs gegen ein konvexes ClipPolygon (z.B. Bildschirm); der Polygonzug darf konkav sein. Problem: unnötige Kanten können am Rand entstehen, was nicht unbedingt zu Fehlern führt; aus Effizienzgründen können diese nachträglich gelöscht werden. Lässt sich sehr gut als Pipeline in Hardware umsetzen. Erweiterung für konkave Clip-Polygone: Weiler-Atherton UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 19 - Clippen von Texten und Bildern Schrift besteht aus Kurven für Umrisse der Buchstaben Diese werden in der Regel einmal gezeichnet und in verschiedenen Auflösungen als Pixelmuster/Bitmap gespeichert Diese Bitmaps werden als Rechtecke betrachtet und gegen das Clip-Objekt geschnitten und nur der sichtbare Teil gezeichnet. Das gleiche gilt auch für Bilder. UNIVERSITÄT KOBLENZ · LANDAU a S. Müller - 20 - GPU: Vertex Attribute UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 21 - CPU vs. GPU CPU: mehrere Recheneinheiten GPU: tausende Recheneinheiten „Stream“ Quasi jeder Computer hat heute einen Grafikprozessor (Graphics Processing Unit, GPU) Vorteil: Tasks können hoch parallel bearbeitet werden UNIVERSITÄT KOBLENZ · LANDAU Idee: möglichst gleiches Programm auf vielen Daten ausführen (single instruction multiple data, SIMD) S. Müller - 22 - Vertices Die Eingabedaten für das Rendering sind Linienzüge (Polygone, in der Regel Dreiecke) als Liste von 3DEckpunkten (vertices). Für jeden Vertex können unterschiedliche Attribute (Position, Farbe, Normale) definiert werden mit 1-4 Werten pro Eintrag Die Liste der Attribute werden als Arrays (ARRAY_BUFFER) in einem Buffer-Objekt übergeben (oft Vertex-Buffer-Objects (VBOs) genannt) UNIVERSITÄT KOBLENZ · LANDAU Diese Daten werden dann auf die GPU geladen (oder liegen dort schon vor). Durch glDraw… werden dann alle Polygone des Objekts gerendert. Hierfür gibt es 2 Buffer-Typen Nicht indizierte Arrays Indizierte Arrays S. Müller - 23 - 2 Buffer-Typen v y v y (1, 2) 2 (3, 2) 2 1 v3 v2 1 (0, 0) 0 0 (2, 0) 1 2 3 v x Nicht indiziert Für jeden Eckpunkt (gegen den Uhrzeigersinn) die Koordinaten des Eckpunkt (x, y) GLfloat vertices[] = {0,0, 2,0, 1,2, 1,2, 2,0, 3,2}; v0 0 0 v1 1 2 3 v x Indiziert Eine Liste der Koordinaten der Eckpunkte Eine Liste von Indizes (gegen den Uhrzeigersinn) GLfloat vertices[] = {0,0, 2,0, 1,2, 3,2}; Glint indices[] = {0,1,2, 2,1,3}; UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 24 - Mehrere Attribute Pro Vertex können mehrere Attribute angegeben werden. Jedes Attribut kann unterschiedliche Dimension haben (z.B. Position (x, y) und Farbe (r, g, b)) GLfloat vertices[] = (6 Vertices ≈ 12 Einträge) {0,0, 2,0, 1,2, 1,2, 2,0, 3,2}; GLfloat colors[] = (6 Vertices ≈ 18 Einträge) {1,0,0, 1,0,0, 1,0,0, 0,0,1, 0,0,1, 0,0,1}; Aber die Anzahl der Vertices muss in allen Listen gleich sein UNIVERSITÄT KOBLENZ · LANDAU v y (1, 2 ) 2 (3, 2) 1 (0, 0) 0 0 (2, 0) 1 2 3 v x Nicht indizierte Liste Vorteil: verschiedene Werte (z.B. Farben) pro Eckpunkt Nachteil: braucht mehr Speicher S. Müller - 25 - OpenGL Buffer Objekte CPU Viele Daten, wie hier die Vertex-Arrays, werden in Buffern angelegt. Um einen Buffer anzulegen, wird allerdings ein eigenes „Objektmodell“ verwendet. Z.B. GPU Lösung Buffer allokieren und ID (fortlaufende Nummer) holen GLuint vbo; glGenBuffers(1, &vbo); Bufferid = new Buffer(); würde nicht funktionieren, da es nur einen Pointer auf einen Speicherbereich der CPU liefern würde. Ein Buffer braucht aber eine eindeutige ID für CPU und GPU UNIVERSITÄT KOBLENZ · LANDAU Buffer binden (quasi eine glob. Variable setzen), alle BufferKommandos beziehen sich auf diesen „aktiven“ (gebundenen) Buffer glBindBuffer(GL_ARRAY_BUFFER, vbo); Indizierte Liste: glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, … S. Müller - 26 - GLfloat vertices[] = {-1.0,-1.0, 0.0,-1.0, -0.5,0.0, -0.5, 0.0, 0.0,-1.0, 0.5,0.0}; Vertex Attribute zuordnen Wir haben das Array (z.B. von Vertices) und ein „aktives“ Bufferobjekt. Die Zuordnung der Daten geschieht mit glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //Bei Index-Liste GL_ELEMENT_ARRAY_BUFFER //Größe des Array in Bytes //Pointer auf das Array Das letzte Flag gibt dem Treiber einen Hinweis, wo er die Daten ablegen soll GL_STATIC_DRAW: Die Daten werden nicht verändert und können einmal auf die Karte runtergeladen werden GL_DYNAMIC_DRAW: Die Daten werden verändert und sollten auf der CPU verbleiben UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 27 - Vollständige Liste (aus OpenGL SuperBible 6th ed.) UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 28 - Letzer Schritt Genaue Anweisung geben, wie der aktive (gebundene) Buffer zu interpretieren ist glVertexAttribPointer( 0, // Eigene Location ID (z.B 0 für Position, // // // // // // 1 für Farbe (Details später…) Anzahl der Elemente/Eintrag (x,y) oder (r,g,b) Datentyp der Elemente Normalized oder nicht Schrittweite Offset, wo in Array begonnen wird 2, GL_FLOAT, GL_FALSE, 0, 0); Normalized ist relevant, wenn man als Datentypen int hat, die automatisch nach float konvertiert werden. True: die Werte werden auf [0,1] normalisert Schrittweite: 0 gibt an, dass die Daten direkt aufeinander folgen. Alternative: interleaved (Position, Farbe etc. werden nicht in eigenen Arrays gespeichert, sondern hintereinander in einem). UNIVERSITÄT KOBLENZ · LANDAU x1 y1 r1 g1 b1 Schrittweite (in Byte) x2 y2 … S. Müller - 29 - Buffer rendern glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); In der Renderingschleife jedes Attribut explizit einschalten (der Wert muss der location ID entsprechen, Details später…) glEnableVertexAttribArray(0); Gesamten Buffer Rendern glDrawArrays( GL_TRIANGLES, 0, sizeof(vertices)); //Modus, wie gerendert wird //Start-Index //Anzahl der vertices Alternative (indizierte Liste): glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); //Modus, wie gerendert wird //Anzahl der zu rendernden vertices //Typ der Werte in der Indexliste //Start-Index Eventuell jedes Array wieder ausschalten glDisableVertexAttribArray(0); UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 30 - Beispiele mode 2. 2. 1. 3. GL_POINTS 1. 3. 0. 4. 2. 0. 4. 1. 3. 0. 4. GL_LINE_STRIP GL_LINE_LOOP Mehrfachprimitive 2. 1. 5. 4. 1. 3. 0. 0. 2. 4. 2. 4. 3. 4. 0. GL_LINES 0. 5. GL_TRIANGLES UNIVERSITÄT KOBLENZ · LANDAU 1. 3. GL_TRIANGLE_STRIP 3. 1. 2. GL_TRIANGLE_FAN S. Müller - 31 - Typischer Ablauf GLfloat v[] = {-1.0,-1.0, 0.0,-1.0, -0.5,0.0, -0.5, 0.0, 0.0,-1.0, 0.5,0.0}; Ein VertexArray mit Positionsdaten Einmalig: • Einen Buffer allockieren, • diesen Buffer „aktiv“ schalten, • Daten zuordnen GLuint vertexbuffer; … glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW); while( !glfwWindowShouldClose( window)) { glClear(GL_COLOR_BUFFER_BIT); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); glDrawArrays( GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); glfwSwapBuffers( window); glfwPollEvents(); Pro Rendering • Buffer „aktiv“ schalten, • Traversierung bekannt geben • An Shader Location 0 binden und einschalten } UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 32 - CPU GPU 0 Typischer Ablauf GLfloat v[] = {…}; GLuint vertexbuffer; … glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(v), &v, GL_STATIC_DRAW); while( !glfwWindowShouldClose( window)) { glClear(GL_COLOR_BUFFER_BIT); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); glDrawArrays( GL_TRIANGLES, 0, 6); glDisableVertexAttribArray(0); glfwSwapBuffers( window); glfwPollEvents(); 05_Polygone.sln } UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 33 - Punkte und Linien in OpenGL UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 34 - Punkte, Linien, Flächen Alle bisher behandelten Algorithmen zum Zeichnen von Punkten Zeichnen von Linien (mit Clipping und linearer Interpolation von Eckpunktwerten z.B. Farbe) … … sind in OpenGL sehr effizient implementiert und auch entsprechend auf die Möglichkeiten der GraphikHardware abgebildet. OpenGL bietet uns daher eine wichtige Bibliothek zur Erstellung von graphischen Systemen (API: application programming interface) UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 35 - Namenstypisierung Funktionen mit verschiedenen Parametern tragen Typ und Dimension im Namen: gl<FUNC>{1234}{b,ub,s,us,i,ui,f,d}[v](...) 1,2,3,4: Dimension der Argumente b,ub,s,us,i,ui,f,d: Typ: GLbyte, GLubyte, etc. Sonderfall: GLclampf, GLclampd optional können Parameter auch als Vektor übergeben werden, gekennzeichnet durch das abschließende v UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 36 - Namenstypisierung Beispiel: glColor{34}{b,ub,s,us,i,ui,f,d}[v](...) GLfloat f[3] = { 0.0, 0.5, 1.0 }; GLubyte b[4] = { 0, 127, 255, 255 }; glColor3f( 0.0, 0.5, 1.0 ); glColor3fv( f ); glColor4ubv( b ); UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 37 - Primitivspezifische Einstellungen Punkte: Größe mittels glPointSize( GLfloat size ); nicht jede Größe unterstützt, über glGet() abzufragen Wenn Antialiasing abgeschaltet ist (default), dann ist der Punkt ein Quadrat von size*size Pixeln. Nicht-Integer Werte werden gerundet. glDisable(GL_POINT_SMOOTH); Wenn Antialiasing eingeschaltet ist, dann wird ein Kreis gezeichnet. Nicht-Integer Werte für size werden hier nicht gerundet. glEnable(GL_POINT_SMOOTH); UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 38 - Aktivieren / Inaktivieren Viele Features müssen explizit aktiviert werden glEnable( GLenum feature ); zum Inaktivieren dient dann glDisable( GLenum feature ); der Zustand kann abgefragt werden mittels glIsEnabled( GLenum feature ); die Konstanten können nicht verodert werden UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 39 - Linien Linien: Breite mittels glLineWidth( GLfloat width ); ähnlich wie Punkte nicht jede Größe möglich Wenn Antialiasing abgeschaltet ist (default), dann ist width die Breite der Linie in Pixeln (also unabhängig von Fenstergröße…). Nicht-Integer Werte werden gerundet. glDisable(GL_LINE_SMOOTH); Wenn Antialiasing eingeschaltet ist, dann wird die Helligkeit der Pixel abhängig vom Bedeckungsgrad berechnet. NichtInteger Werte werden hier nicht gerundet. glEnable(GL_LINE_SMOOTH); UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 40 - Beispiel points_lines.c points_lines.exe UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 41 - GLFW: Input Manager UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 42 - Events Während der Renderer in einer Endlosschleife läuft, wollen wir in der Regel auf Events (z.B. Taste gedrückt, Maus bewegt, Maustaste gedrückt) reagieren. GLFW bietet zwei Modi an: Callbacks: hier definieren wir eine Funktion, die automatisch aufgerufen wird, wenn eine Event auftrifft Polling: hier fragen wir explizit nach dem Zustand (z.B. einer Taste) UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 43 - Maus Callback Callback Funktion definieren int main() { … glfwSetMouseButtonCallback(window, mouseCallback); … Callback Funktion void mouseCallback(GLFWwindow* window, int button, int action, int mods) window: The window that received the event. button: The mouse button that was pressed or released. action: GLFW_PRESS or GLFW_RELEASE. mods: Bit field describing which modifier keys were held down (GLFW_MOD_SHIFT, GLFW_MOD_CONTROL, GLFW_MOD_ALT, GLFW_MOD_SUPER). UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 44 - Beispiel void mouseCallback(GLFWwindow* window, int button, int action, int mods) { if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) { … } if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) { …; } } UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 45 - Tastatur Callback Callback Funktion definieren int main() { … glfwSetKeyCallback (window, keyCallback); … Callback Funktion void keyCallback (GLFWwindow *window, int key, int code, int action, int mods) window: The window that received the event. key: The keyboard key that was pressed or released. code: The system-specific scancode of the key. action: GLFW_PRESS, GLFW_RELEASE, GLFW_REPEAT. mods: Bit field describing which modifier keys were held down. UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 46 - Beispiel void keyCallback (GLFWwindow *window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_C && action == GLFW_PRESS) …; if (key == GLFW_KEY_DOWN && action == GLFW_PRESS) …; if (key == GLFW_KEY_F1 && action == GLFW_PRESS) …; } 05_Polygone.sln UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 47 - Weitere Callbacks GLFWkeyfun glfwSetKeyCallback (GLFWwindow *window, GLFWkeyfun cbfun) Sets the key callback. GLFWcharfun glfwSetCharCallback (GLFWwindow *window, GLFWcharfun cbfun) Sets the Unicode character callback. GLFWmousebuttonfun glfwSetMouseButtonCallback (GLFWwindow *window, GLFWmousebuttonfun cbfun) Sets the mouse button callback. GLFWcursorposfun glfwSetCursorPosCallback (GLFWwindow *window, GLFWcursorposfun cbfun) Sets the cursor position callback. GLFWcursorenterfun glfwSetCursorEnterCallback (GLFWwindow *window, GLFWcursorenterfun cbfun) Sets the cursor enter/exit callback. GLFWscrollfun glfwSetScrollCallback (GLFWwindow *window, GLFWscrollfun cbfun) Sets the scroll callback. UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 48 - Alternative: direkt abfragen int glfwGetInputMode (GLFWwindow *window, int mode) Returns the value of an input option for the specified window. int glfwGetKey (GLFWwindow *window, int key) Returns the last reported state of a keyboard key for the specified window. int glfwGetMouseButton (GLFWwindow *window, int button) Returns the last reported state of a mouse button for the specified window. void glfwGetCursorPos (GLFWwindow *window, double *xpos, double *ypos) Retrieves the last reported cursor position, relative to the client area of the window. void glfwSetCursorPos (GLFWwindow *window, double xpos, double ypos) Sets the position of the cursor, relative to the client area of the window. int const float * const unsigned char * const char * glfwJoystickPresent (int joy) Returns whether the specified joystick is present. glfwGetJoystickAxes (int joy, int *count) Returns the values of all axes of the specified joystick. glfwGetJoystickButtons (int joy, int *count) Returns the state of all buttons of the specified joystick. glfwGetJoystickName (int joy) Returns the name of the specified joystick. UNIVERSITÄT KOBLENZ · LANDAU S. Müller - 49 -