|
|
1.1 root 1: /* w_map.c
2: *
3: * Micropolis, Unix Version. This game was released for the Unix platform
4: * in or about 1990 and has been modified for inclusion in the One Laptop
5: * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6: * you need assistance with this program, you may contact:
7: * http://wiki.laptop.org/go/Micropolis or email [email protected].
8: *
9: * This program is free software: you can redistribute it and/or modify
10: * it under the terms of the GNU General Public License as published by
11: * the Free Software Foundation, either version 3 of the License, or (at
12: * your option) any later version.
13: *
14: * This program is distributed in the hope that it will be useful, but
15: * WITHOUT ANY WARRANTY; without even the implied warranty of
16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17: * General Public License for more details. You should have received a
18: * copy of the GNU General Public License along with this program. If
19: * not, see <http://www.gnu.org/licenses/>.
20: *
21: * ADDITIONAL TERMS per GNU GPL Section 7
22: *
23: * No trademark or publicity rights are granted. This license does NOT
24: * give you any right, title or interest in the trademark SimCity or any
25: * other Electronic Arts trademark. You may not distribute any
26: * modification of this program using the trademark SimCity or claim any
27: * affliation or association with Electronic Arts Inc. or its employees.
28: *
29: * Any propagation or conveyance of this program must include this
30: * copyright notice and these terms.
31: *
32: * If you convey this program (or any modifications of it) and assume
33: * contractual liability for the program to recipients of it, you agree
34: * to indemnify Electronic Arts for any liability that those contractual
35: * assumptions impose on Electronic Arts.
36: *
37: * You may not misrepresent the origins of this program; modified
38: * versions of the program must be marked as such and not identified as
39: * the original program.
40: *
41: * This disclaimer supplements the one included in the General Public
42: * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43: * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44: * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45: * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46: * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47: * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48: * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49: * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50: * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51: * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52: * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53: * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54: * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55: * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56: * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57: * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58: * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59: * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60: * NOT APPLY TO YOU.
61: */
62: #include "sim.h"
63:
64:
65: Tcl_HashTable MapCmds;
66:
67:
68: extern Tk_ConfigSpec TileViewConfigSpecs[];
69:
70:
71: Ink *NewInk();
72:
73:
74: MapCmdconfigure(VIEW_ARGS)
75: {
76: int result = TCL_OK;
77:
78: if (argc == 2) {
79: result = Tk_ConfigureInfo(interp, view->tkwin, TileViewConfigSpecs,
80: (char *) view, (char *) NULL, 0);
81: } else if (argc == 3) {
82: result = Tk_ConfigureInfo(interp, view->tkwin, TileViewConfigSpecs,
83: (char *) view, argv[2], 0);
84: } else {
85: result = ConfigureTileView(interp, view, argc-2, argv+2,
86: TK_CONFIG_ARGV_ONLY);
87: }
88: return result;
89: }
90:
91: MapCmdposition(VIEW_ARGS)
92: {
93: if ((argc != 2) && (argc != 4)) {
94: return TCL_ERROR;
95: }
96: if (argc == 4) {
97: if ((Tcl_GetInt(interp, argv[2], &view->w_x) != TCL_OK)
98: || (Tcl_GetInt(interp, argv[3], &view->w_y) != TCL_OK)) {
99: return TCL_ERROR;
100: }
101: }
102: sprintf(interp->result, "%d %d", view->w_x, view->w_y);
103: return TCL_OK;
104: }
105:
106: MapCmdsize(VIEW_ARGS)
107: {
108: if ((argc != 2) && (argc != 4)) {
109: return TCL_ERROR;
110: }
111: if (argc == 4) {
112: int w, h;
113:
114: if (Tcl_GetInt(interp, argv[2], &w) != TCL_OK) {
115: return TCL_ERROR;
116: }
117: if (Tcl_GetInt(interp, argv[3], &h) != TCL_OK) {
118: return TCL_ERROR;
119: }
120: view->w_width = w;
121: view->w_height = h;
122: }
123: sprintf(interp->result, "%d %d", view->w_width, view->w_height);
124: return TCL_OK;
125: }
126:
127: MapCmdMapState(VIEW_ARGS)
128: {
129: int state;
130:
131: if ((argc != 2) && (argc != 3)) {
132: return TCL_ERROR;
133: }
134:
135: if (argc == 3) {
136: if ((Tcl_GetInt(interp, argv[2], &state) != TCL_OK) ||
137: (state < 0) || (state >= NMAPS)) {
138: return TCL_ERROR;
139: }
140:
141: DoSetMapState(view, state); Kick();
142: }
143:
144: sprintf(interp->result, "%d", view->map_state);
145: return TCL_OK;
146: }
147:
148: MapCmdShowEditors(VIEW_ARGS)
149: {
150: int val;
151:
152: if ((argc != 2) && (argc != 3)) {
153: return TCL_ERROR;
154: }
155:
156: if (argc == 3) {
157: if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) {
158: return TCL_ERROR;
159: }
160:
161: view->show_editors = val;
162: }
163:
164: sprintf(interp->result, "%d", view->show_editors);
165: return TCL_OK;
166: }
167:
168: MapCmdPanStart(VIEW_ARGS)
169: {
170: int x, y, left, right, top, bottom, width, height;
171: SimView *ed;
172:
173: if (argc != 4) {
174: return TCL_ERROR;
175: }
176:
177: if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
178: (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
179: return TCL_ERROR;
180: }
181:
182: for (ed = sim->editor; ed != NULL; ed = ed->next) {
183: if ((ed->x != view->x) || (ed->show_me == 0))
184: continue;
185:
186: width = ed->w_width;
187: height = ed->w_height;
188: left = ed->pan_x - (width / 2);
189: top = ed->pan_y - (height / 2);
190: right = left + width;
191: bottom = top + height;
192:
193: left = left * 3 / 16 - 4;
194: top = top * 3 / 16 - 4;
195: right = right * 3 / 16 + 4;
196: bottom = bottom * 3 / 16 + 4;
197:
198: if ((x >= left) && (x <= right) &&
199: (y >= top) && (y <= bottom)) {
200: goto gotit;
201: }
202: }
203:
204: gotit:
205: view->last_x = x;
206: view->last_y = y;
207: view->track_info = (char *)ed;
208: return TCL_OK;
209: }
210:
211: MapCmdPanTo(VIEW_ARGS)
212: {
213: int x, y, dx, dy;
214: SimView *ed;
215:
216: if (argc != 4) {
217: return TCL_ERROR;
218: }
219:
220: if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
221: (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
222: return TCL_ERROR;
223: }
224:
225: if ((ed = (SimView *)view->track_info) != NULL) {
226: dx = x - view->last_x;
227: dy = y - view->last_y;
228: if (dx || dy) {
229: view->last_x = x;
230: view->last_y = y;
231: dx = dx * 16 / 3;
232: dy = dy * 16 / 3;
233:
234: ed->skip = 0;
235: DoPanBy(ed, dx, dy); Kick();
236: }
237: }
238: return TCL_OK;
239: }
240:
241: MapCmdVisible(VIEW_ARGS)
242: {
243: int visible;
244:
245: if ((argc != 2) && (argc != 3)) {
246: return TCL_ERROR;
247: }
248:
249: if (argc == 3) {
250: if ((Tcl_GetInt(interp, argv[2], &visible) != TCL_OK) ||
251: (visible < 0) || (visible > 1)) {
252: return TCL_ERROR;
253: }
254:
255: visible = visible && Tk_IsMapped(view->tkwin);
256: view->visible = visible;
257: }
258:
259: sprintf(interp->result, "%d", view->visible);
260: return TCL_OK;
261: }
262:
263: MapCmdViewAt(VIEW_ARGS)
264: {
265: int x, y;
266:
267: if (argc != 4) {
268: return TCL_ERROR;
269: }
270:
271: if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
272: (x < 0) || (x >= WORLD_X) ||
273: (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) ||
274: (y < 0) || (y >= WORLD_Y)) {
275: return TCL_ERROR;
276: }
277:
278: sprintf(interp->result, "Sorry Not Implemented Yet"); /* XXX */
279: return TCL_OK;
280: }
281:
282:
283: map_command_init()
284: {
285: int new;
286: extern int TileViewCmd(CLIENT_ARGS);
287:
288: Tcl_CreateCommand(tk_mainInterp, "mapview", TileViewCmd,
289: (ClientData)MainWindow, (void (*)()) NULL);
290:
291: Tcl_InitHashTable(&MapCmds, TCL_STRING_KEYS);
292:
293: #define MAP_CMD(name) HASHED_CMD(Map, name)
294:
295: MAP_CMD(configure);
296: MAP_CMD(position);
297: MAP_CMD(size);
298: MAP_CMD(MapState);
299: MAP_CMD(ShowEditors);
300: MAP_CMD(PanStart);
301: MAP_CMD(PanTo);
302: MAP_CMD(Visible);
303: MAP_CMD(ViewAt);
304: }
305:
306:
307: int
308: DoMapCmd(CLIENT_ARGS)
309: {
310: SimView *view = (SimView *) clientData;
311: Tcl_HashEntry *ent;
312: int result = TCL_OK;
313: int (*cmd)();
314:
315: if (argc < 2) {
316: return TCL_ERROR;
317: }
318:
319: if (ent = Tcl_FindHashEntry(&MapCmds, argv[1])) {
320: cmd = (int (*)())ent->clientData;
321: Tk_Preserve((ClientData) view);
322: result = cmd(view, interp, argc, argv);
323: Tk_Release((ClientData) view);
324: } else {
325: Tcl_AppendResult(interp, "unknown command name: \"",
326: argv[0], " ", argv[1], "\".", (char *) NULL);
327: result = TCL_ERROR;
328: }
329: return result;
330: }
331:
332:
333: /*************************************************************************/
334:
335: DoNewMap(SimView *view)
336: {
337: sim->maps++; view->next = sim->map; sim->map = view;
338: /* NewMap = 1; */
339: view->invalid = 1;
340: }
341:
342:
343: int DoUpdateMap(SimView *view)
344: {
345: int dx, dy, i;
346:
347: view->updates++;
348:
349: // fprintf(stderr, "UpdateMaps sim_skips %d skips %d skip %d visible %d\n", sim_skips, view->skips, view->skip, view->visible);
350:
351: if (!view->visible) {
352: return 0;
353: }
354:
355: if ((!ShakeNow) &&
356: (!view->update) &&
357: (sim_skips ||
358: view->skips)) {
359: if (sim_skips) {
360: if (sim_skip > 0) {
361: return 0;
362: }
363: } else {
364: if (view->skip > 0) {
365: --view->skip;
366: return 0;
367: } else {
368: view->skip = view->skips;
369: }
370: }
371: }
372:
373: view->update = 0;
374: view->skip = 0;
375:
376: // view->invalid = 1;
377:
378: if (view->invalid || NewMap || ShakeNow) {
379:
380: view->invalid = 0;
381:
382: switch (view->type) {
383:
384: case X_Mem_View:
385: MemDrawMap(view);
386: break;
387:
388: case X_Wire_View:
389: WireDrawMap(view);
390: break;
391: }
392:
393: }
394:
395: /* XXX: don't do this stuff if just redrawing overlay */
396:
397: for (dx = dy = i = 0; i < ShakeNow; i++) {
398: dx += Rand(16) - 8;
399: dy += Rand(16) - 8;
400: }
401:
402: XCopyArea(view->x->dpy, view->pixmap, view->pixmap2, view->x->gc,
403: dx, dy, view->w_width, view->w_height, 0, 0);
404: DrawMapInk(view);
405:
406: /* XXX: do this if just redrawing overlay */
407:
408: XCopyArea(view->x->dpy, view->pixmap2,
409: Tk_WindowId(view->tkwin), view->x->gc,
410: 0, 0, view->w_width, view->w_height, 0, 0);
411:
412: if (view->show_editors) {
413: DrawMapEditorViews(view);
414: }
415:
416: return 1;
417: }
418:
419:
420: DrawMapEditorViews(SimView *view)
421: {
422: Pixmap pm = Tk_WindowId(view->tkwin);
423: struct SimView *ed;
424: int left, right, top, bottom, width, height;
425: int mine;
426:
427: XSetLineAttributes(view->x->dpy, view->x->gc, 1,
428: LineSolid, CapButt, JoinBevel);
429:
430: for (ed = sim->editor; ed != NULL; ed = ed->next) {
431: if ((ed->x != view->x) || (ed->show_me == 0))
432: continue;
433:
434: width = ed->w_width;
435: height = ed->w_height;
436: left = ed->pan_x - (width / 2);
437: top = ed->pan_y - (height / 2);
438: right = left + width;
439: bottom = top + height;
440:
441: left = left * 3 / 16;
442: top = top * 3 / 16;
443: right = right * 3 / 16;
444: bottom = bottom * 3 / 16;
445: width = right - left;
446: height = bottom - top;
447:
448: XSetForeground(view->x->dpy, view->x->gc,
449: view->pixels[COLOR_WHITE]);
450: XDrawRectangle(view->x->dpy, pm, view->x->gc,
451: left - 3, top - 3, width + 3, height + 3);
452:
453: XSetForeground(view->x->dpy, view->x->gc,
454: view->pixels[COLOR_BLACK]);
455: XDrawRectangle(view->x->dpy, pm, view->x->gc,
456: left - 1, top - 1, width + 3, height + 3);
457:
458: XSetForeground(view->x->dpy, view->x->gc,
459: view->pixels[COLOR_YELLOW]);
460: XDrawRectangle(view->x->dpy, pm, view->x->gc,
461: left - 2, top - 2, width + 3, height + 3);
462: }
463: }
464:
465:
466: /*
467: * Sending the whole image is 108108 bytes.
468: * Sending points is 4.4 bytes per point.
469: * One image is as big as 24570 points.
470: * But we have to sort these dang things.
471: */
472:
473: #define MAX_PIX 256
474: int max_pix = MAX_PIX;
475:
476: struct Pix {
477: long color;
478: short x, y;
479: };
480:
481: struct Pix pix[MAX_PIX];
482:
483:
484: CompareColor(struct Pix *p1, struct Pix *p2)
485: {
486: register char c1 = p1->color, c2 = p2->color;
487:
488: if (c1 == c2)
489: return (0);
490: return ((c1 < c2) ? -1 : 1);
491: }
492:
493:
494: WireDrawMap(SimView *view)
495: {
496: int different, x, y, i, last, pts;
497: unsigned char *old, *new;
498: XPoint *points;
499:
500: if (!view->x->color) {
501: MemDrawMap(view);
502: return;
503: }
504:
505: memcpy(view->other_data, view->data, view->line_bytes * view->m_height); /* XXX: handle depth */
506: MemDrawMap(view);
507:
508: old = view->other_data; new = view->data; /* XXX: handle depth */
509: different = 0;
510:
511: /* Scan the pixels that have changed */
512: for (y = 0; y < view->m_height; y++) {
513: for (x = 0; x < view->m_width; x++) {
514: if (old[x] != new[x]) {
515: if (different >= max_pix) {
516: /* Wow, lots of the pixels have changed.
517: Maybe we ought to just do it the hard way. */
518: XPutImage(view->x->dpy, view->pixmap, view->x->gc, view->image,
519: 0, 0, 0, 0, view->m_width, view->m_height);
520: return;
521: }
522: pix[different].color = new[x];
523: pix[different].x = x;
524: pix[different].y = y;
525: different++;
526: }
527: }
528: old += view->line_bytes; new += view->line_bytes; /* XXX: handle depth */
529: }
530:
531: /* Whew, the images are identical! */
532: if (different == 0)
533: return;
534:
535: #if 1
536:
537: /* Always draw the whole pixmap, for now. */
538: XPutImage(view->x->dpy, view->pixmap, view->x->gc, view->image,
539: 0, 0, 0, 0, view->m_width, view->m_height);
540:
541: #else
542:
543: /* TODO: Fix this. I disabled this incremental drawing code for now since it seems to be buggy. */
544:
545: /* Sort the changed pixels by their color */
546: qsort(pix, different, sizeof (struct Pix), (int (*)())CompareColor);
547:
548: /* Draw the points of each color that have changed */
549: points = (XPoint *)malloc(sizeof (XPoint) * different);
550: last = 0; pts = 0;
551: for (i = 0; i <= different; i++) {
552: if ((i == different) ||
553: (pix[i].color != pix[last].color)) {
554: XSetForeground(view->x->dpy, view->x->gc, pix[last].color);
555: XDrawPoints(view->x->dpy, view->pixmap, view->x->gc,
556: points, pts, CoordModeOrigin);
557: if (i == different)
558: break;
559: pts = 0;
560: last = i;
561: }
562: points[pts].x = pix[i].x;
563: points[pts].y = pix[i].y;
564: pts++;
565: }
566: free(points);
567:
568: #endif
569:
570: }
571:
572:
573: DrawMapInk(SimView *view)
574: {
575: Pixmap pm = view->pixmap2;
576: SimView *v;
577: Ink *ink, *ink2 = NewInk();
578: int i, X, Y, x, y;
579:
580: XSetLineAttributes(view->x->dpy, view->x->gc, 0,
581: LineSolid, CapButt, JoinBevel);
582:
583: for (ink = sim->overlay; ink != NULL; ink = ink->next) {
584: X = ink->x; x = (X * 3) >>4;
585: Y = ink->y; y = (Y * 3) >>4;
586:
587: if (ink->length <= 1) {
588: XSetForeground(view->x->dpy, view->x->gc,
589: view->pixels[ink->color]);
590: XFillArc(view->x->dpy, pm, view->x->gc,
591: ink->x - 1, ink->y - 1, 1, 1, 0, 360 * 64);
592: } else {
593: StartInk(ink2, x, y);
594:
595: for (i = 1; i < ink->length; i++) {
596: X += ink->points[i].x; x = (X * 3) >>4;
597: Y += ink->points[i].y; y = (Y * 3) >>4;
598: AddInk(ink2, x, y);
599: }
600:
601: XSetForeground(view->x->dpy, view->x->gc,
602: view->pixels[ink->color]);
603: XDrawLines(view->x->dpy, pm, view->x->gc,
604: ink2->points, ink2->length, CoordModePrevious);
605: }
606: }
607:
608: FreeInk(ink2);
609: }
610:
611:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.