Suivez-nous sur X

|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Programmation graphique système - 5e partie : changer une palette et accélérer les tracés 2D
(Article écrit par l'équipe de GuruMed et extrait de GuruMed.net - août 2002)
|
|
Aujourd'hui, nous allons voir deux choses : d'abord, l'utilisation de LoadRGB32() pour changer la palette
de couleurs d'un écran privé ; ensuite, comment accélérer le tracé d'images en utilisant BltBitMapRastPort()
au lieu de WriteChunkyPixels().
LoadRGB32()
La seule méthode vue jusqu'à maintenant dans notre série d'articles pour changer la palette d'un écran,
et notamment du Workbench, était l'utilisation d'ObtainBestPen() de la graphics.library. Cette fonction
marche sur tout écran, public comme privé, mais je ne peux pas cependant m'abstenir de vous présenter
LoadRGB32().
LoadRGB32() permet de changer une ou plusieurs couleurs de la palette d'un écran d'un seul coup. A la
différence d'ObtainBestPen(), les pinceaux modifiés ne seront cependant pas alloués. LoadRGB32()
convient donc très bien pour les écrans privés où seul votre programme a accès, et très mal pour les
écrans publics, susceptibles d'accueillir des fenêtres d'autres programmes que le vôtre, qui pourraient
vouloir modifier la palette.
LoadRGB32() est très simple à utiliser, vous permet d'obtenir la palette exacte souhaitée, et vous épargne
le recalcul des pinceaux de votre image chunky. Mais, je le répète, elle n'est utile que si votre
programme s'ouvre dans un écran privé (sauf cas particuliers).
Cette fonction prend deux paramètres :
- struct ViewPort *vp : le ViewPort de l'écran dont vous voulez modifier la palette.
- ULONG *table : la palette telle que décrite dans l'article
numéro 3 de cette série. Des outils tels que ArtPro et Personal Paint peuvent générer des
palettes au format LoadRGB32.
Comme je l'avais dit précédemment, une palette de format LoadRGB32 commence par deux mots de 16 bits chacun.
Le premier contient le nombre de couleurs de la palette, et le second le numéro de la première couleur à modifier.
Donc, si vous souhaitez changer la couleur des pinceaux 0 à 5 (soit six pinceaux), votre palette devrait
commencer par les deux nombres 6 et 0, soit en hexadécimal 0x00060000. Par exemple, pScreen étant un
pointeur sur votre écran :
ULONG palette[] = {
0x00060000,
0x12345678, 0x12345678, 0x12345678, /* couleur du pinceau 0 */
0x12345678, 0x12345678, 0x12345678, /* couleur du pinceau 1 */
0x12345678, 0x12345678, 0x12345678,
0x12345678, 0x12345678, 0x12345678,
0x12345678, 0x12345678, 0x12345678,
0x12345678, 0x12345678, 0x12345678, /* couleur du pinceau 5 */
0x00000000 /* zéro final */
};
LoadRGB32( &pScreen->ViewPort, palette );
|
Maintenant, si vous souhaitez modifier les pinceaux 10 à 15 de la palette en utilisant ces mêmes couleurs,
il vous suffit de remplacer 0x00060000 par 0x006000A (car 0x000A == 10).
BltBitMapRastPort()
Nous n'avons pour l'instant vu que la fonction WriteChunkyPixels() pour tracer des images. Hors, cette
fonction nécessite une conversion de l'image par le processeur, pour adapter les pixels "chunky"
de l'image au format de pixel de l'écran de destination.
Par exemple, vous connaissez déjà sûrement la fameuse conversion "Chunky to planar" ou "C2P". C'est
ce qu'il se passe lorsque vous tracez une image chunky sur un écran AGA à l'aide de WriteChunkyPixels() :
chaque pixel tenant à l'origine sur un seul octet doit être décomposé en 8 bits séparés appartenant
chacun à un plan différent de l'écran.
Sur cartes graphiques, les écrans ne sont habituellement pas au format planaire, mais des opérations
sur le format des pixels sont en général également nécessaires (par exemple, pour tracer une image chunky
8 bits sur un écran 24 bits, il est évident qu'une conversion est indispensable).
Cette transformation prend du temps, et si vous tracez une image de nombreuses fois dans votre programme,
il peut être très intéressant de la faire une fois pour toutes à l'initialisation du programme... et
d'ensuite utiliser le Blitter pour tracer l'image dans votre fenêtre très rapidement.
Rassurez-vous, il ne sera pas nécessaire de programmer le Blitter directement : la graphics.library se
charge des détails pour vous ;-). Notez également que par le terme "Blitter", je désigne aussi bien le
Blitter de l'AGA que les Blitters des différentes cartes graphiques, c'est-à-dire un coprocesseur
dédié à la copie d'images 2D.
Pré-conversion de l'image chunky
Pas de surprise, nous allons utiliser WriteChunkyPixels(). Cependant, comme nous n'allons pas tracer
directement dans la fenêtre, nous avons besoin de créer un RastPort et un BitMap pour y stocker l'image
transformée au format de l'écran.
Un RastPort se crée très facilement avec la fonction InitRastPort() :
struct RastPort rp;
InitRastPort( &rp );
|
(vous aurez besoin d'inclure graphics/rastport.h pour cela)
Le BitMap, lui, s'alloue avec la fonction AllocBitMap() :
struct BitMap *pBM;
pBM = AllocBitMap( largeur, hauteur, profondeur, flags, friend_bitmap );
|
Comment faire pour que l'image soit transformée au format de l'écran lorsqu'on la trace dans ce BitMap
avec WriteChunkyPixels() ? Il suffit que ce BitMap soit justement dans le même format que l'écran.
C'est à ça que sert le paramètre "friend_bitmap" : il faut donner ici le BitMap de l'écran pour que
le BitMap alloué ait le même format.
"largeur" et "hauteur" sont bien sûr la taille de votre image, et "profondeur" la profondeur de l'écran.
Pour obtenir la profondeur de l'écran, il faut utiliser la fonction GetBitMapAttr() de la graphics.library
sur le BitMap de l'écran. Soit pWin un pointeur sur votre fenêtre, cela donne :
ULONG screenDepth;
screenDepth = GetBitMapAttr( pWin->WScreen->RastPort.BitMap, BMA_DEPTH );
|
Attention : comme cela est précisé dans le fichier d'inclusion intuitions/screens.h, n'utilisez
jamais &Screen-;>BitMap, mais toujours Screen->RastPort.BitMap.
Quand aux drapeaux... leur liste se trouve dans le fichier d'inclusion graphics/gfx.h. Seuls deux
d'entre eux seront abordés ici : BMF_DISPLAYABLE et BMF_MINPLANES.
Le drapeau BMF_DISPLAYABLE demande à ce que le BitMap soit alloué dans la mémoire de la carte graphique
(ou dans la mémoire Chip en AGA). C'est nécessaire pour que le Blitter y ait accès et donc que le tracé
se fasse le plus rapidement possible. Il y a cependant une exception : FBlit. Ce programme sert à accélérer
les Amiga sous AGA en utilisant le processeur à la place du Blitter (vous allez me dire que ça contredit
ce que je viens de dire, et vous aurez raison, mais tant pis). Bref, lorsque FBlit est lancé, il ne faut
pas positionner le drapeau BMF_DISPLAYABLE ; ainsi, le BitMap ira en mémoire Fast et FBlit pourra le
copier plus rapidement. Comment savoir si FBlit est lancé ? En cherchant un port nommé "FBlit" avec la
fonction FindPort() d'exec.library.
Quant à BMF_MINPLANES, cet autre drapeau est à positionner sous CyberGraphX (voire Picasso96) mais pas
en AGA. Je ne m'étendrai pas sur le sujet, mais sachez que ça va plus vite comme ça.
Voici donc comment allouer le RastPort et le BitMap intermédiaire et tracer l'image chunky dedans,
en supposant que l'on souhaite tracer au final dans la fenêtre "pWin" :
struct RastPort rp;
struct BitMap *pBM;
ULONG screenDepth, flags;
BOOL isStandardBM;
InitRastPort( &rp );
screenDepth = GetBitMapAttr( pWin->WScreen->RastPort.BitMap, BMA_DEPTH );
isStandardBM = GetBitMapAttr( pWin->WScreen->RastPort.BitMap, BMA_FLAGS ) & BMF_STANDARD;
flags = ( FindPort("FBlit") ? 0 : BMF_DISPLAYABLE ) | ( isStandardBM ? 0 : BMF_MINPLANES );
pBM = AllocBitMap( IMAGE_WIDTH, IMAGE_HEIGHT, screenDepth, flags, pWin->WScreen->RastPort.BitMap );
if( !pBM ) return; /* quitte si allocation échouée */
rp.BitMap = pBM; /* lie le BitMap au RastPort */
WriteChunkyPixels( &rp, 0, 0, IMAGE_WIDTH-1, IMAGE_HEIGHT-1, image, IMAGE_WIDTH );
|
Tracé du BitMap dans la fenêtre
Maintenant que le plus dur est fait, il ne reste plus qu'à utiliser la fonction BltBitMapRastPort() de
la graphics.library pour tracer le BitMap dans la fenêtre.
BltBitMapRastPort( struct BitMap *bitmap_source, WORD src_x, WORD src_y,
struct RastPort *rastport_dest, WORD dest_x, WORD dest_y,
WORD largeur, WORD hauteur, UBYTE minterm );
|
- bitmap_source : il s'agit du BitMap dans lequel se trouve l'image que vous voulez tracer.
- src_x, src_y : les coordonnées du coin supérieur gauche de l'image que vous voulez tracer,
dans le BitMap source. Si vous voulez tracer tout le BitMap, il faut fournir 0,0.
- rastport_dest : le RastPort de la fenêtre ou de l'écran dans lequel vous voulez tracer l'image.
- dest_x, dest_y : les coordonnées du coin supérieur gauche de la zone du RastPort destination
où vous voulez tracer l'image.
- largeur, hauteur : la taille de l'image à tracer.
- minterm : une valeur décrivant la façon dont l'image doit être copiée... En effet le Blitter
d'origine de l'Amiga permet d'effectuer des opérations sur les images lors d'une copie. Cependant, ceci
n'est pas aussi évident lors de l'utilisation d'une carte graphique, et seules certaines valeurs bien
précises fonctionneront. Sachez juste qu'une valeur de 0xC0 doit être utilisée pour une simple copie d'image
sans modification.
Voici donc l'appel à faire pour tracer votre image :
BltBitMapRastPort( pBM, 0, 0, pWin->RPort, dest_x, dest_y, IMAGE_WIDTH, IMAGE_HEIGHT, 0xC0 );
|
N'oubliez pas de libérer le BitMap avant de quitter le programme, avec la fonction FreeBitMap().
Notez que l'AutoDoc de FreeBitMap() recommande d'appeler WaitBlit() avant de libérer le BitMap pour
être sûr que rien n'est en train d'être écrit dedans. Cependant, ce n'est pas utile dans notre cas, puisque
nous n'utilisons que WriteChunkyPixels() pour écrire dedans et que cette fonction n'utilise pas le Blitter.
Pas de source directement compilable pour cette fois, mais il devrait être facile d'en créer un à partir de
tous les bouts de source de cet article !
|