Videogames Laboratory

O συναρπαστικός κόσμος της ανάπτυξης βιντεοπαιχνιδιών

Εισαγωγή στην OpenGL: μέρος 1ο

Δημοσιεύθηκε από Κώστας Αναγνώστου στο Νοεμβρίου 5, 2008

Με μια σειρά από άρθρα στο blog αυτό, θα κάνουμε μια μικρή εισαγωγή στην OpenGL η οποία μπορεί να χρησιμοποιηθεί για να αναπτυχθούν παιχνίδια. Τα άρθρα αυτά βασίζονται σε υλικό που ανέπτυξα και χρησιμοποιώ για τα εργαστήρια «Γραφικά με Υπολογιστή» στο Τμήμα Πληροφορικής του Ιονίου Πανεπιστημίου. Στο τέλος θα ανεβάσω το κώδικα για ένα απλό παιχνίδι σε OpenGL.

Ελπίζω να βρείτε την σειρά άρθρων αυτή χρήσιμη.


Τι είναι η OpenGL

Η OpenGL είναι ένα σύνολο εντολών (Application Programming Interface – API) που μας επιτρέπει την δημιουργία τριδιάστατων γραφικών. Δεν είναι γλώσσα προγραμματισμού αλλά μπορεί να χρησιμοποιηθεί με μια πληθώρα γλωσσών προγραμματισμού (C, C++, Java και άλλες) και σε μια πληθώρα λειτουργικών συστημάτων (Windows, Unix, Linux, Mac OS).

Προσφέρει πάνω από 300 εντολές για δημιουργία γραφικών και δρα σαν ένα ενδιάμεσο στρώμα ανάμεσα στην εφαρμογή και στη κάρτα γραφικών που θα αναλάβει τα απεικονίσει τα γραφικά στην οθόνη, κρύβοντας λεπτομέρειες υλοποίησης του υλικού και των οδηγών του.


Προγράμματα που χρησιμοποιούν OpenGL μπορούν να τρέξουν και χωρίς επιταχυντή γραφικών (3D graphics card), θα είναι όμως πολύ πιο αργά και πιθανώς να μην υποστηρίζουν όλες τις λειτουργίες της OpenGL.

Η OpenGL είναι το πρώτο ευρέως διαδεδομένο API για γραφικά και υπάρχει σαν στάνταρντ από το 1992. Άλλο ευρέως διαδεδομένο API γραφικών είναι το DirectX της Microsoft το οποίο είναι γραμμένο αποκλειστικά για πλατφόρμες Windows και Xbox/Xbox360.

OpenGL graphics pipeline

Ας δούμε σχηματικά τα βήματα που κάνει η OpenGL από την στιγμή που πάρει τις εντολές γραφικών από την εφαρμογή μας μέχρι την στιγμή δημιουργίας της τελικής εικόνας (rendered image).


H OpenGL χρησιμοποιεί μια μηχανή καταστάσεων (state machine) για να επικοινωνεί με την εφαρμογή. Σε αυτή την μηχανή καταστάσεων η OpenGL παραμένει διαρκώς σε μια κατάσταση μέχρι να αλλάξει η εφαρμογή την κατάσταση. Παράδειγμα αν θέσουμε το χρώμα που θα χρησιμοποιεί η OpenGL για να ζωγραφίσει ένα μοντέλο, το χρώμα θα παραμείνει στη μνήμη και θα χρησιμοποιείται μέχρι να το αλλάξουμε ή να κλείσουμε την εφαρμογή.

Εφόσον λοιπόν η εφαρμογή καθορίσει το περιβάλλον που θα χρησιμοποιήσει η OpenGL για να απεικονίσει το μοντέλο μας (χρώματα, υφές, πηγές φωτός, κάμερα κλπ), περνάει στο πρώτο στάδιο κατά το οποίο θα μετασχηματίσει και θα φωτίσει (transform and lighting) τα σημεία(vertices) του μοντέλου.

Στην συνέχεια η OpenGL περνά στο στάδιο της ψηφιοποίησης το οποίο λαμβάνει όλες τις πληροφορίες και την γεωμετρία από το προηγούμενο στάδιο (του μετασχηματισμού) και παράγει την τελική, ψηφιακή, εικόνα. Η εικόνα αντιγράφεται στην μνήμη του frame buffer και φτάνει έτσι στην οθόνη του υπολογιστή.

