1// MIT License
2
3// Copyright (c) 2017 Vadim Grigoruk @nesbox // grigoruk@gmail.com
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#include "tools.h"
24
25#include <ctype.h>
26#include <string.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <zlib.h>
30
31extern void tic_tool_poke4(void* addr, u32 index, u8 value);
32extern u8 tic_tool_peek4(const void* addr, u32 index);
33extern void tic_tool_poke2(void* addr, u32 index, u8 value);
34extern u8 tic_tool_peek2(const void* addr, u32 index);
35extern void tic_tool_poke1(void* addr, u32 index, u8 value);
36extern u8 tic_tool_peek1(const void* addr, u32 index);
37extern s32 tic_tool_sfx_pos(s32 speed, s32 ticks);
38extern u32 tic_rgba(const tic_rgb* c);
39extern s32 tic_modulo(s32 x, s32 m);
40
41static u32 getPatternData(const tic_track* track, s32 frame)
42{
43 u32 patternData = 0;
44 for(s32 b = 0; b < TRACK_PATTERNS_SIZE; b++)
45 patternData |= track->data[frame * TRACK_PATTERNS_SIZE + b] << (BITS_IN_BYTE * b);
46
47 return patternData;
48}
49
50s32 tic_tool_get_pattern_id(const tic_track* track, s32 frame, s32 channel)
51{
52 return (getPatternData(track, frame) >> (channel * TRACK_PATTERN_BITS)) & TRACK_PATTERN_MASK;
53}
54
55void tic_tool_set_pattern_id(tic_track* track, s32 frame, s32 channel, s32 pattern)
56{
57 u32 patternData = getPatternData(track, frame);
58 s32 shift = channel * TRACK_PATTERN_BITS;
59
60 patternData &= ~(TRACK_PATTERN_MASK << shift);
61 patternData |= pattern << shift;
62
63 for(s32 b = 0; b < TRACK_PATTERNS_SIZE; b++)
64 track->data[frame * TRACK_PATTERNS_SIZE + b] = (patternData >> (b * BITS_IN_BYTE)) & 0xff;
65}
66
67bool tic_tool_parse_note(const char* noteStr, s32* note, s32* octave)
68{
69 if(noteStr && strlen(noteStr) == 3)
70 {
71 static const char* Notes[] = SFX_NOTES;
72
73 for(s32 i = 0; i < COUNT_OF(Notes); i++)
74 {
75 if(memcmp(Notes[i], noteStr, 2) == 0)
76 {
77 *note = i;
78 *octave = noteStr[2] - '1';
79 break;
80 }
81 }
82
83 return true;
84 }
85
86 return false;
87}
88
89u32 tic_nearest_color(const tic_rgb* palette, const tic_rgb* color, s32 count)
90{
91 u32 min = -1;
92 s32 nearest, i = 0;
93
94 for(const tic_rgb *rgb = palette, *end = rgb + count; rgb < end; rgb++, i++)
95 {
96 s32 d[] = {color->r - rgb->r, color->g - rgb->g, color->b - rgb->b};
97
98 u32 dst = 0;
99 for(const s32 *v = d, *end = v + COUNT_OF(d); v < end; v++)
100 dst += (*v) * (*v);
101
102 if (dst < min)
103 {
104 min = dst;
105 nearest = i;
106 }
107 }
108
109 return nearest;
110}
111
112tic_blitpal tic_tool_palette_blit(const tic_palette* srcpal, tic80_pixel_color_format fmt)
113{
114 tic_blitpal pal;
115
116 const tic_rgb* src = srcpal->colors;
117 const tic_rgb* end = src + TIC_PALETTE_SIZE;
118 u8* dst = (u8*)pal.data;
119
120 while(src != end)
121 {
122 switch(fmt){
123 case TIC80_PIXEL_COLOR_BGRA8888:
124 *dst++ = src->b;
125 *dst++ = src->g;
126 *dst++ = src->r;
127 *dst++ = 0xff;
128 break;
129 case TIC80_PIXEL_COLOR_RGBA8888:
130 *dst++ = src->r;
131 *dst++ = src->g;
132 *dst++ = src->b;
133 *dst++ = 0xff;
134 break;
135 case TIC80_PIXEL_COLOR_ABGR8888:
136 *dst++ = 0xff;
137 *dst++ = src->b;
138 *dst++ = src->g;
139 *dst++ = src->r;
140 break;
141 case TIC80_PIXEL_COLOR_ARGB8888:
142 *dst++ = 0xff;
143 *dst++ = src->r;
144 *dst++ = src->g;
145 *dst++ = src->b;
146 break;
147 }
148 src++;
149 }
150
151 return pal;
152}
153
154bool tic_project_ext(const char* name)
155{
156 FOR_EACH_LANG(ln)
157 {
158 if(tic_tool_has_ext(name, ln->fileExtension))
159 return true;
160 }
161 FOR_EACH_LANG_END
162 return false;
163}
164
165bool tic_tool_has_ext(const char* name, const char* ext)
166{
167 return strcmp(name + strlen(name) - strlen(ext), ext) == 0;
168}
169
170s32 tic_tool_get_track_row_sfx(const tic_track_row* row)
171{
172 return (row->sfxhi << MUSIC_SFXID_LOW_BITS) | row->sfxlow;
173}
174
175void tic_tool_set_track_row_sfx(tic_track_row* row, s32 sfx)
176{
177 if(sfx >= SFX_COUNT) sfx = SFX_COUNT-1;
178
179 row->sfxhi = (sfx & 0x20) >> MUSIC_SFXID_LOW_BITS;
180 row->sfxlow = sfx & 0x1f;
181}
182
183bool tic_tool_empty(const void* buffer, s32 size)
184{
185 for(const u8 *ptr = buffer, *end = ptr + size; ptr < end;)
186 if(*ptr++)
187 return false;
188
189 return true;
190}
191
192bool tic_tool_flat4(const void* buffer, s32 size)
193{
194 u8 first = (*(u8*)buffer) & 0xf;
195 first |= first << 4;
196 for(const u8 *ptr = buffer, *end = ptr + size; ptr < end;)
197 if(*ptr++ != first)
198 return false;
199
200 return true;
201}
202
203bool tic_tool_noise(const tic_waveform* wave)
204{
205 return FLAT4(wave->data) && *wave->data % 0xff == 0;
206}
207
208void tic_tool_str2buf(const char* str, s32 size, void* buf, bool flip)
209{
210 char val[] = "0x00";
211 const char* ptr = str;
212
213 for(s32 i = 0; i < size/2; i++)
214 {
215 if(flip)
216 {
217 val[3] = *ptr++;
218 val[2] = *ptr++;
219 }
220 else
221 {
222 val[2] = *ptr++;
223 val[3] = *ptr++;
224 }
225
226 ((u8*)buf)[i] = (u8)strtol(val, NULL, 16);
227 }
228}
229
230u32 tic_tool_zip(void* dest, s32 destSize, const void* source, s32 size)
231{
232 unsigned long destSizeLong = destSize;
233 return compress2(dest, &destSizeLong, source, size, Z_BEST_COMPRESSION) == Z_OK ? destSizeLong : 0;
234}
235
236u32 tic_tool_unzip(void* dest, s32 destSize, const void* source, s32 size)
237{
238 unsigned long destSizeLong = destSize;
239 return uncompress(dest, &destSizeLong, source, size) == Z_OK ? destSizeLong : 0;
240}
241
242char* tic_tool_metatag(const char* code, const char* tag, const char* comment)
243{
244 const char* start = NULL;
245
246 {
247 static char format[] = "%s %s:";
248
249 char* tagBuffer = malloc(sizeof format + strlen(tag));
250
251 SCOPE(free(tagBuffer))
252 {
253 sprintf(tagBuffer, format, comment, tag);
254 if ((start = strstr(code, tagBuffer)))
255 start += strlen(tagBuffer);
256 }
257 }
258
259 if (start)
260 {
261 const char* end = strstr(start, "\n");
262
263 if (end)
264 {
265 while (isspace(*start) && start < end) start++;
266 while (isspace(*(end - 1)) && end > start) end--;
267
268 const s32 size = (s32)(end - start);
269
270 char* value = (char*)malloc(size + 1);
271
272 if (value)
273 {
274 memset(value, 0, size + 1);
275 memcpy(value, start, size);
276
277 return value;
278 }
279 }
280 }
281
282 return NULL;
283}