1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222 |
- /* stbhw - v0.7 - http://nothings.org/gamedev/herringbone
- Herringbone Wang Tile Generator - Sean Barrett 2014 - public domain
- == 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.
- == WHAT IT IS ===========================
- This library is an SDK for Herringbone Wang Tile generation:
- http://nothings.org/gamedev/herringbone
- The core design is that you use this library offline to generate a
- "template" of the tiles you'll create. You then edit those tiles, then
- load the created tile image file back into this library and use it at
- runtime to generate "maps".
- You cannot load arbitrary tile image files with this library; it is
- only designed to load image files made from the template it created.
- It stores a binary description of the tile sizes & constraints in a
- few pixels, and uses those to recover the rules, rather than trying
- to parse the tiles themselves.
- You *can* use this library to generate from arbitrary tile sets, but
- only by loading the tile set and specifying the constraints explicitly
- yourself.
- == COMPILING ============================
- 1. #define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION before including this
- header file in *one* source file to create the implementation
- in that source file.
- 2. optionally #define STB_HBWANG_RAND() to be a random number
- generator. if you don't define it, it will use rand(),
- and you need to seed srand() yourself.
- 3. optionally #define STB_HBWANG_ASSERT(x), otherwise
- it will use assert()
- 4. optionally #define STB_HBWANG_STATIC to force all symbols to be
- static instead of public, so they are only accesible
- in the source file that creates the implementation
- 5. optionally #define STB_HBWANG_NO_REPITITION_REDUCTION to disable
- the code that tries to reduce having the same tile appear
- adjacent to itself in wang-corner-tile mode (e.g. imagine
- if you were doing something where 90% of things should be
- the same grass tile, you need to disable this system)
- 6. optionally define STB_HBWANG_MAX_X and STB_HBWANG_MAX_Y
- to be the max dimensions of the generated map in multiples
- of the wang tile's short side's length (e.g. if you
- have 20x10 wang tiles, so short_side_len=10, and you
- have MAX_X is 17, then the largest map you can generate
- is 170 pixels wide). The defaults are 100x100. This
- is used to define static arrays which affect memory
- usage.
- == USING ================================
- To use the map generator, you need a tileset. You can download
- some sample tilesets from http://nothings.org/gamedev/herringbone
- Then see the "sample application" below.
- You can also use this file to generate templates for
- tilesets which you then hand-edit to create the data.
- == MEMORY MANAGEMENT ====================
- The tileset loader allocates memory with malloc(). The map
- generator does no memory allocation, so e.g. you can load
- tilesets at startup and never free them and never do any
- further allocation.
- == SAMPLE APPLICATION ===================
- #include <stdlib.h>
- #include <stdio.h>
- #include <time.h>
- #define STB_IMAGE_IMPLEMENTATION
- #include "stb_image.h" // http://nothings.org/stb_image.c
- #define STB_IMAGE_WRITE_IMPLEMENTATION
- #include "stb_image_write.h" // http://nothings.org/stb/stb_image_write.h
- #define STB_HBWANG_IMPLEMENTATION
- #include "stb_hbwang.h"
- int main(int argc, char **argv)
- {
- unsigned char *data;
- int xs,ys, w,h;
- stbhw_tileset ts;
- if (argc != 4) {
- fprintf(stderr, "Usage: mapgen {tile-file} {xsize} {ysize}\n"
- "generates file named 'test_map.png'\n");
- exit(1);
- }
- data = stbi_load(argv[1], &w, &h, NULL, 3);
- xs = atoi(argv[2]);
- ys = atoi(argv[3]);
- if (data == NULL) {
- fprintf(stderr, "Error opening or parsing '%s' as an image file\n", argv[1]);
- exit(1);
- }
- if (xs < 1 || xs > 1000) {
- fprintf(stderr, "xsize invalid or out of range\n");
- exit(1);
- }
- if (ys < 1 || ys > 1000) {
- fprintf(stderr, "ysize invalid or out of range\n");
- exit(1);
- }
- stbhw_build_tileset_from_image(&ts, data, w*3, w, h);
- free(data);
- // allocate a buffer to create the final image to
- data = malloc(3 * xs * ys);
- srand(time(NULL));
- stbhw_generate_image(&ts, NULL, data, xs*3, xs, ys);
- stbi_write_png("test_map.png", xs, ys, 3, data, xs*3);
- stbhw_free_tileset(&ts);
- free(data);
- return 0;
- }
- == VERSION HISTORY ===================
- 0.7 2019-03-04 - fix warnings
- 0.6 2014-08-17 - fix broken map-maker
- 0.5 2014-07-07 - initial release
- */
- //////////////////////////////////////////////////////////////////////////////
- // //
- // HEADER FILE SECTION //
- // //
- #ifndef INCLUDE_STB_HWANG_H
- #define INCLUDE_STB_HWANG_H
- #ifdef STB_HBWANG_STATIC
- #define STBHW_EXTERN static
- #else
- #ifdef __cplusplus
- #define STBHW_EXTERN extern "C"
- #else
- #define STBHW_EXTERN extern
- #endif
- #endif
- typedef struct stbhw_tileset stbhw_tileset;
- // returns description of last error produced by any function (not thread-safe)
- STBHW_EXTERN const char *stbhw_get_last_error(void);
- // build a tileset from an image that conforms to a template created by this
- // library. (you allocate storage for stbhw_tileset and function fills it out;
- // memory for individual tiles are malloc()ed).
- // returns non-zero on success, 0 on error
- STBHW_EXTERN int stbhw_build_tileset_from_image(stbhw_tileset *ts,
- unsigned char *pixels, int stride_in_bytes, int w, int h);
- // free a tileset built by stbhw_build_tileset_from_image
- STBHW_EXTERN void stbhw_free_tileset(stbhw_tileset *ts);
- // generate a map that is w * h pixels (3-bytes each)
- // returns non-zero on success, 0 on error
- // not thread-safe (uses a global data structure to avoid memory management)
- // weighting should be NULL, as non-NULL weighting is currently untested
- STBHW_EXTERN int stbhw_generate_image(stbhw_tileset *ts, int **weighting,
- unsigned char *pixels, int stride_in_bytes, int w, int h);
- //////////////////////////////////////
- //
- // TILESET DATA STRUCTURE
- //
- // if you use the image-to-tileset system from this file, you
- // don't need to worry about these data structures. but if you
- // want to build/load a tileset yourself, you'll need to fill
- // these out.
- typedef struct
- {
- // the edge or vertex constraints, according to diagram below
- signed char a,b,c,d,e,f;
- // The herringbone wang tile data; it is a bitmap which is either
- // w=2*short_sidelen,h=short_sidelen, or w=short_sidelen,h=2*short_sidelen.
- // it is always RGB, stored row-major, with no padding between rows.
- // (allocate stbhw_tile structure to be large enough for the pixel data)
- unsigned char pixels[1];
- } stbhw_tile;
- struct stbhw_tileset
- {
- int is_corner;
- int num_color[6]; // number of colors for each of 6 edge types or 4 corner types
- int short_side_len;
- stbhw_tile **h_tiles;
- stbhw_tile **v_tiles;
- int num_h_tiles, max_h_tiles;
- int num_v_tiles, max_v_tiles;
- };
- /////////////// TEMPLATE GENERATOR //////////////////////////
- // when requesting a template, you fill out this data
- typedef struct
- {
- int is_corner; // using corner colors or edge colors?
- int short_side_len; // rectangles is 2n x n, n = short_side_len
- int num_color[6]; // see below diagram for meaning of the index to this;
- // 6 values if edge (!is_corner), 4 values if is_corner
- // legal numbers: 1..8 if edge, 1..4 if is_corner
- int num_vary_x; // additional number of variations along x axis in the template
- int num_vary_y; // additional number of variations along y axis in the template
- int corner_type_color_template[4][4];
- // if corner_type_color_template[s][t] is non-zero, then any
- // corner of type s generated as color t will get a little
- // corner sample markup in the template image data
- } stbhw_config;
- // computes the size needed for the template image
- STBHW_EXTERN void stbhw_get_template_size(stbhw_config *c, int *w, int *h);
- // generates a template image, assuming data is 3*w*h bytes long, RGB format
- STBHW_EXTERN int stbhw_make_template(stbhw_config *c, unsigned char *data, int w, int h, int stride_in_bytes);
- #endif//INCLUDE_STB_HWANG_H
- // TILE CONSTRAINT TYPES
- //
- // there are 4 "types" of corners and 6 types of edges.
- // you can configure the tileset to have different numbers
- // of colors for each type of color or edge.
- //
- // corner types:
- //
- // 0---*---1---*---2---*---3
- // | | |
- // * * *
- // | | |
- // 1---*---2---*---3 0---*---1---*---2
- // | | |
- // * * *
- // | | |
- // 0---*---1---*---2---*---3
- //
- //
- // edge types:
- //
- // *---2---*---3---* *---0---*
- // | | | |
- // 1 4 5 1
- // | | | |
- // *---0---*---2---* * *
- // | |
- // 4 5
- // | |
- // *---3---*
- //
- // TILE CONSTRAINTS
- //
- // each corner/edge has a color; this shows the name
- // of the variable containing the color
- //
- // corner constraints:
- //
- // a---*---d
- // | |
- // * *
- // | |
- // a---*---b---*---c b e
- // | | | |
- // * * * *
- // | | | |
- // d---*---e---*---f c---*---f
- //
- //
- // edge constraints:
- //
- // *---a---*---b---* *---a---*
- // | | | |
- // c d b c
- // | | | |
- // *---e---*---f---* * *
- // | |
- // d e
- // | |
- // *---f---*
- //
- //////////////////////////////////////////////////////////////////////////////
- // //
- // IMPLEMENTATION SECTION //
- // //
- #ifdef STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION
- #include <string.h> // memcpy
- #include <stdlib.h> // malloc
- #ifndef STB_HBWANG_RAND
- #include <stdlib.h>
- #define STB_HBWANG_RAND() (rand() >> 4)
- #endif
- #ifndef STB_HBWANG_ASSERT
- #include <assert.h>
- #define STB_HBWANG_ASSERT(x) assert(x)
- #endif
- // map size
- #ifndef STB_HBWANG_MAX_X
- #define STB_HBWANG_MAX_X 100
- #endif
- #ifndef STB_HBWANG_MAX_Y
- #define STB_HBWANG_MAX_Y 100
- #endif
- // global variables for color assignments
- // @MEMORY change these to just store last two/three rows
- // and keep them on the stack
- static signed char c_color[STB_HBWANG_MAX_Y+6][STB_HBWANG_MAX_X+6];
- static signed char v_color[STB_HBWANG_MAX_Y+6][STB_HBWANG_MAX_X+5];
- static signed char h_color[STB_HBWANG_MAX_Y+5][STB_HBWANG_MAX_X+6];
- static const char *stbhw_error;
- STBHW_EXTERN const char *stbhw_get_last_error(void)
- {
- const char *temp = stbhw_error;
- stbhw_error = 0;
- return temp;
- }
- /////////////////////////////////////////////////////////////
- //
- // SHARED TEMPLATE-DESCRIPTION CODE
- //
- // Used by both template generator and tileset parser; by
- // using the same code, they are locked in sync and we don't
- // need to try to do more sophisticated parsing of edge color
- // markup or something.
- typedef void stbhw__process_rect(struct stbhw__process *p, int xpos, int ypos,
- int a, int b, int c, int d, int e, int f);
- typedef struct stbhw__process
- {
- stbhw_tileset *ts;
- stbhw_config *c;
- stbhw__process_rect *process_h_rect;
- stbhw__process_rect *process_v_rect;
- unsigned char *data;
- int stride,w,h;
- } stbhw__process;
- static void stbhw__process_h_row(stbhw__process *p,
- int xpos, int ypos,
- int a0, int a1,
- int b0, int b1,
- int c0, int c1,
- int d0, int d1,
- int e0, int e1,
- int f0, int f1,
- int variants)
- {
- int a,b,c,d,e,f,v;
- for (v=0; v < variants; ++v)
- for (f=f0; f <= f1; ++f)
- for (e=e0; e <= e1; ++e)
- for (d=d0; d <= d1; ++d)
- for (c=c0; c <= c1; ++c)
- for (b=b0; b <= b1; ++b)
- for (a=a0; a <= a1; ++a) {
- p->process_h_rect(p, xpos, ypos, a,b,c,d,e,f);
- xpos += 2*p->c->short_side_len + 3;
- }
- }
- static void stbhw__process_v_row(stbhw__process *p,
- int xpos, int ypos,
- int a0, int a1,
- int b0, int b1,
- int c0, int c1,
- int d0, int d1,
- int e0, int e1,
- int f0, int f1,
- int variants)
- {
- int a,b,c,d,e,f,v;
- for (v=0; v < variants; ++v)
- for (f=f0; f <= f1; ++f)
- for (e=e0; e <= e1; ++e)
- for (d=d0; d <= d1; ++d)
- for (c=c0; c <= c1; ++c)
- for (b=b0; b <= b1; ++b)
- for (a=a0; a <= a1; ++a) {
- p->process_v_rect(p, xpos, ypos, a,b,c,d,e,f);
- xpos += p->c->short_side_len+3;
- }
- }
- static void stbhw__get_template_info(stbhw_config *c, int *w, int *h, int *h_count, int *v_count)
- {
- int size_x,size_y;
- int horz_count,vert_count;
- if (c->is_corner) {
- int horz_w = c->num_color[1] * c->num_color[2] * c->num_color[3] * c->num_vary_x;
- int horz_h = c->num_color[0] * c->num_color[1] * c->num_color[2] * c->num_vary_y;
- int vert_w = c->num_color[0] * c->num_color[3] * c->num_color[2] * c->num_vary_y;
- int vert_h = c->num_color[1] * c->num_color[0] * c->num_color[3] * c->num_vary_x;
- int horz_x = horz_w * (2*c->short_side_len + 3);
- int horz_y = horz_h * ( c->short_side_len + 3);
- int vert_x = vert_w * ( c->short_side_len + 3);
- int vert_y = vert_h * (2*c->short_side_len + 3);
- horz_count = horz_w * horz_h;
- vert_count = vert_w * vert_h;
- size_x = horz_x > vert_x ? horz_x : vert_x;
- size_y = 2 + horz_y + 2 + vert_y;
- } else {
- int horz_w = c->num_color[0] * c->num_color[1] * c->num_color[2] * c->num_vary_x;
- int horz_h = c->num_color[3] * c->num_color[4] * c->num_color[2] * c->num_vary_y;
- int vert_w = c->num_color[0] * c->num_color[5] * c->num_color[1] * c->num_vary_y;
- int vert_h = c->num_color[3] * c->num_color[4] * c->num_color[5] * c->num_vary_x;
- int horz_x = horz_w * (2*c->short_side_len + 3);
- int horz_y = horz_h * ( c->short_side_len + 3);
- int vert_x = vert_w * ( c->short_side_len + 3);
- int vert_y = vert_h * (2*c->short_side_len + 3);
- horz_count = horz_w * horz_h;
- vert_count = vert_w * vert_h;
- size_x = horz_x > vert_x ? horz_x : vert_x;
- size_y = 2 + horz_y + 2 + vert_y;
- }
- if (w) *w = size_x;
- if (h) *h = size_y;
- if (h_count) *h_count = horz_count;
- if (v_count) *v_count = vert_count;
- }
- STBHW_EXTERN void stbhw_get_template_size(stbhw_config *c, int *w, int *h)
- {
- stbhw__get_template_info(c, w, h, NULL, NULL);
- }
- static int stbhw__process_template(stbhw__process *p)
- {
- int i,j,k,q, ypos;
- int size_x, size_y;
- stbhw_config *c = p->c;
- stbhw__get_template_info(c, &size_x, &size_y, NULL, NULL);
- if (p->w < size_x || p->h < size_y) {
- stbhw_error = "image too small for configuration";
- return 0;
- }
- if (c->is_corner) {
- ypos = 2;
- for (k=0; k < c->num_color[2]; ++k) {
- for (j=0; j < c->num_color[1]; ++j) {
- for (i=0; i < c->num_color[0]; ++i) {
- for (q=0; q < c->num_vary_y; ++q) {
- stbhw__process_h_row(p, 0,ypos,
- 0,c->num_color[1]-1, 0,c->num_color[2]-1, 0,c->num_color[3]-1,
- i,i, j,j, k,k,
- c->num_vary_x);
- ypos += c->short_side_len + 3;
- }
- }
- }
- }
- ypos += 2;
- for (k=0; k < c->num_color[3]; ++k) {
- for (j=0; j < c->num_color[0]; ++j) {
- for (i=0; i < c->num_color[1]; ++i) {
- for (q=0; q < c->num_vary_x; ++q) {
- stbhw__process_v_row(p, 0,ypos,
- 0,c->num_color[0]-1, 0,c->num_color[3]-1, 0,c->num_color[2]-1,
- i,i, j,j, k,k,
- c->num_vary_y);
- ypos += (c->short_side_len*2) + 3;
- }
- }
- }
- }
- assert(ypos == size_y);
- } else {
- ypos = 2;
- for (k=0; k < c->num_color[3]; ++k) {
- for (j=0; j < c->num_color[4]; ++j) {
- for (i=0; i < c->num_color[2]; ++i) {
- for (q=0; q < c->num_vary_y; ++q) {
- stbhw__process_h_row(p, 0,ypos,
- 0,c->num_color[2]-1, k,k,
- 0,c->num_color[1]-1, j,j,
- 0,c->num_color[0]-1, i,i,
- c->num_vary_x);
- ypos += c->short_side_len + 3;
- }
- }
- }
- }
- ypos += 2;
- for (k=0; k < c->num_color[3]; ++k) {
- for (j=0; j < c->num_color[4]; ++j) {
- for (i=0; i < c->num_color[5]; ++i) {
- for (q=0; q < c->num_vary_x; ++q) {
- stbhw__process_v_row(p, 0,ypos,
- 0,c->num_color[0]-1, i,i,
- 0,c->num_color[1]-1, j,j,
- 0,c->num_color[5]-1, k,k,
- c->num_vary_y);
- ypos += (c->short_side_len*2) + 3;
- }
- }
- }
- }
- assert(ypos == size_y);
- }
- return 1;
- }
- /////////////////////////////////////////////////////////////
- //
- // MAP GENERATOR
- //
- static void stbhw__draw_pixel(unsigned char *output, int stride, int x, int y, unsigned char c[3])
- {
- memcpy(output + y*stride + x*3, c, 3);
- }
- static void stbhw__draw_h_tile(unsigned char *output, int stride, int xmax, int ymax, int x, int y, stbhw_tile *h, int sz)
- {
- int i,j;
- for (j=0; j < sz; ++j)
- if (y+j >= 0 && y+j < ymax)
- for (i=0; i < sz*2; ++i)
- if (x+i >= 0 && x+i < xmax)
- stbhw__draw_pixel(output,stride, x+i,y+j, &h->pixels[(j*sz*2 + i)*3]);
- }
- static void stbhw__draw_v_tile(unsigned char *output, int stride, int xmax, int ymax, int x, int y, stbhw_tile *h, int sz)
- {
- int i,j;
- for (j=0; j < sz*2; ++j)
- if (y+j >= 0 && y+j < ymax)
- for (i=0; i < sz; ++i)
- if (x+i >= 0 && x+i < xmax)
- stbhw__draw_pixel(output,stride, x+i,y+j, &h->pixels[(j*sz + i)*3]);
- }
- // randomly choose a tile that fits constraints for a given spot, and update the constraints
- static stbhw_tile * stbhw__choose_tile(stbhw_tile **list, int numlist,
- signed char *a, signed char *b, signed char *c,
- signed char *d, signed char *e, signed char *f,
- int **weighting)
- {
- int i,n,m = 1<<30,pass;
- for (pass=0; pass < 2; ++pass) {
- n=0;
- // pass #1:
- // count number of variants that match this partial set of constraints
- // pass #2:
- // stop on randomly selected match
- for (i=0; i < numlist; ++i) {
- stbhw_tile *h = list[i];
- if ((*a < 0 || *a == h->a) &&
- (*b < 0 || *b == h->b) &&
- (*c < 0 || *c == h->c) &&
- (*d < 0 || *d == h->d) &&
- (*e < 0 || *e == h->e) &&
- (*f < 0 || *f == h->f)) {
- if (weighting)
- n += weighting[0][i];
- else
- n += 1;
- if (n > m) {
- // use list[i]
- // update constraints to reflect what we placed
- *a = h->a;
- *b = h->b;
- *c = h->c;
- *d = h->d;
- *e = h->e;
- *f = h->f;
- return h;
- }
- }
- }
- if (n == 0) {
- stbhw_error = "couldn't find tile matching constraints";
- return NULL;
- }
- m = STB_HBWANG_RAND() % n;
- }
- STB_HBWANG_ASSERT(0);
- return NULL;
- }
- static int stbhw__match(int x, int y)
- {
- return c_color[y][x] == c_color[y+1][x+1];
- }
- static int stbhw__weighted(int num_options, int *weights)
- {
- int k, total, choice;
- total = 0;
- for (k=0; k < num_options; ++k)
- total += weights[k];
- choice = STB_HBWANG_RAND() % total;
- total = 0;
- for (k=0; k < num_options; ++k) {
- total += weights[k];
- if (choice < total)
- break;
- }
- STB_HBWANG_ASSERT(k < num_options);
- return k;
- }
- static int stbhw__change_color(int old_color, int num_options, int *weights)
- {
- if (weights) {
- int k, total, choice;
- total = 0;
- for (k=0; k < num_options; ++k)
- if (k != old_color)
- total += weights[k];
- choice = STB_HBWANG_RAND() % total;
- total = 0;
- for (k=0; k < num_options; ++k) {
- if (k != old_color) {
- total += weights[k];
- if (choice < total)
- break;
- }
- }
- STB_HBWANG_ASSERT(k < num_options);
- return k;
- } else {
- int offset = 1+STB_HBWANG_RAND() % (num_options-1);
- return (old_color+offset) % num_options;
- }
- }
- // generate a map that is w * h pixels (3-bytes each)
- // returns 1 on success, 0 on error
- STBHW_EXTERN int stbhw_generate_image(stbhw_tileset *ts, int **weighting, unsigned char *output, int stride, int w, int h)
- {
- int sidelen = ts->short_side_len;
- int xmax = (w / sidelen) + 6;
- int ymax = (h / sidelen) + 6;
- if (xmax > STB_HBWANG_MAX_X+6 || ymax > STB_HBWANG_MAX_Y+6) {
- stbhw_error = "increase STB_HBWANG_MAX_X/Y";
- return 0;
- }
- if (ts->is_corner) {
- int i,j, ypos;
- int *cc = ts->num_color;
- for (j=0; j < ymax; ++j) {
- for (i=0; i < xmax; ++i) {
- int p = (i-j+1)&3; // corner type
- if (weighting==NULL || weighting[p]==0 || cc[p] == 1)
- c_color[j][i] = STB_HBWANG_RAND() % cc[p];
- else
- c_color[j][i] = stbhw__weighted(cc[p], weighting[p]);
- }
- }
- #ifndef STB_HBWANG_NO_REPITITION_REDUCTION
- // now go back through and make sure we don't have adjancent 3x2 vertices that are identical,
- // to avoid really obvious repetition (which happens easily with extreme weights)
- for (j=0; j < ymax-3; ++j) {
- for (i=0; i < xmax-3; ++i) {
- //int p = (i-j+1) & 3; // corner type // unused, not sure what the intent was so commenting it out
- STB_HBWANG_ASSERT(i+3 < STB_HBWANG_MAX_X+6);
- STB_HBWANG_ASSERT(j+3 < STB_HBWANG_MAX_Y+6);
- if (stbhw__match(i,j) && stbhw__match(i,j+1) && stbhw__match(i,j+2)
- && stbhw__match(i+1,j) && stbhw__match(i+1,j+1) && stbhw__match(i+1,j+2)) {
- int p = ((i+1)-(j+1)+1) & 3;
- if (cc[p] > 1)
- c_color[j+1][i+1] = stbhw__change_color(c_color[j+1][i+1], cc[p], weighting ? weighting[p] : NULL);
- }
- if (stbhw__match(i,j) && stbhw__match(i+1,j) && stbhw__match(i+2,j)
- && stbhw__match(i,j+1) && stbhw__match(i+1,j+1) && stbhw__match(i+2,j+1)) {
- int p = ((i+2)-(j+1)+1) & 3;
- if (cc[p] > 1)
- c_color[j+1][i+2] = stbhw__change_color(c_color[j+1][i+2], cc[p], weighting ? weighting[p] : NULL);
- }
- }
- }
- #endif
- ypos = -1 * sidelen;
- for (j = -1; ypos < h; ++j) {
- // a general herringbone row consists of:
- // horizontal left block, the bottom of a previous vertical, the top of a new vertical
- int phase = (j & 3);
- // displace horizontally according to pattern
- if (phase == 0) {
- i = 0;
- } else {
- i = phase-4;
- }
- for (;; i += 4) {
- int xpos = i * sidelen;
- if (xpos >= w)
- break;
- // horizontal left-block
- if (xpos + sidelen*2 >= 0 && ypos >= 0) {
- stbhw_tile *t = stbhw__choose_tile(
- ts->h_tiles, ts->num_h_tiles,
- &c_color[j+2][i+2], &c_color[j+2][i+3], &c_color[j+2][i+4],
- &c_color[j+3][i+2], &c_color[j+3][i+3], &c_color[j+3][i+4],
- weighting
- );
- if (t == NULL)
- return 0;
- stbhw__draw_h_tile(output,stride,w,h, xpos, ypos, t, sidelen);
- }
- xpos += sidelen * 2;
- // now we're at the end of a previous vertical one
- xpos += sidelen;
- // now we're at the start of a new vertical one
- if (xpos < w) {
- stbhw_tile *t = stbhw__choose_tile(
- ts->v_tiles, ts->num_v_tiles,
- &c_color[j+2][i+5], &c_color[j+3][i+5], &c_color[j+4][i+5],
- &c_color[j+2][i+6], &c_color[j+3][i+6], &c_color[j+4][i+6],
- weighting
- );
- if (t == NULL)
- return 0;
- stbhw__draw_v_tile(output,stride,w,h, xpos, ypos, t, sidelen);
- }
- }
- ypos += sidelen;
- }
- } else {
- // @TODO edge-color repetition reduction
- int i,j, ypos;
- memset(v_color, -1, sizeof(v_color));
- memset(h_color, -1, sizeof(h_color));
- ypos = -1 * sidelen;
- for (j = -1; ypos<h; ++j) {
- // a general herringbone row consists of:
- // horizontal left block, the bottom of a previous vertical, the top of a new vertical
- int phase = (j & 3);
- // displace horizontally according to pattern
- if (phase == 0) {
- i = 0;
- } else {
- i = phase-4;
- }
- for (;; i += 4) {
- int xpos = i * sidelen;
- if (xpos >= w)
- break;
- // horizontal left-block
- if (xpos + sidelen*2 >= 0 && ypos >= 0) {
- stbhw_tile *t = stbhw__choose_tile(
- ts->h_tiles, ts->num_h_tiles,
- &h_color[j+2][i+2], &h_color[j+2][i+3],
- &v_color[j+2][i+2], &v_color[j+2][i+4],
- &h_color[j+3][i+2], &h_color[j+3][i+3],
- weighting
- );
- if (t == NULL) return 0;
- stbhw__draw_h_tile(output,stride,w,h, xpos, ypos, t, sidelen);
- }
- xpos += sidelen * 2;
- // now we're at the end of a previous vertical one
- xpos += sidelen;
- // now we're at the start of a new vertical one
- if (xpos < w) {
- stbhw_tile *t = stbhw__choose_tile(
- ts->v_tiles, ts->num_v_tiles,
- &h_color[j+2][i+5],
- &v_color[j+2][i+5], &v_color[j+2][i+6],
- &v_color[j+3][i+5], &v_color[j+3][i+6],
- &h_color[j+4][i+5],
- weighting
- );
- if (t == NULL) return 0;
- stbhw__draw_v_tile(output,stride,w,h, xpos, ypos, t, sidelen);
- }
- }
- ypos += sidelen;
- }
- }
- return 1;
- }
- static void stbhw__parse_h_rect(stbhw__process *p, int xpos, int ypos,
- int a, int b, int c, int d, int e, int f)
- {
- int len = p->c->short_side_len;
- stbhw_tile *h = (stbhw_tile *) malloc(sizeof(*h)-1 + 3 * (len*2) * len);
- int i,j;
- ++xpos;
- ++ypos;
- h->a = a, h->b = b, h->c = c, h->d = d, h->e = e, h->f = f;
- for (j=0; j < len; ++j)
- for (i=0; i < len*2; ++i)
- memcpy(h->pixels + j*(3*len*2) + i*3, p->data+(ypos+j)*p->stride+(xpos+i)*3, 3);
- STB_HBWANG_ASSERT(p->ts->num_h_tiles < p->ts->max_h_tiles);
- p->ts->h_tiles[p->ts->num_h_tiles++] = h;
- }
- static void stbhw__parse_v_rect(stbhw__process *p, int xpos, int ypos,
- int a, int b, int c, int d, int e, int f)
- {
- int len = p->c->short_side_len;
- stbhw_tile *h = (stbhw_tile *) malloc(sizeof(*h)-1 + 3 * (len*2) * len);
- int i,j;
- ++xpos;
- ++ypos;
- h->a = a, h->b = b, h->c = c, h->d = d, h->e = e, h->f = f;
- for (j=0; j < len*2; ++j)
- for (i=0; i < len; ++i)
- memcpy(h->pixels + j*(3*len) + i*3, p->data+(ypos+j)*p->stride+(xpos+i)*3, 3);
- STB_HBWANG_ASSERT(p->ts->num_v_tiles < p->ts->max_v_tiles);
- p->ts->v_tiles[p->ts->num_v_tiles++] = h;
- }
- STBHW_EXTERN int stbhw_build_tileset_from_image(stbhw_tileset *ts, unsigned char *data, int stride, int w, int h)
- {
- int i, h_count, v_count;
- unsigned char header[9];
- stbhw_config c = { 0 };
- stbhw__process p = { 0 };
- // extract binary header
- // remove encoding that makes it more visually obvious it encodes actual data
- for (i=0; i < 9; ++i)
- header[i] = data[w*3 - 1 - i] ^ (i*55);
- // extract header info
- if (header[7] == 0xc0) {
- // corner-type
- c.is_corner = 1;
- for (i=0; i < 4; ++i)
- c.num_color[i] = header[i];
- c.num_vary_x = header[4];
- c.num_vary_y = header[5];
- c.short_side_len = header[6];
- } else {
- c.is_corner = 0;
- // edge-type
- for (i=0; i < 6; ++i)
- c.num_color[i] = header[i];
- c.num_vary_x = header[6];
- c.num_vary_y = header[7];
- c.short_side_len = header[8];
- }
- if (c.num_vary_x < 0 || c.num_vary_x > 64 || c.num_vary_y < 0 || c.num_vary_y > 64)
- return 0;
- if (c.short_side_len == 0)
- return 0;
- if (c.num_color[0] > 32 || c.num_color[1] > 32 || c.num_color[2] > 32 || c.num_color[3] > 32)
- return 0;
- stbhw__get_template_info(&c, NULL, NULL, &h_count, &v_count);
- ts->is_corner = c.is_corner;
- ts->short_side_len = c.short_side_len;
- memcpy(ts->num_color, c.num_color, sizeof(ts->num_color));
- ts->max_h_tiles = h_count;
- ts->max_v_tiles = v_count;
- ts->num_h_tiles = ts->num_v_tiles = 0;
- ts->h_tiles = (stbhw_tile **) malloc(sizeof(*ts->h_tiles) * h_count);
- ts->v_tiles = (stbhw_tile **) malloc(sizeof(*ts->v_tiles) * v_count);
- p.ts = ts;
- p.data = data;
- p.stride = stride;
- p.process_h_rect = stbhw__parse_h_rect;
- p.process_v_rect = stbhw__parse_v_rect;
- p.w = w;
- p.h = h;
- p.c = &c;
- // load all the tiles out of the image
- return stbhw__process_template(&p);
- }
- STBHW_EXTERN void stbhw_free_tileset(stbhw_tileset *ts)
- {
- int i;
- for (i=0; i < ts->num_h_tiles; ++i)
- free(ts->h_tiles[i]);
- for (i=0; i < ts->num_v_tiles; ++i)
- free(ts->v_tiles[i]);
- free(ts->h_tiles);
- free(ts->v_tiles);
- ts->h_tiles = NULL;
- ts->v_tiles = NULL;
- ts->num_h_tiles = ts->max_h_tiles = 0;
- ts->num_v_tiles = ts->max_v_tiles = 0;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // GENERATOR
- //
- //
- // shared code
- static void stbhw__set_pixel(unsigned char *data, int stride, int xpos, int ypos, unsigned char color[3])
- {
- memcpy(data + ypos*stride + xpos*3, color, 3);
- }
- static void stbhw__stbhw__set_pixel_whiten(unsigned char *data, int stride, int xpos, int ypos, unsigned char color[3])
- {
- unsigned char c2[3];
- int i;
- for (i=0; i < 3; ++i)
- c2[i] = (color[i]*2 + 255)/3;
- memcpy(data + ypos*stride + xpos*3, c2, 3);
- }
- static unsigned char stbhw__black[3] = { 0,0,0 };
- // each edge set gets its own unique color variants
- // used http://phrogz.net/css/distinct-colors.html to generate this set,
- // but it's not very good and needs to be revised
- static unsigned char stbhw__color[7][8][3] =
- {
- { {255,51,51} , {143,143,29}, {0,199,199}, {159,119,199}, {0,149,199} , {143, 0,143}, {255,128,0}, {64,255,0}, },
- { {235,255,30 }, {255,0,255}, {199,139,119}, {29,143, 57}, {143,0,71} , { 0,143,143}, {0,99,199}, {143,71,0}, },
- { {0,149,199} , {143, 0,143}, {255,128,0}, {64,255,0}, {255,191,0} , {51,255,153}, {0,0,143}, {199,119,159},},
- { {143,0,71} , { 0,143,143}, {0,99,199}, {143,71,0}, {255,190,153}, { 0,255,255}, {128,0,255}, {255,51,102},},
- { {255,191,0} , {51,255,153}, {0,0,143}, {199,119,159}, {255,51,51} , {143,143,29}, {0,199,199}, {159,119,199},},
- { {255,190,153}, { 0,255,255}, {128,0,255}, {255,51,102}, {235,255,30 }, {255,0,255}, {199,139,119}, {29,143, 57}, },
- { {40,40,40 }, { 90,90,90 }, { 150,150,150 }, { 200,200,200 },
- { 255,90,90 }, { 160,160,80}, { 50,150,150 }, { 200,50,200 } },
- };
- static void stbhw__draw_hline(unsigned char *data, int stride, int xpos, int ypos, int color, int len, int slot)
- {
- int i;
- int j = len * 6 / 16;
- int k = len * 10 / 16;
- for (i=0; i < len; ++i)
- stbhw__set_pixel(data, stride, xpos+i, ypos, stbhw__black);
- if (k-j < 2) {
- j = len/2 - 1;
- k = j+2;
- if (len & 1)
- ++k;
- }
- for (i=j; i < k; ++i)
- stbhw__stbhw__set_pixel_whiten(data, stride, xpos+i, ypos, stbhw__color[slot][color]);
- }
- static void stbhw__draw_vline(unsigned char *data, int stride, int xpos, int ypos, int color, int len, int slot)
- {
- int i;
- int j = len * 6 / 16;
- int k = len * 10 / 16;
- for (i=0; i < len; ++i)
- stbhw__set_pixel(data, stride, xpos, ypos+i, stbhw__black);
- if (k-j < 2) {
- j = len/2 - 1;
- k = j+2;
- if (len & 1)
- ++k;
- }
- for (i=j; i < k; ++i)
- stbhw__stbhw__set_pixel_whiten(data, stride, xpos, ypos+i, stbhw__color[slot][color]);
- }
- // 0--*--1--*--2--*--3
- // | | |
- // * * *
- // | | |
- // 1--*--2--*--3 0--*--1--*--2
- // | | |
- // * * *
- // | | |
- // 0--*--1--*--2--*--3
- //
- // variables while enumerating (no correspondence between corners
- // of the types is implied by these variables)
- //
- // a-----b-----c a-----d
- // | | | |
- // | | | |
- // | | | |
- // d-----e-----f b e
- // | |
- // | |
- // | |
- // c-----f
- //
- unsigned char stbhw__corner_colors[4][4][3] =
- {
- { { 255,0,0 }, { 200,200,200 }, { 100,100,200 }, { 255,200,150 }, },
- { { 0,0,255 }, { 255,255,0 }, { 100,200,100 }, { 150,255,200 }, },
- { { 255,0,255 }, { 80,80,80 }, { 200,100,100 }, { 200,150,255 }, },
- { { 0,255,255 }, { 0,255,0 }, { 200,120,200 }, { 255,200,200 }, },
- };
- int stbhw__corner_colors_to_edge_color[4][4] =
- {
- // 0 1 2 3
- { 0, 1, 4, 9, }, // 0
- { 2, 3, 5, 10, }, // 1
- { 6, 7, 8, 11, }, // 2
- { 12, 13, 14, 15, }, // 3
- };
- #define stbhw__c2e stbhw__corner_colors_to_edge_color
- static void stbhw__draw_clipped_corner(unsigned char *data, int stride, int xpos, int ypos, int w, int h, int x, int y)
- {
- static unsigned char template_color[3] = { 167,204,204 };
- int i,j;
- for (j = -2; j <= 1; ++j) {
- for (i = -2; i <= 1; ++i) {
- if ((i == -2 || i == 1) && (j == -2 || j == 1))
- continue;
- else {
- if (x+i < 1 || x+i > w) continue;
- if (y+j < 1 || y+j > h) continue;
- stbhw__set_pixel(data, stride, xpos+x+i, ypos+y+j, template_color);
- }
- }
- }
- }
- static void stbhw__edge_process_h_rect(stbhw__process *p, int xpos, int ypos,
- int a, int b, int c, int d, int e, int f)
- {
- int len = p->c->short_side_len;
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos , a, len, 2);
- stbhw__draw_hline(p->data, p->stride, xpos+ len+1 , ypos , b, len, 3);
- stbhw__draw_vline(p->data, p->stride, xpos , ypos+1 , c, len, 1);
- stbhw__draw_vline(p->data, p->stride, xpos+2*len+1 , ypos+1 , d, len, 4);
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos + len+1, e, len, 0);
- stbhw__draw_hline(p->data, p->stride, xpos + len+1 , ypos + len+1, f, len, 2);
- }
- static void stbhw__edge_process_v_rect(stbhw__process *p, int xpos, int ypos,
- int a, int b, int c, int d, int e, int f)
- {
- int len = p->c->short_side_len;
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos , a, len, 0);
- stbhw__draw_vline(p->data, p->stride, xpos , ypos+1 , b, len, 5);
- stbhw__draw_vline(p->data, p->stride, xpos + len+1, ypos+1 , c, len, 1);
- stbhw__draw_vline(p->data, p->stride, xpos , ypos + len+1, d, len, 4);
- stbhw__draw_vline(p->data, p->stride, xpos + len+1, ypos + len+1, e, len, 5);
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos + 2*len+1, f, len, 3);
- }
- static void stbhw__corner_process_h_rect(stbhw__process *p, int xpos, int ypos,
- int a, int b, int c, int d, int e, int f)
- {
- int len = p->c->short_side_len;
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos , stbhw__c2e[a][b], len, 2);
- stbhw__draw_hline(p->data, p->stride, xpos+ len+1 , ypos , stbhw__c2e[b][c], len, 3);
- stbhw__draw_vline(p->data, p->stride, xpos , ypos+1 , stbhw__c2e[a][d], len, 1);
- stbhw__draw_vline(p->data, p->stride, xpos+2*len+1 , ypos+1 , stbhw__c2e[c][f], len, 4);
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos + len+1, stbhw__c2e[d][e], len, 0);
- stbhw__draw_hline(p->data, p->stride, xpos + len+1 , ypos + len+1, stbhw__c2e[e][f], len, 2);
- if (p->c->corner_type_color_template[1][a]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len*2,len, 1,1);
- if (p->c->corner_type_color_template[2][b]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len*2,len, len+1,1);
- if (p->c->corner_type_color_template[3][c]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len*2,len, len*2+1,1);
- if (p->c->corner_type_color_template[0][d]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len*2,len, 1,len+1);
- if (p->c->corner_type_color_template[1][e]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len*2,len, len+1,len+1);
- if (p->c->corner_type_color_template[2][f]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len*2,len, len*2+1,len+1);
- stbhw__set_pixel(p->data, p->stride, xpos , ypos, stbhw__corner_colors[1][a]);
- stbhw__set_pixel(p->data, p->stride, xpos+len , ypos, stbhw__corner_colors[2][b]);
- stbhw__set_pixel(p->data, p->stride, xpos+2*len+1, ypos, stbhw__corner_colors[3][c]);
- stbhw__set_pixel(p->data, p->stride, xpos , ypos+len+1, stbhw__corner_colors[0][d]);
- stbhw__set_pixel(p->data, p->stride, xpos+len , ypos+len+1, stbhw__corner_colors[1][e]);
- stbhw__set_pixel(p->data, p->stride, xpos+2*len+1, ypos+len+1, stbhw__corner_colors[2][f]);
- }
- static void stbhw__corner_process_v_rect(stbhw__process *p, int xpos, int ypos,
- int a, int b, int c, int d, int e, int f)
- {
- int len = p->c->short_side_len;
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos , stbhw__c2e[a][d], len, 0);
- stbhw__draw_vline(p->data, p->stride, xpos , ypos+1 , stbhw__c2e[a][b], len, 5);
- stbhw__draw_vline(p->data, p->stride, xpos + len+1, ypos+1 , stbhw__c2e[d][e], len, 1);
- stbhw__draw_vline(p->data, p->stride, xpos , ypos + len+1, stbhw__c2e[b][c], len, 4);
- stbhw__draw_vline(p->data, p->stride, xpos + len+1, ypos + len+1, stbhw__c2e[e][f], len, 5);
- stbhw__draw_hline(p->data, p->stride, xpos+1 , ypos + 2*len+1, stbhw__c2e[c][f], len, 3);
- if (p->c->corner_type_color_template[0][a]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len,len*2, 1,1);
- if (p->c->corner_type_color_template[3][b]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len,len*2, 1,len+1);
- if (p->c->corner_type_color_template[2][c]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len,len*2, 1,len*2+1);
- if (p->c->corner_type_color_template[1][d]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len,len*2, len+1,1);
- if (p->c->corner_type_color_template[0][e]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len,len*2, len+1,len+1);
- if (p->c->corner_type_color_template[3][f]) stbhw__draw_clipped_corner(p->data,p->stride, xpos,ypos, len,len*2, len+1,len*2+1);
- stbhw__set_pixel(p->data, p->stride, xpos , ypos , stbhw__corner_colors[0][a]);
- stbhw__set_pixel(p->data, p->stride, xpos , ypos+len , stbhw__corner_colors[3][b]);
- stbhw__set_pixel(p->data, p->stride, xpos , ypos+2*len+1, stbhw__corner_colors[2][c]);
- stbhw__set_pixel(p->data, p->stride, xpos+len+1, ypos , stbhw__corner_colors[1][d]);
- stbhw__set_pixel(p->data, p->stride, xpos+len+1, ypos+len , stbhw__corner_colors[0][e]);
- stbhw__set_pixel(p->data, p->stride, xpos+len+1, ypos+2*len+1, stbhw__corner_colors[3][f]);
- }
- // generates a template image, assuming data is 3*w*h bytes long, RGB format
- STBHW_EXTERN int stbhw_make_template(stbhw_config *c, unsigned char *data, int w, int h, int stride_in_bytes)
- {
- stbhw__process p;
- int i;
- p.data = data;
- p.w = w;
- p.h = h;
- p.stride = stride_in_bytes;
- p.ts = 0;
- p.c = c;
- if (c->is_corner) {
- p.process_h_rect = stbhw__corner_process_h_rect;
- p.process_v_rect = stbhw__corner_process_v_rect;
- } else {
- p.process_h_rect = stbhw__edge_process_h_rect;
- p.process_v_rect = stbhw__edge_process_v_rect;
- }
- for (i=0; i < p.h; ++i)
- memset(p.data + i*p.stride, 255, 3*p.w);
- if (!stbhw__process_template(&p))
- return 0;
- if (c->is_corner) {
- // write out binary information in first line of image
- for (i=0; i < 4; ++i)
- data[w*3-1-i] = c->num_color[i];
- data[w*3-1-i] = c->num_vary_x;
- data[w*3-2-i] = c->num_vary_y;
- data[w*3-3-i] = c->short_side_len;
- data[w*3-4-i] = 0xc0;
- } else {
- for (i=0; i < 6; ++i)
- data[w*3-1-i] = c->num_color[i];
- data[w*3-1-i] = c->num_vary_x;
- data[w*3-2-i] = c->num_vary_y;
- data[w*3-3-i] = c->short_side_len;
- }
- // make it more obvious it encodes actual data
- for (i=0; i < 9; ++i)
- p.data[p.w*3 - 1 - i] ^= i*55;
- return 1;
- }
- #endif // STB_HBWANG_IMPLEMENTATION
|