OSDN Git Service

[General][Qt] Merge upstream 2015-03-15.
[csp-qt/common_source_project-fm7.git] / source / src / vm / scv / vdp.cpp
1 /*
2         EPOCH Super Cassette Vision Emulator 'eSCV'
3
4         Author : Takeda.Toshiya
5         Date   : 2006.08.21 -
6
7         [ EPOCH TV-1 ]
8 */
9
10 #include "vdp.h"
11 #include "../upd7801.h"
12
13 static const scrntype palette_pc[16] = {
14 #if 1
15         RGB_COLOR(  0, 90,156), RGB_COLOR(  0,  0,  0), RGB_COLOR( 58,148,255), RGB_COLOR(  0,  0,255),
16         RGB_COLOR( 16,214,  0), RGB_COLOR( 66,255, 16), RGB_COLOR(123,230,197), RGB_COLOR(  0,173,  0),
17         RGB_COLOR(255, 41,148), RGB_COLOR(255, 49, 16), RGB_COLOR(255, 58,255), RGB_COLOR(239,156,255),
18         RGB_COLOR(255,206, 33), RGB_COLOR( 74,123, 16), RGB_COLOR(165,148,165), RGB_COLOR(255,255,255)
19 #else
20         RGB_COLOR(  0, 90,156), RGB_COLOR(  0,  0,  0), RGB_COLOR(  0, 58,255), RGB_COLOR(  0,  0,255),
21         RGB_COLOR(  0,255,  0), RGB_COLOR( 58,255, 90), RGB_COLOR(  0,255,255), RGB_COLOR(  0,255,  0),
22         RGB_COLOR(255, 58,156), RGB_COLOR(255,156,156), RGB_COLOR(255, 58,255), RGB_COLOR(255,156,255),
23         RGB_COLOR(255,255, 90), RGB_COLOR(123,156,  0), RGB_COLOR(189,189,189), RGB_COLOR(255,255,255)
24 #endif
25 };
26
27 #if 1
28 // table analyzed by Enri
29 static const uint8 color_pair0[16] = {0x0, 0xf, 0xc, 0xd, 0xa, 0xb, 0x8, 0x9, 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x1, 0x1};
30 static const uint8 color_pair1[16] = {0x0, 0x1, 0x8, 0xb, 0x2, 0x3, 0xa, 0x9, 0x4, 0x5, 0xc, 0xd, 0x6, 0x7, 0xe, 0xf};
31 #else
32 static const uint8 color_pair0[16] = {0xe, 0xf, 0xc, 0xd, 0xa, 0xb, 0x8, 0x9, 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1};
33 static const uint8 color_pair1[16] = {0x0, 0x1, 0x8, 0x9, 0x2, 0x3, 0xa, 0xb, 0x4, 0x5, 0xc, 0xd, 0x6, 0x7, 0xe, 0xf};
34 #endif
35
36 static const uint8 symbol[32][8] = {
37         {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x00,0x02,0x7a,0x84,0x84,0x7a,0x00,0x00},
38         {0x00,0x3c,0x42,0x7c,0x42,0x7c,0x40,0x40},{0x00,0x62,0x94,0x08,0x08,0x08,0x00,0x00},
39         {0x00,0xfc,0x50,0x50,0x52,0x8c,0x00,0x00},{0xfe,0x82,0x60,0x10,0x60,0x82,0xfe,0x00},
40         {0x38,0x44,0x82,0x82,0x82,0x44,0xc6,0x00},{0x10,0x7c,0xfe,0xfe,0xfe,0x10,0x38,0x00},
41         {0x6c,0xfe,0xfe,0xfe,0xfe,0x7c,0x10,0x00},{0x10,0x10,0x38,0xfe,0x38,0x10,0x10,0x00},
42         {0x10,0x7c,0x92,0xfe,0x92,0x10,0x38,0x00},{0x38,0x44,0xba,0xa2,0xba,0x44,0x38,0x00},
43         {0x80,0x80,0x88,0x44,0x3e,0x04,0x08,0x00},{0x02,0x02,0x22,0x44,0xf8,0x40,0x20,0x00},
44         {0x10,0x00,0x00,0xfe,0x00,0x00,0x10,0x00},{0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x00},
45         {0x7c,0x82,0x82,0x82,0x82,0x82,0x7c,0x00},{0x7c,0xfe,0xfe,0xfe,0xfe,0xfe,0x7c,0x00},
46         {0x7c,0x82,0xba,0xba,0xba,0x82,0x7c,0x00},{0xfe,0x82,0x82,0x82,0x82,0x82,0xfe,0x00},
47         {0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55},{0xff,0x80,0x80,0x80,0x80,0x80,0x80,0x80},
48         {0xff,0x01,0x01,0x01,0x01,0x01,0x01,0x01},{0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xff},
49         {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xff},{0xfe,0x00,0xfe,0x10,0x10,0x10,0x10,0x00},
50         {0x18,0x14,0x12,0x12,0x72,0xf0,0x60,0x00},{0x18,0x14,0x12,0x12,0x72,0x90,0x60,0x00},
51         {0x10,0x08,0x04,0xfe,0x04,0x08,0x10,0x00},{0x10,0x20,0x40,0xfe,0x40,0x20,0x10,0x00},
52         {0x10,0x38,0x54,0x92,0x10,0x10,0x10,0x00},{0x10,0x10,0x10,0x92,0x54,0x38,0x10,0x00}
53 };
54
55 void VDP::initialize()
56 {
57         // copy font in bios
58         for(int i = 0, c = 0x20, p = 0; i < 3; i++, c += 32) {
59                 for(int j = 0; j < 16; j++) {
60                         for(int k = 0; k < 8; k += 2) {
61                                 uint8 d0 = font_ptr[p++];
62                                 uint8 d1 = font_ptr[p++];
63                                 uint8 d2 = font_ptr[p++];
64                                 uint8 d3 = font_ptr[p++];
65                                 
66                                 font[c + j     ][k    ] = (d0 & 0xf0) | (d1 >> 4);
67                                 font[c + j + 16][k    ] = (d2 & 0xf0) | (d3 >> 4);
68                                 font[c + j     ][k + 1] = (d0 << 4) | (d1 & 0x0f);
69                                 font[c + j + 16][k + 1] = (d2 << 4) | (d3 & 0x0f);
70                         }
71                 }
72         }
73         memcpy(font, symbol, sizeof(symbol));
74         memcpy(font[0xb], font[0x60], 8);       // copyright mark
75         
76         // register event to interrupt
77         register_vline_event(this);
78 }
79
80 void VDP::event_vline(int v, int clock)
81 {
82         if(v == 239) {
83                 d_cpu->write_signal(SIG_UPD7801_INTF2, 1, 1);
84         } else if(v == 261) {
85                 d_cpu->write_signal(SIG_UPD7801_INTF2, 0, 1);
86         }
87 }
88
89 void VDP::draw_screen()
90 {
91         // get vdc control params
92         vdc0 = vram1[0x400];
93         vdc1 = vram1[0x401];
94         vdc2 = vram1[0x402];
95         vdc3 = vram1[0x403];
96         
97         // draw text screen
98         memset(text, vdc1 & 0xf, sizeof(text));
99         draw_text_screen();
100         
101         // draw sprite screen
102         memset(sprite, 0, sizeof(sprite));
103         if(vdc0 & 0x10) {
104                 draw_sprite_screen();
105         }
106         
107         // mix screens
108         int ty = ((vdc0 & 0xf7) == 0x17 && (vdc2 & 0xef) == 0x4f) ? 32 : 0;
109         uint16 back = palette_pc[vdc1 & 0xf];
110         
111         for(int y = 0; y < ty; y++) {
112                 // patch for nekketsu kung-fu road
113                 scrntype* d = emu->screen_buffer(y);
114                 uint8* t = &text[y + 23][24];
115                 
116                 for(int x = 0; x < SCREEN_WIDTH; x++) {
117                         d[x] = palette_pc[t[x]];
118                 }
119         }
120         for(int y = ty; y < SCREEN_HEIGHT; y++) {
121                 scrntype* d = emu->screen_buffer(y);
122                 uint8* s = &sprite[y + 21][28];
123                 uint8* t = &text[y + 23][24];
124                 
125                 for(int x = 0; x < SCREEN_WIDTH; x++) {
126                         d[x] = palette_pc[s[x] ? s[x] : t[x]];
127                 }
128         }
129 }
130
131 void VDP::draw_text_screen()
132 {
133         int xmax = (vdc2 & 0xf) * 2;
134         //xmax = xmax ? xmax : 32;
135         int ymax = vdc2 >> 4;
136         int xs = (vdc0 & 0x40) ? xmax : 0;
137         int xe = (vdc0 & 0x40) ? 32 : xmax;
138         int ys = (vdc0 & 0x80) ? ymax : 0;
139         int ye = (vdc0 & 0x80) ? 16 : ymax;
140         
141         uint8 ct = vdc3 >> 4;
142         uint8 cb = vdc3 & 0xf;
143         uint8 cg = vdc1 >> 4;
144         
145         for(int y = 1; y < 16; y++) {
146                 bool t = (ys <= y && y < ye);
147                 int y32 = y << 5;
148                 
149                 for(int x = 2; x < 29; x++) {
150                         if(t && (xs <= x && x < xe)) {
151                                 // draw text
152                                 uint8 data = (x < 26) ? (vram1[y32 + x] & 0x7f) : 0;
153                                 draw_text(x, y, data, ct, cb);
154                         } else if((vdc0 & 3) == 1) {
155                                 // semi graph
156                                 uint8 data = vram1[y32 + x];
157                                 draw_graph(x, y, data, cg);
158                         } else if((vdc0 & 3) == 3) {
159                                 // block
160                                 uint8 data = vram1[y32 + x];
161                                 draw_block(x, y, data);
162                         }
163                 }
164         }
165 }
166
167 void VDP::draw_text(int dx, int dy, uint8 data, uint8 tcol, uint8 bcol)
168 {
169         int dx8 = dx << 3, dy16 = dy << 4;
170         
171         for(int l = 0; l < 8 && data; l++) {
172                 uint8* dest = &text[dy16 + l][dx8];
173                 uint8 pat = font[data][l];
174                 
175                 dest[0] = (pat & 0x80) ? tcol : bcol;
176                 dest[1] = (pat & 0x40) ? tcol : bcol;
177                 dest[2] = (pat & 0x20) ? tcol : bcol;
178                 dest[3] = (pat & 0x10) ? tcol : bcol;
179                 dest[4] = (pat & 0x08) ? tcol : bcol;
180                 dest[5] = (pat & 0x04) ? tcol : bcol;
181                 dest[6] = (pat & 0x02) ? tcol : bcol;
182                 dest[7] = (pat & 0x01) ? tcol : bcol;
183         }
184         for(int l = (data ? 8 : 0); l < 16; l++) {
185                 memset(&text[dy16 + l][dx8], bcol, 8);
186         }
187 }
188
189 void VDP::draw_block(int dx, int dy, uint8 data)
190 {
191         int dx8 = dx << 3, dy16 = dy << 4;
192         uint8 cu = data >> 4, cl = data & 0xf;
193         
194         if(cu) {
195                 for(int l = 0; l < 8; l++) {
196                         memset(&text[dy16 + l][dx8], cu, 8);
197                 }
198         }
199         if(cl) {
200                 for(int l = 8; l < 16; l++) {
201                         memset(&text[dy16 + l][dx8], cl, 8);
202                 }
203         }
204 }
205
206 void VDP::draw_graph(int dx, int dy, uint8 data, uint8 col)
207 {
208         int dx8l = dx << 3, dx8r = (dx << 3) + 4, dy16 = dy << 4;
209         
210         if(data & 0x80) {
211                 for(int l = 0; l < 4; l++) {
212                         memset(&text[dy16 + l][dx8l], col, 4);
213                 }
214         }
215         if(data & 0x40) {
216                 for(int l = 0; l < 4; l++) {
217                         memset(&text[dy16 + l][dx8r], col, 4);
218                 }
219         }
220         if(data & 0x20) {
221                 for(int l = 4; l < 8; l++) {
222                         memset(&text[dy16 + l][dx8l], col, 4);
223                 }
224         }
225         if(data & 0x10) {
226                 for(int l = 4; l < 8; l++) {
227                         memset(&text[dy16 + l][dx8r], col, 4);
228                 }
229         }
230         if(data & 0x08) {
231                 for(int l = 8; l < 12; l++) {
232                         memset(&text[dy16 + l][dx8l], col, 4);
233                 }
234         }
235         if(data & 0x04) {
236                 for(int l = 8; l < 12; l++) {
237                         memset(&text[dy16 + l][dx8r], col, 4);
238                 }
239         }
240         if(data & 0x02) {
241                 for(int l = 12; l < 16; l++) {
242                         memset(&text[dy16 + l][dx8l], col, 4);
243                 }
244         }
245         if(data & 0x01) {
246                 for(int l = 12; l < 16; l++) {
247                         memset(&text[dy16 + l][dx8r], col, 4);
248                 }
249         }
250 }
251
252 void VDP::draw_sprite_screen()
253 {
254         for(int index = 0; index < 128; index++) {
255                 uint8 atb0 = vram1[0x200 + (index << 2)];
256                 uint8 atb1 = vram1[0x201 + (index << 2)];
257                 uint8 atb2 = vram1[0x202 + (index << 2)];
258                 uint8 atb3 = vram1[0x203 + (index << 2)];
259                 
260                 int dx = atb2 & 0xfe;
261                 int dy = atb0 & 0xfe;
262                 bool conx = ((atb2 & 1) != 0);
263                 bool cony = ((atb0 & 1) != 0);
264                 uint8 col0 = atb1 & 0xf;
265                 
266                 int sx = 0, ex = 4;
267                 int sy = atb1 >> 4, ey = 8;
268                 if(atb3 & 0x80) {
269                         // half/quarter sprite
270                         if(atb3 & 0x40) {
271                                 sy = !cony ? 0 : 4;
272                                 ey = !cony ? 4 : 8;
273                                 dy = !cony ? dy : dy - 8;
274                                 cony = false;
275                         }
276                         sx = !conx ? 0 : 2;
277                         ex = !conx ? 2 : 4;
278                         dx = !conx ? dx : dx - 8;
279                         conx = false;
280                         
281                         atb3 &= 0x7f;
282                 }
283                 
284                 if((index & 0x20) && (vdc0 & 0x20)) {
285                         // 2 colors sprite
286                         uint8 col1 = (index & 0x40) ? color_pair1[col0] : color_pair0[col0];
287                         int no1 = atb3, no2 = atb3 ^ ((conx ? 8 : 0) | (cony ? 1 : 0));
288                         
289                         draw_sprite(dx, dy, sx, ex, sy, ey, no1, col0);
290                         if(conx || cony) {
291                                 draw_sprite(dx, dy, sx, ex, sy, ey, no2, col1);
292                         }
293                 } else {
294                         // mono color sprite
295                         int no1 = atb3, no2 = atb3 | 1, no3 = atb3 | 8, no4 = atb3 | 9;
296                         
297                         draw_sprite(dx, dy, sx, ex, sy, ey, no1, col0);
298                         if(cony) {
299                                 draw_sprite(dx, dy + 16, sx, ex, sy - 8, 8, no2, col0);
300                         }
301                         if(conx) {
302                                 draw_sprite(dx + 16, dy, 0, 4, sy, ey, no3, col0);
303                         }
304                         if(conx && cony) {
305                                 draw_sprite(dx + 16, dy + 16, 0, 4, sy - 8, 8, no4, col0);
306                         }
307                 }
308         }
309 }
310
311 void VDP::draw_sprite(int dx, int dy, int sx, int ex, int sy, int ey, int no, uint8 col)
312 {
313         // color #0 is transparent
314         if(!col) {
315                 return;
316         }
317         for(int y = (sy < 0 ? 0 : sy), no32 = no << 5; y < ey; y++) {
318                 int y2u = (y << 1) + dy, y2l = (y << 1) + dy + 1, y4 = (y << 2) + no32;
319                 
320                 for(int x = sx; x < ex; x++) {
321                         int x4 = dx + (x << 2);
322                         uint8* du = &sprite[y2u][x4];
323                         uint8* dl = &sprite[y2l][x4];
324                         uint8 p = vram0[y4 + x];
325                         
326                         if(p & 0x80) du[0] = col;
327                         if(p & 0x40) du[1] = col;
328                         if(p & 0x20) du[2] = col;
329                         if(p & 0x10) du[3] = col;
330                         if(p & 0x08) dl[0] = col;
331                         if(p & 0x04) dl[1] = col;
332                         if(p & 0x02) dl[2] = col;
333                         if(p & 0x01) dl[3] = col;
334                 }
335         }
336 }
337
338 #define STATE_VERSION   1
339
340 void VDP::save_state(FILEIO* state_fio)
341 {
342         state_fio->FputUint32(STATE_VERSION);
343         state_fio->FputInt32(this_device_id);
344         
345         state_fio->FputUint8(vdc0);
346         state_fio->FputUint8(vdc1);
347         state_fio->FputUint8(vdc2);
348         state_fio->FputUint8(vdc3);
349 }
350
351 bool VDP::load_state(FILEIO* state_fio)
352 {
353         if(state_fio->FgetUint32() != STATE_VERSION) {
354                 return false;
355         }
356         if(state_fio->FgetInt32() != this_device_id) {
357                 return false;
358         }
359         vdc0 = state_fio->FgetUint8();
360         vdc1 = state_fio->FgetUint8();
361         vdc2 = state_fio->FgetUint8();
362         vdc3 = state_fio->FgetUint8();
363         return true;
364 }
365