Αυτή η ακολουθία βημάτων που ακολουθεί η OpenGL για να απεικονίσει το μοντέλο λέγεται graphics pipeline (διασωλήνωση)

Τι είναι το GLUT

Η OpenGL όπως είπαμε είναι ένας γρήγορος και ευέλικτος τρόπος να επικοινωνούμε με το hardware γραφικών του υπολογιστή χωρίς να ενδιαφερόμαστε για τις λεπτομέρειες υλοποίησης του. Όμως δεν προσφέρει καθόλου λειτουργίες GUI (Graphical User Interface), δηλαδή δεν έχει την δυνατότητα να ανοίξει και να κλείσει παράθυρα στο λειτουργικό σύστημα, να ζωγραφίσει σε αυτά, ούτε να καταλάβει το πάτημα ενός πλήκτρου ή την κίνηση του ποντικιού, ούτε μπορεί να διαβάσει ένα αρχείο από το δίσκο.

Αυτό έγινε επί σκοπού, μιας και η OpenGL σχεδιάστηκε να τρέχει σε πολλά λειτουργικά συστήματα τα οποία έχουν το δικό τους τρόπους επικοινωνίας με την οθόνη, το ποντίκι, το δίσκο, το πληκτρολόγιο.

Για να γίνει αυτό θα πρέπει να χρησιμοποιήσουμε απευθείας τις εντολές του λειτουργικού μας συστήματος (Win32 εντολές στην περίπτωση των Windows). Εναλλακτικά μπορούμε να χρησιμοποιήσουμε μια από τις έτοιμες βιβλιοθήκες εντολών που υπάρχουν και που θα κάνουν αυτές τις λειτουργίες για εμάς εύκολα.

Μια από τις πιο διαδεδομένες βιβλιοθήκες για αυτό το σκοπό είναι το GLUT (OpenGL
Utility Toolkit) το οποίο είναι και αυτό σχεδιασμένο να τρέχει σε πολλά λειτουργικά συστήματα.

Το GLUT προσφέρει ένα σύνολο εντολών που αναλαμβάνουν να ανοίξουν και να κλείσουν εύκολα παράθυρα, να καταγράψουν το πάτημα ενός πλήκτρου ή την κίνηση του ποντικιού. Δεν είναι κατάλληλο να γράψουμε μια κανονική εφαρμογή με αυτό (πχ ένα παιχνίδι) όμως είναι πολύ κατάλληλο για εκπαιδευτικές και πρότυπες εφαρμογές.

Μορφή εντολών OpenGL/GLUT

Η OpenGL χρησιμοποιεί μια απλή, στάνταρντ, μορφή ονοματολογίας για τις εντολές της. Όλες οι εντολές της έχουν μορφή παρόμοια με:


Οι εντολές του GLUT δεν έχουν κάποιο ιδιαίτερο χαρακτηριστικό εκτός του ότι κάθε εντολή ξεκινά με το πρόθεμα glut:

glutInitWindowSize(Width, Height);

Τύποι δεδομένων OpenGL

Χάριν ομοιομορφίας, και για να μπορέσει να υποστηρίξει διαφορετικές πλατφόρμες, η OpenGL ορίζει μια σειρά από τύπους δεδομένων οι κυριότεροι των οποίων φαίνονται στο παρακάτω πίνακα:

Τύπος δεδομένων OpenGL

Ορίζεται ως

Αντιστοιχία με τύπο δεδομένων στη C

Επίθεμα

GLbyte

Ακέραιος 8-bit

signed char

b

GLshort

Ακέραιος 16-bit

short

s

GLint

Ακέραιος 32-bit

int

i

GLdouble

Κινητής υποδιαστολής 64-bit

double

d

GLubyte

Θετικός ακέραιος 8-bit

unsigned char

ub

GLushort

Θετικός ακέραιος 16-bit

unsigned short

us

GLuint

Θετικός ακέραιος 32-bit

unsigned int

ui

GLchar

Χαρακτήρας 8-bit

char

-

GLfloat

Κινητής υποδιαστολής 32-bit

float

f

GLboolean

Θετικός ακέραιος 8-bit

unsigned char

