]> 4ch.mooo.com Git - 16.git/blob - src/lib/modex16/16render.c
save/restore AX/BX when calling BIOS to get ROM font.
[16.git] / src / lib / modex16 / 16render.c
1 /* Project 16 Source Code~\r
2  * Copyright (C) 2012-2016 sparky4 & pngwen & andrius4669 & joncampbell123\r
3  *\r
4  * This file is part of Project 16.\r
5  *\r
6  * Project 16 is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 3 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Project 16 is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>, or\r
18  * write to the Free Software Foundation, Inc., 51 Franklin Street,\r
19  * Fifth Floor, Boston, MA 02110-1301 USA.\r
20  *\r
21  */\r
22 /*\r
23  * Render data code~\r
24  */\r
25 \r
26 #include "src/lib/modex16/16render.h"\r
27 \r
28 //TODO! ADD CLIPPING!!\r
29 //memory management needs to be added\r
30 //void\r
31 //modexDrawBmpRegion    (page_t *page, int x, int y, int rx, int ry, int rw, int rh, bitmap_t *bmp)\r
32 void modexDrawPBufRegion        (page_t *page, int x, int y, int rx, int ry, int rw, int rh, planar_buf_t *p, boolean sprite)\r
33 {\r
34         word plane;\r
35         int i;\r
36         const int px=x+page->dx;\r
37         const int py=y+page->dy;\r
38         const int prw = rw/4;\r
39         int prh;\r
40 \r
41         //fine tuning\r
42         rx+=1;\r
43         ry+=1;\r
44 \r
45         //^^;\r
46         #define PEEE    rx-prw\r
47         #define PE              (p->pwidth)\r
48         if(rh<p->height) prh = (PE*(ry-4));\r
49         else if(rh==p->height) prh = (PE*(ry));\r
50         y=py;\r
51         x=px;\r
52         //printf("%d,%d p(%d,%d) r(%d,%d) rwh(%d,%d)\n", x, y, px, py, rx, ry, rw, rh);\r
53         for(plane=0; plane < 4; plane++) {\r
54                 i=PEEE+prh;\r
55                 modexSelectPlane(PLANE(plane-1));\r
56                 for(; y < py+rh; y++) {\r
57                                 _fmemcpy(page->data + (((page->width/4) * (y)) + ((x) / 4)), &(p->plane[plane][i]), prw);\r
58                                 i+=PE;\r
59                 }\r
60                 x=px;\r
61                 y=py;\r
62         }\r
63 }\r
64 \r
65 \r
66 /*temp*/\r
67 void\r
68 modexDrawPBuf(page_t *page, int x, int y, planar_buf_t *p, boolean sprite)\r
69 {\r
70         modexDrawPBufRegion     (page, x, x, 0, 0, p->width, p->height, p, sprite);\r
71         /*\r
72         sword plane;\r
73         int i;\r
74 //      byte near *buff;\r
75         const int px=x+page->dx;\r
76         const int py=y+page->dy;\r
77         x=px;\r
78         y=py;\r
79 //      buff = _nmalloc(p->pwidth+1);\r
80         // TODO Make this fast.  It's SLOOOOOOW\r
81 //      for(plane=0; plane < 4; plane++) {\r
82 //              i=0;\r
83 //              modexSelectPlane(PLANE(plane+x));\r
84 //              for(px = plane; px < p->width; px+=4) {\r
85 //                      offset=px;\r
86 //                      for(py=0; py<p->height/2; py++) {\r
87 //                              //SELECT_ALL_PLANES();\r
88 //                              if(!sprite || p->plane[offset])\r
89 //                                      page->data = &(p->plane[offset][i++]);\r
90 //                              offset+=p->width;\r
91 //                              offset++;\r
92 //                      }\r
93 //              }\r
94 //      }\r
95         for(plane=0; plane < 4; plane++) {\r
96                 i=0;\r
97                 modexSelectPlane(PLANE(plane-1));\r
98                 for(; y < py+p->height; y++) {\r
99                         //for(px=0; px < p->width; px++) {\r
100                                 //printf("%02X ", (int) p->plane[plane][i++]);\r
101 //                              _fmemcpy(buff, &(p->plane[plane][i+=p->pwidth]), p->pwidth);\r
102 //                              printf("buff %u==%s\n", y, *buff);\r
103 //                              _fmemcpy(page->data + (((page->width/4) * (y+page->dy)) + ((x+page->dx) / 4)), buff, p->pwidth);\r
104                                 _fmemcpy(page->data + (((page->width/4) * y) + (x / 4)), &(p->plane[plane][i+=p->pwidth]), p->pwidth);\r
105                         //}\r
106                 }\r
107 //getch();\r
108                 x=px;\r
109                 y=py;\r
110         }\r
111 //      _nfree(buff);*/\r
112 }\r
113 \r
114 void\r
115 oldDrawBmp(byte far* page, int x, int y, bitmap_t *bmp, byte sprite)\r
116 {\r
117         byte plane;\r
118         word px, py;\r
119         word offset;\r
120 \r
121         /* TODO Make this fast.  It's SLOOOOOOW */\r
122         for(plane=0; plane < 4; plane++) {\r
123                 modexSelectPlane(PLANE(plane+x));\r
124                 for(px = plane; px < bmp->width; px+=4) {\r
125                         offset=px;\r
126                         for(py=0; py<bmp->height; py++) {\r
127                         if(!sprite || bmp->data[offset])\r
128                                 page[PAGE_OFFSET(x+px, y+py)] = bmp->data[offset];\r
129                         offset+=bmp->width;\r
130                         }\r
131                 }\r
132         }\r
133 }\r
134 \r
135 //* normal versions *//\r
136 void\r
137 modexDrawBmp(page_t *page, int x, int y, bitmap_t *bmp) {\r
138     /* draw the region (the entire freakin bitmap) */\r
139     modexDrawBmpRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);\r
140 }\r
141 \r
142 void\r
143 modexDrawBmpRegion(page_t *page, int x, int y,\r
144                    int rx, int ry, int rw, int rh, bitmap_t *bmp) {\r
145         word poffset = (word) page->data  + y*(page->width/4) + x/4;\r
146         byte *data = bmp->data;//+bmp->offset;\r
147         word bmpOffset = (word) data + ry * bmp->width + rx;\r
148         word width = rw;\r
149         word height = rh;\r
150         byte plane = 1 << ((byte) x & 0x03);\r
151         word scanCount = width/4 + (width%4 ? 1 :0);\r
152         word nextPageRow = page->width/4 - scanCount;\r
153         word nextBmpRow = (word) bmp->width - width;\r
154         word rowCounter;\r
155         byte planeCounter = 4;\r
156 \r
157     __asm {\r
158                 MOV AX, SCREEN_SEG      ; go to the VGA memory\r
159                 MOV ES, AX\r
160 \r
161                 MOV DX, SC_INDEX        ; point at the map mask register\r
162                 MOV AL, MAP_MASK        ;\r
163                 OUT DX, AL            ;\r
164 \r
165         PLANE_LOOP:\r
166                 MOV DX, SC_DATA  ; select the current plane\r
167                 MOV AL, plane      ;\r
168                 OUT DX, AL            ;\r
169 \r
170                 ;-- begin plane painting\r
171                 MOV AX, height    ; start the row counter\r
172                 MOV rowCounter, AX      ;\r
173                 MOV DI, poffset  ; go to the first pixel\r
174                 MOV SI, bmpOffset       ; go to the bmp pixel\r
175         ROW_LOOP:\r
176                 MOV CX, width      ; count the columns\r
177         SCAN_LOOP:\r
178                 MOVSB              ; copy the pixel\r
179                 SUB CX, 3              ; we skip the next 3\r
180                 ADD SI, 3              ; skip the bmp pixels\r
181                 LOOP SCAN_LOOP    ; finish the scan\r
182 \r
183                 MOV AX, nextPageRow\r
184                 ADD DI, AX            ; go to the next row on screen\r
185                 MOV AX, nextBmpRow\r
186                 ADD SI, AX            ; go to the next row on bmp\r
187 \r
188                 DEC rowCounter\r
189                 JNZ ROW_LOOP        ; do all the rows\r
190                 ;-- end plane painting\r
191                 MOV AL, plane      ; advance to the next plane\r
192                 SHL AL, 1              ;\r
193                 AND AL, 0x0f        ; mask the plane properly\r
194                 MOV plane, AL      ; store the plane\r
195 \r
196                 INC bmpOffset      ; start bmp at the right spot\r
197 \r
198                 DEC planeCounter\r
199                 JNZ PLANE_LOOP    ; do all 4 planes\r
200     }\r
201 }\r
202 \r
203 void\r
204 modexDrawSprite(page_t *page, int x, int y, bitmap_t *bmp) {\r
205     /* draw the whole sprite */\r
206     modexDrawSpriteRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);\r
207 }\r
208 \r
209 void\r
210 modexDrawSpriteRegion(page_t *page, int x, int y,\r
211                       int rx, int ry, int rw, int rh, bitmap_t *bmp) {\r
212         word poffset = (word)page->data + y*(page->width/4) + x/4;\r
213         byte *data = bmp->data;//+bmp->offset;\r
214         word bmpOffset = (word) data + ry * bmp->width + rx;\r
215         word width = rw;\r
216         word height = rh;\r
217         byte plane = 1 << ((byte) x & 0x03);\r
218         word scanCount = width/4 + (width%4 ? 1 :0);\r
219         word nextPageRow = page->width/4 - scanCount;\r
220         word nextBmpRow = (word) bmp->width - width;\r
221         word rowCounter;\r
222         byte planeCounter = 4;\r
223 \r
224     __asm {\r
225                 MOV AX, SCREEN_SEG      ; go to the VGA memory\r
226                 MOV ES, AX\r
227 \r
228                 MOV DX, SC_INDEX        ; point at the map mask register\r
229                 MOV AL, MAP_MASK        ;\r
230                 OUT DX, AL            ;\r
231 \r
232         PLANE_LOOP:\r
233                 MOV DX, SC_DATA  ; select the current plane\r
234                 MOV AL, plane      ;\r
235                 OUT DX, AL            ;\r
236 \r
237                 ;-- begin plane painting\r
238                 MOV AX, height    ; start the row counter\r
239                 MOV rowCounter, AX      ;\r
240                 MOV DI, poffset  ; go to the first pixel\r
241                 MOV SI, bmpOffset       ; go to the bmp pixel\r
242         ROW_LOOP:\r
243                 MOV CX, width      ; count the columns\r
244         SCAN_LOOP:\r
245                 LODSB\r
246                 DEC SI\r
247                 CMP AL, 0\r
248                 JNE DRAW_PIXEL    ; draw non-zero pixels\r
249 \r
250                 INC DI            ; skip the transparent pixel\r
251                 ADD SI, 1\r
252                 JMP NEXT_PIXEL\r
253         DRAW_PIXEL:\r
254                 MOVSB              ; copy the pixel\r
255         NEXT_PIXEL:\r
256                 SUB CX, 3              ; we skip the next 3\r
257                 ADD SI, 3              ; skip the bmp pixels\r
258                 LOOP SCAN_LOOP    ; finish the scan\r
259 \r
260                 MOV AX, nextPageRow\r
261                 ADD DI, AX            ; go to the next row on screen\r
262                 MOV AX, nextBmpRow\r
263                 ADD SI, AX            ; go to the next row on bmp\r
264 \r
265                 DEC rowCounter\r
266                 JNZ ROW_LOOP        ; do all the rows\r
267                 ;-- end plane painting\r
268 \r
269                 MOV AL, plane      ; advance to the next plane\r
270                 SHL AL, 1              ;\r
271                 AND AL, 0x0f        ; mask the plane properly\r
272                 MOV plane, AL      ; store the plane\r
273 \r
274                 INC bmpOffset      ; start bmp at the right spot\r
275 \r
276                 DEC planeCounter\r
277                 JNZ PLANE_LOOP    ; do all 4 planes\r
278     }\r
279 }\r
280 \r
281 //* planar buffer versions *//\r
282 void\r
283 modexDrawBmpPBuf(page_t *page, int x, int y, planar_buf_t *bmp) {\r
284     /* draw the region (the entire freakin bitmap) */\r
285     modexDrawBmpPBufRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);\r
286 }\r
287 \r
288 void\r
289 modexDrawBmpPBufRegion(page_t *page, int x, int y,\r
290                    int rx, int ry, int rw, int rh, planar_buf_t *bmp) {\r
291         word poffset = (word) page->data  + y*(page->width/4) + x/4;\r
292         byte *data = bmp->plane[0];\r
293         word bmpOffset = (word) data + ry * bmp->width + rx;\r
294         word width = rw;\r
295         word height = rh;\r
296         byte plane = 1 << ((byte) x & 0x03);\r
297         word scanCount = width/4 + (width%4 ? 1 :0);\r
298         word nextPageRow = page->width/4 - scanCount;\r
299         word nextBmpRow = (word) bmp->width - width;\r
300         word rowCounter;\r
301         byte planeCounter = 4;\r
302 \r
303     __asm {\r
304                 MOV AX, SCREEN_SEG      ; go to the VGA memory\r
305                 MOV ES, AX\r
306 \r
307                 MOV DX, SC_INDEX        ; point at the map mask register\r
308                 MOV AL, MAP_MASK        ;\r
309                 OUT DX, AL            ;\r
310 \r
311         PLANE_LOOP:\r
312                 MOV DX, SC_DATA  ; select the current plane\r
313                 MOV AL, plane      ;\r
314                 OUT DX, AL            ;\r
315 \r
316                 ;-- begin plane painting\r
317                 MOV AX, height    ; start the row counter\r
318                 MOV rowCounter, AX      ;\r
319                 MOV DI, poffset  ; go to the first pixel\r
320                 MOV SI, bmpOffset       ; go to the bmp pixel\r
321         ROW_LOOP:\r
322                 MOV CX, width      ; count the columns\r
323         SCAN_LOOP:\r
324 \r
325 \r
326 \r
327 \r
328 \r
329 \r
330 \r
331 \r
332 \r
333                 MOVSB              ; copy the pixel\r
334 \r
335                 SUB CX, 3              ; we skip the next 3\r
336                 ADD SI, 3              ; skip the bmp pixels\r
337                 LOOP SCAN_LOOP    ; finish the scan\r
338 \r
339                 MOV AX, nextPageRow\r
340                 ADD DI, AX            ; go to the next row on screen\r
341                 MOV AX, nextBmpRow\r
342                 ADD SI, AX            ; go to the next row on bmp\r
343 \r
344                 DEC rowCounter\r
345                 JNZ ROW_LOOP        ; do all the rows\r
346                 ;-- end plane painting\r
347 \r
348                 MOV AL, plane      ; advance to the next plane\r
349                 SHL AL, 1              ;\r
350                 AND AL, 0x0f        ; mask the plane properly\r
351                 MOV plane, AL      ; store the plane\r
352 \r
353                 INC bmpOffset      ; start bmp at the right spot\r
354 \r
355                 DEC planeCounter\r
356                 JNZ PLANE_LOOP    ; do all 4 planes\r
357     }\r
358 }\r
359 \r
360 void\r
361 modexDrawSpritePBuf(page_t *page, int x, int y, planar_buf_t *bmp) {\r
362     /* draw the whole sprite */\r
363     modexDrawSpritePBufRegion(page, x, y, 0, 0, bmp->width, bmp->height, bmp);\r
364 }\r
365 \r
366 void\r
367 modexDrawSpritePBufRegion(page_t *page, int x, int y,\r
368                       int rx, int ry, int rw, int rh, planar_buf_t *bmp) {\r
369         word poffset = (word)page->data + y*(page->width/4) + x/4;\r
370         byte *data = bmp->plane[0];\r
371         word bmpOffset = (word) data + ry * bmp->width + rx;\r
372         word width = rw;\r
373         word height = rh;\r
374         byte plane = 1 << ((byte) x & 0x03);\r
375         word scanCount = width/4 + (width%4 ? 1 :0);\r
376         word nextPageRow = page->width/4 - scanCount;\r
377         word nextBmpRow = (word) bmp->width - width;\r
378         word rowCounter;\r
379         byte planeCounter = 4;\r
380 \r
381     __asm {\r
382                 MOV AX, SCREEN_SEG      ; go to the VGA memory\r
383                 MOV ES, AX\r
384 \r
385                 MOV DX, SC_INDEX        ; point at the map mask register\r
386                 MOV AL, MAP_MASK        ;\r
387                 OUT DX, AL            ;\r
388 \r
389         PLANE_LOOP:\r
390                 MOV DX, SC_DATA  ; select the current plane\r
391                 MOV AL, plane      ;\r
392                 OUT DX, AL            ;\r
393 \r
394                 ;-- begin plane painting\r
395                 MOV AX, height    ; start the row counter\r
396                 MOV rowCounter, AX      ;\r
397                 MOV DI, poffset  ; go to the first pixel\r
398                 MOV SI, bmpOffset       ; go to the bmp pixel\r
399         ROW_LOOP:\r
400                 MOV CX, width      ; count the columns\r
401         SCAN_LOOP:\r
402                 LODSB\r
403                 DEC SI\r
404                 CMP AL, 0\r
405                 JNE DRAW_PIXEL    ; draw non-zero pixels\r
406 \r
407                 INC DI            ; skip the transparent pixel\r
408                 ADD SI, 1\r
409                 JMP NEXT_PIXEL\r
410         DRAW_PIXEL:\r
411                 MOVSB              ; copy the pixel\r
412         NEXT_PIXEL:\r
413                 SUB CX, 3              ; we skip the next 3\r
414                 ADD SI, 3              ; skip the bmp pixels\r
415                 LOOP SCAN_LOOP    ; finish the scan\r
416 \r
417                 MOV AX, nextPageRow\r
418                 ADD DI, AX            ; go to the next row on screen\r
419                 MOV AX, nextBmpRow\r
420                 ADD SI, AX            ; go to the next row on bmp\r
421 \r
422                 DEC rowCounter\r
423                 JNZ ROW_LOOP        ; do all the rows\r
424                 ;-- end plane painting\r
425 \r
426                 MOV AL, plane      ; advance to the next plane\r
427                 SHL AL, 1              ;\r
428                 AND AL, 0x0f        ; mask the plane properly\r
429                 MOV plane, AL      ; store the plane\r
430 \r
431                 INC bmpOffset      ; start bmp at the right spot\r
432 \r
433                 DEC planeCounter\r
434                 JNZ PLANE_LOOP    ; do all 4 planes\r
435     }\r
436 }\r
437 \r
438 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)\r
439 {\r
440         /* vertical drawing routine by joncampbell123.\r
441          *\r
442          * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.\r
443          * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.\r
444          *\r
445          * NTS: addr defines what VGA memory address we use, "x" is redundant except to specify which of the 4 pixels we select in the map mask register. */\r
446         word drawaddr;\r
447         word colm, row;\r
448         byte fontbyte;\r
449         byte plane;\r
450         byte m1,m2;\r
451 \r
452         plane = x & 3;\r
453         m1 = 0x80; // left half\r
454         m2 = 0x08; // right half\r
455         for (colm=0;colm < 4;colm++) {\r
456                 drawaddr = addr;\r
457                 modexSelectPlane(PLANE(plane));\r
458                 for (row=0;row < 8;row++) {\r
459                         fontbyte = romFontsData.l[row];\r
460                         vga_state.vga_graphics_ram[drawaddr  ] = (fontbyte & m1) ? col : bgcol;\r
461                         vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;\r
462                         drawaddr += page->width >> 2;\r
463                 }\r
464 \r
465                 m1 >>= 1;\r
466                 m2 >>= 1;\r
467                 if ((++plane) == 4) {\r
468                         addr++;\r
469                         plane = 0;\r
470                 }\r
471         }\r
472 }\r