1 /* Version 1.3 - 990522
2 ******************************************************************************
3 
4    LibGGI display code for Doom and Heretic
5 
6    Copyright (C) 1999	Marcus Sundberg [marcus@ggi-project.org]
7 
8    Permission is hereby granted, free of charge, to any person obtaining a
9    copy of this software and associated documentation files (the "Software"),
10    to deal in the Software without restriction, including without limitation
11    the rights to use, copy, modify, merge, publish, distribute, sublicense,
12    and/or sell copies of the Software, and to permit persons to whom the
13    Software is furnished to do so, subject to the following conditions:
14 
15    The above copyright notice and this permission notice shall be included in
16    all copies or substantial portions of the Software.
17 
18    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21    THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 ******************************************************************************
26 */
27 
28 /* Comment this out to disable support for FPS meter */
29 #define SHOW_FPS
30 
31 /* Uncomment this is you have a Linux Heretic prior to 1.0beta1 */
32 /*
33 #define NO_FILTERING
34 */
35 
36 #include <stdlib.h>
37 #include <ctype.h>
38 #include <ggi/ggi.h>
39 
40 #ifdef I_GGI_DOOM
41 #include "doomstat.h"
42 #include "i_system.h"
43 #include "v_video.h"
44 #include "m_argv.h"
45 #include "d_main.h"
46 #include "r_draw.h"
47 #endif
48 #ifdef I_GGI_HERETIC
49 void R_InitBuffer (int width, int height);
50 #endif
51 
52 #include "doomdef.h"
53 
54 #if defined(I_GGI_DOOM)
55 #define SCREEN0_PTR	(screens[0])
56 #elif defined(I_GGI_HERETIC)
57 #define SCREEN0_PTR	(screen)
58 #else
59 #error You must define I_GGI_DOOM or I_GGI_HERETIC!
60 #endif
61 
62 /* Needed by reset_framecounter() */
63 static ggi_visual_t ggivis=NULL;
64 
65 #ifdef SHOW_FPS
66 #include <unistd.h>
67 #include <sys/time.h>
68 
69 static struct timeval	starttime;
70 static long		totalframes;
71 static int		showfps = 0;
72 
reset_framecounter(void)73 static void reset_framecounter(void)
74 {
75 	ggi_color black = { 0x0, 0x0, 0x0 };
76 	ggi_color white = { 0xffff, 0xffff, 0xffff };
77 
78 	/* Set text colors */
79 	ggiSetGCForeground(ggivis, ggiMapColor(ggivis, &white));
80 	ggiSetGCBackground(ggivis, ggiMapColor(ggivis, &black));
81 
82 	totalframes = 0;
83 	gettimeofday(&starttime, NULL);
84 }
85 #endif
86 
87 static int     lastmousex = 0;
88 static int     lastmousey = 0;
89 boolean        mousemoved = false;
90 int            buttonstate=0;
91 
92 static int     realwidth, realheight;
93 static int     doublebuffer;
94 static int     scale;
95 static int     stride;
96 static int     pixelsize;
97 
98 static const ggi_directbuffer *dbuf1, *dbuf2;
99 static int     usedbuf, havedbuf;
100 static void   *frameptr[2] = { NULL, NULL };
101 static void   *oneline = NULL;
102 static void   *palette = NULL;
103 static int     curframe = 0;
104 static int     modexrefresh=0;
105 static int     dontdraw = 0;
106 
107 
108 static inline void
do_scale8(int xsize,int ysize,uint8 * dest,uint8 * src)109 do_scale8(int xsize, int ysize, uint8 *dest, uint8 *src)
110 {
111 	int i, j, destinc = stride*2-xsize*2;
112 	for (j = 0; j < ysize; j++) {
113 		for (i = 0; i < xsize; /* i is incremented below */) {
114 			register uint32 pix1 = src[i++], pix2 = src[i++];
115 #ifdef GGI_LITTLE_ENDIAN
116 			*((uint32 *) (dest + stride))
117 				= *((uint32 *) dest)
118 				= (pix1 | (pix1 << 8)
119 				   | (pix2 << 16) | (pix2 << 24));
120 #else
121 			*((uint32 *) (dest + stride))
122 				= *((uint32 *) dest)
123 				= (pix2 | (pix2 << 8)
124 				   | (pix1 << 16) | (pix1 << 24));
125 #endif
126 			dest += 4;
127 		}
128 		dest += destinc;
129 		src += xsize;
130 	}
131 }
132 
133 static inline void
do_scale16(int xsize,int ysize,uint8 * dest,uint8 * src)134 do_scale16(int xsize, int ysize, uint8 *dest, uint8 *src)
135 {
136 	int i, j, destinc = stride*2-xsize*4;
137 	uint16 *palptr = palette;
138 	for (j = 0; j < ysize; j++) {
139 		for (i = 0; i < xsize; /* i is incremented below */) {
140 			register uint32 pixel = palptr[src[i++]];
141 			*((uint32 *) (dest + stride))
142 				= *((uint32 *) dest)
143 				= pixel | (pixel << 16);
144 			dest += 4;
145 		}
146 		dest += destinc;
147 		src += xsize;
148 	}
149 }
150 
151 static inline void
do_scale32(int xsize,int ysize,uint8 * dest,uint8 * src)152 do_scale32(int xsize, int ysize, uint8 *dest, uint8 *src)
153 {
154 	int i, j, destinc = stride*2-xsize*8;
155 	uint32 *palptr = palette;
156 	for (j = 0; j < ysize; j++) {
157 		for (i = 0; i < xsize; /* i is incremented below */) {
158 			register uint32 pixel = palptr[src[i++]];
159 			*((uint32 *) (dest + stride))
160 				= *((uint32 *) (dest)) = pixel;
161 			dest += 4;
162 			*((uint32 *) (dest + stride))
163 				= *((uint32 *) (dest)) = pixel;
164 			dest += 4;
165 		}
166 		dest += destinc;
167 		src += xsize;
168 	}
169 }
170 
171 
172 static inline void
do_copy8(int xsize,int ysize,uint8 * dest,uint8 * src)173 do_copy8(int xsize, int ysize, uint8 *dest, uint8 *src)
174 {
175 	int i, j;
176 	uint8 *palptr = palette;
177 
178 	for (j = 0; j < ysize; j++) {
179 		for (i = 0; i < xsize; i++) {
180 			dest[i] = palptr[src[i]];
181 		}
182 		dest += stride;
183 		src += xsize;
184 	}
185 }
186 
187 static inline void
do_copy16(int xsize,int ysize,uint16 * dest,uint8 * src)188 do_copy16(int xsize, int ysize, uint16 *dest, uint8 *src)
189 {
190 	int i, j, destinc = stride/2;
191 	uint16 *palptr = palette;
192 
193 	for (j = 0; j < ysize; j++) {
194 		for (i = 0; i < xsize; i++) {
195 			dest[i] = palptr[src[i]];
196 		}
197 		dest += destinc;
198 		src += xsize;
199 	}
200 }
201 
202 static inline void
do_copy32(int xsize,int ysize,uint32 * dest,uint8 * src)203 do_copy32(int xsize, int ysize, uint32 *dest, uint8 *src)
204 {
205 	int i, j, destinc = stride/4;
206 	uint32 *palptr = palette;
207 
208 	for (j = 0; j < ysize; j++) {
209 		for (i = 0; i < xsize; i++) {
210 			dest[i] = palptr[src[i]];
211 		}
212 		dest += destinc;
213 		src += xsize;
214 	}
215 }
216 
217 
key(int label,int sym)218 int key(int label, int sym)
219 {
220 	int rc=0;
221 	switch(label) {
222 	case GIIK_CtrlL:  case GIIK_CtrlR:  rc=KEY_RCTRL; 	break;
223 	case GIIK_ShiftL: case GIIK_ShiftR: rc=KEY_RSHIFT;	break;
224 	case GIIK_MetaL:  case GIIK_MetaR:
225 	case GIIK_AltL:   case GIIK_AltR:   rc=KEY_RALT;	break;
226 
227 	case GIIUC_BackSpace:	rc = KEY_BACKSPACE;	break;
228 	case GIIUC_Escape:	rc = KEY_ESCAPE;	break;
229 #ifdef I_GGI_HERETIC
230 	case GIIK_Delete:	rc = KEY_DELETE;	break;
231 	case GIIK_Insert:	rc = KEY_INSERT;	break;
232 	case GIIK_PageUp:	rc = KEY_PAGEUP;	break;
233 	case GIIK_PageDown:	rc = KEY_PAGEDOWN;	break;
234 	case GIIK_Home:	rc = KEY_HOME;		break;
235 	case GIIK_End:	rc = KEY_END;		break;
236 #endif /* I_GGI_HERETIC */
237 	case GIIUC_Tab:	rc = KEY_TAB;		break;
238 	case GIIK_Up:	rc = KEY_UPARROW;	break;
239 	case GIIK_Down:	rc = KEY_DOWNARROW;	break;
240 	case GIIK_Left:	rc = KEY_LEFTARROW;	break;
241 	case GIIK_Right:rc = KEY_RIGHTARROW;	break;
242 	case GIIK_Enter:rc = KEY_ENTER;		break;
243 	case GIIK_F1:	rc = KEY_F1;		break;
244 	case GIIK_F2:	rc = KEY_F2;		break;
245 	case GIIK_F3:	rc = KEY_F3;		break;
246 	case GIIK_F4:	rc = KEY_F4;		break;
247 	case GIIK_F5:	rc = KEY_F5;		break;
248 	case GIIK_F6:	rc = KEY_F6;		break;
249 	case GIIK_F7:	rc = KEY_F7;		break;
250 	case GIIK_F8:	rc = KEY_F8;		break;
251 	case GIIK_F9:	rc = KEY_F9;		break;
252 	case GIIK_F10:	rc = KEY_F10;		break;
253 	case GIIK_F11:	rc = KEY_F11;		break;
254 	case GIIK_F12:	rc = KEY_F12;		break;
255 	case GIIK_Pause:rc = KEY_PAUSE;		break;
256 
257 	default:
258 		/* Must use label here, or it won't work when shift is down */
259 		if ((label >= '0' && label <= '9') ||
260 		    (label >= 'A' && label <= 'Z') ||
261 		    label == '.' ||
262 		    label == ',') {
263 			/* We want lowercase */
264 			rc = tolower(label);
265 		} else if (sym < 256) {
266 			/* ASCII key - we want those */
267 			rc = sym;
268 			switch (sym) {
269 				/* Some special cases */
270 			case '+': rc = KEY_EQUALS;	break;
271 			case '-': rc = KEY_MINUS;
272 			default:			break;
273 			}
274 		}
275 	}
276 	return rc;
277 }
278 
I_ShutdownGraphics(void)279 void I_ShutdownGraphics(void)
280 {
281 	if (ggivis != NULL) {
282 		if (!usedbuf) {
283 			free(SCREEN0_PTR);
284 		}
285 		if (oneline) {
286 			free(oneline);
287 			oneline = NULL;
288 		}
289 		if (palette) {
290 			free(palette);
291 			palette = NULL;
292 		}
293 		ggiClose(ggivis);
294 		ggivis = NULL;
295 	}
296 	ggiExit();
297 }
298 
299 
I_StartFrame(void)300 void I_StartFrame (void)
301 {
302 }
303 
I_GetEvent(void)304 void I_GetEvent(void)
305 {
306 	event_t event;
307 	int nev;
308 	ggi_event ev;
309 	struct timeval t = {0,0};
310 	ggi_event_mask mask;
311 
312 	mask = ggiEventPoll(ggivis, emAll, &t);
313 	if (!mask) return;
314 
315 	nev = ggiEventsQueued(ggivis, mask);
316 
317 	while (nev) {
318 		ggiEventRead(ggivis, &ev, mask);
319 		switch (ev.any.type) {
320 		case evKeyPress:
321 			event.type = ev_keydown;
322 			event.data1 = key(ev.key.label,ev.key.sym);
323 #ifdef SHOW_FPS
324 			if (event.data1 == KEY_BACKSPACE &&
325 			    gamestate == GS_LEVEL) {
326 				/* Toggle and reset the FPS counter */
327 				showfps = !showfps;
328 				reset_framecounter();
329 			}
330 #endif
331 			D_PostEvent(&event);
332 			break;
333 		case evKeyRelease:
334 			event.type = ev_keyup;
335 			event.data1 = key(ev.key.label,ev.key.sym);
336 			D_PostEvent(&event);
337 			break;
338 		case evPtrButtonPress:
339 			event.type = ev_mouse;
340 			buttonstate = event.data1 =
341 				buttonstate | 1<<(ev.pbutton.button-1);
342 			event.data2 = event.data3 = 0;
343 			D_PostEvent(&event);
344 			break;
345 		case evPtrButtonRelease:
346 			event.type = ev_mouse;
347 			buttonstate = event.data1 =
348 				buttonstate ^ 1<<(ev.pbutton.button-1);
349 			event.data2 = event.data3 = 0;
350 			D_PostEvent(&event);
351 			break;
352 		case evPtrAbsolute:
353 			event.type = ev_mouse;
354 			event.data1 = buttonstate;
355 			event.data2 = (ev.pmove.x - lastmousex) << 2;
356 			event.data3 = (lastmousey - ev.pmove.y) << 2;
357 
358 			if (event.data2 || event.data3) {
359 				lastmousex = ev.pmove.x;
360 				lastmousey = ev.pmove.y;
361 				if (ev.pmove.x != screenwidth/2 &&
362 				    ev.pmove.y != screenheight/2) {
363 					D_PostEvent(&event);
364 					mousemoved = false;
365 				} else {
366 					mousemoved = true;
367 				}
368 			}
369 			break;
370 		case evPtrRelative:
371 			event.type = ev_mouse;
372 			event.data1 = buttonstate;
373 			event.data2 = ev.pmove.x << 2;
374 			event.data3 = -ev.pmove.y << 2;
375 
376 			if (event.data2 || event.data3) {
377 				lastmousex += ev.pmove.x;
378 				lastmousey += ev.pmove.y;
379 				if (ev.pmove.x != screenwidth/2 &&
380 				    ev.pmove.y != screenheight/2) {
381 					D_PostEvent(&event);
382 					mousemoved = false;
383 				} else {
384 					mousemoved = true;
385 				}
386 			}
387 			break;
388 		case evCommand:
389 			if (ev.cmd.code == GGICMD_REQUEST_SWITCH) {
390 				ggi_cmddata_switchrequest *data = (void*)
391 					ev.cmd.data;
392 				if (data->request == GGI_REQSW_UNMAP) {
393 					ggi_event ev;
394 					ev.cmd.size = sizeof(gii_cmd_nodata_event);
395 					ev.cmd.type = evCommand;
396 					ev.cmd.code =GGICMD_ACKNOWLEDGE_SWITCH;
397 					ggiEventSend(ggivis, &ev);
398 					dontdraw = 1;
399 				}
400 			}
401 			break;
402 		case evExpose:
403 			dontdraw = 0;
404 			break;
405 		}
406 		nev--;
407 	}
408 }
409 
I_StartTic(void)410 void I_StartTic (void)
411 {
412 	if (ggivis) I_GetEvent();
413 }
414 
I_UpdateNoBlit(void)415 void I_UpdateNoBlit (void)
416 {
417 }
418 
I_FinishUpdate(void)419 void I_FinishUpdate (void)
420 {
421 	if (dontdraw) return;
422 
423 #ifdef I_GGI_HERETIC
424 #ifndef NO_FILTERING
425 	/* Filters the first 32 palette-entry-color'd(gray-color) pixels
426 	   if wanted */
427 	if (lifilter && !bilifilter) {
428 		V_Filter_Screen_linear(SCREEN0_PTR);
429 	}
430 	if (bilifilter && !lifilter) {
431 		V_Filter_Screen_bilinear(SCREEN0_PTR);
432 	}
433 #endif
434 #endif
435 
436 	if (!usedbuf) {
437 		int	i;
438 
439 		if (havedbuf) {
440 			if (ggiResourceAcquire(dbuf1->resource,
441 					       GGI_ACTYPE_WRITE) != 0 ||
442 			    (doublebuffer ?
443 			     ggiResourceAcquire(dbuf2->resource,
444 						GGI_ACTYPE_WRITE) != 0
445 			     : 0)) {
446 				ggiPanic("Unable to acquire DirectBuffer!\n");
447 			}
448 			frameptr[0] = dbuf1->write;
449 			if (doublebuffer) {
450 				frameptr[1] = dbuf2->write;
451 			} else {
452 				frameptr[1] = frameptr[0];
453 			}
454 		}
455 		if (scale) {
456 			switch (pixelsize) {
457 			case 1:	if (havedbuf) {
458 				do_scale8(screenwidth, screenheight,
459 					  frameptr[curframe], SCREEN0_PTR);
460 			} else {
461 				uint8 *buf = SCREEN0_PTR;
462 				for (i=0; i < screenheight; i++) {
463 					do_scale8(screenwidth, 1, oneline,buf);
464 					ggiPutBox(ggivis, 0, i*2, realwidth,
465 						  2, oneline);
466 					buf += screenwidth;
467 				}
468 			}
469 			break;
470 			case 2: if (havedbuf) {
471 				do_scale16(screenwidth, screenheight,
472 					   frameptr[curframe], SCREEN0_PTR);
473 			} else {
474 				uint8 *buf = SCREEN0_PTR;
475 				for (i=0; i < screenheight; i++) {
476 					do_scale16(screenwidth, 1,
477 						   oneline, buf);
478 					ggiPutBox(ggivis, 0, i*2, realwidth,
479 						  2, oneline);
480 					buf += screenwidth;
481 				}
482 			}
483 			break;
484 			case 4: if (havedbuf) {
485 				do_scale32(screenwidth, screenheight,
486 					   frameptr[curframe], SCREEN0_PTR);
487 			} else {
488 				uint8 *buf = SCREEN0_PTR;
489 				for (i=0; i < screenheight; i++) {
490 					do_scale32(screenwidth, 1,
491 						   oneline, buf);
492 					ggiPutBox(ggivis, 0, i*2, realwidth,
493 						  2, oneline);
494 					buf += screenwidth;
495 				}
496 			}
497 			break;
498 			}
499 		} else if (palette) {
500 			switch (pixelsize) {
501 			case 1:	if (havedbuf) {
502 				do_copy8(screenwidth, screenheight,
503 					 frameptr[curframe], SCREEN0_PTR);
504 			} else {
505 				uint8 *buf = SCREEN0_PTR;
506 				for (i=0; i < screenheight; i++) {
507 					do_copy8(screenwidth, 1, oneline,buf);
508 					ggiPutBox(ggivis, 0, i, realwidth,
509 						  1, oneline);
510 					buf += screenwidth;
511 				}
512 			}
513 			break;
514 			case 2: if (havedbuf) {
515 				do_copy16(screenwidth, screenheight,
516 					  frameptr[curframe], SCREEN0_PTR);
517 			} else {
518 				uint8 *buf = SCREEN0_PTR;
519 				for (i=0; i < screenheight; i++) {
520 					do_copy16(screenwidth, 1,
521 						  oneline, buf);
522 					ggiPutBox(ggivis, 0, i, realwidth,
523 						  1, oneline);
524 					buf += screenwidth;
525 				}
526 			}
527 			break;
528 			case 4: if (havedbuf) {
529 				do_copy32(screenwidth, screenheight,
530 					  frameptr[curframe], SCREEN0_PTR);
531 			} else {
532 				uint8 *buf = SCREEN0_PTR;
533 				for (i=0; i < screenheight; i++) {
534 					do_copy32(screenwidth, 1,
535 						  oneline, buf);
536 					ggiPutBox(ggivis, 0, i, realwidth,
537 						  1, oneline);
538 					buf += screenwidth;
539 				}
540 			}
541 			break;
542 			}
543 		} else if (!modexrefresh) {
544 			/* faster, but ugly in ModeX modes */
545 			ggiPutBox(ggivis, 0, 0, screenwidth, screenheight,
546 				  SCREEN0_PTR);
547 		} else {
548 			/* slower, but nicer in ModeX modes */
549 			uint8 *buf = SCREEN0_PTR;
550 			for (i = 0; i < screenheight; i++) {
551 				ggiPutHLine(ggivis, 0, i, screenwidth, buf);
552 				buf += screenwidth;
553 			}
554 		}
555 		if (havedbuf) {
556 			ggiResourceRelease(dbuf1->resource);
557 			if (doublebuffer) {
558 				ggiResourceRelease(dbuf2->resource);
559 			}
560 		}
561 
562 	}
563 #ifdef SHOW_FPS
564 	if (showfps) {
565 		struct timeval curtime;
566 		double diff;
567 		char str[64];
568 
569 		totalframes++;
570 		gettimeofday(&curtime, NULL);
571 		diff = (curtime.tv_sec - starttime.tv_sec);
572 		diff += ((double)curtime.tv_usec - starttime.tv_usec)/1000000;
573 		if (diff != 0) {
574 			sprintf(str, "FPS: %.1f", totalframes/diff);
575 			ggiPuts(ggivis, 1, 1, str);
576 		}
577 	}
578 #endif
579 	if (doublebuffer) {
580 		ggiSetDisplayFrame(ggivis, curframe);
581 		curframe = !curframe;
582 		if (usedbuf) {
583 			SCREEN0_PTR = frameptr[curframe];
584 			/* Ouch, we need to recalculate the line offsets */
585 			R_InitBuffer(scaledviewwidth, viewheight);
586 		}
587 		ggiSetWriteFrame(ggivis, curframe);
588 	}
589 
590 	ggiFlush(ggivis);
591 }
592 
I_SetPalette(byte * pal)593 void I_SetPalette (byte* pal)
594 {
595 	int i;
596 	ggi_color col[256];
597 	byte *gamma = gammatable[usegamma];
598 
599 	for (i = 0; i < 256; i++) {
600 		col[i].r = gamma[(*pal++)] << (GGI_COLOR_PRECISION-8);
601 		col[i].g = gamma[(*pal++)] << (GGI_COLOR_PRECISION-8);
602 		col[i].b = gamma[(*pal++)] << (GGI_COLOR_PRECISION-8);
603 	}
604 	if (palette) {
605 		ggiPackColors(ggivis, palette, col, 256);
606 	} else {
607 		ggiSetPalette(ggivis, 0, 256, col);
608 	}
609 }
610 
I_CheckRes()611 void I_CheckRes()
612 {
613 }
614 
InitGraphLib(void)615 void InitGraphLib(void)
616 {
617 }
618 
I_InitGraphics(void)619 void I_InitGraphics(void)
620 {
621 	ggi_mode mode;
622 	int noflicker = 0;
623 
624 	fprintf(stderr, "I_InitGraphics: Init GGI-visual.\n");
625 
626 	if (ggiInit() < 0) I_Error("Unable to init LibGGI!\n");
627 	if ((ggivis = ggiOpen(NULL)) == NULL) {
628 		I_Error("Unable to open default visual!\n");
629 	}
630 	ggiSetFlags(ggivis, GGIFLAG_ASYNC);
631 	ggiSetEventMask(ggivis, emKey | emPointer);
632 
633 	modexrefresh = M_CheckParm("-modex") > 0;
634 	doublebuffer = M_CheckParm("-doublebuffer") > 0;
635 	scale = M_CheckParm("-scale") > 0;
636 	noflicker = M_CheckParm("-noflicker") > 0;
637 
638 	realwidth = screenwidth;
639 	realheight = screenheight;
640 	if (scale) {
641 		realwidth *= 2;
642 		realheight *= 2;
643 	}
644 
645 	if ((!doublebuffer || ggiCheckSimpleMode(ggivis, realwidth, realheight,
646 						 2, GT_8BIT, &mode) < 0) &&
647 	    (ggiCheckSimpleMode(ggivis, realwidth, realheight, GGI_AUTO,
648 				GT_8BIT, &mode) < 0) &&
649 #if defined(I_GGI_HERETIC)
650 /* Heretic still only works reliably in 320x200 (640x400 if scaled) */
651 	    (ggiCheckSimpleMode(ggivis, realwidth, realheight, GGI_AUTO,
652 				GT_AUTO, &mode) < 0 )) {
653 		I_Error("Can't set %ix%i mode\n",
654 			realwidth, realheight);
655 #elif defined(I_GGI_DOOM)
656 		(ggiCheckSimpleMode(ggivis, realwidth, realheight, GGI_AUTO,
657 				    GT_AUTO, &mode) < 0) &&
658 			(mode.visible.x > MAXSCREENWIDTH ||
659 			 mode.visible.y > MAXSCREENHEIGHT)) {
660 					I_Error("Can't find a suitable mode\n",
661 						realwidth, realheight);
662 #endif
663 				}
664 	if (ggiSetMode(ggivis, &mode) < 0) {
665 		I_Error("LibGGI can't set any modes at all?!\n");
666 	}
667 
668 	realwidth  = mode.visible.x;
669 	realheight = mode.visible.y;
670 	if (scale) {
671 		screenwidth  = realwidth / 2;
672 		screenheight = realheight / 2;
673 	} else {
674 		screenwidth  = realwidth;
675 		screenheight = realheight;
676 	}
677 
678 	pixelsize = (GT_SIZE(mode.graphtype)+7) / 8;
679 	if (mode.graphtype != GT_8BIT) {
680 		if ((palette = malloc(pixelsize*256)) == NULL) {
681 			I_Error("Unable to allocate memory?!\n");
682 		}
683 	}
684 
685 
686 	usedbuf = havedbuf = 0;
687 	stride = realwidth*pixelsize;
688 	if ((dbuf1 = ggiDBGetBuffer(ggivis, 0)) != NULL &&
689 	    (dbuf1->type & GGI_DB_SIMPLE_PLB) &&
690 	    (doublebuffer ? ((dbuf2 = ggiDBGetBuffer(ggivis, 1)) != NULL &&
691 			     (dbuf2->type & GGI_DB_SIMPLE_PLB)) : 1)) {
692 		havedbuf = 1;
693 		stride = dbuf1->buffer.plb.stride;
694 		fprintf(stderr, "I_InitGraphics: Have DirectBuffer visual\n");
695 		if (!noflicker && !scale && !palette &&
696 		    stride == pixelsize*realwidth &&
697 		    !ggiResourceMustAcquire(dbuf1->resource) &&
698 		    (doublebuffer ? !ggiResourceMustAcquire(dbuf2->resource)
699 		     : 1)) {
700 			usedbuf = 1;
701 			frameptr[0] = dbuf1->write;
702 			if (doublebuffer) {
703 				frameptr[1] = dbuf2->write;
704 			} else {
705 				frameptr[1] = frameptr[0];
706 			}
707 			SCREEN0_PTR = frameptr[0];
708 			fprintf(stderr,
709 				"I_InitGraphics: Using DirectBuffer with");
710 			if (doublebuffer)	{
711 				fprintf(stderr, " doublebuffering\n");
712 			} else {
713 				fprintf(stderr, " singlebuffering\n");
714 			}
715 		}
716 	}
717 	if (!usedbuf) {
718 		ggi_event ev;
719 		ev.cmd.size = sizeof(gii_cmd_nodata_event);
720 		ev.cmd.type = evCommand;
721 		ev.cmd.code = GGICMD_NOHALT_ON_UNMAP;
722 		ggiEventSend(ggivis, &ev);
723 
724 		ggiAddEventMask(ggivis, emCommand | emExpose);
725 
726 		if ((SCREEN0_PTR = malloc(screenwidth*screenheight)) == NULL) {
727 			I_Error("Unable to allocate memory?!\n");
728 		}
729 		if (!havedbuf && (scale || palette)) {
730 			int linesize = pixelsize*realwidth;
731 			if (scale) linesize *= 4;
732 			if ((oneline = malloc(linesize)) == NULL) {
733 				I_Error("Unable to allocate memory?!\n");
734 			}
735 		}
736 		fprintf(stderr,
737 			"I_InitGraphics: Drawing into offscreen memory\n");
738 	}
739 	/* We will start drawing to frame 0, and start displaying frame 1 */
740 	if (doublebuffer)	{
741 		ggiSetWriteFrame(ggivis, 0);
742 		ggiSetDisplayFrame(ggivis, 1);
743 	}
744 
745 	curframe = 0;
746 }
747