H OpenGL εγγυάται ότι για παράδειγμα ένας GLShort αριθμός θα έχει εύρος 16-bit ανεξάρτητα αν το λειτουργικό σύστημα είναι Windows, Unix ή κάποιο άλλο.

Το επίθεμα είναι το γράμμα που βρίσκουμε στο τέλος μιας OpenGL εντολής και που δείχνει τον τύπο δεδομένων των παραμέτρων.

Γνωριμία με την OpenGL

Στην πρώτη εργαστηριακή άσκηση θα γνωρίσουμε το περιβάλλον ανάπτυξης που θα χρησιμοποιήσουμε για την εισαγωγή στην OpenGL και θα μελετήσουμε τον τρόπο λειτουργίας ενός απλού προγράμματος που χρησιμοποιεί την OpenGL και το GLUT για να ζωγραφίσει ένα αντικείμενο στην οθόνη.

Περιγραφή εφαρμογής

Όλο το πρόγραμμα βρίσκεται μέσα στο αρχείο main.cpp. Ξεκινώντας με την συνάρτηση main που είναι και η είσοδος της εφαρμογής πρέπει να αρχικοποιήσουμε το Glut καλώντας τις συναρτήσεις

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

Η glutInitDisplayMode() δέχεται μια πληθώρα επιλογών για την αρχικοποίηση της OpenGL που είναι πέρα από τους σκοπούς του πρώτου εργαστηρίου να εξετάσουμε. Στην συγκεκριμένη περίπτωση απλά επιλέγουμε το μοντέλο χρώματος που θα χρησιμοποιήσουμε (Red – Green – Blue και διαφάνεια) και ότι θα χρησιμοποιήσουμε διπλό buffer για την απεικόνιση.

Η χρήση διπλού buffer (double buffering) κατά την απεικόνιση μιας σκηνής είναι μια βασική μέθοδος αποφυγής «τρεμοπαίγματος»(flickering). Ο τρόπος με τον οποίο δουλεύει είναι ορίζοντας 2 ενδιάμεσες περιοχές στην μνήμη (buffers) στις οποίες αποθηκεύουμε τις εικόνες που δημιουργούμε. Όσο η οθόνη παίρνει (απεικονίζει) την εικόνα από τον έναν buffer εμείς ζωγραφίζουμε την σκηνή στον άλλον. Έπειτα ανταλλάσουμε τους ρόλους των buffer και συνεχίζουμε. Έτσι η οθόνη δείχνει πάντα μια ολοκληρωμένη εικόνα της σκηνής.

Στην συνέχεια δημιουργούμε το παράθυρο που θα απεικονίσουμε την τελική εικόνα με το σετ εντολών:

glutInitWindowSize(800, 600);
glutInitWindowPosition(150,150);
glutCreateWindow("Computer Graphics - Lab 1");

Το παράθυρο θα έχει μέγεθος 800×600 pixels, θα τοποθετηθεί 150,150 pixels από την πάνω αριστερή γωνία της οθόνης και το τίτλο που δηλώσαμε.

Το παρακάτω σετ εντολών μας δίνουν μια ιδέα για το πώς δουλεύει ουσιαστικά το GLUT:

glutDisplayFunc(renderScene);
glutKeyboardFunc(κeyPressFunc);
glutIdleFunc(renderScene);

Οι εντολές αυτές καθορίζουν τι θα συμβεί σε περίπτωση όταν λάβει χώρα ένα γεγονός που μας ενδιαφέρει και που θέλουμε να επεξεργαστούμε. Τέτοια συμβάντα είναι για παράδειγμα το πάτημα ενός πλήκτρου, η κίνηση του ποντικιού, η εντολή να επανασχεδιάσουμε το παράθυρο λόγω μετακίνησης του.

Το GLUT μας δίνει την δυνατότητα να ορίσουμε τι θέλουμε να γίνεται όταν λαμβάνει χώρα ένα τέτοιο γεγονός μέσω μια σειράς εντολών της μορφής:

Glut_OnomaEntolis_Func(συνάρτηση που θα καλείται);

Στην εφαρμογή ενδιαφερόμαστε για 3 γεγονότα, όταν πατηθεί κάποιο πλήκτρο, όταν δοθεί εντολή να επανασχεδιαστεί το παράθυρο και όταν το GLUT δεν κάνει τίποτα (είναι δηλαδή idle). Αυτή η στιγμή είναι κατάλληλη για να σχεδιάσουμε το αντικείμενο στην οθόνη.

