Skip to content

Commit 87bf082

Browse files
committed
Better abstraction and separation of renderers
1 parent 1a9e8ab commit 87bf082

File tree

6 files changed

+378
-391
lines changed

6 files changed

+378
-391
lines changed

src/CDI/Video/Renderer.cpp

Lines changed: 19 additions & 284 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ void Renderer::IncrementCursorTime(const double ns) noexcept
2828
}
2929
}
3030

31+
std::pair<uint16_t, uint16_t> Renderer::DrawLine(const uint8_t* lineA, const uint8_t* lineB, uint16_t lineNumber) noexcept
32+
{
33+
m_lineNumber = lineNumber;
34+
if(m_lineNumber == 0) [[unlikely]]
35+
{
36+
const uint16_t width = getDisplayWidth(m_displayFormat);
37+
const uint16_t height = GetDisplayHeight();
38+
39+
m_screen.m_width = m_plane[A].m_width = m_plane[B].m_width = width * 2;
40+
m_screen.m_height = m_plane[A].m_height = m_plane[B].m_height = m_backdropPlane.m_height = height;
41+
}
42+
43+
ResetMatte();
44+
45+
DrawLineBackdrop();
46+
47+
return DrawLineImpl(lineA, lineB);
48+
}
49+
3150
/** \brief To be called when the whole frame is drawn.
3251
* \return The final screen.
3352
*
@@ -47,288 +66,4 @@ const Plane& Renderer::RenderFrame() noexcept
4766
return m_screen;
4867
}
4968

50-
/** \brief Handles the transparency of the current pixel for each plane.
51-
* \tparam PLANE The video plane to operate on.
52-
* \tparam TRANSPARENT The low 3-bits of the transparency instruction.
53-
* \tparam BOOL_FLAG True if bit 3 is 0, false if bit 3 is 1.
54-
* \param pixel The ARGB pixel.
55-
* TODO: do not compute colorKey if not CLUT.
56-
*/
57-
template<ImagePlane PLANE, Renderer::TransparentIf TRANSPARENT, bool BOOL_FLAG>
58-
constexpr void Renderer::HandleTransparency(Pixel& pixel) noexcept
59-
{
60-
uint32_t color = static_cast<uint32_t>(pixel) & 0x00'FF'FF'FF;
61-
color = clutColorKey(color | m_maskColorRgb[PLANE]);
62-
const bool colorKey = color == clutColorKey(m_transparentColorRgb[PLANE] | m_maskColorRgb[PLANE]);
63-
64-
pixel.a = PIXEL_FULL_INTENSITY;
65-
66-
switch(TRANSPARENT)
67-
{
68-
case TransparentIf::AlwaysNever: // Always/Never.
69-
pixel.a = static_cast<uint8_t>(PIXEL_FULL_INTENSITY + BOOL_FLAG); // Branchless.
70-
break;
71-
72-
case TransparentIf::ColorKey: // Color Key.
73-
if(colorKey == BOOL_FLAG)
74-
pixel.a = PIXEL_TRANSPARENT;
75-
break;
76-
77-
case TransparentIf::TransparencyBit: // Transparent Bit.
78-
// TODO: currently decodeRGB555 make the pixel visible if the bit is set.
79-
// TODO: disable if not RGB555.
80-
if((pixel.a == PIXEL_FULL_INTENSITY) != BOOL_FLAG)
81-
pixel.a = PIXEL_TRANSPARENT;
82-
break;
83-
84-
case TransparentIf::MatteFlag0: // Matte Flag 0.
85-
if(m_matteFlags[A] == BOOL_FLAG)
86-
pixel.a = PIXEL_TRANSPARENT;
87-
break;
88-
89-
case TransparentIf::MatteFlag1: // Matte Flag 1.
90-
if(m_matteFlags[B] == BOOL_FLAG)
91-
pixel.a = PIXEL_TRANSPARENT;
92-
break;
93-
94-
case TransparentIf::MatteFlag0OrColorKey: // Matte Flag 0 or Color Key.
95-
if(m_matteFlags[A] == BOOL_FLAG || colorKey == BOOL_FLAG)
96-
pixel.a = PIXEL_TRANSPARENT;
97-
break;
98-
99-
case TransparentIf::MatteFlag1OrColorKey: // Matte Flag 1 or Color Key.
100-
if(m_matteFlags[B] == BOOL_FLAG || colorKey == BOOL_FLAG)
101-
pixel.a = PIXEL_TRANSPARENT;
102-
break;
103-
104-
default: // Reserved.
105-
std::unreachable();
106-
break;
107-
}
108-
}
109-
110-
/** \brief Applies matte and transparency to the two video planes. */
111-
void Renderer::HandleMatteAndTransparency(const uint16_t lineNumber) noexcept
112-
{
113-
const bool booleanA = !bit<3>(m_transparencyControl[A]);
114-
const uint8_t controlA = bits<0, 2>(m_transparencyControl[A]);
115-
116-
switch(static_cast<TransparentIf>(controlA))
117-
{
118-
case TransparentIf::AlwaysNever: // Always/Never.
119-
if(booleanA)
120-
HandleMatteAndTransparencyDispatchB<TransparentIf::AlwaysNever, true>(lineNumber);
121-
else
122-
HandleMatteAndTransparencyDispatchB<TransparentIf::AlwaysNever, false>(lineNumber);
123-
break;
124-
125-
case TransparentIf::ColorKey: // Color Key.
126-
if(booleanA)
127-
HandleMatteAndTransparencyDispatchB<TransparentIf::ColorKey, true>(lineNumber);
128-
else
129-
HandleMatteAndTransparencyDispatchB<TransparentIf::ColorKey, false>(lineNumber);
130-
break;
131-
132-
case TransparentIf::TransparencyBit: // Transparent Bit.
133-
// TODO: currently decodeRGB555 make the pixel visible if the bit is set.
134-
// TODO: disable if not RGB555.
135-
if(booleanA)
136-
HandleMatteAndTransparencyDispatchB<TransparentIf::TransparencyBit, true>(lineNumber);
137-
else
138-
HandleMatteAndTransparencyDispatchB<TransparentIf::TransparencyBit, false>(lineNumber);
139-
break;
140-
141-
case TransparentIf::MatteFlag0: // Matte Flag 0.
142-
if(booleanA)
143-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag0, true>(lineNumber);
144-
else
145-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag0, false>(lineNumber);
146-
break;
147-
148-
case TransparentIf::MatteFlag1: // Matte Flag 1.
149-
if(booleanA)
150-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag1, true>(lineNumber);
151-
else
152-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag1, false>(lineNumber);
153-
break;
154-
155-
case TransparentIf::MatteFlag0OrColorKey: // Matte Flag 0 or Color Key.
156-
if(booleanA)
157-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag0OrColorKey, true>(lineNumber);
158-
else
159-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag0OrColorKey, false>(lineNumber);
160-
break;
161-
162-
case TransparentIf::MatteFlag1OrColorKey: // Matte Flag 1 or Color Key.
163-
if(booleanA)
164-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag1OrColorKey, true>(lineNumber);
165-
else
166-
HandleMatteAndTransparencyDispatchB<TransparentIf::MatteFlag1OrColorKey, false>(lineNumber);
167-
break;
168-
169-
default: // Reserved.
170-
std::unreachable();
171-
break;
172-
}
173-
}
174-
175-
/** \brief Takes the template transparency control of A and mixes it with B's and handle them both. */
176-
template<Renderer::TransparentIf TRANSPARENCY_A, bool FLAG_A>
177-
void Renderer::HandleMatteAndTransparencyDispatchB(const uint16_t lineNumber) noexcept
178-
{
179-
const bool booleanB = !bit<3>(m_transparencyControl[B]);
180-
const uint8_t controlB = bits<0, 2>(m_transparencyControl[B]);
181-
182-
switch(static_cast<TransparentIf>(controlB))
183-
{
184-
case TransparentIf::AlwaysNever: // Always/Never.
185-
if(booleanB)
186-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::AlwaysNever, true>(lineNumber);
187-
else
188-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::AlwaysNever, false>(lineNumber);
189-
break;
190-
191-
case TransparentIf::ColorKey: // Color Key.
192-
if(booleanB)
193-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::ColorKey, true>(lineNumber);
194-
else
195-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::ColorKey, false>(lineNumber);
196-
break;
197-
198-
case TransparentIf::TransparencyBit: // Transparent Bit.
199-
// TODO: currently decodeRGB555 make the pixel visible if the bit is set.
200-
// TODO: disable if not RGB555.
201-
if(booleanB)
202-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::TransparencyBit, true>(lineNumber);
203-
else
204-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::TransparencyBit, false>(lineNumber);
205-
break;
206-
207-
case TransparentIf::MatteFlag0: // Matte Flag 0.
208-
if(booleanB)
209-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag0, true>(lineNumber);
210-
else
211-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag0, false>(lineNumber);
212-
break;
213-
214-
case TransparentIf::MatteFlag1: // Matte Flag 1.
215-
if(booleanB)
216-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag1, true>(lineNumber);
217-
else
218-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag1, false>(lineNumber);
219-
break;
220-
221-
case TransparentIf::MatteFlag0OrColorKey: // Matte Flag 0 or Color Key.
222-
if(booleanB)
223-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag0OrColorKey, true>(lineNumber);
224-
else
225-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag0OrColorKey, false>(lineNumber);
226-
break;
227-
228-
case TransparentIf::MatteFlag1OrColorKey: // Matte Flag 1 or Color Key.
229-
if(booleanB)
230-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag1OrColorKey, true>(lineNumber);
231-
else
232-
HandleMatteAndTransparencyLoop<TRANSPARENCY_A, FLAG_A, TransparentIf::MatteFlag1OrColorKey, false>(lineNumber);
233-
break;
234-
235-
default: // Reserved.
236-
std::unreachable();
237-
break;
238-
}
239-
}
240-
241-
/** \brief Actually handles matte and transparency for both planes statically. */
242-
template<Renderer::TransparentIf TRANSPARENCY_A, bool FLAG_A, Renderer::TransparentIf TRANSPARENCY_B, bool FLAG_B>
243-
void Renderer::HandleMatteAndTransparencyLoop(const uint16_t lineNumber) noexcept
244-
{
245-
Pixel* planeA = m_plane[A].GetLinePointer(lineNumber);
246-
Pixel* planeB = m_plane[B].GetLinePointer(lineNumber);
247-
248-
for(uint16_t i = 0; i < m_plane[A].m_width; ++i) // Plane B has the same width.
249-
{
250-
HandleMatte<A>(i);
251-
HandleMatte<B>(i);
252-
m_icfLine[A][i] = m_icf[A];
253-
m_icfLine[B][i] = m_icf[B];
254-
HandleTransparency<A, TRANSPARENCY_A, FLAG_A>(*planeA++);
255-
HandleTransparency<B, TRANSPARENCY_B, FLAG_B>(*planeB++);
256-
}
257-
}
258-
259-
/** \brief Handles the matte flags for the given plane at the given pixel position.
260-
* \param pos The current pixel position (in double resolution).
261-
*/
262-
template<ImagePlane PLANE>
263-
void Renderer::HandleMatte(uint16_t pos) noexcept
264-
{
265-
if(!m_matteNumber) // One matte.
266-
{
267-
if(m_nextMatte[PLANE] >= m_matteControl.size())
268-
return;
269-
}
270-
else // Two mattes.
271-
{
272-
if constexpr(PLANE == A)
273-
{
274-
if(m_nextMatte[A] >= MATTE_HALF)
275-
return;
276-
}
277-
else
278-
if(m_nextMatte[B] >= m_matteControl.size())
279-
return;
280-
}
281-
282-
const uint32_t command = m_matteControl[m_nextMatte[PLANE]];
283-
if(matteXPosition(command) > pos)
284-
return;
285-
286-
++m_nextMatte[PLANE];
287-
288-
/* TODO: matte flag index changed should be based on its index. V.5.10.2 note 8 */
289-
const uint8_t op = matteOp(command);
290-
switch(op)
291-
{
292-
case 0b0000:
293-
m_nextMatte[PLANE] = m_matteControl.size();
294-
break;
295-
296-
case 0b0100:
297-
m_icf[A] = matteICF(command);
298-
break;
299-
300-
case 0b0110:
301-
m_icf[B] = matteICF(command);
302-
break;
303-
304-
case 0b1000:
305-
m_matteFlags[PLANE] = false;
306-
break;
307-
308-
case 0b1001:
309-
m_matteFlags[PLANE] = true;
310-
break;
311-
312-
case 0b1100:
313-
m_icf[A] = matteICF(command);
314-
m_matteFlags[PLANE] = false;
315-
break;
316-
317-
case 0b1101:
318-
m_icf[A] = matteICF(command);
319-
m_matteFlags[PLANE] = true;
320-
break;
321-
322-
case 0b1110:
323-
m_icf[B] = matteICF(command);
324-
m_matteFlags[PLANE] = false;
325-
break;
326-
327-
case 0b1111:
328-
m_icf[B] = matteICF(command);
329-
m_matteFlags[PLANE] = true;
330-
break;
331-
}
332-
}
333-
33469
} // namespace Video

0 commit comments

Comments
 (0)