15template<std::
unsigned_
integral Pixel>
22 , settings(renderSettings)
26template<std::
unsigned_
integral Pixel>
29 unsigned c1 = settings.getBlurFactor();
30 unsigned c2 = (3 * 256) - (2 * c1);
34[[nodiscard]]
static inline std::pair<unsigned, unsigned> calcSpill(
unsigned c1,
unsigned c2,
unsigned x)
36 unsigned r = (c2 * x) >> 8;
37 unsigned s = (c1 * x) >> 8;
45template<std::
unsigned_
integral Pixel>
46void RGBTriplet3xScaler<Pixel>::rgbify(
47 std::span<const Pixel> in, std::span<Pixel> out,
unsigned c1,
unsigned c2)
49 assert((3 * in.size()) == out.size());
50 auto inSize = in.size();
53 auto [r, rs] = calcSpill(c1, c2, pixelOps.red256 (in[i + 0]));
54 auto [
g, gs] = calcSpill(c1, c2, pixelOps.green256(in[i + 0]));
55 out[3 * i + 0] = pixelOps.combine256(r , gs, 0);
56 auto [b, bs] = calcSpill(c1, c2, pixelOps.blue256 (in[i + 0]));
57 out[3 * i + 1] = pixelOps.combine256(rs,
g , bs);
58 std::tie(r, rs) = calcSpill(c1, c2, pixelOps.red256 (in[i + 1]));
59 out[3 * i + 2] = pixelOps.combine256(rs, gs, b);
61 for (++i; i < (inSize - 1); ++i) {
62 std::tie(
g, gs) = calcSpill(c1, c2, pixelOps.green256(in[i + 0]));
63 out[3 * i + 0] = pixelOps.combine256(r , gs, bs);
64 std::tie(b, bs) = calcSpill(c1, c2, pixelOps.blue256 (in[i + 0]));
65 out[3 * i + 1] = pixelOps.combine256(rs,
g , bs);
66 std::tie(r, rs) = calcSpill(c1, c2, pixelOps.red256 (in[i + 1]));
67 out[3 * i + 2] = pixelOps.combine256(rs, gs, b);
70 std::tie(
g, gs) = calcSpill(c1, c2, pixelOps.green256(in[i + 0]));
71 out[3 * i + 0] = pixelOps.combine256(r , gs, bs);
72 std::tie(b, bs) = calcSpill(c1, c2, pixelOps.blue256 (in[i + 0]));
73 out[3 * i + 1] = pixelOps.combine256(rs,
g , bs);
74 out[3 * i + 2] = pixelOps.combine256(0 , gs, b);
77template<std::
unsigned_
integral Pixel>
78void RGBTriplet3xScaler<Pixel>::scaleLine(
79 std::span<const Pixel> srcLine, std::span<Pixel> dstLine, PolyLineScaler<Pixel>&
scale,
80 unsigned c1,
unsigned c2)
83 rgbify(srcLine, dstLine, c1, c2);
87 rgbify(tmp, dstLine, c1, c2);
94template<std::
unsigned_
integral Pixel>
95void RGBTriplet3xScaler<Pixel>::doScale1(FrameSource& src,
96 unsigned srcStartY,
unsigned ,
unsigned srcWidth,
97 ScalerOutput<Pixel>& dst,
unsigned dstStartY,
unsigned dstEndY,
98 PolyLineScaler<Pixel>&
scale)
102 auto [c1, c2] = calcBlur();
104 unsigned dstWidth = dst.getWidth();
105 int scanlineFactor = settings.getScanlineFactor();
106 unsigned y = dstStartY;
107 auto srcLine = src.getLine(srcStartY++, buf);
108 auto dstLine0 = dst.acquireLine(y + 0);
109 scaleLine(srcLine, dstLine0,
scale, c1, c2);
111 Scale_1on1<Pixel>
copy;
112 auto dstLine1 = dst.acquireLine(y + 1);
113 copy(dstLine0, dstLine1);
115 for (; (y + 4) < dstEndY; y += 3, srcStartY += 1) {
116 srcLine = src.getLine(srcStartY, buf);
117 auto dstLine3 = dst.acquireLine(y + 3);
118 scaleLine(srcLine, dstLine3,
scale, c1, c2);
120 auto dstLine4 = dst.acquireLine(y + 4);
121 copy(dstLine3, dstLine4);
123 auto dstLine2 = dst.acquireLine(y + 2);
124 scanline.draw(dstLine0, dstLine3,
125 dstLine2, scanlineFactor);
127 dst.releaseLine(y + 0, dstLine0);
128 dst.releaseLine(y + 1, dstLine1);
129 dst.releaseLine(y + 2, dstLine2);
134 srcLine = src.getLine(srcStartY, buf);
136 scaleLine(srcLine, buf2,
scale, c1, c2);
137 auto dstLine2 = dst.acquireLine(y + 2);
138 scanline.draw(dstLine0, buf2, dstLine2, scanlineFactor);
139 dst.releaseLine(y + 0, dstLine0);
140 dst.releaseLine(y + 1, dstLine1);
141 dst.releaseLine(y + 2, dstLine2);
144template<std::
unsigned_
integral Pixel>
145void RGBTriplet3xScaler<Pixel>::doScale2(FrameSource& src,
146 unsigned srcStartY,
unsigned ,
unsigned srcWidth,
147 ScalerOutput<Pixel>& dst,
unsigned dstStartY,
unsigned dstEndY,
148 PolyLineScaler<Pixel>&
scale)
151 auto [c1, c2] = calcBlur();
153 int scanlineFactor = settings.getScanlineFactor();
154 for (
unsigned srcY = srcStartY, dstY = dstStartY; dstY < dstEndY;
155 srcY += 2, dstY += 3) {
156 auto srcLine0 = src.getLine(srcY + 0, buf);
157 auto dstLine0 = dst.acquireLine(dstY + 0);
158 scaleLine(srcLine0, dstLine0,
scale, c1, c2);
160 auto srcLine1 = src.getLine(srcY + 1, buf);
161 auto dstLine2 = dst.acquireLine(dstY + 2);
162 scaleLine(srcLine1, dstLine2,
scale, c1, c2);
164 auto dstLine1 = dst.acquireLine(dstY + 1);
165 scanline.draw(dstLine0, dstLine2,
166 dstLine1, scanlineFactor);
168 dst.releaseLine(dstY + 0, dstLine0);
169 dst.releaseLine(dstY + 1, dstLine1);
170 dst.releaseLine(dstY + 2, dstLine2);
174template<std::
unsigned_
integral Pixel>
176 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
180 doScale1(src, srcStartY, srcEndY, srcWidth,
181 dst, dstStartY, dstEndY, op);
184template<std::
unsigned_
integral Pixel>
186 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
190 doScale2(src, srcStartY, srcEndY, srcWidth,
191 dst, dstStartY, dstEndY, op);
194template<std::
unsigned_
integral Pixel>
196 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
200 doScale1(src, srcStartY, srcEndY, srcWidth,
201 dst, dstStartY, dstEndY, op);
204template<std::
unsigned_
integral Pixel>
206 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
210 doScale2(src, srcStartY, srcEndY, srcWidth,
211 dst, dstStartY, dstEndY, op);
214template<std::
unsigned_
integral Pixel>
216 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
220 doScale1(src, srcStartY, srcEndY, srcWidth,
221 dst, dstStartY, dstEndY, op);
224template<std::
unsigned_
integral Pixel>
226 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
230 doScale2(src, srcStartY, srcEndY, srcWidth,
231 dst, dstStartY, dstEndY, op);
234template<std::
unsigned_
integral Pixel>
236 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
240 doScale1(src, srcStartY, srcEndY, srcWidth,
241 dst, dstStartY, dstEndY, op);
244template<std::
unsigned_
integral Pixel>
246 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
250 doScale2(src, srcStartY, srcEndY, srcWidth,
251 dst, dstStartY, dstEndY, op);
254template<std::
unsigned_
integral Pixel>
256 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
260 doScale1(src, srcStartY, srcEndY, srcWidth,
261 dst, dstStartY, dstEndY, op);
264template<std::
unsigned_
integral Pixel>
266 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
270 doScale2(src, srcStartY, srcEndY, srcWidth,
271 dst, dstStartY, dstEndY, op);
274template<std::
unsigned_
integral Pixel>
276 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
280 doScale1(src, srcStartY, srcEndY, srcWidth,
281 dst, dstStartY, dstEndY, op);
284template<std::
unsigned_
integral Pixel>
286 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
290 doScale2(src, srcStartY, srcEndY, srcWidth,
291 dst, dstStartY, dstEndY, op);
294template<std::
unsigned_
integral Pixel>
295static constexpr void fillLoop(std::span<Pixel, 9> in, std::span<Pixel> out)
297 size_t outSize = out.size();
298 assert(outSize >= 6);
299 assert((outSize % 3) == 0);
307 for (
unsigned x = 3; x < (outSize - 3); x += 3) {
312 out[outSize - 3] = in[6];
313 out[outSize - 2] = in[7];
314 out[outSize - 1] = in[8];
317template<std::
unsigned_
integral Pixel>
319 FrameSource& src,
unsigned srcStartY,
unsigned srcEndY,
322 auto [c1, c2] = calcBlur();
323 int scanlineFactor = settings.getScanlineFactor();
326 unsigned stopDstY = (dstEndY == dstHeight)
327 ? dstEndY : dstEndY - 3;
328 unsigned srcY = srcStartY, dstY = dstStartY;
329 for (; dstY < stopDstY; srcY += 1, dstY += 3) {
332 std::array<Pixel, 3> inNormal;
333 std::array<Pixel, 3 * 3> outNormal;
334 std::array<Pixel, 3 * 3> outScanline;
335 inNormal[0] = inNormal[1] = inNormal[2] = color;
336 rgbify(inNormal, outNormal, c1, c2);
337 for (
auto [i, out] :
enumerate(outScanline)) {
338 out = scanline.darken(outNormal[i], scanlineFactor);
342 fillLoop(std::span{outNormal}, dstLine0);
346 fillLoop(std::span{outNormal}, dstLine1);
350 fillLoop(std::span{outScanline}, dstLine2);
353 if (dstY != dstHeight) {
356 assert(nextLineWidth != 1);
357 this->dispatchScale(src, srcY, srcEndY, nextLineWidth,
362template<std::
unsigned_
integral Pixel>
367 auto [c1, c2] = calcBlur();
368 int scanlineFactor = settings.getScanlineFactor();
369 for (
unsigned srcY = srcStartY, dstY = dstStartY;
370 dstY < dstEndY; srcY += 2, dstY += 3) {
374 std::array<Pixel, 3> inNormal;
375 std::array<Pixel, 3 * 3> out0Normal;
376 std::array<Pixel, 3 * 3> out1Normal;
377 std::array<Pixel, 3 * 3> outScanline;
379 inNormal[0] = inNormal[1] = inNormal[2] = color0;
380 rgbify(inNormal, out0Normal, c1, c2);
381 inNormal[0] = inNormal[1] = inNormal[2] = color1;
382 rgbify(inNormal, out1Normal, c1, c2);
384 for (
auto [i, out] :
enumerate(outScanline)) {
385 out = scanline.darken(
386 out0Normal[i], out1Normal[i],
391 fillLoop(std::span{out0Normal}, dstLine0);
395 fillLoop(std::span{outScanline}, dstLine1);
399 fillLoop(std::span{out1Normal}, dstLine2);
404template<std::
unsigned_
integral Pixel>
406 unsigned srcStartY,
unsigned srcEndY,
unsigned srcWidth,
412 this->dispatchScale(sf, srcStartY, srcEndY, srcWidth,
413 dst, dstStartY, dstEndY);
415 this->dispatchScale(src, srcStartY, srcEndY, srcWidth,
416 dst, dstStartY, dstEndY);
Interface for getting lines from a video frame.
Pixel getLineColor(unsigned line) const
Get the (single) color of the given line.
virtual unsigned getLineWidth(unsigned line) const =0
Gets the number of display pixels on the given line.
Polymorphic wrapper around another line scaler.
void scaleBlank2to3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale4x1to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale8x1to9x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale8x2to9x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale2x1to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale1x1to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale2x1to9x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale4x2to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
RGBTriplet3xScaler(const PixelOperations< Pixel > &pixelOps, const RenderSettings &renderSettings)
void scale4x1to9x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scaleImage(FrameSource &src, const RawFrame *superImpose, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
Scales the image in the given area, which must consist of lines which are all equally wide.
void scale2x2to9x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale1x2to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale2x2to3x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scale4x2to9x3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, unsigned srcWidth, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
void scaleBlank1to3(FrameSource &src, unsigned srcStartY, unsigned srcEndY, ScalerOutput< Pixel > &dst, unsigned dstStartY, unsigned dstEndY) override
A video frame as output by the VDP scanline conversion unit, before any postprocessing filters are ap...
Class containing all settings for renderers.
Base class for 3x scalers.
virtual unsigned getHeight() const =0
virtual void releaseLine(unsigned y, std::span< Pixel > buf)=0
virtual std::span< Pixel > acquireLine(unsigned y)=0
This class represents a frame that is the (per-pixel) alpha-blend of a (laser-disc) video frame and a...
unsigned getLineWidth(unsigned line) const override
Gets the number of display pixels on the given line.
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
constexpr mat4 scale(const vec3 &xyz)
This file implemented 3 utility functions:
auto copy(InputRange &&range, OutputIter out)
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)