Το GLUT μας επιτρέπει να ορίσουμε συναρτήσεις που θα εξυπηρετούν διάφορα συμβάντα. Αυτός είναι και ο μόνος τρόπος να προσθέσουμε λειτουργικότητα σε μια GLUT εφαρμογή.

Στην συνέχεια καλούμε την συνάρτηση

init();

που στην συνέχεια θα καλέσει εντολές της OpenGL και θα κάνει αρχικοποιήσεις που χρειάζεται να γίνουν μόνο μια φορά. Από αυτές τις εντολές προς το παρόν μας ενδιαφέρουν μόνο οι

glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor3f(1.0f, 1.0f, 0.0f);

Η πρώτη καθορίζει το χρώμα στο οποίο θα καθαρίζουμε (clear) το παράθυρο (όταν δοθεί η εντολή). Το χρώμα καθαρισμού δεν είναι ανάγκη να είναι μαύρο, μπορεί να είναι οτιδήποτε. Η δεύτερη καθορίζει το χρώμα με το οποίο θα «βάψουμε» το αντικείμενο όταν το θα το ζωγραφίσουμε την οθόνη.

Το ότι θέτουμε το χρώμα καθαρισμού και χρωματισμού του αντικειμένου μία φορά κατά την αρχικοποίηση της εφαρμογής είναι ένα καλό παράδειγμα λειτουργίας της OpenGL ως μηχανή καταστάσεων (state machine) – μια τιμή που θέτουμε διατηρείται μέχρι να την ξαναλλάξουμε.

Τέλος καλούμε την συνάρτηση που θα αρχίσει το κυρίως loop της εφαρμογής.

glutMainLoop();

Από αυτό το loop η εφαρμογή θα βγει μόνο όταν κλείσουμε το παράθυρο ή την εφαρμογή. Στο μεταξύ το GLUT θα τρέχει αυτό το loop ακούγοντας για διάφορα γεγονότα (όπως είσοδο από πληκτρολόγιο, κίνηση ποντικιού, κίνηση joystick) και ανάλογα με το αν έχουμε δηλώσει κάποια συνάρτηση για κάποιο συμβάν ( με την χρήση της glutXXXXXFunc() ) την καλεί για να το εξυπηρετήσει.

Μια τέτοια συνάρτηση είναι και η


void κeyPressFunc(unsigned
char key, int x, int y)

To GLUT θα καλέσει την συνάρτηση αυτή όταν πατηθεί κάποιο πλήκτρο. Στην συνάρτηση ελέγχουμε αν έχει πατηθεί το πλήκτρο ESC και αν ναι τερματίζουμε την εφαρμογή.

Η συνάρτηση που θα ζωγραφίσει το αντικείμενο στην οθόνη είναι η

renderScene(void);

Η συνάρτηση αυτή αρχικά καθαρίζει το τρέχον buffer στο χρώμα το οποίο θέσαμε στην init() με την εντολή glClearColor().

Στην συνέχεια καλεί μια εντολή GLUT για να ζωγραφίσει το αντικείμενο στον buffer.

glutSolidTeapot(15.0);

με μέγεθος 15. Η εντολή αυτή καλεί πολλές OpenGL εντολές για να δημιουργήσει και να απεικονίσει το μοντέλο της τσαγιέρας. To GLUT προσφέρει και άλλες εντολές που δημιουργούν μοντέλα όπως< glutSolidCube(), glutSolidCone(), glutSolidTetrahedron().

Στο τέλος καλεί την εντολή

glutSwapBuffers();

η οποία θα αντικαθιστά τον buffer που χρησιμοποιεί η οθόνη με αυτόν που περιέχει το αντικείμενο που μόλις ζωγραφίσαμε.

Για να δείτε το double buffering σε λειτουργία δοκιμάστε να σβήσετε αυτή την εντολή και να αντικαταστήστε την παράμετρο GLUT_DOUBLE με GLUT_SINGLE στην εντολή glutInitDisplayMode().

Η έξοδος του προγράμματος θα πρέπει να είναι η παρακάτω, μια κίτρινη τσαγιέρα:

Κώδικας παραδείγματος

