home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / i / iv26_w_3.zip / EXAMPLES / IDRAW / MAPIPAIN.C < prev    next >
C/C++ Source or Header  |  1992-01-21  |  20KB  |  685 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. // $Header: mapipaint.c,v 1.11 89/10/09 14:48:59 linton Exp $
  24. // implements MapIPaint subclasses.
  25.  
  26. #include "ipaint.h"
  27. #include "istring.h"
  28. #include "listibrush.h"
  29. #include "listicolor.h"
  30. #include "listifont.h"
  31. #include "listipattern.h"
  32. #include "mapipaint.h"
  33. #include <InterViews/interactor.h>
  34. #include <iostream.h>
  35.  
  36. // Init creates the list's entries, initializes the number denoting
  37. // the initial entry, and ensures both list and initial are valid.
  38.  
  39. void MapIPaint::Init (BaseList* list, Interactor* i, const char* menu) {
  40.     DefineEntries(list, i, menu);
  41.     DefineInitial(i, menu);
  42.     if (list->Size() == 0) {
  43.     fprintf(stderr, "No entries in %s menu, ", menu);
  44.     fprintf(stderr, "creating a default entry\n");
  45.     list->Append(CreateEntry(nil));
  46.     }
  47.     if (list->Index(initial-1) == nil) {
  48.     fprintf(stderr, "No attribute at %s entry %d, ", menu, initial);
  49.     fprintf(stderr, "setting initial attribute from first entry\n");
  50.     initial = 1;
  51.     }
  52. }
  53.  
  54. // DefineEntries reads predefined or user-defined attributes and
  55. // creates entries in the list from these attributes.  It retrieves
  56. // each attribute using the concatenation of the menu's name and a
  57. // number which increments from 1.  The first undefined or empty
  58. // attribute terminates the menu's definition.
  59.  
  60. void MapIPaint::DefineEntries (BaseList* list, Interactor* i,
  61. const char* menu) {
  62.     char menuproperty[20];
  63.     int num = 1;
  64.     sprintf(menuproperty, "%s%d", menu, num);
  65.  
  66.     const char* attribute = i->GetAttribute(menuproperty);
  67.     while (attribute != nil && strlen(attribute) > 0) {
  68.     BaseNode* entry = CreateEntry(attribute);
  69.     if (entry != nil) {
  70.         list->Append(entry);
  71.     } else {
  72.         fprintf(stderr, "couldn't parse attribute for %s\n", menuproperty);
  73.     }
  74.  
  75.     sprintf(menuproperty, "%s%d", menu, ++num);
  76.     attribute = i->GetAttribute(menuproperty);
  77.     }
  78. }
  79.  
  80. // DefineInitial reads a predefined or user-defined attribute to
  81. // define the number denoting the initial entry.  For example,
  82. // "idraw.initialfont: 2" sets the initial font from the second entry.
  83.  
  84. void MapIPaint::DefineInitial (Interactor* i, const char* menu) {
  85.     char property[20];
  86.     sprintf(property, "initial%s", menu);
  87.  
  88.     const char* def = i->GetAttribute(property);
  89.     char* definition = strdup(def); // some sscanfs write to their format...
  90.     if (sscanf(definition, "%d", &initial) != 1) {
  91.     initial = 2;        // default if we can't parse definition
  92.     fprintf(stderr, "can't parse attribute for %s, ", property);
  93.     fprintf(stderr, "value set to %d\n", initial);
  94.     }
  95.     delete definition;
  96. }
  97.  
  98. // CreateEntry creates and returns an entry containing an attribute
  99. // defined by the given string.  A subclass must implement it.
  100.  
  101. BaseNode* MapIPaint::CreateEntry (const char*) {
  102.     return new BaseNode;
  103. }
  104.  
  105. // Skew comments/code ratio to work around cpp bug
  106. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  107.  
  108. // MapIBrush creates its brushes from predefined or user-defined
  109. // attributes.
  110.  
  111. MapIBrush::MapIBrush (Interactor* i, const char* menu) {
  112.     ibrushlist = new IBrushList;
  113.     Init(ibrushlist, i, menu);
  114. }
  115.  
  116. // ~MapIBrush frees storage allocated for the brushes and the list.
  117.  
  118. MapIBrush::~MapIBrush () {
  119.     for (IBrush* brush = First(); !AtEnd(); brush = Next()) {
  120.     delete brush;
  121.     }
  122.     delete ibrushlist;
  123. }
  124.  
  125. // Implement functions to give readonly access to the list.
  126.  
  127. int MapIBrush::Size () {
  128.     return ibrushlist->Size();
  129. }
  130.  
  131. boolean MapIBrush::AtEnd () {
  132.     return ibrushlist->AtEnd();
  133. }
  134.  
  135. IBrush* MapIBrush::First () {
  136.     return ibrushlist->First()->GetBrush();
  137. }
  138.  
  139. IBrush* MapIBrush::Last () {
  140.     return ibrushlist->Last()->GetBrush();
  141. }
  142.  
  143. IBrush* MapIBrush::Prev () {
  144.     return ibrushlist->Prev()->GetBrush();
  145. }
  146.  
  147. IBrush* MapIBrush::Next () {
  148.     return ibrushlist->Next()->GetBrush();
  149. }
  150.  
  151. IBrush* MapIBrush::GetCur () {
  152.     return ibrushlist->GetCur()->GetBrush();
  153. }
  154.  
  155. IBrush* MapIBrush::Index (int index) {
  156.     return ibrushlist->Index(index)->GetBrush();
  157. }
  158.  
  159. boolean MapIBrush::Find (IBrush* brush) {
  160.     return ibrushlist->Find(brush);
  161. }
  162.  
  163. IBrush* MapIBrush::GetInitial () {
  164.     // remember index = 0-base, initial = 1-base
  165.     return ibrushlist->Index(initial-1)->GetBrush();
  166. }
  167.  
  168. // FindOrAppend checks if the list already has a brush with the same
  169. // attributes as the given attributes.  If so, it returns the brush
  170. // already in the list; otherwise, it creates a new brush, appends it
  171. // to the list, and returns it.
  172.  
  173. IBrush* MapIBrush::FindOrAppend (boolean none, int p, int w, int l, int r) {
  174.     IBrush* brush = nil;
  175.     if (none) {
  176.     for (brush = First(); !AtEnd(); brush = Next()) {
  177.         if (brush->None()) {
  178.         return brush;
  179.         }
  180.     }
  181.     brush = new IBrush;
  182.     } else {
  183.     for (brush = First(); !AtEnd(); brush = Next()) {
  184.         if (!brush->None() &&
  185.         brush->GetLinePattern() == p &&
  186.         brush->Width() == w &&
  187.         brush->LeftArrow() == l &&
  188.         brush->RightArrow() == r)
  189.         {
  190.         return brush;
  191.         }
  192.     }
  193.     brush = new IBrush(p, w, l, r);
  194.     }
  195.  
  196.     ibrushlist->Append(new IBrushNode(brush));
  197.     return brush;
  198. }
  199.  
  200. // CreateEntry returns an entry containing a brush created by parsing
  201. // the given definition or an entry containing a default brush if no
  202. // definition was given.  The definition usually contains two numbers
  203. // and two booleans: a 16-bit hexadecimal number to define the brush's
  204. // pattern, a decimal integer to define the brush's width in pixels,
  205. // either 0 or 1 to determine whether lines start from an arrowhead,
  206. // and either 0 or 1 to determine whether lines end in an arrowhead.
  207. // One definition may contain the string "none" to define the
  208. // nonexistent brush.  I found out sscanf barfs if you put 0x before
  209. // the hexadecimal number so you can't do that.
  210.  
  211. BaseNode* MapIBrush::CreateEntry (const char* def) {
  212.     if (def == nil) {
  213.     def = "ffff 1 0 0";
  214.     }
  215.     char* definition = strdup(def); // some sscanfs write to their format...
  216.  
  217.     BaseNode* entry = nil;
  218.     int p, w;
  219.     boolean l, r;
  220.     boolean none = (definition[0] == 'n' || definition[0] == 'N');
  221.  
  222.     if (none) {
  223.     entry = new IBrushNode(new IBrush);
  224.     } else if (sscanf(definition, "%x %d %d %d", &p, &w, &l, &r) == 4) {
  225.     entry = new IBrushNode(new IBrush(p, w, l, r));
  226.     }
  227.     delete definition;
  228.  
  229.     return entry;
  230. }
  231.  
  232. // MapIColor creates its colors from predefined or user-defined
  233. // attributes.
  234.  
  235. MapIColor::MapIColor (Interactor* i, const char* menu) {
  236.     icolorlist = new IColorList;
  237.     Init(icolorlist, i, menu);
  238. }
  239.  
  240. // ~MapIColor frees storage allocated for the colors and the list.
  241.  
  242. MapIColor::~MapIColor () {
  243.     for (IColor* color = First(); !AtEnd(); color = Next()) {
  244.     delete color;
  245.     }
  246.     delete icolorlist;
  247. }
  248.  
  249. // Implement functions to give readonly access to the list.
  250.  
  251. int MapIColor::Size () {
  252.     return icolorlist->Size();
  253. }
  254.  
  255. boolean MapIColor::AtEnd () {
  256.     return icolorlist->AtEnd();
  257. }
  258.  
  259. IColor* MapIColor::First () {
  260.     return icolorlist->First()->GetColor();
  261. }
  262.  
  263. IColor* MapIColor::Last () {
  264.     return icolorlist->Last()->GetColor();
  265. }
  266.  
  267. IColor* MapIColor::Prev () {
  268.     return icolorlist->Prev()->GetColor();
  269. }
  270.  
  271. IColor* MapIColor::Next () {
  272.     return icolorlist->Next()->GetColor();
  273. }
  274.  
  275. IColor* MapIColor::GetCur () {
  276.     return icolorlist->GetCur()->GetColor();
  277. }
  278.  
  279. IColor* MapIColor::Index (int index) {
  280.     return icolorlist->Index(index)->GetColor();
  281. }
  282.  
  283. boolean MapIColor::Find (IColor* color) {
  284.     return icolorlist->Find(color);
  285. }
  286.  
  287. IColor* MapIColor::GetInitial () {
  288.     // remember index = 0-base, initial = 1-base
  289.     return icolorlist->Index(initial-1)->GetColor();
  290. }
  291.  
  292. // FindOrAppend checks if the list already has a color with the same
  293. // name as the given name.  If so, it returns the color already in the
  294. // list; otherwise, it creates a new color, appends it to the list,
  295. // and returns it.
  296.  
  297. IColor* MapIColor::FindOrAppend (const char* name, int r, int g, int b) {
  298.     IColor* color = nil;
  299.     for (color = First(); !AtEnd(); color = Next()) {
  300.     if (strcmp(color->GetName(), name) == 0) {
  301.         return color;
  302.     }
  303.     }
  304.  
  305.     color = new IColor(name);
  306.     if (!color->Valid()) {
  307.     delete color;
  308.     color = new IColor(r, g, b, name);
  309.     if (!color->Valid()) {
  310.         fprintf(stderr, "invalid color name %s ", name);
  311.         fprintf(stderr, "and intensities %d %d %d, ", r, g, b);
  312.         fprintf(stderr, "substituting black\n");
  313.         delete color;
  314.         color = new IColor(black, name);
  315.     }
  316.     }
  317.     icolorlist->Append(new IColorNode(color));
  318.     return color;
  319. }
  320.  
  321. // CreateEntry returns an entry containing a color created by using
  322. // the given name or an entry containing a default color if no name
  323. // was given.
  324.  
  325. BaseNode* MapIColor::CreateEntry (const char* def) {
  326.     if (def == nil) {
  327.     def = "Black";
  328.     }
  329.     char* definition = strdup(def); // some sscanfs write to their format...
  330.  
  331.     IColor* color = nil;
  332.     char name[100];
  333.     int r = 0, g = 0, b = 0;
  334.  
  335.     if (sscanf(definition, "%s %d %d %d", name, &r, &g, &b) == 4) {
  336.     color = new IColor(r, g, b, name);
  337.     if (!color->Valid()) {
  338.         fprintf(stderr, "invalid intensities %d %d %d, ", r, g, b);
  339.         fprintf(stderr, "using color name %s\n", name);
  340.         delete color;
  341.         color = new IColor(name);
  342.         if (!color->Valid()) {
  343.         fprintf(stderr, "invalid color name %s, ", name);
  344.         fprintf(stderr, "substituting black\n");
  345.         delete color;
  346.         color = new IColor(black, name);
  347.         }
  348.     }
  349.     } else if (sscanf(definition, "%s", name) == 1) {
  350.     color = new IColor(name);
  351.     if (!color->Valid()) {
  352.         fprintf(stderr, "invalid color name %s, ", name);
  353.         fprintf(stderr, "substituting black\n");
  354.         delete color;
  355.         color = new IColor(black, name);
  356.     }
  357.     }
  358.     delete definition;
  359.  
  360.     BaseNode* entry = nil;
  361.     if (color != nil) {
  362.     entry = new IColorNode(color);
  363.     }
  364.     return entry;
  365. }
  366.  
  367. // MapIFont creates its fonts from predefined or user-defined
  368. // attributes.
  369.  
  370. MapIFont::MapIFont (Interactor* i, const char* menu) {
  371.     ifontlist = new IFontList;
  372.     Init(ifontlist, i, menu);
  373. }
  374.  
  375. // ~MapIFont frees storage allocated for the fonts and the list.
  376.  
  377. MapIFont::~MapIFont () {
  378.     for (IFont* font = First(); !AtEnd(); font = Next()) {
  379.     delete font;
  380.     }
  381.     delete ifontlist;
  382. }
  383.  
  384. // Implement functions to give readonly access to the list.
  385.  
  386. int MapIFont::Size () {
  387.     return ifontlist->Size();
  388. }
  389.  
  390. boolean MapIFont::AtEnd () {
  391.     return ifontlist->AtEnd();
  392. }
  393.  
  394. IFont* MapIFont::First () {
  395.     return ifontlist->First()->GetFont();
  396. }
  397.  
  398. IFont* MapIFont::Last () {
  399.     return ifontlist->Last()->GetFont();
  400. }
  401.  
  402. IFont* MapIFont::Prev () {
  403.     return ifontlist->Prev()->GetFont();
  404. }
  405.  
  406. IFont* MapIFont::Next () {
  407.     return ifontlist->Next()->GetFont();
  408. }
  409.  
  410. IFont* MapIFont::GetCur () {
  411.     return ifontlist->GetCur()->GetFont();
  412. }
  413.  
  414. IFont* MapIFont::Index (int index) {
  415.     return ifontlist->Index(index)->GetFont();
  416. }
  417.  
  418. boolean MapIFont::Find (IFont* font) {
  419.     return ifontlist->Find(font);
  420. }
  421.  
  422. IFont* MapIFont::GetInitial () {
  423.     // remember index = 0-base, initial = 1-base
  424.     return ifontlist->Index(initial-1)->GetFont();
  425. }
  426.  
  427. // FindOrAppend checks if the list already has a font with the same
  428. // attributes as the given attributes (except for the name because it
  429. // depends on the window system used).  If so, it returns the font
  430. // already in the list; otherwise, it creates a new font, appends it
  431. // to the list, and returns it.
  432.  
  433. IFont* MapIFont::FindOrAppend (const char* name, const char* pf,
  434. const char* ps) {
  435.     IFont* font = nil;
  436.     for (font = First(); !AtEnd(); font = Next()) {
  437.     if (strcmp(font->GetPrintFont(), pf) == 0
  438.         && strcmp(font->GetPrintSize(), ps) == 0)
  439.     {
  440.         return font;
  441.     }
  442.     }
  443.  
  444.     font = new IFont(name, pf, ps);
  445.     if (!font->Valid()) {
  446.     fprintf(stderr, "invalid font name %s, ", name);
  447.     fprintf(stderr, "substituting stdfont\n");
  448.     delete font;
  449.     font = new IFont("stdfont", pf, ps);
  450.     }
  451.     ifontlist->Append(new IFontNode(font));
  452.     return font;
  453. }
  454.  
  455. // CreateEntry returns an entry containing a font created by parsing
  456. // the given definition or an entry containing a default font if no
  457. // definition was given.  The definition must contain three strings
  458. // separated by whitespace to define a font.  The first string defines
  459. // the font's name, the second string the corresponding print font,
  460. // and the third string the print size.
  461.  
  462. BaseNode* MapIFont::CreateEntry (const char* def) {
  463.     if (def == nil) {
  464.     def = "stdfont Courier 10";
  465.     }
  466.     char* definition = strdup(def); // some sscanfs write to their format...
  467.  
  468.     BaseNode* entry = nil;
  469.     char name[100];
  470.     char pf[100];
  471.     char ps[10];
  472.  
  473.     if (sscanf(definition, "%s %s %s", name, pf, ps) == 3) {
  474.     IFont* font = new IFont(name, pf, ps);
  475.     if (!font->Valid()) {
  476.         fprintf(stderr, "invalid font name %s, ", name);
  477.         fprintf(stderr, "substituting stdfont\n");
  478.         delete font;
  479.         font = new IFont("stdfont", pf, ps);
  480.     }
  481.     entry = new IFontNode(font);
  482.     }
  483.     delete definition;
  484.  
  485.     return entry;
  486. }
  487.  
  488. // MapIPattern creates its patterns from predefined or user-defined
  489. // attributes.
  490.  
  491. MapIPattern::MapIPattern (Interactor* i, const char* menu) {
  492.     ipatternlist = new IPatternList;
  493.     Init(ipatternlist, i, menu);
  494. }
  495.  
  496. // ~MapIPattern frees storage allocated for the patterns and the list.
  497.  
  498. MapIPattern::~MapIPattern () {
  499.     for (IPattern* pattern = First(); !AtEnd(); pattern = Next()) {
  500.     delete pattern;
  501.     }
  502.     delete ipatternlist;
  503. }
  504.  
  505. // Implement functions to give readonly access to the list.
  506.  
  507. int MapIPattern::Size () {
  508.     return ipatternlist->Size();
  509. }
  510.  
  511. boolean MapIPattern::AtEnd () {
  512.     return ipatternlist->AtEnd();
  513. }
  514.  
  515. IPattern* MapIPattern::First () {
  516.     return ipatternlist->First()->GetPattern();
  517. }
  518.  
  519. IPattern* MapIPattern::Last () {
  520.     return ipatternlist->Last()->GetPattern();
  521. }
  522.  
  523. IPattern* MapIPattern::Prev () {
  524.     return ipatternlist->Prev()->GetPattern();
  525. }
  526.  
  527. IPattern* MapIPattern::Next () {
  528.     return ipatternlist->Next()->GetPattern();
  529. }
  530.  
  531. IPattern* MapIPattern::GetCur () {
  532.     return ipatternlist->GetCur()->GetPattern();
  533. }
  534.  
  535. IPattern* MapIPattern::Index (int index) {
  536.     return ipatternlist->Index(index)->GetPattern();
  537. }
  538.  
  539. boolean MapIPattern::Find (IPattern* pattern) {
  540.     return ipatternlist->Find(pattern);
  541. }
  542.  
  543. IPattern* MapIPattern::GetInitial () {
  544.     // remember index = 0-base, initial = 1-base
  545.     return ipatternlist->Index(initial-1)->GetPattern();
  546. }
  547.  
  548. // Skew comments/code ratio to work around cpp bug
  549. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  550.  
  551. // FindOrAppend checks if the list already has a pattern with the same
  552. // attributes as the given attributes.  If so, it returns the pattern
  553. // already in the list; otherwise, it creates a new pattern, appends
  554. // it to the list, and returns it.
  555.  
  556. IPattern* MapIPattern::FindOrAppend (boolean none, float graylevel,
  557. int data[patternHeight], int size) {
  558.     IPattern* pattern = nil;
  559.     if (none) {
  560.     for (pattern = First(); !AtEnd(); pattern = Next()) {
  561.         if (pattern->None()) {
  562.         return pattern;
  563.         }
  564.     }
  565.     pattern = new IPattern;
  566.     } else if (graylevel != -1) {
  567.     for (pattern = First(); !AtEnd(); pattern = Next()) {
  568.         if (pattern->GetGrayLevel() == graylevel) {
  569.         return pattern;
  570.         }
  571.     }
  572.     int shade = CalcBitmap(graylevel);
  573.     pattern = new IPattern(shade, graylevel);
  574.     } else {
  575.     ExpandToFullSize(data, size);
  576.     for (pattern = First(); !AtEnd(); pattern = Next()) {
  577.         if (pattern->GetSize() != 0) {
  578.         const int* cmpdata = pattern->GetData();
  579.         if (memcmp(data, cmpdata, patternHeight * sizeof(int)) == 0) {
  580.             return pattern;
  581.         }
  582.         }
  583.     }
  584.     pattern = new IPattern(data, size);
  585.     }
  586.  
  587.     ipatternlist->Append(new IPatternNode(pattern));
  588.     return pattern;
  589. }
  590.  
  591. // CreateEntry returns an entry containing a pattern created by
  592. // parsing the given definition or an entry containing a default
  593. // pattern if no definition was given.  The definition usually
  594. // contains either one or patternHeight 16-bit hexadecimal numbers to
  595. // define either a 4x4 pattern or a patternWidth x patternHeight
  596. // pattern.  One definition may contain the string "none" to define
  597. // the nonexistent pattern.  I found out sscanf barfs if you put 0x
  598. // before the hexadecimal number so you can't do that.
  599.  
  600. BaseNode* MapIPattern::CreateEntry (const char* def) {
  601.     if (def == nil) {
  602.     def = "0.0";
  603.     }
  604.     char* definition = strdup(def); // some sscanfs write to their format...
  605.  
  606.     BaseNode* entry = nil;
  607.     boolean none = (definition[0] == 'n' || definition[0] == 'N');
  608.  
  609.     if (none) {
  610.     entry = new IPatternNode(new IPattern);
  611.     } else {
  612.     if (strchr(definition, '.') != nil) {
  613.         float graylevel;
  614.  
  615.         if (sscanf(definition, "%f", &graylevel) == 1) {
  616.         int shade = CalcBitmap(graylevel);
  617.         entry = new IPatternNode(new IPattern(shade, graylevel));
  618.         }
  619.     } else {
  620.         istream from(strlen(definition) + 1, definition);
  621.         char buffer[80];
  622.         int data[patternHeight];
  623.  
  624.         for (int i = 0; from >> buffer && i < patternHeight; i++) {
  625.         if (sscanf(buffer, "%x", &data[i]) != 1) {
  626.             break;
  627.         }
  628.         }
  629.  
  630.         if (i == 1 || i == 8 || i == patternHeight) {
  631.         ExpandToFullSize(data, i);
  632.         entry = new IPatternNode(new IPattern(data, i));
  633.         }
  634.     }
  635.     }
  636.     delete definition;
  637.  
  638.     return entry;
  639. }
  640.  
  641. // CalcBitmap calculates a 4x4 bitmap to represent a shade having the
  642. // given gray level.
  643.  
  644. int MapIPattern::CalcBitmap (float graylevel) {
  645.     static const int SHADES = 17;
  646.     static int shades[SHADES] = {
  647.     0xffff, 0xefff, 0xefbf, 0xafbf,
  648.     0xafaf, 0xadaf, 0xada7, 0xa5a7,
  649.     0xa5a5, 0x85a5, 0x8525, 0x0525,
  650.     0x0505, 0x0405, 0x0401, 0x0001,
  651.     0x0000
  652.     };
  653.     return shades[round(graylevel * (SHADES - 1))];
  654. }
  655.  
  656. // ExpandToFullSize expands the bitmap from 4x4 or 8x8 to 16x16.
  657.  
  658. void MapIPattern::ExpandToFullSize (int data[patternHeight], int size) {
  659.     if (size == 1) {
  660.     int seed = data[0];
  661.     for (int i = 0; i < 4; i++) {
  662.         data[i] = (seed & 0xf000) >> 12;
  663.         data[i] |= data[i] << 4;
  664.         data[i] |= data[i] << 8;
  665.         data[i+4] = data[i];
  666.         data[i+8] = data[i];
  667.         data[i+12] = data[i];
  668.         seed <<= 4;
  669.     }
  670.     } else if (size == 8) {
  671.     for (int i = 0; i < 8; i++) {
  672.         data[i] &= 0xff;
  673.         data[i] |= data[i] << 8;
  674.         data[i+8] = data[i];
  675.     }
  676.     } else if (size == patternHeight) {
  677.     const unsigned int patternWidthMask = ~(~0 << patternWidth);
  678.     for (int i = 0; i < patternHeight; i++) {
  679.         data[i] &= patternWidthMask;
  680.     }
  681.     } else {
  682.     fprintf(stderr, "invalid size passed to ExpandToFullSize\n");
  683.     }
  684. }
  685.