107 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(StringSpriteToDraw)); |
107 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(StringSpriteToDraw)); |
108 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(TileSpriteToDraw)); |
108 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(TileSpriteToDraw)); |
109 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ChildScreenSpriteToDraw)); |
109 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ChildScreenSpriteToDraw)); |
110 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ParentSpriteToDraw)); |
110 assert_compile(sizeof(LARGEST_SPRITELIST_STRUCT) >= sizeof(ParentSpriteToDraw)); |
111 |
111 |
|
112 /* Enumeration of multi-part foundations */ |
|
113 enum FoundationPart { |
|
114 FOUNDATION_PART_NONE = 0xFF, ///< Neither foundation nor groundsprite drawn yet. |
|
115 FOUNDATION_PART_NORMAL = 0, ///< First part (normal foundation or no foundation) |
|
116 FOUNDATION_PART_HALFTILE = 1, ///< Second part (halftile foundation) |
|
117 FOUNDATION_PART_END |
|
118 }; |
|
119 |
112 struct ViewportDrawer { |
120 struct ViewportDrawer { |
113 DrawPixelInfo dpi; |
121 DrawPixelInfo dpi; |
114 |
122 |
115 byte *spritelist_mem; |
123 byte *spritelist_mem; |
116 const byte *eof_spritelist_mem; |
124 const byte *eof_spritelist_mem; |
123 ParentSpriteToDraw **parent_list; |
131 ParentSpriteToDraw **parent_list; |
124 ParentSpriteToDraw * const *eof_parent_list; |
132 ParentSpriteToDraw * const *eof_parent_list; |
125 |
133 |
126 byte combine_sprites; |
134 byte combine_sprites; |
127 |
135 |
128 ParentSpriteToDraw *foundation; ///< Foundation sprite. |
136 ParentSpriteToDraw *foundation[FOUNDATION_PART_END]; ///< Foundation sprites. |
129 ChildScreenSpriteToDraw **last_foundation_child; ///< Tail of ChildSprite list of active foundation. |
137 FoundationPart foundation_part; ///< Currently active foundation for ground sprite drawing. |
130 Point foundation_offset; ///< Pixeloffset of ground sprites on the foundation. |
138 ChildScreenSpriteToDraw **last_foundation_child[FOUNDATION_PART_END]; ///< Tail of ChildSprite list of the foundations. |
|
139 Point foundation_offset[FOUNDATION_PART_END]; ///< Pixeloffset for ground sprites on the foundations. |
131 }; |
140 }; |
132 |
141 |
133 static ViewportDrawer *_cur_vd; |
142 static ViewportDrawer *_cur_vd; |
134 |
143 |
135 TileHighlightData _thd; |
144 TileHighlightData _thd; |
479 * The pixel offset of the sprite relative to the ParentSprite is the sum of the offset passed to OffsetGroundSprite() and extra_offs_?. |
488 * The pixel offset of the sprite relative to the ParentSprite is the sum of the offset passed to OffsetGroundSprite() and extra_offs_?. |
480 * |
489 * |
481 * @param image the image to draw. |
490 * @param image the image to draw. |
482 * @param pal the provided palette. |
491 * @param pal the provided palette. |
483 * @param sub Only draw a part of the sprite. |
492 * @param sub Only draw a part of the sprite. |
|
493 * @param foundation_part Foundation part. |
484 * @param extra_offs_x Pixel X offset for the sprite position. |
494 * @param extra_offs_x Pixel X offset for the sprite position. |
485 * @param extra_offs_y Pixel Y offset for the sprite position. |
495 * @param extra_offs_y Pixel Y offset for the sprite position. |
486 */ |
496 */ |
487 static void AddChildSpriteToFoundation(SpriteID image, SpriteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y) |
497 static void AddChildSpriteToFoundation(SpriteID image, SpriteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y) |
488 { |
498 { |
489 ViewportDrawer *vd = _cur_vd; |
499 ViewportDrawer *vd = _cur_vd; |
490 assert(vd->foundation != NULL); |
500 assert(IS_INT_INSIDE(foundation_part, 0, FOUNDATION_PART_END)); |
491 Point offs = vd->foundation_offset; |
501 assert(vd->foundation[foundation_part] != NULL); |
|
502 Point offs = vd->foundation_offset[foundation_part]; |
492 |
503 |
493 /* Change the active ChildSprite list to the one of the foundation */ |
504 /* Change the active ChildSprite list to the one of the foundation */ |
494 ChildScreenSpriteToDraw **old_child = vd->last_child; |
505 ChildScreenSpriteToDraw **old_child = vd->last_child; |
495 vd->last_child = vd->last_foundation_child; |
506 vd->last_child = vd->last_foundation_child[foundation_part]; |
496 |
507 |
497 AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub); |
508 AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub); |
498 |
509 |
499 /* Switch back to last ChildSprite list */ |
510 /* Switch back to last ChildSprite list */ |
500 vd->last_child = old_child; |
511 vd->last_child = old_child; |
509 * @param sub Only draw a part of the sprite. |
520 * @param sub Only draw a part of the sprite. |
510 */ |
521 */ |
511 void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub) |
522 void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub) |
512 { |
523 { |
513 ViewportDrawer *vd = _cur_vd; |
524 ViewportDrawer *vd = _cur_vd; |
514 if (vd->foundation != NULL) { |
525 /* Switch to first foundation part, if no foundation was drawn */ |
515 AddChildSpriteToFoundation(image, pal, sub, 0, 0); |
526 if (vd->foundation_part == FOUNDATION_PART_NONE) vd->foundation_part = FOUNDATION_PART_NORMAL; |
|
527 |
|
528 if (vd->foundation[vd->foundation_part] != NULL) { |
|
529 AddChildSpriteToFoundation(image, pal, sub, vd->foundation_part, 0, 0); |
516 } else { |
530 } else { |
517 DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z, sub); |
531 DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z, sub); |
518 } |
532 } |
519 } |
533 } |
520 |
534 |
527 * @param y sprite y-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. |
541 * @param y sprite y-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. |
528 */ |
542 */ |
529 void OffsetGroundSprite(int x, int y) |
543 void OffsetGroundSprite(int x, int y) |
530 { |
544 { |
531 ViewportDrawer *vd = _cur_vd; |
545 ViewportDrawer *vd = _cur_vd; |
532 assert(vd->foundation == NULL); |
546 /* Switch to next foundation part */ |
|
547 switch (vd->foundation_part) { |
|
548 case FOUNDATION_PART_NONE: |
|
549 vd->foundation_part = FOUNDATION_PART_NORMAL; |
|
550 break; |
|
551 case FOUNDATION_PART_NORMAL: |
|
552 vd->foundation_part = FOUNDATION_PART_HALFTILE; |
|
553 break; |
|
554 default: NOT_REACHED(); |
|
555 } |
533 |
556 |
534 /* vd->last_child == NULL if foundation sprite was clipped by the viewport bounds */ |
557 /* vd->last_child == NULL if foundation sprite was clipped by the viewport bounds */ |
535 if (vd->last_child != NULL) vd->foundation = vd->parent_list[-1]; |
558 if (vd->last_child != NULL) vd->foundation[vd->foundation_part] = vd->parent_list[-1]; |
536 |
559 |
537 vd->foundation_offset.x = x; |
560 vd->foundation_offset[vd->foundation_part].x = x; |
538 vd->foundation_offset.y = y; |
561 vd->foundation_offset[vd->foundation_part].y = y; |
539 vd->last_foundation_child = vd->last_child; |
562 vd->last_foundation_child[vd->foundation_part] = vd->last_child; |
540 } |
563 } |
541 |
564 |
542 /** |
565 /** |
543 * Adds a child sprite to a parent sprite. |
566 * Adds a child sprite to a parent sprite. |
544 * In contrast to "AddChildSpriteScreen()" the sprite position is in world coordinates |
567 * In contrast to "AddChildSpriteScreen()" the sprite position is in world coordinates |
728 vd->spritelist_mem += sizeof(ChildScreenSpriteToDraw); |
751 vd->spritelist_mem += sizeof(ChildScreenSpriteToDraw); |
729 |
752 |
730 /* Append the sprite to the active ChildSprite list. |
753 /* Append the sprite to the active ChildSprite list. |
731 * If the active ParentSprite is a foundation, update last_foundation_child as well. */ |
754 * If the active ParentSprite is a foundation, update last_foundation_child as well. */ |
732 *vd->last_child = cs; |
755 *vd->last_child = cs; |
733 if (vd->last_foundation_child == vd->last_child) vd->last_foundation_child = &cs->next; |
756 if (vd->last_foundation_child[0] == vd->last_child) vd->last_foundation_child[0] = &cs->next; |
|
757 if (vd->last_foundation_child[1] == vd->last_child) vd->last_foundation_child[1] = &cs->next; |
734 vd->last_child = &cs->next; |
758 vd->last_child = &cs->next; |
735 |
759 |
736 cs->image = image; |
760 cs->image = image; |
737 cs->pal = pal; |
761 cs->pal = pal; |
738 cs->sub = sub; |
762 cs->sub = sub; |
777 * |
801 * |
778 * @param image the image to draw. |
802 * @param image the image to draw. |
779 * @param pal the provided palette. |
803 * @param pal the provided palette. |
780 * @param ti TileInfo Tile that is being drawn |
804 * @param ti TileInfo Tile that is being drawn |
781 * @param z_offset Z offset relative to the groundsprite. Only used for the sprite position, not for sprite sorting. |
805 * @param z_offset Z offset relative to the groundsprite. Only used for the sprite position, not for sprite sorting. |
|
806 * @param foundation_part Foundation part the sprite belongs to. |
782 */ |
807 */ |
783 static void DrawSelectionSprite(SpriteID image, SpriteID pal, const TileInfo *ti, int z_offset) |
808 static void DrawSelectionSprite(SpriteID image, SpriteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part) |
784 { |
809 { |
785 /* FIXME: This is not totally valid for some autorail highlights, that extent over the edges of the tile. */ |
810 /* FIXME: This is not totally valid for some autorail highlights, that extent over the edges of the tile. */ |
786 if (_cur_vd->foundation == NULL) { |
811 if (_cur_vd->foundation[foundation_part] == NULL) { |
787 /* draw on real ground */ |
812 /* draw on real ground */ |
788 DrawGroundSpriteAt(image, pal, ti->x, ti->y, ti->z + z_offset); |
813 DrawGroundSpriteAt(image, pal, ti->x, ti->y, ti->z + z_offset); |
789 } else { |
814 } else { |
790 /* draw on top of foundation */ |
815 /* draw on top of foundation */ |
791 AddChildSpriteToFoundation(image, pal, NULL, 0, -z_offset); |
816 AddChildSpriteToFoundation(image, pal, NULL, foundation_part, 0, -z_offset); |
792 } |
817 } |
793 } |
818 } |
794 |
819 |
795 /** |
820 /** |
796 * Draws a selection rectangle on a tile. |
821 * Draws a selection rectangle on a tile. |
798 * @param ti TileInfo Tile that is being drawn |
823 * @param ti TileInfo Tile that is being drawn |
799 * @param pal Palette to apply. |
824 * @param pal Palette to apply. |
800 */ |
825 */ |
801 static void DrawTileSelectionRect(const TileInfo *ti, SpriteID pal) |
826 static void DrawTileSelectionRect(const TileInfo *ti, SpriteID pal) |
802 { |
827 { |
803 DrawSelectionSprite(SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh], pal, ti, 7); |
828 SpriteID sel; |
|
829 if (IsHalftileSlope(ti->tileh)) { |
|
830 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); |
|
831 SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner; |
|
832 DrawSelectionSprite(sel2, pal, ti, 7 + TILE_HEIGHT, FOUNDATION_PART_HALFTILE); |
|
833 |
|
834 Corner opposite_corner = OppositeCorner(halftile_corner); |
|
835 if (IsSteepSlope(ti->tileh)) { |
|
836 sel = SPR_HALFTILE_SELECTION_DOWN; |
|
837 } else { |
|
838 sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT); |
|
839 } |
|
840 sel += opposite_corner; |
|
841 } else { |
|
842 sel = SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]; |
|
843 } |
|
844 DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL); |
804 } |
845 } |
805 |
846 |
806 static bool IsPartOfAutoLine(int px, int py) |
847 static bool IsPartOfAutoLine(int px, int py) |
807 { |
848 { |
808 px -= _thd.selstart.x; |
849 px -= _thd.selstart.x; |
845 { |
886 { |
846 SpriteID image; |
887 SpriteID image; |
847 SpriteID pal; |
888 SpriteID pal; |
848 int offset; |
889 int offset; |
849 |
890 |
850 offset = _AutorailTilehSprite[ti->tileh][autorail_type]; |
891 FoundationPart foundation_part = FOUNDATION_PART_NORMAL; |
|
892 Slope autorail_tileh = (Slope)(ti->tileh & ~SLOPE_HALFTILE_MASK); |
|
893 if (IsHalftileSlope(ti->tileh)) { |
|
894 static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U }; |
|
895 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); |
|
896 if (autorail_type != _lower_rail[halftile_corner]) { |
|
897 foundation_part = FOUNDATION_PART_HALFTILE; |
|
898 /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */ |
|
899 autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner)); |
|
900 } |
|
901 } |
|
902 |
|
903 offset = _AutorailTilehSprite[autorail_tileh][autorail_type]; |
851 if (offset >= 0) { |
904 if (offset >= 0) { |
852 image = SPR_AUTORAIL_BASE + offset; |
905 image = SPR_AUTORAIL_BASE + offset; |
853 pal = PAL_NONE; |
906 pal = PAL_NONE; |
854 } else { |
907 } else { |
855 image = SPR_AUTORAIL_BASE - offset; |
908 image = SPR_AUTORAIL_BASE - offset; |
856 pal = PALETTE_SEL_TILE_RED; |
909 pal = PALETTE_SEL_TILE_RED; |
857 } |
910 } |
858 |
911 |
859 DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7); |
912 DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part); |
860 } |
913 } |
861 |
914 |
862 /** |
915 /** |
863 * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. |
916 * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. |
864 * @param *ti TileInfo Tile that is being drawn |
917 * @param *ti TileInfo Tile that is being drawn |
880 if (_thd.drawstyle & HT_RECT) { |
933 if (_thd.drawstyle & HT_RECT) { |
881 DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); |
934 DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); |
882 } else if (_thd.drawstyle & HT_POINT) { |
935 } else if (_thd.drawstyle & HT_POINT) { |
883 /* Figure out the Z coordinate for the single dot. */ |
936 /* Figure out the Z coordinate for the single dot. */ |
884 byte z = 0; |
937 byte z = 0; |
|
938 FoundationPart foundation_part = FOUNDATION_PART_NORMAL; |
885 if (ti->tileh & SLOPE_N) { |
939 if (ti->tileh & SLOPE_N) { |
886 z += TILE_HEIGHT; |
940 z += TILE_HEIGHT; |
887 if (ti->tileh == SLOPE_STEEP_N) z += TILE_HEIGHT; |
941 if ((ti->tileh & ~SLOPE_HALFTILE_MASK) == SLOPE_STEEP_N) z += TILE_HEIGHT; |
888 } |
942 } |
889 DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z); |
943 if (IsHalftileSlope(ti->tileh)) { |
|
944 Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); |
|
945 if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT; |
|
946 if (halftile_corner != CORNER_S) { |
|
947 foundation_part = FOUNDATION_PART_HALFTILE; |
|
948 if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT; |
|
949 } |
|
950 } |
|
951 DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part); |
890 } else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) { |
952 } else if (_thd.drawstyle & HT_RAIL /*&& _thd.place_mode == VHM_RAIL*/) { |
891 /* autorail highlight piece under cursor */ |
953 /* autorail highlight piece under cursor */ |
892 uint type = _thd.drawstyle & 0xF; |
954 uint type = _thd.drawstyle & 0xF; |
893 assert(type <= 5); |
955 assert(type <= 5); |
894 DrawAutorailSelection(ti, _AutorailType[type][0]); |
956 DrawAutorailSelection(ti, _AutorailType[type][0]); |
895 |
|
896 } else if (IsPartOfAutoLine(ti->x, ti->y)) { |
957 } else if (IsPartOfAutoLine(ti->x, ti->y)) { |
897 /* autorail highlighting long line */ |
958 /* autorail highlighting long line */ |
898 int dir = _thd.drawstyle & ~0xF0; |
959 int dir = _thd.drawstyle & ~0xF0; |
899 uint side; |
960 uint side; |
900 |
961 |
971 } |
1032 } |
972 |
1033 |
973 y_cur += 0x10; |
1034 y_cur += 0x10; |
974 x_cur -= 0x10; |
1035 x_cur -= 0x10; |
975 |
1036 |
976 vd->foundation = NULL; |
1037 vd->foundation_part = FOUNDATION_PART_NONE; |
977 vd->last_foundation_child = NULL; |
1038 vd->foundation[0] = NULL; |
|
1039 vd->foundation[1] = NULL; |
|
1040 vd->last_foundation_child[0] = NULL; |
|
1041 vd->last_foundation_child[1] = NULL; |
978 |
1042 |
979 _tile_type_procs[tt]->draw_tile_proc(&ti); |
1043 _tile_type_procs[tt]->draw_tile_proc(&ti); |
980 DrawTileSelection(&ti); |
1044 DrawTileSelection(&ti); |
981 } while (--width_cur); |
1045 } while (--width_cur); |
982 |
1046 |