2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file 8bpp_optimized.cpp Implementation of the optimized 8 bpp blitter. */
10 #include "../stdafx.h"
11 #include "../zoom_func.h"
12 #include "../settings_type.h"
13 #include "../core/math_func.hpp"
14 #include "../core/mem_func.hpp"
15 #include "8bpp_optimized.hpp"
17 #include "../safeguards.h"
19 /** Instantiation of the 8bpp optimised blitter factory. */
20 static FBlitter_8bppOptimized iFBlitter_8bppOptimized
;
22 void Blitter_8bppOptimized::Draw(Blitter::BlitterParams
*bp
, BlitterMode mode
, ZoomLevel zoom
)
24 /* Find the offset of this zoom-level */
25 const SpriteData
*sprite_src
= (const SpriteData
*)bp
->sprite
;
26 uint offset
= sprite_src
->offset
[zoom
];
28 /* Find where to start reading in the source sprite */
29 const uint8
*src
= sprite_src
->data
+ offset
;
30 uint8
*dst_line
= (uint8
*)bp
->dst
+ bp
->top
* bp
->pitch
+ bp
->left
;
32 /* Skip over the top lines in the source image */
33 for (int y
= 0; y
< bp
->skip_top
; y
++) {
37 if (trans
== 0 && pixels
== 0) break;
42 const uint8
*src_next
= src
;
44 for (int y
= 0; y
< bp
->height
; y
++) {
45 uint8
*dst
= dst_line
;
46 dst_line
+= bp
->pitch
;
48 uint skip_left
= bp
->skip_left
;
49 int width
= bp
->width
;
55 src_next
= src
+ pixels
;
56 if (trans
== 0 && pixels
== 0) break;
57 if (width
<= 0) continue;
60 if (skip_left
< trans
) {
67 if (skip_left
< pixels
) {
77 if (skip_left
!= 0) continue;
79 /* Skip transparent pixels */
82 if (width
<= 0 || pixels
== 0) continue;
83 pixels
= std::min
<uint
>(pixels
, width
);
88 case BM_CRASH_REMAP
: {
89 const uint8
*remap
= bp
->remap
;
94 } while (--pixels
!= 0);
99 MemSetT(dst
, 0, pixels
);
103 case BM_TRANSPARENT
: {
104 const uint8
*remap
= bp
->remap
;
109 } while (--pixels
!= 0);
114 MemCpyT(dst
, src
, pixels
);
115 dst
+= pixels
; src
+= pixels
;
122 Sprite
*Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite
*sprite
, AllocatorProc
*allocator
)
124 /* Make memory for all zoom-levels */
125 uint memory
= sizeof(SpriteData
);
130 if (sprite
->type
== ST_FONT
) {
131 zoom_min
= ZOOM_LVL_NORMAL
;
132 zoom_max
= ZOOM_LVL_NORMAL
;
134 zoom_min
= _settings_client
.gui
.zoom_min
;
135 zoom_max
= _settings_client
.gui
.zoom_max
;
136 if (zoom_max
== zoom_min
) zoom_max
= ZOOM_LVL_MAX
;
139 for (ZoomLevel i
= zoom_min
; i
<= zoom_max
; i
++) {
140 memory
+= sprite
[i
].width
* sprite
[i
].height
;
143 /* We have no idea how much memory we really need, so just guess something */
146 /* Don't allocate memory each time, but just keep some
147 * memory around as this function is called quite often
148 * and the memory usage is quite low. */
149 static ReusableBuffer
<byte
> temp_buffer
;
150 SpriteData
*temp_dst
= (SpriteData
*)temp_buffer
.Allocate(memory
);
151 memset(temp_dst
, 0, sizeof(*temp_dst
));
152 byte
*dst
= temp_dst
->data
;
154 /* Make the sprites per zoom-level */
155 for (ZoomLevel i
= zoom_min
; i
<= zoom_max
; i
++) {
156 /* Store the index table */
157 uint offset
= dst
- temp_dst
->data
;
158 temp_dst
->offset
[i
] = offset
;
160 /* cache values, because compiler can't cache it */
161 int scaled_height
= sprite
[i
].height
;
162 int scaled_width
= sprite
[i
].width
;
164 for (int y
= 0; y
< scaled_height
; y
++) {
167 uint last_colour
= 0;
168 byte
*count_dst
= nullptr;
170 /* Store the scaled image */
171 const SpriteLoader::CommonPixel
*src
= &sprite
[i
].data
[y
* sprite
[i
].width
];
173 for (int x
= 0; x
< scaled_width
; x
++) {
174 uint colour
= src
++->m
;
176 if (last_colour
== 0 || colour
== 0 || pixels
== 255) {
177 if (count_dst
!= nullptr) {
178 /* Write how many non-transparent bytes we get */
183 /* As long as we find transparency bytes, keep counting */
184 if (colour
== 0 && trans
!= 255) {
189 /* No longer transparency, so write the amount of transparent bytes */
193 /* Reserve a byte for the pixel counter */
197 last_colour
= colour
;
207 if (count_dst
!= nullptr) *count_dst
= pixels
;
209 /* Write line-ending */
215 uint size
= dst
- (byte
*)temp_dst
;
217 /* Safety check, to make sure we guessed the size correctly */
218 assert(size
< memory
);
220 /* Allocate the exact amount of memory we need */
221 Sprite
*dest_sprite
= (Sprite
*)allocator(sizeof(*dest_sprite
) + size
);
223 dest_sprite
->height
= sprite
->height
;
224 dest_sprite
->width
= sprite
->width
;
225 dest_sprite
->x_offs
= sprite
->x_offs
;
226 dest_sprite
->y_offs
= sprite
->y_offs
;
227 memcpy(dest_sprite
->data
, temp_dst
, size
);