// vid_next.m -- NEXTSTEP video driver #define INTERCEPTOR #import #import #import "intercep.h" #include "quakedef.h" #include "d_local.h" int BASEWIDTH = 320; int BASEHEIGHT = 200; void SetupBitmap (void); void SetupFramebuffer (void); void UpdateBitmap (void); void UpdateFramebuffer (vrect_t *vrect); void SetVideoEncoding (char *encoding); void Update8_1 (pixel_t *src, byte *dest, int width, int height, int destrowbytes); void Update16_1 (pixel_t *src, unsigned short *dest, int width, int height, int destrowbytes); void Update32_1 (pixel_t *src, unsigned *dest, int width, int height, int destrowbytes); @interface QuakeView : View @end @interface FrameWindow:Window @end unsigned short d_8to16table[256]; // not used in 8 bpp mode unsigned d_8to24table[256]; // not used in 8 bpp mode /* ========================================================================== API FUNCTIONS ========================================================================== */ typedef enum {disp_bitmap, disp_framebuffer} display_t; pixel_t *vid_buffer; pixel_t *buffernative; unsigned pcolormap[4][256]; // map from quake pixels to native pixels unsigned pixbytesnative; unsigned rowbytesnative; int dither; int drawdirect = 0; int d_con_indirect = 0; display_t vid_display; byte vid_palette[768]; // saved for restarting vid system id vid_window_i; id vid_view_i; #ifdef INTERCEPTOR NXDirectBitmap *vid_dbitmap_i; NXFramebuffer *vid_framebuffer_i; #endif NXRect screenBounds; // only valid in framebuffer mode int vid_scale; char *vid_encodingstring; int vid_fullscreen; int vid_screen; int vid_high_hunk_mark; typedef enum { enc_24_rgba, enc_24_0rgb, enc_24_rgb0, enc_12_rgba, enc_12_rgb0, enc_15_0rgb, enc_564, enc_8_gray, enc_8_rgb } vid_encoding_t; typedef struct { char *string; int pixelbytes; void (*colormap) (void); vid_encoding_t name; } vidtype_t; vid_encoding_t vid_encoding; void Table8 (void); void Table15 (void); void Table12 (void); void Table12Swap (void); void Table24 (void); void Table24Swap (void); vidtype_t vid_encodingtable[]= { {"RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA",4, Table24Swap, enc_24_rgba}, {"--------RRRRRRRRGGGGGGGGBBBBBBBB",4, Table24, enc_24_0rgb}, {"RRRRRRRRGGGGGGGGBBBBBBBB--------",4, Table24Swap, enc_24_rgb0}, {"RRRRGGGGBBBBAAAA",2, Table12Swap, enc_12_rgba}, {"RRRRGGGGBBBB----",2, Table12, enc_12_rgb0}, {"-RRRRRGGGGGBBBBB",2, Table15, enc_15_0rgb}, {"WWWWWWWW",1, Table8, enc_8_gray}, {"PPPPPPPP",1, Table8, enc_8_rgb}, {NULL,0, 0, 0} }; vidtype_t *vid_type; void InitNS8Bit (void); /* ================ D_BeginDirectRect ================ */ void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) { // direct drawing of the "accessing disk" icon isn't supported under Nextstep } /* ================ D_EndDirectRect ================ */ void D_EndDirectRect (int x, int y, int width, int height) { // direct drawing of the "accessing disk" icon isn't supported under Nextstep } /* ============== VID_Restart internal call only =============== */ void VID_Restart (display_t mode, int scale) { vid_display = mode; vid_scale = scale; [NXApp activateSelf:YES]; if (vid_display == disp_framebuffer) SetupFramebuffer (); else SetupBitmap (); vid.recalc_refdef = 1; } /* ================= VID_Scale_f Keybinding command ================= */ void VID_Scale_f (void) { int scale; if (Cmd_Argc () != 2) return; scale = atoi (Cmd_Argv(1)); if (scale != 1 && scale != 2) { Con_Printf ("scale must be 1 or 2\n"); return; } VID_Shutdown (); VID_Restart (vid_display, scale); } /* ================= VID_Mode_f Keybinding command ================= */ void VID_Mode_f (void) { int mode; if (Cmd_Argc () != 2) return; mode = atoi (Cmd_Argv(1)); VID_Shutdown (); if (mode == 0) { drawdirect = 0; VID_Restart (disp_bitmap, vid_scale); } else if (mode == 1) { drawdirect = 0; VID_Restart (disp_framebuffer, vid_scale); } else { drawdirect = 1; VID_Restart (disp_framebuffer, vid_scale); } } /* ================= VID_Size_f Keybinding command ================= */ void VID_Size_f (void) { if (Cmd_Argc () != 3) return; VID_Shutdown (); BASEWIDTH = atoi (Cmd_Argv(1)); BASEHEIGHT = atoi (Cmd_Argv(2)); VID_Restart (vid_display, vid_scale); } /* ================ VID_Init ================ */ void VID_Init (unsigned char *palette) { InitNS8Bit (); // fixed palette lookups Q_memcpy (vid_palette, palette, sizeof(vid_palette)); if (COM_CheckParm ("-bitmap")) vid_display = disp_bitmap; else vid_display = disp_framebuffer; if (COM_CheckParm ("-screen2")) vid_screen = 1; else vid_screen = 0; if (COM_CheckParm ("-direct")) drawdirect = 1; Cmd_AddCommand ("vid_scale", VID_Scale_f); Cmd_AddCommand ("vid_mode", VID_Mode_f); Cmd_AddCommand ("vid_size", VID_Size_f); vid.width = BASEWIDTH; vid.height = BASEHEIGHT; vid.aspect = 1.0; vid.numpages = 1; vid.colormap = host_colormap; vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); vid.maxwarpwidth = WARP_WIDTH; vid.maxwarpheight = WARP_HEIGHT; if (COM_CheckParm ("-scale2")) vid_scale = 2; else vid_scale = 1; [Application new]; VID_Restart (vid_display, vid_scale); } /* ================ VID_Shutdown ================ */ void VID_Shutdown (void) { #ifdef INTERCEPTOR if (vid_dbitmap_i) { [vid_dbitmap_i free]; vid_dbitmap_i = 0; } if (vid_framebuffer_i) { [vid_framebuffer_i free]; vid_framebuffer_i = 0; } #endif [vid_window_i close]; [vid_window_i free]; } /* ================ VID_Update ================ */ void VID_Update (vrect_t *rects) { if (drawdirect) return; while (rects) { UpdateFramebuffer (rects); rects = rects->pnext; } if (vid_display == disp_bitmap) UpdateBitmap (); } /* ================ VID_SetPalette ================ */ void VID_SetPalette (unsigned char *palette) { Q_memcpy (vid_palette, palette, sizeof(vid_palette)); vid_type->colormap (); } /* ================ VID_ShiftPalette ================ */ void VID_ShiftPalette (unsigned char *palette) { VID_SetPalette (palette); } /* ========================================================================== NS STUFF ========================================================================== */ /* ================= SetVideoEncoding ================= */ void SetVideoEncoding (char *encoding) { vidtype_t *type; Sys_Printf ("SetVideoEncoding: %s\n",encoding); vid_encodingstring = encoding; for (type = vid_encodingtable ; type->string ; type++) { if (strcmp(type->string, encoding) == 0) { pixbytesnative = type->pixelbytes; vid_encoding = type->name; type->colormap (); vid_type = type; return; } } Sys_Error ("Unsupported video encoding: %s\n",encoding); } /* ================= AllocBuffers ================= */ void AllocBuffers (qboolean withnative) { int surfcachesize; void *surfcache; int pixels; int pixbytes; int vid_buffersize; if (vid_buffer) { D_FlushCaches (); Hunk_FreeToHighMark (vid_high_hunk_mark); vid_high_hunk_mark = 0; vid_buffer = NULL; } pixels = vid.width * vid.height; pixbytes = 1 +sizeof (*d_pzbuffer); if (withnative) pixbytes += pixbytesnative; surfcachesize = D_SurfaceCacheForRes (vid.width, vid.height); vid_buffersize = pixels * pixbytes + surfcachesize; vid_high_hunk_mark = Hunk_HighMark (); vid_buffer = Hunk_HighAllocName (vid_buffersize, "video"); if (!vid_buffer) Sys_Error ("Couldn't alloc video buffers"); vid.buffer = vid_buffer; d_pzbuffer = (unsigned short *)((byte *)vid_buffer + pixels); surfcache = (byte *)d_pzbuffer + pixels * sizeof (*d_pzbuffer); if (withnative) buffernative = (byte *)surfcache + surfcachesize; D_InitCaches (surfcache, surfcachesize); } /* ================= SetupFramebuffer ================= */ void SetupFramebuffer (void) { #ifdef INTERCEPTOR int windowNum; NXRect cont; NXScreen const *screens; int screencount; // // get the screen list // [NXApp getScreens:&screens count:&screencount]; // // create vid_framebuffer_i // vid_framebuffer_i = [[NXFramebuffer alloc] initFromScreen:screens[vid_screen].screenNumber andMapIfPossible:YES]; [vid_framebuffer_i screenBounds:&screenBounds]; SetVideoEncoding ([vid_framebuffer_i pixelEncoding]); buffernative = [vid_framebuffer_i data]; rowbytesnative = [vid_framebuffer_i bytesPerRow]; // // create window // if (vid_fullscreen) { vid.height = screenBounds.size.height / vid_scale; vid.width = screenBounds.size.width / vid_scale; cont.origin.x = 0; cont.origin.y = 0; cont.size.width = screenBounds.size.width; cont.size.height = screenBounds.size.height; } else { buffernative = (unsigned char *)buffernative + 8 * rowbytesnative + 8 * pixbytesnative; vid.width = BASEWIDTH; vid.height = BASEHEIGHT; cont.origin.x = 8; cont.origin.y = screenBounds.size.height - (vid.height*vid_scale) - 8; cont.size.width = vid.width * vid_scale; cont.size.height = vid.height * vid_scale; } vid_window_i = [[FrameWindow alloc] initContent: &cont style: NX_PLAINSTYLE backing: NX_NONRETAINED buttonMask: 0 defer: NO screen: screens+vid_screen]; windowNum = [vid_window_i windowNum]; PSsetwindowlevel(40, windowNum); PSsetautofill(YES, windowNum); PSgsave(); PSwindowdeviceround(windowNum); PSsetgray(NX_BLACK); PSsetexposurecolor(); PSgrestore(); // // create view // vid_view_i = [[QuakeView alloc] initFrame: &screenBounds]; [[vid_window_i setContentView: vid_view_i] free]; [vid_window_i makeFirstResponder: vid_view_i]; [vid_window_i setDelegate: vid_view_i]; [vid_window_i display]; [vid_window_i makeKeyAndOrderFront: nil]; NXPing (); AllocBuffers (false); // no native buffer if (drawdirect) { // the direct drawing mode to NeXT colorspace vid.buffer = buffernative; vid.rowbytes = rowbytesnative; } else vid.rowbytes = vid.width; vid.conbuffer = vid.buffer; vid.conrowbytes = vid.rowbytes; vid.conwidth = vid.width; vid.conheight = vid.height; #endif } /* ================= SetupBitmap ================= */ void SetupBitmap (void) { int depth; NXRect content; // // open a window // NXSetRect (&content, 8,136, vid.width*vid_scale, vid.height*vid_scale); vid_window_i = [[Window alloc] initContent: &content style: NX_RESIZEBARSTYLE backing: NX_RETAINED buttonMask: 0 defer: NO ]; [vid_window_i display]; [vid_window_i makeKeyAndOrderFront: nil]; NXPing (); content.origin.x = content.origin.y = 0; vid_view_i = [[QuakeView alloc] initFrame: &content]; [[vid_window_i setContentView: vid_view_i] free]; [vid_window_i makeFirstResponder: vid_view_i]; [vid_window_i setDelegate: vid_view_i]; [vid_window_i addToEventMask: NX_FLAGSCHANGEDMASK]; // // find video info // depth = [Window defaultDepthLimit]; switch (depth) { case NX_EightBitGrayDepth: SetVideoEncoding ("WWWWWWWW"); break; case NX_TwelveBitRGBDepth: SetVideoEncoding ("RRRRGGGGBBBBAAAA"); break; default: case NX_TwentyFourBitRGBDepth: SetVideoEncoding ("RRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA"); break; // default: // 8 bit color shows up as an unknown... Sys_Error ("Unsupported window depth"); } [vid_window_i setTitle: "Bitmap Quake Console"]; // // allocate memory for the back and translation buffers // vid.rowbytes = vid.width; rowbytesnative = vid.width * pixbytesnative; AllocBuffers (true); vid.conbuffer = vid.buffer; vid.conrowbytes = vid.rowbytes; vid.conwidth = vid.width; vid.conheight = vid.height; } /* ================= UpdateFramebuffer ================= */ void UpdateFramebuffer (vrect_t *vrect) { byte *psourcebase; byte *pdestbase; int scale; psourcebase = vid.buffer + vrect->x + vrect->y * vid.rowbytes; if (vid_display == disp_bitmap) scale = 1; // let NS do the scaling else scale = vid_scale; pdestbase = buffernative + scale * (vrect->x * pixbytesnative + vrect->y * rowbytesnative); // // translate from ideal to native (except 8 bpp direct) and copy to screen // if (pixbytesnative == 1) Update8_1 (psourcebase, pdestbase, vrect->width, vrect->height, rowbytesnative); else if (pixbytesnative == 2) Update16_1 (psourcebase, (unsigned short *)pdestbase, vrect->width, vrect->height, rowbytesnative); else Update32_1 (psourcebase, (unsigned *)pdestbase, vrect->width, vrect->height, rowbytesnative); } /* ================= UpdateBitmap ================= */ void UpdateBitmap (void) { unsigned char *planes[5]; NXRect bounds; int bpp, spp, bps, bpr, colorspace; // // flush the screen with an image call // if (pixbytesnative == 1) { bps = 8; spp = 1; bpp = 8; bpr = vid.width; colorspace = NX_OneIsWhiteColorSpace; planes[0] = vid.buffer; } else if (pixbytesnative == 2) { bps = 4; spp = 3; bpp = 16; bpr = vid.width * 2; colorspace = NX_RGBColorSpace; planes[0] = buffernative; } else { bps = 8; spp = 3; bpp = 32; bpr = vid.width * 4; colorspace = NX_RGBColorSpace; planes[0] = buffernative; } [vid_view_i getBounds: &bounds]; [vid_view_i lockFocus]; NXDrawBitmap( &bounds, vid.width, vid.height, bps, spp, bpp, bpr, NO, NO, colorspace, planes ); [vid_view_i unlockFocus]; NXPing (); } /* ========================================================================== TRANSLATION TABLE BUILDING ========================================================================== */ int redramp[] = {0, 19, 59, 113, 178, 255, 300}; int greenramp[] = {0, 11, 34, 66, 104, 149, 199, 255, 300}; int blueramp[] = {0, 28, 84, 161, 255, 300}; int greyramp[] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255, 300}; byte greytable[256]; byte redtable[256]; byte greentable[256]; byte bluetable[256]; void FillTable (byte *table, int *ramp, int base) { int i, j, o; o = 0; for (i=0 ; i<16 && o < 256; i++) { j = ramp[i]; for ( ; o<=j ; o++) table[o] = base + i; } } void InitNS8Bit (void) { FillTable (greytable, greyramp, 240); FillTable (redtable, redramp, 0); FillTable (greentable, greenramp, 0); FillTable (bluetable, blueramp, 0); } byte ns8trans[256] = // FIXME: dynamically calc this so palettes work { 0,241,242,243,244,244,245,246,247,248,249,250,251,252,253,254, 45,241,241,242,91,91,91,96,96,136,136,136,141,141,141,141, 241,46,242,243,243,97,97,97,245,246,143,143,143,143,148,148, 0,5,45,45,50,50,90,90,95,95,95,95,95,140,140,141, 0,40,40,40,40,80,80,80,80,80,120,120,120,120,120,120, 45,50,50,90,90,95,95,135,135,135,136,141,141,181,181,181, 45,90,91,91,131,131,136,136,136,176,181,181,186,226,231,236, 45,45,91,91,96,96,136,136,137,142,182,182,187,188,188,233, 188,249,248,247,246,137,137,137,244,243,243,91,242,241,241,45, 183,183,183,247,137,137,137,137,137,244,91,91,91,241,241,45, 252,251,188,188,248,248,142,142,142,244,244,243,91,242,241,45, 247,247,246,246,245,245,244,244,243,243,242,242,51,241,241,5, 236,231,231,191,186,185,185,140,140,135,135,95,90,90,45,45, 4,49,49,53,53,93,93,93,93,92,92,92,243,242,46,241, 239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, 239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,182 }; /* =================== Table8 =================== */ void Table8 (void) { byte *pal; int r,g,b,v; int i; byte *table; pal = vid_palette; table = (byte *)pcolormap[0]; for (i=0 ; i<256 ; i++) { r = pal[0]; g = pal[1]; b = pal[2]; pal += 3; // use the grey ramp if all indexes are close if (r-g < 16 && r-g > -16 && r-b < 16 && r-b > -16) { v = (r+g+b)/3; *table++ = greytable[v]; continue; } r = redtable[r]; g = greentable[g]; b = bluetable[b]; // otherwise use the color cube *table++ = r*(8*5) + g*5 + b; } } /* =================== Table24 =================== */ void Table24 (void) { byte *pal; int r,g,b,v; int i; unsigned *table; // // 8 8 8 encoding // pal = vid_palette; table = (unsigned *)pcolormap[0]; for (i=0 ; i<256 ; i++) { r = pal[0]; g = pal[1]; b = pal[2]; pal += 3; v = (r<<16) + (g<<8) + b; *table++ = v; } } /* =================== Table24Swap =================== */ void Table24Swap (void) { byte *pal; int r,g,b,v; int i; unsigned *table; // // 8 8 8 encoding // pal = vid_palette; table = (unsigned *)pcolormap[0]; for (i=0 ; i<256 ; i++) { r = pal[0]; g = pal[1]; b = pal[2]; pal += 3; v = (r<<24) + (g<<16) + (b<<8) /*+ 255*/; v = NXSwapBigLongToHost (v); *table++ = v; } } /* =================== Table15 =================== */ void Table15 (void) { byte *pal; int r,g,b,v; int i, k; unsigned char *palette; unsigned short *table; int dadj; int ditheradjust[4] = {(1 << 9) * 3 / 8, (1 << 9) * 5 / 8, (1 << 9) * 7 / 8, (1 << 9) * 1 / 8}; palette = vid_palette; table = (unsigned short *)pcolormap; // // 5 5 5 encoding // for (k=0 ; k<4 ; k++) { dadj = ditheradjust[k]; pal = vid_palette; for (i=0 ; i<256 ; i++) { // shift 6 bits to get back to 0-255, & 3 more for 5 bit color // FIXME: scale intensity levels properly r = (pal[0] + dadj) >> 3; g = (pal[1] + dadj) >> 3; b = (pal[2] + dadj) >> 3; pal += 3; v = (r<<10) + (g<<5) + b; *table++ = v; } } } /* =================== Table12 =================== */ void Table12 (void) { byte *pal; int r,g,b,v; int i, k; unsigned short *table; int dadj; static int ditheradjust[4] = {(1 << 9) * 3 / 8, (1 << 9) * 5 / 8, (1 << 9) * 7 / 8, (1 << 9) * 1 / 8}; table = (unsigned short *)pcolormap; // // 4 4 4 encoding // for (k=0 ; k<4 ; k++) { dadj = ditheradjust[k]; pal = vid_palette; for (i=0 ; i<256 ; i++) { // shift 5 bits to get back to 0-255, & 4 more for 4 bit color // FIXME: scale intensity levels properly r = (pal[0] + dadj) >> 4; g = (pal[1] + dadj) >> 4; b = (pal[2] + dadj) >> 4; pal += 3; v = ((r<<12) + (g<<8) + (b<<4) /*+ 15*/); *table++ = v; } } } /* =================== Table12Swap =================== */ void Table12Swap (void) { byte *pal; int r,g,b,v; int i, k; unsigned short *table; int dadj; static int ditheradjust[4] = {(1 << 9) * 3 / 8, (1 << 9) * 5 / 8, (1 << 9) * 7 / 8, (1 << 9) * 1 / 8}; table = (unsigned short *)pcolormap; // // 4 4 4 encoding // for (k=0 ; k<4 ; k++) { dadj = ditheradjust[k]; pal = vid_palette; for (i=0 ; i<256 ; i++) { // shift 5 bits to get back to 0-255, & 4 more for 4 bit color // FIXME: scale intensity levels properly r = (pal[0] + dadj) >> 4; g = (pal[1] + dadj) >> 4; b = (pal[2] + dadj) >> 4; pal += 3; v = ((r<<12) + (g<<8) + (b<<4) /*+ 15*/); v = NXSwapBigShortToHost (v); *table++ = v; } } } /* ========================================================================== GENERIC IMAGING FUNCTIONS ========================================================================== */ /* =================== Update8_1 =================== */ void Update8_1 (pixel_t *src, byte *dest, int width, int height, int destrowbytes) { int x,y; unsigned rowdelta, srcdelta; unsigned xcount; byte *pdest; int xwidth; pdest = dest; xcount = width >> 3; srcdelta = vid.width - width; xwidth = width - (xcount << 3); if (xwidth) Sys_Error ("Width not multiple of 8"); if ((vid_display == disp_framebuffer) && (vid_scale == 2)) { int nextrow = destrowbytes; rowdelta = destrowbytes - (width << 1) + destrowbytes; if (dither) { unsigned short *psrc; psrc = (unsigned short *)src; for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { unsigned temp; temp = psrc[0]; pdest[0] = ((byte *)pcolormap[0])[temp]; pdest[1] = ((byte *)pcolormap[1])[temp]; pdest[nextrow] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 1] = ((byte *)pcolormap[3])[temp]; temp = psrc[1]; pdest[2] = ((byte *)pcolormap[0])[temp]; pdest[3] = ((byte *)pcolormap[1])[temp]; pdest[nextrow + 2] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 3] = ((byte *)pcolormap[3])[temp]; temp = psrc[2]; pdest[4] = ((byte *)pcolormap[0])[temp]; pdest[5] = ((byte *)pcolormap[1])[temp]; pdest[nextrow + 4] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 5] = ((byte *)pcolormap[3])[temp]; temp = psrc[3]; pdest[6] = ((byte *)pcolormap[0])[temp]; pdest[7] = ((byte *)pcolormap[1])[temp]; pdest[nextrow + 6] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 7] = ((byte *)pcolormap[3])[temp]; temp = psrc[4]; pdest[8] = ((byte *)pcolormap[0])[temp]; pdest[9] = ((byte *)pcolormap[1])[temp]; pdest[nextrow + 8] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 9] = ((byte *)pcolormap[3])[temp]; temp = psrc[5]; pdest[10] = ((byte *)pcolormap[0])[temp]; pdest[11] = ((byte *)pcolormap[1])[temp]; pdest[nextrow + 10] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 11] = ((byte *)pcolormap[3])[temp]; temp = psrc[6]; pdest[12] = ((byte *)pcolormap[0])[temp]; pdest[13] = ((byte *)pcolormap[1])[temp]; pdest[nextrow + 12] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 13] = ((byte *)pcolormap[3])[temp]; temp = psrc[7]; pdest[14] = ((byte *)pcolormap[0])[temp]; pdest[15] = ((byte *)pcolormap[1])[temp]; pdest[nextrow + 14] = ((byte *)pcolormap[2])[temp]; pdest[nextrow + 15] = ((byte *)pcolormap[3])[temp]; pdest += 16; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } else { byte *psrc; psrc = (byte *)src; for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { pdest[0] = pdest[1] = pdest[nextrow] = pdest[nextrow + 1] = ((byte *)pcolormap[0])[psrc[0]]; pdest[2] = pdest[3] = pdest[nextrow + 2] = pdest[nextrow + 3] = ((byte *)pcolormap[0])[psrc[1]]; pdest[4] = pdest[5] = pdest[nextrow + 4] = pdest[nextrow + 5] = ((byte *)pcolormap[0])[psrc[2]]; pdest[6] = pdest[7] = pdest[nextrow + 6] = pdest[nextrow + 7] = ((byte *)pcolormap[0])[psrc[3]]; pdest[8] = pdest[9] = pdest[nextrow + 8] = pdest[nextrow + 9] = ((byte *)pcolormap[0])[psrc[4]]; pdest[10] = pdest[11] = pdest[nextrow + 10] = pdest[nextrow + 11] = ((byte *)pcolormap[0])[psrc[5]]; pdest[12] = pdest[13] = pdest[nextrow + 12] = pdest[nextrow + 13] = ((byte *)pcolormap[0])[psrc[6]]; pdest[14] = pdest[15] = pdest[nextrow + 14] = pdest[nextrow + 15] = ((byte *)pcolormap[0])[psrc[7]]; pdest += 16; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } } else { rowdelta = destrowbytes - width; if (dither) { unsigned short *psrc; psrc = (unsigned short *)src; for (y = height ; y>0 ; y -= 2) { for (x = xcount ; x ;x--) { pdest[0] = ((byte *)pcolormap[0])[psrc[0]]; pdest[1] = ((byte *)pcolormap[1])[psrc[1]]; pdest[2] = ((byte *)pcolormap[0])[psrc[2]]; pdest[3] = ((byte *)pcolormap[1])[psrc[3]]; pdest[4] = ((byte *)pcolormap[0])[psrc[4]]; pdest[5] = ((byte *)pcolormap[1])[psrc[5]]; pdest[6] = ((byte *)pcolormap[0])[psrc[6]]; pdest[7] = ((byte *)pcolormap[1])[psrc[7]]; pdest += 8; psrc += 8; } psrc += srcdelta; pdest += rowdelta; for (x = xcount ; x ;x--) { pdest[0] = ((byte *)pcolormap[2])[psrc[0]]; pdest[1] = ((byte *)pcolormap[3])[psrc[1]]; pdest[2] = ((byte *)pcolormap[2])[psrc[2]]; pdest[3] = ((byte *)pcolormap[3])[psrc[3]]; pdest[4] = ((byte *)pcolormap[2])[psrc[4]]; pdest[5] = ((byte *)pcolormap[3])[psrc[5]]; pdest[6] = ((byte *)pcolormap[2])[psrc[6]]; pdest[7] = ((byte *)pcolormap[3])[psrc[7]]; pdest += 8; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } else { byte *psrc; psrc = (byte *)src; // srcdelta += width; // rowdelta += width; for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { pdest[0] = ((byte *)pcolormap[0])[psrc[0]]; pdest[1] = ((byte *)pcolormap[0])[psrc[1]]; pdest[2] = ((byte *)pcolormap[0])[psrc[2]]; pdest[3] = ((byte *)pcolormap[0])[psrc[3]]; pdest[4] = ((byte *)pcolormap[0])[psrc[4]]; pdest[5] = ((byte *)pcolormap[0])[psrc[5]]; pdest[6] = ((byte *)pcolormap[0])[psrc[6]]; pdest[7] = ((byte *)pcolormap[0])[psrc[7]]; pdest += 8; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } } } /* =================== Update16_1 =================== */ void Update16_1 (pixel_t *src, unsigned short *dest, int width, int height, int destrowbytes) { int x,y; unsigned rowdelta, srcdelta; unsigned xcount; pixel_t *psrc; unsigned short *pdest; int xwidth; psrc = src; pdest = dest; xcount = width >> 3; srcdelta = vid.width - width; xwidth = width - (xcount << 3); if (xwidth) Sys_Error ("Width not multiple of 8"); if ((vid_display == disp_framebuffer) && (vid_scale == 2)) { int nextrow = destrowbytes >> 1; rowdelta = (destrowbytes - ((width << 1) << 1) + destrowbytes) >> 1; if (dither) { for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { unsigned temp; temp = psrc[0]; pdest[0] = ((unsigned short *)pcolormap[0])[temp]; pdest[1] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 1] = ((unsigned short *)pcolormap[3])[temp]; temp = psrc[1]; pdest[2] = ((unsigned short *)pcolormap[0])[temp]; pdest[3] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow + 2] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 3] = ((unsigned short *)pcolormap[3])[temp]; temp = psrc[2]; pdest[4] = ((unsigned short *)pcolormap[0])[temp]; pdest[5] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow + 4] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 5] = ((unsigned short *)pcolormap[3])[temp]; temp = psrc[3]; pdest[6] = ((unsigned short *)pcolormap[0])[temp]; pdest[7] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow + 6] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 7] = ((unsigned short *)pcolormap[3])[temp]; temp = psrc[4]; pdest[8] = ((unsigned short *)pcolormap[0])[temp]; pdest[9] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow + 8] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 9] = ((unsigned short *)pcolormap[3])[temp]; temp = psrc[5]; pdest[10] = ((unsigned short *)pcolormap[0])[temp]; pdest[11] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow + 10] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 11] = ((unsigned short *)pcolormap[3])[temp]; temp = psrc[6]; pdest[12] = ((unsigned short *)pcolormap[0])[temp]; pdest[13] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow + 12] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 13] = ((unsigned short *)pcolormap[3])[temp]; temp = psrc[7]; pdest[14] = ((unsigned short *)pcolormap[0])[temp]; pdest[15] = ((unsigned short *)pcolormap[1])[temp]; pdest[nextrow + 14] = ((unsigned short *)pcolormap[2])[temp]; pdest[nextrow + 15] = ((unsigned short *)pcolormap[3])[temp]; pdest += 16; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } else { for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { pdest[0] = pdest[1] = pdest[nextrow] = pdest[nextrow + 1] = pcolormap[0][psrc[0]]; pdest[2] = pdest[3] = pdest[nextrow + 2] = pdest[nextrow + 3] = pcolormap[0][psrc[1]]; pdest[4] = pdest[5] = pdest[nextrow + 4] = pdest[nextrow + 5] = pcolormap[0][psrc[2]]; pdest[6] = pdest[7] = pdest[nextrow + 6] = pdest[nextrow + 7] = pcolormap[0][psrc[3]]; pdest[8] = pdest[9] = pdest[nextrow + 8] = pdest[nextrow + 9] = pcolormap[0][psrc[4]]; pdest[10] = pdest[11] = pdest[nextrow + 10] = pdest[nextrow + 11] = pcolormap[0][psrc[5]]; pdest[12] = pdest[13] = pdest[nextrow + 12] = pdest[nextrow + 13] = pcolormap[0][psrc[6]]; pdest[14] = pdest[15] = pdest[nextrow + 14] = pdest[nextrow + 15] = pcolormap[0][psrc[7]]; pdest += 16; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } } else { rowdelta = (destrowbytes - (width<<1))>>1; if (dither) { for (y = height ; y>0 ; y -= 2) { for (x = xcount ; x ;x--) { pdest[0] = ((unsigned short *)pcolormap[0])[psrc[0]]; pdest[1] = ((unsigned short *)pcolormap[1])[psrc[1]]; pdest[2] = ((unsigned short *)pcolormap[0])[psrc[2]]; pdest[3] = ((unsigned short *)pcolormap[1])[psrc[3]]; pdest[4] = ((unsigned short *)pcolormap[0])[psrc[4]]; pdest[5] = ((unsigned short *)pcolormap[1])[psrc[5]]; pdest[6] = ((unsigned short *)pcolormap[0])[psrc[6]]; pdest[7] = ((unsigned short *)pcolormap[1])[psrc[7]]; pdest += 8; psrc += 8; } psrc += srcdelta; pdest += rowdelta; for (x = xcount ; x ;x--) { pdest[0] = ((unsigned short *)pcolormap[2])[psrc[0]]; pdest[1] = ((unsigned short *)pcolormap[3])[psrc[1]]; pdest[2] = ((unsigned short *)pcolormap[2])[psrc[2]]; pdest[3] = ((unsigned short *)pcolormap[3])[psrc[3]]; pdest[4] = ((unsigned short *)pcolormap[2])[psrc[4]]; pdest[5] = ((unsigned short *)pcolormap[3])[psrc[5]]; pdest[6] = ((unsigned short *)pcolormap[2])[psrc[6]]; pdest[7] = ((unsigned short *)pcolormap[3])[psrc[7]]; pdest += 8; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } else { for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { pdest[0] = pcolormap[0][psrc[0]]; pdest[1] = pcolormap[0][psrc[1]]; pdest[2] = pcolormap[0][psrc[2]]; pdest[3] = pcolormap[0][psrc[3]]; pdest[4] = pcolormap[0][psrc[4]]; pdest[5] = pcolormap[0][psrc[5]]; pdest[6] = pcolormap[0][psrc[6]]; pdest[7] = pcolormap[0][psrc[7]]; pdest += 8; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } } } /* =================== Update32_1 =================== */ void Update32_1 (pixel_t *src, unsigned *dest, int width, int height, int destrowbytes) { int x,y; unsigned rowdelta, srcdelta; unsigned xcount; pixel_t *psrc; unsigned *pdest; int xwidth; psrc = src; pdest = dest; xcount = width >> 3; srcdelta = vid.width - width; xwidth = width - (xcount << 3); if (xwidth) Sys_Error ("Width not multiple of 8"); if ((vid_display == disp_framebuffer) && (vid_scale == 2)) { int nextrow = destrowbytes >> 2; rowdelta = ((destrowbytes - ((width << 1) << 2)) >> 2) + (destrowbytes >> 2); for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { pdest[0] = pdest[1] = pdest[nextrow] = pdest[nextrow + 1] = pcolormap[0][psrc[0]]; pdest[2] = pdest[3] = pdest[nextrow + 2] = pdest[nextrow + 3] = pcolormap[0][psrc[1]]; pdest[4] = pdest[5] = pdest[nextrow + 4] = pdest[nextrow + 5] = pcolormap[0][psrc[2]]; pdest[6] = pdest[7] = pdest[nextrow + 6] = pdest[nextrow + 7] = pcolormap[0][psrc[3]]; pdest[8] = pdest[9] = pdest[nextrow + 8] = pdest[nextrow + 9] = pcolormap[0][psrc[4]]; pdest[10] = pdest[11] = pdest[nextrow + 10] = pdest[nextrow + 11] = pcolormap[0][psrc[5]]; pdest[12] = pdest[13] = pdest[nextrow + 12] = pdest[nextrow + 13] = pcolormap[0][psrc[6]]; pdest[14] = pdest[15] = pdest[nextrow + 14] = pdest[nextrow + 15] = pcolormap[0][psrc[7]]; pdest += 16; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } else { rowdelta = (destrowbytes - (width<<2))>>2; for (y = height ; y ; y--) { for (x = xcount ; x ;x--) { pdest[0] = pcolormap[0][psrc[0]]; pdest[1] = pcolormap[0][psrc[1]]; pdest[2] = pcolormap[0][psrc[2]]; pdest[3] = pcolormap[0][psrc[3]]; pdest[4] = pcolormap[0][psrc[4]]; pdest[5] = pcolormap[0][psrc[5]]; pdest[6] = pcolormap[0][psrc[6]]; pdest[7] = pcolormap[0][psrc[7]]; pdest += 8; psrc += 8; } psrc += srcdelta; pdest += rowdelta; } } } /* ========================================================================== NEXTSTEP VIEW CLASS ========================================================================== */ @implementation QuakeView /* ================= windowDidMove ================= */ - windowDidMove:sender { NXPoint aPoint; NXRect winframe; aPoint.x = aPoint.y = 0; [self convertPoint:&aPoint toView:nil]; [window convertBaseToScreen: &aPoint]; [window getFrame: &winframe]; if ((int)aPoint.x & 7) { [window moveTo:winframe.origin.x - ((int)aPoint.x&7) :winframe.origin.y]; [window getFrame: &winframe]; } return self; } - windowWillResize:sender toSize:(NXSize *)frameSize { NXRect fr, cont; fr.origin.x = fr.origin.y = 0; fr.size = *frameSize; [Window getContentRect:&cont forFrameRect: &fr style:[window style]]; cont.size.width = (int)cont.size.width & ~15; if (cont.size.width < 128) cont.size.width = 128; cont.size.height = (int)cont.size.height & ~3; if (cont.size.height < 32) cont.size.height = 32; [Window getFrameRect:&fr forContentRect: &cont style:[window style]]; *frameSize = fr.size; return self; } - windowDidResize:sender { if (vid_display == disp_framebuffer) Sys_Error ("How the heck are you resizing a framebuffer window?!?"); vid.width = bounds.size.width/vid_scale; vid.height = bounds.size.height/vid_scale; // // allocate memory for the back and translation buffers // vid.rowbytes = vid.width; rowbytesnative = vid.width * pixbytesnative; AllocBuffers (true); vid.conbuffer = vid.buffer; vid.conrowbytes = vid.rowbytes; vid.conwidth = vid.width; vid.conheight = vid.height; vid.recalc_refdef = 1; return self; } -(BOOL) acceptsFirstResponder { return YES; } typedef struct { int source, dest; } keymap_t; keymap_t keymaps[] = { {103, K_RIGHTARROW}, {102, K_LEFTARROW}, {100, K_UPARROW}, {101, K_DOWNARROW}, {111, K_PAUSE}, {59, K_F1}, {60, K_F2}, {61, K_F3}, {62, K_F4}, {63, K_F5}, {64, K_F6}, {65, K_F7}, {66, K_F8}, {67, K_F9}, {68, K_F10}, {87, K_F11}, {88, K_F12}, {-1,-1} }; keymap_t flagmaps[] = { {NX_SHIFTMASK, K_SHIFT}, {NX_CONTROLMASK, K_CTRL}, {NX_ALTERNATEMASK, K_ALT}, {NX_COMMANDMASK, K_ALT}, {-1,-1} }; /* =================== keyboard methods =================== */ - keyDown:(NXEvent *)theEvent { int ch; keymap_t *km; PSobscurecursor (); // check for non-ascii first ch = theEvent->data.key.keyCode; for (km=keymaps;km->source!=-1;km++) if (ch == km->source) { Key_Event (km->dest, true); return self; } ch = theEvent->data.key.charCode; if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A'; if (ch>=256) return self; Key_Event (ch, true); return self; } - flagsChanged:(NXEvent *)theEvent { static int oldflags; int newflags; int delta; keymap_t *km; int i; PSobscurecursor (); newflags = theEvent->flags; delta = newflags ^ oldflags; for (i=0 ; i<32 ; i++) { if ( !(delta & (1<source!=-1;km++) if ( (1<source) { if (newflags & (1<dest, true); else Key_Event (km->dest, false); } } oldflags = newflags; return self; } - keyUp:(NXEvent *)theEvent { int ch; keymap_t *km; // check for non-ascii first ch = theEvent->data.key.keyCode; for (km=keymaps;km->source!=-1;km++) if (ch == km->source) { Key_Event (km->dest, false); return self; } ch = theEvent->data.key.charCode; if (ch >= 'A' && ch <= 'Z') ch += 'a' - 'A'; if (ch>=256) return self; Key_Event (ch, false); return self; } - tiffShot { id imagerep, image; NXRect r; NXStream *stream; int fd; int i; char tiffname[80]; [vid_window_i getFrame: &r]; r.origin.x = r.origin.y = 0; image = [[NXImage alloc] initSize: &r.size]; imagerep = [[NXCachedImageRep alloc] initFromWindow:vid_window_i rect:&r]; [image lockFocus]; [imagerep draw]; [image unlockFocus]; // // find a file name to save it to // strcpy(tiffname,"quake00.tif"); for (i=0 ; i<=99 ; i++) { tiffname[5] = i/10 + '0'; tiffname[6] = i%10 + '0'; if (Sys_FileTime(tiffname) == -1) break; // file doesn't exist } if (i==100) Sys_Error ("SCR_ScreenShot_f: Couldn't create a tiff"); fd = open (tiffname, O_RDWR|O_CREAT|O_TRUNC, 0666); stream = NXOpenFile (fd, NX_READWRITE); [image writeTIFF: stream]; NXClose (stream); close (fd); printf ("wrote %s\n", tiffname); [image free]; [imagerep free]; return self; } - screenShot: sender { return [self tiffShot]; } - setScaleFullScreen: sender { VID_Shutdown (); if (vid_fullscreen) { vid_fullscreen = 0; VID_Restart (vid_display, vid_scale); } else { vid_fullscreen = 1; VID_Restart (vid_display, vid_scale); } return self; } @end //============================================================================ @implementation FrameWindow - windowExposed:(NXEvent *)theEvent { return self; } @end