OSDN Git Service

Merge branch 'master' of https://github.com/sparky4/16
[proj16/16.git] / src / tesuto.c
1 #include <hw/cpu/cpu.h>
2 #include <hw/dos/dos.h>
3 #include <hw/vga/vga.h>
4 #include <hw/vga/vrl.h>
5
6 #include "src/tesuto.h"
7
8 static unsigned char palette[768];
9
10 int main(int argc,char **argv) {
11         struct vrl1_vgax_header *vrl_header;
12         vrl1_vgax_offset_t *vrl_lineoffs;
13         unsigned char *buffer;
14         unsigned int bufsz;
15         int fd;
16
17         if (argc < 3) {
18                 fprintf(stderr,"drawvrl <VRL file> <palette file>\n");
19                 return 1;
20         }
21
22         fd = open(argv[1],O_RDONLY|O_BINARY);
23         if (fd < 0) {
24                 fprintf(stderr,"Unable to open '%s'\n",argv[1]);
25                 return 1;
26         }
27         {
28                 unsigned long sz = lseek(fd,0,SEEK_END);
29                 if (sz < sizeof(*vrl_header)) return 1;
30                 if (sz >= 65535UL) return 1;
31
32                 bufsz = (unsigned int)sz;
33                 buffer = malloc(bufsz);
34                 if (buffer == NULL) return 1;
35
36                 lseek(fd,0,SEEK_SET);
37                 if ((unsigned int)read(fd,buffer,bufsz) < bufsz) return 1;
38
39                 vrl_header = (struct vrl1_vgax_header*)buffer;
40                 if (memcmp(vrl_header->vrl_sig,"VRL1",4) || memcmp(vrl_header->fmt_sig,"VGAX",4)) return 1;
41                 if (vrl_header->width == 0 || vrl_header->height == 0) return 1;
42         }
43         close(fd);
44
45         probe_dos();
46         if (!probe_vga()) {
47                 printf("VGA probe failed\n");
48                 return 1;
49         }
50         int10_setmode(19);
51         update_state_from_vga();
52         vga_enable_256color_modex(); // VGA mode X
53         vga_state.vga_width = 320; // VGA lib currently does not update this
54         vga_state.vga_height = 240; // VGA lib currently does not update this
55
56 //#if 1 // 320x240 test mode: this is how Project 16 is using our code, enable for test case
57         {
58                 struct vga_mode_params cm;
59
60                 vga_read_crtc_mode(&cm);
61
62                 // 320x240 mode 60Hz
63                 cm.vertical_total = 525;
64                 cm.vertical_start_retrace = 0x1EA;
65                 cm.vertical_end_retrace = 0x1EC;
66                 cm.vertical_display_end = 480;
67                 cm.vertical_blank_start = 489;
68                 cm.vertical_blank_end = 517;
69
70                 vga_write_crtc_mode(&cm,0);
71         }
72         vga_state.vga_height = 240; // VGA lib currently does not update this
73 //#endif
74
75         /* load color palette */
76         fd = open(argv[2],O_RDONLY|O_BINARY);
77         if (fd >= 0) {
78                 unsigned int i;
79
80                 read(fd,palette,768);
81                 close(fd);
82
83                 vga_palette_lseek(0);
84                 for (i=0;i < 256;i++) vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);
85         }
86
87         /* preprocess the sprite to generate line offsets */
88         vrl_lineoffs = vrl1_vgax_genlineoffsets(vrl_header,buffer+sizeof(*vrl_header),bufsz-sizeof(*vrl_header));
89         if (vrl_lineoffs == NULL) return 1;
90
91         {
92                 unsigned int i,j,o;
93
94                 /* fill screen with a distinctive pattern */
95                 for (i=0;i < vga_state.vga_width;i++) {
96                         o = i >> 2;
97                         vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
98                         for (j=0;j < vga_state.vga_height;j++,o += vga_state.vga_stride)
99                                 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
100                 }
101         }
102         while (getch() != 13);
103
104         /* make distinctive pattern offscreen, render sprite, copy onscreen */
105         {
106                 const unsigned int offscreen_ofs = (vga_state.vga_stride * vga_state.vga_height);
107                 unsigned int i,j,o,o2,x,y,rx,ry,w,h;
108                 unsigned int overdraw = 1;      // how many pixels to "overdraw" so that moving sprites with edge pixels don't leave streaks.
109                                                 // if the sprite's edge pixels are clear anyway, you can set this to 0.
110                 VGA_RAM_PTR omemptr;
111                 int xdir=1,ydir=1;
112
113                 /* starting coords. note: this technique is limited to x coordinates of multiple of 4 */
114                 x = 0;
115                 y = 0;
116
117                 /* do it */
118                 omemptr = vga_state.vga_graphics_ram; // save original mem ptr
119                 while (1) {
120                         /* stop animating if the user hits ENTER */
121                         if (kbhit()) {
122                                 if (getch() == 13) break;
123                         }
124
125                         /* render box bounds. y does not need modification, but x and width must be multiple of 4 */
126                         if (x >= overdraw) rx = (x - overdraw) & (~3);
127                         else rx = 0;
128                         if (y >= overdraw) ry = (y - overdraw);
129                         else ry = 0;
130                         h = vrl_header->height + overdraw + y - ry;
131                         w = (x + vrl_header->width + (overdraw*2) + 3/*round up*/ - rx) & (~3);
132                         if ((rx+w) > vga_state.vga_width) w = vga_state.vga_width-rx;
133                         if ((ry+h) > vga_state.vga_height) h = vga_state.vga_height-ry;
134
135                         /* replace VGA stride with our own and mem ptr. then sprite rendering at this stage is just (0,0) */
136                         vga_state.vga_draw_stride_limit = (vga_state.vga_width + 3/*round up*/ - x) >> 2;
137                         vga_state.vga_draw_stride = w >> 2;
138                         vga_state.vga_graphics_ram = omemptr + offscreen_ofs;
139
140                         /* first draw pattern corresponding to that part of the screen. this COULD be optimized, obviously, but it's designed for study.
141                          * also note we don't have to use the same stride as the display! */
142                         for (i=rx;i < (rx+w);i++) {
143                                 o = (i-rx) >> 2;
144                                 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
145                                 for (j=ry;j < (ry+h);j++,o += vga_state.vga_draw_stride)
146                                         vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
147                         }
148
149                         /* then the sprite. note modding ram ptr means we just draw to (x&3,0) */
150                         draw_vrl1_vgax_modex(x-rx,y-ry,vrl_header,vrl_lineoffs,buffer+sizeof(*vrl_header),bufsz-sizeof(*vrl_header));
151
152                         /* restore ptr */
153                         vga_state.vga_graphics_ram = omemptr;
154
155                         /* block copy to visible RAM from offscreen */
156                         vga_setup_wm1_block_copy();
157                         o = offscreen_ofs; // source offscreen
158                         o2 = (ry * vga_state.vga_stride) + (rx >> 2); // dest visible (original stride)
159                         for (i=0;i < h;i++,o += vga_state.vga_draw_stride,o2 += vga_state.vga_stride) vga_wm1_mem_block_copy(o2,o,w >> 2);
160                         /* must restore Write Mode 0/Read Mode 0 for this code to continue drawing normally */
161                         vga_restore_rm0wm0();
162
163                         /* restore stride */
164                         vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = vga_state.vga_stride;
165
166                         /* step */
167                         x += xdir;
168                         y += ydir;
169                         if (x >= (vga_state.vga_width - 1) || x == 0)
170                                 xdir = -xdir;
171                         if (y >= (vga_state.vga_height - 1) || y == 0)
172                                 ydir = -ydir;
173                 }
174         }
175
176         /* make distinctive pattern offscreen, render sprite, copy onscreen.
177          * this time, we render the distinctive pattern to another offscreen location and just copy.
178          * note this version is much faster too! */
179         {
180                 const unsigned int offscreen_ofs = (vga_state.vga_stride * vga_state.vga_height);
181                 const unsigned int pattern_ofs = 0x10000UL - (vga_state.vga_stride * vga_state.vga_height);
182                 unsigned int i,j,o,o2,x,y,rx,ry,w,h;
183                 unsigned int overdraw = 1;      // how many pixels to "overdraw" so that moving sprites with edge pixels don't leave streaks.
184                                                 // if the sprite's edge pixels are clear anyway, you can set this to 0.
185                 VGA_RAM_PTR omemptr;
186                 int xdir=1,ydir=1;
187
188                 /* fill pattern offset with a distinctive pattern */
189                 for (i=0;i < vga_state.vga_width;i++) {
190                         o = (i >> 2) + pattern_ofs;
191                         vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
192                         for (j=0;j < vga_state.vga_height;j++,o += vga_state.vga_stride)
193                                 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
194                 }
195
196                 /* starting coords. note: this technique is limited to x coordinates of multiple of 4 */
197                 x = 0;
198                 y = 0;
199
200                 /* do it */
201                 omemptr = vga_state.vga_graphics_ram; // save original mem ptr
202                 while (1) {
203                         /* stop animating if the user hits ENTER */
204                         if (kbhit()) {
205                                 if (getch() == 13) break;
206                         }
207
208                         /* render box bounds. y does not need modification, but x and width must be multiple of 4 */
209                         if (x >= overdraw) rx = (x - overdraw) & (~3);
210                         else rx = 0;
211                         if (y >= overdraw) ry = (y - overdraw);
212                         else ry = 0;
213                         h = vrl_header->height + overdraw + y - ry;
214                         w = (x + vrl_header->width + (overdraw*2) + 3/*round up*/ - rx) & (~3);
215                         if ((rx+w) > vga_state.vga_width) w = vga_state.vga_width-rx;
216                         if ((ry+h) > vga_state.vga_height) h = vga_state.vga_height-ry;
217
218                         /* block copy pattern to where we will draw the sprite */
219                         vga_setup_wm1_block_copy();
220                         o2 = offscreen_ofs;
221                         o = pattern_ofs + (ry * vga_state.vga_stride) + (rx >> 2); // source offscreen
222                         for (i=0;i < h;i++,o += vga_state.vga_stride,o2 += (w >> 2)) vga_wm1_mem_block_copy(o2,o,w >> 2);
223                         /* must restore Write Mode 0/Read Mode 0 for this code to continue drawing normally */
224                         vga_restore_rm0wm0();
225
226                         /* replace VGA stride with our own and mem ptr. then sprite rendering at this stage is just (0,0) */
227                         vga_state.vga_draw_stride_limit = (vga_state.vga_width + 3/*round up*/ - x) >> 2;
228                         vga_state.vga_draw_stride = w >> 2;
229                         vga_state.vga_graphics_ram = omemptr + offscreen_ofs;
230
231                         /* then the sprite. note modding ram ptr means we just draw to (x&3,0) */
232                         draw_vrl1_vgax_modex(x-rx,y-ry,vrl_header,vrl_lineoffs,buffer+sizeof(*vrl_header),bufsz-sizeof(*vrl_header));
233
234                         /* restore ptr */
235                         vga_state.vga_graphics_ram = omemptr;
236
237                         /* block copy to visible RAM from offscreen */
238                         vga_setup_wm1_block_copy();
239                         o = offscreen_ofs; // source offscreen
240                         o2 = (ry * vga_state.vga_stride) + (rx >> 2); // dest visible (original stride)
241                         for (i=0;i < h;i++,o += vga_state.vga_draw_stride,o2 += vga_state.vga_stride) vga_wm1_mem_block_copy(o2,o,w >> 2);
242                         /* must restore Write Mode 0/Read Mode 0 for this code to continue drawing normally */
243                         vga_restore_rm0wm0();
244
245                         /* restore stride */
246                         vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = vga_state.vga_stride;
247
248                         /* step */
249                         x += xdir;
250                         y += ydir;
251                         if (x >= (vga_state.vga_width - 1) || x == 0)
252                                 xdir = -xdir;
253                         if (y >= (vga_state.vga_height - 1) || y == 0)
254                                 ydir = -ydir;
255                 }
256         }
257
258         /* another handy "demo" effect using VGA write mode 1.
259          * we can take what's on screen and vertically squash it like an old analog TV set turning off. */
260         {
261                 unsigned int blank_line_ofs = (vga_state.vga_stride * vga_state.vga_height * 2);
262                 unsigned int copy_ofs = (vga_state.vga_stride * vga_state.vga_height);
263                 unsigned int display_ofs = 0x0000;
264                 unsigned int i,y,soh,doh,dstart;
265                 unsigned int dh_blankfill = 8;
266                 unsigned int dh_step = 8;
267                 uint32_t sh,dh,yf,ystep;
268
269                 /* copy active display (0) to offscreen buffer (0x4000) */
270                 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = vga_state.vga_stride;
271                 vga_setup_wm1_block_copy();
272                 vga_wm1_mem_block_copy(copy_ofs,display_ofs,vga_state.vga_stride * vga_state.vga_height);
273                 vga_restore_rm0wm0();
274
275                 /* need a blank line as well */
276                 for (i=0;i < vga_state.vga_stride;i++) vga_state.vga_graphics_ram[i+blank_line_ofs] = 0;
277
278                 sh = dh = vga_state.vga_height;
279                 while (dh >= dh_step) {
280                         /* stop animating if the user hits ENTER */
281                         if (kbhit()) {
282                                 if (getch() == 13) break;
283                         }
284
285                         /* wait for vsync end */
286                         vga_wait_for_vsync_end();
287
288                         /* what scalefactor to use for stretching? */
289                         ystep = (0x10000UL * sh) / dh;
290                         dstart = (vga_state.vga_height - dh) / 2; // center the squash effect on screen, otherwise it would squash to top of screen
291                         doh = display_ofs;
292                         soh = copy_ofs;
293                         yf = 0;
294                         y = 0;
295
296                         /* for performance, keep VGA in write mode 1 the entire render */
297                         vga_setup_wm1_block_copy();
298
299                         /* blank lines */
300                         if (dstart >= dh_blankfill) y = dstart - dh_blankfill;
301                         else y = 0;
302                         doh = vga_state.vga_stride * y;
303
304                         while (y < dstart) {
305                                 vga_wm1_mem_block_copy(doh,blank_line_ofs,vga_state.vga_stride);
306                                 doh += vga_state.vga_stride;
307                                 y++;
308                         }
309
310                         /* draw */
311                         while (y < (dh+dstart)) {
312                                 soh = copy_ofs + ((yf >> 16UL) * vga_state.vga_stride);
313                                 vga_wm1_mem_block_copy(doh,soh,vga_state.vga_stride);
314                                 doh += vga_state.vga_stride;
315                                 yf += ystep;
316                                 y++;
317                         }
318
319                         /* blank lines */
320                         while (y < vga_state.vga_height && y < (dh+dstart+dh_blankfill)) {
321                                 vga_wm1_mem_block_copy(doh,blank_line_ofs,vga_state.vga_stride);
322                                 doh += vga_state.vga_stride;
323                                 y++;
324                         }
325
326                         /* done */
327                         vga_restore_rm0wm0();
328
329                         /* wait for vsync */
330                         vga_wait_for_vsync();
331
332                         /* make it shrink */
333                         dh -= dh_step;
334                         if (dh < 40) dh_step = 1;
335                 }
336         }
337
338         int10_setmode(3);
339         free(vrl_lineoffs);
340         buffer = NULL;
341         free(buffer);
342         bufsz = 0;
343         return 0;
344 }
345