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
;
23 void Blitter_32bppSSE2_Anim::PaletteAnimate(const Palette
&palette
)
25 assert(!_screen_disable_anim
);
27 this->palette
= palette
;
28 /* If first_dirty is 0, it is for 8bpp indication to send the new
29 * palette. However, only the animation colours might possibly change.
30 * Especially when going between toyland and non-toyland. */
31 assert(this->palette
.first_dirty
== PALETTE_ANIM_START
|| this->palette
.first_dirty
== 0);
33 const uint16
*anim
= this->anim_buf
;
34 Colour
*dst
= (Colour
*)_screen
.dst_ptr
;
36 bool screen_dirty
= false;
38 /* Let's walk the anim buffer and try to find the pixels */
39 const int width
= this->anim_buf_width
;
40 const int screen_pitch
= _screen
.pitch
;
41 const int anim_pitch
= this->anim_buf_pitch
;
42 __m128i anim_cmp
= _mm_set1_epi16(PALETTE_ANIM_START
- 1);
43 __m128i brightness_cmp
= _mm_set1_epi16(Blitter_32bppBase::DEFAULT_BRIGHTNESS
);
44 __m128i colour_mask
= _mm_set1_epi16(0xFF);
45 for (int y
= this->anim_buf_height
; y
!= 0 ; y
--) {
46 Colour
*next_dst_ln
= dst
+ screen_pitch
;
47 const uint16
*next_anim_ln
= anim
+ anim_pitch
;
50 __m128i data
= _mm_load_si128((const __m128i
*) anim
);
52 /* low bytes only, shifted into high positions */
53 __m128i colour_data
= _mm_and_si128(data
, colour_mask
);
55 /* test if any colour >= PALETTE_ANIM_START */
56 int colour_cmp_result
= _mm_movemask_epi8(_mm_cmpgt_epi16(colour_data
, anim_cmp
));
57 if (colour_cmp_result
) {
58 /* test if any brightness is unexpected */
59 if (x
< 8 || colour_cmp_result
!= 0xFFFF ||
60 _mm_movemask_epi8(_mm_cmpeq_epi16(_mm_srli_epi16(data
, 8), brightness_cmp
)) != 0xFFFF) {
61 /* slow path: < 8 pixels left or unexpected brightnesses */
62 for (int z
= std::min
<int>(x
, 8); z
!= 0 ; z
--) {
63 int value
= _mm_extract_epi16(data
, 0);
64 uint8 colour
= GB(value
, 0, 8);
65 if (colour
>= PALETTE_ANIM_START
) {
66 /* Update this pixel */
67 *dst
= AdjustBrightneSSE(LookupColourInPalette(colour
), GB(value
, 8, 8));
70 data
= _mm_srli_si128(data
, 2);
74 /* medium path: 8 pixels to animate all of expected brightnesses */
75 for (int z
= 0; z
< 8; z
++) {
76 *dst
= LookupColourInPalette(_mm_extract_epi16(colour_data
, 0));
77 colour_data
= _mm_srli_si128(colour_data
, 2);
83 /* fast path, no animation */
94 /* Make sure the backend redraws the whole screen */
95 VideoDriver::GetInstance()->MakeDirty(0, 0, _screen
.width
, _screen
.height
);