summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/progs/quake/vid_vga.c
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2018-02-11 15:34:30 -0500
committerFranklin Wei <git@fwei.tk>2019-07-19 22:37:40 -0400
commit5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4 (patch)
tree84406e21639529a185556a33e5de7f43cffc277b /apps/plugins/sdl/progs/quake/vid_vga.c
parentb70fecf21ddc21877ec1ae7888d9c18a979e37ad (diff)
downloadrockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.tar.gz
rockbox-5d05b9d3e920a6aa5fcb553758e98ed0da8c91e4.zip
Quake!
This ports id Software's Quake to run on the SDL plugin runtime. The source code originated from id under the GPLv2 license. I used https://github.com/ahefner/sdlquake as the base of my port. Performance is, unsurprisingly, not on par with what you're probably used to on PC. I average about 10FPS on ipod6g, but it's still playable. Sound works well enough, but in-game music is not supported. I've written ARM assembly routines for the inner sound loop. Make sure you turn the "brightness" all the way down, or colors will look funky. To run, extract Quake's data files to /.rockbox/quake. Have fun! Change-Id: I4285036e967d7f0722802d43cf2096c808ca5799
Diffstat (limited to 'apps/plugins/sdl/progs/quake/vid_vga.c')
-rw-r--r--apps/plugins/sdl/progs/quake/vid_vga.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/quake/vid_vga.c b/apps/plugins/sdl/progs/quake/vid_vga.c
new file mode 100644
index 0000000000..6fbec9de5c
--- /dev/null
+++ b/apps/plugins/sdl/progs/quake/vid_vga.c
@@ -0,0 +1,478 @@
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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 <dos.h>
27
28#include "quakedef.h"
29#include "d_local.h"
30#include "dosisms.h"
31#include "vid_dos.h"
32#include <dpmi.h>
33
34extern regs_t regs;
35
36int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
37byte *VGA_pagebase;
38vmode_t *VGA_pcurmode;
39
40static int VGA_planar;
41static int VGA_numpages;
42static int VGA_buffersize;
43
44void *vid_surfcache;
45int vid_surfcachesize;
46
47int VGA_highhunkmark;
48
49#include "vgamodes.h"
50
51#define NUMVIDMODES (sizeof(vgavidmodes) / sizeof(vgavidmodes[0]))
52
53void VGA_UpdatePlanarScreen (void *srcbuffer);
54
55static byte backingbuf[48*24];
56
57/*
58================
59VGA_BeginDirectRect
60================
61*/
62void 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<reps ; 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<reps ; 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================
130VGA_EndDirectRect
131================
132*/
133void 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<reps ; 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<reps ; 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================
191VGA_Init
192================
193*/
194void 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================
214VGA_WaitVsync
215================
216*/
217void VGA_WaitVsync (void)
218{
219 while ((inportb (0x3DA) & 0x08) == 0)
220 ;
221}
222
223
224/*
225================
226VGA_ClearVideoMem
227================
228*/
229void 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================
244VGA_FreeAndAllocVidbuffer
245================
246*/
247qboolean 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================
307VGA_CheckAdequateMem
308================
309*/
310qboolean 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================
339VGA_InitMode
340================
341*/
342int 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================
408VGA_SetPalette
409================
410*/
411void 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================
427VGA_SwapBuffersCopy
428================
429*/
430void 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================
466VGA_SwapBuffers
467================
468*/
469void 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