Για να τρέξετε το κώδικα του παραδείγματος  πρέπει να εγκαταστήσετε το περιβάλλον ανάπτυξης Dev-C++ 5.0 beta 9.2 (4.9.9.2) (9.0 MB) with Mingw/GCC 3.4.2 και στην συνέχεια να το παραμετροποίησετε ώς εξής:

1. Τρέξτε το Dev-Cpp που μόλις εγκαταστήσατε και μόλις ξεκινήσει, από το μενού Tools, επιλέξτε Check for Updates/Packages.
2. Στο Select devpack server επιλέξτε devpack.org και πατήστε το Check for Updates κάτω αριστερά
3. Σαν Group επιλέξτε OpenGL
4. Από την λίστα που θα εμφανιστεί επιλέξτε να εγκαταστήσετε το πακέτο freeglut

Στην συνέχεια αποσυμπιέστε να αρχεία lab1.zip και shared.zip σε αντίστοιχα folder (με ονόματα dev-cpp/lab1 και dev-cpp/shared δηλαδή), και ανοίξτε το αρχείο lab1.dev του καταλόγου lab1. Αν όλα πήγαν καλά, με F9 ο κώδικας πρέπει να εκτελεστεί και να δείτε το παράθυρο της εφαρμογής με την τσαγιέρα.

Με μικρές αλλαγές ο κώδικας μπορεί να τρέξει σε οποιοδήποτε περιβάλλον προγραμματισμού C/C++ διαθετετε.

