Commit | Line | Data |
---|---|---|
9c106321 TC |
1 | /* |
2 | Render utilities | |
3 | */ | |
4 | #include "imager.h" | |
5 | ||
6 | #define RENDER_MAGIC 0x765AE | |
7 | ||
8 | typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *src, i_color const *color); | |
9 | ||
10 | #code | |
11 | ||
12 | static void IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color); | |
13 | static void IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color); | |
14 | ||
15 | static render_color_f IM_SUFFIX(render_color_tab)[] = | |
16 | { | |
17 | NULL, | |
18 | IM_SUFFIX(render_color_13), | |
19 | IM_SUFFIX(render_color_alpha), | |
20 | IM_SUFFIX(render_color_13), | |
21 | IM_SUFFIX(render_color_alpha), | |
22 | }; | |
23 | ||
24 | #/code | |
25 | ||
26 | void | |
27 | i_render_init(i_render *r, i_img *im, int width) { | |
28 | r->magic = RENDER_MAGIC; | |
29 | r->im = im; | |
30 | r->width = width; | |
31 | r->line_8 = NULL; | |
32 | r->line_double = NULL; | |
33 | #code im->bits <= 8 | |
34 | r->IM_SUFFIX(line) = mymalloc(sizeof(i_fcolor) * width); | |
35 | #/code | |
36 | } | |
37 | ||
38 | void | |
39 | i_render_done(i_render *r) { | |
40 | if (r->line_8) | |
41 | myfree(r->line_8); | |
42 | else | |
43 | myfree(r->line_double); | |
44 | r->magic = 0; | |
45 | } | |
46 | ||
47 | void | |
48 | i_render_color(i_render *r, int x, int y, int width, unsigned char const *src, | |
49 | i_color const *color) { | |
50 | i_img *im = r->im; | |
51 | if (y < 0 || y >= im->ysize) | |
52 | return; | |
53 | if (x < 0) { | |
54 | width += x; | |
55 | src -= x; | |
56 | x = 0; | |
57 | } | |
58 | if (x + width > im->xsize) { | |
59 | width = im->xsize - x; | |
60 | } | |
61 | if (x >= im->xsize || x + width <= 0 || width <= 0) | |
62 | return; | |
63 | ||
64 | /* avoid as much work as we can */ | |
65 | while (width > 0 && *src == 0) { | |
66 | --width; | |
67 | ++src; | |
68 | ++x; | |
69 | } | |
70 | while (width > 0 && src[width-1] == 0) { | |
71 | --width; | |
72 | } | |
73 | if (!width) | |
74 | return; | |
75 | ||
76 | /* make sure our line buffer is big enough */ | |
77 | if (width > r->width) { | |
78 | int new_width = r->width * 2; | |
79 | if (new_width < width) | |
80 | new_width = width; | |
81 | ||
82 | if (r->line_8) | |
83 | r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width); | |
84 | else | |
85 | r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width); | |
86 | } | |
87 | ||
88 | #code r->im->bits <= 8 | |
89 | (IM_SUFFIX(render_color_tab)[im->channels])(r, x, y, width, src, color); | |
90 | #/code | |
91 | } | |
92 | ||
93 | static void | |
94 | dump_src(const char *note, unsigned char const *src, int width) { | |
95 | int i; | |
96 | printf("%s - %p/%d\n", note, src, width); | |
97 | for (i = 0; i < width; ++i) { | |
98 | printf("%02x ", src[i]); | |
99 | } | |
100 | putchar('\n'); | |
101 | } | |
102 | ||
103 | #code | |
104 | ||
105 | static | |
106 | void | |
107 | IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, | |
108 | unsigned char const *src, i_color const *color) { | |
109 | i_img *im = r->im; | |
110 | IM_COLOR *linep = r->IM_SUFFIX(line); | |
111 | int ch, channels = im->channels; | |
112 | int fetch_offset; | |
113 | #undef STORE_COLOR | |
114 | #ifdef IM_EIGHT_BIT | |
115 | #define STORE_COLOR (*color) | |
116 | #else | |
117 | i_fcolor fcolor; | |
118 | ||
119 | for (ch = 0; ch < channels; ++ch) { | |
120 | fcolor.channel[ch] = color->channel[ch] / 255.0; | |
121 | } | |
122 | #define STORE_COLOR fcolor | |
123 | #endif | |
124 | ||
125 | fetch_offset = 0; | |
126 | while (fetch_offset < width && *src == 0xFF) { | |
127 | *linep++ = STORE_COLOR; | |
128 | ++src; | |
129 | ++fetch_offset; | |
130 | } | |
131 | IM_GLIN(im, x+fetch_offset, x+width, y, linep); | |
132 | while (fetch_offset < width) { | |
133 | #ifdef IM_EIGHT_BIT | |
134 | IM_WORK_T alpha = *src++; | |
135 | #else | |
136 | IM_WORK_T alpha = *src++ / 255.0; | |
137 | #endif | |
138 | if (alpha == IM_SAMPLE_MAX) | |
139 | *linep = STORE_COLOR; | |
140 | else if (alpha) { | |
141 | for (ch = 0; ch < channels; ++ch) { | |
142 | linep->channel[ch] = (linep->channel[ch] * (IM_SAMPLE_MAX - alpha) | |
143 | + STORE_COLOR.channel[ch] * alpha) / IM_SAMPLE_MAX; | |
144 | } | |
145 | } | |
146 | ++linep; | |
147 | ++fetch_offset; | |
148 | } | |
149 | IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line)); | |
150 | } | |
151 | ||
152 | static | |
153 | void | |
154 | IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, | |
155 | unsigned char const *src, i_color const *color) { | |
156 | IM_COLOR *linep = r->IM_SUFFIX(line); | |
157 | int ch; | |
158 | int alpha_channel = r->im->channels - 1; | |
159 | int fetch_offset; | |
160 | #undef STORE_COLOR | |
161 | #ifdef IM_EIGHT_BIT | |
162 | #define STORE_COLOR (*color) | |
163 | #else | |
164 | i_fcolor fcolor; | |
165 | ||
166 | for (ch = 0; ch < r->im->channels; ++ch) { | |
167 | fcolor.channel[ch] = color->channel[ch] / 255.0; | |
168 | } | |
169 | #define STORE_COLOR fcolor | |
170 | #endif | |
171 | ||
172 | fetch_offset = 0; | |
173 | while (fetch_offset < width && *src == 0xFF) { | |
174 | *linep++ = STORE_COLOR; | |
175 | ++src; | |
176 | ++fetch_offset; | |
177 | } | |
178 | IM_GLIN(r->im, x+fetch_offset, x+width, y, linep); | |
179 | while (fetch_offset < width) { | |
180 | #ifdef IM_EIGHT_BIT | |
181 | IM_WORK_T src_alpha = *src++; | |
182 | #else | |
183 | IM_WORK_T src_alpha = *src++ / 255.0; | |
184 | #endif | |
185 | if (src_alpha == IM_SAMPLE_MAX) | |
186 | *linep = STORE_COLOR; | |
187 | else if (src_alpha) { | |
188 | IM_WORK_T remains = - src_alpha; | |
189 | IM_WORK_T orig_alpha = linep->channel[alpha_channel]; | |
190 | IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX; | |
191 | for (ch = 0; ch < alpha_channel; ++ch) { | |
192 | linep->channel[ch] = ( src_alpha * STORE_COLOR.channel[ch] | |
193 | + remains * linep->channel[ch] * orig_alpha / IM_SAMPLE_MAX | |
194 | ) / dest_alpha; | |
195 | } | |
196 | linep->channel[alpha_channel] = dest_alpha; | |
197 | } | |
198 | ++linep; | |
199 | ++fetch_offset; | |
200 | } | |
201 | IM_PLIN(r->im, x, x+width, y, r->IM_SUFFIX(line)); | |
202 | } | |
203 | ||
204 | #/code |