Mercurial > audlegacy
comparison Plugins/Visualization/paranormal/pn/pnimage.c @ 1507:0c5fdcf3f947 trunk
[svn] - incomplete stuff
author | nenolod |
---|---|
date | Sun, 06 Aug 2006 01:53:29 -0700 |
parents | |
children | a898e415ad8f |
comparison
equal
deleted
inserted
replaced
1506:2a8e193c07a6 | 1507:0c5fdcf3f947 |
---|---|
1 /* Paranormal - A highly customizable audio visualization library | |
2 * Copyright (C) 2001 Jamie Gennis <jgennis@mindspring.com> | |
3 * | |
4 * This library is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU Library General Public | |
6 * License as published by the Free Software Foundation; either | |
7 * version 2 of the License, or (at your option) any later version. | |
8 * | |
9 * This library is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 * Library General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU Library General Public | |
15 * License along with this library; if not, write to the Free | |
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
17 */ | |
18 | |
19 #include <config.h> | |
20 | |
21 #include <glib.h> | |
22 #include "pnimage.h" | |
23 #include "pnerror.h" | |
24 #include "pncpu.h" | |
25 | |
26 static void pn_image_class_init (PnImageClass *class); | |
27 static void pn_image_init (PnImage *image, | |
28 PnImageClass *class); | |
29 | |
30 /* GObject signals */ | |
31 static void pn_image_finalize (GObject *gobject); | |
32 | |
33 static PnObjectClass *parent_class = NULL; | |
34 | |
35 const gchar *pn_image_blend_mode_strings[] = | |
36 { | |
37 "Ignore", | |
38 "Replace", | |
39 "50/50" | |
40 }; | |
41 const guint pn_image_blend_mode_count = 3; | |
42 | |
43 GType | |
44 pn_image_get_type (void) | |
45 { | |
46 static GType image_type = 0; | |
47 | |
48 if (! image_type) | |
49 { | |
50 static const GTypeInfo image_info = | |
51 { | |
52 sizeof (PnImageClass), | |
53 NULL, /* base_init */ | |
54 NULL, /* base_finalize */ | |
55 (GClassInitFunc) pn_image_class_init, | |
56 NULL, /* class_finalize */ | |
57 NULL, /* class_data */ | |
58 sizeof (PnImage), | |
59 0, /* n_preallocs */ | |
60 (GInstanceInitFunc) pn_image_init | |
61 }; | |
62 | |
63 /* FIXME: should this be dynamic? */ | |
64 image_type = g_type_register_static (PN_TYPE_OBJECT, | |
65 "PnImage", | |
66 &image_info, | |
67 0); | |
68 } | |
69 return image_type; | |
70 } | |
71 | |
72 static void | |
73 pn_image_class_init (PnImageClass *class) | |
74 { | |
75 GObjectClass *gobject_class; | |
76 PnObjectClass *object_class; | |
77 | |
78 parent_class = g_type_class_peek_parent (class); | |
79 | |
80 gobject_class = (GObjectClass *) class; | |
81 object_class = (PnObjectClass *) class; | |
82 | |
83 /* GObject signals */ | |
84 gobject_class->finalize = pn_image_finalize; | |
85 } | |
86 | |
87 static void | |
88 pn_image_init (PnImage *image, PnImageClass *class) | |
89 { | |
90 image->render_mode = PN_BLEND_MODE_REPLACE; | |
91 image->transform_mode = PN_BLEND_MODE_REPLACE; | |
92 } | |
93 | |
94 static void | |
95 pn_image_finalize (GObject *gobject) | |
96 { | |
97 PnImage *image; | |
98 | |
99 image = (PnImage *) gobject; | |
100 | |
101 if (image->image_buffer) | |
102 g_free (image->image_buffer); | |
103 | |
104 if (image->transform_buffer) | |
105 g_free (image->transform_buffer); | |
106 } | |
107 | |
108 /** | |
109 * pn_image_new | |
110 * | |
111 * Creates a new #PnImage object | |
112 * | |
113 * Returns: The new #PnImage object | |
114 */ | |
115 PnImage* | |
116 pn_image_new (void) | |
117 { | |
118 return (PnImage *) g_object_new (PN_TYPE_IMAGE, NULL); | |
119 } | |
120 | |
121 /** | |
122 * pn_image_new_width_size | |
123 * @width: the width of the new image | |
124 * @height: the hight of the new image | |
125 * | |
126 * Creates a new #PnImage object with the given dimensions | |
127 * | |
128 * Returns: The new #PnImage object | |
129 */ | |
130 PnImage* | |
131 pn_image_new_with_size (guint width, guint height) | |
132 { | |
133 PnImage *image; | |
134 | |
135 image = (PnImage *) g_object_new (PN_TYPE_IMAGE, NULL); | |
136 | |
137 pn_image_set_size (image, width, height); | |
138 | |
139 return image; | |
140 } | |
141 | |
142 /** | |
143 * pn_image_set_size | |
144 * @image: a #PnImage | |
145 * @width: the new width of the image | |
146 * @height: the new height of the image | |
147 * | |
148 * Sets the size of the image contained in a #PnImage object | |
149 */ | |
150 void | |
151 pn_image_set_size (PnImage *image, guint width, guint height) | |
152 { | |
153 guint pitch; | |
154 | |
155 g_return_if_fail (image != NULL); | |
156 g_return_if_fail (PN_IS_IMAGE (image)); | |
157 g_return_if_fail (width > 0 && height > 0); | |
158 | |
159 pitch = width * sizeof (PnColor); | |
160 | |
161 /* Align each row to 8 bytes */ | |
162 if (pitch & 0x00000007) | |
163 pitch = (pitch & 0xfffffff8) + 8; | |
164 | |
165 if (image->image_buffer) | |
166 g_free (image->image_buffer); | |
167 | |
168 if (image->transform_buffer) | |
169 g_free (image->transform_buffer); | |
170 | |
171 image->pitch = pitch; | |
172 image->width = width; | |
173 image->height = height; | |
174 image->image_buffer = g_malloc0 (pitch * height); | |
175 image->transform_buffer = g_malloc0 (pitch * height); | |
176 } | |
177 | |
178 /** | |
179 * pn_image_get_width | |
180 * @image: a #PnImage | |
181 * | |
182 * Gets the width of a #PnImage | |
183 * | |
184 * Returns: The width of the image | |
185 */ | |
186 guint | |
187 pn_image_get_width (PnImage *image) | |
188 { | |
189 g_return_val_if_fail (image != NULL, 0); | |
190 g_return_val_if_fail (PN_IS_IMAGE (image), 0); | |
191 | |
192 return image->width; | |
193 } | |
194 | |
195 /** | |
196 * pn_image_get_height | |
197 * @image: a #PnImage | |
198 * | |
199 * Gets the height of a #PnImage | |
200 * | |
201 * Returns: The height of the image | |
202 */ | |
203 guint | |
204 pn_image_get_height (PnImage *image) | |
205 { | |
206 g_return_val_if_fail (image != NULL, 0); | |
207 g_return_val_if_fail (PN_IS_IMAGE (image), 0); | |
208 | |
209 return image->height; | |
210 } | |
211 | |
212 /** | |
213 * pn_image_get_pitch | |
214 * @image: a #PnImage | |
215 * | |
216 * Gets the pitch (width in bytes) of a #PnImage | |
217 * | |
218 * Returns: The pitch of the image | |
219 */ | |
220 guint | |
221 pn_image_get_pitch (PnImage *image) | |
222 { | |
223 g_return_val_if_fail (image != NULL, 0); | |
224 g_return_val_if_fail (PN_IS_IMAGE (image), 0); | |
225 | |
226 return image->pitch; | |
227 } | |
228 | |
229 /** | |
230 * pn_image_set_render_mode | |
231 * @image: a #PnImage | |
232 * @render_mode: the blend mode to use | |
233 * | |
234 * Sets the blend mode to be used by render functions. The | |
235 * render functions are pn_image_render_pixel(), | |
236 * pn_image_render_pixel_by_offset(), and pn_image_render_line(). | |
237 */ | |
238 void | |
239 pn_image_set_render_mode (PnImage *image, PnBlendMode render_mode) | |
240 { | |
241 g_return_if_fail (image != NULL); | |
242 g_return_if_fail (PN_IS_IMAGE (image)); | |
243 g_return_if_fail (render_mode < PN_BLEND_MODE_LAST); | |
244 | |
245 image->render_mode = render_mode; | |
246 } | |
247 | |
248 /** | |
249 * pn_image_set_transform_mode | |
250 * @image: a #PnImage | |
251 * @transform_mode: the blend mode to use | |
252 * | |
253 * Sets the blend mode to be used by pn_image_apply_transform(). | |
254 */ | |
255 void | |
256 pn_image_set_transform_mode (PnImage *image, PnBlendMode transform_mode) | |
257 { | |
258 g_return_if_fail (image != NULL); | |
259 g_return_if_fail (PN_IS_IMAGE (image)); | |
260 g_return_if_fail (transform_mode < PN_BLEND_MODE_LAST); | |
261 | |
262 image->transform_mode = transform_mode; | |
263 } | |
264 | |
265 /** | |
266 * pn_image_get_image_buffer | |
267 * @image: a #PnImage | |
268 * | |
269 * Retrieves the image buffer (the 'front buffer') of a #PnImage. | |
270 * | |
271 * Returns: A pointer to the image buffer | |
272 */ | |
273 PnColor* | |
274 pn_image_get_image_buffer (PnImage *image) | |
275 { | |
276 g_return_val_if_fail (image != NULL, NULL); | |
277 g_return_val_if_fail (PN_IS_IMAGE (image), NULL); | |
278 | |
279 return image->image_buffer; | |
280 } | |
281 | |
282 /** | |
283 * pn_image_get_transform_buffer | |
284 * @image: a #PnImage | |
285 * | |
286 * Retrieves the transform buffer (the 'back buffer') of a #PnImage. | |
287 * The transform buffer should only be used internally by transform | |
288 * actuators. *EVERY* pixel in the transform buffer *MUST* be set. | |
289 * The transform buffer can be 'copied' to the image buffer using | |
290 * pn_image_apply_transform(). | |
291 * | |
292 * Returns: A pointer to the transform buffer | |
293 */ | |
294 PnColor* | |
295 pn_image_get_transform_buffer (PnImage *image) | |
296 { | |
297 g_return_val_if_fail (image != NULL, NULL); | |
298 g_return_val_if_fail (PN_IS_IMAGE (image), NULL); | |
299 | |
300 return image->transform_buffer; | |
301 } | |
302 | |
303 /** | |
304 * pn_image_render_pixel | |
305 * @image: a #PnImage | |
306 * @x: the x coordinate (left being 0) | |
307 * @y: the y coordinate (top being 0) | |
308 * @color: the color | |
309 * | |
310 * Renders a pixel to the image buffer of a #PnImage. pn_image_set_render_mode() | |
311 * can be used to set the blend mode that is used by this function. | |
312 */ | |
313 void | |
314 pn_image_render_pixel (PnImage *image, guint x, guint y, PnColor color) | |
315 { | |
316 g_return_if_fail (image != NULL); | |
317 g_return_if_fail (PN_IS_IMAGE (image)); | |
318 g_return_if_fail (image->image_buffer != NULL); | |
319 | |
320 if (x > image->width || y > image->height) | |
321 return; | |
322 | |
323 switch (image->render_mode) | |
324 { | |
325 case PN_BLEND_MODE_LAST: break; | |
326 case PN_BLEND_MODE_IGNORE: | |
327 break; | |
328 | |
329 case PN_BLEND_MODE_REPLACE: | |
330 image->image_buffer[(y * (image->pitch>>2)) + x] = color; | |
331 break; | |
332 | |
333 case PN_BLEND_MODE_5050: | |
334 image->image_buffer[(y * (image->pitch>>2)) + x].red = | |
335 (image->image_buffer[(y * (image->pitch>>2)) + x].red + color.red) >> 1; | |
336 image->image_buffer[(y * (image->pitch>>2)) + x].green = | |
337 (image->image_buffer[(y * (image->pitch>>2)) + x].green + color.green) >> 1; | |
338 image->image_buffer[(y * (image->pitch>>2)) + x].blue = | |
339 (image->image_buffer[(y * (image->pitch>>2)) + x].blue + color.blue) >> 1; | |
340 break; | |
341 } | |
342 } | |
343 | |
344 /** | |
345 * pn_image_render_pixel_by_offset | |
346 * @image: a #PnImage | |
347 * @offset: the pixel offset (0 being the top left) NOTE: Use (pitch>>2) rather | |
348 * than width | |
349 * @color: the color | |
350 * | |
351 * Renders a pixel to the image buffer of a #PnImage based on a pixel offset rather than | |
352 * rectangular coordinates. This function should be used if there is a more optimum way | |
353 * to calculate the offset than multiplying at every pixel. pn_image_set_render_mode() | |
354 * can be used to set the blend mode that is used by this function. | |
355 */ | |
356 void | |
357 pn_image_render_pixel_by_offset (PnImage *image, guint offset, PnColor color) | |
358 { | |
359 g_return_if_fail (image != NULL); | |
360 g_return_if_fail (PN_IS_IMAGE (image)); | |
361 g_return_if_fail (image->image_buffer != NULL); | |
362 | |
363 if (offset > (image->pitch>>2) * image->height) | |
364 return; | |
365 | |
366 switch (image->render_mode) | |
367 { | |
368 case PN_BLEND_MODE_LAST: break; | |
369 case PN_BLEND_MODE_IGNORE: | |
370 break; | |
371 | |
372 case PN_BLEND_MODE_REPLACE: | |
373 image->image_buffer[offset] = color; | |
374 break; | |
375 | |
376 case PN_BLEND_MODE_5050: | |
377 image->image_buffer[offset].red = | |
378 (image->image_buffer[offset].red + color.red) >> 1; | |
379 image->image_buffer[offset].green = | |
380 (image->image_buffer[offset].green + color.green) >> 1; | |
381 image->image_buffer[offset].blue = | |
382 (image->image_buffer[offset].blue + color.blue) >> 1; | |
383 break; | |
384 } | |
385 } | |
386 | |
387 /* FIXME: Add clipping to this */ | |
388 /** | |
389 * pn_image_render_line | |
390 * @image: a #PnImage | |
391 * @x0: the x coordinate of the first point | |
392 * @y0: the y coordinate of the first point | |
393 * @x1: the x coordinate of the second point | |
394 * @y1: the y coordinate of the second point | |
395 * @color: the color | |
396 * | |
397 * Renders a line from (x0,y0) to (x1,y1) to the image buffer of a #PnImage. | |
398 * Currently ***NO CLIPPING IS CURRENTLY DONE!!!*** | |
399 */ | |
400 void | |
401 pn_image_render_line (PnImage *image, guint _x0, guint _y0, guint _x1, guint _y1, PnColor color) | |
402 { | |
403 gint x0 = _x0; | |
404 gint y0 = _y0; | |
405 gint x1 = _x1; | |
406 gint y1 = _y1; | |
407 | |
408 gint dy = y1 - y0; | |
409 gint dx = x1 - x0; | |
410 gint stepx, stepy; | |
411 gint fraction; | |
412 | |
413 g_return_if_fail (image != NULL); | |
414 g_return_if_fail (PN_IS_IMAGE (image)); | |
415 g_return_if_fail (image->image_buffer != NULL); | |
416 | |
417 if (dy < 0) | |
418 { | |
419 dy = -dy; | |
420 stepy = -(image->pitch>>2); | |
421 } | |
422 else | |
423 { | |
424 stepy = image->pitch>>2; | |
425 } | |
426 if (dx < 0) | |
427 { | |
428 dx = -dx; | |
429 stepx = -1; | |
430 } | |
431 else | |
432 { | |
433 stepx = 1; | |
434 } | |
435 dy <<= 1; | |
436 dx <<= 1; | |
437 | |
438 y0 *= image->pitch>>2; | |
439 y1 *= image->pitch>>2; | |
440 pn_image_render_pixel_by_offset(image, x0+y0, color); | |
441 if (dx > dy) | |
442 { | |
443 fraction = dy - (dx >> 1); | |
444 while (x0 != x1) | |
445 { | |
446 if (fraction >= 0) | |
447 { | |
448 y0 += stepy; | |
449 fraction -= dx; | |
450 } | |
451 x0 += stepx; | |
452 fraction += dy; | |
453 pn_image_render_pixel_by_offset (image, x0+y0, color); | |
454 } | |
455 } | |
456 else | |
457 { | |
458 fraction = dx - (dy >> 1); | |
459 while (y0 != y1) | |
460 { | |
461 if (fraction >= 0) | |
462 { | |
463 x0 += stepx; | |
464 fraction -= dy; | |
465 } | |
466 y0 += stepy; | |
467 fraction += dx; | |
468 pn_image_render_pixel_by_offset (image, x0+y0, color); | |
469 } | |
470 } | |
471 } | |
472 | |
473 static void | |
474 pn_image_bufcopy_5050 (PnColor *dest, PnColor *src, guint bufsize) | |
475 { | |
476 register guint i; | |
477 register PnColor *d, *s; | |
478 | |
479 d = dest; | |
480 s = src; | |
481 | |
482 for (i=0; i<bufsize; i++) | |
483 { | |
484 d->red = (s->red + d->red) >> 1; | |
485 d->green = (s->green + d->green) >> 1; | |
486 d->blue = (s->blue + d->blue) >> 1; | |
487 d++; | |
488 s++; | |
489 } | |
490 } | |
491 | |
492 #ifdef PN_USE_MMX | |
493 static void | |
494 pn_image_bufcopy_5050_mmx (PnColor *dest, PnColor *src, guint bufsize) | |
495 { | |
496 __asm__ __volatile__ ( | |
497 "pxor %%mm7,%%mm7\n\t" /* zero mm7 */ | |
498 | |
499 "10:\n\t" /* The start of the loop */ | |
500 | |
501 "movq (%0),%%mm0\n\t" /* Read the pixels */ | |
502 "movq (%1),%%mm2\n\t" | |
503 "movq %%mm0,%%mm1\n\t" | |
504 "movq %%mm2,%%mm3\n\t" | |
505 | |
506 "punpcklbw %%mm7,%%mm0\n\t" /* Unpack the pixels */ | |
507 "punpckhbw %%mm7,%%mm1\n\t" | |
508 "punpcklbw %%mm7,%%mm2\n\t" | |
509 "punpckhbw %%mm7,%%mm3\n\t" | |
510 | |
511 "paddw %%mm2,%%mm0\n\t" /* Add the pixels */ | |
512 "paddw %%mm3,%%mm1\n\t" | |
513 | |
514 "psrlw $1,%%mm0\n\t" /* Divide the pixels by 2 */ | |
515 "psrlw $1,%%mm1\n\t" | |
516 | |
517 "packuswb %%mm1,%%mm0\n\t" /* Pack it up & write it */ | |
518 "movq %%mm0,(%0)\n\t" | |
519 | |
520 "addl $8,%0\n\t" /* Advance the pointers */ | |
521 "addl $8,%1\n\t" | |
522 | |
523 "decl %2\n\t" /* See if we're done */ | |
524 "jnz 10b\n\t" | |
525 | |
526 "emms" | |
527 : /* no outputs */ | |
528 : "r" (dest), "r" (src), "r" (bufsize >> 1) | |
529 ); | |
530 } | |
531 | |
532 /* FIXME: Should this be in a separate #define PN_USE_MMXEXT ? */ | |
533 static void | |
534 pn_image_bufcopy_5050_mmxext (PnColor *dest, PnColor *src, guint bufsize) | |
535 { | |
536 | |
537 | |
538 __asm__ __volatile__ ( | |
539 "10:\n\t" /* The non-unrolled loop */ | |
540 | |
541 "decl %2\n\t" /* See if we're done */ | |
542 "js 20f\n\t" | |
543 | |
544 "movq (%0),%%mm0\n\t" /* Read the pixels */ | |
545 "movq (%1),%%mm1\n\t" | |
546 "pavgb %%mm1,%%mm0\n\t" /* Average the pixels */ | |
547 | |
548 "movq %%mm0,(%0)\n\t" /* Write the pixels */ | |
549 | |
550 "addl $8,%0\n\t" /* Advance the pointers */ | |
551 "addl $8,%1\n\t" | |
552 | |
553 "20:\n\t" /* The unrolled loop */ | |
554 | |
555 "decl %3\n\t" /* See if we're done */ | |
556 "js 30f\n\t" | |
557 | |
558 /* First 2 pixels */ | |
559 "movq (%0),%%mm0\n\t" /* Read the pixels */ | |
560 "movq (%1),%%mm1\n\t" | |
561 "pavgb %%mm1,%%mm0\n\t" /* Average the pixels */ | |
562 | |
563 /* Second 2 pixels */ | |
564 "movq 8(%0),%%mm2\n\t" /* Read the pixels */ | |
565 "movq 8(%1),%%mm3\n\t" | |
566 "pavgb %%mm3,%%mm2\n\t" /* Average the pixels */ | |
567 | |
568 /* Third 2 pixels */ | |
569 "movq 16(%0),%%mm4\n\t" /* Read the pixels */ | |
570 "movq 16(%1),%%mm5\n\t" | |
571 "pavgb %%mm5,%%mm4\n\t" /* Average the pixels */ | |
572 | |
573 /* Fourth 2 pixels */ | |
574 "movq 24(%0),%%mm6\n\t" /* Read the pixels */ | |
575 "movq 24(%1),%%mm7\n\t" | |
576 "pavgb %%mm7,%%mm6\n\t" /* Average the pixels */ | |
577 | |
578 /* Write them all */ | |
579 "movq %%mm0,(%0)\n\t" | |
580 "movq %%mm2,8(%0)\n\t" | |
581 "movq %%mm4,16(%0)\n\t" | |
582 "movq %%mm6,24(%0)\n\t" | |
583 | |
584 "addl $32,%0\n\t" /* Advance the pointers */ | |
585 "addl $32,%1\n\t" | |
586 | |
587 "jmp 20b\n\t" /* And again */ | |
588 | |
589 "30:\n\t" | |
590 | |
591 "emms" | |
592 : /* no outputs */ | |
593 : "r" (dest), "r" (src), "r" ((bufsize >> 1) & 0x3), "r" (bufsize >> 3) | |
594 ); | |
595 } | |
596 | |
597 #endif /* PN_USE_MMX */ | |
598 | |
599 /** | |
600 * pn_image_apply_transform | |
601 * @image: a #PnImage | |
602 * | |
603 * Renders the transform buffer onto the image buffer. | |
604 * pn_image_set_transform_mode() may be used to set the blend mode that is | |
605 * used by this function. | |
606 */ | |
607 void | |
608 pn_image_apply_transform (PnImage *image) | |
609 { | |
610 g_return_if_fail (image != NULL); | |
611 g_return_if_fail (PN_IS_IMAGE (image)); | |
612 | |
613 switch (image->transform_mode) | |
614 { | |
615 case PN_BLEND_MODE_LAST: | |
616 case PN_BLEND_MODE_IGNORE: | |
617 return; | |
618 | |
619 case PN_BLEND_MODE_REPLACE: | |
620 { | |
621 PnColor *tmp = image->image_buffer; | |
622 image->image_buffer = image->transform_buffer; | |
623 image->transform_buffer = tmp; | |
624 } | |
625 break; | |
626 | |
627 case PN_BLEND_MODE_5050: | |
628 #ifdef PN_USE_MMX | |
629 if (pn_cpu_get_caps () & PN_CPU_CAP_MMXEXT) | |
630 pn_image_bufcopy_5050_mmxext (image->image_buffer, image->transform_buffer, | |
631 image->height * (image->pitch >> 2)); | |
632 else if (pn_cpu_get_caps () & PN_CPU_CAP_MMX) | |
633 pn_image_bufcopy_5050_mmx (image->image_buffer, image->transform_buffer, | |
634 image->height * (image->pitch >> 2)); | |
635 else | |
636 #endif /* PN_USE_MMX */ | |
637 pn_image_bufcopy_5050 (image->image_buffer, image->transform_buffer, | |
638 image->height * (image->pitch >> 2)); | |
639 break; | |
640 } | |
641 } | |
642 | |
643 /** | |
644 * pn_image_render_image | |
645 * @image: a #PnImage | |
646 * @src: the source image | |
647 * @blend_mode: the blend mode to use | |
648 * | |
649 * Renders the image buffer of @src onto the image buffer of an image. | |
650 */ | |
651 void | |
652 pn_image_render_image (PnImage *image, PnImage *src, PnBlendMode blend_mode) | |
653 { | |
654 g_return_if_fail (image != NULL); | |
655 g_return_if_fail (PN_IS_IMAGE (image)); | |
656 g_return_if_fail (src != NULL); | |
657 g_return_if_fail (PN_IS_IMAGE (src)); | |
658 g_return_if_fail (blend_mode < PN_BLEND_MODE_LAST); | |
659 g_return_if_fail (image->width == src->width); | |
660 g_return_if_fail (image->height == src->height); | |
661 | |
662 switch (blend_mode) | |
663 { | |
664 case PN_BLEND_MODE_LAST: | |
665 case PN_BLEND_MODE_IGNORE: | |
666 return; | |
667 | |
668 case PN_BLEND_MODE_REPLACE: | |
669 memcpy (image->image_buffer, src->image_buffer, image->height * (image->pitch >> 2) * sizeof (PnColor)); | |
670 break; | |
671 | |
672 case PN_BLEND_MODE_5050: | |
673 #ifdef PN_USE_MMX | |
674 if (pn_cpu_get_caps () & PN_CPU_CAP_MMXEXT) | |
675 pn_image_bufcopy_5050_mmxext (image->image_buffer, src->image_buffer, | |
676 image->height * (image->pitch >> 2)); | |
677 else if (pn_cpu_get_caps () & PN_CPU_CAP_MMX) | |
678 pn_image_bufcopy_5050_mmx (image->image_buffer, src->image_buffer, image->height * (image->pitch >> 2)); | |
679 else | |
680 #endif /* PN_USE_MMX */ | |
681 pn_image_bufcopy_5050 (image->image_buffer, src->image_buffer, image->height * (image->pitch >> 2)); | |
682 } | |
683 } |