diff --git a/CHANGELOG b/CHANGELOG index 9f016d9..e2e772b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,15 +7,44 @@ Ideas for future versions: - Export diagrams to some format which Visio can import - Perhaps change to SVG for objects - Add more objects (eg. broadband router, etc) -- Snap-to-grid feature -- Make size+position matching work for text (currently only works on objects) - Implement a toggle-able traffic flow display (for example, you might click a button and have arrows appear to show all SMTP mail flows) +Version 1.2: +- Implemented copy/paste of objects, text and maps +- Changed background of object box to be light grey instead of black +- Made object box buttons look more 3d +- Fixed crash when adding zero-length text +- Size/position match tool now works on text +- Implemented "rollover" context sensitive help +- Toolbox buttons are now highlighted when the mouse moves over them +- Partially implemented snap-to-grid feature (no toolbox button yet, toggle with 'g') +- Implemented AP_BOTH for lines with arrowheads on both ends +- Implement change object type function (RMB on object tool, or 'm') +- Mouse wheel now scrolls object box +- Added two new vector shapes: + Ellipse + Filled box +- Added new objects: + Person + Truck + Webcam + Camera + Satellite Dish + Satellite + Wireless Router + VPN Concentrator + Generic circle (replaces "blue square") +- Updated CHANGELOG + + + + Version 1.1: - Added rollover help text and highlights - Added object: VPN concentrator - Added dual-head arrows on lines +- Replaced "grey box" object with "VPN concentrator" Version 1.0: - Sub-map list is now scrollable diff --git a/constants.h b/constants.h index 7e298ca..e824cbc 100644 --- a/constants.h +++ b/constants.h @@ -1,4 +1,4 @@ -#define VERSION "1.1" +#define VERSION "1.1a" #define BUFLEN 512 @@ -71,6 +71,8 @@ #define VT_BOX (1) #define VT_DOT (2) #define VT_FILL (3) +#define VT_ELLIPSE (4) +#define VT_FILLBOX (5) #define TRUE (-1) #define FALSE (0) @@ -99,6 +101,7 @@ #define S_REALLYQUIT (21) #define S_FILLCOL (22) #define S_EDITTEXT (23) +#define S_CHANGEOBJECT (24) #define TB_POINTER (0) diff --git a/netmapr.c b/netmapr.c index c9a4b21..6071e68 100644 --- a/netmapr.c +++ b/netmapr.c @@ -36,6 +36,10 @@ SDL_Color grey2 = { 70, 70, 70, 0}; SDL_Color grey3 = { 50, 50, 50, 0}; SDL_Color grey4 = { 30, 30, 30, 0}; +SDL_Color gridhigh = {255, 255, 255, 0}; +SDL_Color gridmiddle = {90, 90, 90, 0}; +SDL_Color gridlow = {50, 50, 50, 0}; + SDL_Cursor *normalmouse; SDL_Cursor *objmouse; SDL_Cursor *textmouse; @@ -59,6 +63,12 @@ int copyfrom = -1; int copymap = -1; int copytype = T_MAP; +int grid = TRUE; +int gridsize = 10; +SDL_Color gridcol = {0, 0, 0, 0 }; + +int matchtype = 0; + int numobjtypes = 0; int numletters = 0; int numbuttons = 0; @@ -199,7 +209,6 @@ int main (int argc, char **argv) { break; } } - } } else if ((event.button.button == SDL_BUTTON_MIDDLE) || ((event.button.button == SDL_BUTTON_LEFT) && (mod & KMOD_CTRL))) { @@ -252,6 +261,27 @@ int main (int argc, char **argv) { } } } + } else if (isonobox(event.button.x, event.button.y)) { + if (event.button.button == SDL_BUTTON_WHEELUP) { + if (obox.pos > 0) { + obox.pos--; + drawobox(); + } + } else if (event.button.button == SDL_BUTTON_WHEELDOWN) { + int fitx,fity,fit; + + /* figure out how many objects we can fit in the box */ + fitx = (obox.width / obox.gridsize); + fity = ((obox.height+3) / obox.gridsize); + fit = fitx * fity; + + /* check if incrementing position is okay or not */ + if (((obox.pos+1)*3 + fit) <= (numobjtypes+2)) { + obox.pos++; + drawobox(); + } + } + } else if (isonobox(event.button.x, event.button.y)) { } break; case SDL_MOUSEBUTTONUP: @@ -307,63 +337,134 @@ int main (int argc, char **argv) { drawmap(); } } else if (state == S_MATCHSIZE) { - o = objat(event.button.x, event.button.y); - if (o == -1) { - changestate(S_NONE); - sprintf(statustext, "Size match mode aborted."); - drawstatusbar(); - } else { - int n; - /* resize selected item to match one which was clicked */ - map[curmap].obj[map[curmap].selecteditem].w = map[curmap].obj[o].w; - map[curmap].obj[map[curmap].selecteditem].h = map[curmap].obj[o].h; - /* adjust offsets on all links to/from object */ - for (n = 0; n < map[curmap].numlinks; n++) { - if (map[curmap].olink[n].srcobj == map[curmap].selecteditem) { - map[curmap].olink[n].srcxoff = (map[curmap].obj[o].w / 2); - map[curmap].olink[n].srcyoff = (map[curmap].obj[o].h / 2); - } - if (map[curmap].olink[n].dstobj == map[curmap].selecteditem) { - map[curmap].olink[n].dstxoff = (map[curmap].obj[o].w / 2); - map[curmap].olink[n].dstyoff = (map[curmap].obj[o].h / 2); + if (matchtype == T_OBJECT) { + o = objat(event.button.x, event.button.y); + if (o == -1) { + changestate(S_NONE); + sprintf(statustext, "Size match mode aborted."); + drawstatusbar(); + } else { + int n; + /* resize selected item to match one which was clicked */ + map[curmap].obj[map[curmap].selecteditem].w = map[curmap].obj[o].w; + map[curmap].obj[map[curmap].selecteditem].h = map[curmap].obj[o].h; + /* adjust offsets on all links to/from object */ + for (n = 0; n < map[curmap].numlinks; n++) { + if (map[curmap].olink[n].srcobj == map[curmap].selecteditem) { + map[curmap].olink[n].srcxoff = (map[curmap].obj[o].w / 2); + map[curmap].olink[n].srcyoff = (map[curmap].obj[o].h / 2); + } + if (map[curmap].olink[n].dstobj == map[curmap].selecteditem) { + map[curmap].olink[n].dstxoff = (map[curmap].obj[o].w / 2); + map[curmap].olink[n].dstyoff = (map[curmap].obj[o].h / 2); + } } + changestate(S_NONE); + sprintf(statustext, "Object #%d resized to match object #%d.",map[curmap].selecteditem,o); + drawmap(); + } + } else if (matchtype == T_TEXT) { + o = textat(event.button.x, event.button.y); + if (o == -1) { + changestate(S_NONE); + sprintf(statustext, "Size match mode aborted."); + drawstatusbar(); + } else { + int tw,th; + /* resize selected text to match one which was clicked */ + map[curmap].textob[map[curmap].selecteditem].h = map[curmap].textob[o].h; + TTF_SizeText(font[map[curmap].textob[o].h], map[curmap].textob[map[curmap].selecteditem].text, &tw,&th); + map[curmap].textob[map[curmap].selecteditem].w = tw; + /* adjust offsets on all links to/from object */ + changestate(S_NONE); + sprintf(statustext, "Text #%d resized to match text #%d.",map[curmap].selecteditem,o); + drawmap(); } - changestate(S_NONE); - sprintf(statustext, "Object #%d resized to match object #%d.",map[curmap].selecteditem,o); - drawmap(); } } else if (state == S_MATCHX) { - o = objat(event.button.x, event.button.y); - if (o == -1) { - changestate(S_NONE); - sprintf(statustext, "X position match mode aborted."); - drawstatusbar(); - } else { - /* move selected item to match one which was clicked */ - /* match middle of objects! */ - map[curmap].obj[map[curmap].selecteditem].x = - (map[curmap].obj[o].x + (map[curmap].obj[o].w/2)) - - - (map[curmap].obj[map[curmap].selecteditem].w/2); - changestate(S_NONE); - sprintf(statustext, "Object #%d X relocated to match object #%d.",map[curmap].selecteditem,o); - drawmap(); + if (matchtype == T_OBJECT) { + o = objat(event.button.x, event.button.y); + if (o == -1) { + changestate(S_NONE); + sprintf(statustext, "X position match mode aborted."); + drawstatusbar(); + } else { + /* move selected item to match one which was clicked */ + /* match middle of objects! */ + map[curmap].obj[map[curmap].selecteditem].x = + (map[curmap].obj[o].x + (map[curmap].obj[o].w/2)) + - + (map[curmap].obj[map[curmap].selecteditem].w/2); + changestate(S_NONE); + sprintf(statustext, "Object #%d X relocated to match object #%d.",map[curmap].selecteditem,o); + drawmap(); + } + } else if (matchtype == T_TEXT) { + o = textat(event.button.x, event.button.y); + if (o == -1) { + changestate(S_NONE); + sprintf(statustext, "X position match mode aborted."); + drawstatusbar(); + } else { + /* move selected item to match one which was clicked */ + /* match middle of text */ + map[curmap].textob[map[curmap].selecteditem].x = + (map[curmap].textob[o].x + (map[curmap].textob[o].w/2)) + - + (map[curmap].textob[map[curmap].selecteditem].w/2); + /* validate */ + if (map[curmap].textob[map[curmap].selecteditem].x < 1) map[curmap].textob[map[curmap].selecteditem].x = 1; + if (map[curmap].textob[map[curmap].selecteditem].x + map[curmap].textob[map[curmap].selecteditem].w > map[curmap].width) map[curmap].textob[map[curmap].selecteditem].x = map[curmap].width - map[curmap].textob[map[curmap].selecteditem].w; + + changestate(S_NONE); + sprintf(statustext, "Text #%d X relocated to match text #%d.",map[curmap].selecteditem,o); + drawmap(); + } } } else if (state == S_MATCHY) { - o = objat(event.button.x, event.button.y); - if (o == -1) { - changestate(S_NONE); - sprintf(statustext, "Y position match mode aborted."); - drawstatusbar(); - } else { - /* move selected item to match one which was clicked */ - map[curmap].obj[map[curmap].selecteditem].y = - (map[curmap].obj[o].y + (map[curmap].obj[o].h / 2)) - - - map[curmap].obj[map[curmap].selecteditem].h/2; - changestate(S_NONE); - sprintf(statustext, "Object #%d Y relocated to match object #%d.",map[curmap].selecteditem,o); - drawmap(); + if (matchtype == T_OBJECT) { + o = objat(event.button.x, event.button.y); + if (o == -1) { + changestate(S_NONE); + sprintf(statustext, "Y position match mode aborted."); + drawstatusbar(); + } else { + /* move selected item to match one which was clicked */ + map[curmap].obj[map[curmap].selecteditem].y = + (map[curmap].obj[o].y + (map[curmap].obj[o].h / 2)) + - + map[curmap].obj[map[curmap].selecteditem].h/2; + changestate(S_NONE); + sprintf(statustext, "Object #%d Y relocated to match object #%d.",map[curmap].selecteditem,o); + drawmap(); + } + } else if (matchtype == T_TEXT) { + o = textat(event.button.x, event.button.y); + if (o == -1) { + changestate(S_NONE); + sprintf(statustext, "Y position match mode aborted."); + drawstatusbar(); + } else { + int curh, copyh; + + curh = TTF_FontHeight(font[map[curmap].textob[map[curmap].selecteditem].h]); + copyh = TTF_FontHeight(font[map[curmap].textob[o].h]); + /* move selected item to match one which was clicked */ + map[curmap].textob[map[curmap].selecteditem].y = + (map[curmap].textob[o].y + (copyh / 2)) + - + (curh / 2); + + + /* validate */ + if (map[curmap].textob[map[curmap].selecteditem].y < 1) map[curmap].textob[map[curmap].selecteditem].y = 1; + if (map[curmap].textob[map[curmap].selecteditem].y + curh > map[curmap].height) map[curmap].textob[map[curmap].selecteditem].y = map[curmap].height - curh - 1; + + /* match middle of text */ + changestate(S_NONE); + sprintf(statustext, "Text #%d Y relocated to match text #%d.",map[curmap].selecteditem,o); + drawmap(); + } } } else if (state == S_OBJMOVING) { /* has mouse actually moved? */ @@ -537,11 +638,30 @@ int main (int argc, char **argv) { } else if (isonobox(event.button.x, event.button.y)) { int tempx,tempy; - tempx = (event.button.x - obox.x) / obox.gridsize; - tempy = (event.button.y - obox.y) / obox.gridsize; - map[curmap].selectedtype = tempy*obox.gridrowlen + tempx + (obox.pos*3); - if (map[curmap].selectedtype >= numobjtypes) map[curmap].selectedtype = numobjtypes-1; - sprintf(statustext,"Object type '%s' selected.\n",objtype[map[curmap].selectedtype].name); + tempx = (event.button.x - obox.x) / (obox.gridsize+3); + tempy = (event.button.y - obox.y) / (obox.gridsize+3); + if (state == S_CHANGEOBJECT) { + int seltype; + seltype = tempy*obox.gridrowlen + tempx + (obox.pos*3); + if (seltype >= numobjtypes) seltype = numobjtypes-1; + if (map[curmap].selecteditemtype != T_OBJECT) { + sprintf(statustext, "Must select an object to change the type of!"); + drawstatusbar(); + } else if (map[curmap].selecteditem == -1) { + sprintf(statustext, "Must select an object to change the type of!"); + drawstatusbar(); + } else { + sprintf(statustext, "Object #%d type changed from '%s' to '%s'.", map[curmap].selecteditem, objtype[map[curmap].obj[map[curmap].selecteditem].type].name, objtype[seltype].name); + map[curmap].obj[map[curmap].selecteditem].type = seltype; + state = S_NONE; + drawtoolbox(); + drawmap(); + } + } else { + map[curmap].selectedtype = tempy*obox.gridrowlen + tempx + (obox.pos*3); + if (map[curmap].selectedtype >= numobjtypes) map[curmap].selectedtype = numobjtypes-1; + sprintf(statustext,"Object type '%s' selected.\n",objtype[map[curmap].selectedtype].name); + } drawstatusbar(); drawobox(); @@ -669,17 +789,25 @@ int main (int argc, char **argv) { break; case TB_MATCHSIZE: if (map[curmap].selecteditem != -1) { - if (map[curmap].selecteditemtype == T_OBJECT) { - changestate(S_MATCHSIZE); - drawmap(); + switch (map[curmap].selecteditemtype) { + case T_OBJECT: + case T_TEXT: + matchtype = map[curmap].selecteditemtype; + changestate(S_MATCHSIZE); + drawmap(); + break; } } break; case TB_MATCHX: if (map[curmap].selecteditem != -1) { - if (map[curmap].selecteditemtype == T_OBJECT) { - changestate(S_MATCHX); - drawmap(); + switch (map[curmap].selecteditemtype) { + case T_OBJECT: + case T_TEXT: + matchtype = map[curmap].selecteditemtype; + changestate(S_MATCHX); + drawmap(); + break; } } break; @@ -885,6 +1013,17 @@ int main (int argc, char **argv) { boxy = toolbox.y + (tempy*(toolbox.gridsize+3)); selection = tempy*toolbox.gridrowlen + tempx; switch (selection) { + case TB_ADDOBJ: + if (map[curmap].selecteditemtype != T_OBJECT) { + sprintf(statustext, "Must select an object to change the type of first!"); + drawstatusbar(); + } else if (map[curmap].selecteditem == -1) { + sprintf(statustext, "Must select an object to change the type of first!"); + drawstatusbar(); + } else { + changestate(S_CHANGEOBJECT); + } + break; case TB_FGCOL: changestate(S_FGCOL); drawmap(); @@ -1022,7 +1161,7 @@ int main (int argc, char **argv) { drawstatusbar(); break; case TB_ADDOBJ: - sprintf(statustext, "LMB = Add an object to the map"); + sprintf(statustext, "LMB = Add an object to the map, RMB = Change object type"); drawstatusbar(); break; case TB_ADDTEXT: @@ -1048,15 +1187,15 @@ int main (int argc, char **argv) { drawstatusbar(); break; case TB_MATCHSIZE: - sprintf(statustext, "LMB = Match size of current selection to next object clicked"); + sprintf(statustext, "LMB = Match size of current selection to next item clicked"); drawstatusbar(); break; case TB_MATCHX: - sprintf(statustext, "LMB = Match horizontal position of currently selected object to next object clicked"); + sprintf(statustext, "LMB = Match horizontal position of currently selected item to next item clicked"); drawstatusbar(); break; case TB_MATCHY: - sprintf(statustext, "LMB = Match vertical position of currently selected object to next object clicked"); + sprintf(statustext, "LMB = Match vertical position of currently selected item to next item clicked"); drawstatusbar(); break; case TB_DRILLDOWN: @@ -1217,6 +1356,11 @@ int main (int argc, char **argv) { changestate(S_ADDOBJ); } } + if (c == 'm') { /* modify object type */ + if (state == S_NONE) { + changestate(S_CHANGEOBJECT); + } + } if (c == 't') { /* add text */ if (state == S_NONE) { changestate(S_ADDTEXT); @@ -1271,28 +1415,50 @@ int main (int argc, char **argv) { } if (c == 'x') { if (map[curmap].selecteditem != -1) { - if (map[curmap].selecteditemtype == T_OBJECT) { - changestate(S_MATCHX); - drawmap(); + switch (map[curmap].selecteditemtype) { + case T_OBJECT: + case T_TEXT: + matchtype = map[curmap].selecteditemtype; + changestate(S_MATCHX); + drawmap(); + break; } } } if (c == 'y') { if (map[curmap].selecteditem != -1) { - if (map[curmap].selecteditemtype == T_OBJECT) { - changestate(S_MATCHY); - drawmap(); + switch (map[curmap].selecteditemtype) { + case T_OBJECT: + case T_TEXT: + matchtype = map[curmap].selecteditemtype; + changestate(S_MATCHY); + drawmap(); + break; } } } if (c == 'b') { if (map[curmap].selecteditem != -1) { - if (map[curmap].selecteditemtype == T_OBJECT) { - changestate(S_MATCHSIZE); - drawmap(); + switch (map[curmap].selecteditemtype) { + case T_OBJECT: + case T_TEXT: + matchtype = map[curmap].selecteditemtype; + changestate(S_MATCHSIZE); + drawmap(); + break; } } } + if (c == 'g') { /* toggle gridsize */ + if (grid) { + grid = FALSE; + strcpy(statustext, "Grid mode disabled."); + } else { + grid = TRUE; + strcpy(statustext, "Grid mode enabled."); + } + drawmap(); + } if (c == 'c') { /* copy */ if (map[curmap].selecteditem == -1) { /* copy entire map */ @@ -1391,6 +1557,52 @@ int main (int argc, char **argv) { copytype = -1; copymap = -1; + drawmap(); + } else if (copytype == T_OBJECT) { + int newtype, newx, newy, n; + int newnum; + + newtype = map[copymap].obj[copyfrom].type; + newx = map[copymap].obj[copyfrom].x + 10; + newy = map[copymap].obj[copyfrom].y + 10; + + /* TODO: validate new position */ + + createobject(newtype, newx,newy); + + /* match size, colour, etc */ + newnum = map[curmap].numobjects-1; + map[curmap].obj[newnum].w = map[copymap].obj[copyfrom].w; + map[curmap].obj[newnum].h = map[copymap].obj[copyfrom].h; + map[curmap].obj[newnum].fillcol = map[copymap].obj[copyfrom].fillcol; + + /* copy over all attached text */ + + for (n = 0; n < map[copymap].numtext; n++) { + if (map[copymap].textob[n].anchor == copyfrom) { + int tnum; + + /* duplicate it */ + startx = map[copymap].textob[n].x + map[curmap].obj[newnum].x; + starty = map[copymap].textob[n].y + map[curmap].obj[newnum].y; + textanchor = newnum; + strcpy(text, map[copymap].textob[n].text); + endtext(); + + /* update text size */ + tnum = map[curmap].numtext-1; + + map[curmap].textob[tnum].h = map[copymap].textob[n].h; + map[curmap].textob[tnum].w = map[copymap].textob[n].w; + map[curmap].textob[tnum].c = map[copymap].textob[n].c; + } + } + + /* select new object */ + map[curmap].selecteditemtype = T_OBJECT; + map[curmap].selecteditem = newnum; + + sprintf(statustext,"Object pasted at %d,%d.",newx,newy); drawmap(); } else { sprintf(statustext,"Error: No copy source selected!"); @@ -1591,6 +1803,9 @@ void changestate(int newstate) { case S_ADDOBJ: sprintf(statustext,"Object creation mode enabled.\n"); fflush(stdout); break; + case S_CHANGEOBJECT: + sprintf(statustext,"Object type modification mode enabled.\n"); fflush(stdout); + break; case S_ADDTEXT: sprintf(statustext,"Text creation mode entered.\n"); fflush(stdout); break; @@ -1604,10 +1819,10 @@ void changestate(int newstate) { sprintf(statustext,"Size-matching mode entered - select object to copy size from...\n"); fflush(stdout); break; case S_MATCHX: - sprintf(statustext,"X-matching mode entered - select object to align with...\n"); fflush(stdout); + sprintf(statustext,"X-matching mode entered - select item to align with...\n"); fflush(stdout); break; case S_MATCHY: - sprintf(statustext,"Y-matching mode entered - select object to align with...\n"); fflush(stdout); + sprintf(statustext,"Y-matching mode entered - select item to align with...\n"); fflush(stdout); break; case S_MAPNAMING: sprintf(statustext,"Map rename mode entered.\n"); fflush(stdout); @@ -1644,6 +1859,13 @@ int createobject(int type, int x, int y) { if ((y + map[curmap].obj[map[curmap].numobjects].h) >= map[curmap].height) { y = map[curmap].height - map[curmap].obj[map[curmap].numobjects].h - 1; } + + /* adjust for grid */ + if (grid) { + x = x - (x % gridsize); + y = y - (y % gridsize); + } + map[curmap].obj[map[curmap].numobjects].x = x; map[curmap].obj[map[curmap].numobjects].y = y; @@ -2145,6 +2367,84 @@ void drawbox(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c) { drawline(screen,x2,y1,x2,y2,c,1); } +void drawfillbox(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c) { + int x; + + if (x1 < x2) { + for (x = x1; x <= x2; x++) { + drawline(screen, x, y1, x,y2,c,1); + } + } else { + for (x = x1; x >= x2; x--) { + drawline(screen, x, y1, x,y2,c,1); + } + } +} + +void drawellipsepoints(SDL_Surface *screen, int x1, int y1, int x, int y, SDL_Color c) { + drawpixel(screen, x1 + x, y1 + y, c); + drawpixel(screen, x1 - x, y1 + y, c); + drawpixel(screen, x1 - x, y1 - y, c); + drawpixel(screen, x1 + x, y1 - y, c); +} + +void drawellipse(SDL_Surface *screen, int x1, int y1, int xr, int yr, SDL_Color c) { + double x,y; + double xc,yc; + double ee; + double twoas, twobs; + double stoppingx,stoppingy; + + twoas = 2 * xr * xr; + twobs = 2 * yr * yr; + + /* first set */ + x = xr; + y = 0; + xc = yr * yr * (1 - 2*xr); + yc = xr * xr; + ee = 0; + stoppingx = twobs * xr; + stoppingy = 0; + while (stoppingx >= stoppingy) { + drawellipsepoints(screen, x1, y1, x,y, c); + y++; + stoppingy += twoas; + ee += yc; + yc += twoas; + if ((2*ee + xc) > 0) { + x--; + stoppingx -= twobs; + ee += xc; + xc += twobs; + } + } + + + /* second set */ + x = 0; + y = yr; + xc = yr * yr; + yc = xr * xr * (1 - 2*yr); + ee = 0; + stoppingx = 0; + stoppingy = twoas * yr; + while (stoppingx <= stoppingy) { + drawellipsepoints(screen, x1, y1, x,y, c); + x++; + stoppingx += twobs; + ee += xc; + xc += twobs; + if ((2*ee + yc) > 0) { + y--; + stoppingy -= twoas; + ee += yc; + yc += twoas; + } + } + +} + void drawcolorchart(SDL_Surface *dest) { int x,y; int i; @@ -2511,6 +2811,16 @@ void drawmap(void) { fillcol = SDL_MapRGB(buffer->format, map[curmap].bgcol.r,map[curmap].bgcol.g,map[curmap].bgcol.b); SDL_FillRect(buffer, NULL, fillcol); + /* draw grid if required */ + if (grid) { + int x,y; + for (y = 0; y < map[curmap].height; y += gridsize) { + for (x = 0; x < map[curmap].width; x += gridsize) { + drawpixel(buffer, x, y, gridcol); + } + } + } + if (testing) { printf("DRAWING THINGS \n"); fflush(stdout); } @@ -2920,6 +3230,8 @@ void drawmapbox(void) { SDL_Rect ar; /* off the bottom of the page - replace previous item with an arrow */ + printf("showing arrow\n"); fflush(stdout); + y = y - th - 1; /* go back one line */ /* clear previous text */ ar.x = x; @@ -3025,7 +3337,7 @@ void drawobox(void) { area.x = obox.x; area.y = obox.y; area.w = obox.width; - area.h = obox.height+3; + area.h = obox.height+4; SDL_FillRect(screen, &area, fillcol); x = obox.x; @@ -3044,14 +3356,14 @@ void drawobox(void) { if ((y + obox.gridsize) >= (map[curmap].height)) { break; } - y += obox.gridsize; + y += obox.gridsize + 3; } /* draw box */ - outlinecol = obox.gridcol; - drawline(screen, x, y,x+obox.gridsize,y,outlinecol,1); /* top */ - drawline(screen, x, y+obox.gridsize,x+obox.gridsize,y+obox.gridsize,outlinecol,1); /* bottom */ - drawline(screen, x, y,x,y+obox.gridsize,outlinecol,1); /* left */ - drawline(screen, x+obox.gridsize, y,x+obox.gridsize,y+obox.gridsize,outlinecol,1); /* right */ + //outlinecol = obox.gridcol; + drawline(screen, x, y,x+obox.gridsize,y,gridhigh,1); /* top */ + drawline(screen, x, y+obox.gridsize,x+obox.gridsize,y+obox.gridsize,gridlow,1); /* bottom */ + drawline(screen, x, y,x,y+obox.gridsize,gridhigh,1); /* left */ + drawline(screen, x+obox.gridsize, y,x+obox.gridsize,y+obox.gridsize,gridlow,1); /* right */ /* fill it */ fillcol = SDL_MapRGB(screen->format, obox.gridbgcol.r,obox.gridbgcol.g,obox.gridbgcol.b); area.x = x+1; @@ -3070,7 +3382,7 @@ void drawobox(void) { //SDL_UpdateRect(screen, x, y, obox.gridsize+1,obox.gridsize+1); - x += obox.gridsize; + x += obox.gridsize+3; } @@ -3079,8 +3391,8 @@ void drawobox(void) { outlinepos = map[curmap].selectedtype - (obox.pos*3); if ((outlinepos >= 0) && (outlinepos < fit)) { - y = ((map[curmap].selectedtype - (obox.pos*3)) / obox.gridrowlen) * obox.gridsize + obox.y; - x = ((map[curmap].selectedtype - (obox.pos*3)) % obox.gridrowlen) * obox.gridsize + obox.x; + y = ((map[curmap].selectedtype - (obox.pos*3)) / obox.gridrowlen) * (obox.gridsize+3) + obox.y; + x = ((map[curmap].selectedtype - (obox.pos*3)) % obox.gridrowlen) * (obox.gridsize+3) + obox.x; drawline(screen, x, y,x+obox.gridsize,y,outlinecol,1); /* top */ drawline(screen, x, y+obox.gridsize,x+obox.gridsize,y+obox.gridsize,outlinecol,1); /* bottom */ @@ -3090,7 +3402,7 @@ void drawobox(void) { //SDL_UpdateRect(screen, x, y, obox.gridsize+1,obox.gridsize+1); - SDL_UpdateRect(screen,obox.x, obox.y, obox.width-1, obox.height+3); + SDL_UpdateRect(screen,obox.x, obox.y, obox.width-1, obox.height+5); } void drawscreen(void){ @@ -3162,9 +3474,6 @@ void drawtoolbox(void) { Uint32 fillcol; Uint32 bcol; int z; - SDL_Color gridhigh = {255, 255, 255, 0}; - SDL_Color gridmiddle = {90, 90, 90, 0}; - SDL_Color gridlow = {50, 50, 50, 0}; dontpaste = TRUE; @@ -3252,25 +3561,30 @@ void drawtoolbox(void) { } /* draw selectors */ - if (state == S_NONE) drawtoolboxselector(TB_POINTER); - if (state == S_ADDOBJ) drawtoolboxselector(TB_ADDOBJ); - if (state == S_ADDTEXT) drawtoolboxselector(TB_ADDTEXT); - if (state == S_SAVING) drawtoolboxselector(TB_SAVE); - if (state == S_LOADING) drawtoolboxselector(TB_LOAD); - if (state == S_MATCHSIZE) drawtoolboxselector(TB_MATCHSIZE); - if (state == S_MATCHX) drawtoolboxselector(TB_MATCHX); - if (state == S_MATCHY) drawtoolboxselector(TB_MATCHY); - if (state == S_CREATETELE) drawtoolboxselector(TB_CREATETELE); + if (state == S_NONE) drawtoolboxselector(TB_POINTER, 0); + if (state == S_ADDOBJ) drawtoolboxselector(TB_ADDOBJ, 0); + if (state == S_CHANGEOBJECT) drawtoolboxselector(TB_ADDOBJ, 1); + if (state == S_ADDTEXT) drawtoolboxselector(TB_ADDTEXT, 0); + if (state == S_SAVING) drawtoolboxselector(TB_SAVE, 0); + if (state == S_LOADING) drawtoolboxselector(TB_LOAD, 0); + if (state == S_MATCHSIZE) drawtoolboxselector(TB_MATCHSIZE, 0); + if (state == S_MATCHX) drawtoolboxselector(TB_MATCHX, 0); + if (state == S_MATCHY) drawtoolboxselector(TB_MATCHY, 0); + if (state == S_CREATETELE) drawtoolboxselector(TB_CREATETELE, 0); } -void drawtoolboxselector(int buttonid) { +void drawtoolboxselector(int buttonid, int altcolour) { SDL_Color outlinecol; int x,y; /* draw selector */ - outlinecol = red; + if (altcolour) { + outlinecol = blue; + } else { + outlinecol = red; + } y = (buttonid / toolbox.gridrowlen) * (toolbox.gridsize+3) + toolbox.y; x = (buttonid % toolbox.gridrowlen) * (toolbox.gridsize+3) + toolbox.x; @@ -3336,6 +3650,12 @@ void drawvector(SDL_Surface *dest, vectorimg_t *vimg, int x, int y, int w, int h case VT_BOX: drawbox(dest,realx1,realy1, realx2,realy2,linecol); break; + case VT_FILLBOX: + drawfillbox(dest,realx1,realy1, realx2,realy2, linecol); + break; + case VT_ELLIPSE: + drawellipse(dest,realx1,realy1, realx2,realy2, linecol); + break; case VT_FILL: floodfill(dest,realx1,realy1, fillcol); break; @@ -3378,6 +3698,18 @@ int endtext(void) { map[curmap].textob[map[curmap].numtext].y = starty - map[curmap].obj[textanchor].y; } + /* adjust for grid */ + if (grid) { + int m; + + m = map[curmap].textob[map[curmap].numtext].x; + map[curmap].textob[map[curmap].numtext].x -= (m % gridsize); + + m = map[curmap].textob[map[curmap].numtext].y; + map[curmap].textob[map[curmap].numtext].y -= (m % gridsize); + } + + /* calculate width */ TTF_SizeText(font[DEFTEXTH], text, &tw,&th); @@ -3465,6 +3797,7 @@ int endtextmove(int x, int y) { tyoff = map[curmap].obj[map[curmap].textob[map[curmap].curtext].anchor].y; } + /* check position */ if ((map[curmap].textob[map[curmap].curtext].x + txoff + x - startx) >= (map[curmap].width - map[curmap].textob[map[curmap].curtext].w)) { return -1; @@ -3479,6 +3812,17 @@ int endtextmove(int x, int y) { return -1; } + /* adjust for grid */ + if (grid) { + int m; + + m = map[curmap].textob[map[curmap].curtext].x + x - startx; + x = x - (m % gridsize); + + m = map[curmap].textob[map[curmap].curtext].y + y - starty; + y = y - (m % gridsize); + } + map[curmap].textob[map[curmap].curtext].x += (x - startx); map[curmap].textob[map[curmap].curtext].y += (y - starty); @@ -4372,6 +4716,60 @@ screen->format->Amask); printf("Too many vectors on line %d of objects file.\n",line); exit(1); } + } else if (!strcmp(p, "fillbox")) { + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + x1 = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + y1 = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + x2 = atoi(p); /* x2 is actually the x radius */ + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + y2 = atoi(p); /* y2 is actually the y radius */ + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + c.r = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + c.g = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + c.b = atoi(p); + + if (addvector(&objtype[numobjtypes].vimg,VT_FILLBOX,x1,y1,x2,y2,&c)) { + printf("Too many vectors on line %d of objects file.\n",line); + exit(1); + } + } else if (!strcmp(p, "circle")) { + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + x1 = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + y1 = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + x2 = atoi(p); /* x2 is actually the x radius */ + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + y2 = atoi(p); /* y2 is actually the y radius */ + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + c.r = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + c.g = atoi(p); + p = strtok(NULL, " "); + if (p == NULL) { printf("Missing token on line #%d of objects file.\n",line); exit(1); } + c.b = atoi(p); + + if (addvector(&objtype[numobjtypes].vimg,VT_ELLIPSE,x1,y1,x2,y2,&c)) { + printf("Too many vectors on line %d of objects file.\n",line); + exit(1); + } } else if (!strcmp(p, "end")) { state = 0; numobjtypes++; @@ -4960,12 +5358,11 @@ void initvars(void) { curmap = 0; obox.x = map[curmap].width + 1; - obox.y = (map[curmap].height / 4) * 3; + obox.y = ((map[curmap].height / 4) * 3) - 10; obox.width = SIDEBARW; obox.height = map[curmap].height - obox.y; - obox.pos = 0; obox.bgcol = black; - obox.gridbgcol = grey4; + obox.gridbgcol = grey; obox.gridcol = grey; obox.gridsize = 30; obox.gridrowlen = SIDEBARW / obox.gridsize; @@ -4975,7 +5372,6 @@ void initvars(void) { toolbox.width = SIDEBARW; toolbox.height = map[curmap].height / 3; toolbox.bgcol = black; - //toolbox.gridcol = grey3; toolbox.gridsize = 30; toolbox.gridrowlen = SIDEBARW / toolbox.gridsize; @@ -5719,6 +6115,12 @@ int updatelinkpointshadow(int x, int y) { SDL_UpdateRect(screen, area.x, area.y, area.w, area.h); + /* adjust for grid */ + if (grid) { + x = x - (x % gridsize); + y = y - (y % gridsize); + } + /* copy background */ linex1 = x - (LINESELHANDLESIZE / 2); liney1 = y - (LINESELHANDLESIZE / 2); @@ -5762,6 +6164,12 @@ int updatemoveshadow(int x, int y) { y += yoff; + /* adjust for grid */ + if (grid) { + x = x - (x % gridsize); + y = y - (y % gridsize); + } + /* replace old bg */ area.x = bgx; area.y = bgy; @@ -5769,6 +6177,8 @@ int updatemoveshadow(int x, int y) { area.h = bgh; SDL_BlitSurface(bg, 0, screen, &area); SDL_UpdateRect(screen, area.x, area.y, area.w, area.h); + + /* copy current bg */ area.x = x; area.y = y; @@ -5779,6 +6189,8 @@ int updatemoveshadow(int x, int y) { bgy = area.y; bgw = area.w; bgh = area.h; + + /* draw box */ if ((x > 0) && (y > 0) && (x+map[curmap].obj[map[curmap].curobj].w-1 < map[curmap].width) && (y+map[curmap].obj[map[curmap].curobj].h-1 < map[curmap].height)) { drawline(screen,x,y,x+map[curmap].obj[map[curmap].curobj].w-1,y, map[curmap].boxcol,1); @@ -5794,10 +6206,21 @@ int updateresizeshadow(int x, int y) { SDL_Rect sarea; SDL_Rect area; int xdiff,ydiff; + xdiff = x - startx; ydiff = y - starty; + /* adjust for grid */ + if (grid) { + int m; + + m = map[curmap].obj[map[curmap].curobj].x + map[curmap].obj[map[curmap].curobj].w + xdiff; + xdiff -= (m % gridsize); + m = map[curmap].obj[map[curmap].curobj].y + map[curmap].obj[map[curmap].curobj].h + ydiff; + ydiff -= (m % gridsize); + } + /* check for maximum object sizes */ if ((map[curmap].obj[map[curmap].curobj].w + xdiff) > MAXOBJWIDTH) xdiff = MAXOBJWIDTH - map[curmap].obj[map[curmap].curobj].w; if ((map[curmap].obj[map[curmap].curobj].h + ydiff) > MAXOBJHEIGHT) ydiff = MAXOBJHEIGHT - map[curmap].obj[map[curmap].curobj].h; @@ -6104,6 +6527,12 @@ int endlinkpointmove(int x, int y) { if (bg) free(bg); + /* adjust for grid */ + if (grid) { + x = x - (x % gridsize); + y = y - (y % gridsize); + } + map[curmap].olink[map[curmap].curlink].point[map[curmap].curlinkpoint].x = x; map[curmap].olink[map[curmap].curlink].point[map[curmap].curlinkpoint].y = y; @@ -6213,6 +6642,7 @@ printf("drilling to: %d\n",mapnum); int endobjmove(int x, int y) { SDL_FreeSurface(bg); + int newx, newy; /* check position */ if ((map[curmap].obj[map[curmap].curobj].x + x - startx) >= (map[curmap].width - map[curmap].obj[map[curmap].curobj].w)) { @@ -6228,9 +6658,21 @@ int endobjmove(int x, int y) { return -1; } + modified = TRUE; - map[curmap].obj[map[curmap].curobj].x += (x - startx); - map[curmap].obj[map[curmap].curobj].y += (y - starty); + newx = map[curmap].obj[map[curmap].curobj].x + (x - startx); + newy = map[curmap].obj[map[curmap].curobj].y + (y - starty); + + /* adjust for grid */ + if (grid) { + newx = newx - (newx % gridsize); + newy = newy - (newy % gridsize); + } + + + map[curmap].obj[map[curmap].curobj].x = newx; + map[curmap].obj[map[curmap].curobj].y = newy; + return 0; } @@ -6268,6 +6710,17 @@ int endresize(int x, int y) { newh = map[curmap].height - map[curmap].obj[map[curmap].curobj].y-1; } + /* adjust for grid */ + if (grid) { + int m; + + m = map[curmap].obj[map[curmap].curobj].x + map[curmap].obj[map[curmap].curobj].w + neww; + neww -= (m % gridsize); + + m = map[curmap].obj[map[curmap].curobj].y + map[curmap].obj[map[curmap].curobj].h + newh; + newh -= (m % gridsize); + } + map[curmap].obj[map[curmap].curobj].w = neww; map[curmap].obj[map[curmap].curobj].h = newh; @@ -6367,6 +6820,13 @@ int updatetextshadow(int x, int y) { area.h = bgh; SDL_BlitSurface(bg, 0, screen, &area); SDL_UpdateRect(screen, area.x, area.y, area.w, area.h); + + /* adjust for grid */ + if (grid) { + x = x - (x % gridsize); + y = y - (y % gridsize); + } + /* copy current bg */ area.x = x; area.y = y; diff --git a/netmapr.exe b/netmapr.exe index 058fd02..c0f1a15 100755 Binary files a/netmapr.exe and b/netmapr.exe differ diff --git a/netmapr.h b/netmapr.h index b7286c4..53e21d0 100644 --- a/netmapr.h +++ b/netmapr.h @@ -178,6 +178,9 @@ void deleteobject(int oid ); void deletetext(int textid); void drawarrowhead(SDL_Surface *screen, double x1, double y1, double x2, double y2, SDL_Color c, int arrowstyle, int arrowpos); void drawbox(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c); +void drawfillbox(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c); +void drawellipsepoints(SDL_Surface *screen, int x1, int y1, int x, int y, SDL_Color c); +void drawellipse(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c); void drawcolorchart(SDL_Surface *dest); void drawmaplist(SDL_Surface *dest); int drawletter(SDL_Surface *dest,int x, int y, int w, int h, char let, SDL_Color col); @@ -193,7 +196,7 @@ void drawscreen(void); void drawstatusbar(void); void drawtext(SDL_Surface *dest, text_t *t); void drawtoolbox(void); -void drawtoolboxselector(int buttonid); +void drawtoolboxselector(int buttonid, int altcolour); void drawvector(SDL_Surface *dest, vectorimg_t *vimg, int x, int y, int w, int h,SDL_Color *overridefg, SDL_Color *overridebg ); void drillto(int mapnum); int endobjmove(int x, int y); diff --git a/objects.dat b/objects.dat index cd89bdf..067e67d 100644 --- a/objects.dat +++ b/objects.dat @@ -561,9 +561,9 @@ line 95 260 95 255 250 250 250 # fill fill 85 250 252 252 252 end -object bluebox 120 120 -box 0 0 119 119 0 0 0 -fill 50 50 0 0 255 +object genericcircle 120 120 +circle 60 60 55 55 0 0 0 0 +fill 60 60 255 0 0 end object pda 100 210 # outline @@ -684,3 +684,314 @@ line 300 249 399 190 170 230 255 line 399 150 399 190 170 230 255 fill 350 200 0 90 128 end +object truck 300 223 +# CABIN (starts bottom left) +line 0 160 0 100 0 0 0 +line 0 100 35 90 0 0 0 +line 35 90 50 50 0 0 0 +line 50 50 100 50 0 0 0 +line 100 50 100 160 0 0 0 +line 100 160 0 160 0 0 0 +# WINDOW (from top left) +line 60 60 90 60 0 0 0 +line 90 60 90 90 0 0 0 +line 90 90 50 90 0 0 0 +line 50 90 60 60 0 0 0 +# JOINER +box 85 160 100 190 0 0 0 +#box 100 160 299 175 0 0 0 +line 100 175 100 160 0 0 0 +line 100 160 299 160 0 0 0 +line 299 160 299 175 0 0 0 +# conenctions to tyres +line 299 175 275 175 0 0 0 +line 235 175 210 175 0 0 0 +line 170 175 100 175 0 0 0 +# BACK +box 100 0 290 160 0 0 0 +# front wheel +circle 50 190 30 30 0 0 0 +circle 50 190 15 15 0 0 0 +fill 50 190 250 250 250 +fill 25 190 0 0 0 +# back wheels +circle 255 190 30 30 0 0 0 +circle 255 190 15 15 0 0 0 +fill 255 190 250 250 250 +fill 235 190 0 0 0 +# +circle 190 190 30 30 0 0 0 +circle 190 190 15 15 0 0 0 +fill 190 190 250 250 250 +fill 170 190 0 0 0 +# fill cabin +fill 60 100 190 0 0 +# fill window +fill 70 80 0 0 190 +# fill joiner (front) +fill 90 180 200 0 0 +# fill joiner (back) +fill 150 167 190 0 0 +fill 220 167 195 0 0 +fill 290 167 190 0 0 +# fill back +fill 250 100 190 190 210 +end +object man 100 200 +# left shoulder +line 50 50 20 50 0 0 0 +# left arm +line 20 50 0 110 0 0 0 +line 0 110 10 110 0 0 0 +line 10 110 30 60 0 0 0 +# left body +line 30 60 30 120 0 0 0 +# left leg +line 30 120 10 190 0 0 0 +line 10 190 20 190 0 0 0 +line 20 190 50 130 0 0 0 +# right shoulder +line 50 50 80 50 0 0 0 +# right arm +line 80 50 100 110 0 0 0 +line 100 110 90 110 0 0 0 +line 90 110 70 60 0 0 0 +# right body +line 70 60 70 120 0 0 0 +# right leg +line 70 120 90 190 0 0 0 +line 90 190 80 190 0 0 0 +line 80 190 50 130 0 0 0 +# belt +line 30 110 70 110 0 0 0 +line 30 115 70 115 0 0 0 +# head +circle 50 29 18 20 0 0 0 +fill 50 29 255 219 198 +# fill belt +fill 50 112 0 0 0 +# fill shirt +fill 50 80 150 90 100 +# fill trousers +fill 40 130 0 0 90 +# tie +box 48 50 52 54 0 0 0 +#fill 50 52 255 0 0 +line 48 54 45 90 0 0 0 +line 45 90 50 95 0 0 0 +# +line 50 95 55 90 0 0 0 +line 55 90 52 54 0 0 0 +fill 50 90 255 0 0 +end +object camera 200 100 +box 0 10 199 99 0 0 0 +# fill base +fill 50 50 60 60 60 +# lens +circle 100 55 40 40 0 0 0 +fill 100 50 190 190 190 +circle 100 55 35 35 0 0 0 +fill 100 50 0 0 255 +line 50 10 60 0 0 0 0 +line 60 0 140 0 0 0 0 +line 140 0 150 10 0 0 0 +# switch +box 180 0 190 10 0 0 0 +fill 185 5 190 190 190 +# fill top middle bit +fill 100 5 190 190 190 +end +object webcam 100 120 +# top bit +circle 50 50 45 45 0 0 0 +fill 50 50 200 200 200 +# base +line 30 90 0 119 0 0 0 +line 0 119 99 119 0 0 0 +line 70 90 99 119 0 0 0 +fill 40 105 176 176 176 +# lens +circle 35 35 15 15 0 0 0 +fill 35 35 240 240 240 +circle 35 35 10 10 0 0 0 +fill 35 35 0 0 255 +end +object wirelessrouter 200 300 +# top left +line 0 150 0 138 170 230 255 +line 0 138 10 126 170 230 255 +line 10 126 30 114 170 230 255 +line 30 114 60 100 170 230 255 +line 60 100 100 100 170 230 255 +# bottom left +line 0 150 0 162 170 230 255 +line 0 162 10 174 170 230 255 +line 10 174 30 186 170 230 255 +line 30 186 60 199 170 230 255 +line 60 199 100 199 170 230 255 +# top right +line 199 150 199 138 170 230 255 +line 199 138 190 126 170 230 255 +line 190 126 170 114 170 230 255 +line 170 114 140 100 170 230 255 +line 140 100 100 100 170 230 255 +# bottom right +line 199 150 199 162 170 230 255 +line 199 162 190 174 170 230 255 +line 190 174 170 186 170 230 255 +line 170 186 140 199 170 230 255 +line 140 199 100 199 170 230 255 +# fill top +fill 100 150 0 180 255 +# bottom half - sides +line 0 150 0 262 170 230 255 +line 199 150 199 262 170 230 255 +# bottom half - bottom left +# next line not being drawn on windows?? +line 0 250 0 212 170 230 255 +line 0 262 10 274 170 230 255 +line 10 274 30 286 170 230 255 +line 30 286 60 299 170 230 255 +line 60 299 100 299 170 230 255 +# bottom half - bottom right +line 199 250 199 262 170 230 255 +line 199 262 190 274 170 230 255 +line 190 274 170 286 170 230 255 +line 170 286 140 299 170 230 255 +line 140 299 100 299 170 230 255 +# fill bottom half +fill 100 262 0 120 170 +# arrows +# top left arrow +line 35 125 65 140 0 0 0 +line 55 115 85 130 0 0 0 +line 35 125 55 115 0 0 0 +# arrowhead /____ +line 55 147 65 140 0 0 0 +line 55 147 90 147 0 0 0 +# arrowhead /| +line 95 120 90 147 0 0 0 +line 95 120 85 130 0 0 0 +# fill it +fill 60 130 250 250 250 +# +# +# bottom left arrow +line 95 165 65 180 0 0 0 +line 75 155 45 170 0 0 0 +line 95 165 75 155 0 0 0 +# arrowhead /____ +line 75 187 65 180 0 0 0 +line 75 187 40 187 0 0 0 +# arrowhead /| +line 45 160 40 187 0 0 0 +line 45 160 45 170 0 0 0 +# fill it +fill 70 170 250 250 250 +# top right arrow +line 110 140 140 125 0 0 0 +line 130 150 160 135 0 0 0 +line 110 140 130 150 0 0 0 +# arrowhead /____ +line 130 118 140 125 0 0 0 +line 130 118 165 118 0 0 0 +# arrowhead /| +line 160 145 165 118 0 0 0 +line 160 145 160 135 0 0 0 +# fill it +fill 135 135 250 250 250 +# bottom right arrow +line 165 180 135 165 0 0 0 +line 145 190 115 175 0 0 0 +# joining +line 165 180 145 190 0 0 0 +# arrowhead /____ +line 145 158 135 165 0 0 0 +line 145 158 110 158 0 0 0 +# arrowhead /| +line 115 185 110 158 0 0 0 +line 115 185 115 175 0 0 0 +# fill it +fill 140 175 250 250 250 +# WIRELESS ANTENNAE +fillbox 46 20 54 150 0 150 213 +line 46 20 46 150 170 230 255 +line 54 20 54 150 170 230 255 +fillbox 146 20 154 150 0 150 213 +line 146 20 146 150 170 230 255 +line 154 20 154 150 170 230 255 +end +object dish 250 161 +# front of dish +circle 130 80 30 50 0 0 0 +fill 130 80 190 190 190 +# back of dish +line 130 30 90 30 0 0 0 +line 90 30 80 35 0 0 0 +line 80 35 55 55 0 0 0 +line 55 55 40 75 0 0 0 +line 40 75 40 85 0 0 0 +# +line 130 130 90 130 0 0 0 +line 90 130 80 125 0 0 0 +line 80 125 55 105 0 0 0 +line 55 105 40 85 0 0 0 +fill 100 50 210 210 210 +# +# base +line 100 130 70 160 0 0 0 +line 70 160 150 160 0 0 0 +line 150 160 120 130 0 0 0 +fill 125 150 200 200 200 +# end of antenna +fillbox 227 77 234 83 0 0 0 +# antenna wires +line 130 80 230 80 0 0 0 +line 130 30 230 80 0 0 0 +line 130 130 230 80 0 0 0 +end +object satellite 300 150 +# top of cylinder +line 125 40 140 40 0 0 0 +line 140 40 153 35 0 0 0 +line 153 35 137 33 0 0 0 +line 137 33 125 40 0 0 0 +fill 140 35 0 90 128 +# antenna +line 140 36 135 20 0 0 0 +fillbox 133 18 136 21 0 0 0 +# sides of cylinder +line 125 40 155 130 0 0 0 +line 153 35 182 125 0 0 0 +# rounded bottom of cylinder +line 155 130 165 133 0 0 0 +line 165 133 175 130 0 0 0 +line 175 130 182 125 0 0 0 +# left wing connector +line 140 80 125 85 0 0 0 +# left wing - RHS +line 125 85 130 95 0 0 0 +line 125 85 120 75 0 0 0 +# left wing - TOP + BOTTOM +line 120 75 20 110 0 0 0 +line 130 95 30 130 0 0 0 +# left wing - LHS +line 20 110 30 130 0 0 0 +# right wing connector +line 165 75 180 70 0 0 0 +# right wing - RHS +line 278 35 283 45 0 0 0 +line 278 35 273 25 0 0 0 +# right wing - TOP + BOTTOM +line 273 25 173 60 0 0 0 +line 283 45 183 80 0 0 0 +# right wing - LHS +line 173 60 183 80 0 0 0 +# fill front +fill 150 80 0 150 213 +# fill left wing +fill 100 90 0 180 255 +# fill right wing +fill 200 60 0 110 148 +end