25 #include "train.h" |
25 #include "train.h" |
26 #include "roadveh.h" |
26 #include "roadveh.h" |
27 #include "vehicle_gui.h" |
27 #include "vehicle_gui.h" |
28 #include "blitter/factory.hpp" |
28 #include "blitter/factory.hpp" |
29 #include "newgrf_fsmports.h" |
29 #include "newgrf_fsmports.h" |
|
30 #include "transparency.h" |
30 |
31 |
31 #define VIEWPORT_DRAW_MEM (65536 * 2) |
32 #define VIEWPORT_DRAW_MEM (65536 * 2) |
32 |
33 |
33 ZoomLevel _saved_scrollpos_zoom; |
34 ZoomLevel _saved_scrollpos_zoom; |
34 |
35 |
35 /* XXX - maximum viewports is maximum windows - 2 (main toolbar + status bar) */ |
36 /* XXX - maximum viewports is maximum windows - 2 (main toolbar + status bar) */ |
36 static ViewPort _viewports[25 - 2]; |
37 static ViewPort _viewports[25 - 2]; |
37 static uint32 _active_viewports; ///< bitmasked variable where each bit signifies if a viewport is in use or not |
38 static uint32 _active_viewports; ///< bitmasked variable where each bit signifies if a viewport is in use or not |
38 assert_compile(lengthof(_viewports) < sizeof(_active_viewports) * 8); |
39 assert_compile(lengthof(_viewports) < sizeof(_active_viewports) * 8); |
39 |
|
40 static bool _added_tile_sprite; |
|
41 static bool _offset_ground_sprites; |
|
42 |
40 |
43 /* The in-game coordiante system looks like this * |
41 /* The in-game coordiante system looks like this * |
44 * * |
42 * * |
45 * ^ Z * |
43 * ^ Z * |
46 * | * |
44 * | * |
111 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(StringSpriteToDraw)); |
109 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(StringSpriteToDraw)); |
112 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(TileSpriteToDraw)); |
110 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(TileSpriteToDraw)); |
113 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ChildScreenSpriteToDraw)); |
111 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ChildScreenSpriteToDraw)); |
114 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ParentSpriteToDraw)); |
112 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ParentSpriteToDraw)); |
115 |
113 |
|
114 /* Enumeration of multi-part foundations */ |
|
115 enum FoundationPart { |
|
116 FOUNDATION_PART_NONE = 0xFF, ///< Neither foundation nor groundsprite drawn yet. |
|
117 FOUNDATION_PART_NORMAL = 0, ///< First part (normal foundation or no foundation) |
|
118 FOUNDATION_PART_HALFTILE = 1, ///< Second part (halftile foundation) |
|
119 FOUNDATION_PART_END |
|
120 }; |
|
121 |
116 struct ViewportDrawer { |
122 struct ViewportDrawer { |
117 DrawPixelInfo dpi; |
123 DrawPixelInfo dpi; |
118 |
124 |
119 byte *spritelist_mem; |
125 byte *spritelist_mem; |
120 const byte *eof_spritelist_mem; |
126 const byte *eof_spritelist_mem; |
286 int left, top, width, height; |
295 int left, top, width, height; |
287 |
296 |
288 vp->virtual_left = x; |
297 vp->virtual_left = x; |
289 vp->virtual_top = y; |
298 vp->virtual_top = y; |
290 |
299 |
291 old_left = UnScaleByZoom(old_left, vp->zoom); |
300 /* viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower) |
292 old_top = UnScaleByZoom(old_top, vp->zoom); |
301 * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL) |
293 x = UnScaleByZoom(x, vp->zoom); |
302 */ |
294 y = UnScaleByZoom(y, vp->zoom); |
303 old_left = UnScaleByZoomLower(old_left, vp->zoom); |
|
304 old_top = UnScaleByZoomLower(old_top, vp->zoom); |
|
305 x = UnScaleByZoomLower(x, vp->zoom); |
|
306 y = UnScaleByZoomLower(y, vp->zoom); |
295 |
307 |
296 old_left -= x; |
308 old_left -= x; |
297 old_top -= y; |
309 old_top -= y; |
298 |
310 |
299 if (old_top == 0 && old_left == 0) return; |
311 if (old_top == 0 && old_left == 0) return; |
359 b = y+x; |
371 b = y+x; |
360 |
372 |
361 /* we need to move variables in to the valid range, as the |
373 /* we need to move variables in to the valid range, as the |
362 * GetTileZoomCenterWindow() function can call here with invalid x and/or y, |
374 * GetTileZoomCenterWindow() function can call here with invalid x and/or y, |
363 * when the user tries to zoom out along the sides of the map */ |
375 * when the user tries to zoom out along the sides of the map */ |
364 a = clamp(a, 0, (int)(MapMaxX() * TILE_SIZE) - 1); |
376 a = Clamp(a, 0, (int)(MapMaxX() * TILE_SIZE) - 1); |
365 b = clamp(b, 0, (int)(MapMaxY() * TILE_SIZE) - 1); |
377 b = Clamp(b, 0, (int)(MapMaxY() * TILE_SIZE) - 1); |
366 |
378 |
367 z = GetSlopeZ(a, b ) / 2; |
379 /* (a, b) is the X/Y-world coordinate that belongs to (x,y) if the landscape would be completely flat on height 0. |
368 z = GetSlopeZ(a + z, b + z) / 2; |
380 * Now find the Z-world coordinate by fix point iteration. |
369 z = GetSlopeZ(a + z, b + z) / 2; |
381 * This is a bit tricky because the tile height is non-continuous at foundations. |
370 z = GetSlopeZ(a + z, b + z) / 2; |
382 * The clicked point should be approached from the back, otherwise there are regions that are not clickable. |
371 z = GetSlopeZ(a + z, b + z) / 2; |
383 * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely) |
|
384 * So give it a z-malus of 4 in the first iterations. |
|
385 */ |
|
386 z = 0; |
|
387 for (int i = 0; i < 5; i++) z = GetSlopeZ(a + max(z, 4u) - 4, b + max(z, 4u) - 4) / 2; |
|
388 for (uint malus = 3; malus > 0; malus--) z = GetSlopeZ(a + max(z, malus) - malus, b + max(z, malus) - malus) / 2; |
|
389 for (int i = 0; i < 5; i++) z = GetSlopeZ(a + z, b + z) / 2; |
372 |
390 |
373 pt.x = a + z; |
391 pt.x = a + z; |
374 pt.y = b + z; |
392 pt.y = b + z; |
375 |
393 |
376 return pt; |
394 return pt; |
423 * @param vp pointer to the viewport whose zoom-level the buttons represent |
441 * @param vp pointer to the viewport whose zoom-level the buttons represent |
424 * @param widget_zoom_in widget index for window with zoom-in button |
442 * @param widget_zoom_in widget index for window with zoom-in button |
425 * @param widget_zoom_out widget index for window with zoom-out button */ |
443 * @param widget_zoom_out widget index for window with zoom-out button */ |
426 void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out) |
444 void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out) |
427 { |
445 { |
428 SetWindowWidgetDisabledState(w, widget_zoom_in, vp->zoom == ZOOM_LVL_MIN); |
446 w->SetWidgetDisabledState(widget_zoom_in, vp->zoom == ZOOM_LVL_MIN); |
429 InvalidateWidget(w, widget_zoom_in); |
447 InvalidateWidget(w, widget_zoom_in); |
430 |
448 |
431 SetWindowWidgetDisabledState(w, widget_zoom_out, vp->zoom == ZOOM_LVL_MAX); |
449 w->SetWidgetDisabledState(widget_zoom_out, vp->zoom == ZOOM_LVL_MAX); |
432 InvalidateWidget(w, widget_zoom_out); |
450 InvalidateWidget(w, widget_zoom_out); |
433 } |
451 } |
434 |
452 |
435 /** |
453 /** |
436 * Draws a ground sprite at a specific world-coordinate. |
454 * Draws a ground sprite at a specific world-coordinate. |
468 *vd->last_tile = ts; |
486 *vd->last_tile = ts; |
469 vd->last_tile = &ts->next; |
487 vd->last_tile = &ts->next; |
470 } |
488 } |
471 |
489 |
472 /** |
490 /** |
|
491 * Adds a child sprite to the active foundation. |
|
492 * |
|
493 * The pixel offset of the sprite relative to the ParentSprite is the sum of the offset passed to OffsetGroundSprite() and extra_offs_?. |
|
494 * |
|
495 * @param image the image to draw. |
|
496 * @param pal the provided palette. |
|
497 * @param sub Only draw a part of the sprite. |
|
498 * @param foundation_part Foundation part. |
|
499 * @param extra_offs_x Pixel X offset for the sprite position. |
|
500 * @param extra_offs_y Pixel Y offset for the sprite position. |
|
501 */ |
|
502 static void AddChildSpriteToFoundation(SpriteID image, SpriteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y) |
|
503 { |
|
504 ViewportDrawer *vd = _cur_vd; |
|
505 assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END)); |
|
506 assert(vd->foundation[foundation_part] != NULL); |
|
507 Point offs = vd->foundation_offset[foundation_part]; |
|
508 |
|
509 /* Change the active ChildSprite list to the one of the foundation */ |
|
510 ChildScreenSpriteToDraw **old_child = vd->last_child; |
|
511 vd->last_child = vd->last_foundation_child[foundation_part]; |
|
512 |
|
513 AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub); |
|
514 |
|
515 /* Switch back to last ChildSprite list */ |
|
516 vd->last_child = old_child; |
|
517 } |
|
518 |
|
519 /** |
473 * Draws a ground sprite for the current tile. |
520 * Draws a ground sprite for the current tile. |
474 * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. |
521 * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. |
475 * |
522 * |
476 * @param image the image to draw. |
523 * @param image the image to draw. |
477 * @param pal the provided palette. |
524 * @param pal the provided palette. |
478 * @param sub Only draw a part of the sprite. |
525 * @param sub Only draw a part of the sprite. |
479 */ |
526 */ |
480 void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub) |
527 void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub) |
481 { |
528 { |
482 if (_offset_ground_sprites) { |
529 ViewportDrawer *vd = _cur_vd; |
483 /* offset ground sprite because of foundation? */ |
530 /* Switch to first foundation part, if no foundation was drawn */ |
484 AddChildSpriteScreen(image, pal, _cur_vd->offs_x, _cur_vd->offs_y, false, sub); |
531 if (vd->foundation_part == FOUNDATION_PART_NONE) vd->foundation_part = FOUNDATION_PART_NORMAL; |
|
532 |
|
533 if (vd->foundation[vd->foundation_part] != NULL) { |
|
534 AddChildSpriteToFoundation(image, pal, sub, vd->foundation_part, 0, 0); |
485 } else { |
535 } else { |
486 _added_tile_sprite = true; |
|
487 DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z, sub); |
536 DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z, sub); |
488 } |
537 } |
489 } |
538 } |
490 |
539 |
491 |
540 |
|
541 /** |
|
542 * Called when a foundation has been drawn for the current tile. |
|
543 * Successive ground sprites for the current tile will be drawn as child sprites of the "foundation"-ParentSprite, not as TileSprites. |
|
544 * |
|
545 * @param x sprite x-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. |
|
546 * @param y sprite y-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. |
|
547 */ |
492 void OffsetGroundSprite(int x, int y) |
548 void OffsetGroundSprite(int x, int y) |
493 { |
549 { |
494 _cur_vd->offs_x = x; |
550 ViewportDrawer *vd = _cur_vd; |
495 _cur_vd->offs_y = y; |
551 /* Switch to next foundation part */ |
496 _offset_ground_sprites = true; |
552 switch (vd->foundation_part) { |
|
553 case FOUNDATION_PART_NONE: |
|
554 vd->foundation_part = FOUNDATION_PART_NORMAL; |
|
555 break; |
|
556 case FOUNDATION_PART_NORMAL: |
|
557 vd->foundation_part = FOUNDATION_PART_HALFTILE; |
|
558 break; |
|
559 default: NOT_REACHED(); |
|
560 } |
|
561 |
|
562 /* vd->last_child == NULL if foundation sprite was clipped by the viewport bounds */ |
|
563 if (vd->last_child != NULL) vd->foundation[vd->foundation_part] = vd->parent_list[-1]; |
|
564 |
|
565 vd->foundation_offset[vd->foundation_part].x = x; |
|
566 vd->foundation_offset[vd->foundation_part].y = y; |
|
567 vd->last_foundation_child[vd->foundation_part] = vd->last_child; |
497 } |
568 } |
498 |
569 |
499 /** |
570 /** |
500 * Adds a child sprite to a parent sprite. |
571 * Adds a child sprite to a parent sprite. |
501 * In contrast to "AddChildSpriteScreen()" the sprite position is in world coordinates |
572 * In contrast to "AddChildSpriteScreen()" the sprite position is in world coordinates |
722 |
797 |
723 return ss; |
798 return ss; |
724 } |
799 } |
725 |
800 |
726 |
801 |
727 static void DrawSelectionSprite(SpriteID image, SpriteID pal, const TileInfo *ti) |
802 /** |
728 { |
803 * Draws sprites between ground sprite and everything above. |
729 if (_added_tile_sprite && !(_thd.drawstyle & HT_LINE)) { // draw on real ground |
804 * |
730 DrawGroundSpriteAt(image, pal, ti->x, ti->y, ti->z + 7); |
805 * The sprite is either drawn as TileSprite or as ChildSprite of the active foundation. |
731 } else { // draw on top of foundation |
806 * |
732 AddSortableSpriteToDraw(image, pal, ti->x, ti->y, 0x10, 0x10, 1, ti->z + 7); |
807 * @param image the image to draw. |
|
808 * @param pal the provided palette. |
|
809 * @param ti TileInfo Tile that is being drawn |
|
810 * @param z_offset Z offset relative to the groundsprite. Only used for the sprite position, not for sprite sorting. |
|
811 * @param foundation_part Foundation part the sprite belongs to. |
|
812 */ |
|
813 static void DrawSelectionSprite(SpriteID image, SpriteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part) |
|
814 { |
|
815 /* FIXME: This is not totally valid for some autorail highlights, that extent over the edges of the tile. */ |
|
816 if (_cur_vd->foundation[foundation_part] == NULL) { |
|
817 /* draw on real ground */ |
|
818 DrawGroundSpriteAt(image, pal, ti->x, ti->y, ti->z + z_offset); |
|
819 } else { |
|
820 /* draw on top of foundation */ |
|
821 AddChildSpriteToFoundation(image, pal, NULL, foundation_part, 0, -z_offset); |
733 } |
822 } |
734 } |
823 } |
735 |
824 |
736 /** |
825 /** |
737 * Draws a selection rectangle on a tile. |
826 * Draws a selection rectangle on a tile. |
739 * @param ti TileInfo Tile that is being drawn |
828 * @param ti TileInfo Tile that is being drawn |
740 * @param pal Palette to apply. |
829 * @param pal Palette to apply. |
741 */ |
830 */ |
742 static void DrawTileSelectionRect(const TileInfo *ti, SpriteID pal) |
831 static void DrawTileSelectionRect(const TileInfo *ti, SpriteID pal) |
743 { |
832 { |
744 DrawSelectionSprite(SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh], pal, ti); |
833 SpriteID sel; |
|
834 if (IsHalftileSlope(ti->tileh)) { |
|
835 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); |
|
836 SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner; |
|
837 DrawSelectionSprite(sel2, pal, ti, 7 + TILE_HEIGHT, FOUNDATION_PART_HALFTILE); |
|
838 |
|
839 Corner opposite_corner = OppositeCorner(halftile_corner); |
|
840 if (IsSteepSlope(ti->tileh)) { |
|
841 sel = SPR_HALFTILE_SELECTION_DOWN; |
|
842 } else { |
|
843 sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT); |
|
844 } |
|
845 sel += opposite_corner; |
|
846 } else { |
|
847 sel = SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]; |
|
848 } |
|
849 DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL); |
745 } |
850 } |
746 |
851 |
747 static bool IsPartOfAutoLine(int px, int py) |
852 static bool IsPartOfAutoLine(int px, int py) |
748 { |
853 { |
749 px -= _thd.selstart.x; |
854 px -= _thd.selstart.x; |
786 { |
891 { |
787 SpriteID image; |
892 SpriteID image; |
788 SpriteID pal; |
893 SpriteID pal; |
789 int offset; |
894 int offset; |
790 |
895 |
791 offset = _AutorailTilehSprite[ti->tileh][autorail_type]; |
896 FoundationPart foundation_part = FOUNDATION_PART_NORMAL; |
|
897 Slope autorail_tileh = (Slope)(ti->tileh & ~SLOPE_HALFTILE_MASK); |
|
898 if (IsHalftileSlope(ti->tileh)) { |
|
899 static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U }; |
|
900 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); |
|
901 if (autorail_type != _lower_rail[halftile_corner]) { |
|
902 foundation_part = FOUNDATION_PART_HALFTILE; |
|
903 /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */ |
|
904 autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner)); |
|
905 } |
|
906 } |
|
907 |
|
908 offset = _AutorailTilehSprite[autorail_tileh][autorail_type]; |
792 if (offset >= 0) { |
909 if (offset >= 0) { |
793 image = SPR_AUTORAIL_BASE + offset; |
910 image = SPR_AUTORAIL_BASE + offset; |
794 pal = PAL_NONE; |
911 pal = PAL_NONE; |
795 } else { |
912 } else { |
796 image = SPR_AUTORAIL_BASE - offset; |
913 image = SPR_AUTORAIL_BASE - offset; |
797 pal = PALETTE_SEL_TILE_RED; |
914 pal = PALETTE_SEL_TILE_RED; |
798 } |
915 } |
799 |
916 |
800 DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti); |
917 DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part); |
801 } |
918 } |
802 |
919 |
803 /** |
920 /** |
804 * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. |
921 * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. |
805 * @param *ti TileInfo Tile that is being drawn |
922 * @param *ti TileInfo Tile that is being drawn |
814 |
931 |
815 /* no selection active? */ |
932 /* no selection active? */ |
816 if (_thd.drawstyle == 0) return; |
933 if (_thd.drawstyle == 0) return; |
817 |
934 |
818 /* Inside the inner area? */ |
935 /* Inside the inner area? */ |
819 if (IS_INSIDE_1D(ti->x, _thd.pos.x, _thd.size.x) && |
936 if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) && |
820 IS_INSIDE_1D(ti->y, _thd.pos.y, _thd.size.y)) { |
937 IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) { |
821 if (_thd.drawstyle & HT_RECT) { |
938 if (_thd.drawstyle & HT_RECT) { |
822 if (_thd.FSMportLayout != NULL) { |
939 if (_thd.FSMportLayout != NULL) { |
823 byte *b = *_thd.FSMportLayout; |
940 byte *b = *_thd.FSMportLayout; |
824 byte *m; |
941 byte *m; |
825 if (_thd.FSMportMask != NULL) m = *_thd.FSMportMask; |
942 if (_thd.FSMportMask != NULL) m = *_thd.FSMportMask; |
844 if (_thd.FSMportLayout == NULL) { |
961 if (_thd.FSMportLayout == NULL) { |
845 DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); |
962 DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); |
846 } |
963 } |
847 } else if (_thd.drawstyle & HT_POINT) { |
964 } else if (_thd.drawstyle & HT_POINT) { |
848 /* Figure out the Z coordinate for the single dot. */ |
965 /* Figure out the Z coordinate for the single dot. */ |
849 byte z = ti->z; |
966 byte z = 0; |
|
967 FoundationPart foundation_part = FOUNDATION_PART_NORMAL; |
850 if (ti->tileh & SLOPE_N) { |
968 if (ti->tileh & SLOPE_N) { |
851 z += TILE_HEIGHT; |
969 z += TILE_HEIGHT; |
852 if (ti->tileh == SLOPE_STEEP_N) z += TILE_HEIGHT; |
970 if ((ti->tileh & ~SLOPE_HALFTILE_MASK) == SLOPE_STEEP_N) z += TILE_HEIGHT; |
853 } |
971 } |
854 DrawGroundSpriteAt(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti->x, ti->y, z); |
972 if (IsHalftileSlope(ti->tileh)) { |
|
973 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); |
|
974 if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT; |
|
975 if (halftile_corner != CORNER_S) { |
|
976 foundation_part = FOUNDATION_PART_HALFTILE; |
|
977 if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT; |
|
978 } |
|
979 } |
|
980 DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part); |
855 } else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) { |
981 } else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) { |
856 /* autorail highlight piece under cursor */ |
982 /* autorail highlight piece under cursor */ |
857 uint type = _thd.drawstyle & 0xF; |
983 uint type = _thd.drawstyle & 0xF; |
858 assert(type <= 5); |
984 assert(type <= 5); |
859 DrawAutorailSelection(ti, _AutorailType[type][0]); |
985 DrawAutorailSelection(ti, _AutorailType[type][0]); |
860 |
|
861 } else if (IsPartOfAutoLine(ti->x, ti->y)) { |
986 } else if (IsPartOfAutoLine(ti->x, ti->y)) { |
862 /* autorail highlighting long line */ |
987 /* autorail highlighting long line */ |
863 int dir = _thd.drawstyle & ~0xF0; |
988 int dir = _thd.drawstyle & ~0xF0; |
864 uint side; |
989 uint side; |
865 |
990 |
866 if (dir < 2) { |
991 if (dir < 2) { |
867 side = 0; |
992 side = 0; |
868 } else { |
993 } else { |
869 TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y); |
994 TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y); |
870 side = delta(delta(TileX(start), TileX(ti->tile)), delta(TileY(start), TileY(ti->tile))); |
995 side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile))); |
871 } |
996 } |
872 |
997 |
873 DrawAutorailSelection(ti, _AutorailType[dir][side]); |
998 DrawAutorailSelection(ti, _AutorailType[dir][side]); |
874 } |
999 } |
875 return; |
1000 return; |
876 } |
1001 } |
877 |
1002 |
878 /* Check if it's inside the outer area? */ |
1003 /* Check if it's inside the outer area? */ |
879 if (_thd.outersize.x && |
1004 if (_thd.outersize.x && |
880 _thd.size.x < _thd.size.x + _thd.outersize.x && |
1005 _thd.size.x < _thd.size.x + _thd.outersize.x && |
881 IS_INSIDE_1D(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) && |
1006 IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) && |
882 IS_INSIDE_1D(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) { |
1007 IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) { |
883 /* Draw a blue rect. */ |
1008 /* Draw a blue rect. */ |
884 DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); |
1009 DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); |
885 return; |
1010 return; |
886 } |
1011 } |
887 } |
1012 } |
1382 w -= 3; |
1510 w -= 3; |
1383 } |
1511 } |
1384 |
1512 |
1385 /* Draw the rectangle if 'tranparent station signs' is off, |
1513 /* Draw the rectangle if 'tranparent station signs' is off, |
1386 * or if we are drawing a general text sign (STR_2806) */ |
1514 * or if we are drawing a general text sign (STR_2806) */ |
1387 if (!HASBIT(_transparent_opt, TO_SIGNS) || ss->string == STR_2806) { |
1515 if (!IsTransparencySet(TO_SIGNS) || ss->string == STR_2806) { |
1388 DrawFrameRect( |
1516 DrawFrameRect( |
1389 x, y, x + w, bottom, ss->color, |
1517 x, y, x + w, bottom, ss->color, |
1390 HASBIT(_transparent_opt, TO_SIGNS) ? FR_TRANSPARENT : FR_NONE |
1518 IsTransparencySet(TO_SIGNS) ? FR_TRANSPARENT : FR_NONE |
1391 ); |
1519 ); |
1392 } |
1520 } |
1393 } |
1521 } |
1394 |
1522 |
1395 SetDParam(0, ss->params[0]); |
1523 SetDParam(0, ss->params[0]); |
1396 SetDParam(1, ss->params[1]); |
1524 SetDParam(1, ss->params[1]); |
1397 /* if we didn't draw a rectangle, or if transparant building is on, |
1525 /* if we didn't draw a rectangle, or if transparant building is on, |
1398 * draw the text in the color the rectangle would have */ |
1526 * draw the text in the color the rectangle would have */ |
1399 if (HASBIT(_transparent_opt, TO_SIGNS) && ss->string != STR_2806 && ss->width != 0) { |
1527 if (IsTransparencySet(TO_SIGNS) && ss->string != STR_2806 && ss->width != 0) { |
1400 /* Real colors need the IS_PALETTE_COLOR flag |
1528 /* Real colors need the IS_PALETTE_COLOR flag |
1401 * otherwise colors from _string_colormap are assumed. */ |
1529 * otherwise colors from _string_colormap are assumed. */ |
1402 colour = _colour_gradient[ss->color][6] | IS_PALETTE_COLOR; |
1530 colour = _colour_gradient[ss->color][6] | IS_PALETTE_COLOR; |
1403 } else { |
1531 } else { |
1404 colour = 16; |
1532 colour = TC_BLACK; |
1405 } |
1533 } |
1406 DrawString( |
1534 DrawString( |
1407 UnScaleByZoom(ss->x, zoom), UnScaleByZoom(ss->y, zoom) - (ss->width & 0x8000 ? 2 : 0), |
1535 UnScaleByZoom(ss->x, zoom), UnScaleByZoom(ss->y, zoom) - (ss->width & 0x8000 ? 2 : 0), |
1408 ss->string, colour |
1536 ss->string, colour |
1409 ); |
1537 ); |
1576 |
1704 |
1577 if (delta_x != 0 || delta_y != 0) { |
1705 if (delta_x != 0 || delta_y != 0) { |
1578 if (_patches.smooth_scroll) { |
1706 if (_patches.smooth_scroll) { |
1579 int max_scroll = ScaleByMapSize1D(512); |
1707 int max_scroll = ScaleByMapSize1D(512); |
1580 /* Not at our desired positon yet... */ |
1708 /* Not at our desired positon yet... */ |
1581 WP(w, vp_d).scrollpos_x += clamp(delta_x / 4, -max_scroll, max_scroll); |
1709 WP(w, vp_d).scrollpos_x += Clamp(delta_x / 4, -max_scroll, max_scroll); |
1582 WP(w, vp_d).scrollpos_y += clamp(delta_y / 4, -max_scroll, max_scroll); |
1710 WP(w, vp_d).scrollpos_y += Clamp(delta_y / 4, -max_scroll, max_scroll); |
1583 } else { |
1711 } else { |
1584 WP(w, vp_d).scrollpos_x = WP(w, vp_d).dest_scrollpos_x; |
1712 WP(w, vp_d).scrollpos_x = WP(w, vp_d).dest_scrollpos_x; |
1585 WP(w, vp_d).scrollpos_y = WP(w, vp_d).dest_scrollpos_y; |
1713 WP(w, vp_d).scrollpos_y = WP(w, vp_d).dest_scrollpos_y; |
1586 } |
1714 } |
1587 } |
1715 } |
2192 if (_thd.new_drawstyle) SetSelectionTilesDirty(); |
2324 if (_thd.new_drawstyle) SetSelectionTilesDirty(); |
2193 } |
2325 } |
2194 } |
2326 } |
2195 |
2327 |
2196 /** highlighting tiles while only going over them with the mouse */ |
2328 /** highlighting tiles while only going over them with the mouse */ |
2197 void VpStartPlaceSizing(TileIndex tile, byte method, byte process) |
2329 void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, byte process) |
2198 { |
2330 { |
2199 _thd.select_method = method; |
2331 _thd.select_method = method; |
2200 _thd.select_proc = process; |
2332 _thd.select_proc = process; |
2201 _thd.selend.x = TileX(tile) * TILE_SIZE; |
2333 _thd.selend.x = TileX(tile) * TILE_SIZE; |
2202 _thd.selstart.x = TileX(tile) * TILE_SIZE; |
2334 _thd.selstart.x = TileX(tile) * TILE_SIZE; |
2203 _thd.selend.y = TileY(tile) * TILE_SIZE; |
2335 _thd.selend.y = TileY(tile) * TILE_SIZE; |
2204 _thd.selstart.y = TileY(tile) * TILE_SIZE; |
2336 _thd.selstart.y = TileY(tile) * TILE_SIZE; |
|
2337 |
|
2338 /* Needed so several things (road, autoroad, bridges, ...) are placed correctly. |
|
2339 * In effect, placement starts from the centre of a tile |
|
2340 */ |
|
2341 if (method == VPM_X_OR_Y || method == VPM_FIX_X || method == VPM_FIX_Y) { |
|
2342 _thd.selend.x += TILE_SIZE / 2; |
|
2343 _thd.selend.y += TILE_SIZE / 2; |
|
2344 _thd.selstart.x += TILE_SIZE / 2; |
|
2345 _thd.selstart.y += TILE_SIZE / 2; |
|
2346 } |
|
2347 |
2205 if (_thd.place_mode == VHM_RECT) { |
2348 if (_thd.place_mode == VHM_RECT) { |
2206 _thd.place_mode = VHM_SPECIAL; |
2349 _thd.place_mode = VHM_SPECIAL; |
2207 _thd.next_drawstyle = HT_RECT; |
2350 _thd.next_drawstyle = HT_RECT; |
2208 } else if (_thd.place_mode == VHM_RAIL) { // autorail one piece |
2351 } else if (_thd.place_mode == VHM_RAIL) { // autorail one piece |
2209 _thd.place_mode = VHM_SPECIAL; |
2352 _thd.place_mode = VHM_SPECIAL; |
2598 GuiShowTooltipsWithArgs(measure_strings_length[index], index, params); |
2742 GuiShowTooltipsWithArgs(measure_strings_length[index], index, params); |
2599 } break; |
2743 } break; |
2600 |
2744 |
2601 case VPM_X_AND_Y_LIMITED: { /* drag an X by Y constrained rect area */ |
2745 case VPM_X_AND_Y_LIMITED: { /* drag an X by Y constrained rect area */ |
2602 int limit = (_thd.sizelimit - 1) * TILE_SIZE; |
2746 int limit = (_thd.sizelimit - 1) * TILE_SIZE; |
2603 x = sx + clamp(x - sx, -limit, limit); |
2747 x = sx + Clamp(x - sx, -limit, limit); |
2604 y = sy + clamp(y - sy, -limit, limit); |
2748 y = sy + Clamp(y - sy, -limit, limit); |
2605 } /* Fallthrough */ |
2749 } /* Fallthrough */ |
2606 case VPM_X_AND_Y: { /* drag an X by Y area */ |
2750 case VPM_X_AND_Y: { /* drag an X by Y area */ |
2607 if (_patches.measure_tooltip) { |
2751 if (_patches.measure_tooltip) { |
2608 static const StringID measure_strings_area[] = { |
2752 static const StringID measure_strings_area[] = { |
2609 STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF |
2753 STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF |
2610 }; |
2754 }; |
2611 |
2755 |
2612 TileIndex t0 = TileVirtXY(sx, sy); |
2756 TileIndex t0 = TileVirtXY(sx, sy); |
2613 TileIndex t1 = TileVirtXY(x, y); |
2757 TileIndex t1 = TileVirtXY(x, y); |
2614 uint dx = delta(TileX(t0), TileX(t1)) + 1; |
2758 uint dx = Delta(TileX(t0), TileX(t1)) + 1; |
2615 uint dy = delta(TileY(t0), TileY(t1)) + 1; |
2759 uint dy = Delta(TileY(t0), TileY(t1)) + 1; |
2616 byte index = 0; |
2760 byte index = 0; |
2617 uint64 params[3]; |
2761 uint64 params[3]; |
2618 |
2762 |
2619 /* If dragging an area (eg dynamite tool) and it is actually a single |
2763 /* If dragging an area (eg dynamite tool) and it is actually a single |
2620 * row/column, change the type to 'line' to get proper calculation for height */ |
2764 * row/column, change the type to 'line' to get proper calculation for height */ |
2697 w->wndproc(w, &e); |
2841 w->wndproc(w, &e); |
2698 |
2842 |
2699 return false; |
2843 return false; |
2700 } |
2844 } |
2701 |
2845 |
2702 void SetObjectToPlaceWnd(CursorID icon, SpriteID pal, byte mode, Window *w) |
2846 void SetObjectToPlaceWnd(CursorID icon, SpriteID pal, ViewportHighlightMode mode, Window *w) |
2703 { |
2847 { |
2704 SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number); |
2848 SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number); |
2705 } |
2849 } |
2706 |
2850 |
2707 #include "table/animcursors.h" |
2851 #include "table/animcursors.h" |
2708 |
2852 |
2709 void SetObjectToPlace(CursorID icon, SpriteID pal, byte mode, WindowClass window_class, WindowNumber window_num) |
2853 void SetObjectToPlace(CursorID icon, SpriteID pal, ViewportHighlightMode mode, WindowClass window_class, WindowNumber window_num) |
2710 { |
2854 { |
2711 Window *w; |
2855 Window *w; |
2712 |
2856 |
2713 /* undo clicking on button */ |
2857 /* undo clicking on button */ |
2714 if (_thd.place_mode != 0) { |
2858 if (_thd.place_mode != VHM_NONE) { |
2715 _thd.place_mode = 0; |
2859 _thd.place_mode = VHM_NONE; |
2716 w = FindWindowById(_thd.window_class, _thd.window_number); |
2860 w = FindWindowById(_thd.window_class, _thd.window_number); |
2717 if (w != NULL) CallWindowEventNP(w, WE_ABORT_PLACE_OBJ); |
2861 if (w != NULL) CallWindowEventNP(w, WE_ABORT_PLACE_OBJ); |
2718 } |
2862 } |
2719 |
2863 |
2720 SetTileSelectSize(1, 1); |
2864 SetTileSelectSize(1, 1); |
2721 |
2865 |
2722 _thd.make_square_red = false; |
2866 _thd.make_square_red = false; |
2723 |
2867 |
2724 if (mode == VHM_DRAG) { // mode 4 is for dragdropping trains in the depot window |
2868 if (mode == VHM_DRAG) { // VHM_DRAG is for dragdropping trains in the depot window |
2725 mode = 0; |
2869 mode = VHM_NONE; |
2726 _special_mouse_mode = WSM_DRAGDROP; |
2870 _special_mouse_mode = WSM_DRAGDROP; |
2727 } else { |
2871 } else { |
2728 _special_mouse_mode = WSM_NONE; |
2872 _special_mouse_mode = WSM_NONE; |
2729 } |
2873 } |
2730 |
2874 |