5 #include "../siflib/sif.h"
6 #include "../siflib/sifloader.h"
7 #include "../siflib/sectSprites.h"
8 #include "../siflib/sectStringArray.h"
9 #include "../autogen/sprites.h"
10 #include "../common/StringList.h"
11 #include "../dirnames.h"
12 #include "../settings.h"
13 using namespace Graphics
;
16 #include "sprites.fdh"
18 static NXSurface
*spritesheet
[MAX_SPRITESHEETS
];
19 static int num_spritesheets
;
20 static StringList sheetfiles
;
22 SIFSprite sprites
[MAX_SPRITES
];
28 memset(spritesheet
, 0, sizeof(spritesheet
));
30 // load sprites info--sheet positions, bounding boxes etc
31 if (load_sif("sprites.sif"))
34 num_spritesheets
= sheetfiles
.CountItems();
41 sheetfiles
.MakeEmpty();
44 void Sprites::FlushSheets()
46 for(int i
=0;i
<MAX_SPRITESHEETS
;i
++)
50 delete spritesheet
[i
];
51 spritesheet
[i
] = NULL
;
57 void c------------------------------() {}
60 // ensure the given spritesheet is loaded
61 static void Sprites::LoadSheetIfNeeded(int sheetno
)
63 if (!spritesheet
[sheetno
])
65 char pbm_name
[MAXPATHLEN
];
67 sprintf(pbm_name
, "%s/%s", data_dir
, sheetfiles
.StringAt(sheetno
));
68 spritesheet
[sheetno
] = new NXSurface
;
69 spritesheet
[sheetno
]->LoadImage(pbm_name
, true);
71 // fix the blue dash in the middle of the starpoof effect on that one frame,
72 // I'm pretty sure this is a glitch.
73 if (!settings
->emulate_bugs
)
75 if (sheetno
== 3) // Caret.pbm
76 spritesheet
[sheetno
]->FillRect(40, 58, 41, 58, 0, 0, 0);
82 // master sprite drawing function
83 static void Sprites::BlitSprite(int x
, int y
, int s
, int frame
, uint8_t dir
, \
84 int xoff
, int yoff
, int wd
, int ht
)
86 LoadSheetIfNeeded(sprites
[s
].spritesheet
);
88 dir
%= sprites
[s
].ndirs
;
89 SIFDir
*sprdir
= &sprites
[s
].frame
[frame
].dir
[dir
];
91 DrawSurface(spritesheet
[sprites
[s
].spritesheet
], \
93 (sprdir
->sheet_offset
.x
+ xoff
), \
94 (sprdir
->sheet_offset
.y
+ yoff
), \
99 void c------------------------------() {}
103 // draw sprite "s" at [x,y]. drawing frame "frame" and dir "dir".
104 void Sprites::draw_sprite(int x
, int y
, int s
, int frame
, uint8_t dir
)
106 BlitSprite(x
, y
, s
, frame
, dir
, 0, 0, sprites
[s
].w
, sprites
[s
].h
);
109 // draw sprite "s", place it's draw point at [x,y] instead of it's upper-left corner.
110 void Sprites::draw_sprite_at_dp(int x
, int y
, int s
, int frame
, uint8_t dir
)
112 x
-= sprites
[s
].frame
[frame
].dir
[dir
].drawpoint
.x
;
113 y
-= sprites
[s
].frame
[frame
].dir
[dir
].drawpoint
.y
;
114 BlitSprite(x
, y
, s
, frame
, dir
, 0, 0, sprites
[s
].w
, sprites
[s
].h
);
118 // draw a portion of a sprite, such as a sprite in the middle of "teleporting".
119 // only the area between clipy1 (inclusive) and clipy2 (exclusive) are visible.
120 void Sprites::draw_sprite_clipped(int x
, int y
, int s
, int frame
, uint8_t dir
, \
121 int clipx1
, int clipx2
, int clipy1
, int clipy2
)
123 BlitSprite(x
+ clipx1
, y
+ clipy1
, s
, frame
, dir
, clipx1
, clipy1
, \
124 (clipx2
- clipx1
), (clipy2
- clipy1
));
127 // draw a clipped sprite while clipping only the width.
128 // used for drawing percentage bars, etc.
129 void Sprites::draw_sprite_clip_width(int x
, int y
, int s
, int frame
, int wd
)
131 BlitSprite(x
, y
, s
, frame
, 0, 0, 0, wd
, sprites
[s
].h
);
134 // draws a sprite at less than it's actual width by chopping it into two chunks.
135 // on the left, the first "repeat_at" pixels are drawn.
136 // then, the remaining "wd" is drawn from the right half of the sprite.
137 // used for things like drawing the textboxes.
138 void Sprites::draw_sprite_chopped(int x
, int y
, int s
, int frame
, int wd
, int repeat_at
)
142 if (wd
>= sprites
[s
].w
)
144 draw_sprite(x
, y
, s
, frame
);
148 // draw the left part
149 BlitSprite(x
, y
, s
, frame
, 0, 0, 0, repeat_at
, sprites
[s
].h
);
153 // draw the rest of it
154 xoff
= (sprites
[s
].w
- wd
);
156 BlitSprite(x
, y
, s
, frame
, 0, xoff
, 0, wd
, sprites
[s
].h
);
159 // draws a sprite to any arbitrary width by repeating it over the given distance.
160 // if needed, the rightmost instance of the sprite is clipped.
161 void Sprites::draw_sprite_repeating_x(int x
, int y
, int s
, int frame
, int wd
)
167 if (blitwd
> sprites
[s
].w
) blitwd
= sprites
[s
].w
;
169 BlitSprite(x
, y
, s
, frame
, 0, 0, 0, blitwd
, sprites
[s
].h
);
176 void c------------------------------() {}
179 // return the NXSurface for a given spritesheet #
180 NXSurface
*Sprites::get_spritesheet(int sheetno
)
182 LoadSheetIfNeeded(sheetno
);
183 return spritesheet
[sheetno
];
186 // create an empty spritesheet of the given size and return it's index.
187 int Sprites::create_spritesheet(int wd
, int ht
)
189 if (num_spritesheets
>= MAX_SPRITESHEETS
)
192 spritesheet
[num_spritesheets
] = new NXSurface(wd
, ht
);
193 return num_spritesheets
++;
196 // draw a sprite onto some surface other than the screen
197 void Sprites::draw_sprite_to_surface(NXSurface
*dst
, int x
, int y
, int s
, int frame
, uint8_t dir
)
199 Graphics::SetDrawTarget(dst
);
200 draw_sprite(x
, y
, s
, frame
, dir
);
201 Graphics::SetDrawTarget(screen
);
205 void c------------------------------() {}
208 static bool load_sif(const char *fname
)
211 uint8_t *sheetdata
, *spritesdata
;
212 int sheetdatalength
, spritesdatalength
;
214 if (sif
.LoadHeader(fname
))
217 if (!(sheetdata
= sif
.FindSection(SIF_SECTION_SHEETS
, &sheetdatalength
)))
219 staterr("load_sif: file '%s' missing SIF_SECTION_SHEETS", fname
);
223 if (!(spritesdata
= sif
.FindSection(SIF_SECTION_SPRITES
, &spritesdatalength
)))
225 staterr("load_sif: file '%s' missing SIF_SECTION_SPRITES", fname
);
230 sheetfiles
.MakeEmpty();
231 if (SIFStringArraySect::Decode(sheetdata
, sheetdatalength
, &sheetfiles
))
235 if (SIFSpritesSect::Decode(spritesdata
, spritesdatalength
, \
236 &sprites
[0], &num_sprites
, MAX_SPRITES
))
238 staterr("load_sif: SIFSpritesSect decoder failed");
244 create_slope_boxes();
245 offset_by_draw_points();
246 expand_single_dir_sprites();
252 // create slope boxes for all sprites, used by the slope-handling routines
253 // these are basically just a form of bounding box describing the bounds of the
255 static void create_slope_boxes()
257 for(int s
=0;s
<num_sprites
;s
++)
259 if (sprites
[s
].block_d
.count
!= 0)
261 int leftmost
= 99999;
262 int rightmost
= -99999;
263 for(int i
=0;i
<sprites
[s
].block_d
.count
;i
++)
265 if (sprites
[s
].block_d
[i
].x
< leftmost
) leftmost
= sprites
[s
].block_d
[i
].x
;
266 if (sprites
[s
].block_d
[i
].x
> rightmost
) rightmost
= sprites
[s
].block_d
[i
].x
;
269 sprites
[s
].slopebox
.x1
= leftmost
;
270 sprites
[s
].slopebox
.x2
= rightmost
;
272 if (sprites
[s
].block_u
.count
)
273 sprites
[s
].slopebox
.y1
= (sprites
[s
].block_u
[0].y
+ 1);
275 sprites
[s
].slopebox
.y1
= 0;
277 sprites
[s
].slopebox
.y2
= (sprites
[s
].block_d
[0].y
- 1);
281 sprites
[SPR_MYCHAR
].slopebox
.y1
+= 3;
284 // offset things like blockl/r/u/d, bounding box etc by the draw point of all
285 // sprites so that these things are consistent with where the sprite appears to be
286 static void offset_by_draw_points()
288 for(int s
=0;s
<num_sprites
;s
++)
290 int dx
= -sprites
[s
].frame
[0].dir
[0].drawpoint
.x
;
291 int dy
= -sprites
[s
].frame
[0].dir
[0].drawpoint
.y
;
293 sprites
[s
].bbox
.offset(dx
, dy
);
294 sprites
[s
].slopebox
.offset(dx
, dy
);
295 sprites
[s
].solidbox
.offset(dx
, dy
);
297 sprites
[s
].block_l
.offset(dx
, dy
);
298 sprites
[s
].block_r
.offset(dx
, dy
);
299 sprites
[s
].block_u
.offset(dx
, dy
);
300 sprites
[s
].block_d
.offset(dx
, dy
);
302 for(int f
=0;f
<sprites
[s
].nframes
;f
++)
304 for(int d
=0;d
<sprites
[s
].ndirs
;d
++)
306 int dx
= -sprites
[s
].frame
[f
].dir
[d
].drawpoint
.x
;
307 int dy
= -sprites
[s
].frame
[f
].dir
[d
].drawpoint
.y
;
308 sprites
[s
].frame
[f
].dir
[d
].pf_bbox
.offset(dx
, dy
);
314 // for sprites which only have 1 dir (no separate frames for left & right),
315 // create a 2nd identical dir as the rest of the engine doesn't bother
316 // with this complication.
317 static void expand_single_dir_sprites()
319 for(int s
=0;s
<num_sprites
;s
++)
321 if (sprites
[s
].ndirs
== 1)
323 sprites
[s
].ndirs
= 2;
324 for(int f
=0;f
<sprites
[s
].nframes
;f
++)
325 sprites
[s
].frame
[f
].dir
[1] = sprites
[s
].frame
[f
].dir
[0];