new 32x renderers, auto fskip change, massive refactoring
[picodrive.git] / pico / 32x / draw.c
1 #include "../pico_int.h"
2
3 int (*PicoScan32xBegin)(unsigned int num);
4 int (*PicoScan32xEnd)(unsigned int num);
5 int Pico32xDrawMode;
6
7 static void convert_pal555(int invert_prio)
8 {
9   unsigned int *ps = (void *)Pico32xMem->pal;
10   unsigned int *pd = (void *)Pico32xMem->pal_native;
11   unsigned int m1 = 0x001f001f;
12   unsigned int m2 = 0x03e003e0;
13   unsigned int m3 = 0xfc00fc00;
14   unsigned int inv = 0;
15   int i;
16
17   if (invert_prio)
18     inv = 0x00200020;
19
20   // place prio to LS green bit
21   for (i = 0x100/2; i > 0; i--, ps++, pd++) {
22     unsigned int t = *ps;
23     *pd = (((t & m1) << 11) | ((t & m2) << 1) | ((t & m3) >> 10)) ^ inv;
24   }
25
26   Pico32x.dirty_pal = 0;
27 }
28
29 // direct color mode
30 #define do_line_dc(pd, p32x, pmd, inv, pmd_draw_code)             \
31 {                                                                 \
32   const unsigned int m1 = 0x001f;                                 \
33   const unsigned int m2 = 0x03e0;                                 \
34   const unsigned int m3 = 0x7c00;                                 \
35   int i;                                                          \
36                                                                   \
37   for (i = 320; i > 0; i--, pd++, p32x++, pmd++) {                \
38     unsigned short t = *p32x;                                     \
39     if (*pmd != mdbg && !((t ^ inv) & 0x8000)) {                  \
40       pmd_draw_code;                                              \
41       continue;                                                   \
42     }                                                             \
43                                                                   \
44     *pd = ((t & m1) << 11) | ((t & m2) << 1) | ((t & m3) >> 10);  \
45   }                                                               \
46 }
47
48 // packed pixel mode
49 #define do_line_pp(pd, p32x, pmd, pmd_draw_code)                  \
50 {                                                                 \
51   unsigned short t;                                               \
52   int i;                                                          \
53   for (i = 320/2; i > 0; i--, p32x++) {                           \
54     t = pal[*p32x >> 8];                                          \
55     if (*pmd == mdbg || (t & 0x20))                               \
56       *pd = t;                                                    \
57     else                                                          \
58       pmd_draw_code;                                              \
59     pd++; pmd++;                                                  \
60     t = pal[*p32x & 0xff];                                        \
61     if (*pmd == mdbg || (t & 0x20))                               \
62       *pd = t;                                                    \
63     else                                                          \
64       pmd_draw_code;                                              \
65     pd++; pmd++;                                                  \
66   }                                                               \
67
68
69 // run length mode
70 #define do_line_rl(pd, p32x, pmd, pmd_draw_code)                  \
71 {                                                                 \
72   unsigned short len, t;                                          \
73   int i;                                                          \
74   for (i = 320; i > 0; p32x++) {                                  \
75     t = pal[*p32x & 0xff];                                        \
76     for (len = (*p32x >> 8) + 1; len > 0 && i > 0; len--, i--, pd++, pmd++) { \
77       if (*pmd == mdbg || (t & 0x20))                             \
78         *pd = t;                                                  \
79       else                                                        \
80         pmd_draw_code;                                            \
81     }                                                             \
82   }                                                               \
83 }
84
85 void FinalizeLine32xRGB555(int sh, int line)
86 {
87   unsigned short *pd = DrawLineDest;
88   unsigned short *pal = Pico32xMem->pal_native;
89   unsigned char  *pmd = HighCol + 8;
90   unsigned short *dram, *p32x;
91   unsigned char   mdbg;
92
93   FinalizeLine555(sh, line);
94
95   if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 0 || // 32x blanking
96       // XXX: how is 32col mode hadled by real hardware?
97       !(Pico.video.reg[12] & 1) || // 32col mode
98       !(PicoDrawMask & PDRAW_32X_ON))
99   {
100     return;
101   }
102
103   dram = (void *)Pico32xMem->dram[Pico32x.vdp_regs[0x0a/2] & P32XV_FS];
104   p32x = dram + dram[line];
105   mdbg = Pico.video.reg[7] & 0x3f;
106
107   if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 2) { // Direct Color Mode
108     int inv_bit = (Pico32x.vdp_regs[0] & P32XV_PRI) ? 0x8000 : 0;
109     do_line_dc(pd, p32x, pmd, inv_bit,);
110     return;
111   }
112
113   if (Pico32x.dirty_pal)
114     convert_pal555(Pico32x.vdp_regs[0] & P32XV_PRI);
115
116   if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 1) { // Packed Pixel Mode
117     do_line_pp(pd, p32x, pmd,);
118   }
119   else { // Run Length Mode
120     do_line_rl(pd, p32x, pmd,);
121   }
122 }
123
124 #define MD_LAYER_CODE \
125   *dst = palmd[*pmd]
126
127 #define PICOSCAN_PRE \
128   PicoScan32xBegin(l + (lines_offs & 0xff)); \
129   dst = DrawLineDest; \
130
131 #define PICOSCAN_POST \
132   PicoScan32xEnd(l + (lines_offs & 0xff)); \
133
134 #define make_do_loop(name, pre_code, post_code, md_code)        \
135 /* Direct Color Mode */                                         \
136 static void do_loop_dc##name(unsigned short *dst,               \
137     unsigned short *dram, int lines_offs, int mdbg)             \
138 {                                                               \
139   int inv_bit = (Pico32x.vdp_regs[0] & P32XV_PRI) ? 0x8000 : 0; \
140   unsigned char  *pmd = PicoDraw2FB + 328 * 8 + 8;              \
141   unsigned short *palmd = HighPal;                              \
142   unsigned short *p32x;                                         \
143   int lines = lines_offs >> 16;                                 \
144   int l;                                                        \
145   (void)palmd;                                                  \
146   for (l = 0; l < lines; l++, pmd += 8) {                       \
147     pre_code;                                                   \
148     p32x = dram + dram[l];                                      \
149     do_line_dc(dst, p32x, pmd, inv_bit, md_code);               \
150     post_code;                                                  \
151   }                                                             \
152 }                                                               \
153                                                                 \
154 /* Packed Pixel Mode */                                         \
155 static void do_loop_pp##name(unsigned short *dst,               \
156     unsigned short *dram, int lines_offs, int mdbg)             \
157 {                                                               \
158   unsigned short *pal = Pico32xMem->pal_native;                 \
159   unsigned char  *pmd = PicoDraw2FB + 328 * 8 + 8;              \
160   unsigned short *palmd = HighPal;                              \
161   unsigned short *p32x;                                         \
162   int lines = lines_offs >> 16;                                 \
163   int l;                                                        \
164   (void)palmd;                                                  \
165   for (l = 0; l < lines; l++, pmd += 8) {                       \
166     pre_code;                                                   \
167     p32x = dram + dram[l];                                      \
168     do_line_pp(dst, p32x, pmd, md_code);                        \
169     post_code;                                                  \
170   }                                                             \
171 }                                                               \
172                                                                 \
173 /* Run Length Mode */                                           \
174 static void do_loop_rl##name(unsigned short *dst,               \
175     unsigned short *dram, int lines_offs, int mdbg)             \
176 {                                                               \
177   unsigned short *pal = Pico32xMem->pal_native;                 \
178   unsigned char  *pmd = PicoDraw2FB + 328 * 8 + 8;              \
179   unsigned short *palmd = HighPal;                              \
180   unsigned short *p32x;                                         \
181   int lines = lines_offs >> 16;                                 \
182   int l;                                                        \
183   (void)palmd;                                                  \
184   for (l = 0; l < lines; l++, pmd += 8) {                       \
185     pre_code;                                                   \
186     p32x = dram + dram[l];                                      \
187     do_line_rl(dst, p32x, pmd, md_code);                        \
188     post_code;                                                  \
189   }                                                             \
190 }
191
192 #ifdef _ASM_32X_DRAW
193 #undef make_do_loop
194 #define make_do_loop(name, pre_code, post_code, md_code) \
195 extern void do_loop_dc##name(unsigned short *dst,        \
196     unsigned short *dram, int lines_offs, int mdbg);     \
197 extern void do_loop_pp##name(unsigned short *dst,        \
198     unsigned short *dram, int lines_offs, int mdbg);     \
199 extern void do_loop_rl##name(unsigned short *dst,        \
200     unsigned short *dram, int lines_offs, int mdbg);
201 #endif
202
203 make_do_loop(,,,)
204 make_do_loop(_md, , , MD_LAYER_CODE)
205 make_do_loop(_scan, PICOSCAN_PRE, PICOSCAN_POST, )
206 make_do_loop(_scan_md, PICOSCAN_PRE, PICOSCAN_POST, MD_LAYER_CODE)
207
208 typedef void (*do_loop_func)(unsigned short *dst, unsigned short *dram, int lines, int mdbg);
209 enum { DO_LOOP, DO_LOOP_MD, DO_LOOP_SCAN, DO_LOOP_MD_SCAN };
210
211 static const do_loop_func do_loop_dc_f[] = { do_loop_dc, do_loop_dc_md, do_loop_dc_scan, do_loop_dc_scan_md };
212 static const do_loop_func do_loop_pp_f[] = { do_loop_pp, do_loop_pp_md, do_loop_pp_scan, do_loop_pp_scan_md };
213 static const do_loop_func do_loop_rl_f[] = { do_loop_rl, do_loop_rl_md, do_loop_rl_scan, do_loop_rl_scan_md };
214
215 void PicoDraw32xLayer(int offs, int lines, int md_bg)
216 {
217   int have_scan = PicoScan32xBegin != NULL && PicoScan32xEnd != NULL;
218   const do_loop_func *do_loop;
219   unsigned short *dram;
220   int which_func;
221
222   DrawLineDest = DrawLineDestBase + offs * DrawLineDestIncrement;
223   dram = Pico32xMem->dram[Pico32x.vdp_regs[0x0a/2] & P32XV_FS];
224
225   if (Pico32xDrawMode == 2) {
226     if (Pico.m.dirtyPal)
227       PicoDrawUpdateHighPal();
228   }
229
230   if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 2)
231   {
232     // Direct Color Mode
233     do_loop = do_loop_dc_f;
234     goto do_it;
235   }
236
237   if (Pico32x.dirty_pal)
238     convert_pal555(Pico32x.vdp_regs[0] & P32XV_PRI);
239
240   if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 1)
241   {
242     // Packed Pixel Mode
243     do_loop = do_loop_pp_f;
244   }
245   else
246   {
247     // Run Length Mode
248     do_loop = do_loop_rl_f;
249   }
250
251 do_it:
252   if (Pico32xDrawMode == 2)
253     which_func = have_scan ? DO_LOOP_MD_SCAN : DO_LOOP_MD;
254   else
255     which_func = have_scan ? DO_LOOP_SCAN : DO_LOOP;
256
257   do_loop[which_func](DrawLineDest, dram, (lines << 16) | offs, md_bg);
258 }
259
260 void PicoDraw32xSetFrameMode(int is_on, int only_32x)
261 {
262 #ifdef _ASM_32X_DRAW
263   extern void *Pico32xNativePal;
264   Pico32xNativePal = Pico32xMem->pal_native;
265 #endif
266
267   if (is_on) {
268     // use the same layout as alt renderer
269     PicoDrawSetInternalBuf(PicoDraw2FB + 328*8, 328);
270     Pico32xDrawMode = only_32x ? 1 : 2;
271   } else {
272     PicoDrawSetInternalBuf(NULL, 0);
273     Pico32xDrawMode = 0;
274   }
275 }
276