Το εγχειρίδιο αυτό δεν είναι ολοκληρωμένο. Μπορείτε να βρείτε και να προσθέσετε πειραματικές σελίδες εδώ. Επίσης, δείτε τις διαθέσιμες μεταφράσεις.
Καλωσορίσατε και ευχαριστούμε που χρησιμοποιείτε τη βιβλιοθήκη Open Toolkit!
Αυτό το εγχειρίδιο θα σας οδηγήσει στα βασικά βήματα για να αναπτύξετε ένα project με την OpenTK. Θα μάθετε πώς να εγκαθιστάτε ένα καινούριο project, πώς να χρησιμοποιείτε επιτυχώς τα εργαλεία που παρέχει η OpenTK και τελικά, πώς να διανέμετε το project σας στους τελικούς σας χρήστες. Επίσης θα βρείτε πληροφορίες για το πώς να γράψετε αποδοτικό κώδικα και να διατηρείτε την cross-platform συμβατότητα.
Το εγχειρίδιο αυτό είναι γραμμένο με τέτοιο τρόπο ώστε να επιτρέπει να μεταπηδάτε από τη μία ενότητα στην άλλη κατά βούληση, οπότε κάντε το ελεύθερα. Ή ακόμα μπορείτε και να το διαβάσετε σειριακά από την αρχή μέχρι το τέλος αν το προτιμάτε. Απλά θυμηθείτε ότι μπορείτε να προσθέσετε σχόλια σε οποιοδήποτε σημείο – πάντα προσπαθούμε να βελτιώσουμε το εγχειρίδιο και τα σχόλιά σας θα βοηθήσουν όχι μόνο εμάς αλλά και μελλοντικούς χρήστες της OpenTK.
Ελπίζουμε ότι ο χρόνος που θα επενδύσετε στην ανάγνωση αυτού του εγχειριδίου θα αποδειχτεί χρήσιμος.
This page is the Greek Translation of The Open Toolkit Manual.
Για να χρησιμοποιήσετε την OpenTK, θα χρειαστείτε είτε το περιβάλλον .Net 2.0 (σε windows) ή την τελευταία έκδοση του 1.2.xMono (για Linux/Mac OS X/Windows). Αν χρησιμοποιείτε το Μono, σας συμβουλεύουμε να αναβαθμίσετε στη τελευταία διαθέσιμη έκδοση, καθώς οι παλαιότερες εκδόσεις από την 1.2.6 έχουν bugs που επηρεάζουν τη σταθερότητα της OpenTK.
Αν σκέφτεστε να κάνετε build από τον κώδικα, θα χρειαστείτε το Nant(αυτή η εξάρτηση θα αφαιρεθεί στο μέλλον).
Τέλος, κατεβάστε την OpenTK από τη σελίδα του Sourceforge. Οι εκδόσεις της OpenTK είναι απλά zip/7z αρχεία και η εγκατάσταση έγκειται στο να ξεζιπάρετε τα περιεχόμενα αρχεία σε μία τοποθεσία στο δίσκο – δεν είναι δυνατό να εγκαταστήσετε την OpenTK στη Global Assembly Cache σε αυτή τη φάση.
Για να χρησιμοποιήσετε την OpenTK, απλά έχετε σαν αναφορά στο project σας το OpenTK.dll. Επίσης πρέπει να τοποθετήσετε το OpenTK.dll.config στον ίδιο φάκελο με τα αρχεία του κώδικά σας, για να πετύχετε τη «compile μία φορά, τρέχει παντού» συμβατότητα.
Στις επόμενες σελίδες μπορείτε να βρείτε συγκεκριμένες οδηγίες ανά πλατφόρμα.
This page is the Greek Translation of Linux
Εγκατάσταση του Mono
Αν χρησιμοποιείτε κάποια πρόσφατη διανομή Linux, όλα τα προαπαιτούμενα για τα projects της OpenTK θα πρέπει να είναι ήδη διαθέσιμα: το the Mono runtime και οι Mono compilers. Με τις εντολές “mono – version” και “gmcs – version” ελέγξτε αν η έξοδος είναι κάπως έτσι:
Αν μία ή και οι δύο εντολές αποτύχουν, θα πρέπει να εγκαταστήσετε το Monο, το οποίο θα πρέπει να είναι ήδη διαθέσιμο από το μενού Προσθαφαίρεση Προγραμμάτων (package manager), οπότε μία γραμμή σαν και αυτή θα πρέπει να αρκεί:
Αν δεν υπάρχουν διαθέσιμα αρχεία Mono για εγκατάσταση, ή αν είναι παλιές εκδόσεις (η mono – version επιστρέφει κάτι μικρότερο του 1.2.6), πρέπει να κάνετε build το Mono από τον κώδικα. Υπάρχει ένα μήνυμα στο support forum που περιγράφει τη διαδικασία του πώς να κάνετε build το Mono από τον πηγαίο κώδικα.
Αλλιώς, μπορείτε να βρείτε τα αρχεία στην έκδοση του Mono Project opentk-x.y.z-mono.tar.gz από το Sourceforge και να τα αποσυμπιέσετε:
Ένα νέο opentk-x.y.z θα δημιουργηθεί με τέσσερις υποφακέλους: "Documentation", "Examples", "Libraries" και "QuickStart". Προσπαθήστε να τρέξετε τα παραδείγματα που περιέχονται στο δεύτερο υποφάκελο για να βεβαιωθείτε ότι όλα δουλεύουν:
Λογικά θα δημιουργηθεί ένα νέο παράθυρο, με μία λίστα με όλα τα διαθέσιμα παραδείγματα. Αν όχι, κοιτάξτε τη περιοχή σφαλμάτων παρακάτω.
Ο φάκελος “Libraries” περιέχει την κύρια OpenTK (OpenTK.dll) και το αρχείο OpenTK.dll.config – αυτά είναι όλα όσα χρειάζεστε για να τρέξετε τα OpenTK projects. Αν χρησιμοποιείτε το MonoDevelo, κοιτάξτε στον “QuickStart” φάκελο για ένα project έτοιμο για χρήση. Τέλος, μη ξεχάσετε να ρίξετε μια ματιά στις release notes στο φάκελο "Documentation".
Επίλυση Σφαλμάτων
Το ακόλουθο σφάλμα έχει εντοπιστεί σε Fedora Core 8, όταν τρέχει το Examples.exe:
Αυτό οφείλεται σε μία έλλειψη στο "/etc/mono/config". Για να το διορθώσετε, ανοίξτε το προαναφερθέν αρχείο (πρέπει να είστε root!) και προσθέστε αυτή τη γραμμή:
Τώρα, το Examples.exe πρέπει να δουλεύει.
OpenTK από κώδικα
Το σύστημα build της OpenTK αυτή τη στιγμή χρησιμοποιεί NAnt, οπότε θα χρειαστεί να το εγκαταστήσετε:
Μόλις τελειώσετε με αυτό, αποσυμπιέστε τη source release και κάντε cd στον Build φάκελο
Περιμέντε μερικά δευτερόλεπτα για να τελειώσει το compile, και ελέγξτε το φάκελο "Binaries", που μόλις εμφανίστηκε στο βασικό φάκελο της OpenTK. Για να κάνετε build στη debug έκδοση, προσθέστε "debug" ώστε η τελευταία εντολή να μοιάζει κάπως έτσι:
This page is the Greek Translation of Windows
Η OpenTK δεν έχει κάποιον installer ή setup. Πρέπει λοιπόν να κατεβάσετε τα αρχεία της OpenTK και αφού τα ξεζιπάρετε να προσθέσετε μία αναφορά (reference) στο "OpenTK.dll" στο Visual Studio/SharpDevelop/MonoDevelop project σας.
Είναι καλύτερα να προσθέσετε το "OpenTK.dll.config" στο project σας και να βεβαιωθείται ότι το "Copy To Output Folder" (όχι "compile"!) είναι ρυθμισμένο σε "Copy Always". Η εφαρμογή θα τρέχει και χωρίς αυτό σε windows αλλά όχι σε Linux ή Mac OS X, οπότε μη το ξεχάσετε!
Τέλος, σιγουρευτείτε ότι η ιδιότητα "Copy Local" είναι ρυθμισμένη σε true για την OpenTK, για να απλοποιήσετε τη διανομή της εφαρμογής σας.
Τόσο απλό!
Todo:
2. OpenTK Classes
2.1 OpenTK.Input
2.2 OpenTK.Math
2.3 Rendering Context
2.4 OpenTK.Fonts & Timing
2.5 OpenTK.OpenGL
2.6 OpenTK.OpenAL [75%]
This page is the Greek Translation of OpenGL
Αυτό το μέρος του εγχειριδίου θα εισάγει το χρήστη στο προγραμματισμό γραφικών με την OpenGL.
Θα καλυφθούν σημαντικά ζητήματα όπως υφές, σκιές κτλ καθώς και το πώς χρησιμοποιούνται οι OpenTK.Utility κλάσεις για να βοηθήσουν σε κάποιες απλές εργασίες.
This page is the Greek translation of Geometry
Εδώ θα συζητήσουμε το πώς ορίζουμε ή σχεδιάζουμε γεωμετρικά αντικείμενα χρησιμοποιώντας την OpenTK.OpenGL.
Θα επικεντρωθούμε στην αποθήκευση της γεωμετρίας κατευθείαν στη Video Memory χρησιμοποιώντας Vertex Buffer Objects (VBO). Αυτό είναι, όπως φαίνεται και από το όνομά του, όταν θέλουμε να αποθηκεύουμε στατικά αντικείμενα από το Περιβάλλον.
[υπό κατασκευή]
* 6. Drawing Optimizations
This page is the Greek translation of 1. The vertex
To Vertex (κορυφή) (πληθ. Vertices) ορίζει ένα σύνολο Ιδιοτήτων που σχετίζονται με ένα μοναδικό σημείο στο χώρο. Σε ένα στατικό περιβάλλον η κορυφή συνήθως περιλαμβάνει συντεταγμένες Θέσης, Κάθετου Διανύσματος, Χρώματος και/ή Υφής. Η μόνη ιδιότητα που πρέπει υποχρεωτικά να προσδιοριστεί είναι η θέση της κορυφής, η οποία συνήθως αποτελείται από τρεις συντεταγμένες τύπου float. Στην αναπαράσταση με βάση τη σκίαση είναι επίσης δυνατό να ορίσουμε κάποιες ιδιότητες για κορυφές οι οποίες ήταν άγνωστες στην OpenGL, όπως Ακτινοβολία ή Δείκτης οστών και βάρος για κίνηση με σκελετό. Για απλότητα θα ξαναφτιάξουμε ένα από τα formats των κορυφών που η OpenGL γνωρίζει ήδη, το λεγόμενο InterleavedArrayFormat.T2fN3fV3f. Το format αυτό περιέχει 2 αριθμούς τύπου float για συνιστώσες υφής, 3 floats για το κάθετο διάνυσμα και άλλους 3 για το προσδιορισμό της θέσης.
Χάρη στη βιβλιοθήκη μαθηματικών (Math-Library) που περιέχεται στην OpenTK, μπορούμε να προσδιορίσουμε μία βοηθητική Vertex δομή η οποία είναι πολύ πιο απλή και εύχρηστη από ένα πίνακα τύπου float[]. Αποτελείται συνολικά από 8 float, ή 32 byte:
Μπορούμε τώρα να ορίσουμε ένα πίνακα από κορυφές για να προσδιορίσουμε πολλαπλά σημεία και να έχουμε εύκολη πρόσβαση/αναφορά σε αυτά:
Ο πίνακας κορυφών Vertices μπορεί τώρα να συμπληρωθεί με δεδομένα. Η προσπέλαση των δεδομένων αυτών είναι τόσο απλή όσο και στο επόμενο παράδειγμα:
Ένας Index είναι απλά ένα byte, ushort ή uint, σαν δείκτης στον πίνακα Vertices. Άρα, αν αποφασίσουμε να σχεδιάσουμε την ίδια κορυφή 100 φορές αντί να το αποθηκεύουμε 100 φορές στον πίνακα Vertices είναι προτιμότερο να το προσπελαύνουμε 100 φορές από τον πίνακα Indices:
Βασικά ο πίνακας Indices χρησιμοποιείται για να δηλώνουμε τα κύρια σημεία και ο πίνακας Vertex για να δηλώνουμε τα γωνιακά.
Επίσης μπορούμε να χρησιμοποιήσουμε συλλογές (collections) για να αποθηκεύουμε τα Vertices, αλλά είναι καλύτερα να κρατήσετε ένα απλό πίνακα για να είστε σίγουροι ότι τα Indices είναι έγκυρα ανά πάσα στιγμή.
Οι πίνακες Vertices και Indices μπορούν τώρα να χρησιμοποιηθούν για να περιγράψουν τις κορυφές ενός οποιουδήποτε Γεωμετρικού Πρωτεύοντος Τύπου.
Μόλις οι πίνακες γεμίσουν με δεδομένα μπορούν να σχεδιαστούν σαν ένας Immediate ModeVertex πίνακας ή να σταλούν σε ένα Vertex Buffer Object.
This page is the Greek Translation of Building a Windows.Forms+GLControl based application
Αυτό το εγχειρίδιο προϋποθέτει κάποια οικειότητα με την εφαρμογή Windows.Forms σε Visual Studio 2005/C#, και τουλάχιστον βασική γνώση της OpenGL.
Για αρχή, είναι αρκετά διαφορετική η προσέγγιση που πρέπει να έχει κάποιος όταν σχεδιάζει ένα παιχνίδι/εφαρμογή χρησιμοποιώντας το GLControl σε μια Windows.Form, απ’ ότι όταν χρησιμοποιεί το GameWindow. Το GLControl είναι πιο χαμηλού επιπέδου επομένως πρέπει να κάνετε πολλά πράγματα μόνοι σας, όπως για παράδειγμα τις μετρήσεις χρόνου. Στο GameWindow έχετε περισσότερες ευκολίες!
Αν έρχεστε από ένα "main-loop-background" (C/SDL/Allegro etc.) θα πρέπει να σκεφτείτε τα πάντα από την αρχή στο προγραμματισμό παιχνιδιών. Θα πρέπει να αλλάξετε τρόπο σκέψης με κάτι σαν: «Σε ποιο event πρέπει να κολλήσω, και σε ποια να δώσω trigger, και πότε;».
Γιατί λοιπόν να χρησιμοποιήσετε Windows.Forms+GLControl αντί για GameWindow?
Το πρώτο πράγμα για το οποίο πρέπει να αποφασίσετε είναι το εξής:
"Πράγματι χρειάζομαι την επιπρόσθετη πολυπλοκότητα των Windows.Forms και του embedded GLControl αντί για ένα απλό GameWindow?"
Να μερικοί λόγοι γιατί πιθανόν να θέλατε αυτή την επιπρόσθετη πολυπλοκότητα:
Υποθέτοντας λοιπόν ότι έχετε τουλάχιστον ένα από αυτούς τους λόγους για να θέλετε να φτιάξετε μία Windows.Forms+GLControl – βασισμένη εφαρμογή, να τα βήματα για να τη φτιάξετε:
Προσθέτοντας το GLControl στη Windows.Form σας
Υποθέτω ότι χρησιμοποιείτε Visual Studio 2005 Express Edition. Η διαδικασία μπορεί να διαφέρει αν χρησιμοποιείτε VS2008 or Monodevelop – δε ξέρω τις λεπτομέρειες για αυτά – αλλά οι επόμενες ενότητες θα πρέπει να είναι οι ίδιες με όποιο τρόπο και να προσθέσετε το GLControl.
Για αρχή, δημιουργήστε μία Form στην οποία θα τοποθετήσετε το GLControl σας. Κάντε δεξί κλικ σε κάποιο άδειο σημείο του Toolbox, διαλέξτε "Choose Items..." και ψάξτε το OpenTK.dll. Σιγουρευτείτε ότι μπορείτε να βρείτε το "GLControl" στη λίστα ".NET Framework Components", όπως στην παρακάτω εικόνα:
Στη συνέχεια μπορείτε να προσθέσετε το GLContrοl στη φόρμα σας σαν οποιοδήποτε .ΝΕΤ control και ένα GLControl με όνομα
GLControl χρησιμοποιεί ένα GLContext, όπως λέγεται για να κάνει το πραγματικό GL-rendering και ούτω καθ’ εξής, και αυτό το περιεχόμενο δημιουργείται μόνο στην ώρα εκτέλεσης, όχι σχεδίασης. Οπότε μην ανησυχείτε.
Σειρά δημιουργίας
Είναι σημαντικό να το θυμάστε ότι το GLContext του glControl1 δημιουργείται κατά την εκτέλεση, εφόσον δε μπορείτε να έχετε πρόσβαση ή να αλλάξετε τις ιδιότητες του glControl1 μέχρι να δημιουργηθεί το GLCοntext. Το ίδιο ισχύει και για οποιαδήποτε GL.* εντολή (ή Glu για αυτό το θέμα!). Η σειρά σύλληψης είναι η εξής:
Επομένως μία προσέγγιση για να λύσετε αυτό το πρόβλημα είναι να έχετε μία λογική μεταβλητή bool loaded = false, μέλος στη φόρμα σας, η οποία θα γίνει true κατά το Load του event handler:
Κατόπιν σε οποιονδήποτε event handler θα έχει πρόσβαση το glControl1/GL μπορείτε να προσθέσετε τον εξής έλεγχο:
Hello World!
Ο απλούστερος κώδικας που μπορείτε να προσθέσετε σε αυτό το στάδιο για να δείτε κάποιο αποτέλεσμα είναι να προσθέσετε έναν event handler στο Paint event του glControl1 και σε αυτό να γράψετε τα εξής:

