Laid out basic project structure
This commit is contained in:
parent
f78f66cf9a
commit
18701f56a6
6
Makefile
6
Makefile
|
@ -1,7 +1,9 @@
|
|||
CFLAGS := -Wall -Wextra -Werror -pedantic -std=c99
|
||||
CFLAGS := -Wall -Wextra -Werror -pedantic -std=c99 -ggdb
|
||||
CLIBS := -lm
|
||||
INCLUDES := -Isrc
|
||||
OBJECTS := obj/stb_image.o
|
||||
OBJECTS := obj/stb_image.o obj/stb_image_resize.o \
|
||||
obj/colors.o obj/args.o obj/image.o \
|
||||
obj/mod_blocks.o
|
||||
|
||||
all: lib asciify
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# Why?
|
||||
I just wasn't happy with state of old project, so I thought about recreating it.
|
||||
|
||||
# Anything new?
|
||||
Nothing.
|
||||
|
||||
Oh wait. It's single binary now. Yay.
|
|
@ -0,0 +1,265 @@
|
|||
#include "args.h"
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct {
|
||||
int value;
|
||||
char *strings[8];
|
||||
char *description;
|
||||
} __option_t;
|
||||
|
||||
int __find_value(const __option_t *options, char *option);
|
||||
void __print_options(const __option_t *options);
|
||||
|
||||
const __option_t __mode_options[ASC_MOD_ENDL + 1] = {
|
||||
{ ASC_MOD_BLOCKS,
|
||||
{ "b", "blk", "blocks", NULL },
|
||||
"Box-drawing characters (\342\226\204) (default)" },
|
||||
{ ASC_MOD_BRAILLE,
|
||||
{ "r", "brl", "braille", NULL },
|
||||
"Braille characters (literally stolen from MineOS)" },
|
||||
{ ASC_MOD_GRADIENT,
|
||||
{ "g", "grd", "gradient", NULL },
|
||||
"Gradient of characters. No matching at all" },
|
||||
{ ASC_MOD_BRUTEFORCE,
|
||||
{ "f", "guess", "bruteforce", NULL },
|
||||
"Looking for best possible character" },
|
||||
{ -1, { NULL }, NULL }
|
||||
};
|
||||
|
||||
const __option_t __style_options[ASC_STL_ENDL + 1] = {
|
||||
{ ASC_STL_BLACKWHITE,
|
||||
{ "1", "bw", "black-white", "1bit", NULL },
|
||||
"1-bit black/white" },
|
||||
{ ASC_STL_ANSI_VGA,
|
||||
{ "vga", "ansi-vga", NULL },
|
||||
"VGA palette" },
|
||||
{ ASC_STL_ANSI_XTERM,
|
||||
{ "xterm", "ansi-xterm", NULL },
|
||||
"xTerm palette. A bit more rough, compared to VGA" },
|
||||
{ ASC_STL_ANSI_DISCORD,
|
||||
{ "discord", "ansi-discord", NULL },
|
||||
"Palette in Discord ANSI highlight" },
|
||||
{ ASC_STL_256COLOR,
|
||||
{ "256", "pal256", "8bit", NULL },
|
||||
"256-color palette (default)" },
|
||||
{ ASC_STL_TRUECOLOR,
|
||||
{ "true", "truecolor", "24bit", NULL },
|
||||
"24-bit RGB (TrueColor)" },
|
||||
{ ASC_STL_PALETTE,
|
||||
{ "pal", "palette", "custom", NULL },
|
||||
"Custom palette (specified via -P)" },
|
||||
{ -1, { NULL }, NULL }
|
||||
};
|
||||
|
||||
const __option_t __format_options[ASC_FMT_ENDL + 1] = {
|
||||
{ ASC_FMT_ANSI,
|
||||
{ "ansi", "raw", NULL },
|
||||
"Output, suitable for terminal (default)" },
|
||||
{ ASC_FMT_HTML,
|
||||
{ "html", NULL },
|
||||
"Output as HTML table" },
|
||||
{ ASC_FMT_JSON,
|
||||
{ "json", NULL },
|
||||
"Output as JSON 2D array of characters with properties" },
|
||||
{ -1, { NULL }, NULL }
|
||||
};
|
||||
|
||||
void usage(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
fprintf(stderr, "usage: %s ", *argv);
|
||||
fprintf(stderr, "[-vhd] [-O FILE] [-W WIDTH] [-H HEIGHT] ");
|
||||
fprintf(stderr, "[-M MODE] [-S STYLE] [-F FORMAT] [-P PALETTE] ");
|
||||
fprintf(stderr, "FILE\n\n");
|
||||
fprintf(stderr, "-v\t\tEnable verbose mode\n");
|
||||
fprintf(stderr, "-h\t\tShow this help\n");
|
||||
fprintf(stderr, "-d\t\tEnable dithering\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "-O FILE\t\tOutput file. Default: - (stdout)\n");
|
||||
fprintf(stderr, "-W WIDTH\tOutput width (in characters)\n");
|
||||
fprintf(stderr, "-H HEIGHT\tOutput height (in characters)\n");
|
||||
fprintf(stderr, "-M MODE\t\tOutput mode\n");
|
||||
fprintf(stderr, "-S STYLE\tStyle (palette)\n");
|
||||
fprintf(stderr, "-F FORMAT\tOutput format\n");
|
||||
fprintf(stderr, "-P PALETTE\tPath to palette file (when -S pal)\n");
|
||||
fprintf(stderr, "\n\n");
|
||||
fprintf(stderr, "Options for MODE:\n");
|
||||
__print_options(__mode_options);
|
||||
fprintf(stderr, "Options for STYLE:\n");
|
||||
__print_options(__style_options);
|
||||
fprintf(stderr, "Options for FORMAT:\n");
|
||||
__print_options(__format_options);
|
||||
}
|
||||
|
||||
int parse_args(int argc, char **argv, asc_args_t *args)
|
||||
{
|
||||
args->input_filename = NULL;
|
||||
args->output_filename = "-";
|
||||
args->palette_filename = NULL;
|
||||
args->width = 80;
|
||||
args->height = 24;
|
||||
args->out_format = ASC_FMT_ANSI;
|
||||
args->out_style = ASC_STL_256COLOR;
|
||||
args->mode = ASC_MOD_BLOCKS;
|
||||
args->dither = false;
|
||||
args->verbose = false;
|
||||
args->charset = " .'-*+$@";
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "vhdW:H:M:S:F:P:O:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'v':
|
||||
args->verbose = true;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argc, argv);
|
||||
return 1;
|
||||
break;
|
||||
case 'd':
|
||||
args->dither = true;
|
||||
break;
|
||||
case 'W':
|
||||
if ((args->width = atoi(optarg)) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: WIDTH is invalid\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
if ((args->height = atoi(optarg)) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: HEIGHT is invalid\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
{
|
||||
int val = __find_value(__mode_options, optarg);
|
||||
if (val < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: invalid mode '%s'\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
args->mode = val;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
int val = __find_value(__style_options, optarg);
|
||||
if (val < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: invalid style '%s'\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
args->out_style = val;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
{
|
||||
int val = __find_value(__format_options, optarg);
|
||||
if (val < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: invalid format '%s'\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
args->out_format = val;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
args->palette_filename = optarg;
|
||||
break;
|
||||
case 'O':
|
||||
args->output_filename = optarg;
|
||||
break;
|
||||
case '?':
|
||||
if (optopt == 'O'
|
||||
|| optopt == 'W' || optopt == 'H'
|
||||
|| optopt == 'S' || optopt == 'M' || optopt == 'F')
|
||||
{
|
||||
fprintf(stderr, "Error: missing argument for -%c\n", optopt);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Unknown parameter -%c\n", optopt);
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
if (args->out_style == ASC_STL_PALETTE && args->palette_filename == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: no palette file provided, but palette mode selected\n");
|
||||
return -3;
|
||||
}
|
||||
if (argc <= optind || argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Error: no image provided\n");
|
||||
return -2;
|
||||
}
|
||||
args->input_filename = argv[optind];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prepare_state(int argc, char **argv, asc_args_t args, asc_state_t *state)
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
state->args = args;
|
||||
|
||||
FILE *image_file;
|
||||
if ((image_file = fopen(args.input_filename, "rb")) == NULL
|
||||
|| ferror(image_file) != 0)
|
||||
{
|
||||
int err = errno;
|
||||
fprintf(stderr, "Error: failed to open file %s for reading: %d: %s\n",
|
||||
args.input_filename, err, strerror(err));
|
||||
return -100 - err;
|
||||
}
|
||||
|
||||
state->source_image = image_load(image_file);
|
||||
fclose(image_file);
|
||||
|
||||
state->out_file = stdout;
|
||||
if (strcmp(args.output_filename, "-"))
|
||||
state->out_file = fopen(args.output_filename, "wb");
|
||||
if (state->out_file == NULL)
|
||||
{
|
||||
int err = errno;
|
||||
fprintf(stderr, "Error: failed to open file %s for writing: %d: %s\n",
|
||||
args.output_filename, err, strerror(err));
|
||||
return -100 - err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __find_value(const __option_t *options, char *option)
|
||||
{
|
||||
__option_t *opt;
|
||||
while ((opt = (__option_t *)options++)->value >= 0)
|
||||
{
|
||||
char *str = opt->strings[0];
|
||||
for (int i = 0; str != NULL; i++, str = opt->strings[i])
|
||||
{
|
||||
if (!strcmp(str, option)) return opt->value;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void __print_options(const __option_t *options)
|
||||
{
|
||||
__option_t *opt;
|
||||
while ((opt = (__option_t *)options++)->value >= 0)
|
||||
{
|
||||
fprintf(stderr, " - %s:\n\t", opt->description);
|
||||
char *str = opt->strings[0];
|
||||
for (int i = 0; str != NULL; i++, str = opt->strings[i])
|
||||
{
|
||||
fprintf(stderr, "%s ", str);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef _ARGS_H_
|
||||
#define _ARGS_H_
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "image.h"
|
||||
|
||||
typedef enum {
|
||||
ASC_MOD_BLOCKS = 0,
|
||||
ASC_MOD_BRAILLE = 1,
|
||||
ASC_MOD_GRADIENT = 2,
|
||||
ASC_MOD_BRUTEFORCE = 3,
|
||||
ASC_MOD_ENDL = 4
|
||||
} asc_mode_t;
|
||||
|
||||
typedef enum {
|
||||
ASC_FMT_ANSI = 0,
|
||||
ASC_FMT_HTML = 1,
|
||||
ASC_FMT_JSON = 2,
|
||||
ASC_FMT_ENDL = 3
|
||||
} asc_format_t;
|
||||
|
||||
typedef enum {
|
||||
ASC_STL_BLACKWHITE = 0,
|
||||
ASC_STL_ANSI_VGA = 1,
|
||||
ASC_STL_ANSI_XTERM = 2,
|
||||
ASC_STL_ANSI_DISCORD = 3,
|
||||
ASC_STL_256COLOR = 4,
|
||||
ASC_STL_TRUECOLOR = 5,
|
||||
ASC_STL_PALETTE = 6,
|
||||
ASC_STL_ENDL = 7
|
||||
} asc_style_t;
|
||||
|
||||
typedef struct {
|
||||
char *input_filename;
|
||||
char *output_filename;
|
||||
char *palette_filename;
|
||||
int width;
|
||||
int height;
|
||||
asc_format_t out_format;
|
||||
asc_style_t out_style;
|
||||
asc_mode_t mode;
|
||||
bool dither;
|
||||
bool verbose;
|
||||
char *charset;
|
||||
} asc_args_t;
|
||||
|
||||
typedef struct {
|
||||
asc_args_t args;
|
||||
image_t *source_image;
|
||||
image_t *image;
|
||||
palette_t *palette;
|
||||
FILE *out_file;
|
||||
} asc_state_t;
|
||||
|
||||
void usage(int argc, char **argv);
|
||||
int parse_args(int argc, char **argv, asc_args_t *args);
|
||||
int prepare_state(int argc, char **argv, asc_args_t args, asc_state_t *state);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
#include "colors.h"
|
||||
|
||||
palette_t c_palette_ansi_discord = {
|
||||
.n_colors = 8,
|
||||
.palette = {
|
||||
{ 0x4f, 0x54, 0x5c, 0 },
|
||||
{ 0xd1, 0x31, 0x35, 0 },
|
||||
{ 0x85, 0x99, 0x00, 0 },
|
||||
{ 0xb5, 0x89, 0x00, 0 },
|
||||
{ 0x26, 0x8b, 0xd2, 0 },
|
||||
{ 0xd3, 0x36, 0x82, 0 },
|
||||
{ 0xd3, 0x36, 0x82, 0 },
|
||||
{ 0xff, 0xff, 0xff, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
palette_t c_palette_ansi_vga = {
|
||||
.n_colors = 16,
|
||||
.palette = {
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 170, 0, 0, 0 },
|
||||
{ 0, 170, 0, 0 },
|
||||
{ 170, 85, 0, 0 },
|
||||
{ 0, 0, 170, 0 },
|
||||
{ 170, 0, 170, 0 },
|
||||
{ 0, 170, 170, 0 },
|
||||
{ 170, 170, 170, 0 },
|
||||
{ 85, 85, 85, 0 },
|
||||
{ 255, 85, 85, 0 },
|
||||
{ 85, 255, 85, 0 },
|
||||
{ 255, 255, 85, 0 },
|
||||
{ 85, 85, 255, 0 },
|
||||
{ 255, 85, 255, 0 },
|
||||
{ 85, 255, 255, 0 },
|
||||
{ 255, 255, 255, 0 }
|
||||
}
|
||||
};
|
||||
|
||||
palette_t c_palette_ansi_xterm = {
|
||||
.n_colors = 16,
|
||||
.palette = {
|
||||
{ 0, 0, 0, 0 },
|
||||
{ 205, 0, 0, 0 },
|
||||
{ 0, 205, 0, 0 },
|
||||
{ 205, 205, 0, 0 },
|
||||
{ 0, 0, 238, 0 },
|
||||
{ 205, 0, 205, 0 },
|
||||
{ 0, 205, 205, 0 },
|
||||
{ 229, 229, 229, 0 },
|
||||
{ 127, 127, 127, 0 },
|
||||
{ 255, 0, 0, 0 },
|
||||
{ 0, 255, 0, 0 },
|
||||
{ 255, 255, 0, 0 },
|
||||
{ 0, 0, 252, 0 },
|
||||
{ 255, 0, 255, 0 },
|
||||
{ 0, 255, 255, 0 },
|
||||
{ 255, 255, 255, 0 },
|
||||
}
|
||||
};
|
||||
|
||||
int closest_color(palette_t *pal, rgba8 color)
|
||||
{
|
||||
int nearest = -1;
|
||||
int32_t min_distance = 0x0fffffff;
|
||||
for (int i = 0; i < pal->n_colors; i++)
|
||||
{
|
||||
rgba8 pal_color = pal->palette[i];
|
||||
int16_t dr = pal_color.r - color.r;
|
||||
int16_t dg = pal_color.g - color.g;
|
||||
int16_t db = pal_color.b - color.b;
|
||||
int32_t distance = dr * dr + dg * dg + db * db;
|
||||
if (distance < min_distance)
|
||||
{
|
||||
min_distance = distance;
|
||||
nearest = i;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
void load_palette_gpl(palette_t *pal, FILE *fp)
|
||||
{
|
||||
(void)pal; (void)fp;
|
||||
// TODO: load GNU palette file
|
||||
}
|
||||
|
||||
void load_palette_raw(palette_t *pal, FILE *fp)
|
||||
{
|
||||
(void)pal; (void)fp;
|
||||
// TODO: load raw palette file
|
||||
}
|
||||
|
||||
void load_palette(palette_t *pal, FILE *fp)
|
||||
{
|
||||
(void)pal; (void)fp;
|
||||
// TODO: guess palette file type and load it
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef _COLORS_H_
|
||||
#define _COLORS_H_
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t r, g, b, a;
|
||||
} rgba8;
|
||||
|
||||
typedef struct {
|
||||
int n_colors;
|
||||
rgba8 palette[255];
|
||||
} palette_t;
|
||||
|
||||
extern palette_t c_palette_ansi_discord;
|
||||
extern palette_t c_palette_ansi_vga;
|
||||
extern palette_t c_palette_ansi_xterm;
|
||||
|
||||
int closest_color(palette_t *pal, rgba8 color);
|
||||
void load_palette_gpl(palette_t *pal, FILE *fp);
|
||||
void load_palette_raw(palette_t *pal, FILE *fp);
|
||||
void load_palette(palette_t *pal, FILE *fp);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,66 @@
|
|||
#include "image.h"
|
||||
#include "stb_image.h"
|
||||
#include "stb_image_resize.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
image_t *image_load(FILE *file)
|
||||
{
|
||||
image_t *img = calloc(1, sizeof(image_t));
|
||||
int n;
|
||||
img->pixels = (rgba8 *)stbi_load_from_file(file,
|
||||
&img->width, &img->height,
|
||||
&n, STBI_rgb_alpha);
|
||||
return img;
|
||||
}
|
||||
|
||||
|
||||
image_t *image_resize(image_t *img, int width, int height)
|
||||
{
|
||||
image_t *res = calloc(1, sizeof(image_t));
|
||||
res->width = width;
|
||||
res->height = height;
|
||||
res->pixels = calloc(width * height, sizeof(rgba8));
|
||||
stbir_resize_uint8((const unsigned char *)img->pixels,
|
||||
img->width, img->height, 0,
|
||||
(unsigned char *)res->pixels,
|
||||
res->width, res->height, 0, STBI_rgb_alpha);
|
||||
return res;
|
||||
}
|
||||
|
||||
void image_unload(image_t *img)
|
||||
{
|
||||
free(img->pixels);
|
||||
free(img);
|
||||
}
|
||||
|
||||
void get_size_keep_aspect(int w, int h, int dw, int dh, int *ow, int *oh)
|
||||
{
|
||||
*ow = dw;
|
||||
*oh = dh;
|
||||
float ratio = (float)w / (float)h;
|
||||
float ratio_dst = (float)dw / (float)dh;
|
||||
int tmp_1, tmp_2;
|
||||
if (ratio_dst >= ratio)
|
||||
{
|
||||
tmp_1 = floor(dh * ratio);
|
||||
tmp_2 = ceil(dh * ratio);
|
||||
if (fabsf(ratio - (float)tmp_1 / dh) < fabsf(ratio - (float)tmp_1 / dh))
|
||||
*ow = tmp_1 < 1 ? 1 : tmp_1;
|
||||
else
|
||||
*ow = tmp_2 < 1 ? 1 : tmp_2;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_1 = floor(dw / ratio);
|
||||
tmp_2 = ceil(dw / ratio);
|
||||
if (tmp_2 == 0 ||
|
||||
fabs(ratio - (float)dw / tmp_1) < fabs(ratio - (float)dw / tmp_2))
|
||||
(*oh) = tmp_1 < 1 ? 1 : tmp_1;
|
||||
else
|
||||
(*oh) = tmp_2 < 1 ? 1 : tmp_2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _IMAGE_H_
|
||||
#define _IMAGE_H_
|
||||
#include <stdio.h>
|
||||
#include "colors.h"
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int errno;
|
||||
rgba8 *pixels;
|
||||
} image_t;
|
||||
|
||||
image_t *image_load(FILE *file);
|
||||
image_t *image_resize(image_t *img, int width, int height);
|
||||
void image_unload(image_t *img);
|
||||
|
||||
void get_size_keep_aspect(int w, int h, int dw, int dh, int *ow, int *oh);
|
||||
|
||||
#endif
|
15
src/main.c
15
src/main.c
|
@ -1,11 +1,20 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "args.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
printf("ah shit, here we go again\n");
|
||||
asc_args_t args;
|
||||
int res = parse_args(argc, argv, &args);
|
||||
if (res == 1) return 0;
|
||||
if (res < 0) return -res;
|
||||
|
||||
asc_state_t state;
|
||||
res = prepare_state(argc, argv, args, &state);
|
||||
if (res == 1) return 0;
|
||||
if (res < 0) return -res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#include "mod_blocks.h"
|
||||
|
||||
void mod_blocks_prepare(asc_state_t *state)
|
||||
{
|
||||
(void)state;
|
||||
}
|
||||
|
||||
void mod_blocks_main(asc_state_t state)
|
||||
{
|
||||
(void)state;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef _MOD_BLOCKS_
|
||||
#define _MOD_BLOCKS_
|
||||
#include <stdio.h>
|
||||
#include "colors.h"
|
||||
#include "args.h"
|
||||
|
||||
void mod_blocks_prepare(asc_state_t *state);
|
||||
void mod_blocks_main(asc_state_t state);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,2 @@
|
|||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "stb_image_resize.h"
|
|
@ -0,0 +1 @@
|
|||
#include "../thirdparty/stb/stb_image_resize.h"
|
Loading…
Reference in New Issue