mesh, obj loading, sorting, shitty normals...
[dos_low3d] / src / video.asm
1         bits 32
2         section .text USE32
3
4 SC_ADDR         equ 3c4h        ; sequence controller address register
5 CRTC_ADDR       equ 3d4h        ; CRTC address register
6
7         global init_video_
8 init_video_:
9         pusha
10         mov ax, 13h
11         int 10h
12
13         ; disable chain-4 (bit 3 of sequencer memory mode register [4])
14         mov dx, SC_ADDR
15         mov ax, 0604h
16         out dx, ax
17         ; disable double-word addressing (bit 6 of CRTC underline location
18         ; register [14h])
19         mov dx, CRTC_ADDR
20         mov ax, 0014h
21         out dx, ax
22         ; enable byte mode address generation (bit 6 of CRTC mode control
23         ; register [17h])
24         mov ax, 0e317h
25         out dx, ax
26
27         ; clear all 256kb of vram
28         mov dx, SC_ADDR
29         mov ax, 0f02h   ; map mask reg (2) enable all planes (f)
30         out dx, ax
31         mov edi, 0a0000h
32         mov ecx, 3fffh
33         xor eax, eax
34         rep stosd
35
36         ; initial back buffer is the second page
37         mov dword [_vid_backbuf], 0a4000h
38
39         ; set initial scanout address to page 0. if we never pageflip, we
40         ; can just draw to a0000 as usual and it will be visible.
41         ; This also makes sure the low byte is 0, because we're not touching it
42         ; while page flipping; we flip by toggling a bit in the high byte.
43         mov dx, 3dah
44 .invb:  in al, dx
45         and al, 8
46         jnz .invb
47         mov dx, CRTC_ADDR
48         mov ax, 000ch   ; 0ch: start address high register
49         mov ax, 000dh   ; 0dh: start address low register
50         out dx, ax
51
52         popa
53         ret
54
55         global close_video_
56 close_video_:
57         push ax
58         mov ax, 3
59         int 10h
60         pop ax
61         ret
62
63         global vid_setpalent_
64 vid_setpalent_:
65         mov ah, dl
66         mov dx, 3c8h
67         out dx, al
68         inc dx
69         mov al, ah
70         shr al, 2
71         out dx, al
72         mov al, bl
73         shr al, 2
74         out dx, al
75         mov al, cl
76         shr al, 2
77         out dx, al
78         ret
79
80         ; clear the framebuffer 4 pixels at a time
81         global vid_clearfb_
82 vid_clearfb_:
83         push eax
84         push ecx
85         push edx
86         push edi
87         mov dx, SC_ADDR
88         mov ax, 0f02h   ; map mask reg (2) enable all planes (f)
89         out dx, ax
90         mov edi, [_vid_backbuf]
91         mov ecx, 4000   ; 4000 dwords * 4 planes * 4 bytes = 64000 pixels
92         ;xor eax, eax
93         mov eax, 08080808h
94         rep stosd
95         pop edi
96         pop edx
97         pop ecx
98         pop eax
99         ret
100
101         ; clear area of the framebuffer
102         ; eax: x  edx: y  ebx: width  ecx: height
103         global vid_clearfb_rect_
104 vid_clearfb_rect_:
105         push edi
106         push esi
107         mov edi, [_vid_backbuf]
108         shr eax, 2
109         add edi, eax
110         lea eax, [edx * 4 + edx]
111         shl eax, 4
112         add edi, eax
113
114         mov eax, ebx
115         or eax, ecx
116         cmp eax, 0
117         jle .done       ; abort if width or height is negative or zero
118
119         ; enable all planes
120         mov dx, SC_ADDR
121         mov ax, 0f02h   ; map mask reg (2) enable all planes (f)
122         out dx, ax
123
124         xor eax, eax
125         ;mov eax, [xyzzy]
126         ;add eax, 01010101h
127         ;cmp al, 3
128         ;jbe .foo
129         ;mov eax, 01010101h
130 ;.foo:  mov [xyzzy], eax
131         add ebx, 15     ; round up to next 16-pixel block
132         shr ebx, 4      ; /4 (planes) /4 (stosd) = /16
133         mov edx, ecx    ; use edx for height, to free ecx for rep stosd
134 .yloop: mov esi, edi    ; save pointer
135         mov ecx, ebx
136         rep stosd
137         mov edi, esi    ; restore pointer
138         add edi, 80     ; advance scanline (320 / 4 planes)
139         dec edx
140         jnz .yloop
141 .done:  pop esi
142         pop edi
143         ret
144
145
146         ; vid_backbuf is the linear address of the back buffer in video RAM
147         ; either a0000 or a4000. Flipping bit 14 switches between them, and
148         ; masking with ffff gives the CRTC start address.
149
150         global vid_pgflip_
151 vid_pgflip_:
152         push eax
153         push ebx
154         push edx
155         ; set the current backbuffer as the new CRTC scanout start address
156         mov ebx, [_vid_backbuf]
157         mov bl, 0ch             ; CRTC start address high register
158
159         ; only proceed if we're out of vblank, otherwise we might think we've
160         ; set a new scanout address, but it might not be latched until the next
161         ; vblank, and we'll be drawing over the scanout buffer in the meantime.
162         mov dx, 3dah
163 .wait:  in al, dx
164         and al, 8
165         jnz .wait
166
167         mov dx, CRTC_ADDR
168         mov ax, bx              ; get previously prepared reg addr and value
169         out dx, ax
170         ; clear low bits and flip the backbuffer pointer
171         xor ax, 400ch
172         mov [_vid_backbuf], ax
173         pop edx
174         pop ebx
175         pop eax
176         ret
177
178         section .data
179
180         align 4
181         global _vid_backbuf
182 _vid_backbuf dd 0
183 xyzzy   dd 01010101h