Subversion Repositories Kolibri OS

Rev

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
}
478