first public version
This commit is contained in:
parent
91eed00957
commit
44cf800d41
6 changed files with 8481 additions and 1 deletions
1
.dummy
1
.dummy
|
@ -1 +0,0 @@
|
|||
.
|
122
kyaa.h
Normal file
122
kyaa.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* kyaa.h - macro hacks for handling main() arguments
|
||||
license: public domain or whatever.
|
||||
documentation is kept separate in kyaa.md
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef KYAA_OKAY
|
||||
#define KYAA_OKAY 0
|
||||
#endif
|
||||
#ifndef KYAA_ERROR
|
||||
#define KYAA_ERROR 1
|
||||
#endif
|
||||
#ifndef KYAA_ITER
|
||||
#define KYAA_ITER i
|
||||
#endif
|
||||
|
||||
#define KYAA_SETUP \
|
||||
/* dumb sanity checks */ \
|
||||
if (argc <= 0 || argv == NULL || argv[0] == NULL || argv[0][0] == '\0') { \
|
||||
fprintf(stderr, "You've met with a terrible fate.\n"); \
|
||||
return KYAA_ERROR; \
|
||||
} \
|
||||
char *kyaa_name = argv[0]; \
|
||||
bool kyaa_read_stdin = false; \
|
||||
char kyaa_flag = '\0'; \
|
||||
bool kyaa_keep_parsing = true; \
|
||||
bool kyaa_parse_next = false; \
|
||||
|
||||
#define KYAA_LOOP \
|
||||
KYAA_SETUP \
|
||||
for (int KYAA_ITER = 1; KYAA_ITER < argc; KYAA_ITER++) \
|
||||
|
||||
#define KYAA_BEGIN \
|
||||
char *kyaa_arg = argv[KYAA_ITER]; \
|
||||
if (kyaa_keep_parsing && (kyaa_parse_next || kyaa_arg[0] == '-')) { \
|
||||
if (!kyaa_parse_next && kyaa_arg[1] == '-' && kyaa_arg[2] == '\0') { \
|
||||
kyaa_keep_parsing = false; \
|
||||
continue; \
|
||||
} \
|
||||
if (!kyaa_parse_next && kyaa_arg[1] == '\0') { \
|
||||
kyaa_read_stdin = true; \
|
||||
} else { \
|
||||
/* case: kyaa_parse_next: arg is at least 1 char initialized. */ \
|
||||
/* case: !kyaa_parse_next: arg is at least 3 chars initialized. */ \
|
||||
char *kyaa_etc = kyaa_parse_next ? kyaa_arg : kyaa_arg + 2; \
|
||||
bool kyaa_no_more = false; \
|
||||
bool kyaa_helping = false; \
|
||||
bool kyaa_any = false; \
|
||||
if (!kyaa_parse_next && kyaa_arg[1] != '-') { \
|
||||
kyaa_flag = kyaa_arg[1]; \
|
||||
kyaa_no_more = kyaa_arg[2] == '\0'; \
|
||||
} \
|
||||
if (kyaa_flag == 'h' || !strcmp(kyaa_arg, "--help")) { \
|
||||
printf("usage:\n"); \
|
||||
kyaa_helping = true; \
|
||||
} \
|
||||
if (0) { \
|
||||
|
||||
#define KYAA_END \
|
||||
} \
|
||||
if (!kyaa_any && !kyaa_helping) { \
|
||||
if (kyaa_flag) { \
|
||||
fprintf(stderr, "unknown flag: -%c\n", kyaa_flag); \
|
||||
} else { \
|
||||
fprintf(stderr, "unknown flag: %s\n", kyaa_arg); \
|
||||
} \
|
||||
return KYAA_ERROR; \
|
||||
} \
|
||||
if (kyaa_helping) { \
|
||||
return KYAA_OKAY; \
|
||||
} \
|
||||
kyaa_parse_next = false; \
|
||||
kyaa_flag = '\0'; \
|
||||
continue; \
|
||||
} \
|
||||
} \
|
||||
|
||||
#define KYAA_DESCRIBE(c, name, description) \
|
||||
printf(" -%c --%s\n%s\n", c, name, description) \
|
||||
|
||||
#define KYAA_FLAG(c, name, description) \
|
||||
} \
|
||||
if (kyaa_helping) { \
|
||||
KYAA_DESCRIBE(c, name, description); \
|
||||
} else if (kyaa_flag == c || !strcmp(kyaa_arg, "--"name)) { \
|
||||
kyaa_flag = c; \
|
||||
kyaa_any = true; \
|
||||
|
||||
#define KYAA_FLAG_ARG(c, name, description) \
|
||||
} \
|
||||
if (kyaa_helping) { \
|
||||
KYAA_DESCRIBE(c, name, description); \
|
||||
} else if (kyaa_flag == c || !strcmp(kyaa_arg, "--"name)) { \
|
||||
if (kyaa_no_more || kyaa_flag != c) { \
|
||||
kyaa_parse_next = true; \
|
||||
if (KYAA_ITER + 1 == argc || argv[KYAA_ITER + 1][0] == '\0') { \
|
||||
fprintf(stderr, "expected an argument for --%s (-%c)\n", name, c); \
|
||||
return KYAA_ERROR; \
|
||||
} \
|
||||
kyaa_flag = c; \
|
||||
continue; \
|
||||
} \
|
||||
kyaa_flag = c; \
|
||||
kyaa_any = true; \
|
||||
|
||||
#define KYAA_FLAG_LONG(c, name, description) \
|
||||
KYAA_FLAG_ARG(c, name, description) \
|
||||
errno = 0; \
|
||||
long kyaa_flag_arg = strtol(kyaa_etc, NULL, 0); \
|
||||
if (errno) { \
|
||||
perror(NULL); \
|
||||
return KYAA_ERROR; \
|
||||
} \
|
||||
|
||||
#define KYAA_HELP(description) \
|
||||
} \
|
||||
if (kyaa_helping) { \
|
||||
if (description != NULL) { \
|
||||
printf("%s\n", description); \
|
||||
} \
|
||||
|
501
resynth.c
Normal file
501
resynth.c
Normal file
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
resynth - A program for resynthesizing textures.
|
||||
modified by Connor Olding, 2016
|
||||
Copyright (C) 2000 2008 Paul Francis Harrison
|
||||
Copyright (C) 2002 Laurent Despeyroux
|
||||
Copyright (C) 2002 David Rodríguez García
|
||||
|
||||
This program is licensed under the terms of the GNU General Public
|
||||
License (version 2), and is distributed without any warranty.
|
||||
You should have received a copy of the license with the program.
|
||||
If not, visit <http://gnu.org/licenses/> to obtain one.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_STATIC
|
||||
#define STBI_ONLY_JPEG
|
||||
#define STBI_ONLY_PNG
|
||||
#define STBI_ONLY_BMP
|
||||
#define STBI_ONLY_GIF
|
||||
#include "stb_image.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_STATIC
|
||||
#include "stb_image_write.h"
|
||||
|
||||
#define STRETCHY_BUFFER_OUT_OF_MEMORY \
|
||||
fprintf(stderr, "fatal error: ran out of memory in stb__sbgrowf\n"); \
|
||||
exit(1);
|
||||
#include "stretchy_buffer.h"
|
||||
|
||||
#include "kyaa.h"
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define CLAMP(x, l, u) (MIN(MAX(x, l), u))
|
||||
#define CLAMPV(x, l, u) x = CLAMP(x, l, u)
|
||||
#define LEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define MEMORY(a, size) \
|
||||
do { \
|
||||
if (a) (a) = (free(a), NULL); \
|
||||
if (size > 0) (a) = (typeof(a))(calloc(size, sizeof((a)[0]))); \
|
||||
} while (0) \
|
||||
|
||||
#define sb_freeset(a) ((a) = (sb_free(a), NULL))
|
||||
|
||||
#define INLINE static inline
|
||||
|
||||
// end of generic boilerplate, here's the actual program:
|
||||
|
||||
typedef struct coord {
|
||||
int x, y;
|
||||
} Coord;
|
||||
|
||||
INLINE Coord coord_add(const Coord a, const Coord b) {
|
||||
return (Coord){a.x + b.x, a.y + b.y};
|
||||
}
|
||||
|
||||
INLINE Coord coord_sub(const Coord a, const Coord b) {
|
||||
return (Coord){a.x - b.x, a.y - b.y};
|
||||
}
|
||||
|
||||
static int coord_compare(const void *v_a, const void *v_b) {
|
||||
const Coord *a = (Coord *) v_a;
|
||||
const Coord *b = (Coord *) v_b;
|
||||
return (a->x * a->x + a->y * a->y) - (b->x * b->x + b->y * b->y);
|
||||
}
|
||||
|
||||
typedef uint8_t Pixel;
|
||||
|
||||
typedef union {
|
||||
Pixel v[4];
|
||||
struct {
|
||||
Pixel r, g, b, a;
|
||||
};
|
||||
} Pixel32;
|
||||
|
||||
typedef struct {
|
||||
bool has_value, has_source;
|
||||
Coord source;
|
||||
} Status;
|
||||
|
||||
typedef struct {
|
||||
int width, height, depth;
|
||||
} Image;
|
||||
|
||||
#define IMAGE_RESIZE(image, w, h, d) \
|
||||
do { \
|
||||
image.width = w; \
|
||||
image.height = h; \
|
||||
image.depth = d; \
|
||||
MEMORY(image##_array, w * h * d); \
|
||||
} while (0) \
|
||||
|
||||
#define image_at(image, x, y) (image##_array + (y * image.width + x) * image.depth)
|
||||
#define image_atc(image, coord) image_at(image, coord.x, coord.y)
|
||||
|
||||
typedef struct {
|
||||
bool h_tile, v_tile;
|
||||
double autism;
|
||||
int neighbors, tries;
|
||||
int polish, magic;
|
||||
} Parameters;
|
||||
|
||||
INLINE bool wrap_or_clip(const Parameters parameters, const Image image,
|
||||
Coord *point) {
|
||||
while (point->x < 0) {
|
||||
if (parameters.h_tile) point->x += image.width;
|
||||
else return false;
|
||||
}
|
||||
while (point->x >= image.width) {
|
||||
if (parameters.h_tile) point->x -= image.width;
|
||||
else return false;
|
||||
}
|
||||
while (point->y < 0) {
|
||||
if (parameters.v_tile) point->y += image.height;
|
||||
else return false;
|
||||
}
|
||||
while (point->y >= image.height) {
|
||||
if (parameters.v_tile) point->y -= image.height;
|
||||
else return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int input_bytes;
|
||||
Image data, corpus, status;
|
||||
Pixel *data_array, *corpus_array;
|
||||
Status *status_array;
|
||||
Coord *data_points, *corpus_points, *sorted_offsets;
|
||||
Image tried;
|
||||
int *tried_array;
|
||||
|
||||
Coord *neighbors;
|
||||
Pixel32 *neighbor_values;
|
||||
Status **neighbor_statuses;
|
||||
int n_neighbors;
|
||||
|
||||
int *diff_table; // uint16_t ?
|
||||
|
||||
int best;
|
||||
Coord best_point;
|
||||
} Resynth_state;
|
||||
|
||||
static void state_free(Resynth_state *s) {
|
||||
sb_freeset(s->data_points);
|
||||
sb_freeset(s->corpus_points);
|
||||
sb_freeset(s->sorted_offsets);
|
||||
MEMORY(s->diff_table, 0);
|
||||
MEMORY(s->data_array, 0);
|
||||
MEMORY(s->corpus_array, 0);
|
||||
MEMORY(s->status_array, 0);
|
||||
MEMORY(s->tried_array, 0);
|
||||
}
|
||||
|
||||
static double neglog_cauchy(double x) {
|
||||
return log(x * x + 1.0);
|
||||
}
|
||||
|
||||
static void make_offset_list(Resynth_state *s) {
|
||||
int width = MIN(s->corpus.width, s->data.width);
|
||||
int height = MIN(s->corpus.height, s->data.height);
|
||||
|
||||
sb_freeset(s->sorted_offsets);
|
||||
for (int y = -height + 1; y < height; y++) {
|
||||
for (int x = -width + 1; x < width; x++) {
|
||||
Coord c = {x, y};
|
||||
sb_push(s->sorted_offsets, c);
|
||||
}
|
||||
}
|
||||
|
||||
qsort(s->sorted_offsets, sb_count(s->sorted_offsets),
|
||||
sizeof(Coord), coord_compare);
|
||||
}
|
||||
|
||||
INLINE void try_point(Resynth_state *s, const Coord point) {
|
||||
int sum = 0;
|
||||
|
||||
for (int i = 0; i < s->n_neighbors; i++) {
|
||||
Coord off_point = coord_add(point, s->neighbors[i]);
|
||||
if (off_point.x < 0 || off_point.y < 0 ||
|
||||
off_point.x >= s->corpus.width || off_point.y >= s->corpus.height) {
|
||||
sum += s->diff_table[0] * s->input_bytes;
|
||||
} else if (i) {
|
||||
const Pixel *corpus_pixel = image_atc(s->corpus, off_point);
|
||||
const Pixel *data_pixel = s->neighbor_values[i].v;
|
||||
for (int j = 0; j < s->input_bytes; j++) {
|
||||
sum += s->diff_table[256 + data_pixel[j] - corpus_pixel[j]];
|
||||
}
|
||||
}
|
||||
|
||||
if (sum >= s->best) return;
|
||||
}
|
||||
|
||||
s->best = sum;
|
||||
s->best_point = point;
|
||||
}
|
||||
|
||||
static void run(Resynth_state *s, Parameters parameters) {
|
||||
sb_freeset(s->data_points);
|
||||
sb_freeset(s->corpus_points);
|
||||
sb_freeset(s->sorted_offsets);
|
||||
|
||||
MEMORY(s->diff_table, 512);
|
||||
MEMORY(s->neighbors, parameters.neighbors);
|
||||
MEMORY(s->neighbor_values, parameters.neighbors);
|
||||
MEMORY(s->neighbor_statuses, parameters.neighbors);
|
||||
|
||||
IMAGE_RESIZE(s->status, s->data.width, s->data.height, 1);
|
||||
|
||||
for (int y = 0; y < s->status.height; y++) {
|
||||
for (int x = 0; x < s->status.width; x++) {
|
||||
image_at(s->status, x, y)->has_source = false;
|
||||
image_at(s->status, x, y)->has_value = false;
|
||||
Coord coord = {x, y};
|
||||
sb_push(s->data_points, coord);
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < s->corpus.height; y++) {
|
||||
for (int x = 0; x < s->corpus.width; x++) {
|
||||
Coord coord = {x, y};
|
||||
sb_push(s->corpus_points, coord);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sb_count(s->corpus_points) || !sb_count(s->data_points)) {
|
||||
fprintf(stderr, "invalid sizes\n");
|
||||
fprintf(stderr, "corpus: %i\n", sb_count(s->corpus_points));
|
||||
fprintf(stderr, "data: %i\n", sb_count(s->data_points));
|
||||
return;
|
||||
}
|
||||
|
||||
make_offset_list(s);
|
||||
|
||||
if (parameters.autism > 0) for (int i = -256; i < 256; i++) {
|
||||
double value = neglog_cauchy(i / 256.0 / parameters.autism) /
|
||||
neglog_cauchy(1.0 / parameters.autism) * 65536.0;
|
||||
s->diff_table[256 + i] = (int)(value);
|
||||
} else for (int i = -256; i < 256; i++) {
|
||||
s->diff_table[256 + i] = (int)(i != 0) * 65536;
|
||||
}
|
||||
|
||||
int data_area = sb_count(s->data_points);
|
||||
|
||||
for (int p = 0; p < parameters.polish + p; p++) {
|
||||
for (int i = 0; i < data_area; i++) {
|
||||
// shuffle
|
||||
int j = rand() % data_area;
|
||||
Coord temp = s->data_points[i];
|
||||
s->data_points[i] = s->data_points[j];
|
||||
s->data_points[j] = temp;
|
||||
}
|
||||
|
||||
if (parameters.magic) for (int n = data_area; n > 0;) {
|
||||
n = n * parameters.magic / 256;
|
||||
for (int i = 0; i < n; i++) {
|
||||
sb_push(s->data_points, s->data_points[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMAGE_RESIZE(s->tried, s->corpus.width, s->corpus.height, 1);
|
||||
int corpus_area = s->corpus.width * s->corpus.height;
|
||||
for (int i = 0; i < corpus_area; i++) s->tried_array[i] = -1;
|
||||
|
||||
// finally, do it
|
||||
|
||||
for (int i = sb_count(s->data_points) - 1; i >= 0; i--) {
|
||||
Coord position = s->data_points[i];
|
||||
|
||||
// this point will always have a value by the end of this iteration
|
||||
image_atc(s->status, position)->has_value = true;
|
||||
|
||||
s->n_neighbors = 0;
|
||||
const int sorted_offsets_size = sb_count(s->sorted_offsets);
|
||||
for (int j = 0; j < sorted_offsets_size; j++) {
|
||||
Coord point = coord_add(position, s->sorted_offsets[j]);
|
||||
|
||||
if (wrap_or_clip(parameters, s->data, &point) &&
|
||||
image_atc(s->status, point)->has_value) {
|
||||
s->neighbors[s->n_neighbors] = s->sorted_offsets[j];
|
||||
s->neighbor_statuses[s->n_neighbors] =
|
||||
image_atc(s->status, point);
|
||||
for (int k = 0; k < s->input_bytes; k++) {
|
||||
s->neighbor_values[s->n_neighbors].v[k] =
|
||||
image_atc(s->data, point)[k];
|
||||
}
|
||||
s->n_neighbors++;
|
||||
if (s->n_neighbors >= parameters.neighbors) break;
|
||||
}
|
||||
}
|
||||
|
||||
s->best = __INT_MAX__;
|
||||
|
||||
for (int j = 0; j < s->n_neighbors && s->best != 0; j++) {
|
||||
if (s->neighbor_statuses[j]->has_source) {
|
||||
Coord point = coord_sub(s->neighbor_statuses[j]->source,
|
||||
s->neighbors[j]);
|
||||
if (point.x < 0 || point.y < 0 ||
|
||||
point.x >= s->corpus.width || point.y >= s->corpus.height) {
|
||||
continue;
|
||||
}
|
||||
if (*image_atc(s->tried, point) == i) continue;
|
||||
try_point(s, point);
|
||||
*image_atc(s->tried, point) = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < parameters.tries && s->best != 0; j++) {
|
||||
try_point(s, s->corpus_points[rand() % sb_count(s->corpus_points)]);
|
||||
}
|
||||
|
||||
for (int j = 0; j < s->input_bytes; j++) {
|
||||
image_atc(s->data, position)[j] =
|
||||
image_atc(s->corpus, s->best_point)[j];
|
||||
}
|
||||
image_atc(s->status, position)->has_source = true;
|
||||
image_atc(s->status, position)->source = s->best_point;
|
||||
}
|
||||
}
|
||||
|
||||
static char *manipulate_filename(const char *fn,
|
||||
const char *new_extension) {
|
||||
#define MAX_LENGTH 256
|
||||
int length = strlen(fn);
|
||||
if (length > MAX_LENGTH)
|
||||
length = MAX_LENGTH;
|
||||
char *out_fn = (char *)calloc(2 * MAX_LENGTH, 1);
|
||||
strncpy(out_fn, fn, length);
|
||||
|
||||
char *hint = strrchr(out_fn, '.');
|
||||
if (hint == NULL) strcpy(out_fn + length, new_extension);
|
||||
else strcpy(hint, new_extension);
|
||||
|
||||
return out_fn;
|
||||
#undef MAX_LENGTH
|
||||
}
|
||||
|
||||
static const int disc00[] = {
|
||||
// http://oeis.org/A057961
|
||||
1, 5, 9, 13, 21, 25, 29, 37,
|
||||
45, 49, 57, 61, 69, 81, 89, 97,
|
||||
101, 109, 113, 121, 129, 137, 145, 149,
|
||||
161, 169, 177, 185, 193, 197, 213, 221,
|
||||
225, 233, 241, 249, 253, 261, 277, 285,
|
||||
293, 301, 305, 317, 325, 333, 341, 349,
|
||||
357, 365, 373, 377, 385, 401, 405, 421,
|
||||
429, 437, 441, 457, 465, 473, 481, 489,
|
||||
497, 505, 509, 517, 529, 545, 553, 561,
|
||||
569, 577, 593, 601, 609, 613, 621, 633,
|
||||
641, 657, 665, 673, 681, 697, 709, 717,
|
||||
725, 733, 741, 749, 757, 761, 769, 777,
|
||||
793, 797, 805, 821, 829, 845, 853, 861,
|
||||
869, 877, 885, 889, 901, 917, 925, 933,
|
||||
941, 949, 965, 973, 981, 989, 997, 1005,
|
||||
1009, 1033, 1041, 1049, 1057, 1069, 1085, 1093
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
Resynth_state state = {0};
|
||||
Resynth_state *s = &state; // just for consistency
|
||||
|
||||
Parameters parameters = {0};
|
||||
parameters.v_tile = true;
|
||||
parameters.h_tile = true;
|
||||
parameters.magic = 192; // 192 (3/4)
|
||||
parameters.autism = 32. / 256.; // 30. / 256.
|
||||
parameters.neighbors = 29; // 30
|
||||
parameters.tries = 192; // 200 (or 80 in the paper)
|
||||
parameters.polish = 0; // 0
|
||||
|
||||
int scale = 1;
|
||||
unsigned long seed = 0;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
KYAA_LOOP {
|
||||
KYAA_BEGIN
|
||||
|
||||
KYAA_FLAG_LONG('a', "autism",
|
||||
" sensitivity to outliers\n"
|
||||
" range: (0,256); default: 32")
|
||||
parameters.autism = (double)(kyaa_flag_arg) / 256.;
|
||||
|
||||
KYAA_FLAG_LONG('N', "neighbors",
|
||||
" points to use when sampling\n"
|
||||
" range: (0,1024); default: 29")
|
||||
parameters.neighbors = kyaa_flag_arg;
|
||||
|
||||
KYAA_FLAG_LONG('r', "radius",
|
||||
" square neighborhood, always odd\n"
|
||||
" range: (0,32); default: [n/a]")
|
||||
int radius = kyaa_flag_arg;
|
||||
radius = 2 * MAX(radius, 0) + 1;
|
||||
parameters.neighbors = radius * radius;
|
||||
|
||||
KYAA_FLAG_LONG('R', "circle-radius",
|
||||
" circle neighborhood radius\n"
|
||||
" range: (1,128); default: [n/a]")
|
||||
int radius = kyaa_flag_arg;
|
||||
radius = CLAMP(radius, 1, (int)(LEN(disc00)));
|
||||
parameters.neighbors = disc00[radius - 1];
|
||||
|
||||
KYAA_FLAG_LONG('M', "tries",
|
||||
" random points added to candidates\n"
|
||||
" range: (0,65536); default: 192")
|
||||
parameters.tries = kyaa_flag_arg;
|
||||
|
||||
KYAA_FLAG_LONG('p', "polish",
|
||||
" extra iterations\n"
|
||||
" range: (0,9); default: 0")
|
||||
parameters.polish = kyaa_flag_arg;
|
||||
|
||||
KYAA_FLAG_LONG('m', "magic",
|
||||
" magic constant, affects iterations\n"
|
||||
" range: (0,255); default: 192")
|
||||
parameters.magic = kyaa_flag_arg;
|
||||
|
||||
KYAA_FLAG_LONG('s', "scale",
|
||||
" output size multiplier; negative values set width and height\n"
|
||||
" range: (-8192,32); default: 1")
|
||||
scale = kyaa_flag_arg;
|
||||
|
||||
KYAA_FLAG_LONG('S', "seed",
|
||||
" initial RNG value\n"
|
||||
" range: (0,); default: 0 [time(0)]")
|
||||
seed = (unsigned long) kyaa_flag_arg;
|
||||
|
||||
KYAA_HELP(" {files...}\n"
|
||||
" image files to open, resynthesize, and save as {filename}.resynth.png\n"
|
||||
" required default: [none]")
|
||||
|
||||
KYAA_END
|
||||
|
||||
if (kyaa_read_stdin) {
|
||||
fprintf(stderr, "fatal error: reading from stdin is unsupported\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CLAMPV(parameters.polish, 0, 9);
|
||||
CLAMPV(parameters.magic, 0, 255);
|
||||
CLAMPV(parameters.autism, 0., 1.);
|
||||
CLAMPV(parameters.neighbors, 0, disc00[LEN(disc00) - 1]);
|
||||
CLAMPV(parameters.tries, 0, 65536);
|
||||
CLAMPV(scale, -8192, 32);
|
||||
|
||||
char *fn = kyaa_arg;
|
||||
|
||||
int w, h, d;
|
||||
uint8_t *image = stbi_load(fn, &w, &h, &d, 0);
|
||||
if (image == NULL) {
|
||||
fprintf(stderr, "invalid image: %s\n", fn);
|
||||
ret--;
|
||||
continue;
|
||||
}
|
||||
|
||||
IMAGE_RESIZE(s->corpus, w, h, d);
|
||||
memcpy(s->corpus_array, image, w * h * d);
|
||||
|
||||
s->input_bytes = MIN(d, 3);
|
||||
|
||||
{
|
||||
int data_w = 256, data_h = 256;
|
||||
if (scale > 0) data_w = scale * w, data_h = scale * h;
|
||||
if (scale < 0) data_w = -scale, data_h = -scale;
|
||||
IMAGE_RESIZE(s->data, data_w, data_h, s->input_bytes);
|
||||
}
|
||||
|
||||
stbi_image_free(image);
|
||||
|
||||
if (seed) srand(seed);
|
||||
else srand(time(0));
|
||||
run(s, parameters);
|
||||
|
||||
char *out_fn = manipulate_filename(fn, ".resynth.png");
|
||||
puts(out_fn);
|
||||
int result = stbi_write_png(out_fn, s->data.width, s->data.height,
|
||||
s->data.depth, s->data_array, 0);
|
||||
if (!result) {
|
||||
fprintf(stderr, "failed to write: %s\n", out_fn);
|
||||
ret--;
|
||||
}
|
||||
|
||||
free(out_fn);
|
||||
}
|
||||
|
||||
state_free(s);
|
||||
|
||||
return ret;
|
||||
}
|
6755
stb_image.h
Normal file
6755
stb_image.h
Normal file
File diff suppressed because it is too large
Load diff
1048
stb_image_write.h
Normal file
1048
stb_image_write.h
Normal file
File diff suppressed because it is too large
Load diff
55
stretchy_buffer.h
Normal file
55
stretchy_buffer.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// stretchy_buffer.h - v1.02 - public domain - nothings.org/stb
|
||||
// a vector<>-like dynamic array for C
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// This software is dual-licensed to the public domain and under the following
|
||||
// license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||
// publish, and distribute this file as you see fit.
|
||||
|
||||
#ifndef STB_STRETCHY_BUFFER_H_INCLUDED
|
||||
#define STB_STRETCHY_BUFFER_H_INCLUDED
|
||||
|
||||
#ifndef NO_STRETCHY_BUFFER_SHORT_NAMES
|
||||
#define sb_free stb_sb_free
|
||||
#define sb_push stb_sb_push
|
||||
#define sb_count stb_sb_count
|
||||
#define sb_add stb_sb_add
|
||||
#define sb_last stb_sb_last
|
||||
#endif
|
||||
|
||||
#define stb_sb_free(a) ((a) ? free(stb__sbraw(a)),0 : 0)
|
||||
#define stb_sb_push(a,v) (stb__sbmaybegrow(a,1), (a)[stb__sbn(a)++] = (v))
|
||||
#define stb_sb_count(a) ((a) ? stb__sbn(a) : 0)
|
||||
#define stb_sb_add(a,n) (stb__sbmaybegrow(a,n), stb__sbn(a)+=(n), &(a)[stb__sbn(a)-(n)])
|
||||
#define stb_sb_last(a) ((a)[stb__sbn(a)-1])
|
||||
|
||||
#define stb__sbraw(a) ((int *) (a) - 2)
|
||||
#define stb__sbm(a) stb__sbraw(a)[0]
|
||||
#define stb__sbn(a) stb__sbraw(a)[1]
|
||||
|
||||
#define stb__sbneedgrow(a,n) ((a)==0 || stb__sbn(a)+(n) >= stb__sbm(a))
|
||||
#define stb__sbmaybegrow(a,n) (stb__sbneedgrow(a,(n)) ? stb__sbgrow(a,n) : 0)
|
||||
#define stb__sbgrow(a,n) ((a) = stb__sbgrowf((a), (n), sizeof(*(a))))
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void * stb__sbgrowf(void *arr, int increment, int itemsize)
|
||||
{
|
||||
int dbl_cur = arr ? 2*stb__sbm(arr) : 0;
|
||||
int min_needed = stb_sb_count(arr) + increment;
|
||||
int m = dbl_cur > min_needed ? dbl_cur : min_needed;
|
||||
int *p = (int *) realloc(arr ? stb__sbraw(arr) : 0, itemsize * m + sizeof(int)*2);
|
||||
if (p) {
|
||||
if (!arr)
|
||||
p[1] = 0;
|
||||
p[0] = m;
|
||||
return p+2;
|
||||
} else {
|
||||
#ifdef STRETCHY_BUFFER_OUT_OF_MEMORY
|
||||
STRETCHY_BUFFER_OUT_OF_MEMORY ;
|
||||
#endif
|
||||
return (void *) (2*sizeof(int)); // try to force a NULL pointer exception later
|
||||
}
|
||||
}
|
||||
#endif // STB_STRETCHY_BUFFER_H_INCLUDED
|
Loading…
Reference in a new issue