Clean up some more bin2c calls from the Makefile (#286)

* Remove some bin2c calls from the Makefile

* Found a way to make n64graphics use shared tluts

* Added an option that makes n64graphics operate in a mode where it
 takes an image and tlut (as pngs) and spits out the appropriate
 CI8 indices inc.c form

* Turns out all the TLUTs for Lakitu are kept in one place, far away
 from the textures that use them

* Names some textures and tluts

* Pretty helpful actually, helped identify where a few different
 objects types are initialized. Should be a little useful to
 whoever dives into the object stuff more deeply

* Minor cleanup in n64graphics

* Added some comments, gave more appropriate names to some
 variables.

* Leaving the new mode argument as `-Z` for now

Signed-off-by: Taggerung <tyler.taggerung@gmail.com>

* Textures compile using makefile rules

* Patched n64 graphics memory leak and ci output

* Added memset16safe to initialize ci palettes to magic numbers (transparent pixels).

---------

Signed-off-by: Taggerung <tyler.taggerung@gmail.com>
Co-authored-by: MegaMech <MegaMech@users.noreply.github.com>
This commit is contained in:
Tyler McGavran
2023-02-07 00:52:34 -05:00
committed by GitHub
parent 533d035875
commit 3a99685c2f
39 changed files with 1442 additions and 1564 deletions
+366 -212
View File
@@ -21,6 +21,7 @@
#define SCALE_3_8(VAL_) ((VAL_) * 0x24)
#define SCALE_8_3(VAL_) ((VAL_) / 0x24)
unsigned short magicFiller = 0x07FE;
typedef struct
{
@@ -287,6 +288,54 @@ int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth)
return size;
}
/**
* Check 2 rgba structs for equality. 0 if unequal, 1 if equal
**/
int comp_rgba(const rgba left, const rgba right) {
if ((left.red != right.red) || (left.green != right.green) || (left.blue != right.blue) || (left.alpha != right.alpha)) {
return 0;
} else {
return 1;
}
}
/**
* Check if a given rgba (comp) is in a given palette (pal, represented as an array of rgba structs)
* If found, return the index in pal it was found out
* Otherwise, return -1
**/
int get_color_index(const rgba comp, const rgba *pal, int pal_size) {
int pal_idx;
for (pal_idx = 0; pal_idx < pal_size; pal_idx++) {
if (comp_rgba(comp, pal[pal_idx]) == 1) return pal_idx;
}
ERROR("Could not find a color in the palette\n");
ERROR("comp: %x%x%x%x\n", comp.red, comp.green, comp.blue, comp.alpha);
return -1;
}
/**
* Takes an image (img, an array of rgba structs) and a palette (pal, also an array of rgba structs)
* Sets the values of rawci (8 bit color index array) to the appropriate index in pal that each entry in img can be found at
* If a value in img is not found in pal, return 0, indicating an error
* Returns 1 if all values in img are found somewhere in pal
**/
int imgpal2rawci(uint8_t *rawci, const rgba *img, const rgba *pal, int raw_size, int img_size, int pal_size) {
int img_idx;
int pal_idx;
memset(rawci, 0, raw_size);
for (img_idx = 0; img_idx < img_size; img_idx++) {
pal_idx = get_color_index(img[img_idx], pal, pal_size);
if (pal_idx != -1) {
rawci[img_idx] = pal_idx;
} else {
return 0;
}
}
return 1;
}
int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth)
{
int size = (width * height * depth + 7) / 8;
@@ -539,7 +588,7 @@ int raw2ci(uint8_t *rawci, palette_t *pal, const uint8_t *raw, int raw_len, int
{
// assign colors to palette
pal->used = 0;
memset(pal->data, 0, sizeof(pal->data));
memset16safe(pal->data, magicFiller, sizeof(pal->data) / sizeof(uint16_t));
int ci_idx = 0;
for (int i = 0; i < raw_len; i += sizeof(uint16_t)) {
uint16_t val = read_u16_be(&raw[i]);
@@ -550,6 +599,15 @@ int raw2ci(uint8_t *rawci, palette_t *pal, const uint8_t *raw, int raw_len, int
} else {
switch (ci_depth) {
case 8:
// It appears some palettes have a default index of transparent/0.
// This requires iterating the pal_idx unless the CI really does begin with 0.
if (i == 0) {
pal->data[0] = 0;
if (val != 0) {
rawci[ci_idx] = (uint8_t) ++pal_idx;
break;
}
}
rawci[ci_idx] = (uint8_t)pal_idx;
break;
case 4:
@@ -585,6 +643,7 @@ typedef enum
{
MODE_EXPORT,
MODE_IMPORT,
MODE_EXPORT_CI,
} tool_mode;
typedef struct
@@ -804,6 +863,15 @@ static int parse_arguments(int argc, char *argv[], graphics_config *config)
if (++i >= argc) return 0;
config->width = strtoul(argv[i], NULL, 0);
break;
case 'Z':
if (++i >= argc) return 0;
config->bin_filename = argv[i];
config->mode = MODE_EXPORT_CI;
break;
case 'm':
if (i++ >= argc) return 0;
magicFiller = strtol(argv[i], NULL, 16);
break;
default:
return 0;
break;
@@ -834,6 +902,7 @@ int main(int argc, char *argv[])
{
graphics_config config = default_config;
rgba *imgr;
rgba *palr;
ia *imgi;
FILE *bin_fp;
uint8_t *raw;
@@ -841,235 +910,320 @@ int main(int argc, char *argv[])
int length = 0;
int flength;
int res;
int valid = parse_arguments(argc, argv, &config);
if (!valid || !valid_config(&config)) {
print_usage();
exit(EXIT_FAILURE);
}
if (config.mode == MODE_IMPORT) {
if (0 == strcmp("-", config.bin_filename)) {
bin_fp = stdout;
} else {
if (config.bin_truncate) {
bin_fp = fopen(config.bin_filename, "wb");
switch(config.mode){
case MODE_IMPORT:
if (0 == strcmp("-", config.bin_filename)) {
bin_fp = stdout;
} else {
bin_fp = fopen(config.bin_filename, "r+b");
}
}
if (!bin_fp) {
ERROR("Error opening \"%s\"\n", config.bin_filename);
return -1;
}
if (!config.bin_truncate) {
fseek(bin_fp, config.bin_offset, SEEK_SET);
}
switch (config.format.format) {
case IMG_FORMAT_RGBA:
imgr = png2rgba(config.img_filename, &config.width, &config.height);
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (!raw) {
ERROR("Error allocating %u bytes\n", raw_size);
}
length = rgba2raw(raw, imgr, config.width, config.height, config.format.depth);
break;
case IMG_FORMAT_IA:
imgi = png2ia(config.img_filename, &config.width, &config.height);
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (!raw) {
ERROR("Error allocating %u bytes\n", raw_size);
}
length = ia2raw(raw, imgi, config.width, config.height, config.format.depth);
break;
case IMG_FORMAT_I:
imgi = png2ia(config.img_filename, &config.width, &config.height);
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (!raw) {
ERROR("Error allocating %u bytes\n", raw_size);
}
length = i2raw(raw, imgi, config.width, config.height, config.format.depth);
break;
case IMG_FORMAT_CI:
{
palette_t pal = {0};
FILE *pal_fp;
uint8_t *raw16;
int raw16_size;
int raw16_length;
uint8_t *ci;
int ci_length;
int pal_success;
int pal_length;
if (config.pal_truncate) {
pal_fp = fopen(config.pal_filename, "wb");
if (config.bin_truncate) {
bin_fp = fopen(config.bin_filename, "wb");
} else {
pal_fp = fopen(config.pal_filename, "r+b");
bin_fp = fopen(config.bin_filename, "r+b");
}
if (!pal_fp) {
ERROR("Error opening \"%s\"\n", config.pal_filename);
return EXIT_FAILURE;
}
if (!config.pal_truncate) {
fseek(pal_fp, config.bin_offset, SEEK_SET);
}
raw16_size = config.width * config.height * config.pal_format.depth / 8;
raw16 = malloc(raw16_size);
if (!raw16) {
ERROR("Error allocating %d bytes\n", raw16_size);
return EXIT_FAILURE;
}
switch (config.pal_format.format) {
case IMG_FORMAT_RGBA:
imgr = png2rgba(config.img_filename, &config.width, &config.height);
raw16_length = rgba2raw(raw16, imgr, config.width, config.height, config.pal_format.depth);
break;
case IMG_FORMAT_IA:
imgi = png2ia(config.img_filename, &config.width, &config.height);
raw16_length = ia2raw(raw16, imgi, config.width, config.height, config.pal_format.depth);
break;
default:
ERROR("Unsupported palette format: %s\n", format2str(&config.pal_format));
exit(EXIT_FAILURE);
}
// convert raw to palette
pal.max = (1 << config.format.depth);
ci_length = config.width * config.height * config.format.depth / 8;
ci = malloc(ci_length);
pal_success = raw2ci(ci, &pal, raw16, raw16_length, config.format.depth);
if (!pal_success) {
ERROR("Error converting palette\n");
exit(EXIT_FAILURE);
}
// pack the bytes
uint8_t raw_pal[sizeof(pal.data)];
for (int i = 0; i < pal.max; i++) {
write_u16_be(&raw_pal[2*i], pal.data[i]);
}
pal_length = pal.max * sizeof(pal.data[0]);
INFO("Writing 0x%X bytes to offset 0x%X of \"%s\"\n", pal_length, config.pal_offset, config.pal_filename);
flength = fprint_write_output(pal_fp, config.encoding, raw_pal, pal_length);
if (config.encoding == ENCODING_RAW && flength != pal_length) {
ERROR("Error writing %d bytes to \"%s\"\n", pal_length, config.pal_filename);
}
INFO("Wrote 0x%X bytes to \"%s\"\n", flength, config.pal_filename);
raw = ci;
length = ci_length;
free(raw16);
fclose(pal_fp);
break;
}
default:
return EXIT_FAILURE;
}
if (length <= 0) {
ERROR("Error converting to raw format\n");
return EXIT_FAILURE;
}
INFO("Writing 0x%X bytes to offset 0x%X of \"%s\"\n", length, config.bin_offset, config.bin_filename);
flength = fprint_write_output(bin_fp, config.encoding, raw, length);
if (config.encoding == ENCODING_RAW && flength != length) {
ERROR("Error writing %d bytes to \"%s\"\n", length, config.bin_filename);
}
INFO("Wrote 0x%X bytes to \"%s\"\n", flength, config.bin_filename);
if (bin_fp != stdout) {
fclose(bin_fp);
}
if (!bin_fp) {
ERROR("Error opening \"%s\"\n", config.bin_filename);
return -1;
}
if (!config.bin_truncate) {
fseek(bin_fp, config.bin_offset, SEEK_SET);
}
switch (config.format.format) {
case IMG_FORMAT_RGBA:
imgr = png2rgba(config.img_filename, &config.width, &config.height);
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (!raw) {
ERROR("Error allocating %u bytes\n", raw_size);
}
length = rgba2raw(raw, imgr, config.width, config.height, config.format.depth);
break;
case IMG_FORMAT_IA:
imgi = png2ia(config.img_filename, &config.width, &config.height);
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (!raw) {
ERROR("Error allocating %u bytes\n", raw_size);
}
length = ia2raw(raw, imgi, config.width, config.height, config.format.depth);
break;
case IMG_FORMAT_I:
imgi = png2ia(config.img_filename, &config.width, &config.height);
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (!raw) {
ERROR("Error allocating %u bytes\n", raw_size);
}
length = i2raw(raw, imgi, config.width, config.height, config.format.depth);
break;
case IMG_FORMAT_CI:
{
int w = 0;
int h = 0;
int channels = 0;
stbi_uc *data = stbi_load(config.img_filename, &w, &h, &channels, STBI_default);
palette_t pal = {0};
FILE *pal_fp;
uint8_t *raw16;
int raw16_size;
int raw16_length;
uint8_t *ci;
int ci_length;
int pal_success;
int pal_length;
} else {
if (config.width <= 0 || config.height <= 0 || config.format.depth <= 0) {
ERROR("Error: must set position width and height for export\n");
return EXIT_FAILURE;
}
bin_fp = fopen(config.bin_filename, "rb");
if (!bin_fp) {
ERROR("Error opening \"%s\"\n", config.bin_filename);
return -1;
}
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (config.bin_offset > 0) {
fseek(bin_fp, config.bin_offset, SEEK_SET);
}
flength = fread(raw, 1, raw_size, bin_fp);
if (flength != raw_size) {
ERROR("Error reading %d bytes from \"%s\"\n", raw_size, config.bin_filename);
}
switch (config.format.format) {
case IMG_FORMAT_RGBA:
imgr = raw2rgba(raw, config.width, config.height, config.format.depth);
res = rgba2png(config.img_filename, imgr, config.width, config.height);
break;
case IMG_FORMAT_IA:
imgi = raw2ia(raw, config.width, config.height, config.format.depth);
res = ia2png(config.img_filename, imgi, config.width, config.height);
break;
case IMG_FORMAT_I:
imgi = raw2i(raw, config.width, config.height, config.format.depth);
res = ia2png(config.img_filename, imgi, config.width, config.height);
break;
case IMG_FORMAT_CI:
{
FILE *pal_fp;
uint8_t *pal;
uint8_t *raw_fmt;
int pal_size;
if (!data || w <= 0 || h <= 0) {
ERROR("Error reading w/h from img \"%s\"\n", config.img_filename);
return 0;
}
INFO("Extracting %s offset 0x%X, pal.offset 0x%0X, pal.format %s\n", format2str(&config.format),
config.bin_offset, config.pal_offset, format2str(&config.pal_format));
pal_fp = fopen(config.pal_filename, "rb");
if (!pal_fp) {
ERROR("Error opening \"%s\"\n", config.bin_filename);
return EXIT_FAILURE;
}
if (config.pal_offset > 0) {
fseek(pal_fp, config.pal_offset, SEEK_SET);
}
pal_size = sizeof(uint16_t) * (1 << config.format.depth);
INFO("Palette size: %d\n", pal_size);
pal = malloc(pal_size);
flength = fread(pal, 1, pal_size, pal_fp);
if (flength != pal_size) {
ERROR("Error reading %d bytes from \"%s\"\n", pal_size, config.pal_filename);
}
raw_fmt = ci2raw(raw, pal, config.width, config.height, config.format.depth);
switch (config.pal_format.format) {
case IMG_FORMAT_RGBA:
INFO("Converting raw to RGBA16\n");
imgr = raw2rgba(raw_fmt, config.width, config.height, config.pal_format.depth);
res = rgba2png(config.img_filename, imgr, config.width, config.height);
break;
case IMG_FORMAT_IA:
INFO("Converting raw to IA16\n");
imgi = raw2ia(raw_fmt, config.width, config.height, config.pal_format.depth);
res = ia2png(config.img_filename, imgi, config.width, config.height);
break;
default:
ERROR("Unsupported palette format: %s\n", format2str(&config.pal_format));
if (config.pal_truncate) {
pal_fp = fopen(config.pal_filename, "wb");
} else {
pal_fp = fopen(config.pal_filename, "r+b");
}
if (!pal_fp) {
ERROR("Error opening \"%s\"\n", config.pal_filename);
return EXIT_FAILURE;
}
if (!config.pal_truncate) {
fseek(pal_fp, config.bin_offset, SEEK_SET);
}
raw16_size = w * h * config.pal_format.depth / 8;
raw16 = malloc(raw16_size);
if (!raw16) {
ERROR("Error allocating %d bytes\n", raw16_size);
return EXIT_FAILURE;
}
switch (config.pal_format.format) {
case IMG_FORMAT_RGBA:
imgr = png2rgba(config.img_filename, &config.width, &config.height);
raw16_length = rgba2raw(raw16, imgr, config.width, config.height, config.pal_format.depth);
break;
case IMG_FORMAT_IA:
imgi = png2ia(config.img_filename, &config.width, &config.height);
raw16_length = ia2raw(raw16, imgi, config.width, config.height, config.pal_format.depth);
break;
default:
ERROR("Unsupported palette format: %s\n", format2str(&config.pal_format));
exit(EXIT_FAILURE);
}
// convert raw to palette
pal.max = (1 << config.format.depth);
ci_length = config.width * config.height * config.format.depth / 8;
ci = malloc(ci_length);
pal_success = raw2ci(ci, &pal, raw16, raw16_length, config.format.depth);
if (!pal_success) {
ERROR("Error converting palette\n");
exit(EXIT_FAILURE);
}
// pack the bytes
uint8_t raw_pal[sizeof(pal.data)];
for (int i = 0; i < pal.max; i++) {
write_u16_be(&raw_pal[2*i], pal.data[i]);
}
pal_length = pal.max * sizeof(pal.data[0]);
INFO("Writing 0x%X bytes to offset 0x%X of \"%s\"\n", pal_length, config.pal_offset, config.pal_filename);
flength = fprint_write_output(pal_fp, config.encoding, raw_pal, pal_length);
if (config.encoding == ENCODING_RAW && flength != pal_length) {
ERROR("Error writing %d bytes to \"%s\"\n", pal_length, config.pal_filename);
}
INFO("Wrote 0x%X bytes to \"%s\"\n", flength, config.pal_filename);
raw = ci;
length = ci_length;
free(raw16);
fclose(pal_fp);
break;
}
free(raw_fmt);
free(pal);
break;
default:
return EXIT_FAILURE;
}
default:
if (length <= 0) {
ERROR("Error converting to raw format\n");
return EXIT_FAILURE;
}
INFO("Writing 0x%X bytes to offset 0x%X of \"%s\"\n", length, config.bin_offset, config.bin_filename);
flength = fprint_write_output(bin_fp, config.encoding, raw, length);
if (config.encoding == ENCODING_RAW && flength != length) {
ERROR("Error writing %d bytes to \"%s\"\n", length, config.bin_filename);
}
INFO("Wrote 0x%X bytes to \"%s\"\n", flength, config.bin_filename);
if (bin_fp != stdout) {
fclose(bin_fp);
}
break;
case MODE_EXPORT:
if (config.width <= 0 || config.height <= 0 || config.format.depth <= 0) {
ERROR("Error: must set position width and height for export\n");
return EXIT_FAILURE;
}
bin_fp = fopen(config.bin_filename, "rb");
if (!bin_fp) {
ERROR("Error opening \"%s\"\n", config.bin_filename);
return -1;
}
raw_size = (config.width * config.height * config.format.depth + 7) / 8;
raw = malloc(raw_size);
if (config.bin_offset > 0) {
fseek(bin_fp, config.bin_offset, SEEK_SET);
}
flength = fread(raw, 1, raw_size, bin_fp);
if (flength != raw_size) {
ERROR("Error reading %d bytes from \"%s\"\n", raw_size, config.bin_filename);
}
switch (config.format.format) {
case IMG_FORMAT_RGBA:
imgr = raw2rgba(raw, config.width, config.height, config.format.depth);
res = rgba2png(config.img_filename, imgr, config.width, config.height);
break;
case IMG_FORMAT_IA:
imgi = raw2ia(raw, config.width, config.height, config.format.depth);
res = ia2png(config.img_filename, imgi, config.width, config.height);
break;
case IMG_FORMAT_I:
imgi = raw2i(raw, config.width, config.height, config.format.depth);
res = ia2png(config.img_filename, imgi, config.width, config.height);
break;
case IMG_FORMAT_CI:
{
FILE *pal_fp;
uint8_t *pal;
uint8_t *raw_fmt;
int pal_size;
INFO("Extracting %s offset 0x%X, pal.offset 0x%0X, pal.format %s\n", format2str(&config.format),
config.bin_offset, config.pal_offset, format2str(&config.pal_format));
pal_fp = fopen(config.pal_filename, "rb");
if (!pal_fp) {
ERROR("Error opening \"%s\"\n", config.bin_filename);
return EXIT_FAILURE;
}
if (config.pal_offset > 0) {
fseek(pal_fp, config.pal_offset, SEEK_SET);
}
pal_size = sizeof(uint16_t) * (1 << config.format.depth);
INFO("Palette size: %d\n", pal_size);
pal = malloc(pal_size);
flength = fread(pal, 1, pal_size, pal_fp);
if (flength != pal_size) {
ERROR("Error reading %d bytes from \"%s\"\n", pal_size, config.pal_filename);
}
raw_fmt = ci2raw(raw, pal, config.width, config.height, config.format.depth);
switch (config.pal_format.format) {
case IMG_FORMAT_RGBA:
INFO("Converting raw to RGBA16\n");
imgr = raw2rgba(raw_fmt, config.width, config.height, config.pal_format.depth);
res = rgba2png(config.img_filename, imgr, config.width, config.height);
break;
case IMG_FORMAT_IA:
INFO("Converting raw to IA16\n");
imgi = raw2ia(raw_fmt, config.width, config.height, config.pal_format.depth);
res = ia2png(config.img_filename, imgi, config.width, config.height);
break;
default:
ERROR("Unsupported palette format: %s\n", format2str(&config.pal_format));
return EXIT_FAILURE;
}
free(raw_fmt);
free(pal);
break;
}
default:
return EXIT_FAILURE;
}
if (!res) {
ERROR("Error writing to \"%s\"\n", config.img_filename);
return EXIT_FAILURE;
}
break;
case MODE_EXPORT_CI:
{
uint8_t *rawci;
int img_length;
int pal_length;
int ci_length;
int conversion_success;
if (0 == strcmp("-", config.bin_filename)) {
bin_fp = stdout;
} else {
if (config.bin_truncate) {
bin_fp = fopen(config.bin_filename, "wb");
} else {
bin_fp = fopen(config.bin_filename, "r+b");
}
}
if (!bin_fp) {
ERROR("Error opening \"%s\"\n", config.bin_filename);
return -1;
}
if (!config.bin_truncate) {
fseek(bin_fp, config.bin_offset, SEEK_SET);
}
switch (config.pal_format.format) {
case IMG_FORMAT_RGBA:
palr = png2rgba(config.pal_filename, &config.width, &config.height);
break;
default:
ERROR("Unexpected format for the palette: %s\n", format2str(&config.pal_format));
return EXIT_FAILURE;
}
pal_length = config.width * config.height;
/**
* We're kind misusing the config stuff here
* We at first use it to convert the input image into an rgba16 (always 16, not 32)
* But then we re-use it to control the output bin file's size
* The proper thing to do here would be to:
* Expand the config to have separate image and bin file parameters
* Add optional argument(s) to specify the new parameters
* In practice what this means is that, as written, when using the -Z mode you MUST set the -f
* argument to `ci8`. Anything else is erroneous
**/
switch (config.format.format) {
case IMG_FORMAT_CI:
imgr = png2rgba(config.img_filename, &config.width, &config.height);
break;
default:
ERROR("Unexpected format for the image: %s\n", format2str(&config.format));
return EXIT_FAILURE;
}
img_length = config.width * config.height;
ci_length = img_length * config.format.depth / 8;
rawci = malloc(ci_length);
conversion_success = imgpal2rawci(rawci, imgr, palr, ci_length, img_length, pal_length);
if (!conversion_success) {
ERROR("Error converting PNG and TLUT to CI\n");
exit(EXIT_FAILURE);
}
INFO("Writing 0x%X bytes to offset 0x%X of \"%s\"\n", ci_length, config.bin_offset, config.bin_filename);
flength = fprint_write_output(bin_fp, config.encoding, rawci, ci_length);
if (config.encoding == ENCODING_RAW && flength != ci_length) {
ERROR("Error writing %d bytes to \"%s\"\n", ci_length, config.bin_filename);
}
INFO("Wrote 0x%X bytes to \"%s\"\n", flength, config.bin_filename);
if (bin_fp != stdout) {
fclose(bin_fp);
}
free(rawci);
break;
}
if (!res) {
ERROR("Error writing to \"%s\"\n", config.img_filename);
default:
ERROR("Unexpected run mode: %d\n", config.mode);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
+17
View File
@@ -37,6 +37,23 @@ float read_f32_be(unsigned char *buf)
return ret.f;
}
void *memset16safe(void *m, uint16_t val, size_t count)
{
char *buf = m;
union
{
uint8_t d8[2];
uint16_t d16;
}u16 = {.d16 = val};
while(count--)
{
*buf++ = u16.d8[0];
*buf++ = u16.d8[1];
}
return m;
}
int is_power2(unsigned int val)
{
while (((val & 1) == 0) && (val > 1)) {
+3
View File
@@ -91,6 +91,9 @@ int read_s16_be(unsigned char *buf);
// convert four bytes in big-endian to float
float read_f32_be(unsigned char *buf);
// initialize memory to u16 value
void *memset16safe(void *m, uint16_t val, size_t count);
// determine if value is power of 2
// returns 1 if val is power of 2, 0 otherwise
int is_power2(unsigned int val);