Ναι! Ένα μαύρο παράθυρο! Παρατηρήστε ότι το GLControl παρέχει ένα χρώμα - και ένα buffer που πρέπει να καθαρίζουμε χρησιμοποιώντας GL.Clear(). [TODO: Πώς γίνεται να ελέγχουμε ποιους buffers και formats έχει το GLControl; Είναι δυνατόν;]
Στη συνέχεια θα μπορούσαμε να ρυθμίσουμε το καθαρό χρώμα. Το κατάλληλο μέρος για να κάνουμε την αρχικοποίηση GL είναι στον Load event handler της φόρμας:

Αρχικοποίηση του Viewport
Το επόμενο πράγμα που μπορούμε να κάνουμε είναι να σχεδιάσουμε ένα κίτρινο τρίγωνο.
Πρώτα χρειάζεται να είστε καλός γνώστης της OpenGL και να μπορείτε να στήσετε ένα ορθογώνιο πίνακα προβολής χρησιμοποιώντας τη GL.Ortho(). Χρειάζεται επίσης να καλέσετε τη GL.Viewport().
Προς το παρόν θα προσθέσουμε αυτό στον Load event handler από τον άλλο κώδικα αρχικοποίησης – αγνοώντας το γεγονός ότι μπορεί να θέλουμε να επιτρέψουμε στο χρήστη να αλλάζει το μέγεθος του παραθύρου/GLContrl. Θα ασχοληθούμε με το θέμα αλλαγής μεγέθους παραθύρου αργότερα.
Εδώ έβαλα τη viewport initialization σε μία ξεχωριστή μέθοδο για την κάνω λίγο πιο ευανάγνωστη.
Kαι μεταξύ των Clear() και SwapBuffers() το κίτρινο τρίγωνό μας:
Voila!