7 σχόλια προς “Εισαγωγή στην OpenGL: μέρος 1ο”

  1. Javatzis είπε

    Κ. Αναγνώστου, σας συγχαίρω για το καταπληκτικό blog αλλά και το φοβερό post. Ελπίζω σύντομα να δημοσιεύσετε τη συνέχεια

  2. Γιώργος είπε

    χαίρετε,
    Λέτε ότι το glut δεν είναι κατάλληλο για να χρησιμοποιηθεί σε μία κανονική εφαρμογή. Γιατί δεν είναι κατάλληλο; Τι μπορεί να χρησιμοποιηθεί στη θέση του glut;
    ευχαριστούμε

  3. thinkinggamer είπε

    Εξαρτάται από το τι ονομάζουμε κανονική εφαρμογή. Αν η εφαρμογή σου αφορά ανάγνωση ενός μοντέλου από το δίσκο και απεικόνιση του σε ένα παράθυρο στην οθόνη με κάποια αλληλεπίδραση (πχ για περιστροφή, κλιμάκωση) από το χρήστη τότε το GLUT είναι αρκετό. Αν θέλεις όμως πλήρη έλεγχο του game loop (όπως θα ήθελες σε ένα παιχνίδι) δεν μπορείς να τον έχεις με το GLUT γιατί λειτουργεί αποκλειστικά με callbacks και μόνο όπως αναφέρει το tutorial.

    Εναλλακτικοί τρόποι ανάπτυξης ενός παιχνιδιού (με OpenGL) αποτελούν η χρήση Windows API για την διαχείριση παραθύρων και εισόδου από το χρήστη (πολύπλοκος τρόπος, μη προτεινόμενος αν δεν έχεις καλή γνώση win32 API) ή βιβλιοθηκών όπως Allegro (http://www.talula.demon.co.uk/allegro/) και SDL (http://www.libsdl.org/) που σου δίνουν μεγαλύτερο έλεγχο από ότι το GLUT, αλλά και περισσότερες ευκολίες στην διαχείριση εισόδου/εξόδου από ότι το Win32 API.

    Edit: Η απάντηση αυτή εκφράζει προσωπική μου εκτίμηση. Για μια αντίθετη άποψη διαβάστε τα σχόλια που ακολουθούν

  4. nikos είπε

    > Αν θέλεις όμως πλήρη έλεγχο του game loop (όπως θα ήθελες σε ένα παιχνίδι) δεν μπορείς να τον έχεις με το GLUT γιατί λειτουργεί αποκλειστικά με callbacks και > μόνο όπως αναφέρει το tutorial.

    Αυτό δεν είναι εξήγηση. Τέτοιοι αφορισμοί πρέπει να συνοδέυονται με εξηγήσεις, αλλιώς δεν είναι δυνατό να σε πάρουμε στα σοβαρά.

    Γιατί είναι πρόβλημα τα callbacks ?
    Τι ενοείς με πλήρη έλεγχο του game loop ?
    Τι παραπάνω πρέπει να κάνει κανεις για ενα ‘κανονικό’ παιχνίδι (σύμφωνα με τη γνώμη σου)

    Προσωπικά, υποθέτω οτι κάπου διάβασες οτι το glut δεν κάνει για “σοβαρές” εφαρμογές και παιχνίδια
    και χωρίς να μπεις καθόλου στον κόπο να το ψάξεις, αναπαράγεις εδω πέρα λανθασμένες αντιλείψεις.

    Ελπίζω να με αποδείξεις λάθος και να μας απαντήσεις στα ερωτήματα που έθεσα.

  5. Με πλήρη έλεγχο του game loop εννοώ:

    while (!exit)
    {
    Get_Input();
    Update_game(time, input);
    Render_game();
    }
    Με αυτή τη σειρά.

    Σε GLUT το παραπάνω είναι η εξής συνάρτηση:
    glutMainLoop();

    Μειονέκτημα των callbacks είναι ότι δεν ξέρεις πότε ακριβώς θα τα καλέσει το κλειστό loop της GLUT. Τι θα γίνει αν το callback και το πάτημα πλήκτρου εκτελεστεί ανάμεσα στο Update και Render; Επιπλέον callbacks που ορίζονται με το glutTimerFunc, θα εκτελεστούν «περίπου» τα millisecond που δηλώνεις και με glutIdleFunc όταν δεν έχει να κάνει κάτι άλλο το λειτουργικό σύστημα.

    Αυτή η μη-ντερμινιστική προσέγγιση της GLUT θα δημιουργούσε πρόβλημα σε ένα developer που θα ήθελε ο ίδιος να κοιτά αν ο παίκτης έχει πατήσει ένα πλήκτρο και να μην προσπαθεί το σύστημα να καλέσει μια συνάρτηση όποτε το κάνει αυτό, ή αν λόγω του χαμηλού ρυθμού ανανέωσης θα έπρεπε να μην κάνει Update το παιχνίδι σε αυτή την επανάληψη του game loop αλλά να κάνει Render.

    Επιπλέον ο απόλυτος έλεγχος των callbacks από το GLUT, δεν μου δίνει την ευκαιρία να χρησιμοποιήσω πολυνηματικό προγραμματισμό, χρησιμοποιώντας για παράδειγμα ένα πυρήνα (thread καλύτερα) για το Update και ένα για το Render που κάνουν τα περισσότερα σύγχρονα παιχνίδια.

    Τώρα αν με ρωτάς αν έχω αναπτύξει ένα «μεγάλο» παιχνίδι σε GLUT, όχι δεν έχω. Η επαγγελματική μου εμπειρία βασίζεται στο DirectX. Δεν γνωρίζω όμως και καμία μεγάλη παραγωγή παιχνιδιού να έχει βασιστεί στο GLUT (αν κάνω λάθος διορθώστε με).

    Το GLUT είναι καλό για prototyping και για να δοκιμάσεις ιδέες ενός παιχνιδιού. Δεν σημαίνει ότι δεν μπορείς να αναπτύξεις παιχνίδια σε αυτό όμως. Απλά όχι μεγάλες παραγωγές στις οποίες ο πλήρης έλεγχος της παιχνιδομηχανής είναι κρίσιμης σημασίας.

    Επιπλέον την άποψη ότι το GLUT δεν είναι το πλέον κατάλληλο για μεγάλες παραγωγές δεν την άκουσα και την αντέγραψα από πουθενά, βασίζεται στη δική μου εκτίμηση για τους λόγους που ανέφερα.

    Παραθέτω και την άποψη του δημιουργού του GLUT:
    «GLUT is designed for simple to moderately complex programs focused on OpenGL rendering. GLUT implements its own event loop. For this reason, mixing GLUT with other APIs that demand their own event handling structure may be difficult. The advantage of a builtin event dispatch loop is simplicity.»

    ΥΣ: Και για να μην αρχίσει ο πόλεμος για το αν το GLUT/OpenGL είναι καλύτερο από το DirectX, δηλώνω ότι αδιαφορώ για το ποιο είναι καλύτερο, αρκεί αυτό που χρησιμοποιώ να με καλύπτει σε αυτό που θέλω να κάνω! :-)

  6. nikos είπε

    Ωραία, με κάλυψες πλήρως αν και δεν συμφωνώ απόλυτα μαζί σου (λεπτομέρειες παρακάτω).

    Δεν προσπαθω να αρχισω πόλεμο glut/directx, απλά όταν διαβάζω πράγματα που είναι προσωπικές
    εκτιμίσεις αλλά παρουσιάζονται σαν απολύτες αλήθειες χωρίς εξήγηση κάτι αντιδρά μέσα μου .
    Δηλαδή αν αντι για “δεν είναι κατάλληλο για …” έγραφες “άποψη μου είναι ότι δεν …” και εξηγούσες
    τους λόγους που σε κάνουν να το πιστευεις δεν θα είχα κανένα πρόβλημα. Χαίρομαι που μπήκες στον
    κόπο και εξήγησες, αλλα και δέχτηκες την κριτικη μου, αυτο είναι δείγμα ανοιχτού μυαλου, πράγμα
    σπανιο στις μέρες μας.

    Απαντω για το glut:

    while (!exit)
    {
    Get_Input();
    Update_game(time, input);
    Render_game();
    } vs glutMainLoop

    Aυτό ακριβώς κάνει και το glut όταν καλείς τη glutMainLoop.Πρώτα ελέγχει τα input devices
    και καλεί τα callbacks που έχεις ορίσει και τελευταία καλεί την idlefunc αν χρειάζεται redisplay
    την displayfunc. Οπότε στην ουσία έχεις απόλυτο έλεγχο πάνω στην render function αφού
    εσύ ελέγχεις πότε θα τρέξει το callback (me glutPostRedisplay, και εξαιρούνται repaint events apo to windowing systhma
    που δεν έχουν καμία σημασία fullscreen). Επίσης έχεις απόλυτο έλεγχο πάνω στην idlefunc.
    Μπορείς μετρώντας τον ellapsed χρόνο να την περιορίσεις σε οτι rate θέλεις (60 φορές το δευτερόλεπτο π.χ)
    Για την glutTimerFunc έχεις δίκιο, πρέπει κανείς να λάβει υπόψην του τον scheduler του λειτουργικού
    ο οποίος, συνίθως, _δεν_ έχει millisecond scheduling overheads.

    Καταλαβένεις λοιπόν οτι δεν υπάρχει non-deterministic προσέγκιση απο glut. Ακριβώς επειδή είναι callback based/
    single-threaded έχεις full determinism αρκεί βέβεα να το ψάξεις και να δεις με ποια σειρά γίνονται dispatch τα events.

    Επίσης να πω οτι αντι για glutMainLoop που δεν επιστρέφει ποτέ, μπορεί κάποιος να κρατήσει τον έλεγχο του event loop
    στο freeglut/osx glut (glutCheckLoop στο osx, glutLeaveMainLoop/glutMainLoopEvent στο freeglut).

    «GLUT is designed for simple to moderately complex programs focused on OpenGL rendering. GLUT implements its own event loop. For this reason, mixing GLUT with other APIs that demand their own event handling structure may be difficult. The advantage of a builtin event dispatch loop is simplicity.»

    Αυτό λοιπόν δεν ισχύει πλέον, αφού μπορείς να κρατήσεις τον ελεγχο του event loop και να το κάνεις integrate με άλλα.
    Απο τα docs του freeglut:

    “Freeglut allows the application programmer to specify more direct control over the event loop by means of two new functions. The first, glutMainLoopEvent, processes a single iteration of the event loop and allows the application to use a different event loop controller or to contain re-entrant code. The second, glutLeaveMainLoop, causes the event loop to exit nicely; this is preferable to the application’s calling exit from within a GLUT callback. ”

    Για τα threads έχεις δίκιο, αλλά εδω μπορεί κάποιος να πει οτι olo to opengl api δεν είναι multithread friendly.
    Επίσης, το να καλείς opengl/glut functions απο διαφορετικά threads είναι εξαιρετικά σπάνιο.

    Thanks for reading :-)

  7. jmanji είπε

    Ωραίο άρθρο. Keep up.

Υποβολή απάντησης

XHTML: Μπορείτε να χρησιμοποιήσετε αυτές τις ετικέτες: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>