13 |
13 |
14 #include "../table/sprites.h" |
14 #include "../table/sprites.h" |
15 |
15 |
16 static FBlitter_32bppAnim iFBlitter_32bppAnim; |
16 static FBlitter_32bppAnim iFBlitter_32bppAnim; |
17 |
17 |
|
18 template <BlitterMode mode> |
|
19 inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) |
|
20 { |
|
21 const SpriteData *src = (const SpriteData *)bp->sprite; |
|
22 |
|
23 const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); |
|
24 const uint8 *src_n = (const uint8 *)(src->data + src->offset[zoom][1]); |
|
25 |
|
26 for (uint i = bp->skip_top; i != 0; i--) { |
|
27 src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); |
|
28 src_n += *(const uint32 *)src_n; |
|
29 } |
|
30 |
|
31 uint32 *dst = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left; |
|
32 uint8 *anim = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left; |
|
33 |
|
34 const byte *remap = bp->remap; // store so we don't have to access it via bp everytime |
|
35 |
|
36 for (int y = 0; y < bp->height; y++) { |
|
37 uint32 *dst_ln = dst + bp->pitch; |
|
38 uint8 *anim_ln = anim + this->anim_buf_width; |
|
39 |
|
40 const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); |
|
41 src_px++; |
|
42 |
|
43 const uint8 *src_n_ln = src_n + *(uint32 *)src_n; |
|
44 src_n += 4; |
|
45 |
|
46 uint32 *dst_end = dst + bp->skip_left; |
|
47 |
|
48 uint n; |
|
49 |
|
50 while (dst < dst_end) { |
|
51 n = *src_n++; |
|
52 |
|
53 if (src_px->a == 0) { |
|
54 dst += n; |
|
55 src_px ++; |
|
56 src_n++; |
|
57 |
|
58 if (dst > dst_end) anim += dst - dst_end; |
|
59 } else { |
|
60 if (dst + n > dst_end) { |
|
61 uint d = dst_end - dst; |
|
62 src_px += d; |
|
63 src_n += d; |
|
64 |
|
65 dst = dst_end - bp->skip_left; |
|
66 dst_end = dst + bp->width; |
|
67 |
|
68 n = min<uint>(n - d, (uint)bp->width); |
|
69 goto draw; |
|
70 } |
|
71 dst += n; |
|
72 src_px += n; |
|
73 src_n += n; |
|
74 } |
|
75 } |
|
76 |
|
77 dst -= bp->skip_left; |
|
78 dst_end -= bp->skip_left; |
|
79 |
|
80 dst_end += bp->width; |
|
81 |
|
82 while (dst < dst_end) { |
|
83 n = min<uint>(*src_n++, (uint)(dst_end - dst)); |
|
84 |
|
85 if (src_px->a == 0) { |
|
86 anim += n; |
|
87 dst += n; |
|
88 src_px++; |
|
89 src_n++; |
|
90 continue; |
|
91 } |
|
92 |
|
93 draw:; |
|
94 |
|
95 switch (mode) { |
|
96 case BM_COLOUR_REMAP: |
|
97 if (src_px->a == 255) { |
|
98 do { |
|
99 uint m = *src_n; |
|
100 /* In case the m-channel is zero, do not remap this pixel in any way */ |
|
101 if (m == 0) { |
|
102 *dst = *src_px; |
|
103 *anim = 0; |
|
104 } else { |
|
105 uint r = remap[m]; |
|
106 *anim = r; |
|
107 if (r != 0) *dst = this->LookupColourInPalette(r); |
|
108 } |
|
109 anim++; |
|
110 dst++; |
|
111 src_px++; |
|
112 src_n++; |
|
113 } while (--n != 0); |
|
114 } else { |
|
115 do { |
|
116 uint m = *src_n; |
|
117 if (m == 0) { |
|
118 *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); |
|
119 *anim = 0; |
|
120 } else { |
|
121 uint r = remap[m]; |
|
122 *anim = r; |
|
123 if (r != 0) *dst = ComposeColourPANoCheck(this->LookupColourInPalette(r), src_px->a, *dst); |
|
124 } |
|
125 anim++; |
|
126 dst++; |
|
127 src_px++; |
|
128 src_n++; |
|
129 } while (--n != 0); |
|
130 } |
|
131 break; |
|
132 |
|
133 case BM_TRANSPARENT: |
|
134 /* TODO -- We make an assumption here that the remap in fact is transparency, not some color. |
|
135 * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: |
|
136 * we produce a result the newgrf maker didn't expect ;) */ |
|
137 |
|
138 /* Make the current color a bit more black, so it looks like this image is transparent */ |
|
139 src_px += n; |
|
140 src_n += n; |
|
141 |
|
142 do { |
|
143 *dst = MakeTransparent(*dst, 192); |
|
144 *anim = remap[*anim]; |
|
145 anim++; |
|
146 dst++; |
|
147 } while (--n != 0); |
|
148 break; |
|
149 |
|
150 default: |
|
151 if (src_px->a == 255) { |
|
152 do { |
|
153 /* Compiler assumes pointer aliasing, can't optimise this on its own */ |
|
154 uint m = *src_n++; |
|
155 /* Above 217 is palette animation */ |
|
156 *anim++ = m; |
|
157 *dst++ = (m >= 217) ? this->LookupColourInPalette(m) : *src_px; |
|
158 src_px++; |
|
159 } while (--n != 0); |
|
160 } else { |
|
161 do { |
|
162 uint m = *src_n++; |
|
163 *anim++ = m; |
|
164 if (m >= 217) { |
|
165 *dst = ComposeColourPANoCheck(this->LookupColourInPalette(m), src_px->a, *dst); |
|
166 } else { |
|
167 *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); |
|
168 } |
|
169 dst++; |
|
170 src_px++; |
|
171 } while (--n != 0); |
|
172 } |
|
173 break; |
|
174 } |
|
175 } |
|
176 |
|
177 anim = anim_ln; |
|
178 dst = dst_ln; |
|
179 src_px = src_px_ln; |
|
180 src_n = src_n_ln; |
|
181 } |
|
182 } |
|
183 |
18 void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) |
184 void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) |
19 { |
185 { |
20 if (_screen_disable_anim) { |
186 if (_screen_disable_anim) { |
21 /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent Draw() */ |
187 /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent Draw() */ |
22 Blitter_32bppOptimized::Draw(bp, mode, zoom); |
188 Blitter_32bppOptimized::Draw(bp, mode, zoom); |
23 return; |
189 return; |
24 } |
190 } |
25 |
|
26 const SpriteLoader::CommonPixel *src, *src_line; |
|
27 uint32 *dst, *dst_line; |
|
28 uint8 *anim, *anim_line; |
|
29 |
191 |
30 if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) { |
192 if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) { |
31 /* The size of the screen changed; we can assume we can wipe all data from our buffer */ |
193 /* The size of the screen changed; we can assume we can wipe all data from our buffer */ |
32 free(this->anim_buf); |
194 free(this->anim_buf); |
33 this->anim_buf = CallocT<uint8>(_screen.width * _screen.height); |
195 this->anim_buf = CallocT<uint8>(_screen.width * _screen.height); |
34 this->anim_buf_width = _screen.width; |
196 this->anim_buf_width = _screen.width; |
35 this->anim_buf_height = _screen.height; |
197 this->anim_buf_height = _screen.height; |
36 } |
198 } |
37 |
199 |
38 /* Find where to start reading in the source sprite */ |
200 switch (mode) { |
39 src_line = (const SpriteLoader::CommonPixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); |
201 default: NOT_REACHED(); |
40 dst_line = (uint32 *)bp->dst + bp->top * bp->pitch + bp->left; |
202 case BM_NORMAL: Draw<BM_NORMAL> (bp, zoom); return; |
41 anim_line = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left; |
203 case BM_COLOUR_REMAP: Draw<BM_COLOUR_REMAP>(bp, zoom); return; |
42 |
204 case BM_TRANSPARENT: Draw<BM_TRANSPARENT> (bp, zoom); return; |
43 for (int y = 0; y < bp->height; y++) { |
|
44 dst = dst_line; |
|
45 dst_line += bp->pitch; |
|
46 |
|
47 src = src_line; |
|
48 src_line += bp->sprite_width * ScaleByZoom(1, zoom); |
|
49 |
|
50 anim = anim_line; |
|
51 anim_line += this->anim_buf_width; |
|
52 |
|
53 for (int x = 0; x < bp->width; x++) { |
|
54 if (src->a == 0) { |
|
55 /* src->r is 'misused' here to indicate how much more pixels are following with an alpha of 0 */ |
|
56 int skip = UnScaleByZoom(src->r, zoom); |
|
57 |
|
58 dst += skip; |
|
59 anim += skip; |
|
60 x += skip - 1; |
|
61 src += ScaleByZoom(1, zoom) * skip; |
|
62 continue; |
|
63 } |
|
64 |
|
65 switch (mode) { |
|
66 case BM_COLOUR_REMAP: |
|
67 /* In case the m-channel is zero, do not remap this pixel in any way */ |
|
68 if (src->m == 0) { |
|
69 *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst); |
|
70 *anim = 0; |
|
71 } else { |
|
72 if (bp->remap[src->m] != 0) { |
|
73 *dst = ComposeColourPA(this->LookupColourInPalette(bp->remap[src->m]), src->a, *dst); |
|
74 *anim = bp->remap[src->m]; |
|
75 } |
|
76 } |
|
77 break; |
|
78 |
|
79 case BM_TRANSPARENT: |
|
80 /* TODO -- We make an assumption here that the remap in fact is transparency, not some color. |
|
81 * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: |
|
82 * we produce a result the newgrf maker didn't expect ;) */ |
|
83 |
|
84 /* Make the current color a bit more black, so it looks like this image is transparent */ |
|
85 *dst = MakeTransparent(*dst, 192); |
|
86 *anim = bp->remap[*anim]; |
|
87 break; |
|
88 |
|
89 default: |
|
90 /* Above 217 is palette animation */ |
|
91 if (src->m >= 217) *dst = ComposeColourPA(this->LookupColourInPalette(src->m), src->a, *dst); |
|
92 else *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst); |
|
93 *anim = src->m; |
|
94 break; |
|
95 } |
|
96 dst++; |
|
97 anim++; |
|
98 src += ScaleByZoom(1, zoom); |
|
99 } |
|
100 } |
205 } |
101 } |
206 } |
102 |
207 |
103 void Blitter_32bppAnim::DrawColorMappingRect(void *dst, int width, int height, int pal) |
208 void Blitter_32bppAnim::DrawColorMappingRect(void *dst, int width, int height, int pal) |
104 { |
209 { |