Είσοδος από το πληκτρολόγιο
Το επόμενο πράγμα που θέλουμε είναι η δυνατότητα στο χρήστη να κινεί το τρίγωνο. Κάθε φορά που πιέζει το Space, θέλουμε το τρίγωνο να κινείται κατά ένα pixel δεξιά.
Οι δύο γενικές προσεγγίσεις στην είσοδο από πληκτρολόγιο σε ένα GLControl σενάριο είναι να χρησιμοποιούμε τα Windows.Forms key events και την OpenTK KeyboardDevice. Εφόσον το υπόλοιπο από το πρόγραμμά μας έγκειται στον κόσμο του Windows.Forms (το παράθυρό μας μπορεί να είναι ένα μικρό κομμάτι ενός μεγαλύτερου GUI), θα παίξουμε ωραία με τα Windows.Forms key events σε αυτό τον οδηγό.
Θα έχουμε μια μεταβλητή int x=0; την οποία θα μειώνουμε με έναν KeyDown event handler. Αν αυτά τα προσθέσουμε στο glControl1 και όχι στη Form, σημαίνει ότι πρέπει να εστιάσουμε στο glControl, για παράδειγμα ο χρήστης πρέπει να κάνει κλικ για να σταλθούν τα key events στον handler μας.
Προσθέτουμε την εντολή GL.Translate() στον Paint event handler:
...και τρέχουμε το πρόγραμμά μας. Αλλά μισό λεπτό! Τίποτα δε συμβαίνει όταν πιέζουμε το Space! Ο λόγος είναι ότι το glControl1 δε χρωματίζεται όλη την ώρα, ο window manager των λειτουργικών συστημάτων (Windows/X/OSX) προσπαθεί να εκτελέσει όσα λιγότερα Paint events γίνεται. Μόνο στην αλλαγή μεγέθους και σε λίγες ακόμα καταστάσεις ενεργοποιούνται τα Paint events.
Επομένως, αυτό που θα θέλαμε είναι να είχαμε ένα τρόπο να πούμε στον window manager «Αυτό το control χρειάζεται να χρωματίζεται όταν αλλάζουν τα δεδομένα στα οποία βασίζεται». Θέλουμε δηλαδή να ειδοποιούμε τον window manager ότι το glControl1 πρέπει να επαναχρωματιστεί. Εύκολο, με την εντολή Invalidate():
Συμπεριφορά του Focus
Αν μου μοιάζετε λίγο θα αναρωτιέστε τώρα πώς δουλεύει αυτό το focus, ας μάθουμε!
Ένας απλός τρόπος είναι να χρωματίσετε το τρίγωνο κίτρινο όταν το glControl1 είναι σε focus και μπλε όταν δεν είναι. Κάτι τετοιο δηλαδή:
Οπότε όποια στιγμή το τρίγωνο είναι κίτρινο, το πλήκτρο Space πρέπει να δουλεύει, και όταν είναι μπλε όποιο πλήκτρο και να πατηθεί θα πρέπει να αγνοείται.
Επιτέλους Ελευθερία: Αλλάζοντας το μέγεθος του παραθύρου
Τώρα θα ασχοληθούμε με ένα πιο σοβαρό ζήτημα: την αλλαγή μεγέθους των παραθύρων.
Όποια στιγμή ένα Windows.Forms control αλλάζει μέγεθος γίνεται trigger στο Resize event. Αυτό ισχύει και για το glControl1. Ένα το κρατούμενο.
Το επόμενο βήμα είναι να βρούμε "Τι χρειάζεται να κάνουμε για να ενημερώνουμε όταν ένα GLControl αλλάζει μέγεθος;" και η απάντηση είναι "Το viewport και τον πίνακα προβολών"
Απ' ότι φαίνεται ότι θα χρησιμοποιήσουμε το SetupViewport() ακόμα μία φορά! Προσθέστε έναν event handler στο Resize event of glControl1 και συμπληρώστε τον:

