OSDN Git Service

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