PDA

View Full Version : [OpenGL] Riuscirò mai a disegnare in 2D?


DanieleC88
20-08-2005, 16:02
Sto cercando di programmare un gioco in 2D con SDL+OpenGL, ma nonostante i miei sforzi, non riesco ad avere alcun risultato.

Codice di inizializzazione:
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
if (!(screen = SDL_SetVideoMode(vwidth, vheight, vbpp, SDL_OPENGL))) {
fprintf(stderr, "Impossibile cambiare modalità grafica (%s).\n", SDL_GetError());
fprintf(stderr, "Per usare \"" game_name "\" è necessario che la scheda grafica supporti il rendering hardware e il double buffering.\n");
// return false;
}
SDL_WM_SetCaption(game_name, NULL);

glViewport(0, 0, vwidth, vheight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, vwidth, 0.0f, vheight, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW);
Dove vwidth e vheight sono la larghezza e l'altezza dello schermo (ad esempio 640 e 480).

Ogni volta che devo disegnare sullo schermo, pulisco la visuale con questo codice:
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Disegno ogni SDL_Surface con questo codice:
glPixelZoom(1.0, -1.0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glRasterPos2f((GLfloat)(dst_rect->x/vwidth), (GLfloat)((dst_rect->y + dst_rect->h)/vheight));
glDrawPixels(dst_rect->w, dst_rect->h, GL_RGB, GL_UNSIGNED_BYTE, src->pixels);
E, infine, aggiorno la visuale con:
glFlush();
SDL_GL_SwapBuffers();
Non riesco a capire cosa c'è di sbagliato in questo codice, ma sta di fatto che vedo solo una "bella" schermata nera.

Suggerimenti?

fek
20-08-2005, 16:25
Prova a disabilitare il depth buffer. Controlla se la viewport e' corretta. Non disegnare pixel, disegna triangoli (molto piu' veloce). Parti da un esempio che funziona e poi modificalo poco per volta per ottenere quello che vuoi tu.

Si parte tutti col famoso schermo nero :)

DanieleC88
20-08-2005, 16:30
Prova a disabilitare il depth buffer. Controlla se la viewport e' corretta.
È tutto nel codice di inizializzazione: la viewport dovrebbe essere a posto. Proverò usando anche glDisable(GL_GEPTH_BUFFER)...
Non disegnare pixel, disegna triangoli (molto piu' veloce).
Disegnare triangoli al posto di pixel? Come? (E poi il giochino non richiede grande velocità, quindi...)
Si parte tutti col famoso schermo nero :)
Vero, ma prima il gioco, in SDL puro, funzionava bene, ma troppo lentamente (qualcosa come 12 FPS). Con OpenGL ho un framerate di minimo 400 FPS, ma non vedo nulla... :cry:

fek
20-08-2005, 18:36
È tutto nel codice di inizializzazione: la viewport dovrebbe essere a posto. Proverò usando anche glDisable(GL_GEPTH_BUFFER)...

Disegnare triangoli al posto di pixel? Come? (E poi il giochino non richiede grande velocità, quindi...)

