Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 1 | /* |
2 | Copyright (C) 1996-1997 Id Software, Inc. |
||
3 | |||
4 | This program is free software; you can redistribute it and/or |
||
5 | modify it under the terms of the GNU General Public License |
||
6 | as published by the Free Software Foundation; either version 2 |
||
7 | of the License, or (at your option) any later version. |
||
8 | |||
9 | This program is distributed in the hope that it will be useful, |
||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
12 | |||
13 | See the GNU General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU General Public License |
||
16 | along with this program; if not, write to the Free Software |
||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||
18 | |||
19 | */ |
||
20 | // |
||
21 | // vid_vga.c: VGA-specific DOS video stuff |
||
22 | // |
||
23 | |||
24 | // TODO: proper handling of page-swap failure |
||
25 | |||
26 | #include |
||
27 | |||
28 | #include "quakedef.h" |
||
29 | #include "d_local.h" |
||
30 | #include "dosisms.h" |
||
31 | #include "vid_dos.h" |
||
32 | #include |
||
33 | |||
34 | extern regs_t regs; |
||
35 | |||
36 | int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes; |
||
37 | byte *VGA_pagebase; |
||
38 | vmode_t *VGA_pcurmode; |
||
39 | |||
40 | static int VGA_planar; |
||
41 | static int VGA_numpages; |
||
42 | static int VGA_buffersize; |
||
43 | |||
44 | void *vid_surfcache; |
||
45 | int vid_surfcachesize; |
||
46 | |||
47 | int VGA_highhunkmark; |
||
48 | |||
49 | #include "vgamodes.h" |
||
50 | |||
51 | #define NUMVIDMODES (sizeof(vgavidmodes) / sizeof(vgavidmodes[0])) |
||
52 | |||
53 | void VGA_UpdatePlanarScreen (void *srcbuffer); |
||
54 | |||
55 | static byte backingbuf[48*24]; |
||
56 | |||
57 | /* |
||
58 | ================ |
||
59 | VGA_BeginDirectRect |
||
60 | ================ |
||
61 | */ |
||
62 | void VGA_BeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x, |
||
63 | int y, byte *pbitmap, int width, int height) |
||
64 | { |
||
65 | int i, j, k, plane, reps, repshift; |
||
66 | |||
67 | if (!lvid->direct) |
||
68 | return; |
||
69 | |||
70 | if (lvid->aspect > 1.5) |
||
71 | { |
||
72 | reps = 2; |
||
73 | repshift = 1; |
||
74 | } |
||
75 | else |
||
76 | { |
||
77 | reps = 1; |
||
78 | repshift = 0; |
||
79 | } |
||
80 | |||
81 | if (pcurrentmode->planar) |
||
82 | { |
||
83 | for (plane=0 ; plane<4 ; plane++) |
||
84 | { |
||
85 | // select the correct plane for reading and writing |
||
86 | outportb (SC_INDEX, MAP_MASK); |
||
87 | outportb (SC_DATA, 1 << plane); |
||
88 | outportb (GC_INDEX, READ_MAP); |
||
89 | outportb (GC_DATA, plane); |
||
90 | |||
91 | for (i=0 ; i<(height << repshift) ; i += reps) |
||
92 | { |
||
93 | for (k=0 ; k |
||
94 | { |
||
95 | for (j=0 ; j<(width >> 2) ; j++) |
||
96 | { |
||
97 | backingbuf[(i + k) * 24 + (j << 2) + plane] = |
||
98 | lvid->direct[(y + i + k) * VGA_rowbytes + |
||
99 | (x >> 2) + j]; |
||
100 | lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] = |
||
101 | pbitmap[(i >> repshift) * 24 + |
||
102 | (j << 2) + plane]; |
||
103 | } |
||
104 | } |
||
105 | } |
||
106 | } |
||
107 | } |
||
108 | else |
||
109 | { |
||
110 | for (i=0 ; i<(height << repshift) ; i += reps) |
||
111 | { |
||
112 | for (j=0 ; j |
||
113 | { |
||
114 | memcpy (&backingbuf[(i + j) * 24], |
||
115 | lvid->direct + x + ((y << repshift) + i + j) * |
||
116 | VGA_rowbytes, |
||
117 | width); |
||
118 | memcpy (lvid->direct + x + ((y << repshift) + i + j) * |
||
119 | VGA_rowbytes, |
||
120 | &pbitmap[(i >> repshift) * width], |
||
121 | width); |
||
122 | } |
||
123 | } |
||
124 | } |
||
125 | } |
||
126 | |||
127 | |||
128 | /* |
||
129 | ================ |
||
130 | VGA_EndDirectRect |
||
131 | ================ |
||
132 | */ |
||
133 | void VGA_EndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x, |
||
134 | int y, int width, int height) |
||
135 | { |
||
136 | int i, j, k, plane, reps, repshift; |
||
137 | |||
138 | if (!lvid->direct) |
||
139 | return; |
||
140 | |||
141 | if (lvid->aspect > 1.5) |
||
142 | { |
||
143 | reps = 2; |
||
144 | repshift = 1; |
||
145 | } |
||
146 | else |
||
147 | { |
||
148 | reps = 1; |
||
149 | repshift = 0; |
||
150 | } |
||
151 | |||
152 | if (pcurrentmode->planar) |
||
153 | { |
||
154 | for (plane=0 ; plane<4 ; plane++) |
||
155 | { |
||
156 | // select the correct plane for writing |
||
157 | outportb (SC_INDEX, MAP_MASK); |
||
158 | outportb (SC_DATA, 1 << plane); |
||
159 | |||
160 | for (i=0 ; i<(height << repshift) ; i += reps) |
||
161 | { |
||
162 | for (k=0 ; k |
||
163 | { |
||
164 | for (j=0 ; j<(width >> 2) ; j++) |
||
165 | { |
||
166 | lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] = |
||
167 | backingbuf[(i + k) * 24 + (j << 2) + plane]; |
||
168 | } |
||
169 | } |
||
170 | } |
||
171 | } |
||
172 | } |
||
173 | else |
||
174 | { |
||
175 | for (i=0 ; i<(height << repshift) ; i += reps) |
||
176 | { |
||
177 | for (j=0 ; j |
||
178 | { |
||
179 | memcpy (lvid->direct + x + ((y << repshift) + i + j) * |
||
180 | VGA_rowbytes, |
||
181 | &backingbuf[(i + j) * 24], |
||
182 | width); |
||
183 | } |
||
184 | } |
||
185 | } |
||
186 | } |
||
187 | |||
188 | |||
189 | /* |
||
190 | ================ |
||
191 | VGA_Init |
||
192 | ================ |
||
193 | */ |
||
194 | void VGA_Init (void) |
||
195 | { |
||
196 | int i; |
||
197 | |||
198 | // link together all the VGA modes |
||
199 | for (i=0 ; i<(NUMVIDMODES - 1) ; i++) |
||
200 | { |
||
201 | vgavidmodes[i].pnext = &vgavidmodes[i+1]; |
||
202 | } |
||
203 | |||
204 | // add the VGA modes at the start of the mode list |
||
205 | vgavidmodes[NUMVIDMODES-1].pnext = pvidmodes; |
||
206 | pvidmodes = &vgavidmodes[0]; |
||
207 | |||
208 | numvidmodes += NUMVIDMODES; |
||
209 | } |
||
210 | |||
211 | |||
212 | /* |
||
213 | ================ |
||
214 | VGA_WaitVsync |
||
215 | ================ |
||
216 | */ |
||
217 | void VGA_WaitVsync (void) |
||
218 | { |
||
219 | while ((inportb (0x3DA) & 0x08) == 0) |
||
220 | ; |
||
221 | } |
||
222 | |||
223 | |||
224 | /* |
||
225 | ================ |
||
226 | VGA_ClearVideoMem |
||
227 | ================ |
||
228 | */ |
||
229 | void VGA_ClearVideoMem (int planar) |
||
230 | { |
||
231 | |||
232 | if (planar) |
||
233 | { |
||
234 | // enable all planes for writing |
||
235 | outportb (SC_INDEX, MAP_MASK); |
||
236 | outportb (SC_DATA, 0x0F); |
||
237 | } |
||
238 | |||
239 | Q_memset (VGA_pagebase, 0, VGA_rowbytes * VGA_height); |
||
240 | } |
||
241 | |||
242 | /* |
||
243 | ================ |
||
244 | VGA_FreeAndAllocVidbuffer |
||
245 | ================ |
||
246 | */ |
||
247 | qboolean VGA_FreeAndAllocVidbuffer (viddef_t *lvid, int allocnewbuffer) |
||
248 | { |
||
249 | int tsize, tbuffersize; |
||
250 | |||
251 | if (allocnewbuffer) |
||
252 | { |
||
253 | // alloc an extra line in case we want to wrap, and allocate the z-buffer |
||
254 | tbuffersize = (lvid->rowbytes * (lvid->height + 1)) + |
||
255 | (lvid->width * lvid->height * sizeof (*d_pzbuffer)); |
||
256 | } |
||
257 | else |
||
258 | { |
||
259 | // just allocate the z-buffer |
||
260 | tbuffersize = lvid->width * lvid->height * sizeof (*d_pzbuffer); |
||
261 | } |
||
262 | |||
263 | tsize = D_SurfaceCacheForRes (lvid->width, lvid->height); |
||
264 | |||
265 | tbuffersize += tsize; |
||
266 | |||
267 | // see if there's enough memory, allowing for the normal mode 0x13 pixel, |
||
268 | // z, and surface buffers |
||
269 | if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 + |
||
270 | 0x10000 * 3) < minimum_memory) |
||
271 | { |
||
272 | Con_Printf ("Not enough memory for video mode\n"); |
||
273 | VGA_pcurmode = NULL; // so no further accesses to the buffer are |
||
274 | // attempted, particularly when clearing |
||
275 | return false; // not enough memory for mode |
||
276 | } |
||
277 | |||
278 | VGA_buffersize = tbuffersize; |
||
279 | vid_surfcachesize = tsize; |
||
280 | |||
281 | if (d_pzbuffer) |
||
282 | { |
||
283 | D_FlushCaches (); |
||
284 | Hunk_FreeToHighMark (VGA_highhunkmark); |
||
285 | d_pzbuffer = NULL; |
||
286 | } |
||
287 | |||
288 | VGA_highhunkmark = Hunk_HighMark (); |
||
289 | |||
290 | d_pzbuffer = Hunk_HighAllocName (VGA_buffersize, "video"); |
||
291 | |||
292 | vid_surfcache = (byte *)d_pzbuffer |
||
293 | + lvid->width * lvid->height * sizeof (*d_pzbuffer); |
||
294 | |||
295 | if (allocnewbuffer) |
||
296 | { |
||
297 | lvid->buffer = (void *)( (byte *)vid_surfcache + vid_surfcachesize); |
||
298 | lvid->conbuffer = lvid->buffer; |
||
299 | } |
||
300 | |||
301 | return true; |
||
302 | } |
||
303 | |||
304 | |||
305 | /* |
||
306 | ================ |
||
307 | VGA_CheckAdequateMem |
||
308 | ================ |
||
309 | */ |
||
310 | qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes, |
||
311 | int allocnewbuffer) |
||
312 | { |
||
313 | int tbuffersize; |
||
314 | |||
315 | tbuffersize = width * height * sizeof (*d_pzbuffer); |
||
316 | |||
317 | if (allocnewbuffer) |
||
318 | { |
||
319 | // alloc an extra line in case we want to wrap, and allocate the z-buffer |
||
320 | tbuffersize += (rowbytes * (height + 1)); |
||
321 | } |
||
322 | |||
323 | tbuffersize += D_SurfaceCacheForRes (width, height); |
||
324 | |||
325 | // see if there's enough memory, allowing for the normal mode 0x13 pixel, |
||
326 | // z, and surface buffers |
||
327 | if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 + |
||
328 | 0x10000 * 3) < minimum_memory) |
||
329 | { |
||
330 | return false; // not enough memory for mode |
||
331 | } |
||
332 | |||
333 | return true; |
||
334 | } |
||
335 | |||
336 | |||
337 | /* |
||
338 | ================ |
||
339 | VGA_InitMode |
||
340 | ================ |
||
341 | */ |
||
342 | int VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode) |
||
343 | { |
||
344 | vextra_t *pextra; |
||
345 | |||
346 | pextra = pcurrentmode->pextradata; |
||
347 | |||
348 | if (!VGA_FreeAndAllocVidbuffer (lvid, pextra->vidbuffer)) |
||
349 | return -1; // memory alloc failed |
||
350 | |||
351 | if (VGA_pcurmode) |
||
352 | VGA_ClearVideoMem (VGA_pcurmode->planar); |
||
353 | |||
354 | // mode 0x13 is the base for all the Mode X-class mode sets |
||
355 | regs.h.ah = 0; |
||
356 | regs.h.al = 0x13; |
||
357 | dos_int86(0x10); |
||
358 | |||
359 | VGA_pagebase = (void *)real2ptr(0xa0000); |
||
360 | lvid->direct = (pixel_t *)VGA_pagebase; |
||
361 | |||
362 | // set additional registers as needed |
||
363 | VideoRegisterSet (pextra->pregset); |
||
364 | |||
365 | VGA_numpages = 1; |
||
366 | lvid->numpages = VGA_numpages; |
||
367 | |||
368 | VGA_width = (lvid->width + 0x1F) & ~0x1F; |
||
369 | VGA_height = lvid->height; |
||
370 | VGA_planar = pcurrentmode->planar; |
||
371 | if (VGA_planar) |
||
372 | VGA_rowbytes = lvid->rowbytes / 4; |
||
373 | else |
||
374 | VGA_rowbytes = lvid->rowbytes; |
||
375 | VGA_bufferrowbytes = lvid->rowbytes; |
||
376 | lvid->colormap = host_colormap; |
||
377 | lvid->fullbright = 256 - LittleLong (*((int *)lvid->colormap + 2048)); |
||
378 | |||
379 | lvid->maxwarpwidth = WARP_WIDTH; |
||
380 | lvid->maxwarpheight = WARP_HEIGHT; |
||
381 | |||
382 | lvid->conbuffer = lvid->buffer; |
||
383 | lvid->conrowbytes = lvid->rowbytes; |
||
384 | lvid->conwidth = lvid->width; |
||
385 | lvid->conheight = lvid->height; |
||
386 | |||
387 | VGA_pcurmode = pcurrentmode; |
||
388 | |||
389 | VGA_ClearVideoMem (pcurrentmode->planar); |
||
390 | |||
391 | if (_vid_wait_override.value) |
||
392 | { |
||
393 | Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC); |
||
394 | } |
||
395 | else |
||
396 | { |
||
397 | Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE); |
||
398 | } |
||
399 | |||
400 | D_InitCaches (vid_surfcache, vid_surfcachesize); |
||
401 | |||
402 | return 1; |
||
403 | } |
||
404 | |||
405 | |||
406 | /* |
||
407 | ================ |
||
408 | VGA_SetPalette |
||
409 | ================ |
||
410 | */ |
||
411 | void VGA_SetPalette(viddef_t *lvid, vmode_t *pcurrentmode, unsigned char *pal) |
||
412 | { |
||
413 | int shiftcomponents=2; |
||
414 | int i; |
||
415 | |||
416 | UNUSED(lvid); |
||
417 | UNUSED(pcurrentmode); |
||
418 | |||
419 | dos_outportb(0x3c8, 0); |
||
420 | for (i=0 ; i<768 ; i++) |
||
421 | outportb(0x3c9, pal[i]>>shiftcomponents); |
||
422 | } |
||
423 | |||
424 | |||
425 | /* |
||
426 | ================ |
||
427 | VGA_SwapBuffersCopy |
||
428 | ================ |
||
429 | */ |
||
430 | void VGA_SwapBuffersCopy (viddef_t *lvid, vmode_t *pcurrentmode, |
||
431 | vrect_t *rects) |
||
432 | { |
||
433 | |||
434 | UNUSED(pcurrentmode); |
||
435 | |||
436 | // TODO: can write a dword at a time |
||
437 | // TODO: put in ASM |
||
438 | // TODO: copy only specified rectangles |
||
439 | if (VGA_planar) |
||
440 | { |
||
441 | |||
442 | // TODO: copy only specified rectangles |
||
443 | |||
444 | VGA_UpdatePlanarScreen (lvid->buffer); |
||
445 | } |
||
446 | else |
||
447 | { |
||
448 | while (rects) |
||
449 | { |
||
450 | VGA_UpdateLinearScreen ( |
||
451 | lvid->buffer + rects->x + (rects->y * lvid->rowbytes), |
||
452 | VGA_pagebase + rects->x + (rects->y * VGA_rowbytes), |
||
453 | rects->width, |
||
454 | rects->height, |
||
455 | lvid->rowbytes, |
||
456 | VGA_rowbytes); |
||
457 | |||
458 | rects = rects->pnext; |
||
459 | } |
||
460 | } |
||
461 | } |
||
462 | |||
463 | |||
464 | /* |
||
465 | ================ |
||
466 | VGA_SwapBuffers |
||
467 | ================ |
||
468 | */ |
||
469 | void VGA_SwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode, vrect_t *rects) |
||
470 | { |
||
471 | UNUSED(lvid); |
||
472 | |||
473 | if (vid_wait.value == VID_WAIT_VSYNC) |
||
474 | VGA_WaitVsync (); |
||
475 | |||
476 | VGA_SwapBuffersCopy (lvid, pcurrentmode, rects); |
||
477 | }768>>>(NUMVIDMODES>><>><>(height>><>(width>><>(height>><>4>><>><>><>(height>><>><>(width>><>(height>><>4> |
||
478 |