diff --git a/README.md b/README.md index ce88871..15cd7c7 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Random single-file programs I've written in my spare time for small tasks. * **dood:** Reads an ENDOOM lump and mirrors every word "down the middle". * **dtexdupes:** Small tool I've used once or twice to clean up my doom projects of duplicate textures. * **endoomview:** Renders ENDOOM lumps onto a terminal. Requires an Unicode terminal with 256-color support (not xterm, basically). +* **fontatlas:** Tool used in Demolitionist development, converts json font atlas data to plaintext for easier ZScript parsing. +* **fontspread:** Tool used in Demolitionist development, converts back and forth between "compressed" font atlas texture and a linear spread of all glyphs. Useful for adding gradient effects and others, since all glyphs are properly centered. * **fmod\_playbank (formerly fuck\_fmod):** Tool for playback of .fsb files. * **fuzrip:** Tool for awkwardly extracting audio from Creation Engine .fuz voice files. * **fuzz:** A fancy blocky noise filter using proto-AliceGL designs. diff --git a/cropng.c b/cropng.c index 0ece865..64d8182 100644 --- a/cropng.c +++ b/cropng.c @@ -278,6 +278,14 @@ void processpic( const char *fname ) cropy = 0; croph = h; } + if ( (cropx >= w) || (cropy >= h) || (cropw <= 0) || (croph <= 0) ) + { + printf(" Image crops to zero size, skipping.\n"); + free(idata); + if ( plte ) free(plte); + if ( trns ) free(trns); + return; + } uint8_t *odata = calloc(cropw*croph,pxsize); uint32_t ow = cropw, oh = croph; int32_t ox = x-cropx, oy = y-cropy; diff --git a/fontatlas.c b/fontatlas.c new file mode 100644 index 0000000..a1105eb --- /dev/null +++ b/fontatlas.c @@ -0,0 +1,89 @@ +/* + fontatlas.c : Convert json data from font texture generator to a + plaintext format that's easier to read from zscript code. + (https://evanw.github.io/font-texture-generator/) + + Copyright (c) 2022 Marisa the Magician, UnSX Team + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include + +typedef struct +{ + int x, y, width, height, xofs, yofs, advance; +} glyph_t; + +int main( int argc, char **argv ) +{ + if ( argc < 2 ) + { + fprintf(stderr,"usage: fontatlas \n"); + return 0; + } + glyph_t glyphs[256] = {{0}}; + json_error_t error; + json_t *root = json_load_file(argv[1],0,&error); + if ( !root ) + { + fprintf(stderr,"fontatlas: parse error at line %d: %s\n", + error.line,error.text); + return 1; + } + json_t *fontheight = json_object_get(root,"size"); + int fonth = json_integer_value(fontheight); + json_t *chars = json_object_get(root,"characters"); + const char *key; + json_t *val; + json_object_foreach(chars,key,val) + { + int ch = 0; + if ( key[1] ) + { + ch = (key[0]&0b00011111)<<6; + ch |= key[1]&0b00111111; + } + else ch = key[0]; + json_t *go = json_object_get(val,"x"); + glyphs[ch].x = json_integer_value(go); + go = json_object_get(val,"y"); + glyphs[ch].y = json_integer_value(go); + go = json_object_get(val,"width"); + glyphs[ch].width = json_integer_value(go); + go = json_object_get(val,"height"); + glyphs[ch].height = json_integer_value(go); + go = json_object_get(val,"originX"); + glyphs[ch].xofs = json_integer_value(go); + go = json_object_get(val,"originY"); + glyphs[ch].yofs = json_integer_value(go); + go = json_object_get(val,"advance"); + glyphs[ch].advance = json_integer_value(go); + } + json_decref(root); + glyphs[' '].advance = ceilf(glyphs['m'].advance/4.); // set space width (quarter-em) + printf("%d\n",fonth); + for ( int i=0; i<256; i++ ) + printf("%d %d %d %d %d %d %d\n",glyphs[i].x,glyphs[i].y, + glyphs[i].width,glyphs[i].height,glyphs[i].xofs, + glyphs[i].yofs,glyphs[i].advance); + return 0; +} diff --git a/fontspread.c b/fontspread.c new file mode 100644 index 0000000..f327648 --- /dev/null +++ b/fontspread.c @@ -0,0 +1,209 @@ +/* + fontspread.c : Spread font atlas texture from font texture generator + into a linear texture with all characters one after another, or reverse + the process. This allows applying effects such as gradients with ease. + (https://evanw.github.io/font-texture-generator/) + + Copyright (c) 2022 Marisa the Magician, UnSX Team + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include +#include +#include +#include +#include + +// TODO: use PNGs instead of goddamn raw RGBA8 image data + +typedef struct +{ + int x, y, width, height, xofs, yofs, advance; +} glyph_t; + +uint32_t getpixel( uint32_t *buf, int bw, int bh, int x, int y ) +{ + if ( (x < 0) || (x >= bw) || (y < 0) || (y >= bh) ) + return 0; + return buf[x+y*bw]; +} + +void putpixel( uint32_t px, uint32_t *buf, int bw, int bh, int x, int y ) +{ + if ( (x < 0) || (x >= bw) || (y < 0) || (y >= bh) ) + return; + buf[x+y*bw] = px; +} + +int main( int argc, char **argv ) +{ + int rev = 0; + int barg = 1; + if ( (argc > 1) && !strcmp(argv[1],"-i") ) + { + rev = 1; + barg++; + } + if ( argc < barg+3 ) + { + fprintf(stderr,"usage: fontspread [-i] \n"); + return 0; + } + glyph_t glyphs[256] = {{0}}; + json_error_t error; + json_t *root = json_load_file(argv[barg],0,&error); + if ( !root ) + { + fprintf(stderr,"fontspread: parse error at line %d: %s\n", + error.line,error.text); + return 1; + } + json_t *fontheight = json_object_get(root,"size"); + int fonth = json_integer_value(fontheight); + json_t *atlaswidth = json_object_get(root,"width"); + int atlasw = json_integer_value(atlaswidth); + json_t *atlasheight = json_object_get(root,"height"); + int atlash = json_integer_value(atlasheight); + json_t *chars = json_object_get(root,"characters"); + const char *key; + json_t *val; + json_object_foreach(chars,key,val) + { + int ch = 0; + if ( key[1] ) + { + ch = (key[0]&0b00011111)<<6; + ch |= key[1]&0b00111111; + } + else ch = key[0]; + json_t *go = json_object_get(val,"x"); + glyphs[ch].x = json_integer_value(go); + go = json_object_get(val,"y"); + glyphs[ch].y = json_integer_value(go); + go = json_object_get(val,"width"); + glyphs[ch].width = json_integer_value(go); + go = json_object_get(val,"height"); + glyphs[ch].height = json_integer_value(go); + go = json_object_get(val,"originX"); + glyphs[ch].xofs = json_integer_value(go); + go = json_object_get(val,"originY"); + glyphs[ch].yofs = json_integer_value(go); + go = json_object_get(val,"advance"); + glyphs[ch].advance = json_integer_value(go); + } + json_decref(root); + int iw = 0, ih = fonth, xx = 0; + for ( int i=0; i<256; i++ ) + { + int yy = fonth-glyphs[i].yofs; + if ( yy+glyphs[i].height > ih ) ih = yy+glyphs[i].height; + xx += glyphs[i].width; + iw = xx; + } + printf("Estimated texture dimensions: %dx%d\n",iw,ih); + if ( rev ) + { + FILE *f = fopen(argv[barg+2],"rb"); + if ( !f ) + { + fprintf(stderr,"fontspread: failed to open texture: %s\n",strerror(errno)); + return 2; + } + uint32_t *tdata = calloc(iw*ih,sizeof(uint32_t)); + int got = fread(tdata,sizeof(uint32_t),iw*ih,f); + if ( got < (iw*ih) ) + { + fprintf(stderr,"fontspread: size mismatch in texture, should be %d, got %d\n",iw*ih,got); + free(tdata); + fclose(f); + return 4; + } + fclose(f); + uint32_t *adata = calloc(atlasw*atlash,sizeof(uint32_t)); + xx = 0; + for ( int i=0; i<256; i++ ) + { + int yy = fonth-glyphs[i].yofs; + for ( int y=0; y