1 /*
2 pygame - Python Game Library
3 Copyright (C) 2009 Vicent Marti
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 */
20
21 #define PYGAME_FREETYPE_INTERNAL
22 #define NO_PYGAME_C_API
23
24 #include "ft_wrap.h"
25 #include FT_MODULE_H
26
27 #if defined (PGFT_PYGAME1_COMPAT)
28 # include "ft_pixel.h"
29 #elif defined (HAVE_PYGAME_SDL_VIDEO)
30 # include "surface.h"
31 #endif
32
__render_glyph_GRAY1(int x,int y,FontSurface * surface,const FT_Bitmap * bitmap,const FontColor * fg_color)33 void __render_glyph_GRAY1(int x, int y, FontSurface *surface,
34 const FT_Bitmap *bitmap, const FontColor *fg_color)
35 {
36 FT_Byte *dst = ((FT_Byte *)surface->buffer) + x + (y * surface->pitch);
37 FT_Byte *dst_cpy;
38
39 const FT_Byte *src = bitmap->buffer;
40 const FT_Byte *src_cpy;
41
42 FT_Byte src_byte;
43 unsigned int j, i;
44
45 #ifndef NDEBUG
46 const FT_Byte *src_end = src + (bitmap->rows * bitmap->pitch);
47 const FT_Byte *dst_end = ((FT_Byte *)surface->buffer +
48 (surface->height * surface->pitch));
49 #endif
50
51 assert(dst >= (FT_Byte *)surface->buffer && dst < dst_end);
52
53 /*
54 * Assumption, target buffer was filled with zeros before any rendering.
55 */
56
57 for (j = 0; j < bitmap->rows; ++j) {
58 src_cpy = src;
59 dst_cpy = dst;
60
61 for (i = 0; i < bitmap->width; ++i) {
62 assert(src_cpy < src_end);
63 src_byte = *src_cpy;
64 if (src_byte) {
65 assert(dst_cpy < dst_end);
66 *dst_cpy = src_byte + *dst_cpy - src_byte * *dst_cpy / 255;
67 }
68 ++src_cpy;
69 ++dst_cpy;
70 }
71
72 dst += surface->pitch;
73 src += bitmap->pitch;
74 }
75 }
76
__render_glyph_MONO_as_GRAY1(int x,int y,FontSurface * surface,const FT_Bitmap * bitmap,const FontColor * fg_color)77 void __render_glyph_MONO_as_GRAY1(int x, int y, FontSurface *surface,
78 const FT_Bitmap *bitmap,
79 const FontColor *fg_color)
80 {
81 const int off_x = (x < 0) ? -x : 0;
82 const int off_y = (y < 0) ? -y : 0;
83
84 const int max_x = MIN(x + bitmap->width, surface->width);
85 const int max_y = MIN(y + bitmap->rows, surface->height);
86
87 const int rx = MAX(0, x);
88 const int ry = MAX(0, y);
89
90 int i, j, shift;
91 const unsigned char* src;
92 unsigned char* dst;
93 const unsigned char* src_cpy;
94 unsigned char* dst_cpy;
95 FT_UInt32 val;
96 FT_Byte shade = fg_color->a;
97
98 src = bitmap->buffer + (off_y * bitmap->pitch) + (off_x >> 3);
99 dst = (unsigned char *)surface->buffer + rx + (ry * surface->pitch);
100
101 shift = off_x & 7;
102
103 for (j = ry; j < max_y; ++j) {
104 src_cpy = src;
105 dst_cpy = dst;
106 val = (FT_UInt32)(*src_cpy++ | 0x100) << shift;
107
108 for (i = rx; i < max_x; ++i, ++dst_cpy) {
109 if (val & 0x10000) {
110 val = (FT_UInt32)(*src_cpy++ | 0x100);
111 }
112
113 if (val & 0x80) {
114 *dst_cpy = shade;
115 }
116
117 val <<= 1;
118 }
119
120 src += bitmap->pitch;
121 dst += surface->pitch;
122 }
123 }
124
__render_glyph_GRAY_as_MONO1(int x,int y,FontSurface * surface,const FT_Bitmap * bitmap,const FontColor * fg_color)125 void __render_glyph_GRAY_as_MONO1(int x, int y, FontSurface *surface,
126 const FT_Bitmap *bitmap,
127 const FontColor *fg_color)
128 {
129 FT_Byte *dst = ((FT_Byte *)surface->buffer) + x + (y * surface->pitch);
130 FT_Byte *dst_cpy;
131 FT_Byte shade = fg_color->a;
132
133 const FT_Byte *src = bitmap->buffer;
134 const FT_Byte *src_cpy;
135
136 unsigned int j, i;
137
138 /*
139 * Assumption, target buffer was filled with the background color before
140 * any rendering.
141 */
142
143 for (j = 0; j < bitmap->rows; ++j) {
144 src_cpy = src;
145 dst_cpy = dst;
146
147 for (i = 0; i < bitmap->width; ++i) {
148 if (*src_cpy & '\200') /* Round up on 128 */ {
149 *dst_cpy = shade;
150 }
151 ++src_cpy;
152 ++dst_cpy;
153 }
154
155 dst += surface->pitch;
156 src += bitmap->pitch;
157 }
158 }
159
__fill_glyph_GRAY1(FT_Fixed x,FT_Fixed y,FT_Fixed w,FT_Fixed h,FontSurface * surface,const FontColor * color)160 void __fill_glyph_GRAY1(FT_Fixed x, FT_Fixed y, FT_Fixed w, FT_Fixed h,
161 FontSurface *surface, const FontColor *color)
162 {
163 int i, j;
164 FT_Byte *dst;
165 FT_Byte *dst_cpy;
166 FT_Byte shade = color->a;
167 FT_Byte edge_shade;
168
169 #ifndef NDEBUG
170 FT_Byte *dst_end = ((FT_Byte *)surface->buffer +
171 (surface->height * surface->pitch));
172 #endif
173
174 x = MAX(0, x);
175 y = MAX(0, y);
176
177 if (x + w > INT_TO_FX6(surface->width)) {
178 w = INT_TO_FX6(surface->width) - x;
179 }
180 if (y + h > INT_TO_FX6(surface->height)) {
181 h = INT_TO_FX6(surface->height) - y;
182 }
183
184 dst = ((FT_Byte *)surface->buffer +
185 FX6_TRUNC(FX6_CEIL(x)) +
186 FX6_TRUNC(FX6_CEIL(y)) * surface->pitch);
187
188 if (y < FX6_CEIL(y)) {
189 dst_cpy = dst - surface->pitch;
190 edge_shade = FX6_TRUNC(FX6_ROUND(shade * (FX6_CEIL(y) - y)));
191
192 for (i = 0; i < FX6_TRUNC(FX6_CEIL(w)); ++i, ++dst_cpy) {
193 assert(dst_cpy < dst_end);
194 *dst_cpy = edge_shade;
195 }
196 }
197
198 for (j = 0; j < FX6_TRUNC(FX6_FLOOR(h + y) - FX6_CEIL(y)); ++j) {
199 dst_cpy = dst;
200
201 for (i = 0; i < FX6_TRUNC(FX6_CEIL(w)); ++i, ++dst_cpy) {
202 assert(dst_cpy < dst_end);
203 *dst_cpy = shade;
204 }
205
206 dst += surface->pitch;
207 }
208
209 if (h > FX6_FLOOR(h + y) - y) {
210 dst_cpy = dst;
211 edge_shade = FX6_TRUNC(FX6_ROUND(shade * (y + y - FX6_FLOOR(h + y))));
212 for (i = 0; i < FX6_TRUNC(FX6_CEIL(w)); ++i, ++dst_cpy) {
213 assert(dst_cpy < dst_end);
214 *dst_cpy = edge_shade;
215 }
216 }
217 }
218
__render_glyph_INT(int x,int y,FontSurface * surface,const FT_Bitmap * bitmap,const FontColor * fg_color)219 void __render_glyph_INT(int x, int y, FontSurface *surface,
220 const FT_Bitmap *bitmap, const FontColor *fg_color)
221 {
222 FT_Byte *dst = ((FT_Byte *)surface->buffer +
223 x * surface->item_stride + y * surface->pitch);
224 int item_size = surface->format->BytesPerPixel;
225 int item_stride = surface->item_stride;
226 FT_Byte *dst_cpy;
227
228 const FT_Byte *src = bitmap->buffer;
229 const FT_Byte *src_cpy;
230 FT_Byte src_byte;
231 FT_Byte mask = ~fg_color->a;
232
233 unsigned int j, i;
234
235 /*
236 * Assumption, target buffer was filled with the background color before
237 * any rendering.
238 */
239
240 if (item_size == 1) {
241 for (j = 0; j < bitmap->rows; ++j) {
242 src_cpy = src;
243 dst_cpy = dst;
244
245 for (i = 0; i < bitmap->width; ++i) {
246 src_byte = *src_cpy;
247 if (src_byte) {
248 *dst_cpy = ((src_byte + *dst_cpy -
249 src_byte * *dst_cpy / 255) ^ mask);
250 }
251 ++src_cpy;
252 dst_cpy += item_stride;
253 }
254
255 dst += surface->pitch;
256 src += bitmap->pitch;
257 }
258 }
259 else {
260 FT_Byte dst_byte;
261 int b, int_offset = surface->format->Ashift / 8;
262
263 for (j = 0; j < bitmap->rows; ++j) {
264 src_cpy = src;
265 dst_cpy = dst;
266
267 for (i = 0; i < bitmap->width; ++i) {
268 dst_byte = dst_cpy[int_offset];
269 for (b = 0; b < item_size; ++b) {
270 dst_cpy[b] = 0;
271 }
272
273 src_byte = *src_cpy;
274 if (src_byte) {
275 dst_cpy[int_offset] = ((src_byte + dst_byte -
276 src_byte * dst_byte / 255) ^ mask);
277 }
278 ++src_cpy;
279 dst_cpy += item_stride;
280 }
281
282 dst += surface->pitch;
283 src += bitmap->pitch;
284 }
285 }
286 }
287
__render_glyph_MONO_as_INT(int x,int y,FontSurface * surface,const FT_Bitmap * bitmap,const FontColor * fg_color)288 void __render_glyph_MONO_as_INT(int x, int y, FontSurface *surface,
289 const FT_Bitmap *bitmap,
290 const FontColor *fg_color)
291 {
292 const int off_x = (x < 0) ? -x : 0;
293 const int off_y = (y < 0) ? -y : 0;
294
295 const int max_x = MIN(x + bitmap->width, surface->width);
296 const int max_y = MIN(y + bitmap->rows, surface->height);
297
298 const int rx = MAX(0, x);
299 const int ry = MAX(0, y);
300
301 int i, j, shift;
302 int item_stride = surface->item_stride;
303 int item_size = surface->format->BytesPerPixel;
304 unsigned char *src;
305 unsigned char *dst;
306 unsigned char *src_cpy;
307 unsigned char *dst_cpy;
308 FT_UInt32 val;
309 FT_Byte shade = fg_color->a;
310
311 /*
312 * Assumption, target buffer was filled with the background color before
313 * any rendering.
314 */
315
316 src = bitmap->buffer + (off_y * bitmap->pitch) + (off_x >> 3);
317 dst = ((unsigned char *)surface->buffer +
318 rx * surface->item_stride + ry * surface->pitch);
319
320 shift = off_x & 7;
321
322 if (item_size == 1) {
323 /* Slightly optimized loop for 1 byte target int */
324 for (j = ry; j < max_y; ++j) {
325 src_cpy = src;
326 dst_cpy = dst;
327 val = (FT_UInt32)(*src_cpy++ | 0x100) << shift;
328
329 for (i = rx; i < max_x; ++i, dst_cpy += item_stride) {
330 if (val & 0x10000) {
331 val = (FT_UInt32)(*src_cpy++ | 0x100);
332 }
333
334 if (val & 0x80) {
335 *dst_cpy = shade;
336 }
337
338 val <<= 1;
339 }
340
341 src += bitmap->pitch;
342 dst += surface->pitch;
343 }
344 }
345 else {
346 /* Generic copy for arbitrary target int size */
347 int b, int_offset = surface->format->Ashift / 8;
348
349 for (j = ry; j < max_y; ++j) {
350 src_cpy = src;
351 dst_cpy = dst;
352 val = (FT_UInt32)(*src_cpy++ | 0x100) << shift;
353
354 for (i = rx; i < max_x; ++i, dst_cpy += item_stride) {
355 for (b = 0; b < item_size; ++b) {
356 dst_cpy[b] = 0;
357 }
358
359 if (val & 0x10000) {
360 val = (FT_UInt32)(*src_cpy++ | 0x100);
361 }
362
363 if (val & 0x80) {
364 dst_cpy[int_offset] = shade;
365 }
366
367 val <<= 1;
368 }
369
370 src += bitmap->pitch;
371 dst += surface->pitch;
372 }
373 }
374 }
375
__fill_glyph_INT(FT_Fixed x,FT_Fixed y,FT_Fixed w,FT_Fixed h,FontSurface * surface,const FontColor * color)376 void __fill_glyph_INT(FT_Fixed x, FT_Fixed y, FT_Fixed w, FT_Fixed h,
377 FontSurface *surface, const FontColor *color)
378 {
379 int i, j;
380 FT_Byte *dst;
381 int itemsize = surface->format->BytesPerPixel;
382 int item_stride = surface->item_stride;
383 int byteoffset = surface->format->Ashift / 8;
384 FT_Byte *dst_cpy;
385 FT_Byte shade = color->a;
386 FT_Byte edge_shade;
387
388 x = MAX(0, x);
389 y = MAX(0, y);
390
391 if (x + w > INT_TO_FX6(surface->width)) {
392 w = INT_TO_FX6(surface->width) - x;
393 }
394 if (y + h > INT_TO_FX6(surface->height)) {
395 h = INT_TO_FX6(surface->height) - y;
396 }
397
398 dst = ((FT_Byte *)surface->buffer +
399 FX6_TRUNC(FX6_CEIL(x)) * itemsize +
400 FX6_TRUNC(FX6_CEIL(y)) * surface->pitch);
401
402 if (itemsize == 1) {
403 if (y < FX6_CEIL(y)) {
404 dst_cpy = dst - surface->pitch;
405 edge_shade = FX6_TRUNC(FX6_ROUND(shade * (FX6_CEIL(y) - y)));
406
407 for (i = 0;
408 i < FX6_TRUNC(FX6_CEIL(w));
409 ++i, dst_cpy += item_stride) {
410 *dst_cpy = edge_shade;
411 }
412 }
413
414 for (j = 0; j < FX6_TRUNC(FX6_FLOOR(h + y) - FX6_CEIL(y)); ++j) {
415 dst_cpy = dst;
416
417 for (i = 0;
418 i < FX6_TRUNC(FX6_CEIL(w));
419 ++i, dst_cpy += item_stride) {
420 *dst_cpy = shade;
421 }
422
423 dst += surface->pitch;
424 }
425
426 if (h > FX6_FLOOR(h + y) - y) {
427 dst_cpy = dst;
428 edge_shade = FX6_TRUNC(FX6_ROUND(shade *
429 (y + y - FX6_FLOOR(h + y))));
430 for (i = 0;
431 i < FX6_TRUNC(FX6_CEIL(w));
432 ++i, dst_cpy += item_stride) {
433 *dst_cpy = edge_shade;
434 }
435 }
436 }
437 else {
438 int b;
439
440 if (y < FX6_CEIL(y)) {
441 dst_cpy = dst - surface->pitch;
442 edge_shade = FX6_TRUNC(FX6_ROUND(shade * (FX6_CEIL(y) - y)));
443
444 for (i = 0;
445 i < FX6_TRUNC(FX6_CEIL(w));
446 ++i, dst_cpy += item_stride) {
447 for (b = 0; b < itemsize; ++b) {
448 dst_cpy[b] = 0;
449 }
450 dst_cpy[byteoffset] = edge_shade;
451 }
452 }
453
454 for (j = 0; j < FX6_TRUNC(FX6_FLOOR(h + y) - FX6_CEIL(y)); ++j) {
455 dst_cpy = dst;
456
457 for (i = 0;
458 i < FX6_TRUNC(FX6_CEIL(w));
459 ++i, dst_cpy += item_stride) {
460 for (b = 0; b < itemsize; ++b) {
461 dst_cpy[b] = 0;
462 }
463 dst_cpy[byteoffset] = shade;
464 }
465
466 dst += surface->pitch;
467 }
468
469 if (h > FX6_FLOOR(h + y) - y) {
470 dst_cpy = dst;
471 edge_shade = FX6_TRUNC(FX6_ROUND(shade *
472 (h + y - FX6_FLOOR(h + y))));
473 for (i = 0;
474 i < FX6_TRUNC(FX6_CEIL(w));
475 ++i, dst_cpy += item_stride) {
476 for (b = 0; b < itemsize; ++b) {
477 dst_cpy[b] = 0;
478 }
479 dst_cpy[byteoffset] = edge_shade;
480 }
481 }
482 }
483 }
484
485 #ifdef HAVE_PYGAME_SDL_VIDEO
486
487 #ifndef NDEBUG
488 #define POINTER_ASSERT_DECLARATIONS(s) \
489 const unsigned char *PA_bstart = ((unsigned char *)(s)->buffer);\
490 const unsigned char *PA_bend =\
491 (PA_bstart + (s)->height * (s)->pitch);
492 #define POINTER_ASSERT(p) \
493 assert((const unsigned char *)(p) >= PA_bstart);\
494 assert((const unsigned char *)(p) < PA_bend);
495 #else
496 #define POINTER_ASSERT_DECLARATIONS(s)
497 #define POINTER_ASSERT(p)
498 #endif
499
500 #define _CREATE_RGB_FILLER(_bpp, _getp, _setp, _blendp) \
501 void __fill_glyph_RGB##_bpp(FT_Fixed x, FT_Fixed y, \
502 FT_Fixed w, FT_Fixed h, \
503 FontSurface *surface, \
504 const FontColor *color) \
505 { \
506 FT_Fixed dh = 0; \
507 int i; \
508 unsigned char *dst; \
509 FT_UInt32 bgR, bgG, bgB, bgA; \
510 FT_Byte edge_a; \
511 POINTER_ASSERT_DECLARATIONS(surface) \
512 \
513 /* Crop the rectangle to the top and left of the \
514 * surface. \
515 */ \
516 x = MAX(0, x); \
517 y = MAX(0, y); \
518 \
519 /* Crop the rectangle to the bottom and right of \
520 * the surface. \
521 */ \
522 if (x + w > INT_TO_FX6(surface->width)) { \
523 w = INT_TO_FX6(surface->width) - x; \
524 } \
525 if (y + h > INT_TO_FX6(surface->height)) { \
526 h = INT_TO_FX6(surface->height) - y; \
527 } \
528 \
529 /* Start at the first pixel of the first row. \
530 */ \
531 dst = ((FT_Byte *)surface->buffer + \
532 FX6_TRUNC(FX6_CEIL(x)) * _bpp + \
533 FX6_TRUNC(FX6_CEIL(y)) * surface->pitch); \
534 \
535 /* Take care of the top row of the rectangle if the \
536 * rectangle starts within the pixels: y is not on \
537 * a pixel boundary. A special case is when the \
538 * bottom of the rectangle is also with the pixel \
539 * row. \
540 */ \
541 dh = FX6_CEIL(y) - y; \
542 if (dh > h) { \
543 dh = h; \
544 } \
545 h -= dh; \
546 if (dh > 0) { \
547 unsigned char *_dst = dst - surface->pitch; \
548 \
549 edge_a = FX6_TRUNC(FX6_ROUND(color->a * dh)); \
550 \
551 for (i = 0; \
552 i < FX6_TRUNC(FX6_CEIL(w)); \
553 ++i, _dst += _bpp) { \
554 FT_UInt32 pixel = (FT_UInt32)_getp; \
555 \
556 POINTER_ASSERT(_dst) \
557 \
558 if (_bpp == 1) { \
559 GET_PALETTE_VALS( \
560 pixel, surface->format, \
561 bgR, bgG, bgB, bgA); \
562 } \
563 else { \
564 GET_RGB_VALS( \
565 pixel, surface->format, \
566 bgR, bgG, bgB, bgA); \
567 \
568 } \
569 \
570 ALPHA_BLEND( \
571 color->r, color->g, color->b, \
572 edge_a, bgR, bgG, bgB, bgA); \
573 \
574 _blendp; \
575 } \
576 \
577 y += dh; \
578 } \
579 \
580 /* Fill in all entirely covered rows. These are \
581 * pixels which are entirely within the upper and \
582 * lower edges of the rectangle. \
583 */ \
584 dh = FX6_FLOOR(h); \
585 h -= dh; \
586 while (dh > 0) { \
587 unsigned char *_dst = dst; \
588 \
589 for (i = 0; \
590 i < FX6_TRUNC(FX6_CEIL(w)); \
591 ++i, _dst += _bpp) { \
592 FT_UInt32 pixel = (FT_UInt32)_getp; \
593 \
594 POINTER_ASSERT(_dst) \
595 \
596 if (_bpp == 1) { \
597 GET_PALETTE_VALS( \
598 pixel, surface->format, \
599 bgR, bgG, bgB, bgA); \
600 } \
601 else { \
602 GET_RGB_VALS( \
603 pixel, surface->format, \
604 bgR, bgG, bgB, bgA); \
605 \
606 } \
607 \
608 ALPHA_BLEND( \
609 color->r, color->g, color->b, \
610 color->a, bgR, bgG, bgB, bgA); \
611 \
612 _blendp; \
613 } \
614 \
615 dst += surface->pitch; \
616 dh -= FX6_ONE; \
617 y += FX6_ONE; \
618 } \
619 \
620 /* Fill in the bottom row of pixels if these pixels \
621 * are only partially covered: the rectangle bottom \
622 * is not on a pixel boundary. Otherwise, done. \
623 */ \
624 if (h > 0) { \
625 unsigned char *_dst = dst; \
626 edge_a = FX6_TRUNC(FX6_ROUND(color->a * h)); \
627 \
628 for (i = 0; \
629 i < FX6_TRUNC(FX6_CEIL(w)); \
630 ++i, _dst += _bpp) { \
631 FT_UInt32 pixel = (FT_UInt32)_getp; \
632 \
633 POINTER_ASSERT(_dst) \
634 \
635 if (_bpp == 1) { \
636 GET_PALETTE_VALS( \
637 pixel, surface->format, \
638 bgR, bgG, bgB, bgA); \
639 } \
640 else { \
641 GET_RGB_VALS( \
642 pixel, surface->format, \
643 bgR, bgG, bgB, bgA); \
644 \
645 } \
646 \
647 ALPHA_BLEND( \
648 color->r, color->g, color->b, \
649 edge_a, bgR, bgG, bgB, bgA); \
650 \
651 _blendp; \
652 } \
653 } \
654 }
655
656
657 #define __MONO_RENDER_INNER_LOOP(_bpp, _code) \
658 for (j = ry; j < max_y; ++j) \
659 { \
660 const unsigned char* _src = src; \
661 unsigned char* _dst = dst; \
662 FT_UInt32 val = \
663 (FT_UInt32)(*_src++ | 0x100) << shift; \
664 \
665 for (i = rx; i < max_x; ++i, _dst += _bpp) { \
666 if (val & 0x10000) { \
667 val = (FT_UInt32)(*_src++ | 0x100); \
668 } \
669 if (val & 0x80) { \
670 _code; \
671 } \
672 val <<= 1; \
673 } \
674 \
675 src += bitmap->pitch; \
676 dst += surface->pitch; \
677 } \
678
679 #define _CREATE_MONO_RENDER(_bpp, _getp, _setp, _blendp) \
680 void __render_glyph_MONO##_bpp(int x, int y, \
681 FontSurface *surface, \
682 const FT_Bitmap *bitmap, \
683 const FontColor *color) \
684 { \
685 const int off_x = (x < 0) ? -x : 0; \
686 const int off_y = (y < 0) ? -y : 0; \
687 \
688 const int max_x = \
689 MIN(x + bitmap->width, surface->width); \
690 const int max_y = \
691 MIN(y + bitmap->rows, surface->height); \
692 \
693 const int rx = MAX(0, x); \
694 const int ry = MAX(0, y); \
695 \
696 int i, j, shift; \
697 const unsigned char* src; \
698 unsigned char* dst; \
699 FT_UInt32 full_color; \
700 FT_UInt32 bgR, bgG, bgB, bgA; \
701 \
702 src = bitmap->buffer + (off_y * bitmap->pitch) + (off_x >> 3); \
703 dst = (unsigned char *)surface->buffer + (rx * _bpp) + \
704 (ry * surface->pitch); \
705 \
706 full_color = SDL_MapRGBA(surface->format, (FT_Byte)color->r, \
707 (FT_Byte)color->g, (FT_Byte)color->b, 255); \
708 \
709 shift = off_x & 7; \
710 \
711 if (color->a == 0xFF) { \
712 __MONO_RENDER_INNER_LOOP(_bpp, \
713 { \
714 _setp; \
715 }); \
716 } \
717 else if (color->a > 0) { \
718 __MONO_RENDER_INNER_LOOP(_bpp, \
719 { \
720 FT_UInt32 pixel = (FT_UInt32)_getp; \
721 \
722 if (_bpp == 1) { \
723 GET_PALETTE_VALS( \
724 pixel, surface->format, \
725 bgR, bgG, bgB, bgA); \
726 } \
727 else { \
728 GET_RGB_VALS( \
729 pixel, surface->format, \
730 bgR, bgG, bgB, bgA); \
731 \
732 } \
733 \
734 ALPHA_BLEND( \
735 color->r, color->g, color->b, color->a, \
736 bgR, bgG, bgB, bgA); \
737 \
738 _blendp; \
739 }); \
740 } \
741 }
742
743 #define _CREATE_RGB_RENDER(_bpp, _getp, _setp, _blendp) \
744 void __render_glyph_RGB##_bpp(int x, int y, FontSurface *surface, \
745 const FT_Bitmap *bitmap, \
746 const FontColor *color) \
747 { \
748 const int off_x = (x < 0) ? -x : 0; \
749 const int off_y = (y < 0) ? -y : 0; \
750 \
751 const int max_x = MIN(x + bitmap->width, surface->width); \
752 const int max_y = MIN(y + bitmap->rows, surface->height); \
753 \
754 const int rx = MAX(0, x); \
755 const int ry = MAX(0, y); \
756 \
757 FT_Byte *dst = ((FT_Byte*)surface->buffer) + (rx * _bpp) + \
758 (ry * surface->pitch); \
759 FT_Byte *_dst; \
760 \
761 const FT_Byte *src = bitmap->buffer + off_x + \
762 (off_y * bitmap->pitch); \
763 const FT_Byte *_src; \
764 \
765 _DECLARE_full_color##_bpp(surface, color) \
766 /* \
767 const FT_UInt32 full_color = \
768 SDL_MapRGBA(surface->format, (FT_Byte)color->r, \
769 (FT_Byte)color->g, (FT_Byte)color->b, 255); \
770 */ \
771 \
772 FT_UInt32 bgR, bgG, bgB, bgA; \
773 int j, i; \
774 \
775 for (j = ry; j < max_y; ++j) { \
776 _src = src; \
777 _dst = dst; \
778 \
779 for (i = rx; i < max_x; ++i, _dst += _bpp) { \
780 FT_UInt32 alpha = (*_src++); \
781 alpha = (alpha * color->a) / 255; \
782 \
783 if (alpha == 0xFF) { \
784 _setp; \
785 } \
786 else if (alpha > 0) { \
787 FT_UInt32 pixel = (FT_UInt32)_getp; \
788 \
789 if (_bpp == 1) { \
790 GET_PALETTE_VALS( \
791 pixel, surface->format, \
792 bgR, bgG, bgB, bgA); \
793 } \
794 else { \
795 GET_RGB_VALS( \
796 pixel, surface->format, \
797 bgR, bgG, bgB, bgA); \
798 \
799 } \
800 \
801 ALPHA_BLEND( \
802 color->r, color->g, color->b, alpha, \
803 bgR, bgG, bgB, bgA); \
804 \
805 _blendp; \
806 } \
807 } \
808 \
809 dst += surface->pitch; \
810 src += bitmap->pitch; \
811 } \
812 }
813
814 /* These macros removes a gcc unused variable warning for __render_glyph_RGB3 */
815 #define _DECLARE_full_color(s, c) const FT_UInt32 full_color = \
816 SDL_MapRGBA((s)->format, (FT_Byte)(c)->r, (FT_Byte)(c)->g, \
817 (FT_Byte)(c)->b, 255);
818 #define _DECLARE_full_color1(s, c) _DECLARE_full_color(s, c)
819 #define _DECLARE_full_color2(s, c) _DECLARE_full_color(s, c)
820 #define _DECLARE_full_color3(s, c)
821 #define _DECLARE_full_color4(s, c) _DECLARE_full_color(s, c)
822
823
824 #define _SET_PIXEL_24 \
825 SET_PIXEL24_RGB(_dst, surface->format, color->r, color->g, color->b);
826
827 #define _BLEND_PIXEL_24 \
828 SET_PIXEL24_RGB(_dst, surface->format, bgR, bgG, bgB);
829
830 #define _SET_PIXEL(T) \
831 *(T*)_dst = (T)full_color;
832
833 #define _BLEND_PIXEL(T) *((T*)_dst) = (T)( \
834 ((bgR >> surface->format->Rloss) << surface->format->Rshift) | \
835 ((bgG >> surface->format->Gloss) << surface->format->Gshift) | \
836 ((bgB >> surface->format->Bloss) << surface->format->Bshift) | \
837 ((bgA >> surface->format->Aloss) << surface->format->Ashift & \
838 surface->format->Amask) )
839
840 #define _BLEND_PIXEL_GENERIC(T) *(T*)_dst = (T)( \
841 SDL_MapRGB(surface->format, \
842 (FT_Byte)bgR, (FT_Byte)bgG, (FT_Byte)bgB) )
843
844 #define _GET_PIXEL(T) (*((T*)_dst))
845
846 _CREATE_RGB_RENDER(4, _GET_PIXEL(FT_UInt32), _SET_PIXEL(FT_UInt32), _BLEND_PIXEL(FT_UInt32))
847 _CREATE_RGB_RENDER(3, GET_PIXEL24(_dst), _SET_PIXEL_24, _BLEND_PIXEL_24)
848 _CREATE_RGB_RENDER(2, _GET_PIXEL(FT_UInt16), _SET_PIXEL(FT_UInt16), _BLEND_PIXEL(FT_UInt16))
849 _CREATE_RGB_RENDER(1, _GET_PIXEL(FT_Byte), _SET_PIXEL(FT_Byte), _BLEND_PIXEL_GENERIC(FT_Byte))
850
851 _CREATE_MONO_RENDER(4, _GET_PIXEL(FT_UInt32), _SET_PIXEL(FT_UInt32), _BLEND_PIXEL(FT_UInt32))
852 _CREATE_MONO_RENDER(3, GET_PIXEL24(_dst), _SET_PIXEL_24, _BLEND_PIXEL_24)
853 _CREATE_MONO_RENDER(2, _GET_PIXEL(FT_UInt16), _SET_PIXEL(FT_UInt16), _BLEND_PIXEL(FT_UInt16))
854 _CREATE_MONO_RENDER(1, _GET_PIXEL(FT_Byte), _SET_PIXEL(FT_Byte), _BLEND_PIXEL_GENERIC(FT_Byte))
855
856 _CREATE_RGB_FILLER(4, _GET_PIXEL(FT_UInt32), _SET_PIXEL(FT_UInt32), _BLEND_PIXEL(FT_UInt32))
857 _CREATE_RGB_FILLER(3, GET_PIXEL24(_dst), _SET_PIXEL_24, _BLEND_PIXEL_24)
858 _CREATE_RGB_FILLER(2, _GET_PIXEL(FT_UInt16), _SET_PIXEL(FT_UInt16), _BLEND_PIXEL(FT_UInt16))
859 _CREATE_RGB_FILLER(1, _GET_PIXEL(FT_Byte), _SET_PIXEL(FT_Byte), _BLEND_PIXEL_GENERIC(FT_Byte))
860 #endif
861