OSDN Git Service

modified: 16/DOS_GFX.EXE
[proj16/16.git] / 16 / lib / MODEX16.C
1 #include <dos.h>\r
2 #include <string.h>\r
3 #include <mem.h>\r
4 #include <conio.h>\r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 #include "lib\modex16.h"\r
8 \r
9 \r
10 byte far* VGA=(byte far*) 0xA0000000;   /* this points to video memory. */\r
11 \r
12 static void fadePalette(sbyte fade, sbyte start, word iter, byte *palette);\r
13 static byte tmppal[PAL_SIZE];\r
14 static struct pcxHeader {\r
15     byte id;\r
16     byte version;\r
17     byte encoding;\r
18     byte bpp;\r
19     word xmin;\r
20     word ymin;\r
21     word xmax;\r
22     word ymax;\r
23     word hres;\r
24     word vres;\r
25     byte pal16[48];\r
26     byte res1;\r
27     word bpplane;\r
28     word palType;\r
29     word hScreenSize;\r
30     word vScreenSize;\r
31     byte padding[54];\r
32 };\r
33 \r
34 \r
35 static void\r
36 vgaSetMode(byte mode)\r
37 {\r
38   union REGS regs;\r
39 \r
40   regs.h.ah = SET_MODE;\r
41   regs.h.al = mode;\r
42   int86(VIDEO_INT, &regs, &regs);\r
43 }\r
44 \r
45 \r
46 /* -========================= Entry  Points ==========================- */\r
47 void\r
48 modexEnter() {\r
49     word i;\r
50     dword far*ptr=(dword far*)VGA;      /* used for faster screen clearing */\r
51     word CRTParms[] = {\r
52         0x0d06,         /* vertical total */\r
53         0x3e07,         /* overflow (bit 8 of vertical counts) */\r
54         0x4109,         /* cell height (2 to double-scan */\r
55         0xea10,         /* v sync start */\r
56         0xac11,         /* v sync end and protect cr0-cr7 */\r
57         0xdf12,         /* vertical displayed */\r
58         0x0014,         /* turn off dword mode */\r
59         0xe715,         /* v blank start */\r
60         0x0616,         /* v blank end */\r
61         0xe317          /* turn on byte mode */\r
62     };\r
63     int CRTParmCount = sizeof(CRTParms) / sizeof(CRTParms[0]);\r
64 \r
65     /* TODO save current video mode and palette */\r
66     vgaSetMode(VGA_256_COLOR_MODE);\r
67 \r
68     /* disable chain4 mode */\r
69     outpw(SC_INDEX, 0x0604);\r
70 \r
71     /* synchronous reset while setting Misc Output */\r
72     outpw(SC_INDEX, 0x0100);\r
73 \r
74     /* select 25 MHz dot clock & 60 Hz scanning rate */\r
75     outp(MISC_OUTPUT, 0xe3);\r
76 \r
77     /* undo reset (restart sequencer) */\r
78     outpw(SC_INDEX, 0x0300);\r
79 \r
80     /* reprogram the CRT controller */\r
81     outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */\r
82     outp(CRTC_DATA, 0x7f);  /* get current write protect on varios regs */\r
83 \r
84     /* send the CRTParms */\r
85     for(i=0; i<CRTParmCount; i++) {\r
86         outpw(CRTC_INDEX, CRTParms[i]);\r
87     }\r
88 \r
89     /* clear video memory */\r
90     outpw(SC_INDEX, 0x0f02);\r
91     for(i=0; i<0x8000; i++) {\r
92         ptr[i] = 0x0000;\r
93     }\r
94 }\r
95 \r
96 \r
97 void\r
98 modexLeave() {\r
99     /* TODO restore original mode and palette */\r
100     vgaSetMode(TEXT_MODE);\r
101 }\r
102 \r
103 \r
104 void\r
105 modexShowPage(page_t page) {\r
106     word high_address;\r
107     word low_address;\r
108 \r
109     high_address = HIGH_ADDRESS | ((word)(page) & 0xff00);\r
110     low_address  = LOW_ADDRESS  | ((word)(page) << 8);\r
111 \r
112     /* wait for appropriate timing */\r
113     while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));\r
114     outpw(CRTC_INDEX, high_address);\r
115     outpw(CRTC_INDEX, low_address);\r
116 \r
117     /*  wait for one retrace */\r
118     while (!(inp(INPUT_STATUS_1) & VRETRACE)); \r
119 }\r
120 \r
121 \r
122 void\r
123 modexPanPage(page_t *page, int dx, int dy) {\r
124     /* TODO figure out how the $@#! you do horizontal panning */\r
125     *page += dy * SCREEN_WIDTH;\r
126 }\r
127 \r
128 \r
129 void\r
130 modexSelectPlane(byte plane) {\r
131     outp(SC_INDEX, MAP_MASK);          /* select plane */\r
132     outp(SC_DATA,  plane);\r
133 }\r
134 \r
135 \r
136 void\r
137 modexClearRegion(page_t page, int x, int y, int w, int h, byte color) {\r
138     byte plane;\r
139     word endx = x + w;\r
140     word endy = y + h;\r
141     word dx, dy;\r
142 \r
143     /* TODO Make this fast.  It's SLOOOOOOW */\r
144     for(plane=0; plane < 4; plane++) {\r
145         modexSelectPlane(PLANE(plane+x));\r
146         for(dx = x; dx < endx; dx+=4) {\r
147             for(dy=y; dy<endy; dy++) {\r
148                 page[PAGE_OFFSET(dx, dy)] = color;\r
149             }\r
150         }\r
151     }\r
152 }\r
153 \r
154 \r
155 void\r
156 modexDrawBmp(page_t page, int x, int y, bitmap_t *bmp, byte sprite) {\r
157     byte plane;\r
158     word px, py;\r
159     word offset;\r
160 \r
161     /* TODO Make this fast.  It's SLOOOOOOW */\r
162     for(plane=0; plane < 4; plane++) {\r
163         modexSelectPlane(PLANE(plane+x));\r
164         for(px = plane; px < bmp->width; px+=4) {\r
165             offset=px;\r
166             for(py=0; py<bmp->height; py++) {
167                 if(!sprite || bmp->data[offset])\r
168                   page[PAGE_OFFSET(x+px, y+py)] = bmp->data[offset];\r
169                 offset+=bmp->width;\r
170             }\r
171         }\r
172     }\r
173 }\r
174 \r
175 \r
176 /* fade and flash */\r
177 void\r
178 modexFadeOn(word fade, byte *palette) {\r
179     fadePalette(-fade, 64, 64/fade+1, palette);\r
180 }\r
181 \r
182 \r
183 void\r
184 modexFadeOff(word fade, byte *palette) {\r
185     fadePalette(fade, 0, 64/fade+1, palette);\r
186 }\r
187 \r
188 \r
189 void\r
190 modexFlashOn(word fade, byte *palette) {\r
191     fadePalette(fade, -64, 64/fade+1, palette);\r
192 }\r
193 \r
194 \r
195 void\r
196 modexFlashOff(word fade, byte *palette) {\r
197     fadePalette(-fade, 0, 64/fade+1, palette);\r
198 }\r
199 \r
200 \r
201 static void\r
202 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {\r
203     word i;\r
204     byte dim = start;\r
205 \r
206     /* handle the case where we just update */\r
207     if(iter == 0) {\r
208         modexPalUpdate(palette);\r
209         return;\r
210     }\r
211 \r
212     while(iter > 0) {  /* FadeLoop */\r
213         for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */\r
214             tmppal[i] = palette[i] - dim;\r
215             if(tmppal[i] > 127) {\r
216                 tmppal[i] = 0;\r
217             } else if(tmppal[i] > 63) {\r
218                 tmppal[i] = 63;\r
219             }\r
220         }\r
221         modexPalUpdate(tmppal);\r
222         iter--;\r
223         dim += fade;\r
224     }\r
225 }\r
226 \r
227 \r
228 /* save and load */\r
229 void\r
230 modexPalSave(byte *palette) {\r
231     int  i;\r
232 \r
233     outp(PAL_READ_REG, 0);      /* start at palette entry 0 */\r
234     for(i=0; i<PAL_SIZE; i++) {\r
235         palette[i] = inp(PAL_DATA_REG); /* read the palette data */\r
236     }\r
237 }\r
238 \r
239 \r
240 byte *\r
241 modexNewPal() {\r
242     byte *ptr;\r
243     ptr = malloc(PAL_SIZE);\r
244 \r
245     /* handle errors */\r
246     if(!ptr) {\r
247         printf("Could not allocate palette.\n");\r
248         exit(-1);\r
249     }\r
250 \r
251     return ptr;\r
252 }\r
253 \r
254 \r
255 void\r
256 modexLoadPalFile(byte *filename, byte **palette) {\r
257     FILE *file;\r
258     byte *ptr;\r
259 \r
260     /* free the palette if it exists */\r
261     if(*palette) {\r
262         free(*palette);\r
263     }\r
264 \r
265     /* allocate the new palette */\r
266     *palette = modexNewPal();\r
267 \r
268     /* open the file */\r
269     file = fopen(filename, "rb");\r
270     if(!file) {\r
271         printf("Could not open palette file: %s\n", filename);\r
272         exit(-2);\r
273     }\r
274 \r
275     /* read the file */\r
276     ptr = *palette;\r
277     while(!feof(file)) {\r
278         *ptr++ = fgetc(file);\r
279     }\r
280 \r
281     fclose(file);\r
282 }\r
283 \r
284 \r
285 void\r
286 modexSavePalFile(char *filename, byte *pal) {\r
287     unsigned int i;\r
288     FILE *file;\r
289 \r
290     /* open the file for writing */\r
291     file = fopen(filename, "wb");\r
292     if(!file) {\r
293         printf("Could not open %s for writing\n", filename);\r
294         exit(-2);\r
295     }\r
296 \r
297     /* write the data to the file */\r
298     fwrite(pal, 1, PAL_SIZE, file);\r
299     fclose(file);\r
300 }\r
301 \r
302 \r
303 /* blanking */\r
304 void\r
305 modexPalBlack() {\r
306     fadePalette(-1, 64, 1, tmppal);\r
307 }\r
308 \r
309 \r
310 void\r
311 modexPalWhite() {\r
312     fadePalette(-1, -64, 1, tmppal);\r
313 }\r
314 \r
315 \r
316 /* utility */\r
317 void\r
318 modexPalUpdate(byte *p) {\r
319     int i;\r
320     modexWaitBorder();\r
321     outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
322     for(i=0; i<PAL_SIZE/2; i++) {\r
323         outp(PAL_DATA_REG, p[i]);\r
324     }\r
325     modexWaitBorder();      /* waits one retrace -- less flicker */\r
326     for(i=PAL_SIZE/2; i<PAL_SIZE; i++) {\r
327         outp(PAL_DATA_REG, p[i]);\r
328     }\r
329 }\r
330 \r
331 \r
332 void\r
333 modexWaitBorder() {\r
334     while(inp(INPUT_STATUS_1)  & 8)  {\r
335         /* spin */\r
336     }\r
337 \r
338     while(!(inp(INPUT_STATUS_1)  & 8))  {\r
339         /* spin */\r
340     }\r
341 }\r
342 \r
343 \r
344 bitmap_t\r
345 modexLoadPcx(char *filename) {\r
346     FILE *file;\r
347     bitmap_t result;\r
348     struct pcxHeader head;\r
349     long bufSize;\r
350     int index;\r
351     byte count, val;\r
352 \r
353     /* open the PCX file for reading */\r
354     file = fopen(filename, "rb");\r
355     if(!file) {\r
356         printf("Could not open %s for reading.\n", filename);\r
357         exit(-2);\r
358     }\r
359 \r
360     /* read the header */\r
361     fread(&head, sizeof(char), sizeof(struct pcxHeader), file);\r
362 \r
363     /* make sure this  is 8bpp */\r
364     if(head.bpp != 8) {\r
365         printf("I only know how to handle 8bpp pcx files!\n");\r
366         fclose(file);\r
367         exit(-2);\r
368     }\r
369 \r
370     /* allocate the buffer */\r
371     result.width = head.xmax - head.xmin + 1;\r
372     result.height = head.ymax - head.ymin + 1;\r
373     bufSize = result.width * result.height;\r
374     result.data = malloc(bufSize);\r
375     if(!result.data) {\r
376         printf("Could not allocate memory for bitmap data.");\r
377         fclose(file);\r
378         exit(-1);\r
379     }\r
380 \r
381     /*  read the buffer in */\r
382     index = 0;\r
383     do {\r
384         /* get the run length and the value */\r
385         count = fgetc(file);\r
386         if(0xC0 ==  (count & 0xC0)) { /* this is the run count */\r
387             count &= 0x3f;\r
388             val = fgetc(file);\r
389         } else {\r
390             val = count;\r
391             count = 1;\r
392         }\r
393 \r
394         /* write the pixel the specified number of times */\r
395         for(; count && index < bufSize; count--,index++)  {\r
396             result.data[index] = val;\r
397         }\r
398     } while(index < bufSize);\r
399 \r
400     /* handle the palette */\r
401     fseek(file, -769, SEEK_END);\r
402     val = fgetc(file);\r
403     result.palette = modexNewPal();\r
404     if(head.version == 5 && val == 12) {\r
405         /* use the vga palette */\r
406         for(index=0; !feof(file) && index < PAL_SIZE; index++) {\r
407             val = fgetc(file);\r
408             result.palette[index] = val >> 2;\r
409         }\r
410     } else {\r
411         /* use the 16 color palette */\r
412         for(index=0; index<48; index++) {\r
413             result.palette[index]  = head.pal16[index];\r
414         }\r
415     }\r
416 \r
417     fclose(file);\r
418 \r
419     return result;\r
420 }\r