Όμως υπάρχει ακόμα ένα πρόβλημα: αν μειώσετε το μέγεθος του παραθύρου μετακινώντας για παράδειγμα το κάτω-αριστερά άκρο του, δε θα γίνει αυτόματα trigger στον επαναχρωματισμό. Αυτό γίνεται γιατί ο window manager υποθέτει που βρίσκεται το (0, 0) pixel του control, ονομαστικά στην επάνω αριστερά γωνία του control. (δοκιμάστε να αλλάξετε μέγεθος μετακινώντας την πάνω αριστερά γωνία – το τρίγωνο αλλάζει συνεχώς χρώμα!) Αυτό που μπορούμε να κάνουμε για να το διορθώσουμε αυτό είναι να δώσουμε οδηγίες στον window manager ότι θέλουμε να γίνεται ο επαναχρωματισμός με κάθε event αλλαγής μεγέθους:
Θέλω τον κυρίως βρόχο μου: κίνηση με χρήση της Application.Idle
Τι θα συνέβαινε αν θέλαμε το τρίγωνό μας να περιστρεφόταν συνεχώς; Αυτό θα ήταν παιχνιδάκι σε ένα σενάριο με main loop: απλά θα αυξάναμε μία μεταβλητή rotation στην main loop, πριν σχεδιαστεί το τρίγωνο.
Όμως δεν έχουμε κανένα βρόχο, μόνο events!
Για να επιδιορθώσουμε αυτή την έλλειψη συνέχειας πρέπει να αναγκάσουμε τα Windows.Forms να το κάνουν με τον τρόπο που θέλουμε, δηλαδή να γίνεται trigger σε ένα event κάθε τρεις και λίγο, αρκετά συχνά όμως για να έχουμε την αίσθηση ότι γίνεται σε realtime.
Υπάρχουν αρκετοί τρόποι για να το πετύχουμε αυτό. Ένας είναι να προσθέσουμε ένα Timer control στη φόρμα μας, αλλάζοντας τη rotation στο Tick του event handler. Ένας άλλος είναι να προσθέσουμε και ένα Thread στο παιχνίδι. Ο πρώτος είναι πολύ υψηλού επιπέδου και αργός ενώ ο δεύτερος πολύ χαμηλού επιπέδου και λίγο πιο δύσκολο να δουλέψει σωστά.
Οπότε θα ακολουθήσουμε ένα τρίτο δρόμο και θα χρησιμοποιήσουμε ένα Windows.Forms event σχεδιασμένο να εκτελείται ειδικά για την περίπτωση όπου «τίποτ’ άλλο δε συμβαίνει», δηλαδή το Application.Idle event.
Όπως μπορεί ήδη να μαντέψατε το event αυτό είναι ιδιαίτερο με πολλούς τρόπους. Δε σχετίζεται με καμία φόρμα ή άλλο control, αλλά με το πρόγραμμα σαν σύνολο. Δε μπορείτε να το προσθέσετε από το GUI Designer, αλλά με το χέρι – για παράδειγμα, στο Load event:
Ένα καλό με το Idle event είναι ότι οι αντίστοιχοι event handlers εκτελούνται στο the Windows.Forms thread. Αυτό είναι καλό γιατί σημαίνει ότι μπορούμε να έχουμε πρόσβαση σε όλα τα GUI controls χωρίς να χρειάζεται να ανησυχούμε για θέματα των threads, ένας μπελάς που θα είχαμε να αντιμετωπίσουμε αν φτιάχναμε δικό μας thread.
Επομένως απλά αυξάνουμε τη rotation μεταβλητή στον Idle event handler και Invalidate() στο glControl1 – κατά τα γνωστά.
Ας ενημερώσουμε και τον άλλο κώδικά μας:
Απολαύστε το!

