@@ -21,7 +21,7 @@ inline constexpr Video::Pixel GREEN{0xFF'00'FF'00};
2121inline constexpr Video::Pixel HALF_GREEN{0xFF'09'85'09 };
2222inline constexpr Video::Pixel HIDDEN_GREEN{0x00'00'FF'00 };
2323inline constexpr Video::Pixel MAGENTA{0xFF'FF'00'FF };
24- inline constexpr Video::Pixel BLUE{0xFF'00'00'FF };
24+ inline constexpr Video::Pixel BLUE{0xFF'00'00'FF }; // Background color.
2525
2626inline constexpr Video::ImagePlane PLANEA = Video::A;
2727inline constexpr Video::ImagePlane PLANEB = Video::B;
@@ -156,7 +156,7 @@ static constexpr void configureOneMatte(Video::Renderer& renderer) noexcept
156156 renderer.m_matteNumber = false ;
157157 renderer.m_icf [PLANEA] = 63 ;
158158 renderer.m_icf [PLANEB] = 63 ;
159- // starts with matte flag false.
159+ // starts with matte flags false.
160160 renderer.m_matteControl [0 ] = makeCommand (0b0100 , true , 63 , 0 ); // ICF A 63.
161161 renderer.m_matteControl [1 ] = makeCommand (0b0110 , true , 63 , 1 ); // ICF B 63.
162162 renderer.m_matteControl [2 ] = makeCommand (0b0100 , true , 31 , 2 ); // ICF A 31.
@@ -177,7 +177,7 @@ static constexpr void configureTwoMattes(Video::Renderer& renderer) noexcept
177177 renderer.m_matteNumber = true ;
178178 renderer.m_icf [PLANEA] = 63 ;
179179 renderer.m_icf [PLANEB] = 63 ;
180- // starts with matte flag false.
180+ // starts with matte flags false.
181181 // mf bit must be ignored.
182182 renderer.m_matteControl [0 ] = makeCommand (0b1111 , true , 31 , 8 ); // Set matte flag 0, ICF B 31, plane B visible.
183183 renderer.m_matteControl [2 ] = makeCommand (0 , true , 0 , 3 ); // Ignore later commands.
@@ -200,6 +200,18 @@ static void configureCLUT(Video::Renderer& renderer) noexcept
200200 renderer.m_clut [128 ] = GREEN.AsU32 ();
201201}
202202
203+ static constexpr std::array<uint8_t , 384 > INPUT_A = [] () {
204+ std::array<uint8_t , 384 > array{};
205+ std::ranges::fill (array, 0 ); // CLUT 0
206+ return array;
207+ }();
208+
209+ static constexpr std::array<uint8_t , 384 > INPUT_B = [] () {
210+ std::array<uint8_t , 384 > array{};
211+ std::ranges::fill (array, 0 ); // CLUT 0 + 128
212+ return array;
213+ }();
214+
203215TEST_CASE (" Matte" , " [Video]" )
204216{
205217 Video::RendererSoftware rendererSoft;
@@ -213,17 +225,6 @@ TEST_CASE("Matte", "[Video]")
213225 configureCLUT (rendererSoft);
214226 IF_SIMD (configureCLUT (rendererSIMD))
215227
216- constexpr std::array<uint8_t , 384 > INPUT_A = [] () {
217- std::array<uint8_t , 384 > array{};
218- std::ranges::fill (array, 0 ); // CLUT 0
219- return array;
220- }();
221- constexpr std::array<uint8_t , 384 > INPUT_B = [] () {
222- std::array<uint8_t , 384 > array{};
223- std::ranges::fill (array, 0 ); // CLUT 0 + 128
224- return array;
225- }();
226-
227228 rendererSoft.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 );
228229 IF_SIMD (rendererSIMD.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 ))
229230
@@ -265,17 +266,6 @@ TEST_CASE("Matte", "[Video]")
265266 configureCLUT (rendererSoft);
266267 IF_SIMD (configureCLUT (rendererSIMD))
267268
268- constexpr std::array<uint8_t , 384 > INPUT_A = [] () {
269- std::array<uint8_t , 384 > array{};
270- std::ranges::fill (array, 0 ); // CLUT 0
271- return array;
272- }();
273- constexpr std::array<uint8_t , 384 > INPUT_B = [] () {
274- std::array<uint8_t , 384 > array{};
275- std::ranges::fill (array, 0 ); // CLUT 0 + 128
276- return array;
277- }();
278-
279269 rendererSoft.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 );
280270 IF_SIMD (rendererSIMD.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 ))
281271
@@ -311,6 +301,135 @@ TEST_CASE("Matte", "[Video]")
311301 }
312302}
313303
304+ static constexpr void configureOneMatteLower (Video::Renderer& renderer) noexcept
305+ {
306+ renderer.m_transparencyControl [PLANEA] = 0b0100 ; // Matte flag 1 = true.
307+ renderer.m_transparencyControl [PLANEB] = 0b1000 ; // Never.
308+ renderer.m_mix = false ;
309+ renderer.m_planeOrder = false ; // A in front of B.
310+
311+ renderer.m_matteNumber = false ;
312+ renderer.m_icf [PLANEA] = 63 ;
313+ renderer.m_icf [PLANEB] = 63 ;
314+ // starts with matte flags false.
315+ renderer.m_matteControl [0 ] = makeCommand (0b0100 , true , 63 , 0 ); // ICF A 63.
316+ renderer.m_matteControl [1 ] = makeCommand (0b0110 , true , 63 , 1 ); // ICF B 63.
317+ renderer.m_matteControl [2 ] = makeCommand (0b0100 , true , 31 , 2 ); // ICF A 31.
318+ renderer.m_matteControl [3 ] = makeCommand (0b1001 , true , 0 , 3 ); // Set matte flag 1, plane A hidden.
319+ renderer.m_matteControl [4 ] = makeCommand (0b0110 , true , 31 , 4 ); // ICF B 31.
320+ renderer.m_matteControl [5 ] = makeCommand (0b1000 , true , 0 , 5 ); // Reset matte flag 1, plane A visible.
321+ renderer.m_matteControl [6 ] = makeCommand (0b1000 , true , 0 , 5 ); // Not above previous command, must not infinite loop.
322+ renderer.m_matteControl [7 ] = makeCommand (0b0100 , true , 0 , 740 ); // ICF A 0, must be ignored.
323+ }
324+
325+ static constexpr void configureTwoMattesLower (Video::Renderer& renderer) noexcept
326+ {
327+ renderer.m_transparencyControl [PLANEA] = 0b1100 ; // Matte flag 1 = false.
328+ renderer.m_transparencyControl [PLANEB] = 0b1011 ; // Matte flag 0 = false.
329+ renderer.m_mix = false ;
330+ renderer.m_planeOrder = true ; // B in front of A.
331+
332+ renderer.m_matteNumber = true ;
333+ renderer.m_icf [PLANEA] = 63 ;
334+ renderer.m_icf [PLANEB] = 63 ;
335+ // starts with matte flags false.
336+ // mf bit must be ignored.
337+ renderer.m_matteControl [0 ] = makeCommand (0b1111 , true , 31 , 1 ); // Set matte flag 0, ICF B 31, plane B visible.
338+ renderer.m_matteControl [2 ] = makeCommand (0b1111 , true , 0 , 1 ); // Ignore later commands.
339+ renderer.m_matteControl [3 ] = makeCommand (0b1000 , true , 0 , 2 ); // ICF B 0, must be ignored.
340+ renderer.m_matteControl [3 ] = makeCommand (0 , true , 63 , 3 ); // ICF B 63, must be ignored.
341+
342+ renderer.m_matteControl [4 ] = makeCommand (0b1101 , false , 63 , 2 ); // Set matte flag 1, ICF A 63, plane A visible.
343+ renderer.m_matteControl [5 ] = makeCommand (0b0100 , false , 31 , 4 ); // ICF A 31.
344+ renderer.m_matteControl [6 ] = makeCommand (0b0100 , false , 63 , 4 ); // Ignored.
345+ renderer.m_matteControl [7 ] = makeCommand (0b0110 , false , 63 , 8 ); // ICF B 63, ignored.
346+ }
347+
348+ TEST_CASE (" Matte lower position" , " [Video]" )
349+ {
350+ // Tests the case where a next matte control register has a lower position than the next one.
351+ Video::RendererSoftware rendererSoft;
352+ IF_SIMD (Video::RendererSIMD rendererSIMD)
353+
354+ SECTION (" One matte" )
355+ {
356+ configureOneMatteLower (rendererSoft);
357+ IF_SIMD (configureOneMatteLower (rendererSIMD))
358+
359+ configureCLUT (rendererSoft);
360+ IF_SIMD (configureCLUT (rendererSIMD))
361+
362+ rendererSoft.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 );
363+ IF_SIMD (rendererSIMD.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 ))
364+
365+ constexpr std::array<Video::Pixel, 768 > EXPECTED_A = [] () {
366+ std::array<Video::Pixel, 768 > array{RED, RED, RED, HIDDEN_RED, HIDDEN_RED};
367+ std::fill (array.begin () + 5 , array.end (), RED);
368+ return array;
369+ }();
370+ constexpr std::array<Video::Pixel, 768 > EXPECTED_B = [] () {
371+ std::array<Video::Pixel, 768 > array;
372+ std::ranges::fill (array, GREEN);
373+ return array;
374+ }();
375+ constexpr std::array<Video::Pixel, 768 > EXPECTED_SCREEN = [] () {
376+ std::array<Video::Pixel, 768 > array{
377+ RED, RED, HALF_RED, GREEN, HALF_GREEN,
378+ };
379+ std::fill (array.begin () + 5 , array.end (), HALF_RED);
380+ return array;
381+ }();
382+
383+ REQUIRE (std::equal (EXPECTED_A.cbegin (), EXPECTED_A.cend (), rendererSoft.m_plane [PLANEA].GetLinePointer (0 )));
384+ IF_SIMD (REQUIRE (std::equal (EXPECTED_A.cbegin (), EXPECTED_A.cend (), rendererSIMD.m_plane [PLANEA].GetLinePointer (0 ))))
385+
386+ REQUIRE (std::equal (EXPECTED_B.cbegin (), EXPECTED_B.cend (), rendererSoft.m_plane [PLANEB].GetLinePointer (0 )));
387+ IF_SIMD (REQUIRE (std::equal (EXPECTED_B.cbegin (), EXPECTED_B.cend (), rendererSIMD.m_plane [PLANEB].GetLinePointer (0 ))))
388+
389+ REQUIRE (std::equal (EXPECTED_SCREEN.cbegin (), EXPECTED_SCREEN.cend (), rendererSoft.m_screen .GetLinePointer (0 )));
390+ IF_SIMD (REQUIRE (std::equal (EXPECTED_SCREEN.cbegin (), EXPECTED_SCREEN.cend (), rendererSIMD.m_screen .GetLinePointer (0 ))))
391+ }
392+
393+ SECTION (" Two matte" )
394+ {
395+ configureTwoMattesLower (rendererSoft);
396+ IF_SIMD (configureTwoMattesLower (rendererSIMD))
397+
398+ configureCLUT (rendererSoft);
399+ IF_SIMD (configureCLUT (rendererSIMD))
400+
401+ rendererSoft.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 );
402+ IF_SIMD (rendererSIMD.DrawLine (INPUT_A.data (), INPUT_B.data (), 0 ))
403+
404+ constexpr std::array<Video::Pixel, 768 > EXPECTED_A = [] () {
405+ std::array<Video::Pixel, 768 > array{
406+ HIDDEN_RED, HIDDEN_RED,
407+ };
408+ std::fill (array.begin () + 2 , array.end (), RED);
409+ return array;
410+ }();
411+ constexpr std::array<Video::Pixel, 768 > EXPECTED_B = [] () {
412+ std::array<Video::Pixel, 768 > array{HIDDEN_GREEN};
413+ std::fill (array.begin () + 1 , array.end (), GREEN);
414+ return array;
415+ }();
416+ constexpr std::array<Video::Pixel, 768 > EXPECTED_SCREEN = [] () {
417+ std::array<Video::Pixel, 768 > array{BLUE};
418+ std::fill (array.begin () + 1 , array.end (), HALF_GREEN);
419+ return array;
420+ }();
421+
422+ REQUIRE (std::equal (EXPECTED_A.cbegin (), EXPECTED_A.cend (), rendererSoft.m_plane [PLANEA].GetLinePointer (0 )));
423+ IF_SIMD (REQUIRE (std::equal (EXPECTED_A.cbegin (), EXPECTED_A.cend (), rendererSIMD.m_plane [PLANEA].GetLinePointer (0 ))))
424+
425+ REQUIRE (std::equal (EXPECTED_B.cbegin (), EXPECTED_B.cend (), rendererSoft.m_plane [PLANEB].GetLinePointer (0 )));
426+ IF_SIMD (REQUIRE (std::equal (EXPECTED_B.cbegin (), EXPECTED_B.cend (), rendererSIMD.m_plane [PLANEB].GetLinePointer (0 ))))
427+
428+ REQUIRE (std::equal (EXPECTED_SCREEN.cbegin (), EXPECTED_SCREEN.cend (), rendererSoft.m_screen .GetLinePointer (0 )));
429+ IF_SIMD (REQUIRE (std::equal (EXPECTED_SCREEN.cbegin (), EXPECTED_SCREEN.cend (), rendererSIMD.m_screen .GetLinePointer (0 ))))
430+ }
431+ }
432+
314433TEST_CASE (" Decoding length" , " [Video]" )
315434{
316435 Video::RendererSoftware rendererSoft;
0 commit comments