ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/Deliantra/MapWidget.pm
(Generate patch)

Comparing deliantra/Deliantra/Deliantra/MapWidget.pm (file contents):
Revision 1.17 by root, Thu Feb 9 22:18:56 2006 UTC vs.
Revision 1.18 by root, Sun Feb 12 04:50:24 2006 UTC

25 25
26use Glib::Object::Subclass 26use Glib::Object::Subclass
27 'Gtk2::DrawingArea'; 27 'Gtk2::DrawingArea';
28 28
29use List::Util qw(min max); 29use List::Util qw(min max);
30
31#my ($TILE_MINX, $TILE_MINY, $TILE_MAXX, $TILE_MAXY);
32#
33#for (values %TILE) {
34# $TILE_MAXX = max $TILE_MAXX, $_->{w} - 1;
35# $TILE_MAXY = max $TILE_MAXY, $_->{h} - 1;
36#}
37#
38#for (values %ARCH) {
39# for (; $_; $_ = $_->{more}) {
40# $TILE_MINX = min $TILE_MINX, $_->{x};
41# $TILE_MINY = min $TILE_MINY, $_->{y};
42# $TILE_MAXX = max $TILE_MAXX, $_->{x};
43# $TILE_MAXY = max $TILE_MAXY, $_->{y};
44# }
45#}
30 46
31sub INIT_INSTANCE { 47sub INIT_INSTANCE {
32 my ($self) = @_; 48 my ($self) = @_;
33 49
34 $self->signal_connect (destroy => sub { 50 $self->signal_connect (destroy => sub {
194 210
195 $self->{window}->draw_rectangle ($_ & 1 ? $self->style->black_gc : $self->style->white_gc, 0, 211 $self->{window}->draw_rectangle ($_ & 1 ? $self->style->black_gc : $self->style->white_gc, 0,
196 $x + $_, $y + $_, 212 $x + $_, $y + $_,
197 TILESIZE - 1 - $_ * 2, TILESIZE - 1 - $_ * 2) 213 TILESIZE - 1 - $_ * 2, TILESIZE - 1 - $_ * 2)
198 for 0..3; 214 for 0..3;
199
200 my $req = $self->{tip}->size_request;
201 $self->{tip}->resize ($req->width, $req->height);
202 }); 215 });
216
217 my $req = $self->{tip}->size_request;
218 $self->{tip}->resize ($req->width, $req->height);
203 } 219 }
204 220
205 $self->{tip}->move ($x + TILESIZE, $y); 221 $self->{tip}->move ($x + TILESIZE, $y);
206 $self->{tip}->show_all; 222 $self->{tip}->show_all;
207 223
234 # fill tooltip with info about $x, $y 250 # fill tooltip with info about $x, $y
235 my $as = $self->{map}{map}[$x][$y] || []; 251 my $as = $self->{map}{map}[$x][$y] || [];
236 for my $a (reverse @$as) { 252 for my $a (reverse @$as) {
237 $vbox->add (my $hbox = new Gtk2::HBox 0, 2); 253 $vbox->add (my $hbox = new Gtk2::HBox 0, 2);
238 254
239 my $tile = $Crossfire::Tilecache::TILECACHE{ $a->{face} || $ARCH->{$a->{_name}}{face} }; 255 my $tile = $FACE{ $a->{face} || $ARCH{$a->{_name}}{face} };
240 256
241 # this is awful, is this really the best way? 257 # this is awful, is this really the best way?
242 my $pb = new Gtk2::Gdk::Pixbuf 'rgb', 1, 8, TILESIZE, TILESIZE; 258 my $pb = new Gtk2::Gdk::Pixbuf 'rgb', 1, 8, TILESIZE, TILESIZE;
243 $pb->fill (0x00000000); 259 $pb->fill (0x00000000);
244 260
245 $Crossfire::Tilecache::TILECACHE->composite ($pb, 261 $TILE->composite ($pb,
246 0, 0, 262 0, 0,
247 TILESIZE, TILESIZE, 263 TILESIZE, TILESIZE,
248 - ($tile->{idx} % 64) * TILESIZE, - TILESIZE * int $tile->{idx} / 64, 264 - ($tile->{idx} % 64) * TILESIZE, - TILESIZE * int $tile->{idx} / 64,
249 1, 1, 'nearest', 255 265 1, 1, 'nearest', 255
250 ); 266 );
282 $self->{x} = 298 $self->{x} =
283 $self->{y} = 0; 299 $self->{y} = 0;
284 300
285 delete $self->{face}; 301 delete $self->{face};
286 delete $self->{face_extents}; 302 delete $self->{face_extents};
287 $self->update_map (0, 0, $map->{width}, $map->{height}); 303 $self->update_map (0, 0, $map->{width} - 1, $map->{height} - 1);
288 delete $self->{tipinfo}; $self->update_tooltip; 304 delete $self->{tipinfo}; $self->update_tooltip;
289 $self->invalidate_all; 305 $self->invalidate_all;
290} 306}
291 307
292sub coord { 308sub coord {
326 my ($self) = @_; 342 my ($self) = @_;
327 343
328 $self->queue_draw; 344 $self->queue_draw;
329} 345}
330 346
347sub expose {
348 my ($self, $event) = @_;
349
350 no integer;
351
352 my $ox = $self->{x}; my $ix = int $ox / TILESIZE;
353 my $oy = $self->{y}; my $iy = int $oy / TILESIZE;
354
355 # get_rectangles is buggy in older versions
356 my @rectangles = $Gtk2::VERSION > 1.115
357 ? $event->region->get_rectangles : $event->area;
358
359 for my $area (@rectangles) {
360 my ($x, $y, $w, $h) = $area->values; # x y w h
361
362 my @x = ((int ($ox + $x) / TILESIZE) .. int +($ox + $x + $w + TILESIZE - 1) / TILESIZE);
363 my @y = ((int ($oy + $y) / TILESIZE) .. int +($oy + $y + $h + TILESIZE - 1) / TILESIZE);
364
365 my $window = $self->{window};
366
367 my $pb = new Gtk2::Gdk::Pixbuf 'rgb', 0, 8, TILESIZE * (@x + 1), TILESIZE * (@y + 1);
368 $pb->fill (0xff69b400);
369
370 for my $x (@x) {
371 my $dx = ($x - $x[0]) * TILESIZE;
372 my $oss = $self->{face}[$x];
373
374 for my $y (@y) {
375 my $dy = ($y - $y[0]) * TILESIZE;
376
377 for my $idx (@{$oss->[$y]}) {
378 $TILE->composite ($pb,
379 $dx, $dy,
380 TILESIZE, TILESIZE,
381 $dx - ($idx % 64) * TILESIZE, $dy - TILESIZE * int $idx / 64,
382 1, 1, 'nearest', 255
383 );
384 }
385 }
386 }
387
388 $pb->render_to_drawable ($window, $self->style->black_gc,
389 0, 0,
390 $x[0] * TILESIZE - $ox, $y[0] * TILESIZE - $oy,
391 TILESIZE * @x, TILESIZE * @y,
392 'max', 0, 0);
393 }
394
395 $_->[4]->($self, $_->[0] - $self->{x}, $_->[1] - $self->{y})
396 for values %{ $self->{overlay} || {} };
397}
398
331sub update_map { 399sub update_map {
332 my ($self, $x, $y, $w, $h) = @_; 400 my ($self, $x1, $y1, $x2, $y2) = @_;
333 401
334 delete $self->{tipinfo}; $self->update_tooltip; 402 delete $self->{tipinfo}; $self->update_tooltip;
335
336 my ($x1, $y1, $x2, $y2) = ($x, $y, $x + $w - 1, $y + $h - 1);
337 403
338# push @{ $self->{queue_draw_areay} }, [$x * TILESIZE - $self->{x}, 404# push @{ $self->{queue_draw_areay} }, [$x * TILESIZE - $self->{x},
339# $y * TILESIZE - $self->{y}, 405# $y * TILESIZE - $self->{y},
340# $w * TILESIZE, $h * TILESIZE]; 406# $w * TILESIZE, $h * TILESIZE];
341 407
342 # we store precomputed tile info into $self->{face} 408 # we store precomputed tile info into $self->{face}
343 # and the minimum/maximum extents into $self->{face_extents} 409 # and the minimum/maximum extents into $self->{face_extents}
344 my $map = $self->{map}{map}; 410 my $map = $self->{map}{map};
345 my $ov = $self->{face} ||= []; 411 my $ov = $self->{face} ||= [];
346 my $ext = $self->{face_extents} ||= []; 412 my $ext = $self->{face_extents} ||= [];
413
414 $x1 = max 0, min $self->{map}{width} - 1, $x1;
415 $y1 = max 0, min $self->{map}{height} - 1, $y1;
416 $x2 = max 0, min $self->{map}{width} - 1, $x2;
417 $y2 = max 0, min $self->{map}{height} - 1, $y2;
347 418
348 # extend update area as neccessary to include all bigfaces 419 # extend update area as neccessary to include all bigfaces
349 # that overlap the update area 420 # that overlap the update area
350 for (;;) { 421 for (;;) {
351 my $redo; 422 my $redo;
364 } 435 }
365 } 436 }
366 $redo or last; 437 $redo or last;
367 } 438 }
368 439
369 my $TC = \%Crossfire::Tilecache::TILECACHE; 440 $x1 = max 0, min $self->{map}{width} - 1, $x1;
441 $y1 = max 0, min $self->{map}{height} - 1, $y1;
442 $x2 = max 0, min $self->{map}{width} - 1, $x2;
443 $y2 = max 0, min $self->{map}{height} - 1, $y2;
370 444
371 $self->queue_draw_area ( 445 $self->queue_draw_area (
372 $x1 * TILESIZE - $self->{x}, $y1 * TILESIZE - $self->{y}, 446 $x1 * TILESIZE - $self->{x}, $y1 * TILESIZE - $self->{y},
373 ($x2 - $x1 + 1) * TILESIZE , ($y2 - $y1 + 1) * TILESIZE , 447 ($x2 - $x1 + 1) * TILESIZE , ($y2 - $y1 + 1) * TILESIZE ,
374 ); 448 );
376 my @ov; 450 my @ov;
377 451
378 # update overlay map with bigfaces and chained faces 452 # update overlay map with bigfaces and chained faces
379 my $a; 453 my $a;
380 for my $x ($x1 .. $x2) { 454 for my $x ($x1 .. $x2) {
381 my $ass = $self->{map}{map}[$x]; 455 my $ass = $map->[$x];
382 my $oss = $ov->[$x] ||= []; 456 my $oss = $ov->[$x] ||= [];
383 for my $y ($y1 .. $y2) { 457 for my $y ($y1 .. $y2) {
384 my $os = $oss->[$y] = []; 458 my $os = $oss->[$y] = [];
385 for my $a (@{ $ass->[$y] || [] }) { 459 for my $a (@{ $ass->[$y] || [] }) {
386 my $o = $ARCH->{$a->{_name}} 460 my $o = $ARCH{$a->{_name}}
387 or (warn "arch '$a->{_name}' not found at ($x|$y)\n"), next; 461 or (warn "arch '$a->{_name}' not found at ($x|$y)\n"), next;
388 462
389 my $tile = $TC->{$a->{face} || $o->{face}} 463 my $tile = $FACE{$a->{face} || $o->{face}}
390 or (warn "no gfx found for arch '$a->{_name}' at ($x|$y)\n"), next; 464 or (warn "no gfx found for arch '$a->{_name}' at ($x|$y)\n"), next;
391 465
392 if ($tile->{w} > 1 || $tile->{h} > 1) { 466 if ($tile->{w} > 1 || $tile->{h} > 1) {
393 # bigfaces 467 # bigfaces
394 my $maxx = $x + $tile->{w} - 1; 468 my $maxx = $x + $tile->{w} - 1;
396 470
397 for my $ox (0 .. $tile->{w} - 1) { 471 for my $ox (0 .. $tile->{w} - 1) {
398 for my $oy (0 .. $tile->{h} - 1) { 472 for my $oy (0 .. $tile->{h} - 1) {
399 my $ext = $ext->[$x + $ox][$y + $oy]; 473 my $ext = $ext->[$x + $ox][$y + $oy];
400 474
401 $ext->[0] = $x if $ext->[0] > $x; 475 $ext->[0] = min $ext->[0], $x;
402 $ext->[1] = $y if $ext->[1] > $y; 476 $ext->[1] = min $ext->[1], $y;
403 $ext->[2] = $maxx if $ext->[2] < $maxx; 477 $ext->[2] = max $ext->[2], $maxx;
404 $ext->[3] = $maxy if $ext->[3] < $maxy; 478 $ext->[3] = max $ext->[3], $maxy;
405 479
406 push @ov, [$x + $ox, $y + $oy, 480 push @ov, [$x + $ox, $y + $oy,
407 $tile->{idx} + $ox + $oy * $tile->{w}]; 481 $tile->{idx} + $ox + $oy * $tile->{w}];
408 } 482 }
409 } 483 }
410 484
411 } elsif ($o->{more}) { 485 } elsif ($o->{more}) {
412 # linked faces, slowest and mosta nnoying 486 # linked faces, slowest and most annoying
413 487
414 my ($minx, $miny, $maxx, $maxy); 488 my ($minx, $miny, $maxx, $maxy);
415 489
416 for (my $o = $o; $o; $o = $o->{more}) { 490 for (my $o = $o; $o; $o = $o->{more}) {
417 $minx = $o->{x} if $minx > $o->{x}; 491 $minx = min $minx, $o->{x};
418 $miny = $o->{y} if $miny > $o->{y}; 492 $miny = min $miny, $o->{y};
419 $maxx = $o->{x} if $maxx < $o->{x}; 493 $maxx = max $maxx, $o->{x};
420 $maxy = $o->{y} if $maxy < $o->{y}; 494 $maxy = max $maxy, $o->{y};
421 } 495 }
422 496
423 $minx += $x; 497 $minx += $x; $miny += $y;
424 $miny += $y;
425 $maxx += $x; 498 $maxx += $x; $maxy += $y;
426 $maxy += $y;
427 499
428 for (my $o = $o; $o; $o = $o->{more}) { 500 for (my $o = $o; $o; $o = $o->{more}) {
429 my $tile = $TC->{$o->{face}} 501 my $tile = $FACE{$o->{face}}
430 or (warn "no gfx found for arch '$a->{_name}' at ($x*|$y*)\n"), next; 502 or (warn "no gfx found for arch '$a->{_name}' at ($x*|$y*)\n"), next;
431 503
432 my $ext = $ext->[$x + $o->{x}][$y + $o->{y}]; 504 my $ext = $ext->[$x + $o->{x}][$y + $o->{y}];
433 505
434 $ext->[0] = $minx if $ext->[0] > $minx; 506 $ext->[0] = min $ext->[0], $minx;
435 $ext->[1] = $miny if $ext->[1] > $miny; 507 $ext->[1] = min $ext->[1], $miny;
436 $ext->[2] = $maxx if $ext->[2] < $maxx; 508 $ext->[2] = max $ext->[2], $maxx;
437 $ext->[3] = $maxy if $ext->[3] < $maxy; 509 $ext->[3] = max $ext->[3], $maxy;
438 510
439 push @ov, [$x + $o->{x}, $y + $o->{y}, $tile->{idx}]; 511 push @ov, [$x + $o->{x}, $y + $o->{y}, $tile->{idx}];
440 } 512 }
441 513
442 } else { 514 } else {
449 } 521 }
450 522
451 # bigger faces always on top, I don't give a shit to those who think otherwise 523 # bigger faces always on top, I don't give a shit to those who think otherwise
452 for (@ov) { 524 for (@ov) {
453 my ($x, $y, $idx) = @$_; 525 my ($x, $y, $idx) = @$_;
526
527 next if $x < 0 || $self->{map}{width} <= $x
528 || $y < 0 || $self->{map}{height} <= $y;
454 529
455 push @{ $ov->[$x][$y] }, $idx; 530 push @{ $ov->[$x][$y] }, $idx;
456 } 531 }
457 532
458 # dump extent info 533 # dump extent info
464# } 539# }
465# } 540# }
466# } 541# }
467} 542}
468 543
469sub expose { 544sub change_begin {
470 my ($self, $event) = @_; 545 my ($self, $title) = @_;
471 546
472 no integer; 547 $self->{change} ||= {
473 548 title => $title,
474 my $ox = $self->{x}; my $ix = int $ox / TILESIZE;
475 my $oy = $self->{y}; my $iy = int $oy / TILESIZE;
476
477 # get_rectangles is buggy in older versions
478 my @rectangles = $Gtk2::VERSION > 1.115
479 ? $event->region->get_rectangles : $event->area;
480
481 for my $area (@rectangles) {
482 my ($x, $y, $w, $h) = $area->values; # x y w h
483
484 my @x = ((int ($ox + $x) / TILESIZE) .. int +($ox + $x + $w + TILESIZE - 1) / TILESIZE);
485 my @y = ((int ($oy + $y) / TILESIZE) .. int +($oy + $y + $h + TILESIZE - 1) / TILESIZE);
486
487 my $PB = $Crossfire::Tilecache::TILECACHE;
488
489 my $window = $self->{window};
490
491 my $pb = new Gtk2::Gdk::Pixbuf 'rgb', 0, 8, TILESIZE * (@x + 1), TILESIZE * (@y + 1);
492 $pb->fill (0x00000000);
493
494 for my $x (@x) {
495 my $dx = ($x - $x[0]) * TILESIZE;
496 my $oss = $self->{face}[$x];
497
498 for my $y (@y) {
499 my $dy = ($y - $y[0]) * TILESIZE;
500
501 for my $idx (@{$oss->[$y]}) {
502 $PB->composite ($pb,
503 $dx, $dy,
504 TILESIZE, TILESIZE,
505 $dx - ($idx % 64) * TILESIZE, $dy - TILESIZE * int $idx / 64,
506 1, 1, 'nearest', 255
507 );
508 }
509 }
510 }
511
512 $pb->render_to_drawable ($window, $self->style->black_gc,
513 0, 0,
514 $x[0] * TILESIZE - $ox, $y[0] * TILESIZE - $oy,
515 TILESIZE * @x, TILESIZE * @y,
516 'max', 0, 0);
517 } 549 };
550 $self->{change}{nest}++;
551}
518 552
519 $_->[4]->($self, $_->[0] - $self->{x}, $_->[1] - $self->{y}) 553sub get {
520 for values %{ $self->{overlay} || {} }; 554 my ($self, $x, $y) = @_;
555
556 $self->{map}{map}[$x][$y] || []
557}
558
559sub set {
560 my ($self, $x, $y, $as) = @_;
561
562 $self->{map}{map}[$x][$y] = $as;
563
564 $self->{update} ||= [$x, $y, $x, $y];
565
566 for (@$as) {
567 my ($x1, $y1, $x2, $y2) = arch_extents $_;
568
569 $self->{update}[0] = min $self->{update}[0], $x + $x1;
570 $self->{update}[1] = min $self->{update}[1], $y + $y1;
571 $self->{update}[2] = max $self->{update}[2], $x + $x2;
572 $self->{update}[3] = max $self->{update}[3], $y + $y2;
573 }
574
575 $self->{update_idle} ||= add Glib::Idle sub {
576 delete $self->{update_idle};
577 my $coord = delete $self->{update};
578
579 $self->update_map (@$coord);
580
581 0
582 }, undef, 10;
583}
584
585sub change_stack {
586 my ($self, $x, $y, $as) = @_;
587
588 $self->{change}{map}[$x][$y] ||= [$x, $y, $self->{map}{map}[$x][$y]];
589
590 $self->set ($x, $y, $as);
591}
592
593sub change_end {
594 my ($self) = @_;
595
596 --$self->{change}{nest} and return;
597
598 my $change = delete $self->{change};
599
600 delete $change->{nest};
601
602 $change->{set} = [
603 grep $_,
604 map @$_,
605 grep $_,
606 @{ delete $change->{map} || [] }
607 ];
608
609 @{ $change->{set} } or return;
610
611 $change
612}
613
614sub change_swap {
615 my ($self, $change) = @_;
616
617 for (@{ $change->{set} }) {
618 my $stack = \$self->{map}{map}[$_->[0]][$_->[1]];
619
620 ($$stack, $_->[2]) = ($_->[2], $$stack);
621 }
521} 622}
522 623
523=back 624=back
524 625
525=head1 AUTHOR 626=head1 AUTHOR

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines