1 /*
2  * render1x1ntsc.c - 1x1 NTSC renderers
3  *
4  * Written by
5  *  groepaz <groepaz@gmx.net> based on the pal renderers written by
6  *  John Selck <graham@cruise.de>
7  *
8  * This file is part of VICE, the Versatile Commodore Emulator.
9  * See README for copyright notice.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24  *  02111-1307  USA.
25  *
26  */
27 
28 #include "vice.h"
29 
30 #include "render1x1ntsc.h"
31 #include "types.h"
32 #include "video-color.h"
33 
34 /*
35     right now this is basically the PAL renderer without delay line emulation
36 */
37 
38 /*
39     YIQ->RGB (Sony CXA2025AS US decoder matrix)
40 
41     R = Y + (1.630 * I + 0.317 * Q)
42     G = Y - (0.378 * I + 0.466 * Q)
43     B = Y - (1.089 * I - 1.677 * Q)
44 */
45 static inline
yuv_to_rgb(int32_t y,int32_t u,int32_t v,int32_t * red,int32_t * grn,int32_t * blu)46 void yuv_to_rgb(int32_t y, int32_t u, int32_t v,
47                 int32_t *red, int32_t *grn, int32_t *blu)
48 {
49     *red = (y + ((209 * u +  41 * v) >> 7)) >> 15;
50     *grn = (y - (( 48 * u +  69 * v) >> 7)) >> 15;
51     *blu = (y - ((139 * u - 215 * v) >> 7)) >> 15;
52 }
53 
54 static inline
store_pixel_2(uint8_t * trg,int32_t y1,int32_t u1,int32_t v1,int32_t y2,int32_t u2,int32_t v2)55 void store_pixel_2(uint8_t *trg, int32_t y1, int32_t u1, int32_t v1, int32_t y2, int32_t u2, int32_t v2)
56 {
57     uint16_t *tmp;
58     int32_t red;
59     int32_t grn;
60     int32_t blu;
61 
62     yuv_to_rgb(y1, u1, v1, &red, &grn, &blu);
63     tmp = (uint16_t *) trg;
64     tmp[0] = (uint16_t) (gamma_red[256 + red] | gamma_grn[256 + grn] | gamma_blu[256 + blu]);
65 
66     yuv_to_rgb(y2, u2, v2, &red, &grn, &blu);
67     tmp[1] = (uint16_t) (gamma_red[256 + red] | gamma_grn[256 + grn] | gamma_blu[256 + blu]);
68 }
69 
70 static inline
store_pixel_3(uint8_t * trg,int32_t y1,int32_t u1,int32_t v1,int32_t y2,int32_t u2,int32_t v2)71 void store_pixel_3(uint8_t *trg, int32_t y1, int32_t u1, int32_t v1, int32_t y2, int32_t u2, int32_t v2)
72 {
73     uint32_t tmp;
74     int32_t red;
75     int32_t grn;
76     int32_t blu;
77 
78     yuv_to_rgb(y1, u1, v1, &red, &grn, &blu);
79     tmp = gamma_red[256 + red] | gamma_grn[256 + grn] | gamma_blu[256 + blu];
80     trg[0] = (uint8_t) tmp;
81     tmp >>= 8;
82     trg[1] = (uint8_t) tmp;
83     tmp >>= 8;
84     trg[2] = (uint8_t) tmp;
85 
86     yuv_to_rgb(y2, u2, v2, &red, &grn, &blu);
87     tmp = gamma_red[256 + red] | gamma_grn[256 + grn] | gamma_blu[256 + blu];
88     trg[3] = (uint8_t) tmp;
89     tmp >>= 8;
90     trg[4] = (uint8_t) tmp;
91     tmp >>= 8;
92     trg[5] = (uint8_t) tmp;
93 }
94 
95 static inline
store_pixel_4(uint8_t * trg,int32_t y1,int32_t u1,int32_t v1,int32_t y2,int32_t u2,int32_t v2)96 void store_pixel_4(uint8_t *trg, int32_t y1, int32_t u1, int32_t v1, int32_t y2, int32_t u2, int32_t v2)
97 {
98     uint32_t *tmp;
99     int32_t red;
100     int32_t grn;
101     int32_t blu;
102 
103     yuv_to_rgb(y1, u1, v1, &red, &grn, &blu);
104     tmp = (uint32_t *) trg;
105     tmp[0] = gamma_red[256 + red] | gamma_grn[256 + grn] | gamma_blu[256 + blu] | alpha;
106 
107     yuv_to_rgb(y2, u2, v2, &red, &grn, &blu);
108     tmp[1] = gamma_red[256 + red] | gamma_grn[256 + grn] | gamma_blu[256 + blu] | alpha;
109 }
110 
111 static inline
store_pixel_UYVY(uint8_t * trg,int32_t y1_,int32_t u1,int32_t v1,int32_t y2_,int32_t u2,int32_t v2)112 void store_pixel_UYVY(uint8_t *trg, int32_t y1_, int32_t u1, int32_t v1, int32_t y2_, int32_t u2, int32_t v2)
113 {
114     uint8_t y1 = (uint8_t)((y1_ >> 16) & 0xFFu);
115     uint8_t y2 = (uint8_t)((y2_ >> 16) & 0xFFu);
116 
117     u1 = (u1 + u2) >> 17;
118     v1 = (v1 + v2) >> 17;
119 
120     trg[0] = (uint8_t)(u1 + 128);
121     trg[1] = y1;
122     trg[2] = (uint8_t)(v1 + 128);
123     trg[3] = y2;
124 }
125 
126 static inline
store_pixel_YUY2(uint8_t * trg,int32_t y1_,int32_t u1,int32_t v1,int32_t y2_,int32_t u2,int32_t v2)127 void store_pixel_YUY2(uint8_t *trg, int32_t y1_, int32_t u1, int32_t v1, int32_t y2_, int32_t u2, int32_t v2)
128 {
129     uint8_t y1 = (uint8_t)((y1_ >> 16) & 0xFFu);
130     uint8_t y2 = (uint8_t)((y2_ >> 16) & 0xFFu);
131 
132     u1 = (u1 + u2) >> 17;
133     v1 = (v1 + v2) >> 17;
134 
135     trg[0] = y1;
136     trg[1] = (uint8_t)(u1 + 128);
137     trg[2] = y2;
138     trg[3] = (uint8_t)(v1 + 128);
139 }
140 
141 static inline
store_pixel_YVYU(uint8_t * trg,int32_t y1_,int32_t u1,int32_t v1,int32_t y2_,int32_t u2,int32_t v2)142 void store_pixel_YVYU(uint8_t *trg, int32_t y1_, int32_t u1, int32_t v1, int32_t y2_, int32_t u2, int32_t v2)
143 {
144     uint8_t y1 = (uint8_t)((y1_ >> 16) & 0xFFu);
145     uint8_t y2 = (uint8_t)((y2_ >> 16) & 0xFFu);
146 
147     u1 = (u1 + u2) >> 17;
148     v1 = (v1 + v2) >> 17;
149 
150     trg[0] = y1;
151     trg[1] = (uint8_t)(v1 + 128);
152     trg[2] = y2;
153     trg[3] = (uint8_t)(u1 + 128);
154 }
155 
156 /* NTSC 1x1 renderers */
157 static inline void
render_generic_1x1_ntsc(video_render_color_tables_t * color_tab,const uint8_t * src,uint8_t * trg,unsigned int width,const unsigned int height,unsigned int xs,const unsigned int ys,unsigned int xt,const unsigned int yt,const unsigned int pitchs,const unsigned int pitcht,const unsigned int pixelstride,void (* store_func)(uint8_t * trg,int32_t y1,int32_t u1,int32_t v1,int32_t y2,int32_t u2,int32_t v2),int yuvtarget)158 render_generic_1x1_ntsc(video_render_color_tables_t *color_tab, const uint8_t *src, uint8_t *trg,
159                         unsigned int width, const unsigned int height,
160                         unsigned int xs, const unsigned int ys,
161                         unsigned int xt, const unsigned int yt,
162                         const unsigned int pitchs, const unsigned int pitcht,
163                         const unsigned int pixelstride,
164                         void (*store_func)(uint8_t *trg,
165                                            int32_t y1, int32_t u1, int32_t v1,
166                                            int32_t y2, int32_t u2, int32_t v2),
167                         int yuvtarget)
168 {
169     const int32_t *cbtable = color_tab->cbtable;
170     const int32_t *crtable = color_tab->crtable;
171     const int32_t *ytablel = color_tab->ytablel;
172     const int32_t *ytableh = color_tab->ytableh;
173     const uint8_t *tmpsrc;
174     uint8_t *tmptrg;
175     unsigned int x, y;
176     int32_t l1, l2, u1, u2, v1, v2, unew, vnew;
177     uint8_t cl0, cl1, cl2, cl3;
178     int off_flip;
179 
180     /* ensure starting on even coords */
181     if ((xt & 1) && xs > 0) {
182         xs--;
183         xt--;
184         width++;
185     }
186 
187     src = src + pitchs * ys + xs - 2;
188     trg = trg + pitcht * yt + (xt >> 1) * pixelstride;
189 
190     width >>= 1;
191 
192     off_flip = 1 << 6;
193 
194     for (y = ys; y < height + ys; y++) {
195         tmpsrc = src;
196         tmptrg = trg;
197 
198         cbtable = yuvtarget ? color_tab->cutable : color_tab->cbtable;
199         crtable = yuvtarget ? color_tab->cvtable : color_tab->crtable;
200 
201         /* one scanline */
202         for (x = 0; x < width; x++) {
203             cl0 = tmpsrc[0];
204             cl1 = tmpsrc[1];
205             cl2 = tmpsrc[2];
206             cl3 = tmpsrc[3];
207             tmpsrc += 1;
208             l1 = ytablel[cl1] + ytableh[cl2] + ytablel[cl3];
209             unew = cbtable[cl0] + cbtable[cl1] + cbtable[cl2] + cbtable[cl3];
210             vnew = crtable[cl0] + crtable[cl1] + crtable[cl2] + crtable[cl3];
211             u1 = (unew) * off_flip;
212             v1 = (vnew) * off_flip;
213 
214             cl0 = tmpsrc[0];
215             cl1 = tmpsrc[1];
216             cl2 = tmpsrc[2];
217             cl3 = tmpsrc[3];
218             tmpsrc += 1;
219             l2 = ytablel[cl1] + ytableh[cl2] + ytablel[cl3];
220             unew = cbtable[cl0] + cbtable[cl1] + cbtable[cl2] + cbtable[cl3];
221             vnew = crtable[cl0] + crtable[cl1] + crtable[cl2] + crtable[cl3];
222             u2 = (unew) * off_flip;
223             v2 = (vnew) * off_flip;
224 
225             store_func(tmptrg, l1, u1, v1, l2, u2, v2);
226             tmptrg += pixelstride;
227         }
228 
229         src += pitchs;
230         trg += pitcht;
231     }
232 }
233 
234 void
render_UYVY_1x1_ntsc(video_render_color_tables_t * color_tab,const uint8_t * src,uint8_t * trg,const unsigned int width,const unsigned int height,const unsigned int xs,const unsigned int ys,const unsigned int xt,const unsigned int yt,const unsigned int pitchs,const unsigned int pitcht)235 render_UYVY_1x1_ntsc(video_render_color_tables_t *color_tab,
236                      const uint8_t *src, uint8_t *trg,
237                      const unsigned int width, const unsigned int height,
238                      const unsigned int xs, const unsigned int ys,
239                      const unsigned int xt, const unsigned int yt,
240                      const unsigned int pitchs, const unsigned int pitcht)
241 {
242     render_generic_1x1_ntsc(color_tab, src, trg, width, height, xs, ys, xt, yt,
243                             pitchs, pitcht,
244                             4, store_pixel_UYVY, 1);
245 }
246 
247 void
render_YUY2_1x1_ntsc(video_render_color_tables_t * color_tab,const uint8_t * src,uint8_t * trg,const unsigned int width,const unsigned int height,const unsigned int xs,const unsigned int ys,const unsigned int xt,const unsigned int yt,const unsigned int pitchs,const unsigned int pitcht)248 render_YUY2_1x1_ntsc(video_render_color_tables_t *color_tab,
249                      const uint8_t *src, uint8_t *trg,
250                      const unsigned int width, const unsigned int height,
251                      const unsigned int xs, const unsigned int ys,
252                      const unsigned int xt, const unsigned int yt,
253                      const unsigned int pitchs, const unsigned int pitcht)
254 {
255     render_generic_1x1_ntsc(color_tab, src, trg, width, height, xs, ys, xt, yt,
256                             pitchs, pitcht,
257                             4, store_pixel_YUY2, 1);
258 }
259 
260 void
render_YVYU_1x1_ntsc(video_render_color_tables_t * color_tab,const uint8_t * src,uint8_t * trg,const unsigned int width,const unsigned int height,const unsigned int xs,const unsigned int ys,const unsigned int xt,const unsigned int yt,const unsigned int pitchs,const unsigned int pitcht)261 render_YVYU_1x1_ntsc(video_render_color_tables_t *color_tab,
262                      const uint8_t *src, uint8_t *trg,
263                      const unsigned int width, const unsigned int height,
264                      const unsigned int xs, const unsigned int ys,
265                      const unsigned int xt, const unsigned int yt,
266                      const unsigned int pitchs, const unsigned int pitcht)
267 {
268     render_generic_1x1_ntsc(color_tab, src, trg, width, height, xs, ys, xt, yt,
269                             pitchs, pitcht,
270                             4, store_pixel_YVYU, 1);
271 }
272 
273 void
render_16_1x1_ntsc(video_render_color_tables_t * color_tab,const uint8_t * src,uint8_t * trg,const unsigned int width,const unsigned int height,const unsigned int xs,const unsigned int ys,const unsigned int xt,const unsigned int yt,const unsigned int pitchs,const unsigned int pitcht)274 render_16_1x1_ntsc(video_render_color_tables_t *color_tab,
275                    const uint8_t *src, uint8_t *trg,
276                    const unsigned int width, const unsigned int height,
277                    const unsigned int xs, const unsigned int ys,
278                    const unsigned int xt, const unsigned int yt,
279                    const unsigned int pitchs, const unsigned int pitcht)
280 {
281     render_generic_1x1_ntsc(color_tab, src, trg, width, height, xs, ys, xt, yt,
282                             pitchs, pitcht,
283                             4, store_pixel_2, 0);
284 }
285 
286 void
render_24_1x1_ntsc(video_render_color_tables_t * color_tab,const uint8_t * src,uint8_t * trg,const unsigned int width,const unsigned int height,const unsigned int xs,const unsigned int ys,const unsigned int xt,const unsigned int yt,const unsigned int pitchs,const unsigned int pitcht)287 render_24_1x1_ntsc(video_render_color_tables_t *color_tab,
288                    const uint8_t *src, uint8_t *trg,
289                    const unsigned int width, const unsigned int height,
290                    const unsigned int xs, const unsigned int ys,
291                    const unsigned int xt, const unsigned int yt,
292                    const unsigned int pitchs, const unsigned int pitcht)
293 {
294     render_generic_1x1_ntsc(color_tab, src, trg, width, height, xs, ys, xt, yt,
295                             pitchs, pitcht,
296                             6, store_pixel_3, 0);
297 }
298 
299 void
render_32_1x1_ntsc(video_render_color_tables_t * color_tab,const uint8_t * src,uint8_t * trg,const unsigned int width,const unsigned int height,const unsigned int xs,const unsigned int ys,const unsigned int xt,const unsigned int yt,const unsigned int pitchs,const unsigned int pitcht)300 render_32_1x1_ntsc(video_render_color_tables_t *color_tab,
301                    const uint8_t *src, uint8_t *trg,
302                    const unsigned int width, const unsigned int height,
303                    const unsigned int xs, const unsigned int ys,
304                    const unsigned int xt, const unsigned int yt,
305                    const unsigned int pitchs, const unsigned int pitcht)
306 {
307     render_generic_1x1_ntsc(color_tab, src, trg, width, height, xs, ys, xt, yt,
308                             pitchs, pitcht,
309                             8, store_pixel_4, 0);
310 }
311