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 32bpp_anim.cpp Implementation of a partially SSSE2 32bpp blitter with animation support. */
12 #include "../stdafx.h"
13 #include "../video/video_driver.hpp"
14 #include "32bpp_anim_sse2.hpp"
15 #include "32bpp_sse_func.hpp"
17 #include "../safeguards.h"
19 /** Instantiation of the partially SSSE2 32bpp with animation blitter factory. */
20 static FBlitter_32bppSSE2_Anim iFBlitter_32bppSSE2_Anim
;
22 void Blitter_32bppSSE2_Anim::PaletteAnimate(const Palette
&palette
)
24 assert(!_screen_disable_anim
);
26 this->palette
= palette
;
27 /* If first_dirty is 0, it is for 8bpp indication to send the new
28 * palette. However, only the animation colours might possibly change.
29 * Especially when going between toyland and non-toyland. */
30 assert(this->palette
.first_dirty
== PALETTE_ANIM_START
|| this->palette
.first_dirty
== 0);
32 const uint16
*anim
= this->anim_buf
;
33 Colour
*dst
= (Colour
*)_screen
.dst_ptr
;
35 bool screen_dirty
= false;
37 /* Let's walk the anim buffer and try to find the pixels */
38 const int width
= this->anim_buf_width
;
39 const int screen_pitch
= _screen
.pitch
;
40 const int anim_pitch
= this->anim_buf_pitch
;
41 __m128i anim_cmp
= _mm_set1_epi16(PALETTE_ANIM_START
- 1);
42 __m128i brightness_cmp
= _mm_set1_epi16(Blitter_32bppBase::DEFAULT_BRIGHTNESS
);
43 __m128i colour_mask
= _mm_set1_epi16(0xFF);
44 for (int y
= this->anim_buf_height
; y
!= 0 ; y
--) {
45 Colour
*next_dst_ln
= dst
+ screen_pitch
;
46 const uint16
*next_anim_ln
= anim
+ anim_pitch
;
49 __m128i data
= _mm_load_si128((const __m128i
*) anim
);
51 /* low bytes only, shifted into high positions */
52 __m128i colour_data
= _mm_and_si128(data
, colour_mask
);
54 /* test if any colour >= PALETTE_ANIM_START */
55 int colour_cmp_result
= _mm_movemask_epi8(_mm_cmpgt_epi16(colour_data
, anim_cmp
));
56 if (colour_cmp_result
) {
57 /* test if any brightness is unexpected */
58 if (x
< 8 || colour_cmp_result
!= 0xFFFF ||
59 _mm_movemask_epi8(_mm_cmpeq_epi16(_mm_srli_epi16(data
, 8), brightness_cmp
)) != 0xFFFF) {
60 /* slow path: < 8 pixels left or unexpected brightnesses */
61 for (int z
= min
<int>(x
, 8); z
!= 0 ; z
--) {
62 int value
= _mm_extract_epi16(data
, 0);
63 uint8 colour
= GB(value
, 0, 8);
64 if (colour
>= PALETTE_ANIM_START
) {
65 /* Update this pixel */
66 *dst
= AdjustBrightneSSE(LookupColourInPalette(colour
), GB(value
, 8, 8));
69 data
= _mm_srli_si128(data
, 2);
73 /* medium path: 8 pixels to animate all of expected brightnesses */
74 for (int z
= 0; z
< 8; z
++) {
75 *dst
= LookupColourInPalette(_mm_extract_epi16(colour_data
, 0));
76 colour_data
= _mm_srli_si128(colour_data
, 2);
82 /* fast path, no animation */
93 /* Make sure the backend redraws the whole screen */
94 VideoDriver::GetInstance()->MakeDirty(0, 0, _screen
.width
, _screen
.height
);