sms wip: initial graphics support
[picodrive.git] / pico / mode4.c
1 #include "pico_int.h"
2
3 static void (*FinalizeLineM4)(void);
4 static int skip_next_line;
5
6 #define PLANAR_PIXEL(x,p) \
7   t = pack & (0x80808080 >> p); \
8   if (t) { \
9     t = ((t >> (7-p)) | (t >> (14-p)) | (t >> (21-p)) | (t >> (28-p))) & 0x0f; \
10     pd[x] = pal|t; \
11   }
12
13 static int TileNormM4(int sx, int addr, int pal)
14 {
15   unsigned char *pd = HighCol + sx;
16   unsigned int pack, t;
17
18   pack = *(unsigned int *)(Pico.vram + addr); /* Get 4 bitplanes / 8 pixels */
19   if (pack)
20   {
21     PLANAR_PIXEL(0, 0)
22     PLANAR_PIXEL(1, 1)
23     PLANAR_PIXEL(2, 2)
24     PLANAR_PIXEL(3, 3)
25     PLANAR_PIXEL(4, 4)
26     PLANAR_PIXEL(5, 5)
27     PLANAR_PIXEL(6, 6)
28     PLANAR_PIXEL(7, 7)
29     return 0;
30   }
31
32   return 1; /* Tile blank */
33 }
34
35 static int TileFlipM4(int sx,int addr,int pal)
36 {
37   unsigned char *pd = HighCol + sx;
38   unsigned int pack, t;
39
40   pack = *(unsigned int *)(Pico.vram + addr); /* Get 4 bitplanes / 8 pixels */
41   if (pack)
42   {
43     PLANAR_PIXEL(0, 7)
44     PLANAR_PIXEL(1, 6)
45     PLANAR_PIXEL(2, 5)
46     PLANAR_PIXEL(3, 4)
47     PLANAR_PIXEL(4, 3)
48     PLANAR_PIXEL(5, 2)
49     PLANAR_PIXEL(6, 1)
50     PLANAR_PIXEL(7, 0)
51     return 0;
52   }
53
54   return 1; /* Tile blank */
55 }
56
57 struct TileStrip
58 {
59   int nametab; // Position in VRAM of name table (for this tile line)
60   int line;    // Line number in pixels 0x000-0x3ff within the virtual tilemap
61   int hscroll; // Horizontal scroll value in pixels for the line
62   int xmask;   // X-Mask (0x1f - 0x7f) for horizontal wraparound in the tilemap
63   int *hc;     // cache for high tile codes and their positions
64   int cells;   // cells (tiles) to draw (32 col mode doesn't need to update whole 320)
65 };
66
67 static void DrawStrip(struct TileStrip *ts, int cellskip)
68 {
69   int tilex,dx,ty,code=0,addr=0,cells;
70   int oldcode=-1,blank=-1; // The tile we know is blank
71   int pal=0;
72
73   // Draw tiles across screen:
74   tilex=((-ts->hscroll)>>3)+cellskip;
75   ty=(ts->line&7)<<1; // Y-Offset into tile
76   dx=((ts->hscroll-1)&7)+1;
77   cells = ts->cells - cellskip;
78   if (dx != 8) cells++; // have hscroll, need to draw 1 cell more
79   dx+=cellskip<<3;
80
81   for (; cells > 0; dx+=8,tilex++,cells--)
82   {
83     int zero;
84
85     code=Pico.vram[ts->nametab + (tilex & 0x1f)];
86     if (code==blank) continue;
87
88     if (code!=oldcode) {
89       oldcode = code;
90       // Get tile address/2:
91       addr=(code&0x1ff)<<4;
92       addr+=ty;
93       if (code&0x0400) addr^=0xe; // Y-flip
94
95       pal=((code>>7)&0x10);
96     }
97
98     if (code&0x0200) zero=TileFlipM4(dx,addr,pal);
99     else             zero=TileNormM4(dx,addr,pal);
100
101     if (zero) blank=code; // We know this tile is blank now
102   }
103 }
104
105 static void DrawLayer(int cellskip, int maxcells)
106 {
107   struct PicoVideo *pvid=&Pico.video;
108   struct TileStrip ts;
109   int vscroll;
110
111   ts.cells=maxcells;
112
113   // Find name table:
114   ts.nametab=(pvid->reg[2]&0x0e) << (10-1);
115
116   // Get horizontal scroll value, will be masked later
117   ts.hscroll=0;//pvid->reg[8];
118   vscroll=0;//pvid->reg[9]; // Get vertical scroll value
119
120   // Find the line in the name table
121   ts.line=(vscroll+DrawScanline)&0xff;
122   ts.nametab+=(ts.line>>3) << (6-1);
123
124   DrawStrip(&ts, cellskip);
125 }
126
127 static void DrawDisplayM4(void)
128 {
129   DrawLayer(0, 32);
130 }
131
132 void PicoFrameStartMode4(void)
133 {
134   DrawScanline = 0;
135   skip_next_line = 0;
136 }
137
138 void PicoLineMode4(int line)
139 {
140   if (skip_next_line > 0) {
141     skip_next_line--;
142     return;
143   }
144
145   DrawScanline = line;
146
147   if (PicoScanBegin != NULL)
148     skip_next_line = PicoScanBegin(DrawScanline);
149
150   // Draw screen:
151   BackFill((Pico.video.reg[7] & 0x0f) | 0x10, 0);
152   if (Pico.video.reg[1] & 0x40)
153     DrawDisplayM4();
154
155   if (FinalizeLineM4 != NULL)
156     FinalizeLineM4();
157
158   if (PicoScanEnd != NULL)
159     skip_next_line = PicoScanEnd(DrawScanline);
160 }
161
162 void PicoDoHighPal555M4(void)
163 {
164   unsigned int *spal=(void *)Pico.cram;
165   unsigned int *dpal=(void *)HighPal;
166   unsigned int t;
167   int i;
168
169   Pico.m.dirtyPal = 0;
170
171   /* cram is always stored as shorts, even though real hardware probably uses bytes */
172   for (i = 0x20/2; i > 0; i--, spal++, dpal++) {
173     t = *spal;
174 #ifdef USE_BGR555
175     t = ((t & 0x00030003)<< 3) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)<<10);
176 #else
177     t = ((t & 0x00030003)<<14) | ((t & 0x000c000c)<<7) | ((t & 0x00300030)>>1);
178 #endif
179     t |= t >> 2;
180     t |= (t >> 4) & 0x08610861;
181     *dpal = t;
182   }
183 }
184
185 static void FinalizeLineRGB555M4(void)
186 {
187   unsigned short *pd=DrawLineDest;
188   unsigned char  *ps=HighCol+8;
189   unsigned short *pal=HighPal;
190   int i;
191
192   if (Pico.m.dirtyPal)
193     PicoDoHighPal555M4();
194
195   if (!(PicoOpt & POPT_DIS_32C_BORDER))
196     pd += 32;
197
198   for (i = 256/4; i > 0; i--) {
199     *pd++ = pal[*ps++];
200     *pd++ = pal[*ps++];
201     *pd++ = pal[*ps++];
202     *pd++ = pal[*ps++];
203   }
204 }
205
206 void PicoDrawSetColorFormatMode4(int which)
207 {
208   switch (which)
209   {
210     case 1: FinalizeLineM4 = FinalizeLineRGB555M4; break;
211     default:FinalizeLineM4 = NULL; break;
212   }
213 #if OVERRIDE_HIGHCOL
214   if (which)
215     HighCol = DefHighCol;
216 #endif
217 }
218