]> 4ch.mooo.com Git - 16.git/blob - 16/lib/MODEX16.C
d8b646e6feb945a67057e36229e7043889404d7a
[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
96 int old_mode;\r
97 \r
98 /////////////////////////////////////////////////////////////////////////////\r
99 //                                                                         //\r
100 // setvideo() - This function Manages the video modes                                     //\r
101 //                                                                         //\r
102 /////////////////////////////////////////////////////////////////////////////\r
103 void setvideo(/*byte mode, */short vq){\r
104                 union REGS in, out;\r
105 \r
106                 if(!vq){ // deinit the video\r
107                                 // change to the video mode we were in before we switched to mode 13h\r
108                                 in.h.ah = 0x00;\r
109                                 in.h.al = old_mode;\r
110                                 int86(0x10, &in, &out);\r
111 \r
112                 }else if(vq==1){ // init the video\r
113                                 // get old video mode\r
114                                 in.h.ah = 0xf;\r
115                                 int86(0x10, &in, &out);\r
116                                 old_mode = out.h.al;\r
117                                 // enter mode
118                                 modexEnter();\r
119                 }\r
120 }
121 \r
122 page_t\r
123 modexDefaultPage() {\r
124     page_t page;\r
125 \r
126     /* default page values */\r
127     page.data = VGA;\r
128     page.dx = 0;\r
129     page.dy = 0;\r
130     page.width = SCREEN_WIDTH;\r
131     page.height = SCREEN_HEIGHT;\r
132 \r
133     return page;\r
134 }\r
135 \r
136 /* returns the next page in contiguous memory\r
137  * the next page will be the same size as p, by default\r
138  */\r
139 page_t\r
140 modexNextPage(page_t *p) {\r
141     page_t result;\r
142 \r
143     result.data = p->data + (p->width/4)*p->height;  /* compute the offset */\r
144     result.dx = 0;\r
145     result.dy = 0;\r
146     result.width = p->width;\r
147     result.height = p->height;\r
148 \r
149     return result;\r
150 }\r
151 \r
152 \r
153 void\r
154 modexShowPage(page_t *page) {\r
155     word high_address;\r
156     word low_address;\r
157     word offset;\r
158     byte crtcOffset;\r
159 \r
160     /* calculate offset */\r
161     offset = (word) page->data;\r
162     offset += page->dy * (page->width >> 2 );\r
163     offset += page->dx >> 2;\r
164 \r
165     /* calculate crtcOffset according to virtual width */\r
166     crtcOffset = page->width >> 3;\r
167 \r
168     high_address = HIGH_ADDRESS | (offset & 0xff00);\r
169     low_address  = LOW_ADDRESS  | (offset << 8);\r
170 \r
171     /* wait for appropriate timing and then program CRTC */\r
172     while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));\r
173     outpw(CRTC_INDEX, high_address);\r
174     outpw(CRTC_INDEX, low_address);\r
175     outp(CRTC_INDEX, 0x13);\r
176     outp(CRTC_DATA, crtcOffset);\r
177 \r
178     /*  wait for one retrace */\r
179     while (!(inp(INPUT_STATUS_1) & VRETRACE)); \r
180 \r
181     /* do PEL panning here */\r
182     outp(AC_INDEX, 0x33);\r
183     outp(AC_INDEX, (page->dx & 0x03) << 1);\r
184 }\r
185 \r
186 \r
187 void\r
188 modexPanPage(page_t *page, int dx, int dy) {\r
189     page->dx = dx;\r
190     page->dy = dy;\r
191 }\r
192 \r
193 \r
194 void\r
195 modexSelectPlane(byte plane) {\r
196     outp(SC_INDEX, MAP_MASK);          /* select plane */\r
197     outp(SC_DATA,  plane);\r
198 }\r
199 \r
200 \r
201 void\r
202 modexClearRegion(page_t *page, int x, int y, int w, int h, byte  color) {\r
203     word pageOff = (word) page->data;\r
204     word xoff=x/4;       /* xoffset that begins each row */\r
205     word scanCount=w/4;  /* number of iterations per row (excluding right clip)*/\r
206     word poffset = pageOff + y*(page->width/4) + xoff; /* starting offset */\r
207     word nextRow = page->width/4-scanCount-1;  /* loc of next row */\r
208     byte lclip[] = {0x0f, 0x0e, 0x0c, 0x08};  /* clips for rectangles not on 4s */\r
209     byte rclip[] = {0x00, 0x01, 0x03, 0x07};\r
210     byte left = lclip[x&0x03];\r
211     byte right = rclip[(x+w)&0x03];\r
212 \r
213     /* handle the case which requires an extra group */\r
214     if((x & 0x03) && !((x+w) & 0x03)) {\r
215       right=0x0f;\r
216     }\r
217 \r
218     __asm {\r
219                 MOV AX, SCREEN_SEG      ; go to the VGA memory\r
220                 MOV ES, AX\r
221                 MOV DI, poffset         ; go to the first pixel\r
222                 MOV DX, SC_INDEX        ; point to the map mask\r
223                 MOV AL, MAP_MASK\r
224                 OUT DX, AL\r
225                 INC DX\r
226                 MOV AL, color           ; get ready to write colors\r
227         SCAN_START:\r
228                 MOV CX, scanCount       ; count the line\r
229                 MOV BL, AL              ; remember color\r
230                 MOV AL, left            ; do the left clip\r
231                 OUT DX, AL              ; set the left clip\r
232                 MOV AL, BL              ; restore color\r
233                 STOSB                   ; write the color\r
234                 DEC CX\r
235                 JZ SCAN_DONE            ; handle 1 group stuff\r
236 \r
237                 ;-- write the main body of the scanline\r
238                 MOV BL, AL              ; remember color\r
239                 MOV AL, 0x0f            ; write to all pixels\r
240                 OUT DX, AL\r
241                 MOV AL, BL              ; restore color\r
242                 REP STOSB               ; write the color\r
243         SCAN_DONE:\r
244                 MOV BL, AL              ; remeber color\r
245                 MOV AL, right\r
246                 OUT DX, AL              ; do the right clip\r
247                 MOV AL, BL              ; restore color\r
248                 STOSB                   ; write pixel\r
249                 ADD DI, nextRow         ; go to the next row\r
250                 DEC h\r
251                 JNZ SCAN_START\r
252     }\r
253 }\r
254 \r
255 \r
256 void\r
257 modexDrawBmp(page_t *page, int x, int y, bitmap_t *bmp) {\r
258     /* draw the region (the entire freakin bitmap) */\r
259     modexDrawBmpRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);\r
260 }\r
261 \r
262 \r
263 void\r
264 modexDrawBmpRegion(page_t *page, int x, int y,\r
265                    int rx, int ry, int rw, int rh, bitmap_t *bmp) {\r
266     word poffset = (word) page->data  + y*(page->width/4) + x/4;\r
267     byte *data = bmp->data;\r
268     word bmpOffset = (word) data + ry * bmp->width + rx;\r
269     word width = rw;\r
270     word height = rh;\r
271     byte plane = 1 << ((byte) x & 0x03);\r
272     word scanCount = width/4 + (width%4 ? 1 :0);\r
273     word nextPageRow = page->width/4 - scanCount;\r
274     word nextBmpRow = (word) bmp->width - width;\r
275     word rowCounter;\r
276     byte planeCounter = 4;\r
277 \r
278     __asm {\r
279                 MOV AX, SCREEN_SEG      ; go to the VGA memory\r
280                 MOV ES, AX\r
281 \r
282                 MOV DX, SC_INDEX        ; point at the map mask register\r
283                 MOV AL, MAP_MASK        ;\r
284                 OUT DX, AL              ;\r
285 \r
286         PLANE_LOOP:\r
287                 MOV DX, SC_DATA         ; select the current plane\r
288                 MOV AL, plane           ;\r
289                 OUT DX, AL              ;\r
290 \r
291                 ;-- begin plane painting\r
292                 MOV AX, height          ; start the row counter\r
293                 MOV rowCounter, AX      ; \r
294                 MOV DI, poffset         ; go to the first pixel\r
295                 MOV SI, bmpOffset       ; go to the bmp pixel\r
296         ROW_LOOP:\r
297                 MOV CX, width           ; count the columns\r
298         SCAN_LOOP:\r
299                 MOVSB                   ; copy the pixel\r
300                 SUB CX, 3               ; we skip the next 3\r
301                 ADD SI, 3               ; skip the bmp pixels\r
302                 LOOP SCAN_LOOP          ; finish the scan\r
303 \r
304                 MOV AX, nextPageRow\r
305                 ADD DI, AX              ; go to the next row on screen\r
306                 MOV AX, nextBmpRow\r
307                 ADD SI, AX              ; go to the next row on bmp\r
308 \r
309                 DEC rowCounter\r
310                 JNZ ROW_LOOP            ; do all the rows\r
311                 ;-- end plane painting\r
312 \r
313                 MOV AL, plane           ; advance to the next plane\r
314                 SHL AL, 1               ;\r
315                 AND AL, 0x0f            ; mask the plane properly\r
316                 MOV plane, AL           ; store the plane\r
317 \r
318                 INC bmpOffset           ; start bmp at the right spot\r
319 \r
320                 DEC planeCounter\r
321                 JNZ PLANE_LOOP          ; do all 4 planes\r
322     }\r
323 }\r
324 \r
325 \r
326 void\r
327 modexDrawSprite(page_t *page, int x, int y, bitmap_t *bmp) {\r
328     /* draw the whole sprite */\r
329     modexDrawSpriteRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);\r
330 }\r
331 \r
332 void\r
333 modexDrawSpriteRegion(page_t *page, int x, int y,\r
334                       int rx, int ry, int rw, int rh, bitmap_t *bmp) {\r
335     word poffset = (word)page->data + y*(page->width/4) + x/4;\r
336     byte *data = bmp->data;\r
337     word bmpOffset = (word) data + ry * bmp->width + rx;\r
338     word width = rw;\r
339     word height = rh;\r
340     byte plane = 1 << ((byte) x & 0x03);\r
341     word scanCount = width/4 + (width%4 ? 1 :0);\r
342     word nextPageRow = page->width/4 - scanCount;\r
343     word nextBmpRow = (word) bmp->width - width;\r
344     word rowCounter;\r
345     byte planeCounter = 4;\r
346 \r
347     __asm {\r
348                 MOV AX, SCREEN_SEG      ; go to the VGA memory\r
349                 MOV ES, AX\r
350 \r
351                 MOV DX, SC_INDEX        ; point at the map mask register\r
352                 MOV AL, MAP_MASK        ;\r
353                 OUT DX, AL              ;\r
354 \r
355         PLANE_LOOP:\r
356                 MOV DX, SC_DATA         ; select the current plane\r
357                 MOV AL, plane           ;\r
358                 OUT DX, AL              ;\r
359 \r
360                 ;-- begin plane painting\r
361                 MOV AX, height          ; start the row counter\r
362                 MOV rowCounter, AX      ; \r
363                 MOV DI, poffset         ; go to the first pixel\r
364                 MOV SI, bmpOffset       ; go to the bmp pixel\r
365         ROW_LOOP:\r
366                 MOV CX, width           ; count the columns\r
367         SCAN_LOOP:\r
368                 LODSB\r
369                 DEC SI\r
370                 CMP AL, 0\r
371                 JNE DRAW_PIXEL          ; draw non-zero pixels\r
372 \r
373                 INC DI                  ; skip the transparent pixel\r
374                 ADD SI, 1\r
375                 JMP NEXT_PIXEL\r
376         DRAW_PIXEL:\r
377                 MOVSB                   ; copy the pixel\r
378         NEXT_PIXEL:\r
379                 SUB CX, 3               ; we skip the next 3\r
380                 ADD SI, 3               ; skip the bmp pixels\r
381                 LOOP SCAN_LOOP          ; finish the scan\r
382 \r
383                 MOV AX, nextPageRow\r
384                 ADD DI, AX              ; go to the next row on screen\r
385                 MOV AX, nextBmpRow\r
386                 ADD SI, AX              ; go to the next row on bmp\r
387 \r
388                 DEC rowCounter\r
389                 JNZ ROW_LOOP            ; do all the rows\r
390                 ;-- end plane painting\r
391 \r
392                 MOV AL, plane           ; advance to the next plane\r
393                 SHL AL, 1               ;\r
394                 AND AL, 0x0f            ; mask the plane properly\r
395                 MOV plane, AL           ; store the plane\r
396 \r
397                 INC bmpOffset           ; start bmp at the right spot\r
398 \r
399                 DEC planeCounter\r
400                 JNZ PLANE_LOOP          ; do all 4 planes\r
401     }\r
402 }\r
403 \r
404 \r
405 void\r
406 modexCopyPageRegion(page_t *dest, page_t src,\r
407                     word sx, word sy,\r
408                     word dx, word dy,\r
409                     word width, word height)\r
410 {\r
411     /* todo */\r
412 }\r
413 \r
414 \r
415 /* fade and flash */\r
416 void\r
417 modexFadeOn(word fade, byte *palette) {\r
418     fadePalette(-fade, 64, 64/fade+1, palette);\r
419 }\r
420 \r
421 \r
422 void\r
423 modexFadeOff(word fade, byte *palette) {\r
424     fadePalette(fade, 0, 64/fade+1, palette);\r
425 }\r
426 \r
427 \r
428 void\r
429 modexFlashOn(word fade, byte *palette) {\r
430     fadePalette(fade, -64, 64/fade+1, palette);\r
431 }\r
432 \r
433 \r
434 void\r
435 modexFlashOff(word fade, byte *palette) {\r
436     fadePalette(-fade, 0, 64/fade+1, palette);\r
437 }\r
438 \r
439 \r
440 static void\r
441 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {\r
442     word i;\r
443     byte dim = start;\r
444 \r
445     /* handle the case where we just update */\r
446     if(iter == 0) {\r
447         modexPalUpdate(palette);\r
448         return;\r
449     }\r
450 \r
451     while(iter > 0) {  /* FadeLoop */\r
452         for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */\r
453             tmppal[i] = palette[i] - dim;\r
454             if(tmppal[i] > 127) {\r
455                 tmppal[i] = 0;\r
456             } else if(tmppal[i] > 63) {\r
457                 tmppal[i] = 63;\r
458             }\r
459         }\r
460         modexPalUpdate(tmppal);\r
461         iter--;\r
462         dim += fade;\r
463     }\r
464 }\r
465 \r
466 \r
467 /* save and load */\r
468 void\r
469 modexPalSave(byte *palette) {\r
470     int  i;\r
471 \r
472     outp(PAL_READ_REG, 0);      /* start at palette entry 0 */\r
473     for(i=0; i<PAL_SIZE; i++) {\r
474         palette[i] = inp(PAL_DATA_REG); /* read the palette data */\r
475     }\r
476 }\r
477 \r
478 \r
479 byte *\r
480 modexNewPal() {\r
481     byte *ptr;\r
482     ptr = malloc(PAL_SIZE);\r
483 \r
484     /* handle errors */\r
485     if(!ptr) {\r
486         printf("Could not allocate palette.\n");\r
487         exit(-1);\r
488     }\r
489 \r
490     return ptr;\r
491 }\r
492 \r
493 \r
494 void\r
495 modexLoadPalFile(byte *filename, byte **palette) {\r
496     FILE *file;\r
497     byte *ptr;\r
498 \r
499     /* free the palette if it exists */\r
500     if(*palette) {\r
501         free(*palette);\r
502     }\r
503 \r
504     /* allocate the new palette */\r
505     *palette = modexNewPal();\r
506 \r
507     /* open the file */\r
508     file = fopen(filename, "rb");\r
509     if(!file) {\r
510         printf("Could not open palette file: %s\n", filename);\r
511         exit(-2);\r
512     }\r
513 \r
514     /* read the file */\r
515     ptr = *palette;\r
516     while(!feof(file)) {\r
517         *ptr++ = fgetc(file);\r
518     }\r
519 \r
520     fclose(file);\r
521 }\r
522 \r
523 \r
524 void\r
525 modexSavePalFile(char *filename, byte *pal) {\r
526     unsigned int i;\r
527     FILE *file;\r
528 \r
529     /* open the file for writing */\r
530     file = fopen(filename, "wb");\r
531     if(!file) {\r
532         printf("Could not open %s for writing\n", filename);\r
533         exit(-2);\r
534     }\r
535 \r
536     /* write the data to the file */\r
537     fwrite(pal, 1, PAL_SIZE, file);\r
538     fclose(file);\r
539 }\r
540 \r
541 \r
542 /* blanking */\r
543 void\r
544 modexPalBlack() {\r
545     fadePalette(-1, 64, 1, tmppal);\r
546 }\r
547 \r
548 \r
549 void\r
550 modexPalWhite() {\r
551     fadePalette(-1, -64, 1, tmppal);\r
552 }\r
553 \r
554 \r
555 /* utility */\r
556 void\r
557 modexPalUpdate(byte *p) {\r
558     int i;\r
559     modexWaitBorder();\r
560     outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
561     for(i=0; i<PAL_SIZE/2; i++) {\r
562         outp(PAL_DATA_REG, p[i]);\r
563     }\r
564     modexWaitBorder();      /* waits one retrace -- less flicker */\r
565     for(i=PAL_SIZE/2; i<PAL_SIZE; i++) {\r
566         outp(PAL_DATA_REG, p[i]);\r
567     }\r
568 }\r
569 \r
570 \r
571 void\r
572 modexWaitBorder() {\r
573     while(inp(INPUT_STATUS_1)  & 8)  {\r
574         /* spin */\r
575     }\r
576 \r
577     while(!(inp(INPUT_STATUS_1)  & 8))  {\r
578         /* spin */\r
579     }\r
580 }\r
581 \r
582 \r
583 bitmap_t\r
584 modexLoadPcx(char *filename) {\r
585     FILE *file;\r
586     bitmap_t result;\r
587     struct pcxHeader head;\r
588     long bufSize;\r
589     int index;\r
590     byte count, val;\r
591 \r
592     /* open the PCX file for reading */\r
593     file = fopen(filename, "rb");\r
594     if(!file) {\r
595         printf("Could not open %s for reading.\n", filename);\r
596         exit(-2);\r
597     }\r
598 \r
599     /* read the header */\r
600     fread(&head, sizeof(char), sizeof(struct pcxHeader), file);\r
601 \r
602     /* make sure this  is 8bpp */\r
603     if(head.bpp != 8) {\r
604         printf("I only know how to handle 8bpp pcx files!\n");\r
605         fclose(file);\r
606         exit(-2);\r
607     }\r
608 \r
609     /* allocate the buffer */\r
610     result.width = head.xmax - head.xmin + 1;\r
611     result.height = head.ymax - head.ymin + 1;\r
612     bufSize = result.width * result.height;\r
613     result.data = malloc(bufSize);\r
614     if(!result.data) {\r
615         printf("Could not allocate memory for bitmap data.");\r
616         fclose(file);\r
617         exit(-1);\r
618     }\r
619 \r
620     /*  read the buffer in */\r
621     index = 0;\r
622     do {\r
623         /* get the run length and the value */\r
624         count = fgetc(file);\r
625         if(0xC0 ==  (count & 0xC0)) { /* this is the run count */\r
626             count &= 0x3f;\r
627             val = fgetc(file);\r
628         } else {\r
629             val = count;\r
630             count = 1;\r
631         }\r
632 \r
633         /* write the pixel the specified number of times */\r
634         for(; count && index < bufSize; count--,index++)  {\r
635             result.data[index] = val;\r
636         }\r
637     } while(index < bufSize);\r
638 \r
639     /* handle the palette */\r
640     fseek(file, -769, SEEK_END);\r
641     val = fgetc(file);\r
642     result.palette = modexNewPal();\r
643     if(head.version == 5 && val == 12) {\r
644         /* use the vga palette */\r
645         for(index=0; !feof(file) && index < PAL_SIZE; index++) {\r
646             val = fgetc(file);\r
647             result.palette[index] = val >> 2;\r
648         }\r
649     } else {\r
650         /* use the 16 color palette */\r
651         for(index=0; index<48; index++) {\r
652             result.palette[index]  = head.pal16[index];\r
653         }\r
654     }\r
655 \r
656     fclose(file);\r
657 \r
658     return result;\r
659 }\r