Το τρίγωνο περιστρέφεται πιο αργά όταν το παράθυρο είναι μεγάλο! Πώς γίνεται;
Αυτό μπορεί και να μην ισχύει αν έχετε ένα πολύ γρήγορο υπολογιστή με μία πολύ γρήγορη κάρτα γραφικών, αλλά θέλετε το παιχνίδι σας να τρέχει και σε άλλους υπολογιστές, έτσι δεν είναι;
Ο λόγος είναι ότι γενικά η απεικόνιση 3d γραφικών σε παράθυρο είναι πολύ πιο αργή απ’ ότι σε πλήρη οθόνη.
Αλλά μπορείτε να μειώσετε το κακό χρησιμοποιώντας μία τεχνική που λέγεται
frame-rate independent animation. Η ιδέα είναι απλή: η αύξηση της μεταβλητής rotation όχι κατά 1 αλλά κατά μία ποσότητα που εξαρτάται από τη τρέχουσα ταχύτητα απεικόνισης (αν η ταχύτητα είναι αργή, αύξηση της rotation κατά μία μεγαλύτερη ποσότητα απ’ όταν η ταχύτητα είναι μεγάλη.
Αλλά πρέπει να μπορείτε να μετρήσετε τη τρέχουσα ταχύτητα απεικόνισης, ή ισοδύναμα, την ώρα που απαιτείται για να απεικονιστεί ένα frame.
Από τη .NET2.0 υπάρχει μία κλάση διαθέσιμη για να κάνουμε μετρήσεις υψηλής ακρίβειας που λέγεται Stopwatch. Να πώς μπορείτε να τη χρησιμοποιήσετε:
(μη το δοκιμάσετε με την DateTime.Now -- έχει σφάλμα 10 ή και περισσότερα milliseconds, δηλαδή ίδιας τάξης μεγέθους με μία τυπική frame rendering – μάταιος κόπος..)
Τώρα,αν θα μπορούσαμε να μετρήσουμε το χρόνο που χρειαζόμαστε για να κάνουμε τον glControl χρωματισμό, θα ήταν ένα πρώτο βήμα για να φτιάξουμε ένα είδος κίνησης ανεξάρτητης από το frame-rate. Αλλά υπάρχει ένας ακόμα πιο κομψός τρόπος: μπορούμε να μετρήσουμε όλο το χρόνο που δεν είναι Application.Idle χρόνος! Έτσι θα είμαστε σίγουροι ότι δε μετράμε μόνο το χρωματισμό, αλλά ό,τι συμβαίνει από το τελευταίο Idle τρέξιμο:
Τέλεια! Το τρίγωνο περιστρέφεται με την ίδια ταχύτητα ανεξάρτητα από το μέγεθος του παραθύρου.
Θέλω ένα FPS μετρητή!
Ναι, κι εγώ. Είναι αρκετά απλό τώρα που έχουμε ένα Stopwatch.
Η ιδέα είναι απλά να μετράμε τα Idle τρεξίματα, και κάθε δευτερόλεπτο περίπου να ενημερώνουμε ένα Label control με τον μετρητή! Αλλά θα πρέπει να ξέρουμε πότε πέρασε το ένα δευτερόλεπτο, οπότε χρειαζόμαστε μία ακόμα μεταβληρή αθροιστική, που να προσθέτει όλες τις χρονικές περιόδους μαζί.
Έχουν μαζευτεί πολλά στον Idle event handler, οπότε θα τον χωρίσω λίγο:
Ο FPS μετρητής μας σε όλη του τη δόξα:

Δε μπορώ να μαζέψω τον ολοκληρωμένο κώδικα κάπου;
Φυσικά, να τος: