]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/md/vdp.c
demote libemu to common code
[plan9front.git] / sys / src / games / md / vdp.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "../eui.h"
5 #include "dat.h"
6 #include "fns.h"
7
8 u16int vdpstat = 0x3400;
9 int vdpx, vdpy, vdpyy, frame, intla;
10 u16int hctr;
11 static int xmax, xdisp;
12 static int sx, snx, col, pri, lum;
13 enum { DARK, NORM, BRIGHT };
14 enum { ymax = 262, yvbl = 234 };
15
16 void
17 vdpmode(void)
18 {
19         if((reg[MODE4] & WIDE) != 0){
20                 xmax = 406;
21                 xdisp = 320;
22         }else{
23                 xdisp = 256;
24                 xmax = 342;
25         }
26         intla = (reg[MODE4] & 6) == 6;
27 }
28
29 static void
30 pixeldraw(int x, int y, int v)
31 {
32         u32int *p;
33         union { u32int l; u8int b[4]; } u;
34
35         p = (u32int *)pic + (x + y * 320) * scale;
36         u.b[0] = v >> 16;
37         u.b[1] = v >> 8;
38         u.b[2] = v;
39         u.b[3] = 0;
40         switch(scale){
41         case 16: *p++ = u.l;
42         case 15: *p++ = u.l;
43         case 14: *p++ = u.l;
44         case 13: *p++ = u.l;
45         case 12: *p++ = u.l;
46         case 11: *p++ = u.l;
47         case 10: *p++ = u.l;
48         case 9: *p++ = u.l;
49         case 8: *p++ = u.l;
50         case 7: *p++ = u.l;
51         case 6: *p++ = u.l;
52         case 5: *p++ = u.l;
53         case 4: *p++ = u.l;
54         case 3: *p++ = u.l;
55         case 2: *p++ = u.l;     /* intla ignored */
56         default: *p = u.l;
57         }
58 }
59
60 static u32int
61 shade(u32int v, int l)
62 {
63         if(l == 1)
64                 return v;
65         if(l == 2)
66                 return v << 1 & 0xefefef;
67         return v >> 1 & 0xf7f7f7;
68 }
69
70 static void
71 pixel(int v, int p)
72 {
73         if(p >= pri){
74                 col = v;
75                 pri = p;
76         }
77 }
78
79 struct pctxt {
80         u8int ws, w, hs, h;
81         u16int tx, ty;
82         u8int tnx, tny;
83         u16int t;
84         u32int c;
85 } pctxt[3];
86 int lwin, rwin;
87
88 static void
89 tile(struct pctxt *p)
90 {
91         u16int a;
92         int y;
93         
94         switch(p - pctxt){
95         default: a = (reg[PANT] & 0x38) << 9; break;
96         case 1: a = (reg[PBNT] & 7) << 12; break;
97         case 2: a = (reg[PWNT] & 0x3e) << 9; break;
98         }
99         a += p->ty << p->ws;
100         a += p->tx;
101         p->t = vram[a];
102         y = p->tny;
103         if(intla){
104                 if((p->t & 0x1000) != 0)
105                         y = 15 - y;
106                 a = (p->t & 0x7ff) << 5 | y << 1;
107         }else{
108                 if((p->t & 0x1000) != 0)
109                         y = 7 - y;
110                 a = (p->t & 0x7ff) << 4 | y << 1;
111         }
112         p->c = vram[a] << 16 | vram[a+1];
113 }
114
115 static void
116 planeinit(void)
117 {
118         static int szs[] = {5, 6, 6, 7};
119         int v, a, i;
120         struct pctxt *p;
121         
122         pctxt[0].hs = pctxt[1].hs = szs[reg[PLSIZ] >> 4 & 3];
123         pctxt[0].ws = pctxt[1].ws = szs[reg[PLSIZ] & 3];
124         pctxt[2].ws = (reg[MODE4] & WIDE) != 0 ? 6 : 5;
125         pctxt[2].hs = 5;
126         for(i = 0; i <= 2; i++){
127                 pctxt[i].h = 1<<pctxt[i].hs;
128                 pctxt[i].w = 1<<pctxt[i].ws;
129         }
130         a = reg[HORSCR] << 9 & 0x7fff;
131         switch(reg[MODE3] & 3){
132         case 1: a += vdpy << 1 & 0xe; break;
133         case 2: a += vdpy << 1 & 0xff0; break;
134         case 3: a += vdpy << 1 & 0xffe; break;
135         }
136         for(i = 0; i < 2; i++){
137                 p = pctxt + i;
138                 v = -(vram[a + i] & 0x3ff);
139                 p->tnx = v & 7;
140                 p->tx = v >> 3 & pctxt[i].w - 1;
141                 if(intla){
142                         v = vsram[i] + vdpyy;
143                         p->tny = v & 15;
144                         p->ty = v >> 4 & pctxt[i].h - 1;
145                 }else{
146                         v = vsram[i] + vdpy;
147                         p->tny = v & 7;
148                         p->ty = v >> 3 & pctxt[i].h - 1;
149                 }
150                 tile(p);
151                 if(p->tnx != 0)
152                         if((p->t & 0x800) != 0)
153                                 p->c >>= p->tnx << 2;
154                         else
155                                 p->c <<= p->tnx << 2;
156         }
157         sx = 0;
158         snx = 0;
159         v = reg[WINV] << 3 & 0xf8;
160         if((reg[WINV] & 0x80) != 0 ? vdpy < v : vdpy >= v){
161                 lwin = 0;
162                 rwin = reg[WINH] << 4 & 0x1f0;
163                 if((reg[WINH] & 0x80) != 0){
164                         lwin = rwin;
165                         rwin = 320;
166                 }
167         }else{
168                 lwin = 0;
169                 rwin = 320;
170         }
171         if(rwin > lwin){
172                 p = pctxt + 2;
173                 p->tx = lwin >> 3 & pctxt[2].w - 1;
174                 p->tnx = lwin & 7;
175                 p->tny = vdpy & 7;
176                 p->ty = vdpy >> 3 & pctxt[2].h - 1;
177                 tile(p);
178         }
179 }
180
181 static void
182 plane(int n, int vis)
183 {
184         struct pctxt *p;
185         u8int v, pr;
186         
187         p = pctxt + n;
188         if((p->t & 0x800) != 0){
189                 v = p->c & 15;
190                 p->c >>= 4;
191         }else{
192                 v = p->c >> 28;
193                 p->c <<= 4;
194         }
195         if(vis != 0){
196                 if(v != 0){
197                         v |= p->t >> 9 & 48;
198                         pr = 2 - (n & 1) + (p->t >> 13 & 4);
199                         pixel(v, pr);
200                 }
201                 lum |= p->t >> 15;
202         }
203         if(++p->tnx == 8){
204                 p->tnx = 0;
205                 if(++p->tx == p->w)
206                         p->tx = 0;
207                 tile(pctxt + n);
208         }
209 }
210
211 static void
212 planes(void)
213 {
214         int i, w;
215         u16int v;
216
217         if((reg[MODE3] & 4) != 0 && ++snx == 16){
218                 snx = 0;
219                 sx++;
220                 for(i = 0; i < 2; i++){
221                         v = vsram[sx + i] + vdpy;
222                         pctxt[i].tny = v & 7;
223                         pctxt[i].ty = v >> 3 & pctxt[i].h - 1;
224                 }
225         }
226         w = vdpx < rwin && vdpx >= lwin;
227         plane(0, !w);
228         plane(1, 1);
229         if(w)
230                 plane(2, 1);
231 }
232
233 static struct sprite {
234         u16int y, x;
235         u8int w, h;
236         u16int t;
237         u32int c[4];
238 } spr[21], *lsp;
239
240 static void
241 spritesinit(void)
242 {
243         u16int t, *p, dy, c;
244         u32int v;
245         int i, ns, np, nt;
246         struct sprite *q;
247         
248         t = (reg[SPRTAB] << 8 & 0x7f00);
249         p = vram + t;
250         q = spr;
251         ns = (reg[MODE4] & WIDE) != 0 ? 20 : 16;
252         np = 0;
253         nt = 0;
254         do{
255                 if(intla){
256                         q->y = (p[0] & 0x3ff) - 256;
257                         q->h = (p[1] >> 8 & 3) + 1 << 4;
258                         dy = vdpyy - q->y;
259                 }else{
260                         q->y = (p[0] & 0x3ff) - 128;
261                         q->h = (p[1] >> 8 & 3) + 1 << 3;
262                         dy = vdpy - q->y;
263                 }
264                 if(dy >= q->h)
265                         continue;
266                 q->t = p[2];
267                 if((q->t & 0x1000) != 0)
268                         dy = q->h + ~dy;
269                 q->x = (p[3] & 0x3ff) - 128;
270                 if(q->x == 0xff80)
271                         break;
272                 q->w = (p[1] >> 10 & 3) + 1 << 3;
273                 c = ((q->t & 0x7ff) << 4+intla) + (dy << 1);
274                 for(i = 0; i < q->w >> 3 && np < xdisp; i++){
275                         v = vram[c] << 16 | vram[(u16int)(c+1)];
276                         c += q->h << 1;
277                         if((q->t & 0x800) != 0)
278                                 q->c[(q->w >> 3) - 1 - i] = v;
279                         else
280                                 q->c[i] = v;
281                         np += 8;
282                 }
283                 if((u16int)-q->x < q->w){
284                         i = -(s16int)q->x;
285                         if((q->t & 0x800) != 0)
286                                 q->c[i>>3] >>= (i & 7) << 2;
287                         else
288                                 q->c[i>>3] <<= (i & 7) << 2;
289                 }
290                 if(++q == spr + ns || np >= xdisp){
291                         vdpstat |= STATOVR;
292                         break;
293                 }
294         }while(p = vram + (u16int)(t + ((p[1] & 0x7f) << 2)), p - vram != t && ++nt < 80);
295         lsp = q;
296 }
297
298 static void
299 sprites(void)
300 {
301         struct sprite *p;
302         u16int dx;
303         int v, col, set;
304         u32int *c;
305         
306         set = 0;
307         col = 0;
308         for(p = spr; p < lsp; p++){
309                 dx = vdpx - p->x;
310                 if(dx >= p->w)
311                         continue;
312                 c = p->c + (dx >> 3);
313                 if((p->t & 0x800) != 0){
314                         v = *c & 15;
315                         *c >>= 4;
316                 }else{
317                         v = *c >> 28;
318                         *c <<= 4;
319                 }
320                 if(v != 0)
321                         if(set != 0)
322                                 vdpstat |= STATCOLL;
323                         else{
324                                 set = 1 | p->t & 0x8000;
325                                 col = p->t >> 9 & 48 | v;
326                         }
327         }
328         if(set)
329                 if((reg[MODE4] & SHI) != 0)
330                         if((col & 0xfe) == 0x3e)
331                                 lum = col & 1;
332                         else{
333                                 pixel(col, set >> 13 | 2);
334                                 if((col & 0xf) == 0xe)
335                                         lum = 1;
336                                 else
337                                         lum |= set >> 15;
338                         }
339                 else
340                         pixel(col, set >> 13 | 2);
341 }
342
343 void
344 vdpstep(void)
345 {
346         u32int v;
347
348         if(vdpx == 0){
349                 planeinit();
350                 spritesinit();
351         }
352         if(vdpx < 320 && vdpy < 224)
353                 if(vdpx < xdisp){
354                         col = reg[BGCOL] & 0x3f;
355                         pri = 0;
356                         lum = 0;
357                         planes();
358                         sprites();
359                         if((reg[MODE2] & 0x40) != 0 && (vdpx >= 8 || (reg[MODE1] & 0x20) == 0)){
360                                 v = cramc[col];
361                                 if((reg[MODE4] & SHI) != 0)
362                                         v = shade(v, lum);
363                                 pixeldraw(vdpx, vdpy, v);
364                         }else
365                                 pixeldraw(vdpx, vdpy, 0);
366                 }else
367                         pixeldraw(vdpx, vdpy, 0xcccccc);
368         if(++vdpx >= xmax){
369                 z80irq = 0;
370                 vdpx = 0;
371                 if(++vdpy >= ymax){
372                         vdpy = 0;
373                         irq &= ~INTVBL;
374                         vdpstat ^= STATFR;
375                         vdpstat &= ~(STATINT | STATVBL | STATOVR | STATCOLL);
376                         flush();
377                 }
378                 if(intla)
379                         vdpyy = vdpy << 1 | frame;
380                 if(vdpy == 0 || vdpy >= 225)
381                         hctr = reg[HORCTR];
382                 else
383                         if(hctr-- == 0){
384                                 if((reg[MODE1] & IE1) != 0)
385                                         irq |= INTHOR;
386                                 hctr = reg[HORCTR];
387                         }
388                 if(vdpy == yvbl){
389                         vdpstat |= STATVBL | STATINT;
390                         frame ^= 1;
391                         z80irq = 1;
392                         if((reg[MODE2] & IE0) != 0)
393                                 irq |= INTVBL;
394                 }
395         }
396 }