This is winSunView.c in view mode; [Download] [Up]
/* $Header$ */ /* * window_sunview.c - Window-system specific routines * * Author: Bob Brown * RIACS * NASA Ames Research Center * Date: Thu Dec 5 1986 * Copyright (c) 1986 Robert L. Brown * * Revised by: Malcolm Slaney (@ Schlumberger Palo Alto Research) * August 1987 and January 1988 * */ /* * It is intended that this file presents a window system-independent * set of routines to MazeWar; that is, if you want to run MW under * another window system, this is the only file that needs to be * changed. It isn't yet clear how well I've succeeded, but it's a start. * * Routines that are presented to the outside are capitalized; local * routines are not. * * This file is for Sun 3.1 Sunview. It has also been tested under Sun 3.4. */ /* * $Log$ */ #ifndef lint static char rcs_ident[] = "$Header$"; #endif #include <sys/types.h> /* I hate programs that do this... */ #include <sys/socket.h> /* ... but sometimes you just gotta */ #include <netinet/in.h> #include <suntool/sunview.h> #include <suntool/canvas.h> #include <stdio.h> #include "mazewar.h" #include <errno.h> /* ** These constants define where in the main pixwin the subregions lie */ #define VIEW_X_DIM 400 #define VIEW_Y_DIM 400 #define VIEW_X_ORIGIN 100 #define VIEW_Y_ORIGIN 50 #define MAZE_X_DIM (MAZEXMAX*16) #define MAZE_Y_DIM (MAZEYMAX*16) #define MAZE_X_ORIGIN 48 #define MAZE_Y_ORIGIN 451 #define SCORE_X_DIM 192 #define SCORE_Y_DIM (mwFontHeight * MAXRATS) #define SCORE_X_ORIGIN 208 #define SCORE_Y_ORIGIN 708 #define MIN_X_DIM 608 /* see comments for InitWindow() */ #define MIN_Y_DIM SCORE_Y_ORIGIN /* see InitWindow() */ #define MAX_X_DIM MIN_X_DIM #define MAX_Y_DIM (MIN_Y_DIM + SCORE_Y_DIM) short mazeBits[MAZEXMAX*MAZEYMAX*16]; /* shorts better be 16 bits! */ Frame BaseFrame; /* parent frame */ Canvas BaseCanvas; /* Base canvas */ Pixwin *mwPixwin; /* parent pixel window */ Pixwin *viewPixwin; /* view subwindow */ Pixwin *mazePixwin; /* maze subwindow */ Pixwin *scorePixwin; /* score subwindow */ struct pixrect *mazePixrect; /* Pixrect that has the maze */ struct pixrect *ratsPixrect; /* Pixrect that has the rats */ struct pixfont *mwFont; /* Font being used */ int mwFontHeight; /* Height of the font */ Boolean inverted = FALSE; /* user warned of window exit */ int displayFD; /* fd of display for events */ int frameFD; /* for handling frame events */ int RastOp = PIX_SRC; int MaxOffset; /* max vertical font offset from * baseline */ int flashIcon = FALSE; /* Should icon be flashing ? */ static short grayBits[16] = { 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555 }; static short ratBits[] = { 0x0000,0x0000,0x07C0,0x0FE8,0x0FFC,0x7FFA,0x8FFF,0x8842, 0x4000,0x3F00,0x0080,0x0100,0x0200,0x0100,0x0000,0x0000 }; mpr_static(ratPixrect, 16, 16, 1, ratBits); static short deadRatBits[] = { 0x0000, 0x2088, 0x1045, 0x0082, 0x0000, 0x1000, 0x2000, 0x4100, 0x8220, 0x87ff, 0x8ffa, 0x7ffc, 0x0fe8, 0x07c0, 0x0000, 0x0000 }; mpr_static(deadRatPixrect, 16, 16, 1, deadRatBits); static short coffeeCupBits[] = { 0x0080, 0x0700, 0x0800, 0x07c0, 0x0020, 0x07f0, 0x3c48, 0x47f8, 0x5808, 0x4008, 0x3c08, 0x0818, 0x37f6, 0x2002, 0x17fc, 0x0000 }; mpr_static(coffeeCupPixrect, 16, 16, 1, coffeeCupBits); static short ToolIconBits[] = { /* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 */ 0x8888,0x8888,0x8888,0x8888,0x8800,0x0000,0x0000,0x0008, 0x2200,0x0000,0x0000,0x0022,0x2284,0x0000,0x0820,0x0022, 0x8884,0x0000,0x0820,0x0008,0x88CC,0x71F1,0xC827,0x1608, 0x22CC,0x8812,0x2928,0x9922,0x22B4,0x0822,0x2540,0x9022, 0x88B4,0x7843,0xE547,0x9008,0x8884,0x8882,0x0548,0x9008, 0x2284,0x8902,0x2288,0x9022,0x2284,0x79F1,0xC287,0x9022, 0x8800,0x0000,0x0000,0x0008,0x8800,0x0000,0x0000,0x0008, 0x2200,0x0000,0x0000,0x0022,0x2222,0x2222,0x2222,0x2222, 0x8888,0x8888,0x8888,0x8888,0x9FFF,0xFFFF,0xFFFF,0xFFFC, 0x3800,0x0000,0x0000,0x0006,0x3400,0x0000,0x0000,0x0006, 0x9200,0x0000,0x0000,0x0004,0x9100,0x0000,0x0000,0x0004, 0x3080,0x0000,0x0000,0x0006,0x3040,0x0000,0x0000,0x01FE, 0x9020,0x0000,0x0000,0x0304,0x9010,0x0000,0x0000,0x0504, 0x3008,0x0000,0x0000,0x0906,0x3004,0x0000,0x0000,0x1106, 0x9002,0x0000,0x0000,0x2104,0x9001,0x0000,0x0000,0x4104, 0x3000,0x8000,0x0000,0x8106,0x3000,0x4000,0x0001,0x0106, 0x9000,0x3FFF,0xFFFE,0x0104,0x9000,0x2000,0x0002,0x0104, 0x3000,0x2000,0x0002,0x0106,0x3000,0x2000,0x0002,0x0106, 0x9000,0x2000,0x0002,0x0104,0x9000,0x2000,0x0002,0x0104, 0x3000,0x2000,0x0002,0x0106,0x3000,0x2000,0x0002,0x0106, 0x9000,0x2000,0x0002,0x0104,0x9000,0x2000,0x0002,0x0104, 0x3000,0x2000,0x0002,0x0106,0x3000,0x3FFF,0xFFFE,0x0106, 0x9000,0x4000,0x0001,0x0104,0x9000,0x8000,0x0000,0x8104, 0x3001,0x0000,0x0000,0x4106,0x3002,0x0000,0x0000,0x2106, 0x9004,0x0000,0x0000,0x1104,0x9008,0x0001,0xF000,0x0904, 0x3010,0x000B,0xF800,0x0506,0x3020,0x001F,0xF800,0x0306, 0x9040,0x002F,0xFF00,0x01FC,0x9080,0x007F,0xF880,0x0004, 0x3100,0x0021,0x0880,0x0006,0x3200,0x0000,0x0100,0x0006, 0x9400,0x0000,0x7E00,0x0004,0x9800,0x0000,0x8000,0x0004, 0x3000,0x0000,0x4000,0x0006,0x3000,0x0000,0x2000,0x0006, 0x9FFF,0xFFFF,0xFFFF,0xFFFC,0x8888,0x8888,0x8888,0x8888, 0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222 }; DEFINE_ICON_FROM_IMAGE(ToolIcon, ToolIconBits); static Cursor ratCursor, deadRatCursor, hourGlassCursor; extern char *getenv(); extern int errno; /* state between InitWindow() and StartWindow() */ static char *progName; /* * ALL COORDINATES ASSUME ORIGIN (0,0) AT UPPER LEFT! */ /* * Initialize the window. The overall window must be at least 608x by * 808y (the size of the Alto screen). There are three distinct * subregions: * A 400x by 400y area for the view, beginning at (100,50) * A 512x by 256y area for the maze, beginning at (48, 451) * A 192x by 96y area for the score lines, at (208, 706) * * Actually, the y dimension of both the whole window and the score * subwindow must be enough to accommodate MAXRATS lines of the * height of the scoreFont. */ /* parse arguments and set up window state */ InitWindow(argc, argv) char **argv; { int i; progName = argv[0]; BaseFrame = window_create(NULL, FRAME, FRAME_ARGC_PTR_ARGV, &argc, argv, FRAME_LABEL, "Maze War", FRAME_ICON, &ToolIcon, 0); mwFont = (struct pixfont *)window_get(BaseFrame, WIN_FONT); mwFontHeight = mwFont->pf_defaultsize.y; MaxOffset = 999; for(i=0;i<256;i++) { if(MaxOffset > mwFont->pf_char[i].pc_home.y) MaxOffset = mwFont->pf_char[i].pc_home.y; } /* printf("maxoffset = %d\n", MaxOffset); */ frameFD = (int)window_get(BaseFrame, WIN_FD); } /* * actually start the display up, after all the user interaction has * been done. */ StartWindow(ratBits, ratWidth, ratHeight) short *ratBits; { int repaintWindow(); initCursors(); HourGlassCursor(); initMaze(); /* FlipBitmaps(); /* bit-reverse all the bitmaps */ initRats(ratBits, ratWidth, ratHeight); BaseCanvas = window_create(BaseFrame, CANVAS, WIN_X, 0, WIN_Y, 0, WIN_WIDTH, MAX_X_DIM, WIN_HEIGHT, MAX_Y_DIM, 0); window_fit(BaseFrame); window_set(BaseFrame, WIN_SHOW, TRUE, 0); window_set(BaseCanvas, WIN_CONSUME_KBD_EVENTS, WIN_NO_EVENTS, WIN_ASCII_EVENTS, KBD_USE, KBD_DONE, 0, WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, WIN_MOUSE_BUTTONS, LOC_WINENTER, LOC_WINEXIT, 0, 0); mwPixwin = (Pixwin *)window_get(BaseCanvas, CANVAS_PIXWIN); notify_dispatch(); displayFD = (int)window_get(BaseCanvas, WIN_FD); viewPixwin = (Pixwin *)pw_region(mwPixwin, VIEW_X_ORIGIN, VIEW_Y_ORIGIN, VIEW_X_DIM, VIEW_Y_DIM); mazePixwin = (Pixwin *)pw_region(mwPixwin, MAZE_X_ORIGIN, MAZE_Y_ORIGIN, MAZE_X_DIM, MAZE_Y_DIM); scorePixwin = (Pixwin *)pw_region(mwPixwin, SCORE_X_ORIGIN, SCORE_Y_ORIGIN, SCORE_X_DIM, SCORE_Y_DIM); window_set(BaseCanvas, CANVAS_REPAINT_PROC, repaintWindow, CANVAS_RESIZE_PROC, repaintWindow, CANVAS_RETAINED, TRUE, CANVAS_AUTO_CLEAR, TRUE, 0); repaintWindow(); } /* * Shut down the window system, resetting any terminal modes or what * have you that may have been altered. No-op for Sun View */ StopWindow() { } /* * Clear out the view subwindow. If possible, delay the visible effect * until all the lines have been drawn (since this is only called by * ShowView(), which is about to draw a bunch of lines). */ ClearView() { pw_writebackground(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM, RastOp); } /* * Flash the view window to indicate a hit on an opponent. */ FlashTop() { pw_rop(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM, PIX_NOT(PIX_SRC), viewPixwin, 0, 0); /* might want some delay here */ pw_rop(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM, PIX_NOT(PIX_SRC), viewPixwin, 0, 0); } /* * Flash the whole window to indicate we were hit. */ FlashScreen() { pw_rop(mwPixwin, 0, 0, window_get(BaseCanvas, WIN_WIDTH), window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC), mwPixwin, 0, 0); /* might want some delay here */ pw_rop(mwPixwin, 0, 0, window_get(BaseCanvas, WIN_WIDTH), window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC), mwPixwin, 0, 0); } /* * Draw a line in the view subwindow. Don't show it right away if possible. */ DrawViewLine(x1, y1, x2, y2) { pw_vector(viewPixwin, x1, y1, x2, y2, RastOp, 1); } /* * Event handling. Presents a uniform event interface to the game, and * handles all other events in here. The game only sees the events * that affect it directly, as defined in mazewar.h. They are: * * keypresses that affect the game * mouse button clicks * incoming network packets * timeouts (there's a "heartbeat" to drive the shot clock) * * All other events should be swallowed by this routine. Also, since * keyboard focus is dependent on the mouse being in the game window, * try to let the user know that he's wandered outside the window * by inverting the window (should make it obvious) and is now vulnerable * and defenseless. */ void NextEvent(event) MWEvent *event; { int fdmask; Event sunEvent; struct timeval timeout; int ret; static int LastWinEnterExit = 0; while (1) { if (flashIcon == TRUE){ if (window_get(BaseFrame, FRAME_CLOSED)){ InvertIcon(); } else { flashIcon = FALSE; window_set(BaseFrame, FRAME_ICON, &ToolIcon, 0); } } /* must do this every time, since M.theSocket may change! */ fdmask = (1 << displayFD) | (1 << frameFD) | (1 << M.theSocket); timeout.tv_sec = 0; timeout.tv_usec = 250000; while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1){ /* EINTR implies interrupts * which we don't care about. * EBADF implies that things * are probably being shut down * so we should exit. */ if (errno == EBADF){ event->eventType = EVENT_INT; return; } if (errno != EINTR) MWError("select error on events"); } if (ret == 0) { event->eventType = EVENT_TIMEOUT; (void) notify_dispatch(); return; } if (fdmask & (1 <<displayFD)) { window_read_event(BaseCanvas, &sunEvent); event->eventType = 0; switch (sunEvent.ie_code) { case 'a': event->eventType = EVENT_A; return; case 's': event->eventType = EVENT_S; return; case 'd': event->eventType = EVENT_D; return; case 'f': event->eventType = EVENT_F; return; case ' ': event->eventType = EVENT_BAR; return; case 'i': event->eventType = EVENT_I; return; case 'k': event->eventType = EVENT_K; return; case 'o': event->eventType = EVENT_O; return; case 'l': event->eventType = EVENT_L; return; case 'q': case 077: /* should also deal with Interrupt char */ event->eventType = EVENT_INT; return; case MS_RIGHT: event->eventType = event_is_down(&sunEvent) ? EVENT_RIGHT_D : EVENT_RIGHT_U; return; case MS_MIDDLE: event->eventType = event_is_down(&sunEvent) ? EVENT_MIDDLE_D : 0; return; case MS_LEFT: event->eventType = event_is_down(&sunEvent) ? EVENT_LEFT_D : EVENT_LEFT_U; return; case KBD_USE: #ifdef DEBUG printf("Have keyboard focus again.....\n"); #endif DEBUG if (RastOp != PIX_SRC) { invertDisplay(); } RastOp = PIX_SRC; break; case KBD_DONE: #ifdef DEBUG printf("Lost keyboard focus.....\n"); #endif DEBUG if (RastOp != PIX_NOT(PIX_SRC)) { invertDisplay(); } RastOp = PIX_NOT(PIX_SRC); break; case WIN_REPAINT: repaintWindow(); break; default: /* printf("Window event %d\n", sunEvent.ie_code); */ break; } continue; } if (fdmask & (1 << M.theSocket)) { int fromLen = sizeof(event->eventSource); int cc; event->eventType = EVENT_NETWORK; cc = recvfrom(M.theSocket, event->eventDetail, sizeof(RatPacket), 0, &event->eventSource, &fromLen); ConvertIncoming(event->eventDetail); if (cc <= 0) { if (cc < 0 && errno != EINTR) perror("event recvfrom"); continue; } if (fromLen != sizeof(struct sockaddr_in)) continue; return; } if ( fdmask & (1 << frameFD)) { notify_dispatch(); } } } /* Please stand by ... */ HourGlassCursor() { window_set(BaseCanvas, WIN_CURSOR, hourGlassCursor, 0); } /* Let the games begin! */ RatCursor() { window_set(BaseCanvas, WIN_CURSOR, ratCursor, 0); } /* He's dead, Jim ... or might be */ DeadRatCursor() { window_set(BaseCanvas, WIN_CURSOR, deadRatCursor, 0); } /* update the displayed bitmap */ mpr_static(Hack_pr, 16, 16, 1, NULL); HackMazeBitmap(x, y, newBits) BitCell *newBits; { Hack_pr_data.md_image = newBits->bits; pw_rop(mazePixwin, x*16, y*16, 16, 16, RastOp, &Hack_pr, 0, 0); } /* * Display a rat. Width, height, srcX and srcY describe the subbitmap * in the rats bitmap that is the desired view of the opponent. */ DisplayRatBitmap(screenX, screenY, width, height, srcX, srcY) { pw_rop(viewPixwin, screenX, screenY, width, height, PIX_SRC^PIX_DST, ratsPixrect, srcX, srcY); } /* * Display the score line for the indicated player. Name is left * justified, score is right justified within the score window. */ WriteScoreString(rat) RatId rat; { char buf[64]; int leftEdge; struct pr_size size; pw_text(scorePixwin, 0, (rat+1)*mwFontHeight, RastOp, mwFont, M.ratcb.rats[rat].name); sprintf(buf, "%d", (unsigned int)M.ratcb.rats[rat].score); size = pf_textwidth(strlen(buf), mwFont, buf); leftEdge = SCORE_X_DIM - size.x; pw_text(scorePixwin, leftEdge, (rat+1)*mwFontHeight, RastOp, mwFont, buf); } /* * Clear out the score line for a player that's left the game. */ ClearScoreLine(rat) RatId rat; { pw_writebackground(scorePixwin, 0, (rat+1)*mwFontHeight+MaxOffset, SCORE_X_DIM, mwFontHeight, RastOp); } /* * Pretty obvious, eh? Means the guy's in sight. */ InvertScoreLine(rat) RatId rat; { pw_writebackground(scorePixwin, 0, (rat+1)*mwFontHeight+MaxOffset, SCORE_X_DIM, mwFontHeight, PIX_NOT(PIX_DST)); } /* * END PUBLIC ROUTINES */ /* set up needed bitmaps in the server */ initCursors() { ratCursor = cursor_create(CURSOR_IMAGE, &ratPixrect, CURSOR_OP, PIX_SRC^PIX_DST, 0); deadRatCursor = cursor_create(CURSOR_IMAGE, &deadRatPixrect, CURSOR_OP, PIX_SRC^PIX_DST, 0); hourGlassCursor = cursor_create(CURSOR_IMAGE, &coffeeCupPixrect, CURSOR_OP, PIX_SRC^PIX_DST, 0); } /* * construct a Pixmap of the maze, and store it in the server. */ initMaze() { register int i, j, k, line, index; for (i = 0; i < MAZEYMAX; i++) { line = i * MAZEXMAX * MAZEYMAX; for (j = 0; j < MAZEXMAX; j++) { index = line + j; for (k = 0; k < 16; k++) { if (M.maze[j].y[i]) mazeBits[index] = 0177777; else mazeBits[index] = 0; index += 32; } } } mazePixrect = mem_point(MAZE_X_DIM, MAZE_Y_DIM, 1, mazeBits); } /* * actually put the maze Pixmap on the screen */ drawMaze() { pw_rop(mazePixwin, 0, 0, MAZE_X_DIM, MAZE_Y_DIM, RastOp, mazePixrect, 0, 0); } /* * Create a memory pixrect of the rats so we can do arbitrary * bitblts on them later. */ initRats(bits, width, height) short *bits; { ratsPixrect = mem_point(width, height, 1, bits); } usage() { fprintf(stderr,"usage: mazewar\n"); exit(1); } repaintWindow() { #ifdef DEBUG printf("repaint window called\n"); if (RastOp == PIX_SRC) printf("repaintWindow called with RastOp = PIX_SRC.\n"); else printf( "repaintWindow called with RastOp = PIX_NOT(PIX_SRC).\n"); #endif DEBUG if (RastOp != PIX_SRC) pw_rop(mwPixwin, 0, 0, (int)window_get(BaseCanvas, WIN_WIDTH), (int)window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_CLR), mwPixwin, 0, 0); drawMaze(); ShowPosition(M.xloc, M.yloc, M.invincible, M.dir); ShowView(M.xloc, M.yloc, M.dir); ShowAllPositions(); NewScoreCard(); } /* * Invert the whole display. Used to let the user know the mouse has * strayed outside the window. */ invertDisplay() { pw_rop(mwPixwin, 0, 0, (int)window_get(BaseCanvas, WIN_WIDTH), (int)window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC), mwPixwin, 0, 0); } /* * Peek to see if there's a keyboard event waiting, in case the * program wants to short-circuit some code. If your system won't let * you implement this feature easily, just always return FALSE. */ Boolean KBEventPending() { return (FALSE); } /* * Let the user know that a new player joined. This really should only * take effect if the window is iconic, so you can keep a game around * all day, close it up when there's no activity, and know when * someone else is also out to kill some time. */ NotifyPlayer() { flashIcon = TRUE; } InvertIcon(){ Icon icon; Pixrect *pr; icon = (Icon) window_get(BaseFrame, FRAME_ICON); pr = (Pixrect *) icon_get(icon, ICON_IMAGE); pr_rop(pr, 0, 0, 64, 64, PIX_NOT(PIX_DST), pr, 0, 0); icon_set(icon, ICON_IMAGE, pr, 0); window_set(BaseFrame, FRAME_ICON, icon, 0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.