home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume13 / xsokoban3 / part01 / display.c next >
C/C++ Source or Header  |  1992-02-11  |  17KB  |  560 lines

  1. #include <stdio.h>
  2. #include "externs.h"
  3. #include "globals.h"
  4. #include "defaults.h"
  5. #include "help.h"
  6.  
  7. /* mnemonic defines to help orient some of the text/line drawing, sizes */
  8. #define HELPLINE ((bit_height * MAXROW) + 30)
  9. #define STATUSLINE ((bit_height * MAXROW) + 5)
  10. #define HELP_H (bit_height * MAXROW)
  11. #define HELP_W (bit_width * MAXCOL)
  12.  
  13. /* useful globals */
  14. Display *dpy;
  15. Window win;
  16. int scr;
  17. GC gc, rgc, drgc;
  18. XFontStruct *finfo;
  19. unsigned int width, height, depth, bit_height, bit_width;
  20. Boolean display_alloc = False, font_alloc = False, gc_alloc = False,
  21.         pix_alloc = False;
  22. Boolean optwalls;
  23. Colormap cmap;
  24. Cursor this_curs;
  25. Pixmap help[HELP_PAGES], floor;
  26. Pixmap blank, work, man, saveman, goal, object, treasure, walls[NUM_WALLS];
  27. int hlpscrn = -1;
  28. char buf[500];
  29.  
  30. extern char *progname;
  31. extern char map[MAXROW+1][MAXCOL+1];
  32. extern short rows, cols, level, moves, pushes, packets, savepack;
  33. extern char *bitpath;
  34.  
  35. /* names of the fancy wall bitmap files.  If you define a set of fancy
  36.  * wall bitmaps, they must use these names
  37.  */
  38. char *wallname[] = {
  39.  "lonewall.xbm", "southwall.xbm", "westwall.xbm", "llcornerwall.xbm",
  40.  "northwall.xbm", "vertiwall.xbm", "ulcornerwall.xbm", "west_twall.xbm",
  41.  "eastwall.xbm", "lrcornerwall.xbm", "horizwall.xbm", "south_twall.xbm",
  42.  "urcornerwall.xbm", "east_twall.xbm", "north_twall.xbm", "centerwall.xbm"
  43. };
  44.  
  45. /* Do all the nasty stuff like makeing the windows, setting all the defaults
  46.  * creating all the pixmaps, loading everything, and mapping the window.
  47.  * this does NOT do the XOpenDisplay() so that the -display switch can be
  48.  * handled cleanly.
  49.  */
  50. short InitX(void)
  51. {
  52.   int i;
  53.   Boolean reverse = _false_, tmpwalls = _false_;
  54.   char *rval;
  55.   unsigned long fore, back, bord, curs, gc_mask;
  56.   XSizeHints szh;
  57.   XWMHints wmh;
  58.   XSetWindowAttributes wattr;
  59.   XClassHint clh;
  60.   XGCValues val, reval;
  61.   XTextProperty wname, iname;
  62.   XColor cfg, cbg;
  63.  
  64.   /* these are always needed */
  65.   scr = DefaultScreen(dpy);
  66.   cmap = DefaultColormap(dpy, scr);
  67.   depth = DefaultDepth(dpy, scr);
  68.  
  69.   /* here is where we figure out the resources and set the defaults.
  70.    * resources can be either on the command line, or in your .Xdefaults/
  71.    * .Xresources files.  They are read in and parsed in main.c, but used
  72.    * here.
  73.    */
  74.   rval = GetResource(FONT);
  75.   if(rval == (char *)0)
  76.     rval = DEF_FONT;
  77.   finfo = XLoadQueryFont(dpy, rval);
  78.   if(finfo == (XFontStruct *)0)
  79.     return E_NOFONT;
  80.   font_alloc = _true_;
  81.  
  82.   rval = GetResource(REVERSE);
  83.   if(rval != (char *)0) {
  84.     reverse = StringToBoolean(rval);
  85.   }
  86.  
  87.   if(!GetColorResource(FOREG, &fore))
  88.     fore = BlackPixel(dpy, scr);
  89.  
  90.   if(!GetColorResource(BACKG, &back))
  91.     back = WhitePixel(dpy, scr);
  92.  
  93.   if(reverse) {
  94.     unsigned long t;
  95.     t = fore;
  96.     fore = back;
  97.     back = t;
  98.   }
  99.  
  100.   if(!GetColorResource(BORDER, &bord))
  101.     bord = fore;
  102.   if(!GetColorResource(CURSOR, &curs))
  103.     curs = fore;
  104.  
  105.   bitpath = GetResource(BITDIR);
  106.   rval = GetResource(WALLS);
  107.   if(rval != (char *)0)
  108.     tmpwalls = StringToBoolean(rval);
  109.  
  110.   /* walls are funny.  if a alternate bitpath has been defined, assume
  111.    * !fancywalls unless explicitly told fancy walls.  If the default 
  112.    * bitpath is being used, you can assume fancy walls.
  113.    */
  114.   if(bitpath && !tmpwalls)
  115.     optwalls = _false_;
  116.   else
  117.     optwalls = _true_;
  118.  
  119.   width = MAXCOL * DEF_BITW;
  120.   height = MAXROW * DEF_BITH + 50;
  121.  
  122.   wmh.initial_state = NormalState;
  123.   wmh.input = True;
  124.   wmh.flags = (StateHint | InputHint);
  125.  
  126.   clh.res_class = clh.res_name = progname;
  127.  
  128.   /* Make sure the window and icon names are set */
  129.   if(!XStringListToTextProperty(&progname, 1, &wname))
  130.     return E_NOMEM;
  131.   if(!XStringListToTextProperty(&progname, 1, &iname))
  132.     return E_NOMEM;
  133.  
  134.   /* load in a cursor, and recolor it so it looks pretty */
  135.   this_curs = XCreateFontCursor(dpy, DEF_CURSOR);
  136.   cfg.pixel = curs;
  137.   cbg.pixel = back;
  138.   XQueryColor(dpy, cmap, &cfg);
  139.   XQueryColor(dpy, cmap, &cbg);
  140.   XRecolorCursor(dpy, this_curs, &cfg, &cbg);
  141.  
  142.   /* set up the funky little window attributes */
  143.   wattr.background_pixel = back;
  144.   wattr.border_pixel = bord;
  145.   wattr.backing_store = Always;
  146.   wattr.event_mask = (KeyPressMask | ExposureMask | ButtonPressMask);
  147.   wattr.cursor = this_curs;
  148.  
  149.   /* whee, create the window, we create it with NO size so that we
  150.    * can load in the bitmaps, we later resize it correctly
  151.    */
  152.   win = XCreateWindow(dpy, RootWindow(dpy, scr), 0, 0, width, height, 4,
  153.               CopyFromParent, InputOutput, CopyFromParent,
  154.                       (CWBackPixel | CWBorderPixel | CWBackingStore |
  155.                        CWEventMask | CWCursor), &wattr);
  156.  
  157.   /* this will set the bit_width and bit_height as well as loading
  158.    * in the pretty little bitmaps
  159.    */
  160.   if(LoadBitmaps() == E_NOBITMAP)
  161.     return E_NOBITMAP;
  162.   blank = XCreatePixmap(dpy, win, bit_width, bit_height, 1);
  163.   pix_alloc = _true_;
  164.  
  165.   width = MAXCOL * bit_width;
  166.   height = MAXROW * bit_height + 50;
  167.   
  168.   /* whee, resize the window with the correct size now that we know it */
  169.   XResizeWindow(dpy, win, width, height);
  170.  
  171.   /* set up the size hints, we don't want manual resizing allowed. */
  172.   szh.min_width = szh.width = szh.max_width = width;
  173.   szh.min_height = szh.height = szh.max_height = height;
  174.   szh.x = szh.y = 0;
  175.   szh.flags = (PSize | PPosition | PMinSize | PMaxSize);
  176.  
  177.   /* now SET all those hints we create above */
  178.   XSetWMNormalHints(dpy, win, &szh);
  179.   XSetWMHints(dpy, win, &wmh);
  180.   XSetClassHint(dpy, win, &clh);
  181.   XSetWMName(dpy, win, &wname);
  182.   XSetWMIconName(dpy, win, &iname);
  183.  
  184.   work = XCreatePixmap(dpy, win, width, height, depth);
  185.  
  186.   /* set up all the relevant GC's */
  187.   val.foreground = reval.background = fore;
  188.   val.background = reval.foreground = back;
  189.   val.function = reval.function = GXcopy;
  190.   val.font = reval.font = finfo->fid;
  191.   gc_mask = (GCForeground | GCBackground | GCFunction | GCFont);
  192.   gc = XCreateGC(dpy, work, gc_mask, &val);
  193.   rgc = XCreateGC(dpy, blank, gc_mask, &reval);
  194.   drgc = XCreateGC(dpy, work, gc_mask, &reval);
  195.   
  196.   /* make the help windows and the working bitmaps */
  197.   /* we need to do this down here since it requires GCs to be allocated */
  198.   for(i = 0; i < HELP_PAGES; i++)
  199.     help[i] = XCreatePixmap(dpy, win, HELP_W, HELP_H, depth);
  200.   MakeHelpWindows();
  201.   XFillRectangle(dpy, blank, rgc, 0, 0, bit_width, bit_height);
  202.  
  203.   gc_alloc = _true_;
  204.  
  205.   /* display the friendly little clear screen */
  206.   ClearScreen();
  207.   XMapWindow(dpy, win);
  208.   RedisplayScreen();
  209.   
  210.   return 0;
  211. }
  212.  
  213. /* deallocate all the memory and structures used in creating stuff */
  214. void DestroyDisplay(void)
  215. {
  216.   int i;
  217.  
  218.   /* kill the font */
  219.   if(font_alloc)
  220.     XFreeFont(dpy, finfo);
  221.  
  222.   /* destroy everything allocted right around the gcs.  Help windows are
  223.    * freed here cause they are created about the same time.  (Yes, I know
  224.    * this could cause problems, it hasn't yet.
  225.    */
  226.   if(gc_alloc) {
  227.     XFreeGC(dpy, gc);
  228.     XFreeGC(dpy, rgc);
  229.     XFreeGC(dpy, drgc);
  230.     XFreePixmap(dpy, work);
  231.     for (i = 0; i < HELP_PAGES; i++)
  232.       XFreePixmap(dpy, help[i]);
  233.   }
  234.   /* free up all the allocated pix */
  235.   if(pix_alloc) {
  236.     XFreePixmap(dpy, man);
  237.     XFreePixmap(dpy, saveman);
  238.     XFreePixmap(dpy, goal);
  239.     XFreePixmap(dpy, treasure);
  240.     XFreePixmap(dpy, object);
  241.     XFreePixmap(dpy, floor);
  242.     XFreePixmap(dpy, blank);
  243.     for(i = 0; i < NUM_WALLS; i++)
  244.       if(i == 0 || optwalls)
  245.         XFreePixmap(dpy, walls[i]);
  246.   }
  247.   /* okay.. NOW we can destroy the main window and the display */
  248.   if(display_alloc) {
  249.     XDestroyWindow(dpy, win);
  250.     XCloseDisplay(dpy);
  251.   }
  252. }
  253.  
  254. /* this loads in a single bitmap.  If this bitmap is the largest in the x or
  255.  * y direction, set bit_width or bit_height appropriately.  If your pixmaps
  256.  * are of varying sizes, a bit_width by bit_height box is gaurenteed to be
  257.  * able to surround all of them.
  258.  */
  259. Boolean LoadOneBitmap(char *fname, char *altname, Pixmap *pix)
  260. {
  261.   unsigned int dum1, dum2;
  262.   int dum3, dum4;
  263.   Boolean load_fail = _false_;
  264.   char buf[1024];
  265.  
  266.   if(bitpath && *bitpath) {
  267.     /* we have something to try other than the default, let's do it */
  268.     sprintf(buf, "%s/%s", bitpath, fname);
  269.     if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  270.        BitmapSuccess) {
  271.       if(altname && *altname) {
  272.         fprintf(stderr, "%s: Cannot find '%s/%s', trying alternate.\n",
  273.                 progname, bitpath, fname);
  274.         sprintf(buf, "%s/%s", bitpath, altname);
  275.         if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  276.            BitmapSuccess) {
  277.           load_fail = _true_;
  278.           fprintf(stderr, "%s: Cannot find '%s/%s', trying defaults.\n",
  279.                   progname, bitpath, altname);
  280.         } else {
  281.       if(dum1 > bit_width) bit_width = dum1;
  282.       if(dum2 > bit_height) bit_height = dum2;
  283.           return _true_;
  284.         }
  285.       } else {
  286.         load_fail = _true_;
  287.         fprintf(stderr, "%s: Cannot find '%s/%s', trying alternate.\n",
  288.                 progname, bitpath, fname);
  289.       }
  290.     } else {
  291.       if(dum1 > bit_width) bit_width = dum1;
  292.       if(dum2 > bit_height) bit_height = dum2;
  293.       return _true_;
  294.     }
  295.   }
  296.   if(!bitpath || !*bitpath || load_fail) {
  297.     sprintf(buf, "%s/%s", BITPATH, fname);
  298.     if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  299.        BitmapSuccess) {
  300.       if(altname && *altname) {
  301.         fprintf(stderr, "%s: Cannot find '%s', trying alternate.\n",
  302.                 progname, fname);
  303.         sprintf(buf, "%s/%s", BITPATH, fname);
  304.         if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  305.            BitmapSuccess) {
  306.           fprintf(stderr, "%s: Cannot find '%s'!\n", progname, altname);
  307.           return _false_;
  308.         } else {
  309.       if(dum1 > bit_width) bit_width = dum1;
  310.       if(dum2 > bit_height) bit_height = dum2;
  311.           return _true_;
  312.     }
  313.       } else {
  314.         fprintf(stderr, "%s: Cannot find '%s'!\n", progname, fname);
  315.         return _false_;
  316.       }
  317.     } else {
  318.       if(dum1 > bit_width) bit_width = dum1;
  319.       if(dum2 > bit_height) bit_height = dum2;
  320.       return _true_;
  321.     }
  322.   }
  323. }
  324.  
  325. /* loads all the bitmaps in.. if any fail, it returns E_NOBITMAP up a level
  326.  * so the program can report the error to the user.  It tries to load in the
  327.  * alternates as well.
  328.  */
  329. short LoadBitmaps(void)
  330. {
  331.   register int i;
  332.  
  333.   if(!LoadOneBitmap("man.xbm", NULL, &man)) return E_NOBITMAP;
  334.   if(!LoadOneBitmap("saveman.xbm", "man.xbm", &saveman)) return E_NOBITMAP;
  335.   if(!LoadOneBitmap("object.xbm", NULL, &object)) return E_NOBITMAP;
  336.   if(!LoadOneBitmap("treasure.xbm", NULL, &treasure)) return E_NOBITMAP;
  337.   if(!LoadOneBitmap("goal.xbm", NULL, &goal)) return E_NOBITMAP;
  338.   if(!LoadOneBitmap("floor.xbm", NULL, &floor)) return E_NOBITMAP;
  339.  
  340.   if(optwalls) {
  341.     for(i = 0; i < NUM_WALLS; i++) {
  342.       if(!LoadOneBitmap(wallname[i], "wall.xbm", &walls[i])) return E_NOBITMAP;
  343.     }
  344.   } else {
  345.     if(!LoadOneBitmap("wall.xbm", NULL, &walls[0])) return E_NOBITMAP;
  346.   }
  347.   return 0;
  348. }
  349.  
  350. /* create and draw all the help windows in.  This is not wholly fullproff with
  351.  * the variable size bitmap code yet, as the constants to place things on the
  352.  * screen, are just that, constants.  This could most likley be reworked.
  353.  */
  354. void MakeHelpWindows(void)
  355. {
  356.   register int i;
  357.   char *title =
  358.     "    Sokoban  --  X version by Joseph L. Traub  --  Help page %d";
  359.   char *next =
  360.      "     Press Enter to exit  --   Any other key for next page.";
  361.  
  362.   for(i = 0; i < HELP_PAGES; i++) {
  363.     XFillRectangle(dpy, help[i], drgc, 0, 0, HELP_W, HELP_H);
  364.     sprintf(buf, title, (i+1));
  365.     XDrawImageString(dpy, help[i], gc, 0, 11, buf, strlen(buf));
  366.     XDrawLine(dpy, help[i], gc, 0, 17, HELP_W, 17);
  367.     XDrawLine(dpy, help[i], gc, 0, HELP_H-20, HELP_W, HELP_H-20);
  368.     XDrawImageString(dpy, help[i], gc, 2, HELP_H-7, next, strlen(next));
  369.   }
  370.   for(i = 0; help_pages[i].textline != NULL; i++) {
  371.     XDrawImageString(dpy,help[help_pages[i].page], gc,
  372.                      help_pages[i].xpos * (finfo->max_bounds.width),
  373.                      help_pages[i].ypos, help_pages[i].textline,
  374.                      strlen(help_pages[i].textline));
  375.   }
  376.   XCopyPlane(dpy, man, help[0], gc, 0, 0, bit_width, bit_height, 180, 360, 1);
  377.   XCopyPlane(dpy, goal, help[0], gc, 0, 0, bit_width, bit_height, 270, 360, 1);
  378.   XCopyPlane(dpy, walls[0], help[0], gc, 0, 0, bit_width, bit_height,
  379.          369, 360, 1);
  380.   XCopyPlane(dpy, object, help[0], gc, 0, 0, bit_width, bit_height,
  381.          477, 360, 1);
  382.   XCopyPlane(dpy, treasure, help[0], gc, 0, 0, bit_width, bit_height,
  383.          270, 400, 1);
  384.   XCopyPlane(dpy, saveman, help[0], gc, 0, 0, bit_width, bit_height,
  385.          477, 400, 1);
  386. }
  387.  
  388. /* wipe out the entire contents of the screen */
  389. void ClearScreen(void)
  390. {
  391.   register int i,j;
  392.  
  393.   XFillRectangle(dpy, work, drgc, 0, 0, width, height);
  394.   for(i = 0; i < MAXROW; i++)
  395.     for(j = 0; j < MAXCOL; j++)
  396.       XCopyPlane(dpy, floor, work, gc, 0, 0, bit_width, bit_height,
  397.                  j*bit_width, i*bit_height, 1);
  398.   XDrawLine(dpy, work, gc, 0, bit_height*MAXROW, bit_width*MAXCOL,
  399.             bit_height*MAXROW);
  400. }
  401.  
  402. /* redisplay the current screen.. Has to handle the help screens if one
  403.  * is currently active..  Copys the correct bitmaps onto the window.
  404.  */
  405. void RedisplayScreen(void)
  406. {
  407.   if(hlpscrn == -1)
  408.     XCopyArea(dpy, work, win, gc, 0, 0, width, height, 0, 0);
  409.   else
  410.     XCopyArea(dpy, help[hlpscrn], win, gc, 0, 0, HELP_W, HELP_H, 0, 0);
  411.   XFlush(dpy);
  412. }
  413.  
  414. /* Draws all the neat little pictures and text onto the working pixmap
  415.  * so that RedisplayScreen is happy.
  416.  */
  417. void ShowScreen(void)
  418. {
  419.   register int i,j;
  420.  
  421.   for(i = 0; i < rows; i++)
  422.     for(j = 0; j < cols && map[i][j] != NULL; j++)
  423.       MapChar(map[i][j], i, j);
  424.   DisplayLevel();
  425.   DisplayPackets();
  426.   DisplaySave();
  427.   DisplayMoves();
  428.   DisplayPushes();
  429.   DisplayHelp();
  430.   RedisplayScreen();
  431. }
  432.  
  433. /* Draws a single pixmap, translating from the character map to the pixmap
  434.  * rendition.
  435.  */
  436. void MapChar(char c, int i, int j)
  437. {
  438.   Pixmap this;
  439.  
  440.   this = GetObjectPixmap(i, j, c); /* i, j are passed so walls can be done */
  441.   XCopyPlane(dpy, this, work, gc, 0, 0, bit_width, bit_height, cX(j), cY(i), 1);
  442. }
  443.  
  444. /* figures out the appropriate pixmap from the internal game representation.
  445.  * Handles fancy walls.
  446.  */
  447. Pixmap GetObjectPixmap(int i, int j, char c)
  448. {
  449.   switch(c) {
  450.     case player: return man;
  451.     case playerstore: return saveman;
  452.     case store: return goal;
  453.     case save: return treasure;
  454.     case packet: return object;
  455.     case wall:
  456.        if(optwalls) return walls[PickWall(i,j)];
  457.        else return walls[0];
  458.     case ground: return floor;
  459.     default: return blank;
  460.   }
  461. }
  462.  
  463. /* returns and index into the fancy walls array. works by assigning a value
  464.  * to each 'position'.. the type of fancy wall is computed based on how
  465.  * many neighboring walls there are.
  466.  */
  467. int PickWall(int i, int j)
  468. {
  469.   int ret = 0;
  470.  
  471.   if(i > 0 && map[i-1][j] == wall) ret += 1;
  472.   if(j < cols && map[i][j+1] == wall) ret += 2;
  473.   if(i < rows && map[i+1][j] == wall) ret += 4;
  474.   if(j > 0 && map[i][j-1] == wall) ret += 8;
  475.   return ret;
  476. }
  477.  
  478. /* Draws a string onto the working pixmap */
  479. void DrawString(int x, int y, char *text)
  480. {
  481.   int x_off, y_off;
  482.  
  483.   x_off = x * finfo->max_bounds.width;
  484.   y_off = y + finfo->ascent;
  485.  
  486.   XDrawImageString(dpy, work, gc, x_off, y_off, text, strlen(text));
  487. }
  488.  
  489. /* The following routines display various 'statusline' stuff (ie moves, pushes,
  490.  * etc) on the screen.  they are called as they are needed to be changed to
  491.  * avoid unneccesary drawing */
  492. void DisplayLevel(void)
  493. {
  494.    sprintf(buf, "Level: %3d", level);
  495.    DrawString(0, STATUSLINE, buf);
  496. }
  497.  
  498. void DisplayPackets(void)
  499. {
  500.    sprintf(buf, "Packets: %3d", packets);
  501.    DrawString(12, STATUSLINE, buf);
  502. }
  503.  
  504. void DisplaySave(void)
  505. {
  506.   sprintf(buf, "Saved: %3d", savepack);
  507.   DrawString(26, STATUSLINE, buf);
  508. }
  509.  
  510. void DisplayMoves(void)
  511. {
  512.   sprintf(buf, "Moves: %5d", moves);
  513.   DrawString(38, STATUSLINE, buf);
  514. }
  515.  
  516. void DisplayPushes(void)
  517. {
  518.   sprintf(buf, "Pushes: %3d", pushes);
  519.   DrawString(52, STATUSLINE, buf);
  520. }
  521.  
  522. void DisplayHelp(void)
  523. {
  524.   DrawString(0, HELPLINE, "Press ? for help.");
  525. }
  526.  
  527. /* Displays the first help page, and flips help pages (one per key press)
  528.  * until a return is pressed.
  529.  */
  530. void ShowHelp(void)
  531. {
  532.   int i = 0;
  533.   Boolean done = _false_;
  534.  
  535.   hlpscrn = 0;
  536.   XCopyArea(dpy, help[i], win, gc, 0, 0, HELP_W, HELP_H, 0, 0);
  537.   XFlush(dpy);
  538.   while(!done) {
  539.     done = WaitForEnter();
  540.     if(done) {
  541.       hlpscrn = -1;
  542.       return;
  543.     } else {
  544.       i = (i+1)%HELP_PAGES;
  545.       hlpscrn = i;
  546.       XCopyArea(dpy, help[i], win, gc, 0, 0, HELP_W, HELP_H, 0, 0);
  547.       XFlush(dpy);
  548.     }
  549.   }
  550. }
  551.  
  552. /* since the 'press ? for help' is ALWAYS displayed, just beep when there is
  553.  * a problem.
  554.  */
  555. void HelpMessage(void)
  556. {
  557.   XBell(dpy, 0);
  558.   RedisplayScreen();
  559. }
  560.