sms wip: initial graphics support
[picodrive.git] / pico / mode4.c
CommitLineData
200772b7 1#include "pico_int.h"
2
3static void (*FinalizeLineM4)(void);
4static 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
13static 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
35static 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
57struct 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
67static 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
105static 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
127static void DrawDisplayM4(void)
128{
129 DrawLayer(0, 32);
130}
131
132void PicoFrameStartMode4(void)
133{
134 DrawScanline = 0;
135 skip_next_line = 0;
136}
137
138void 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
162void 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
185static 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
206void 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