4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file 8bpp_optimized.cpp Implementation of the optimized 8 bpp blitter. */
12 #include "../stdafx.h"
13 #include "../zoom_func.h"
14 #include "../settings_type.h"
15 #include "../core/math_func.hpp"
16 #include "../core/mem_func.hpp"
17 #include "8bpp_optimized.hpp"
19 #include "../safeguards.h"
21 /** Instantiation of the 8bpp optimised blitter factory. */
22 static FBlitter_8bppOptimized iFBlitter_8bppOptimized
;
24 void Blitter_8bppOptimized::Draw(Blitter::BlitterParams
*bp
, BlitterMode mode
, ZoomLevel zoom
)
26 /* Find the offset of this zoom-level */
27 const SpriteData
*sprite_src
= (const SpriteData
*)bp
->sprite
;
28 uint offset
= sprite_src
->offset
[zoom
];
30 /* Find where to start reading in the source sprite */
31 const uint8
*src
= sprite_src
->data
+ offset
;
32 uint8
*dst_line
= (uint8
*)bp
->dst
+ bp
->top
* bp
->pitch
+ bp
->left
;
34 /* Skip over the top lines in the source image */
35 for (int y
= 0; y
< bp
->skip_top
; y
++) {
39 if (trans
== 0 && pixels
== 0) break;
44 const uint8
*src_next
= src
;
46 for (int y
= 0; y
< bp
->height
; y
++) {
47 uint8
*dst
= dst_line
;
48 dst_line
+= bp
->pitch
;
50 uint skip_left
= bp
->skip_left
;
51 int width
= bp
->width
;
57 src_next
= src
+ pixels
;
58 if (trans
== 0 && pixels
== 0) break;
59 if (width
<= 0) continue;
62 if (skip_left
< trans
) {
69 if (skip_left
< pixels
) {
79 if (skip_left
!= 0) continue;
81 /* Skip transparent pixels */
84 if (width
<= 0 || pixels
== 0) continue;
85 pixels
= min
<uint
>(pixels
, (uint
)width
);
90 case BM_CRASH_REMAP
: {
91 const uint8
*remap
= bp
->remap
;
96 } while (--pixels
!= 0);
101 MemSetT(dst
, 0, pixels
);
105 case BM_TRANSPARENT
: {
106 const uint8
*remap
= bp
->remap
;
111 } while (--pixels
!= 0);
116 MemCpyT(dst
, src
, pixels
);
117 dst
+= pixels
; src
+= pixels
;
124 Sprite
*Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite
*sprite
, AllocatorProc
*allocator
)
126 /* Make memory for all zoom-levels */
127 uint memory
= sizeof(SpriteData
);
132 if (sprite
->type
== ST_FONT
) {
133 zoom_min
= ZOOM_LVL_NORMAL
;
134 zoom_max
= ZOOM_LVL_NORMAL
;
136 zoom_min
= _settings_client
.gui
.zoom_min
;
137 zoom_max
= (ZoomLevel
)min(_settings_client
.gui
.zoom_max
, ZOOM_LVL_DRAW_SPR
);
138 if (zoom_max
== zoom_min
) zoom_max
= ZOOM_LVL_DRAW_SPR
;
141 for (ZoomLevel i
= zoom_min
; i
<= zoom_max
; i
++) {
142 memory
+= sprite
[i
].width
* sprite
[i
].height
;
145 /* We have no idea how much memory we really need, so just guess something */
148 /* Don't allocate memory each time, but just keep some
149 * memory around as this function is called quite often
150 * and the memory usage is quite low. */
151 static ReusableBuffer
<byte
> temp_buffer
;
152 SpriteData
*temp_dst
= (SpriteData
*)temp_buffer
.Allocate(memory
);
153 memset(temp_dst
, 0, sizeof(*temp_dst
));
154 byte
*dst
= temp_dst
->data
;
156 /* Make the sprites per zoom-level */
157 for (ZoomLevel i
= zoom_min
; i
<= zoom_max
; i
++) {
158 /* Store the index table */
159 uint offset
= dst
- temp_dst
->data
;
160 temp_dst
->offset
[i
] = offset
;
162 /* cache values, because compiler can't cache it */
163 int scaled_height
= sprite
[i
].height
;
164 int scaled_width
= sprite
[i
].width
;
166 for (int y
= 0; y
< scaled_height
; y
++) {
169 uint last_colour
= 0;
170 byte
*count_dst
= nullptr;
172 /* Store the scaled image */
173 const SpriteLoader::CommonPixel
*src
= &sprite
[i
].data
[y
* sprite
[i
].width
];
175 for (int x
= 0; x
< scaled_width
; x
++) {
176 uint colour
= src
++->m
;
178 if (last_colour
== 0 || colour
== 0 || pixels
== 255) {
179 if (count_dst
!= nullptr) {
180 /* Write how many non-transparent bytes we get */
185 /* As long as we find transparency bytes, keep counting */
186 if (colour
== 0 && trans
!= 255) {
191 /* No longer transparency, so write the amount of transparent bytes */
195 /* Reserve a byte for the pixel counter */
199 last_colour
= colour
;
209 if (count_dst
!= nullptr) *count_dst
= pixels
;
211 /* Write line-ending */
217 uint size
= dst
- (byte
*)temp_dst
;
219 /* Safety check, to make sure we guessed the size correctly */
220 assert(size
< memory
);
222 /* Allocate the exact amount of memory we need */
223 Sprite
*dest_sprite
= (Sprite
*)allocator(sizeof(*dest_sprite
) + size
);
225 dest_sprite
->height
= sprite
->height
;
226 dest_sprite
->width
= sprite
->width
;
227 dest_sprite
->x_offs
= sprite
->x_offs
;
228 dest_sprite
->y_offs
= sprite
->y_offs
;
229 memcpy(dest_sprite
->data
, temp_dst
, size
);