1 | ␊ |
2 | /* Graphic utility functions and data types␊ |
3 | * Prashant Vaibhav (C) 12/12/2008␊ |
4 | * Chameleon␊ |
5 | */␊ |
6 | #include "boot.h"␊ |
7 | #include "graphic_utils.h"␊ |
8 | #include "graphics.h"␊ |
9 | #include "vbe.h"␊ |
10 | #include "gui.h"␊ |
11 | ␊ |
12 | #define VIDEO(x) (bootArgs->Video.v_ ## x)␊ |
13 | ␊ |
14 | #define MIN(x, y) ((x) < (y) ? (x) : (y))␊ |
15 | ␊ |
16 | ␊ |
17 | ␊ |
18 | #ifdef OPTION_ROM␊ |
19 | int␊ |
20 | convertImage( unsigned short width,␊ |
21 | ␉␉␉ unsigned short height,␊ |
22 | ␉␉␉ const unsigned char *imageData,␊ |
23 | ␉␉␉ unsigned char **newImageData )␊ |
24 | {␊ |
25 | int cnt;␊ |
26 | unsigned char *img = 0;␊ |
27 | unsigned short *img16;␊ |
28 | unsigned long *img32;␊ |
29 | ␉␊ |
30 | switch ( VIDEO(depth) ) {␊ |
31 | ␉␉case 16 :␊ |
32 | ␉␉␉img16 = malloc(width * height * 2);␊ |
33 | ␉␉␉if ( !img16 ) break;␊ |
34 | ␉␉␉for (cnt = 0; cnt < (width * height); cnt++)␊ |
35 | ␉␉␉␉img16[cnt] = lookUpCLUTIndex(imageData[cnt], 16);␊ |
36 | ␉␉␉img = (unsigned char *)img16;␊ |
37 | ␉␉␉break;␊ |
38 | ␉␉␉␊ |
39 | ␉␉case 32 :␊ |
40 | ␉␉␉img32 = malloc(width * height * 4);␊ |
41 | ␉␉␉if ( !img32 ) break;␊ |
42 | ␉␉␉for (cnt = 0; cnt < (width * height); cnt++)␊ |
43 | ␉␉␉␉img32[cnt] = lookUpCLUTIndex(imageData[cnt], 32);␊ |
44 | ␉␉␉img = (unsigned char *)img32;␊ |
45 | ␉␉␉break;␊ |
46 | ␉␉␉␊ |
47 | ␉␉default :␊ |
48 | ␉␉␉img = malloc(width * height);␊ |
49 | ␉␉␉bcopy(imageData, img, width * height);␊ |
50 | ␉␉␉break;␊ |
51 | }␊ |
52 | *newImageData = img;␊ |
53 | return 0;␊ |
54 | }␊ |
55 | ␊ |
56 | //==========================================================================␊ |
57 | // drawDataRectangle␊ |
58 | ␊ |
59 | void drawDataRectangle( unsigned short x,␊ |
60 | ␉␉␉␉␉ unsigned short y,␊ |
61 | ␉␉␉␉␉ unsigned short width,␊ |
62 | ␉␉␉␉␉ unsigned short height,␊ |
63 | ␉␉␉␉␉ unsigned char * data )␊ |
64 | {␊ |
65 | unsigned short drawWidth;␊ |
66 | long pixelBytes = VIDEO(depth) / 8;␊ |
67 | unsigned char * vram = (unsigned char *) VIDEO(baseAddr) +␊ |
68 | ␉VIDEO(rowBytes) * y + pixelBytes * x;␊ |
69 | ␉␊ |
70 | drawWidth = MIN(width, VIDEO(width) - x);␊ |
71 | height = MIN(height, VIDEO(height) - y);␊ |
72 | while ( height-- ) {␊ |
73 | bcopy( data, vram, drawWidth * pixelBytes );␊ |
74 | vram += VIDEO(rowBytes);␊ |
75 | data += width * pixelBytes;␊ |
76 | }␊ |
77 | }␊ |
78 | #endif␊ |
79 | ␊ |
80 | ␊ |
81 | //==========================================================================␊ |
82 | //␊ |
83 | void ␊ |
84 | printVBEModeInfo()␊ |
85 | {␊ |
86 | VBEInfoBlock vbeInfo;␊ |
87 | unsigned short * modePtr;␊ |
88 | VBEModeInfoBlock modeInfo;␊ |
89 | int err;␊ |
90 | int line;␊ |
91 | ␉␊ |
92 | ␉//bzero( &vbeInfo, sizeof(vbeInfo) );␊ |
93 | bzero( &vbeInfo, sizeof(VBEInfoBlock) );␊ |
94 | ␊ |
95 | strcpy( (char*)&vbeInfo, "VBE2" );␊ |
96 | err = getVBEInfo( &vbeInfo );␊ |
97 | if ( err != errSuccess )␊ |
98 | return;␊ |
99 | ␉␊ |
100 | line = 0;␊ |
101 | ␉␊ |
102 | // Activate and clear page 1␊ |
103 | setActiveDisplayPage(1);␊ |
104 | clearScreenRows(0, 24);␊ |
105 | setCursorPosition( 0, 0, 1 );␊ |
106 | ␉␊ |
107 | ␉printf("Video modes supported:\n", VBEDecodeFP(const char *, vbeInfo.OEMStringPtr));␊ |
108 | ␉␊ |
109 | ␉// Loop through the mode list, and find the matching mode.␊ |
110 | ␉␊ |
111 | for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );␊ |
112 | ␉␉ *modePtr != modeEndOfList; modePtr++ )␊ |
113 | {␊ |
114 | // Get mode information.␊ |
115 | ␉␉␊ |
116 | //bzero( &modeInfo, sizeof(modeInfo) );␊ |
117 | bzero( &modeInfo, sizeof(VBEModeInfoBlock) );␊ |
118 | ␊ |
119 | err = getVBEModeInfo( *modePtr, &modeInfo );␊ |
120 | if ( err != errSuccess )␊ |
121 | {␊ |
122 | continue;␊ |
123 | }␊ |
124 | ␉␉␊ |
125 | printf("Mode %x: %dx%dx%d mm:%d attr:%x\n",␊ |
126 | *modePtr, modeInfo.XResolution, modeInfo.YResolution,␊ |
127 | modeInfo.BitsPerPixel, modeInfo.MemoryModel,␊ |
128 | modeInfo.ModeAttributes);␊ |
129 | ␉␉␊ |
130 | if (line++ >= 20) {␊ |
131 | pause();␊ |
132 | line = 0;␊ |
133 | clearScreenRows(0, 24);␊ |
134 | setCursorPosition( 0, 0, 1 );␊ |
135 | }␊ |
136 | } ␊ |
137 | if (line != 0) {␊ |
138 | pause();␊ |
139 | }␊ |
140 | setActiveDisplayPage(0);␊ |
141 | }␊ |
142 | ␊ |
143 | ␊ |
144 | ␊ |
145 | char *getVBEModeInfoString()␊ |
146 | {␊ |
147 | ␉VBEInfoBlock vbeInfo;␊ |
148 | unsigned short * modePtr;␊ |
149 | VBEModeInfoBlock modeInfo;␊ |
150 | int err;␊ |
151 | ␉␊ |
152 | ␉//bzero( &vbeInfo, sizeof(vbeInfo) );␊ |
153 | bzero( &vbeInfo, sizeof(VBEInfoBlock) );␊ |
154 | ␊ |
155 | strcpy( (char*)&vbeInfo, "VBE2" );␊ |
156 | err = getVBEInfo( &vbeInfo );␊ |
157 | if ( err != errSuccess )␊ |
158 | return 0;␊ |
159 | ␉␊ |
160 | ␉char *buff=malloc(sizeof(char)*3072);␊ |
161 | ␉if(!buff) return 0;␊ |
162 | ␉␊ |
163 | ␉// Loop through the mode list, and find the matching mode.␊ |
164 | for ( modePtr = VBEDecodeFP( unsigned short *, vbeInfo.VideoModePtr );␊ |
165 | ␉␉ *modePtr != modeEndOfList; modePtr++ )␊ |
166 | {␊ |
167 | // Get mode information.␊ |
168 | ␉␉␊ |
169 | //bzero( &modeInfo, sizeof(modeInfo) );␊ |
170 | bzero( &modeInfo, sizeof(VBEModeInfoBlock) );␊ |
171 | ␊ |
172 | err = getVBEModeInfo( *modePtr, &modeInfo );␊ |
173 | if ( err != errSuccess )␊ |
174 | {␊ |
175 | continue;␊ |
176 | }␊ |
177 | ␉␉␊ |
178 | sprintf(buff+strlen(buff), "Mode %x: %dx%dx%d mm:%d attr:%x\n",␊ |
179 | ␉␉␉␉*modePtr, modeInfo.XResolution, modeInfo.YResolution,␊ |
180 | ␉␉␉␉modeInfo.BitsPerPixel, modeInfo.MemoryModel,␊ |
181 | ␉␉␉␉modeInfo.ModeAttributes);␊ |
182 | ␉␉␊ |
183 | } ␊ |
184 | ␉return buff;␊ |
185 | }␊ |
186 | ␊ |
187 | ␊ |
188 | void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height,␊ |
189 | ␉␉␉␉uint8_t *data)␊ |
190 | {␊ |
191 | uint16_t drawWidth;␊ |
192 | uint8_t *vram = (uint8_t *) VIDEO(baseAddr) + VIDEO(rowBytes) * y + 4 * x;␊ |
193 | ␉␊ |
194 | drawWidth = MIN(width, VIDEO(width) - x);␊ |
195 | height = MIN(height, VIDEO(height) - y);␊ |
196 | while (height--) {␊ |
197 | ␉␉switch (VIDEO (depth))␊ |
198 | ␉␉{␊ |
199 | ␉␉␉case 32: /* Optimized version*/␊ |
200 | ␉␉␉{␊ |
201 | ␉␉␉␉uint32_t s; uint32_t* d; // Source (img) and destination (bkgd) pixels␊ |
202 | ␉␉␉␉uint32_t a; // Alpha␊ |
203 | ␉␉␉␉uint32_t dstrb, dstg, srcrb, srcg, drb, dg, rb, g, tempB; // Intermediate variables␊ |
204 | ␉␉␉␉uint16_t pos;␊ |
205 | ␉␉␉␉␊ |
206 | ␉␉␉␉for (pos = 0; pos < drawWidth * 4; pos += 4) {␊ |
207 | ␉␉␉␉␉// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html␊ |
208 | ␉␉␉␉␉s = *((uint32_t*) (data + pos));␊ |
209 | ␉␉␉␉␉d = (uint32_t*) (vram + pos);␊ |
210 | ␉␉␉␉␉␊ |
211 | ␉␉␉␉␉// Flip B and R in source␊ |
212 | ␉␉␉␉␉// TODO: use XCHG and inline assembly to do this in a faster, saner way␊ |
213 | ␉␉␉␉␉tempB = (s & 0xFF0000); // save B␊ |
214 | ␉␉␉␉␉s = (s & 0xFF00FFFF) | ((s & 0xFF) << 16); // put R in B␊ |
215 | ␉␉␉␉␉s = (s & 0xFFFFFF00) | (tempB >> 16); // put B in R␊ |
216 | ␉␉␉␉␉␊ |
217 | ␉␉␉␉␉a = (s >> 24) + 1;␊ |
218 | ␉␉␉␉␉␊ |
219 | ␉␉␉␉␉dstrb = *d & 0xFF00FF; dstg = *d & 0xFF00;␊ |
220 | ␉␉␉␉␉srcrb = s & 0xFF00FF; srcg = s & 0xFF00;␊ |
221 | ␉␉␉␉␉␊ |
222 | ␉␉␉␉␉drb = srcrb - dstrb;␊ |
223 | ␉␉␉␉␉dg = srcg - dstg;␊ |
224 | ␉␉␉␉␉drb *= a; dg *= a;␊ |
225 | ␉␉␉␉␉drb >>= 8; dg >>= 8;␊ |
226 | ␉␉␉␉␉␊ |
227 | ␉␉␉␉␉rb = (drb + dstrb) & 0xFF00FF;␊ |
228 | ␉␉␉␉␉g = (dg + dstg) & 0xFF00;␊ |
229 | ␉␉␉␉␉␊ |
230 | ␉␉␉␉␉*d = rb | g;␊ |
231 | ␉␉␉␉}␊ |
232 | ␉␉␉}␊ |
233 | ␉␉␉␉break;␊ |
234 | ␉␉␉␉␊ |
235 | ␉␉␉default: /*Universal version*/␊ |
236 | ␉␉␉{␊ |
237 | ␉␉␉␉uint32_t s; ␊ |
238 | ␉␉␉␉uint32_t a; // Alpha␊ |
239 | ␉␉␉␉uint32_t dr, dg, db, sr, sg, sb; // Intermediate variables␊ |
240 | ␉␉␉␉uint16_t pos;␊ |
241 | ␉␉␉␉int bpp = (VIDEO (depth) + 7)/8;␊ |
242 | ␉␉␉␉␊ |
243 | ␉␉␉␉for (pos = 0; pos < drawWidth; pos ++) {␊ |
244 | ␉␉␉␉␉// Fast pseudo-vector alpha blending, adapted from: http://www.stereopsis.com/doubleblend.html␊ |
245 | ␉␉␉␉␉s = *((uint32_t*) (data + 4*pos));␊ |
246 | ␉␉␉␉␉␊ |
247 | ␉␉␉␉␉sb = (s & 0xFF0000) >> 16;␊ |
248 | ␉␉␉␉␉sg = (s & 0xFF00) >> 8;␊ |
249 | ␉␉␉␉␉sr = (s & 0xFF);␊ |
250 | ␉␉␉␉␉␊ |
251 | ␉␉␉␉␉a = (s >> 24) + 1;␊ |
252 | ␉␉␉␉␉␊ |
253 | ␉␉␉␉␉switch (VIDEO (depth))␊ |
254 | ␉␉␉␉␉{␊ |
255 | ␉␉␉␉␉␉case 24:␊ |
256 | ␉␉␉␉␉␉␉db = ((*(uint32_t *)(vram + bpp*pos))&0xff);␊ |
257 | ␉␉␉␉␉␉␉dg = ((*(uint32_t *)(vram + bpp*pos))&0xff00)>>8;␊ |
258 | ␉␉␉␉␉␉␉dr = ((*(uint32_t *)(vram + bpp*pos))&0xff0000)>>16;␊ |
259 | ␉␉␉␉␉␉␉break;␊ |
260 | ␉␉␉␉␉␉case 16://16-bit seems to be 15-bit␊ |
261 | ␉␉␉␉␉␉␉/*␉␉␉␉␉␉␉db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;␊ |
262 | ␉␉␉␉␉␉␉ dg = ((*(uint16_t *)(vram + bpp*pos))&0x07e0)>>3;␊ |
263 | ␉␉␉␉␉␉␉ dr = ((*(uint16_t *)(vram + bpp*pos))&0xf800)>>8;␊ |
264 | ␉␉␉␉␉␉␉ break;␉␉␉␉␉␉␉*/␊ |
265 | ␉␉␉␉␉␉case 15:␊ |
266 | ␉␉␉␉␉␉␉db = ((*(uint16_t *)(vram + bpp*pos))&0x1f)<<3;␊ |
267 | ␉␉␉␉␉␉␉dg = ((*(uint16_t *)(vram + bpp*pos))&0x03e0)>>2;␊ |
268 | ␉␉␉␉␉␉␉dr = ((*(uint16_t *)(vram + bpp*pos))&0x7c00)>>7;␊ |
269 | ␉␉␉␉␉␉␉break;␉␉␊ |
270 | ␉␉␉␉␉␉default:␊ |
271 | ␉␉␉␉␉␉␉return;␊ |
272 | ␉␉␉␉␉}␊ |
273 | ␉␉␉␉␉␊ |
274 | ␉␉␉␉␉dr = (((sr - dr) * a) >> 8) + dr;␊ |
275 | ␉␉␉␉␉dg = (((sg - dg) * a) >> 8) + dg;␊ |
276 | ␉␉␉␉␉db = (((sb - db) * a) >> 8) + db;␊ |
277 | ␉␉␉␉␉switch (VIDEO (depth))␊ |
278 | ␉␉␉␉␉{␊ |
279 | ␉␉␉␉␉␉case 24:␊ |
280 | ␉␉␉␉␉␉␉*(uint32_t *)(vram + bpp*pos) = (*(uint32_t *)(vram + bpp*pos) &0xff000000)␊ |
281 | ␉␉␉␉␉␉␉| (db&0xff) | ((dg&0xff)<<8) | ((dr&0xff)<<16);␊ |
282 | ␉␉␉␉␉␉␉break;␊ |
283 | ␉␉␉␉␉␉case 16:␊ |
284 | ␉␉␉␉␉␉␉//␉␉␉␉␉␉␉*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xfc)<<3) | ((dr&0xf8)<<8);␊ |
285 | ␉␉␉␉␉␉␉//␉␉␉␉␉␉␉break;␉␉␉␉␉␉␉␊ |
286 | ␉␉␉␉␉␉case 15:␊ |
287 | ␉␉␉␉␉␉␉*(uint16_t *)(vram + bpp*pos) = ((db&0xf8)>>3) | ((dg&0xf8)<<2) | ((dr&0xf8)<<7);␊ |
288 | ␉␉␉␉␉␉␉break;␉␊ |
289 | ␉␉␉␉␉␉default:␊ |
290 | ␉␉␉␉␉␉␉break;␊ |
291 | ␉␉␉␉␉}␊ |
292 | ␉␉␉␉␉␊ |
293 | ␉␉␉␉}␉␉␉␉␊ |
294 | ␉␉␉}␊ |
295 | ␉␉␉␉break;␊ |
296 | }␊ |
297 | vram += VIDEO(rowBytes);␊ |
298 | data += width * 4;␊ |
299 | }␊ |
300 | }␊ |
301 | ␊ |
302 | void drawCheckerBoard()␊ |
303 | {␊ |
304 | uint32_t *vram = (uint32_t *) VIDEO(baseAddr);␊ |
305 | uint16_t x, y;␊ |
306 | uint8_t color;␊ |
307 | ␉␊ |
308 | for (y = 0; y < VIDEO(height); y++, vram += VIDEO(width)) {␊ |
309 | for (x = 0; x < VIDEO(width); x++) {␊ |
310 | color = 204 + 51 * (((x / 8) % 2) == ((y / 8) % 2));␊ |
311 | vram[x] = (color << 16) | (color << 8) | color;␊ |
312 | }␊ |
313 | }␊ |
314 | }␊ |
315 | ␊ |
316 | void getGraphicModeParams(unsigned long params[]) {␊ |
317 | ␉␊ |
318 | ␉params[3] = 0;␊ |
319 | ␉␊ |
320 | ␉VBEModeInfoBlock minfo;␊ |
321 | ␉␊ |
322 | unsigned short vesaVersion;␊ |
323 | unsigned short mode = modeEndOfList;␊ |
324 | ␉␊ |
325 | ␉getNumberArrayFromProperty( kGraphicsModeKey, params, 4);␊ |
326 | ␉␊ |
327 | ␉mode = getVESAModeWithProperties( params[0], params[1], params[2],␊ |
328 | ␉␉␉␉␉␉␉␉␉ maColorModeBit |␊ |
329 | ␉␉␉␉␉␉␉␉␉ maModeIsSupportedBit |␊ |
330 | ␉␉␉␉␉␉␉␉␉ maGraphicsModeBit |␊ |
331 | ␉␉␉␉␉␉␉␉␉ maLinearFrameBufferAvailBit,␊ |
332 | ␉␉␉␉␉␉␉␉␉ 0,␊ |
333 | ␉␉␉␉␉␉␉␉␉ &minfo, &vesaVersion );␊ |
334 | ␉␊ |
335 | ␉params[0] = minfo.XResolution;␊ |
336 | ␉params[1] = minfo.YResolution;␊ |
337 | ␉params[2] = 32;␊ |
338 | }␊ |
339 | ␊ |
340 | ␊ |
341 | //==========================================================================␊ |
342 | // getVBEInfoString␊ |
343 | ␊ |
344 | char *getVBEInfoString()␊ |
345 | {␊ |
346 | ␉VBEInfoBlock vbeInfo;␊ |
347 | ␉int err, small;␊ |
348 | ␉char *buff = malloc(sizeof(char)*256);␊ |
349 | ␉if(!buff) return 0;␊ |
350 | ␉␊ |
351 | ␉//bzero( &vbeInfo, sizeof(vbeInfo) );␊ |
352 | bzero( &vbeInfo, sizeof(VBEInfoBlock) );␊ |
353 | ␊ |
354 | ␉strcpy( (char*)&vbeInfo, "VBE2" );␊ |
355 | ␉err = getVBEInfo( &vbeInfo );␊ |
356 | ␉if (err != errSuccess)␊ |
357 | ␉␉return 0;␊ |
358 | ␉␊ |
359 | ␉if ( strncmp( (char *)vbeInfo.VESASignature, "VESA", 4 ) )␊ |
360 | ␉␉return 0;␊ |
361 | ␉␊ |
362 | ␉small = (vbeInfo.TotalMemory < 16);␊ |
363 | ␉␊ |
364 | ␉sprintf(buff, "VESA v%d.%d %d%s (%s)\n",␊ |
365 | ␉␉␉vbeInfo.VESAVersion >> 8,␊ |
366 | ␉␉␉vbeInfo.VESAVersion & 0xf,␊ |
367 | ␉␉␉small ? (vbeInfo.TotalMemory * 64) : (vbeInfo.TotalMemory / 16),␊ |
368 | ␉␉␉small ? "KB" : "MB",␊ |
369 | ␉␉␉VBEDecodeFP(const char *, vbeInfo.OEMStringPtr) );␊ |
370 | ␉␊ |
371 | ␉return buff;␊ |
372 | }␊ |
373 | ␊ |
374 | void blend( const pixmap_t *blendThis, // Source image␊ |
375 | ␉␉ pixmap_t *blendInto, // Dest image␊ |
376 | ␉␉ const position_t position) // Where to place the source image␊ |
377 | {␊ |
378 | uint16_t sx, sy, dx, dy;␊ |
379 | uint32_t dstrb, dstag, srcrb, srcag, drb, dag, rb, ag, alpha;␊ |
380 | ␉␊ |
381 | ␉uint16_t width = (blendThis->width + position.x < blendInto->width) ? blendThis->width: blendInto->width-position.x;␊ |
382 | ␉uint16_t height = (blendThis->height + position.y < blendInto->height) ? blendThis->height: blendInto->height-position.y;␊ |
383 | ␉␊ |
384 | ␉for (dy = position.y, sy = 0; sy < height; dy++, sy++) ␊ |
385 | ␉{␊ |
386 | for (dx = position.x, sx = 0; sx < width; dx++, sx++) ␊ |
387 | ␉␉{␊ |
388 | alpha = (pixel(blendThis, sx, sy).ch.a);␊ |
389 | ␉␉␉␊ |
390 | ␉␉␉/* Skip blending for fully transparent pixel */␊ |
391 | ␉␉␉if (alpha == 0) continue;␊ |
392 | ␉␉␉␊ |
393 | ␉␉␉/* For fully opaque pixel, there is no need to interpolate */␊ |
394 | ␉␉␉if (alpha == 255)␊ |
395 | ␉␉␉{␊ |
396 | ␉␉␉␉pixel(blendInto, dx, dy).value = pixel(blendThis, sx, sy).value;␊ |
397 | ␉␉␉␉continue;␊ |
398 | ␉␉␉}␊ |
399 | ␉␉␉␊ |
400 | ␉␉␉/* For semi-transparent pixels, do a full blend */␊ |
401 | ␉␉␉//alpha++␊ |
402 | ␉␉␉/* This is needed to spread the alpha over [0..256] instead of [0..255]␊ |
403 | ␉␉␉ Boundary conditions were handled above */␊ |
404 | dstrb = pixel(blendInto, dx, dy).value & 0xFF00FF;␊ |
405 | dstag = (pixel(blendInto, dx, dy).value >> 8) & 0xFF00FF;␊ |
406 | srcrb = pixel(blendThis, sx, sy).value & 0xFF00FF;␊ |
407 | srcag = (pixel(blendThis, sx, sy).value >> 8) & 0xFF00FF;␊ |
408 | drb = srcrb - dstrb;␊ |
409 | dag = srcag - dstag;␊ |
410 | drb *= alpha; dag *= alpha;␊ |
411 | drb >>= 8; dag >>= 8;␊ |
412 | rb = (drb + dstrb) & 0x00FF00FF;␊ |
413 | ag = ((dag + dstag) << 8) & 0xFF00FF00;␊ |
414 | pixel(blendInto, dx, dy).value = (rb | ag);␊ |
415 | }␊ |
416 | }␊ |
417 | }␊ |
418 | ␊ |
419 | position_t centeredIn( const pixmap_t *background, const pixmap_t *toCenter )␊ |
420 | {␊ |
421 | position_t centered;␊ |
422 | centered.x = ( background->width - toCenter->width ) / 2;␊ |
423 | centered.y = ( background->height - toCenter->height ) / 2;␊ |
424 | return centered;␊ |
425 | }␊ |
426 | ␊ |
427 | position_t centeredAt( const pixmap_t *pixmap, const position_t center )␊ |
428 | {␊ |
429 | position_t topleft;␊ |
430 | topleft.x = center.x - (pixmap->width / 2);␊ |
431 | topleft.y = center.y - (pixmap->height / 2);␊ |
432 | return topleft;␊ |
433 | }␊ |
434 | ␊ |
435 | position_t pos(const uint16_t x, const uint16_t y) { position_t p; p.x = x; p.y = y; return p; }␊ |
436 | ␊ |
437 | void flipRB(pixmap_t *p)␊ |
438 | {␊ |
439 | ␉//if(testForQemu()) return;␊ |
440 | ␉␊ |
441 | ␉uint32_t x;␊ |
442 | register uint8_t tempB;␊ |
443 | ␉for (x = 0; x < (unsigned long)(p->height) * (p->width) ; x++) {␊ |
444 | ␉␉tempB = (p->pixels[x]).ch.b;␊ |
445 | (p->pixels[x]).ch.b = (p->pixels[x]).ch.r;␊ |
446 | (p->pixels[x]).ch.r = tempB;␊ |
447 | ␉}␊ |
448 | }␊ |
449 | |