Finalmente dopo svariati giorni di smadonnamenti sono riuscito ad aprire una finestra MUI con all'interno una viewport TinyGL e bottoni MUI standard.
Ho deciso di scrivre un po' quello che ho dovuto fare per avere un punto di riferimento nel caso qualcun'altro volesse provare.
Essendo completamente a digiuno di gui (anche per altri sistemi operativi) pensavo che fosse una stupidata mettere una viewport in una finestra, invece non è esattamente semplice
Oltretutto su MOS con la scusa di rimanere compatibili con il '92 bisogna fare un sacco di lavoro in più.(oltre a cercare documentazione varia che è vecchia come il cucco )
L'idea di base è quella di creare una bitmap da usare come offscreen rendering per tinygl e poi "incollare" il risultato nella nostra finestra mui.
Attenzione però non lo "incolleremo" nella finestra nel suo "totale" ma su di un oggetto "custom" che popola la finestra, in modo da potergli affiancare anche altri oggetti MUI.
Scartabellando tra gli header di TinyGL le funzioni che servono allo scopo si trovano in gla.h (la parte GL che si interfaccia ad "amiga")
La funzione preposta è
glAInitializeContextBitMap( *bitmap);Soltanto che bitmap non è intesa come una array di uchar come in OpenGL od un'immagine raw, è proprio la truttura BitMap di 20 anni fa
In genere una BitMap è contenuta in una struttura più grande, la RasterPort che è una "porta" adibita a funzioni di disegno.
La struttura di una
BitMap è questa :
struct BitMap
{
UWORD BytesPerRow;
UWORD Rows;
UBYTE Flags;
UBYTE Depth;
UWORD pad;
PLANEPTR Planes[8];
};
Dal contenuto si vede che ci sono ancora i bitplanes purtroppo
Comunque per creare una BitMap come vuole amigados esiste una funzione che ne facilita la creazione ed è
AllocBitMap definita così :
struct BitMap *AllocBitMap( ULONG sizex, ULONG sizey, ULONG depth, ULONG flags, CONST struct BitMap *friend_bitmap );
Ma i problemi si moltiplicano purtroppo...
PROBLEMA 1: il terzo parametro da passare ad
AllocBitMap è la profondità della BitMap da creare, ma è in bit o numero di bitplane?
per non sbagliare ci viene incontro la funzione
GetBitMapAttr che tra le altre cose con il flag
BMA_DEPTH ci indica la profondità di colore di una BitMap.
Ma la profondità di quale BitMap, visto che noi la stiamo creando per la prima volta ?
L'opzione più "logica" è di usare la profondità dello schermo che conterrà la nostra finestra mui, quindi l'opzione depth la otteniamo da :
depth = GetBitMapAttr(_screen(obj)->RastPort.BitMap, BMA_DEPTH);
dove
obj è l'oggetto che creeremo nella finestra e la
rasterport è la struttura che contiene la struttura BitMap dello schermo.
PROBLEMA 2: il quarto parametro della
AllocBitMap sono una serie di flags da mettere per la creazione della BitMap, dai 3 sorgenti (gli unici) che ho trovato è bene specificare
BMF_DISPLAYABLE|BMF_MINPLANES, che significa che la BitMap creata andrà visualizzata, e che deve contenere il minimo dei bitplane in modo da risultare meno pesante (si parla sempre del '92).
Ho notato che omettendo
BMF_MINPLANES l'immagine è "trashata", quindi meglio metterlo
PROBLEMA 3: l'ultimo parametro da passare alla
AllocBitMap è una BitMap amica, serve probabilmente per velocizzare le operazioni di creazione della nostra bitmap, e per renderla "compatibile" (penso probabilmente a problemi di palette degli amiga anni '90) quando si dovrà disegnare.
Cercando nei vari autodocs su internet e sul wiki di aros, si consiglia di mettere come friend BitMap, la BitMap della finestra o dello schermo sul quale andrà disegnata la nostra BitMap appena creata. Io per non sbagliare ho messo la BitMap dello schermo:)
Si può passare anche NULL come parametro, ma non crea la BitMap in maniera corretta.
Riassumendo la funzione
AllocBitMap diventa così :
AllocBitMap(256, 256, depth, BMF_DISPLAYABLE|BMF_MINPLANES, _screen(obj)->RastPort.BitMap);
finalmente si può usare questa "superficie" come buffer per TinyGL con la funzione glAInitializeContextBitMap( * BitMap);
Il grosso del lavoro è ormai fatto, ma come riesco a disegnare questa "immagine" nella finestra?
Visto che si parla di BitMap ho cercato un po' ed ho trovato
BltBitMapRastPort che è definita così :
void BltBitMapRastPort(
struct BitMap * srcBitMap,
LONG xSrc,
LONG ySrc,
struct RastPort * destRP,
LONG xDest,
LONG yDest,
LONG xSize,
LONG ySize,
ULONG minterm );
srcBitMap è il nostro "offscreen Buffer" mentre
destRP è la rasterport del nostro oggetto nella finestra . La cosa particolare è il
minterm che altro non è che una maschera da effettuare in fase di blitting per sovrascrivere,sovrascrivere in negativo, o con trasparenza la nostra BitMap nella rasterport di destinazione. Nel mio caso mi occorre una viewport "solida" quindi il parametro da passare è
0xC0.
La funzione finita è quindi :
BltBitMapRastPort(data->RastPort.BitMap, 0, 0, _rp(obj),_mleft(obj), _mtop(obj), 256, 256, 0xC0);
_rp(obj),_mleft(obj), _mtop(obj) sono delle macro che definiscono la posizione dell'oggetto nella finestra.
Ormai il gioco è fatto, bisogna solo ricordarsi di swappare il buffer BitMap (anche se non si utilizza il doublebuffer) in modo da aggiornare la BitMap offscreen e disegnarla nel momento opportuno. La fuzione da usare è
glASwapBuffers() ;Ricapitolando le varie fasi :
- Inizializziamo le librerie MUI e TinyGL.
- Creiamo una classe custom MUI che contenga nell'area dati una struttura BitMap ,visto che quando si crea un oggetto già contiene una RasterPort, con annessa BitMap. (io nella mia classe ho messo addirittura una RasterPort intera che non si sa mai
)
- Allochiamo la struttura BitMap della nostra classe custom
- Diciamo a TinyGL di utilizzarla come context per il renderinig.
- Partiamo con l'inizializzazione delle OpenGL come al solito
Fino a qua il setup è finito, per visualizzare l'immagine, nel metodo di draw della nostra classe, basterà "blittare" il contenuto della BitMap creata allo scopo , nella BitMap della clsse stessa, ed il gioco è fatto, con la funzione
BltBitMapRastPortQuesto per un'immagine statica
Se volessimo far ruotare un cubo, bisogna ricordarsi che la fase di draw della classe custom, non coincide con ad esempio la rotazione del nostro oggetto,perciò bisogna lasciare separato il blitting della BitMap, rispetto all'aggiornamento dello stesso.
Non metto il listato completo perchè cho patchato un esempio dell'SDK , e quindi non ho aggiunto ancora i vari dispose della classe, ma posso assicurare che col procedimento descritto, funziona tutto.
Ecco un'immagine dell'esperimento :
Edit : ho linkato questa pagina al thread su Mzone , nel caso qualcun'altro volesse sapere come si fa