1 #include "sectSprites.h"
2 
3 #include "../common/bufio.h"
4 #include "../Utils/Logger.h"
5 
6 #include <cstdlib>
7 #include <cstring>
8 
GetSpriteCount(const uint8_t * data,int datalen)9 int SIFSpritesSect::GetSpriteCount(const uint8_t *data, int datalen)
10 {
11   const uint8_t *data_end = data + (datalen - 1);
12   return read_U16(&data, data_end);
13 }
14 
Decode(const uint8_t * data,int datalen,SIFSprite * sprites,int * nsprites_out,int maxsprites)15 bool SIFSpritesSect::Decode(const uint8_t *data, int datalen, SIFSprite *sprites, int *nsprites_out, int maxsprites)
16 {
17   const uint8_t *data_end = data + (datalen - 1);
18   int i, f, nsprites;
19 
20   nsprites = read_U16(&data, data_end);
21   if (nsprites_out)
22     *nsprites_out = nsprites;
23 
24   if (nsprites >= maxsprites)
25   {
26     LOG_ERROR("SIFSpritesSect::Decode: too many sprites in file (nsprites={}, maxsprites={})", nsprites, maxsprites);
27     return 1;
28   }
29 
30   LOG_DEBUG("SIFSpritesSect: loading {} sprites", nsprites);
31   for (i = 0; i < nsprites; i++)
32   {
33     if (data > data_end)
34     {
35       LOG_ERROR("SIFSpritesSect::Decode: section corrupt: overran end of data");
36       return 1;
37     }
38 
39     // read sprite-level fields
40     sprites[i].w           = read_U8(&data, data_end);
41     sprites[i].h           = read_U8(&data, data_end);
42     sprites[i].spritesheet = read_U8(&data, data_end);
43 
44     sprites[i].nframes = read_U8(&data, data_end);
45     sprites[i].ndirs   = read_U8(&data, data_end);
46 
47     if (sprites[i].ndirs > SIF_MAX_DIRS)
48     {
49       LOG_ERROR("SIFSpritesSect::Decode: SIF_MAX_DIRS exceeded on sprite {} (ndirs={})", i, sprites[i].ndirs);
50       return 1;
51     }
52 
53 
54     for (f = 0; f < sprites[i].ndirs; f++)
55       LoadRect(&sprites[i].bbox[f], &data, data_end);
56     LoadRect(&sprites[i].solidbox, &data, data_end);
57 
58     LoadPoint(&sprites[i].spawn_point, &data, data_end);
59 
60     LoadPointList(&sprites[i].block_l, &data, data_end);
61     LoadPointList(&sprites[i].block_r, &data, data_end);
62     LoadPointList(&sprites[i].block_u, &data, data_end);
63     LoadPointList(&sprites[i].block_d, &data, data_end);
64 
65     // malloc enough space to hold the specified number
66     // of apple fritters, i mean, frames.
67     sprites[i].frame = (SIFFrame *)malloc(sizeof(SIFFrame) * sprites[i].nframes);
68 
69     // then load all frames
70     for (f = 0; f < sprites[i].nframes; f++)
71     {
72       if (LoadFrame(&sprites[i].frame[f], sprites[i].ndirs, &data, data_end))
73         return 1;
74     }
75   }
76 
77   return 0;
78 }
79 
LoadFrame(SIFFrame * frame,int ndirs,const uint8_t ** data,const uint8_t * data_end)80 bool SIFSpritesSect::LoadFrame(SIFFrame *frame, int ndirs, const uint8_t **data, const uint8_t *data_end)
81 {
82   // sets defaults for un-specified/default fields
83   memset(frame, 0, sizeof(SIFFrame));
84 
85   for (int d = 0; d < ndirs; d++)
86   {
87     SIFDir *dir = &frame->dir[d];
88     LoadPoint(&dir->sheet_offset, data, data_end);
89 
90     int t;
91     for (;;)
92     {
93       t = read_U8(data, data_end);
94       if (t == S_DIR_END)
95         break;
96 
97       switch (t)
98       {
99         case S_DIR_DRAW_POINT:
100           LoadPoint(&dir->drawpoint, data, data_end);
101           break;
102         case S_DIR_ACTION_POINT:
103           LoadPoint(&dir->actionpoint, data, data_end);
104           break;
105         case S_DIR_ACTION_POINT_2:
106           LoadPoint(&dir->actionpoint2, data, data_end);
107           break;
108 
109         case S_DIR_PF_BBOX:
110           LoadRect(&dir->pf_bbox, data, data_end);
111           break;
112 
113         default:
114           LOG_WARN("SIFSpriteSect::LoadFrame: encountered unknown optional field type {}", t);
115           return 1;
116       }
117     }
118   }
119 
120   return 0;
121 }
122 
123 /*
124 void c------------------------------() {}
125 */
126 
LoadRect(SIFRect * rect,const uint8_t ** data,const uint8_t * data_end)127 void SIFSpritesSect::LoadRect(SIFRect *rect, const uint8_t **data, const uint8_t *data_end)
128 {
129   rect->x1 = (int16_t)read_U16(data, data_end);
130   rect->y1 = (int16_t)read_U16(data, data_end);
131   rect->x2 = (int16_t)read_U16(data, data_end);
132   rect->y2 = (int16_t)read_U16(data, data_end);
133 }
134 
LoadPoint(SIFPoint * pt,const uint8_t ** data,const uint8_t * data_end)135 void SIFSpritesSect::LoadPoint(SIFPoint *pt, const uint8_t **data, const uint8_t *data_end)
136 {
137   pt->x = (int16_t)read_U16(data, data_end);
138   pt->y = (int16_t)read_U16(data, data_end);
139 }
140 
LoadPointList(SIFPointList * lst,const uint8_t ** data,const uint8_t * data_end)141 void SIFSpritesSect::LoadPointList(SIFPointList *lst, const uint8_t **data, const uint8_t *data_end)
142 {
143   lst->count = read_U8(data, data_end);
144   if (lst->count > SIF_MAX_BLOCK_POINTS)
145   {
146     LOG_ERROR("SIFSpritesSect::LoadPointList: too many block points ({}, max={})", lst->count, SIF_MAX_BLOCK_POINTS);
147     return;
148   }
149 
150   for (int i = 0; i < lst->count; i++)
151   {
152     lst->point[i].x = (int16_t)read_U16(data, data_end);
153     lst->point[i].y = (int16_t)read_U16(data, data_end);
154   }
155 }
156