Imposti la matrice di proiezione per una proiezione ortogonale invece che prospettica, e poi glTriangle (se ricordo bene, sono un po' arrugginito con OpenGL).

In D3D sono due colpetti di DIP ed un paio di shader :p

71104
20-08-2005, 19:14
[...] e poi glTriangle (se ricordo bene, sono un po' arrugginito con OpenGL). forse glBegin(GL_TRIANGLES)? :)

71104
20-08-2005, 19:15
Si parte tutti col famoso schermo nero :) salvo casi di demenza avanzata (il sottoscritto :D) che prima ancora di arrivare allo schermo nero devono superare quello bianco perché si dimenticano di fare SetPixelFormat dopo aver scritto valanghe di codice per riempire PIXELFORMATDESCRIPTOR e fare ChoosePixelFormat :D

DanieleC88
20-08-2005, 22:52
salvo casi di demenza avanzata (il sottoscritto :D) che prima ancora di arrivare allo schermo nero devono superare quello bianco perché si dimenticano di fare SetPixelFormat dopo aver scritto valanghe di codice per riempire PIXELFORMATDESCRIPTOR e fare ChoosePixelFormat :D
Non con X, soprattutto se tramite SDL. ;)
Imposti la matrice di proiezione per una proiezione ortogonale invece che prospettica, e poi glTriangle (se ricordo bene, sono un po' arrugginito con OpenGL).

In D3D sono due colpetti di DIP ed un paio di shader :p
Fammi capire, ché la cosa mi incuriosisce: in pratica dovrei disegnare triangoli della dimensione di un pixel, uno collegato all'altro?

Comunque, ho sostituito "glOrtho(0.0f, vwidth, 0.0f, vheight, -1.0f, +1.0f);" del codice di prima con "glOrtho(0, vwidth, vheight, 0, -1, 1);", come letto in alcuni codici di MPlayer (se non sbaglio, in questo modo non dovrò specificare con glRasterPos l'angolo in basso a sinistra, ma quello in alto a sinistra).
Inoltre, ho disabilitato anche il depth testing con questo codice:
if (glIsEnabled(GL_DEPTH_TEST)) {
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
}
Purtroppo non ho risultati.

Prima di fare questi due cambiamenti, però, ho notato che c'era una sottile linea (credo di un solo pixel di altezza), nella parte bassa dello schermo, con pixel di vari colori. Quindi tutte le chiamate non andavano proprio a vuoto, ma forse erano sbagliate. Ora che ho fatto questi cambiamenti (e un altro paio), lo schermo è totalmente nero.

71104
20-08-2005, 23:01
secondo me ciò che non va è come fai glOrtho: imho devi passare (nell'ordine) valori del seguente tipo: negativo, positivo, negativo, positivo, positivo piccolo, positivo grande.

shinya
21-08-2005, 09:15
La sintassi di glOrtho e':
void glOrtho(
GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top,
GLdouble zNear,
GLdouble zFar
);
quindi da quanto mi pare di capire, quello che hai scritto dovrebbe essere corretto.
Il depth buffer e' disabilitato di default, a meno che non lo abiliti con:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); //o un'altra funzione per lo z-buffering
glClearDepth(1.0f);

Non conosco le sdl, ma e' possibile che ti manchi del codice da eseguire quando si esegue il resize della finestra?
Qualcosa tipo:

void reshape(int height, int width) {
if (height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(...);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

Bane
21-08-2005, 11:43
Dopo glMatrixMode(GL_MODELVIEW) prova ad aggiungerci un bel glLoadIdentity() per inizializzare la matrice.
Altrimenti... boh, hanno gia' detto tutto gli altri =)

DanieleC88
21-08-2005, 16:32
secondo me ciò che non va è come fai glOrtho: imho devi passare (nell'ordine) valori del seguente tipo: negativo, positivo, negativo, positivo, positivo piccolo, positivo grande.
Secondo me ti confondi con glFrustum(). Dovrebbe essere corretto, anche in base a quanto detto da shinya.
Il depth buffer e' disabilitato di default, a meno che non lo abiliti con:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); //o un'altra funzione per lo z-buffering
glClearDepth(1.0f);
Lo so, ma per sicurezza ho messo anche del codice per diabilitarlo. Nessun cambiamento.
Non conosco le sdl, ma e' possibile che ti manchi del codice da eseguire quando si esegue il resize della finestra?
Qualcosa tipo:

void reshape(int height, int width) {
if (height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(...);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Non ridimensiono mai la finestra, a parte la prima volta, dopo l'inizializzazione di SDL e OpenGL (ma in quel caso il codice appropriato c'è). Proverò comunque ad aggiungerlo, non si sa mai (anche se non credo sia così fondamentale, anche in altri progetti in SDL+OpenGL - in 3D, però, non 2D - che ho fatto, anche senza il codice per ridimensionare visuale e viewport, va tutto benissimo).
Dopo glMatrixMode(GL_MODELVIEW) prova ad aggiungerci un bel glLoadIdentity() per inizializzare la matrice.
Altrimenti... boh, hanno gia' detto tutto gli altri =)
Chiamo già glLoadIdentity() ogni volta che devo iniziare a disegnare qualcosa sullo schermo. Ho provato anche a metterci glLoadIdentity() dopo glMatrixMode(GL_MODELVIEW), ma non fa nulla neanche in questo caso...

Aiutoooo!! Non capisco come si possa fare... proverò anche a leggermi un po' di sorgenti di SuperTux e altri giochi 2D. Ho già letto quelli di Chromium B.S.U. e a quanto pare, utilizza delle texture disegnate su quadrati disegnati sullo spazio 3D. Io volevo disegnare direttamente sullo schermo, per evitare di caricare le texture in OpenGL oltre che in SDL, generare le liste, gestire glBegin() e glEnd(), accertarsi che la visuale non sia angolata, ecc...

DanieleC88
21-08-2005, 16:41
forse glBegin(GL_TRIANGLES)? :)
o glBegin(GL_TRIANGLE_STRIP)? :confused:

Bane
21-08-2005, 16:57
Se ti puo' essere d'aiuto, ho provato a scrivere quanto segue (in base al tuo codice):

unsigned char s[100*3];

for (int j = 0; j < 100*3; j++)
s[j] = 50;

glViewport(0, 0, 640, 480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, 640, 0.0f, 480, -1, +1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glPixelZoom(1.0, -1.0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glRasterPos2f(100, 100);
glDrawPixels(10, 10, GL_RGB, GL_UNSIGNED_BYTE, s);


e funziona correttamente, quindi il tuo problema deve stare altrove...

DanieleC88
22-08-2005, 08:33
Se ti puo' essere d'aiuto, ho provato a scrivere quanto segue (in base al tuo codice) e funziona correttamente, quindi il tuo problema deve stare altrove...
Lo credo anch'io, ormai, ma non riesco a capire dove sia l'errore. Ho provato anche ad usare quadrati con delle texture, ma vedo solo una schermata bianca, in qualsiasi profondità.

A questo punto penso che la cosa migliore sia tornare ad usare il rendering software tramite SDL, anche se è decisamente più lento (circa quattro/cinque volte).

Se poi la cosa vi incuriosisce posso anche allegarvi il progetto; è un po' lungo da leggere, ma non mastodontico (il file principale sono 421 linee, il progetto intero sono circa 642).

Bane
22-08-2005, 10:25
Se poi la cosa vi incuriosisce posso anche allegarvi il progetto;
Allega... non si sa mai... =)

fek
22-08-2005, 10:38
forse glBegin(GL_TRIANGLES)? :)

Si'. Dio quanto sono arrugginito con OpenGL.

Ricordo che ai tempi belli usavo un'estensione per disegnare batch di triangoli, ed il singolo triangolo penso di non averlo mai neppure scritto in vita mia :(

fek
22-08-2005, 10:41
Non con X, soprattutto se tramite SDL. ;)

Fammi capire, ché la cosa mi incuriosisce: in pratica dovrei disegnare triangoli della dimensione di un pixel, uno collegato all'altro?

Paradossalmente si', e' piu' veloce :D

Quando disegni un solo pixel, la GPU e la CPU si devono sincronizzare, la CPU deve accedere alla memoria video, scrivere il pixel, e rilasciare la memoria video. A meno che il driver non mappi da solo il disegno di un pixel al disegno di un triangolo.

Ma immagino che tu non voglia disegnare pixel, voglia disegnare uno sprite, giusto? Allora non e' altro che un quad con una texture mappata 1 a 1. Domanda a 71104 come si disegnano i quad che io sono arrugginito in OpenGL :D

DanieleC88
22-08-2005, 13:29
EDIT: whooops! Doppio post, perdonatemi.... :doh:

DanieleC88
22-08-2005, 13:35
Paradossalmente si', e' piu' veloce :D

Quando disegni un solo pixel, la GPU e la CPU si devono sincronizzare, la CPU deve accedere alla memoria video, scrivere il pixel, e rilasciare la memoria video. A meno che il driver non mappi da solo il disegno di un pixel al disegno di un triangolo.

Ma immagino che tu non voglia disegnare pixel, voglia disegnare uno sprite, giusto? Allora non e' altro che un quad con una texture mappata 1 a 1. Domanda a 71104 come si disegnano i quad che io sono arrugginito in OpenGL :D
glBegin(GL_QUADS), questa te la posso dire pure io. ;)
Strana 'sta cosa...

P.S.: HO RISOLTO! Ora, finalmente, funziona bene*. Sapete qual'era l'errore?
...
...
...
.
.
.
...le immagini venivano disegnate fuori dallo schermo per un errore nel posizionamento... e io che ho fatto tutto quel casino! :(
Ora non mi resta che capire come disegnare la mask (penso con glBitmap, vero?) e ho finito! ;)
Devo dire che, tutto sommato, sono soddisfatto, perché quello che finora ho fatto funziona bene sia con OpenGL che con SDL. :)
Il progetto ve lo allego lo stesso, tanto per condividere con voi un po' di codice, visto che mi avete aiutato a risolvere. (ricordo che è ancora incompeto)
Ultima cosa, rivolta a fek e 71104: questo è il progetto di cui ho parlato nel famoso thread del gioco che stiamo cercando di creare, dall'idea di questo gioco era nato poi t³, the teacher terminator... :D
Altro P.S.: non includo il sottofondo musicale (anche se vorrei), perché le dimensioni sarebbero proibitive per HWUpgrade...

* = ringrazio Bane per il suo ultimo post, mi ha dato la spinta per provare ancora una volta a cambiare quella parte di codice, che pensavo ormai fosse corretta. :mano:

Edit: al diavolo! Non me lo fa caricare... lo linko da Altervista... http://jmc.altervista.org/killgloria.zip

DanieleC88
22-08-2005, 13:42
Dimenticavo: se qualcuno proverà ad usare questo progetto, vedrà che il puntatore e il personaggio sono ancora una massa confusa di pixel grigi, perché mi sono messo a fare esperimenti con GL_RGB(A)/GL_BGR(A)/altri formati... :)

71104
22-08-2005, 13:47
...le immagini venivano disegnate fuori dallo schermo per un errore nel posizionamento... l'errore è per forza quello quando agli inizi di un programma OpenGL tutto quello che ottieni nonostante le maree di codice che hai scritto è uno schermo nero ;)