1// vid_next.m -- NEXTSTEP video driver
2
3#define	INTERCEPTOR
4
5#import <appkit/appkit.h>
6#import <string.h>
7#import "intercep.h"
8#include "quakedef.h"
9#include "d_local.h"
10
11int	BASEWIDTH = 320;
12int BASEHEIGHT = 200;
13
14void SetupBitmap (void);
15void SetupFramebuffer (void);
16void UpdateBitmap (void);
17void UpdateFramebuffer (vrect_t *vrect);
18void SetVideoEncoding (char *encoding);
19void Update8_1 (pixel_t *src, byte *dest, int width,
20		int height, int destrowbytes);
21void Update16_1 (pixel_t *src, unsigned short *dest, int width,
22		int height, int destrowbytes);
23void Update32_1 (pixel_t *src, unsigned *dest, int width,
24		int height, int destrowbytes);
25
26
27@interface QuakeView : View
28@end
29
30@interface FrameWindow:Window
31@end
32
33unsigned short	d_8to16table[256];	// not used in 8 bpp mode
34unsigned	d_8to24table[256];	// not used in 8 bpp mode
35
36
37/*
38==========================================================================
39
40						API FUNCTIONS
41
42==========================================================================
43*/
44
45typedef enum {disp_bitmap, disp_framebuffer}	display_t;
46
47pixel_t		*vid_buffer;
48pixel_t		*buffernative;
49unsigned	pcolormap[4][256];	// map from quake pixels to native pixels
50unsigned	pixbytesnative;
51unsigned	rowbytesnative;
52int			dither;
53
54int			drawdirect = 0;
55
56int			d_con_indirect = 0;
57
58display_t		vid_display;
59
60byte			vid_palette[768];	// saved for restarting vid system
61
62id				vid_window_i;
63id				vid_view_i;
64#ifdef INTERCEPTOR
65NXDirectBitmap	*vid_dbitmap_i;
66NXFramebuffer	*vid_framebuffer_i;
67#endif
68
69NXRect   		screenBounds;		// only valid in framebuffer mode
70
71int				vid_scale;
72
73char			*vid_encodingstring;
74
75int				vid_fullscreen;
76int				vid_screen;
77
78int				vid_high_hunk_mark;
79
80typedef enum
81{
82	enc_24_rgba,
83	enc_24_0rgb,
84	enc_24_rgb0,
85	enc_12_rgba,
86	enc_12_rgb0,
87	enc_15_0rgb,
88	enc_564,
89	enc_8_gray,
90	enc_8_rgb
91} vid_encoding_t;
92
93typedef struct
94{
95	char			*string;
96	int				pixelbytes;
97	void			(*colormap) (void);
98	vid_encoding_t	name;
99} vidtype_t;
100
101vid_encoding_t	vid_encoding;
102
103void	Table8 (void);
104void	Table15 (void);
105void	Table12 (void);
106void	Table12Swap (void);
107void	Table24 (void);
108void	Table24Swap (void);
109
110vidtype_t vid_encodingtable[]=
111{
112{"RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA",4, Table24Swap, enc_24_rgba},
113{"--------RRRRRRRRGGGGGGGGBBBBBBBB",4, Table24, enc_24_0rgb},
114{"RRRRRRRRGGGGGGGGBBBBBBBB--------",4, Table24Swap, enc_24_rgb0},
115{"RRRRGGGGBBBBAAAA",2, Table12Swap, enc_12_rgba},
116{"RRRRGGGGBBBB----",2, Table12, enc_12_rgb0},
117{"-RRRRRGGGGGBBBBB",2, Table15, enc_15_0rgb},
118{"WWWWWWWW",1, Table8, enc_8_gray},
119{"PPPPPPPP",1, Table8, enc_8_rgb},
120{NULL,0, 0, 0}
121};
122
123vidtype_t	*vid_type;
124void	InitNS8Bit (void);
125
126/*
127================
128D_BeginDirectRect
129================
130*/
131void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
132{
133// direct drawing of the "accessing disk" icon isn't supported under Nextstep
134}
135
136
137/*
138================
139D_EndDirectRect
140================
141*/
142void D_EndDirectRect (int x, int y, int width, int height)
143{
144// direct drawing of the "accessing disk" icon isn't supported under Nextstep
145}
146
147
148/*
149==============
150VID_Restart
151
152internal call only
153===============
154*/
155void VID_Restart (display_t mode, int scale)
156{
157	vid_display = mode;
158	vid_scale = scale;
159
160	[NXApp activateSelf:YES];
161
162	if (vid_display == disp_framebuffer)
163		SetupFramebuffer ();
164	else
165		SetupBitmap ();
166
167	vid.recalc_refdef = 1;
168}
169
170
171/*
172=================
173VID_Scale_f
174
175Keybinding command
176=================
177*/
178void VID_Scale_f (void)
179{
180	int		scale;
181
182	if (Cmd_Argc () != 2)
183		return;
184
185	scale = atoi (Cmd_Argv(1));
186	if (scale != 1 && scale != 2)
187	{
188		Con_Printf ("scale must be 1 or 2\n");
189		return;
190	}
191	VID_Shutdown ();
192	VID_Restart (vid_display, scale);
193}
194
195/*
196=================
197VID_Mode_f
198
199Keybinding command
200=================
201*/
202void VID_Mode_f (void)
203{
204	int		mode;
205
206	if (Cmd_Argc () != 2)
207		return;
208
209	mode = atoi (Cmd_Argv(1));
210
211	VID_Shutdown ();
212	if (mode == 0)
213	{
214		drawdirect = 0;
215		VID_Restart (disp_bitmap, vid_scale);
216	}
217	else if (mode == 1)
218	{
219		drawdirect = 0;
220		VID_Restart (disp_framebuffer, vid_scale);
221	}
222	else
223	{
224		drawdirect = 1;
225		VID_Restart (disp_framebuffer, vid_scale);
226	}
227}
228
229/*
230=================
231VID_Size_f
232
233Keybinding command
234=================
235*/
236void VID_Size_f (void)
237{
238	if (Cmd_Argc () != 3)
239		return;
240
241	VID_Shutdown ();
242
243	BASEWIDTH = atoi (Cmd_Argv(1));
244	BASEHEIGHT = atoi (Cmd_Argv(2));
245
246	VID_Restart (vid_display, vid_scale);
247}
248
249/*
250================
251VID_Init
252================
253*/
254void	VID_Init (unsigned char *palette)
255{
256	InitNS8Bit ();			// fixed palette lookups
257
258	Q_memcpy (vid_palette, palette, sizeof(vid_palette));
259
260	if (COM_CheckParm ("-bitmap"))
261		vid_display = disp_bitmap;
262	else
263		vid_display = disp_framebuffer;
264
265	if (COM_CheckParm ("-screen2"))
266		vid_screen = 1;
267	else
268		vid_screen = 0;
269
270	if (COM_CheckParm ("-direct"))
271		drawdirect = 1;
272
273	Cmd_AddCommand ("vid_scale", VID_Scale_f);
274	Cmd_AddCommand ("vid_mode", VID_Mode_f);
275	Cmd_AddCommand ("vid_size", VID_Size_f);
276
277	vid.width = BASEWIDTH;
278	vid.height = BASEHEIGHT;
279	vid.aspect = 1.0;
280	vid.numpages = 1;
281	vid.colormap = host_colormap;
282	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
283	vid.maxwarpwidth = WARP_WIDTH;
284	vid.maxwarpheight = WARP_HEIGHT;
285
286	if (COM_CheckParm ("-scale2"))
287		vid_scale = 2;
288	else
289		vid_scale = 1;
290
291    [Application new];
292
293	VID_Restart (vid_display, vid_scale);
294}
295
296
297/*
298================
299VID_Shutdown
300================
301*/
302void VID_Shutdown (void)
303{
304#ifdef INTERCEPTOR
305	if (vid_dbitmap_i)
306	{
307		[vid_dbitmap_i free];
308		vid_dbitmap_i = 0;
309	}
310	if (vid_framebuffer_i)
311	{
312		[vid_framebuffer_i free];
313		vid_framebuffer_i = 0;
314	}
315#endif
316	[vid_window_i close];
317	[vid_window_i free];
318}
319
320
321/*
322================
323VID_Update
324================
325*/
326void	VID_Update (vrect_t *rects)
327{
328	if (drawdirect)
329		return;
330
331	while (rects)
332	{
333		UpdateFramebuffer (rects);
334		rects = rects->pnext;
335	}
336
337	if (vid_display == disp_bitmap)
338		UpdateBitmap ();
339}
340
341
342/*
343================
344VID_SetPalette
345================
346*/
347void	VID_SetPalette (unsigned char *palette)
348{
349	Q_memcpy (vid_palette, palette, sizeof(vid_palette));
350	vid_type->colormap ();
351}
352
353
354/*
355================
356VID_ShiftPalette
357================
358*/
359void    VID_ShiftPalette (unsigned char *palette)
360{
361
362	VID_SetPalette (palette);
363}
364
365
366/*
367==========================================================================
368
369						NS STUFF
370
371==========================================================================
372*/
373
374
375/*
376=================
377SetVideoEncoding
378=================
379*/
380void SetVideoEncoding (char *encoding)
381{
382	vidtype_t			*type;
383
384	Sys_Printf ("SetVideoEncoding: %s\n",encoding);
385	vid_encodingstring = encoding;
386
387	for (type = vid_encodingtable ; type->string ; type++)
388	{
389		if (strcmp(type->string, encoding) == 0)
390		{
391			pixbytesnative = type->pixelbytes;
392			vid_encoding = type->name;
393			type->colormap ();
394			vid_type = type;
395			return;
396		}
397	}
398
399	Sys_Error ("Unsupported video encoding: %s\n",encoding);
400}
401
402/*
403=================
404AllocBuffers
405=================
406*/
407void AllocBuffers (qboolean withnative)
408{
409	int		surfcachesize;
410	void	*surfcache;
411	int		pixels;
412	int		pixbytes;
413	int		vid_buffersize;
414
415	if (vid_buffer)
416	{
417		D_FlushCaches ();
418		Hunk_FreeToHighMark (vid_high_hunk_mark);
419		vid_high_hunk_mark = 0;
420		vid_buffer = NULL;
421	}
422
423	pixels = vid.width * vid.height;
424
425	pixbytes = 1 +sizeof (*d_pzbuffer);
426	if (withnative)
427		pixbytes += pixbytesnative;
428
429	surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height);
430	vid_buffersize = pixels * pixbytes + surfcachesize;
431
432	vid_high_hunk_mark = Hunk_HighMark ();
433	vid_buffer = Hunk_HighAllocName (vid_buffersize, "video");
434	if (!vid_buffer)
435		Sys_Error ("Couldn't alloc video buffers");
436
437	vid.buffer = vid_buffer;
438
439	d_pzbuffer = (unsigned short *)((byte *)vid_buffer + pixels);
440	surfcache = (byte *)d_pzbuffer + pixels * sizeof (*d_pzbuffer);
441	if (withnative)
442		buffernative = (byte *)surfcache + surfcachesize;
443
444	D_InitCaches (surfcache, surfcachesize);
445}
446
447/*
448=================
449SetupFramebuffer
450=================
451*/
452void SetupFramebuffer (void)
453{
454#ifdef INTERCEPTOR
455    int			windowNum;
456	NXRect		cont;
457	NXScreen	const *screens;
458	int			screencount;
459
460//
461// get the screen list
462//
463	[NXApp getScreens:&screens count:&screencount];
464
465//
466// create vid_framebuffer_i
467//
468    vid_framebuffer_i = [[NXFramebuffer alloc]
469		   initFromScreen:screens[vid_screen].screenNumber andMapIfPossible:YES];
470    [vid_framebuffer_i screenBounds:&screenBounds];
471
472	SetVideoEncoding ([vid_framebuffer_i pixelEncoding]);
473
474	buffernative = [vid_framebuffer_i data];
475	rowbytesnative = [vid_framebuffer_i bytesPerRow];
476
477//
478// create window
479//
480	if (vid_fullscreen)
481	{
482		vid.height = screenBounds.size.height / vid_scale;
483		vid.width = screenBounds.size.width / vid_scale;
484		cont.origin.x = 0;
485		cont.origin.y = 0;
486		cont.size.width = screenBounds.size.width;
487		cont.size.height = screenBounds.size.height;
488	}
489	else
490	{
491		buffernative = (unsigned char *)buffernative + 8 * rowbytesnative +
492				8 * pixbytesnative;
493		vid.width = BASEWIDTH;
494		vid.height = BASEHEIGHT;
495		cont.origin.x = 8;
496		cont.origin.y = screenBounds.size.height - (vid.height*vid_scale) - 8;
497		cont.size.width = vid.width * vid_scale;
498		cont.size.height = vid.height * vid_scale;
499	}
500
501    vid_window_i = [[FrameWindow alloc]
502		 initContent:		&cont
503		 style:				NX_PLAINSTYLE
504		 backing:			NX_NONRETAINED
505		 buttonMask:		0
506		 defer:				NO
507		 screen:			screens+vid_screen];
508    windowNum = [vid_window_i windowNum];
509    PSsetwindowlevel(40, windowNum);
510    PSsetautofill(YES, windowNum);
511    PSgsave();
512    PSwindowdeviceround(windowNum);
513    PSsetgray(NX_BLACK);
514    PSsetexposurecolor();
515    PSgrestore();
516
517//
518// create view
519//
520	vid_view_i = [[QuakeView alloc] initFrame: &screenBounds];
521	[[vid_window_i setContentView: vid_view_i] free];
522	[vid_window_i makeFirstResponder: vid_view_i];
523	[vid_window_i setDelegate: vid_view_i];
524	[vid_window_i display];
525	[vid_window_i makeKeyAndOrderFront: nil];
526	NXPing ();
527
528	AllocBuffers (false);	// no native buffer
529
530	if (drawdirect)
531	{	// the direct drawing mode to NeXT colorspace
532		vid.buffer = buffernative;
533		vid.rowbytes = rowbytesnative;
534	}
535	else
536		vid.rowbytes = vid.width;
537
538	vid.conbuffer = vid.buffer;
539	vid.conrowbytes = vid.rowbytes;
540	vid.conwidth = vid.width;
541	vid.conheight = vid.height;
542#endif
543}
544
545/*
546=================
547SetupBitmap
548=================
549*/
550void SetupBitmap (void)
551{
552	int		depth;
553	NXRect	content;
554
555//
556// open a window
557//
558	NXSetRect (&content, 8,136, vid.width*vid_scale, vid.height*vid_scale);
559	vid_window_i = [[Window alloc]
560			initContent:	&content
561			style:			NX_RESIZEBARSTYLE
562			backing:		NX_RETAINED
563			buttonMask:		0
564			defer:			NO
565		];
566	[vid_window_i display];
567	[vid_window_i makeKeyAndOrderFront: nil];
568
569	NXPing ();
570
571	content.origin.x = content.origin.y = 0;
572	vid_view_i = [[QuakeView alloc] initFrame: &content];
573	[[vid_window_i setContentView: vid_view_i] free];
574	[vid_window_i makeFirstResponder: vid_view_i];
575	[vid_window_i setDelegate: vid_view_i];
576
577	[vid_window_i addToEventMask: NX_FLAGSCHANGEDMASK];
578
579//
580// find video info
581//
582    depth = [Window defaultDepthLimit];
583    switch (depth) {
584	case NX_EightBitGrayDepth:
585		SetVideoEncoding ("WWWWWWWW");
586	    break;
587	case NX_TwelveBitRGBDepth:
588		SetVideoEncoding ("RRRRGGGGBBBBAAAA");
589	    break;
590	default:
591	case NX_TwentyFourBitRGBDepth:
592		SetVideoEncoding ("RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA");
593	    break;
594//	default:	// 8 bit color shows up as an unknown...
595		Sys_Error ("Unsupported window depth");
596    }
597
598	[vid_window_i setTitle: "Bitmap Quake Console"];
599
600//
601// allocate memory for the back and translation buffers
602//
603	vid.rowbytes = vid.width;
604	rowbytesnative = vid.width * pixbytesnative;
605
606	AllocBuffers (true);
607
608	vid.conbuffer = vid.buffer;
609	vid.conrowbytes = vid.rowbytes;
610	vid.conwidth = vid.width;
611	vid.conheight = vid.height;
612}
613
614
615/*
616=================
617UpdateFramebuffer
618=================
619*/
620void UpdateFramebuffer (vrect_t *vrect)
621{
622	byte		*psourcebase;
623	byte		*pdestbase;
624	int			scale;
625
626	psourcebase = vid.buffer + vrect->x + vrect->y * vid.rowbytes;
627
628	if (vid_display == disp_bitmap)
629		scale = 1;		// let NS do the scaling
630	else
631		scale = vid_scale;
632
633	pdestbase = buffernative + scale *
634			(vrect->x * pixbytesnative + vrect->y * rowbytesnative);
635
636//
637// translate from ideal to native (except 8 bpp direct) and copy to screen
638//
639
640	if (pixbytesnative == 1)
641		Update8_1 (psourcebase, pdestbase, vrect->width, vrect->height,
642				rowbytesnative);
643	else if (pixbytesnative == 2)
644		Update16_1 (psourcebase, (unsigned short *)pdestbase, vrect->width, vrect->height,
645				rowbytesnative);
646	else
647		Update32_1 (psourcebase, (unsigned *)pdestbase, vrect->width, vrect->height,
648				rowbytesnative);
649}
650
651
652/*
653=================
654UpdateBitmap
655=================
656*/
657void UpdateBitmap (void)
658{
659	unsigned char	*planes[5];
660	NXRect			bounds;
661	int				bpp, spp, bps, bpr, colorspace;
662
663//
664// flush the screen with an image call
665//
666	if (pixbytesnative == 1)
667	{
668		bps = 8;
669		spp = 1;
670		bpp = 8;
671		bpr = vid.width;
672		colorspace = NX_OneIsWhiteColorSpace;
673		planes[0] = vid.buffer;
674	}
675	else if (pixbytesnative == 2)
676	{
677		bps = 4;
678		spp = 3;
679		bpp = 16;
680		bpr = vid.width * 2;
681		colorspace = NX_RGBColorSpace;
682		planes[0] = buffernative;
683	}
684	else
685	{
686		bps = 8;
687		spp = 3;
688		bpp = 32;
689		bpr = vid.width * 4;
690		colorspace = NX_RGBColorSpace;
691		planes[0] = buffernative;
692	}
693
694	[vid_view_i getBounds: &bounds];
695	[vid_view_i lockFocus];
696
697	NXDrawBitmap(
698		&bounds,
699		vid.width,
700		vid.height,
701		bps,
702		spp,
703		bpp,
704		bpr,
705		NO,
706		NO,
707		colorspace,
708		planes
709	);
710
711	[vid_view_i unlockFocus];
712    NXPing ();
713}
714
715
716
717/*
718==========================================================================
719
720					TRANSLATION TABLE BUILDING
721
722==========================================================================
723*/
724
725int	redramp[] = {0, 19, 59, 113, 178, 255, 300};
726int greenramp[] = {0, 11, 34,  66, 104, 149, 199, 255, 300};
727int blueramp[] = {0, 28, 84, 161, 255, 300};
728int greyramp[] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204,
729				   221, 238, 255, 300};
730
731byte	greytable[256];
732byte	redtable[256];
733byte	greentable[256];
734byte	bluetable[256];
735
736void FillTable (byte *table, int *ramp, int base)
737{
738	int		i, j, o;
739
740	o = 0;
741	for (i=0 ; i<16 && o < 256; i++)
742	{
743		j = ramp[i];
744		for ( ; o<=j ; o++)
745			table[o] = base + i;
746	}
747}
748
749void	InitNS8Bit (void)
750{
751	FillTable (greytable, greyramp, 240);
752	FillTable (redtable, redramp, 0);
753	FillTable (greentable, greenramp, 0);
754	FillTable (bluetable, blueramp, 0);
755}
756
757
758byte ns8trans[256] =	// FIXME: dynamically calc this so palettes work
759{
7600,241,242,243,244,244,245,246,247,248,249,250,251,252,253,254,
76145,241,241,242,91,91,91,96,96,136,136,136,141,141,141,141,
762241,46,242,243,243,97,97,97,245,246,143,143,143,143,148,148,
7630,5,45,45,50,50,90,90,95,95,95,95,95,140,140,141,
7640,40,40,40,40,80,80,80,80,80,120,120,120,120,120,120,
76545,50,50,90,90,95,95,135,135,135,136,141,141,181,181,181,
76645,90,91,91,131,131,136,136,136,176,181,181,186,226,231,236,
76745,45,91,91,96,96,136,136,137,142,182,182,187,188,188,233,
768188,249,248,247,246,137,137,137,244,243,243,91,242,241,241,45,
769183,183,183,247,137,137,137,137,137,244,91,91,91,241,241,45,
770252,251,188,188,248,248,142,142,142,244,244,243,91,242,241,45,
771247,247,246,246,245,245,244,244,243,243,242,242,51,241,241,5,
772236,231,231,191,186,185,185,140,140,135,135,95,90,90,45,45,
7734,49,49,53,53,93,93,93,93,92,92,92,243,242,46,241,
774239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,
775239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,182
776};
777
778/*
779===================
780Table8
781===================
782*/
783void	Table8 (void)
784{
785	byte	*pal;
786	int		r,g,b,v;
787	int		i;
788	byte	*table;
789
790	pal = vid_palette;
791	table = (byte *)pcolormap[0];
792
793	for (i=0 ; i<256 ; i++)
794	{
795		r = pal[0];
796		g = pal[1];
797		b = pal[2];
798		pal += 3;
799
800// use the grey ramp if all indexes are close
801
802		if (r-g < 16 && r-g > -16 && r-b < 16 && r-b > -16)
803		{
804			v = (r+g+b)/3;
805			*table++ = greytable[v];
806			continue;
807		}
808
809		r = redtable[r];
810		g = greentable[g];
811		b = bluetable[b];
812
813// otherwise use the color cube
814		*table++ = r*(8*5) + g*5 + b;
815	}
816}
817
818/*
819===================
820Table24
821===================
822*/
823void	Table24 (void)
824{
825	byte	*pal;
826	int		r,g,b,v;
827	int		i;
828	unsigned	*table;
829
830
831//
832// 8 8 8 encoding
833//
834	pal = vid_palette;
835	table = (unsigned *)pcolormap[0];
836
837	for (i=0 ; i<256 ; i++)
838	{
839		r = pal[0];
840		g = pal[1];
841		b = pal[2];
842		pal += 3;
843
844		v = (r<<16) + (g<<8) + b;
845		*table++ = v;
846	}
847}
848
849/*
850===================
851Table24Swap
852===================
853*/
854void	Table24Swap (void)
855{
856	byte	*pal;
857	int		r,g,b,v;
858	int		i;
859	unsigned	*table;
860
861//
862// 8 8 8 encoding
863//
864	pal = vid_palette;
865	table = (unsigned *)pcolormap[0];
866
867	for (i=0 ; i<256 ; i++)
868	{
869		r = pal[0];
870		g = pal[1];
871		b = pal[2];
872		pal += 3;
873
874		v = (r<<24) + (g<<16) + (b<<8) /*+ 255*/;
875		v = NXSwapBigLongToHost (v);
876		*table++ = v;
877	}
878}
879
880
881/*
882===================
883Table15
884===================
885*/
886void	Table15 (void)
887{
888	byte			*pal;
889	int				r,g,b,v;
890	int				i, k;
891	unsigned char	*palette;
892	unsigned short	*table;
893	int				dadj;
894	int		ditheradjust[4] = {(1 << 9) * 3 / 8,
895									(1 << 9) * 5 / 8,
896									(1 << 9) * 7 / 8,
897									(1 << 9) * 1 / 8};
898
899	palette = vid_palette;
900	table = (unsigned short *)pcolormap;
901
902//
903// 5 5 5 encoding
904//
905	for (k=0 ; k<4 ; k++)
906	{
907		dadj = ditheradjust[k];
908
909		pal = vid_palette;
910
911		for (i=0 ; i<256 ; i++)
912		{
913		// shift 6 bits to get back to 0-255, & 3 more for 5 bit color
914		// FIXME: scale intensity levels properly
915			r = (pal[0] + dadj) >> 3;
916			g = (pal[1] + dadj) >> 3;
917			b = (pal[2] + dadj) >> 3;
918			pal += 3;
919
920			v = (r<<10) + (g<<5) + b;
921
922			*table++ = v;
923		}
924	}
925}
926
927/*
928===================
929Table12
930===================
931*/
932void	Table12 (void)
933{
934	byte			*pal;
935	int				r,g,b,v;
936	int				i, k;
937	unsigned short	*table;
938	int				dadj;
939	static int		ditheradjust[4] = {(1 << 9) * 3 / 8,
940									   (1 << 9) * 5 / 8,
941									   (1 << 9) * 7 / 8,
942									   (1 << 9) * 1 / 8};
943
944	table = (unsigned short *)pcolormap;
945
946//
947// 4 4 4 encoding
948//
949	for (k=0 ; k<4 ; k++)
950	{
951		dadj = ditheradjust[k];
952
953		pal = vid_palette;
954
955		for (i=0 ; i<256 ; i++)
956		{
957		// shift 5 bits to get back to 0-255, & 4 more for 4 bit color
958		// FIXME: scale intensity levels properly
959			r = (pal[0] + dadj) >> 4;
960			g = (pal[1] + dadj) >> 4;
961			b = (pal[2] + dadj) >> 4;
962			pal += 3;
963
964			v = ((r<<12) + (g<<8) + (b<<4) /*+ 15*/);
965
966			*table++ = v;
967		}
968	}
969}
970
971/*
972===================
973Table12Swap
974===================
975*/
976void	Table12Swap (void)
977{
978	byte			*pal;
979	int				r,g,b,v;
980	int				i, k;
981	unsigned short	*table;
982	int				dadj;
983	static int		ditheradjust[4] = {(1 << 9) * 3 / 8,
984									   (1 << 9) * 5 / 8,
985									   (1 << 9) * 7 / 8,
986									   (1 << 9) * 1 / 8};
987
988	table = (unsigned short *)pcolormap;
989
990//
991// 4 4 4 encoding
992//
993	for (k=0 ; k<4 ; k++)
994	{
995		dadj = ditheradjust[k];
996
997		pal = vid_palette;
998
999		for (i=0 ; i<256 ; i++)
1000		{
1001		// shift 5 bits to get back to 0-255, & 4 more for 4 bit color
1002		// FIXME: scale intensity levels properly
1003			r = (pal[0] + dadj) >> 4;
1004			g = (pal[1] + dadj) >> 4;
1005			b = (pal[2] + dadj) >> 4;
1006			pal += 3;
1007
1008			v = ((r<<12) + (g<<8) + (b<<4) /*+ 15*/);
1009			v = NXSwapBigShortToHost (v);
1010
1011			*table++ = v;
1012		}
1013	}
1014}
1015
1016
1017/*
1018==========================================================================
1019
1020					GENERIC IMAGING FUNCTIONS
1021
1022==========================================================================
1023*/
1024
1025/*
1026===================
1027Update8_1
1028===================
1029*/
1030void Update8_1 (pixel_t *src, byte *dest, int width, int height,
1031		int destrowbytes)
1032{
1033	int				x,y;
1034	unsigned		rowdelta, srcdelta;
1035	unsigned		xcount;
1036	byte			*pdest;
1037	int				xwidth;
1038
1039	pdest = dest;
1040
1041	xcount = width >> 3;
1042	srcdelta = vid.width - width;
1043
1044	xwidth = width - (xcount << 3);
1045	if (xwidth)
1046		Sys_Error ("Width not multiple of 8");
1047
1048	if ((vid_display == disp_framebuffer) && (vid_scale == 2))
1049	{
1050		int		nextrow = destrowbytes;
1051
1052	    rowdelta = destrowbytes - (width << 1)  + destrowbytes;
1053
1054		if (dither)
1055		{
1056			unsigned short	*psrc;
1057
1058			psrc = (unsigned short *)src;
1059
1060			for (y = height ; y ; y--)
1061			{
1062		    	for (x = xcount ; x ;x--)
1063			    {
1064					unsigned	temp;
1065
1066					temp = psrc[0];
1067					pdest[0] = ((byte *)pcolormap[0])[temp];
1068					pdest[1] = ((byte *)pcolormap[1])[temp];
1069					pdest[nextrow] = ((byte *)pcolormap[2])[temp];
1070					pdest[nextrow + 1] = ((byte *)pcolormap[3])[temp];
1071					temp = psrc[1];
1072					pdest[2] = ((byte *)pcolormap[0])[temp];
1073					pdest[3] = ((byte *)pcolormap[1])[temp];
1074					pdest[nextrow + 2] = ((byte *)pcolormap[2])[temp];
1075					pdest[nextrow + 3] = ((byte *)pcolormap[3])[temp];
1076					temp = psrc[2];
1077					pdest[4] = ((byte *)pcolormap[0])[temp];
1078					pdest[5] = ((byte *)pcolormap[1])[temp];
1079					pdest[nextrow + 4] = ((byte *)pcolormap[2])[temp];
1080					pdest[nextrow + 5] = ((byte *)pcolormap[3])[temp];
1081					temp = psrc[3];
1082					pdest[6] = ((byte *)pcolormap[0])[temp];
1083					pdest[7] = ((byte *)pcolormap[1])[temp];
1084					pdest[nextrow + 6] = ((byte *)pcolormap[2])[temp];
1085					pdest[nextrow + 7] = ((byte *)pcolormap[3])[temp];
1086					temp = psrc[4];
1087					pdest[8] = ((byte *)pcolormap[0])[temp];
1088					pdest[9] = ((byte *)pcolormap[1])[temp];
1089					pdest[nextrow + 8] = ((byte *)pcolormap[2])[temp];
1090					pdest[nextrow + 9] = ((byte *)pcolormap[3])[temp];
1091					temp = psrc[5];
1092					pdest[10] = ((byte *)pcolormap[0])[temp];
1093					pdest[11] = ((byte *)pcolormap[1])[temp];
1094					pdest[nextrow + 10] = ((byte *)pcolormap[2])[temp];
1095					pdest[nextrow + 11] = ((byte *)pcolormap[3])[temp];
1096					temp = psrc[6];
1097					pdest[12] = ((byte *)pcolormap[0])[temp];
1098					pdest[13] = ((byte *)pcolormap[1])[temp];
1099					pdest[nextrow + 12] = ((byte *)pcolormap[2])[temp];
1100					pdest[nextrow + 13] = ((byte *)pcolormap[3])[temp];
1101					temp = psrc[7];
1102					pdest[14] = ((byte *)pcolormap[0])[temp];
1103					pdest[15] = ((byte *)pcolormap[1])[temp];
1104					pdest[nextrow + 14] = ((byte *)pcolormap[2])[temp];
1105					pdest[nextrow + 15] = ((byte *)pcolormap[3])[temp];
1106					pdest += 16; psrc += 8;
1107			    }
1108
1109				psrc += srcdelta;
1110			    pdest += rowdelta;
1111			}
1112		}
1113		else
1114		{
1115			byte	*psrc;
1116
1117			psrc = (byte *)src;
1118
1119			for (y = height ; y ; y--)
1120			{
1121				for (x = xcount ; x ;x--)
1122		    	{
1123					pdest[0] = pdest[1] = pdest[nextrow] =
1124						pdest[nextrow + 1] = ((byte *)pcolormap[0])[psrc[0]];
1125					pdest[2] = pdest[3] = pdest[nextrow + 2] =
1126						pdest[nextrow + 3] = ((byte *)pcolormap[0])[psrc[1]];
1127					pdest[4] = pdest[5] = pdest[nextrow + 4] =
1128						pdest[nextrow + 5] = ((byte *)pcolormap[0])[psrc[2]];
1129					pdest[6] = pdest[7] = pdest[nextrow + 6] =
1130						pdest[nextrow + 7] = ((byte *)pcolormap[0])[psrc[3]];
1131					pdest[8] = pdest[9] = pdest[nextrow + 8] =
1132						pdest[nextrow + 9] = ((byte *)pcolormap[0])[psrc[4]];
1133					pdest[10] = pdest[11] = pdest[nextrow + 10] =
1134						pdest[nextrow + 11] = ((byte *)pcolormap[0])[psrc[5]];
1135					pdest[12] = pdest[13] = pdest[nextrow + 12] =
1136						pdest[nextrow + 13] = ((byte *)pcolormap[0])[psrc[6]];
1137					pdest[14] = pdest[15] = pdest[nextrow + 14] =
1138						pdest[nextrow + 15] = ((byte *)pcolormap[0])[psrc[7]];
1139					pdest += 16; psrc += 8;
1140		    	}
1141
1142				psrc += srcdelta;
1143			    pdest += rowdelta;
1144			}
1145		}
1146    }
1147	else
1148	{
1149	    rowdelta = destrowbytes - width;
1150
1151		if (dither)
1152		{
1153			unsigned short	*psrc;
1154
1155			psrc = (unsigned short *)src;
1156
1157			for (y = height ; y>0 ; y -= 2)
1158			{
1159		    	for (x = xcount ; x ;x--)
1160			    {
1161					pdest[0] = ((byte *)pcolormap[0])[psrc[0]];
1162					pdest[1] = ((byte *)pcolormap[1])[psrc[1]];
1163					pdest[2] = ((byte *)pcolormap[0])[psrc[2]];
1164					pdest[3] = ((byte *)pcolormap[1])[psrc[3]];
1165					pdest[4] = ((byte *)pcolormap[0])[psrc[4]];
1166					pdest[5] = ((byte *)pcolormap[1])[psrc[5]];
1167					pdest[6] = ((byte *)pcolormap[0])[psrc[6]];
1168					pdest[7] = ((byte *)pcolormap[1])[psrc[7]];
1169					pdest += 8; psrc += 8;
1170			    }
1171
1172				psrc += srcdelta;
1173			    pdest += rowdelta;
1174
1175		    	for (x = xcount ; x ;x--)
1176			    {
1177					pdest[0] = ((byte *)pcolormap[2])[psrc[0]];
1178					pdest[1] = ((byte *)pcolormap[3])[psrc[1]];
1179					pdest[2] = ((byte *)pcolormap[2])[psrc[2]];
1180					pdest[3] = ((byte *)pcolormap[3])[psrc[3]];
1181					pdest[4] = ((byte *)pcolormap[2])[psrc[4]];
1182					pdest[5] = ((byte *)pcolormap[3])[psrc[5]];
1183					pdest[6] = ((byte *)pcolormap[2])[psrc[6]];
1184					pdest[7] = ((byte *)pcolormap[3])[psrc[7]];
1185					pdest += 8; psrc += 8;
1186			    }
1187
1188				psrc += srcdelta;
1189			    pdest += rowdelta;
1190			}
1191		}
1192		else
1193		{
1194			byte	*psrc;
1195
1196			psrc = (byte *)src;
1197//			srcdelta += width;
1198//			rowdelta += width;
1199
1200			for (y = height ; y ; y--)
1201			{
1202		    	for (x = xcount ; x ;x--)
1203			    {
1204					pdest[0] = ((byte *)pcolormap[0])[psrc[0]];
1205					pdest[1] = ((byte *)pcolormap[0])[psrc[1]];
1206					pdest[2] = ((byte *)pcolormap[0])[psrc[2]];
1207					pdest[3] = ((byte *)pcolormap[0])[psrc[3]];
1208					pdest[4] = ((byte *)pcolormap[0])[psrc[4]];
1209					pdest[5] = ((byte *)pcolormap[0])[psrc[5]];
1210					pdest[6] = ((byte *)pcolormap[0])[psrc[6]];
1211					pdest[7] = ((byte *)pcolormap[0])[psrc[7]];
1212					pdest += 8; psrc += 8;
1213			    }
1214
1215				psrc += srcdelta;
1216			    pdest += rowdelta;
1217		    }
1218		}
1219    }
1220}
1221
1222
1223/*
1224===================
1225Update16_1
1226===================
1227*/
1228void Update16_1 (pixel_t *src, unsigned short *dest, int width,
1229		int height, int destrowbytes)
1230{
1231	int				x,y;
1232	unsigned		rowdelta, srcdelta;
1233	unsigned		xcount;
1234	pixel_t			*psrc;
1235	unsigned short	*pdest;
1236	int				xwidth;
1237
1238
1239	psrc = src;
1240	pdest = dest;
1241
1242	xcount = width >> 3;
1243	srcdelta = vid.width - width;
1244
1245	xwidth = width - (xcount << 3);
1246	if (xwidth)
1247		Sys_Error ("Width not multiple of 8");
1248
1249	if ((vid_display == disp_framebuffer) && (vid_scale == 2))
1250	{
1251		int		nextrow = destrowbytes >> 1;
1252
1253	    rowdelta = (destrowbytes - ((width << 1) << 1) + destrowbytes) >> 1;
1254
1255		if (dither)
1256		{
1257			for (y = height ; y ; y--)
1258			{
1259		    	for (x = xcount ; x ;x--)
1260			    {
1261					unsigned	temp;
1262
1263					temp = psrc[0];
1264					pdest[0] = ((unsigned short *)pcolormap[0])[temp];
1265					pdest[1] = ((unsigned short *)pcolormap[1])[temp];
1266					pdest[nextrow] = ((unsigned short *)pcolormap[2])[temp];
1267					pdest[nextrow + 1] = ((unsigned short *)pcolormap[3])[temp];
1268					temp = psrc[1];
1269					pdest[2] = ((unsigned short *)pcolormap[0])[temp];
1270					pdest[3] = ((unsigned short *)pcolormap[1])[temp];
1271					pdest[nextrow + 2] = ((unsigned short *)pcolormap[2])[temp];
1272					pdest[nextrow + 3] = ((unsigned short *)pcolormap[3])[temp];
1273					temp = psrc[2];
1274					pdest[4] = ((unsigned short *)pcolormap[0])[temp];
1275					pdest[5] = ((unsigned short *)pcolormap[1])[temp];
1276					pdest[nextrow + 4] = ((unsigned short *)pcolormap[2])[temp];
1277					pdest[nextrow + 5] = ((unsigned short *)pcolormap[3])[temp];
1278					temp = psrc[3];
1279					pdest[6] = ((unsigned short *)pcolormap[0])[temp];
1280					pdest[7] = ((unsigned short *)pcolormap[1])[temp];
1281					pdest[nextrow + 6] = ((unsigned short *)pcolormap[2])[temp];
1282					pdest[nextrow + 7] = ((unsigned short *)pcolormap[3])[temp];
1283					temp = psrc[4];
1284					pdest[8] = ((unsigned short *)pcolormap[0])[temp];
1285					pdest[9] = ((unsigned short *)pcolormap[1])[temp];
1286					pdest[nextrow + 8] = ((unsigned short *)pcolormap[2])[temp];
1287					pdest[nextrow + 9] = ((unsigned short *)pcolormap[3])[temp];
1288					temp = psrc[5];
1289					pdest[10] = ((unsigned short *)pcolormap[0])[temp];
1290					pdest[11] = ((unsigned short *)pcolormap[1])[temp];
1291					pdest[nextrow + 10] = ((unsigned short *)pcolormap[2])[temp];
1292					pdest[nextrow + 11] = ((unsigned short *)pcolormap[3])[temp];
1293					temp = psrc[6];
1294					pdest[12] = ((unsigned short *)pcolormap[0])[temp];
1295					pdest[13] = ((unsigned short *)pcolormap[1])[temp];
1296					pdest[nextrow + 12] = ((unsigned short *)pcolormap[2])[temp];
1297					pdest[nextrow + 13] = ((unsigned short *)pcolormap[3])[temp];
1298					temp = psrc[7];
1299					pdest[14] = ((unsigned short *)pcolormap[0])[temp];
1300					pdest[15] = ((unsigned short *)pcolormap[1])[temp];
1301					pdest[nextrow + 14] = ((unsigned short *)pcolormap[2])[temp];
1302					pdest[nextrow + 15] = ((unsigned short *)pcolormap[3])[temp];
1303					pdest += 16; psrc += 8;
1304			    }
1305
1306				psrc += srcdelta;
1307			    pdest += rowdelta;
1308			}
1309		}
1310		else
1311		{
1312			for (y = height ; y ; y--)
1313			{
1314			for (x = xcount ; x ;x--)
1315			    {
1316					pdest[0] = pdest[1] = pdest[nextrow] =
1317							pdest[nextrow + 1] = pcolormap[0][psrc[0]];
1318					pdest[2] = pdest[3] = pdest[nextrow + 2] =
1319							pdest[nextrow + 3] = pcolormap[0][psrc[1]];
1320					pdest[4] = pdest[5] = pdest[nextrow + 4] =
1321							pdest[nextrow + 5] = pcolormap[0][psrc[2]];
1322					pdest[6] = pdest[7] = pdest[nextrow + 6] =
1323							pdest[nextrow + 7] = pcolormap[0][psrc[3]];
1324					pdest[8] = pdest[9] = pdest[nextrow + 8] =
1325							pdest[nextrow + 9] = pcolormap[0][psrc[4]];
1326					pdest[10] = pdest[11] = pdest[nextrow + 10] =
1327							pdest[nextrow + 11] = pcolormap[0][psrc[5]];
1328					pdest[12] = pdest[13] = pdest[nextrow + 12] =
1329							pdest[nextrow + 13] = pcolormap[0][psrc[6]];
1330					pdest[14] = pdest[15] = pdest[nextrow + 14] =
1331							pdest[nextrow + 15] = pcolormap[0][psrc[7]];
1332					pdest += 16; psrc += 8;
1333			    }
1334
1335				psrc += srcdelta;
1336			    pdest += rowdelta;
1337			}
1338    	}
1339	}
1340	else
1341	{
1342	    rowdelta = (destrowbytes - (width<<1))>>1;
1343
1344		if (dither)
1345		{
1346			for (y = height ; y>0 ; y -= 2)
1347			{
1348		    	for (x = xcount ; x ;x--)
1349			    {
1350					pdest[0] = ((unsigned short *)pcolormap[0])[psrc[0]];
1351					pdest[1] = ((unsigned short *)pcolormap[1])[psrc[1]];
1352					pdest[2] = ((unsigned short *)pcolormap[0])[psrc[2]];
1353					pdest[3] = ((unsigned short *)pcolormap[1])[psrc[3]];
1354					pdest[4] = ((unsigned short *)pcolormap[0])[psrc[4]];
1355					pdest[5] = ((unsigned short *)pcolormap[1])[psrc[5]];
1356					pdest[6] = ((unsigned short *)pcolormap[0])[psrc[6]];
1357					pdest[7] = ((unsigned short *)pcolormap[1])[psrc[7]];
1358					pdest += 8; psrc += 8;
1359			    }
1360
1361				psrc += srcdelta;
1362			    pdest += rowdelta;
1363
1364		    	for (x = xcount ; x ;x--)
1365			    {
1366					pdest[0] = ((unsigned short *)pcolormap[2])[psrc[0]];
1367					pdest[1] = ((unsigned short *)pcolormap[3])[psrc[1]];
1368					pdest[2] = ((unsigned short *)pcolormap[2])[psrc[2]];
1369					pdest[3] = ((unsigned short *)pcolormap[3])[psrc[3]];
1370					pdest[4] = ((unsigned short *)pcolormap[2])[psrc[4]];
1371					pdest[5] = ((unsigned short *)pcolormap[3])[psrc[5]];
1372					pdest[6] = ((unsigned short *)pcolormap[2])[psrc[6]];
1373					pdest[7] = ((unsigned short *)pcolormap[3])[psrc[7]];
1374					pdest += 8; psrc += 8;
1375			    }
1376
1377				psrc += srcdelta;
1378			    pdest += rowdelta;
1379			}
1380		}
1381		else
1382		{
1383			for (y = height ; y ; y--)
1384			{
1385			for (x = xcount ; x ;x--)
1386			    {
1387					pdest[0] = pcolormap[0][psrc[0]];
1388					pdest[1] = pcolormap[0][psrc[1]];
1389					pdest[2] = pcolormap[0][psrc[2]];
1390					pdest[3] = pcolormap[0][psrc[3]];
1391					pdest[4] = pcolormap[0][psrc[4]];
1392					pdest[5] = pcolormap[0][psrc[5]];
1393					pdest[6] = pcolormap[0][psrc[6]];
1394					pdest[7] = pcolormap[0][psrc[7]];
1395					pdest += 8; psrc += 8;
1396			    }
1397
1398				psrc += srcdelta;
1399			    pdest += rowdelta;
1400			}
1401    	}
1402	}
1403}
1404
1405
1406/*
1407===================
1408Update32_1
1409===================
1410*/
1411void Update32_1 (pixel_t *src, unsigned *dest, int width, int height,
1412		int destrowbytes)
1413{
1414	int				x,y;
1415	unsigned		rowdelta, srcdelta;
1416	unsigned		xcount;
1417	pixel_t			*psrc;
1418	unsigned		*pdest;
1419	int				xwidth;
1420
1421	psrc = src;
1422	pdest = dest;
1423
1424	xcount = width >> 3;
1425	srcdelta = vid.width - width;
1426
1427	xwidth = width - (xcount << 3);
1428	if (xwidth)
1429		Sys_Error ("Width not multiple of 8");
1430
1431	if ((vid_display == disp_framebuffer) && (vid_scale == 2))
1432	{
1433		int		nextrow = destrowbytes >> 2;
1434
1435	    rowdelta = ((destrowbytes - ((width << 1) << 2)) >> 2)  +
1436				(destrowbytes >> 2);
1437
1438		for (y = height ; y ; y--)
1439		{
1440			for (x = xcount ; x ;x--)
1441		    {
1442				pdest[0] = pdest[1] = pdest[nextrow] =
1443						pdest[nextrow + 1] = pcolormap[0][psrc[0]];
1444				pdest[2] = pdest[3] = pdest[nextrow + 2] =
1445						pdest[nextrow + 3] = pcolormap[0][psrc[1]];
1446				pdest[4] = pdest[5] = pdest[nextrow + 4] =
1447						pdest[nextrow + 5] = pcolormap[0][psrc[2]];
1448				pdest[6] = pdest[7] = pdest[nextrow + 6] =
1449						pdest[nextrow + 7] = pcolormap[0][psrc[3]];
1450				pdest[8] = pdest[9] = pdest[nextrow + 8] =
1451						pdest[nextrow + 9] = pcolormap[0][psrc[4]];
1452				pdest[10] = pdest[11] = pdest[nextrow + 10] =
1453						pdest[nextrow + 11] = pcolormap[0][psrc[5]];
1454				pdest[12] = pdest[13] = pdest[nextrow + 12] =
1455						pdest[nextrow + 13] = pcolormap[0][psrc[6]];
1456				pdest[14] = pdest[15] = pdest[nextrow + 14] =
1457						pdest[nextrow + 15] = pcolormap[0][psrc[7]];
1458				pdest += 16; psrc += 8;
1459		    }
1460
1461			psrc += srcdelta;
1462		    pdest += rowdelta;
1463		}
1464    }
1465	else
1466	{
1467	    rowdelta = (destrowbytes - (width<<2))>>2;
1468
1469		for (y = height ; y ; y--)
1470		{
1471			for (x = xcount ; x ;x--)
1472		    {
1473				pdest[0] = pcolormap[0][psrc[0]];
1474				pdest[1] = pcolormap[0][psrc[1]];
1475				pdest[2] = pcolormap[0][psrc[2]];
1476				pdest[3] = pcolormap[0][psrc[3]];
1477				pdest[4] = pcolormap[0][psrc[4]];
1478				pdest[5] = pcolormap[0][psrc[5]];
1479				pdest[6] = pcolormap[0][psrc[6]];
1480				pdest[7] = pcolormap[0][psrc[7]];
1481				pdest += 8; psrc += 8;
1482		    }
1483
1484			psrc += srcdelta;
1485		    pdest += rowdelta;
1486		}
1487	}
1488}
1489
1490
1491/*
1492==========================================================================
1493
1494						NEXTSTEP VIEW CLASS
1495
1496==========================================================================
1497*/
1498
1499
1500@implementation QuakeView
1501
1502/*
1503=================
1504windowDidMove
1505
1506=================
1507*/
1508- windowDidMove:sender
1509{
1510    NXPoint	aPoint;
1511    NXRect	winframe;
1512
1513    aPoint.x = aPoint.y = 0;
1514    [self convertPoint:&aPoint toView:nil];
1515    [window convertBaseToScreen: &aPoint];
1516    [window getFrame: &winframe];
1517
1518    if ((int)aPoint.x & 7)
1519    {
1520	[window moveTo:winframe.origin.x - ((int)aPoint.x&7)
1521			:winframe.origin.y];
1522	[window getFrame: &winframe];
1523    }
1524    return self;
1525}
1526
1527- windowWillResize:sender toSize:(NXSize *)frameSize
1528{
1529	NXRect		fr, cont;
1530
1531	fr.origin.x = fr.origin.y = 0;
1532	fr.size = *frameSize;
1533
1534	[Window getContentRect:&cont forFrameRect: &fr style:[window style]];
1535
1536	cont.size.width = (int)cont.size.width & ~15;
1537	if (cont.size.width < 128)
1538		cont.size.width = 128;
1539	cont.size.height = (int)cont.size.height & ~3;
1540	if (cont.size.height < 32)
1541		cont.size.height = 32;
1542
1543	[Window getFrameRect:&fr forContentRect: &cont style:[window style]];
1544
1545	*frameSize = fr.size;
1546
1547	return self;
1548}
1549
1550- windowDidResize:sender
1551{
1552	if (vid_display == disp_framebuffer)
1553		Sys_Error ("How the heck are you resizing a framebuffer window?!?");
1554
1555	vid.width = bounds.size.width/vid_scale;
1556	vid.height = bounds.size.height/vid_scale;
1557
1558//
1559// allocate memory for the back and translation buffers
1560//
1561	vid.rowbytes = vid.width;
1562	rowbytesnative = vid.width * pixbytesnative;
1563
1564	AllocBuffers (true);
1565
1566	vid.conbuffer = vid.buffer;
1567	vid.conrowbytes = vid.rowbytes;
1568	vid.conwidth = vid.width;
1569	vid.conheight = vid.height;
1570
1571	vid.recalc_refdef = 1;
1572
1573	return self;
1574}
1575
1576-(BOOL) acceptsFirstResponder
1577{
1578    return YES;
1579}
1580
1581
1582typedef struct
1583{
1584	int		source, dest;
1585} keymap_t;
1586
1587keymap_t keymaps[] =
1588{
1589	{103, K_RIGHTARROW},
1590	{102, K_LEFTARROW},
1591	{100, K_UPARROW},
1592	{101, K_DOWNARROW},
1593	{111, K_PAUSE},
1594
1595	{59, K_F1},
1596	{60, K_F2},
1597	{61, K_F3},
1598	{62, K_F4},
1599	{63, K_F5},
1600	{64, K_F6},
1601	{65, K_F7},
1602	{66, K_F8},
1603	{67, K_F9},
1604	{68, K_F10},
1605	{87, K_F11},
1606	{88, K_F12},
1607
1608	{-1,-1}
1609};
1610
1611keymap_t flagmaps[] =
1612{
1613	{NX_SHIFTMASK, K_SHIFT},
1614	{NX_CONTROLMASK, K_CTRL},
1615	{NX_ALTERNATEMASK, K_ALT},
1616	{NX_COMMANDMASK, K_ALT},
1617
1618	{-1,-1}
1619};
1620
1621/*
1622===================
1623keyboard methods
1624===================
1625*/
1626- keyDown:(NXEvent *)theEvent
1627{
1628    int	ch;
1629	keymap_t	*km;
1630
1631	PSobscurecursor ();
1632
1633// check for non-ascii first
1634	ch = theEvent->data.key.keyCode;
1635	for (km=keymaps;km->source!=-1;km++)
1636		if (ch == km->source)
1637		{
1638			Key_Event (km->dest, true);
1639			return self;
1640		}
1641
1642    ch = theEvent->data.key.charCode;
1643	if (ch >= 'A' && ch <= 'Z')
1644		ch += 'a' - 'A';
1645    if (ch>=256)
1646		return self;
1647
1648	Key_Event (ch, true);
1649    return self;
1650}
1651
1652- flagsChanged:(NXEvent *)theEvent
1653{
1654	static int	oldflags;
1655    int		newflags;
1656	int		delta;
1657	keymap_t	*km;
1658	int		i;
1659
1660	PSobscurecursor ();
1661    newflags = theEvent->flags;
1662	delta = newflags ^ oldflags;
1663	for (i=0 ; i<32 ; i++)
1664	{
1665		if ( !(delta & (1<<i)))
1666			continue;
1667	// changed
1668		for (km=flagmaps;km->source!=-1;km++)
1669			if ( (1<<i) == km->source)
1670			{
1671				if (newflags & (1<<i))
1672					Key_Event (km->dest, true);
1673				else
1674					Key_Event (km->dest, false);
1675			}
1676
1677	}
1678
1679	oldflags = newflags;
1680
1681    return self;
1682}
1683
1684
1685- keyUp:(NXEvent *)theEvent
1686{
1687    int	ch;
1688 	keymap_t	*km;
1689
1690 // check for non-ascii first
1691	ch = theEvent->data.key.keyCode;
1692	for (km=keymaps;km->source!=-1;km++)
1693		if (ch == km->source)
1694		{
1695			Key_Event (km->dest, false);
1696			return self;
1697		}
1698
1699   ch = theEvent->data.key.charCode;
1700	if (ch >= 'A' && ch <= 'Z')
1701		ch += 'a' - 'A';
1702    if (ch>=256)
1703		return self;
1704	Key_Event (ch, false);
1705    return self;
1706}
1707
1708
1709- tiffShot
1710{
1711	id			imagerep, image;
1712	NXRect		r;
1713	NXStream	*stream;
1714	int			fd;
1715	int    		i;
1716	char		tiffname[80];
1717
1718	[vid_window_i getFrame: &r];
1719	r.origin.x = r.origin.y = 0;
1720	image = [[NXImage alloc] initSize: &r.size];
1721	imagerep = [[NXCachedImageRep alloc] initFromWindow:vid_window_i rect:&r];
1722
1723	[image lockFocus];
1724	[imagerep draw];
1725	[image unlockFocus];
1726
1727//
1728// find a file name to save it to
1729//
1730	strcpy(tiffname,"quake00.tif");
1731
1732	for (i=0 ; i<=99 ; i++)
1733	{
1734		tiffname[5] = i/10 + '0';
1735		tiffname[6] = i%10 + '0';
1736		if (Sys_FileTime(tiffname) == -1)
1737			break;	// file doesn't exist
1738	}
1739	if (i==100)
1740		Sys_Error ("SCR_ScreenShot_f: Couldn't create a tiff");
1741
1742	fd = open (tiffname, O_RDWR|O_CREAT|O_TRUNC, 0666);
1743	stream = NXOpenFile (fd, NX_READWRITE);
1744	[image writeTIFF: stream];
1745	NXClose (stream);
1746	close (fd);
1747	printf ("wrote %s\n", tiffname);
1748
1749	[image free];
1750	[imagerep free];
1751	return self;
1752
1753}
1754
1755- screenShot: sender
1756{
1757	return [self tiffShot];
1758}
1759
1760- setScaleFullScreen: sender
1761{
1762	VID_Shutdown ();
1763	if (vid_fullscreen)
1764	{
1765		vid_fullscreen = 0;
1766		VID_Restart (vid_display, vid_scale);
1767	}
1768	else
1769	{
1770		vid_fullscreen = 1;
1771		VID_Restart (vid_display, vid_scale);
1772	}
1773	return self;
1774}
1775
1776@end
1777
1778//============================================================================
1779
1780@implementation FrameWindow
1781
1782- windowExposed:(NXEvent *)theEvent
1783{
1784	return self;
1785}
1786
1787@end
1788
1789
1790