]> git.zerfleddert.de Git - micropolis/blame - src/sim/w_map.c
correctly resize editor window to be in sync with the mini map
[micropolis] / src / sim / w_map.c
CommitLineData
6a5fa4e0
MG
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 micropolis@laptop.org.
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
65Tcl_HashTable MapCmds;
66
67
68extern Tk_ConfigSpec TileViewConfigSpecs[];
69
70
71Ink *NewInk();
72
73
74MapCmdconfigure(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
91MapCmdposition(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
106MapCmdsize(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
127MapCmdMapState(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
148MapCmdShowEditors(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
168MapCmdPanStart(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
204gotit:
205 view->last_x = x;
206 view->last_y = y;
207 view->track_info = (char *)ed;
208 return TCL_OK;
209}
210
211MapCmdPanTo(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
241MapCmdVisible(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
263MapCmdViewAt(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
283map_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
307int
308DoMapCmd(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
335DoNewMap(SimView *view)
336{
337 sim->maps++; view->next = sim->map; sim->map = view;
338/* NewMap = 1; */
339 view->invalid = 1;
340}
341
342
343int 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
420DrawMapEditorViews(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
474int max_pix = MAX_PIX;
475
476struct Pix {
477 long color;
478 short x, y;
479};
480
481struct Pix pix[MAX_PIX];
482
483
484CompareColor(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
494WireDrawMap(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
573DrawMapInk(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
Impressum, Datenschutz