main
Dominik Madarász 2024-03-01 10:12:47 +01:00
parent 2ea8b3da07
commit 3070fece7e
119 changed files with 1090965 additions and 1090938 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,140 +1,140 @@
// base64 de/encoder. Based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN). // base64 de/encoder. Based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN).
// - rlyeh, public domain // - rlyeh, public domain
#ifndef BASE64_H #ifndef BASE64_H
#define BASE64_H #define BASE64_H
unsigned base64_bounds(unsigned size); unsigned base64_bounds(unsigned size);
char* base64_encode(const void *inp, unsigned inlen); // free() after use char* base64_encode(const void *inp, unsigned inlen); // free() after use
char* base64_decode(const char *inp, unsigned inlen); // array_free() after use char* base64_decode(const char *inp, unsigned inlen); // array_free() after use
#endif #endif
#ifdef BASE64_C #ifdef BASE64_C
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h> #include <stddef.h>
#include <ctype.h> #include <ctype.h>
#define BASE64_ENCODE_OUT_SIZE(s) ((unsigned int)((((s) + 2) / 3) * 4 + 1)) #define BASE64_ENCODE_OUT_SIZE(s) ((unsigned int)((((s) + 2) / 3) * 4 + 1))
#define BASE64_DECODE_OUT_SIZE(s) ((unsigned int)(((s) / 4) * 3)) #define BASE64_DECODE_OUT_SIZE(s) ((unsigned int)(((s) / 4) * 3))
unsigned base64_bounds(unsigned size) { unsigned base64_bounds(unsigned size) {
return BASE64_ENCODE_OUT_SIZE(size); return BASE64_ENCODE_OUT_SIZE(size);
} }
char* base64_encode(const void *inp, unsigned inlen) { // free() after use char* base64_encode(const void *inp, unsigned inlen) { // free() after use
unsigned outlen = base64_bounds(inlen); unsigned outlen = base64_bounds(inlen);
char *out_ = MALLOC(outlen); char *out_ = MALLOC(outlen);
out_[outlen] = 0; out_[outlen] = 0;
uint_least32_t v; uint_least32_t v;
unsigned ii, io, rem; unsigned ii, io, rem;
char *out = (char *)out_; char *out = (char *)out_;
const unsigned char *in = (const unsigned char *)inp; const unsigned char *in = (const unsigned char *)inp;
const uint8_t base64enc_tab[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const uint8_t base64enc_tab[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for(io = 0, ii = 0, v = 0, rem = 0; ii < inlen; ii ++) { for(io = 0, ii = 0, v = 0, rem = 0; ii < inlen; ii ++) {
unsigned char ch; unsigned char ch;
ch = in[ii]; ch = in[ii];
v = (v << 8) | ch; v = (v << 8) | ch;
rem += 8; rem += 8;
while (rem >= 6) { while (rem >= 6) {
rem -= 6; rem -= 6;
if (io >= outlen) if (io >= outlen)
return (FREE(out_), NULL); /* truncation is failure */ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[(v >> rem) & 63]; out[io ++] = base64enc_tab[(v >> rem) & 63];
} }
} }
if (rem) { if (rem) {
v <<= (6 - rem); v <<= (6 - rem);
if (io >= outlen) if (io >= outlen)
return (FREE(out_), NULL); /* truncation is failure */ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[v & 63]; out[io ++] = base64enc_tab[v & 63];
} }
while(io&3) { while(io&3) {
if(io>=outlen) return (FREE(out_), NULL); /* truncation is failure */ if(io>=outlen) return (FREE(out_), NULL); /* truncation is failure */
out[io++]='='; out[io++]='=';
} }
if(io>=outlen) return (FREE(out_), NULL); /* no room for null terminator */ if(io>=outlen) return (FREE(out_), NULL); /* no room for null terminator */
out[io]=0; out[io]=0;
return out_; return out_;
} }
#ifdef array_resize #ifdef array_resize
array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() after use array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() after use
#if 0 #if 0
unsigned long outlen = BASE64_DECODE_OUT_SIZE(inlen); unsigned long outlen = BASE64_DECODE_OUT_SIZE(inlen);
array(char) out_ = 0; array_resize(out_, outlen+1); array(char) out_ = 0; array_resize(out_, outlen+1);
if( base64_decodex((const unsigned char *)inp, (unsigned long)inlen, (unsigned char *)out_, &outlen) != CRYPT_OK ) { if( base64_decodex((const unsigned char *)inp, (unsigned long)inlen, (unsigned char *)out_, &outlen) != CRYPT_OK ) {
array_free(out_); array_free(out_);
return 0; return 0;
} }
array_resize(out_, outlen); array_resize(out_, outlen);
out_[outlen] = 0; out_[outlen] = 0;
return out_; return out_;
#else #else
unsigned outlen = BASE64_DECODE_OUT_SIZE(inlen); unsigned outlen = BASE64_DECODE_OUT_SIZE(inlen);
array(char) out_ = 0; array_resize(out_, outlen); array(char) out_ = 0; array_resize(out_, outlen);
// based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN) // based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN)
uint_least32_t v; uint_least32_t v;
unsigned ii, io, rem; unsigned ii, io, rem;
char *out = (char *)out_; char *out = (char *)out_;
const unsigned char *in = (const unsigned char *)inp; const unsigned char *in = (const unsigned char *)inp;
const uint8_t base64dec_tab[256]= { const uint8_t base64dec_tab[256]= {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255 }; 255, 255, 255, 255 };
for (io = 0, ii = 0,v = 0, rem = 0; ii < inlen; ii ++) { for (io = 0, ii = 0,v = 0, rem = 0; ii < inlen; ii ++) {
unsigned char ch; unsigned char ch;
if (isspace(in[ii])) if (isspace(in[ii]))
continue; continue;
if ((in[ii]=='=') || (!in[ii])) if ((in[ii]=='=') || (!in[ii]))
break; /* stop at = or null character*/ break; /* stop at = or null character*/
ch = base64dec_tab[(unsigned char)in[ii]]; ch = base64dec_tab[(unsigned char)in[ii]];
if (ch == 255) if (ch == 255)
break; /* stop at a parse error */ break; /* stop at a parse error */
v = (v<<6) | ch; v = (v<<6) | ch;
rem += 6; rem += 6;
if (rem >= 8) { if (rem >= 8) {
rem -= 8; rem -= 8;
if (io >= outlen) if (io >= outlen)
return (array_free(out_), NULL); /* truncation is failure */ return (array_free(out_), NULL); /* truncation is failure */
out[io ++] = (v >> rem) & 255; out[io ++] = (v >> rem) & 255;
} }
} }
if (rem >= 8) { if (rem >= 8) {
rem -= 8; rem -= 8;
if (io >= outlen) if (io >= outlen)
return (array_free(out_), NULL); /* truncation is failure */ return (array_free(out_), NULL); /* truncation is failure */
out[io ++] = (v >> rem) & 255; out[io ++] = (v >> rem) & 255;
} }
return (array_resize(out_, io), out_); return (array_resize(out_, io), out_);
#endif #endif
} }
#endif // array_resize #endif // array_resize
#endif // BASE64_C #endif // BASE64_C

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,407 +1,407 @@
/* public domain Simple, Minimalistic MPEG Layer 1 decoder - http://jonolick.com /* public domain Simple, Minimalistic MPEG Layer 1 decoder - http://jonolick.com
* *
* Revision History: * Revision History:
* 1.00 (2014-26-1) Initial release. * 1.00 (2014-26-1) Initial release.
* *
* Basic usage: * Basic usage:
* int hz, channels, outputSize; * int hz, channels, outputSize;
* short *output; * short *output;
* jo_read_mp1(input, inputSize, output, outputSize, hz, channels); * jo_read_mp1(input, inputSize, output, outputSize, hz, channels);
* // Do something with the data here * // Do something with the data here
* free(output); * free(output);
* *
* */ * */
#ifndef JO_INCLUDE_MP1_H #ifndef JO_INCLUDE_MP1_H
#define JO_INCLUDE_MP1_H #define JO_INCLUDE_MP1_H
#include <stdbool.h> #include <stdbool.h>
extern bool jo_read_mp1(const void *input, int inputSize, short **output, int *outputSize, int *hz, int *channels); extern bool jo_read_mp1(const void *input, int inputSize, short **output, int *outputSize, int *hz, int *channels);
#endif // JO_INCLUDE_MP1_H #endif // JO_INCLUDE_MP1_H
#ifndef JO_MP1_HEADER_FILE_ONLY #ifndef JO_MP1_HEADER_FILE_ONLY
#if defined(_MSC_VER) && _MSC_VER >= 0x1400 #if defined(_MSC_VER) && _MSC_VER >= 0x1400
#define _CRT_SECURE_NO_WARNINGS // suppress warnings about fopen() #define _CRT_SECURE_NO_WARNINGS // suppress warnings about fopen()
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <limits.h> #include <limits.h>
static const double s_jo_multTbl[64] = { static const double s_jo_multTbl[64] = {
2.000000,1.587401,1.259921,1.000000,0.793701,0.629961,0.500000,0.396850,0.314980,0.250000,0.198425,0.157490,0.125000,0.099213,0.078745,0.062500, 2.000000,1.587401,1.259921,1.000000,0.793701,0.629961,0.500000,0.396850,0.314980,0.250000,0.198425,0.157490,0.125000,0.099213,0.078745,0.062500,
0.049606,0.039373,0.031250,0.024803,0.019686,0.015625,0.012402,0.009843,0.007812,0.006201,0.004922,0.003906,0.003100,0.002461,0.001953,0.001550, 0.049606,0.039373,0.031250,0.024803,0.019686,0.015625,0.012402,0.009843,0.007812,0.006201,0.004922,0.003906,0.003100,0.002461,0.001953,0.001550,
0.001230,0.000977,0.000775,0.000615,0.000488,0.000388,0.000308,0.000244,0.000194,0.000154,0.000122,0.000097,0.000077,0.000061,0.000048,0.000038, 0.001230,0.000977,0.000775,0.000615,0.000488,0.000388,0.000308,0.000244,0.000194,0.000154,0.000122,0.000097,0.000077,0.000061,0.000048,0.000038,
0.000031,0.000024,0.000019,0.000015,0.000012,0.000010,0.000008,0.000006,0.000005,0.000004,0.000003,0.000002,0.000002,0.000002,0.000001,1e-20 0.000031,0.000024,0.000019,0.000015,0.000012,0.000010,0.000008,0.000006,0.000005,0.000004,0.000003,0.000002,0.000002,0.000002,0.000001,1e-20
}; };
// l = i - 256; // l = i - 256;
// s = (i & 0x40) ? 1 : -1; // s = (i & 0x40) ? 1 : -1;
// windowTbl[(i/16)|((i%16)<<5)] = s * 20 * exp(-(l/112)*-(l/112)) * sin(l * M_PI*2 / 112) / l; // windowTbl[(i/16)|((i%16)<<5)] = s * 20 * exp(-(l/112)*-(l/112)) * sin(l * M_PI*2 / 112) / l;
static const double s_jo_windowTbl[512] = { static const double s_jo_windowTbl[512] = {
-0.000000,-0.000443,0.003250,-0.007004,0.031082,-0.078629,0.100311,-0.572037,1.144989,0.572037,0.100311,0.078629,0.031082,0.007004,0.003250,0.000443, -0.000000,-0.000443,0.003250,-0.007004,0.031082,-0.078629,0.100311,-0.572037,1.144989,0.572037,0.100311,0.078629,0.031082,0.007004,0.003250,0.000443,
-0.000015,-0.000473,0.003326,-0.007919,0.030518,-0.084183,0.090927,-0.600220,1.144287,0.543823,0.108856,0.073059,0.031479,0.006119,0.003174,0.000397, -0.000015,-0.000473,0.003326,-0.007919,0.030518,-0.084183,0.090927,-0.600220,1.144287,0.543823,0.108856,0.073059,0.031479,0.006119,0.003174,0.000397,
-0.000015,-0.000534,0.003387,-0.008865,0.029785,-0.089706,0.080688,-0.628296,1.142212,0.515610,0.116577,0.067520,0.031738,0.005295,0.003082,0.000366, -0.000015,-0.000534,0.003387,-0.008865,0.029785,-0.089706,0.080688,-0.628296,1.142212,0.515610,0.116577,0.067520,0.031738,0.005295,0.003082,0.000366,
-0.000015,-0.000580,0.003433,-0.009842,0.028885,-0.095169,0.069595,-0.656219,1.138763,0.487473,0.123474,0.061996,0.031845,0.004486,0.002991,0.000320, -0.000015,-0.000580,0.003433,-0.009842,0.028885,-0.095169,0.069595,-0.656219,1.138763,0.487473,0.123474,0.061996,0.031845,0.004486,0.002991,0.000320,
-0.000015,-0.000626,0.003464,-0.010849,0.027802,-0.100540,0.057617,-0.683914,1.133926,0.459473,0.129578,0.056534,0.031815,0.003723,0.002899,0.000290, -0.000015,-0.000626,0.003464,-0.010849,0.027802,-0.100540,0.057617,-0.683914,1.133926,0.459473,0.129578,0.056534,0.031815,0.003723,0.002899,0.000290,
-0.000015,-0.000687,0.003479,-0.011887,0.026535,-0.105820,0.044785,-0.711319,1.127747,0.431656,0.134888,0.051132,0.031662,0.003006,0.002792,0.000259, -0.000015,-0.000687,0.003479,-0.011887,0.026535,-0.105820,0.044785,-0.711319,1.127747,0.431656,0.134888,0.051132,0.031662,0.003006,0.002792,0.000259,
-0.000015,-0.000748,0.003479,-0.012939,0.025085,-0.110947,0.031082,-0.738373,1.120224,0.404083,0.139450,0.045837,0.031387,0.002335,0.002686,0.000244, -0.000015,-0.000748,0.003479,-0.012939,0.025085,-0.110947,0.031082,-0.738373,1.120224,0.404083,0.139450,0.045837,0.031387,0.002335,0.002686,0.000244,
-0.000031,-0.000809,0.003464,-0.014023,0.023422,-0.115921,0.016510,-0.765030,1.111374,0.376801,0.143265,0.040634,0.031006,0.001694,0.002579,0.000214, -0.000031,-0.000809,0.003464,-0.014023,0.023422,-0.115921,0.016510,-0.765030,1.111374,0.376801,0.143265,0.040634,0.031006,0.001694,0.002579,0.000214,
-0.000031,-0.000885,0.003418,-0.015121,0.021576,-0.120697,0.001068,-0.791214,1.101212,0.349869,0.146362,0.035553,0.030533,0.001099,0.002457,0.000198, -0.000031,-0.000885,0.003418,-0.015121,0.021576,-0.120697,0.001068,-0.791214,1.101212,0.349869,0.146362,0.035553,0.030533,0.001099,0.002457,0.000198,
-0.000031,-0.000961,0.003372,-0.016235,0.019531,-0.125259,-0.015228,-0.816864,1.089783,0.323318,0.148773,0.030609,0.029938,0.000549,0.002350,0.000168, -0.000031,-0.000961,0.003372,-0.016235,0.019531,-0.125259,-0.015228,-0.816864,1.089783,0.323318,0.148773,0.030609,0.029938,0.000549,0.002350,0.000168,
-0.000031,-0.001038,0.003281,-0.017349,0.017258,-0.129562,-0.032379,-0.841949,1.077118,0.297211,0.150497,0.025818,0.029282,0.000031,0.002243,0.000153, -0.000031,-0.001038,0.003281,-0.017349,0.017258,-0.129562,-0.032379,-0.841949,1.077118,0.297211,0.150497,0.025818,0.029282,0.000031,0.002243,0.000153,
-0.000046,-0.001114,0.003174,-0.018463,0.014801,-0.133591,-0.050354,-0.866364,1.063217,0.271591,0.151596,0.021179,0.028534,-0.000443,0.002121,0.000137, -0.000046,-0.001114,0.003174,-0.018463,0.014801,-0.133591,-0.050354,-0.866364,1.063217,0.271591,0.151596,0.021179,0.028534,-0.000443,0.002121,0.000137,
-0.000046,-0.001205,0.003052,-0.019577,0.012115,-0.137299,-0.069168,-0.890091,1.048157,0.246506,0.152069,0.016708,0.027725,-0.000870,0.002014,0.000122, -0.000046,-0.001205,0.003052,-0.019577,0.012115,-0.137299,-0.069168,-0.890091,1.048157,0.246506,0.152069,0.016708,0.027725,-0.000870,0.002014,0.000122,
-0.000061,-0.001297,0.002884,-0.020691,0.009232,-0.140671,-0.088776,-0.913055,1.031937,0.221985,0.151962,0.012421,0.026840,-0.001266,0.001907,0.000107, -0.000061,-0.001297,0.002884,-0.020691,0.009232,-0.140671,-0.088776,-0.913055,1.031937,0.221985,0.151962,0.012421,0.026840,-0.001266,0.001907,0.000107,
-0.000061,-0.001389,0.002701,-0.021790,0.006134,-0.143677,-0.109161,-0.935196,1.014618,0.198059,0.151306,0.008316,0.025909,-0.001617,0.001785,0.000107, -0.000061,-0.001389,0.002701,-0.021790,0.006134,-0.143677,-0.109161,-0.935196,1.014618,0.198059,0.151306,0.008316,0.025909,-0.001617,0.001785,0.000107,
-0.000076,-0.001480,0.002487,-0.022858,0.002823,-0.146255,-0.130310,-0.956482,0.996246,0.174789,0.150116,0.004395,0.024933,-0.001938,0.001694,0.000092, -0.000076,-0.001480,0.002487,-0.022858,0.002823,-0.146255,-0.130310,-0.956482,0.996246,0.174789,0.150116,0.004395,0.024933,-0.001938,0.001694,0.000092,
-0.000076,-0.001587,0.002228,-0.023911,-0.000687,-0.148422,-0.152206,-0.976852,0.976852,0.152206,0.148422,0.000687,0.023911,-0.002228,0.001587,0.000076, -0.000076,-0.001587,0.002228,-0.023911,-0.000687,-0.148422,-0.152206,-0.976852,0.976852,0.152206,0.148422,0.000687,0.023911,-0.002228,0.001587,0.000076,
-0.000092,-0.001694,0.001938,-0.024933,-0.004395,-0.150116,-0.174789,-0.996246,0.956482,0.130310,0.146255,-0.002823,0.022858,-0.002487,0.001480,0.000076, -0.000092,-0.001694,0.001938,-0.024933,-0.004395,-0.150116,-0.174789,-0.996246,0.956482,0.130310,0.146255,-0.002823,0.022858,-0.002487,0.001480,0.000076,
-0.000107,-0.001785,0.001617,-0.025909,-0.008316,-0.151306,-0.198059,-1.014618,0.935196,0.109161,0.143677,-0.006134,0.021790,-0.002701,0.001389,0.000061, -0.000107,-0.001785,0.001617,-0.025909,-0.008316,-0.151306,-0.198059,-1.014618,0.935196,0.109161,0.143677,-0.006134,0.021790,-0.002701,0.001389,0.000061,
-0.000107,-0.001907,0.001266,-0.026840,-0.012421,-0.151962,-0.221985,-1.031937,0.913055,0.088776,0.140671,-0.009232,0.020691,-0.002884,0.001297,0.000061, -0.000107,-0.001907,0.001266,-0.026840,-0.012421,-0.151962,-0.221985,-1.031937,0.913055,0.088776,0.140671,-0.009232,0.020691,-0.002884,0.001297,0.000061,
-0.000122,-0.002014,0.000870,-0.027725,-0.016708,-0.152069,-0.246506,-1.048157,0.890091,0.069168,0.137299,-0.012115,0.019577,-0.003052,0.001205,0.000046, -0.000122,-0.002014,0.000870,-0.027725,-0.016708,-0.152069,-0.246506,-1.048157,0.890091,0.069168,0.137299,-0.012115,0.019577,-0.003052,0.001205,0.000046,
-0.000137,-0.002121,0.000443,-0.028534,-0.021179,-0.151596,-0.271591,-1.063217,0.866364,0.050354,0.133591,-0.014801,0.018463,-0.003174,0.001114,0.000046, -0.000137,-0.002121,0.000443,-0.028534,-0.021179,-0.151596,-0.271591,-1.063217,0.866364,0.050354,0.133591,-0.014801,0.018463,-0.003174,0.001114,0.000046,
-0.000153,-0.002243,-0.000031,-0.029282,-0.025818,-0.150497,-0.297211,-1.077118,0.841949,0.032379,0.129562,-0.017258,0.017349,-0.003281,0.001038,0.000031, -0.000153,-0.002243,-0.000031,-0.029282,-0.025818,-0.150497,-0.297211,-1.077118,0.841949,0.032379,0.129562,-0.017258,0.017349,-0.003281,0.001038,0.000031,
-0.000168,-0.002350,-0.000549,-0.029938,-0.030609,-0.148773,-0.323318,-1.089783,0.816864,0.015228,0.125259,-0.019531,0.016235,-0.003372,0.000961,0.000031, -0.000168,-0.002350,-0.000549,-0.029938,-0.030609,-0.148773,-0.323318,-1.089783,0.816864,0.015228,0.125259,-0.019531,0.016235,-0.003372,0.000961,0.000031,
-0.000198,-0.002457,-0.001099,-0.030533,-0.035553,-0.146362,-0.349869,-1.101212,0.791214,-0.001068,0.120697,-0.021576,0.015121,-0.003418,0.000885,0.000031, -0.000198,-0.002457,-0.001099,-0.030533,-0.035553,-0.146362,-0.349869,-1.101212,0.791214,-0.001068,0.120697,-0.021576,0.015121,-0.003418,0.000885,0.000031,
-0.000214,-0.002579,-0.001694,-0.031006,-0.040634,-0.143265,-0.376801,-1.111374,0.765030,-0.016510,0.115921,-0.023422,0.014023,-0.003464,0.000809,0.000031, -0.000214,-0.002579,-0.001694,-0.031006,-0.040634,-0.143265,-0.376801,-1.111374,0.765030,-0.016510,0.115921,-0.023422,0.014023,-0.003464,0.000809,0.000031,
-0.000244,-0.002686,-0.002335,-0.031387,-0.045837,-0.139450,-0.404083,-1.120224,0.738373,-0.031082,0.110947,-0.025085,0.012939,-0.003479,0.000748,0.000015, -0.000244,-0.002686,-0.002335,-0.031387,-0.045837,-0.139450,-0.404083,-1.120224,0.738373,-0.031082,0.110947,-0.025085,0.012939,-0.003479,0.000748,0.000015,
-0.000259,-0.002792,-0.003006,-0.031662,-0.051132,-0.134888,-0.431656,-1.127747,0.711319,-0.044785,0.105820,-0.026535,0.011887,-0.003479,0.000687,0.000015, -0.000259,-0.002792,-0.003006,-0.031662,-0.051132,-0.134888,-0.431656,-1.127747,0.711319,-0.044785,0.105820,-0.026535,0.011887,-0.003479,0.000687,0.000015,
-0.000290,-0.002899,-0.003723,-0.031815,-0.056534,-0.129578,-0.459473,-1.133926,0.683914,-0.057617,0.100540,-0.027802,0.010849,-0.003464,0.000626,0.000015, -0.000290,-0.002899,-0.003723,-0.031815,-0.056534,-0.129578,-0.459473,-1.133926,0.683914,-0.057617,0.100540,-0.027802,0.010849,-0.003464,0.000626,0.000015,
-0.000320,-0.002991,-0.004486,-0.031845,-0.061996,-0.123474,-0.487473,-1.138763,0.656219,-0.069595,0.095169,-0.028885,0.009842,-0.003433,0.000580,0.000015, -0.000320,-0.002991,-0.004486,-0.031845,-0.061996,-0.123474,-0.487473,-1.138763,0.656219,-0.069595,0.095169,-0.028885,0.009842,-0.003433,0.000580,0.000015,
-0.000366,-0.003082,-0.005295,-0.031738,-0.067520,-0.116577,-0.515610,-1.142212,0.628296,-0.080688,0.089706,-0.029785,0.008865,-0.003387,0.000534,0.000015, -0.000366,-0.003082,-0.005295,-0.031738,-0.067520,-0.116577,-0.515610,-1.142212,0.628296,-0.080688,0.089706,-0.029785,0.008865,-0.003387,0.000534,0.000015,
-0.000397,-0.003174,-0.006119,-0.031479,-0.073059,-0.108856,-0.543823,-1.144287,0.600220,-0.090927,0.084183,-0.030518,0.007919,-0.003326,0.000473,0.000015, -0.000397,-0.003174,-0.006119,-0.031479,-0.073059,-0.108856,-0.543823,-1.144287,0.600220,-0.090927,0.084183,-0.030518,0.007919,-0.003326,0.000473,0.000015,
}; };
// filterTbl[i][j] = cos(((M_PI/64*i+M_PI/4)*(2*j+1))); // filterTbl[i][j] = cos(((M_PI/64*i+M_PI/4)*(2*j+1)));
static const double s_jo_filterTbl[64][32] = { static const double s_jo_filterTbl[64][32] = {
{0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107, {0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,
0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107}, 0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107},
{0.671559,-0.803208,-0.514103,0.903989,0.336890,-0.970031,-0.146730,0.998795,-0.049068,-0.989177,0.242980,0.941544,-0.427555,-0.857729,0.595699,0.740951, {0.671559,-0.803208,-0.514103,0.903989,0.336890,-0.970031,-0.146730,0.998795,-0.049068,-0.989177,0.242980,0.941544,-0.427555,-0.857729,0.595699,0.740951,
-0.740951,-0.595699,0.857729,0.427555,-0.941544,-0.242980,0.989177,0.049068,-0.998795,0.146730,0.970031,-0.336890,-0.903989,0.514103,0.803208,-0.671559}, -0.740951,-0.595699,0.857729,0.427555,-0.941544,-0.242980,0.989177,0.049068,-0.998795,0.146730,0.970031,-0.336890,-0.903989,0.514103,0.803208,-0.671559},
{0.634393,-0.881921,-0.290285,0.995185,-0.098017,-0.956940,0.471397,0.773010,-0.773010,-0.471397,0.956940,0.098017,-0.995185,0.290285,0.881921,-0.634393, {0.634393,-0.881921,-0.290285,0.995185,-0.098017,-0.956940,0.471397,0.773010,-0.773010,-0.471397,0.956940,0.098017,-0.995185,0.290285,0.881921,-0.634393,
-0.634393,0.881921,0.290285,-0.995185,0.098017,0.956940,-0.471397,-0.773010,0.773010,0.471397,-0.956940,-0.098017,0.995185,-0.290285,-0.881921,0.634393}, -0.634393,0.881921,0.290285,-0.995185,0.098017,0.956940,-0.471397,-0.773010,0.773010,0.471397,-0.956940,-0.098017,0.995185,-0.290285,-0.881921,0.634393},
{0.595699,-0.941544,-0.049068,0.970031,-0.514103,-0.671559,0.903989,0.146730,-0.989177,0.427555,0.740951,-0.857729,-0.242980,0.998795,-0.336890,-0.803208, {0.595699,-0.941544,-0.049068,0.970031,-0.514103,-0.671559,0.903989,0.146730,-0.989177,0.427555,0.740951,-0.857729,-0.242980,0.998795,-0.336890,-0.803208,
0.803208,0.336890,-0.998795,0.242980,0.857729,-0.740951,-0.427555,0.989177,-0.146730,-0.903989,0.671559,0.514103,-0.970031,0.049068,0.941544,-0.595699}, 0.803208,0.336890,-0.998795,0.242980,0.857729,-0.740951,-0.427555,0.989177,-0.146730,-0.903989,0.671559,0.514103,-0.970031,0.049068,0.941544,-0.595699},
{0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570,-0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570, {0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570,-0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570,
0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570,-0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570}, 0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570,-0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570},
{0.514103,-0.998795,0.427555,0.595699,-0.989177,0.336890,0.671559,-0.970031,0.242980,0.740951,-0.941544,0.146730,0.803208,-0.903989,0.049068,0.857729, {0.514103,-0.998795,0.427555,0.595699,-0.989177,0.336890,0.671559,-0.970031,0.242980,0.740951,-0.941544,0.146730,0.803208,-0.903989,0.049068,0.857729,
-0.857729,-0.049068,0.903989,-0.803208,-0.146730,0.941544,-0.740951,-0.242980,0.970031,-0.671559,-0.336890,0.989177,-0.595699,-0.427555,0.998795,-0.514103}, -0.857729,-0.049068,0.903989,-0.803208,-0.146730,0.941544,-0.740951,-0.242980,0.970031,-0.671559,-0.336890,0.989177,-0.595699,-0.427555,0.998795,-0.514103},
{0.471397,-0.995185,0.634393,0.290285,-0.956940,0.773010,0.098017,-0.881921,0.881921,-0.098017,-0.773010,0.956940,-0.290285,-0.634393,0.995185,-0.471397, {0.471397,-0.995185,0.634393,0.290285,-0.956940,0.773010,0.098017,-0.881921,0.881921,-0.098017,-0.773010,0.956940,-0.290285,-0.634393,0.995185,-0.471397,
-0.471397,0.995185,-0.634393,-0.290285,0.956940,-0.773010,-0.098017,0.881921,-0.881921,0.098017,0.773010,-0.956940,0.290285,0.634393,-0.995185,0.471397}, -0.471397,0.995185,-0.634393,-0.290285,0.956940,-0.773010,-0.098017,0.881921,-0.881921,0.098017,0.773010,-0.956940,0.290285,0.634393,-0.995185,0.471397},
{0.427555,-0.970031,0.803208,-0.049068,-0.740951,0.989177,-0.514103,-0.336890,0.941544,-0.857729,0.146730,0.671559,-0.998795,0.595699,0.242980,-0.903989, {0.427555,-0.970031,0.803208,-0.049068,-0.740951,0.989177,-0.514103,-0.336890,0.941544,-0.857729,0.146730,0.671559,-0.998795,0.595699,0.242980,-0.903989,
0.903989,-0.242980,-0.595699,0.998795,-0.671559,-0.146730,0.857729,-0.941544,0.336890,0.514103,-0.989177,0.740951,0.049068,-0.803208,0.970031,-0.427555}, 0.903989,-0.242980,-0.595699,0.998795,-0.671559,-0.146730,0.857729,-0.941544,0.336890,0.514103,-0.989177,0.740951,0.049068,-0.803208,0.970031,-0.427555},
{0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683, {0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,
0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683}, 0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683},
{0.336890,-0.857729,0.989177,-0.671559,0.049068,0.595699,-0.970031,0.903989,-0.427555,-0.242980,0.803208,-0.998795,0.740951,-0.146730,-0.514103,0.941544, {0.336890,-0.857729,0.989177,-0.671559,0.049068,0.595699,-0.970031,0.903989,-0.427555,-0.242980,0.803208,-0.998795,0.740951,-0.146730,-0.514103,0.941544,
-0.941544,0.514103,0.146730,-0.740951,0.998795,-0.803208,0.242980,0.427555,-0.903989,0.970031,-0.595699,-0.049068,0.671559,-0.989177,0.857729,-0.336890}, -0.941544,0.514103,0.146730,-0.740951,0.998795,-0.803208,0.242980,0.427555,-0.903989,0.970031,-0.595699,-0.049068,0.671559,-0.989177,0.857729,-0.336890},
{0.290285,-0.773010,0.995185,-0.881921,0.471397,0.098017,-0.634393,0.956940,-0.956940,0.634393,-0.098017,-0.471397,0.881921,-0.995185,0.773010,-0.290285, {0.290285,-0.773010,0.995185,-0.881921,0.471397,0.098017,-0.634393,0.956940,-0.956940,0.634393,-0.098017,-0.471397,0.881921,-0.995185,0.773010,-0.290285,
-0.290285,0.773010,-0.995185,0.881921,-0.471397,-0.098017,0.634393,-0.956940,0.956940,-0.634393,0.098017,0.471397,-0.881921,0.995185,-0.773010,0.290285}, -0.290285,0.773010,-0.995185,0.881921,-0.471397,-0.098017,0.634393,-0.956940,0.956940,-0.634393,0.098017,0.471397,-0.881921,0.995185,-0.773010,0.290285},
{0.242980,-0.671559,0.941544,-0.989177,0.803208,-0.427555,-0.049068,0.514103,-0.857729,0.998795,-0.903989,0.595699,-0.146730,-0.336890,0.740951,-0.970031, {0.242980,-0.671559,0.941544,-0.989177,0.803208,-0.427555,-0.049068,0.514103,-0.857729,0.998795,-0.903989,0.595699,-0.146730,-0.336890,0.740951,-0.970031,
0.970031,-0.740951,0.336890,0.146730,-0.595699,0.903989,-0.998795,0.857729,-0.514103,0.049068,0.427555,-0.803208,0.989177,-0.941544,0.671559,-0.242980}, 0.970031,-0.740951,0.336890,0.146730,-0.595699,0.903989,-0.998795,0.857729,-0.514103,0.049068,0.427555,-0.803208,0.989177,-0.941544,0.671559,-0.242980},
{0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090,-0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090, {0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090,-0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090,
0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090,-0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090}, 0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090,-0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090},
{0.146730,-0.427555,0.671559,-0.857729,0.970031,-0.998795,0.941544,-0.803208,0.595699,-0.336890,0.049068,0.242980,-0.514103,0.740951,-0.903989,0.989177, {0.146730,-0.427555,0.671559,-0.857729,0.970031,-0.998795,0.941544,-0.803208,0.595699,-0.336890,0.049068,0.242980,-0.514103,0.740951,-0.903989,0.989177,
-0.989177,0.903989,-0.740951,0.514103,-0.242980,-0.049068,0.336890,-0.595699,0.803208,-0.941544,0.998795,-0.970031,0.857729,-0.671559,0.427555,-0.146730}, -0.989177,0.903989,-0.740951,0.514103,-0.242980,-0.049068,0.336890,-0.595699,0.803208,-0.941544,0.998795,-0.970031,0.857729,-0.671559,0.427555,-0.146730},
{0.098017,-0.290285,0.471397,-0.634393,0.773010,-0.881921,0.956940,-0.995185,0.995185,-0.956940,0.881921,-0.773010,0.634393,-0.471397,0.290285,-0.098017, {0.098017,-0.290285,0.471397,-0.634393,0.773010,-0.881921,0.956940,-0.995185,0.995185,-0.956940,0.881921,-0.773010,0.634393,-0.471397,0.290285,-0.098017,
-0.098017,0.290285,-0.471397,0.634393,-0.773010,0.881921,-0.956940,0.995185,-0.995185,0.956940,-0.881921,0.773010,-0.634393,0.471397,-0.290285,0.098017}, -0.098017,0.290285,-0.471397,0.634393,-0.773010,0.881921,-0.956940,0.995185,-0.995185,0.956940,-0.881921,0.773010,-0.634393,0.471397,-0.290285,0.098017},
{0.049068,-0.146730,0.242980,-0.336890,0.427555,-0.514103,0.595699,-0.671559,0.740951,-0.803208,0.857729,-0.903989,0.941544,-0.970031,0.989177,-0.998795, {0.049068,-0.146730,0.242980,-0.336890,0.427555,-0.514103,0.595699,-0.671559,0.740951,-0.803208,0.857729,-0.903989,0.941544,-0.970031,0.989177,-0.998795,
0.998795,-0.989177,0.970031,-0.941544,0.903989,-0.857729,0.803208,-0.740951,0.671559,-0.595699,0.514103,-0.427555,0.336890,-0.242980,0.146730,-0.049068}, 0.998795,-0.989177,0.970031,-0.941544,0.903989,-0.857729,0.803208,-0.740951,0.671559,-0.595699,0.514103,-0.427555,0.336890,-0.242980,0.146730,-0.049068},
{0.000000,-0.000000,0.000000,-0.000000,0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000, {0.000000,-0.000000,0.000000,-0.000000,0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,-0.000000,
0.000000,-0.000000,0.000000,-0.000000,0.000000,-0.000000,0.000000,0.000000,0.000000,-0.000000,0.000000,0.000000,0.000000,-0.000000,0.000000,0.000000}, 0.000000,-0.000000,0.000000,-0.000000,0.000000,-0.000000,0.000000,0.000000,0.000000,-0.000000,0.000000,0.000000,0.000000,-0.000000,0.000000,0.000000},
{-0.049068,0.146730,-0.242980,0.336890,-0.427555,0.514103,-0.595699,0.671559,-0.740951,0.803208,-0.857729,0.903989,-0.941544,0.970031,-0.989177,0.998795, {-0.049068,0.146730,-0.242980,0.336890,-0.427555,0.514103,-0.595699,0.671559,-0.740951,0.803208,-0.857729,0.903989,-0.941544,0.970031,-0.989177,0.998795,
-0.998795,0.989177,-0.970031,0.941544,-0.903989,0.857729,-0.803208,0.740951,-0.671559,0.595699,-0.514103,0.427555,-0.336890,0.242980,-0.146730,0.049068}, -0.998795,0.989177,-0.970031,0.941544,-0.903989,0.857729,-0.803208,0.740951,-0.671559,0.595699,-0.514103,0.427555,-0.336890,0.242980,-0.146730,0.049068},
{-0.098017,0.290285,-0.471397,0.634393,-0.773010,0.881921,-0.956940,0.995185,-0.995185,0.956940,-0.881921,0.773010,-0.634393,0.471397,-0.290285,0.098017, {-0.098017,0.290285,-0.471397,0.634393,-0.773010,0.881921,-0.956940,0.995185,-0.995185,0.956940,-0.881921,0.773010,-0.634393,0.471397,-0.290285,0.098017,
0.098017,-0.290285,0.471397,-0.634393,0.773010,-0.881921,0.956940,-0.995185,0.995185,-0.956940,0.881921,-0.773010,0.634393,-0.471397,0.290285,-0.098017}, 0.098017,-0.290285,0.471397,-0.634393,0.773010,-0.881921,0.956940,-0.995185,0.995185,-0.956940,0.881921,-0.773010,0.634393,-0.471397,0.290285,-0.098017},
{-0.146730,0.427555,-0.671559,0.857729,-0.970031,0.998795,-0.941544,0.803208,-0.595699,0.336890,-0.049068,-0.242980,0.514103,-0.740951,0.903989,-0.989177, {-0.146730,0.427555,-0.671559,0.857729,-0.970031,0.998795,-0.941544,0.803208,-0.595699,0.336890,-0.049068,-0.242980,0.514103,-0.740951,0.903989,-0.989177,
0.989177,-0.903989,0.740951,-0.514103,0.242980,0.049068,-0.336890,0.595699,-0.803208,0.941544,-0.998795,0.970031,-0.857729,0.671559,-0.427555,0.146730}, 0.989177,-0.903989,0.740951,-0.514103,0.242980,0.049068,-0.336890,0.595699,-0.803208,0.941544,-0.998795,0.970031,-0.857729,0.671559,-0.427555,0.146730},
{-0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090,0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090, {-0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090,0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090,
-0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090,0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090}, -0.195090,0.555570,-0.831470,0.980785,-0.980785,0.831470,-0.555570,0.195090,0.195090,-0.555570,0.831470,-0.980785,0.980785,-0.831470,0.555570,-0.195090},
{-0.242980,0.671559,-0.941544,0.989177,-0.803208,0.427555,0.049068,-0.514103,0.857729,-0.998795,0.903989,-0.595699,0.146730,0.336890,-0.740951,0.970031, {-0.242980,0.671559,-0.941544,0.989177,-0.803208,0.427555,0.049068,-0.514103,0.857729,-0.998795,0.903989,-0.595699,0.146730,0.336890,-0.740951,0.970031,
-0.970031,0.740951,-0.336890,-0.146730,0.595699,-0.903989,0.998795,-0.857729,0.514103,-0.049068,-0.427555,0.803208,-0.989177,0.941544,-0.671559,0.242980}, -0.970031,0.740951,-0.336890,-0.146730,0.595699,-0.903989,0.998795,-0.857729,0.514103,-0.049068,-0.427555,0.803208,-0.989177,0.941544,-0.671559,0.242980},
{-0.290285,0.773010,-0.995185,0.881921,-0.471397,-0.098017,0.634393,-0.956940,0.956940,-0.634393,0.098017,0.471397,-0.881921,0.995185,-0.773010,0.290285, {-0.290285,0.773010,-0.995185,0.881921,-0.471397,-0.098017,0.634393,-0.956940,0.956940,-0.634393,0.098017,0.471397,-0.881921,0.995185,-0.773010,0.290285,
0.290285,-0.773010,0.995185,-0.881921,0.471397,0.098017,-0.634393,0.956940,-0.956940,0.634393,-0.098017,-0.471397,0.881921,-0.995185,0.773010,-0.290285}, 0.290285,-0.773010,0.995185,-0.881921,0.471397,0.098017,-0.634393,0.956940,-0.956940,0.634393,-0.098017,-0.471397,0.881921,-0.995185,0.773010,-0.290285},
{-0.336890,0.857729,-0.989177,0.671559,-0.049068,-0.595699,0.970031,-0.903989,0.427555,0.242980,-0.803208,0.998795,-0.740951,0.146730,0.514103,-0.941544, {-0.336890,0.857729,-0.989177,0.671559,-0.049068,-0.595699,0.970031,-0.903989,0.427555,0.242980,-0.803208,0.998795,-0.740951,0.146730,0.514103,-0.941544,
0.941544,-0.514103,-0.146730,0.740951,-0.998795,0.803208,-0.242980,-0.427555,0.903989,-0.970031,0.595699,0.049068,-0.671559,0.989177,-0.857729,0.336890}, 0.941544,-0.514103,-0.146730,0.740951,-0.998795,0.803208,-0.242980,-0.427555,0.903989,-0.970031,0.595699,0.049068,-0.671559,0.989177,-0.857729,0.336890},
{-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683, {-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,
-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683}, -0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683,-0.382683,0.923880,-0.923880,0.382683,0.382683,-0.923880,0.923880,-0.382683},
{-0.427555,0.970031,-0.803208,0.049068,0.740951,-0.989177,0.514103,0.336890,-0.941544,0.857729,-0.146730,-0.671559,0.998795,-0.595699,-0.242980,0.903989, {-0.427555,0.970031,-0.803208,0.049068,0.740951,-0.989177,0.514103,0.336890,-0.941544,0.857729,-0.146730,-0.671559,0.998795,-0.595699,-0.242980,0.903989,
-0.903989,0.242980,0.595699,-0.998795,0.671559,0.146730,-0.857729,0.941544,-0.336890,-0.514103,0.989177,-0.740951,-0.049068,0.803208,-0.970031,0.427555}, -0.903989,0.242980,0.595699,-0.998795,0.671559,0.146730,-0.857729,0.941544,-0.336890,-0.514103,0.989177,-0.740951,-0.049068,0.803208,-0.970031,0.427555},
{-0.471397,0.995185,-0.634393,-0.290285,0.956940,-0.773010,-0.098017,0.881921,-0.881921,0.098017,0.773010,-0.956940,0.290285,0.634393,-0.995185,0.471397, {-0.471397,0.995185,-0.634393,-0.290285,0.956940,-0.773010,-0.098017,0.881921,-0.881921,0.098017,0.773010,-0.956940,0.290285,0.634393,-0.995185,0.471397,
0.471397,-0.995185,0.634393,0.290285,-0.956940,0.773010,0.098017,-0.881921,0.881921,-0.098017,-0.773010,0.956940,-0.290285,-0.634393,0.995185,-0.471397}, 0.471397,-0.995185,0.634393,0.290285,-0.956940,0.773010,0.098017,-0.881921,0.881921,-0.098017,-0.773010,0.956940,-0.290285,-0.634393,0.995185,-0.471397},
{-0.514103,0.998795,-0.427555,-0.595699,0.989177,-0.336890,-0.671559,0.970031,-0.242980,-0.740951,0.941544,-0.146730,-0.803208,0.903989,-0.049068,-0.857729, {-0.514103,0.998795,-0.427555,-0.595699,0.989177,-0.336890,-0.671559,0.970031,-0.242980,-0.740951,0.941544,-0.146730,-0.803208,0.903989,-0.049068,-0.857729,
0.857729,0.049068,-0.903989,0.803208,0.146730,-0.941544,0.740951,0.242980,-0.970031,0.671559,0.336890,-0.989177,0.595699,0.427555,-0.998795,0.514103}, 0.857729,0.049068,-0.903989,0.803208,0.146730,-0.941544,0.740951,0.242980,-0.970031,0.671559,0.336890,-0.989177,0.595699,0.427555,-0.998795,0.514103},
{-0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570,0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570, {-0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570,0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570,
-0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570,0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570}, -0.555570,0.980785,-0.195090,-0.831470,0.831470,0.195090,-0.980785,0.555570,0.555570,-0.980785,0.195090,0.831470,-0.831470,-0.195090,0.980785,-0.555570},
{-0.595699,0.941544,0.049068,-0.970031,0.514103,0.671559,-0.903989,-0.146730,0.989177,-0.427555,-0.740951,0.857729,0.242980,-0.998795,0.336890,0.803208, {-0.595699,0.941544,0.049068,-0.970031,0.514103,0.671559,-0.903989,-0.146730,0.989177,-0.427555,-0.740951,0.857729,0.242980,-0.998795,0.336890,0.803208,
-0.803208,-0.336890,0.998795,-0.242980,-0.857729,0.740951,0.427555,-0.989177,0.146730,0.903989,-0.671559,-0.514103,0.970031,-0.049068,-0.941544,0.595699}, -0.803208,-0.336890,0.998795,-0.242980,-0.857729,0.740951,0.427555,-0.989177,0.146730,0.903989,-0.671559,-0.514103,0.970031,-0.049068,-0.941544,0.595699},
{-0.634393,0.881921,0.290285,-0.995185,0.098017,0.956940,-0.471397,-0.773010,0.773010,0.471397,-0.956940,-0.098017,0.995185,-0.290285,-0.881921,0.634393, {-0.634393,0.881921,0.290285,-0.995185,0.098017,0.956940,-0.471397,-0.773010,0.773010,0.471397,-0.956940,-0.098017,0.995185,-0.290285,-0.881921,0.634393,
0.634393,-0.881921,-0.290285,0.995185,-0.098017,-0.956940,0.471397,0.773010,-0.773010,-0.471397,0.956940,0.098017,-0.995185,0.290285,0.881921,-0.634393}, 0.634393,-0.881921,-0.290285,0.995185,-0.098017,-0.956940,0.471397,0.773010,-0.773010,-0.471397,0.956940,0.098017,-0.995185,0.290285,0.881921,-0.634393},
{-0.671559,0.803208,0.514103,-0.903989,-0.336890,0.970031,0.146730,-0.998795,0.049068,0.989177,-0.242980,-0.941544,0.427555,0.857729,-0.595699,-0.740951, {-0.671559,0.803208,0.514103,-0.903989,-0.336890,0.970031,0.146730,-0.998795,0.049068,0.989177,-0.242980,-0.941544,0.427555,0.857729,-0.595699,-0.740951,
0.740951,0.595699,-0.857729,-0.427555,0.941544,0.242980,-0.989177,-0.049068,0.998795,-0.146730,-0.970031,0.336890,0.903989,-0.514103,-0.803208,0.671559}, 0.740951,0.595699,-0.857729,-0.427555,0.941544,0.242980,-0.989177,-0.049068,0.998795,-0.146730,-0.970031,0.336890,0.903989,-0.514103,-0.803208,0.671559},
{-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107, {-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,
-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107}, -0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107,-0.707107,0.707107,0.707107,-0.707107},
{-0.740951,0.595699,0.857729,-0.427555,-0.941544,0.242980,0.989177,-0.049068,-0.998795,-0.146730,0.970031,0.336890,-0.903989,-0.514103,0.803208,0.671559, {-0.740951,0.595699,0.857729,-0.427555,-0.941544,0.242980,0.989177,-0.049068,-0.998795,-0.146730,0.970031,0.336890,-0.903989,-0.514103,0.803208,0.671559,
-0.671559,-0.803208,0.514103,0.903989,-0.336890,-0.970031,0.146730,0.998795,0.049068,-0.989177,-0.242980,0.941544,0.427555,-0.857729,-0.595699,0.740951}, -0.671559,-0.803208,0.514103,0.903989,-0.336890,-0.970031,0.146730,0.998795,0.049068,-0.989177,-0.242980,0.941544,0.427555,-0.857729,-0.595699,0.740951},
{-0.773010,0.471397,0.956940,-0.098017,-0.995185,-0.290285,0.881921,0.634393,-0.634393,-0.881921,0.290285,0.995185,0.098017,-0.956940,-0.471397,0.773010, {-0.773010,0.471397,0.956940,-0.098017,-0.995185,-0.290285,0.881921,0.634393,-0.634393,-0.881921,0.290285,0.995185,0.098017,-0.956940,-0.471397,0.773010,
0.773010,-0.471397,-0.956940,0.098017,0.995185,0.290285,-0.881921,-0.634393,0.634393,0.881921,-0.290285,-0.995185,-0.098017,0.956940,0.471397,-0.773010}, 0.773010,-0.471397,-0.956940,0.098017,0.995185,0.290285,-0.881921,-0.634393,0.634393,0.881921,-0.290285,-0.995185,-0.098017,0.956940,0.471397,-0.773010},
{-0.803208,0.336890,0.998795,0.242980,-0.857729,-0.740951,0.427555,0.989177,0.146730,-0.903989,-0.671559,0.514103,0.970031,0.049068,-0.941544,-0.595699, {-0.803208,0.336890,0.998795,0.242980,-0.857729,-0.740951,0.427555,0.989177,0.146730,-0.903989,-0.671559,0.514103,0.970031,0.049068,-0.941544,-0.595699,
0.595699,0.941544,-0.049068,-0.970031,-0.514103,0.671559,0.903989,-0.146730,-0.989177,-0.427555,0.740951,0.857729,-0.242980,-0.998795,-0.336890,0.803208}, 0.595699,0.941544,-0.049068,-0.970031,-0.514103,0.671559,0.903989,-0.146730,-0.989177,-0.427555,0.740951,0.857729,-0.242980,-0.998795,-0.336890,0.803208},
{-0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470, {-0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470,
-0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470}, -0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470},
{-0.857729,0.049068,0.903989,0.803208,-0.146730,-0.941544,-0.740951,0.242980,0.970031,0.671559,-0.336890,-0.989177,-0.595699,0.427555,0.998795,0.514103, {-0.857729,0.049068,0.903989,0.803208,-0.146730,-0.941544,-0.740951,0.242980,0.970031,0.671559,-0.336890,-0.989177,-0.595699,0.427555,0.998795,0.514103,
-0.514103,-0.998795,-0.427555,0.595699,0.989177,0.336890,-0.671559,-0.970031,-0.242980,0.740951,0.941544,0.146730,-0.803208,-0.903989,-0.049068,0.857729}, -0.514103,-0.998795,-0.427555,0.595699,0.989177,0.336890,-0.671559,-0.970031,-0.242980,0.740951,0.941544,0.146730,-0.803208,-0.903989,-0.049068,0.857729},
{-0.881921,-0.098017,0.773010,0.956940,0.290285,-0.634393,-0.995185,-0.471397,0.471397,0.995185,0.634393,-0.290285,-0.956940,-0.773010,0.098017,0.881921, {-0.881921,-0.098017,0.773010,0.956940,0.290285,-0.634393,-0.995185,-0.471397,0.471397,0.995185,0.634393,-0.290285,-0.956940,-0.773010,0.098017,0.881921,
0.881921,0.098017,-0.773010,-0.956940,-0.290285,0.634393,0.995185,0.471397,-0.471397,-0.995185,-0.634393,0.290285,0.956940,0.773010,-0.098017,-0.881921}, 0.881921,0.098017,-0.773010,-0.956940,-0.290285,0.634393,0.995185,0.471397,-0.471397,-0.995185,-0.634393,0.290285,0.956940,0.773010,-0.098017,-0.881921},
{-0.903989,-0.242980,0.595699,0.998795,0.671559,-0.146730,-0.857729,-0.941544,-0.336890,0.514103,0.989177,0.740951,-0.049068,-0.803208,-0.970031,-0.427555, {-0.903989,-0.242980,0.595699,0.998795,0.671559,-0.146730,-0.857729,-0.941544,-0.336890,0.514103,0.989177,0.740951,-0.049068,-0.803208,-0.970031,-0.427555,
0.427555,0.970031,0.803208,0.049068,-0.740951,-0.989177,-0.514103,0.336890,0.941544,0.857729,0.146730,-0.671559,-0.998795,-0.595699,0.242980,0.903989}, 0.427555,0.970031,0.803208,0.049068,-0.740951,-0.989177,-0.514103,0.336890,0.941544,0.857729,0.146730,-0.671559,-0.998795,-0.595699,0.242980,0.903989},
{-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880, {-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,
-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880}, -0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880},
{-0.941544,-0.514103,0.146730,0.740951,0.998795,0.803208,0.242980,-0.427555,-0.903989,-0.970031,-0.595699,0.049068,0.671559,0.989177,0.857729,0.336890, {-0.941544,-0.514103,0.146730,0.740951,0.998795,0.803208,0.242980,-0.427555,-0.903989,-0.970031,-0.595699,0.049068,0.671559,0.989177,0.857729,0.336890,
-0.336890,-0.857729,-0.989177,-0.671559,-0.049068,0.595699,0.970031,0.903989,0.427555,-0.242980,-0.803208,-0.998795,-0.740951,-0.146730,0.514103,0.941544}, -0.336890,-0.857729,-0.989177,-0.671559,-0.049068,0.595699,0.970031,0.903989,0.427555,-0.242980,-0.803208,-0.998795,-0.740951,-0.146730,0.514103,0.941544},
{-0.956940,-0.634393,-0.098017,0.471397,0.881921,0.995185,0.773010,0.290285,-0.290285,-0.773010,-0.995185,-0.881921,-0.471397,0.098017,0.634393,0.956940, {-0.956940,-0.634393,-0.098017,0.471397,0.881921,0.995185,0.773010,0.290285,-0.290285,-0.773010,-0.995185,-0.881921,-0.471397,0.098017,0.634393,0.956940,
0.956940,0.634393,0.098017,-0.471397,-0.881921,-0.995185,-0.773010,-0.290285,0.290285,0.773010,0.995185,0.881921,0.471397,-0.098017,-0.634393,-0.956940}, 0.956940,0.634393,0.098017,-0.471397,-0.881921,-0.995185,-0.773010,-0.290285,0.290285,0.773010,0.995185,0.881921,0.471397,-0.098017,-0.634393,-0.956940},
{-0.970031,-0.740951,-0.336890,0.146730,0.595699,0.903989,0.998795,0.857729,0.514103,0.049068,-0.427555,-0.803208,-0.989177,-0.941544,-0.671559,-0.242980, {-0.970031,-0.740951,-0.336890,0.146730,0.595699,0.903989,0.998795,0.857729,0.514103,0.049068,-0.427555,-0.803208,-0.989177,-0.941544,-0.671559,-0.242980,
0.242980,0.671559,0.941544,0.989177,0.803208,0.427555,-0.049068,-0.514103,-0.857729,-0.998795,-0.903989,-0.595699,-0.146730,0.336890,0.740951,0.970031}, 0.242980,0.671559,0.941544,0.989177,0.803208,0.427555,-0.049068,-0.514103,-0.857729,-0.998795,-0.903989,-0.595699,-0.146730,0.336890,0.740951,0.970031},
{-0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785, {-0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785,
-0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785}, -0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785},
{-0.989177,-0.903989,-0.740951,-0.514103,-0.242980,0.049068,0.336890,0.595699,0.803208,0.941544,0.998795,0.970031,0.857729,0.671559,0.427555,0.146730, {-0.989177,-0.903989,-0.740951,-0.514103,-0.242980,0.049068,0.336890,0.595699,0.803208,0.941544,0.998795,0.970031,0.857729,0.671559,0.427555,0.146730,
-0.146730,-0.427555,-0.671559,-0.857729,-0.970031,-0.998795,-0.941544,-0.803208,-0.595699,-0.336890,-0.049068,0.242980,0.514103,0.740951,0.903989,0.989177}, -0.146730,-0.427555,-0.671559,-0.857729,-0.970031,-0.998795,-0.941544,-0.803208,-0.595699,-0.336890,-0.049068,0.242980,0.514103,0.740951,0.903989,0.989177},
{-0.995185,-0.956940,-0.881921,-0.773010,-0.634393,-0.471397,-0.290285,-0.098017,0.098017,0.290285,0.471397,0.634393,0.773010,0.881921,0.956940,0.995185, {-0.995185,-0.956940,-0.881921,-0.773010,-0.634393,-0.471397,-0.290285,-0.098017,0.098017,0.290285,0.471397,0.634393,0.773010,0.881921,0.956940,0.995185,
0.995185,0.956940,0.881921,0.773010,0.634393,0.471397,0.290285,0.098017,-0.098017,-0.290285,-0.471397,-0.634393,-0.773010,-0.881921,-0.956940,-0.995185}, 0.995185,0.956940,0.881921,0.773010,0.634393,0.471397,0.290285,0.098017,-0.098017,-0.290285,-0.471397,-0.634393,-0.773010,-0.881921,-0.956940,-0.995185},
{-0.998795,-0.989177,-0.970031,-0.941544,-0.903989,-0.857729,-0.803208,-0.740951,-0.671559,-0.595699,-0.514103,-0.427555,-0.336890,-0.242980,-0.146730,-0.049068, {-0.998795,-0.989177,-0.970031,-0.941544,-0.903989,-0.857729,-0.803208,-0.740951,-0.671559,-0.595699,-0.514103,-0.427555,-0.336890,-0.242980,-0.146730,-0.049068,
0.049068,0.146730,0.242980,0.336890,0.427555,0.514103,0.595699,0.671559,0.740951,0.803208,0.857729,0.903989,0.941544,0.970031,0.989177,0.998795}, 0.049068,0.146730,0.242980,0.336890,0.427555,0.514103,0.595699,0.671559,0.740951,0.803208,0.857729,0.903989,0.941544,0.970031,0.989177,0.998795},
{-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000, {-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,
-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000}, -1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000,-1.000000},
{-0.998795,-0.989177,-0.970031,-0.941544,-0.903989,-0.857729,-0.803208,-0.740951,-0.671559,-0.595699,-0.514103,-0.427555,-0.336890,-0.242980,-0.146730,-0.049068, {-0.998795,-0.989177,-0.970031,-0.941544,-0.903989,-0.857729,-0.803208,-0.740951,-0.671559,-0.595699,-0.514103,-0.427555,-0.336890,-0.242980,-0.146730,-0.049068,
0.049068,0.146730,0.242980,0.336890,0.427555,0.514103,0.595699,0.671559,0.740951,0.803208,0.857729,0.903989,0.941544,0.970031,0.989177,0.998795}, 0.049068,0.146730,0.242980,0.336890,0.427555,0.514103,0.595699,0.671559,0.740951,0.803208,0.857729,0.903989,0.941544,0.970031,0.989177,0.998795},
{-0.995185,-0.956940,-0.881921,-0.773010,-0.634393,-0.471397,-0.290285,-0.098017,0.098017,0.290285,0.471397,0.634393,0.773010,0.881921,0.956940,0.995185, {-0.995185,-0.956940,-0.881921,-0.773010,-0.634393,-0.471397,-0.290285,-0.098017,0.098017,0.290285,0.471397,0.634393,0.773010,0.881921,0.956940,0.995185,
0.995185,0.956940,0.881921,0.773010,0.634393,0.471397,0.290285,0.098017,-0.098017,-0.290285,-0.471397,-0.634393,-0.773010,-0.881921,-0.956940,-0.995185}, 0.995185,0.956940,0.881921,0.773010,0.634393,0.471397,0.290285,0.098017,-0.098017,-0.290285,-0.471397,-0.634393,-0.773010,-0.881921,-0.956940,-0.995185},
{-0.989177,-0.903989,-0.740951,-0.514103,-0.242980,0.049068,0.336890,0.595699,0.803208,0.941544,0.998795,0.970031,0.857729,0.671559,0.427555,0.146730, {-0.989177,-0.903989,-0.740951,-0.514103,-0.242980,0.049068,0.336890,0.595699,0.803208,0.941544,0.998795,0.970031,0.857729,0.671559,0.427555,0.146730,
-0.146730,-0.427555,-0.671559,-0.857729,-0.970031,-0.998795,-0.941544,-0.803208,-0.595699,-0.336890,-0.049068,0.242980,0.514103,0.740951,0.903989,0.989177}, -0.146730,-0.427555,-0.671559,-0.857729,-0.970031,-0.998795,-0.941544,-0.803208,-0.595699,-0.336890,-0.049068,0.242980,0.514103,0.740951,0.903989,0.989177},
{-0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785, {-0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785,
-0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785}, -0.980785,-0.831470,-0.555570,-0.195090,0.195090,0.555570,0.831470,0.980785,0.980785,0.831470,0.555570,0.195090,-0.195090,-0.555570,-0.831470,-0.980785},
{-0.970031,-0.740951,-0.336890,0.146730,0.595699,0.903989,0.998795,0.857729,0.514103,0.049068,-0.427555,-0.803208,-0.989177,-0.941544,-0.671559,-0.242980, {-0.970031,-0.740951,-0.336890,0.146730,0.595699,0.903989,0.998795,0.857729,0.514103,0.049068,-0.427555,-0.803208,-0.989177,-0.941544,-0.671559,-0.242980,
0.242980,0.671559,0.941544,0.989177,0.803208,0.427555,-0.049068,-0.514103,-0.857729,-0.998795,-0.903989,-0.595699,-0.146730,0.336890,0.740951,0.970031}, 0.242980,0.671559,0.941544,0.989177,0.803208,0.427555,-0.049068,-0.514103,-0.857729,-0.998795,-0.903989,-0.595699,-0.146730,0.336890,0.740951,0.970031},
{-0.956940,-0.634393,-0.098017,0.471397,0.881921,0.995185,0.773010,0.290285,-0.290285,-0.773010,-0.995185,-0.881921,-0.471397,0.098017,0.634393,0.956940, {-0.956940,-0.634393,-0.098017,0.471397,0.881921,0.995185,0.773010,0.290285,-0.290285,-0.773010,-0.995185,-0.881921,-0.471397,0.098017,0.634393,0.956940,
0.956940,0.634393,0.098017,-0.471397,-0.881921,-0.995185,-0.773010,-0.290285,0.290285,0.773010,0.995185,0.881921,0.471397,-0.098017,-0.634393,-0.956940}, 0.956940,0.634393,0.098017,-0.471397,-0.881921,-0.995185,-0.773010,-0.290285,0.290285,0.773010,0.995185,0.881921,0.471397,-0.098017,-0.634393,-0.956940},
{-0.941544,-0.514103,0.146730,0.740951,0.998795,0.803208,0.242980,-0.427555,-0.903989,-0.970031,-0.595699,0.049068,0.671559,0.989177,0.857729,0.336890, {-0.941544,-0.514103,0.146730,0.740951,0.998795,0.803208,0.242980,-0.427555,-0.903989,-0.970031,-0.595699,0.049068,0.671559,0.989177,0.857729,0.336890,
-0.336890,-0.857729,-0.989177,-0.671559,-0.049068,0.595699,0.970031,0.903989,0.427555,-0.242980,-0.803208,-0.998795,-0.740951,-0.146730,0.514103,0.941544}, -0.336890,-0.857729,-0.989177,-0.671559,-0.049068,0.595699,0.970031,0.903989,0.427555,-0.242980,-0.803208,-0.998795,-0.740951,-0.146730,0.514103,0.941544},
{-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880, {-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,
-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880}, -0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880,-0.923880,-0.382683,0.382683,0.923880,0.923880,0.382683,-0.382683,-0.923880},
{-0.903989,-0.242980,0.595699,0.998795,0.671559,-0.146730,-0.857729,-0.941544,-0.336890,0.514103,0.989177,0.740951,-0.049068,-0.803208,-0.970031,-0.427555, {-0.903989,-0.242980,0.595699,0.998795,0.671559,-0.146730,-0.857729,-0.941544,-0.336890,0.514103,0.989177,0.740951,-0.049068,-0.803208,-0.970031,-0.427555,
0.427555,0.970031,0.803208,0.049068,-0.740951,-0.989177,-0.514103,0.336890,0.941544,0.857729,0.146730,-0.671559,-0.998795,-0.595699,0.242980,0.903989}, 0.427555,0.970031,0.803208,0.049068,-0.740951,-0.989177,-0.514103,0.336890,0.941544,0.857729,0.146730,-0.671559,-0.998795,-0.595699,0.242980,0.903989},
{-0.881921,-0.098017,0.773010,0.956940,0.290285,-0.634393,-0.995185,-0.471397,0.471397,0.995185,0.634393,-0.290285,-0.956940,-0.773010,0.098017,0.881921, {-0.881921,-0.098017,0.773010,0.956940,0.290285,-0.634393,-0.995185,-0.471397,0.471397,0.995185,0.634393,-0.290285,-0.956940,-0.773010,0.098017,0.881921,
0.881921,0.098017,-0.773010,-0.956940,-0.290285,0.634393,0.995185,0.471397,-0.471397,-0.995185,-0.634393,0.290285,0.956940,0.773010,-0.098017,-0.881921}, 0.881921,0.098017,-0.773010,-0.956940,-0.290285,0.634393,0.995185,0.471397,-0.471397,-0.995185,-0.634393,0.290285,0.956940,0.773010,-0.098017,-0.881921},
{-0.857729,0.049068,0.903989,0.803208,-0.146730,-0.941544,-0.740951,0.242980,0.970031,0.671559,-0.336890,-0.989177,-0.595699,0.427555,0.998795,0.514103, {-0.857729,0.049068,0.903989,0.803208,-0.146730,-0.941544,-0.740951,0.242980,0.970031,0.671559,-0.336890,-0.989177,-0.595699,0.427555,0.998795,0.514103,
-0.514103,-0.998795,-0.427555,0.595699,0.989177,0.336890,-0.671559,-0.970031,-0.242980,0.740951,0.941544,0.146730,-0.803208,-0.903989,-0.049068,0.857729}, -0.514103,-0.998795,-0.427555,0.595699,0.989177,0.336890,-0.671559,-0.970031,-0.242980,0.740951,0.941544,0.146730,-0.803208,-0.903989,-0.049068,0.857729},
{-0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470, {-0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470,
-0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470}, -0.831470,0.195090,0.980785,0.555570,-0.555570,-0.980785,-0.195090,0.831470,0.831470,-0.195090,-0.980785,-0.555570,0.555570,0.980785,0.195090,-0.831470},
{-0.803208,0.336890,0.998795,0.242980,-0.857729,-0.740951,0.427555,0.989177,0.146730,-0.903989,-0.671559,0.514103,0.970031,0.049068,-0.941544,-0.595699, {-0.803208,0.336890,0.998795,0.242980,-0.857729,-0.740951,0.427555,0.989177,0.146730,-0.903989,-0.671559,0.514103,0.970031,0.049068,-0.941544,-0.595699,
0.595699,0.941544,-0.049068,-0.970031,-0.514103,0.671559,0.903989,-0.146730,-0.989177,-0.427555,0.740951,0.857729,-0.242980,-0.998795,-0.336890,0.803208}, 0.595699,0.941544,-0.049068,-0.970031,-0.514103,0.671559,0.903989,-0.146730,-0.989177,-0.427555,0.740951,0.857729,-0.242980,-0.998795,-0.336890,0.803208},
{-0.773010,0.471397,0.956940,-0.098017,-0.995185,-0.290285,0.881921,0.634393,-0.634393,-0.881921,0.290285,0.995185,0.098017,-0.956940,-0.471397,0.773010, {-0.773010,0.471397,0.956940,-0.098017,-0.995185,-0.290285,0.881921,0.634393,-0.634393,-0.881921,0.290285,0.995185,0.098017,-0.956940,-0.471397,0.773010,
0.773010,-0.471397,-0.956940,0.098017,0.995185,0.290285,-0.881921,-0.634393,0.634393,0.881921,-0.290285,-0.995185,-0.098017,0.956940,0.471397,-0.773010}, 0.773010,-0.471397,-0.956940,0.098017,0.995185,0.290285,-0.881921,-0.634393,0.634393,0.881921,-0.290285,-0.995185,-0.098017,0.956940,0.471397,-0.773010},
{-0.740951,0.595699,0.857729,-0.427555,-0.941544,0.242980,0.989177,-0.049068,-0.998795,-0.146730,0.970031,0.336890,-0.903989,-0.514103,0.803208,0.671559, {-0.740951,0.595699,0.857729,-0.427555,-0.941544,0.242980,0.989177,-0.049068,-0.998795,-0.146730,0.970031,0.336890,-0.903989,-0.514103,0.803208,0.671559,
-0.671559,-0.803208,0.514103,0.903989,-0.336890,-0.970031,0.146730,0.998795,0.049068,-0.989177,-0.242980,0.941544,0.427555,-0.857729,-0.595699,0.740951} -0.671559,-0.803208,0.514103,0.903989,-0.336890,-0.970031,0.146730,0.998795,0.049068,-0.989177,-0.242980,0.941544,0.427555,-0.857729,-0.595699,0.740951}
}; };
// up to 32-bits // up to 32-bits
static unsigned jo_readBits(const unsigned char *data, int *at, int num) { static unsigned jo_readBits(const unsigned char *data, int *at, int num) {
unsigned r = 0; unsigned r = 0;
// read partial starting bits // read partial starting bits
int sc = (8 - (*at & 7)) & 7; int sc = (8 - (*at & 7)) & 7;
sc = sc > num ? num : sc; sc = sc > num ? num : sc;
if(sc) { if(sc) {
r = (data[*at/8] >> (8 - (*at&7) - sc)) & ((1<<sc)-1); r = (data[*at/8] >> (8 - (*at&7) - sc)) & ((1<<sc)-1);
num -= sc; num -= sc;
*at += sc; *at += sc;
} }
// read full bytes // read full bytes
while(num>=8) { while(num>=8) {
r <<= 8; r <<= 8;
r |= data[*at/8]; r |= data[*at/8];
*at += 8; *at += 8;
num -= 8; num -= 8;
} }
// read partial ending bits // read partial ending bits
if(num) { if(num) {
r <<= num; r <<= num;
r |= (data[*at/8] >> (8 - num)) & ((1<<num)-1); r |= (data[*at/8] >> (8 - num)) & ((1<<num)-1);
*at += num; *at += num;
} }
return r; return r;
} }
bool jo_read_mp1(const void *input, int inputSize, short **output_, int *outputSize_, int *hz_, int *channels_) { bool jo_read_mp1(const void *input, int inputSize, short **output_, int *outputSize_, int *hz_, int *channels_) {
int outputSize = 0, hz, channels; int outputSize = 0, hz, channels;
short *output = 0; short *output = 0;
int outputMax = 0; int outputMax = 0;
const unsigned char *data = (const unsigned char *)input; const unsigned char *data = (const unsigned char *)input;
// Buffers for the lapped transform // Buffers for the lapped transform
double buf[2][2 * 512] = { 0 }; double buf[2][2 * 512] = { 0 };
int bufOffset[2] = { 64,64 }; int bufOffset[2] = { 64,64 };
int at = 0; // Where in the stream are we? int at = 0; // Where in the stream are we?
while (at < inputSize * 8) { while (at < inputSize * 8) {
// Sync markers are byte aligned // Sync markers are byte aligned
at = (at + 7)&-8; at = (at + 7)&-8;
while (at < inputSize * 8 - 32) { while (at < inputSize * 8 - 32) {
if (data[at / 8] == 0xFF && (data[at / 8 + 1] & 0xF0) == 0xF0) { if (data[at / 8] == 0xFF && (data[at / 8 + 1] & 0xF0) == 0xF0) {
break; break;
} }
else { else {
at += 8; at += 8;
} }
} }
if (at >= inputSize * 8 - 32) { if (at >= inputSize * 8 - 32) {
break; break;
} }
unsigned header = jo_readBits(data, &at, 32); unsigned header = jo_readBits(data, &at, 32);
//printf("header: %x.%x/%x: %08x\n", (at-32)/8, (at-32)&7, inputSize, header); //printf("header: %x.%x/%x: %08x\n", (at-32)/8, (at-32)&7, inputSize, header);
// sync = 0xFFF // sync = 0xFFF
// ID = 1 // ID = 1
// layer = 3 (layer 1) // layer = 3 (layer 1)
if ((header & 0xFFFE0000) != 0xFFFE0000) { if ((header & 0xFFFE0000) != 0xFFFE0000) {
return false; return false;
} }
static const int bitrateTbl[16] = { 0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1 }; static const int bitrateTbl[16] = { 0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,-1 };
int kbps = bitrateTbl[(header >> 12) & 15]; int kbps = bitrateTbl[(header >> 12) & 15];
if (kbps < 0) { if (kbps < 0) {
return false; return false;
} }
static const int hzTbl[4] = { 44100, 48000, 32000, 0 }; static const int hzTbl[4] = { 44100, 48000, 32000, 0 };
hz = hzTbl[(header >> 10) & 3]; hz = hzTbl[(header >> 10) & 3];
if (!hz) { if (!hz) {
return false; return false;
} }
// mode 0 = stereo // mode 0 = stereo
// mode 1 = joint stereo // mode 1 = joint stereo
// mode 2 = dual channel (no idea what this does TODO) // mode 2 = dual channel (no idea what this does TODO)
// mode 3 = mono // mode 3 = mono
int mode = (header >> 6) & 3; int mode = (header >> 6) & 3;
int modeExt = (header >> 4) & 3; int modeExt = (header >> 4) & 3;
channels = mode == 3 ? 1 : 2; channels = mode == 3 ? 1 : 2;
const int bound = mode == 1 ? (modeExt + 1) * 4 : 32; const int bound = mode == 1 ? (modeExt + 1) * 4 : 32;
bool errorProtection = ((header >> 16) & 1) ^ 1; //< @r-lyeh extra parens bool errorProtection = ((header >> 16) & 1) ^ 1; //< @r-lyeh extra parens
if (errorProtection) { if (errorProtection) {
at += 16; // skip the CRC. at += 16; // skip the CRC.
} }
// Read bit allocations // Read bit allocations
int bitAlloc[32][2] = { 0 }; int bitAlloc[32][2] = { 0 };
for (int i = 0; i < bound; ++i) { for (int i = 0; i < bound; ++i) {
for (int ch = 0; ch < channels; ++ch) { for (int ch = 0; ch < channels; ++ch) {
bitAlloc[i][ch] = jo_readBits(data, &at, 4); bitAlloc[i][ch] = jo_readBits(data, &at, 4);
} }
} }
for (int i = bound; i < 32; ++i) { for (int i = bound; i < 32; ++i) {
bitAlloc[i][1] = bitAlloc[i][0] = jo_readBits(data, &at, 4); bitAlloc[i][1] = bitAlloc[i][0] = jo_readBits(data, &at, 4);
} }
// Read scale indexes // Read scale indexes
int scaleIdx[32][2]; int scaleIdx[32][2];
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i) {
for (int ch = 0; ch < channels; ++ch) { for (int ch = 0; ch < channels; ++ch) {
scaleIdx[i][ch] = bitAlloc[i][ch] ? jo_readBits(data, &at, 6) : 63; scaleIdx[i][ch] = bitAlloc[i][ch] ? jo_readBits(data, &at, 6) : 63;
} }
} }
// Read & compute output samples // Read & compute output samples
short pcm[12][2][32]; short pcm[12][2][32];
for (int s = 0; s < 12; ++s) { for (int s = 0; s < 12; ++s) {
// Read normalized, quantized band samples // Read normalized, quantized band samples
int samples[32][2] = { 0 }; int samples[32][2] = { 0 };
for (int i = 0; i < bound; ++i) { for (int i = 0; i < bound; ++i) {
for (int ch = 0; ch < channels; ++ch) { for (int ch = 0; ch < channels; ++ch) {
if (bitAlloc[i][ch]) { if (bitAlloc[i][ch]) {
samples[i][ch] = jo_readBits(data, &at, bitAlloc[i][ch] + 1); samples[i][ch] = jo_readBits(data, &at, bitAlloc[i][ch] + 1);
} }
} }
} }
for (int i = bound; i < 32; ++i) { for (int i = bound; i < 32; ++i) {
if (bitAlloc[i][0]) { if (bitAlloc[i][0]) {
samples[i][1] = samples[i][0] = jo_readBits(data, &at, bitAlloc[i][0] + 1); samples[i][1] = samples[i][0] = jo_readBits(data, &at, bitAlloc[i][0] + 1);
} }
} }
// Compute bands: Dequantize & Denormalize // Compute bands: Dequantize & Denormalize
double bandTbl[2][32] = { 0 }; double bandTbl[2][32] = { 0 };
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i) {
for (int ch = 0; ch < channels; ++ch) { for (int ch = 0; ch < channels; ++ch) {
int b = bitAlloc[i][ch]; int b = bitAlloc[i][ch];
if (b++) { if (b++) {
int samp = samples[i][ch]; int samp = samples[i][ch];
double f = ((samp >> (b - 1)) & 1) ? 0 : -1; double f = ((samp >> (b - 1)) & 1) ? 0 : -1;
f += (samp & ((1 << (b - 1)) - 1)) / (double)(1 << (b - 1)); f += (samp & ((1 << (b - 1)) - 1)) / (double)(1 << (b - 1));
f = (f + 1.0 / (1 << (b - 1))) * (1 << b) / ((1 << b) - 1.0); f = (f + 1.0 / (1 << (b - 1))) * (1 << b) / ((1 << b) - 1.0);
f *= s_jo_multTbl[scaleIdx[i][ch]]; f *= s_jo_multTbl[scaleIdx[i][ch]];
bandTbl[ch][i] = f; bandTbl[ch][i] = f;
} }
} }
} }
// Convert subbands to PCM // Convert subbands to PCM
for (int ch = 0; ch < channels; ++ch) { for (int ch = 0; ch < channels; ++ch) {
bufOffset[ch] = (bufOffset[ch] + 0x3C0) & 0x3ff; bufOffset[ch] = (bufOffset[ch] + 0x3C0) & 0x3ff;
double *bufOffsetPtr = buf[ch] + bufOffset[ch]; double *bufOffsetPtr = buf[ch] + bufOffset[ch];
const double *f = s_jo_filterTbl[0]; const double *f = s_jo_filterTbl[0];
for (int i = 0; i < 64; ++i) { for (int i = 0; i < 64; ++i) {
double sum = 0; double sum = 0;
for (int j = 0; j < 32; ++j) { for (int j = 0; j < 32; ++j) {
sum += *f++ * bandTbl[ch][j]; sum += *f++ * bandTbl[ch][j];
} }
bufOffsetPtr[i] = sum; bufOffsetPtr[i] = sum;
} }
const double *w = s_jo_windowTbl; const double *w = s_jo_windowTbl;
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i) {
double sum = 0; double sum = 0;
for (int j = 0; j < 16; ++j) { for (int j = 0; j < 16; ++j) {
int k = i | (j + (j + 1 & -2)) << 5; int k = i | (j + (j + 1 & -2)) << 5;
sum += *w++ * buf[ch][(k + bufOffset[ch]) & 0x3ff]; sum += *w++ * buf[ch][(k + bufOffset[ch]) & 0x3ff];
} }
int ss = (int)(sum * 0x8000); int ss = (int)(sum * 0x8000);
ss = ss > SHRT_MAX ? SHRT_MAX : ss < SHRT_MIN ? SHRT_MIN : ss; ss = ss > SHRT_MAX ? SHRT_MAX : ss < SHRT_MIN ? SHRT_MIN : ss;
pcm[s][ch][i] = ss; pcm[s][ch][i] = ss;
} }
} }
} }
if (at > inputSize * 8) { if (at > inputSize * 8) {
printf("file corruption?\n"); printf("file corruption?\n");
return false; return false;
} }
if (outputMax == 0) { if (outputMax == 0) {
// estimate total number of samples (may be totally wrong, but its better than nothing) // estimate total number of samples (may be totally wrong, but its better than nothing)
at = (at + 7)&-8; at = (at + 7)&-8;
outputMax = inputSize / (at / 8) * 384 * channels * sizeof(*output); outputMax = inputSize / (at / 8) * 384 * channels * sizeof(*output);
output = (short*)REALLOC(output, outputMax); output = (short*)REALLOC(output, outputMax);
} }
if (outputSize * sizeof(*output) + 384 * channels * sizeof(*output) > outputMax) { if (outputSize * sizeof(*output) + 384 * channels * sizeof(*output) > outputMax) {
outputMax += 384 * channels * sizeof(*output); outputMax += 384 * channels * sizeof(*output);
output = (short*)REALLOC(output, outputMax); output = (short*)REALLOC(output, outputMax);
} }
for (int i = 0; i < 12; ++i) { for (int i = 0; i < 12; ++i) {
for (int j = 0; j < 32; ++j) { for (int j = 0; j < 32; ++j) {
for (int k = 0; k < channels; ++k) { for (int k = 0; k < channels; ++k) {
output[outputSize++] = pcm[i][k][j]; output[outputSize++] = pcm[i][k][j];
} }
} }
} }
} }
*outputSize_ = outputSize; *outputSize_ = outputSize;
*hz_ = hz; *hz_ = hz;
*channels_ = channels; *channels_ = channels;
*output_ = output; *output_ = output;
return outputSize && hz && channels && output; return outputSize && hz && channels && output;
} }
#endif // JO_MP1_HEADER_FILE_ONLY #endif // JO_MP1_HEADER_FILE_ONLY

View File

@ -1,264 +1,264 @@
/* public domain Simple, Minimalistic, No Allocations MPEG writer - http://jonolick.com /* public domain Simple, Minimalistic, No Allocations MPEG writer - http://jonolick.com
* *
* Latest revisions: * Latest revisions:
* 1.02c rgbx -> bgrx channel swap && vertical image flip && userdef components (@r-lyeh) * 1.02c rgbx -> bgrx channel swap && vertical image flip && userdef components (@r-lyeh)
* 1.02 (22-03-2017) Fixed AC encoding bug. * 1.02 (22-03-2017) Fixed AC encoding bug.
* Fixed color space bug (thx r- lyeh!) * Fixed color space bug (thx r- lyeh!)
* 1.01 (18-10-2016) warning fixes * 1.01 (18-10-2016) warning fixes
* 1.00 (25-09-2016) initial release * 1.00 (25-09-2016) initial release
* *
* Basic usage: * Basic usage:
* char *frame = new char[width*height*4]; // 4 component. bgrx format, where X is unused * char *frame = new char[width*height*4]; // 4 component. bgrx format, where X is unused
* FILE *fp = fopen("foo.mpg", "wb"); * FILE *fp = fopen("foo.mpg", "wb");
* jo_write_mpeg(fp, frame, width, height, 60); // frame 0 * jo_write_mpeg(fp, frame, width, height, 60); // frame 0
* jo_write_mpeg(fp, frame, width, height, 60); // frame 1 * jo_write_mpeg(fp, frame, width, height, 60); // frame 1
* jo_write_mpeg(fp, frame, width, height, 60); // frame 2 * jo_write_mpeg(fp, frame, width, height, 60); // frame 2
* ... * ...
* fclose(fp); * fclose(fp);
* *
* Notes: * Notes:
* Only supports 24, 25, 30, 50, or 60 fps * Only supports 24, 25, 30, 50, or 60 fps
* *
* I don't know if decoders support changing of fps, or dimensions for each frame. * I don't know if decoders support changing of fps, or dimensions for each frame.
* Movie players *should* support it as the spec allows it, but ... * Movie players *should* support it as the spec allows it, but ...
* *
* MPEG-1/2 currently has no active patents as far as I am aware. * MPEG-1/2 currently has no active patents as far as I am aware.
* *
* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html * http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html
* http://www.cs.cornell.edu/dali/api/mpegvideo-c.html * http://www.cs.cornell.edu/dali/api/mpegvideo-c.html
* */ * */
#ifndef JO_INCLUDE_MPEG_H #ifndef JO_INCLUDE_MPEG_H
#define JO_INCLUDE_MPEG_H #define JO_INCLUDE_MPEG_H
#include <stdio.h> #include <stdio.h>
// To get a header file for this, either cut and paste the header, // To get a header file for this, either cut and paste the header,
// or create jo_mpeg.h, #define JO_MPEG_HEADER_FILE_ONLY, and // or create jo_mpeg.h, #define JO_MPEG_HEADER_FILE_ONLY, and
// then include jo_mpeg.c from it. // then include jo_mpeg.c from it.
// Returns false on failure // Returns false on failure
extern void jo_write_mpeg(FILE *fp, const unsigned char *bgrx, int width, int height, int fps); extern void jo_write_mpeg(FILE *fp, const unsigned char *bgrx, int width, int height, int fps);
#endif // JO_INCLUDE_MPEG_H #endif // JO_INCLUDE_MPEG_H
#ifndef JO_MPEG_HEADER_FILE_ONLY #ifndef JO_MPEG_HEADER_FILE_ONLY
#ifndef JO_MPEG_COMPONENTS #ifndef JO_MPEG_COMPONENTS
#define JO_MPEG_COMPONENTS 4 #define JO_MPEG_COMPONENTS 4
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include <memory.h> #include <memory.h>
// Huffman tables // Huffman tables
static const unsigned char s_jo_HTDC_Y[9][2] = {{4,3}, {0,2}, {1,2}, {5,3}, {6,3}, {14,4}, {30,5}, {62,6}, {126,7}}; static const unsigned char s_jo_HTDC_Y[9][2] = {{4,3}, {0,2}, {1,2}, {5,3}, {6,3}, {14,4}, {30,5}, {62,6}, {126,7}};
static const unsigned char s_jo_HTDC_C[9][2] = {{0,2}, {1,2}, {2,2}, {6,3}, {14,4}, {30,5}, {62,6}, {126,7}, {254,8}}; static const unsigned char s_jo_HTDC_C[9][2] = {{0,2}, {1,2}, {2,2}, {6,3}, {14,4}, {30,5}, {62,6}, {126,7}, {254,8}};
static const unsigned char s_jo_HTAC[32][40][2] = { static const unsigned char s_jo_HTAC[32][40][2] = {
{{6,3},{8,5},{10,6},{12,8},{76,9},{66,9},{20,11},{58,13},{48,13},{38,13},{32,13},{52,14},{50,14},{48,14},{46,14},{62,15},{62,15},{58,15},{56,15},{54,15},{52,15},{50,15},{48,15},{46,15},{44,15},{42,15},{40,15},{38,15},{36,15},{34,15},{32,15},{48,16},{46,16},{44,16},{42,16},{40,16},{38,16},{36,16},{34,16},{32,16},}, {{6,3},{8,5},{10,6},{12,8},{76,9},{66,9},{20,11},{58,13},{48,13},{38,13},{32,13},{52,14},{50,14},{48,14},{46,14},{62,15},{62,15},{58,15},{56,15},{54,15},{52,15},{50,15},{48,15},{46,15},{44,15},{42,15},{40,15},{38,15},{36,15},{34,15},{32,15},{48,16},{46,16},{44,16},{42,16},{40,16},{38,16},{36,16},{34,16},{32,16},},
{{6,4},{12,7},{74,9},{24,11},{54,13},{44,14},{42,14},{62,16},{60,16},{58,16},{56,16},{54,16},{52,16},{50,16},{38,17},{36,17},{34,17},{32,17}}, {{6,4},{12,7},{74,9},{24,11},{54,13},{44,14},{42,14},{62,16},{60,16},{58,16},{56,16},{54,16},{52,16},{50,16},{38,17},{36,17},{34,17},{32,17}},
{{10,5},{8,8},{22,11},{40,13},{40,14}}, {{10,5},{8,8},{22,11},{40,13},{40,14}},
{{14,6},{72,9},{56,13},{38,14}}, {{14,6},{72,9},{56,13},{38,14}},
{{12,6},{30,11},{36,13}}, {{14,7},{18,11},{36,14}}, {{10,7},{60,13},{40,17}}, {{12,6},{30,11},{36,13}}, {{14,7},{18,11},{36,14}}, {{10,7},{60,13},{40,17}},
{{8,7},{42,13}}, {{14,8},{34,13}}, {{10,8},{34,14}}, {{78,9},{32,14}}, {{70,9},{52,17}}, {{68,9},{50,17}}, {{64,9},{48,17}}, {{28,11},{46,17}}, {{26,11},{44,17}}, {{16,11},{42,17}}, {{8,7},{42,13}}, {{14,8},{34,13}}, {{10,8},{34,14}}, {{78,9},{32,14}}, {{70,9},{52,17}}, {{68,9},{50,17}}, {{64,9},{48,17}}, {{28,11},{46,17}}, {{26,11},{44,17}}, {{16,11},{42,17}},
{{62,13}}, {{52,13}}, {{50,13}}, {{46,13}}, {{44,13}}, {{62,14}}, {{60,14}}, {{58,14}}, {{56,14}}, {{54,14}}, {{62,17}}, {{60,17}}, {{58,17}}, {{56,17}}, {{54,17}}, {{62,13}}, {{52,13}}, {{50,13}}, {{46,13}}, {{44,13}}, {{62,14}}, {{60,14}}, {{58,14}}, {{56,14}}, {{54,14}}, {{62,17}}, {{60,17}}, {{58,17}}, {{56,17}}, {{54,17}},
}; };
static const float s_jo_quantTbl[64] = { static const float s_jo_quantTbl[64] = {
0.015625f,0.005632f,0.005035f,0.004832f,0.004808f,0.005892f,0.007964f,0.013325f, 0.015625f,0.005632f,0.005035f,0.004832f,0.004808f,0.005892f,0.007964f,0.013325f,
0.005632f,0.004061f,0.003135f,0.003193f,0.003338f,0.003955f,0.004898f,0.008828f, 0.005632f,0.004061f,0.003135f,0.003193f,0.003338f,0.003955f,0.004898f,0.008828f,
0.005035f,0.003135f,0.002816f,0.003013f,0.003299f,0.003581f,0.005199f,0.009125f, 0.005035f,0.003135f,0.002816f,0.003013f,0.003299f,0.003581f,0.005199f,0.009125f,
0.004832f,0.003484f,0.003129f,0.003348f,0.003666f,0.003979f,0.005309f,0.009632f, 0.004832f,0.003484f,0.003129f,0.003348f,0.003666f,0.003979f,0.005309f,0.009632f,
0.005682f,0.003466f,0.003543f,0.003666f,0.003906f,0.004546f,0.005774f,0.009439f, 0.005682f,0.003466f,0.003543f,0.003666f,0.003906f,0.004546f,0.005774f,0.009439f,
0.006119f,0.004248f,0.004199f,0.004228f,0.004546f,0.005062f,0.006124f,0.009942f, 0.006119f,0.004248f,0.004199f,0.004228f,0.004546f,0.005062f,0.006124f,0.009942f,
0.008883f,0.006167f,0.006096f,0.005777f,0.006078f,0.006391f,0.007621f,0.012133f, 0.008883f,0.006167f,0.006096f,0.005777f,0.006078f,0.006391f,0.007621f,0.012133f,
0.016780f,0.011263f,0.009907f,0.010139f,0.009849f,0.010297f,0.012133f,0.019785f, 0.016780f,0.011263f,0.009907f,0.010139f,0.009849f,0.010297f,0.012133f,0.019785f,
}; };
static const unsigned char s_jo_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; static const unsigned char s_jo_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };
typedef struct { typedef struct {
FILE *fp; FILE *fp;
int buf, cnt; int buf, cnt;
} jo_bits_t; } jo_bits_t;
static void jo_writeBits(jo_bits_t *b, int value, int count) { static void jo_writeBits(jo_bits_t *b, int value, int count) {
b->cnt += count; b->cnt += count;
b->buf |= value << (24 - b->cnt); b->buf |= value << (24 - b->cnt);
while(b->cnt >= 8) { while(b->cnt >= 8) {
unsigned char c = (b->buf >> 16) & 255; unsigned char c = (b->buf >> 16) & 255;
putc(c, b->fp); putc(c, b->fp);
b->buf <<= 8; b->buf <<= 8;
b->cnt -= 8; b->cnt -= 8;
} }
} }
static void jo_DCT(float *d0, float *d1, float *d2, float *d3, float *d4, float *d5, float *d6, float *d7) { static void jo_DCT(float *d0, float *d1, float *d2, float *d3, float *d4, float *d5, float *d6, float *d7) {
float tmp0 = *d0 + *d7; float tmp0 = *d0 + *d7;
float tmp7 = *d0 - *d7; float tmp7 = *d0 - *d7;
float tmp1 = *d1 + *d6; float tmp1 = *d1 + *d6;
float tmp6 = *d1 - *d6; float tmp6 = *d1 - *d6;
float tmp2 = *d2 + *d5; float tmp2 = *d2 + *d5;
float tmp5 = *d2 - *d5; float tmp5 = *d2 - *d5;
float tmp3 = *d3 + *d4; float tmp3 = *d3 + *d4;
float tmp4 = *d3 - *d4; float tmp4 = *d3 - *d4;
// Even part // Even part
float tmp10 = tmp0 + tmp3; // phase 2 float tmp10 = tmp0 + tmp3; // phase 2
float tmp13 = tmp0 - tmp3; float tmp13 = tmp0 - tmp3;
float tmp11 = tmp1 + tmp2; float tmp11 = tmp1 + tmp2;
float tmp12 = tmp1 - tmp2; float tmp12 = tmp1 - tmp2;
*d0 = tmp10 + tmp11; // phase 3 *d0 = tmp10 + tmp11; // phase 3
*d4 = tmp10 - tmp11; *d4 = tmp10 - tmp11;
float z1 = (tmp12 + tmp13) * 0.707106781f; // c4 float z1 = (tmp12 + tmp13) * 0.707106781f; // c4
*d2 = tmp13 + z1; // phase 5 *d2 = tmp13 + z1; // phase 5
*d6 = tmp13 - z1; *d6 = tmp13 - z1;
// Odd part // Odd part
tmp10 = tmp4 + tmp5; // phase 2 tmp10 = tmp4 + tmp5; // phase 2
tmp11 = tmp5 + tmp6; tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7; tmp12 = tmp6 + tmp7;
// The rotator is modified from fig 4-8 to avoid extra negations. // The rotator is modified from fig 4-8 to avoid extra negations.
float z5 = (tmp10 - tmp12) * 0.382683433f; // c6 float z5 = (tmp10 - tmp12) * 0.382683433f; // c6
float z2 = tmp10 * 0.541196100f + z5; // c2-c6 float z2 = tmp10 * 0.541196100f + z5; // c2-c6
float z4 = tmp12 * 1.306562965f + z5; // c2+c6 float z4 = tmp12 * 1.306562965f + z5; // c2+c6
float z3 = tmp11 * 0.707106781f; // c4 float z3 = tmp11 * 0.707106781f; // c4
float z11 = tmp7 + z3; // phase 5 float z11 = tmp7 + z3; // phase 5
float z13 = tmp7 - z3; float z13 = tmp7 - z3;
*d5 = z13 + z2; // phase 6 *d5 = z13 + z2; // phase 6
*d3 = z13 - z2; *d3 = z13 - z2;
*d1 = z11 + z4; *d1 = z11 + z4;
*d7 = z11 - z4; *d7 = z11 - z4;
} }
static int jo_processDU(jo_bits_t *bits, float A[64], const unsigned char htdc[9][2], int DC) { static int jo_processDU(jo_bits_t *bits, float A[64], const unsigned char htdc[9][2], int DC) {
for(int dataOff=0; dataOff<64; dataOff+=8) { for(int dataOff=0; dataOff<64; dataOff+=8) {
jo_DCT(&A[dataOff], &A[dataOff+1], &A[dataOff+2], &A[dataOff+3], &A[dataOff+4], &A[dataOff+5], &A[dataOff+6], &A[dataOff+7]); jo_DCT(&A[dataOff], &A[dataOff+1], &A[dataOff+2], &A[dataOff+3], &A[dataOff+4], &A[dataOff+5], &A[dataOff+6], &A[dataOff+7]);
} }
for(int dataOff=0; dataOff<8; ++dataOff) { for(int dataOff=0; dataOff<8; ++dataOff) {
jo_DCT(&A[dataOff], &A[dataOff+8], &A[dataOff+16], &A[dataOff+24], &A[dataOff+32], &A[dataOff+40], &A[dataOff+48], &A[dataOff+56]); jo_DCT(&A[dataOff], &A[dataOff+8], &A[dataOff+16], &A[dataOff+24], &A[dataOff+32], &A[dataOff+40], &A[dataOff+48], &A[dataOff+56]);
} }
int Q[64]; int Q[64];
for(int i=0; i<64; ++i) { for(int i=0; i<64; ++i) {
float v = A[i]*s_jo_quantTbl[i]; float v = A[i]*s_jo_quantTbl[i];
Q[s_jo_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); Q[s_jo_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
} }
DC = Q[0] - DC; DC = Q[0] - DC;
int aDC = DC < 0 ? -DC : DC; int aDC = DC < 0 ? -DC : DC;
int size = 0; int size = 0;
int tempval = aDC; int tempval = aDC;
while(tempval) { while(tempval) {
size++; size++;
tempval >>= 1; tempval >>= 1;
} }
jo_writeBits(bits, htdc[size][0], htdc[size][1]); jo_writeBits(bits, htdc[size][0], htdc[size][1]);
if(DC < 0) aDC ^= (1 << size) - 1; if(DC < 0) aDC ^= (1 << size) - 1;
jo_writeBits(bits, aDC, size); jo_writeBits(bits, aDC, size);
int endpos = 63; int endpos = 63;
for(; (endpos>0)&&(Q[endpos]==0); --endpos) { /* do nothing */ } for(; (endpos>0)&&(Q[endpos]==0); --endpos) { /* do nothing */ }
for(int i = 1; i <= endpos;) { for(int i = 1; i <= endpos;) {
int run = 0; int run = 0;
while (Q[i]==0 && i<endpos) { while (Q[i]==0 && i<endpos) {
++run; ++run;
++i; ++i;
} }
int AC = Q[i++]; int AC = Q[i++];
int aAC = AC < 0 ? -AC : AC; int aAC = AC < 0 ? -AC : AC;
int code = 0, size = 0; int code = 0, size = 0;
if (run<32 && aAC<=40) { if (run<32 && aAC<=40) {
code = s_jo_HTAC[run][aAC-1][0]; code = s_jo_HTAC[run][aAC-1][0];
size = s_jo_HTAC[run][aAC-1][1]; size = s_jo_HTAC[run][aAC-1][1];
if (AC < 0) code += 1; if (AC < 0) code += 1;
} }
if(!size) { if(!size) {
jo_writeBits(bits, 1, 6); jo_writeBits(bits, 1, 6);
jo_writeBits(bits, run, 6); jo_writeBits(bits, run, 6);
if (AC < -127) { if (AC < -127) {
jo_writeBits(bits, 128, 8); jo_writeBits(bits, 128, 8);
} else if(AC > 127) { } else if(AC > 127) {
jo_writeBits(bits, 0, 8); jo_writeBits(bits, 0, 8);
} }
code = AC&255; code = AC&255;
size = 8; size = 8;
} }
jo_writeBits(bits, code, size); jo_writeBits(bits, code, size);
} }
jo_writeBits(bits, 2, 2); jo_writeBits(bits, 2, 2);
return Q[0]; return Q[0];
} }
void jo_write_mpeg(FILE *fp, const unsigned char *bgrx, int width, int height, int fps) { void jo_write_mpeg(FILE *fp, const unsigned char *bgrx, int width, int height, int fps) {
int lastDCY = 128, lastDCCR = 128, lastDCCB = 128; int lastDCY = 128, lastDCCR = 128, lastDCCB = 128;
jo_bits_t bits = {fp}; jo_bits_t bits = {fp};
// Sequence Header // Sequence Header
fwrite("\x00\x00\x01\xB3", 4, 1, fp); fwrite("\x00\x00\x01\xB3", 4, 1, fp);
// 12 bits for width, height // 12 bits for width, height
putc((width>>4)&0xFF, fp); putc((width>>4)&0xFF, fp);
putc(((width&0xF)<<4) | ((height>>8) & 0xF), fp); putc(((width&0xF)<<4) | ((height>>8) & 0xF), fp);
putc(height & 0xFF, fp); putc(height & 0xFF, fp);
// aspect ratio, framerate // aspect ratio, framerate
if(fps <= 24) putc(0x12, fp); if(fps <= 24) putc(0x12, fp);
else if(fps <= 25) putc(0x13, fp); else if(fps <= 25) putc(0x13, fp);
else if(fps <= 30) putc(0x15, fp); else if(fps <= 30) putc(0x15, fp);
else if(fps <= 50) putc(0x16, fp); else if(fps <= 50) putc(0x16, fp);
else putc(0x18, fp); // 60fps else putc(0x18, fp); // 60fps
fwrite("\xFF\xFF\xE0\xA0", 4, 1, fp); fwrite("\xFF\xFF\xE0\xA0", 4, 1, fp);
fwrite("\x00\x00\x01\xB8\x80\x08\x00\x40", 8, 1, fp); // GOP header fwrite("\x00\x00\x01\xB8\x80\x08\x00\x40", 8, 1, fp); // GOP header
fwrite("\x00\x00\x01\x00\x00\x0C\x00\x00", 8, 1, fp); // PIC header fwrite("\x00\x00\x01\x00\x00\x0C\x00\x00", 8, 1, fp); // PIC header
fwrite("\x00\x00\x01\x01", 4, 1, fp); // Slice header fwrite("\x00\x00\x01\x01", 4, 1, fp); // Slice header
jo_writeBits(&bits, 0x10, 6); jo_writeBits(&bits, 0x10, 6);
for (int vblock=0; vblock<(height+15)/16; vblock++) { for (int vblock=0; vblock<(height+15)/16; vblock++) {
for (int hblock=0; hblock<(width+15)/16; hblock++) { for (int hblock=0; hblock<(width+15)/16; hblock++) {
jo_writeBits(&bits, 3, 2); jo_writeBits(&bits, 3, 2);
float Y[256], CBx[256], CRx[256]; float Y[256], CBx[256], CRx[256];
for (int i=0; i<256; ++i) { for (int i=0; i<256; ++i) {
int y = vblock*16+(i/16); int y = vblock*16+(i/16);
int x = hblock*16+(i&15); int x = hblock*16+(i&15);
x = x >= width ? width-1 : x; x = x >= width ? width-1 : x;
y = y >= height ? height-1 : y; y = y >= height ? height-1 : y;
int _4 = JO_MPEG_COMPONENTS; int _4 = JO_MPEG_COMPONENTS;
// const unsigned char *c = bgrx + y*width*_4+x*_4; // original // const unsigned char *c = bgrx + y*width*_4+x*_4; // original
const unsigned char *c = bgrx + ((height-1)-y)*width*_4+x*_4; // flipped const unsigned char *c = bgrx + ((height-1)-y)*width*_4+x*_4; // flipped
float b = c[0], g = c[1], r = c[2]; // channel swap float b = c[0], g = c[1], r = c[2]; // channel swap
Y[i] = ( 0.299f*r + 0.587f*g + 0.114f*b) * (219.f/255) + 16; Y[i] = ( 0.299f*r + 0.587f*g + 0.114f*b) * (219.f/255) + 16;
CBx[i] = (-0.299f*r - 0.587f*g + 0.886f*b) * (224.f/255) + 128; CBx[i] = (-0.299f*r - 0.587f*g + 0.886f*b) * (224.f/255) + 128;
CRx[i] = ( 0.701f*r - 0.587f*g - 0.114f*b) * (224.f/255) + 128; CRx[i] = ( 0.701f*r - 0.587f*g - 0.114f*b) * (224.f/255) + 128;
} }
// Downsample Cb,Cr (420 format) // Downsample Cb,Cr (420 format)
float CB[64], CR[64]; float CB[64], CR[64];
for (int i=0; i<64; ++i) { for (int i=0; i<64; ++i) {
int j =(i&7)*2 + (i&56)*4; int j =(i&7)*2 + (i&56)*4;
CB[i] = (CBx[j] + CBx[j+1] + CBx[j+16] + CBx[j+17]) * 0.25f; CB[i] = (CBx[j] + CBx[j+1] + CBx[j+16] + CBx[j+17]) * 0.25f;
CR[i] = (CRx[j] + CRx[j+1] + CRx[j+16] + CRx[j+17]) * 0.25f; CR[i] = (CRx[j] + CRx[j+1] + CRx[j+16] + CRx[j+17]) * 0.25f;
} }
for (int k1=0; k1<2; ++k1) { for (int k1=0; k1<2; ++k1) {
for (int k2=0; k2<2; ++k2) { for (int k2=0; k2<2; ++k2) {
float block[64]; float block[64];
for (int i=0; i<64; i+=8) { for (int i=0; i<64; i+=8) {
int j = (i&7)+(i&56)*2 + k1*8*16 + k2*8; int j = (i&7)+(i&56)*2 + k1*8*16 + k2*8;
memcpy(block+i, Y+j, 8*sizeof(Y[0])); memcpy(block+i, Y+j, 8*sizeof(Y[0]));
} }
lastDCY = jo_processDU(&bits, block, s_jo_HTDC_Y, lastDCY); lastDCY = jo_processDU(&bits, block, s_jo_HTDC_Y, lastDCY);
} }
} }
lastDCCB = jo_processDU(&bits, CB, s_jo_HTDC_C, lastDCCB); lastDCCB = jo_processDU(&bits, CB, s_jo_HTDC_C, lastDCCB);
lastDCCR = jo_processDU(&bits, CR, s_jo_HTDC_C, lastDCCR); lastDCCR = jo_processDU(&bits, CR, s_jo_HTDC_C, lastDCCR);
} }
} }
jo_writeBits(&bits, 0, 7); jo_writeBits(&bits, 0, 7);
fwrite("\x00\x00\x01\xb7", 4, 1, fp); // End of Sequence fwrite("\x00\x00\x01\xb7", 4, 1, fp); // End of Sequence
} }
#endif #endif

View File

@ -1,440 +1,440 @@
// JSON5 + SJSON parser module // JSON5 + SJSON parser module
// //
// License: // License:
// This software is dual-licensed to the public domain and under the following // This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify, // license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit. // publish, and distribute this file as you see fit.
// No warranty is implied, use at your own risk. // No warranty is implied, use at your own risk.
// //
// Credits: // Credits:
// r-lyeh (fork) // r-lyeh (fork)
// Dominik Madarasz (@zaklaus) (original code) // Dominik Madarasz (@zaklaus) (original code)
#ifndef JSON5_H #ifndef JSON5_H
#define JSON5_H #define JSON5_H
#ifndef JSON5_ASSERT #ifndef JSON5_ASSERT
#define JSON5_ASSERT do { printf("JSON5: Error L%d while parsing '%c' in '%.16s'\n", __LINE__, p[0], p); assert(0); } while(0) #define JSON5_ASSERT do { printf("JSON5: Error L%d while parsing '%c' in '%.16s'\n", __LINE__, p[0], p); assert(0); } while(0)
#endif #endif
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
typedef enum json5_type { typedef enum json5_type {
JSON5_UNDEFINED, // 0 JSON5_UNDEFINED, // 0
JSON5_NULL, // 1 JSON5_NULL, // 1
JSON5_BOOL, // 2 JSON5_BOOL, // 2
JSON5_OBJECT, // 3 JSON5_OBJECT, // 3
JSON5_STRING, // 4 JSON5_STRING, // 4
JSON5_ARRAY, // 5 JSON5_ARRAY, // 5
JSON5_INTEGER, // 6 JSON5_INTEGER, // 6
JSON5_REAL, // 7 JSON5_REAL, // 7
} json5_type; } json5_type;
typedef struct json5 { typedef struct json5 {
char* name; char* name;
#ifdef NDEBUG #ifdef NDEBUG
unsigned type : 3; unsigned type : 3;
#else #else
json5_type type; json5_type type;
#endif #endif
unsigned count : 29; unsigned count : 29;
union { union {
struct json5* array; struct json5* array;
struct json5* nodes; struct json5* nodes;
int64_t integer; int64_t integer;
double real; double real;
char* string; char* string;
int boolean; int boolean;
}; };
} json5; } json5;
char* json5_parse(json5 *root, char *source, int flags); char* json5_parse(json5 *root, char *source, int flags);
void json5_write(FILE *fp, const json5 *root); void json5_write(FILE *fp, const json5 *root);
void json5_free(json5 *root); void json5_free(json5 *root);
#endif // JSON5_H #endif // JSON5_H
// json5 ---------------------------------------------------------------------- // json5 ----------------------------------------------------------------------
#ifdef JSON5_C #ifdef JSON5_C
//#pragma once //#pragma once
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
char *json5__trim(char *p) { char *json5__trim(char *p) {
while (*p) { while (*p) {
/**/ if( isspace(*p) ) ++p; /**/ if( isspace(*p) ) ++p;
else if( p[0] == '/' && p[1] == '*' ) { // skip C comment else if( p[0] == '/' && p[1] == '*' ) { // skip C comment
for( p += 2; *p && !(p[0] == '*' && p[1] == '/'); ++p) {} for( p += 2; *p && !(p[0] == '*' && p[1] == '/'); ++p) {}
if( *p ) p += 2; if( *p ) p += 2;
} }
else if( p[0] == '/' && p[1] == '/' ) { // skip C++ comment else if( p[0] == '/' && p[1] == '/' ) { // skip C++ comment
for( p += 2; *p && p[0] != '\n'; ++p) {} for( p += 2; *p && p[0] != '\n'; ++p) {}
if( *p ) ++p; if( *p ) ++p;
} }
else break; else break;
} }
return p; return p;
} }
char *json5__parse_value(json5 *obj, char *p, char **err_code); char *json5__parse_value(json5 *obj, char *p, char **err_code);
char *json5__parse_string(json5 *obj, char *p, char **err_code) { char *json5__parse_string(json5 *obj, char *p, char **err_code) {
assert(obj && p); assert(obj && p);
if( *p == '"' || *p == '\'' || *p == '`' ) { if( *p == '"' || *p == '\'' || *p == '`' ) {
obj->type = JSON5_STRING; obj->type = JSON5_STRING;
obj->string = p + 1; obj->string = p + 1;
char eos_char = *p, *b = obj->string, *e = b; char eos_char = *p, *b = obj->string, *e = b;
while (*e) { while (*e) {
/**/ if( *e == '\\' && (e[1] == eos_char) ) ++e; /**/ if( *e == '\\' && (e[1] == eos_char) ) ++e;
else if( *e == '\\' && (e[1] == '\r' || e[1] == '\n') ) *e = ' '; else if( *e == '\\' && (e[1] == '\r' || e[1] == '\n') ) *e = ' ';
else if( *e == eos_char ) break; else if( *e == eos_char ) break;
++e; ++e;
} }
*e = '\0'; *e = '\0';
return p = e + 1; return p = e + 1;
} }
//JSON5_ASSERT; *err_code = "json5_error_invalid_value"; //JSON5_ASSERT; *err_code = "json5_error_invalid_value";
return NULL; return NULL;
} }
char *json5__parse_object(json5 *obj, char *p, char **err_code) { char *json5__parse_object(json5 *obj, char *p, char **err_code) {
assert(obj && p); assert(obj && p);
if( 1 /* *p == '{' */ ) { /* <-- for SJSON */ if( 1 /* *p == '{' */ ) { /* <-- for SJSON */
int skip = *p == '{'; /* <-- for SJSON */ int skip = *p == '{'; /* <-- for SJSON */
obj->type = JSON5_OBJECT; obj->type = JSON5_OBJECT;
obj->nodes = 0; obj->nodes = 0;
obj->count = 0; obj->count = 0;
while (*p) { while (*p) {
json5 node = { 0 }; json5 node = { 0 };
do { p = json5__trim(p + skip); skip = 1; } while( *p == ',' ); do { p = json5__trim(p + skip); skip = 1; } while( *p == ',' );
if( *p == '}' ) { if( *p == '}' ) {
++p; ++p;
break; break;
} }
// @todo: is_unicode() (s[0] == '\\' && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]))) { // @todo: is_unicode() (s[0] == '\\' && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) && isxdigit(s[4]))) {
else if( isalnum(*p) || *p == '_' || *p == '$' || *p == '.' ) { // also || is_unicode(p) else if( isalnum(*p) || *p == '_' || *p == '$' || *p == '.' ) { // also || is_unicode(p)
node.name = p; node.name = p;
do { do {
++p; ++p;
} while (*p && (isalnum(*p) || *p == '_' || *p == '$' || *p == '.') ); // also || is_unicode(p) } while (*p && (isalnum(*p) || *p == '_' || *p == '$' || *p == '.') ); // also || is_unicode(p)
char *e = p; char *e = p;
p = json5__trim(p); p = json5__trim(p);
*e = '\0'; *e = '\0';
} }
else { //if( *p == '"' || *p == '\'' || *p == '`' ) { else { //if( *p == '"' || *p == '\'' || *p == '`' ) {
char *ps = json5__parse_string(&node, p, err_code); char *ps = json5__parse_string(&node, p, err_code);
if( !ps ) { if( !ps ) {
return NULL; return NULL;
} }
p = ps; p = ps;
node.name = node.string; node.name = node.string;
p = json5__trim(p); p = json5__trim(p);
} }
// @todo: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6 // @todo: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6
if( !(node.name && node.name[0]) ) { // !json5__validate_name(node.name) ) { if( !(node.name && node.name[0]) ) { // !json5__validate_name(node.name) ) {
JSON5_ASSERT; *err_code = "json5_error_invalid_name"; JSON5_ASSERT; *err_code = "json5_error_invalid_name";
return NULL; return NULL;
} }
if( !p || (*p && (*p != ':' && *p != '=' /* <-- for SJSON */)) ) { if( !p || (*p && (*p != ':' && *p != '=' /* <-- for SJSON */)) ) {
JSON5_ASSERT; *err_code = "json5_error_invalid_name"; JSON5_ASSERT; *err_code = "json5_error_invalid_name";
return NULL; return NULL;
} }
p = json5__trim(p + 1); p = json5__trim(p + 1);
p = json5__parse_value(&node, p, err_code); p = json5__parse_value(&node, p, err_code);
if( *err_code[0] ) { if( *err_code[0] ) {
return NULL; return NULL;
} }
if( node.type != JSON5_UNDEFINED ) { if( node.type != JSON5_UNDEFINED ) {
array_push(obj->nodes, node); array_push(obj->nodes, node);
++obj->count; ++obj->count;
} }
if( *p == '}') { ++p; break; } if( *p == '}') { ++p; break; }
} }
return p; return p;
} }
JSON5_ASSERT; *err_code = "json5_error_invalid_value"; JSON5_ASSERT; *err_code = "json5_error_invalid_value";
return NULL; return NULL;
} }
char *json5__parse_value(json5 *obj, char *p, char **err_code) { char *json5__parse_value(json5 *obj, char *p, char **err_code) {
assert(obj && p); assert(obj && p);
p = json5__trim(p); p = json5__trim(p);
char *is_string = json5__parse_string(obj, p, err_code); char *is_string = json5__parse_string(obj, p, err_code);
if( is_string ) { if( is_string ) {
p = is_string; p = is_string;
if( *err_code[0] ) { if( *err_code[0] ) {
return NULL; return NULL;
} }
} }
else if( *p == '{' ) { else if( *p == '{' ) {
p = json5__parse_object( obj, p, err_code ); p = json5__parse_object( obj, p, err_code );
if( *err_code[0] ) { if( *err_code[0] ) {
return NULL; return NULL;
} }
} }
else if( *p == '[' ) { else if( *p == '[' ) {
obj->type = JSON5_ARRAY; obj->type = JSON5_ARRAY;
obj->array = 0; obj->array = 0;
obj->count = 0; obj->count = 0;
while (*p) { while (*p) {
json5 elem = { 0 }; json5 elem = { 0 };
do { p = json5__trim(p + 1); } while( *p == ',' ); do { p = json5__trim(p + 1); } while( *p == ',' );
if( *p == ']') { ++p; break; } if( *p == ']') { ++p; break; }
p = json5__parse_value(&elem, p, err_code); p = json5__parse_value(&elem, p, err_code);
if( *err_code[0] ) { if( *err_code[0] ) {
return NULL; return NULL;
} }
if( elem.type != JSON5_UNDEFINED ) { if( elem.type != JSON5_UNDEFINED ) {
array_push(obj->array, elem); array_push(obj->array, elem);
++obj->count; ++obj->count;
} }
if (*p == ']') { ++p; break; } if (*p == ']') { ++p; break; }
} }
} }
else if( isalpha(*p) || (*p == '-' && !isdigit(p[1])) ) { else if( isalpha(*p) || (*p == '-' && !isdigit(p[1])) ) {
const char *labels[] = { "null", "on","true", "off","false", "nan","NaN", "-nan","-NaN", "inf","Infinity", "-inf","-Infinity", 0 }; const char *labels[] = { "null", "on","true", "off","false", "nan","NaN", "-nan","-NaN", "inf","Infinity", "-inf","-Infinity", 0 };
const int lenghts[] = { 4, 2,4, 3,5, 3,3, 4,4, 3,8, 4,9 }; const int lenghts[] = { 4, 2,4, 3,5, 3,3, 4,4, 3,8, 4,9 };
for( int i = 0; labels[i]; ++i ) { for( int i = 0; labels[i]; ++i ) {
if( !strncmp(p, labels[i], lenghts[i] ) ) { if( !strncmp(p, labels[i], lenghts[i] ) ) {
p += lenghts[i]; p += lenghts[i];
#ifdef _MSC_VER // somehow, NaN is apparently signed in MSC #ifdef _MSC_VER // somehow, NaN is apparently signed in MSC
/**/ if( i >= 5 ) obj->type = JSON5_REAL, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ? NAN :-NAN; /**/ if( i >= 5 ) obj->type = JSON5_REAL, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ? NAN :-NAN;
#else #else
/**/ if( i >= 5 ) obj->type = JSON5_REAL, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ? -NAN : NAN; /**/ if( i >= 5 ) obj->type = JSON5_REAL, obj->real = i >= 11 ? -INFINITY : i >= 9 ? INFINITY : i >= 7 ? -NAN : NAN;
#endif #endif
else if( i >= 1 ) obj->type = JSON5_BOOL, obj->boolean = i <= 2; else if( i >= 1 ) obj->type = JSON5_BOOL, obj->boolean = i <= 2;
else obj->type = JSON5_NULL; else obj->type = JSON5_NULL;
break; break;
} }
} }
if( obj->type == JSON5_UNDEFINED ) { if( obj->type == JSON5_UNDEFINED ) {
JSON5_ASSERT; *err_code = "json5_error_invalid_value"; JSON5_ASSERT; *err_code = "json5_error_invalid_value";
return NULL; return NULL;
} }
} }
else if( isdigit(*p) || *p == '+' || *p == '-' || *p == '.' ) { else if( isdigit(*p) || *p == '+' || *p == '-' || *p == '.' ) {
char buffer[32] = {0}, *buf = buffer, is_hex = 0, is_dbl = 0; char buffer[32] = {0}, *buf = buffer, is_hex = 0, is_dbl = 0;
while( *p && strchr("+-.xX0123456789aAbBcCdDeEfF", *p)) { while( *p && strchr("+-.xX0123456789aAbBcCdDeEfF", *p)) {
is_hex |= (*p | 32) == 'x'; is_hex |= (*p | 32) == 'x';
is_dbl |= *p == '.'; is_dbl |= *p == '.';
*buf++ = *p++; *buf++ = *p++;
} }
obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER; obj->type = is_dbl ? JSON5_REAL : JSON5_INTEGER;
long long unsigned int llu; long long unsigned int llu;
long long int lli; long long int lli;
/**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real ); /**/ if( is_dbl ) sscanf( buffer, "%lf", &obj->real );
else if( is_hex ) sscanf( buffer, "%llx", &llu ), obj->integer = llu; // SCNx64 -> inttypes.h else if( is_hex ) sscanf( buffer, "%llx", &llu ), obj->integer = llu; // SCNx64 -> inttypes.h
else sscanf( buffer, "%lld", &lli ), obj->integer = lli; // SCNd64 -> inttypes.h else sscanf( buffer, "%lld", &lli ), obj->integer = lli; // SCNd64 -> inttypes.h
} }
else { else {
return NULL; return NULL;
} }
return p; return p;
} }
char *json5_parse(json5 *root, char *p, int flags) { char *json5_parse(json5 *root, char *p, int flags) {
char *err_code = ""; char *err_code = "";
*root = (json5) {0}; *root = (json5) {0};
if( p && p[0] ) { if( p && p[0] ) {
p = json5__trim(p); p = json5__trim(p);
if( *p == '[' ) { /* <-- for SJSON */ if( *p == '[' ) { /* <-- for SJSON */
json5__parse_value(root, p, &err_code); json5__parse_value(root, p, &err_code);
} else { } else {
json5__parse_object(root, p, &err_code); /* <-- for SJSON */ json5__parse_object(root, p, &err_code); /* <-- for SJSON */
} }
} else { } else {
root->type = JSON5_OBJECT; root->type = JSON5_OBJECT;
} }
return err_code[0] ? err_code : 0; return err_code[0] ? err_code : 0;
} }
void json5_free(json5 *root) { void json5_free(json5 *root) {
if( root->type == JSON5_ARRAY && root->array ) { if( root->type == JSON5_ARRAY && root->array ) {
for( int i = 0, cnt = array_count(root->array); i < cnt; ++i ) { for( int i = 0, cnt = array_count(root->array); i < cnt; ++i ) {
json5_free(root->array + i); json5_free(root->array + i);
} }
array_free(root->array); array_free(root->array);
} }
if( root->type == JSON5_OBJECT && root->nodes ) { if( root->type == JSON5_OBJECT && root->nodes ) {
for( int i = 0, cnt = array_count(root->nodes); i < cnt; ++i ) { for( int i = 0, cnt = array_count(root->nodes); i < cnt; ++i ) {
json5_free(root->nodes + i); json5_free(root->nodes + i);
} }
array_free(root->nodes); array_free(root->nodes);
} }
*root = (json5) {0}; // needed? *root = (json5) {0}; // needed?
} }
void json5_write(FILE *fp, const json5 *o) { void json5_write(FILE *fp, const json5 *o) {
static __thread int indent = 0; static __thread int indent = 0;
int tabs = 1; // 0,1,2,4,8 int tabs = 1; // 0,1,2,4,8
if( o->name ) { if( o->name ) {
fprintf(fp, "%*.s\"%s\"%s", indent * tabs, "", o->name, tabs ? ": " : ":"); fprintf(fp, "%*.s\"%s\"%s", indent * tabs, "", o->name, tabs ? ": " : ":");
} }
/**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null"); /**/ if( o->type == JSON5_NULL ) fprintf(fp, "%s", "null");
else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false"); else if( o->type == JSON5_BOOL ) fprintf(fp, "%s", o->boolean ? "true" : "false");
else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", (long long int)o->integer); else if( o->type == JSON5_INTEGER ) fprintf(fp, "%lld", (long long int)o->integer);
else if( o->type == JSON5_REAL ) { else if( o->type == JSON5_REAL ) {
/**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" ); /**/ if( isnan(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-nan" : "nan" );
else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" ); else if( isinf(o->real) ) fprintf(fp, "%s", signbit(o->real) ? "-inf" : "inf" );
else fprintf(fp, "%1.8e", o->real); // %1.8e from google:"randomascii 100 digits" ; %.4llf for compactness else fprintf(fp, "%1.8e", o->real); // %1.8e from google:"randomascii 100 digits" ; %.4llf for compactness
} }
#if 0 #if 0
else if( o->type == JSON5_STRING ) { // write (escaped) string else if( o->type == JSON5_STRING ) { // write (escaped) string
char chars[] = "\\\"\n\r\b\f\v", remap[] = "\\\"nrbfv", esc[256]; char chars[] = "\\\"\n\r\b\f\v", remap[] = "\\\"nrbfv", esc[256];
for( int i = 0; chars[i]; ++i ) esc[ chars[i] ] = remap[i]; for( int i = 0; chars[i]; ++i ) esc[ chars[i] ] = remap[i];
const char *b = o->string, *e = strpbrk(b, chars), *sep = "\""; const char *b = o->string, *e = strpbrk(b, chars), *sep = "\"";
while( e ) { while( e ) {
fprintf(fp, "%s%.*s\\%c", sep, (int)(e - b), b, esc[(unsigned char)*e] ); fprintf(fp, "%s%.*s\\%c", sep, (int)(e - b), b, esc[(unsigned char)*e] );
e = strpbrk( b = e + 1, chars); e = strpbrk( b = e + 1, chars);
sep = ""; sep = "";
} }
fprintf(fp, "%s%s\"", sep, b); fprintf(fp, "%s%s\"", sep, b);
} }
#else #else
else if( o->type == JSON5_STRING ) { // write string else if( o->type == JSON5_STRING ) { // write string
fprintf(fp, "\"%s\"", o->string); fprintf(fp, "\"%s\"", o->string);
} }
#endif #endif
else if( o->type == JSON5_ARRAY ) { else if( o->type == JSON5_ARRAY ) {
const char *sep = ""; const char *sep = "";
fprintf(fp, "%s", tabs ? "[ " : "["); fprintf(fp, "%s", tabs ? "[ " : "[");
for( int i = 0, cnt = o->count; i < cnt; ++i ) { for( int i = 0, cnt = o->count; i < cnt; ++i ) {
fprintf(fp, "%s", sep); sep = tabs ? ", " : ","; fprintf(fp, "%s", sep); sep = tabs ? ", " : ",";
json5_write(fp, o->array + i); json5_write(fp, o->array + i);
} }
fprintf(fp, "%s", tabs ? " ]" : "]"); fprintf(fp, "%s", tabs ? " ]" : "]");
} }
else if( o->type == JSON5_OBJECT ) { else if( o->type == JSON5_OBJECT ) {
const char *sep = ""; const char *sep = "";
fprintf(fp, "%*.s{%s", 0 * (++indent) * tabs, "", tabs ? "\n":""); fprintf(fp, "%*.s{%s", 0 * (++indent) * tabs, "", tabs ? "\n":"");
for( int i = 0, cnt = o->count; i < cnt; ++i ) { for( int i = 0, cnt = o->count; i < cnt; ++i ) {
fprintf(fp, "%s", sep); sep = tabs ? ",\n" : ","; fprintf(fp, "%s", sep); sep = tabs ? ",\n" : ",";
json5_write(fp, o->nodes + i); json5_write(fp, o->nodes + i);
} }
fprintf(fp, "%s%*.s}", tabs ? "\n":"", (--indent) * tabs, ""); fprintf(fp, "%s%*.s}", tabs ? "\n":"", (--indent) * tabs, "");
} else { } else {
char p[16] = {0}; char p[16] = {0};
JSON5_ASSERT; /* "json5_error_invalid_value"; */ JSON5_ASSERT; /* "json5_error_invalid_value"; */
} }
} }
#ifdef JSON5_BENCH #ifdef JSON5_BENCH
#include <time.h> #include <time.h>
int main() { int main() {
// https://www.reddit.com/r/datasets/comments/1uyd0t/200000_jeopardy_questions_in_a_json_file/ // https://www.reddit.com/r/datasets/comments/1uyd0t/200000_jeopardy_questions_in_a_json_file/
char *content = 0; char *content = 0;
for( FILE *fp = fopen("jeopardy.json", "rb"); fp; fclose(fp), fp = 0 ) { for( FILE *fp = fopen("jeopardy.json", "rb"); fp; fclose(fp), fp = 0 ) {
fseek(fp, 0L, SEEK_END); fseek(fp, 0L, SEEK_END);
size_t pos = ftell(fp); size_t pos = ftell(fp);
fseek(fp, 0L, SEEK_SET); fseek(fp, 0L, SEEK_SET);
content = (char*)malloc( pos + 1 ); content = (char*)malloc( pos + 1 );
fread(content, 1, pos, fp); fread(content, 1, pos, fp);
content[pos] = 0; content[pos] = 0;
} }
if( content ) { if( content ) {
clock_t start = clock(); clock_t start = clock();
json5 root = {0}; json5 root = {0};
char *error = json5_parse(&root, content, 0); char *error = json5_parse(&root, content, 0);
clock_t end = clock(); clock_t end = clock();
double delta = ( end - start ) / (double)CLOCKS_PER_SEC; double delta = ( end - start ) / (double)CLOCKS_PER_SEC;
if( !error ) { if( !error ) {
printf("Parsing time: %.3fms\n", delta*1000); printf("Parsing time: %.3fms\n", delta*1000);
printf("Total nodes: %d\n", array_count(root.array)); printf("Total nodes: %d\n", array_count(root.array));
printf("Category: %s, air date: %s\nQuestion: %s\n", root.array[0].nodes[0].string, printf("Category: %s, air date: %s\nQuestion: %s\n", root.array[0].nodes[0].string,
root.array[0].nodes[1].string, root.array[0].nodes[1].string,
root.array[0].nodes[2].string); root.array[0].nodes[2].string);
} else { } else {
printf("Error: %s\n", error); printf("Error: %s\n", error);
} }
json5_free(&root); json5_free(&root);
free(content); free(content);
} }
} }
#define main main__ #define main main__
#endif #endif
#ifdef JSON5_DEMO #ifdef JSON5_DEMO
int main() { int main() {
char source5[] = char source5[] =
" // comments\n" /* json5 sample */ " // comments\n" /* json5 sample */
" unquoted: 'and you can quote me on that',\n" " unquoted: 'and you can quote me on that',\n"
" singleQuotes: 'I can use \"double quotes\" here',\n" " singleQuotes: 'I can use \"double quotes\" here',\n"
" lineBreaks : \"Look, Mom! \\\n" " lineBreaks : \"Look, Mom! \\\n"
"No \\n's!\",\n" "No \\n's!\",\n"
" hexadecimal: 0x100,\n" " hexadecimal: 0x100,\n"
" leadingDecimalPoint: .8675309, andTrailing: 8675309.,\n" " leadingDecimalPoint: .8675309, andTrailing: 8675309.,\n"
" positiveSign: +1,\n" " positiveSign: +1,\n"
" trailingComma: 'in objects', andIn: ['arrays', ],\n" " trailingComma: 'in objects', andIn: ['arrays', ],\n"
" \"backwardsCompatible\": \"with JSON\",\n" " \"backwardsCompatible\": \"with JSON\",\n"
"" ""
" ip = \"127.0.0.1\"\n" /* sjson sample */ " ip = \"127.0.0.1\"\n" /* sjson sample */
" port = 8888\n" " port = 8888\n"
"" ""
" /* comment //nested comment*/\n" /* tests */ " /* comment //nested comment*/\n" /* tests */
" // comment /*nested comment*/\n" " // comment /*nested comment*/\n"
" nil: null," " nil: null,"
" \"+lšctžýáíé=:\": true,,,," " \"+lšctžýáíé=:\": true,,,,"
" huge: 2.2239333e5, " " huge: 2.2239333e5, "
" array: [+1,2,-3,4,5], " " array: [+1,2,-3,4,5], "
" hello: 'world /*comment in string*/ //again', " " hello: 'world /*comment in string*/ //again', "
" abc: 42.67, def: false, " " abc: 42.67, def: false, "
" children : { a: 1, b: 2, }," " children : { a: 1, b: 2, },"
" invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ]," " invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ],"
"" ""
" multiline: `this is\n" " multiline: `this is\n"
"a multiline string\n" "a multiline string\n"
"yeah`" "yeah`"
"}\n"; "}\n";
json5 root = { 0 }; json5 root = { 0 };
char *error = json5_parse(&root, source5, 0); char *error = json5_parse(&root, source5, 0);
if( error ) { if( error ) {
printf("Error: %s\n", error); printf("Error: %s\n", error);
} else { } else {
json5_write(stdout, &root); json5_write(stdout, &root);
} }
json5_free(&root); json5_free(&root);
} }
#define main main__ #define main main__
#endif #endif
#endif // JSON5_C #endif // JSON5_C

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,275 +1,275 @@
// lite editor, platform details // lite editor, platform details
// - rlyeh, public domain // - rlyeh, public domain
#define LT_DATAPATH "/lite" #define LT_DATAPATH "/lite"
#define lt_assert(x) ASSERT(x) #define lt_assert(x) ASSERT(x)
#define lt_realpath(p, q) file_pathabs(p) #define lt_realpath(p, q) file_pathabs(p)
#define lt_realpath_free(p) #define lt_realpath_free(p)
#define lt_malloc(n) MALLOC(n) #define lt_malloc(n) MALLOC(n)
#define lt_calloc(n,m) CALLOC(n,m) #define lt_calloc(n,m) CALLOC(n,m)
#define lt_free(p) FREE(p) #define lt_free(p) FREE(p)
#define lt_memcpy(d,s,c) memcpy(d,s,c) #define lt_memcpy(d,s,c) memcpy(d,s,c)
#define lt_memset(p,ch,c) memset(p,ch,c) #define lt_memset(p,ch,c) memset(p,ch,c)
#define lt_time_ms() time_ms() #define lt_time_ms() time_ms()
#define lt_sleep_ms(ms) sleep_ms(ms) #define lt_sleep_ms(ms) sleep_ms(ms)
#define lt_getclipboard(w) window_clipboard() #define lt_getclipboard(w) window_clipboard()
#define lt_setclipboard(w,s) window_setclipboard(s) #define lt_setclipboard(w,s) window_setclipboard(s)
#define lt_window() window_handle() #define lt_window() window_handle()
#define lt_setwindowmode(m) window_fullscreen(m == 2), (m < 2 && (window_maximize(m),1)) // 0:normal,1:maximized,2:fullscreen #define lt_setwindowmode(m) window_fullscreen(m == 2), (m < 2 && (window_maximize(m),1)) // 0:normal,1:maximized,2:fullscreen
#define lt_setwindowtitle(t) //window_title(t) #define lt_setwindowtitle(t) //window_title(t)
#define lt_haswindowfocus() window_has_focus() #define lt_haswindowfocus() window_has_focus()
#define lt_setcursor(shape) window_cursor_shape(lt_events & (1<<31) ? CURSOR_SW_AUTO : shape+1) // 0:arrow,1:ibeam,2:sizeh,3:sizev,4:hand #define lt_setcursor(shape) window_cursor_shape(lt_events & (1<<31) ? CURSOR_SW_AUTO : shape+1) // 0:arrow,1:ibeam,2:sizeh,3:sizev,4:hand
#define lt_prompt(msg,title) ifndef(win32, 0, (MessageBoxA(0, msg, title, MB_YESNO | MB_ICONWARNING) == IDYES)) #define lt_prompt(msg,title) ifndef(win32, 0, (MessageBoxA(0, msg, title, MB_YESNO | MB_ICONWARNING) == IDYES))
unsigned lt_events = ~0u; unsigned lt_events = ~0u;
int lt_mx = 0, lt_my = 0, lt_wx = 0, lt_wy = 0, lt_ww = 0, lt_wh = 0; int lt_mx = 0, lt_my = 0, lt_wx = 0, lt_wy = 0, lt_ww = 0, lt_wh = 0;
typedef struct lt_surface { typedef struct lt_surface {
unsigned w, h; unsigned w, h;
void *pixels; void *pixels;
texture_t t; texture_t t;
} lt_surface; } lt_surface;
typedef struct lt_rect { typedef struct lt_rect {
int x, y, width, height; int x, y, width, height;
} lt_rect; } lt_rect;
lt_surface *lt_getsurface(void *window) { lt_surface *lt_getsurface(void *window) {
static lt_surface s = {0}; static lt_surface s = {0};
return &s; return &s;
} }
void lt_updatesurfacerects(lt_surface *s, lt_rect* rects, unsigned count) { void lt_updatesurfacerects(lt_surface *s, lt_rect* rects, unsigned count) {
if(0) if(0)
for( int i = 0; i < count; ++i ) { for( int i = 0; i < count; ++i ) {
memset( (unsigned*)s->pixels + (rects[i].x + rects[i].y * s->w), 0xFF, rects[i].width*4 ); memset( (unsigned*)s->pixels + (rects[i].x + rects[i].y * s->w), 0xFF, rects[i].width*4 );
memset( (unsigned*)s->pixels + (rects[i].x + (rects[i].y + (rects[i].height-1)) * s->w), 0xFF, rects[i].width*4 ); memset( (unsigned*)s->pixels + (rects[i].x + (rects[i].y + (rects[i].height-1)) * s->w), 0xFF, rects[i].width*4 );
for( int y = 1; y < (rects[i].height-1); ++y ) { for( int y = 1; y < (rects[i].height-1); ++y ) {
((unsigned*)s->pixels)[ rects[i].x + y * s->w ] = ((unsigned*)s->pixels)[ rects[i].x + y * s->w ] =
((unsigned*)s->pixels)[ rects[i].x + (rects[i].width-1) + y * s->w ] = 0xFFFFFFFF; ((unsigned*)s->pixels)[ rects[i].x + (rects[i].width-1) + y * s->w ] = 0xFFFFFFFF;
} }
} }
// update contents // update contents
texture_update(&s->t, s->w, s->h, 4, s->pixels, TEXTURE_LINEAR|TEXTURE_BGRA); texture_update(&s->t, s->w, s->h, 4, s->pixels, TEXTURE_LINEAR|TEXTURE_BGRA);
} }
void ren_set_clip_rect(struct lt_rect rect); void ren_set_clip_rect(struct lt_rect rect);
void rencache_invalidate(void); void rencache_invalidate(void);
int lt_resizesurface(lt_surface *s, int ww, int wh) { int lt_resizesurface(lt_surface *s, int ww, int wh) {
s->w = ww, s->h = wh; s->w = ww, s->h = wh;
if( s->t.id == 0 || s->w != s->t.w || s->h != s->t.h ) { if( s->t.id == 0 || s->w != s->t.w || s->h != s->t.h ) {
// invalidate tiles // invalidate tiles
ren_set_clip_rect( (lt_rect) { 0, 0, s->w, s->h } ); ren_set_clip_rect( (lt_rect) { 0, 0, s->w, s->h } );
rencache_invalidate(); rencache_invalidate();
// texture clear // texture clear
if( !s->t.id ) s->t = texture_create(1, 1, 4, " ", TEXTURE_LINEAR|TEXTURE_RGBA|TEXTURE_BYTE ); if( !s->t.id ) s->t = texture_create(1, 1, 4, " ", TEXTURE_LINEAR|TEXTURE_RGBA|TEXTURE_BYTE );
s->pixels = REALLOC(s->pixels, s->w * s->h * 4); s->pixels = REALLOC(s->pixels, s->w * s->h * 4);
memset(s->pixels, 0, s->w * s->h * 4); memset(s->pixels, 0, s->w * s->h * 4);
// texture update // texture update
lt_updatesurfacerects(s,0,0); lt_updatesurfacerects(s,0,0);
return 1; // resized return 1; // resized
} }
return 0; // unchanged return 0; // unchanged
} }
void *lt_load_file(const char *filename, int *size) { void *lt_load_file(const char *filename, int *size) {
int datalen; char *data = file_load(filename, &datalen); int datalen; char *data = file_load(filename, &datalen);
if( !data || !datalen ) { if( !data || !datalen ) {
filename = (const char *)file_normalize(filename); filename = (const char *)file_normalize(filename);
if( strbegi(filename, app_path()) ) filename += strlen(app_path()); if( strbegi(filename, app_path()) ) filename += strlen(app_path());
data = vfs_load(filename, &datalen); data = vfs_load(filename, &datalen);
} }
if (size) *size = 0; if (size) *size = 0;
if (!data) { return NULL; } if (!data) { return NULL; }
if (size) *size = datalen; if (size) *size = datalen;
// return permanent buffers here, as file_load() and vfs_load() do return temporaries // return permanent buffers here, as file_load() and vfs_load() do return temporaries
data = memcpy(MALLOC(datalen+1), data, datalen); data = memcpy(MALLOC(datalen+1), data, datalen);
data[datalen] = 0; data[datalen] = 0;
return data; return data;
} }
const char* lt_button_name(int button) { const char* lt_button_name(int button) {
if(button == GLFW_MOUSE_BUTTON_LEFT) return "left"; if(button == GLFW_MOUSE_BUTTON_LEFT) return "left";
if(button == GLFW_MOUSE_BUTTON_RIGHT) return "right"; if(button == GLFW_MOUSE_BUTTON_RIGHT) return "right";
if(button == GLFW_MOUSE_BUTTON_MIDDLE) return "middle"; if(button == GLFW_MOUSE_BUTTON_MIDDLE) return "middle";
return "?"; return "?";
} }
char* lt_key_name(char *dst, int key, int vk, int mods) { char* lt_key_name(char *dst, int key, int vk, int mods) {
// @todo: "altgr" -> left ctrl + right alt // @todo: "altgr" -> left ctrl + right alt
if( key == GLFW_KEY_UP ) return "up"; if( key == GLFW_KEY_UP ) return "up";
if( key == GLFW_KEY_DOWN ) return "down"; if( key == GLFW_KEY_DOWN ) return "down";
if( key == GLFW_KEY_LEFT ) return "left"; if( key == GLFW_KEY_LEFT ) return "left";
if( key == GLFW_KEY_RIGHT ) return "right"; if( key == GLFW_KEY_RIGHT ) return "right";
if( key == GLFW_KEY_LEFT_ALT ) return "left alt"; if( key == GLFW_KEY_LEFT_ALT ) return "left alt";
if( key == GLFW_KEY_RIGHT_ALT ) return "right alt"; if( key == GLFW_KEY_RIGHT_ALT ) return "right alt";
if( key == GLFW_KEY_LEFT_SHIFT ) return "left shift"; if( key == GLFW_KEY_LEFT_SHIFT ) return "left shift";
if( key == GLFW_KEY_RIGHT_SHIFT ) return "right shift"; if( key == GLFW_KEY_RIGHT_SHIFT ) return "right shift";
if( key == GLFW_KEY_LEFT_CONTROL ) return "left ctrl"; if( key == GLFW_KEY_LEFT_CONTROL ) return "left ctrl";
if( key == GLFW_KEY_RIGHT_CONTROL ) return "right ctrl"; if( key == GLFW_KEY_RIGHT_CONTROL ) return "right ctrl";
if( key == GLFW_KEY_LEFT_SUPER ) return "left windows"; if( key == GLFW_KEY_LEFT_SUPER ) return "left windows";
if( key == GLFW_KEY_RIGHT_SUPER ) return "left windows"; if( key == GLFW_KEY_RIGHT_SUPER ) return "left windows";
if( key == GLFW_KEY_MENU ) return "menu"; if( key == GLFW_KEY_MENU ) return "menu";
if( key == GLFW_KEY_ESCAPE ) return "escape"; if( key == GLFW_KEY_ESCAPE ) return "escape";
if( key == GLFW_KEY_BACKSPACE ) return "backspace"; if( key == GLFW_KEY_BACKSPACE ) return "backspace";
if( key == GLFW_KEY_ENTER ) return "return"; if( key == GLFW_KEY_ENTER ) return "return";
if( key == GLFW_KEY_KP_ENTER ) return "keypad enter"; if( key == GLFW_KEY_KP_ENTER ) return "keypad enter";
if( key == GLFW_KEY_TAB ) return "tab"; if( key == GLFW_KEY_TAB ) return "tab";
if( key == GLFW_KEY_CAPS_LOCK ) return "capslock"; if( key == GLFW_KEY_CAPS_LOCK ) return "capslock";
if( key == GLFW_KEY_HOME ) return "home"; if( key == GLFW_KEY_HOME ) return "home";
if( key == GLFW_KEY_END ) return "end"; if( key == GLFW_KEY_END ) return "end";
if( key == GLFW_KEY_INSERT ) return "insert"; if( key == GLFW_KEY_INSERT ) return "insert";
if( key == GLFW_KEY_DELETE ) return "delete"; if( key == GLFW_KEY_DELETE ) return "delete";
if( key == GLFW_KEY_PAGE_UP ) return "pageup"; if( key == GLFW_KEY_PAGE_UP ) return "pageup";
if( key == GLFW_KEY_PAGE_DOWN ) return "pagedown"; if( key == GLFW_KEY_PAGE_DOWN ) return "pagedown";
if( key == GLFW_KEY_F1 ) return "f1"; if( key == GLFW_KEY_F1 ) return "f1";
if( key == GLFW_KEY_F2 ) return "f2"; if( key == GLFW_KEY_F2 ) return "f2";
if( key == GLFW_KEY_F3 ) return "f3"; if( key == GLFW_KEY_F3 ) return "f3";
if( key == GLFW_KEY_F4 ) return "f4"; if( key == GLFW_KEY_F4 ) return "f4";
if( key == GLFW_KEY_F5 ) return "f5"; if( key == GLFW_KEY_F5 ) return "f5";
if( key == GLFW_KEY_F6 ) return "f6"; if( key == GLFW_KEY_F6 ) return "f6";
if( key == GLFW_KEY_F7 ) return "f7"; if( key == GLFW_KEY_F7 ) return "f7";
if( key == GLFW_KEY_F8 ) return "f8"; if( key == GLFW_KEY_F8 ) return "f8";
if( key == GLFW_KEY_F9 ) return "f9"; if( key == GLFW_KEY_F9 ) return "f9";
if( key == GLFW_KEY_F10 ) return "f10"; if( key == GLFW_KEY_F10 ) return "f10";
if( key == GLFW_KEY_F11 ) return "f11"; if( key == GLFW_KEY_F11 ) return "f11";
if( key == GLFW_KEY_F12 ) return "f12"; if( key == GLFW_KEY_F12 ) return "f12";
const char *name = glfwGetKeyName(key, vk); const char *name = glfwGetKeyName(key, vk);
strcpy(dst, name ? name : ""); strcpy(dst, name ? name : "");
char *p = dst; char *p = dst;
while (*p) { while (*p) {
*p = tolower(*p); *p = tolower(*p);
p++; p++;
} }
return dst; return dst;
} }
void lt_globpath(struct lua_State*L, const char *path) { void lt_globpath(struct lua_State*L, const char *path) {
unsigned j = 0; unsigned j = 0;
if(!strend(path, "/")) path = (const char *)va("%s/", path); if(!strend(path, "/")) path = (const char *)va("%s/", path);
for( dir *d = dir_open(path, ""); d; dir_close(d), d = 0 ) { for( dir *d = dir_open(path, ""); d; dir_close(d), d = 0 ) {
for( unsigned i = 0, end = dir_count(d); i < end; ++i ) { for( unsigned i = 0, end = dir_count(d); i < end; ++i ) {
char *name = dir_name(d,i); char *name = dir_name(d,i);
char *last = name + strlen(name) - 1; char *last = name + strlen(name) - 1;
if( *last == '/' ) *last = '\0'; if( *last == '/' ) *last = '\0';
name = file_name(name); name = file_name(name);
lua_pushstring(L, name); lua_pushstring(L, name);
lua_rawseti(L, -2, ++j); lua_rawseti(L, -2, ++j);
} }
} }
for( const char *section = strstri(path, LT_DATAPATH); section && section[sizeof(LT_DATAPATH)-1] == '/'; section = 0) { for( const char *section = strstri(path, LT_DATAPATH); section && section[sizeof(LT_DATAPATH)-1] == '/'; section = 0) {
array(char*) list = vfs_list("**"); array(char*) list = vfs_list("**");
for( unsigned i = 0, end = array_count(list); i < end; ++i ) { for( unsigned i = 0, end = array_count(list); i < end; ++i ) {
char *name = list[i]; char *name = list[i];
if( !strstri(name, section+1) ) continue; if( !strstri(name, section+1) ) continue;
lua_pushstring(L, file_name(name)); lua_pushstring(L, file_name(name));
lua_rawseti(L, -2, ++j); lua_rawseti(L, -2, ++j);
} }
if( array_count(list) ) return; if( array_count(list) ) return;
} }
} }
int lt_emit_event(lua_State *L, const char *event_name, const char *event_fmt, ...) { int lt_emit_event(lua_State *L, const char *event_name, const char *event_fmt, ...) {
int count = 0; int count = 0;
lua_pushstring(L, event_name); lua_pushstring(L, event_name);
if( event_fmt ) { if( event_fmt ) {
va_list va; va_list va;
va_start(va, event_fmt); va_start(va, event_fmt);
for( ; event_fmt[count]; ++count ) { for( ; event_fmt[count]; ++count ) {
/**/ if( event_fmt[count] == 'd' ) { int d = va_arg(va, int); lua_pushnumber(L, d); } /**/ if( event_fmt[count] == 'd' ) { int d = va_arg(va, int); lua_pushnumber(L, d); }
else if( event_fmt[count] == 'f' ) { double f = va_arg(va, double); lua_pushnumber(L, f); } else if( event_fmt[count] == 'f' ) { double f = va_arg(va, double); lua_pushnumber(L, f); }
else if( event_fmt[count] == 's' ) { const char *s = va_arg(va, const char *); lua_pushstring(L, s); } else if( event_fmt[count] == 's' ) { const char *s = va_arg(va, const char *); lua_pushstring(L, s); }
} }
va_end(va); va_end(va);
} }
return 1+count; return 1+count;
} }
int printi(int i) { int printi(int i) {
// printf("clicks: %d\n", i); // printf("clicks: %d\n", i);
return i; return i;
} }
static const char* codepoint_to_utf8_(unsigned c); static const char* codepoint_to_utf8_(unsigned c);
int lt_poll_event(lua_State *L) { // init.lua > core.step() wakes on mousemoved || inputtext int lt_poll_event(lua_State *L) { // init.lua > core.step() wakes on mousemoved || inputtext
int rc = 0; int rc = 0;
char buf[16]; char buf[16];
static int prevx = 0, prevy = 0; static int prevx = 0, prevy = 0;
static unsigned clicks_time = 0, clicks = 0; static unsigned clicks_time = 0, clicks = 0;
if( (lt_time_ms() - clicks_time) > 400 ) clicks = 0; if( (lt_time_ms() - clicks_time) > 400 ) clicks = 0;
// //
for( GLEQevent e; gleqNextEvent(&e); gleqFreeEvent(&e) ) for( GLEQevent e; gleqNextEvent(&e); gleqFreeEvent(&e) )
if( lt_events & e.type ) if( lt_events & e.type )
switch (e.type) { switch (e.type) {
default: default:
break; case GLEQ_WINDOW_CLOSED: // it used to be ok. depends on window_swap() flow break; case GLEQ_WINDOW_CLOSED: // it used to be ok. depends on window_swap() flow
rc += lt_emit_event(L, "quit", NULL); rc += lt_emit_event(L, "quit", NULL);
return rc; return rc;
break; case GLEQ_WINDOW_MOVED: break; case GLEQ_WINDOW_MOVED:
lt_wx = e.pos.x; lt_wx = e.pos.x;
lt_wy = e.pos.y; lt_wy = e.pos.y;
break; case GLEQ_WINDOW_RESIZED: break; case GLEQ_WINDOW_RESIZED:
rc += lt_emit_event(L, "resized", "dd", lt_ww = e.size.width, lt_wh = e.size.height); rc += lt_emit_event(L, "resized", "dd", lt_ww = e.size.width, lt_wh = e.size.height);
lt_resizesurface(lt_getsurface(lt_window()), lt_ww, lt_wh); lt_resizesurface(lt_getsurface(lt_window()), lt_ww, lt_wh);
break; case GLEQ_WINDOW_REFRESH: break; case GLEQ_WINDOW_REFRESH:
rc += lt_emit_event(L, "exposed", NULL); rc += lt_emit_event(L, "exposed", NULL);
rencache_invalidate(); rencache_invalidate();
break; case GLEQ_FILE_DROPPED: break; case GLEQ_FILE_DROPPED:
rc += lt_emit_event(L, "filedropped", "sdd", e.file.paths[0], lt_mx, lt_my); rc += lt_emit_event(L, "filedropped", "sdd", e.file.paths[0], lt_mx, lt_my);
break; case GLEQ_KEY_PRESSED: break; case GLEQ_KEY_PRESSED:
case GLEQ_KEY_REPEATED: case GLEQ_KEY_REPEATED:
rc += lt_emit_event(L, "keypressed", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods)); rc += lt_emit_event(L, "keypressed", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
goto bottom; goto bottom;
break; case GLEQ_KEY_RELEASED: break; case GLEQ_KEY_RELEASED:
rc += lt_emit_event(L, "keyreleased", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods)); rc += lt_emit_event(L, "keyreleased", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
goto bottom; goto bottom;
break; case GLEQ_CODEPOINT_INPUT: break; case GLEQ_CODEPOINT_INPUT:
rc += lt_emit_event(L, "textinput", "s", codepoint_to_utf8_(e.codepoint)); rc += lt_emit_event(L, "textinput", "s", codepoint_to_utf8_(e.codepoint));
break; case GLEQ_BUTTON_PRESSED: break; case GLEQ_BUTTON_PRESSED:
rc += lt_emit_event(L, "mousepressed", "sddd", lt_button_name(e.mouse.button), lt_mx, lt_my, printi(1 + clicks)); rc += lt_emit_event(L, "mousepressed", "sddd", lt_button_name(e.mouse.button), lt_mx, lt_my, printi(1 + clicks));
break; case GLEQ_BUTTON_RELEASED: break; case GLEQ_BUTTON_RELEASED:
clicks += e.mouse.button == GLFW_MOUSE_BUTTON_1; clicks += e.mouse.button == GLFW_MOUSE_BUTTON_1;
clicks_time = lt_time_ms(); clicks_time = lt_time_ms();
rc += lt_emit_event(L, "mousereleased", "sdd", lt_button_name(e.mouse.button), lt_mx, lt_my); rc += lt_emit_event(L, "mousereleased", "sdd", lt_button_name(e.mouse.button), lt_mx, lt_my);
break; case GLEQ_CURSOR_MOVED: break; case GLEQ_CURSOR_MOVED:
lt_mx = e.pos.x - lt_wx, lt_my = e.pos.y - lt_wy; lt_mx = e.pos.x - lt_wx, lt_my = e.pos.y - lt_wy;
rc += lt_emit_event(L, "mousemoved", "dddd", lt_mx, lt_my, lt_mx - prevx, lt_my - prevy); rc += lt_emit_event(L, "mousemoved", "dddd", lt_mx, lt_my, lt_mx - prevx, lt_my - prevy);
prevx = lt_mx, prevy = lt_my; prevx = lt_mx, prevy = lt_my;
break; case GLEQ_SCROLLED: break; case GLEQ_SCROLLED:
rc += lt_emit_event(L, "mousewheel", "f", e.scroll.y); rc += lt_emit_event(L, "mousewheel", "f", e.scroll.y);
} }
bottom:; bottom:;
return rc; return rc;
} }

View File

@ -1,424 +1,424 @@
/* /*
* GLEQ - A basic event queue for GLFW 3 * GLEQ - A basic event queue for GLFW 3
* Copyright © Camilla Löwy <elmindreda@glfw.org> * Copyright © Camilla Löwy <elmindreda@glfw.org>
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
* arising from the use of this software. * arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, * Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it * including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions: * freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not * 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software * claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would * in a product, an acknowledgment in the product documentation would
* be appreciated but is not required. * be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not * 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software. * be misrepresented as being the original software.
* *
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#ifndef GLEQ_HEADER_FILE #ifndef GLEQ_HEADER_FILE
#define GLEQ_HEADER_FILE #define GLEQ_HEADER_FILE
// #include <GLFW/glfw3.h> // #include <GLFW/glfw3.h>
#ifdef GLEQ_STATIC #ifdef GLEQ_STATIC
#define GLEQDEF static #define GLEQDEF static
#else #else
#define GLEQDEF extern #define GLEQDEF extern
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef enum typedef enum
{ {
GLEQ_NONE = 0, GLEQ_NONE = 0,
GLEQ_WINDOW_MOVED = 1<<1, GLEQ_WINDOW_MOVED = 1<<1,
GLEQ_WINDOW_RESIZED = 1<<2, GLEQ_WINDOW_RESIZED = 1<<2,
GLEQ_WINDOW_CLOSED = 1<<3, GLEQ_WINDOW_CLOSED = 1<<3,
GLEQ_WINDOW_REFRESH = 1<<4, GLEQ_WINDOW_REFRESH = 1<<4,
GLEQ_WINDOW_FOCUSED = 1<<5, GLEQ_WINDOW_FOCUSED = 1<<5,
GLEQ_WINDOW_DEFOCUSED = 1<<6, GLEQ_WINDOW_DEFOCUSED = 1<<6,
GLEQ_WINDOW_ICONIFIED = 1<<7, GLEQ_WINDOW_ICONIFIED = 1<<7,
GLEQ_WINDOW_UNICONIFIED = 1<<8, GLEQ_WINDOW_UNICONIFIED = 1<<8,
GLEQ_FRAMEBUFFER_RESIZED = 1<<9, GLEQ_FRAMEBUFFER_RESIZED = 1<<9,
GLEQ_BUTTON_PRESSED = 1<<10, GLEQ_BUTTON_PRESSED = 1<<10,
GLEQ_BUTTON_RELEASED = 1<<11, GLEQ_BUTTON_RELEASED = 1<<11,
GLEQ_CURSOR_MOVED = 1<<12, GLEQ_CURSOR_MOVED = 1<<12,
GLEQ_CURSOR_ENTERED = 1<<13, GLEQ_CURSOR_ENTERED = 1<<13,
GLEQ_CURSOR_LEFT = 1<<14, GLEQ_CURSOR_LEFT = 1<<14,
GLEQ_SCROLLED = 1<<15, GLEQ_SCROLLED = 1<<15,
GLEQ_KEY_PRESSED = 1<<16, GLEQ_KEY_PRESSED = 1<<16,
GLEQ_KEY_REPEATED = 1<<17, GLEQ_KEY_REPEATED = 1<<17,
GLEQ_KEY_RELEASED = 1<<18, GLEQ_KEY_RELEASED = 1<<18,
GLEQ_CODEPOINT_INPUT = 1<<19, GLEQ_CODEPOINT_INPUT = 1<<19,
GLEQ_MONITOR_CONNECTED = 1<<20, GLEQ_MONITOR_CONNECTED = 1<<20,
GLEQ_MONITOR_DISCONNECTED = 1<<21, GLEQ_MONITOR_DISCONNECTED = 1<<21,
#if GLFW_VERSION_MINOR >= 1 #if GLFW_VERSION_MINOR >= 1
GLEQ_FILE_DROPPED = 1<<22, GLEQ_FILE_DROPPED = 1<<22,
#endif #endif
#if GLFW_VERSION_MINOR >= 2 #if GLFW_VERSION_MINOR >= 2
GLEQ_JOYSTICK_CONNECTED = 1<<23, GLEQ_JOYSTICK_CONNECTED = 1<<23,
GLEQ_JOYSTICK_DISCONNECTED = 1<<24, GLEQ_JOYSTICK_DISCONNECTED = 1<<24,
#endif #endif
#if GLFW_VERSION_MINOR >= 3 #if GLFW_VERSION_MINOR >= 3
GLEQ_WINDOW_MAXIMIZED = 1<<25, GLEQ_WINDOW_MAXIMIZED = 1<<25,
GLEQ_WINDOW_UNMAXIMIZED = 1<<26, GLEQ_WINDOW_UNMAXIMIZED = 1<<26,
GLEQ_WINDOW_SCALE_CHANGED = 1<<27, GLEQ_WINDOW_SCALE_CHANGED = 1<<27,
#endif #endif
} GLEQtype; } GLEQtype;
typedef struct GLEQevent typedef struct GLEQevent
{ {
unsigned/*GLEQtype*/ type; unsigned/*GLEQtype*/ type;
union { union {
GLFWwindow* window; GLFWwindow* window;
GLFWmonitor* monitor; GLFWmonitor* monitor;
int joystick; int joystick;
}; };
union { union {
struct { struct {
int x; int x;
int y; int y;
} pos; } pos;
struct { struct {
int width; int width;
int height; int height;
} size; } size;
struct { struct {
double x; double x;
double y; double y;
} scroll; } scroll;
struct { struct {
int key; int key;
int scancode; int scancode;
int mods; int mods;
} keyboard; } keyboard;
struct { struct {
int button; int button;
int mods; int mods;
} mouse; } mouse;
unsigned int codepoint; unsigned int codepoint;
#if GLFW_VERSION_MINOR >= 1 #if GLFW_VERSION_MINOR >= 1
struct { struct {
char** paths; char** paths;
int count; int count;
} file; } file;
#endif #endif
#if GLFW_VERSION_MINOR >= 3 #if GLFW_VERSION_MINOR >= 3
struct { struct {
float x; float x;
float y; float y;
} scale; } scale;
#endif #endif
}; };
} GLEQevent; } GLEQevent;
GLEQDEF void gleqInit(void); GLEQDEF void gleqInit(void);
GLEQDEF void gleqTrackWindow(GLFWwindow* window); GLEQDEF void gleqTrackWindow(GLFWwindow* window);
GLEQDEF int gleqNextEvent(GLEQevent* event); GLEQDEF int gleqNextEvent(GLEQevent* event);
GLEQDEF void gleqFreeEvent(GLEQevent* event); GLEQDEF void gleqFreeEvent(GLEQevent* event);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#ifdef GLEQ_IMPLEMENTATION #ifdef GLEQ_IMPLEMENTATION
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#ifndef GLEQ_CAPACITY #ifndef GLEQ_CAPACITY
#define GLEQ_CAPACITY 1024 #define GLEQ_CAPACITY 1024
#endif #endif
static struct static struct
{ {
GLEQevent events[GLEQ_CAPACITY]; GLEQevent events[GLEQ_CAPACITY];
size_t head; size_t head;
size_t tail; size_t tail;
} gleq_queue = { {0}, 0, 0 }; } gleq_queue = { {0}, 0, 0 };
static char* gleq_strdup(const char* string) static char* gleq_strdup(const char* string)
{ {
const size_t size = strlen(string) + 1; const size_t size = strlen(string) + 1;
char* result = (char*) malloc(size); char* result = (char*) malloc(size);
memcpy(result, string, size); memcpy(result, string, size);
return result; return result;
} }
static GLEQevent* gleq_new_event(void) static GLEQevent* gleq_new_event(void)
{ {
GLEQevent* event = gleq_queue.events + gleq_queue.head; GLEQevent* event = gleq_queue.events + gleq_queue.head;
gleq_queue.head = (gleq_queue.head + 1) % GLEQ_CAPACITY; gleq_queue.head = (gleq_queue.head + 1) % GLEQ_CAPACITY;
assert(gleq_queue.head != gleq_queue.tail); assert(gleq_queue.head != gleq_queue.tail);
memset(event, 0, sizeof(GLEQevent)); memset(event, 0, sizeof(GLEQevent));
return event; return event;
} }
static void gleq_window_pos_callback(GLFWwindow* window, int x, int y) static void gleq_window_pos_callback(GLFWwindow* window, int x, int y)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_WINDOW_MOVED; event->type = GLEQ_WINDOW_MOVED;
event->window = window; event->window = window;
event->pos.x = x; event->pos.x = x;
event->pos.y = y; event->pos.y = y;
} }
static void gleq_window_size_callback(GLFWwindow* window, int width, int height) static void gleq_window_size_callback(GLFWwindow* window, int width, int height)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_WINDOW_RESIZED; event->type = GLEQ_WINDOW_RESIZED;
event->window = window; event->window = window;
event->size.width = width; event->size.width = width;
event->size.height = height; event->size.height = height;
} }
static void gleq_window_close_callback(GLFWwindow* window) static void gleq_window_close_callback(GLFWwindow* window)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_WINDOW_CLOSED; event->type = GLEQ_WINDOW_CLOSED;
event->window = window; event->window = window;
} }
static void gleq_window_refresh_callback(GLFWwindow* window) static void gleq_window_refresh_callback(GLFWwindow* window)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_WINDOW_REFRESH; event->type = GLEQ_WINDOW_REFRESH;
event->window = window; event->window = window;
} }
static void gleq_window_focus_callback(GLFWwindow* window, int focused) static void gleq_window_focus_callback(GLFWwindow* window, int focused)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->window = window; event->window = window;
if (focused) if (focused)
event->type = GLEQ_WINDOW_FOCUSED; event->type = GLEQ_WINDOW_FOCUSED;
else else
event->type = GLEQ_WINDOW_DEFOCUSED; event->type = GLEQ_WINDOW_DEFOCUSED;
} }
static void gleq_window_iconify_callback(GLFWwindow* window, int iconified) static void gleq_window_iconify_callback(GLFWwindow* window, int iconified)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->window = window; event->window = window;
if (iconified) if (iconified)
event->type = GLEQ_WINDOW_ICONIFIED; event->type = GLEQ_WINDOW_ICONIFIED;
else else
event->type = GLEQ_WINDOW_UNICONIFIED; event->type = GLEQ_WINDOW_UNICONIFIED;
} }
static void gleq_framebuffer_size_callback(GLFWwindow* window, int width, int height) static void gleq_framebuffer_size_callback(GLFWwindow* window, int width, int height)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_FRAMEBUFFER_RESIZED; event->type = GLEQ_FRAMEBUFFER_RESIZED;
event->window = window; event->window = window;
event->size.width = width; event->size.width = width;
event->size.height = height; event->size.height = height;
} }
static void gleq_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) static void gleq_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->window = window; event->window = window;
event->mouse.button = button; event->mouse.button = button;
event->mouse.mods = mods; event->mouse.mods = mods;
if (action == GLFW_PRESS) if (action == GLFW_PRESS)
event->type = GLEQ_BUTTON_PRESSED; event->type = GLEQ_BUTTON_PRESSED;
else if (action == GLFW_RELEASE) else if (action == GLFW_RELEASE)
event->type = GLEQ_BUTTON_RELEASED; event->type = GLEQ_BUTTON_RELEASED;
} }
static void gleq_cursor_pos_callback(GLFWwindow* window, double x, double y) static void gleq_cursor_pos_callback(GLFWwindow* window, double x, double y)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_CURSOR_MOVED; event->type = GLEQ_CURSOR_MOVED;
event->window = window; event->window = window;
event->pos.x = (int) x; event->pos.x = (int) x;
event->pos.y = (int) y; event->pos.y = (int) y;
} }
static void gleq_cursor_enter_callback(GLFWwindow* window, int entered) static void gleq_cursor_enter_callback(GLFWwindow* window, int entered)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->window = window; event->window = window;
if (entered) if (entered)
event->type = GLEQ_CURSOR_ENTERED; event->type = GLEQ_CURSOR_ENTERED;
else else
event->type = GLEQ_CURSOR_LEFT; event->type = GLEQ_CURSOR_LEFT;
} }
static void gleq_scroll_callback(GLFWwindow* window, double x, double y) static void gleq_scroll_callback(GLFWwindow* window, double x, double y)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_SCROLLED; event->type = GLEQ_SCROLLED;
event->window = window; event->window = window;
event->scroll.x = x; event->scroll.x = x;
event->scroll.y = y; event->scroll.y = y;
} }
static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->window = window; event->window = window;
event->keyboard.key = key; event->keyboard.key = key;
event->keyboard.scancode = scancode; event->keyboard.scancode = scancode;
event->keyboard.mods = mods; event->keyboard.mods = mods;
if (action == GLFW_PRESS) if (action == GLFW_PRESS)
event->type = GLEQ_KEY_PRESSED; event->type = GLEQ_KEY_PRESSED;
else if (action == GLFW_RELEASE) else if (action == GLFW_RELEASE)
event->type = GLEQ_KEY_RELEASED; event->type = GLEQ_KEY_RELEASED;
else if (action == GLFW_REPEAT) else if (action == GLFW_REPEAT)
event->type = GLEQ_KEY_REPEATED; event->type = GLEQ_KEY_REPEATED;
} }
static void (*gleq_char_callback_prev)(GLFWwindow* window, unsigned int codepoint) = 0; static void (*gleq_char_callback_prev)(GLFWwindow* window, unsigned int codepoint) = 0;
static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint) static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint)
{ {
if( gleq_char_callback_prev ) if( gleq_char_callback_prev )
gleq_char_callback_prev(window, codepoint); gleq_char_callback_prev(window, codepoint);
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_CODEPOINT_INPUT; event->type = GLEQ_CODEPOINT_INPUT;
event->window = window; event->window = window;
event->codepoint = codepoint; event->codepoint = codepoint;
} }
static void gleq_monitor_callback(GLFWmonitor* monitor, int action) static void gleq_monitor_callback(GLFWmonitor* monitor, int action)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->monitor = monitor; event->monitor = monitor;
if (action == GLFW_CONNECTED) if (action == GLFW_CONNECTED)
event->type = GLEQ_MONITOR_CONNECTED; event->type = GLEQ_MONITOR_CONNECTED;
else if (action == GLFW_DISCONNECTED) else if (action == GLFW_DISCONNECTED)
event->type = GLEQ_MONITOR_DISCONNECTED; event->type = GLEQ_MONITOR_DISCONNECTED;
} }
#if GLFW_VERSION_MINOR >= 1 #if GLFW_VERSION_MINOR >= 1
static void gleq_file_drop_callback(GLFWwindow* window, int count, const char** paths) static void gleq_file_drop_callback(GLFWwindow* window, int count, const char** paths)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->type = GLEQ_FILE_DROPPED; event->type = GLEQ_FILE_DROPPED;
event->window = window; event->window = window;
event->file.paths = (char**) malloc(count * sizeof(char*)); event->file.paths = (char**) malloc(count * sizeof(char*));
event->file.count = count; event->file.count = count;
while (count--) while (count--)
event->file.paths[count] = gleq_strdup(paths[count]); event->file.paths[count] = gleq_strdup(paths[count]);
} }
#endif #endif
#if GLFW_VERSION_MINOR >= 2 #if GLFW_VERSION_MINOR >= 2
static void gleq_joystick_callback(int jid, int action) static void gleq_joystick_callback(int jid, int action)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->joystick = jid; event->joystick = jid;
if (action == GLFW_CONNECTED) if (action == GLFW_CONNECTED)
event->type = GLEQ_JOYSTICK_CONNECTED; event->type = GLEQ_JOYSTICK_CONNECTED;
else if (action == GLFW_DISCONNECTED) else if (action == GLFW_DISCONNECTED)
event->type = GLEQ_JOYSTICK_DISCONNECTED; event->type = GLEQ_JOYSTICK_DISCONNECTED;
} }
#endif #endif
#if GLFW_VERSION_MINOR >= 3 #if GLFW_VERSION_MINOR >= 3
static void gleq_window_maximize_callback(GLFWwindow* window, int maximized) static void gleq_window_maximize_callback(GLFWwindow* window, int maximized)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->window = window; event->window = window;
if (maximized) if (maximized)
event->type = GLEQ_WINDOW_MAXIMIZED; event->type = GLEQ_WINDOW_MAXIMIZED;
else else
event->type = GLEQ_WINDOW_UNMAXIMIZED; event->type = GLEQ_WINDOW_UNMAXIMIZED;
} }
static void gleq_window_content_scale_callback(GLFWwindow* window, float xscale, float yscale) static void gleq_window_content_scale_callback(GLFWwindow* window, float xscale, float yscale)
{ {
GLEQevent* event = gleq_new_event(); GLEQevent* event = gleq_new_event();
event->window = window; event->window = window;
event->type = GLEQ_WINDOW_SCALE_CHANGED; event->type = GLEQ_WINDOW_SCALE_CHANGED;
event->scale.x = xscale; event->scale.x = xscale;
event->scale.y = yscale; event->scale.y = yscale;
} }
#endif #endif
GLEQDEF void gleqInit(void) GLEQDEF void gleqInit(void)
{ {
glfwSetMonitorCallback(gleq_monitor_callback); glfwSetMonitorCallback(gleq_monitor_callback);
#if GLFW_VERSION_MINOR >= 2 #if GLFW_VERSION_MINOR >= 2
glfwSetJoystickCallback(gleq_joystick_callback); glfwSetJoystickCallback(gleq_joystick_callback);
#endif #endif
} }
GLEQDEF void gleqTrackWindow(GLFWwindow* window) GLEQDEF void gleqTrackWindow(GLFWwindow* window)
{ {
glfwSetWindowPosCallback(window, gleq_window_pos_callback); glfwSetWindowPosCallback(window, gleq_window_pos_callback);
glfwSetWindowSizeCallback(window, gleq_window_size_callback); glfwSetWindowSizeCallback(window, gleq_window_size_callback);
glfwSetWindowCloseCallback(window, gleq_window_close_callback); glfwSetWindowCloseCallback(window, gleq_window_close_callback);
glfwSetWindowRefreshCallback(window, gleq_window_refresh_callback); glfwSetWindowRefreshCallback(window, gleq_window_refresh_callback);
glfwSetWindowFocusCallback(window, gleq_window_focus_callback); glfwSetWindowFocusCallback(window, gleq_window_focus_callback);
glfwSetWindowIconifyCallback(window, gleq_window_iconify_callback); glfwSetWindowIconifyCallback(window, gleq_window_iconify_callback);
glfwSetFramebufferSizeCallback(window, gleq_framebuffer_size_callback); glfwSetFramebufferSizeCallback(window, gleq_framebuffer_size_callback);
glfwSetMouseButtonCallback(window, gleq_mouse_button_callback); glfwSetMouseButtonCallback(window, gleq_mouse_button_callback);
glfwSetCursorPosCallback(window, gleq_cursor_pos_callback); glfwSetCursorPosCallback(window, gleq_cursor_pos_callback);
glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback); glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback);
glfwSetScrollCallback(window, gleq_scroll_callback); glfwSetScrollCallback(window, gleq_scroll_callback);
glfwSetKeyCallback(window, gleq_key_callback); glfwSetKeyCallback(window, gleq_key_callback);
gleq_char_callback_prev = //< @r-lyeh gleq_char_callback_prev = //< @r-lyeh
glfwSetCharCallback(window, gleq_char_callback); glfwSetCharCallback(window, gleq_char_callback);
#if GLFW_VERSION_MINOR >= 1 #if GLFW_VERSION_MINOR >= 1
glfwSetDropCallback(window, gleq_file_drop_callback); glfwSetDropCallback(window, gleq_file_drop_callback);
#endif #endif
#if GLFW_VERSION_MINOR >= 3 #if GLFW_VERSION_MINOR >= 3
glfwSetWindowMaximizeCallback(window, gleq_window_maximize_callback); glfwSetWindowMaximizeCallback(window, gleq_window_maximize_callback);
glfwSetWindowContentScaleCallback(window, gleq_window_content_scale_callback); glfwSetWindowContentScaleCallback(window, gleq_window_content_scale_callback);
#endif #endif
} }
GLEQDEF int gleqNextEvent(GLEQevent* event) GLEQDEF int gleqNextEvent(GLEQevent* event)
{ {
memset(event, 0, sizeof(GLEQevent)); memset(event, 0, sizeof(GLEQevent));
if (gleq_queue.head != gleq_queue.tail) if (gleq_queue.head != gleq_queue.tail)
{ {
*event = gleq_queue.events[gleq_queue.tail]; *event = gleq_queue.events[gleq_queue.tail];
gleq_queue.tail = (gleq_queue.tail + 1) % GLEQ_CAPACITY; gleq_queue.tail = (gleq_queue.tail + 1) % GLEQ_CAPACITY;
} }
return event->type != GLEQ_NONE; return event->type != GLEQ_NONE;
} }
GLEQDEF void gleqFreeEvent(GLEQevent* event) GLEQDEF void gleqFreeEvent(GLEQevent* event)
{ {
#if GLFW_VERSION_MINOR >= 1 #if GLFW_VERSION_MINOR >= 1
if (event->type == GLEQ_FILE_DROPPED) if (event->type == GLEQ_FILE_DROPPED)
{ {
while (event->file.count--) while (event->file.count--)
free(event->file.paths[event->file.count]); free(event->file.paths[event->file.count]);
free(event->file.paths); free(event->file.paths);
} }
#endif #endif
memset(event, 0, sizeof(GLEQevent)); memset(event, 0, sizeof(GLEQevent));
} }
#endif /* GLEQ_IMPLEMENTATION */ #endif /* GLEQ_IMPLEMENTATION */
#endif /* GLEQ_HEADER_FILE */ #endif /* GLEQ_HEADER_FILE */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,483 +1,483 @@
// file browser for nuklear, based on https://github.com/vurtun/nuklear/blob/master/example/file_browser.c (public domain) // file browser for nuklear, based on https://github.com/vurtun/nuklear/blob/master/example/file_browser.c (public domain)
// - rlyeh, public domain // - rlyeh, public domain
// //
// changelog: // changelog:
// - ported to V4K api // - ported to V4K api
// - namespaced symbols // - namespaced symbols
// - diverse win32 fixes // - diverse win32 fixes
// - adaptive cols/rows // - adaptive cols/rows
// - removed nk_begin()/nk_end() pairs // - removed nk_begin()/nk_end() pairs
// - dangling nk_group_begin/end() pairs // - dangling nk_group_begin/end() pairs
// - simplified file<->media_group concept // - simplified file<->media_group concept
// - minor cosmetics // - minor cosmetics
#ifdef _WIN32 #ifdef _WIN32
#include <direct.h> // _getcwd() #include <direct.h> // _getcwd()
#else #else
#include <unistd.h> // getcwd() #include <unistd.h> // getcwd()
#include <pwd.h> // getpwuid() #include <pwd.h> // getpwuid()
#define _popen popen #define _popen popen
#define _pclose pclose #define _pclose pclose
#endif #endif
const char** old_file_list(const char *cwd, const char *masks) { const char** old_file_list(const char *cwd, const char *masks) {
ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd);
static __thread array(char*) list = 0; static __thread array(char*) list = 0;
const char *arg0 = cwd; // app_path(); const char *arg0 = cwd; // app_path();
int larg0 = strlen(arg0); int larg0 = strlen(arg0);
for( int i = 0; i < array_count(list); ++i ) { for( int i = 0; i < array_count(list); ++i ) {
FREE(list[i]); FREE(list[i]);
} }
array_resize(list, 0);//array_free(list); array_resize(list, 0);//array_free(list);
for each_substring(masks,";",it) { for each_substring(masks,";",it) {
int recurse = !!strstr(it, "**"); int recurse = !!strstr(it, "**");
#if is(win32) #if is(win32)
char *glob = va("dir %s/b/o:n \"%s\\%s\" 2> NUL", recurse ? "/s":"", cwd, it); char *glob = va("dir %s/b/o:n \"%s\\%s\" 2> NUL", recurse ? "/s":"", cwd, it);
#else // linux, osx #else // linux, osx
char *glob = va("find %s %s -name \"%s\" | sort", cwd, !recurse ? "-maxdepth 1":"-type f", it); char *glob = va("find %s %s -name \"%s\" | sort", cwd, !recurse ? "-maxdepth 1":"-type f", it);
#endif #endif
for( FILE *in = _popen(glob, "r"); in; _pclose(in), in = 0) { for( FILE *in = _popen(glob, "r"); in; _pclose(in), in = 0) {
char buf[1024], *line = buf; char buf[1024], *line = buf;
while( fgets(buf, sizeof(buf), in) ) { while( fgets(buf, sizeof(buf), in) ) {
// clean up // clean up
if( strstr(line, arg0) ) line = buf + larg0; if( strstr(line, arg0) ) line = buf + larg0;
if( !memcmp(line, "./", 2) ) line += 2; if( !memcmp(line, "./", 2) ) line += 2;
int len = strlen(line); while( len > 0 && line[len-1] < 32 ) line[--len] = 0; int len = strlen(line); while( len > 0 && line[len-1] < 32 ) line[--len] = 0;
if( line[0] == '\0' ) continue; if( line[0] == '\0' ) continue;
// do not insert system folders/files // do not insert system folders/files
for(int i = 0; i < len; ++i ) if(line[i] == '\\') line[i] = '/'; for(int i = 0; i < len; ++i ) if(line[i] == '\\') line[i] = '/';
if( line[0] == '.' ) if( !strcmp(line,".git") || !strcmp(line,".vs") || !strcmp(line,".") || !strcmp(line,"..") ) continue; if( line[0] == '.' ) if( !strcmp(line,".git") || !strcmp(line,".vs") || !strcmp(line,".") || !strcmp(line,"..") ) continue;
if( strstr(line, "/.") ) continue; if( strstr(line, "/.") ) continue;
// insert copy // insert copy
#if is(win32) #if is(win32)
char *copy = STRDUP(line); // full path already provided char *copy = STRDUP(line); // full path already provided
#else #else
// while(line[0] == '/') ++line; // while(line[0] == '/') ++line;
char *copy = STRDUP(va("%s%s", cwd, line)); // need to prepend path char *copy = STRDUP(va("%s%s", cwd, line)); // need to prepend path
#endif #endif
array_push(list, copy); array_push(list, copy);
} }
} }
} }
array_push(list, 0); // terminator array_push(list, 0); // terminator
return (const char**)list; return (const char**)list;
} }
#if 1 #if 1
#define BROWSER_PRINTF(...) do {} while(0) #define BROWSER_PRINTF(...) do {} while(0)
#else #else
#define BROWSER_PRINTF printf #define BROWSER_PRINTF printf
#endif #endif
enum browser_groups { enum browser_groups {
BROWSER_FOLDER, BROWSER_FOLDER,
BROWSER_HOME, BROWSER_HOME,
BROWSER_DESKTOP, BROWSER_DESKTOP,
BROWSER_COMPUTER, BROWSER_COMPUTER,
BROWSER_PROJECT, BROWSER_PROJECT,
BROWSER_MAXFOLDERS, BROWSER_MAXFOLDERS,
BROWSER_MAXTYPES = 64, BROWSER_MAXTYPES = 64,
}; };
struct browser_media_group { struct browser_media_group {
unsigned icon; unsigned icon;
const char *extensions; const char *extensions;
}; };
struct browser_media { struct browser_media {
int font; int font;
int icon_sheet; int icon_sheet;
struct nk_image custom_folders[BROWSER_MAXFOLDERS]; struct nk_image custom_folders[BROWSER_MAXFOLDERS];
struct nk_image custom_files[BROWSER_MAXTYPES]; struct nk_image custom_files[BROWSER_MAXTYPES];
struct browser_media_group group[BROWSER_MAXTYPES]; struct browser_media_group group[BROWSER_MAXTYPES];
} media = {0}; } media = {0};
void browser_config_dir(struct nk_image icon, unsigned counter) { void browser_config_dir(struct nk_image icon, unsigned counter) {
if( counter < BROWSER_MAXFOLDERS ) { if( counter < BROWSER_MAXFOLDERS ) {
media.custom_folders[ counter ] = icon; media.custom_folders[ counter ] = icon;
} }
} }
void browser_config_type(struct nk_image icon, const char *extensions) { void browser_config_type(struct nk_image icon, const char *extensions) {
static int counter = 0; static int counter = 0;
if( counter < BROWSER_MAXTYPES ) { if( counter < BROWSER_MAXTYPES ) {
media.custom_files[ counter ] = icon; media.custom_files[ counter ] = icon;
media.group[ counter ].icon = counter; media.group[ counter ].icon = counter;
media.group[ counter ].extensions = extensions; media.group[ counter ].extensions = extensions;
++counter; ++counter;
} }
} }
#define BROWSER_MAX_PATH 512 #define BROWSER_MAX_PATH 512
struct browser { struct browser {
/* path */ /* path */
char file[BROWSER_MAX_PATH]; // selection char file[BROWSER_MAX_PATH]; // selection
char directory[BROWSER_MAX_PATH]; // current cwd while browsing char directory[BROWSER_MAX_PATH]; // current cwd while browsing
char home[BROWSER_MAX_PATH]; char home[BROWSER_MAX_PATH];
char desktop[BROWSER_MAX_PATH]; char desktop[BROWSER_MAX_PATH];
char computer[BROWSER_MAX_PATH]; char computer[BROWSER_MAX_PATH];
char project[BROWSER_MAX_PATH]; // cwd when first invoked char project[BROWSER_MAX_PATH]; // cwd when first invoked
/* directory content */ /* directory content */
array(char*) files; array(char*) files;
array(char*) directories; array(char*) directories;
size_t file_count; size_t file_count;
size_t dir_count; size_t dir_count;
/* filtered directory content */ /* filtered directory content */
array(char*) ffiles; array(char*) ffiles;
array(char*) fdirectories; array(char*) fdirectories;
/* view mode */ /* view mode */
bool listing; bool listing;
float zooming; float zooming;
}; };
static struct nk_image* media_icon_for_file(const char *file) { static struct nk_image* media_icon_for_file(const char *file) {
/* extract extension .xxx from file */ /* extract extension .xxx from file */
char *ext = strrchr(file, '.'); char *ext = strrchr(file, '.');
if( ext && strlen(ext) < 16 ) { if( ext && strlen(ext) < 16 ) {
char ext_dot[16+1]; char ext_dot[16+1];
snprintf(ext_dot, 16, "%s.", ext); snprintf(ext_dot, 16, "%s.", ext);
/* check for all file definition of all groups for fitting extension. skip first group (default) */ /* check for all file definition of all groups for fitting extension. skip first group (default) */
for (int i = 1; i < BROWSER_MAXTYPES && media.group[i].extensions; ++i) { for (int i = 1; i < BROWSER_MAXTYPES && media.group[i].extensions; ++i) {
if( strstri(media.group[i].extensions, ext_dot) ) { if( strstri(media.group[i].extensions, ext_dot) ) {
return &media.custom_files[ media.group[i].icon ]; return &media.custom_files[ media.group[i].icon ];
} }
} }
} }
// return first (default) group // return first (default) group
return &media.custom_files[0]; return &media.custom_files[0];
} }
static void browser_reload_directory_content(struct browser *browser, const char *path) { static void browser_reload_directory_content(struct browser *browser, const char *path) {
if(path[0] == '\0') path = va("./"); if(path[0] == '\0') path = va("./");
if(!strend(path, "/")) path = va("%s/", path); if(!strend(path, "/")) path = va("%s/", path);
for(int i = 0; i < array_count(browser->files); ++i) FREE(browser->files[i]); for(int i = 0; i < array_count(browser->files); ++i) FREE(browser->files[i]);
for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]); for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]);
array_resize(browser->files, 0); array_resize(browser->files, 0);
array_resize(browser->directories, 0); array_resize(browser->directories, 0);
BROWSER_PRINTF("searching at %s\n", path); BROWSER_PRINTF("searching at %s\n", path);
const char** list = old_file_list(path, "*"); const char** list = old_file_list(path, "*");
for( int i = 0; list[i]; ++i ) { for( int i = 0; list[i]; ++i ) {
char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext
BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) ); BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) );
if( file_directory(absolute) ) { if( file_directory(absolute) ) {
// remove last '/' if present. ok to overwrite absolute var, file_*() API returns writeable strings. // remove last '/' if present. ok to overwrite absolute var, file_*() API returns writeable strings.
char *dir = absolute; if( dir[ strlen(dir) - 1 ] == '/' ) dir[ strlen(dir) - 1 ] = '\0'; char *dir = absolute; if( dir[ strlen(dir) - 1 ] == '/' ) dir[ strlen(dir) - 1 ] = '\0';
dir = file_name(dir); // /home/rlyeh/prj/v4k/art -> art dir = file_name(dir); // /home/rlyeh/prj/v4k/art -> art
BROWSER_PRINTF("%s\n", dir); BROWSER_PRINTF("%s\n", dir);
if( dir[0] != '.' ) // skip special files, folders and internal files like .git or .art.zip if( dir[0] != '.' ) // skip special files, folders and internal files like .git or .art.zip
array_push(browser->directories, STRDUP(dir)); array_push(browser->directories, STRDUP(dir));
} else { } else {
const char *fname = file_name(absolute); const char *fname = file_name(absolute);
BROWSER_PRINTF("%s\n", fname); BROWSER_PRINTF("%s\n", fname);
if( fname[0] != '.' ) // skip special files, folders and internal files like .git or .art.zip if( fname[0] != '.' ) // skip special files, folders and internal files like .git or .art.zip
array_push(browser->files, STRDUP(fname)); array_push(browser->files, STRDUP(fname));
} }
} }
browser->file_count = array_count(browser->files); browser->file_count = array_count(browser->files);
browser->dir_count = array_count(browser->directories); browser->dir_count = array_count(browser->directories);
} }
static void browser_chdir_and_reload_directory_content(struct browser *browser, const char *path) { static void browser_chdir_and_reload_directory_content(struct browser *browser, const char *path) {
if( path != browser->directory ) strncpy(browser->directory, path, BROWSER_MAX_PATH); if( path != browser->directory ) strncpy(browser->directory, path, BROWSER_MAX_PATH);
browser_reload_directory_content(browser, path); browser_reload_directory_content(browser, path);
} }
static void browser_init(struct browser *browser) { static void browser_init(struct browser *browser) {
memset(browser, 0, sizeof(*browser)); memset(browser, 0, sizeof(*browser));
{ {
/* load files and sub-directory list */ /* load files and sub-directory list */
const char *home = getenv("HOME"); const char *home = getenv("HOME");
#ifdef _WIN32 #ifdef _WIN32
if (!home) home = getenv("USERPROFILE"); if (!home) home = getenv("USERPROFILE");
#else #else
if (!home) home = getpwuid(getuid())->pw_dir; if (!home) home = getpwuid(getuid())->pw_dir;
#endif #endif
snprintf(browser->home, BROWSER_MAX_PATH, "%s/", home); snprintf(browser->home, BROWSER_MAX_PATH, "%s/", home);
snprintf(browser->desktop, BROWSER_MAX_PATH, "%s/Desktop/", home); snprintf(browser->desktop, BROWSER_MAX_PATH, "%s/Desktop/", home);
snprintf(browser->computer, BROWSER_MAX_PATH, "%s", ifdef(win32, va("%.*s", 3, getenv("windir")), "/")); snprintf(browser->computer, BROWSER_MAX_PATH, "%s", ifdef(win32, va("%.*s", 3, getenv("windir")), "/"));
{ {
ifdef(win32, _getcwd, getcwd)(browser->project, sizeof(browser->project) - 1); // -1 == room for '/' ifdef(win32, _getcwd, getcwd)(browser->project, sizeof(browser->project) - 1); // -1 == room for '/'
strcat(browser->project, "/"); strcat(browser->project, "/");
} }
BROWSER_PRINTF("%s\n", browser->home); BROWSER_PRINTF("%s\n", browser->home);
BROWSER_PRINTF("%s\n", browser->desktop); BROWSER_PRINTF("%s\n", browser->desktop);
BROWSER_PRINTF("%s\n", browser->computer); BROWSER_PRINTF("%s\n", browser->computer);
BROWSER_PRINTF("%s\n", browser->project); BROWSER_PRINTF("%s\n", browser->project);
browser_chdir_and_reload_directory_content(browser, browser->project); browser_chdir_and_reload_directory_content(browser, browser->project);
} }
} }
static void browser_free(struct browser *browser) { static void browser_free(struct browser *browser) {
for(int i = 0; i < array_count(browser->files); ++i) FREE(browser->files[i]); for(int i = 0; i < array_count(browser->files); ++i) FREE(browser->files[i]);
for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]); for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]);
array_free(browser->files); array_free(browser->files);
array_free(browser->directories); array_free(browser->directories);
array_free(browser->ffiles); array_free(browser->ffiles);
array_free(browser->fdirectories); array_free(browser->fdirectories);
memset(browser, 0, sizeof(*browser)); memset(browser, 0, sizeof(*browser));
} }
static int browser_run(struct nk_context *ctx, struct browser *browser, int windowed, struct nk_rect total_space) { static int browser_run(struct nk_context *ctx, struct browser *browser, int windowed, struct nk_rect total_space) {
int clicked = 0; int clicked = 0;
static float ratio[] = {0.25f, NK_UNDEFINED}; static float ratio[] = {0.25f, NK_UNDEFINED};
float spacing_x = ctx->style.window.spacing.x; float spacing_x = ctx->style.window.spacing.x;
/* output path directory selector in the menubar */ /* output path directory selector in the menubar */
ctx->style.window.spacing.x = 0; ctx->style.window.spacing.x = 0;
if( windowed ) nk_menubar_begin(ctx); if( windowed ) nk_menubar_begin(ctx);
{ {
char *d = browser->directory; char *d = browser->directory;
#ifdef _WIN32 #ifdef _WIN32
char *begin = d; char *begin = d;
#else #else
char *begin = d + 1; char *begin = d + 1;
#endif #endif
nk_layout_row_template_begin(ctx, 25); nk_layout_row_template_begin(ctx, 25);
nk_layout_row_template_push_variable(ctx, 40); nk_layout_row_template_push_variable(ctx, 40);
nk_layout_row_template_push_variable(ctx, 40); nk_layout_row_template_push_variable(ctx, 40);
nk_layout_row_template_push_variable(ctx, 40); nk_layout_row_template_push_variable(ctx, 40);
nk_layout_row_template_end(ctx); nk_layout_row_template_end(ctx);
if (nk_button_label(ctx, !browser->listing ? ICON_MD_LIST : ICON_MD_GRID_VIEW)) { if (nk_button_label(ctx, !browser->listing ? ICON_MD_LIST : ICON_MD_GRID_VIEW)) {
browser->listing ^= 1; browser->listing ^= 1;
} }
while (*d++) { while (*d++) {
if (*d == '/') { if (*d == '/') {
*d = '\0'; *d = '\0';
if (nk_button_label(ctx, va("%s" ICON_MD_ARROW_RIGHT, file_name(begin)))) { if (nk_button_label(ctx, va("%s" ICON_MD_ARROW_RIGHT, file_name(begin)))) {
*d++ = '/'; *d = '\0'; *d++ = '/'; *d = '\0';
browser_chdir_and_reload_directory_content(browser, browser->directory); browser_chdir_and_reload_directory_content(browser, browser->directory);
break; break;
} }
*d = '/'; *d = '/';
begin = d + 1; begin = d + 1;
} }
} }
} }
if( windowed ) nk_menubar_end(ctx); if( windowed ) nk_menubar_end(ctx);
ctx->style.window.spacing.x = spacing_x; ctx->style.window.spacing.x = spacing_x;
if(nk_window_has_focus(ctx)) { if(nk_window_has_focus(ctx)) {
browser->zooming = clampf( browser->zooming + (input(KEY_LCTRL) || input(KEY_RCTRL)) * input_diff(MOUSE_W) * 0.1, 1, 3); browser->zooming = clampf( browser->zooming + (input(KEY_LCTRL) || input(KEY_RCTRL)) * input_diff(MOUSE_W) * 0.1, 1, 3);
} }
bool compact = 0, tiny = browser->listing; // compact, no left panel. tiny, no large icons bool compact = 0, tiny = browser->listing; // compact, no left panel. tiny, no large icons
size_t cols = total_space.w / (100 * browser->zooming); size_t cols = total_space.w / (100 * browser->zooming);
int icon_height = (67 * browser->zooming) * (tiny ? 0.33 : 1.); // icon height (96) + button padding (??). originally: 135 int icon_height = (67 * browser->zooming) * (tiny ? 0.33 : 1.); // icon height (96) + button padding (??). originally: 135
/**/ if( tiny ) cols = (int)cols+1.5, cols /= 2, compact = total_space.w < 500; // cols <= 2; /**/ if( tiny ) cols = (int)cols+1.5, cols /= 2, compact = total_space.w < 500; // cols <= 2;
else cols = (int)cols+1, compact = total_space.w < 500; // cols <= 5; else cols = (int)cols+1, compact = total_space.w < 500; // cols <= 5;
if( cols < 1 ) cols=1; if( cols < 1 ) cols=1;
/* window layout */ /* window layout */
nk_layout_row(ctx, NK_DYNAMIC, total_space.h, compact ? 1 : 2, compact ? ratio+1 : ratio); nk_layout_row(ctx, NK_DYNAMIC, total_space.h, compact ? 1 : 2, compact ? ratio+1 : ratio);
if( !compact ) if( !compact )
if( nk_group_begin(ctx, "Special", NK_WINDOW_NO_SCROLLBAR) ) { if( nk_group_begin(ctx, "Special", NK_WINDOW_NO_SCROLLBAR) ) {
nk_layout_row_dynamic(ctx, 40, 1); nk_layout_row_dynamic(ctx, 40, 1);
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_HOME],"Home",NK_TEXT_RIGHT)) if (nk_button_image_label(ctx,media.custom_folders[BROWSER_HOME],"Home",NK_TEXT_RIGHT))
browser_chdir_and_reload_directory_content(browser, browser->home); browser_chdir_and_reload_directory_content(browser, browser->home);
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_DESKTOP],"Desktop",NK_TEXT_RIGHT)) if (nk_button_image_label(ctx,media.custom_folders[BROWSER_DESKTOP],"Desktop",NK_TEXT_RIGHT))
browser_chdir_and_reload_directory_content(browser, browser->desktop); browser_chdir_and_reload_directory_content(browser, browser->desktop);
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_COMPUTER],"Computer",NK_TEXT_RIGHT)) if (nk_button_image_label(ctx,media.custom_folders[BROWSER_COMPUTER],"Computer",NK_TEXT_RIGHT))
browser_chdir_and_reload_directory_content(browser, browser->computer); browser_chdir_and_reload_directory_content(browser, browser->computer);
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_PROJECT],"Project",NK_TEXT_RIGHT)) if (nk_button_image_label(ctx,media.custom_folders[BROWSER_PROJECT],"Project",NK_TEXT_RIGHT))
browser_chdir_and_reload_directory_content(browser, browser->project); browser_chdir_and_reload_directory_content(browser, browser->project);
nk_group_end(ctx); nk_group_end(ctx);
} }
/* output directory content window */ /* output directory content window */
if(nk_group_begin(ctx, "Content", windowed ? NK_WINDOW_NO_SCROLLBAR : 0)) { if(nk_group_begin(ctx, "Content", windowed ? NK_WINDOW_NO_SCROLLBAR : 0)) {
array(char*) *directories = &browser->directories; array(char*) *directories = &browser->directories;
array(char*) *files = &browser->files; array(char*) *files = &browser->files;
if( ui_filter && ui_filter[0] ) { if( ui_filter && ui_filter[0] ) {
array_resize(browser->fdirectories, 0); array_resize(browser->fdirectories, 0);
array_resize(browser->ffiles, 0); array_resize(browser->ffiles, 0);
for each_array(browser->directories,char*,k) for each_array(browser->directories,char*,k)
if( strstri(k, ui_filter) ) if( strstri(k, ui_filter) )
array_push(browser->fdirectories, k); array_push(browser->fdirectories, k);
for each_array(browser->files,char*,k) for each_array(browser->files,char*,k)
if( strstri(k, ui_filter) ) if( strstri(k, ui_filter) )
array_push(browser->ffiles, k); array_push(browser->ffiles, k);
directories = &browser->fdirectories; directories = &browser->fdirectories;
files = &browser->ffiles; files = &browser->ffiles;
} }
int dir_count = array_count(*directories); int dir_count = array_count(*directories);
int file_count = array_count(*files); int file_count = array_count(*files);
int index = -1; int index = -1;
size_t i = 0, j = 0, k = 0; size_t i = 0, j = 0, k = 0;
size_t rows = 0; size_t rows = 0;
size_t count = dir_count + file_count; size_t count = dir_count + file_count;
rows = count / cols; rows = count / cols;
for (i = 0; i <= rows; i += 1) { for (i = 0; i <= rows; i += 1) {
if(!tiny) if(!tiny)
{size_t n = j + cols; {size_t n = j + cols;
nk_layout_row_dynamic(ctx, icon_height, (int)cols); nk_layout_row_dynamic(ctx, icon_height, (int)cols);
for (; j < count && j < n; ++j) { for (; j < count && j < n; ++j) {
size_t t = j-dir_count; size_t t = j-dir_count;
/* draw one row of icons */ /* draw one row of icons */
if (j < dir_count) { if (j < dir_count) {
/* draw and execute directory buttons */ /* draw and execute directory buttons */
if (nk_button_image(ctx,media.custom_folders[BROWSER_FOLDER])) if (nk_button_image(ctx,media.custom_folders[BROWSER_FOLDER]))
index = (int)j; index = (int)j;
} else { } else {
/* draw and execute files buttons */ /* draw and execute files buttons */
struct nk_image *icon; struct nk_image *icon;
size_t fileIndex = ((size_t)j - dir_count); size_t fileIndex = ((size_t)j - dir_count);
icon = media_icon_for_file((*files)[fileIndex]); icon = media_icon_for_file((*files)[fileIndex]);
if (nk_button_image(ctx, *icon)) { if (nk_button_image(ctx, *icon)) {
snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]);
clicked = 1; clicked = 1;
} }
} }
}} }}
if(!tiny) if(!tiny)
{size_t n = k + cols; {size_t n = k + cols;
nk_layout_row_dynamic(ctx, 20, (int)cols); nk_layout_row_dynamic(ctx, 20, (int)cols);
for (; k < count && k < n; k++) { for (; k < count && k < n; k++) {
size_t t = k-dir_count; size_t t = k-dir_count;
/* draw one row of labels */ /* draw one row of labels */
if (k < dir_count) { if (k < dir_count) {
nk_label(ctx, (*directories)[k], NK_TEXT_CENTERED); nk_label(ctx, (*directories)[k], NK_TEXT_CENTERED);
} else { } else {
nk_label(ctx, (*files)[t], NK_TEXT_CENTERED); nk_label(ctx, (*files)[t], NK_TEXT_CENTERED);
} }
}} }}
if(tiny) if(tiny)
{size_t n = j + cols; {size_t n = j + cols;
nk_layout_row_dynamic(ctx, icon_height, (int)cols); nk_layout_row_dynamic(ctx, icon_height, (int)cols);
for (; j < count && j < n; ++j) { for (; j < count && j < n; ++j) {
size_t t = j-dir_count; size_t t = j-dir_count;
/* draw one row of icons */ /* draw one row of icons */
if (j < dir_count) { if (j < dir_count) {
/* draw and execute directory buttons */ /* draw and execute directory buttons */
if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], (*directories)[j], NK_TEXT_RIGHT)) if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], (*directories)[j], NK_TEXT_RIGHT))
index = (int)j; index = (int)j;
} else { } else {
/* draw and execute files buttons */ /* draw and execute files buttons */
struct nk_image *icon; struct nk_image *icon;
size_t fileIndex = ((size_t)j - dir_count); size_t fileIndex = ((size_t)j - dir_count);
icon = media_icon_for_file((*files)[fileIndex]); icon = media_icon_for_file((*files)[fileIndex]);
if (nk_button_image_label(ctx, *icon, (*files)[t],NK_TEXT_RIGHT)) { if (nk_button_image_label(ctx, *icon, (*files)[t],NK_TEXT_RIGHT)) {
snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]);
clicked = 1; clicked = 1;
} }
} }
#if 0 #if 0
bool has_focus = nk_window_has_focus(ctx); // @fixme: move out of loop bool has_focus = nk_window_has_focus(ctx); // @fixme: move out of loop
bool has_popups = ui_popups(); // @fixme: move out of loop bool has_popups = ui_popups(); // @fixme: move out of loop
if( !has_popups && has_focus ) { if( !has_popups && has_focus ) {
struct nk_rect bounds = nk_widget_bounds(ctx); struct nk_rect bounds = nk_widget_bounds(ctx);
if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds) ) { if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds) ) {
char *name = j < dir_count ? (*directories)[j] : (*files)[j-dir_count]; char *name = j < dir_count ? (*directories)[j] : (*files)[j-dir_count];
char fullpath[PATH_MAX]; char fullpath[PATH_MAX];
snprintf(fullpath, PATH_MAX, "%s%s", browser->directory, name); snprintf(fullpath, PATH_MAX, "%s%s", browser->directory, name);
struct stat t = {0}; struct stat t = {0};
if( stat( fullpath, &t ) != -1 ) { if( stat( fullpath, &t ) != -1 ) {
char tooltip[256]; char tooltip[256];
snprintf(tooltip, 256, snprintf(tooltip, 256,
"Path: %s\n" "Path: %s\n"
"Type: %lld\n" // file type and mode "Type: %lld\n" // file type and mode
"Size: %lld\n" // file size "Size: %lld\n" // file size
"Owner: %lld\n" // user ID of file owner "Owner: %lld\n" // user ID of file owner
"Modified: %s (%lld)", // last modification date "Modified: %s (%lld)", // last modification date
name, (int64_t)t.st_mode, (int64_t)t.st_size, (int64_t)t.st_uid, ctime(&t.st_mtime), (int64_t)t.st_mtime name, (int64_t)t.st_mode, (int64_t)t.st_size, (int64_t)t.st_uid, ctime(&t.st_mtime), (int64_t)t.st_mtime
); );
nk_tooltip(ctx, tooltip); nk_tooltip(ctx, tooltip);
} }
} }
} }
#endif #endif
}} }}
} }
if (index != -1) { if (index != -1) {
BROWSER_PRINTF("%s + %s = ", browser->directory, browser->directories[index]); BROWSER_PRINTF("%s + %s = ", browser->directory, browser->directories[index]);
size_t n = strlen(browser->directory); size_t n = strlen(browser->directory);
snprintf(browser->directory + n, BROWSER_MAX_PATH - n, "%s/", browser->directories[index]); snprintf(browser->directory + n, BROWSER_MAX_PATH - n, "%s/", browser->directories[index]);
BROWSER_PRINTF("%s\n", browser->directory); BROWSER_PRINTF("%s\n", browser->directory);
browser_chdir_and_reload_directory_content(browser, browser->directory); browser_chdir_and_reload_directory_content(browser, browser->directory);
} }
nk_group_end(ctx); nk_group_end(ctx);
} }
return clicked; return clicked;
} }
static struct nk_image icon_load(const char *filename) { static struct nk_image icon_load(const char *filename) {
texture_t t = texture(filename, 0); texture_t t = texture(filename, 0);
return nk_image_id((int)t.id); return nk_image_id((int)t.id);
} }
static struct nk_image icon_load_rect(unsigned id, unsigned w, unsigned h, unsigned wcell, unsigned hcell, unsigned col, unsigned row) { static struct nk_image icon_load_rect(unsigned id, unsigned w, unsigned h, unsigned wcell, unsigned hcell, unsigned col, unsigned row) {
return nk_subimage_id((int)id, w, h, (struct nk_rect){ wcell * col, hcell * row, wcell, hcell }); return nk_subimage_id((int)id, w, h, (struct nk_rect){ wcell * col, hcell * row, wcell, hcell });
} }
/* demo: /* demo:
struct browser browser = {0}; struct browser browser = {0};
browser_init(&browser); browser_init(&browser);
browser_config_dir(nk_image, BROWSER_HOME); browser_config_dir(nk_image, BROWSER_HOME);
browser_config_dir(nk_image, BROWSER_PROJECT); browser_config_dir(nk_image, BROWSER_PROJECT);
// [...] // [...]
browser_config_type(nk_image, ".ext1.ext2.ext3."); browser_config_type(nk_image, ".ext1.ext2.ext3.");
browser_config_type(nk_image, ".ext1.ext2.ext3."); browser_config_type(nk_image, ".ext1.ext2.ext3.");
browser_config_type(nk_image, ".ext1.ext2.ext3."); browser_config_type(nk_image, ".ext1.ext2.ext3.");
// [...] // [...]
[...] [...]
if( nk_begin(ctx, "window", ...) ) { if( nk_begin(ctx, "window", ...) ) {
struct nk_rect total_space = nk_window_get_content_region(ctx); struct nk_rect total_space = nk_window_get_content_region(ctx);
if( browser_run(ctx, &browser, 0, total_space) ) { if( browser_run(ctx, &browser, 0, total_space) ) {
puts( browser->directory ); puts( browser->directory );
puts( browser->file ); puts( browser->file );
} }
} }
nk_end(); nk_end();
*/ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,409 +1,409 @@
/* Progressive Mesh type Polygon Reduction Algorithm /* Progressive Mesh type Polygon Reduction Algorithm
* *
* 1998: Original version by Stan Melax (c) 1998 * 1998: Original version by Stan Melax (c) 1998
* Permission to use any of this code wherever you want is granted.. * Permission to use any of this code wherever you want is granted..
* Although, please do acknowledge authorship if appropriate. * Although, please do acknowledge authorship if appropriate.
* *
* 2014: Code style upgraded to be more consistent with graphics/gamedev conventions. Relicensed as MIT/PD. * 2014: Code style upgraded to be more consistent with graphics/gamedev conventions. Relicensed as MIT/PD.
* Stan Melax: "Yes, this code can be licensed with the same license as the original. That should be fine." * Stan Melax: "Yes, this code can be licensed with the same license as the original. That should be fine."
* *
* 2020: C version by Cloud Wu (c) 2020. Licensed as MIT/PD. * 2020: C version by Cloud Wu (c) 2020. Licensed as MIT/PD.
*/ */
static inline void array_find_and_remove(array(int) arr, int v) { static inline void array_find_and_remove(array(int) arr, int v) {
for( int i = 0, end = array_count(arr); i < end; i++ ) for( int i = 0, end = array_count(arr); i < end; i++ )
if( arr[i] == v ) { array_erase_fast(arr, i); --end; break; } if( arr[i] == v ) { array_erase_fast(arr, i); --end; break; }
} }
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
struct triangle_n { struct triangle_n {
int vertex[3]; // the 3 points (id) that make this tri int vertex[3]; // the 3 points (id) that make this tri
vec3 normal; // unit vector othogonal to this face vec3 normal; // unit vector othogonal to this face
}; };
struct vertex { struct vertex {
vec3 position; // location of point in euclidean space vec3 position; // location of point in euclidean space
array(int) neighbor; // adjacent vertices array(int) neighbor; // adjacent vertices
array(int) face; // adjacent triangles array(int) face; // adjacent triangles
int id; // place of vertex in original Array int id; // place of vertex in original Array
int collapse; // candidate vertex (id) for collapse int collapse; // candidate vertex (id) for collapse
float objdist; // cached cost of collapsing edge float objdist; // cached cost of collapsing edge
}; };
struct mesh { struct mesh {
struct vertex *v; struct vertex *v;
struct triangle_n *t; struct triangle_n *t;
int n_face; int n_face;
int n_vertex; int n_vertex;
}; };
// array // array
static inline struct vertex *Vertex(struct mesh *M, int id) { return M->v + id; } static inline struct vertex *Vertex(struct mesh *M, int id) { return M->v + id; }
static inline struct triangle_n *Triangle(struct mesh *M, int id) { return M->t + id; } static inline struct triangle_n *Triangle(struct mesh *M, int id) { return M->t + id; }
static inline struct triangle_n *Face(struct mesh *M, struct vertex *v, int idx) { return M->t + v->face[idx]; } static inline struct triangle_n *Face(struct mesh *M, struct vertex *v, int idx) { return M->t + v->face[idx]; }
static void AddVertex(struct mesh *M, const float *v) { static void AddVertex(struct mesh *M, const float *v) {
int id = M->n_vertex++; int id = M->n_vertex++;
struct vertex * tmp = Vertex(M, id); struct vertex * tmp = Vertex(M, id);
tmp->position = ptr3(v); tmp->position = ptr3(v);
tmp->neighbor = NULL; tmp->neighbor = NULL;
tmp->face = NULL; tmp->face = NULL;
tmp->id = id; tmp->id = id;
tmp->collapse = -1; tmp->collapse = -1;
tmp->objdist = 0; tmp->objdist = 0;
} }
static void RemoveVertex(struct mesh *M, int id) { static void RemoveVertex(struct mesh *M, int id) {
struct vertex * v = Vertex(M, id); struct vertex * v = Vertex(M, id);
ASSERT(v->id == id); ASSERT(v->id == id);
ASSERT(array_count(v->face) == 0); ASSERT(array_count(v->face) == 0);
for (int i=0;i<array_count(v->face);i++) { for (int i=0;i<array_count(v->face);i++) {
struct vertex * nv = Vertex(M, v->face[i]); struct vertex * nv = Vertex(M, v->face[i]);
array_find_and_remove(nv->neighbor, id); array_find_and_remove(nv->neighbor, id);
} }
v->id = -1; // invalid vertex id v->id = -1; // invalid vertex id
array_free(v->neighbor); array_free(v->neighbor);
array_free(v->face); array_free(v->face);
} }
static void ComputeNormal(struct mesh *M, struct triangle_n *t) { static void ComputeNormal(struct mesh *M, struct triangle_n *t) {
struct vertex * v0 = Vertex(M, t->vertex[0]); struct vertex * v0 = Vertex(M, t->vertex[0]);
struct vertex * v1 = Vertex(M, t->vertex[1]); struct vertex * v1 = Vertex(M, t->vertex[1]);
struct vertex * v2 = Vertex(M, t->vertex[2]); struct vertex * v2 = Vertex(M, t->vertex[2]);
vec3 a = sub3(v1->position, v0->position); vec3 a = sub3(v1->position, v0->position);
vec3 b = sub3(v2->position, v1->position); vec3 b = sub3(v2->position, v1->position);
t->normal = norm3(cross3(a,b)); t->normal = norm3(cross3(a,b));
} }
static void AddNeighbor(struct mesh *M, int vid, int id) { static void AddNeighbor(struct mesh *M, int vid, int id) {
struct vertex *v = Vertex(M, vid); struct vertex *v = Vertex(M, vid);
for (int i=0;i<array_count(v->neighbor);i++) { for (int i=0;i<array_count(v->neighbor);i++) {
if (v->neighbor[i] == id) if (v->neighbor[i] == id)
return; return;
} }
array_push(v->neighbor, id); array_push(v->neighbor, id);
} }
static void AddTriangle(struct mesh *M, const int v[3]) { static void AddTriangle(struct mesh *M, const int v[3]) {
if (v[0] == v[1] || v[0] == v[2] || v[1] == v[2]) if (v[0] == v[1] || v[0] == v[2] || v[1] == v[2])
return; return;
ASSERT(v[0] < M->n_vertex); ASSERT(v[0] < M->n_vertex);
ASSERT(v[1] < M->n_vertex); ASSERT(v[1] < M->n_vertex);
ASSERT(v[2] < M->n_vertex); ASSERT(v[2] < M->n_vertex);
int id = M->n_face++; int id = M->n_face++;
struct triangle_n * tmp = Triangle(M, id); struct triangle_n * tmp = Triangle(M, id);
tmp->vertex[0] = v[0]; tmp->vertex[0] = v[0];
tmp->vertex[1] = v[1]; tmp->vertex[1] = v[1];
tmp->vertex[2] = v[2]; tmp->vertex[2] = v[2];
ComputeNormal(M, tmp); ComputeNormal(M, tmp);
for(int i=0;i<3;i++) { for(int i=0;i<3;i++) {
struct vertex *obj = Vertex(M, v[i]); struct vertex *obj = Vertex(M, v[i]);
array_push(obj->face, id); array_push(obj->face, id);
} }
AddNeighbor(M, v[0], v[1]); AddNeighbor(M, v[0], v[1]);
AddNeighbor(M, v[0], v[2]); AddNeighbor(M, v[0], v[2]);
AddNeighbor(M, v[1], v[0]); AddNeighbor(M, v[1], v[0]);
AddNeighbor(M, v[1], v[2]); AddNeighbor(M, v[1], v[2]);
AddNeighbor(M, v[2], v[0]); AddNeighbor(M, v[2], v[0]);
AddNeighbor(M, v[2], v[1]); AddNeighbor(M, v[2], v[1]);
} }
static int HasVertex(struct triangle_n * t, int vid) { static int HasVertex(struct triangle_n * t, int vid) {
return (t->vertex[0] == vid || t->vertex[1] == vid || t->vertex[2] == vid); return (t->vertex[0] == vid || t->vertex[1] == vid || t->vertex[2] == vid);
} }
static void RemoveIfNonNeighbor_(struct mesh *M, struct vertex *v, int id) { static void RemoveIfNonNeighbor_(struct mesh *M, struct vertex *v, int id) {
for (int i=0;i<array_count(v->neighbor);i++) { for (int i=0;i<array_count(v->neighbor);i++) {
if (v->neighbor[i] == id) { if (v->neighbor[i] == id) {
for (int j=0;j<array_count(v->face);j++) { for (int j=0;j<array_count(v->face);j++) {
if (HasVertex(Face(M, v, j), id)) if (HasVertex(Face(M, v, j), id))
return; return;
} }
// remove from neighbors // remove from neighbors
array_erase_fast(v->neighbor, i); array_erase_fast(v->neighbor, i);
return; return;
} }
} }
} }
static void RemoveIfNonNeighbor(struct mesh *M, struct vertex *v0, struct vertex *v1) { static void RemoveIfNonNeighbor(struct mesh *M, struct vertex *v0, struct vertex *v1) {
if (v0 == NULL || v1 == NULL) if (v0 == NULL || v1 == NULL)
return; return;
RemoveIfNonNeighbor_(M, v0, v1->id); RemoveIfNonNeighbor_(M, v0, v1->id);
RemoveIfNonNeighbor_(M, v1, v0->id); RemoveIfNonNeighbor_(M, v1, v0->id);
} }
static void RemoveTriangle(struct mesh *M, int id) { static void RemoveTriangle(struct mesh *M, int id) {
struct triangle_n * face = Triangle(M, id); struct triangle_n * face = Triangle(M, id);
struct vertex * v[3]; struct vertex * v[3];
for (int i=0;i<3;i++) { for (int i=0;i<3;i++) {
v[i] = Vertex(M, face->vertex[i]); v[i] = Vertex(M, face->vertex[i]);
if (v[i]->id < 0) if (v[i]->id < 0)
v[i] = NULL; v[i] = NULL;
else { else {
array_find_and_remove(v[i]->face, id); array_find_and_remove(v[i]->face, id);
} }
} }
RemoveIfNonNeighbor(M, v[0], v[1]); RemoveIfNonNeighbor(M, v[0], v[1]);
RemoveIfNonNeighbor(M, v[1], v[2]); RemoveIfNonNeighbor(M, v[1], v[2]);
RemoveIfNonNeighbor(M, v[2], v[0]); RemoveIfNonNeighbor(M, v[2], v[0]);
} }
static void ReplaceVertex(struct mesh *M, int faceid, int oldid, int newid) { static void ReplaceVertex(struct mesh *M, int faceid, int oldid, int newid) {
struct triangle_n * face = Triangle(M, faceid); struct triangle_n * face = Triangle(M, faceid);
ASSERT(oldid >=0 && newid >= 0); ASSERT(oldid >=0 && newid >= 0);
ASSERT(HasVertex(face, oldid)); ASSERT(HasVertex(face, oldid));
ASSERT(!HasVertex(face, newid)); ASSERT(!HasVertex(face, newid));
if(oldid==face->vertex[0]){ if(oldid==face->vertex[0]){
face->vertex[0]=newid; face->vertex[0]=newid;
} else if(oldid==face->vertex[1]){ } else if(oldid==face->vertex[1]){
face->vertex[1]=newid; face->vertex[1]=newid;
} else { } else {
face->vertex[2]=newid; face->vertex[2]=newid;
} }
struct vertex *vold = Vertex(M, oldid); struct vertex *vold = Vertex(M, oldid);
struct vertex *vnew = Vertex(M, newid); struct vertex *vnew = Vertex(M, newid);
array_find_and_remove(vold->face, faceid); array_find_and_remove(vold->face, faceid);
array_push(vnew->face, faceid); array_push(vnew->face, faceid);
RemoveIfNonNeighbor(M, vold, Vertex(M, face->vertex[0])); RemoveIfNonNeighbor(M, vold, Vertex(M, face->vertex[0]));
RemoveIfNonNeighbor(M, vold, Vertex(M, face->vertex[1])); RemoveIfNonNeighbor(M, vold, Vertex(M, face->vertex[1]));
RemoveIfNonNeighbor(M, vold, Vertex(M, face->vertex[2])); RemoveIfNonNeighbor(M, vold, Vertex(M, face->vertex[2]));
AddNeighbor(M, face->vertex[0], face->vertex[1]); AddNeighbor(M, face->vertex[0], face->vertex[1]);
AddNeighbor(M, face->vertex[0], face->vertex[2]); AddNeighbor(M, face->vertex[0], face->vertex[2]);
AddNeighbor(M, face->vertex[1], face->vertex[0]); AddNeighbor(M, face->vertex[1], face->vertex[0]);
AddNeighbor(M, face->vertex[1], face->vertex[2]); AddNeighbor(M, face->vertex[1], face->vertex[2]);
AddNeighbor(M, face->vertex[2], face->vertex[0]); AddNeighbor(M, face->vertex[2], face->vertex[0]);
AddNeighbor(M, face->vertex[2], face->vertex[1]); AddNeighbor(M, face->vertex[2], face->vertex[1]);
ComputeNormal(M, face); ComputeNormal(M, face);
} }
static void MeshInit(struct mesh *M, int vert_n, int tri_n) { static void MeshInit(struct mesh *M, int vert_n, int tri_n) {
M->n_face = 0; M->n_face = 0;
M->n_vertex = 0; M->n_vertex = 0;
M->v = (struct vertex *)MALLOC(vert_n * sizeof(struct vertex)); M->v = (struct vertex *)MALLOC(vert_n * sizeof(struct vertex));
M->t = (struct triangle_n *)MALLOC(tri_n * sizeof(struct triangle)); M->t = (struct triangle_n *)MALLOC(tri_n * sizeof(struct triangle));
} }
static void MeshFree(struct mesh *M) { static void MeshFree(struct mesh *M) {
FREE(M->v); FREE(M->v);
FREE(M->t); FREE(M->t);
} }
static float ComputeEdgeCollapseCost(struct mesh *M, struct vertex *u, int vid) { static float ComputeEdgeCollapseCost(struct mesh *M, struct vertex *u, int vid) {
// if we collapse edge uv by moving u to v then how // if we collapse edge uv by moving u to v then how
// much different will the model change, i.e. how much "error". // much different will the model change, i.e. how much "error".
// Texture, vertex normal, and border vertex code was removed // Texture, vertex normal, and border vertex code was removed
// to keep this demo as simple as possible. // to keep this demo as simple as possible.
// The method of determining cost was designed in order // The method of determining cost was designed in order
// to exploit small and coplanar regions for // to exploit small and coplanar regions for
// effective polygon reduction. // effective polygon reduction.
// Is is possible to add some checks here to see if "folds" // Is is possible to add some checks here to see if "folds"
// would be generated. i.e. normal of a remaining face gets // would be generated. i.e. normal of a remaining face gets
// flipped. I never seemed to run into this problem and // flipped. I never seemed to run into this problem and
// therefore never added code to detect this case. // therefore never added code to detect this case.
struct vertex *v = Vertex(M, vid); struct vertex *v = Vertex(M, vid);
vec3 tmp = sub3(v->position, u->position); vec3 tmp = sub3(v->position, u->position);
float edgelength = len3(tmp); float edgelength = len3(tmp);
float curvature=0; float curvature=0;
// find the "sides" triangles that are on the edge uv // find the "sides" triangles that are on the edge uv
array(int) sides = 0; array(int) sides = 0;
for (int i = 0; i<array_count(u->face); i++) { for (int i = 0; i<array_count(u->face); i++) {
if (HasVertex(Face(M, u, i), vid)) { if (HasVertex(Face(M, u, i), vid)) {
array_push(sides, u->face[i]); array_push(sides, u->face[i]);
} }
} }
// use the triangle facing most away from the sides // use the triangle facing most away from the sides
// to determine our curvature term // to determine our curvature term
for (int i = 0; i<array_count(u->face); i++) { for (int i = 0; i<array_count(u->face); i++) {
float mincurv=1; // curve for face i and closer side to it float mincurv=1; // curve for face i and closer side to it
for (int j = 0; j<array_count(sides); j++) { for (int j = 0; j<array_count(sides); j++) {
float dotprod = dot3(Triangle(M, u->face[i])->normal, float dotprod = dot3(Triangle(M, u->face[i])->normal,
Triangle(M, sides[j])->normal); // use dot product of face normals. Triangle(M, sides[j])->normal); // use dot product of face normals.
float t = (1-dotprod)/2.0f; float t = (1-dotprod)/2.0f;
if (t < mincurv) { if (t < mincurv) {
mincurv = t; mincurv = t;
} }
} }
if (mincurv > curvature) if (mincurv > curvature)
curvature = mincurv; curvature = mincurv;
} }
array_free(sides); array_free(sides);
// the more coplanar the lower the curvature term // the more coplanar the lower the curvature term
return edgelength * curvature; return edgelength * curvature;
} }
static void ComputeEdgeCostAtVertex(struct mesh *M, struct vertex *v) { static void ComputeEdgeCostAtVertex(struct mesh *M, struct vertex *v) {
// compute the edge collapse cost for all edges that start // compute the edge collapse cost for all edges that start
// from vertex v. Since we are only interested in reducing // from vertex v. Since we are only interested in reducing
// the object by selecting the min cost edge at each step, we // the object by selecting the min cost edge at each step, we
// only cache the cost of the least cost edge at this vertex // only cache the cost of the least cost edge at this vertex
// (in member variable collapse) as well as the value of the // (in member variable collapse) as well as the value of the
// cost (in member variable objdist). // cost (in member variable objdist).
if (array_count(v->neighbor) == 0) { if (array_count(v->neighbor) == 0) {
// v doesn't have neighbors so it costs nothing to collapse // v doesn't have neighbors so it costs nothing to collapse
v->collapse=-1; v->collapse=-1;
v->objdist=-0.01f; v->objdist=-0.01f;
return; return;
} }
v->objdist = 1000000; v->objdist = 1000000;
v->collapse=-1; v->collapse=-1;
// search all neighboring edges for "least cost" edge // search all neighboring edges for "least cost" edge
for (int i = 0; i<array_count(v->neighbor); i++) { for (int i = 0; i<array_count(v->neighbor); i++) {
float dist = ComputeEdgeCollapseCost(M, v, v->neighbor[i]); float dist = ComputeEdgeCollapseCost(M, v, v->neighbor[i]);
if(dist<v->objdist) { if(dist<v->objdist) {
v->collapse=v->neighbor[i]; // candidate for edge collapse v->collapse=v->neighbor[i]; // candidate for edge collapse
v->objdist=dist; // cost of the collapse v->objdist=dist; // cost of the collapse
} }
} }
} }
static void ComputeAllEdgeCollapseCosts(struct mesh *M) { static void ComputeAllEdgeCollapseCosts(struct mesh *M) {
// For all the edges, compute the difference it would make // For all the edges, compute the difference it would make
// to the model if it was collapsed. The least of these // to the model if it was collapsed. The least of these
// per vertex is cached in each vertex object. // per vertex is cached in each vertex object.
for (int i = 0; i<M->n_vertex; i++) { for (int i = 0; i<M->n_vertex; i++) {
ComputeEdgeCostAtVertex(M, Vertex(M, i)); ComputeEdgeCostAtVertex(M, Vertex(M, i));
} }
} }
static void Collapse(struct mesh *M, int uid, int vid) { static void Collapse(struct mesh *M, int uid, int vid) {
// Collapse the edge uv by moving vertex u onto v // Collapse the edge uv by moving vertex u onto v
// Actually remove tris on uv, then update tris that // Actually remove tris on uv, then update tris that
// have u to have v, and then remove u. // have u to have v, and then remove u.
struct vertex *u = Vertex(M, uid); struct vertex *u = Vertex(M, uid);
if(vid < 0) { if(vid < 0) {
// u is a vertex all by itself so just delete it // u is a vertex all by itself so just delete it
RemoveVertex(M, uid); RemoveVertex(M, uid);
return; return;
} }
array(int) tmp = 0; array(int) tmp = 0;
// make tmp a Array of all the neighbors of u // make tmp a Array of all the neighbors of u
for (int i = 0; i<array_count(u->neighbor); i++) { for (int i = 0; i<array_count(u->neighbor); i++) {
array_push(tmp, u->neighbor[i]); array_push(tmp, u->neighbor[i]);
} }
// delete triangles on edge uv: // delete triangles on edge uv:
for( int i = array_count(u->face); i--; ) { for( int i = array_count(u->face); i--; ) {
if (HasVertex(Face(M, u, i), vid)) { if (HasVertex(Face(M, u, i), vid)) {
RemoveTriangle(M, u->face[i]); RemoveTriangle(M, u->face[i]);
} }
} }
// update remaining triangles to have v instead of u // update remaining triangles to have v instead of u
for( int i = array_count(u->face); i--; ) { for( int i = array_count(u->face); i--; ) {
ReplaceVertex(M, u->face[i], uid, vid); ReplaceVertex(M, u->face[i], uid, vid);
} }
RemoveVertex(M, uid); RemoveVertex(M, uid);
// recompute the edge collapse costs for neighboring vertices // recompute the edge collapse costs for neighboring vertices
for (int i = 0; i<array_count(tmp); i++) { for (int i = 0; i<array_count(tmp); i++) {
ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i])); ComputeEdgeCostAtVertex(M, Vertex(M, tmp[i]));
} }
array_free(tmp); array_free(tmp);
} }
static struct vertex *MinimumCostEdge(struct mesh *M) { static struct vertex *MinimumCostEdge(struct mesh *M) {
// Find the edge that when collapsed will affect model the least. // Find the edge that when collapsed will affect model the least.
// This function actually returns a Vertex, the second vertex // This function actually returns a Vertex, the second vertex
// of the edge (collapse candidate) is stored in the vertex data. // of the edge (collapse candidate) is stored in the vertex data.
// Serious optimization opportunity here: this function currently // Serious optimization opportunity here: this function currently
// does a sequential search through an unsorted Array :-( // does a sequential search through an unsorted Array :-(
// Our algorithm could be O(n*lg(n)) instead of O(n*n) // Our algorithm could be O(n*lg(n)) instead of O(n*n)
struct vertex *mn = NULL; struct vertex *mn = NULL;
for (int i = 0; i<M->n_vertex; i++) { for (int i = 0; i<M->n_vertex; i++) {
struct vertex *v = Vertex(M, i); struct vertex *v = Vertex(M, i);
if (v->id >=0) { if (v->id >=0) {
if (mn == NULL || v->objdist < mn->objdist) { if (mn == NULL || v->objdist < mn->objdist) {
mn = v; mn = v;
} }
} }
} }
return mn; return mn;
} }
/* /*
* The function ProgressiveMesh() takes a model in an "indexed face * The function ProgressiveMesh() takes a model in an "indexed face
* set" sort of way. i.e. Array of vertices and Array of triangles. * set" sort of way. i.e. Array of vertices and Array of triangles.
* The function then does the polygon reduction algorithm * The function then does the polygon reduction algorithm
* internally and reduces the model all the way down to 0 * internally and reduces the model all the way down to 0
* vertices and then returns the order in which the * vertices and then returns the order in which the
* vertices are collapsed and to which neighbor each vertex * vertices are collapsed and to which neighbor each vertex
* is collapsed to. More specifically the returned "permutation" * is collapsed to. More specifically the returned "permutation"
* indicates how to reorder your vertices so you can render * indicates how to reorder your vertices so you can render
* an object by using the first n vertices (for the n * an object by using the first n vertices (for the n
* vertex version). After permuting your vertices, the * vertex version). After permuting your vertices, the
* map Array indicates to which vertex each vertex is collapsed to. * map Array indicates to which vertex each vertex is collapsed to.
*/ */
API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n, const int *tri, int *map, int *permutation) { API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n, const int *tri, int *map, int *permutation) {
struct mesh M; struct mesh M;
MeshInit(&M, vert_n, tri_n); MeshInit(&M, vert_n, tri_n);
// put input data into our data structures M // put input data into our data structures M
const char * tmp = (const char *)v; const char * tmp = (const char *)v;
for (int i=0;i<vert_n;i++, tmp += vert_stride ) { for (int i=0;i<vert_n;i++, tmp += vert_stride ) {
AddVertex(&M, (const float *)tmp); AddVertex(&M, (const float *)tmp);
} }
for (int i=0;i<tri_n;i++) { for (int i=0;i<tri_n;i++) {
AddTriangle(&M, &tri[i*3]); AddTriangle(&M, &tri[i*3]);
} }
ComputeAllEdgeCollapseCosts(&M); // cache all edge collapse costs ComputeAllEdgeCollapseCosts(&M); // cache all edge collapse costs
for (int i = vert_n-1; i>=0; i--) { for (int i = vert_n-1; i>=0; i--) {
// get the next vertex to collapse // get the next vertex to collapse
struct vertex *mn = MinimumCostEdge(&M); struct vertex *mn = MinimumCostEdge(&M);
// keep track of this vertex, i.e. the collapse ordering // keep track of this vertex, i.e. the collapse ordering
permutation[mn->id] = i; permutation[mn->id] = i;
// keep track of vertex to which we collapse to // keep track of vertex to which we collapse to
map[i] = mn->collapse; map[i] = mn->collapse;
// Collapse this edge // Collapse this edge
Collapse(&M, mn->id, mn->collapse); Collapse(&M, mn->id, mn->collapse);
} }
// reorder the map Array based on the collapse ordering // reorder the map Array based on the collapse ordering
for (int i = 0; i<vert_n; i++) { for (int i = 0; i<vert_n; i++) {
map[i] = (map[i]==-1)?0:permutation[map[i]]; map[i] = (map[i]==-1)?0:permutation[map[i]];
} }
// The caller of this function should reorder their vertices // The caller of this function should reorder their vertices
// according to the returned "permutation". // according to the returned "permutation".
MeshFree(&M); MeshFree(&M);
} }
/* /*
* The MIT License (MIT) * The MIT License (MIT)
* *
* Copyright (c) 2014 Stan Melax * Copyright (c) 2014 Stan Melax
* Copyright (c) 2020 Cloud Wu * Copyright (c) 2020 Cloud Wu
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. * copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * 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 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */

File diff suppressed because it is too large Load Diff

View File

@ -1,373 +1,373 @@
/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson /* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson
* *
* This library provides a cross-platform lock free thread caching malloc implementation in C11. * This library provides a cross-platform lock free thread caching malloc implementation in C11.
* The latest source code is always available at * The latest source code is always available at
* *
* https://github.com/mjansson/rpmalloc * https://github.com/mjansson/rpmalloc
* *
* This library is put in the public domain; you can redistribute it and/or modify it without any restrictions. * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
* *
*/ */
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#if defined(__clang__) || defined(__GNUC__) #if defined(__clang__) || defined(__GNUC__)
# define RPMALLOC_EXPORT __attribute__((visibility("default"))) # define RPMALLOC_EXPORT __attribute__((visibility("default")))
# define RPMALLOC_ALLOCATOR # define RPMALLOC_ALLOCATOR
# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD) # if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)
# define RPMALLOC_ATTRIB_MALLOC # define RPMALLOC_ATTRIB_MALLOC
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) # define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)
# else # else
# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__)) # define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size))) # define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size))) # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size)))
# endif # endif
# define RPMALLOC_CDECL # define RPMALLOC_CDECL
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
# define RPMALLOC_EXPORT # define RPMALLOC_EXPORT
# define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict) # define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict)
# define RPMALLOC_ATTRIB_MALLOC # define RPMALLOC_ATTRIB_MALLOC
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) # define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size) # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
# define RPMALLOC_CDECL __cdecl # define RPMALLOC_CDECL __cdecl
#else #else
# define RPMALLOC_EXPORT # define RPMALLOC_EXPORT
# define RPMALLOC_ALLOCATOR # define RPMALLOC_ALLOCATOR
# define RPMALLOC_ATTRIB_MALLOC # define RPMALLOC_ATTRIB_MALLOC
# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) # define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size) # define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
# define RPMALLOC_CDECL # define RPMALLOC_CDECL
#endif #endif
//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce //! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
// a very small overhead due to some size calculations not being compile time constants // a very small overhead due to some size calculations not being compile time constants
#ifndef RPMALLOC_CONFIGURABLE #ifndef RPMALLOC_CONFIGURABLE
#define RPMALLOC_CONFIGURABLE 0 #define RPMALLOC_CONFIGURABLE 0
#endif #endif
//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions). //! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).
// Will introduce a very small overhead to track fully allocated spans in heaps // Will introduce a very small overhead to track fully allocated spans in heaps
#ifndef RPMALLOC_FIRST_CLASS_HEAPS #ifndef RPMALLOC_FIRST_CLASS_HEAPS
#define RPMALLOC_FIRST_CLASS_HEAPS 0 #define RPMALLOC_FIRST_CLASS_HEAPS 0
#endif #endif
//! Flag to rpaligned_realloc to not preserve content in reallocation //! Flag to rpaligned_realloc to not preserve content in reallocation
#define RPMALLOC_NO_PRESERVE 1 #define RPMALLOC_NO_PRESERVE 1
//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place, //! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,
// in which case the original pointer is still valid (just like a call to realloc which failes to allocate // in which case the original pointer is still valid (just like a call to realloc which failes to allocate
// a new block). // a new block).
#define RPMALLOC_GROW_OR_FAIL 2 #define RPMALLOC_GROW_OR_FAIL 2
typedef struct rpmalloc_global_statistics_t { typedef struct rpmalloc_global_statistics_t {
//! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1) //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
size_t mapped; size_t mapped;
//! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1) //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
size_t mapped_peak; size_t mapped_peak;
//! Current amount of memory in global caches for small and medium sizes (<32KiB) //! Current amount of memory in global caches for small and medium sizes (<32KiB)
size_t cached; size_t cached;
//! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1) //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
size_t huge_alloc; size_t huge_alloc;
//! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1) //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
size_t huge_alloc_peak; size_t huge_alloc_peak;
//! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1) //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
size_t mapped_total; size_t mapped_total;
//! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1) //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
size_t unmapped_total; size_t unmapped_total;
} rpmalloc_global_statistics_t; } rpmalloc_global_statistics_t;
typedef struct rpmalloc_thread_statistics_t { typedef struct rpmalloc_thread_statistics_t {
//! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB) //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
size_t sizecache; size_t sizecache;
//! Current number of bytes available in thread span caches for small and medium sizes (<32KiB) //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
size_t spancache; size_t spancache;
//! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1) //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
size_t thread_to_global; size_t thread_to_global;
//! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1) //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
size_t global_to_thread; size_t global_to_thread;
//! Per span count statistics (only if ENABLE_STATISTICS=1) //! Per span count statistics (only if ENABLE_STATISTICS=1)
struct { struct {
//! Currently used number of spans //! Currently used number of spans
size_t current; size_t current;
//! High water mark of spans used //! High water mark of spans used
size_t peak; size_t peak;
//! Number of spans transitioned to global cache //! Number of spans transitioned to global cache
size_t to_global; size_t to_global;
//! Number of spans transitioned from global cache //! Number of spans transitioned from global cache
size_t from_global; size_t from_global;
//! Number of spans transitioned to thread cache //! Number of spans transitioned to thread cache
size_t to_cache; size_t to_cache;
//! Number of spans transitioned from thread cache //! Number of spans transitioned from thread cache
size_t from_cache; size_t from_cache;
//! Number of spans transitioned to reserved state //! Number of spans transitioned to reserved state
size_t to_reserved; size_t to_reserved;
//! Number of spans transitioned from reserved state //! Number of spans transitioned from reserved state
size_t from_reserved; size_t from_reserved;
//! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls) //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
size_t map_calls; size_t map_calls;
} span_use[64]; } span_use[64];
//! Per size class statistics (only if ENABLE_STATISTICS=1) //! Per size class statistics (only if ENABLE_STATISTICS=1)
struct { struct {
//! Current number of allocations //! Current number of allocations
size_t alloc_current; size_t alloc_current;
//! Peak number of allocations //! Peak number of allocations
size_t alloc_peak; size_t alloc_peak;
//! Total number of allocations //! Total number of allocations
size_t alloc_total; size_t alloc_total;
//! Total number of frees //! Total number of frees
size_t free_total; size_t free_total;
//! Number of spans transitioned to cache //! Number of spans transitioned to cache
size_t spans_to_cache; size_t spans_to_cache;
//! Number of spans transitioned from cache //! Number of spans transitioned from cache
size_t spans_from_cache; size_t spans_from_cache;
//! Number of spans transitioned from reserved state //! Number of spans transitioned from reserved state
size_t spans_from_reserved; size_t spans_from_reserved;
//! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls) //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
size_t map_calls; size_t map_calls;
} size_use[128]; } size_use[128];
} rpmalloc_thread_statistics_t; } rpmalloc_thread_statistics_t;
typedef struct rpmalloc_config_t { typedef struct rpmalloc_config_t {
//! Map memory pages for the given number of bytes. The returned address MUST be //! Map memory pages for the given number of bytes. The returned address MUST be
// aligned to the rpmalloc span size, which will always be a power of two. // aligned to the rpmalloc span size, which will always be a power of two.
// Optionally the function can store an alignment offset in the offset variable // Optionally the function can store an alignment offset in the offset variable
// in case it performs alignment and the returned pointer is offset from the // in case it performs alignment and the returned pointer is offset from the
// actual start of the memory region due to this alignment. The alignment offset // actual start of the memory region due to this alignment. The alignment offset
// will be passed to the memory unmap function. The alignment offset MUST NOT be // will be passed to the memory unmap function. The alignment offset MUST NOT be
// larger than 65535 (storable in an uint16_t), if it is you must use natural // larger than 65535 (storable in an uint16_t), if it is you must use natural
// alignment to shift it into 16 bits. If you set a memory_map function, you // alignment to shift it into 16 bits. If you set a memory_map function, you
// must also set a memory_unmap function or else the default implementation will // must also set a memory_unmap function or else the default implementation will
// be used for both. This function must be thread safe, it can be called by // be used for both. This function must be thread safe, it can be called by
// multiple threads simultaneously. // multiple threads simultaneously.
void* (*memory_map)(size_t size, size_t* offset); void* (*memory_map)(size_t size, size_t* offset);
//! Unmap the memory pages starting at address and spanning the given number of bytes. //! Unmap the memory pages starting at address and spanning the given number of bytes.
// If release is set to non-zero, the unmap is for an entire span range as returned by // If release is set to non-zero, the unmap is for an entire span range as returned by
// a previous call to memory_map and that the entire range should be released. The // a previous call to memory_map and that the entire range should be released. The
// release argument holds the size of the entire span range. If release is set to 0, // release argument holds the size of the entire span range. If release is set to 0,
// the unmap is a partial decommit of a subset of the mapped memory range. // the unmap is a partial decommit of a subset of the mapped memory range.
// If you set a memory_unmap function, you must also set a memory_map function or // If you set a memory_unmap function, you must also set a memory_map function or
// else the default implementation will be used for both. This function must be thread // else the default implementation will be used for both. This function must be thread
// safe, it can be called by multiple threads simultaneously. // safe, it can be called by multiple threads simultaneously.
void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release); void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
//! Called when an assert fails, if asserts are enabled. Will use the standard assert() //! Called when an assert fails, if asserts are enabled. Will use the standard assert()
// if this is not set. // if this is not set.
void (*error_callback)(const char* message); void (*error_callback)(const char* message);
//! Called when a call to map memory pages fails (out of memory). If this callback is //! Called when a call to map memory pages fails (out of memory). If this callback is
// not set or returns zero the library will return a null pointer in the allocation // not set or returns zero the library will return a null pointer in the allocation
// call. If this callback returns non-zero the map call will be retried. The argument // call. If this callback returns non-zero the map call will be retried. The argument
// passed is the number of bytes that was requested in the map call. Only used if // passed is the number of bytes that was requested in the map call. Only used if
// the default system memory map function is used (memory_map callback is not set). // the default system memory map function is used (memory_map callback is not set).
int (*map_fail_callback)(size_t size); int (*map_fail_callback)(size_t size);
//! Size of memory pages. The page size MUST be a power of two. All memory mapping //! Size of memory pages. The page size MUST be a power of two. All memory mapping
// requests to memory_map will be made with size set to a multiple of the page size. // requests to memory_map will be made with size set to a multiple of the page size.
// Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used. // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
size_t page_size; size_t page_size;
//! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144] //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
// range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
// is defined to 1. // is defined to 1.
size_t span_size; size_t span_size;
//! Number of spans to map at each request to map new virtual memory blocks. This can //! Number of spans to map at each request to map new virtual memory blocks. This can
// be used to minimize the system call overhead at the cost of virtual memory address // be used to minimize the system call overhead at the cost of virtual memory address
// space. The extra mapped pages will not be written until actually used, so physical // space. The extra mapped pages will not be written until actually used, so physical
// committed memory should not be affected in the default implementation. Will be // committed memory should not be affected in the default implementation. Will be
// aligned to a multiple of spans that match memory page size in case of huge pages. // aligned to a multiple of spans that match memory page size in case of huge pages.
size_t span_map_count; size_t span_map_count;
//! Enable use of large/huge pages. If this flag is set to non-zero and page size is //! Enable use of large/huge pages. If this flag is set to non-zero and page size is
// zero, the allocator will try to enable huge pages and auto detect the configuration. // zero, the allocator will try to enable huge pages and auto detect the configuration.
// If this is set to non-zero and page_size is also non-zero, the allocator will // If this is set to non-zero and page_size is also non-zero, the allocator will
// assume huge pages have been configured and enabled prior to initializing the // assume huge pages have been configured and enabled prior to initializing the
// allocator. // allocator.
// For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
// For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
int enable_huge_pages; int enable_huge_pages;
//! Respectively allocated pages and huge allocated pages names for systems //! Respectively allocated pages and huge allocated pages names for systems
// supporting it to be able to distinguish among anonymous regions. // supporting it to be able to distinguish among anonymous regions.
const char *page_name; const char *page_name;
const char *huge_page_name; const char *huge_page_name;
} rpmalloc_config_t; } rpmalloc_config_t;
//! Initialize allocator with default configuration //! Initialize allocator with default configuration
RPMALLOC_EXPORT int RPMALLOC_EXPORT int
rpmalloc_initialize(void); rpmalloc_initialize(void);
//! Initialize allocator with given configuration //! Initialize allocator with given configuration
RPMALLOC_EXPORT int RPMALLOC_EXPORT int
rpmalloc_initialize_config(const rpmalloc_config_t* config); rpmalloc_initialize_config(const rpmalloc_config_t* config);
//! Get allocator configuration //! Get allocator configuration
RPMALLOC_EXPORT const rpmalloc_config_t* RPMALLOC_EXPORT const rpmalloc_config_t*
rpmalloc_config(void); rpmalloc_config(void);
//! Finalize allocator //! Finalize allocator
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_finalize(void); rpmalloc_finalize(void);
//! Initialize allocator for calling thread //! Initialize allocator for calling thread
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_thread_initialize(void); rpmalloc_thread_initialize(void);
//! Finalize allocator for calling thread //! Finalize allocator for calling thread
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_thread_finalize(int release_caches); rpmalloc_thread_finalize(int release_caches);
//! Perform deferred deallocations pending for the calling thread heap //! Perform deferred deallocations pending for the calling thread heap
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_thread_collect(void); rpmalloc_thread_collect(void);
//! Query if allocator is initialized for calling thread //! Query if allocator is initialized for calling thread
RPMALLOC_EXPORT int RPMALLOC_EXPORT int
rpmalloc_is_thread_initialized(void); rpmalloc_is_thread_initialized(void);
//! Get per-thread statistics //! Get per-thread statistics
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats); rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
//! Get global statistics //! Get global statistics
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats); rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
//! Dump all statistics in human readable format to file (should be a FILE*) //! Dump all statistics in human readable format to file (should be a FILE*)
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_dump_statistics(void* file); rpmalloc_dump_statistics(void* file);
//! Allocate a memory block of at least the given size //! Allocate a memory block of at least the given size
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1); rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
//! Free the given memory block //! Free the given memory block
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpfree(void* ptr); rpfree(void* ptr);
//! Allocate a memory block of at least the given size and zero initialize it //! Allocate a memory block of at least the given size and zero initialize it
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2); rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
//! Reallocate the given block to at least the given size //! Reallocate the given block to at least the given size
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
//! Reallocate the given block to at least the given size and alignment, //! Reallocate the given block to at least the given size and alignment,
// with optional control flags (see RPMALLOC_NO_PRESERVE). // with optional control flags (see RPMALLOC_NO_PRESERVE).
// Alignment must be a power of two and a multiple of sizeof(void*), // Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc // and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB) // internals is that this must also be strictly less than the span size (default 64KiB)
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
//! Allocate a memory block of at least the given size and alignment. //! Allocate a memory block of at least the given size and alignment.
// Alignment must be a power of two and a multiple of sizeof(void*), // Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc // and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB) // internals is that this must also be strictly less than the span size (default 64KiB)
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
//! Allocate a memory block of at least the given size and alignment, and zero initialize it. //! Allocate a memory block of at least the given size and alignment, and zero initialize it.
// Alignment must be a power of two and a multiple of sizeof(void*), // Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc // and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB) // internals is that this must also be strictly less than the span size (default 64KiB)
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
//! Allocate a memory block of at least the given size and alignment. //! Allocate a memory block of at least the given size and alignment.
// Alignment must be a power of two and a multiple of sizeof(void*), // Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc // and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB) // internals is that this must also be strictly less than the span size (default 64KiB)
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
//! Allocate a memory block of at least the given size and alignment. //! Allocate a memory block of at least the given size and alignment.
// Alignment must be a power of two and a multiple of sizeof(void*), // Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc // and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB) // internals is that this must also be strictly less than the span size (default 64KiB)
RPMALLOC_EXPORT int RPMALLOC_EXPORT int
rpposix_memalign(void** memptr, size_t alignment, size_t size); rpposix_memalign(void** memptr, size_t alignment, size_t size);
//! Query the usable size of the given memory block (from given pointer to the end of block) //! Query the usable size of the given memory block (from given pointer to the end of block)
RPMALLOC_EXPORT size_t RPMALLOC_EXPORT size_t
rpmalloc_usable_size(void* ptr); rpmalloc_usable_size(void* ptr);
//! Dummy empty function for forcing linker symbol inclusion //! Dummy empty function for forcing linker symbol inclusion
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_linker_reference(void); rpmalloc_linker_reference(void);
#if RPMALLOC_FIRST_CLASS_HEAPS #if RPMALLOC_FIRST_CLASS_HEAPS
//! Heap type //! Heap type
typedef struct heap_t rpmalloc_heap_t; typedef struct heap_t rpmalloc_heap_t;
//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap //! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
// if none available. Heap API is implemented with the strict assumption that only one single // if none available. Heap API is implemented with the strict assumption that only one single
// thread will call heap functions for a given heap at any given time, no functions are thread safe. // thread will call heap functions for a given heap at any given time, no functions are thread safe.
RPMALLOC_EXPORT rpmalloc_heap_t* RPMALLOC_EXPORT rpmalloc_heap_t*
rpmalloc_heap_acquire(void); rpmalloc_heap_acquire(void);
//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap). //! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
// Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer. // Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_heap_release(rpmalloc_heap_t* heap); rpmalloc_heap_release(rpmalloc_heap_t* heap);
//! Allocate a memory block of at least the given size using the given heap. //! Allocate a memory block of at least the given size using the given heap.
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2); rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
//! Allocate a memory block of at least the given size using the given heap. The returned //! Allocate a memory block of at least the given size using the given heap. The returned
// block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*), // block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc // and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB). // internals is that this must also be strictly less than the span size (default 64KiB).
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
//! Allocate a memory block of at least the given size using the given heap and zero initialize it. //! Allocate a memory block of at least the given size using the given heap and zero initialize it.
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned //! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
// block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*), // block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
// and should ideally be less than memory page size. A caveat of rpmalloc // and should ideally be less than memory page size. A caveat of rpmalloc
// internals is that this must also be strictly less than the span size (default 64KiB). // internals is that this must also be strictly less than the span size (default 64KiB).
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3); rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
//! Reallocate the given block to at least the given size. The memory block MUST be allocated //! Reallocate the given block to at least the given size. The memory block MUST be allocated
// by the same heap given to this function. // by the same heap given to this function.
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3); rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
//! Reallocate the given block to at least the given size. The memory block MUST be allocated //! Reallocate the given block to at least the given size. The memory block MUST be allocated
// by the same heap given to this function. The returned block will have the requested alignment. // by the same heap given to this function. The returned block will have the requested alignment.
// Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be // Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
// less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than // less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
// the span size (default 64KiB). // the span size (default 64KiB).
RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void* RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4); rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
//! Free the given memory block from the given heap. The memory block MUST be allocated //! Free the given memory block from the given heap. The memory block MUST be allocated
// by the same heap given to this function. // by the same heap given to this function.
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr); rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
//! Free all memory allocated by the heap //! Free all memory allocated by the heap
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_heap_free_all(rpmalloc_heap_t* heap); rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap //! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
// for a single thread, a heap can never be shared between multiple threads. The previous // for a single thread, a heap can never be shared between multiple threads. The previous
// current heap for the calling thread is released to be reused by other threads. // current heap for the calling thread is released to be reused by other threads.
RPMALLOC_EXPORT void RPMALLOC_EXPORT void
rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap); rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
//! Returns which heap the given pointer is allocated on //! Returns which heap the given pointer is allocated on
RPMALLOC_EXPORT rpmalloc_heap_t* RPMALLOC_EXPORT rpmalloc_heap_t*
rpmalloc_get_heap_for_ptr(void* ptr); rpmalloc_get_heap_for_ptr(void* ptr);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,481 +1,481 @@
/** 1D, 2D, 3D and 4D float Perlin Simplex noise */ /** 1D, 2D, 3D and 4D float Perlin Simplex noise */
/** Original code, stefan gustavson (PD). */ /** Original code, stefan gustavson (PD). */
#ifdef SIMPLEX_C #ifdef SIMPLEX_C
/* SimplexNoise1234, Simplex noise with true analytic /* SimplexNoise1234, Simplex noise with true analytic
* derivative in 1D to 4D. * derivative in 1D to 4D.
* *
* Author: Stefan Gustavson, 2003-2005 * Author: Stefan Gustavson, 2003-2005
* Contact: stefan.gustavson@liu.se * Contact: stefan.gustavson@liu.se
* *
* This code was GPL licensed until February 2011. * This code was GPL licensed until February 2011.
* As the original author of this code, I hereby * As the original author of this code, I hereby
* release it into the public domain. * release it into the public domain.
* Please feel free to use it for whatever you want. * Please feel free to use it for whatever you want.
* Credit is appreciated where appropriate, and I also * Credit is appreciated where appropriate, and I also
* appreciate being told where this code finds any use, * appreciate being told where this code finds any use,
* but you may do as you like. * but you may do as you like.
*/ */
/* /*
* This implementation is "Simplex Noise" as presented by * This implementation is "Simplex Noise" as presented by
* Ken Perlin at a relatively obscure and not often cited course * Ken Perlin at a relatively obscure and not often cited course
* session "Real-Time Shading" at Siggraph 2001 (before real * session "Real-Time Shading" at Siggraph 2001 (before real
* time shading actually took off), under the title "hardware noise". * time shading actually took off), under the title "hardware noise".
* The 3D function is numerically equivalent to his Java reference * The 3D function is numerically equivalent to his Java reference
* code available in the PDF course notes, although I re-implemented * code available in the PDF course notes, although I re-implemented
* it from scratch to get more readable code. The 1D, 2D and 4D cases * it from scratch to get more readable code. The 1D, 2D and 4D cases
* were implemented from scratch by me from Ken Perlin's text. * were implemented from scratch by me from Ken Perlin's text.
* *
* This file has no dependencies on any other file, not even its own * This file has no dependencies on any other file, not even its own
* header file. The header file is made for use by external code only. * header file. The header file is made for use by external code only.
*/ */
// We don't really need to include this, but play nice and do it anyway. // We don't really need to include this, but play nice and do it anyway.
//#include "noise.c" //#include "noise.c"
#define FASTFLOOR(x) ( ((int)(x)<=(x)) ? ((int)x) : (((int)x)-1) ) #define FASTFLOOR(x) ( ((int)(x)<=(x)) ? ((int)x) : (((int)x)-1) )
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Static data // Static data
/* /*
* Permutation table. This is just a random jumble of all numbers 0-255, * Permutation table. This is just a random jumble of all numbers 0-255,
* repeated twice to avoid wrapping the index at 255 for each lookup. * repeated twice to avoid wrapping the index at 255 for each lookup.
* This needs to be exactly the same for all instances on all platforms, * This needs to be exactly the same for all instances on all platforms,
* so it's easiest to just keep it as static explicit data. * so it's easiest to just keep it as static explicit data.
* This also removes the need for any initialisation of this class. * This also removes the need for any initialisation of this class.
* *
* Note that making this an int[] instead of a char[] might make the * Note that making this an int[] instead of a char[] might make the
* code run faster on platforms with a high penalty for unaligned single * code run faster on platforms with a high penalty for unaligned single
* byte addressing. Intel x86 is generally single-byte-friendly, but * byte addressing. Intel x86 is generally single-byte-friendly, but
* some other CPUs are faster with 4-aligned reads. * some other CPUs are faster with 4-aligned reads.
* However, a char[] is smaller, which avoids cache trashing, and that * However, a char[] is smaller, which avoids cache trashing, and that
* is probably the most important aspect on most architectures. * is probably the most important aspect on most architectures.
* This array is accessed a *lot* by the noise functions. * This array is accessed a *lot* by the noise functions.
* A vector-valued noise over 3D accesses it 96 times, and a * A vector-valued noise over 3D accesses it 96 times, and a
* float-valued 4D noise 64 times. We want this to fit in the cache! * float-valued 4D noise 64 times. We want this to fit in the cache!
*/ */
unsigned char perm[512] = {151,160,137,91,90,15, unsigned char perm[512] = {151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
151,160,137,91,90,15, 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
}; };
//--------------------------------------------------------------------- //---------------------------------------------------------------------
/* /*
* Helper functions to compute gradients-dot-residualvectors (1D to 4D) * Helper functions to compute gradients-dot-residualvectors (1D to 4D)
* Note that these generate gradients of more than unit length. To make * Note that these generate gradients of more than unit length. To make
* a close match with the value range of classic Perlin noise, the final * a close match with the value range of classic Perlin noise, the final
* noise values need to be rescaled to fit nicely within [-1,1]. * noise values need to be rescaled to fit nicely within [-1,1].
* (The simplex noise functions as such also have different scaling.) * (The simplex noise functions as such also have different scaling.)
* Note also that these noise functions are the most practical and useful * Note also that these noise functions are the most practical and useful
* signed version of Perlin noise. To return values according to the * signed version of Perlin noise. To return values according to the
* RenderMan specification from the SL noise() and pnoise() functions, * RenderMan specification from the SL noise() and pnoise() functions,
* the noise values need to be scaled and offset to [0,1], like this: * the noise values need to be scaled and offset to [0,1], like this:
* float SLnoise = (noise(x,y,z) + 1.0) * 0.5; * float SLnoise = (noise(x,y,z) + 1.0) * 0.5;
*/ */
float grad1( int hash, float x ) { float grad1( int hash, float x ) {
int h = hash & 15; int h = hash & 15;
float grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0 float grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0
if (h&8) grad = -grad; // Set a random sign for the gradient if (h&8) grad = -grad; // Set a random sign for the gradient
return ( grad * x ); // Multiply the gradient with the distance return ( grad * x ); // Multiply the gradient with the distance
} }
float grad2( int hash, float x, float y ) { float grad2( int hash, float x, float y ) {
int h = hash & 7; // Convert low 3 bits of hash code int h = hash & 7; // Convert low 3 bits of hash code
float u = h<4 ? x : y; // into 8 simple gradient directions, float u = h<4 ? x : y; // into 8 simple gradient directions,
float v = h<4 ? y : x; // and compute the dot product with (x,y). float v = h<4 ? y : x; // and compute the dot product with (x,y).
return ((h&1)? -u : u) + ((h&2)? -2.0f*v : 2.0f*v); return ((h&1)? -u : u) + ((h&2)? -2.0f*v : 2.0f*v);
} }
float grad3( int hash, float x, float y , float z ) { float grad3( int hash, float x, float y , float z ) {
int h = hash & 15; // Convert low 4 bits of hash code into 12 simple int h = hash & 15; // Convert low 4 bits of hash code into 12 simple
float u = h<8 ? x : y; // gradient directions, and compute dot product. float u = h<8 ? x : y; // gradient directions, and compute dot product.
float v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15 float v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15
return ((h&1)? -u : u) + ((h&2)? -v : v); return ((h&1)? -u : u) + ((h&2)? -v : v);
} }
float grad4( int hash, float x, float y, float z, float t ) { float grad4( int hash, float x, float y, float z, float t ) {
int h = hash & 31; // Convert low 5 bits of hash code into 32 simple int h = hash & 31; // Convert low 5 bits of hash code into 32 simple
float u = h<24 ? x : y; // gradient directions, and compute dot product. float u = h<24 ? x : y; // gradient directions, and compute dot product.
float v = h<16 ? y : z; float v = h<16 ? y : z;
float w = h<8 ? z : t; float w = h<8 ? z : t;
return ((h&1)? -u : u) + ((h&2)? -v : v) + ((h&4)? -w : w); return ((h&1)? -u : u) + ((h&2)? -v : v) + ((h&4)? -w : w);
} }
// A lookup table to traverse the simplex around a given point in 4D. // A lookup table to traverse the simplex around a given point in 4D.
// Details can be found where this table is used, in the 4D noise method. // Details can be found where this table is used, in the 4D noise method.
/* TODO: This should not be required, backport it from Bill's GLSL code! */ /* TODO: This should not be required, backport it from Bill's GLSL code! */
static unsigned char simplex[64][4] = { static unsigned char simplex[64][4] = {
{0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0}, {0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0},
{0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0}, {0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0},
{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
{1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0}, {1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0},
{1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0}, {1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0},
{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},
{2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0}, {2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0},
{2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0}}; {2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0}};
// 1D simplex noise // 1D simplex noise
float snoise1(float x) { float snoise1(float x) {
int i0 = FASTFLOOR(x); int i0 = FASTFLOOR(x);
int i1 = i0 + 1; int i1 = i0 + 1;
float x0 = x - i0; float x0 = x - i0;
float x1 = x0 - 1.0f; float x1 = x0 - 1.0f;
float n0, n1; float n0, n1;
float t0 = 1.0f - x0*x0; float t0 = 1.0f - x0*x0;
// if(t0 < 0.0f) t0 = 0.0f; // this never happens for the 1D case // if(t0 < 0.0f) t0 = 0.0f; // this never happens for the 1D case
t0 *= t0; t0 *= t0;
n0 = t0 * t0 * grad1(perm[i0 & 0xff], x0); n0 = t0 * t0 * grad1(perm[i0 & 0xff], x0);
float t1 = 1.0f - x1*x1; float t1 = 1.0f - x1*x1;
// if(t1 < 0.0f) t1 = 0.0f; // this never happens for the 1D case // if(t1 < 0.0f) t1 = 0.0f; // this never happens for the 1D case
t1 *= t1; t1 *= t1;
n1 = t1 * t1 * grad1(perm[i1 & 0xff], x1); n1 = t1 * t1 * grad1(perm[i1 & 0xff], x1);
// The maximum value of this noise is 8*(3/4)^4 = 2.53125 // The maximum value of this noise is 8*(3/4)^4 = 2.53125
// A factor of 0.395 would scale to fit exactly within [-1,1], but // A factor of 0.395 would scale to fit exactly within [-1,1], but
// we want to match PRMan's 1D noise, so we scale it down some more. // we want to match PRMan's 1D noise, so we scale it down some more.
return 0.25f * (n0 + n1); return 0.25f * (n0 + n1);
} }
// 2D simplex noise // 2D simplex noise
float snoise2(float x, float y) { float snoise2(float x, float y) {
#define F2 0.366025403 // F2 = 0.5*(sqrt(3.0)-1.0) #define F2 0.366025403 // F2 = 0.5*(sqrt(3.0)-1.0)
#define G2 0.211324865 // G2 = (3.0-Math.sqrt(3.0))/6.0 #define G2 0.211324865 // G2 = (3.0-Math.sqrt(3.0))/6.0
float n0, n1, n2; // Noise contributions from the three corners float n0, n1, n2; // Noise contributions from the three corners
// Skew the input space to determine which simplex cell we're in // Skew the input space to determine which simplex cell we're in
float s = (x+y)*F2; // Hairy factor for 2D float s = (x+y)*F2; // Hairy factor for 2D
float xs = x + s; float xs = x + s;
float ys = y + s; float ys = y + s;
int i = FASTFLOOR(xs); int i = FASTFLOOR(xs);
int j = FASTFLOOR(ys); int j = FASTFLOOR(ys);
float t = (float)(i+j)*G2; float t = (float)(i+j)*G2;
float X0 = i-t; // Unskew the cell origin back to (x,y) space float X0 = i-t; // Unskew the cell origin back to (x,y) space
float Y0 = j-t; float Y0 = j-t;
float x0 = x-X0; // The x,y distances from the cell origin float x0 = x-X0; // The x,y distances from the cell origin
float y0 = y-Y0; float y0 = y-Y0;
// For the 2D case, the simplex shape is an equilateral triangle. // For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in. // Determine which simplex we are in.
int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1) if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1) else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6 // c = (3-sqrt(3))/6
float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
float y1 = y0 - j1 + G2; float y1 = y0 - j1 + G2;
float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
float y2 = y0 - 1.0f + 2.0f * G2; float y2 = y0 - 1.0f + 2.0f * G2;
// Wrap the integer indices at 256, to avoid indexing perm[] out of bounds // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
int ii = i & 0xff; int ii = i & 0xff;
int jj = j & 0xff; int jj = j & 0xff;
// Calculate the contribution from the three corners // Calculate the contribution from the three corners
float t0 = 0.5f - x0*x0-y0*y0; float t0 = 0.5f - x0*x0-y0*y0;
if(t0 < 0.0f) n0 = 0.0f; if(t0 < 0.0f) n0 = 0.0f;
else { else {
t0 *= t0; t0 *= t0;
n0 = t0 * t0 * grad2(perm[ii+perm[jj]], x0, y0); n0 = t0 * t0 * grad2(perm[ii+perm[jj]], x0, y0);
} }
float t1 = 0.5f - x1*x1-y1*y1; float t1 = 0.5f - x1*x1-y1*y1;
if(t1 < 0.0f) n1 = 0.0f; if(t1 < 0.0f) n1 = 0.0f;
else { else {
t1 *= t1; t1 *= t1;
n1 = t1 * t1 * grad2(perm[ii+i1+perm[jj+j1]], x1, y1); n1 = t1 * t1 * grad2(perm[ii+i1+perm[jj+j1]], x1, y1);
} }
float t2 = 0.5f - x2*x2-y2*y2; float t2 = 0.5f - x2*x2-y2*y2;
if(t2 < 0.0f) n2 = 0.0f; if(t2 < 0.0f) n2 = 0.0f;
else { else {
t2 *= t2; t2 *= t2;
n2 = t2 * t2 * grad2(perm[ii+1+perm[jj+1]], x2, y2); n2 = t2 * t2 * grad2(perm[ii+1+perm[jj+1]], x2, y2);
} }
// Add contributions from each corner to get the final noise value. // Add contributions from each corner to get the final noise value.
// The result is scaled to return values in the interval [-1,1]. // The result is scaled to return values in the interval [-1,1].
return 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary! return 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary!
} }
// 3D simplex noise // 3D simplex noise
float snoise3(float x, float y, float z) { float snoise3(float x, float y, float z) {
// Simple skewing factors for the 3D case // Simple skewing factors for the 3D case
#define F3 0.333333333 #define F3 0.333333333
#define G3 0.166666667 #define G3 0.166666667
float n0, n1, n2, n3; // Noise contributions from the four corners float n0, n1, n2, n3; // Noise contributions from the four corners
// Skew the input space to determine which simplex cell we're in // Skew the input space to determine which simplex cell we're in
float s = (x+y+z)*F3; // Very nice and simple skew factor for 3D float s = (x+y+z)*F3; // Very nice and simple skew factor for 3D
float xs = x+s; float xs = x+s;
float ys = y+s; float ys = y+s;
float zs = z+s; float zs = z+s;
int i = FASTFLOOR(xs); int i = FASTFLOOR(xs);
int j = FASTFLOOR(ys); int j = FASTFLOOR(ys);
int k = FASTFLOOR(zs); int k = FASTFLOOR(zs);
float t = (float)(i+j+k)*G3; float t = (float)(i+j+k)*G3;
float X0 = i-t; // Unskew the cell origin back to (x,y,z) space float X0 = i-t; // Unskew the cell origin back to (x,y,z) space
float Y0 = j-t; float Y0 = j-t;
float Z0 = k-t; float Z0 = k-t;
float x0 = x-X0; // The x,y,z distances from the cell origin float x0 = x-X0; // The x,y,z distances from the cell origin
float y0 = y-Y0; float y0 = y-Y0;
float z0 = z-Z0; float z0 = z-Z0;
// For the 3D case, the simplex shape is a slightly irregular tetrahedron. // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
// Determine which simplex we are in. // Determine which simplex we are in.
int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
/* This code would benefit from a backport from the GLSL version! */ /* This code would benefit from a backport from the GLSL version! */
if(x0>=y0) { if(x0>=y0) {
if(y0>=z0) if(y0>=z0)
{ i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order
else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order
else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order
} }
else { // x0<y0 else { // x0<y0
if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order
else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order
else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order
} }
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
// c = 1/6. // c = 1/6.
float x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords float x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
float y1 = y0 - j1 + G3; float y1 = y0 - j1 + G3;
float z1 = z0 - k1 + G3; float z1 = z0 - k1 + G3;
float x2 = x0 - i2 + 2.0f*G3; // Offsets for third corner in (x,y,z) coords float x2 = x0 - i2 + 2.0f*G3; // Offsets for third corner in (x,y,z) coords
float y2 = y0 - j2 + 2.0f*G3; float y2 = y0 - j2 + 2.0f*G3;
float z2 = z0 - k2 + 2.0f*G3; float z2 = z0 - k2 + 2.0f*G3;
float x3 = x0 - 1.0f + 3.0f*G3; // Offsets for last corner in (x,y,z) coords float x3 = x0 - 1.0f + 3.0f*G3; // Offsets for last corner in (x,y,z) coords
float y3 = y0 - 1.0f + 3.0f*G3; float y3 = y0 - 1.0f + 3.0f*G3;
float z3 = z0 - 1.0f + 3.0f*G3; float z3 = z0 - 1.0f + 3.0f*G3;
// Wrap the integer indices at 256, to avoid indexing perm[] out of bounds // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
int ii = i & 0xff; int ii = i & 0xff;
int jj = j & 0xff; int jj = j & 0xff;
int kk = k & 0xff; int kk = k & 0xff;
// Calculate the contribution from the four corners // Calculate the contribution from the four corners
float t0 = 0.5f - x0*x0 - y0*y0 - z0*z0; float t0 = 0.5f - x0*x0 - y0*y0 - z0*z0;
if(t0 < 0.0f) n0 = 0.0f; if(t0 < 0.0f) n0 = 0.0f;
else { else {
t0 *= t0; t0 *= t0;
n0 = t0 * t0 * grad3(perm[ii+perm[jj+perm[kk]]], x0, y0, z0); n0 = t0 * t0 * grad3(perm[ii+perm[jj+perm[kk]]], x0, y0, z0);
} }
float t1 = 0.5f - x1*x1 - y1*y1 - z1*z1; float t1 = 0.5f - x1*x1 - y1*y1 - z1*z1;
if(t1 < 0.0f) n1 = 0.0f; if(t1 < 0.0f) n1 = 0.0f;
else { else {
t1 *= t1; t1 *= t1;
n1 = t1 * t1 * grad3(perm[ii+i1+perm[jj+j1+perm[kk+k1]]], x1, y1, z1); n1 = t1 * t1 * grad3(perm[ii+i1+perm[jj+j1+perm[kk+k1]]], x1, y1, z1);
} }
float t2 = 0.5f - x2*x2 - y2*y2 - z2*z2; float t2 = 0.5f - x2*x2 - y2*y2 - z2*z2;
if(t2 < 0.0f) n2 = 0.0f; if(t2 < 0.0f) n2 = 0.0f;
else { else {
t2 *= t2; t2 *= t2;
n2 = t2 * t2 * grad3(perm[ii+i2+perm[jj+j2+perm[kk+k2]]], x2, y2, z2); n2 = t2 * t2 * grad3(perm[ii+i2+perm[jj+j2+perm[kk+k2]]], x2, y2, z2);
} }
float t3 = 0.5f - x3*x3 - y3*y3 - z3*z3; float t3 = 0.5f - x3*x3 - y3*y3 - z3*z3;
if(t3<0.0f) n3 = 0.0f; if(t3<0.0f) n3 = 0.0f;
else { else {
t3 *= t3; t3 *= t3;
n3 = t3 * t3 * grad3(perm[ii+1+perm[jj+1+perm[kk+1]]], x3, y3, z3); n3 = t3 * t3 * grad3(perm[ii+1+perm[jj+1+perm[kk+1]]], x3, y3, z3);
} }
// Add contributions from each corner to get the final noise value. // Add contributions from each corner to get the final noise value.
// The result is scaled to stay just inside [-1,1] // The result is scaled to stay just inside [-1,1]
return 72.0f * (n0 + n1 + n2 + n3); return 72.0f * (n0 + n1 + n2 + n3);
} }
// 4D simplex noise // 4D simplex noise
float snoise4(float x, float y, float z, float w) { float snoise4(float x, float y, float z, float w) {
// The skewing and unskewing factors are hairy again for the 4D case // The skewing and unskewing factors are hairy again for the 4D case
#define F4 0.309016994 // F4 = (Math.sqrt(5.0)-1.0)/4.0 #define F4 0.309016994 // F4 = (Math.sqrt(5.0)-1.0)/4.0
#define G4 0.138196601 // G4 = (5.0-Math.sqrt(5.0))/20.0 #define G4 0.138196601 // G4 = (5.0-Math.sqrt(5.0))/20.0
float n0, n1, n2, n3, n4; // Noise contributions from the five corners float n0, n1, n2, n3, n4; // Noise contributions from the five corners
// Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in // Skew the (x,y,z,w) space to determine which cell of 24 simplices we're in
float s = (x + y + z + w) * F4; // Factor for 4D skewing float s = (x + y + z + w) * F4; // Factor for 4D skewing
float xs = x + s; float xs = x + s;
float ys = y + s; float ys = y + s;
float zs = z + s; float zs = z + s;
float ws = w + s; float ws = w + s;
int i = FASTFLOOR(xs); int i = FASTFLOOR(xs);
int j = FASTFLOOR(ys); int j = FASTFLOOR(ys);
int k = FASTFLOOR(zs); int k = FASTFLOOR(zs);
int l = FASTFLOOR(ws); int l = FASTFLOOR(ws);
float t = (i + j + k + l) * G4; // Factor for 4D unskewing float t = (i + j + k + l) * G4; // Factor for 4D unskewing
float X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space float X0 = i - t; // Unskew the cell origin back to (x,y,z,w) space
float Y0 = j - t; float Y0 = j - t;
float Z0 = k - t; float Z0 = k - t;
float W0 = l - t; float W0 = l - t;
float x0 = x - X0; // The x,y,z,w distances from the cell origin float x0 = x - X0; // The x,y,z,w distances from the cell origin
float y0 = y - Y0; float y0 = y - Y0;
float z0 = z - Z0; float z0 = z - Z0;
float w0 = w - W0; float w0 = w - W0;
// For the 4D case, the simplex is a 4D shape I won't even try to describe. // For the 4D case, the simplex is a 4D shape I won't even try to describe.
// To find out which of the 24 possible simplices we're in, we need to // To find out which of the 24 possible simplices we're in, we need to
// determine the magnitude ordering of x0, y0, z0 and w0. // determine the magnitude ordering of x0, y0, z0 and w0.
// The method below is a good way of finding the ordering of x,y,z,w and // The method below is a good way of finding the ordering of x,y,z,w and
// then find the correct traversal order for the simplex we?re in. // then find the correct traversal order for the simplex we?re in.
// First, six pair-wise comparisons are performed between each possible pair // First, six pair-wise comparisons are performed between each possible pair
// of the four coordinates, and the results are used to add up binary bits // of the four coordinates, and the results are used to add up binary bits
// for an integer index. // for an integer index.
int c1 = (x0 > y0) ? 32 : 0; int c1 = (x0 > y0) ? 32 : 0;
int c2 = (x0 > z0) ? 16 : 0; int c2 = (x0 > z0) ? 16 : 0;
int c3 = (y0 > z0) ? 8 : 0; int c3 = (y0 > z0) ? 8 : 0;
int c4 = (x0 > w0) ? 4 : 0; int c4 = (x0 > w0) ? 4 : 0;
int c5 = (y0 > w0) ? 2 : 0; int c5 = (y0 > w0) ? 2 : 0;
int c6 = (z0 > w0) ? 1 : 0; int c6 = (z0 > w0) ? 1 : 0;
int c = c1 + c2 + c3 + c4 + c5 + c6; int c = c1 + c2 + c3 + c4 + c5 + c6;
int i1, j1, k1, l1; // The integer offsets for the second simplex corner int i1, j1, k1, l1; // The integer offsets for the second simplex corner
int i2, j2, k2, l2; // The integer offsets for the third simplex corner int i2, j2, k2, l2; // The integer offsets for the third simplex corner
int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner
// simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order.
// Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w // Many values of c will never occur, since e.g. x>y>z>w makes x<z, y<w and x<w
// impossible. Only the 24 indices which have non-zero entries make any sense. // impossible. Only the 24 indices which have non-zero entries make any sense.
// We use a thresholding to set the coordinates in turn from the largest magnitude. // We use a thresholding to set the coordinates in turn from the largest magnitude.
// The number 3 in the "simplex" array is at the position of the largest coordinate. // The number 3 in the "simplex" array is at the position of the largest coordinate.
i1 = simplex[c][0]>=3 ? 1 : 0; i1 = simplex[c][0]>=3 ? 1 : 0;
j1 = simplex[c][1]>=3 ? 1 : 0; j1 = simplex[c][1]>=3 ? 1 : 0;
k1 = simplex[c][2]>=3 ? 1 : 0; k1 = simplex[c][2]>=3 ? 1 : 0;
l1 = simplex[c][3]>=3 ? 1 : 0; l1 = simplex[c][3]>=3 ? 1 : 0;
// The number 2 in the "simplex" array is at the second largest coordinate. // The number 2 in the "simplex" array is at the second largest coordinate.
i2 = simplex[c][0]>=2 ? 1 : 0; i2 = simplex[c][0]>=2 ? 1 : 0;
j2 = simplex[c][1]>=2 ? 1 : 0; j2 = simplex[c][1]>=2 ? 1 : 0;
k2 = simplex[c][2]>=2 ? 1 : 0; k2 = simplex[c][2]>=2 ? 1 : 0;
l2 = simplex[c][3]>=2 ? 1 : 0; l2 = simplex[c][3]>=2 ? 1 : 0;
// The number 1 in the "simplex" array is at the second smallest coordinate. // The number 1 in the "simplex" array is at the second smallest coordinate.
i3 = simplex[c][0]>=1 ? 1 : 0; i3 = simplex[c][0]>=1 ? 1 : 0;
j3 = simplex[c][1]>=1 ? 1 : 0; j3 = simplex[c][1]>=1 ? 1 : 0;
k3 = simplex[c][2]>=1 ? 1 : 0; k3 = simplex[c][2]>=1 ? 1 : 0;
l3 = simplex[c][3]>=1 ? 1 : 0; l3 = simplex[c][3]>=1 ? 1 : 0;
// The fifth corner has all coordinate offsets = 1, so no need to look that up. // The fifth corner has all coordinate offsets = 1, so no need to look that up.
float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords
float y1 = y0 - j1 + G4; float y1 = y0 - j1 + G4;
float z1 = z0 - k1 + G4; float z1 = z0 - k1 + G4;
float w1 = w0 - l1 + G4; float w1 = w0 - l1 + G4;
float x2 = x0 - i2 + 2.0f*G4; // Offsets for third corner in (x,y,z,w) coords float x2 = x0 - i2 + 2.0f*G4; // Offsets for third corner in (x,y,z,w) coords
float y2 = y0 - j2 + 2.0f*G4; float y2 = y0 - j2 + 2.0f*G4;
float z2 = z0 - k2 + 2.0f*G4; float z2 = z0 - k2 + 2.0f*G4;
float w2 = w0 - l2 + 2.0f*G4; float w2 = w0 - l2 + 2.0f*G4;
float x3 = x0 - i3 + 3.0f*G4; // Offsets for fourth corner in (x,y,z,w) coords float x3 = x0 - i3 + 3.0f*G4; // Offsets for fourth corner in (x,y,z,w) coords
float y3 = y0 - j3 + 3.0f*G4; float y3 = y0 - j3 + 3.0f*G4;
float z3 = z0 - k3 + 3.0f*G4; float z3 = z0 - k3 + 3.0f*G4;
float w3 = w0 - l3 + 3.0f*G4; float w3 = w0 - l3 + 3.0f*G4;
float x4 = x0 - 1.0f + 4.0f*G4; // Offsets for last corner in (x,y,z,w) coords float x4 = x0 - 1.0f + 4.0f*G4; // Offsets for last corner in (x,y,z,w) coords
float y4 = y0 - 1.0f + 4.0f*G4; float y4 = y0 - 1.0f + 4.0f*G4;
float z4 = z0 - 1.0f + 4.0f*G4; float z4 = z0 - 1.0f + 4.0f*G4;
float w4 = w0 - 1.0f + 4.0f*G4; float w4 = w0 - 1.0f + 4.0f*G4;
// Wrap the integer indices at 256, to avoid indexing perm[] out of bounds // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
int ii = i & 0xff; int ii = i & 0xff;
int jj = j & 0xff; int jj = j & 0xff;
int kk = k & 0xff; int kk = k & 0xff;
int ll = l & 0xff; int ll = l & 0xff;
// Calculate the contribution from the five corners // Calculate the contribution from the five corners
float t0 = 0.5f - x0*x0 - y0*y0 - z0*z0 - w0*w0; float t0 = 0.5f - x0*x0 - y0*y0 - z0*z0 - w0*w0;
if(t0 < 0.0f) n0 = 0.0f; if(t0 < 0.0f) n0 = 0.0f;
else { else {
t0 *= t0; t0 *= t0;
n0 = t0 * t0 * grad4(perm[ii+perm[jj+perm[kk+perm[ll]]]], x0, y0, z0, w0); n0 = t0 * t0 * grad4(perm[ii+perm[jj+perm[kk+perm[ll]]]], x0, y0, z0, w0);
} }
float t1 = 0.5f - x1*x1 - y1*y1 - z1*z1 - w1*w1; float t1 = 0.5f - x1*x1 - y1*y1 - z1*z1 - w1*w1;
if(t1 < 0.0f) n1 = 0.0f; if(t1 < 0.0f) n1 = 0.0f;
else { else {
t1 *= t1; t1 *= t1;
n1 = t1 * t1 * grad4(perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]], x1, y1, z1, w1); n1 = t1 * t1 * grad4(perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]], x1, y1, z1, w1);
} }
float t2 = 0.5f - x2*x2 - y2*y2 - z2*z2 - w2*w2; float t2 = 0.5f - x2*x2 - y2*y2 - z2*z2 - w2*w2;
if(t2 < 0.0f) n2 = 0.0f; if(t2 < 0.0f) n2 = 0.0f;
else { else {
t2 *= t2; t2 *= t2;
n2 = t2 * t2 * grad4(perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]], x2, y2, z2, w2); n2 = t2 * t2 * grad4(perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]], x2, y2, z2, w2);
} }
float t3 = 0.5f - x3*x3 - y3*y3 - z3*z3 - w3*w3; float t3 = 0.5f - x3*x3 - y3*y3 - z3*z3 - w3*w3;
if(t3 < 0.0f) n3 = 0.0f; if(t3 < 0.0f) n3 = 0.0f;
else { else {
t3 *= t3; t3 *= t3;
n3 = t3 * t3 * grad4(perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]], x3, y3, z3, w3); n3 = t3 * t3 * grad4(perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]], x3, y3, z3, w3);
} }
float t4 = 0.5f - x4*x4 - y4*y4 - z4*z4 - w4*w4; float t4 = 0.5f - x4*x4 - y4*y4 - z4*z4 - w4*w4;
if(t4 < 0.0f) n4 = 0.0f; if(t4 < 0.0f) n4 = 0.0f;
else { else {
t4 *= t4; t4 *= t4;
n4 = t4 * t4 * grad4(perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]], x4, y4, z4, w4); n4 = t4 * t4 * grad4(perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]], x4, y4, z4, w4);
} }
// Sum up and scale the result to cover the range [-1,1] // Sum up and scale the result to cover the range [-1,1]
return 62.0f * (n0 + n1 + n2 + n3 + n4); return 62.0f * (n0 + n1 + n2 + n3 + n4);
} }
#undef F2 #undef F2
#undef G2 #undef G2
#undef F3 #undef F3
#undef G3 #undef G3
#undef F4 #undef F4
#undef G4 #undef G4
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,290 +1,290 @@
// https://github.com/BareRose/swrap/blob/master/swrap.h // https://github.com/BareRose/swrap/blob/master/swrap.h
/* /*
swrap - Portable, protocol-agnostic TCP and UDP socket wrapper, primarily designed for client-server models in applications such as games swrap - Portable, protocol-agnostic TCP and UDP socket wrapper, primarily designed for client-server models in applications such as games
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring
rights to this software to the public domain worldwide. This software is distributed without any warranty. rights to this software to the public domain worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with this software. You should have received a copy of the CC0 Public Domain Dedication along with this software.
If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/ */
/* /*
swrap supports the following three configurations: swrap supports the following three configurations:
#define SWRAP_EXTERN #define SWRAP_EXTERN
Default, should be used when using swrap in multiple compilation units within the same project. Default, should be used when using swrap in multiple compilation units within the same project.
#define SWRAP_IMPLEMENTATION #define SWRAP_IMPLEMENTATION
Must be defined in exactly one source file within a project for swrap to be found by the linker. Must be defined in exactly one source file within a project for swrap to be found by the linker.
#define SWRAP_STATIC #define SWRAP_STATIC
Defines all swrap functions as static, useful if swrap is only used in a single compilation unit. Defines all swrap functions as static, useful if swrap is only used in a single compilation unit.
*/ */
//include only once //include only once
#ifndef SWRAP_H #ifndef SWRAP_H
#define SWRAP_H #define SWRAP_H
//process configuration //process configuration
#ifdef SWRAP_STATIC #ifdef SWRAP_STATIC
#define SWRAP_IMPLEMENTATION #define SWRAP_IMPLEMENTATION
#define SWDEF static #define SWDEF static
#else //SWRAP_EXTERN #else //SWRAP_EXTERN
#define SWDEF extern #define SWDEF extern
#endif #endif
//constants //constants
#define SWRAP_TCP 0 #define SWRAP_TCP 0
#define SWRAP_UDP 1 #define SWRAP_UDP 1
#define SWRAP_BIND 0 #define SWRAP_BIND 0
#define SWRAP_CONNECT 1 #define SWRAP_CONNECT 1
#define SWRAP_DEFAULT 0x00 #define SWRAP_DEFAULT 0x00
#define SWRAP_NOBLOCK 0x01 #define SWRAP_NOBLOCK 0x01
#define SWRAP_NODELAY 0x02 #define SWRAP_NODELAY 0x02
//structs //structs
struct swrap_addr { struct swrap_addr {
char data[128]; //enough space to hold any kind of address char data[128]; //enough space to hold any kind of address
}; };
//function declarations //function declarations
SWDEF int swrapInit(); SWDEF int swrapInit();
SWDEF int swrapSocket(int, int, char, const char*, const char*); SWDEF int swrapSocket(int, int, char, const char*, const char*);
SWDEF void swrapClose(int); SWDEF void swrapClose(int);
SWDEF void swrapTerminate(); SWDEF void swrapTerminate();
SWDEF int swrapListen(int, int); SWDEF int swrapListen(int, int);
SWDEF int swrapAccept(int, struct swrap_addr*); SWDEF int swrapAccept(int, struct swrap_addr*);
SWDEF int swrapAddress(int, struct swrap_addr*); SWDEF int swrapAddress(int, struct swrap_addr*);
SWDEF int swrapAddressInfo(struct swrap_addr*, char*, size_t, char*, size_t); SWDEF int swrapAddressInfo(struct swrap_addr*, char*, size_t, char*, size_t);
SWDEF int swrapSend(int, const char*, size_t); SWDEF int swrapSend(int, const char*, size_t);
SWDEF int swrapReceive(int, char*, size_t); SWDEF int swrapReceive(int, char*, size_t);
SWDEF int swrapSendTo(int, struct swrap_addr*, const char*, size_t); SWDEF int swrapSendTo(int, struct swrap_addr*, const char*, size_t);
SWDEF int swrapReceiveFrom(int, struct swrap_addr*, char*, size_t); SWDEF int swrapReceiveFrom(int, struct swrap_addr*, char*, size_t);
SWDEF int swrapSelect(int, double); SWDEF int swrapSelect(int, double);
SWDEF int swrapMultiSelect(int*, size_t, double); SWDEF int swrapMultiSelect(int*, size_t, double);
//implementation section //implementation section
#ifdef SWRAP_IMPLEMENTATION #ifdef SWRAP_IMPLEMENTATION
//includes //includes
#ifdef _WIN32 //windows #ifdef _WIN32 //windows
#include <ws2tcpip.h> #include <ws2tcpip.h>
#else //unix #else //unix
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#endif #endif
#include <stddef.h> //NULL #include <stddef.h> //NULL
#include <limits.h> //INT_MAX on emscripten //< @r-lyeh: added #include <limits.h> //INT_MAX on emscripten //< @r-lyeh: added
//general functions //general functions
SWDEF int swrapInit () { SWDEF int swrapInit () {
//initializes socket functionality, returns 0 on success //initializes socket functionality, returns 0 on success
#ifdef _WIN32 #ifdef _WIN32
WSADATA WsaData; WSADATA WsaData;
return (WSAStartup(MAKEWORD(2,2), &WsaData) != NO_ERROR); return (WSAStartup(MAKEWORD(2,2), &WsaData) != NO_ERROR);
#else #else
return 0; return 0;
#endif #endif
} }
SWDEF int swrapSocket (int prot, int mode, char flags, const char* host, const char* serv) { SWDEF int swrapSocket (int prot, int mode, char flags, const char* host, const char* serv) {
//protocol-agnostically creates a new socket configured according to the given parameters //protocol-agnostically creates a new socket configured according to the given parameters
//sockets have to be created and bound/connected all at once to allow for protocol-agnosticity //sockets have to be created and bound/connected all at once to allow for protocol-agnosticity
//int: Protocol of the socket, either SWRAP_TCP or SWRAP_UDP for TCP or UDP respectively //int: Protocol of the socket, either SWRAP_TCP or SWRAP_UDP for TCP or UDP respectively
// SWRAP_TCP: TCP protocol connection-oriented reliable delivery, see swrapListen/Accept // SWRAP_TCP: TCP protocol connection-oriented reliable delivery, see swrapListen/Accept
// SWRAP_UDP: UDP protocol connectionless unreliable, SWRAP_CONNECT just assigns correspondent // SWRAP_UDP: UDP protocol connectionless unreliable, SWRAP_CONNECT just assigns correspondent
//int: Mode of the socket //int: Mode of the socket
// SWRAP_BIND: Bind to given address (or all interfaces if NULL) and port, e.g. for a server // SWRAP_BIND: Bind to given address (or all interfaces if NULL) and port, e.g. for a server
// SWRAP_CONNECT: Connect to given address (localhost if NULL) and port, e.g. for a client // SWRAP_CONNECT: Connect to given address (localhost if NULL) and port, e.g. for a client
//char: Configuration flags, either SWRAP_DEFAULT or a bitwise combination of flags //char: Configuration flags, either SWRAP_DEFAULT or a bitwise combination of flags
// SWRAP_NOBLOCK: Sets the socket to be non-blocking, default is blocking // SWRAP_NOBLOCK: Sets the socket to be non-blocking, default is blocking
// SWRAP_NODELAY: Disables Nagle's for TCP sockets, default is enabled // SWRAP_NODELAY: Disables Nagle's for TCP sockets, default is enabled
//char*: Host/address as a string, can be IPv4, IPv6, etc... //char*: Host/address as a string, can be IPv4, IPv6, etc...
//char*: Service/port as a string, e.g. "1728" or "http" //char*: Service/port as a string, e.g. "1728" or "http"
//returns socket handle, or -1 on failure //returns socket handle, or -1 on failure
struct addrinfo* result, hint = { struct addrinfo* result, hint = {
(mode == SWRAP_BIND) ? AI_PASSIVE : 0, //ai_flags (mode == SWRAP_BIND) ? AI_PASSIVE : 0, //ai_flags
AF_UNSPEC, //ai_family AF_UNSPEC, //ai_family
(prot == SWRAP_TCP) ? SOCK_STREAM : SOCK_DGRAM, //ai_socktype (prot == SWRAP_TCP) ? SOCK_STREAM : SOCK_DGRAM, //ai_socktype
0, 0, NULL, NULL, NULL}; 0, 0, NULL, NULL, NULL};
//get address info //get address info
if (getaddrinfo(host, serv, &hint, &result)) return -1; if (getaddrinfo(host, serv, &hint, &result)) return -1;
//create socket //create socket
#ifdef _WIN32 #ifdef _WIN32
SOCKET wsck = socket(result->ai_family, result->ai_socktype, result->ai_protocol); SOCKET wsck = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (wsck == INVALID_SOCKET) return -1; if (wsck == INVALID_SOCKET) return -1;
//reject socket handle outside int range //reject socket handle outside int range
if (wsck > INT_MAX) { if (wsck > INT_MAX) {
closesocket(wsck); closesocket(wsck);
return -1; return -1;
} }
//convert to int //convert to int
int sock = wsck; int sock = wsck;
#else #else
int sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol); int sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (sock == -1) return -1; if (sock == -1) return -1;
#endif #endif
//make sure IPV6_ONLY is disabled //make sure IPV6_ONLY is disabled
if (result->ai_family == AF_INET6) { if (result->ai_family == AF_INET6) {
int no = 0; int no = 0;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&no, sizeof(no)); setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&no, sizeof(no));
} }
//set TCP_NODELAY if applicable //set TCP_NODELAY if applicable
if (prot == SWRAP_TCP) { if (prot == SWRAP_TCP) {
int nodelay = (flags&SWRAP_NODELAY); int nodelay = (flags&SWRAP_NODELAY);
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&nodelay, sizeof(nodelay)); setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&nodelay, sizeof(nodelay));
} }
//bind if applicable //bind if applicable
if ((mode == SWRAP_BIND)&&(bind(sock, result->ai_addr, result->ai_addrlen))) { if ((mode == SWRAP_BIND)&&(bind(sock, result->ai_addr, result->ai_addrlen))) {
swrapClose(sock); swrapClose(sock);
return -1; return -1;
} }
//set non-blocking if needed //set non-blocking if needed
if (flags&SWRAP_NOBLOCK) { if (flags&SWRAP_NOBLOCK) {
#ifdef _WIN32 #ifdef _WIN32
DWORD no_block = 1; DWORD no_block = 1;
if (ioctlsocket(sock, FIONBIO, &no_block)) { if (ioctlsocket(sock, FIONBIO, &no_block)) {
swrapClose(sock); swrapClose(sock);
return -1; return -1;
} }
#else #else
if (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == -1) { if (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == -1) {
swrapClose(sock); swrapClose(sock);
return -1; return -1;
} }
#endif #endif
} }
//connect if applicable (return only relevant if blocking) //connect if applicable (return only relevant if blocking)
if ((mode == SWRAP_CONNECT)&&(connect(sock, result->ai_addr, result->ai_addrlen))&&(!(flags&SWRAP_NOBLOCK))) { if ((mode == SWRAP_CONNECT)&&(connect(sock, result->ai_addr, result->ai_addrlen))&&(!(flags&SWRAP_NOBLOCK))) {
swrapClose(sock); swrapClose(sock);
return -1; return -1;
} }
//free address info //free address info
freeaddrinfo(result); freeaddrinfo(result);
//return socket handle //return socket handle
return sock; return sock;
} }
SWDEF void swrapClose (int sock) { SWDEF void swrapClose (int sock) {
//closes the given socket //closes the given socket
#ifdef _WIN32 #ifdef _WIN32
closesocket(sock); closesocket(sock);
#else #else
close(sock); close(sock);
#endif #endif
} }
SWDEF void swrapTerminate () { SWDEF void swrapTerminate () {
//terminates socket functionality //terminates socket functionality
#ifdef _WIN32 #ifdef _WIN32
WSACleanup(); WSACleanup();
#endif #endif
} }
//connection functions //connection functions
SWDEF int swrapListen (int sock, int blog) { SWDEF int swrapListen (int sock, int blog) {
//configures the given socket (must be SWRAP_TCP + SWRAP_BIND) to listen for new connections with given maximum backlog //configures the given socket (must be SWRAP_TCP + SWRAP_BIND) to listen for new connections with given maximum backlog
//returns 0 on success, non-zero on failure //returns 0 on success, non-zero on failure
return listen(sock, blog); return listen(sock, blog);
} }
SWDEF int swrapAccept (int sock, struct swrap_addr* addr) { SWDEF int swrapAccept (int sock, struct swrap_addr* addr) {
//uses the given socket (must be swrapListen) to accept a new incoming connection, optionally returning its address //uses the given socket (must be swrapListen) to accept a new incoming connection, optionally returning its address
//returns a socket handle for the new connection, or -1 on failure (e.g. if there are no new connections) //returns a socket handle for the new connection, or -1 on failure (e.g. if there are no new connections)
#ifdef _WIN32 #ifdef _WIN32
int addr_size = sizeof(struct swrap_addr); int addr_size = sizeof(struct swrap_addr);
SOCKET wsck = accept(sock, (struct sockaddr*)addr, (addr) ? &addr_size : NULL); SOCKET wsck = accept(sock, (struct sockaddr*)addr, (addr) ? &addr_size : NULL);
if (wsck == INVALID_SOCKET) return -1; if (wsck == INVALID_SOCKET) return -1;
//reject socket handle outside int range //reject socket handle outside int range
if (wsck > INT_MAX) { if (wsck > INT_MAX) {
closesocket(wsck); closesocket(wsck);
return -1; return -1;
} }
//return new socket //return new socket
return wsck; return wsck;
#else #else
socklen_t addr_size = sizeof(struct swrap_addr); socklen_t addr_size = sizeof(struct swrap_addr);
return accept(sock, (struct sockaddr*)addr, (addr) ? &addr_size : NULL); return accept(sock, (struct sockaddr*)addr, (addr) ? &addr_size : NULL);
#endif #endif
} }
//address functions //address functions
SWDEF int swrapAddress (int sock, struct swrap_addr* addr) { SWDEF int swrapAddress (int sock, struct swrap_addr* addr) {
//writes the address the given socket is bound to into given address pointer, useful when automatically assigning port //writes the address the given socket is bound to into given address pointer, useful when automatically assigning port
//returns 0 on success, non-zero on failure //returns 0 on success, non-zero on failure
#ifdef _WIN32 #ifdef _WIN32
int addr_size = sizeof(struct swrap_addr); int addr_size = sizeof(struct swrap_addr);
#else #else
socklen_t addr_size = sizeof(struct swrap_addr); socklen_t addr_size = sizeof(struct swrap_addr);
#endif #endif
return getsockname(sock, (struct sockaddr*)addr, &addr_size); return getsockname(sock, (struct sockaddr*)addr, &addr_size);
} }
SWDEF int swrapAddressInfo (struct swrap_addr* addr, char* host, size_t host_size, char* serv, size_t serv_size) { SWDEF int swrapAddressInfo (struct swrap_addr* addr, char* host, size_t host_size, char* serv, size_t serv_size) {
//writes the host/address and service/port of given address into given buffers (pointer + size), either buffer may be NULL //writes the host/address and service/port of given address into given buffers (pointer + size), either buffer may be NULL
//returns 0 on success, non-zero on failure //returns 0 on success, non-zero on failure
return getnameinfo((struct sockaddr*)addr, sizeof(struct swrap_addr), host, host_size, serv, serv_size, 0); return getnameinfo((struct sockaddr*)addr, sizeof(struct swrap_addr), host, host_size, serv, serv_size, 0);
} }
//send/receive functions //send/receive functions
SWDEF int swrapSend (int sock, const char* data, size_t data_size) { SWDEF int swrapSend (int sock, const char* data, size_t data_size) {
//uses the given socket (either SWRAP_CONNECT or returned by swrapAccept) to send given data (pointer + size) //uses the given socket (either SWRAP_CONNECT or returned by swrapAccept) to send given data (pointer + size)
//at most INT_MAX bytes of data will be sent, data sizes greater than that are clamped to INT_MAX //at most INT_MAX bytes of data will be sent, data sizes greater than that are clamped to INT_MAX
//returns how much data was actually sent (may be less than data size), or -1 on failure //returns how much data was actually sent (may be less than data size), or -1 on failure
return send(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0); return send(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0);
} }
SWDEF int swrapReceive (int sock, char* data, size_t data_size) { SWDEF int swrapReceive (int sock, char* data, size_t data_size) {
//receives data using given socket (either SWRAP_CONNECT or returned by swrapAccept) into given buffer (pointer + size) //receives data using given socket (either SWRAP_CONNECT or returned by swrapAccept) into given buffer (pointer + size)
//at most INT_MAX bytes of data will be received, buffer sizes greater than INT_MAX have no additional benefit //at most INT_MAX bytes of data will be received, buffer sizes greater than INT_MAX have no additional benefit
//returns the number of bytes received, 0 on orderly shutdown, or -1 on failure (e.g. no data to receive) //returns the number of bytes received, 0 on orderly shutdown, or -1 on failure (e.g. no data to receive)
return recv(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0); return recv(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0);
} }
SWDEF int swrapSendTo (int sock, struct swrap_addr* addr, const char* data, size_t data_size) { SWDEF int swrapSendTo (int sock, struct swrap_addr* addr, const char* data, size_t data_size) {
//uses the given socket to send given data (pointer + size) to the given swrap_addr (e.g. from swrapReceiveFrom) //uses the given socket to send given data (pointer + size) to the given swrap_addr (e.g. from swrapReceiveFrom)
//at most INT_MAX bytes of data will be sent, data sizes greater than that are clamped to INT_MAX //at most INT_MAX bytes of data will be sent, data sizes greater than that are clamped to INT_MAX
//returns how much data was actually sent (may be less than data size), or -1 on failure //returns how much data was actually sent (may be less than data size), or -1 on failure
return sendto(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0, (struct sockaddr*)addr, sizeof(struct swrap_addr)); return sendto(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0, (struct sockaddr*)addr, sizeof(struct swrap_addr));
} }
SWDEF int swrapReceiveFrom (int sock, struct swrap_addr* addr, char* data, size_t data_size) { SWDEF int swrapReceiveFrom (int sock, struct swrap_addr* addr, char* data, size_t data_size) {
//receives data using given socket into given buffer (pointer + size), optionally returning sender's address //receives data using given socket into given buffer (pointer + size), optionally returning sender's address
//at most INT_MAX bytes of data will be received, buffer sizes greater than INT_MAX have no additional benefit //at most INT_MAX bytes of data will be received, buffer sizes greater than INT_MAX have no additional benefit
//returns the number of bytes received, 0 on orderly shutdown, or -1 on failure (e.g. no data to receive) //returns the number of bytes received, 0 on orderly shutdown, or -1 on failure (e.g. no data to receive)
#ifdef _WIN32 #ifdef _WIN32
int addr_size = sizeof(struct swrap_addr); int addr_size = sizeof(struct swrap_addr);
#else #else
socklen_t addr_size = sizeof(struct swrap_addr); socklen_t addr_size = sizeof(struct swrap_addr);
#endif #endif
return recvfrom(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0, (struct sockaddr*)addr, &addr_size); return recvfrom(sock, data, (data_size > INT_MAX) ? INT_MAX : data_size, 0, (struct sockaddr*)addr, &addr_size);
} }
//select functions //select functions
SWDEF int swrapSelect (int sock, double timeout) { SWDEF int swrapSelect (int sock, double timeout) {
//waits either until given socket has new data to receive or given time (in seconds) has passed //waits either until given socket has new data to receive or given time (in seconds) has passed
//if given socket is -1 an empty select will be performed, which is just a sub-second sleep //if given socket is -1 an empty select will be performed, which is just a sub-second sleep
//returns 1 if new data is available, 0 if timeout was reached, and -1 on error //returns 1 if new data is available, 0 if timeout was reached, and -1 on error
fd_set set; struct timeval time; fd_set set; struct timeval time;
//fd set //fd set
FD_ZERO(&set); FD_ZERO(&set);
if (sock > -1) FD_SET(sock, &set); if (sock > -1) FD_SET(sock, &set);
//timeout //timeout
time.tv_sec = timeout; time.tv_sec = timeout;
time.tv_usec = (timeout - time.tv_sec)*1000000.0; time.tv_usec = (timeout - time.tv_sec)*1000000.0;
//return //return
return select(sock+1, &set, NULL, NULL, &time); return select(sock+1, &set, NULL, NULL, &time);
} }
SWDEF int swrapMultiSelect (int* socks, size_t socks_size, double timeout) { SWDEF int swrapMultiSelect (int* socks, size_t socks_size, double timeout) {
//waits either until a socket in given list has new data to receive or given time (in seconds) has passed //waits either until a socket in given list has new data to receive or given time (in seconds) has passed
//if the given list length is 0 an empty select will be performed, which is just a sub-second sleep //if the given list length is 0 an empty select will be performed, which is just a sub-second sleep
//returns 1 or more if new data is available, 0 if timeout was reached, and -1 on error //returns 1 or more if new data is available, 0 if timeout was reached, and -1 on error
fd_set set; struct timeval time; int sock_max = -1; fd_set set; struct timeval time; int sock_max = -1;
//fd set //fd set
FD_ZERO(&set); FD_ZERO(&set);
for (size_t i = 0; i < socks_size; i++) { for (size_t i = 0; i < socks_size; i++) {
if (socks[i] > sock_max) sock_max = socks[i]; if (socks[i] > sock_max) sock_max = socks[i];
if (socks[i] > -1) FD_SET(socks[i], &set); if (socks[i] > -1) FD_SET(socks[i], &set);
} }
//timeout //timeout
time.tv_sec = timeout; time.tv_sec = timeout;
time.tv_usec = (timeout - time.tv_sec)*1000000.0; time.tv_usec = (timeout - time.tv_sec)*1000000.0;
//return //return
return select(sock_max+1, &set, NULL, NULL, &time); return select(sock_max+1, &set, NULL, NULL, &time);
} }
#endif //SWRAP_IMPLEMENTATION #endif //SWRAP_IMPLEMENTATION
#endif //SWRAP_H #endif //SWRAP_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +1,82 @@
// AI framework // AI framework
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// [src] original A-star code by @mmozeiko (PD) - https://gist.github.com/mmozeiko/68f0a8459ef2f98bcd879158011cc275 // [src] original A-star code by @mmozeiko (PD) - https://gist.github.com/mmozeiko/68f0a8459ef2f98bcd879158011cc275
// [src] original swarm/boids code by @Cultrarius (UNLICENSE) - https://github.com/Cultrarius/Swarmz // [src] original swarm/boids code by @Cultrarius (UNLICENSE) - https://github.com/Cultrarius/Swarmz
// pathfinding ----------------------------------------------------------------- // pathfinding -----------------------------------------------------------------
API int pathfind_astar(int width, int height, const unsigned* map, vec2i src, vec2i dst, vec2i* path, size_t maxpath); API int pathfind_astar(int width, int height, const unsigned* map, vec2i src, vec2i dst, vec2i* path, size_t maxpath);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Behavior trees: decision planning and decision making. // Behavior trees: decision planning and decision making.
// Supersedes finite state-machines (FSM) and hierarchical finite state-machines (HFSM). // Supersedes finite state-machines (FSM) and hierarchical finite state-machines (HFSM).
typedef int (*bt_func)(); typedef int (*bt_func)();
typedef struct bt_t { typedef struct bt_t {
uint64_t type; uint64_t type;
int (*action)(); int (*action)();
union { union {
int argi; int argi;
float argf; float argf;
}; };
array(struct bt_t) children; array(struct bt_t) children;
} bt_t; } bt_t;
API bt_t bt(const char *ini_file, unsigned flags); API bt_t bt(const char *ini_file, unsigned flags);
API int bt_run(bt_t *b); API int bt_run(bt_t *b);
API void bt_addfun(const char *name, int(*func)()); API void bt_addfun(const char *name, int(*func)());
API bt_func bt_findfun(const char *name); API bt_func bt_findfun(const char *name);
API char *bt_funcname(bt_func fn); API char *bt_funcname(bt_func fn);
API int ui_bt(bt_t *b); API int ui_bt(bt_t *b);
// boids/swarm ----------------------------------------------------------------- // boids/swarm -----------------------------------------------------------------
typedef enum SWARM_DISTANCE { typedef enum SWARM_DISTANCE {
SWARM_DISTANCE_LINEAR, SWARM_DISTANCE_LINEAR,
SWARM_DISTANCE_INVERSE_LINEAR, SWARM_DISTANCE_INVERSE_LINEAR,
SWARM_DISTANCE_QUADRATIC, SWARM_DISTANCE_QUADRATIC,
SWARM_DISTANCE_INVERSE_QUADRATIC SWARM_DISTANCE_INVERSE_QUADRATIC
} SWARM_DISTANCE; } SWARM_DISTANCE;
#define boid(...) C_CAST(boid_t, __VA_ARGS__) #define boid(...) C_CAST(boid_t, __VA_ARGS__)
typedef struct boid_t { typedef struct boid_t {
vec3 position; vec3 position;
vec3 velocity; vec3 velocity;
vec3 acceleration; vec3 acceleration;
vec3 prev_position; vec3 prev_position;
} boid_t; } boid_t;
typedef struct swarm_t { typedef struct swarm_t {
array(boid_t) boids; array(boid_t) boids;
float perception_radius; // determines the vision radius of each boid. Only boids within this distance influence each other. float perception_radius; // determines the vision radius of each boid. Only boids within this distance influence each other.
float separation_weight; // how much boids repel each other float separation_weight; // how much boids repel each other
SWARM_DISTANCE separation_type; SWARM_DISTANCE separation_type;
float alignment_weight; // how much boids want go in the same direction float alignment_weight; // how much boids want go in the same direction
float cohesion_weight; // how much boids want to be in the center of the swarm float cohesion_weight; // how much boids want to be in the center of the swarm
float steering_weight; float steering_weight;
array(vec3) steering_targets; array(vec3) steering_targets;
SWARM_DISTANCE steering_target_type; SWARM_DISTANCE steering_target_type;
float blindspot_angledeg; float blindspot_angledeg;
float max_acceleration; // how fast each boid can change its direction float max_acceleration; // how fast each boid can change its direction
float max_velocity; // how fast each boid can move float max_velocity; // how fast each boid can move
// private: // private:
map(vec3*, array(boid_t*)) voxel_cache_; map(vec3*, array(boid_t*)) voxel_cache_;
float blindspot_angledeg_compare_value_; float blindspot_angledeg_compare_value_;
} swarm_t; } swarm_t;
API swarm_t swarm(); API swarm_t swarm();
API void swarm_update(swarm_t *self, float delta); // acc,vel,pos API void swarm_update(swarm_t *self, float delta); // acc,vel,pos
API void swarm_update_acceleration_only(swarm_t *self); // acc API void swarm_update_acceleration_only(swarm_t *self); // acc
API void swarm_update_acceleration_and_velocity_only(swarm_t *self, float delta); // acc,vel API void swarm_update_acceleration_and_velocity_only(swarm_t *self, float delta); // acc,vel
API int ui_swarm(swarm_t *self); API int ui_swarm(swarm_t *self);

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,60 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// audio framework // audio framework
// - rlyeh, public domain // - rlyeh, public domain
// //
// fixme: leaks, audio_delete // fixme: leaks, audio_delete
// @todo: audio_volume_fx, audio_volume_bgm, audio_volume_master instead? // @todo: audio_volume_fx, audio_volume_bgm, audio_volume_master instead?
// @todo: destroystream() if( ss->type == WAV ) drwav_uninit(&ss->wav); // @todo: destroystream() if( ss->type == WAV ) drwav_uninit(&ss->wav);
// @todo: destroystream() if( ss->type == MOD ) jar_mod_unload(&ss->mod); // @todo: destroystream() if( ss->type == MOD ) jar_mod_unload(&ss->mod);
// @todo: destroystream() if( ss->type == XM && ss->xm ) jar_xm_free_context(ss->xm); // @todo: destroystream() if( ss->type == XM && ss->xm ) jar_xm_free_context(ss->xm);
// midi interface // midi interface
API void midi_send(unsigned midi_msg); API void midi_send(unsigned midi_msg);
// audio interface // audio interface
typedef struct audio_handle* audio_t; typedef struct audio_handle* audio_t;
API audio_t audio_clip( const char *pathfile ); API audio_t audio_clip( const char *pathfile );
API audio_t audio_stream( const char *pathfile ); API audio_t audio_stream( const char *pathfile );
API int audio_play( audio_t s, int flags ); API int audio_play( audio_t s, int flags );
API int audio_play_gain( audio_t a, int flags, float gain/*0*/ ); API int audio_play_gain( audio_t a, int flags, float gain/*0*/ );
API int audio_play_gain_pitch( audio_t a, int flags, float gain, float pitch/*1*/ ); API int audio_play_gain_pitch( audio_t a, int flags, float gain, float pitch/*1*/ );
API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ ); API int audio_play_gain_pitch_pan( audio_t a, int flags, float gain, float pitch, float pan/*0*/ );
API int audio_stop( audio_t a ); API int audio_stop( audio_t a );
API void audio_loop( audio_t a, bool loop ); API void audio_loop( audio_t a, bool loop );
API bool audio_playing( audio_t a ); API bool audio_playing( audio_t a );
API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. returns current fx volume in any case API float audio_volume_clip(float gain); // set fx volume if gain is in [0..1] range. returns current fx volume in any case
API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. returns current bgm volume in any case API float audio_volume_stream(float gain); // set bgm volume if gain is in [0..1] range. returns current bgm volume in any case
API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. returns current master volume in any case API float audio_volume_master(float gain); // set master volume if gain is in [0..1] range. returns current master volume in any case
API int audio_mute(int mute); API int audio_mute(int mute);
API int audio_muted(); API int audio_muted();
API int ui_audio(); API int ui_audio();
enum AUDIO_FLAGS { enum AUDIO_FLAGS {
AUDIO_1CH = 0, // default AUDIO_1CH = 0, // default
AUDIO_2CH = 1, AUDIO_2CH = 1,
AUDIO_8 = 2, AUDIO_8 = 2,
AUDIO_16 = 0, // default AUDIO_16 = 0, // default
AUDIO_32 = 4, AUDIO_32 = 4,
AUDIO_FLOAT = 8, AUDIO_FLOAT = 8,
AUDIO_8KHZ = 16, AUDIO_8KHZ = 16,
AUDIO_11KHZ = 32, AUDIO_11KHZ = 32,
AUDIO_22KHZ = 0, // default AUDIO_22KHZ = 0, // default
AUDIO_32KHZ = 64, AUDIO_32KHZ = 64,
AUDIO_44KHZ = 128, AUDIO_44KHZ = 128,
AUDIO_MIXER_GAIN = 0, // default AUDIO_MIXER_GAIN = 0, // default
AUDIO_IGNORE_MIXER_GAIN = 256, AUDIO_IGNORE_MIXER_GAIN = 256,
AUDIO_MULTIPLE_INSTANCES = 0, // default AUDIO_MULTIPLE_INSTANCES = 0, // default
AUDIO_SINGLE_INSTANCE = 512, AUDIO_SINGLE_INSTANCE = 512,
}; };
API int audio_queue( const void *samples, int num_samples, int flags ); API int audio_queue( const void *samples, int num_samples, int flags );

View File

@ -1,6 +1,6 @@
#define do_threadlock(mutexptr) \ #define do_threadlock(mutexptr) \
for( int init_ = !!(mutexptr) || (thread_mutex_init( (mutexptr) = CALLOC(1, sizeof(thread_mutex_t)) ), 1); init_; init_ = 0) \ for( int init_ = !!(mutexptr) || (thread_mutex_init( (mutexptr) = CALLOC(1, sizeof(thread_mutex_t)) ), 1); init_; init_ = 0) \
for( int lock_ = (thread_mutex_lock( mutexptr ), 1); lock_; lock_ = (thread_mutex_unlock( mutexptr ), 0) ) for( int lock_ = (thread_mutex_lock( mutexptr ), 1); lock_; lock_ = (thread_mutex_unlock( mutexptr ), 0) )
#define AS_NKCOLOR(color) \ #define AS_NKCOLOR(color) \
((struct nk_color){ ((color>>0))&255,((color>>8))&255,((color>>16))&255,((color>>24))&255 }) ((struct nk_color){ ((color>>0))&255,((color>>8))&255,((color>>16))&255,((color>>24))&255 })

File diff suppressed because it is too large Load Diff

View File

@ -1,158 +1,158 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// original code by @vurtun (PD) and @barerose (CC0). // original code by @vurtun (PD) and @barerose (CC0).
// [src] https://gist.github.com/vurtun/95f088e4889da2474ad1ce82d7911fee // [src] https://gist.github.com/vurtun/95f088e4889da2474ad1ce82d7911fee
// - rlyeh, public domain. // - rlyeh, public domain.
#ifndef GJK_H #ifndef GJK_H
#define GJK_H #define GJK_H
#define GJK_MAX_ITERATIONS 20 #define GJK_MAX_ITERATIONS 20
typedef struct gjk_support { typedef struct gjk_support {
int aid, bid; int aid, bid;
vec3 a; vec3 a;
vec3 b; vec3 b;
} gjk_support; } gjk_support;
typedef struct gjk_vertex { typedef struct gjk_vertex {
vec3 a; vec3 a;
vec3 b; vec3 b;
vec3 p; vec3 p;
int aid, bid; int aid, bid;
} gjk_vertex; } gjk_vertex;
typedef struct gjk_simplex { typedef struct gjk_simplex {
int max_iter, iter; int max_iter, iter;
int hit, cnt; int hit, cnt;
gjk_vertex v[4]; gjk_vertex v[4];
float bc[4], D; float bc[4], D;
} gjk_simplex; } gjk_simplex;
typedef struct gjk_result { typedef struct gjk_result {
int hit; int hit;
vec3 p0; vec3 p0;
vec3 p1; vec3 p1;
float distance_squared; float distance_squared;
int iterations; int iterations;
} gjk_result; } gjk_result;
int gjk(gjk_simplex *s, const gjk_support *sup, vec3 *dv); int gjk(gjk_simplex *s, const gjk_support *sup, vec3 *dv);
gjk_result gjk_analyze(const gjk_simplex *s); gjk_result gjk_analyze(const gjk_simplex *s);
gjk_result gjk_quad(float a_radius, float b_radius); gjk_result gjk_quad(float a_radius, float b_radius);
#endif #endif
//typedef struct gjk_result gjk_result; //typedef struct gjk_result gjk_result;
typedef struct line { vec3 a, b; } line; typedef struct line { vec3 a, b; } line;
typedef struct sphere { vec3 c; float r; } sphere; typedef struct sphere { vec3 c; float r; } sphere;
typedef struct aabb { vec3 min, max; } aabb; typedef struct aabb { vec3 min, max; } aabb;
typedef struct plane { vec3 p, n; } plane; typedef struct plane { vec3 p, n; } plane;
typedef struct capsule { vec3 a, b; float r; } capsule; typedef struct capsule { vec3 a, b; float r; } capsule;
typedef struct ray { vec3 p, d; } ray; typedef struct ray { vec3 p, d; } ray;
typedef struct triangle { vec3 p0,p1,p2; } triangle; typedef struct triangle { vec3 p0,p1,p2; } triangle;
typedef struct poly { vec3* verts; int cnt; } poly; typedef struct poly { vec3* verts; int cnt; } poly;
typedef union frustum { struct { vec4 l, r, t, b, n, f; }; vec4 pl[6]; float v[24]; } frustum; typedef union frustum { struct { vec4 l, r, t, b, n, f; }; vec4 pl[6]; float v[24]; } frustum;
#define line(...) C_CAST(line, __VA_ARGS__) #define line(...) C_CAST(line, __VA_ARGS__)
#define sphere(...) C_CAST(sphere, __VA_ARGS__) #define sphere(...) C_CAST(sphere, __VA_ARGS__)
#define aabb(...) C_CAST(aabb, __VA_ARGS__) #define aabb(...) C_CAST(aabb, __VA_ARGS__)
#define plane(...) C_CAST(plane, __VA_ARGS__) #define plane(...) C_CAST(plane, __VA_ARGS__)
#define capsule(...) C_CAST(capsule, __VA_ARGS__) #define capsule(...) C_CAST(capsule, __VA_ARGS__)
#define ray(p,normdir) C_CAST(ray, p, normdir) #define ray(p,normdir) C_CAST(ray, p, normdir)
#define triangle(...) C_CAST(triangle, __VA_ARGS__) #define triangle(...) C_CAST(triangle, __VA_ARGS__)
#define poly(...) C_CAST(poly, __VA_ARGS__) #define poly(...) C_CAST(poly, __VA_ARGS__)
#define frustum(...) C_CAST(frustum, __VA_ARGS__) #define frustum(...) C_CAST(frustum, __VA_ARGS__)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
typedef struct hit { typedef struct hit {
union { union {
// general case // general case
float depth; float depth;
// rays only: penetration (t0) and extraction (t1) points along ray line // rays only: penetration (t0) and extraction (t1) points along ray line
struct { float t0, t1; }; struct { float t0, t1; };
// gjk only // gjk only
struct { int hits; vec3 p0, p1; float distance2; int iterations; }; struct { int hits; vec3 p0, p1; float distance2; int iterations; };
}; };
union { vec3 p; vec3 contact_point; }; union { vec3 p; vec3 contact_point; };
union { vec3 n; vec3 normal; }; union { vec3 n; vec3 normal; };
} hit; } hit;
#define hit(...) C_CAST(hit, __VA_ARGS__) #define hit(...) C_CAST(hit, __VA_ARGS__)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/* line/segment */ /* line/segment */
API float line_distance2_point(line l, vec3 p); API float line_distance2_point(line l, vec3 p);
API vec3 line_closest_point(line l, vec3 p); API vec3 line_closest_point(line l, vec3 p);
/* ray */ /* ray */
API float ray_test_plane(ray r, vec4 p4); API float ray_test_plane(ray r, vec4 p4);
API float ray_test_triangle(ray r, triangle t); API float ray_test_triangle(ray r, triangle t);
API int ray_test_sphere(float *t0, float *t1, ray r, sphere s); API int ray_test_sphere(float *t0, float *t1, ray r, sphere s);
API int ray_test_aabb(float *t0, float *t1, ray r, aabb a); API int ray_test_aabb(float *t0, float *t1, ray r, aabb a);
API hit* ray_hit_plane(ray r, plane p); API hit* ray_hit_plane(ray r, plane p);
API hit* ray_hit_triangle(ray r, triangle t); API hit* ray_hit_triangle(ray r, triangle t);
API hit* ray_hit_sphere(ray r, sphere s); API hit* ray_hit_sphere(ray r, sphere s);
API hit* ray_hit_aabb(ray r, aabb a); API hit* ray_hit_aabb(ray r, aabb a);
/* sphere */ /* sphere */
API vec3 sphere_closest_point(sphere s, vec3 p); API vec3 sphere_closest_point(sphere s, vec3 p);
API hit* sphere_hit_aabb(sphere s, aabb a); API hit* sphere_hit_aabb(sphere s, aabb a);
API hit* sphere_hit_capsule(sphere s, capsule c); API hit* sphere_hit_capsule(sphere s, capsule c);
API hit* sphere_hit_sphere(sphere a, sphere b); API hit* sphere_hit_sphere(sphere a, sphere b);
API int sphere_test_aabb(sphere s, aabb a); API int sphere_test_aabb(sphere s, aabb a);
API int sphere_test_capsule(sphere s, capsule c); API int sphere_test_capsule(sphere s, capsule c);
API int sphere_test_poly(sphere s, poly p); API int sphere_test_poly(sphere s, poly p);
API int sphere_test_sphere(sphere a, sphere b); API int sphere_test_sphere(sphere a, sphere b);
/* aabb */ /* aabb */
API vec3 aabb_closest_point(aabb a, vec3 p); API vec3 aabb_closest_point(aabb a, vec3 p);
API float aabb_distance2_point(aabb a, vec3 p); API float aabb_distance2_point(aabb a, vec3 p);
API int aabb_contains_point(aabb a, vec3 p); API int aabb_contains_point(aabb a, vec3 p);
API hit* aabb_hit_aabb(aabb a, aabb b); API hit* aabb_hit_aabb(aabb a, aabb b);
API hit* aabb_hit_capsule(aabb a, capsule c); API hit* aabb_hit_capsule(aabb a, capsule c);
API hit* aabb_hit_sphere(aabb a, sphere s); API hit* aabb_hit_sphere(aabb a, sphere s);
API int aabb_test_aabb(aabb a, aabb b); API int aabb_test_aabb(aabb a, aabb b);
API int aabb_test_capsule(aabb a, capsule c); API int aabb_test_capsule(aabb a, capsule c);
API int aabb_test_poly(aabb a, poly p); API int aabb_test_poly(aabb a, poly p);
API int aabb_test_sphere(aabb a, sphere s); API int aabb_test_sphere(aabb a, sphere s);
/* capsule */ /* capsule */
API float capsule_distance2_point(capsule c, vec3 p); API float capsule_distance2_point(capsule c, vec3 p);
API vec3 capsule_closest_point(capsule c, vec3 p); API vec3 capsule_closest_point(capsule c, vec3 p);
API hit* capsule_hit_aabb(capsule c, aabb a); API hit* capsule_hit_aabb(capsule c, aabb a);
API hit* capsule_hit_capsule(capsule a, capsule b); API hit* capsule_hit_capsule(capsule a, capsule b);
API hit* capsule_hit_sphere(capsule c, sphere s); API hit* capsule_hit_sphere(capsule c, sphere s);
API int capsule_test_aabb(capsule c, aabb a); API int capsule_test_aabb(capsule c, aabb a);
API int capsule_test_capsule(capsule a, capsule b); API int capsule_test_capsule(capsule a, capsule b);
API int capsule_test_poly(capsule c, poly p); API int capsule_test_poly(capsule c, poly p);
API int capsule_test_sphere(capsule c, sphere s); API int capsule_test_sphere(capsule c, sphere s);
/* poly: query */ /* poly: query */
API int poly_test_sphere(poly p, sphere s); API int poly_test_sphere(poly p, sphere s);
API int poly_test_aabb(poly p, aabb a); API int poly_test_aabb(poly p, aabb a);
API int poly_test_capsule(poly p, capsule c); API int poly_test_capsule(poly p, capsule c);
API int poly_test_poly(poly a, poly b); API int poly_test_poly(poly a, poly b);
/* poly: query transformed */ /* poly: query transformed */
API int poly_test_sphere_transform(poly p, vec3 pos3, mat33 rot33, sphere s); API int poly_test_sphere_transform(poly p, vec3 pos3, mat33 rot33, sphere s);
API int poly_test_aabb_transform(poly p, vec3 apos3, mat33 arot33, aabb a); API int poly_test_aabb_transform(poly p, vec3 apos3, mat33 arot33, aabb a);
API int poly_test_capsule_transform(poly p, vec3 pos3, mat33 rot33, capsule c); API int poly_test_capsule_transform(poly p, vec3 pos3, mat33 rot33, capsule c);
API int poly_test_poly_transform(poly a, vec3 apos3, mat33 arot33, poly b, vec3 bpos3, mat33 brot33); API int poly_test_poly_transform(poly a, vec3 apos3, mat33 arot33, poly b, vec3 bpos3, mat33 brot33);
/* poly: gjk result */ /* poly: gjk result */
API int poly_hit_sphere(struct gjk_result *res, poly p, sphere s); API int poly_hit_sphere(struct gjk_result *res, poly p, sphere s);
API int poly_hit_aabb(struct gjk_result *res, poly p, aabb a); API int poly_hit_aabb(struct gjk_result *res, poly p, aabb a);
API int poly_hit_capsule(struct gjk_result *res, poly p, capsule c); API int poly_hit_capsule(struct gjk_result *res, poly p, capsule c);
API int poly_hit_poly(struct gjk_result *res, poly a, poly b); API int poly_hit_poly(struct gjk_result *res, poly a, poly b);
/* poly: gjk result transformed */ /* poly: gjk result transformed */
API int poly_hit_sphere_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, sphere s); API int poly_hit_sphere_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, sphere s);
API int poly_hit_aabb_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, aabb a); API int poly_hit_aabb_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, aabb a);
API int poly_hit_capsule_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, capsule c); API int poly_hit_capsule_transform(struct gjk_result *res, poly p, vec3 pos3, mat33 rot33, capsule c);
API int poly_hit_poly_transform(struct gjk_result *res, poly a, vec3 at3, mat33 ar33, poly b, vec3 bt3, mat33 br33); API int poly_hit_poly_transform(struct gjk_result *res, poly a, vec3 at3, mat33 ar33, poly b, vec3 bt3, mat33 br33);
API vec4 plane4(vec3 p, vec3 n); API vec4 plane4(vec3 p, vec3 n);
API frustum frustum_build(mat44 projview); API frustum frustum_build(mat44 projview);
API int frustum_test_sphere(frustum f, sphere s); API int frustum_test_sphere(frustum f, sphere s);
API int frustum_test_aabb(frustum f, aabb a); API int frustum_test_aabb(frustum f, aabb a);
API poly poly_alloc(int cnt); API poly poly_alloc(int cnt);
API void poly_free(poly *p); API void poly_free(poly *p);
API poly pyramid(vec3 from, vec3 to, float size); // poly_free() required API poly pyramid(vec3 from, vec3 to, float size); // poly_free() required
API poly diamond(vec3 from, vec3 to, float size); // poly_free() required API poly diamond(vec3 from, vec3 to, float size); // poly_free() required
API void collide_demo(); // debug draw collisions API void collide_demo(); // debug draw collisions

View File

@ -1,116 +1,116 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// compat (unix & stdio.h) // compat (unix & stdio.h)
#if is(tcc) && is(win32) // add missing symbols #if is(tcc) && is(win32) // add missing symbols
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; /* :: */ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; /* :: */
const struct in6_addr in6addr_loopback; /* ::1 */ const struct in6_addr in6addr_loopback; /* ::1 */
#endif #endif
#if is(win32) #if is(win32)
#include <io.h> #include <io.h>
#if is(mingw) #if is(mingw)
#include <unistd.h> #include <unistd.h>
#endif #endif
#else #else
#include <unistd.h> #include <unistd.h>
#include <sched.h> // sched_setaffinity(), CPU_ZERO(), CPU_COUNT() #include <sched.h> // sched_setaffinity(), CPU_ZERO(), CPU_COUNT()
#include <sys/ioctl.h> #include <sys/ioctl.h>
#endif #endif
#if is(ems) #if is(ems)
//#define unlink(x) ((void)(x), 0) //#define unlink(x) ((void)(x), 0)
#endif #endif
#if is(win32) #if is(win32)
//#define alloca _alloca //#define alloca _alloca
#define atoi64 _atoi64 #define atoi64 _atoi64
#define popen _popen #define popen _popen
#define pclose _pclose #define pclose _pclose
//#define strncasecmp _strnicmp //#define strncasecmp _strnicmp
#define mkdir(p,m) mkdir(p) #define mkdir(p,m) mkdir(p)
#define chdir ifdef(cl, _chdir, chdir) #define chdir ifdef(cl, _chdir, chdir)
#if is(cl) || is(tcc) #if is(cl) || is(tcc)
#define ftruncate _chsize_s #define ftruncate _chsize_s
#endif #endif
#define flockfile ifdef(cl,_lock_file,ifdef(mingw,_lock_file,(void))) #define flockfile ifdef(cl,_lock_file,ifdef(mingw,_lock_file,(void)))
#define funlockfile ifdef(cl,_unlock_file,ifdef(mingw,_unlock_file,(void))) #define funlockfile ifdef(cl,_unlock_file,ifdef(mingw,_unlock_file,(void)))
#else // gcc #else // gcc
//#include <alloca.h> // mingw64 does not have it //#include <alloca.h> // mingw64 does not have it
#include <strings.h> // strncasecmp #include <strings.h> // strncasecmp
#define atoi64 atoll #define atoi64 atoll
//#define strstri strcasestr //#define strstri strcasestr
//#define strcmpi strcasecmp //#define strcmpi strcasecmp
#endif #endif
#if defined MAX_PATH #if defined MAX_PATH
#define DIR_MAX MAX_PATH #define DIR_MAX MAX_PATH
#elif defined PATH_MAX #elif defined PATH_MAX
#define DIR_MAX PATH_MAX #define DIR_MAX PATH_MAX
#else #else
#define DIR_MAX 260 #define DIR_MAX 260
#endif #endif
#if is(win32) // _MSC_VER and __MINGW64__ #if is(win32) // _MSC_VER and __MINGW64__
#include <stdio.h> #include <stdio.h>
#include <windows.h> #include <windows.h>
#include <share.h> #include <share.h>
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
FILE *fmemopen(void *buf, size_t len, const char *type) { FILE *fmemopen(void *buf, size_t len, const char *type) {
int fd = -1; int fd = -1;
char temppath[DIR_MAX - 14], filename[DIR_MAX + 1]; char temppath[DIR_MAX - 14], filename[DIR_MAX + 1];
if( GetTempPathA(sizeof(temppath), temppath) ) if( GetTempPathA(sizeof(temppath), temppath) )
if( GetTempFileNameA(temppath, "v4k_temp", 0, filename) ) if( GetTempFileNameA(temppath, "v4k_temp", 0, filename) )
if( !_sopen_s(&fd, filename, _O_CREAT | _O_SHORT_LIVED | _O_TEMPORARY | _O_RDWR | _O_BINARY | _O_NOINHERIT, _SH_DENYRW, _S_IREAD | _S_IWRITE) ) if( !_sopen_s(&fd, filename, _O_CREAT | _O_SHORT_LIVED | _O_TEMPORARY | _O_RDWR | _O_BINARY | _O_NOINHERIT, _SH_DENYRW, _S_IREAD | _S_IWRITE) )
for( FILE *fp = fd != -1 ? _fdopen(fd, "w+b") : NULL; fp; ) for( FILE *fp = fd != -1 ? _fdopen(fd, "w+b") : NULL; fp; )
return fwrite(buf, len, 1, fp), rewind(fp), unlink(filename), fp; // no need to _close. fclose(on the returned FILE*) also _closes the file descriptor. return fwrite(buf, len, 1, fp), rewind(fp), unlink(filename), fp; // no need to _close. fclose(on the returned FILE*) also _closes the file descriptor.
return fd != -1 ? _close(fd), NULL : NULL; return fd != -1 ? _close(fd), NULL : NULL;
} }
#endif #endif
#if 0 #if 0
#if !is(cl) #if !is(cl)
#define tmpfile file_temp #define tmpfile file_temp
#endif #endif
#define tmpnam(x) file_tempname() #define tmpnam(x) file_tempname()
#endif #endif
#if 0 #if 0
static static
const char *pathfile_from_handle(FILE *fp) { const char *pathfile_from_handle(FILE *fp) {
#if is(win32) #if is(win32)
int fd = fileno(fp); int fd = fileno(fp);
HANDLE handle = (HANDLE)_get_osfhandle( fd ); // <io.h> HANDLE handle = (HANDLE)_get_osfhandle( fd ); // <io.h>
DWORD size = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); DWORD size = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
wchar_t name[DIR_MAX] = L""; wchar_t name[DIR_MAX] = L"";
size = GetFinalPathNameByHandleW(handle, name, size, VOLUME_NAME_DOS); size = GetFinalPathNameByHandleW(handle, name, size, VOLUME_NAME_DOS);
name[size] = L'\0'; name[size] = L'\0';
return wchar16to8(name + 4); // skip \\?\ header return wchar16to8(name + 4); // skip \\?\ header
#else #else
// In Linux, you can use readlink on /proc/self/fd/NNN where NNN is the file descriptor // In Linux, you can use readlink on /proc/self/fd/NNN where NNN is the file descriptor
// In OSX: // In OSX:
// #include <sys/syslimits.h> // #include <sys/syslimits.h>
// #include <fcntl.h> // #include <fcntl.h>
// char filePath[DIR_MAX]; // char filePath[DIR_MAX];
// if (fcntl(fd, F_GETPATH, filePath) != -1) { // if (fcntl(fd, F_GETPATH, filePath) != -1) {
// // do something with the file path // // do something with the file path
// } // }
return 0; return 0;
#endif #endif
} }
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// new C macros // new C macros
#define cast(T) ifdef(c, void *, decltype(T)) #define cast(T) ifdef(c, void *, decltype(T))
#define literal(T) ifdef(c, T, (T)) #define literal(T) ifdef(c, T, (T))
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void v4k_init(); void v4k_init();
static void v4k_pre_init(); static void v4k_pre_init();
static void v4k_post_init(float); static void v4k_post_init(float);

View File

@ -1,415 +1,415 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// config directives // config directives
#ifndef ENABLE_FASTCALL_LUA #ifndef ENABLE_FASTCALL_LUA
#define ENABLE_FASTCALL_LUA 1 ///+ #define ENABLE_FASTCALL_LUA 1 ///+
#endif #endif
#ifndef ENABLE_PROFILER #ifndef ENABLE_PROFILER
#define ENABLE_PROFILER ifdef(retail, 0, 1) ///+ #define ENABLE_PROFILER ifdef(retail, 0, 1) ///+
#endif #endif
#ifndef ENABLE_SELFIES #ifndef ENABLE_SELFIES
#define ENABLE_SELFIES 0 ///+ #define ENABLE_SELFIES 0 ///+
#endif #endif
#ifndef ENABLE_MEMORY_POISON #ifndef ENABLE_MEMORY_POISON
#define ENABLE_MEMORY_POISON ifdef(debug, 1, 0) ///+ #define ENABLE_MEMORY_POISON ifdef(debug, 1, 0) ///+
#endif #endif
#ifndef ENABLE_MEMORY_LEAKS #ifndef ENABLE_MEMORY_LEAKS
#define ENABLE_MEMORY_LEAKS 0 ///+ #define ENABLE_MEMORY_LEAKS 0 ///+
#endif #endif
#ifndef ENABLE_LINUX_CALLSTACKS #ifndef ENABLE_LINUX_CALLSTACKS
#define ENABLE_LINUX_CALLSTACKS 0 ///+ #define ENABLE_LINUX_CALLSTACKS 0 ///+
#endif #endif
#ifndef ENABLE_AUTOTESTS #ifndef ENABLE_AUTOTESTS
#define ENABLE_AUTOTESTS ifdef(debug, ifndef(ems, 1, 0), 0) ///+ #define ENABLE_AUTOTESTS ifdef(debug, ifndef(ems, 1, 0), 0) ///+
#endif #endif
#ifndef ENABLE_RETAIL #ifndef ENABLE_RETAIL
#define ENABLE_RETAIL 0 // ifdef(retail, 1, 0) ///+ #define ENABLE_RETAIL 0 // ifdef(retail, 1, 0) ///+
#endif #endif
#ifndef ENABLE_COOK #ifndef ENABLE_COOK
#define ENABLE_COOK ifdef(retail, 0, 1) ///+ #define ENABLE_COOK ifdef(retail, 0, 1) ///+
#endif #endif
#ifndef ENABLE_RPMALLOC #ifndef ENABLE_RPMALLOC
#define ENABLE_RPMALLOC 0 // ifdef(tcc, 0, 1) // forbidden on tcc because of lacking TLS support #define ENABLE_RPMALLOC 0 // ifdef(tcc, 0, 1) // forbidden on tcc because of lacking TLS support
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// if/n/def hell // if/n/def hell
#define ifdef(macro, yes, /*no*/...) ifdef_##macro(yes, __VA_ARGS__) #define ifdef(macro, yes, /*no*/...) ifdef_##macro(yes, __VA_ARGS__)
#define ifndef(macro, yes, /*no*/...) ifdef_##macro(__VA_ARGS__, yes) #define ifndef(macro, yes, /*no*/...) ifdef_##macro(__VA_ARGS__, yes)
#define is(macro) ifdef_##macro(1,0) #define is(macro) ifdef_##macro(1,0)
#define isnt(macro) ifdef_##macro(0,1) #define isnt(macro) ifdef_##macro(0,1)
#define ifdef_true(yes, /*no*/...) yes #define ifdef_true(yes, /*no*/...) yes
#define ifdef_false(yes, /*no*/...) __VA_ARGS__ #define ifdef_false(yes, /*no*/...) __VA_ARGS__
#ifdef _MSC_VER #ifdef _MSC_VER
#define ifdef_gcc ifdef_false #define ifdef_gcc ifdef_false
#define ifdef_mingw ifdef_false #define ifdef_mingw ifdef_false
#define ifdef_tcc ifdef_false #define ifdef_tcc ifdef_false
#define ifdef_cl ifdef_true #define ifdef_cl ifdef_true
#elif defined __TINYC__ #elif defined __TINYC__
#define ifdef_gcc ifdef_false #define ifdef_gcc ifdef_false
#define ifdef_mingw ifdef_false #define ifdef_mingw ifdef_false
#define ifdef_tcc ifdef_true #define ifdef_tcc ifdef_true
#define ifdef_cl ifdef_false #define ifdef_cl ifdef_false
#elif defined __MINGW64__ || defined __MINGW32__ #elif defined __MINGW64__ || defined __MINGW32__
#define ifdef_gcc ifdef_true #define ifdef_gcc ifdef_true
#define ifdef_mingw ifdef_true #define ifdef_mingw ifdef_true
#define ifdef_tcc ifdef_false #define ifdef_tcc ifdef_false
#define ifdef_cl ifdef_false #define ifdef_cl ifdef_false
#else // also __clang__ #else // also __clang__
#define ifdef_gcc ifdef_true #define ifdef_gcc ifdef_true
#define ifdef_mingw ifdef_false #define ifdef_mingw ifdef_false
#define ifdef_tcc ifdef_false #define ifdef_tcc ifdef_false
#define ifdef_cl ifdef_false #define ifdef_cl ifdef_false
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
#define ifdef_cpp ifdef_true #define ifdef_cpp ifdef_true
#define ifdef_c ifdef_false #define ifdef_c ifdef_false
#else #else
#define ifdef_c ifdef_true #define ifdef_c ifdef_true
#define ifdef_cpp ifdef_false #define ifdef_cpp ifdef_false
#endif #endif
#if defined _WIN32 #if defined _WIN32
#define ifdef_win32 ifdef_true #define ifdef_win32 ifdef_true
#define ifdef_linux ifdef_false #define ifdef_linux ifdef_false
#define ifdef_osx ifdef_false #define ifdef_osx ifdef_false
#define ifdef_bsd ifdef_false #define ifdef_bsd ifdef_false
#define ifdef_ems ifdef_false #define ifdef_ems ifdef_false
#elif defined __linux__ #elif defined __linux__
#define ifdef_win32 ifdef_false #define ifdef_win32 ifdef_false
#define ifdef_linux ifdef_true #define ifdef_linux ifdef_true
#define ifdef_osx ifdef_false #define ifdef_osx ifdef_false
#define ifdef_bsd ifdef_false #define ifdef_bsd ifdef_false
#define ifdef_ems ifdef_false #define ifdef_ems ifdef_false
#elif defined __APPLE__ #elif defined __APPLE__
#define ifdef_win32 ifdef_false #define ifdef_win32 ifdef_false
#define ifdef_linux ifdef_false #define ifdef_linux ifdef_false
#define ifdef_osx ifdef_true #define ifdef_osx ifdef_true
#define ifdef_bsd ifdef_false #define ifdef_bsd ifdef_false
#define ifdef_ems ifdef_false #define ifdef_ems ifdef_false
#elif defined __EMSCRIPTEN__ #elif defined __EMSCRIPTEN__
#define ifdef_win32 ifdef_false #define ifdef_win32 ifdef_false
#define ifdef_linux ifdef_false #define ifdef_linux ifdef_false
#define ifdef_osx ifdef_false #define ifdef_osx ifdef_false
#define ifdef_bsd ifdef_false #define ifdef_bsd ifdef_false
#define ifdef_ems ifdef_true #define ifdef_ems ifdef_true
#else // __FreeBSD__ || @todo: __ANDROID_API__ #else // __FreeBSD__ || @todo: __ANDROID_API__
#define ifdef_win32 ifdef_false #define ifdef_win32 ifdef_false
#define ifdef_linux ifdef_false #define ifdef_linux ifdef_false
#define ifdef_osx ifdef_false #define ifdef_osx ifdef_false
#define ifdef_bsd ifdef_true #define ifdef_bsd ifdef_true
#define ifdef_ems ifdef_false #define ifdef_ems ifdef_false
#endif #endif
#ifdef NDEBUG // rely on NDEBUG as the official/portable way to disable asserts #ifdef NDEBUG // rely on NDEBUG as the official/portable way to disable asserts
#define ifdef_debug ifdef_false #define ifdef_debug ifdef_false
#define ifdef_release ifdef_true #define ifdef_release ifdef_true
#else #else
#define ifdef_debug ifdef_true #define ifdef_debug ifdef_true
#define ifdef_release ifdef_false #define ifdef_release ifdef_false
#endif #endif
#if ENABLE_RETAIL // NDEBUG>=2 ? #if ENABLE_RETAIL // NDEBUG>=2 ?
#define ifdef_retail ifdef_true #define ifdef_retail ifdef_true
#else #else
#define ifdef_retail ifdef_false #define ifdef_retail ifdef_false
#endif #endif
#if ENABLE_COOK #if ENABLE_COOK
#define ifdef_cook ifdef_true #define ifdef_cook ifdef_true
#define ifdef_nocook ifdef_false #define ifdef_nocook ifdef_false
#else #else
#define ifdef_cook ifdef_false #define ifdef_cook ifdef_false
#define ifdef_nocook ifdef_true #define ifdef_nocook ifdef_true
#endif #endif
#if defined NDEBUG && NDEBUG >= 3 // we use NDEBUG=[0,1,2,3] to signal the compiler optimization flags O0,O1,O2,O3 #if defined NDEBUG && NDEBUG >= 3 // we use NDEBUG=[0,1,2,3] to signal the compiler optimization flags O0,O1,O2,O3
#define ifdef_O3 ifdef_true #define ifdef_O3 ifdef_true
#define ifdef_O2 ifdef_false #define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false #define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false #define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 2 #elif defined NDEBUG && NDEBUG >= 2
#define ifdef_O3 ifdef_false #define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_true #define ifdef_O2 ifdef_true
#define ifdef_O1 ifdef_false #define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_false #define ifdef_O0 ifdef_false
#elif defined NDEBUG && NDEBUG >= 1 #elif defined NDEBUG && NDEBUG >= 1
#define ifdef_O3 ifdef_false #define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false #define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_true #define ifdef_O1 ifdef_true
#define ifdef_O0 ifdef_false #define ifdef_O0 ifdef_false
#else #else
#define ifdef_O3 ifdef_false #define ifdef_O3 ifdef_false
#define ifdef_O2 ifdef_false #define ifdef_O2 ifdef_false
#define ifdef_O1 ifdef_false #define ifdef_O1 ifdef_false
#define ifdef_O0 ifdef_true #define ifdef_O0 ifdef_true
#endif #endif
#include <stdint.h> #include <stdint.h>
#if (defined INTPTR_MAX && INTPTR_MAX == INT64_MAX) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__ppc64__) || __WORDSIZE == 64 #if (defined INTPTR_MAX && INTPTR_MAX == INT64_MAX) || defined(_M_X64) || defined(__amd64__) || defined(__x86_64__) || defined(__ppc64__) || __WORDSIZE == 64
#define ifdef_64 ifdef_true #define ifdef_64 ifdef_true
#define ifdef_32 ifdef_false #define ifdef_32 ifdef_false
#else #else
#define ifdef_64 ifdef_false #define ifdef_64 ifdef_false
#define ifdef_32 ifdef_true #define ifdef_32 ifdef_true
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// new C keywords // new C keywords
#define countof(x) (int)(sizeof (x) / sizeof 0[x]) #define countof(x) (int)(sizeof (x) / sizeof 0[x])
#define concat(a,b) conc4t(a,b) #define concat(a,b) conc4t(a,b)
#define conc4t(a,b) a##b ///- #define conc4t(a,b) a##b ///-
#define macro(name) concat(name, __LINE__) #define macro(name) concat(name, __LINE__)
#define unique(name) concat(concat(concat(name,concat(_L,__LINE__)),_),__COUNTER__) #define unique(name) concat(concat(concat(name,concat(_L,__LINE__)),_),__COUNTER__)
#define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1)) #define defer(begin,end) for(int macro(i) = ((begin), 0); !macro(i); macro(i) = ((end), 1))
#define scope(end) defer((void)0, end) #define scope(end) defer((void)0, end)
#define benchmark for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.4fs %2.f%% (" FILELINE ")\n", macro(t), macro(t)*100/0.0166667 )) #define benchmark for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.4fs %2.f%% (" FILELINE ")\n", macro(t), macro(t)*100/0.0166667 ))
#define benchmark_ms for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.2fms %2.f%% (" FILELINE ")\n", macro(t)*1000, macro(t)*100/0.016666667 )) #define benchmark_ms for(double macro(i) = 1, macro(t) = (time_ss(),-time_ss()); macro(i); macro(t)+=time_ss(), macro(i)=0, printf("%.2fms %2.f%% (" FILELINE ")\n", macro(t)*1000, macro(t)*100/0.016666667 ))
#define do_once static int macro(once) = 0; for(;!macro(once);macro(once)=1) #define do_once static int macro(once) = 0; for(;!macro(once);macro(once)=1)
#if is(cl) #if is(cl)
#define __thread __declspec(thread) #define __thread __declspec(thread)
#elif is(tcc) && is(win32) #elif is(tcc) && is(win32)
#define __thread __declspec(thread) // compiles fine apparently, but does not work #define __thread __declspec(thread) // compiles fine apparently, but does not work
#elif is(tcc) #elif is(tcc)
#define __thread #define __thread
#endif #endif
// usage: bool static(audio_is_init) = audio_init(); // usage: bool static(audio_is_init) = audio_init();
//#define static(var) static var; do_once var //#define static(var) static var; do_once var
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// new C macros // new C macros
#if ENABLE_RETAIL #if ENABLE_RETAIL
#define ASSERT(expr, ...) (void)0 #define ASSERT(expr, ...) (void)0
#define ASSERT_ONCE(expr, ...) (void)0 #define ASSERT_ONCE(expr, ...) (void)0
#else #else
#define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0) #define ASSERT(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0)
#define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0) #define ASSERT_ONCE(expr, ...) do { int fool_msvc[] = {0,}; if(!(expr)) { fool_msvc[0]++; static int seen = 0; if(!seen) seen = 1, alert(va("!Expression failed: " #expr " " FILELINE "\n" __VA_ARGS__)), breakpoint(); } } while(0)
#endif #endif
#ifndef STATIC_ASSERT #ifndef STATIC_ASSERT
#define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_L) : !!(EXPR); } unique(static_assert_on_L) #define STATIC_ASSERT(EXPR) typedef struct { unsigned macro(static_assert_on_L) : !!(EXPR); } unique(static_assert_on_L)
#endif #endif
#define FILELINE __FILE__ ":" STRINGIZE(__LINE__) #define FILELINE __FILE__ ":" STRINGIZE(__LINE__)
#define STRINGIZE(x) STRINGIZ3(x) #define STRINGIZE(x) STRINGIZ3(x)
#define STRINGIZ3(x) #x ///- #define STRINGIZ3(x) #x ///-
#define EXPAND(name, ...) EXPAND_QUOTE(EXPAND_JOIN(name, EXPAND_COUNT_ARGS(__VA_ARGS__)), (__VA_ARGS__)) #define EXPAND(name, ...) EXPAND_QUOTE(EXPAND_JOIN(name, EXPAND_COUNT_ARGS(__VA_ARGS__)), (__VA_ARGS__))
#define EXPAND_QUOTE(x, y) x y ///- #define EXPAND_QUOTE(x, y) x y ///-
#define EXPAND_JOIN(name, count) EXPAND_J0IN(name, count) ///- #define EXPAND_JOIN(name, count) EXPAND_J0IN(name, count) ///-
#define EXPAND_J0IN(name, count) EXPAND_J01N(name, count) ///- #define EXPAND_J0IN(name, count) EXPAND_J01N(name, count) ///-
#define EXPAND_J01N(name, count) name##count ///- #define EXPAND_J01N(name, count) name##count ///-
#define EXPAND_COUNT_ARGS(...) EXPAND_ARGS((__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) ///- #define EXPAND_COUNT_ARGS(...) EXPAND_ARGS((__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) ///-
#define EXPAND_ARGS(args) EXPAND_RETURN_COUNT args ///- #define EXPAND_ARGS(args) EXPAND_RETURN_COUNT args ///-
#define EXPAND_RETURN_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, count, ...) count ///- #define EXPAND_RETURN_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, count, ...) count ///-
// expands to the first argument // expands to the first argument
#define VA_FIRST(...) VA_F1RST(__VA_ARGS__, throwaway) #define VA_FIRST(...) VA_F1RST(__VA_ARGS__, throwaway)
#define VA_F1RST(first, ...) first ///- #define VA_F1RST(first, ...) first ///-
// if there's only one argument, expands to nothing. if there is more // if there's only one argument, expands to nothing. if there is more
// than one argument, expands to a comma followed by everything but // than one argument, expands to a comma followed by everything but
// the first argument. only supports up to 9 arguments but can be expanded. // the first argument. only supports up to 9 arguments but can be expanded.
#define VA_REST(...) VA_R3ST(VA_NUM(__VA_ARGS__), __VA_ARGS__) #define VA_REST(...) VA_R3ST(VA_NUM(__VA_ARGS__), __VA_ARGS__)
#define VA_R3ST(qty, ...) VA_R3S7(qty, __VA_ARGS__) ///- #define VA_R3ST(qty, ...) VA_R3S7(qty, __VA_ARGS__) ///-
#define VA_R3S7(qty, ...) VA_R3S7_##qty(__VA_ARGS__) ///- #define VA_R3S7(qty, ...) VA_R3S7_##qty(__VA_ARGS__) ///-
#define VA_R3S7_ONE(first) ///- #define VA_R3S7_ONE(first) ///-
#define VA_R3S7_TWOORMORE(first, ...) , __VA_ARGS__ ///- #define VA_R3S7_TWOORMORE(first, ...) , __VA_ARGS__ ///-
#define VA_NUM(...) VA_SELECT_10TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway) ///- #define VA_NUM(...) VA_SELECT_10TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway) ///-
#define VA_SELECT_10TH(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A10 #define VA_SELECT_10TH(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A10
// VA_SPLIT() expands to A) 1 item OR B) 1 item + ',' + va_args[1..N] // VA_SPLIT() expands to A) 1 item OR B) 1 item + ',' + va_args[1..N]
#define VA_SPLIT(...) VA_FIRST(__VA_ARGS__) VA_REST(__VA_ARGS__) #define VA_SPLIT(...) VA_FIRST(__VA_ARGS__) VA_REST(__VA_ARGS__)
// VA_COUNT() counts number of va args // VA_COUNT() counts number of va args
#define VA_COUNT(...) (int)(sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1) #define VA_COUNT(...) (int)(sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1)
#if is(cl) && !is(cpp) #if is(cl) && !is(cpp)
#define INLINE __inline #define INLINE __inline
#else #else
#define INLINE inline #define INLINE inline
#endif #endif
#if is(cl) #if is(cl)
#define FORCE_INLINE __forceinline #define FORCE_INLINE __forceinline
#elif is(gcc) #elif is(gcc)
#define FORCE_INLINE __attribute__((always_inline)) inline #define FORCE_INLINE __attribute__((always_inline)) inline
#else #else
#define FORCE_INLINE INLINE #define FORCE_INLINE INLINE
#endif #endif
#if is(cl) && (_MSC_VER <= 1700) #if is(cl) && (_MSC_VER <= 1700)
#define FINITE _finite #define FINITE _finite
#else #else
#define FINITE isfinite #define FINITE isfinite
#endif #endif
// usage: #define vec2(...) C_CAST(vec2, __VA_ARGS__) // usage: #define vec2(...) C_CAST(vec2, __VA_ARGS__)
// typedef union vec2 { float X,Y; }; vec2 a = {0,1}, b = vec2(0,1); // typedef union vec2 { float X,Y; }; vec2 a = {0,1}, b = vec2(0,1);
#define C_CAST(type, ...) ( ifdef(c,(type),type) { __VA_ARGS__ } ) #define C_CAST(type, ...) ( ifdef(c,(type),type) { __VA_ARGS__ } )
// create a WARNING(...) macro // create a WARNING(...) macro
// usage: WARNING("this is displayed at compile time") // usage: WARNING("this is displayed at compile time")
#if is(gcc) #if is(gcc)
# define WARNING(msg) WARN1NG( message( msg ) ) # define WARNING(msg) WARN1NG( message( msg ) )
# define WARN1NG(msg) _Pragma(#msg) # define WARN1NG(msg) _Pragma(#msg)
#elif is(cl) #elif is(cl)
# define WARNING(msg) __pragma( message( msg ) ) # define WARNING(msg) __pragma( message( msg ) )
#else #else
# define WARNING(msg) # define WARNING(msg)
#endif #endif
// document todos and fixmes via compiler warnings // document todos and fixmes via compiler warnings
#define TODO(str) ifdef(debug,WARNING("TO DO: " str " (" FILELINE ")")) #define TODO(str) ifdef(debug,WARNING("TO DO: " str " (" FILELINE ")"))
#define FIXME(str) ifdef(debug,WARNING("FIXME: " str " (" FILELINE ")")) #define FIXME(str) ifdef(debug,WARNING("FIXME: " str " (" FILELINE ")"))
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// autorun initializers for C // autorun initializers for C
// - rlyeh, public domain // - rlyeh, public domain
// //
// note: based on code by Joe Lowe (public domain). // note: based on code by Joe Lowe (public domain).
// note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers // note: XIU for C initializers, XCU for C++ initializers, XTU for C deinitializers
#define AUTORUN AUTORUN_( unique(fn) ) #define AUTORUN AUTORUN_( unique(fn) )
#ifdef __cplusplus #ifdef __cplusplus
#define AUTORUN_(fn) \ #define AUTORUN_(fn) \
static void fn(void); \ static void fn(void); \
static const int concat(fn,__1) = (fn(), 1); \ static const int concat(fn,__1) = (fn(), 1); \
static void fn(void) static void fn(void)
#elif defined _MSC_VER && !defined(__clang__) // cl, but not clang-cl #elif defined _MSC_VER && !defined(__clang__) // cl, but not clang-cl
#define AUTORUN_(fn) \ #define AUTORUN_(fn) \
static void fn(void); \ static void fn(void); \
static int concat(fn,__1) (){ fn(); return 0; } \ static int concat(fn,__1) (){ fn(); return 0; } \
__pragma(section(".CRT$XIU", long, read)) \ __pragma(section(".CRT$XIU", long, read)) \
__declspec(allocate(".CRT$XIU")) \ __declspec(allocate(".CRT$XIU")) \
static int(* concat(fn,__2) )() = concat(fn,__1); \ static int(* concat(fn,__2) )() = concat(fn,__1); \
static void fn(void) static void fn(void)
#elif defined __TINYC__ // tcc... #elif defined __TINYC__ // tcc...
#define AUTORUN_(fn) \ #define AUTORUN_(fn) \
__attribute__((constructor)) \ __attribute__((constructor)) \
static void fn(void) static void fn(void)
#else // gcc,clang,clang-cl... #else // gcc,clang,clang-cl...
#define AUTORUN_(fn) \ #define AUTORUN_(fn) \
__attribute__((constructor(__COUNTER__+101))) \ __attribute__((constructor(__COUNTER__+101))) \
static void fn(void) static void fn(void)
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// build info // build info
#ifndef BUILD_VERSION #ifndef BUILD_VERSION
#define BUILD_VERSION "" #define BUILD_VERSION ""
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// visibility // visibility
// win32 users would need to -DAPI=EXPORT/IMPORT as needed when building/using V4K as DLL. // win32 users would need to -DAPI=EXPORT/IMPORT as needed when building/using V4K as DLL.
#define IMPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport))) #define IMPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllimport)), __declspec(dllimport)))
#define EXPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport))) #define EXPORT ifdef(win32, ifdef(gcc, __attribute__ ((dllexport)), __declspec(dllexport)))
#define STATIC #define STATIC
#ifndef API #ifndef API
#define API STATIC #define API STATIC
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// system headers // system headers
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
#define _GNU_SOURCE ///- for linux #define _GNU_SOURCE ///- for linux
#endif #endif
#if is(cl) && is(win32) // for VC IDE #if is(cl) && is(win32) // for VC IDE
#define _CRT_SECURE_NO_WARNINGS ///- #define _CRT_SECURE_NO_WARNINGS ///-
#define _CRT_NONSTDC_NO_DEPRECATE ///- #define _CRT_NONSTDC_NO_DEPRECATE ///-
#define _WINSOCK_DEPRECATED_NO_WARNINGS ///- #define _WINSOCK_DEPRECATED_NO_WARNINGS ///-
#define _WIN32_WINNT 0x0600 ///- 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86 #define _WIN32_WINNT 0x0600 ///- 0x0502 // GetInfoAddrW/FreeAddrInfoW for X86
#endif #endif
#if is(cl) #if is(cl)
#include <omp.h> // compile with /openmp to speed up some computations #include <omp.h> // compile with /openmp to speed up some computations
#endif #endif
#include <assert.h> #include <assert.h>
//#include <float.h> //#include <float.h>
//#include <limits.h> //#include <limits.h>
#include <math.h> // NAN #include <math.h> // NAN
#include <stdarg.h> // va_*(), ... #include <stdarg.h> // va_*(), ...
#include <stdbool.h> // bool,true,false #include <stdbool.h> // bool,true,false
#include <stdint.h> // u/int8/16/32/64_t #include <stdint.h> // u/int8/16/32/64_t
#include <stdio.h> // FILE,NULL #include <stdio.h> // FILE,NULL
#include <stdlib.h> // malloc,free,exit, #include <stdlib.h> // malloc,free,exit,
#include <string.h> // strlen,memset,memcpy, #include <string.h> // strlen,memset,memcpy,
#if is(tcc) && is(win32) && defined(__x86_64) #if is(tcc) && is(win32) && defined(__x86_64)
#include <tgmath.h> #include <tgmath.h>
// @fixme workarounds on `tcc0.9.27 -m64` (win) for fmod()/trunc() functions. test: 00-easing broken otherwise // @fixme workarounds on `tcc0.9.27 -m64` (win) for fmod()/trunc() functions. test: 00-easing broken otherwise
//#define trunc(x) ((double)(int64_t)(x)) //#define trunc(x) ((double)(int64_t)(x))
//#define fmod(x,y) ((x) - trunc((x) / (y)) * (y)) //#define fmod(x,y) ((x) - trunc((x) / (y)) * (y))
// @fixme workarounds on `tcc0.9.27 -m64` (win) for all functions with ending bool argument. test: 00-anims crashes otherwise // @fixme workarounds on `tcc0.9.27 -m64` (win) for all functions with ending bool argument. test: 00-anims crashes otherwise
#undef bool #undef bool
typedef char bool; typedef char bool;
// missing libm symbols on tinycc HEAD repo (tcc-x64 pre-0.9.28) // missing libm symbols on tinycc HEAD repo (tcc-x64 pre-0.9.28)
//#define fabsf fabs //#define fabsf fabs
#define sqrtf sqrt #define sqrtf sqrt
#define sinf sin #define sinf sin
#define asinf asin #define asinf asin
#define cosf cos #define cosf cos
#define acosf acos #define acosf acos
#define tanf tan #define tanf tan
#define atan2f atan2 #define atan2f atan2
#define powf pow #define powf pow
#define floorf floor #define floorf floor
#define logf log #define logf log
#define ceilf ceil #define ceilf ceil
#define copysignf copysign #define copysignf copysign
//#define ldexpf ldexp //#define ldexpf ldexp
#define expf exp #define expf exp
//#define frexpf frexp //#define frexpf frexp
#define fmodf fmod #define fmodf fmod
#define log10f log10 #define log10f log10
//#define logf log //#define logf log
#define hypotf hypot #define hypotf hypot
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// pragma libs // pragma libs
#if is(win32) && (is(cl) || is(tcc)) #if is(win32) && (is(cl) || is(tcc))
#pragma comment(lib, "advapi32") #pragma comment(lib, "advapi32")
#pragma comment(lib, "comdlg32") #pragma comment(lib, "comdlg32")
#pragma comment(lib, "dbghelp") #pragma comment(lib, "dbghelp")
#pragma comment(lib, "gdi32") #pragma comment(lib, "gdi32")
#pragma comment(lib, "ole32") #pragma comment(lib, "ole32")
#pragma comment(lib, "shell32") #pragma comment(lib, "shell32")
#pragma comment(lib, "user32") #pragma comment(lib, "user32")
#pragma comment(lib, "winmm") #pragma comment(lib, "winmm")
#pragma comment(lib, "wininet") #pragma comment(lib, "wininet")
#pragma comment(lib, "ws2_32") #pragma comment(lib, "ws2_32")
#endif #endif
#if is(linux) && is(tcc) #if is(linux) && is(tcc)
#pragma comment(lib, "dl") #pragma comment(lib, "dl")
#pragma comment(lib, "m") #pragma comment(lib, "m")
#pragma comment(lib, "pthread") #pragma comment(lib, "pthread")
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,33 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// asset pipeline framework // asset pipeline framework
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// all cooked assets are stored inside zip file at root folder, which acts as an asset database. // all cooked assets are stored inside zip file at root folder, which acts as an asset database.
// during game boot, the database gets rebuilt as follows: (note: step 0 is an optional optimization) // during game boot, the database gets rebuilt as follows: (note: step 0 is an optional optimization)
// 0. for N given cores, split list of infiles into N zipfiles. then, parallelize cooks. // 0. for N given cores, split list of infiles into N zipfiles. then, parallelize cooks.
// 1. compare local disk files against file in zip database. for each mismatch do: // 1. compare local disk files against file in zip database. for each mismatch do:
// 2. - invalidate its entry in database, if local file was removed from disk. // 2. - invalidate its entry in database, if local file was removed from disk.
// 3. - write its *cooked* contents into database, if local file was created or modified from disk. // 3. - write its *cooked* contents into database, if local file was created or modified from disk.
// 4. mount any existing zipfile(s) after cooking. // 4. mount any existing zipfile(s) after cooking.
// //
// notes: meta-datas from every raw asset are stored into comment field, inside .cook.zip archive. // notes: meta-datas from every raw asset are stored into comment field, inside .cook.zip archive.
// @todo: fix leaks // @todo: fix leaks
// @todo: symlink exact files // @todo: symlink exact files
// @todo: idle threads should steal jobs from busy threads (maybe use jobs/coroutines for this?) ... // @todo: idle threads should steal jobs from busy threads (maybe use jobs/coroutines for this?) ...
enum COOK_FLAGS { enum COOK_FLAGS {
COOK_SYNC = 0, COOK_SYNC = 0,
COOK_ASYNC = 1, COOK_ASYNC = 1,
COOK_CANCELABLE = 2, COOK_CANCELABLE = 2,
COOK_DEBUGLOG = 4, // log all cooking commands to a batch file COOK_DEBUGLOG = 4, // log all cooking commands to a batch file
}; };
API void cook_config( const char *path_to_cook_ini ); // "tools/cook.ini" API void cook_config( const char *path_to_cook_ini ); // "tools/cook.ini"
API bool cook_start( const char *path_to_cook_ini, const char *masks, int flags ); // COOK_INI, "**" API bool cook_start( const char *path_to_cook_ini, const char *masks, int flags ); // COOK_INI, "**"
API void cook_stop(); API void cook_stop();
API void cook_cancel(); API void cook_cancel();
API int cook_jobs(); // [0..N] API int cook_jobs(); // [0..N]
API int cook_progress(); // [0..100] API int cook_progress(); // [0..100]
// utils // utils
API bool have_tools(); API bool have_tools();

View File

@ -1,226 +1,226 @@
static array(json5) roots; static array(json5) roots;
static array(char*) sources; static array(char*) sources;
bool json_push(const char *source) { bool json_push(const char *source) {
char *source_rw = STRDUP(source); char *source_rw = STRDUP(source);
json5 root = {0}; json5 root = {0};
char *error = json5_parse(&root, source_rw, 0); char *error = json5_parse(&root, source_rw, 0);
if( error ) { if( error ) {
FREE(source_rw); FREE(source_rw);
return false; return false;
} else { } else {
array_push(sources, source_rw); array_push(sources, source_rw);
array_push(roots, root); array_push(roots, root);
return true; return true;
} }
} }
bool json_pop() { bool json_pop() {
if( array_count(roots) > 0 ) { if( array_count(roots) > 0 ) {
FREE(*array_back(sources)); FREE(*array_back(sources));
array_pop(sources); array_pop(sources);
json5_free(array_back(roots)); json5_free(array_back(roots));
array_pop(roots); array_pop(roots);
return true; return true;
} }
return false; return false;
} }
json5* json_node(const char *keypath) { json5* json_node(const char *keypath) {
json5 *j = array_back(roots), *r = j; json5 *j = array_back(roots), *r = j;
for each_substring( keypath, "/[.]", key ) { for each_substring( keypath, "/[.]", key ) {
r = 0; r = 0;
/**/ if( j->type == JSON5_ARRAY ) r = j = &j->array[atoi(key)]; /**/ if( j->type == JSON5_ARRAY ) r = j = &j->array[atoi(key)];
else if( j->type == JSON5_OBJECT && isdigit(key[0]) ) else if( j->type == JSON5_OBJECT && isdigit(key[0]) )
for( int i = 0, seq = atoi(key); !r && i < j->count; ++i ) { for( int i = 0, seq = atoi(key); !r && i < j->count; ++i ) {
if( i == seq ) { if( i == seq ) {
r = j = &j->nodes[i]; r = j = &j->nodes[i];
break; break;
} }
} }
else if( j->type == JSON5_OBJECT ) else if( j->type == JSON5_OBJECT )
for( int i = 0; !r && i < j->count; ++i ) { for( int i = 0; !r && i < j->count; ++i ) {
if( j->nodes[i].name && !strcmp(j->nodes[i].name, key) ) { if( j->nodes[i].name && !strcmp(j->nodes[i].name, key) ) {
r = j = &j->nodes[i]; r = j = &j->nodes[i];
break; break;
} }
} }
if( !j ) break; if( !j ) break;
} }
return r; return r;
} }
int (json_count)(const char *keypath) { int (json_count)(const char *keypath) {
json5* j = json_node(keypath); json5* j = json_node(keypath);
return j ? j->count : 0; return j ? j->count : 0;
} }
json_t *json_find(const char *type_keypath) { json_t *json_find(const char *type_keypath) {
char type = type_keypath[0]; char type = type_keypath[0];
const char *key = type_keypath+1; const char *key = type_keypath+1;
json5 *j = json_node(key); json5 *j = json_node(key);
if( !j ) return NULL; if( !j ) return NULL;
static __thread int slot = 0; static __thread int slot = 0;
static __thread json_t buf[128] = {0}; static __thread json_t buf[128] = {0};
slot = (slot+1) % 128; slot = (slot+1) % 128;
json_t *v = &buf[slot]; json_t *v = &buf[slot];
v->i = j ? j->integer : 0; v->i = j ? j->integer : 0;
if(type == 's' && (!v->p || j->type == JSON5_NULL)) v->s = ""; // if_null_string if(type == 's' && (!v->p || j->type == JSON5_NULL)) v->s = ""; // if_null_string
if(type == 'f' && j && j->type == JSON5_INTEGER) v->f = j->integer; if(type == 'f' && j && j->type == JSON5_INTEGER) v->f = j->integer;
return v; return v;
} }
json_t json_get(const char *type_keypath) { json_t json_get(const char *type_keypath) {
char type = type_keypath[0]; char type = type_keypath[0];
const char *key = type_keypath+1; const char *key = type_keypath+1;
json5 *j = json_node(key); json5 *j = json_node(key);
json_t v = {0}; json_t v = {0};
v.i = j ? j->integer : 0; v.i = j ? j->integer : 0;
if(type == 's' && (!v.p || j->type == JSON5_NULL)) v.s = ""; // if_null_string if(type == 's' && (!v.p || j->type == JSON5_NULL)) v.s = ""; // if_null_string
if(type == 'f' && j && j->type == JSON5_INTEGER) v.f = j->integer; if(type == 'f' && j && j->type == JSON5_INTEGER) v.f = j->integer;
return v; return v;
} }
const char *(json_key)(const char *keypath) { const char *(json_key)(const char *keypath) {
json5 *j = json_node(keypath); json5 *j = json_node(keypath);
if( !j ) return ""; if( !j ) return "";
return j->name; return j->name;
} }
// xml impl // xml impl
static __thread array(char *) xml_sources; static __thread array(char *) xml_sources;
static __thread array(struct xml *) xml_docs; static __thread array(struct xml *) xml_docs;
int xml_push(const char *xml_source) { int xml_push(const char *xml_source) {
if( xml_source ) { if( xml_source ) {
char *src = STRDUP(xml_source), *error = 0; char *src = STRDUP(xml_source), *error = 0;
for( struct xml *doc = xml_parse(src, 0, &error); doc && !error; ) { for( struct xml *doc = xml_parse(src, 0, &error); doc && !error; ) {
array_push(xml_docs, doc); array_push(xml_docs, doc);
array_push(xml_sources, src); array_push(xml_sources, src);
return 1; return 1;
} }
if( error ) PRINTF("%s\n", error); if( error ) PRINTF("%s\n", error);
FREE(src); FREE(src);
} }
return 0; return 0;
} }
void xml_pop() { void xml_pop() {
if( array_count(xml_docs) ) { if( array_count(xml_docs) ) {
xml_free( *array_back(xml_docs) ); xml_free( *array_back(xml_docs) );
array_pop(xml_docs); array_pop(xml_docs);
FREE( *array_back(xml_sources) ); FREE( *array_back(xml_sources) );
array_pop(xml_sources); array_pop(xml_sources);
} }
} }
static void *xml_path(struct xml *node, char *path, int down) { static void *xml_path(struct xml *node, char *path, int down) {
if( !path || !path[0] ) return node; if( !path || !path[0] ) return node;
if( node ) { if( node ) {
char type = path[0]; char type = path[0];
if( type == '/' ) { if( type == '/' ) {
int sep = strcspn(++path, "/[@$"); int sep = strcspn(++path, "/[@$");
if( !sep ) type = path[0]; if( !sep ) type = path[0];
else else
if( 1 ) { // path[ sep ] ) { if( 1 ) { // path[ sep ] ) {
char tag[32]; snprintf(tag, 32, "%.*s", sep, path); char tag[32]; snprintf(tag, 32, "%.*s", sep, path);
// Find the first sibling with the given tag name (may be the same node) // Find the first sibling with the given tag name (may be the same node)
struct xml *next = down ? xml_find_down(node, tag) : xml_find(node, tag); struct xml *next = down ? xml_find_down(node, tag) : xml_find(node, tag);
return xml_path(next, &path[ sep ], 1); return xml_path(next, &path[ sep ], 1);
} }
} }
if( type == '$' ) { if( type == '$' ) {
return (void*)( node->down ? xml_text( node->down ) : xml_tag( node ) ); return (void*)( node->down ? xml_text( node->down ) : xml_tag( node ) );
} }
if( type == '@' ) { if( type == '@' ) {
return (void*)xml_att(node, ++path); return (void*)xml_att(node, ++path);
} }
if( type == '[' ) { if( type == '[' ) {
for( int i = 0, end = atoi(++path); i < end; ++i ) { node = xml_find_next(node, xml_tag(node)); if(!node) return NULL; } for( int i = 0, end = atoi(++path); i < end; ++i ) { node = xml_find_next(node, xml_tag(node)); if(!node) return NULL; }
while( isdigit(path[0]) ) ++path; while( isdigit(path[0]) ) ++path;
return xml_path(node, ++path, 1); return xml_path(node, ++path, 1);
} }
} }
return NULL; return NULL;
} }
const char *(xml_string)(char *key) { const char *(xml_string)(char *key) {
struct xml *node = xml_path(*array_back(xml_docs), key, 0); struct xml *node = xml_path(*array_back(xml_docs), key, 0);
if( node && strchr(key, '@') ) return (const char *)node; if( node && strchr(key, '@') ) return (const char *)node;
if( node && strchr(key, '$') ) return (const char *)node; if( node && strchr(key, '$') ) return (const char *)node;
return ""; return "";
} }
unsigned (xml_count)(char *key) { unsigned (xml_count)(char *key) {
struct xml *node = xml_path(*array_back(xml_docs), key, 0); struct xml *node = xml_path(*array_back(xml_docs), key, 0);
if( !node ) return 0; if( !node ) return 0;
const char *tag = xml_tag(node); const char *tag = xml_tag(node);
unsigned count = 1; unsigned count = 1;
while( (node = xml_find_next(node, tag)) != 0) ++count; while( (node = xml_find_next(node, tag)) != 0) ++count;
return count; return count;
} }
array(char) (xml_blob)(char *key) { // base64 blob array(char) (xml_blob)(char *key) { // base64 blob
struct xml *node = xml_path(*array_back(xml_docs), key, 0); struct xml *node = xml_path(*array_back(xml_docs), key, 0);
if( !node ) return 0; if( !node ) return 0;
if( !strchr(key, '$') ) return 0; if( !strchr(key, '$') ) return 0;
const char *data = (const char*)node; const char *data = (const char*)node;
array(char) out = base64_decode(data, strlen(data)); // either array of chars (ok) or null (error) array(char) out = base64_decode(data, strlen(data)); // either array of chars (ok) or null (error)
return out; return out;
} }
bool data_tests() { bool data_tests() {
// data tests (json5) // data tests (json5)
const char json5[] = const char json5[] =
" /* json5 */ // comment\n" " /* json5 */ // comment\n"
" abc: 42.67, def: true, integer:0x100 \n" " abc: 42.67, def: true, integer:0x100 \n"
" huge: 2.2239333e5, \n" " huge: 2.2239333e5, \n"
" hello: 'world /*comment in string*/ //again', \n" " hello: 'world /*comment in string*/ //again', \n"
" children : { a: 1, b: 2, c: 3 },\n" " children : { a: 1, b: 2, c: 3 },\n"
" array: [+1,2,-3,4,5], \n" " array: [+1,2,-3,4,5], \n"
" invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ],"; " invalids : [ nan, NaN, -nan, -NaN, inf, Infinity, -inf, -Infinity ],";
if( json_push(json5) ) { if( json_push(json5) ) {
assert( json_float("/abc") == 42.67 ); assert( json_float("/abc") == 42.67 );
assert( json_int("/def") == 1 ); assert( json_int("/def") == 1 );
assert( json_int("/integer") == 0x100 ); assert( json_int("/integer") == 0x100 );
assert( json_float("/huge") > 2.22e5 ); assert( json_float("/huge") > 2.22e5 );
assert( strlen(json_string("/hello")) == 35 ); assert( strlen(json_string("/hello")) == 35 );
assert( json_int("/children/a") == 1 ); assert( json_int("/children/a") == 1 );
assert( json_int("/children.b") == 2 ); assert( json_int("/children.b") == 2 );
assert( json_int("/children[c]") == 3 ); assert( json_int("/children[c]") == 3 );
assert( json_int("/array[%d]", 2) == -3 ); assert( json_int("/array[%d]", 2) == -3 );
assert( json_count("/invalids") == 8 ); assert( json_count("/invalids") == 8 );
assert( isnan(json_float("/invalids[0]")) ); assert( isnan(json_float("/invalids[0]")) );
assert( !json_find("/non_existing") ); assert( !json_find("/non_existing") );
assert( PRINTF("json5 tests OK\n") ); assert( PRINTF("json5 tests OK\n") );
json_pop(); json_pop();
} }
// data tests (xml) // data tests (xml)
const char *xml = // vfs_read("test1.xml"); const char *xml = // vfs_read("test1.xml");
"<!-- XML representation of a person record -->" "<!-- XML representation of a person record -->"
"<person created=\"2006-11-11T19:23\" modified=\"2006-12-31T23:59\">" "<person created=\"2006-11-11T19:23\" modified=\"2006-12-31T23:59\">"
" <firstName>Robert</firstName>" " <firstName>Robert</firstName>"
" <lastName>Smith</lastName>" " <lastName>Smith</lastName>"
" <address type=\"home\">" " <address type=\"home\">"
" <street>12345 Sixth Ave</street>" " <street>12345 Sixth Ave</street>"
" <city>Anytown</city>" " <city>Anytown</city>"
" <state>CA</state>" " <state>CA</state>"
" <postalCode>98765-4321</postalCode>" " <postalCode>98765-4321</postalCode>"
" </address>" " </address>"
"</person>"; "</person>";
if( xml_push(xml) ) { if( xml_push(xml) ) {
assert( !strcmp("Robert", xml_string("/person/firstName/$")) ); assert( !strcmp("Robert", xml_string("/person/firstName/$")) );
assert( !strcmp("Smith", xml_string("/person/lastName/$")) ); assert( !strcmp("Smith", xml_string("/person/lastName/$")) );
assert( !strcmp("home", xml_string("/person/address/@type")) ); assert( !strcmp("home", xml_string("/person/address/@type")) );
assert( PRINTF("xml tests OK\n") ); assert( PRINTF("xml tests OK\n") );
xml_pop(); xml_pop();
} }
return true; return true;
} }

View File

@ -1,36 +1,36 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// data framework (json5, xml, compression) @todo:kvdb // data framework (json5, xml, compression) @todo:kvdb
// - rlyeh, public domain // - rlyeh, public domain
// //
// @todo: vec2,vec3,vec4 // @todo: vec2,vec3,vec4
typedef union json_t { char* s; double f; int64_t i; uintptr_t p; array(union json_t) arr; } json_t; typedef union json_t { char* s; double f; int64_t i; uintptr_t p; array(union json_t) arr; } json_t;
// json api // json api
API bool json_push(const char *json_content); API bool json_push(const char *json_content);
API const char* json_key(const char *keypath); API const char* json_key(const char *keypath);
API json_t* json_find(const char *type_keypath); API json_t* json_find(const char *type_keypath);
API json_t json_get(const char *type_keypath); API json_t json_get(const char *type_keypath);
API int json_count(const char *keypath); API int json_count(const char *keypath);
#define json_int(...) (json_get(va("i" __VA_ARGS__)).i) #define json_int(...) (json_get(va("i" __VA_ARGS__)).i)
#define json_float(...) (json_get(va("f" __VA_ARGS__)).f) #define json_float(...) (json_get(va("f" __VA_ARGS__)).f)
#define json_string(...) (json_get(va("s" __VA_ARGS__)).s) #define json_string(...) (json_get(va("s" __VA_ARGS__)).s)
#define json_key(...) json_key(va(__VA_ARGS__)) #define json_key(...) json_key(va(__VA_ARGS__))
#define json_count(...) json_count(va(__VA_ARGS__)) #define json_count(...) json_count(va(__VA_ARGS__))
API bool json_pop(); API bool json_pop();
// xml api // xml api
API int xml_push(const char *xml_content); API int xml_push(const char *xml_content);
API const char * xml_string(char *key); API const char * xml_string(char *key);
API unsigned xml_count(char *key); API unsigned xml_count(char *key);
API array(char) xml_blob(char *key); API array(char) xml_blob(char *key);
#define xml_string(...) xml_string(va(__VA_ARGS__)) // syntax sugar: string #define xml_string(...) xml_string(va(__VA_ARGS__)) // syntax sugar: string
#define xml_int(...) atoi(xml_string(__VA_ARGS__)) // syntax sugar: int #define xml_int(...) atoi(xml_string(__VA_ARGS__)) // syntax sugar: int
#define xml_float(...) atof(xml_string(__VA_ARGS__)) // syntax sugar: float #define xml_float(...) atof(xml_string(__VA_ARGS__)) // syntax sugar: float
#define xml_blob(...) xml_blob(va(__VA_ARGS__)) // syntax sugar: base64 blob #define xml_blob(...) xml_blob(va(__VA_ARGS__)) // syntax sugar: base64 blob
#define xml_count(...) xml_count(va(__VA_ARGS__)) // syntax sugar: count nodes #define xml_count(...) xml_count(va(__VA_ARGS__)) // syntax sugar: count nodes
API void xml_pop(); API void xml_pop();
API bool data_tests(); API bool data_tests();

View File

@ -1,387 +1,387 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// sort/less // sort/less
int less_64_ptr(const void *a, const void *b) { int less_64_ptr(const void *a, const void *b) {
return 0[(uint64_t*)a] - 0[(uint64_t*)b]; return 0[(uint64_t*)a] - 0[(uint64_t*)b];
} }
int less_int_ptr(const void *a, const void *b) { int less_int_ptr(const void *a, const void *b) {
return 0[(int*)a] - 0[(int*)b]; return 0[(int*)a] - 0[(int*)b];
} }
int less_int(int a, int b) { int less_int(int a, int b) {
return a - b; return a - b;
} }
int less_64(uint64_t a, uint64_t b) { int less_64(uint64_t a, uint64_t b) {
return a > b ? +1 : -!!(a - b); return a > b ? +1 : -!!(a - b);
} }
int less_ptr(void *a, void *b) { int less_ptr(void *a, void *b) {
return (uintptr_t)a > (uintptr_t)b ? +1 : -!!((uintptr_t)a - (uintptr_t)b); return (uintptr_t)a > (uintptr_t)b ? +1 : -!!((uintptr_t)a - (uintptr_t)b);
} }
int less_str(char *a, char *b) { int less_str(char *a, char *b) {
return strcmp((const char *)a, (const char *)b); return strcmp((const char *)a, (const char *)b);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// un/hash // un/hash
uint32_t unhash_32(uint32_t x) { uint32_t unhash_32(uint32_t x) {
// Thomas Mueller at https://stackoverflow.com/questions/664014/ - says no collisions for 32bits! // Thomas Mueller at https://stackoverflow.com/questions/664014/ - says no collisions for 32bits!
x = ((x >> 16) ^ x) * 0x119de1f3; x = ((x >> 16) ^ x) * 0x119de1f3;
x = ((x >> 16) ^ x) * 0x119de1f3; x = ((x >> 16) ^ x) * 0x119de1f3;
x = (x >> 16) ^ x; x = (x >> 16) ^ x;
return x; return x;
} }
uint32_t hash_32(uint32_t x) { uint32_t hash_32(uint32_t x) {
// Thomas Mueller at https://stackoverflow.com/questions/664014/ - says no collisions for 32bits! // Thomas Mueller at https://stackoverflow.com/questions/664014/ - says no collisions for 32bits!
x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x; x = (x >> 16) ^ x;
return x; return x;
} }
uint64_t hash_64(uint64_t x) { uint64_t hash_64(uint64_t x) {
#if 1 #if 1
x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
x = x ^ (x >> 31); x = x ^ (x >> 31);
return x; return x;
#else #else
// should we just use x2 hash_32? // should we just use x2 hash_32?
uint32_t hi = (x >> 32ull), lo = (x & ~0u); uint32_t hi = (x >> 32ull), lo = (x & ~0u);
return (hash_32(hi) << 32ull) | hash_32(lo); return (hash_32(hi) << 32ull) | hash_32(lo);
#endif #endif
} }
uint64_t hash_flt(double x) { uint64_t hash_flt(double x) {
union { double d; uint64_t i; } c; union { double d; uint64_t i; } c;
return c.d = x, hash_64(c.i); return c.d = x, hash_64(c.i);
} }
uint64_t hash_str(const char* str) { uint64_t hash_str(const char* str) {
uint64_t hash = 14695981039346656037ULL; // hash(0),mul(131) faster than fnv1a, a few more collisions though uint64_t hash = 14695981039346656037ULL; // hash(0),mul(131) faster than fnv1a, a few more collisions though
while( *str ) hash = ( (unsigned char)*str++ ^ hash ) * 0x100000001b3ULL; while( *str ) hash = ( (unsigned char)*str++ ^ hash ) * 0x100000001b3ULL;
return hash; return hash;
} }
uint64_t hash_bin(const void* ptr, unsigned len) { uint64_t hash_bin(const void* ptr, unsigned len) {
uint64_t hash = 14695981039346656037ULL; // hash(0),mul(131) faster than fnv1a, a few more collisions though uint64_t hash = 14695981039346656037ULL; // hash(0),mul(131) faster than fnv1a, a few more collisions though
for( unsigned char *str = (unsigned char *)ptr; len--; ) for( unsigned char *str = (unsigned char *)ptr; len--; )
hash = ( (unsigned char)*str++ ^ hash ) * 0x100000001b3ULL; hash = ( (unsigned char)*str++ ^ hash ) * 0x100000001b3ULL;
return hash; return hash;
} }
uint64_t hash_int(int key) { uint64_t hash_int(int key) {
return hash_32((uint32_t)key); return hash_32((uint32_t)key);
} }
uint64_t hash_ptr(const void *ptr) { uint64_t hash_ptr(const void *ptr) {
uint64_t key = (uint64_t)(uintptr_t)ptr; uint64_t key = (uint64_t)(uintptr_t)ptr;
return hash_64(key); // >> 3? needed? return hash_64(key); // >> 3? needed?
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// utils // utils
uint64_t popcnt64(uint64_t x) { uint64_t popcnt64(uint64_t x) {
// [src] https://en.wikipedia.org/wiki/Hamming_weight // [src] https://en.wikipedia.org/wiki/Hamming_weight
x -= (x >> 1) & 0x5555555555555555ULL; //put count of each 2 bits into those 2 bits x -= (x >> 1) & 0x5555555555555555ULL; //put count of each 2 bits into those 2 bits
x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); //put count of each 4 bits into those 4 bits x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); //put count of each 4 bits into those 4 bits
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL; //put count of each 8 bits into those 8 bits x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL; //put count of each 8 bits into those 8 bits
return (x * 0x0101010101010101ULL) >> 56; //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... return (x * 0x0101010101010101ULL) >> 56; //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// vector based allocator (x1.75 enlarge factor) // vector based allocator (x1.75 enlarge factor)
void* vrealloc( void* p, size_t sz ) { void* vrealloc( void* p, size_t sz ) {
if( !sz ) { if( !sz ) {
if( p ) { if( p ) {
size_t *ret = (size_t*)p - 2; size_t *ret = (size_t*)p - 2;
ret[0] = 0; ret[0] = 0;
ret[1] = 0; ret[1] = 0;
REALLOC( ret, 0 ); REALLOC( ret, 0 );
} }
return 0; return 0;
} else { } else {
size_t *ret; size_t *ret;
if( !p ) { if( !p ) {
ret = (size_t*)REALLOC( 0, sizeof(size_t) * 2 + sz ); ret = (size_t*)REALLOC( 0, sizeof(size_t) * 2 + sz );
ret[0] = sz; ret[0] = sz;
ret[1] = 0; ret[1] = 0;
} else { } else {
ret = (size_t*)p - 2; ret = (size_t*)p - 2;
size_t osz = ret[0]; size_t osz = ret[0];
size_t ocp = ret[1]; size_t ocp = ret[1];
if( sz <= (osz + ocp) ) { if( sz <= (osz + ocp) ) {
ret[0] = sz; ret[0] = sz;
ret[1] = ocp - (sz - osz); ret[1] = ocp - (sz - osz);
} else { } else {
ret = (size_t*)REALLOC( ret, sizeof(size_t) * 2 + sz * 1.75 ); ret = (size_t*)REALLOC( ret, sizeof(size_t) * 2 + sz * 1.75 );
ret[0] = sz; ret[0] = sz;
ret[1] = (size_t)(sz * 1.75) - sz; ret[1] = (size_t)(sz * 1.75) - sz;
} }
} }
return &ret[2]; return &ret[2];
} }
} }
size_t vlen( void* p ) { size_t vlen( void* p ) {
return p ? 0[ (size_t*)p - 2 ] : 0; return p ? 0[ (size_t*)p - 2 ] : 0;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
enum { MAP_GC_SLOT = MAP_HASHSIZE }; enum { MAP_GC_SLOT = MAP_HASHSIZE };
typedef int map_is_pow2_assert[ !(MAP_HASHSIZE & (MAP_HASHSIZE - 1)) ? 1:-1]; typedef int map_is_pow2_assert[ !(MAP_HASHSIZE & (MAP_HASHSIZE - 1)) ? 1:-1];
static int map_get_index(uint64_t hkey1) { static int map_get_index(uint64_t hkey1) {
return hkey1 & (MAP_HASHSIZE-1); return hkey1 & (MAP_HASHSIZE-1);
} }
void (map_init)(map* m) { void (map_init)(map* m) {
map c = {0}; map c = {0};
*m = c; *m = c;
array_resize(m->array, (MAP_HASHSIZE+1)); array_resize(m->array, (MAP_HASHSIZE+1));
memset(m->array, 0, (MAP_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset() memset(m->array, 0, (MAP_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset()
} }
void (map_insert)(map* m, pair *p, void *key, void *value, uint64_t keyhash, void *super) { void (map_insert)(map* m, pair *p, void *key, void *value, uint64_t keyhash, void *super) {
p->keyhash = keyhash; p->keyhash = keyhash;
p->key = key; p->key = key;
p->value = value; p->value = value;
p->super = super; p->super = super;
/* Insert onto the beginning of the list */ /* Insert onto the beginning of the list */
int index = map_get_index(p->keyhash); int index = map_get_index(p->keyhash);
p->next = m->array[index]; p->next = m->array[index];
m->array[index] = p; m->array[index] = p;
m->is_sorted = 0; m->is_sorted = 0;
++m->count; ++m->count;
} }
void* (map_find)(map* m, void *key, uint64_t keyhash) { void* (map_find)(map* m, void *key, uint64_t keyhash) {
int index = map_get_index(keyhash); int index = map_get_index(keyhash);
for( pair *cur = m->array[index]; cur; cur = cur->next ) { for( pair *cur = m->array[index]; cur; cur = cur->next ) {
if( cur->keyhash == keyhash ) { if( cur->keyhash == keyhash ) {
char **c = (char **)cur->key; char **c = (char **)cur->key;
char **k = (char **)key; char **k = (char **)key;
if( !m->cmp(c[0], k[0]) ) { if( !m->cmp(c[0], k[0]) ) {
return cur->super; return cur->super;
} }
} }
} }
return 0; return 0;
} }
void (map_erase)(map* m, void *key, uint64_t keyhash) { void (map_erase)(map* m, void *key, uint64_t keyhash) {
int index = map_get_index(keyhash); int index = map_get_index(keyhash);
for( pair *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) { for( pair *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) {
if( cur->keyhash == keyhash ) { if( cur->keyhash == keyhash ) {
char **c = (char **)cur->key; char **c = (char **)cur->key;
char **k = (char **)key; char **k = (char **)key;
if( !m->cmp(c[0], k[0]) ) { if( !m->cmp(c[0], k[0]) ) {
if( prev ) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0; if( prev ) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0;
#if MAP_DONT_ERASE #if MAP_DONT_ERASE
/* Insert onto the beginning of the GC list */ /* Insert onto the beginning of the GC list */
cur->next = m->array[MAP_GC_SLOT]; cur->next = m->array[MAP_GC_SLOT];
m->array[MAP_GC_SLOT] = cur; m->array[MAP_GC_SLOT] = cur;
#else #else
REALLOC(cur,0); REALLOC(cur,0);
#endif #endif
--m->count; --m->count;
m->is_sorted = 0; m->is_sorted = 0;
return; return;
} }
} }
} }
} }
int (map_count)(map* m) { // clean deferred GC_SLOT only int (map_count)(map* m) { // clean deferred GC_SLOT only
return m->count; return m->count;
int counter = 0; int counter = 0;
for( int i = 0; i < MAP_HASHSIZE; ++i) { for( int i = 0; i < MAP_HASHSIZE; ++i) {
for( pair *cur = m->array[i]; cur; cur = cur->next ) { for( pair *cur = m->array[i]; cur; cur = cur->next ) {
++counter; ++counter;
} }
} }
return counter; return counter;
} }
int (map_isempty)(map* m) { // clean deferred GC_SLOT only int (map_isempty)(map* m) { // clean deferred GC_SLOT only
return !m->count; return !m->count;
} }
void (map_gc)(map* m) { // clean deferred GC_SLOT only void (map_gc)(map* m) { // clean deferred GC_SLOT only
#if MAP_DONT_ERASE #if MAP_DONT_ERASE
for( pair *next, *cur = m->array[MAP_GC_SLOT]; cur; cur = next ) { for( pair *next, *cur = m->array[MAP_GC_SLOT]; cur; cur = next ) {
next = cur->next; next = cur->next;
REALLOC(cur,0); REALLOC(cur,0);
} }
m->array[MAP_GC_SLOT] = 0; m->array[MAP_GC_SLOT] = 0;
#endif #endif
} }
void (map_clear)(map* m) { void (map_clear)(map* m) {
for( int i = 0; i <= MAP_HASHSIZE; ++i) { for( int i = 0; i <= MAP_HASHSIZE; ++i) {
for( pair *next, *cur = m->array[i]; cur; cur = next ) { for( pair *next, *cur = m->array[i]; cur; cur = next ) {
next = cur->next; next = cur->next;
REALLOC(cur,0); REALLOC(cur,0);
} }
m->array[i] = 0; m->array[i] = 0;
} }
m->count = 0; m->count = 0;
m->is_sorted = 0; m->is_sorted = 0;
} }
bool (map_sort)(map* m) { bool (map_sort)(map* m) {
if( m->is_sorted ) return false; if( m->is_sorted ) return false;
array_clear(m->sorted); array_clear(m->sorted);
// array_reserve(m->sorted, m->count); // array_reserve(m->sorted, m->count);
for( int i = 0; i < array_count(m->array); ++i) { for( int i = 0; i < array_count(m->array); ++i) {
for( pair *cur = m->array[i]; cur; cur = cur->next ) { for( pair *cur = m->array[i]; cur; cur = cur->next ) {
array_push(m->sorted, cur); array_push(m->sorted, cur);
} }
} }
#if 0 #if 0
array_sort(m->sorted, m->cmp); array_sort(m->sorted, m->cmp);
#else #else
// @fixme: do better than bubble sort below // @fixme: do better than bubble sort below
for( int i = 0; i < array_count(m->sorted) - 1; ++i) for( int i = 0; i < array_count(m->sorted) - 1; ++i)
for( int j = i+1; j < array_count(m->sorted); ++j) { for( int j = i+1; j < array_count(m->sorted); ++j) {
pair *curi = m->sorted[i]; pair *curi = m->sorted[i];
pair *curj = m->sorted[j]; pair *curj = m->sorted[j];
char **c = (char **)curi->key; char **c = (char **)curi->key;
char **k = (char **)curj->key; char **k = (char **)curj->key;
if( m->cmp(c[0], k[0]) > 0 ) { if( m->cmp(c[0], k[0]) > 0 ) {
pair *swap = m->sorted[i]; pair *swap = m->sorted[i];
m->sorted[i] = m->sorted[j]; m->sorted[i] = m->sorted[j];
m->sorted[j] = swap; m->sorted[j] = swap;
} }
} }
#endif #endif
return m->is_sorted = true; return m->is_sorted = true;
} }
void (map_free)(map* m) { void (map_free)(map* m) {
(map_clear)(m); (map_clear)(m);
array_free(m->array); array_free(m->array);
m->array = 0; m->array = 0;
map c = {0}; map c = {0};
*m = c; *m = c;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
enum { set_GC_SLOT = SET_HASHSIZE }; enum { set_GC_SLOT = SET_HASHSIZE };
typedef int set_is_pow2_assert[ !(SET_HASHSIZE & (SET_HASHSIZE - 1)) ? 1:-1]; typedef int set_is_pow2_assert[ !(SET_HASHSIZE & (SET_HASHSIZE - 1)) ? 1:-1];
static int set_get_index(uint64_t hkey1) { static int set_get_index(uint64_t hkey1) {
return hkey1 & (SET_HASHSIZE-1); return hkey1 & (SET_HASHSIZE-1);
} }
void (set_init)(set* m) { void (set_init)(set* m) {
set zero = {0}; set zero = {0};
*m = zero; *m = zero;
array_resize(m->array, (SET_HASHSIZE+1)); array_resize(m->array, (SET_HASHSIZE+1));
memset(m->array, 0, (SET_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset() memset(m->array, 0, (SET_HASHSIZE+1) * sizeof(m->array[0]) ); // array_resize() just did memset()
} }
void (set_insert)(set* m, set_item *p, void *key, uint64_t keyhash, void *super) { void (set_insert)(set* m, set_item *p, void *key, uint64_t keyhash, void *super) {
p->keyhash = keyhash; p->keyhash = keyhash;
p->key = key; p->key = key;
p->super = super; p->super = super;
/* Insert onto the beginning of the list */ /* Insert onto the beginning of the list */
int index = set_get_index(p->keyhash); int index = set_get_index(p->keyhash);
p->next = m->array[index]; p->next = m->array[index];
m->array[index] = p; m->array[index] = p;
++m->count; ++m->count;
} }
void* (set_find)(const set* m, void *key, uint64_t keyhash) { void* (set_find)(const set* m, void *key, uint64_t keyhash) {
int index = set_get_index(keyhash); int index = set_get_index(keyhash);
for( const set_item *cur = m->array[index]; cur; cur = cur->next ) { for( const set_item *cur = m->array[index]; cur; cur = cur->next ) {
if( cur->keyhash == keyhash ) { if( cur->keyhash == keyhash ) {
char **c = (char **)cur->key; char **c = (char **)cur->key;
char **k = (char **)key; char **k = (char **)key;
if( !m->cmp(c[0], k[0]) ) { if( !m->cmp(c[0], k[0]) ) {
return cur->super; return cur->super;
} }
} }
} }
return 0; return 0;
} }
void (set_erase)(set* m, void *key, uint64_t keyhash) { void (set_erase)(set* m, void *key, uint64_t keyhash) {
int index = set_get_index(keyhash); int index = set_get_index(keyhash);
for( set_item *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) { for( set_item *prev = 0, *cur = m->array[index]; cur; (prev = cur), (cur = cur->next) ) {
if( cur->keyhash == keyhash ) { if( cur->keyhash == keyhash ) {
char **c = (char **)cur->key; char **c = (char **)cur->key;
char **k = (char **)key; char **k = (char **)key;
if( !m->cmp(c[0], k[0]) ) { if( !m->cmp(c[0], k[0]) ) {
if (prev) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0; if (prev) prev->next = cur->next; else m->array[index] = cur->next ? cur->next : 0;
#if SET_DONT_ERASE #if SET_DONT_ERASE
/* Insert onto the beginning of the GC list */ /* Insert onto the beginning of the GC list */
cur->next = m->array[set_GC_SLOT]; cur->next = m->array[set_GC_SLOT];
m->array[set_GC_SLOT] = cur; m->array[set_GC_SLOT] = cur;
#else #else
REALLOC(cur,0); REALLOC(cur,0);
#endif #endif
--m->count; --m->count;
return; return;
} }
} }
} }
} }
int (set_count)(const set* m) { // does not include GC_SLOT int (set_count)(const set* m) { // does not include GC_SLOT
return m->count; return m->count;
int counter = 0; int counter = 0;
for( int i = 0; i < SET_HASHSIZE; ++i) { for( int i = 0; i < SET_HASHSIZE; ++i) {
for( const set_item *cur = m->array[i]; cur; cur = cur->next ) { for( const set_item *cur = m->array[i]; cur; cur = cur->next ) {
++counter; ++counter;
} }
} }
return counter; return counter;
} }
int (set_isempty)(const set *m) { // clean deferred GC_SLOT only int (set_isempty)(const set *m) { // clean deferred GC_SLOT only
return !m->count; return !m->count;
} }
void (set_gc)(set* m) { // clean deferred GC_SLOT only void (set_gc)(set* m) { // clean deferred GC_SLOT only
#if SET_DONT_ERASE #if SET_DONT_ERASE
for( set_item *next, *cur = m->array[set_GC_SLOT]; cur; cur = next ) { for( set_item *next, *cur = m->array[set_GC_SLOT]; cur; cur = next ) {
next = cur->next; next = cur->next;
REALLOC(cur,0); REALLOC(cur,0);
} }
m->array[set_GC_SLOT] = 0; m->array[set_GC_SLOT] = 0;
#endif #endif
} }
void (set_clear)(set* m) { // include GC_SLOT void (set_clear)(set* m) { // include GC_SLOT
for( int i = 0; i <= SET_HASHSIZE; ++i) { for( int i = 0; i <= SET_HASHSIZE; ++i) {
for( set_item *next, *cur = m->array[i]; cur; cur = next ) { for( set_item *next, *cur = m->array[i]; cur; cur = next ) {
next = cur->next; next = cur->next;
REALLOC(cur,0); REALLOC(cur,0);
} }
m->array[i] = 0; m->array[i] = 0;
} }
m->count = 0; m->count = 0;
} }
void (set_free)(set* m) { void (set_free)(set* m) {
(set_clear)(m); (set_clear)(m);
array_free(m->array); array_free(m->array);
m->array = 0; m->array = 0;
set zero = {0}; set zero = {0};
*m = zero; *m = zero;
} }

View File

@ -1,436 +1,436 @@
// data structures and utils: array, set, map, hash, sort. // data structures and utils: array, set, map, hash, sort.
// - rlyeh, public domain // - rlyeh, public domain
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// less // less
API int less_64(uint64_t a, uint64_t b); API int less_64(uint64_t a, uint64_t b);
API int less_int(int a, int b); API int less_int(int a, int b);
API int less_ptr(void *a, void *b); API int less_ptr(void *a, void *b);
API int less_str(char *a, char *b); API int less_str(char *a, char *b);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// qsort // qsort
API int less_64_ptr(const void *a, const void *b); API int less_64_ptr(const void *a, const void *b);
API int less_int_ptr(const void *a, const void *b); API int less_int_ptr(const void *a, const void *b);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// un/hash // un/hash
API uint32_t unhash_32(uint32_t x); API uint32_t unhash_32(uint32_t x);
API uint32_t hash_32(uint32_t x); API uint32_t hash_32(uint32_t x);
API uint64_t hash_64(uint64_t x); API uint64_t hash_64(uint64_t x);
API uint64_t hash_flt(double x); API uint64_t hash_flt(double x);
API uint64_t hash_int(int key); API uint64_t hash_int(int key);
API uint64_t hash_ptr(const void* ptr); API uint64_t hash_ptr(const void* ptr);
API uint64_t hash_bin(const void* ptr, unsigned len); API uint64_t hash_bin(const void* ptr, unsigned len);
API uint64_t hash_str(const char* str); API uint64_t hash_str(const char* str);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// bits // bits
API uint64_t popcnt64(uint64_t x); API uint64_t popcnt64(uint64_t x);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// vector based allocator (x1.75 enlarge factor) // vector based allocator (x1.75 enlarge factor)
API void* vrealloc( void* p, size_t sz ); API void* vrealloc( void* p, size_t sz );
API size_t vlen( void* p ); API size_t vlen( void* p );
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// arrays // arrays
#if is(cpp) #if is(cpp)
#define array_cast(x) (decltype x) #define array_cast(x) (decltype x)
#else #else
#define array_cast(x) (void *) #define array_cast(x) (void *)
#endif #endif
#define array(t) t* #define array(t) t*
#define array_init(t) ( (t) = 0 ) #define array_init(t) ( (t) = 0 )
#define array_resize(t, n) ( array_c_ = array_count(t), array_n_ = (n), array_realloc_((t),array_n_), (array_n_>array_c_? memset(array_c_+(t),0,(array_n_-array_c_)*sizeof(0[t])) : (void*)0), (t) ) #define array_resize(t, n) ( array_c_ = array_count(t), array_n_ = (n), array_realloc_((t),array_n_), (array_n_>array_c_? memset(array_c_+(t),0,(array_n_-array_c_)*sizeof(0[t])) : (void*)0), (t) )
#define array_push(t, ...) ( array_realloc_((t),array_count(t)+1), (t)[ array_count(t) - 1 ] = (__VA_ARGS__) ) #define array_push(t, ...) ( array_realloc_((t),array_count(t)+1), (t)[ array_count(t) - 1 ] = (__VA_ARGS__) )
#define array_pop(t) ( array_realloc_((t), array_count(t)-1) ) #define array_pop(t) ( array_realloc_((t), array_count(t)-1) )
#define array_back(t) ( &(t)[ array_count(t)-1 ] ) // ( (t) ? &(t)[ array_count(t)-1 ] : NULL ) #define array_back(t) ( &(t)[ array_count(t)-1 ] ) // ( (t) ? &(t)[ array_count(t)-1 ] : NULL )
#define array_data(t) (t) #define array_data(t) (t)
#define array_at(t,i) (t[i]) #define array_at(t,i) (t[i])
#define array_count(t) (int)( (t) ? array_vlen_(t) / sizeof(0[t]) : 0u ) #define array_count(t) (int)( (t) ? array_vlen_(t) / sizeof(0[t]) : 0u )
#define array_bytes(t) (int)( (t) ? array_vlen_(t) : 0u ) #define array_bytes(t) (int)( (t) ? array_vlen_(t) : 0u )
#define array_sort(t, cmpfunc) qsort( t, array_count(t), sizeof(0[t]), (uintptr_t)cmpfunc == (uintptr_t)strcmp ? (void*)strcmp_qsort : (void*)cmpfunc ) #define array_sort(t, cmpfunc) qsort( t, array_count(t), sizeof(0[t]), (uintptr_t)cmpfunc == (uintptr_t)strcmp ? (void*)strcmp_qsort : (void*)cmpfunc )
#define array_empty(t) ( !array_count(t) ) #define array_empty(t) ( !array_count(t) )
#define array_push_front(arr,x) \ #define array_push_front(arr,x) \
(array_resize((arr), array_count(arr)+1), memmove((arr)+1, (arr), sizeof(0[arr])*array_count(arr)), 0[arr] = (x)) (array_resize((arr), array_count(arr)+1), memmove((arr)+1, (arr), sizeof(0[arr])*array_count(arr)), 0[arr] = (x))
#define array_pop_front(arr) ( \ #define array_pop_front(arr) ( \
(array_count(arr) > 1 ? memmove((arr), (arr)+1, sizeof(0[arr])*(array_count(arr)-1)) : (void*)0), \ (array_count(arr) > 1 ? memmove((arr), (arr)+1, sizeof(0[arr])*(array_count(arr)-1)) : (void*)0), \
(array_count(arr) > 0 ? array_resize(arr, array_count(arr) - 1 ) : array_resize( arr, 0 ) ) ) (array_count(arr) > 0 ? array_resize(arr, array_count(arr) - 1 ) : array_resize( arr, 0 ) ) )
static __thread unsigned array_c_; static __thread unsigned array_c_;
static __thread unsigned array_n_; static __thread unsigned array_n_;
#if 0 // original: no reserve support #if 0 // original: no reserve support
#define array_reserve(t, n) ((void)0) // not implemented #define array_reserve(t, n) ((void)0) // not implemented
#define array_clear(t) ( array_realloc_((t), 0), (t) = 0 ) #define array_clear(t) ( array_realloc_((t), 0), (t) = 0 )
#define array_vlen_(t) ( vlen(t) - 0 ) #define array_vlen_(t) ( vlen(t) - 0 )
#define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) ) #define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+0) * sizeof(0[t])) )
#define array_free(t) array_clear(t) #define array_free(t) array_clear(t)
#else // new: with reserve support (@todo: check for bugs?) #else // new: with reserve support (@todo: check for bugs?)
#define array_reserve(t, n) ( array_realloc_((t),(n)), array_clear(t) ) #define array_reserve(t, n) ( array_realloc_((t),(n)), array_clear(t) )
#define array_clear(t) ( array_realloc_((t),0) ) // -1 #define array_clear(t) ( array_realloc_((t),0) ) // -1
#define array_vlen_(t) ( vlen(t) - sizeof(0[t]) ) // -1 #define array_vlen_(t) ( vlen(t) - sizeof(0[t]) ) // -1
#define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+1) * sizeof(0[t])) ) // +1 #define array_realloc_(t,n) ( (t) = array_cast(t) vrealloc((t), ((n)+1) * sizeof(0[t])) ) // +1
#define array_free(t) ( array_realloc_((t), -1), (t) = 0 ) // -1 #define array_free(t) ( array_realloc_((t), -1), (t) = 0 ) // -1
#endif #endif
#define array_reverse(t) \ #define array_reverse(t) \
do if( array_count(t) ) { \ do if( array_count(t) ) { \
for(int l = array_count(t), e = l-1, i = (array_push(t, 0[t]), 0); i <= e/2; ++i ) \ for(int l = array_count(t), e = l-1, i = (array_push(t, 0[t]), 0); i <= e/2; ++i ) \
{ l[t] = i[t]; i[t] = (e-i)[t]; (e-i)[t] = l[t]; } \ { l[t] = i[t]; i[t] = (e-i)[t]; (e-i)[t] = l[t]; } \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)
#define array_foreach(t,val_t,v) for each_array(t,val_t,v) #define array_foreach(t,val_t,v) for each_array(t,val_t,v)
#define each_array(a,val_t,v) \ #define each_array(a,val_t,v) \
( array(val_t) a_ = (a); a_; a_ = 0 ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \ for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t v = i_[a_], *v_ = (void*)(uintptr_t)&v; v_; v_ = 0 ) for( val_t v = i_[a_], *v_ = (void*)(uintptr_t)&v; v_; v_ = 0 )
#define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v) #define array_foreach_ptr(t,val_t,v) for each_array_ptr(t,val_t,v)
#define each_array_ptr(a,val_t,v) \ #define each_array_ptr(a,val_t,v) \
( array(val_t) a_ = (a); a_; a_ = 0 ) \ ( array(val_t) a_ = (a); a_; a_ = 0 ) \
for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \ for( int i_ = 0, e_ = array_count(a_); i_ < e_; ++i_ ) \
for( val_t *v = (val_t*)&i_[a_]; v; v = 0 ) for( val_t *v = (val_t*)&i_[a_]; v; v = 0 )
#define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \ #define array_search(t, key, cmpfn) /* requires sorted array beforehand */ \
bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn ) bsearch(&key, t, array_count(t), sizeof(t[0]), cmpfn )
#define array_insert(t, i, n) do { \ #define array_insert(t, i, n) do { \
int ac = array_count(t); \ int ac = array_count(t); \
if( i >= ac ) { \ if( i >= ac ) { \
array_push(t, n); \ array_push(t, n); \
} else { \ } else { \
array_push(t, array_back(t)); \ array_push(t, array_back(t)); \
memmove( &(t)[(i)+1], &(t)[i], (ac - (i)) * sizeof(t[0]) ); \ memmove( &(t)[(i)+1], &(t)[i], (ac - (i)) * sizeof(t[0]) ); \
(t)[ i ] = (n); \ (t)[ i ] = (n); \
} \ } \
} while(0) } while(0)
#define array_copy(t, src) do { \ #define array_copy(t, src) do { \
array_free(t); \ array_free(t); \
(t) = array_realloc_( (t), array_count(src)); \ (t) = array_realloc_( (t), array_count(src)); \
memcpy( (t), src, array_count(src) * sizeof(0[t])); \ memcpy( (t), src, array_count(src) * sizeof(0[t])); \
} while(0) } while(0)
#define array_erase_fast(t, i) do { /*alters ordering*/ \ #define array_erase_fast(t, i) do { /*alters ordering*/ \
memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \ memcpy( &(t)[i], &(t)[array_count(t) - 1], sizeof(0[t])); \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)
#define array_erase_slow(t, i) do { /*preserves ordering*/ \ #define array_erase_slow(t, i) do { /*preserves ordering*/ \
memmove( &(t)[i], &(t)[i + 1], sizeof(0[t])*(array_count(t) - i - 1)); \ memmove( &(t)[i], &(t)[i + 1], sizeof(0[t])*(array_count(t) - i - 1)); \
array_pop(t); \ array_pop(t); \
} while(0) } while(0)
#define array_unique(t, cmpfunc) do { /*@todo: optimize me. requires array_sort() beforehand*/ \ #define array_unique(t, cmpfunc) do { /*@todo: optimize me. requires array_sort() beforehand*/ \
int cnt = array_count(t), cnt_bak = cnt; \ int cnt = array_count(t), cnt_bak = cnt; \
if( cnt > 1 ) { \ if( cnt > 1 ) { \
for( int i = 1; i < cnt; ++i ) { \ for( int i = 1; i < cnt; ++i ) { \
while( i < cnt && !cmpfunc(&(t)[i-1], &(t)[i]) ) { \ while( i < cnt && !cmpfunc(&(t)[i-1], &(t)[i]) ) { \
memmove(&(t)[i-1], &(t)[i], (cnt - 1 - i) * sizeof((t)[0]) ) ; \ memmove(&(t)[i-1], &(t)[i], (cnt - 1 - i) * sizeof((t)[0]) ) ; \
--cnt; \ --cnt; \
} \ } \
} \ } \
if( cnt_bak != cnt ) array_resize((t), cnt); \ if( cnt_bak != cnt ) array_resize((t), cnt); \
} \ } \
} while(0) } while(0)
#if 0 // snippet below does work #if 0 // snippet below does work
#define array_unique(t, cmpfunc) \ #define array_unique(t, cmpfunc) \
array_sort(t, cmpfunc); \ array_sort(t, cmpfunc); \
for( int i = 0, end = array_count(t) - 1; i < end; ) { \ for( int i = 0, end = array_count(t) - 1; i < end; ) { \
if( !strcmp(t[i], t[i+1]) ) { \ if( !strcmp(t[i], t[i+1]) ) { \
/* array_erase(t, i+1); */ \ /* array_erase(t, i+1); */ \
memmove(&(t)[i+1], &(t)[i+2], (end - 1 - i) * sizeof((t)[0]) ); \ memmove(&(t)[i+1], &(t)[i+2], (end - 1 - i) * sizeof((t)[0]) ); \
array_pop(t); \ array_pop(t); \
--end; \ --end; \
} else { \ } else { \
++i; \ ++i; \
} \ } \
} }
#endif #endif
#define array_shuffle(t) do { /* https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle */ \ #define array_shuffle(t) do { /* https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle */ \
void* tmp = stack(sizeof(0[t])); \ void* tmp = stack(sizeof(0[t])); \
for( int i = 0, n = array_count(t); i < n; ++i ) { \ for( int i = 0, n = array_count(t); i < n; ++i ) { \
int j = randi(i, n); /* j random integer such that [i,n) i<=j<n */ \ int j = randi(i, n); /* j random integer such that [i,n) i<=j<n */ \
memcpy(tmp, &j[t], sizeof(0[t])); \ memcpy(tmp, &j[t], sizeof(0[t])); \
memcpy(&j[t], &i[t], sizeof(0[t])); \ memcpy(&j[t], &i[t], sizeof(0[t])); \
memcpy(&i[t], tmp, sizeof(0[t])); \ memcpy(&i[t], tmp, sizeof(0[t])); \
} \ } \
} while(0) } while(0)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// set<K> // set<K>
// ideas from: https://en.wikipedia.org/wiki/Hash_table // ideas from: https://en.wikipedia.org/wiki/Hash_table
// ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/ // ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/
// ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/ // ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/
// config // config
#ifndef SET_HASHSIZE #ifndef SET_HASHSIZE
#define SET_HASHSIZE (4096 << 4) #define SET_HASHSIZE (4096 << 4)
#endif #endif
#ifndef SET_DONT_ERASE #ifndef SET_DONT_ERASE
#define SET_DONT_ERASE 1 #define SET_DONT_ERASE 1
#endif #endif
// public api // public api
#define set(K) \ #define set(K) \
struct { set base; struct { set_item p; K key; } tmp, *ptr; K *tmpval; \ struct { set base; struct { set_item p; K key; } tmp, *ptr; K *tmpval; \
int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } * int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } *
#define set_init(m, cmpfn, hashfn) ( \ #define set_init(m, cmpfn, hashfn) ( \
(m) = set_cast(m) REALLOC(0, sizeof(*m)), \ (m) = set_cast(m) REALLOC(0, sizeof(*m)), \
set_init(&(m)->base), \ set_init(&(m)->base), \
(m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = set_cast(cmpfn) cmpfn ), \ (m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = set_cast(cmpfn) cmpfn ), \
(m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = set_cast(hashfn) hashfn ) \ (m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = set_cast(hashfn) hashfn ) \
) )
#define set_free(m) ( \ #define set_free(m) ( \
set_clear(m), \ set_clear(m), \
set_free(&(m)->base), \ set_free(&(m)->base), \
(m) = set_cast(m) REALLOC((m), 0), \ (m) = set_cast(m) REALLOC((m), 0), \
(m) = 0 \ (m) = 0 \
) )
#define set_insert(m, k) ( \ #define set_insert(m, k) ( \
(m)->ptr = set_cast((m)->ptr) REALLOC(0, sizeof((m)->tmp)), \ (m)->ptr = set_cast((m)->ptr) REALLOC(0, sizeof((m)->tmp)), \
(m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \
set_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, (m)->ptr->p.keyhash, (m)->ptr), \ set_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, (m)->ptr->p.keyhash, (m)->ptr), \
&(m)->ptr->key \ &(m)->ptr->key \
) )
#define set_find(m, k) ( \ #define set_find(m, k) ( \
(m)->ptr = &(m)->tmp, \ (m)->ptr = &(m)->tmp, \
(m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \
(m)->ptr = set_cast((m)->ptr) set_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \ (m)->ptr = set_cast((m)->ptr) set_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \
(m)->ptr ? &(m)->ptr->key : 0 \ (m)->ptr ? &(m)->ptr->key : 0 \
) )
#define set_find_or_add(m, k) ( \ #define set_find_or_add(m, k) ( \
(m)->tmp.key = (k), \ (m)->tmp.key = (k), \
(m)->tmpval = set_find((m), ((m)->tmp.key)), \ (m)->tmpval = set_find((m), ((m)->tmp.key)), \
(m)->tmpval = (m)->tmpval ? (m)->tmpval : set_insert((m), ((m)->tmp.key)) \ (m)->tmpval = (m)->tmpval ? (m)->tmpval : set_insert((m), ((m)->tmp.key)) \
) )
#define set_find_or_add_allocated_key(m, k) ( \ #define set_find_or_add_allocated_key(m, k) ( \
(m)->tmp.key = (k), \ (m)->tmp.key = (k), \
(m)->tmpval = set_find((m), ((m)->tmp.key)), \ (m)->tmpval = set_find((m), ((m)->tmp.key)), \
(m)->tmpval = (m)->tmpval ? FREE((m)->tmp.key), (m)->tmpval : set_insert((m), ((m)->tmp.key)) \ (m)->tmpval = (m)->tmpval ? FREE((m)->tmp.key), (m)->tmpval : set_insert((m), ((m)->tmp.key)) \
) )
#define set_erase(m, k) ( \ #define set_erase(m, k) ( \
(m)->ptr = &(m)->tmp, \ (m)->ptr = &(m)->tmp, \
(m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \
set_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \ set_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \
) )
#define set_foreach for each_set #define set_foreach for each_set
#define each_set(m,key_t,k) \ #define each_set(m,key_t,k) \
( int i_ = (m)->base.count ? 0 : SET_HASHSIZE; i_ < SET_HASHSIZE; ++i_) \ ( int i_ = (m)->base.count ? 0 : SET_HASHSIZE; i_ < SET_HASHSIZE; ++i_) \
for( set_item *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( set_item *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \
for( key_t k = *(key_t *)cur_->key; on_; on_ = 0 ) for( key_t k = *(key_t *)cur_->key; on_; on_ = 0 )
#define set_foreach_ptr for each_set_ptr #define set_foreach_ptr for each_set_ptr
#define each_set_ptr(m,key_t,k) \ #define each_set_ptr(m,key_t,k) \
( int i_ = (m)->base.count ? 0 : SET_HASHSIZE; i_ < SET_HASHSIZE; ++i_) \ ( int i_ = (m)->base.count ? 0 : SET_HASHSIZE; i_ < SET_HASHSIZE; ++i_) \
for( set_item *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( set_item *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \
for( key_t *k = (key_t *)cur_->key; on_; on_ = 0 ) for( key_t *k = (key_t *)cur_->key; on_; on_ = 0 )
#define set_clear(m) ( \ #define set_clear(m) ( \
set_clear(&(m)->base) \ set_clear(&(m)->base) \
) )
#define set_isempty(m) set_isempty(&(m)->base) #define set_isempty(m) set_isempty(&(m)->base)
#define set_count(m) set_count(&(m)->base) #define set_count(m) set_count(&(m)->base)
#define set_gc(m) set_gc(&(m)->base) #define set_gc(m) set_gc(&(m)->base)
#ifndef set_init_int #ifndef set_init_int
#define set_init_int(m) set_init((m), less_int, hash_64) // hash_int) #define set_init_int(m) set_init((m), less_int, hash_64) // hash_int)
#define set_init_str(m) set_init((m), less_str, hash_str) #define set_init_str(m) set_init((m), less_str, hash_str)
#define set_init_ptr(m) set_init((m), less_ptr, hash_ptr) #define set_init_ptr(m) set_init((m), less_ptr, hash_ptr)
#endif #endif
// private: // private:
#if is(cpp) #if is(cpp)
#define set_cast(t) (decltype(t)) #define set_cast(t) (decltype(t))
#else #else
#define set_cast(t) (void *) #define set_cast(t) (void *)
#endif #endif
typedef struct set_item { typedef struct set_item {
struct set_item *next; struct set_item *next;
uint64_t keyhash; uint64_t keyhash;
void *key; void *key;
void *super; void *super;
} set_item; } set_item;
typedef struct set { typedef struct set {
array(set_item*) array; array(set_item*) array;
int (*cmp)(void *, void *); int (*cmp)(void *, void *);
uint64_t (*hash)(void *); uint64_t (*hash)(void *);
int count; int count;
} set; } set;
API void (set_init)(set *m); API void (set_init)(set *m);
API void (set_free)(set *m); API void (set_free)(set *m);
API void (set_insert)(set *m, set_item *p, void *key, uint64_t keyhash, void *super); API void (set_insert)(set *m, set_item *p, void *key, uint64_t keyhash, void *super);
API void (set_erase)(set *m, void *key, uint64_t keyhash); API void (set_erase)(set *m, void *key, uint64_t keyhash);
API void* (set_find)(const set *m, void *key, uint64_t keyhash); API void* (set_find)(const set *m, void *key, uint64_t keyhash);
API int (set_isempty)(const set *m); API int (set_isempty)(const set *m);
API int (set_count)(const set *m); API int (set_count)(const set *m);
API void (set_gc)(set *m); // only if using SET_DONT_ERASE API void (set_gc)(set *m); // only if using SET_DONT_ERASE
API void (set_clear)(set* m); API void (set_clear)(set* m);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// map<K,V> // map<K,V>
// ideas from: https://en.wikipedia.org/wiki/Hash_table // ideas from: https://en.wikipedia.org/wiki/Hash_table
// ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/ // ideas from: https://probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable/
// ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/ // ideas from: http://www.idryman.org/blog/2017/05/03/writing-a-damn-fast-hash-table-with-tiny-memory-footprints/
// config // config
#ifndef MAP_HASHSIZE #ifndef MAP_HASHSIZE
#define MAP_HASHSIZE (4096 << 4) #define MAP_HASHSIZE (4096 << 4)
#endif #endif
#ifndef MAP_DONT_ERASE #ifndef MAP_DONT_ERASE
#define MAP_DONT_ERASE 1 #define MAP_DONT_ERASE 1
#endif #endif
// public api // public api
#define map(K,V) \ #define map(K,V) \
struct { map base; struct { pair p; K key; V val; } tmp, *ptr; V* tmpval; \ struct { map base; struct { pair p; K key; V val; } tmp, *ptr; V* tmpval; \
int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } * int (*typed_cmp)(K, K); uint64_t (*typed_hash)(K); } *
#define map_init(m, cmpfn, hashfn) ( \ #define map_init(m, cmpfn, hashfn) ( \
(m) = map_cast(m) REALLOC(0, sizeof(*(m))), \ (m) = map_cast(m) REALLOC(0, sizeof(*(m))), \
map_init(&(m)->base), \ map_init(&(m)->base), \
(m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = map_cast((m)->typed_cmp) cmpfn), \ (m)->base.cmp = (int(*)(void*,void*))( (m)->typed_cmp = map_cast((m)->typed_cmp) cmpfn), \
(m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = map_cast((m)->typed_hash) hashfn ) \ (m)->base.hash = (uint64_t(*)(void*))( (m)->typed_hash = map_cast((m)->typed_hash) hashfn ) \
) )
#define map_free(m) ( \ #define map_free(m) ( \
map_free(&(m)->base), \ map_free(&(m)->base), \
map_cast(m) REALLOC((m), sizeof(*(m))), (m) = 0 \ map_cast(m) REALLOC((m), sizeof(*(m))), (m) = 0 \
) )
#define map_insert(m, k, v) ( \ #define map_insert(m, k, v) ( \
(m)->ptr = map_cast((m)->ptr) REALLOC(0, sizeof((m)->tmp)), \ (m)->ptr = map_cast((m)->ptr) REALLOC(0, sizeof((m)->tmp)), \
(m)->ptr->val = (v), \ (m)->ptr->val = (v), \
(m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \
map_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, &(m)->ptr->val, (m)->ptr->p.keyhash, (m)->ptr), \ map_insert(&(m)->base, &(m)->ptr->p, &(m)->ptr->key, &(m)->ptr->val, (m)->ptr->p.keyhash, (m)->ptr), \
&(m)->ptr->val \ &(m)->ptr->val \
) )
#define map_find(m, k) ( \ #define map_find(m, k) ( \
(m)->ptr = &(m)->tmp, \ (m)->ptr = &(m)->tmp, \
(m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \
(m)->ptr = map_cast((m)->ptr) map_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \ (m)->ptr = map_cast((m)->ptr) map_find(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash), \
(m)->ptr ? &(m)->ptr->val : 0 \ (m)->ptr ? &(m)->ptr->val : 0 \
) )
#define map_find_or_add(m, k, v) ( \ #define map_find_or_add(m, k, v) ( \
(m)->tmp.key = (k), (m)->tmp.val = (v), \ (m)->tmp.key = (k), (m)->tmp.val = (v), \
(m)->tmpval = map_find((m), ((m)->tmp.key)), \ (m)->tmpval = map_find((m), ((m)->tmp.key)), \
(m)->tmpval = (m)->tmpval ? (m)->tmpval : map_insert((m), ((m)->tmp.key), ((m)->tmp.val)) \ (m)->tmpval = (m)->tmpval ? (m)->tmpval : map_insert((m), ((m)->tmp.key), ((m)->tmp.val)) \
) )
#define map_find_or_add_allocated_key(m, k, v) ( \ #define map_find_or_add_allocated_key(m, k, v) ( \
(m)->tmp.key = (k), (m)->tmp.val = (v), \ (m)->tmp.key = (k), (m)->tmp.val = (v), \
(m)->tmpval = map_find((m), ((m)->tmp.key)), \ (m)->tmpval = map_find((m), ((m)->tmp.key)), \
(m)->tmpval = (m)->tmpval ? FREE((m)->tmp.key), (m)->tmpval : map_insert((m), ((m)->tmp.key), ((m)->tmp.val)) \ (m)->tmpval = (m)->tmpval ? FREE((m)->tmp.key), (m)->tmpval : map_insert((m), ((m)->tmp.key), ((m)->tmp.val)) \
) )
#define map_erase(m, k) ( \ #define map_erase(m, k) ( \
(m)->ptr = &(m)->tmp, \ (m)->ptr = &(m)->tmp, \
(m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \ (m)->ptr->p.keyhash = (m)->typed_hash((m)->ptr->key = (k)), \
map_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \ map_erase(&(m)->base, &(m)->ptr->key, (m)->ptr->p.keyhash) \
) )
#define map_foreach for each_map #define map_foreach for each_map
#define each_map(m,key_t,k,val_t,v) \ #define each_map(m,key_t,k,val_t,v) \
( int i_ = (m)->base.count ? 0 : MAP_HASHSIZE; i_ < MAP_HASHSIZE; ++i_) \ ( int i_ = (m)->base.count ? 0 : MAP_HASHSIZE; i_ < MAP_HASHSIZE; ++i_) \
for( pair *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( pair *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \
for( key_t k = *(key_t *)cur_->key; on_; ) \ for( key_t k = *(key_t *)cur_->key; on_; ) \
for( val_t v = *(val_t *)cur_->value; on_; on_ = 0 ) for( val_t v = *(val_t *)cur_->value; on_; on_ = 0 )
#define map_foreach_ptr for each_map_ptr #define map_foreach_ptr for each_map_ptr
#define each_map_ptr(m,key_t,k,val_t,v) \ #define each_map_ptr(m,key_t,k,val_t,v) \
( int i_ = (m)->base.count ? 0 : MAP_HASHSIZE; i_ < MAP_HASHSIZE; ++i_) \ ( int i_ = (m)->base.count ? 0 : MAP_HASHSIZE; i_ < MAP_HASHSIZE; ++i_) \
for( pair *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \ for( pair *cur_ = (m)->base.array[i_], *on_ = cur_; cur_; on_ = cur_ = cur_->next ) \
for( key_t *k = (key_t *)cur_->key; on_; ) \ for( key_t *k = (key_t *)cur_->key; on_; ) \
for( val_t *v = (val_t *)cur_->value; on_; on_ = 0 ) for( val_t *v = (val_t *)cur_->value; on_; on_ = 0 )
#define map_foreach_ptr_sorted for each_map_ptr_sorted #define map_foreach_ptr_sorted for each_map_ptr_sorted
#define each_map_ptr_sorted(m,key_t,k,val_t,v) \ #define each_map_ptr_sorted(m,key_t,k,val_t,v) \
( int i_ = (map_sort(&(m)->base), 0); i_ < array_count((m)->base.sorted); ++i_) \ ( int i_ = (map_sort(&(m)->base), 0); i_ < array_count((m)->base.sorted); ++i_) \
for( pair *cur_ = (m)->base.sorted[i_]; cur_; ) \ for( pair *cur_ = (m)->base.sorted[i_]; cur_; ) \
for( key_t *k = (key_t *)cur_->key; cur_; ) \ for( key_t *k = (key_t *)cur_->key; cur_; ) \
for( val_t *v = (val_t *)cur_->value; cur_; cur_ = 0 ) for( val_t *v = (val_t *)cur_->value; cur_; cur_ = 0 )
#define map_clear(m) ( \ #define map_clear(m) ( \
map_clear(&(m)->base) \ map_clear(&(m)->base) \
) )
#define map_isempty(m) map_isempty(&(m)->base) #define map_isempty(m) map_isempty(&(m)->base)
#define map_count(m) map_count(&(m)->base) #define map_count(m) map_count(&(m)->base)
#define map_gc(m) map_gc(&(m)->base) #define map_gc(m) map_gc(&(m)->base)
// aliases: // aliases:
#ifndef map_init_int #ifndef map_init_int
#define map_init_int(m) map_init((m), less_int, hash_64) // hash_int #define map_init_int(m) map_init((m), less_int, hash_64) // hash_int
#define map_init_str(m) map_init((m), less_str, hash_str) #define map_init_str(m) map_init((m), less_str, hash_str)
#define map_init_ptr(m) map_init((m), less_ptr, hash_ptr) #define map_init_ptr(m) map_init((m), less_ptr, hash_ptr)
#endif #endif
// private: // private:
#if is(cpp) #if is(cpp)
#define map_cast(t) (decltype(t)) #define map_cast(t) (decltype(t))
#else #else
#define map_cast(t) (void *) #define map_cast(t) (void *)
#endif #endif
typedef struct pair { typedef struct pair {
struct pair *next; struct pair *next;
uint64_t keyhash; uint64_t keyhash;
void *key; void *key;
void *value; void *value;
void *super; void *super;
} pair; } pair;
typedef struct map { typedef struct map {
array(pair*) array; array(pair*) array;
int (*cmp)(void *, void *); int (*cmp)(void *, void *);
uint64_t (*hash)(void *); uint64_t (*hash)(void *);
int count:31; int count:31;
int is_sorted:1; int is_sorted:1;
array(pair*) sorted; array(pair*) sorted;
} map; } map;
API void (map_init)(map *m); API void (map_init)(map *m);
API void (map_free)(map *m); API void (map_free)(map *m);
API void (map_insert)(map *m, pair *p, void *key, void *value, uint64_t keyhash, void *super); API void (map_insert)(map *m, pair *p, void *key, void *value, uint64_t keyhash, void *super);
API void (map_erase)(map *m, void *key, uint64_t keyhash); API void (map_erase)(map *m, void *key, uint64_t keyhash);
API void* (map_find)(map *m, void *key, uint64_t keyhash); API void* (map_find)(map *m, void *key, uint64_t keyhash);
API int (map_isempty)(map *m); API int (map_isempty)(map *m);
API int (map_count)(map *m); API int (map_count)(map *m);
API void (map_gc)(map *m); // only if using MAP_DONT_ERASE API void (map_gc)(map *m); // only if using MAP_DONT_ERASE
API bool (map_sort)(map* m); API bool (map_sort)(map* m);
API void (map_clear)(map* m); API void (map_clear)(map* m);

File diff suppressed because it is too large Load Diff

View File

@ -1,114 +1,114 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// in-game editor // in-game editor
// - rlyeh, public domain. // - rlyeh, public domain.
#define EDITOR_VERSION "2023.10" #define EDITOR_VERSION "2023.10"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// editor bindings // editor bindings
typedef struct editor_bind_t { typedef struct editor_bind_t {
const char *command; const char *command;
const char *bindings; const char *bindings;
void (*fn)(); void (*fn)();
} editor_bind_t; } editor_bind_t;
API void editor_addbind(editor_bind_t bind); API void editor_addbind(editor_bind_t bind);
#define EDITOR_BIND(CMD,KEYS,...) \ #define EDITOR_BIND(CMD,KEYS,...) \
void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); } void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// editor properties // editor properties
#define EDITOR_PROPERTYDEF(T,property_name) \ #define EDITOR_PROPERTYDEF(T,property_name) \
typedef map(void*,T) editor_##property_name##_map_t; \ typedef map(void*,T) editor_##property_name##_map_t; \
API editor_##property_name##_map_t *editor_##property_name##_map(); \ API editor_##property_name##_map_t *editor_##property_name##_map(); \
API T editor_##property_name(const void *obj); \ API T editor_##property_name(const void *obj); \
API void editor_set##property_name(const void *obj, T value); \ API void editor_set##property_name(const void *obj, T value); \
API void editor_alt##property_name(const void *obj); \ API void editor_alt##property_name(const void *obj); \
API void editor_no##property_name(void *obj); API void editor_no##property_name(void *obj);
EDITOR_PROPERTYDEF(int, open); ///- whether object is tree opened in tree editor EDITOR_PROPERTYDEF(int, open); ///- whether object is tree opened in tree editor
EDITOR_PROPERTYDEF(int, selected); ///- whether object is displaying a contextual popup or not EDITOR_PROPERTYDEF(int, selected); ///- whether object is displaying a contextual popup or not
EDITOR_PROPERTYDEF(int, changed); ///- whether object is displaying a contextual popup or not EDITOR_PROPERTYDEF(int, changed); ///- whether object is displaying a contextual popup or not
EDITOR_PROPERTYDEF(int, popup); ///- whether object is displaying a contextual popup or not EDITOR_PROPERTYDEF(int, popup); ///- whether object is displaying a contextual popup or not
EDITOR_PROPERTYDEF(int, bookmarked); ///- EDITOR_PROPERTYDEF(int, bookmarked); ///-
EDITOR_PROPERTYDEF(int, visible); ///- EDITOR_PROPERTYDEF(int, visible); ///-
EDITOR_PROPERTYDEF(int, script); ///- EDITOR_PROPERTYDEF(int, script); ///-
EDITOR_PROPERTYDEF(int, event); ///- EDITOR_PROPERTYDEF(int, event); ///-
EDITOR_PROPERTYDEF(char*,iconinstance); ///- EDITOR_PROPERTYDEF(char*,iconinstance); ///-
EDITOR_PROPERTYDEF(char*,iconclass); ///- EDITOR_PROPERTYDEF(char*,iconclass); ///-
EDITOR_PROPERTYDEF(int, treeoffsety); ///- EDITOR_PROPERTYDEF(int, treeoffsety); ///-
API void editor_destroy_properties(void *o); API void editor_destroy_properties(void *o);
API void editor_load_on_boot(void); API void editor_load_on_boot(void);
API void editor_save_on_quit(void); API void editor_save_on_quit(void);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// editor ui // editor ui
enum EDITOR_MODE { enum EDITOR_MODE {
EDITOR_PANEL, EDITOR_PANEL,
EDITOR_WINDOW, EDITOR_WINDOW,
EDITOR_WINDOW_NK, EDITOR_WINDOW_NK,
EDITOR_WINDOW_NK_SMALL, EDITOR_WINDOW_NK_SMALL,
}; };
API int editor_begin(const char *title, int mode); API int editor_begin(const char *title, int mode);
API int editor_end(int mode); API int editor_end(int mode);
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// editor selection // editor selection
API int editor_filter(); API int editor_filter();
API void editor_select(const char *mask); API void editor_select(const char *mask);
API void editor_unselect(); // same than editor_select("!**"); API void editor_unselect(); // same than editor_select("!**");
API void editor_select_aabb(aabb box); API void editor_select_aabb(aabb box);
API void editor_selectgroup(obj *first, obj *last); API void editor_selectgroup(obj *first, obj *last);
API void* editor_first_selected(); API void* editor_first_selected();
API void* editor_last_selected(); API void* editor_last_selected();
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// editor instancing // editor instancing
API void editor_addtoworld(obj *o); API void editor_addtoworld(obj *o);
API void editor_watch(const void *o); API void editor_watch(const void *o);
API void* editor_spawn(const char *ini); // deprecate? API void* editor_spawn(const char *ini); // deprecate?
API void editor_spawn1(); API void editor_spawn1();
API void editor_destroy_selected(); API void editor_destroy_selected();
API void editor_inspect(obj *o); API void editor_inspect(obj *o);
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// editor utils // editor utils
//API void editor(); //API void editor();
//API bool editor_active(); //API bool editor_active();
API vec3 editor_pick(float mouse_x, float mouse_y); API vec3 editor_pick(float mouse_x, float mouse_y);
API char* editor_path(const char *path); API char* editor_path(const char *path);
API void editor_setmouse(int x, int y); API void editor_setmouse(int x, int y);
API vec2 editor_glyph(int x, int y, const char *style, unsigned codepoint); API vec2 editor_glyph(int x, int y, const char *style, unsigned codepoint);
API vec2 editor_glyphs(int x, int y, const char *style, const char *utf8); API vec2 editor_glyphs(int x, int y, const char *style, const char *utf8);
API void editor_gizmos(int dim); API void editor_gizmos(int dim);
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// editor loop // editor loop
API int editor_send(const char *cmd); // returns job-id API int editor_send(const char *cmd); // returns job-id
API const char* editor_recv(int jobid, double timeout_ss); API const char* editor_recv(int jobid, double timeout_ss);
API void editor_pump(); API void editor_pump();
API void editor_frame( void (*game)(unsigned, float, double) ); API void editor_frame( void (*game)(unsigned, float, double) );
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// engine section: @todo: expand me // engine section: @todo: expand me
API float* engine_getf(const char *key); API float* engine_getf(const char *key);
API int* engine_geti(const char *key); API int* engine_geti(const char *key);
API char** engine_gets(const char *key); API char** engine_gets(const char *key);
API int engine_send(const char *cmd, const char *optional_value); API int engine_send(const char *cmd, const char *optional_value);
API int ui_engine(); API int ui_engine();

View File

@ -1,390 +1,390 @@
// editing: // editing:
// nope > functions: add/rem property // nope > functions: add/rem property
#define ICON_PLAY ICON_MD_PLAY_ARROW #define ICON_PLAY ICON_MD_PLAY_ARROW
#define ICON_PAUSE ICON_MD_PAUSE #define ICON_PAUSE ICON_MD_PAUSE
#define ICON_STOP ICON_MD_STOP #define ICON_STOP ICON_MD_STOP
#define ICON_CANCEL ICON_MD_CLOSE #define ICON_CANCEL ICON_MD_CLOSE
#define ICON_WARNING ICON_MD_WARNING #define ICON_WARNING ICON_MD_WARNING
#define ICON_BROWSER ICON_MD_FOLDER_SPECIAL #define ICON_BROWSER ICON_MD_FOLDER_SPECIAL
#define ICON_OUTLINER ICON_MD_VIEW_IN_AR #define ICON_OUTLINER ICON_MD_VIEW_IN_AR
#define ICON_BUILD ICON_MD_BUILD #define ICON_BUILD ICON_MD_BUILD
#define ICON_SCREENSHOT ICON_MD_PHOTO_CAMERA #define ICON_SCREENSHOT ICON_MD_PHOTO_CAMERA
#define ICON_CAMERA_ON ICON_MD_VIDEOCAM #define ICON_CAMERA_ON ICON_MD_VIDEOCAM
#define ICON_CAMERA_OFF ICON_MD_VIDEOCAM_OFF #define ICON_CAMERA_OFF ICON_MD_VIDEOCAM_OFF
#define ICON_GAMEPAD_ON ICON_MD_VIDEOGAME_ASSET #define ICON_GAMEPAD_ON ICON_MD_VIDEOGAME_ASSET
#define ICON_GAMEPAD_OFF ICON_MD_VIDEOGAME_ASSET_OFF #define ICON_GAMEPAD_OFF ICON_MD_VIDEOGAME_ASSET_OFF
#define ICON_AUDIO_ON ICON_MD_VOLUME_UP #define ICON_AUDIO_ON ICON_MD_VOLUME_UP
#define ICON_AUDIO_OFF ICON_MD_VOLUME_OFF #define ICON_AUDIO_OFF ICON_MD_VOLUME_OFF
#define ICON_WINDOWED ICON_MD_FULLSCREEN_EXIT #define ICON_WINDOWED ICON_MD_FULLSCREEN_EXIT
#define ICON_FULLSCREEN ICON_MD_FULLSCREEN #define ICON_FULLSCREEN ICON_MD_FULLSCREEN
#define ICON_LIGHTS_ON ICON_MD_LIGHTBULB #define ICON_LIGHTS_ON ICON_MD_LIGHTBULB
#define ICON_LIGHTS_OFF ICON_MD_LIGHTBULB_OUTLINE #define ICON_LIGHTS_OFF ICON_MD_LIGHTBULB_OUTLINE
#define ICON_RENDER_BASIC ICON_MD_IMAGE_SEARCH #define ICON_RENDER_BASIC ICON_MD_IMAGE_SEARCH
#define ICON_RENDER_FULL ICON_MD_INSERT_PHOTO #define ICON_RENDER_FULL ICON_MD_INSERT_PHOTO
#define ICON_SIGNAL ICON_MD_SIGNAL_CELLULAR_ALT #define ICON_SIGNAL ICON_MD_SIGNAL_CELLULAR_ALT
#define ICON_DISK ICON_MD_STORAGE #define ICON_DISK ICON_MD_STORAGE
#define ICON_RATE ICON_MD_SPEED #define ICON_RATE ICON_MD_SPEED
#define ICON_CLOCK ICON_MD_TODAY #define ICON_CLOCK ICON_MD_TODAY
#define ICON_CHRONO ICON_MD_TIMELAPSE #define ICON_CHRONO ICON_MD_TIMELAPSE
#define ICON_SETTINGS ICON_MD_SETTINGS #define ICON_SETTINGS ICON_MD_SETTINGS
#define ICON_LANGUAGE ICON_MD_G_TRANSLATE #define ICON_LANGUAGE ICON_MD_G_TRANSLATE
#define ICON_PERSONA ICON_MD_FACE #define ICON_PERSONA ICON_MD_FACE
#define ICON_SOCIAL ICON_MD_MESSAGE #define ICON_SOCIAL ICON_MD_MESSAGE
#define ICON_GAME ICON_MD_ROCKET_LAUNCH #define ICON_GAME ICON_MD_ROCKET_LAUNCH
#define ICON_KEYBOARD ICON_MD_KEYBOARD #define ICON_KEYBOARD ICON_MD_KEYBOARD
#define ICON_MOUSE ICON_MD_MOUSE #define ICON_MOUSE ICON_MD_MOUSE
#define ICON_GAMEPAD ICON_MD_GAMEPAD #define ICON_GAMEPAD ICON_MD_GAMEPAD
#define ICON_MONITOR ICON_MD_MONITOR #define ICON_MONITOR ICON_MD_MONITOR
#define ICON_WIFI ICON_MD_WIFI #define ICON_WIFI ICON_MD_WIFI
#define ICON_BUDGET ICON_MD_SAVINGS #define ICON_BUDGET ICON_MD_SAVINGS
#define ICON_NEW_FOLDER ICON_MD_CREATE_NEW_FOLDER #define ICON_NEW_FOLDER ICON_MD_CREATE_NEW_FOLDER
#define ICON_PLUGIN ICON_MD_EXTENSION #define ICON_PLUGIN ICON_MD_EXTENSION
#define ICON_RESTART ICON_MD_REPLAY #define ICON_RESTART ICON_MD_REPLAY
#define ICON_QUIT ICON_MD_CLOSE #define ICON_QUIT ICON_MD_CLOSE
#define ICON_POWER ICON_MD_BOLT // ICON_MD_POWER #define ICON_POWER ICON_MD_BOLT // ICON_MD_POWER
#define ICON_BATTERY_CHARGING ICON_MD_BATTERY_CHARGING_FULL #define ICON_BATTERY_CHARGING ICON_MD_BATTERY_CHARGING_FULL
#define ICON_BATTERY_LEVELS \ #define ICON_BATTERY_LEVELS \
ICON_MD_BATTERY_ALERT, \ ICON_MD_BATTERY_ALERT, \
ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, \ ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, \
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR, \ ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR, \
ICON_MD_BATTERY_4_BAR,ICON_MD_BATTERY_5_BAR, \ ICON_MD_BATTERY_4_BAR,ICON_MD_BATTERY_5_BAR, \
ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL
char *editor_path(const char *path) { char *editor_path(const char *path) {
return va("%s/%s", EDITOR, path); return va("%s/%s", EDITOR, path);
} }
vec3 editor_pick(float mouse_x, float mouse_y) { vec3 editor_pick(float mouse_x, float mouse_y) {
#if 0 #if 0
// unproject 2d coord as 3d coord // unproject 2d coord as 3d coord
camera_t *camera = camera_get_active(); camera_t *camera = camera_get_active();
vec3 out, xyd = vec3(mouse_x,window_height()-mouse_y,1); // usually x:mouse_x,y:window_height()-mouse_y,d:0=znear/1=zfar vec3 out, xyd = vec3(mouse_x,window_height()-mouse_y,1); // usually x:mouse_x,y:window_height()-mouse_y,d:0=znear/1=zfar
mat44 mvp, model; identity44(model); multiply44x3(mvp, camera->proj, camera->view, model); mat44 mvp, model; identity44(model); multiply44x3(mvp, camera->proj, camera->view, model);
bool ok = unproject44(&out, xyd, vec4(0,0,window_width(),window_height()), mvp); bool ok = unproject44(&out, xyd, vec4(0,0,window_width(),window_height()), mvp);
return out; return out;
#else #else
// unproject 2d coord as 3d coord // unproject 2d coord as 3d coord
vec2 dpi = ifdef(osx, window_dpi(), vec2(1,1)); vec2 dpi = ifdef(osx, window_dpi(), vec2(1,1));
camera_t *camera = camera_get_active(); camera_t *camera = camera_get_active();
float x = (2.0f * mouse_x) / (dpi.x * window_width()) - 1.0f; float x = (2.0f * mouse_x) / (dpi.x * window_width()) - 1.0f;
float y = 1.0f - (2.0f * mouse_y) / (dpi.y * window_height()); float y = 1.0f - (2.0f * mouse_y) / (dpi.y * window_height());
float z = 1.0f; float z = 1.0f;
vec3 ray_nds = vec3(x, y, z); vec3 ray_nds = vec3(x, y, z);
vec4 ray_clip = vec4(ray_nds.x, ray_nds.y, -1.0, 1.0); vec4 ray_clip = vec4(ray_nds.x, ray_nds.y, -1.0, 1.0);
mat44 inv_proj; invert44(inv_proj, camera->proj); mat44 inv_proj; invert44(inv_proj, camera->proj);
mat44 inv_view; invert44(inv_view, camera->view); mat44 inv_view; invert44(inv_view, camera->view);
vec4 p = transform444(inv_proj, ray_clip); vec4 p = transform444(inv_proj, ray_clip);
vec4 eye = vec4(p.x, p.y, -1.0, 0.0); vec4 eye = vec4(p.x, p.y, -1.0, 0.0);
vec4 wld = norm4(transform444(inv_view, eye)); vec4 wld = norm4(transform444(inv_view, eye));
return vec3(wld.x, wld.y, wld.z); return vec3(wld.x, wld.y, wld.z);
#endif #endif
} }
typedef union engine_var { typedef union engine_var {
int i; int i;
float f; float f;
char *s; char *s;
} engine_var; } engine_var;
static map(char*,engine_var) engine_vars; static map(char*,engine_var) engine_vars;
float *engine_getf(const char *key) { float *engine_getf(const char *key) {
if(!engine_vars) map_init_str(engine_vars); if(!engine_vars) map_init_str(engine_vars);
engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) ); engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
return &found->f; return &found->f;
} }
int *engine_geti(const char *key) { int *engine_geti(const char *key) {
if(!engine_vars) map_init_str(engine_vars); if(!engine_vars) map_init_str(engine_vars);
engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) ); engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
return &found->i; return &found->i;
} }
char **engine_gets(const char *key) { char **engine_gets(const char *key) {
if(!engine_vars) map_init_str(engine_vars); if(!engine_vars) map_init_str(engine_vars);
engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) ); engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
if(!found->s) found->s = stringf("%s",""); if(!found->s) found->s = stringf("%s","");
return &found->s; return &found->s;
} }
int engine_send(const char *cmd, const char *optional_value) { int engine_send(const char *cmd, const char *optional_value) {
unsigned *gamepads = engine_geti("gamepads"); // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)... unsigned *gamepads = engine_geti("gamepads"); // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)...
unsigned *renders = engine_geti("renders"); // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes unsigned *renders = engine_geti("renders"); // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes
float *speed = engine_getf("speed"); // <0 num of frames to advance, 0 paused, [0..1] slomo, 1 play regular speed, >1 fast-forward (x2/x4/x8) float *speed = engine_getf("speed"); // <0 num of frames to advance, 0 paused, [0..1] slomo, 1 play regular speed, >1 fast-forward (x2/x4/x8)
unsigned *powersave = engine_geti("powersave"); unsigned *powersave = engine_geti("powersave");
char *name; char *name;
/**/ if( !strcmp(cmd, "key_quit" )) record_stop(), exit(0); /**/ if( !strcmp(cmd, "key_quit" )) record_stop(), exit(0);
else if( !strcmp(cmd, "key_stop" )) window_pause(1); else if( !strcmp(cmd, "key_stop" )) window_pause(1);
else if( !strcmp(cmd, "key_mute" )) audio_volume_master( 1 ^ !!audio_volume_master(-1) ); else if( !strcmp(cmd, "key_mute" )) audio_volume_master( 1 ^ !!audio_volume_master(-1) );
else if( !strcmp(cmd, "key_pause" )) window_pause( window_has_pause() ^ 1 ); else if( !strcmp(cmd, "key_pause" )) window_pause( window_has_pause() ^ 1 );
else if( !strcmp(cmd, "key_reload" )) window_reload(); else if( !strcmp(cmd, "key_reload" )) window_reload();
else if( !strcmp(cmd, "key_battery" )) *powersave = optional_value ? !!atoi(optional_value) : *powersave ^ 1; else if( !strcmp(cmd, "key_battery" )) *powersave = optional_value ? !!atoi(optional_value) : *powersave ^ 1;
else if( !strcmp(cmd, "key_browser" )) ui_show("File Browser", ui_visible("File Browser") ^ true); else if( !strcmp(cmd, "key_browser" )) ui_show("File Browser", ui_visible("File Browser") ^ true);
else if( !strcmp(cmd, "key_outliner" )) ui_show("Outliner", ui_visible("Outliner") ^ true); else if( !strcmp(cmd, "key_outliner" )) ui_show("Outliner", ui_visible("Outliner") ^ true);
else if( !strcmp(cmd, "key_record" )) if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else else if( !strcmp(cmd, "key_record" )) if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else
app_beep(), name = file_counter(va("%s.mp4",app_name())), window_record(name); app_beep(), name = file_counter(va("%s.mp4",app_name())), window_record(name);
else if( !strcmp(cmd, "key_screenshot" )) name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string()); else if( !strcmp(cmd, "key_screenshot" )) name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string());
else if( !strcmp(cmd, "key_profiler" )) ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true)); else if( !strcmp(cmd, "key_profiler" )) ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true));
else if( !strcmp(cmd, "key_fullscreen" )) record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand else if( !strcmp(cmd, "key_fullscreen" )) record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand
else if( !strcmp(cmd, "key_gamepad" )) *gamepads = (*gamepads & ~1u) | ((*gamepads & 1) ^ 1); else if( !strcmp(cmd, "key_gamepad" )) *gamepads = (*gamepads & ~1u) | ((*gamepads & 1) ^ 1);
else if( !strcmp(cmd, "key_lit" )) *renders = (*renders & ~1u) | ((*renders & 1) ^ 1); else if( !strcmp(cmd, "key_lit" )) *renders = (*renders & ~1u) | ((*renders & 1) ^ 1);
else if( !strcmp(cmd, "key_ddraw" )) *renders = (*renders & ~2u) | ((*renders & 2) ^ 2); else if( !strcmp(cmd, "key_ddraw" )) *renders = (*renders & ~2u) | ((*renders & 2) ^ 2);
else alert(va("editor could not handle `%s` command.", cmd)); else alert(va("editor could not handle `%s` command.", cmd));
return 0; return 0;
} }
int engine_tick() { int engine_tick() {
enum { engine_hz_mid = 30 }; enum { engine_hz_mid = 30 };
enum { engine_hz_low = 10 }; enum { engine_hz_low = 10 };
static double old_hz = 0.0; static double old_hz = 0.0;
if( *engine_geti("powersave") ) { if( *engine_geti("powersave") ) {
// adaptive framerate // adaptive framerate
int app_on_background = !window_has_focus(); int app_on_background = !window_has_focus();
int hz = app_on_background ? engine_hz_low : engine_hz_mid; int hz = app_on_background ? engine_hz_low : engine_hz_mid;
if (!old_hz) old_hz = window_fps_target(); if (!old_hz) old_hz = window_fps_target();
window_fps_lock( hz ); window_fps_lock( hz );
} else if( old_hz && old_hz != window_fps_target() ) { } else if( old_hz && old_hz != window_fps_target() ) {
window_fps_lock( old_hz ); window_fps_lock( old_hz );
old_hz = 0.0; old_hz = 0.0;
} }
return 0; return 0;
} }
int ui_engine() { int ui_engine() {
static int time_factor = 0; static int time_factor = 0;
static int playing = 0; static int playing = 0;
static int paused = 0; static int paused = 0;
int advance_frame = 0; int advance_frame = 0;
#if 0 #if 0
static int do_filter = 0; static int do_filter = 0;
static int do_profile = 0; static int do_profile = 0;
static int do_extra = 0; static int do_extra = 0;
char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s", char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s",
do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH, do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH,
ICON_MD_PLAY_ARROW, ICON_MD_PLAY_ARROW,
paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE, paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE,
ICON_MD_FAST_FORWARD, ICON_MD_FAST_FORWARD,
ICON_MD_STOP, ICON_MD_STOP,
ICON_MD_REPLAY, ICON_MD_REPLAY,
ICON_MD_FACE, ICON_MD_FACE,
ICON_MD_MENU ICON_MD_MENU
); );
if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS); int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS);
if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0; if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0;
if( choice == 2 ) playing = 1, paused = 0; if( choice == 2 ) playing = 1, paused = 0;
if( choice == 3 ) advance_frame = !!paused, paused = 1; if( choice == 3 ) advance_frame = !!paused, paused = 1;
if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4; if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4;
if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0; if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0;
if( choice == 6 ) window_reload(); if( choice == 6 ) window_reload();
if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0; if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0;
if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1; if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1;
if( do_filter ) { if( do_filter ) {
char *bak = ui_filter; ui_filter = 0; char *bak = ui_filter; ui_filter = 0;
ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak); ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak);
ui_filter = bak; ui_filter = bak;
if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
do_filter = 0; do_filter = 0;
} }
} else { } else {
if( ui_filter ) ui_filter[0] = '\0'; if( ui_filter ) ui_filter[0] = '\0';
} }
char *filter_mask = ui_filter && ui_filter[0] ? va("*%s*", ui_filter) : "*"; char *filter_mask = ui_filter && ui_filter[0] ? va("*%s*", ui_filter) : "*";
static char *username = 0; static char *username = 0;
static char *userpass = 0; static char *userpass = 0;
if( do_profile ) { if( do_profile ) {
ui_string(ICON_MD_FACE " Username", &username); ui_string(ICON_MD_FACE " Username", &username);
ui_string(ICON_MD_FACE " Password", &userpass); ui_string(ICON_MD_FACE " Password", &userpass);
} }
if( do_extra ) { if( do_extra ) {
int choice2 = ui_label2_toolbar(NULL, int choice2 = ui_label2_toolbar(NULL,
ICON_MD_VIEW_IN_AR ICON_MD_VIEW_IN_AR
ICON_MD_MESSAGE ICON_MD_MESSAGE
ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE
ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO
ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF
ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0 ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0
ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU
); );
} }
#endif #endif
int open = 0, clicked_or_toggled = 0; int open = 0, clicked_or_toggled = 0;
#define EDITOR_UI_COLLAPSE(f,...) \ #define EDITOR_UI_COLLAPSE(f,...) \
for( int macro(p) = (open = ui_collapse(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0) for( int macro(p) = (open = ui_collapse(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0)
EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " Windows", "Debug.Windows") { EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " Windows", "Debug.Windows") {
int choice = ui_toolbar(ICON_MD_RECYCLING "@Reset layout;" ICON_MD_SAVE_AS "@Save layout"); int choice = ui_toolbar(ICON_MD_RECYCLING "@Reset layout;" ICON_MD_SAVE_AS "@Save layout");
if( choice == 1 ) ui_layout_all_reset("*"); if( choice == 1 ) ui_layout_all_reset("*");
if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*");
for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) { for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) {
bool visible = ui_visible(*k); bool visible = ui_visible(*k);
if( ui_bool( *k, &visible ) ) { if( ui_bool( *k, &visible ) ) {
ui_show( *k, ui_visible(*k) ^ true ); ui_show( *k, ui_visible(*k) ^ true );
} }
} }
} }
EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") { EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") {
// @todo. parse /bugs.ini, includes saved screenshots & videos. // @todo. parse /bugs.ini, includes saved screenshots & videos.
// @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini) // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini)
} }
// Art and bookmarks // Art and bookmarks
EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") { EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") {
bool inlined = true; bool inlined = true;
const char *file = 0; const char *file = 0;
if( ui_browse(&file, &inlined) ) { if( ui_browse(&file, &inlined) ) {
const char *sep = ifdef(win32, "\"", "'"); const char *sep = ifdef(win32, "\"", "'");
app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
} }
} }
EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ } EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ }
// E,C,S,W // E,C,S,W
EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") { EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") {
EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ } EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ } EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ } EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ }
EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") { EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") {
//node_edit(editor.edit.down,&editor.edit); //node_edit(editor.edit.down,&editor.edit);
} }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ } //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ } //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ } //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ } //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ }
//EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ } //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ }
// node_edit(&editor.init,&editor.init); // node_edit(&editor.init,&editor.init);
// node_edit(&editor.draw,&editor.draw); // node_edit(&editor.draw,&editor.draw);
// node_edit(&editor.tick,&editor.tick); // node_edit(&editor.tick,&editor.tick);
// node_edit(&editor.edit,&editor.edit); // node_edit(&editor.edit,&editor.edit);
// node_edit(&editor.quit,&editor.quit); // node_edit(&editor.quit,&editor.quit);
} }
EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") { EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") {
// @todo // @todo
} }
EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") { EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") {
ui_audio(); ui_audio();
} }
EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") { EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") {
ui_camera( camera_get_active() ); ui_camera( camera_get_active() );
} }
EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") { EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") {
// @todo: fps lock, fps target, aspect ratio, fullscreen // @todo: fps lock, fps target, aspect ratio, fullscreen
char *text = va("%s;%s;%s", char *text = va("%s;%s;%s",
window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN, window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN,
ICON_MD_PHOTO_CAMERA, ICON_MD_PHOTO_CAMERA,
record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM
); );
int choice = ui_toolbar(text); int choice = ui_toolbar(text);
if( choice == 1 ) engine_send("key_fullscreen",0); if( choice == 1 ) engine_send("key_fullscreen",0);
if( choice == 2 ) engine_send("key_screenshot",0); if( choice == 2 ) engine_send("key_screenshot",0);
if( choice == 3 ) engine_send("key_record",0); if( choice == 3 ) engine_send("key_record",0);
} }
EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") { EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") {
ui_keyboard(); ui_keyboard();
} }
EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") { EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") {
ui_mouse(); ui_mouse();
} }
EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") { EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") {
for( int q = 0; q < 4; ++q ) { for( int q = 0; q < 4; ++q ) {
for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) {
ui_gamepad(q); ui_gamepad(q);
} }
} }
} }
EDITOR_UI_COLLAPSE(ICON_MD_TEXT_FIELDS " Fonts", "Debug.Fonts") { EDITOR_UI_COLLAPSE(ICON_MD_TEXT_FIELDS " Fonts", "Debug.Fonts") {
ui_font(); ui_font();
} }
EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") { EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") {
// @todo // @todo
} }
EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") { EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") {
ui_shaders(); ui_shaders();
} }
EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") { EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") {
ui_fxs(); ui_fxs();
} }
EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") { EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") {
// @todo. // mem,fps,gfx,net,hdd,... also logging // @todo. // mem,fps,gfx,net,hdd,... also logging
} }
EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") { EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") {
// @todo // @todo
// SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR
} }
EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") { EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") {
ui_profiler(); ui_profiler();
} }
EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") { EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") {
// @todo // @todo
} }
// logic: either plug icon (power saving off) or one of the following ones (power saving on): // logic: either plug icon (power saving off) or one of the following ones (power saving on):
// if 0% batt (no batt): battery alert // if 0% batt (no batt): battery alert
// if discharging: battery levels [alert,0..6,full] // if discharging: battery levels [alert,0..6,full]
// if charging: battery charging // if charging: battery charging
int battery_read = app_battery(); int battery_read = app_battery();
int battery_level = abs(battery_read); int battery_level = abs(battery_read);
int battery_discharging = battery_read < 0 && battery_level < 100; int battery_discharging = battery_read < 0 && battery_level < 100;
const char *power_icon_label = ICON_MD_POWER " Power"; const char *power_icon_label = ICON_MD_POWER " Power";
if( battery_level ) { if( battery_level ) {
const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ? const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ?
ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR,
ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR, ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR,
ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL, ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL,
}; };
power_icon_label = (const char*)va("%s Power %d%%", power_icon_label = (const char*)va("%s Power %d%%",
battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL, battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL,
battery_level); battery_level);
} }
EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") { EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") {
int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT ); int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT );
if( choice == 1 ) engine_send("key_battery","0"); if( choice == 1 ) engine_send("key_battery","0");
if( choice == 2 ) engine_send("key_battery","1"); if( choice == 2 ) engine_send("key_battery","1");
} }
EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") { EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") {
ui_reflect("*"); ui_reflect("*");
} }
EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") { EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") {
// @todo. include VCS // @todo. include VCS
EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") { EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") {
// @todo // @todo
} }
} }
return 0; return 0;
} }

View File

@ -1,21 +1,21 @@
#define BROWSER_ICON ICON_MD_FOLDER_SPECIAL #define BROWSER_ICON ICON_MD_FOLDER_SPECIAL
#define BROWSER_TITLE "Browser " BROWSER_ICON #define BROWSER_TITLE "Browser " BROWSER_ICON
EDITOR_BIND(browser, "held(CTRL)&down(2)", { ui_show(BROWSER_TITLE, ui_visible(BROWSER_TITLE) ^ true); }); EDITOR_BIND(browser, "held(CTRL)&down(2)", { ui_show(BROWSER_TITLE, ui_visible(BROWSER_TITLE) ^ true); });
int editor_browser(int window_mode) { int editor_browser(int window_mode) {
window_mode = EDITOR_WINDOW; // force window window_mode = EDITOR_WINDOW; // force window
if( editor_begin(BROWSER_TITLE, window_mode) ) { if( editor_begin(BROWSER_TITLE, window_mode) ) {
const char *file = 0; const char *file = 0;
if( ui_browse(&file, NULL) ) { if( ui_browse(&file, NULL) ) {
const char *sep = ifdef(win32, "\"", "'"); const char *sep = ifdef(win32, "\"", "'");
app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
} }
editor_end(window_mode); editor_end(window_mode);
} }
return 0; return 0;
} }
AUTORUN { AUTORUN {
array_push(editor.subeditors, editor_browser); array_push(editor.subeditors, editor_browser);
} }

View File

@ -1,56 +1,56 @@
#define CONSOLE_ICON ICON_MDI_CONSOLE #define CONSOLE_ICON ICON_MDI_CONSOLE
#define CONSOLE_TITLE "Console " CONSOLE_ICON #define CONSOLE_TITLE "Console " CONSOLE_ICON
EDITOR_BIND(console, "held(CTRL)&down(4)", { ui_show(CONSOLE_TITLE, ui_visible(CONSOLE_TITLE) ^ true); }); EDITOR_BIND(console, "held(CTRL)&down(4)", { ui_show(CONSOLE_TITLE, ui_visible(CONSOLE_TITLE) ^ true); });
int editor_console(int window_mode) { int editor_console(int window_mode) {
if( editor_begin(CONSOLE_TITLE, window_mode) ) { if( editor_begin(CONSOLE_TITLE, window_mode) ) {
// peek complete window space // peek complete window space
struct nk_rect bounds = nk_window_get_content_region(ui_ctx); struct nk_rect bounds = nk_window_get_content_region(ui_ctx);
enum { CONSOLE_LINE_HEIGHT = 20 }; enum { CONSOLE_LINE_HEIGHT = 20 };
static array(char*) lines = 0; static array(char*) lines = 0;
do_once { do_once {
array_push(lines, stringf("> Editor v%s. Type `%s` for help.", EDITOR_VERSION, "")); array_push(lines, stringf("> Editor v%s. Type `%s` for help.", EDITOR_VERSION, ""));
} }
int max_lines = (bounds.h - UI_ROW_HEIGHT) / (CONSOLE_LINE_HEIGHT * 2); int max_lines = (bounds.h - UI_ROW_HEIGHT) / (CONSOLE_LINE_HEIGHT * 2);
if( max_lines >= 1 ) { if( max_lines >= 1 ) {
nk_layout_row_static(ui_ctx, bounds.h - UI_ROW_HEIGHT, bounds.w, 1); nk_layout_row_static(ui_ctx, bounds.h - UI_ROW_HEIGHT, bounds.w, 1);
if(nk_group_begin(ui_ctx, "console.group", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) { if(nk_group_begin(ui_ctx, "console.group", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
nk_layout_row_static(ui_ctx, CONSOLE_LINE_HEIGHT, bounds.w, 1); nk_layout_row_static(ui_ctx, CONSOLE_LINE_HEIGHT, bounds.w, 1);
for( int i = array_count(lines); i < max_lines; ++i ) for( int i = array_count(lines); i < max_lines; ++i )
array_push_front(lines, 0); array_push_front(lines, 0);
for( int i = array_count(lines) - max_lines; i < array_count(lines); ++i ) { for( int i = array_count(lines) - max_lines; i < array_count(lines); ++i ) {
if( !lines[i] ) { if( !lines[i] ) {
#if 0 // debug #if 0 // debug
nk_label_wrap(ui_ctx, va("%d.A/%d",i+1,max_lines)); nk_label_wrap(ui_ctx, va("%d.A/%d",i+1,max_lines));
nk_label_wrap(ui_ctx, va("%d.B/%d",i+1,max_lines)); nk_label_wrap(ui_ctx, va("%d.B/%d",i+1,max_lines));
#else #else
nk_label_wrap(ui_ctx, ""); nk_label_wrap(ui_ctx, "");
nk_label_wrap(ui_ctx, ""); nk_label_wrap(ui_ctx, "");
#endif #endif
} else { } else {
nk_label_wrap(ui_ctx, lines[i]); nk_label_wrap(ui_ctx, lines[i]);
const char *answer = isdigit(*lines[i]) ? editor_recv( atoi(lines[i]), 0 ) : NULL; const char *answer = isdigit(*lines[i]) ? editor_recv( atoi(lines[i]), 0 ) : NULL;
nk_label_wrap(ui_ctx, answer ? answer : ""); nk_label_wrap(ui_ctx, answer ? answer : "");
} }
} }
nk_group_end(ui_ctx); nk_group_end(ui_ctx);
} }
} }
static char *cmd = 0; static char *cmd = 0;
if( ui_string(NULL, &cmd) ) { if( ui_string(NULL, &cmd) ) {
int jobid = editor_send(cmd); int jobid = editor_send(cmd);
array_push(lines, stringf("%d> %s", jobid, cmd)); array_push(lines, stringf("%d> %s", jobid, cmd));
cmd[0] = 0; cmd[0] = 0;
} }
editor_end(window_mode); editor_end(window_mode);
} }
return 0; return 0;
} }
AUTORUN { AUTORUN {
array_push(editor.subeditors, editor_console); array_push(editor.subeditors, editor_console);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,180 +1,180 @@
#define SCENE_ICON ICON_MDI_FILE_TREE #define SCENE_ICON ICON_MDI_FILE_TREE
#define SCENE_TITLE "Scene " SCENE_ICON #define SCENE_TITLE "Scene " SCENE_ICON
EDITOR_BIND(scene, "held(CTRL)&down(1)", { ui_show(SCENE_TITLE, ui_visible(SCENE_TITLE) ^ true); }); EDITOR_BIND(scene, "held(CTRL)&down(1)", { ui_show(SCENE_TITLE, ui_visible(SCENE_TITLE) ^ true); });
EDITOR_BIND(node_new, "down(INS)", { editor_spawn1(); } ); EDITOR_BIND(node_new, "down(INS)", { editor_spawn1(); } );
EDITOR_BIND(node_del, "down(DEL)", { editor_destroy_selected(); } ); EDITOR_BIND(node_del, "down(DEL)", { editor_destroy_selected(); } );
EDITOR_BIND(node_save, "held(CTRL)&down(S)", { puts("@todo"); } ); EDITOR_BIND(node_save, "held(CTRL)&down(S)", { puts("@todo"); } );
EDITOR_BIND(scene_save, "held(CTRL)&down(S)&held(SHIFT)",{ puts("@todo"); } ); EDITOR_BIND(scene_save, "held(CTRL)&down(S)&held(SHIFT)",{ puts("@todo"); } );
EDITOR_BIND(select_all, "held(CTRL) & down(A)", { editor_select("**"); } ); EDITOR_BIND(select_all, "held(CTRL) & down(A)", { editor_select("**"); } );
EDITOR_BIND(select_none, "held(CTRL) & down(D)", { editor_select("!**"); } ); EDITOR_BIND(select_none, "held(CTRL) & down(D)", { editor_select("!**"); } );
EDITOR_BIND(select_invert, "held(CTRL) & down(I)", { editor_select("~**"); } ); EDITOR_BIND(select_invert, "held(CTRL) & down(I)", { editor_select("~**"); } );
EDITOR_BIND(bookmark, "held(CTRL) & down(B)", { editor_selected_map_t *map = editor_selected_map(); \ EDITOR_BIND(bookmark, "held(CTRL) & down(B)", { editor_selected_map_t *map = editor_selected_map(); \
int on = 0; \ int on = 0; \
for each_map_ptr(*map,void*,o,int,selected) if(*selected) on |= !editor_bookmarked(*o); \ for each_map_ptr(*map,void*,o,int,selected) if(*selected) on |= !editor_bookmarked(*o); \
for each_map_ptr(*map,void*,o,int,selected) if(*selected) editor_setbookmarked(*o, on); \ for each_map_ptr(*map,void*,o,int,selected) if(*selected) editor_setbookmarked(*o, on); \
} ); } );
enum { enum {
SCENE_RECURSE = 1, SCENE_RECURSE = 1,
SCENE_SELECTION = 2, SCENE_SELECTION = 2,
SCENE_CHECKBOX = 4, SCENE_CHECKBOX = 4,
SCENE_INDENT = 8, SCENE_INDENT = 8,
SCENE_ALL = ~0u SCENE_ALL = ~0u
}; };
static static
void editor_scene_(obj *o, unsigned flags) { void editor_scene_(obj *o, unsigned flags) {
static unsigned tabs = ~0u; static unsigned tabs = ~0u;
++tabs; ++tabs;
if( o ) { if( o ) {
unsigned do_tags = 1; unsigned do_tags = 1;
unsigned do_indent = !!(flags & SCENE_INDENT); unsigned do_indent = !!(flags & SCENE_INDENT);
unsigned do_checkbox = !!(flags & SCENE_CHECKBOX); unsigned do_checkbox = !!(flags & SCENE_CHECKBOX);
unsigned do_recurse = !!(flags & SCENE_RECURSE); unsigned do_recurse = !!(flags & SCENE_RECURSE);
unsigned do_selection = !!(flags & SCENE_SELECTION); unsigned do_selection = !!(flags & SCENE_SELECTION);
nk_layout_row_dynamic(ui_ctx, 25, 1); nk_layout_row_dynamic(ui_ctx, 25, 1);
const char *objicon = editor_iconinstance(o); const char *objicon = editor_iconinstance(o);
if(!objicon) objicon = editor_iconclass(obj_type(o)); if(!objicon) objicon = editor_iconclass(obj_type(o));
if(!objicon) objicon = ICON_MDI_CUBE_OUTLINE; if(!objicon) objicon = ICON_MDI_CUBE_OUTLINE;
const char *objname = va("%s (%s)", obj_type(o), obj_name(o)); const char *objname = va("%s (%s)", obj_type(o), obj_name(o));
const char *objchevron = const char *objchevron =
!do_recurse || array_count(*obj_children(o)) <= 1 ? ICON_MDI_CIRCLE_SMALL : !do_recurse || array_count(*obj_children(o)) <= 1 ? ICON_MDI_CIRCLE_SMALL :
editor_open(o) ? ICON_MDI_CHEVRON_DOWN : ICON_MDI_CHEVRON_RIGHT; editor_open(o) ? ICON_MDI_CHEVRON_DOWN : ICON_MDI_CHEVRON_RIGHT;
char *label = va("%*s%s%s %s", do_indent*(4+2*tabs), "", objchevron, objicon, objname); char *label = va("%*s%s%s %s", do_indent*(4+2*tabs), "", objchevron, objicon, objname);
const char *iconsL = const char *iconsL =
//editor_selected(o) ? ICON_MD_CHECK_BOX : ICON_MD_CHECK_BOX_OUTLINE_BLANK; //editor_selected(o) ? ICON_MD_CHECK_BOX : ICON_MD_CHECK_BOX_OUTLINE_BLANK;
editor_selected(o) ? ICON_MDI_CHECKBOX_MARKED : ICON_MDI_CHECKBOX_BLANK_OUTLINE; editor_selected(o) ? ICON_MDI_CHECKBOX_MARKED : ICON_MDI_CHECKBOX_BLANK_OUTLINE;
const char *iconsR = va("%s%s%s", const char *iconsR = va("%s%s%s",
editor_script(o) ? ICON_MDI_SCRIPT : ICON_MDI_CIRCLE_SMALL, editor_script(o) ? ICON_MDI_SCRIPT : ICON_MDI_CIRCLE_SMALL,
editor_event(o) ? ICON_MDI_CALENDAR : ICON_MDI_CIRCLE_SMALL, editor_event(o) ? ICON_MDI_CALENDAR : ICON_MDI_CIRCLE_SMALL,
editor_visible(o) ? ICON_MDI_EYE_OUTLINE : ICON_MDI_EYE_CLOSED ); editor_visible(o) ? ICON_MDI_EYE_OUTLINE : ICON_MDI_EYE_CLOSED );
UI_TOOLBAR_OVERLAY_DECLARE(int choiceL, choiceR); UI_TOOLBAR_OVERLAY_DECLARE(int choiceL, choiceR);
struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx); struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx); struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx);
int clicked = nk_hovered_text(ui_ctx, label, strlen(label), NK_TEXT_LEFT, editor_selected(o)); int clicked = nk_hovered_text(ui_ctx, label, strlen(label), NK_TEXT_LEFT, editor_selected(o));
if( clicked && nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,bounds.w*0.66,bounds.h })) ) if( clicked && nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,bounds.w*0.66,bounds.h })) )
editor_altselected( o ); editor_altselected( o );
vec2i offset_in_tree = {0}; vec2i offset_in_tree = {0};
if( do_indent ) { if( do_indent ) {
float thickness = 2.f; float thickness = 2.f;
struct nk_color color = {255,255,255,64}; struct nk_color color = {255,255,255,64};
int offsx = 30; int offsx = 30;
int spacx = 10; int spacx = 10;
int lenx = (tabs+1)*spacx; int lenx = (tabs+1)*spacx;
int halfy = bounds.h / 2; int halfy = bounds.h / 2;
int offsy = halfy + 2; int offsy = halfy + 2;
offset_in_tree = vec2i(bounds.x+offsx+lenx-spacx,bounds.y+offsy); offset_in_tree = vec2i(bounds.x+offsx+lenx-spacx,bounds.y+offsy);
editor_settreeoffsety(o, offset_in_tree.y); editor_settreeoffsety(o, offset_in_tree.y);
for( obj *p = obj_parent(o); p ; p = 0 ) for( obj *p = obj_parent(o); p ; p = 0 )
nk_stroke_line(canvas, offset_in_tree.x-6,offset_in_tree.y, offset_in_tree.x-spacx,offset_in_tree.y, thickness, color), nk_stroke_line(canvas, offset_in_tree.x-6,offset_in_tree.y, offset_in_tree.x-spacx,offset_in_tree.y, thickness, color),
nk_stroke_line(canvas, offset_in_tree.x-spacx,offset_in_tree.y,offset_in_tree.x-spacx,editor_treeoffsety(p)+4, thickness, color); nk_stroke_line(canvas, offset_in_tree.x-spacx,offset_in_tree.y,offset_in_tree.x-spacx,editor_treeoffsety(p)+4, thickness, color);
} }
if( ui_contextual() ) { if( ui_contextual() ) {
int choice = ui_label(ICON_MD_BOOKMARK_ADDED "Toggle bookmarks (CTRL+B)"); int choice = ui_label(ICON_MD_BOOKMARK_ADDED "Toggle bookmarks (CTRL+B)");
if( choice & 1 ) editor_send("bookmark"); if( choice & 1 ) editor_send("bookmark");
ui_contextual_end(!!choice); ui_contextual_end(!!choice);
} }
UI_TOOLBAR_OVERLAY(choiceL,iconsL,nk_rgba_f(1,1,1,do_checkbox*ui_alpha*0.65),NK_TEXT_LEFT); UI_TOOLBAR_OVERLAY(choiceL,iconsL,nk_rgba_f(1,1,1,do_checkbox*ui_alpha*0.65),NK_TEXT_LEFT);
if( do_tags ) if( do_tags )
UI_TOOLBAR_OVERLAY(choiceR,iconsR,nk_rgba_f(1,1,1,ui_alpha*0.65),NK_TEXT_RIGHT); UI_TOOLBAR_OVERLAY(choiceR,iconsR,nk_rgba_f(1,1,1,ui_alpha*0.65),NK_TEXT_RIGHT);
if( choiceR == 3 ) editor_altscript( o ); if( choiceR == 3 ) editor_altscript( o );
if( choiceR == 2 ) editor_altevent( o); if( choiceR == 2 ) editor_altevent( o);
if( choiceR == 1 ) editor_altvisible( o ); if( choiceR == 1 ) editor_altvisible( o );
if( do_recurse && editor_open(o) ) { if( do_recurse && editor_open(o) ) {
for each_objchild(o,obj*,oo) { for each_objchild(o,obj*,oo) {
editor_scene_(oo,flags); editor_scene_(oo,flags);
} }
} }
if( clicked && !choiceL && !choiceR ) { if( clicked && !choiceL && !choiceR ) {
int is_picking = input(KEY_CTRL); int is_picking = input(KEY_CTRL);
if( !is_picking ) { if( !is_picking ) {
if( input(KEY_SHIFT) ) { if( input(KEY_SHIFT) ) {
editor_selectgroup( editor_first_selected(), editor_last_selected() ); editor_selectgroup( editor_first_selected(), editor_last_selected() );
} else { } else {
editor_unselect(); editor_unselect();
editor_setselected(o, 1); editor_setselected(o, 1);
} }
} }
for( obj *p = obj_parent(o); p; p = obj_parent(p) ) { for( obj *p = obj_parent(o); p; p = obj_parent(p) ) {
editor_setopen(p, 1); editor_setopen(p, 1);
} }
if( nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,offset_in_tree.x-bounds.x+UI_ICON_FONTSIZE/2,bounds.h })) ) { if( nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,offset_in_tree.x-bounds.x+UI_ICON_FONTSIZE/2,bounds.h })) ) {
editor_altopen( o ); editor_altopen( o );
} }
} }
} }
--tabs; --tabs;
} }
int editor_scene(int window_mode) { int editor_scene(int window_mode) {
window_mode = EDITOR_WINDOW; // force window window_mode = EDITOR_WINDOW; // force window
if( editor_begin(SCENE_TITLE, window_mode)) { if( editor_begin(SCENE_TITLE, window_mode)) {
// #define HELP ICON_MDI_INFORMATION_OUTLINE "@-A\n-B\n-C\n" ";" // #define HELP ICON_MDI_INFORMATION_OUTLINE "@-A\n-B\n-C\n" ";"
int choice = ui_toolbar(ICON_MDI_PLUS "@New node (CTRL+N);" ICON_MDI_DOWNLOAD "@Save node (CTRL+S);" ICON_MDI_DOWNLOAD "@Save scene (SHIFT+CTRL+S);" ICON_MD_BOOKMARK_ADDED "@Toggle Bookmark (CTRL+B);"); int choice = ui_toolbar(ICON_MDI_PLUS "@New node (CTRL+N);" ICON_MDI_DOWNLOAD "@Save node (CTRL+S);" ICON_MDI_DOWNLOAD "@Save scene (SHIFT+CTRL+S);" ICON_MD_BOOKMARK_ADDED "@Toggle Bookmark (CTRL+B);");
if( choice == 1 ) editor_send("node_new"); if( choice == 1 ) editor_send("node_new");
if( choice == 2 ) editor_send("node_save"); if( choice == 2 ) editor_send("node_save");
if( choice == 3 ) editor_send("scene_save"); if( choice == 3 ) editor_send("scene_save");
if( choice == 4 ) editor_send("bookmark"); if( choice == 4 ) editor_send("bookmark");
array(obj*) bookmarks = 0; array(obj*) bookmarks = 0;
for each_map_ptr(*editor_bookmarked_map(), void*,o,int,bookmarked) { for each_map_ptr(*editor_bookmarked_map(), void*,o,int,bookmarked) {
if( *bookmarked ) { if( *bookmarked ) {
array_push(bookmarks, *o); array_push(bookmarks, *o);
} }
} }
if( ui_collapse("!" ICON_MD_BOOKMARK "Bookmarks", "DEBUG:BOOKMARK")) { if( ui_collapse("!" ICON_MD_BOOKMARK "Bookmarks", "DEBUG:BOOKMARK")) {
for each_array( bookmarks, obj*, o ) for each_array( bookmarks, obj*, o )
editor_scene_( o, SCENE_ALL & ~(SCENE_RECURSE|SCENE_INDENT|SCENE_CHECKBOX) ); editor_scene_( o, SCENE_ALL & ~(SCENE_RECURSE|SCENE_INDENT|SCENE_CHECKBOX) );
ui_collapse_end(); ui_collapse_end();
} }
array_free(bookmarks); array_free(bookmarks);
editor_scene_( editor.root, SCENE_ALL ); editor_scene_( editor.root, SCENE_ALL );
for each_array( editor.objs, obj*, o ) for each_array( editor.objs, obj*, o )
editor_scene_( o, SCENE_ALL ); editor_scene_( o, SCENE_ALL );
ui_separator(); ui_separator();
// edit selection // edit selection
for each_map(*editor_selected_map(), void*,o, int, k) { for each_map(*editor_selected_map(), void*,o, int, k) {
if( k ) editor_inspect(o); if( k ) editor_inspect(o);
} }
editor_end(window_mode); editor_end(window_mode);
} }
return 0; return 0;
} }
AUTORUN { AUTORUN {
array_push(editor.subeditors, editor_scene); array_push(editor.subeditors, editor_scene);
} }

View File

@ -1,79 +1,79 @@
int ui_texture_fit(texture_t t, struct nk_rect bounds) { int ui_texture_fit(texture_t t, struct nk_rect bounds) {
// allocate complete window space // allocate complete window space
struct nk_rect total_space = nk_window_get_content_region(ui_ctx); struct nk_rect total_space = nk_window_get_content_region(ui_ctx);
nk_layout_space_begin(ui_ctx, NK_DYNAMIC, total_space.h - 4, 1); // -4 to hide scrollbar Y nk_layout_space_begin(ui_ctx, NK_DYNAMIC, total_space.h - 4, 1); // -4 to hide scrollbar Y
nk_layout_space_push(ui_ctx, nk_rect(0,0,1,1)); nk_layout_space_push(ui_ctx, nk_rect(0,0,1,1));
struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx); struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
struct nk_image image = nk_image_id((int)t.id); struct nk_image image = nk_image_id((int)t.id);
nk_draw_image(canvas, bounds, &image, nk_white); nk_draw_image(canvas, bounds, &image, nk_white);
nk_layout_space_end(ui_ctx); nk_layout_space_end(ui_ctx);
return 0; return 0;
} }
#define LITE_ICON ICON_MDI_SCRIPT_TEXT #define LITE_ICON ICON_MDI_SCRIPT_TEXT
#define LITE_TITLE "Script " LITE_ICON #define LITE_TITLE "Script " LITE_ICON
EDITOR_BIND(script, "held(CTRL)&down(6)", { ui_show(LITE_TITLE, ui_visible(LITE_TITLE) ^ true); }); EDITOR_BIND(script, "held(CTRL)&down(6)", { ui_show(LITE_TITLE, ui_visible(LITE_TITLE) ^ true); });
int editor_scripted(int window_mode) { int editor_scripted(int window_mode) {
window_mode = EDITOR_WINDOW; // force mode window_mode = EDITOR_WINDOW; // force mode
static lua_State *L = 0; static lua_State *L = 0;
do_once { do_once {
L = script_init_env(SCRIPT_LUA|SCRIPT_DEBUGGER); L = script_init_env(SCRIPT_LUA|SCRIPT_DEBUGGER);
const char *platform = "" // "Android" "FreeBSD" "OpenBSD" "NetBSD" const char *platform = "" // "Android" "FreeBSD" "OpenBSD" "NetBSD"
ifdef(ems, "Emscripten") ifdef(ems, "Emscripten")
ifdef(linux, "Linux") ifdef(linux, "Linux")
ifdef(osx, "macOS") ifdef(osx, "macOS")
ifdef(win32, "Windows") ifdef(win32, "Windows")
; ;
const char *pathexe = vac("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", "")); const char *pathexe = vac("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", ""));
gleqInit(); gleqInit();
gleqTrackWindow(window_handle()); gleqTrackWindow(window_handle());
lt_init(L, window_handle(), LT_DATAPATH, __argc, __argv, window_scale(), platform, pathexe); lt_init(L, window_handle(), LT_DATAPATH, __argc, __argv, window_scale(), platform, pathexe);
} }
unsigned lt_none = 0u; unsigned lt_none = 0u;
unsigned lt_all = ~0u & ~(GLEQ_WINDOW_MOVED/*|GLEQ_WINDOW_RESIZED|GLEQ_WINDOW_REFRESH*/); unsigned lt_all = ~0u & ~(GLEQ_WINDOW_MOVED/*|GLEQ_WINDOW_RESIZED|GLEQ_WINDOW_REFRESH*/);
lt_events = lt_none; lt_events = lt_none;
int mouse_in_rect = 0; int mouse_in_rect = 0;
if( editor_begin(LITE_TITLE, window_mode) ) { if( editor_begin(LITE_TITLE, window_mode) ) {
lt_events = lt_all; lt_events = lt_all;
if( !nk_window_has_focus(ui_ctx) ) lt_events = lt_none; if( !nk_window_has_focus(ui_ctx) ) lt_events = lt_none;
struct nk_rect bounds = nk_window_get_content_region(ui_ctx); struct nk_rect bounds = nk_window_get_content_region(ui_ctx);
lt_mx = input(MOUSE_X) - bounds.x; lt_mx = input(MOUSE_X) - bounds.x;
lt_my = input(MOUSE_Y) - bounds.y; lt_my = input(MOUSE_Y) - bounds.y;
lt_wx = bounds.x; lt_wx = bounds.x;
lt_wy = bounds.y; lt_wy = bounds.y;
lt_ww = bounds.w; lt_ww = bounds.w;
lt_wh = bounds.h; lt_wh = bounds.h;
if( lt_resizesurface(lt_getsurface(0), lt_ww, lt_wh) ) { if( lt_resizesurface(lt_getsurface(0), lt_ww, lt_wh) ) {
gleq_window_refresh_callback(window_handle()); gleq_window_refresh_callback(window_handle());
} }
// fullscreen_quad_rgb( lt_getsurface(0)->t, 1.2f ); // fullscreen_quad_rgb( lt_getsurface(0)->t, 1.2f );
ui_texture_fit(lt_getsurface(0)->t, bounds); ui_texture_fit(lt_getsurface(0)->t, bounds);
if( !!nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect){lt_wx+5,lt_wy+5,lt_ww-10,lt_wh-10})) ) { if( !!nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect){lt_wx+5,lt_wy+5,lt_ww-10,lt_wh-10})) ) {
lt_events &= ~(1<<31); // dont cursor shape lt_events &= ~(1<<31); // dont cursor shape
} }
editor_end(window_mode); editor_end(window_mode);
} }
lt_tick(L); lt_tick(L);
return 0; return 0;
} }
AUTORUN { AUTORUN {
array_push(editor.subeditors, editor_scripted); array_push(editor.subeditors, editor_scripted);
} }

View File

@ -1,172 +1,172 @@
#define TIMELINE_ICON ICON_MDI_CHART_TIMELINE #define TIMELINE_ICON ICON_MDI_CHART_TIMELINE
#define TIMELINE_TITLE "Timeline " TIMELINE_ICON #define TIMELINE_TITLE "Timeline " TIMELINE_ICON
EDITOR_BIND(timeline, "held(CTRL)&down(3)", { ui_show(TIMELINE_TITLE, ui_visible(TIMELINE_TITLE) ^ true); }); EDITOR_BIND(timeline, "held(CTRL)&down(3)", { ui_show(TIMELINE_TITLE, ui_visible(TIMELINE_TITLE) ^ true); });
int ui_tween(const char *label, tween_t *t) { int ui_tween(const char *label, tween_t *t) {
if( ui_filter && ui_filter[0] ) if( !strstr(label, ui_filter) ) return 0; if( ui_filter && ui_filter[0] ) if( !strstr(label, ui_filter) ) return 0;
int expand_keys = label[0] == '!'; label += expand_keys; int expand_keys = label[0] == '!'; label += expand_keys;
const char *id = label; const char *id = label;
if( strchr(id, '@') ) *strchr((char*)(id = (const char*)va("%s", label)), '@') = '\0'; if( strchr(id, '@') ) *strchr((char*)(id = (const char*)va("%s", label)), '@') = '\0';
enum { LABEL_SPACING = 250 }; enum { LABEL_SPACING = 250 };
enum { ROUNDING = 0 }; enum { ROUNDING = 0 };
enum { THICKNESS = 1 }; enum { THICKNESS = 1 };
enum { PIXELS_PER_SECOND = 60 }; enum { PIXELS_PER_SECOND = 60 };
enum { KEY_WIDTH = 5, KEY_HEIGHT = 5 }; enum { KEY_WIDTH = 5, KEY_HEIGHT = 5 };
enum { TIMELINE_HEIGHT = 25 }; enum { TIMELINE_HEIGHT = 25 };
enum { MARKER1_HEIGHT = 5, MARKER10_HEIGHT = 20, MARKER5_HEIGHT = (MARKER1_HEIGHT + MARKER10_HEIGHT) / 2 }; enum { MARKER1_HEIGHT = 5, MARKER10_HEIGHT = 20, MARKER5_HEIGHT = (MARKER1_HEIGHT + MARKER10_HEIGHT) / 2 };
unsigned base_color = WHITE; unsigned base_color = WHITE;
unsigned time_color = YELLOW; unsigned time_color = YELLOW;
unsigned duration_color = ORANGE; unsigned duration_color = ORANGE;
unsigned key_color = GREEN; unsigned key_color = GREEN;
int changed = 0; int changed = 0;
#if 0 #if 0
// two rows with height:30 composed of three widgets // two rows with height:30 composed of three widgets
nk_layout_row_template_begin(ui_ctx, 30); nk_layout_row_template_begin(ui_ctx, 30);
nk_layout_row_template_push_variable(ui_ctx, t->duration * PIXELS_PER_SECOND); // min 80px. can grow nk_layout_row_template_push_variable(ui_ctx, t->duration * PIXELS_PER_SECOND); // min 80px. can grow
nk_layout_row_template_end(ui_ctx); nk_layout_row_template_end(ui_ctx);
#endif #endif
char *sid = va("%s.%d", id, 0); char *sid = va("%s.%d", id, 0);
uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL; uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult; for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue; ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
ui_label(label); ui_label(label);
struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx); struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx); struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx);
bounds.y -= 30; bounds.y -= 30;
struct nk_rect baseline = bounds; baseline.y += 30/2; struct nk_rect baseline = bounds; baseline.y += 30/2;
baseline.x += LABEL_SPACING; baseline.x += LABEL_SPACING;
baseline.w -= LABEL_SPACING; baseline.w -= LABEL_SPACING;
// tween duration // tween duration
{ {
struct nk_rect pos = baseline; struct nk_rect pos = baseline;
pos.w = pos.x + t->duration * PIXELS_PER_SECOND; pos.w = pos.x + t->duration * PIXELS_PER_SECOND;
pos.y -= TIMELINE_HEIGHT/2; pos.y -= TIMELINE_HEIGHT/2;
pos.h = TIMELINE_HEIGHT; pos.h = TIMELINE_HEIGHT;
nk_stroke_rect(canvas, pos, ROUNDING, THICKNESS*2, AS_NKCOLOR(duration_color)); nk_stroke_rect(canvas, pos, ROUNDING, THICKNESS*2, AS_NKCOLOR(duration_color));
} }
// tween ranges // tween ranges
for(int i = 0, end = array_count(t->keyframes) - 1; i < end; ++i) { for(int i = 0, end = array_count(t->keyframes) - 1; i < end; ++i) {
tween_keyframe_t *k = t->keyframes + i; tween_keyframe_t *k = t->keyframes + i;
tween_keyframe_t *next = k + 1; tween_keyframe_t *next = k + 1;
struct nk_rect pos = baseline; struct nk_rect pos = baseline;
pos.x += k->t * PIXELS_PER_SECOND; pos.x += k->t * PIXELS_PER_SECOND;
pos.w = (next->t - k->t) * PIXELS_PER_SECOND; pos.w = (next->t - k->t) * PIXELS_PER_SECOND;
pos.y -= TIMELINE_HEIGHT/2; pos.y -= TIMELINE_HEIGHT/2;
pos.h = TIMELINE_HEIGHT; pos.h = TIMELINE_HEIGHT;
char *sid = va("%s.%d", id, i); char *sid = va("%s.%d", id, i);
uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL; uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult; for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue; ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
struct nk_color c = nk_hsva_f(ui_hue, 0.75f, 0.8f, ui_alpha); struct nk_color c = nk_hsva_f(ui_hue, 0.75f, 0.8f, ui_alpha);
nk_fill_rect(canvas, pos, ROUNDING, k->ease == EASE_ZERO ? AS_NKCOLOR(0) : c); // AS_NKCOLOR(track_color)); nk_fill_rect(canvas, pos, ROUNDING, k->ease == EASE_ZERO ? AS_NKCOLOR(0) : c); // AS_NKCOLOR(track_color));
} }
// horizontal line // horizontal line
nk_stroke_line(canvas, baseline.x, baseline.y, baseline.x+baseline.w,baseline.y, THICKNESS, AS_NKCOLOR(base_color)); nk_stroke_line(canvas, baseline.x, baseline.y, baseline.x+baseline.w,baseline.y, THICKNESS, AS_NKCOLOR(base_color));
// unit, 5-unit and 10-unit markers // unit, 5-unit and 10-unit markers
for( float i = 0, j = 0; i < baseline.w; i += PIXELS_PER_SECOND/10, ++j ) { for( float i = 0, j = 0; i < baseline.w; i += PIXELS_PER_SECOND/10, ++j ) {
int len = !((int)j%10) ? MARKER10_HEIGHT : !((int)j%5) ? MARKER5_HEIGHT : MARKER1_HEIGHT; int len = !((int)j%10) ? MARKER10_HEIGHT : !((int)j%5) ? MARKER5_HEIGHT : MARKER1_HEIGHT;
nk_stroke_line(canvas, baseline.x+i, baseline.y-len, baseline.x+i, baseline.y+len, THICKNESS, AS_NKCOLOR(base_color)); nk_stroke_line(canvas, baseline.x+i, baseline.y-len, baseline.x+i, baseline.y+len, THICKNESS, AS_NKCOLOR(base_color));
} }
// time marker // time marker
float px = t->time * PIXELS_PER_SECOND; float px = t->time * PIXELS_PER_SECOND;
nk_stroke_line(canvas, baseline.x+px, bounds.y, baseline.x+px, bounds.y+bounds.h, THICKNESS*2, AS_NKCOLOR(time_color)); nk_stroke_line(canvas, baseline.x+px, bounds.y, baseline.x+px, bounds.y+bounds.h, THICKNESS*2, AS_NKCOLOR(time_color));
nk_draw_symbol(canvas, NK_SYMBOL_TRIANGLE_DOWN, ((struct nk_rect){ baseline.x+px-4,bounds.y-4-8,8,8}), /*bg*/AS_NKCOLOR(0), /*fg*/AS_NKCOLOR(time_color), 0.f/*border_width*/, ui_ctx->style.font); nk_draw_symbol(canvas, NK_SYMBOL_TRIANGLE_DOWN, ((struct nk_rect){ baseline.x+px-4,bounds.y-4-8,8,8}), /*bg*/AS_NKCOLOR(0), /*fg*/AS_NKCOLOR(time_color), 0.f/*border_width*/, ui_ctx->style.font);
// key markers // key markers
for each_array_ptr(t->keyframes, tween_keyframe_t, k) { for each_array_ptr(t->keyframes, tween_keyframe_t, k) {
struct nk_rect pos = baseline; struct nk_rect pos = baseline;
pos.x += k->t * PIXELS_PER_SECOND; pos.x += k->t * PIXELS_PER_SECOND;
vec2 romboid[] = { vec2 romboid[] = {
{pos.x-KEY_WIDTH,pos.y}, {pos.x,pos.y-KEY_HEIGHT}, {pos.x-KEY_WIDTH,pos.y}, {pos.x,pos.y-KEY_HEIGHT},
{pos.x+KEY_WIDTH,pos.y}, {pos.x,pos.y+KEY_HEIGHT} {pos.x+KEY_WIDTH,pos.y}, {pos.x,pos.y+KEY_HEIGHT}
}; };
nk_fill_polygon(canvas, (float*)romboid, countof(romboid), AS_NKCOLOR(key_color)); nk_fill_polygon(canvas, (float*)romboid, countof(romboid), AS_NKCOLOR(key_color));
} }
// keys ui // keys ui
if( expand_keys ) if( expand_keys )
for(int i = 0, end = array_count(t->keyframes); i < end; ++i) { for(int i = 0, end = array_count(t->keyframes); i < end; ++i) {
tween_keyframe_t *k = t->keyframes + i; tween_keyframe_t *k = t->keyframes + i;
if( ui_collapse(va("Key %d", i), va("%s.%d", id, i))) { if( ui_collapse(va("Key %d", i), va("%s.%d", id, i))) {
changed |= ui_float("Time", &k->t); changed |= ui_float("Time", &k->t);
changed |= ui_float3("Value", &k->v.x); changed |= ui_float3("Value", &k->v.x);
changed |= ui_list("Ease", ease_enums(), EASE_NUM, &k->ease ); changed |= ui_list("Ease", ease_enums(), EASE_NUM, &k->ease );
ui_collapse_end(); ui_collapse_end();
} }
} }
return changed; return changed;
} }
tween_t* rand_tween() { tween_t* rand_tween() {
tween_t demo = tween(); tween_t demo = tween();
int num_keys = randi(2,8); int num_keys = randi(2,8);
double t = 0; double t = 0;
for( int i = 0; i < num_keys; ++i) { for( int i = 0; i < num_keys; ++i) {
tween_setkey(&demo, t, scale3(vec3(randf(),randf(),randf()),randi(-5,5)), randi(0,EASE_NUM) ); tween_setkey(&demo, t, scale3(vec3(randf(),randf(),randf()),randi(-5,5)), randi(0,EASE_NUM) );
t += randi(1,5) / ((float)(1 << randi(0,2))); t += randi(1,5) / ((float)(1 << randi(0,2)));
} }
tween_t *p = CALLOC(1, sizeof(tween_t)); tween_t *p = CALLOC(1, sizeof(tween_t));
memcpy(p, &demo, sizeof(tween_t)); memcpy(p, &demo, sizeof(tween_t));
return p; return p;
} }
int editor_timeline(int window_mode) { int editor_timeline(int window_mode) {
static array(tween_t*) tweens = 0; static array(tween_t*) tweens = 0;
do_once { do_once {
array_push(tweens, rand_tween()); array_push(tweens, rand_tween());
} }
if( editor.t == 0 ) if( editor.t == 0 )
for each_array(tweens, tween_t*,t) { for each_array(tweens, tween_t*,t) {
tween_reset(t); tween_reset(t);
} }
else else
for each_array(tweens, tween_t*,t) { for each_array(tweens, tween_t*,t) {
tween_update(t, editor.dt); tween_update(t, editor.dt);
} }
static void *selected = NULL; static void *selected = NULL;
if( editor_begin(TIMELINE_TITLE, window_mode) ) { if( editor_begin(TIMELINE_TITLE, window_mode) ) {
int choice = ui_toolbar(ICON_MDI_PLUS ";" ICON_MDI_MINUS ); int choice = ui_toolbar(ICON_MDI_PLUS ";" ICON_MDI_MINUS );
if( choice == 1 ) array_push(tweens, rand_tween()); if( choice == 1 ) array_push(tweens, rand_tween());
if( choice == 2 && selected ) { if( choice == 2 && selected ) {
int target = -1; int target = -1;
for( int i = 0, end = array_count(tweens); i < end; ++i ) if( tweens[i] == selected ) { target = i; break; } for( int i = 0, end = array_count(tweens); i < end; ++i ) if( tweens[i] == selected ) { target = i; break; }
if( target >= 0 ) { array_erase_slow(tweens, target); selected = NULL; } if( target >= 0 ) { array_erase_slow(tweens, target); selected = NULL; }
} }
for each_array(tweens, tween_t*,t) { for each_array(tweens, tween_t*,t) {
ui_tween(va("%s%p@%05.2fs Value: %s", t == selected ? "!":"", t, t->time, ftoa3(t->result)), t); ui_tween(va("%s%p@%05.2fs Value: %s", t == selected ? "!":"", t, t->time, ftoa3(t->result)), t);
if(ui_label_icon_clicked_L.x) selected = (t != selected) ? t : NULL; if(ui_label_icon_clicked_L.x) selected = (t != selected) ? t : NULL;
} }
editor_end(window_mode); editor_end(window_mode);
} }
return 0; return 0;
} }
AUTORUN { AUTORUN {
array_push(editor.subeditors, editor_timeline); array_push(editor.subeditors, editor_timeline);
} }

View File

@ -1,36 +1,36 @@
// Enable more performant GPUs on laptops. Does this work into a dll? // Enable more performant GPUs on laptops. Does this work into a dll?
// int NvOptimusEnablement = 1; // int NvOptimusEnablement = 1;
// int AmdPowerXpressRequestHighPerformance = 1; // int AmdPowerXpressRequestHighPerformance = 1;
#if is(linux) && is(tcc) // fixes `tcc: error: undefined symbol '__dso_handle'` #if is(linux) && is(tcc) // fixes `tcc: error: undefined symbol '__dso_handle'`
int __dso_handle; // compiled with: `tcc demo.c v4k.c -D__STDC_NO_VLA__ -lX11` int __dso_handle; // compiled with: `tcc demo.c v4k.c -D__STDC_NO_VLA__ -lX11`
#endif #endif
#if is(win32) && is(tcc) // fixes `tcc: error: undefined symbol '_InterlockedExchangeAdd'` when compiling with `-m64` flag #if is(win32) && is(tcc) // fixes `tcc: error: undefined symbol '_InterlockedExchangeAdd'` when compiling with `-m64` flag
__CRT_INLINE LONG _InterlockedExchangeAdd(LONG volatile *add, LONG val) { __CRT_INLINE LONG _InterlockedExchangeAdd(LONG volatile *add, LONG val) {
LONG old; LONG old;
do old = *add; while( InterlockedCompareExchange(add, old + val, old) != old ); do old = *add; while( InterlockedCompareExchange(add, old + val, old) != old );
return old; return old;
} }
__CRT_INLINE LONGLONG _InterlockedExchangeAdd64(LONGLONG volatile *add, LONGLONG val) { // 64bit version, for completeness __CRT_INLINE LONGLONG _InterlockedExchangeAdd64(LONGLONG volatile *add, LONGLONG val) { // 64bit version, for completeness
LONGLONG old; LONGLONG old;
do old = *add; while( InterlockedCompareExchange64(add, old + val, old) != old ); do old = *add; while( InterlockedCompareExchange64(add, old + val, old) != old );
return old; return old;
} }
#endif #endif
#ifdef ZIG_CC #ifdef ZIG_CC
static int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0xffff)); } static int IN6_IS_ADDR_V4MAPPED(const struct in6_addr *a) { return ((a->s6_words[0]==0) && (a->s6_words[1]==0) && (a->s6_words[2]==0) && (a->s6_words[3]==0) && (a->s6_words[4]==0) && (a->s6_words[5]==0xffff)); }
const struct in6_addr in6addr_any; // = IN6ADDR_ANY_INIT; const struct in6_addr in6addr_any; // = IN6ADDR_ANY_INIT;
//static const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; //static const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
#endif #endif
ifdef(retail, AUTORUN { ifdef(retail, AUTORUN {
fclose(stderr); fclose(stderr);
fclose(stdout); fclose(stdout);
const char* null_stream = ifdef(win32, "nul:", "/dev/null"); const char* null_stream = ifdef(win32, "nul:", "/dev/null");
if (!freopen(null_stream, "a", stdout)) PANIC("cannot recreate standard streams"); if (!freopen(null_stream, "a", stdout)) PANIC("cannot recreate standard streams");
if (!freopen(null_stream, "a", stderr)) PANIC("cannot recreate standard streams"); if (!freopen(null_stream, "a", stderr)) PANIC("cannot recreate standard streams");
} ) } )

View File

@ -1,301 +1,301 @@
// dll ------------------------------------------------------------------------ // dll ------------------------------------------------------------------------
/* deprecated /* deprecated
#if is(win32) #if is(win32)
# include <winsock2.h> # include <winsock2.h>
# define dlopen(name,flags) (void*)( (name) ? LoadLibraryA(name) : GetModuleHandleA(NULL)) # define dlopen(name,flags) (void*)( (name) ? LoadLibraryA(name) : GetModuleHandleA(NULL))
# define dlsym(handle,symbol) GetProcAddress((HMODULE)(handle), symbol ) # define dlsym(handle,symbol) GetProcAddress((HMODULE)(handle), symbol )
# define dlclose(handle) 0 # define dlclose(handle) 0
#else #else
# include <dlfcn.h> # include <dlfcn.h>
# define dlopen(name,flags) (void*)( (name) ? dlopen(name, flags) : NULL ) # define dlopen(name,flags) (void*)( (name) ? dlopen(name, flags) : NULL )
# define dlsym(handle,symbol) dlsym( (handle) ? (handle) : ifdef(osx,RTLD_SELF,NULL), symbol ) # define dlsym(handle,symbol) dlsym( (handle) ? (handle) : ifdef(osx,RTLD_SELF,NULL), symbol )
#endif #endif
*/ */
void* dll(const char *fname, const char *symbol) { void* dll(const char *fname, const char *symbol) {
if( fname && !file_exist(fname) ) { if( fname && !file_exist(fname) ) {
char *buf, *path = file_path(fname), *base = file_base(fname); char *buf, *path = file_path(fname), *base = file_base(fname);
if( file_exist(buf = va("%s%s.dll", path, base)) || if( file_exist(buf = va("%s%s.dll", path, base)) ||
file_exist(buf = va("%s%s.so", path, base)) || file_exist(buf = va("%s%s.so", path, base)) ||
file_exist(buf = va("%slib%s.so", path, base)) || file_exist(buf = va("%slib%s.so", path, base)) ||
file_exist(buf = va("%s%s.dylib", path, base)) ) { file_exist(buf = va("%s%s.dylib", path, base)) ) {
fname = (const char *)buf; fname = (const char *)buf;
} else { } else {
return NULL; return NULL;
} }
} }
#if is(win32) #if is(win32)
return (void*)GetProcAddress(fname ? LoadLibraryA(fname) : GetModuleHandleA(NULL), symbol); return (void*)GetProcAddress(fname ? LoadLibraryA(fname) : GetModuleHandleA(NULL), symbol);
#else #else
return dlsym(fname ? dlopen(fname, RTLD_NOW|RTLD_LOCAL) : ifdef(osx, RTLD_SELF, NULL), symbol); return dlsym(fname ? dlopen(fname, RTLD_NOW|RTLD_LOCAL) : ifdef(osx, RTLD_SELF, NULL), symbol);
#endif #endif
} }
#if 0 // demo: cl demo.c /LD && REM dll #if 0 // demo: cl demo.c /LD && REM dll
EXPORT int add2(int a, int b) { return a + b; } EXPORT int add2(int a, int b) { return a + b; }
int main() { int (*adder)() = dll("demo.dll", "add2"); printf("%d\n", adder(2,3)); } int main() { int (*adder)() = dll("demo.dll", "add2"); printf("%d\n", adder(2,3)); }
#endif #endif
// script --------------------------------------------------------------------- // script ---------------------------------------------------------------------
typedef lua_State lua; typedef lua_State lua;
// the Lua interpreter(s) // the Lua interpreter(s)
static array(lua*) Ls; static array(lua*) Ls;
// the **current** Lua interpreter // the **current** Lua interpreter
static lua *L; static lua *L;
#if is(linux) #if is(linux)
void luaopen_libv4k(lua_State *L) {} void luaopen_libv4k(lua_State *L) {}
#endif #endif
static void* script__realloc(void *userdef, void *ptr, size_t osize, size_t nsize) { static void* script__realloc(void *userdef, void *ptr, size_t osize, size_t nsize) {
(void)userdef; (void)userdef;
return ptr = REALLOC( ptr, /* (osize+1) * */ nsize ); return ptr = REALLOC( ptr, /* (osize+1) * */ nsize );
} }
static int script__traceback(lua_State *L) { static int script__traceback(lua_State *L) {
if (!lua_isstring(L, 1)) { // try metamethod if non-string error object if (!lua_isstring(L, 1)) { // try metamethod if non-string error object
if (lua_isnoneornil(L, 1) || if (lua_isnoneornil(L, 1) ||
!luaL_callmeta(L, 1, "__tostring") || !luaL_callmeta(L, 1, "__tostring") ||
!lua_isstring(L, -1)) !lua_isstring(L, -1))
return 1; // return non-string error object return 1; // return non-string error object
lua_remove(L, 1); // replace object with result of __tostring metamethod lua_remove(L, 1); // replace object with result of __tostring metamethod
} }
luaL_traceback(L, L, lua_tostring(L, 1), 1); luaL_traceback(L, L, lua_tostring(L, 1), 1);
return 1; return 1;
} }
static void script__error(lua_State *L, int status) { static void script__error(lua_State *L, int status) {
if (status != 0) { if (status != 0) {
const char *errormsg = lua_tostring(L, -1); const char *errormsg = lua_tostring(L, -1);
PRINTF( "!-- %s\n", errormsg); PRINTF( "!-- %s\n", errormsg);
lua_pop(L, 1); // remove error message lua_pop(L, 1); // remove error message
} }
} }
static int script__call(lua_State *L, int narg, int clear) { static int script__call(lua_State *L, int narg, int clear) {
#if ENABLE_FASTCALL_LUA #if ENABLE_FASTCALL_LUA
lua_call(L, 0, 0); lua_call(L, 0, 0);
return 0; return 0;
#else #else
int base = lua_gettop(L) - narg; // function index int base = lua_gettop(L) - narg; // function index
lua_pushcfunction(L, script__traceback); // push traceback function lua_pushcfunction(L, script__traceback); // push traceback function
lua_insert(L, base); // put it under chunk and args lua_insert(L, base); // put it under chunk and args
int status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base); int status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
script__error(L, status); script__error(L, status);
lua_remove(L, base); // remove traceback function lua_remove(L, base); // remove traceback function
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); // force gc in case of errors if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0); // force gc in case of errors
return status; return status;
#endif #endif
} }
void script_bind_function(const char *c_name, void *c_function) { void script_bind_function(const char *c_name, void *c_function) {
lua_pushcfunction( L, c_function ); lua_pushcfunction( L, c_function );
lua_setglobal( L, c_name ); lua_setglobal( L, c_name );
} }
void script_call(const char *lua_function) { void script_call(const char *lua_function) {
lua_getglobal( L, lua_function ); lua_getglobal( L, lua_function );
script__call( L, 0, 1 ); script__call( L, 0, 1 );
} }
void script_bind_class(const char *classname, int num, const char **methods, void **functions) { void script_bind_class(const char *classname, int num, const char **methods, void **functions) {
lua_newtable( L ); lua_newtable( L );
for( int i = 0; i < num; ++i) { for( int i = 0; i < num; ++i) {
lua_pushcfunction( L, functions[i] ); lua_pushcfunction( L, functions[i] );
lua_setfield( L, 1, methods[i] ); lua_setfield( L, 1, methods[i] );
} }
lua_setglobal( L, classname ); lua_setglobal( L, classname );
} }
void script_run(const char *script) { void script_run(const char *script) {
int ret = luaL_dostring(L, script); int ret = luaL_dostring(L, script);
if( ret != LUA_OK ) { if( ret != LUA_OK ) {
PRINTF("!Script failed to run: %s\n", lua_tostring(L, -1)); PRINTF("!Script failed to run: %s\n", lua_tostring(L, -1));
lua_pop(L, 1); // pop error message lua_pop(L, 1); // pop error message
} }
} }
void script_runfile(const char *pathfile) { void script_runfile(const char *pathfile) {
PRINTF( "Loading script '%s'\n", pathfile ); PRINTF( "Loading script '%s'\n", pathfile );
int loadResult = luaL_loadfile( L, pathfile ); int loadResult = luaL_loadfile( L, pathfile );
/**/ if( loadResult == LUA_OK ) { /**/ if( loadResult == LUA_OK ) {
script__call( L, 0, 1 ); script__call( L, 0, 1 );
} }
else if( loadResult == LUA_ERRSYNTAX ) { else if( loadResult == LUA_ERRSYNTAX ) {
PRINTF("!Script failed to load (LUA_ERRSYNTAX, '%s'): %s\n", lua_tostring( L, 1 ), pathfile ); PRINTF("!Script failed to load (LUA_ERRSYNTAX, '%s'): %s\n", lua_tostring( L, 1 ), pathfile );
// lua_pop(L, 1); // pop error message // lua_pop(L, 1); // pop error message
} }
else if( loadResult == LUA_ERRMEM ) { else if( loadResult == LUA_ERRMEM ) {
PRINTF("!Script failed to load (LUA_ERRMEM): %s\n", pathfile); PRINTF("!Script failed to load (LUA_ERRMEM): %s\n", pathfile);
} }
else { else {
PRINTF("!Script failed to load: %s\n", pathfile ); PRINTF("!Script failed to load: %s\n", pathfile );
} }
} }
// syntax sugars // syntax sugars
/* usage: /* usage:
int window_create_lua(lua *L) { int window_create_lua(lua *L) {
window_create(arg_float(1), arg_int(2)); window_create(arg_float(1), arg_int(2));
return_void(0); return_void(0);
} }
int window_swap_lua(lua *L) { int window_swap_lua(lua *L) {
int r = window_swap(); int r = window_swap();
return_int(r); return_int(r);
} }
*/ */
#define arg_int(nth) lua_tointeger(L, nth) #define arg_int(nth) lua_tointeger(L, nth)
#define arg_bool(nth) lua_toboolean(L, nth) #define arg_bool(nth) lua_toboolean(L, nth)
#define arg__Bool(nth) lua_toboolean(L, nth) #define arg__Bool(nth) lua_toboolean(L, nth)
#define arg_float(nth) (float)lua_tonumber(L, nth) #define arg_float(nth) (float)lua_tonumber(L, nth)
#define arg_double(nth) lua_tonumber(L, nth) #define arg_double(nth) lua_tonumber(L, nth)
#define arg_string(nth) lua_tolstring(L, nth, 0) #define arg_string(nth) lua_tolstring(L, nth, 0)
#define return_void(x) return ((x), 0) #define return_void(x) return ((x), 0)
#define return_bool(x) return (lua_pushboolean(L, x), 1) #define return_bool(x) return (lua_pushboolean(L, x), 1)
#define return__Bool(x) return (lua_pushboolean(L, x), 1) #define return__Bool(x) return (lua_pushboolean(L, x), 1)
#define return_int(x) return (lua_pushinteger(L, x), 1) #define return_int(x) return (lua_pushinteger(L, x), 1)
#define return_float(x) return (lua_pushnumber(L, x), 1) #define return_float(x) return (lua_pushnumber(L, x), 1)
#define return_double(x) return (lua_pushnumber(L, x), 1) #define return_double(x) return (lua_pushnumber(L, x), 1)
#define return_string(x) return (lua_pushstring(L, x), 1) #define return_string(x) return (lua_pushstring(L, x), 1)
#define WRAP_ALL(...) EXPAND(WRAP_ALL, __VA_ARGS__) #define WRAP_ALL(...) EXPAND(WRAP_ALL, __VA_ARGS__)
#define WRAP_ALL2(rc, func) int func##_lua(lua*L) { return_##rc(func()); } #define WRAP_ALL2(rc, func) int func##_lua(lua*L) { return_##rc(func()); }
#define WRAP_ALL3(rc, func, a1) int func##_lua(lua*L) { return_##rc(func(arg_##a1(1))); } #define WRAP_ALL3(rc, func, a1) int func##_lua(lua*L) { return_##rc(func(arg_##a1(1))); }
#define WRAP_ALL4(rc, func, a1,a2) int func##_lua(lua*L) { return_##rc(func(arg_##a1(1),arg_##a2(2))); } #define WRAP_ALL4(rc, func, a1,a2) int func##_lua(lua*L) { return_##rc(func(arg_##a1(1),arg_##a2(2))); }
#define BIND_ALL(...) EXPAND(BIND_ALL, __VA_ARGS__); #define BIND_ALL(...) EXPAND(BIND_ALL, __VA_ARGS__);
#define BIND_ALL2(rc,func) script_bind_function(#func, func##_lua) #define BIND_ALL2(rc,func) script_bind_function(#func, func##_lua)
#define BIND_ALL3(rc,func,a1) script_bind_function(#func, func##_lua) #define BIND_ALL3(rc,func,a1) script_bind_function(#func, func##_lua)
#define BIND_ALL4(rc,func,a1,a2) script_bind_function(#func, func##_lua) #define BIND_ALL4(rc,func,a1,a2) script_bind_function(#func, func##_lua)
#define XMACRO(X) /* @fixme: add all remaining V4K functions */ \ #define XMACRO(X) /* @fixme: add all remaining V4K functions */ \
X(bool, window_create, float, int ) \ X(bool, window_create, float, int ) \
X(bool, window_swap ) \ X(bool, window_swap ) \
X(void, ddraw_grid, float ) \ X(void, ddraw_grid, float ) \
X(bool, ui_panel, string, int ) \ X(bool, ui_panel, string, int ) \
X(bool, ui_notify, string, string ) \ X(bool, ui_notify, string, string ) \
X(void, ui_panel_end ) X(void, ui_panel_end )
XMACRO(WRAP_ALL) XMACRO(WRAP_ALL)
void script_quit(void) { void script_quit(void) {
if( L ) { if( L ) {
lua_close(L); lua_close(L);
L = 0; L = 0;
} }
} }
void script_init() { void script_init() {
if( !L ) { if( !L ) {
// v4k_init(); // v4k_init();
// initialize Lua // initialize Lua
L = lua_newstate(script__realloc, 0); // L = luaL_newstate(); L = lua_newstate(script__realloc, 0); // L = luaL_newstate();
// load various Lua libraries // load various Lua libraries
luaL_openlibs(L); luaL_openlibs(L);
luaopen_base(L); luaopen_base(L);
luaopen_table(L); luaopen_table(L);
luaopen_io(L); luaopen_io(L);
luaopen_string(L); luaopen_string(L);
luaopen_math(L); luaopen_math(L);
// @fixme: workaround that prevents script binding on lua 5.4.3 on top of luajit 2.1.0-beta3 on linux. lua_setglobal() crashing when accessing null L->l_G // @fixme: workaround that prevents script binding on lua 5.4.3 on top of luajit 2.1.0-beta3 on linux. lua_setglobal() crashing when accessing null L->l_G
if(L->l_G) { if(L->l_G) {
XMACRO(BIND_ALL); XMACRO(BIND_ALL);
} }
atexit(script_quit); atexit(script_quit);
} }
} }
bool script_tests() { bool script_tests() {
// script test (lua) // script test (lua)
script_run( "-- Bye.lua\nio.write(\"script test: Bye world!, from \", _VERSION, \"\\n\")" ); script_run( "-- Bye.lua\nio.write(\"script test: Bye world!, from \", _VERSION, \"\\n\")" );
return true; return true;
} }
#undef XMACRO #undef XMACRO
// script v2 ------------------------------------------------------------------ // script v2 ------------------------------------------------------------------
#define luaL_dostringsafe(L, str) \ #define luaL_dostringsafe(L, str) \
luaL_dostring(L, \ luaL_dostring(L, \
"xpcall(function()\n" \ "xpcall(function()\n" \
str \ str \
"end, function(err)\n" \ "end, function(err)\n" \
" print('Error: ' .. tostring(err))\n" \ " print('Error: ' .. tostring(err))\n" \
" print(debug.traceback(nil, 2))\n" \ " print(debug.traceback(nil, 2))\n" \
" if core and core.on_error then\n" \ " if core and core.on_error then\n" \
" pcall(core.on_error, err)\n" \ " pcall(core.on_error, err)\n" \
" end\n" \ " end\n" \
" os.exit(1)\n" \ " os.exit(1)\n" \
"end)" \ "end)" \
); );
static int f_vfs_read(lua_State *L) { static int f_vfs_read(lua_State *L) {
char *file = file_normalize(luaL_checkstring(L, 1)); char *file = file_normalize(luaL_checkstring(L, 1));
if( strbegi(file, app_path()) ) file += strlen(app_path()); if( strbegi(file, app_path()) ) file += strlen(app_path());
strswap(file+1, ".", "/"); strswap(file+1, ".", "/");
strswap(file+1, "/lua", ".lua"); strswap(file+1, "/lua", ".lua");
int len; char *data = vfs_load(file, &len); int len; char *data = vfs_load(file, &len);
if( len ) { if( len ) {
data = memcpy(MALLOC(len+1), data, len), data[len] = 0; data = memcpy(MALLOC(len+1), data, len), data[len] = 0;
//tty_color(data ? GREEN : RED); //tty_color(data ? GREEN : RED);
//printf("%s (%s)\n%s", file, data ? "ok" : "failed", data); //printf("%s (%s)\n%s", file, data ? "ok" : "failed", data);
//tty_color(0); //tty_color(0);
} }
return lua_pushstring(L, data), 1; // "\n\tcannot find `%s` within mounted zipfiles", file), 1; return lua_pushstring(L, data), 1; // "\n\tcannot find `%s` within mounted zipfiles", file), 1;
} }
// add our zip loader at the end of package.loaders // add our zip loader at the end of package.loaders
void lua_add_ziploader(lua_State* L) { void lua_add_ziploader(lua_State* L) {
lua_pushcfunction( L, f_vfs_read ); lua_pushcfunction( L, f_vfs_read );
lua_setglobal( L, "vfs_read" ); lua_setglobal( L, "vfs_read" );
luaL_dostringsafe(L, luaL_dostringsafe(L,
// "package.path = [[;<?>;<<?.lua>>;]]\n" // .. package.path\n" // "package.path = [[;<?>;<<?.lua>>;]]\n" // .. package.path\n"
"package.searchers[#package.searchers + 1] = function(libraryname)\n" "package.searchers[#package.searchers + 1] = function(libraryname)\n"
" for pattern in string.gmatch( package.path, '[^;]+' ) do\n" " for pattern in string.gmatch( package.path, '[^;]+' ) do\n"
" local proper_path = string.gsub(pattern, '?', libraryname)\n" " local proper_path = string.gsub(pattern, '?', libraryname)\n"
" local f = vfs_read(proper_path)\n" " local f = vfs_read(proper_path)\n"
" if f ~= nil then\n" " if f ~= nil then\n"
" return load(f, proper_path)\n" " return load(f, proper_path)\n"
" end\n" " end\n"
" end\n" " end\n"
" return nil\n" " return nil\n"
"end\n" "end\n"
); );
} }
void *script_init_env(unsigned flags) { void *script_init_env(unsigned flags) {
if( flags & SCRIPT_LUA ) { if( flags & SCRIPT_LUA ) {
lua_State *L = luaL_newstate(); lua_State *L = luaL_newstate();
luaL_openlibs(L); luaL_openlibs(L);
if( flags & SCRIPT_DEBUGGER ) { if( flags & SCRIPT_DEBUGGER ) {
// Register debuggers/inspectors // Register debuggers/inspectors
// luaL_dostringsafe(L, "I = require('inspect').inspect\n"); // luaL_dostringsafe(L, "I = require('inspect').inspect\n");
dbg_setup_default(L); dbg_setup_default(L);
} }
lua_add_ziploader(L); lua_add_ziploader(L);
return L; return L;
} }
return 0; return 0;
} }
bool script_push(void *env) { bool script_push(void *env) {
array_push(Ls, L = env); array_push(Ls, L = env);
return true; return true;
} }
bool script_pop() { bool script_pop() {
L = array_count(Ls) && (array_pop(Ls), array_count(Ls)) ? *array_back(Ls) : NULL; L = array_count(Ls) && (array_pop(Ls), array_count(Ls)) ? *array_back(Ls) : NULL;
return !!array_count(Ls); return !!array_count(Ls);
} }

View File

@ -1,34 +1,34 @@
// dll ------------------------------------------------------------------------ // dll ------------------------------------------------------------------------
/// !!! `filename` must contain extension /// !!! `filename` must contain extension
/// load dynamic library `file` and search for `symbol` /// load dynamic library `file` and search for `symbol`
/// return: NULL if not found, found symbol otherwise. /// return: NULL if not found, found symbol otherwise.
/// filename: path to dynamic library file. must contain extension. /// filename: path to dynamic library file. must contain extension.
/// symbol: symbol name. must not be NULL. /// symbol: symbol name. must not be NULL.
/// see: dlopen^, dlclose^ /// see: dlopen^, dlclose^
/// > bool (*plugin_init)(void) = dll("plugin.dll", "init"); /// > bool (*plugin_init)(void) = dll("plugin.dll", "init");
/// > assert(plugin_init()); /// > assert(plugin_init());
API void* dll(const char *filename, const char *symbol); API void* dll(const char *filename, const char *symbol);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// script framework // script framework
enum { enum {
SCRIPT_LUA = 1, SCRIPT_LUA = 1,
SCRIPT_DEBUGGER = 2, SCRIPT_DEBUGGER = 2,
}; };
API void script_init(); // @deprecate API void script_init(); // @deprecate
API void *script_init_env(unsigned flags); API void *script_init_env(unsigned flags);
API bool script_push(void *env); API bool script_push(void *env);
API void script_run(const char *script); API void script_run(const char *script);
API void script_runfile(const char *pathfile); API void script_runfile(const char *pathfile);
API void script_bind_class(const char *objname, int num_methods, const char **c_names, void **c_functions); API void script_bind_class(const char *objname, int num_methods, const char **c_names, void **c_functions);
API void script_bind_function(const char *c_name, void *c_function); API void script_bind_function(const char *c_name, void *c_function);
API void script_call(const char *lua_function); API void script_call(const char *lua_function);
API bool script_tests(); API bool script_tests();
API bool script_pop(); API bool script_pop();

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +1,98 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// files, cache and virtual filesystem (registered directories and/or compressed zip archives). // files, cache and virtual filesystem (registered directories and/or compressed zip archives).
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// - note: vfs_mount() order matters (last mounts have higher priority). // - note: vfs_mount() order matters (last mounts have higher priority).
// - note: directory/with/trailing/slash/ as mount_point, or zip/tar/pak archive otherwise. // - note: directory/with/trailing/slash/ as mount_point, or zip/tar/pak archive otherwise.
// //
// @todo: file_mmap // @todo: file_mmap
// @todo: file_find() from first file_scan() // @todo: file_find() from first file_scan()
// physical filesystem. files // physical filesystem. files
API array(char*) file_list( const char *pathmasks ); // folder/*.ico;**.png;*.c API array(char*) file_list( const char *pathmasks ); // folder/*.ico;**.png;*.c
API bool file_write( const char *file, const void *ptr, int len ); API bool file_write( const char *file, const void *ptr, int len );
API bool file_append( const char *file, const void *ptr, int len ); API bool file_append( const char *file, const void *ptr, int len );
API char * file_read(const char *filename); API char * file_read(const char *filename);
API char * file_load(const char *filename, int *len); API char * file_load(const char *filename, int *len);
API uint64_t file_size(const char *pathfile); API uint64_t file_size(const char *pathfile);
API bool file_directory(const char *pathfile); API bool file_directory(const char *pathfile);
API char * file_pathabs(const char *pathfile); // ../dir/./file.ext -> c:/prj/dir/file.ext API char * file_pathabs(const char *pathfile); // ../dir/./file.ext -> c:/prj/dir/file.ext
API char * file_path(const char *pathfile); // c:/prj/dir/file.ext -> c:/prj/dir/ API char * file_path(const char *pathfile); // c:/prj/dir/file.ext -> c:/prj/dir/
API char * file_name(const char *pathfile); // c:/prj/dir/file.ext -> file.ext API char * file_name(const char *pathfile); // c:/prj/dir/file.ext -> file.ext
API char * file_base(const char *pathfile); // c:/prj/dir/file.ext -> file API char * file_base(const char *pathfile); // c:/prj/dir/file.ext -> file
API char * file_ext(const char *pathfile); // c:/prj/dir/file.ext -> .ext API char * file_ext(const char *pathfile); // c:/prj/dir/file.ext -> .ext
API char * file_id(const char *pathfile); // c:/prj/dir/file.ext -> file/dir/prj (name then alphabetical) API char * file_id(const char *pathfile); // c:/prj/dir/file.ext -> file/dir/prj (name then alphabetical)
API char * file_normalize(const char *pathfile); // c:/prj/dir/file.ext -> c/prj/dir/file_ext API char * file_normalize(const char *pathfile); // c:/prj/dir/file.ext -> c/prj/dir/file_ext
//API char * file_normalize_with_folder(const char *pathfile); // c:/prj/dir/file.ext -> dir/file_ext //API char * file_normalize_with_folder(const char *pathfile); // c:/prj/dir/file.ext -> dir/file_ext
API char * file_counter(const char *pathfile); // in: v4k.ini -> out: v4k(001).ini -> out: v4k(002).ini [-> etc...] API char * file_counter(const char *pathfile); // in: v4k.ini -> out: v4k(001).ini -> out: v4k(002).ini [-> etc...]
API uint64_t file_stamp(const char *pathfile); // 1616153596 (seconds since unix epoch) API uint64_t file_stamp(const char *pathfile); // 1616153596 (seconds since unix epoch)
API uint64_t file_stamp10(const char *pathfile); // 20210319113316 (absolute datetime in base10) API uint64_t file_stamp10(const char *pathfile); // 20210319113316 (absolute datetime in base10)
API bool file_exist(const char *pathfile); API bool file_exist(const char *pathfile);
API bool file_delete(const char *pathfile); API bool file_delete(const char *pathfile);
API bool file_copy(const char *src, const char *dst); API bool file_copy(const char *src, const char *dst);
API bool file_move(const char *src, const char *dst); API bool file_move(const char *src, const char *dst);
API FILE* file_temp(); API FILE* file_temp();
API char* file_tempname(); API char* file_tempname();
API void* file_md5(const char *file); // 16 bytes API void* file_md5(const char *file); // 16 bytes
API void* file_sha1(const char *file); // 20 bytes API void* file_sha1(const char *file); // 20 bytes
API void* file_crc32(const char *file); // 4 bytes API void* file_crc32(const char *file); // 4 bytes
// compressed files // compressed files
API array(char*) file_zip_list(const char *zipfile); API array(char*) file_zip_list(const char *zipfile);
API array(char) file_zip_extract(const char *zipfile, const char *filename); API array(char) file_zip_extract(const char *zipfile, const char *filename);
API bool file_zip_append(const char *zipfile, const char *filename, int clevel); API bool file_zip_append(const char *zipfile, const char *filename, int clevel);
API bool file_zip_appendmem(const char *zipfile, const char *entryname, const void *ptr, unsigned len, int clevel); API bool file_zip_appendmem(const char *zipfile, const char *entryname, const void *ptr, unsigned len, int clevel);
// storage (emscripten only) // storage (emscripten only)
// Mounts local storage folder for writing. Useful for Emscripten only. @path_folder: "/save" for example // Mounts local storage folder for writing. Useful for Emscripten only. @path_folder: "/save" for example
// Reads local storage to memory. Usually call it one time only, after mount. Useful for Emscripten only. // Reads local storage to memory. Usually call it one time only, after mount. Useful for Emscripten only.
// Writes memory contents to local storage. Usually call it after all fclose // Writes memory contents to local storage. Usually call it after all fclose
API void storage_mount(const char* folder); API void storage_mount(const char* folder);
API void storage_read(); API void storage_read();
API void storage_flush(); API void storage_flush();
// virtual filesystem // virtual filesystem
API bool vfs_mount(const char *mount_point); API bool vfs_mount(const char *mount_point);
API array(char*) vfs_list(const char *masks); // **.png;*.c API array(char*) vfs_list(const char *masks); // **.png;*.c
API char * vfs_read(const char *pathfile); API char * vfs_read(const char *pathfile);
API char * vfs_load(const char *pathfile, int *size); API char * vfs_load(const char *pathfile, int *size);
API int vfs_size(const char *pathfile); API int vfs_size(const char *pathfile);
API void vfs_reload(); API void vfs_reload();
API const char * vfs_resolve(const char *fuzzyname); // guess best match. @todo: fuzzy path API const char * vfs_resolve(const char *fuzzyname); // guess best match. @todo: fuzzy path
//API const char*vfs_extract(const char *pathfile); // extracts vfs file into local filesystem (temporary file), so it can be read by foreign/3rd party libs //API const char*vfs_extract(const char *pathfile); // extracts vfs file into local filesystem (temporary file), so it can be read by foreign/3rd party libs
API FILE* vfs_handle(const char *pathfile); // same as above, but returns file handle instead. preferred way, will clean descriptors at exit API FILE* vfs_handle(const char *pathfile); // same as above, but returns file handle instead. preferred way, will clean descriptors at exit
// cache // cache
API void * cache_insert(const char *key, void *value, int size); API void * cache_insert(const char *key, void *value, int size);
API void * cache_lookup(const char *key, int *size); API void * cache_lookup(const char *key, int *size);
// ini // ini
// @todo: evaluate alt api #1 // @todo: evaluate alt api #1
// char *ini(filename, section.key, default); // char *ini(filename, section.key, default);
// float inif(filename, section.key, default); // float inif(filename, section.key, default);
// @todo: evaluate alt api #2 // @todo: evaluate alt api #2
// char *val = ini(filename, section_key); // char *val = ini(filename, section_key);
// int count = ini_count(filename); // int count = ini_count(filename);
// char *key = ini_key_id(filename, id); // char *key = ini_key_id(filename, id);
// char *val = ini_val_id(filename, id); // char *val = ini_val_id(filename, id);
typedef map(char*,char*) ini_t; typedef map(char*,char*) ini_t;
API ini_t ini(const char *filename); API ini_t ini(const char *filename);
API ini_t ini_from_mem(const char *data); API ini_t ini_from_mem(const char *data);
API void ini_destroy(ini_t); API void ini_destroy(ini_t);
API bool ini_write(const char *filename, const char *section, const char *key, const char *value); API bool ini_write(const char *filename, const char *section, const char *key, const char *value);

File diff suppressed because it is too large Load Diff

View File

@ -1,102 +1,102 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// font framework // font framework
// - rlyeh, public domain // - rlyeh, public domain
// font size tags // font size tags
#define FONT_H1 "\1" // largest #define FONT_H1 "\1" // largest
#define FONT_H2 "\2" #define FONT_H2 "\2"
#define FONT_H3 "\3" #define FONT_H3 "\3"
#define FONT_H4 "\4" #define FONT_H4 "\4"
#define FONT_H5 "\5" #define FONT_H5 "\5"
#define FONT_H6 "\6" // smallest #define FONT_H6 "\6" // smallest
// font color tags // font color tags
#define FONT_COLOR1 "\x1a" #define FONT_COLOR1 "\x1a"
#define FONT_COLOR2 "\x1b" #define FONT_COLOR2 "\x1b"
#define FONT_COLOR3 "\x1c" #define FONT_COLOR3 "\x1c"
#define FONT_COLOR4 "\x1d" #define FONT_COLOR4 "\x1d"
#define FONT_COLOR5 "\x1e" #define FONT_COLOR5 "\x1e"
#define FONT_COLOR6 "\x1f" #define FONT_COLOR6 "\x1f"
// font face tags // font face tags
#define FONT_FACE1 "\x10" #define FONT_FACE1 "\x10"
#define FONT_FACE2 "\x11" #define FONT_FACE2 "\x11"
#define FONT_FACE3 "\x12" #define FONT_FACE3 "\x12"
#define FONT_FACE4 "\x13" #define FONT_FACE4 "\x13"
#define FONT_FACE5 "\x14" #define FONT_FACE5 "\x14"
#define FONT_FACE6 "\x15" #define FONT_FACE6 "\x15"
#define FONT_FACE7 "\x16" #define FONT_FACE7 "\x16"
#define FONT_FACE8 "\x17" // editor may override this one #define FONT_FACE8 "\x17" // editor may override this one
#define FONT_FACE9 "\x18" // editor may override this one #define FONT_FACE9 "\x18" // editor may override this one
#define FONT_FACE10 "\x19" // editor may override this one #define FONT_FACE10 "\x19" // editor may override this one
// font align tags // font align tags
#define FONT_LEFT "\\<" #define FONT_LEFT "\\<"
#define FONT_CENTER "\\|" #define FONT_CENTER "\\|"
#define FONT_JUSTIFY "\\$" #define FONT_JUSTIFY "\\$"
#define FONT_RIGHT "\\>" #define FONT_RIGHT "\\>"
#define FONT_TOP "\\^" #define FONT_TOP "\\^"
#define FONT_MIDDLE "\\-" #define FONT_MIDDLE "\\-"
#define FONT_BASELINE "\\_" #define FONT_BASELINE "\\_"
#define FONT_BOTTOM "\\v" #define FONT_BOTTOM "\\v"
// font flags // font flags
enum FONT_FLAGS { enum FONT_FLAGS {
// font atlas size // font atlas size
FONT_512 = 0x0, FONT_512 = 0x0,
FONT_1024 = 0x1, FONT_1024 = 0x1,
FONT_2048 = 0x2, FONT_2048 = 0x2,
FONT_4096 = 0x4, FONT_4096 = 0x4,
// font oversampling // font oversampling
FONT_NO_OVERSAMPLE = 0x0, FONT_NO_OVERSAMPLE = 0x0,
FONT_OVERSAMPLE_X = 0x08, FONT_OVERSAMPLE_X = 0x08,
FONT_OVERSAMPLE_Y = 0x10, FONT_OVERSAMPLE_Y = 0x10,
// unicode ranges // unicode ranges
FONT_ASCII = 0x800, // Compatible charset FONT_ASCII = 0x800, // Compatible charset
FONT_AR = 0x001000, // Arabic and Arabic-Indic digits FONT_AR = 0x001000, // Arabic and Arabic-Indic digits
FONT_ZH = 0x002000, // Chinese Simplified (@todo: add ZH_FULL) FONT_ZH = 0x002000, // Chinese Simplified (@todo: add ZH_FULL)
FONT_EL = 0x004000, // Greek, Coptic, modern Georgian, Svan, Mingrelian, Ancient Greek FONT_EL = 0x004000, // Greek, Coptic, modern Georgian, Svan, Mingrelian, Ancient Greek
FONT_EM = 0x008000, // Emoji FONT_EM = 0x008000, // Emoji
FONT_EU = 0x010000, // Eastern/western Europe, IPA, Latin ext A/B FONT_EU = 0x010000, // Eastern/western Europe, IPA, Latin ext A/B
FONT_HE = 0x020000, // Hebrew, Yiddish, Ladino, and other diaspora languages FONT_HE = 0x020000, // Hebrew, Yiddish, Ladino, and other diaspora languages
FONT_JP = 0x040000, // Hiragana, Katakana, Punctuations, Half-width chars FONT_JP = 0x040000, // Hiragana, Katakana, Punctuations, Half-width chars
FONT_KR = 0x080000, // Korean, Hangul FONT_KR = 0x080000, // Korean, Hangul
FONT_RU = 0x100000, // Cyrillic + ext A/B FONT_RU = 0x100000, // Cyrillic + ext A/B
FONT_TH = 0x200000, // Thai FONT_TH = 0x200000, // Thai
FONT_VI = 0x400000, // Vietnamese FONT_VI = 0x400000, // Vietnamese
FONT_CJK = FONT_ZH|FONT_JP|FONT_KR, FONT_CJK = FONT_ZH|FONT_JP|FONT_KR,
// FONT_DEFAULTS = FONT_512 | FONT_NO_OVERSAMPLE | FONT_ASCII, // FONT_DEFAULTS = FONT_512 | FONT_NO_OVERSAMPLE | FONT_ASCII,
}; };
typedef struct font_metrics_t { typedef struct font_metrics_t {
float ascent; // max distance above baseline for all glyphs float ascent; // max distance above baseline for all glyphs
float descent; // max distance below baseline for all glyphs float descent; // max distance below baseline for all glyphs
float linegap; // distance between ascent of next line and descent of current line float linegap; // distance between ascent of next line and descent of current line
float linedist; // distance between the baseline of two lines (ascent - descent + linegap) float linedist; // distance between the baseline of two lines (ascent - descent + linegap)
} font_metrics_t; } font_metrics_t;
// configures // configures
API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags); API void font_face(const char *face_tag, const char *filename_ttf, float font_size, unsigned flags);
API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags); API void font_face_from_mem(const char *tag, const void *ttf_buffer, unsigned ttf_len, float font_size, unsigned flags);
API void font_scale(const char *face_tag, int scale_index, float value); API void font_scale(const char *face_tag, int scale_index, float value);
API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6); API void font_scales(const char *face_tag, float h1, float h2, float h3, float h4, float h5, float h6);
API void font_color(const char *color_tag, uint32_t color); API void font_color(const char *color_tag, uint32_t color);
// commands // commands
API vec2 font_xy(); API vec2 font_xy();
API void font_goto(float x, float y); API void font_goto(float x, float y);
API vec2 font_print(const char *text); API vec2 font_print(const char *text);
API vec2 font_clip(const char *text, vec4 rect); API vec2 font_clip(const char *text, vec4 rect);
API const char* font_wrap(const char *text, float max_width); API const char* font_wrap(const char *text, float max_width);
API vec2 font_rect(const char *text); API vec2 font_rect(const char *text);
API font_metrics_t font_metrics(const char *text); API font_metrics_t font_metrics(const char *text);
// syntax highlighting // syntax highlighting
API void* font_colorize(const char *text, const char *comma_types, const char *comma_keywords); // comma separated tokens. expensive, please cache result. API void* font_colorize(const char *text, const char *comma_types, const char *comma_keywords); // comma separated tokens. expensive, please cache result.
API vec2 font_highlight(const char *text, const void *colors); API vec2 font_highlight(const char *text, const void *colors);
// ui // ui
API void ui_font(); API void ui_font();

View File

@ -1,479 +1,479 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// game ui (utils) // game ui (utils)
API void gui_drawrect( texture_t spritesheet, vec2 tex_start, vec2 tex_end, int rgba, vec2 start, vec2 end ); API void gui_drawrect( texture_t spritesheet, vec2 tex_start, vec2 tex_end, int rgba, vec2 start, vec2 end );
#define v42v2(rect) vec2(rect.x,rect.y), vec2(rect.z,rect.w) #define v42v2(rect) vec2(rect.x,rect.y), vec2(rect.z,rect.w)
void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, vec2 start, vec2 end ) { void gui_drawrect( texture_t texture, vec2 tex_start, vec2 tex_end, int rgba, vec2 start, vec2 end ) {
float gamma = 1; float gamma = 1;
static int program = -1, vbo = -1, vao = -1, u_inv_gamma = -1, u_tint = -1, u_has_tex = -1, u_window_width = -1, u_window_height = -1; static int program = -1, vbo = -1, vao = -1, u_inv_gamma = -1, u_tint = -1, u_has_tex = -1, u_window_width = -1, u_window_height = -1;
vec2 dpi = ifdef(osx, window_dpi(), vec2(1,1)); vec2 dpi = ifdef(osx, window_dpi(), vec2(1,1));
if( program < 0 ) { if( program < 0 ) {
const char* vs = vfs_read("shaders/rect_2d.vs"); const char* vs = vfs_read("shaders/rect_2d.vs");
const char* fs = vfs_read("shaders/rect_2d.fs"); const char* fs = vfs_read("shaders/rect_2d.fs");
program = shader(vs, fs, "", "fragcolor" , NULL); program = shader(vs, fs, "", "fragcolor" , NULL);
ASSERT(program > 0); ASSERT(program > 0);
u_inv_gamma = glGetUniformLocation(program, "u_inv_gamma"); u_inv_gamma = glGetUniformLocation(program, "u_inv_gamma");
u_tint = glGetUniformLocation(program, "u_tint"); u_tint = glGetUniformLocation(program, "u_tint");
u_has_tex = glGetUniformLocation(program, "u_has_tex"); u_has_tex = glGetUniformLocation(program, "u_has_tex");
u_window_width = glGetUniformLocation(program, "u_window_width"); u_window_width = glGetUniformLocation(program, "u_window_width");
u_window_height = glGetUniformLocation(program, "u_window_height"); u_window_height = glGetUniformLocation(program, "u_window_height");
glGenVertexArrays( 1, (GLuint*)&vao ); glGenVertexArrays( 1, (GLuint*)&vao );
glGenBuffers(1, &vbo); glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo);
} }
start = mul2(start, dpi); start = mul2(start, dpi);
end = mul2(end, dpi); end = mul2(end, dpi);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD); glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D; GLenum texture_type = texture.flags & TEXTURE_ARRAY ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;
glUseProgram( program ); glUseProgram( program );
glUniform1f( u_inv_gamma, 1.0f / (gamma + !gamma) ); glUniform1f( u_inv_gamma, 1.0f / (gamma + !gamma) );
glBindVertexArray( vao ); glBindVertexArray( vao );
glActiveTexture( GL_TEXTURE0 ); glActiveTexture( GL_TEXTURE0 );
glBindTexture( texture_type, texture.id ); glBindTexture( texture_type, texture.id );
glUniform1i(u_has_tex, (texture.id != 0)); glUniform1i(u_has_tex, (texture.id != 0));
glUniform1f(u_window_width, (float)window_width()); glUniform1f(u_window_width, (float)window_width());
glUniform1f(u_window_height, (float)window_height()); glUniform1f(u_window_height, (float)window_height());
vec4 rgbaf = {((rgba>>24)&255)/255.f, ((rgba>>16)&255)/255.f,((rgba>>8)&255)/255.f,((rgba>>0)&255)/255.f}; vec4 rgbaf = {((rgba>>24)&255)/255.f, ((rgba>>16)&255)/255.f,((rgba>>8)&255)/255.f,((rgba>>0)&255)/255.f};
glUniform4fv(u_tint, GL_TRUE, &rgbaf.x); glUniform4fv(u_tint, GL_TRUE, &rgbaf.x);
// normalize texture regions // normalize texture regions
if (texture.id != 0) { if (texture.id != 0) {
tex_start.x /= texture.w; tex_start.x /= texture.w;
tex_start.y /= texture.h; tex_start.y /= texture.h;
tex_end.x /= texture.w; tex_end.x /= texture.w;
tex_end.y /= texture.h; tex_end.y /= texture.h;
} }
GLfloat vertices[] = { GLfloat vertices[] = {
// Positions // UVs // Positions // UVs
start.x, start.y, tex_start.x, tex_start.y, start.x, start.y, tex_start.x, tex_start.y,
end.x, start.y, tex_end.x, tex_start.y, end.x, start.y, tex_end.x, tex_start.y,
end.x, end.y, tex_end.x, tex_end.y, end.x, end.y, tex_end.x, tex_end.y,
start.x, start.y, tex_start.x, tex_start.y, start.x, start.y, tex_start.x, tex_start.y,
end.x, end.y, tex_end.x, tex_end.y, end.x, end.y, tex_end.x, tex_end.y,
start.x, end.y, tex_start.x, tex_end.y start.x, end.y, tex_start.x, tex_end.y
}; };
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
glDrawArrays( GL_TRIANGLES, 0, 6 ); glDrawArrays( GL_TRIANGLES, 0, 6 );
profile_incstat("Render.num_drawcalls", +1); profile_incstat("Render.num_drawcalls", +1);
profile_incstat("Render.num_triangles", +2); profile_incstat("Render.num_triangles", +2);
glBindTexture( texture_type, 0 ); glBindTexture( texture_type, 0 );
glDisableVertexAttribArray(0); glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1); glDisableVertexAttribArray(1);
glBindVertexArray( 0 ); glBindVertexArray( 0 );
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram( 0 ); glUseProgram( 0 );
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// game ui // game ui
typedef union gui_state_t { typedef union gui_state_t {
struct { struct {
bool held; bool held;
bool hover; bool hover;
}; };
} gui_state_t; } gui_state_t;
static __thread array(guiskin_t) skins=0; static __thread array(guiskin_t) skins=0;
static __thread guiskin_t *last_skin=0; static __thread guiskin_t *last_skin=0;
static __thread map(int, gui_state_t) ctl_states=0; //@leak static __thread map(int, gui_state_t) ctl_states=0; //@leak
static __thread array(vec4) scissor_rects=0; static __thread array(vec4) scissor_rects=0;
static __thread bool any_widget_used=0; static __thread bool any_widget_used=0;
void gui_pushskin(guiskin_t skin) { void gui_pushskin(guiskin_t skin) {
array_push(skins, skin); array_push(skins, skin);
last_skin = array_back(skins); last_skin = array_back(skins);
} }
void gui_popskin() { void gui_popskin() {
if (!last_skin) return; if (!last_skin) return;
if (last_skin->free) last_skin->free(last_skin->userdata); if (last_skin->free) last_skin->free(last_skin->userdata);
array_pop(skins); array_pop(skins);
last_skin = array_count(skins) ? array_back(skins) : NULL; last_skin = array_count(skins) ? array_back(skins) : NULL;
} }
void *gui_userdata() { void *gui_userdata() {
return last_skin->userdata; return last_skin->userdata;
} }
vec2 gui_getskinsize(const char *skin, const char *fallback) { vec2 gui_getskinsize(const char *skin, const char *fallback) {
vec2 size={0}; vec2 size={0};
if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, skin, fallback, &size); if (last_skin->getskinsize) last_skin->getskinsize(last_skin->userdata, skin, fallback, &size);
return size; return size;
} }
unsigned gui_getskincolor(const char *skin, const char *fallback) { unsigned gui_getskincolor(const char *skin, const char *fallback) {
unsigned color = 0xFFFFFFFF; unsigned color = 0xFFFFFFFF;
if (last_skin->getskincolor) last_skin->getskincolor(last_skin->userdata, skin, fallback, &color); if (last_skin->getskincolor) last_skin->getskincolor(last_skin->userdata, skin, fallback, &color);
return color; return color;
} }
bool gui_ismouseinrect(const char *skin, const char *fallback, vec4 rect) { bool gui_ismouseinrect(const char *skin, const char *fallback, vec4 rect) {
if (last_skin->ismouseinrect) return last_skin->ismouseinrect(last_skin->userdata, skin, fallback, rect); if (last_skin->ismouseinrect) return last_skin->ismouseinrect(last_skin->userdata, skin, fallback, rect);
return false; return false;
} }
vec4 gui_getscissorrect(const char *skin, const char *fallback, vec4 rect) { vec4 gui_getscissorrect(const char *skin, const char *fallback, vec4 rect) {
vec4 scissor = rect; vec4 scissor = rect;
if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, fallback, rect, &scissor); if (last_skin->getscissorrect) last_skin->getscissorrect(last_skin->userdata, skin, fallback, rect, &scissor);
return scissor; return scissor;
} }
static static
gui_state_t *gui_getstate(int id) { gui_state_t *gui_getstate(int id) {
if (!ctl_states) map_init(ctl_states, less_int, hash_int); if (!ctl_states) map_init(ctl_states, less_int, hash_int);
return map_find_or_add(ctl_states, id, (gui_state_t){0}); return map_find_or_add(ctl_states, id, (gui_state_t){0});
} }
void gui_panel_id(int id, vec4 rect, const char *skin) { void gui_panel_id(int id, vec4 rect, const char *skin) {
(void)id; (void)id;
vec4 scissor={0, 0, window_width(), window_height()}; vec4 scissor={0, 0, window_width(), window_height()};
if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, NULL, rect); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, NULL, rect);
scissor = gui_getscissorrect(skin, NULL, rect); scissor = gui_getscissorrect(skin, NULL, rect);
if (!array_count(scissor_rects)) if (!array_count(scissor_rects))
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
glScissor(scissor.x, window_height()-scissor.w-scissor.y, scissor.z, scissor.w); glScissor(scissor.x, window_height()-scissor.w-scissor.y, scissor.z, scissor.w);
array_push(scissor_rects, scissor); array_push(scissor_rects, scissor);
} }
void gui_panel_end() { void gui_panel_end() {
ASSERT(array_count(scissor_rects)); ASSERT(array_count(scissor_rects));
array_pop(scissor_rects); array_pop(scissor_rects);
if (array_count(scissor_rects)) { if (array_count(scissor_rects)) {
vec4 scissor = *array_back(scissor_rects); vec4 scissor = *array_back(scissor_rects);
glScissor(scissor.x, scissor.y, scissor.z, scissor.w); glScissor(scissor.x, scissor.y, scissor.z, scissor.w);
} else { } else {
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
} }
} }
bool gui_button_id(int id, vec4 r, const char *skin) { bool gui_button_id(int id, vec4 r, const char *skin) {
gui_state_t *entry = gui_getstate(id); gui_state_t *entry = gui_getstate(id);
bool was_clicked=0; bool was_clicked=0;
skin=skin?skin:"button"; skin=skin?skin:"button";
char *btn = va("%s%s", skin, entry->held?"_press":entry->hover?"_hover":""); char *btn = va("%s%s", skin, entry->held?"_press":entry->hover?"_hover":"");
if (gui_ismouseinrect(btn, skin, r)) { if (gui_ismouseinrect(btn, skin, r)) {
if (input_up(MOUSE_L) && entry->held) { if (input_up(MOUSE_L) && entry->held) {
was_clicked=1; was_clicked=1;
} }
if (!any_widget_used) { if (!any_widget_used) {
any_widget_used = entry->held = input_held(MOUSE_L); any_widget_used = entry->held = input_held(MOUSE_L);
entry->hover = true; entry->hover = true;
} }
} }
else { else {
entry->hover = false; entry->hover = false;
} }
if (input_up(MOUSE_L) && entry->held) { if (input_up(MOUSE_L) && entry->held) {
entry->held = false; entry->held = false;
any_widget_used = false; any_widget_used = false;
} }
if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, btn, skin, r); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, btn, skin, r);
return was_clicked; return was_clicked;
} }
bool gui_button_label_id(int id, const char *text, vec4 rect, const char *skin) { bool gui_button_label_id(int id, const char *text, vec4 rect, const char *skin) {
gui_state_t *entry = gui_getstate(id); gui_state_t *entry = gui_getstate(id);
bool state = gui_button_id(id, rect, skin); bool state = gui_button_id(id, rect, skin);
vec2 buttonsize={0}; vec2 buttonsize={0};
skin=skin?skin:"button"; skin=skin?skin:"button";
char *btn = va("%s%s", skin, entry->held?"_press":entry->hover?"_hover":""); char *btn = va("%s%s", skin, entry->held?"_press":entry->hover?"_hover":"");
buttonsize = gui_getskinsize(btn, skin); buttonsize = gui_getskinsize(btn, skin);
vec2 textsize = font_rect(text); vec2 textsize = font_rect(text);
vec4 pos; vec4 pos;
pos.x = rect.x + max(buttonsize.x*.5f, rect.z*.5f) - textsize.x*.5f; pos.x = rect.x + max(buttonsize.x*.5f, rect.z*.5f) - textsize.x*.5f;
pos.y = rect.y + max(buttonsize.y*.5f, rect.w*.5f) - textsize.y*.5f; pos.y = rect.y + max(buttonsize.y*.5f, rect.w*.5f) - textsize.y*.5f;
gui_label(btn, text, pos); gui_label(btn, text, pos);
return state; return state;
} }
static static
float slider2posx(float min, float max, float value, float step, float w) { float slider2posx(float min, float max, float value, float step, float w) {
float norm = value - min; float norm = value - min;
float range = max - min; float range = max - min;
float rel = norm / range; float rel = norm / range;
float res = w * rel; float res = w * rel;
return step==0.0f?res:(round(res/step)*step); return step==0.0f?res:(round(res/step)*step);
} }
static static
float posx2slider(vec4 rect, float min, float max, float xpos, float step) { float posx2slider(vec4 rect, float min, float max, float xpos, float step) {
xpos = clampf(xpos, rect.x, rect.x+rect.z); xpos = clampf(xpos, rect.x, rect.x+rect.z);
double rel = (xpos - rect.x) / rect.z; double rel = (xpos - rect.x) / rect.z;
float res = min + (rel * (max - min)); float res = min + (rel * (max - min));
return step==0.0f?res:(round(res/step)*step); return step==0.0f?res:(round(res/step)*step);
} }
bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value) { bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value) {
gui_state_t *entry = gui_getstate(id); gui_state_t *entry = gui_getstate(id);
skin = skin?skin:"slider"; skin = skin?skin:"slider";
char *cursorskin = va("%s_cursor%s", skin, entry->held?"_press":entry->hover?"_hover":""); char *cursorskin = va("%s_cursor%s", skin, entry->held?"_press":entry->hover?"_hover":"");
char *fbcursor = va("%s_cursor", skin); char *fbcursor = va("%s_cursor", skin);
if (gui_ismouseinrect(skin, NULL, rect) && !any_widget_used) { if (gui_ismouseinrect(skin, NULL, rect) && !any_widget_used) {
any_widget_used = entry->held = input_held(MOUSE_L); any_widget_used = entry->held = input_held(MOUSE_L);
entry->hover = true; entry->hover = true;
} }
else if (input_up(MOUSE_L) && entry->held) { else if (input_up(MOUSE_L) && entry->held) {
entry->held = false; entry->held = false;
any_widget_used = false; any_widget_used = false;
} }
else { else {
entry->hover = false; entry->hover = false;
} }
float old_value = *value; float old_value = *value;
if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, NULL, rect); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, NULL, rect);
vec2 slidersize={0}, cursorsize={0}; vec2 slidersize={0}, cursorsize={0};
vec4 usablerect = gui_getscissorrect(skin, NULL, rect); vec4 usablerect = gui_getscissorrect(skin, NULL, rect);
slidersize = gui_getskinsize(skin, NULL); slidersize = gui_getskinsize(skin, NULL);
cursorsize = gui_getskinsize(cursorskin, fbcursor); cursorsize = gui_getskinsize(cursorskin, fbcursor);
if (entry->held) { if (entry->held) {
*value = posx2slider(usablerect, min, max, input(MOUSE_X), step); *value = posx2slider(usablerect, min, max, input(MOUSE_X), step);
} }
float sliderx = slider2posx(min, max, *value, step, usablerect.z); float sliderx = slider2posx(min, max, *value, step, usablerect.z);
vec2 cursorpos = vec2(sliderx+(usablerect.x-rect.x)-cursorsize.x*.5f, (slidersize.y*.5f - cursorsize.y*.5f)); vec2 cursorpos = vec2(sliderx+(usablerect.x-rect.x)-cursorsize.x*.5f, (slidersize.y*.5f - cursorsize.y*.5f));
vec4 cursorrect = rect; vec4 cursorrect = rect;
cursorrect.x += cursorpos.x; cursorrect.x += cursorpos.x;
cursorrect.y += cursorpos.y; cursorrect.y += cursorpos.y;
cursorrect.z = cursorsize.x; cursorrect.z = cursorsize.x;
cursorrect.w = max(cursorsize.y, rect.w); cursorrect.w = max(cursorsize.y, rect.w);
if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, cursorskin, fbcursor, cursorrect); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, cursorskin, fbcursor, cursorrect);
return entry->held && (old_value!=*value); return entry->held && (old_value!=*value);
} }
bool gui_slider_label_id(int id, const char *text, vec4 rect, const char *skin, float min, float max, float step, float *value) { bool gui_slider_label_id(int id, const char *text, vec4 rect, const char *skin, float min, float max, float step, float *value) {
bool state = gui_slider_id(id, rect, skin, min, max, step, value); bool state = gui_slider_id(id, rect, skin, min, max, step, value);
vec2 slidersize={0}; vec2 slidersize={0};
skin=skin?skin:"slider"; skin=skin?skin:"slider";
slidersize = gui_getskinsize(skin, NULL); slidersize = gui_getskinsize(skin, NULL);
vec2 textsize = font_rect(text); vec2 textsize = font_rect(text);
vec4 pos; vec4 pos;
pos.x = rect.x + max(slidersize.x, rect.z) + 8 /*padding*/; pos.x = rect.x + max(slidersize.x, rect.z) + 8 /*padding*/;
pos.y = rect.y + max(slidersize.y*.5f, rect.w*.5f) - textsize.y*.5f; pos.y = rect.y + max(slidersize.y*.5f, rect.w*.5f) - textsize.y*.5f;
gui_label(skin, text, pos); gui_label(skin, text, pos);
return state; return state;
} }
void gui_rect_id(int id, vec4 r, const char *skin) { void gui_rect_id(int id, vec4 r, const char *skin) {
(void)id; (void)id;
if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, NULL, r); if (last_skin->drawrect) last_skin->drawrect(last_skin->userdata, skin, NULL, r);
} }
void gui_label_id(int id, const char *skin, const char *text, vec4 rect) { void gui_label_id(int id, const char *skin, const char *text, vec4 rect) {
(void)id; (void)id;
font_color(FONT_COLOR6, gui_getskincolor(skin, NULL)); font_color(FONT_COLOR6, gui_getskincolor(skin, NULL));
font_goto(rect.x, rect.y); font_goto(rect.x, rect.y);
font_print(va(FONT_COLOR6 "%s", text)); font_print(va(FONT_COLOR6 "%s", text));
} }
/* skinned */ /* skinned */
static static
void skinned_free(void* userdata) { void skinned_free(void* userdata) {
skinned_t *a = C_CAST(skinned_t*, userdata); skinned_t *a = C_CAST(skinned_t*, userdata);
atlas_destroy(&a->atlas); atlas_destroy(&a->atlas);
FREE(a); FREE(a);
} }
static static
atlas_slice_frame_t *skinned_getsliceframe(atlas_t *a, const char *name) { atlas_slice_frame_t *skinned_getsliceframe(atlas_t *a, const char *name) {
if (!name) return NULL; if (!name) return NULL;
for (int i = 0; i < array_count(a->slices); i++) for (int i = 0; i < array_count(a->slices); i++)
if (!strcmp(quark_string(&a->db, a->slices[i].name), name)) if (!strcmp(quark_string(&a->db, a->slices[i].name), name))
return &a->slice_frames[a->slices[i].frames[0]]; return &a->slice_frames[a->slices[i].frames[0]];
// PRINTF("slice name: '%s' is missing in atlas!\n", name); // PRINTF("slice name: '%s' is missing in atlas!\n", name);
return NULL; return NULL;
} }
static static
void skinned_getskincolor(void *userdata, const char *skin, const char *fallback, unsigned *color) { void skinned_getskincolor(void *userdata, const char *skin, const char *fallback, unsigned *color) {
skinned_t *a = C_CAST(skinned_t*, userdata); skinned_t *a = C_CAST(skinned_t*, userdata);
atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin);
if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback); if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback);
if (!f) return; if (!f) return;
if (f->text && f->text[0] == '#') *color = atorgba(f->text); if (f->text && f->text[0] == '#') *color = atorgba(f->text);
} }
static static
void skinned_draw_missing_rect(vec4 r) { void skinned_draw_missing_rect(vec4 r) {
vec4 size = vec4(0, 0, texture_checker().w, texture_checker().h); vec4 size = vec4(0, 0, texture_checker().w, texture_checker().h);
gui_drawrect(texture_checker(), v42v2(size), 0x800080FF, v42v2(r)); gui_drawrect(texture_checker(), v42v2(size), 0x800080FF, v42v2(r));
} }
static static
bool skinned_ismouseinrect(void *userdata, const char *skin, const char *fallback, vec4 r) { bool skinned_ismouseinrect(void *userdata, const char *skin, const char *fallback, vec4 r) {
skinned_t *a = C_CAST(skinned_t*, userdata); skinned_t *a = C_CAST(skinned_t*, userdata);
atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin);
if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback); if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback);
if (!f) return false; if (!f) return false;
vec4 outer = f->bounds; vec4 outer = f->bounds;
r.x -= f->pivot.x*a->scale; r.x -= f->pivot.x*a->scale;
r.y -= f->pivot.y*a->scale; r.y -= f->pivot.y*a->scale;
r.z += r.x; r.z += r.x;
r.w += r.y; r.w += r.y;
if ((r.z-r.x) < (outer.z-outer.x) * a->scale) { if ((r.z-r.x) < (outer.z-outer.x) * a->scale) {
r.z = r.x + (outer.z-outer.x) * a->scale; r.z = r.x + (outer.z-outer.x) * a->scale;
} }
if ((r.w-r.y) < (outer.w-outer.y) * a->scale) { if ((r.w-r.y) < (outer.w-outer.y) * a->scale) {
r.w = r.y + (outer.w-outer.y) * a->scale; r.w = r.y + (outer.w-outer.y) * a->scale;
} }
return (input(MOUSE_X) > r.x && input(MOUSE_X) < r.z && input(MOUSE_Y) > r.y && input(MOUSE_Y) < r.w); return (input(MOUSE_X) > r.x && input(MOUSE_X) < r.z && input(MOUSE_Y) > r.y && input(MOUSE_Y) < r.w);
} }
static static
void skinned_draw_sprite(float scale, atlas_t *a, atlas_slice_frame_t *f, vec4 r) { void skinned_draw_sprite(float scale, atlas_t *a, atlas_slice_frame_t *f, vec4 r) {
vec4 outer = f->bounds; vec4 outer = f->bounds;
r.x -= f->pivot.x*scale; r.x -= f->pivot.x*scale;
r.y -= f->pivot.y*scale; r.y -= f->pivot.y*scale;
r.z += r.x; r.z += r.x;
r.w += r.y; r.w += r.y;
// Ensure dest rectangle is large enough to render the whole element // Ensure dest rectangle is large enough to render the whole element
if ((r.z-r.x) < (outer.z-outer.x) * scale) { if ((r.z-r.x) < (outer.z-outer.x) * scale) {
r.z = r.x + (outer.z-outer.x) * scale; r.z = r.x + (outer.z-outer.x) * scale;
} }
if ((r.w-r.y) < (outer.w-outer.y) * scale) { if ((r.w-r.y) < (outer.w-outer.y) * scale) {
r.w = r.y + (outer.w-outer.y) * scale; r.w = r.y + (outer.w-outer.y) * scale;
} }
if (!f->has_9slice) { if (!f->has_9slice) {
gui_drawrect(a->tex, v42v2(f->bounds), 0xFFFFFFFF, v42v2(r)); gui_drawrect(a->tex, v42v2(f->bounds), 0xFFFFFFFF, v42v2(r));
return; return;
} }
vec4 core = f->core; vec4 core = f->core;
core.x += outer.x; core.x += outer.x;
core.y += outer.y; core.y += outer.y;
core.z += outer.x; core.z += outer.x;
core.w += outer.y; core.w += outer.y;
// Define the 9 slices // Define the 9 slices
vec4 top_left_slice = {outer.x, outer.y, core.x, core.y}; vec4 top_left_slice = {outer.x, outer.y, core.x, core.y};
vec4 top_middle_slice = {core.x, outer.y, core.z, core.y}; vec4 top_middle_slice = {core.x, outer.y, core.z, core.y};
vec4 top_right_slice = {core.z, outer.y, outer.z, core.y}; vec4 top_right_slice = {core.z, outer.y, outer.z, core.y};
vec4 middle_left_slice = {outer.x, core.y, core.x, core.w}; vec4 middle_left_slice = {outer.x, core.y, core.x, core.w};
vec4 center_slice = core; vec4 center_slice = core;
vec4 middle_right_slice = {core.z, core.y, outer.z, core.w}; vec4 middle_right_slice = {core.z, core.y, outer.z, core.w};
vec4 bottom_left_slice = {outer.x, core.w, core.x, outer.w}; vec4 bottom_left_slice = {outer.x, core.w, core.x, outer.w};
vec4 bottom_middle_slice = {core.x, core.w, core.z, outer.w}; vec4 bottom_middle_slice = {core.x, core.w, core.z, outer.w};
vec4 bottom_right_slice = {core.z, core.w, outer.z, outer.w}; vec4 bottom_right_slice = {core.z, core.w, outer.z, outer.w};
vec4 top_left = {r.x, r.y, r.x + (core.x - outer.x) * scale, r.y + (core.y - outer.y) * scale}; vec4 top_left = {r.x, r.y, r.x + (core.x - outer.x) * scale, r.y + (core.y - outer.y) * scale};
vec4 top_right = {r.z - (outer.z - core.z) * scale, r.y, r.z, r.y + (core.y - outer.y) * scale}; vec4 top_right = {r.z - (outer.z - core.z) * scale, r.y, r.z, r.y + (core.y - outer.y) * scale};
vec4 bottom_left = {r.x, r.w - (outer.w - core.w) * scale, r.x + (core.x - outer.x) * scale, r.w}; vec4 bottom_left = {r.x, r.w - (outer.w - core.w) * scale, r.x + (core.x - outer.x) * scale, r.w};
vec4 bottom_right = {r.z - (outer.z - core.z) * scale, r.w - (outer.w - core.w) * scale, r.z, r.w}; vec4 bottom_right = {r.z - (outer.z - core.z) * scale, r.w - (outer.w - core.w) * scale, r.z, r.w};
vec4 top = {top_left.z, r.y, top_right.x, top_left.w}; vec4 top = {top_left.z, r.y, top_right.x, top_left.w};
vec4 bottom = {bottom_left.z, bottom_left.y, bottom_right.x, r.w}; vec4 bottom = {bottom_left.z, bottom_left.y, bottom_right.x, r.w};
vec4 left = {r.x, top_left.w, top_left.z, bottom_left.y}; vec4 left = {r.x, top_left.w, top_left.z, bottom_left.y};
vec4 right = {top_right.x, top_right.w, r.z, bottom_right.y}; vec4 right = {top_right.x, top_right.w, r.z, bottom_right.y};
vec4 center = {top_left.z, top_left.w, top_right.x, bottom_right.y}; vec4 center = {top_left.z, top_left.w, top_right.x, bottom_right.y};
gui_drawrect(a->tex, v42v2(center_slice), 0xFFFFFFFF, v42v2(center)); gui_drawrect(a->tex, v42v2(center_slice), 0xFFFFFFFF, v42v2(center));
gui_drawrect(a->tex, v42v2(top_left_slice), 0xFFFFFFFF, v42v2(top_left)); gui_drawrect(a->tex, v42v2(top_left_slice), 0xFFFFFFFF, v42v2(top_left));
gui_drawrect(a->tex, v42v2(top_right_slice), 0xFFFFFFFF, v42v2(top_right)); gui_drawrect(a->tex, v42v2(top_right_slice), 0xFFFFFFFF, v42v2(top_right));
gui_drawrect(a->tex, v42v2(bottom_left_slice), 0xFFFFFFFF, v42v2(bottom_left)); gui_drawrect(a->tex, v42v2(bottom_left_slice), 0xFFFFFFFF, v42v2(bottom_left));
gui_drawrect(a->tex, v42v2(bottom_right_slice), 0xFFFFFFFF, v42v2(bottom_right)); gui_drawrect(a->tex, v42v2(bottom_right_slice), 0xFFFFFFFF, v42v2(bottom_right));
gui_drawrect(a->tex, v42v2(top_middle_slice), 0xFFFFFFFF, v42v2(top)); gui_drawrect(a->tex, v42v2(top_middle_slice), 0xFFFFFFFF, v42v2(top));
gui_drawrect(a->tex, v42v2(bottom_middle_slice), 0xFFFFFFFF, v42v2(bottom)); gui_drawrect(a->tex, v42v2(bottom_middle_slice), 0xFFFFFFFF, v42v2(bottom));
gui_drawrect(a->tex, v42v2(middle_left_slice), 0xFFFFFFFF, v42v2(left)); gui_drawrect(a->tex, v42v2(middle_left_slice), 0xFFFFFFFF, v42v2(left));
gui_drawrect(a->tex, v42v2(middle_right_slice), 0xFFFFFFFF, v42v2(right)); gui_drawrect(a->tex, v42v2(middle_right_slice), 0xFFFFFFFF, v42v2(right));
} }
static static
void skinned_draw_rect(void* userdata, const char *skin, const char *fallback, vec4 r) { void skinned_draw_rect(void* userdata, const char *skin, const char *fallback, vec4 r) {
skinned_t *a = C_CAST(skinned_t*, userdata); skinned_t *a = C_CAST(skinned_t*, userdata);
atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin);
if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback); if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback);
if (!f) skinned_draw_missing_rect(r); if (!f) skinned_draw_missing_rect(r);
else skinned_draw_sprite(a->scale, &a->atlas, f, r); else skinned_draw_sprite(a->scale, &a->atlas, f, r);
} }
void skinned_getskinsize(void *userdata, const char *skin, const char *fallback, vec2 *size) { void skinned_getskinsize(void *userdata, const char *skin, const char *fallback, vec2 *size) {
skinned_t *a = C_CAST(skinned_t*, userdata); skinned_t *a = C_CAST(skinned_t*, userdata);
atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin);
if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback); if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback);
if (f) { if (f) {
size->x = (f->bounds.z-f->bounds.x)*a->scale; size->x = (f->bounds.z-f->bounds.x)*a->scale;
size->y = (f->bounds.w-f->bounds.y)*a->scale; size->y = (f->bounds.w-f->bounds.y)*a->scale;
} }
} }
static static
void skinned_getscissorrect(void* userdata, const char *skin, const char *fallback, vec4 rect, vec4 *dims) { void skinned_getscissorrect(void* userdata, const char *skin, const char *fallback, vec4 rect, vec4 *dims) {
skinned_t *a = C_CAST(skinned_t*, userdata); skinned_t *a = C_CAST(skinned_t*, userdata);
atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin); atlas_slice_frame_t *f = skinned_getsliceframe(&a->atlas, skin);
if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback); if (!f && fallback) f = skinned_getsliceframe(&a->atlas, fallback);
if (!f) return; if (!f) return;
*dims = rect; *dims = rect;
if (!f->has_9slice) return; if (!f->has_9slice) return;
vec2 skinsize, coresize; vec2 skinsize, coresize;
skinsize.x = (f->bounds.z-f->bounds.x)*a->scale; skinsize.x = (f->bounds.z-f->bounds.x)*a->scale;
skinsize.y = (f->bounds.w-f->bounds.y)*a->scale; skinsize.y = (f->bounds.w-f->bounds.y)*a->scale;
coresize.x = (f->core.z-f->core.x)*a->scale; coresize.x = (f->core.z-f->core.x)*a->scale;
coresize.y = (f->core.w-f->core.y)*a->scale; coresize.y = (f->core.w-f->core.y)*a->scale;
dims->x += f->core.x*a->scale; dims->x += f->core.x*a->scale;
dims->y += f->core.y*a->scale; dims->y += f->core.y*a->scale;
dims->z -= (skinsize.x - coresize.x); dims->z -= (skinsize.x - coresize.x);
dims->w -= (skinsize.y - coresize.y); dims->w -= (skinsize.y - coresize.y);
} }
guiskin_t gui_skinned(const char *asefile, float scale) { guiskin_t gui_skinned(const char *asefile, float scale) {
skinned_t *a = REALLOC(0, sizeof(skinned_t)); skinned_t *a = REALLOC(0, sizeof(skinned_t));
a->atlas = atlas_create(asefile, 0); a->atlas = atlas_create(asefile, 0);
a->scale = scale?scale:1.0f; a->scale = scale?scale:1.0f;
guiskin_t skin={0}; guiskin_t skin={0};
skin.userdata = a; skin.userdata = a;
skin.drawrect = skinned_draw_rect; skin.drawrect = skinned_draw_rect;
skin.getskinsize = skinned_getskinsize; skin.getskinsize = skinned_getskinsize;
skin.getskincolor = skinned_getskincolor; skin.getskincolor = skinned_getskincolor;
skin.ismouseinrect = skinned_ismouseinrect; skin.ismouseinrect = skinned_ismouseinrect;
skin.getscissorrect = skinned_getscissorrect; skin.getscissorrect = skinned_getscissorrect;
skin.free = skinned_free; skin.free = skinned_free;
return skin; return skin;
} }

View File

@ -1,65 +1,65 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// game ui // game ui
typedef struct guiskin_t { typedef struct guiskin_t {
void (*drawrect)(void* userdata, const char *skin, const char *fallback, vec4 rect); void (*drawrect)(void* userdata, const char *skin, const char *fallback, vec4 rect);
void (*getskinsize)(void* userdata, const char *skin, const char *fallback, vec2 *size); void (*getskinsize)(void* userdata, const char *skin, const char *fallback, vec2 *size);
void (*getskincolor)(void* userdata, const char *skin, const char *fallback, unsigned *color); void (*getskincolor)(void* userdata, const char *skin, const char *fallback, unsigned *color);
void (*getscissorrect)(void* userdata, const char *skin, const char *fallback, vec4 rect, vec4 *dims); void (*getscissorrect)(void* userdata, const char *skin, const char *fallback, vec4 rect, vec4 *dims);
bool (*ismouseinrect)(void* userdata, const char *skin, const char *fallback, vec4 rect); bool (*ismouseinrect)(void* userdata, const char *skin, const char *fallback, vec4 rect);
void (*free)(void* userdata); void (*free)(void* userdata);
void *userdata; void *userdata;
} guiskin_t; } guiskin_t;
API void gui_pushskin(guiskin_t skin); API void gui_pushskin(guiskin_t skin);
API void* gui_userdata(); API void* gui_userdata();
API vec2 gui_getskinsize(const char *skin, const char *fallback); API vec2 gui_getskinsize(const char *skin, const char *fallback);
API unsigned gui_getskincolor(const char *skin, const char *fallback); API unsigned gui_getskincolor(const char *skin, const char *fallback);
API bool gui_ismouseinrect(const char *skin, const char *fallback, vec4 rect); API bool gui_ismouseinrect(const char *skin, const char *fallback, vec4 rect);
API vec4 gui_getscissorrect(const char *skin, const char *fallback, vec4 rect); API vec4 gui_getscissorrect(const char *skin, const char *fallback, vec4 rect);
// -- // --
API void gui_panel_id(int id, vec4 rect, const char *skin); API void gui_panel_id(int id, vec4 rect, const char *skin);
API void gui_rect_id(int id, vec4 rect, const char *skin); API void gui_rect_id(int id, vec4 rect, const char *skin);
API void gui_label_id(int id, const char *skin, const char *text, vec4 rect); API void gui_label_id(int id, const char *skin, const char *text, vec4 rect);
API bool gui_button_id(int id, vec4 rect, const char *skin); API bool gui_button_id(int id, vec4 rect, const char *skin);
API bool gui_button_label_id(int id, const char *text, vec4 rect, const char *skin); API bool gui_button_label_id(int id, const char *text, vec4 rect, const char *skin);
API bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value); API bool gui_slider_id(int id, vec4 rect, const char *skin, float min, float max, float step, float *value);
API bool gui_slider_label_id(int id, const char *text, vec4 rect, const char *skin, float min, float max, float step, float *value); API bool gui_slider_label_id(int id, const char *text, vec4 rect, const char *skin, float min, float max, float step, float *value);
API void gui_panel_end(); API void gui_panel_end();
API void gui_popskin(); API void gui_popskin();
// helpers // helpers
#define gui_panel(...) gui_panel_id(__LINE__, __VA_ARGS__) #define gui_panel(...) gui_panel_id(__LINE__, __VA_ARGS__)
#define gui_rect(...) gui_rect_id(__LINE__, __VA_ARGS__) #define gui_rect(...) gui_rect_id(__LINE__, __VA_ARGS__)
#define gui_label(...) gui_label_id(__LINE__, __VA_ARGS__) #define gui_label(...) gui_label_id(__LINE__, __VA_ARGS__)
#define gui_button(...) gui_button_id(__LINE__, __VA_ARGS__) #define gui_button(...) gui_button_id(__LINE__, __VA_ARGS__)
#define gui_button_label(...) gui_button_label_id(__LINE__, __VA_ARGS__) #define gui_button_label(...) gui_button_label_id(__LINE__, __VA_ARGS__)
#define gui_slider(...) gui_slider_id(__LINE__, __VA_ARGS__) #define gui_slider(...) gui_slider_id(__LINE__, __VA_ARGS__)
#define gui_slider_label(...) gui_slider_label_id(__LINE__, __VA_ARGS__) #define gui_slider_label(...) gui_slider_label_id(__LINE__, __VA_ARGS__)
// default renderers // default renderers
typedef struct skinned_t { typedef struct skinned_t {
atlas_t atlas; atlas_t atlas;
float scale; float scale;
} skinned_t; } skinned_t;
// The skinning engine depends on an Aseprite asset with slices set up. // The skinning engine depends on an Aseprite asset with slices set up.
// While you can specify your own skins for various GUI widgets, some // While you can specify your own skins for various GUI widgets, some
// skin variants are hardcoded and expected to be present in your asset: // skin variants are hardcoded and expected to be present in your asset:
// //
// gui_panel(): // gui_panel():
// - "panel" (overridable) // - "panel" (overridable)
// gui_button(): // gui_button():
// - "button" (base overridable) // - "button" (base overridable)
// - "_hover" (ex. "scarybtn_hover") // - "_hover" (ex. "scarybtn_hover")
// - "_press" // - "_press"
// gui_rect(): // gui_rect():
// - no defaults, always pass your own skin/slice name // - no defaults, always pass your own skin/slice name
// gui_slider(): // gui_slider():
// - "slider" (overridable) // - "slider" (overridable)
// - "slider_cursor" (partially overridable, ex. "bigslider_cursor") // - "slider_cursor" (partially overridable, ex. "bigslider_cursor")
// - "_hover" (ex. "slider_cursor_hover") // - "_hover" (ex. "slider_cursor_hover")
// - "_press" // - "_press"
// //
API guiskin_t gui_skinned(const char *asefile, float scale); API guiskin_t gui_skinned(const char *asefile, float scale);

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +1,124 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// input framework // input framework
// - rlyeh, public domain // - rlyeh, public domain
// //
// @todo: window // @todo: window
// @todo: for extra savings (168->72 bytes), promote bits to real bits (/8 %8) & normalized floats [-1,+1] to shorts or chars // @todo: for extra savings (168->72 bytes), promote bits to real bits (/8 %8) & normalized floats [-1,+1] to shorts or chars
// @todo: GAMEPAD_A|2, MOUSE_L|1, KEY_C|3 // @todo: GAMEPAD_A|2, MOUSE_L|1, KEY_C|3
// @todo: load/save // @todo: load/save
// @todo: send virtual presses & outputs (rumble, light, led, text, etc) // @todo: send virtual presses & outputs (rumble, light, led, text, etc)
// @todo: fix if logger !60 hz // @todo: fix if logger !60 hz
// @tofo: fix click2/repeat edge cases // @tofo: fix click2/repeat edge cases
API int input_use( int controller_id ); // [0..3] API int input_use( int controller_id ); // [0..3]
// -- basic polling api (read input at current frame) // -- basic polling api (read input at current frame)
API float input( int vk ); API float input( int vk );
API vec2 input2( int vk ); API vec2 input2( int vk );
API float input_diff( int vk ); // @todo: rename diff->delta API float input_diff( int vk ); // @todo: rename diff->delta
API vec2 input_diff2( int vk ); // @todo: rename diff2->delta2 API vec2 input_diff2( int vk ); // @todo: rename diff2->delta2
API const char* input_string( int vk ); API const char* input_string( int vk );
// -- extended polling api (read input at Nth frame ago) // -- extended polling api (read input at Nth frame ago)
API float input_frame( int vk, int Nth_frame ); API float input_frame( int vk, int Nth_frame );
API vec2 input_frame2( int vk, int Nth_frame ); API vec2 input_frame2( int vk, int Nth_frame );
// -- events api // -- events api
API int input_up( int vk ); // ON -> OFF (release) API int input_up( int vk ); // ON -> OFF (release)
API int input_down( int vk ); // OFF -> ON (trigger) API int input_down( int vk ); // OFF -> ON (trigger)
API int input_held( int vk ); // ON -> ON (pressed) API int input_held( int vk ); // ON -> ON (pressed)
API int input_idle( int vk ); // OFF -> OFF API int input_idle( int vk ); // OFF -> OFF
API int input_click( int vk, int ms ); // OFF -> ON -> OFF API int input_click( int vk, int ms ); // OFF -> ON -> OFF
API int input_click2( int vk, int ms ); // OFF -> ON -> OFF -> ON -> OFF API int input_click2( int vk, int ms ); // OFF -> ON -> OFF -> ON -> OFF
API int input_repeat( int vk, int ms ); // [...] ON -> ON -> ON API int input_repeat( int vk, int ms ); // [...] ON -> ON -> ON
API int input_chord2( int vk1, int vk2 ); // all vk1 && vk2 are ON API int input_chord2( int vk1, int vk2 ); // all vk1 && vk2 are ON
API int input_chord3( int vk1, int vk2, int vk3 ); // all vk1 && vk2 && vk3 are ON API int input_chord3( int vk1, int vk2, int vk3 ); // all vk1 && vk2 && vk3 are ON
API int input_chord4( int vk1, int vk2, int vk3, int vk4 ); // all vk1 && vk2 && vk3 && vk4 are ON API int input_chord4( int vk1, int vk2, int vk3, int vk4 ); // all vk1 && vk2 && vk3 && vk4 are ON
// -- 1d/2d filters // -- 1d/2d filters
API float input_filter_positive( float v ); // [-1..1] -> [0..1] API float input_filter_positive( float v ); // [-1..1] -> [0..1]
API vec2 input_filter_positive2( vec2 v ); // [-1..1] -> [0..1] API vec2 input_filter_positive2( vec2 v ); // [-1..1] -> [0..1]
API vec2 input_filter_deadzone( vec2 v, float deadzone_treshold ); API vec2 input_filter_deadzone( vec2 v, float deadzone_treshold );
API vec2 input_filter_deadzone_4way( vec2 v, float deadzone_treshold ); API vec2 input_filter_deadzone_4way( vec2 v, float deadzone_treshold );
// -- multi-touch // -- multi-touch
enum TOUCH_BUTTONS { enum TOUCH_BUTTONS {
TOUCH_0, // defaults to left screen area. input_touch_area() to override TOUCH_0, // defaults to left screen area. input_touch_area() to override
TOUCH_1, // defaults to right screen area. input_touch_area() to override TOUCH_1, // defaults to right screen area. input_touch_area() to override
}; };
API void input_touch_area(unsigned button, vec2 begin_coord_ndc, vec2 end_coord_ndc); API void input_touch_area(unsigned button, vec2 begin_coord_ndc, vec2 end_coord_ndc);
API vec2 input_touch(unsigned button, float sensitivity); // absolute position in 2d coords API vec2 input_touch(unsigned button, float sensitivity); // absolute position in 2d coords
API vec2 input_touch_delta(unsigned button, float sensitivity); // delta from previous position API vec2 input_touch_delta(unsigned button, float sensitivity); // delta from previous position
API vec2 input_touch_delta_from_origin(unsigned button, float sensitivity); // relative position from initial touch API vec2 input_touch_delta_from_origin(unsigned button, float sensitivity); // relative position from initial touch
API bool input_touch_active(); API bool input_touch_active();
// -- utils // -- utils
API void input_mappings(const char *filename); // update gamepad mappings (usually "gamecontrollerdb.txt" file) API void input_mappings(const char *filename); // update gamepad mappings (usually "gamecontrollerdb.txt" file)
API char input_keychar(unsigned code); // Converts keyboard code to its latin char (if any) API char input_keychar(unsigned code); // Converts keyboard code to its latin char (if any)
API int input_enum(const char *sym); API int input_enum(const char *sym);
API int input_anykey(); API int input_anykey();
API int input_eval(const char *expression); // "down(X)*input(CTRL)" API int input_eval(const char *expression); // "down(X)*input(CTRL)"
// inject state // inject state
API void input_send( int vk ); // @todo API void input_send( int vk ); // @todo
// load/save input // load/save input
API array(char) save_input(); // @todo API array(char) save_input(); // @todo
API bool load_input(array(char) replay); // @todo API bool load_input(array(char) replay); // @todo
// visualize input // visualize input
API int ui_keyboard(); API int ui_keyboard();
API int ui_mouse(); API int ui_mouse();
API int ui_gamepad(int id); API int ui_gamepad(int id);
API int ui_gamepads(); API int ui_gamepads();
// -- // --
enum INPUT_ENUMS { enum INPUT_ENUMS {
// -- bits: x104 keyboard, x3 mouse, x15 gamepad, x7 window // -- bits: x104 keyboard, x3 mouse, x15 gamepad, x7 window
// keyboard gaming keys (53-bit): first-class keys for gaming // keyboard gaming keys (53-bit): first-class keys for gaming
KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9, KEY_TICK,KEY_BS, KEY_ESC, KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9, KEY_TICK,KEY_BS, KEY_ESC,
KEY_TAB, KEY_Q,KEY_W,KEY_E,KEY_R,KEY_T,KEY_Y,KEY_U,KEY_I,KEY_O,KEY_P, KEY_TAB, KEY_Q,KEY_W,KEY_E,KEY_R,KEY_T,KEY_Y,KEY_U,KEY_I,KEY_O,KEY_P,
KEY_CAPS, KEY_A,KEY_S,KEY_D,KEY_F,KEY_G,KEY_H,KEY_J,KEY_K,KEY_L, KEY_ENTER, KEY_CAPS, KEY_A,KEY_S,KEY_D,KEY_F,KEY_G,KEY_H,KEY_J,KEY_K,KEY_L, KEY_ENTER,
KEY_LSHIFT, KEY_Z,KEY_X,KEY_C,KEY_V,KEY_B,KEY_N,KEY_M, KEY_RSHIFT, KEY_UP, KEY_LSHIFT, KEY_Z,KEY_X,KEY_C,KEY_V,KEY_B,KEY_N,KEY_M, KEY_RSHIFT, KEY_UP,
KEY_LCTRL,KEY_LALT, KEY_SPACE, KEY_RALT,KEY_RCTRL, KEY_LEFT,KEY_DOWN,KEY_RIGHT, KEY_LCTRL,KEY_LALT, KEY_SPACE, KEY_RALT,KEY_RCTRL, KEY_LEFT,KEY_DOWN,KEY_RIGHT,
// for completeness, secondary keys below (52-bit). beware! // for completeness, secondary keys below (52-bit). beware!
KEY_INS,KEY_HOME,KEY_PGUP,KEY_DEL,KEY_END,KEY_PGDN, // beware: different behavior win/osx (also, osx: no home/end). KEY_INS,KEY_HOME,KEY_PGUP,KEY_DEL,KEY_END,KEY_PGDN, // beware: different behavior win/osx (also, osx: no home/end).
KEY_LMETA,KEY_RMETA,KEY_MENU,KEY_PRINT,KEY_PAUSE,KEY_SCROLL,KEY_NUMLOCK, // beware: may trigger unexpected OS behavior. (@todo: add RSHIFT here for win?) KEY_LMETA,KEY_RMETA,KEY_MENU,KEY_PRINT,KEY_PAUSE,KEY_SCROLL,KEY_NUMLOCK, // beware: may trigger unexpected OS behavior. (@todo: add RSHIFT here for win?)
KEY_MINUS,KEY_EQUAL,KEY_LSQUARE,KEY_RSQUARE,KEY_SEMICOLON,KEY_QUOTE,KEY_HASH,KEY_BAR,KEY_COMMA,KEY_DOT,KEY_SLASH, // beware: non-us keyboard layouts KEY_MINUS,KEY_EQUAL,KEY_LSQUARE,KEY_RSQUARE,KEY_SEMICOLON,KEY_QUOTE,KEY_HASH,KEY_BAR,KEY_COMMA,KEY_DOT,KEY_SLASH, // beware: non-us keyboard layouts
KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_F11,KEY_F12, // beware: complicated on laptops/osx KEY_F1,KEY_F2,KEY_F3,KEY_F4,KEY_F5,KEY_F6,KEY_F7,KEY_F8,KEY_F9,KEY_F10,KEY_F11,KEY_F12, // beware: complicated on laptops/osx
KEY_PAD1,KEY_PAD2,KEY_PAD3,KEY_PAD4,KEY_PAD5,KEY_PAD6,KEY_PAD7,KEY_PAD8,KEY_PAD9,KEY_PAD0, // beware: complicated on laptops KEY_PAD1,KEY_PAD2,KEY_PAD3,KEY_PAD4,KEY_PAD5,KEY_PAD6,KEY_PAD7,KEY_PAD8,KEY_PAD9,KEY_PAD0, // beware: complicated on laptops
KEY_PADADD,KEY_PADSUB,KEY_PADMUL,KEY_PADDIV,KEY_PADDOT,KEY_PADENTER, // beware: complicated on laptops KEY_PADADD,KEY_PADSUB,KEY_PADMUL,KEY_PADDIV,KEY_PADDOT,KEY_PADENTER, // beware: complicated on laptops
MOUSE_L, MOUSE_M, MOUSE_R, // @todo: MOUSE_CLICKS, MOUSE_L, MOUSE_M, MOUSE_R, // @todo: MOUSE_CLICKS,
GAMEPAD_CONNECTED, GAMEPAD_A, GAMEPAD_B, GAMEPAD_X, GAMEPAD_Y, GAMEPAD_CONNECTED, GAMEPAD_A, GAMEPAD_B, GAMEPAD_X, GAMEPAD_Y,
GAMEPAD_UP, GAMEPAD_DOWN, GAMEPAD_LEFT, GAMEPAD_RIGHT, GAMEPAD_MENU, GAMEPAD_START, GAMEPAD_UP, GAMEPAD_DOWN, GAMEPAD_LEFT, GAMEPAD_RIGHT, GAMEPAD_MENU, GAMEPAD_START,
GAMEPAD_LB, GAMEPAD_RB, GAMEPAD_LTHUMB, GAMEPAD_RTHUMB, GAMEPAD_LB, GAMEPAD_RB, GAMEPAD_LTHUMB, GAMEPAD_RTHUMB,
WINDOW_BLUR, WINDOW_FOCUS, WINDOW_CLOSE, WINDOW_MINIMIZE, WINDOW_MAXIMIZE, WINDOW_FULLSCREEN, WINDOW_WINDOWED, // MINI/MAXI/RESTORED, SHOWN/HIDDEN WINDOW_BLUR, WINDOW_FOCUS, WINDOW_CLOSE, WINDOW_MINIMIZE, WINDOW_MAXIMIZE, WINDOW_FULLSCREEN, WINDOW_WINDOWED, // MINI/MAXI/RESTORED, SHOWN/HIDDEN
// -- floats: x7 gamepad, x3 mouse, x4 touch, x4 window // -- floats: x7 gamepad, x3 mouse, x4 touch, x4 window
GAMEPAD_LPAD, GAMEPAD_LPADX = GAMEPAD_LPAD, GAMEPAD_LPADY, GAMEPAD_LPAD, GAMEPAD_LPADX = GAMEPAD_LPAD, GAMEPAD_LPADY,
GAMEPAD_RPAD, GAMEPAD_RPADX = GAMEPAD_RPAD, GAMEPAD_RPADY, GAMEPAD_RPAD, GAMEPAD_RPADX = GAMEPAD_RPAD, GAMEPAD_RPADY,
GAMEPAD_LTRIGGER, GAMEPAD_LT = GAMEPAD_LTRIGGER, GAMEPAD_RTRIGGER, GAMEPAD_RT = GAMEPAD_RTRIGGER, GAMEPAD_BATTERY, GAMEPAD_LTRIGGER, GAMEPAD_LT = GAMEPAD_LTRIGGER, GAMEPAD_RTRIGGER, GAMEPAD_RT = GAMEPAD_RTRIGGER, GAMEPAD_BATTERY,
MOUSE, MOUSE_X = MOUSE, MOUSE_Y, MOUSE_W, MOUSE, MOUSE_X = MOUSE, MOUSE_Y, MOUSE_W,
TOUCH_X1, TOUCH_Y1, TOUCH_X2, TOUCH_Y2, TOUCH_X1, TOUCH_Y1, TOUCH_X2, TOUCH_Y2,
WINDOW_RESIZE, WINDOW_RESIZEX = WINDOW_RESIZE, WINDOW_RESIZEY, WINDOW_ORIENTATION, WINDOW_BATTERY, WINDOW_RESIZE, WINDOW_RESIZEX = WINDOW_RESIZE, WINDOW_RESIZEY, WINDOW_ORIENTATION, WINDOW_BATTERY,
// -- strings: x2 gamepad // -- strings: x2 gamepad
GAMEPAD_GUID, GAMEPAD_NAME, GAMEPAD_GUID, GAMEPAD_NAME,
}; };
// these aliases do check both left and right counterparts // these aliases do check both left and right counterparts
enum INPUT_ALIASES { enum INPUT_ALIASES {
KEY_SHIFT = KEY_LSHIFT, KEY_SHIFT = KEY_LSHIFT,
KEY_ALT = KEY_LALT, KEY_ALT = KEY_LALT,
KEY_CTRL = KEY_LCTRL, KEY_CTRL = KEY_LCTRL,
}; };

View File

@ -1,90 +1,90 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static void v4k_pre_init() { static void v4k_pre_init() {
window_icon(va("%s%s.png", app_path(), app_name())); window_icon(va("%s%s.png", app_path(), app_name()));
glfwPollEvents(); glfwPollEvents();
int i; int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i) { for( i = 0; i <= 3; ++i) {
/**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up /**/ if( i == 0 ) ddraw_init();// init this on thread#0 since it will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
else if( i == 1 ) sprite_init(); else if( i == 1 ) sprite_init();
else if( i == 2 ) profiler_init(); else if( i == 2 ) profiler_init();
else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems else if( i == 3 ) storage_mount("save/"), storage_read(), touch_init(); // for ems
} }
// window_swap(); // window_swap();
} }
static void v4k_post_init(float refresh_rate) { static void v4k_post_init(float refresh_rate) {
// cook cleanup // cook cleanup
cook_stop(); cook_stop();
vfs_reload(); vfs_reload();
// init subsystems that depend on cooked assets now // init subsystems that depend on cooked assets now
int i; int i;
#pragma omp parallel for #pragma omp parallel for
for( i = 0; i <= 3; ++i ) { for( i = 0; i <= 3; ++i ) {
if(i == 0) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up if(i == 0) scene_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
if(i == 0) ui_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up if(i == 0) ui_init(); // init these on thread #0, since both will be compiling shaders, and shaders need to be compiled from the very same thread than glfwMakeContextCurrent() was set up
if(i == 0) window_icon(va("%s.png", app_name())); // init on thread #0, because of glfw if(i == 0) window_icon(va("%s.png", app_name())); // init on thread #0, because of glfw
if(i == 0) input_init(); // init on thread #0, because of glfw if(i == 0) input_init(); // init on thread #0, because of glfw
if(i == 1) audio_init(0); if(i == 1) audio_init(0);
if(i == 2) script_init(), kit_init(), midi_init(); if(i == 2) script_init(), kit_init(), midi_init();
if(i == 3) network_init(); if(i == 3) network_init();
} }
// display window // display window
glfwShowWindow(window); glfwShowWindow(window);
glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h); glfwGetFramebufferSize(window, &w, &h); //glfwGetWindowSize(window, &w, &h);
randset(time_ns()); randset(time_ns());
boot_time = -time_ss(); // measure boot time, this is continued in window_stats() boot_time = -time_ss(); // measure boot time, this is continued in window_stats()
// clean any errno setup by cooking stage // clean any errno setup by cooking stage
errno = 0; errno = 0;
hz = refresh_rate; hz = refresh_rate;
// t = glfwGetTime(); // t = glfwGetTime();
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
static static
void v4k_quit(void) { void v4k_quit(void) {
storage_flush(); storage_flush();
midi_quit(); midi_quit();
} }
void v4k_init() { void v4k_init() {
do_once { do_once {
// install signal handlers // install signal handlers
ifdef(debug, trap_install()); ifdef(debug, trap_install());
// init panic handler // init panic handler
panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 1<<20); // 1MiB panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 1<<20); // 1MiB
// init glfw // init glfw
glfw_init(); glfw_init();
// enable ansi console // enable ansi console
tty_init(); tty_init();
// chdir to root (if invoked as tcc -g -run) // chdir to root (if invoked as tcc -g -run)
// chdir(app_path()); // chdir(app_path());
// skip tcc argvs (if invoked as tcc file.c v4k.c -g -run) (win) // skip tcc argvs (if invoked as tcc file.c v4k.c -g -run) (win)
if( __argc > 1 ) if( strstr(__argv[0], "/tcc") || strstr(__argv[0], "\\tcc") ) { if( __argc > 1 ) if( strstr(__argv[0], "/tcc") || strstr(__argv[0], "\\tcc") ) {
__argc = 0; __argc = 0;
} }
// create or update cook.zip file // create or update cook.zip file
if( /* !COOK_ON_DEMAND && */ have_tools() && cook_jobs() ) { if( /* !COOK_ON_DEMAND && */ have_tools() && cook_jobs() ) {
cook_start(COOK_INI, "**", 0|COOK_ASYNC|COOK_CANCELABLE ); cook_start(COOK_INI, "**", 0|COOK_ASYNC|COOK_CANCELABLE );
} }
atexit(v4k_quit); atexit(v4k_quit);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,279 +1,279 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// math framework: rand, ease, vec2, vec3, vec4, quat, mat2, mat33, mat34, mat4 // math framework: rand, ease, vec2, vec3, vec4, quat, mat2, mat33, mat34, mat4
// - rlyeh, public domain // - rlyeh, public domain
// //
// Credits: @ands+@krig+@vurtun (PD), @datenwolf (WTFPL2), @evanw+@barerose (CC0), @sgorsten (Unlicense). // Credits: @ands+@krig+@vurtun (PD), @datenwolf (WTFPL2), @evanw+@barerose (CC0), @sgorsten (Unlicense).
#define C_EPSILON (1e-6) #define C_EPSILON (1e-6)
#define C_PI (3.14159265358979323846f) // (3.141592654f) #define C_PI (3.14159265358979323846f) // (3.141592654f)
#define TO_RAD (C_PI/180) #define TO_RAD (C_PI/180)
#define TO_DEG (180/C_PI) #define TO_DEG (180/C_PI)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
//#define ptr(type) 0[&(type).x] //#define ptr(type) 0[&(type).x]
#define vec2i(x, y ) C_CAST(vec2i,(int)(x), (int)(y) ) #define vec2i(x, y ) C_CAST(vec2i,(int)(x), (int)(y) )
#define vec3i(x, y, z ) C_CAST(vec3i,(int)(x), (int)(y), (int)(z) ) #define vec3i(x, y, z ) C_CAST(vec3i,(int)(x), (int)(y), (int)(z) )
#define vec2(x, y ) C_CAST(vec2, (float)(x), (float)(y) ) #define vec2(x, y ) C_CAST(vec2, (float)(x), (float)(y) )
#define vec3(x, y, z ) C_CAST(vec3, (float)(x), (float)(y), (float)(z), ) #define vec3(x, y, z ) C_CAST(vec3, (float)(x), (float)(y), (float)(z), )
#define vec4(x, y, z, w) C_CAST(vec4, (float)(x), (float)(y), (float)(z), (float)(w)) #define vec4(x, y, z, w) C_CAST(vec4, (float)(x), (float)(y), (float)(z), (float)(w))
#define quat(x, y, z, w) C_CAST(quat, (float)(x), (float)(y), (float)(z), (float)(w)) #define quat(x, y, z, w) C_CAST(quat, (float)(x), (float)(y), (float)(z), (float)(w))
#define axis(x, y, z) C_CAST(axis, (float)(x), (float)(y), (float)(z)) #define axis(x, y, z) C_CAST(axis, (float)(x), (float)(y), (float)(z))
#define mat33(...) C_CAST(mat33, __VA_ARGS__ ) #define mat33(...) C_CAST(mat33, __VA_ARGS__ )
#define mat34(...) C_CAST(mat34, __VA_ARGS__ ) #define mat34(...) C_CAST(mat34, __VA_ARGS__ )
#define mat44(...) C_CAST(mat44, __VA_ARGS__ ) #define mat44(...) C_CAST(mat44, __VA_ARGS__ )
typedef union vec2i{ struct { int X,Y; }; struct { int x,y; }; struct { int r,g; }; struct { int w,h; }; struct { int min,max; }; struct { int from,to; }; struct { int src,dst; }; int v2[2]; int array[1]; } vec2i; typedef union vec2i{ struct { int X,Y; }; struct { int x,y; }; struct { int r,g; }; struct { int w,h; }; struct { int min,max; }; struct { int from,to; }; struct { int src,dst; }; int v2[2]; int array[1]; } vec2i;
typedef union vec3i{ struct { int X,Y,Z; }; struct { int x,y,z; }; struct { int r,g,b; }; struct { int w,h,d; }; struct { int min,max; }; struct { int from,to,step; }; struct { int src,dst; }; int v3[3]; int array[1]; } vec3i; typedef union vec3i{ struct { int X,Y,Z; }; struct { int x,y,z; }; struct { int r,g,b; }; struct { int w,h,d; }; struct { int min,max; }; struct { int from,to,step; }; struct { int src,dst; }; int v3[3]; int array[1]; } vec3i;
typedef union vec2 { struct { float X,Y; }; struct { float x,y; }; struct { float r,g; }; struct { float w,h; }; struct { float min,max; }; struct { float from,to; }; struct { float src,dst; }; float v2[2]; float array[1]; } vec2; typedef union vec2 { struct { float X,Y; }; struct { float x,y; }; struct { float r,g; }; struct { float w,h; }; struct { float min,max; }; struct { float from,to; }; struct { float src,dst; }; float v2[2]; float array[1]; } vec2;
typedef union vec3 { struct { float X,Y,Z; }; struct { float x,y,z; }; struct { float r,g,b; }; struct { float min,max; }; struct { float from,to; }; vec2 xy; vec2 rg; vec2 wh; float v3[3]; float array[1]; } vec3; typedef union vec3 { struct { float X,Y,Z; }; struct { float x,y,z; }; struct { float r,g,b; }; struct { float min,max; }; struct { float from,to; }; vec2 xy; vec2 rg; vec2 wh; float v3[3]; float array[1]; } vec3;
typedef union vec4 { struct { float X,Y,Z,W; }; struct { float x,y,z,w; }; struct { float r,g,b,a; }; struct { float min,max; }; struct { float from,to; }; vec2 xy; vec3 xyz; vec2 rg; vec3 rgb; vec2 wh; vec3 whd; float v4[4]; float array[1]; } vec4; typedef union vec4 { struct { float X,Y,Z,W; }; struct { float x,y,z,w; }; struct { float r,g,b,a; }; struct { float min,max; }; struct { float from,to; }; vec2 xy; vec3 xyz; vec2 rg; vec3 rgb; vec2 wh; vec3 whd; float v4[4]; float array[1]; } vec4;
typedef union quat { struct { float X,Y,Z,W; }; struct { float x,y,z,w; }; vec3 xyz; vec4 xyzw; float v4[4]; float array[1]; } quat; typedef union quat { struct { float X,Y,Z,W; }; struct { float x,y,z,w; }; vec3 xyz; vec4 xyzw; float v4[4]; float array[1]; } quat;
typedef float mat33[9]; typedef float mat33[9];
typedef float mat34[12]; typedef float mat34[12];
typedef float mat44[16]; typedef float mat44[16];
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API void randset(uint64_t state); API void randset(uint64_t state);
API uint64_t rand64(void); API uint64_t rand64(void);
API double randf(void); // [0, 1) interval API double randf(void); // [0, 1) interval
API int randi(int mini, int maxi); // [mini, maxi) interval API int randi(int mini, int maxi); // [mini, maxi) interval
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API float simplex1( float x ); API float simplex1( float x );
API float simplex2( vec2 xy ); API float simplex2( vec2 xy );
API float simplex3( vec3 xyz ); API float simplex3( vec3 xyz );
API float simplex4( vec4 xyzw ); API float simplex4( vec4 xyzw );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API float deg (float radians); API float deg (float radians);
API float rad (float degrees); API float rad (float degrees);
API int mini (int a, int b); API int mini (int a, int b);
API int maxi (int a, int b); API int maxi (int a, int b);
API int absi (int a ); API int absi (int a );
API int clampi (int v,int a,int b); API int clampi (int v,int a,int b);
API float minf (float a, float b); API float minf (float a, float b);
API float maxf (float a, float b); API float maxf (float a, float b);
API float absf (float a ); API float absf (float a );
API float pmodf (float a, float b); API float pmodf (float a, float b);
API float signf (float a) ; API float signf (float a) ;
API float clampf (float v,float a,float b); API float clampf (float v,float a,float b);
API float mixf (float a,float b,float t); API float mixf (float a,float b,float t);
API float slerpf (float a,float b,float t); API float slerpf (float a,float b,float t);
API float fractf (float a); API float fractf (float a);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API vec2 ptr2 (const float *a ); API vec2 ptr2 (const float *a );
// //
API vec2 neg2 (vec2 a ); API vec2 neg2 (vec2 a );
API vec2 add2 (vec2 a, vec2 b); API vec2 add2 (vec2 a, vec2 b);
API vec2 sub2 (vec2 a, vec2 b); API vec2 sub2 (vec2 a, vec2 b);
API vec2 mul2 (vec2 a, vec2 b); API vec2 mul2 (vec2 a, vec2 b);
API vec2 div2 (vec2 a, vec2 b); API vec2 div2 (vec2 a, vec2 b);
API vec2 inc2 (vec2 a, float b); API vec2 inc2 (vec2 a, float b);
API vec2 dec2 (vec2 a, float b); API vec2 dec2 (vec2 a, float b);
API vec2 scale2 (vec2 a, float b); API vec2 scale2 (vec2 a, float b);
API vec2 pmod2 (vec2 a, float b); API vec2 pmod2 (vec2 a, float b);
API vec2 min2 (vec2 a, vec2 b); API vec2 min2 (vec2 a, vec2 b);
API vec2 max2 (vec2 a, vec2 b); API vec2 max2 (vec2 a, vec2 b);
API vec2 abs2 (vec2 a ); API vec2 abs2 (vec2 a );
API vec2 floor2 (vec2 a ); API vec2 floor2 (vec2 a );
API vec2 fract2 (vec2 a ); API vec2 fract2 (vec2 a );
API vec2 ceil2 (vec2 a ); API vec2 ceil2 (vec2 a );
API float dot2 (vec2 a, vec2 b); API float dot2 (vec2 a, vec2 b);
API vec2 refl2 (vec2 a, vec2 b); API vec2 refl2 (vec2 a, vec2 b);
API float cross2 (vec2 a, vec2 b); API float cross2 (vec2 a, vec2 b);
API float len2sq (vec2 a ); API float len2sq (vec2 a );
API float len2 (vec2 a ); API float len2 (vec2 a );
API vec2 norm2 (vec2 a ); API vec2 norm2 (vec2 a );
API int finite2 (vec2 a ); API int finite2 (vec2 a );
API vec2 mix2 (vec2 a,vec2 b,float t); API vec2 mix2 (vec2 a,vec2 b,float t);
API vec2 clamp2(vec2 v,vec2 a,vec2 b); API vec2 clamp2(vec2 v,vec2 a,vec2 b);
API vec2 clamp2f(vec2 v,float a,float b); API vec2 clamp2f(vec2 v,float a,float b);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API vec3 rnd3 (void); // @todo: rnd2,rnd4,rndq API vec3 rnd3 (void); // @todo: rnd2,rnd4,rndq
API vec3 ptr3 (const float *a ); API vec3 ptr3 (const float *a );
API vec3 vec23 (vec2 a, float z ); API vec3 vec23 (vec2 a, float z );
// //
API vec3 neg3 (vec3 a ); API vec3 neg3 (vec3 a );
API vec3 add3 (vec3 a, vec3 b); API vec3 add3 (vec3 a, vec3 b);
API vec3 sub3 (vec3 a, vec3 b); API vec3 sub3 (vec3 a, vec3 b);
API vec3 mul3 (vec3 a, vec3 b); API vec3 mul3 (vec3 a, vec3 b);
API vec3 div3 (vec3 a, vec3 b); API vec3 div3 (vec3 a, vec3 b);
API vec3 inc3 (vec3 a, float b); API vec3 inc3 (vec3 a, float b);
API vec3 dec3 (vec3 a, float b); API vec3 dec3 (vec3 a, float b);
API vec3 scale3 (vec3 a, float b); API vec3 scale3 (vec3 a, float b);
API vec3 pmod3 (vec3 a, float b); API vec3 pmod3 (vec3 a, float b);
API vec3 min3 (vec3 a, vec3 b); API vec3 min3 (vec3 a, vec3 b);
API vec3 max3 (vec3 a, vec3 b); API vec3 max3 (vec3 a, vec3 b);
API vec3 abs3 (vec3 a ); API vec3 abs3 (vec3 a );
API vec3 floor3 (vec3 a ); API vec3 floor3 (vec3 a );
API vec3 fract3 (vec3 a ); API vec3 fract3 (vec3 a );
API vec3 ceil3 (vec3 a ); API vec3 ceil3 (vec3 a );
API vec3 cross3 (vec3 a, vec3 b); API vec3 cross3 (vec3 a, vec3 b);
API float dot3 (vec3 a, vec3 b); API float dot3 (vec3 a, vec3 b);
API vec3 refl3 (vec3 a, vec3 b); API vec3 refl3 (vec3 a, vec3 b);
API float len3sq (vec3 a ); API float len3sq (vec3 a );
API float len3 (vec3 a ); API float len3 (vec3 a );
API vec3 norm3 (vec3 a ); API vec3 norm3 (vec3 a );
API vec3 norm3sq (vec3 a ); API vec3 norm3sq (vec3 a );
API int finite3 (vec3 a ); API int finite3 (vec3 a );
API vec3 mix3 (vec3 a,vec3 b,float t); API vec3 mix3 (vec3 a,vec3 b,float t);
API vec3 clamp3(vec3 v,vec3 a,vec3 b); API vec3 clamp3(vec3 v,vec3 a,vec3 b);
API vec3 clamp3f(vec3 v,float a,float b); API vec3 clamp3f(vec3 v,float a,float b);
//vec3 tricross3 (vec3 a, vec3 b, vec3 c); //vec3 tricross3 (vec3 a, vec3 b, vec3 c);
API void ortho3 (vec3 *left, vec3 *up, vec3 v); API void ortho3 (vec3 *left, vec3 *up, vec3 v);
API vec3 rotatex3 (vec3 dir, float degrees); API vec3 rotatex3 (vec3 dir, float degrees);
API vec3 rotatey3 (vec3 dir, float degrees); API vec3 rotatey3 (vec3 dir, float degrees);
API vec3 rotatez3 (vec3 dir, float degrees); API vec3 rotatez3 (vec3 dir, float degrees);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API vec4 ptr4 (const float *a ); API vec4 ptr4 (const float *a );
API vec4 vec34 (vec3 a, float w ); API vec4 vec34 (vec3 a, float w );
// //
API vec4 neg4 (vec4 a ); API vec4 neg4 (vec4 a );
API vec4 add4 (vec4 a, vec4 b); API vec4 add4 (vec4 a, vec4 b);
API vec4 sub4 (vec4 a, vec4 b); API vec4 sub4 (vec4 a, vec4 b);
API vec4 mul4 (vec4 a, vec4 b); API vec4 mul4 (vec4 a, vec4 b);
API vec4 div4 (vec4 a, vec4 b); API vec4 div4 (vec4 a, vec4 b);
API vec4 inc4 (vec4 a, float b); API vec4 inc4 (vec4 a, float b);
API vec4 dec4 (vec4 a, float b); API vec4 dec4 (vec4 a, float b);
API vec4 scale4 (vec4 a, float b); API vec4 scale4 (vec4 a, float b);
API vec4 pmod4 (vec4 a, float b); API vec4 pmod4 (vec4 a, float b);
API vec4 min4 (vec4 a, vec4 b); API vec4 min4 (vec4 a, vec4 b);
API vec4 max4 (vec4 a, vec4 b); API vec4 max4 (vec4 a, vec4 b);
API vec4 abs4 (vec4 a ); API vec4 abs4 (vec4 a );
API vec4 floor4 (vec4 a ); API vec4 floor4 (vec4 a );
API vec4 fract4 (vec4 a ); API vec4 fract4 (vec4 a );
API vec4 ceil4 (vec4 a ); API vec4 ceil4 (vec4 a );
API float dot4 (vec4 a, vec4 b); API float dot4 (vec4 a, vec4 b);
API vec4 refl4 (vec4 a, vec4 b); API vec4 refl4 (vec4 a, vec4 b);
API float len4sq (vec4 a ); API float len4sq (vec4 a );
API float len4 (vec4 a ); API float len4 (vec4 a );
API vec4 norm4 (vec4 a ); API vec4 norm4 (vec4 a );
API vec4 norm4sq (vec4 a ); API vec4 norm4sq (vec4 a );
API int finite4 (vec4 a ); API int finite4 (vec4 a );
API vec4 mix4 (vec4 a,vec4 b,float t); API vec4 mix4 (vec4 a,vec4 b,float t);
API vec4 clamp4(vec4 v,vec4 a,vec4 b); API vec4 clamp4(vec4 v,vec4 a,vec4 b);
API vec4 clamp4f(vec4 v,float a,float b); API vec4 clamp4f(vec4 v,float a,float b);
// vec4 cross4(vec4 v0, vec4 v1); // vec4 cross4(vec4 v0, vec4 v1);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API quat idq ( ); API quat idq ( );
API quat ptrq (const float *a ); API quat ptrq (const float *a );
API quat vec3q (vec3 a, float w ); API quat vec3q (vec3 a, float w );
API quat vec4q (vec4 a ); API quat vec4q (vec4 a );
// //
API quat negq (quat a ); API quat negq (quat a );
API quat conjq (quat a ); API quat conjq (quat a );
API quat addq (quat a, quat b); API quat addq (quat a, quat b);
API quat subq (quat a, quat b); API quat subq (quat a, quat b);
API quat mulq (quat p, quat q); API quat mulq (quat p, quat q);
API quat scaleq (quat a, float s); API quat scaleq (quat a, float s);
API quat normq (quat a ); API quat normq (quat a );
API float dotq (quat a, quat b); API float dotq (quat a, quat b);
API quat mixq(quat a, quat b, float t); API quat mixq(quat a, quat b, float t);
/* quat lerpq(quat a, quat b, float s); /* quat lerpq(quat a, quat b, float s);
return norm(quat((1-s)*a.x + s*b.x, (1-s)*a.y + s*b.y, (1-s)*a.z + s*b.z, (1-s)*a.w + s*b.w)); return norm(quat((1-s)*a.x + s*b.x, (1-s)*a.y + s*b.y, (1-s)*a.z + s*b.z, (1-s)*a.w + s*b.w));
}*/ }*/
API quat slerpq(quat a, quat b, float s); API quat slerpq(quat a, quat b, float s);
API quat rotationq(float deg,float x,float y,float z); API quat rotationq(float deg,float x,float y,float z);
API quat mat44q (mat44 M); API quat mat44q (mat44 M);
API vec3 rotate3q_2(vec3 v, quat q); API vec3 rotate3q_2(vec3 v, quat q);
API vec3 rotate3q(vec3 v, quat r); API vec3 rotate3q(vec3 v, quat r);
// euler <-> quat // euler <-> quat
API vec3 euler (quat q); API vec3 euler (quat q);
API quat eulerq (vec3 pyr_degrees); API quat eulerq (vec3 pyr_degrees);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API void scaling33(mat33 m, float x, float y, float z); API void scaling33(mat33 m, float x, float y, float z);
API void scale33(mat33 m, float x, float y, float z); API void scale33(mat33 m, float x, float y, float z);
API void id33(mat33 m); API void id33(mat33 m);
API void extract33(mat33 m, const mat44 m4); API void extract33(mat33 m, const mat44 m4);
API void copy33(mat33 m, const mat33 a);// API void copy33(mat33 m, const mat33 a);//
API vec3 mulv33(mat33 m, vec3 v); API vec3 mulv33(mat33 m, vec3 v);
API void multiply33x2(mat33 m, const mat33 a, const mat33 b); API void multiply33x2(mat33 m, const mat33 a, const mat33 b);
API void rotation33(mat33 m, float degrees, float x,float y,float z); API void rotation33(mat33 m, float degrees, float x,float y,float z);
API void rotationq33(mat33 m, quat q); API void rotationq33(mat33 m, quat q);
API void rotate33(mat33 r, float degrees, float x,float y,float z); API void rotate33(mat33 r, float degrees, float x,float y,float z);
API void compose33(mat33 m, quat r, vec3 s); API void compose33(mat33 m, quat r, vec3 s);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API void id34(mat34 m); API void id34(mat34 m);
API void copy34(mat34 m, const mat34 a); API void copy34(mat34 m, const mat34 a);
API void scale34(mat34 m, float s); API void scale34(mat34 m, float s);
API void add34(mat34 m, mat34 n); API void add34(mat34 m, mat34 n);
API void muladd34(mat34 m, mat34 n, float s); API void muladd34(mat34 m, mat34 n, float s);
API void add34x2(mat34 m, mat34 n, mat34 o); API void add34x2(mat34 m, mat34 n, mat34 o);
API void lerp34(mat34 m, mat34 n, mat34 o, float alpha); // mix34? API void lerp34(mat34 m, mat34 n, mat34 o, float alpha); // mix34?
API void multiply34x2(mat34 m, const mat34 m0, const mat34 m1); API void multiply34x2(mat34 m, const mat34 m0, const mat34 m1);
API void multiply34(mat34 m, const mat34 a); API void multiply34(mat34 m, const mat34 a);
API void multiply34x3(mat34 m, const mat34 a, const mat34 b, const mat34 c); API void multiply34x3(mat34 m, const mat34 a, const mat34 b, const mat34 c);
API void compose34(mat34 m, vec3 t, quat q, vec3 s); API void compose34(mat34 m, vec3 t, quat q, vec3 s);
API void invert34(mat34 m, const mat34 o); API void invert34(mat34 m, const mat34 o);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API void id44(mat44 m); API void id44(mat44 m);
API void identity44(mat44 m); API void identity44(mat44 m);
API void copy44(mat44 m, const mat44 a); API void copy44(mat44 m, const mat44 a);
API void multiply44x2(mat44 m, const mat44 a, const mat44 b); API void multiply44x2(mat44 m, const mat44 a, const mat44 b);
API void multiply44x3(mat44 m, const mat44 a, const mat44 b, const mat44 c); API void multiply44x3(mat44 m, const mat44 a, const mat44 b, const mat44 c);
API void multiply44(mat44 m, const mat44 a); API void multiply44(mat44 m, const mat44 a);
// --- // ---
API void ortho44(mat44 m, float l, float r, float b, float t, float n, float f); API void ortho44(mat44 m, float l, float r, float b, float t, float n, float f);
API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f); API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f);
API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp); API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp);
API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up); API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up);
// --- // ---
API void translation44(mat44 m, float x, float y, float z); API void translation44(mat44 m, float x, float y, float z);
API void translate44(mat44 m, float x, float y, float z); API void translate44(mat44 m, float x, float y, float z);
API void relocate44(mat44 m, float x, float y, float z); API void relocate44(mat44 m, float x, float y, float z);
API void rotationq44(mat44 m, quat q); API void rotationq44(mat44 m, quat q);
API void rotation44(mat44 m, float degrees, float x, float y, float z); API void rotation44(mat44 m, float degrees, float x, float y, float z);
API void rotate44(mat44 m, float degrees, float x, float y, float z); API void rotate44(mat44 m, float degrees, float x, float y, float z);
API void scaling44(mat44 m, float x, float y, float z); API void scaling44(mat44 m, float x, float y, float z);
API void scale44(mat44 m, float x, float y, float z); API void scale44(mat44 m, float x, float y, float z);
// --- // ---
API void transpose44(mat44 m, const mat44 a); API void transpose44(mat44 m, const mat44 a);
API float det44(const mat44 M); API float det44(const mat44 M);
API bool invert44(mat44 T, const mat44 M); API bool invert44(mat44 T, const mat44 M);
API void compose44(mat44 m, vec3 t, quat q, vec3 s); API void compose44(mat44 m, vec3 t, quat q, vec3 s);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
API vec3 transformq(const quat q, const vec3 v); API vec3 transformq(const quat q, const vec3 v);
API vec3 transform33(const mat33 m, vec3 p); API vec3 transform33(const mat33 m, vec3 p);
API vec3 transform344(const mat44 m, const vec3 p); API vec3 transform344(const mat44 m, const vec3 p);
API vec4 transform444(const mat44 m, const vec4 p); API vec4 transform444(const mat44 m, const vec4 p);
API bool unproject44(vec3 *out, vec3 xyd, vec4 viewport, mat44 mvp); API bool unproject44(vec3 *out, vec3 xyd, vec4 viewport, mat44 mvp);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// debugging and utils // debugging and utils
API void print2i( vec2i v ); API void print2i( vec2i v );
API void print3i( vec3i v ); API void print3i( vec3i v );
API void print2( vec2 v ); API void print2( vec2 v );
API void print3( vec3 v ); API void print3( vec3 v );
API void print4( vec4 v ); API void print4( vec4 v );
API void printq( quat q ); API void printq( quat q );
API void print33( float *m ); API void print33( float *m );
API void print34( float *m ); API void print34( float *m );
API void print44( float *m ); API void print44( float *m );

View File

@ -1,101 +1,101 @@
size_t dlmalloc_usable_size(void*); // __ANDROID_API__ size_t dlmalloc_usable_size(void*); // __ANDROID_API__
#if is(bsd) || is(osx) // bsd or osx #if is(bsd) || is(osx) // bsd or osx
# include <malloc/malloc.h> # include <malloc/malloc.h>
#else #else
# include <malloc.h> # include <malloc.h>
#endif #endif
#ifndef SYS_MEM_INIT #ifndef SYS_MEM_INIT
#define SYS_MEM_INIT() #define SYS_MEM_INIT()
#define SYS_MEM_REALLOC realloc #define SYS_MEM_REALLOC realloc
#define SYS_MEM_SIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \ #define SYS_MEM_SIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \
ifdef(osx, malloc_size, ifdef(bsd, malloc_size, \ ifdef(osx, malloc_size, ifdef(bsd, malloc_size, \
ifdef(win32, _msize, malloc_usable_size))) ifdef(win32, _msize, malloc_usable_size)))
#endif #endif
// xrealloc -------------------------------------------------------------------- // xrealloc --------------------------------------------------------------------
static __thread uint64_t xstats_current = 0, xstats_total = 0, xstats_allocs = 0; static __thread uint64_t xstats_current = 0, xstats_total = 0, xstats_allocs = 0;
void* xrealloc(void* oldptr, size_t size) { void* xrealloc(void* oldptr, size_t size) {
static __thread int once = 0; for(;!once;once = 1) SYS_MEM_INIT(); static __thread int once = 0; for(;!once;once = 1) SYS_MEM_INIT();
// for stats // for stats
size_t oldsize = xsize(oldptr); size_t oldsize = xsize(oldptr);
void *ptr = SYS_MEM_REALLOC(oldptr, size); void *ptr = SYS_MEM_REALLOC(oldptr, size);
if( !ptr && size ) { if( !ptr && size ) {
PANIC("Not memory enough (trying to allocate %u bytes)", (unsigned)size); PANIC("Not memory enough (trying to allocate %u bytes)", (unsigned)size);
} }
#if ENABLE_MEMORY_POISON #if ENABLE_MEMORY_POISON
if( !oldptr && size ) { if( !oldptr && size ) {
memset(ptr, 0xCD, size); memset(ptr, 0xCD, size);
} }
#endif #endif
// for stats // for stats
if( oldptr ) { if( oldptr ) {
xstats_current += (int64_t)size - (int64_t)oldsize; xstats_current += (int64_t)size - (int64_t)oldsize;
xstats_allocs -= !size; xstats_allocs -= !size;
} else { } else {
xstats_current += size; xstats_current += size;
xstats_allocs += !!size; xstats_allocs += !!size;
} }
if( xstats_current > xstats_total ) { if( xstats_current > xstats_total ) {
xstats_total = xstats_current; xstats_total = xstats_current;
} }
return ptr; return ptr;
} }
size_t xsize(void* p) { size_t xsize(void* p) {
if( p ) return SYS_MEM_SIZE(p); if( p ) return SYS_MEM_SIZE(p);
return 0; return 0;
} }
char *xstats(void) { char *xstats(void) {
uint64_t xtra = 0; // xstats_allocs * 65536; // assumes 64K pagesize for every alloc uint64_t xtra = 0; // xstats_allocs * 65536; // assumes 64K pagesize for every alloc
return va("%03u/%03uMB", (unsigned)((xstats_current+xtra) / 1024 / 1024), (unsigned)((xstats_total+xtra) / 1024 / 1024)); return va("%03u/%03uMB", (unsigned)((xstats_current+xtra) / 1024 / 1024), (unsigned)((xstats_total+xtra) / 1024 / 1024));
} }
// stack ----------------------------------------------------------------------- // stack -----------------------------------------------------------------------
void* stack(int bytes) { // use negative bytes to rewind stack void* stack(int bytes) { // use negative bytes to rewind stack
static __thread uint8_t *stack_mem = 0; static __thread uint8_t *stack_mem = 0;
static __thread uint64_t stack_ptr = 0; static __thread uint64_t stack_ptr = 0;
static __thread uint64_t stack_max = 0; // watch this var, in case you want to fine tune 4 MiB value below static __thread uint64_t stack_max = 0; // watch this var, in case you want to fine tune 4 MiB value below
if( bytes < 0 ) { if( bytes < 0 ) {
if( stack_ptr > stack_max ) stack_max = stack_ptr; if( stack_ptr > stack_max ) stack_max = stack_ptr;
return (stack_ptr = 0), NULL; return (stack_ptr = 0), NULL;
} }
if( !stack_mem ) stack_mem = xrealloc(stack_mem, xsize(stack_mem) + 4 * 1024 * 1024); if( !stack_mem ) stack_mem = xrealloc(stack_mem, xsize(stack_mem) + 4 * 1024 * 1024);
return &stack_mem[ (stack_ptr += bytes) - bytes ]; return &stack_mem[ (stack_ptr += bytes) - bytes ];
} }
// leaks ---------------------------------------------------------------------- // leaks ----------------------------------------------------------------------
void* watch( void *ptr, int sz ) { void* watch( void *ptr, int sz ) {
static __thread int open = 1; static __thread int open = 1;
if( ptr && open ) { if( ptr && open ) {
open = 0; open = 0;
char buf[256]; char buf[256];
sprintf(buf, "%p.mem", ptr); sprintf(buf, "%p.mem", ptr);
for( FILE *fp = fopen(buf, "a+"); fp; fclose(fp), fp = 0 ) { for( FILE *fp = fopen(buf, "a+"); fp; fclose(fp), fp = 0 ) {
fseek(fp, 0L, SEEK_END); fseek(fp, 0L, SEEK_END);
const char *cs = callstack( +16 ); // +48 const char *cs = callstack( +16 ); // +48
fprintf(fp, "Built %s %s\n", __DATE__, __TIME__); // today() instead? fprintf(fp, "Built %s %s\n", __DATE__, __TIME__); // today() instead?
fprintf(fp, "Memleak address: [%p], size: %d\n%s\n", ptr, sz, cs ? cs : "No callstack."); fprintf(fp, "Memleak address: [%p], size: %d\n%s\n", ptr, sz, cs ? cs : "No callstack.");
} }
open = 1; open = 1;
} }
return ptr; return ptr;
} }
void* forget( void *ptr ) { void* forget( void *ptr ) {
if( ptr ) { if( ptr ) {
char buf[256]; char buf[256];
sprintf(buf, "%p.mem", ptr); sprintf(buf, "%p.mem", ptr);
unlink(buf); unlink(buf);
} }
return ptr; return ptr;
} }

View File

@ -1,37 +1,37 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// memory framework // memory framework
// - rlyeh, public domain // - rlyeh, public domain
// memory leaks detector // memory leaks detector
#if ENABLE_MEMORY_LEAKS #if ENABLE_MEMORY_LEAKS
#define WATCH(ptr,sz) watch((ptr), (sz)) #define WATCH(ptr,sz) watch((ptr), (sz))
#define FORGET(ptr) forget(ptr) #define FORGET(ptr) forget(ptr)
#else #else
#define WATCH(ptr,sz) (ptr) #define WATCH(ptr,sz) (ptr)
#define FORGET(ptr) (ptr) #define FORGET(ptr) (ptr)
#endif #endif
// default allocator (aborts on out-of-mem) // default allocator (aborts on out-of-mem)
API void* xrealloc(void* p, size_t sz); API void* xrealloc(void* p, size_t sz);
API size_t xsize(void* p); API size_t xsize(void* p);
API char* xstats(void); API char* xstats(void);
// stack based allocator (negative bytes does rewind stack, like when entering new frame) // stack based allocator (negative bytes does rewind stack, like when entering new frame)
API void* stack(int bytes); API void* stack(int bytes);
// memory leaks api (this is already integrated as long as you compile with -DENABLE_MEMORY_LEAKS) // memory leaks api (this is already integrated as long as you compile with -DENABLE_MEMORY_LEAKS)
API void* watch( void *ptr, int sz ); API void* watch( void *ptr, int sz );
API void* forget( void *ptr ); API void* forget( void *ptr );
// memory api // memory api
#define ALLOCSIZE(p) xsize(p) #define ALLOCSIZE(p) xsize(p)
#define MALLOC(n) REALLOC_(0,(n)) #define MALLOC(n) REALLOC_(0,(n))
#define FREE(p) REALLOC_((p), 0) #define FREE(p) REALLOC_((p), 0)
#define REALLOC(p,n) REALLOC_((p),(n)) #define REALLOC(p,n) REALLOC_((p),(n))
#define CALLOC(m,n) CALLOC_((m),(n)) #define CALLOC(m,n) CALLOC_((m),(n))
#define STRDUP(s) STRDUP_(s) #define STRDUP(s) STRDUP_(s)
#define ALLOCA(n) ifdef(gcc, __builtin_alloca(n), _alloca(n)) #define ALLOCA(n) ifdef(gcc, __builtin_alloca(n), _alloca(n))
static FORCE_INLINE void *(REALLOC_)(void *p, size_t n) { return n ? WATCH(xrealloc(p,n),n) : xrealloc(FORGET(p),0); } ///- static FORCE_INLINE void *(REALLOC_)(void *p, size_t n) { return n ? WATCH(xrealloc(p,n),n) : xrealloc(FORGET(p),0); } ///-
static FORCE_INLINE void *(CALLOC_)(size_t m, size_t n) { return n *= m, memset(REALLOC(0,n),0,n); } ///- static FORCE_INLINE void *(CALLOC_)(size_t m, size_t n) { return n *= m, memset(REALLOC(0,n),0,n); } ///-
static FORCE_INLINE char *(STRDUP_)(const char *s) { size_t n = strlen(s)+1; return ((char*)memcpy(REALLOC(0,n), s, n)); } ///- static FORCE_INLINE char *(STRDUP_)(const char *s) { size_t n = strlen(s)+1; return ((char*)memcpy(REALLOC(0,n), s, n)); } ///-

File diff suppressed because it is too large Load Diff

View File

@ -1,83 +1,83 @@
// high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories. // high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories.
// - rlyeh, public domain // - rlyeh, public domain
// //
// Usage: // Usage:
// 1. configure networked memory buffers with flags (world, player1, player2, etc). network_buffer(); // 1. configure networked memory buffers with flags (world, player1, player2, etc). network_buffer();
// 2. then during game loop: // 2. then during game loop:
// - modify your buffers as much as needed. // - modify your buffers as much as needed.
// - sync buffers at least once per frame. network_sync(); // - sync buffers at least once per frame. network_sync();
// - render your world // - render your world
// 3. optionally, monitor network status & variables. network_get(); // 3. optionally, monitor network status & variables. network_get();
// //
// @todo: maybe network_send(msg) + msg *network_recv(); instead of event queue of network_sync() ? // @todo: maybe network_send(msg) + msg *network_recv(); instead of event queue of network_sync() ?
//enum { NETWORK_HANDSHAKE, NETWORK_ENCRYPT, NETWORK_VERSIONED, NETWORK_CHECKSUM }; // negotiation //enum { NETWORK_HANDSHAKE, NETWORK_ENCRYPT, NETWORK_VERSIONED, NETWORK_CHECKSUM }; // negotiation
//enum { NETWORK_TCP, NETWORK_UDP, NETWORK_KCP, NETWORK_ENET, NETWORK_WEBSOCKET }; // transport, where //enum { NETWORK_TCP, NETWORK_UDP, NETWORK_KCP, NETWORK_ENET, NETWORK_WEBSOCKET }; // transport, where
enum { NETWORK_BIND = 2, NETWORK_CONNECT = 4, NETWORK_NOFAIL = 8 }; enum { NETWORK_BIND = 2, NETWORK_CONNECT = 4, NETWORK_NOFAIL = 8 };
API void network_create(unsigned max_clients, const char *ip, const char *port, unsigned flags); // both ip and port can be null API void network_create(unsigned max_clients, const char *ip, const char *port, unsigned flags); // both ip and port can be null
//enum { NETWORK_LOSSY, NETWORK_COMPRESS }; // post-processes //enum { NETWORK_LOSSY, NETWORK_COMPRESS }; // post-processes
//enum { NETWORK_PREDICT, NETWORK_RECONCILE, NETWORK_INTERPOLATE, NETWORK_COMPENSATE }; // time authority, when //enum { NETWORK_PREDICT, NETWORK_RECONCILE, NETWORK_INTERPOLATE, NETWORK_COMPENSATE }; // time authority, when
//enum { NETWORK_LAGS, NETWORK_DROPS, NETWORK_THROTTLES, NETWORK_DUPES }; // quality sim, how much //enum { NETWORK_LAGS, NETWORK_DROPS, NETWORK_THROTTLES, NETWORK_DUPES }; // quality sim, how much
//enum { NETWORK_CONST = 1, NETWORK_64,NETWORK_32,NETWORK_16,NETWORK_8, NETWORK_FLT, NETWORK_STR, NETWORK_BLOB }; // type, what //enum { NETWORK_CONST = 1, NETWORK_64,NETWORK_32,NETWORK_16,NETWORK_8, NETWORK_FLT, NETWORK_STR, NETWORK_BLOB }; // type, what
enum { NETWORK_SEND = 2, NETWORK_RECV = 4 }; enum { NETWORK_SEND = 2, NETWORK_RECV = 4 };
enum { NETWORK_UNRELIABLE = 8, NETWORK_UNORDERED = 16/*, NETWORK_PRIORITY = 32*/ }; enum { NETWORK_UNRELIABLE = 8, NETWORK_UNORDERED = 16/*, NETWORK_PRIORITY = 32*/ };
API void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank); // configures a shared/networked buffer API void* network_buffer(void *ptr, unsigned sz, uint64_t flags, int64_t rank); // configures a shared/networked buffer
API char** network_sync(unsigned timeout_ms); // syncs all buffers & returns null-terminated list of network events API char** network_sync(unsigned timeout_ms); // syncs all buffers & returns null-terminated list of network events
enum { enum {
NETWORK_EVENT_CONNECT, NETWORK_EVENT_CONNECT,
NETWORK_EVENT_DISCONNECT, NETWORK_EVENT_DISCONNECT,
NETWORK_EVENT_RECEIVE, NETWORK_EVENT_RECEIVE,
NETWORK_EVENT_DISCONNECT_TIMEOUT, NETWORK_EVENT_DISCONNECT_TIMEOUT,
/* offset from internal networking events */ /* offset from internal networking events */
NETWORK_EVENT_RPC = 10, NETWORK_EVENT_RPC = 10,
NETWORK_EVENT_RPC_RESP, NETWORK_EVENT_RPC_RESP,
}; };
/* errcode and errstr are optional arguments, pass NULL to ignore them, /* errcode and errstr are optional arguments, pass NULL to ignore them,
errstr is filled by va() */ errstr is filled by va() */
API int network_event(const char *msg, int *errcode, char **errstr); API int network_event(const char *msg, int *errcode, char **errstr);
enum { NETWORK_RANK = 0 }; // [0..N] where 0 is server enum { NETWORK_RANK = 0 }; // [0..N] where 0 is server
enum { NETWORK_PING = 1 }; // NETWORK_BANDWIDTH, NETWORK_QUALITY }; enum { NETWORK_PING = 1 }; // NETWORK_BANDWIDTH, NETWORK_QUALITY };
enum { NETWORK_PORT = 2, NETWORK_IP, NETWORK_LIVE }; enum { NETWORK_PORT = 2, NETWORK_IP, NETWORK_LIVE };
enum { NETWORK_SEND_MS = 4 }; enum { NETWORK_SEND_MS = 4 };
enum { NETWORK_BUF_CLEAR_ON_JOIN = 5 }; enum { NETWORK_BUF_CLEAR_ON_JOIN = 5 };
enum { NETWORK_USERID = 7, /*NETWORK_SALT,*/ NETWORK_COUNT/*N users*/ /*...*/, NETWORK_CAPACITY }; enum { NETWORK_USERID = 7, /*NETWORK_SALT,*/ NETWORK_COUNT/*N users*/ /*...*/, NETWORK_CAPACITY };
API int64_t network_get(uint64_t key); API int64_t network_get(uint64_t key);
API int64_t network_put(uint64_t key, int64_t value); API int64_t network_put(uint64_t key, int64_t value);
API void network_rpc(const char *signature, void *function); API void network_rpc(const char *signature, void *function);
API void network_rpc_send_to(int64_t rank, unsigned id, const char *cmdline); API void network_rpc_send_to(int64_t rank, unsigned id, const char *cmdline);
API void network_rpc_send(unsigned id, const char *cmdline); API void network_rpc_send(unsigned id, const char *cmdline);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// low-level api (sockets based) // low-level api (sockets based)
API bool server_bind(int max_clients, int port); API bool server_bind(int max_clients, int port);
API char** server_poll(unsigned timeout_ms); API char** server_poll(unsigned timeout_ms);
API char** client_poll(unsigned timeout_ms); API char** client_poll(unsigned timeout_ms);
API void server_broadcast_bin_flags(const void *ptr, int len, uint64_t flags); API void server_broadcast_bin_flags(const void *ptr, int len, uint64_t flags);
API void server_broadcast_bin(const void *ptr, int len); API void server_broadcast_bin(const void *ptr, int len);
API void server_broadcast_flags(const char *msg, uint64_t flags); API void server_broadcast_flags(const char *msg, uint64_t flags);
API void server_broadcast(const char *msg); API void server_broadcast(const char *msg);
API void server_terminate(); API void server_terminate();
API void server_send(int64_t handle, const char *msg); API void server_send(int64_t handle, const char *msg);
API void server_send_bin(int64_t handle, const void *ptr, int len); API void server_send_bin(int64_t handle, const void *ptr, int len);
API void server_drop(int64_t handle); API void server_drop(int64_t handle);
API int64_t client_join(const char *ip, int port); API int64_t client_join(const char *ip, int port);
#define client_send_flags(msg,flags) server_broadcast(msg, flags) #define client_send_flags(msg,flags) server_broadcast(msg, flags)
#define client_send(msg) server_broadcast(msg) #define client_send(msg) server_broadcast(msg)
#define client_send_bin_flags(ptr,len,flags) server_broadcast_bin(ptr, len, flags) #define client_send_bin_flags(ptr,len,flags) server_broadcast_bin(ptr, len, flags)
#define client_send_bin(ptr,len) server_broadcast_bin(ptr, len) #define client_send_bin(ptr,len) server_broadcast_bin(ptr, len)
#define client_terminate() server_terminate() #define client_terminate() server_terminate()
#define ANYHOST_IPV4 "0.0.0.0" #define ANYHOST_IPV4 "0.0.0.0"
#define ANYHOST_IPV6 "::0" #define ANYHOST_IPV6 "::0"
#define LOCALHOST_IPV4 "127.0.0.1" #define LOCALHOST_IPV4 "127.0.0.1"
#define LOCALHOST_IPV6 "::1" #define LOCALHOST_IPV6 "::1"

View File

@ -1,294 +1,294 @@
#if is(tcc) && is(win32) // @fixme: https lib is broken with tcc. replaced with InternetReadFile() api for now #if is(tcc) && is(win32) // @fixme: https lib is broken with tcc. replaced with InternetReadFile() api for now
# include <wininet.h> # include <wininet.h>
# pragma comment(lib,"wininet") # pragma comment(lib,"wininet")
int download_file( FILE *out, const char *url ) { int download_file( FILE *out, const char *url ) {
int ok = false; int ok = false;
char buffer[ 4096 ]; char buffer[ 4096 ];
DWORD response_size = 0; DWORD response_size = 0;
if( out ) if( out )
for( HINTERNET session = InternetOpenA("v4k.download_file", PRE_CONFIG_INTERNET_ACCESS, NULL, INTERNET_INVALID_PORT_NUMBER, 0); session; InternetCloseHandle(session), session = 0 ) for( HINTERNET session = InternetOpenA("v4k.download_file", PRE_CONFIG_INTERNET_ACCESS, NULL, INTERNET_INVALID_PORT_NUMBER, 0); session; InternetCloseHandle(session), session = 0 )
for( HINTERNET request = InternetOpenUrlA(session, url, NULL, 0, INTERNET_FLAG_RELOAD, 0); request; InternetCloseHandle(request), request = 0 ) for( HINTERNET request = InternetOpenUrlA(session, url, NULL, 0, INTERNET_FLAG_RELOAD, 0); request; InternetCloseHandle(request), request = 0 )
for(; InternetReadFile(request, buffer, sizeof(buffer), &response_size) != FALSE && response_size > 0; ) { for(; InternetReadFile(request, buffer, sizeof(buffer), &response_size) != FALSE && response_size > 0; ) {
ok = (fwrite(buffer, response_size, 1, out) == 1); ok = (fwrite(buffer, response_size, 1, out) == 1);
if(!ok) break; if(!ok) break;
} }
return ok; return ok;
} }
array(char) download( const char *url ) { array(char) download( const char *url ) {
char buffer[ 4096 ]; char buffer[ 4096 ];
DWORD response_size = 0, pos = 0; DWORD response_size = 0, pos = 0;
array(char) out = 0; array(char) out = 0;
for( HINTERNET session = InternetOpenA("v4k.download", PRE_CONFIG_INTERNET_ACCESS, NULL, INTERNET_INVALID_PORT_NUMBER, 0); session; InternetCloseHandle(session), session = 0 ) for( HINTERNET session = InternetOpenA("v4k.download", PRE_CONFIG_INTERNET_ACCESS, NULL, INTERNET_INVALID_PORT_NUMBER, 0); session; InternetCloseHandle(session), session = 0 )
for( HINTERNET request = InternetOpenUrlA(session, url, NULL, 0, INTERNET_FLAG_RELOAD, 0); request; InternetCloseHandle(request), request = 0 ) for( HINTERNET request = InternetOpenUrlA(session, url, NULL, 0, INTERNET_FLAG_RELOAD, 0); request; InternetCloseHandle(request), request = 0 )
for(; InternetReadFile(request, buffer, sizeof(buffer), &response_size) != FALSE && response_size > 0; ) { for(; InternetReadFile(request, buffer, sizeof(buffer), &response_size) != FALSE && response_size > 0; ) {
array_resize(out, pos + response_size); array_resize(out, pos + response_size);
memcpy(out + (pos += response_size) - response_size, buffer, response_size); memcpy(out + (pos += response_size) - response_size, buffer, response_size);
} }
return out; return out;
} }
#else #else
int download_file( FILE *out, const char *url ) { int download_file( FILE *out, const char *url ) {
int ok = false; int ok = false;
if( out ) for( https_t *h = https_get(url, NULL); h; https_release(h), h = NULL ) { if( out ) for( https_t *h = https_get(url, NULL); h; https_release(h), h = NULL ) {
while (https_process(h) == HTTPS_STATUS_PENDING) sleep_ms(1); while (https_process(h) == HTTPS_STATUS_PENDING) sleep_ms(1);
//printf("fetch status%d, %d %s\n\n%.*s\n", https_process(h), h->status_code, h->content_type, (int)h->response_size, (char*)h->response_data); //printf("fetch status%d, %d %s\n\n%.*s\n", https_process(h), h->status_code, h->content_type, (int)h->response_size, (char*)h->response_data);
if(https_process(h) == HTTPS_STATUS_COMPLETED) if(https_process(h) == HTTPS_STATUS_COMPLETED)
ok = fwrite(h->response_data, h->response_size, 1, out) == 1; ok = fwrite(h->response_data, h->response_size, 1, out) == 1;
} }
return ok; return ok;
} }
// @fixme: broken with tcc -m64 (our default tcc configuration) // @fixme: broken with tcc -m64 (our default tcc configuration)
array(char) download( const char *url ) { array(char) download( const char *url ) {
array(char) out = 0; array(char) out = 0;
for( https_t *h = https_get(url, NULL); h; https_release(h), h = NULL ) { for( https_t *h = https_get(url, NULL); h; https_release(h), h = NULL ) {
while (https_process(h) == HTTPS_STATUS_PENDING) sleep_ms(1); while (https_process(h) == HTTPS_STATUS_PENDING) sleep_ms(1);
//printf("fetch status:%d, %d %s\n\n%.*s\n", https_process(h), h->status_code, h->content_type, (int)h->response_size, (char*)h->response_data); //printf("fetch status:%d, %d %s\n\n%.*s\n", https_process(h), h->status_code, h->content_type, (int)h->response_size, (char*)h->response_data);
if( https_process(h) == HTTPS_STATUS_COMPLETED ) { if( https_process(h) == HTTPS_STATUS_COMPLETED ) {
array_resize(out, h->response_size); array_resize(out, h->response_size);
memcpy(out, h->response_data, h->response_size); memcpy(out, h->response_data, h->response_size);
} }
} }
return out; return out;
} }
#endif #endif
bool network_tests() { bool network_tests() {
// network test (https) // network test (https)
array(char) webfile = download("https://www.google.com/"); array(char) webfile = download("https://www.google.com/");
printf("Network test: %d bytes downloaded from google.com\n", array_count(webfile)); printf("Network test: %d bytes downloaded from google.com\n", array_count(webfile));
// array_push(webfile, '\0'); puts(webfile); // array_push(webfile, '\0'); puts(webfile);
return true; return true;
} }
int portname( const char *service_name, unsigned retries ) { int portname( const char *service_name, unsigned retries ) {
// Determine port for a given service based on hash of its name. // Determine port for a given service based on hash of its name.
// If port cant be reached, client should retry with next hash. // If port cant be reached, client should retry with next hash.
// Algorithm: fnv1a(name of service) -> splitmix64 num retries -> remap bucket as [min..max] ports. // Algorithm: fnv1a(name of service) -> splitmix64 num retries -> remap bucket as [min..max] ports.
// hash64 // hash64
uint64_t hash = 14695981039346656037ULL; uint64_t hash = 14695981039346656037ULL;
while( *service_name ) { while( *service_name ) {
hash = ( (unsigned char)*service_name++ ^ hash ) * 0x100000001b3ULL; hash = ( (unsigned char)*service_name++ ^ hash ) * 0x100000001b3ULL;
} }
// splitmix64 // splitmix64
for( unsigned i = 0; i < retries; ++i ) { for( unsigned i = 0; i < retries; ++i ) {
uint64_t h = (hash += UINT64_C(0x9E3779B97F4A7C15)); uint64_t h = (hash += UINT64_C(0x9E3779B97F4A7C15));
h = (h ^ (h >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); h = (h ^ (h >> 30)) * UINT64_C(0xBF58476D1CE4E5B9);
h = (h ^ (h >> 27)) * UINT64_C(0x94D049BB133111EB); h = (h ^ (h >> 27)) * UINT64_C(0x94D049BB133111EB);
h = (h ^ (h >> 31)); h = (h ^ (h >> 31));
hash = h; hash = h;
} }
// See dynamic ports: https://en.wikipedia.org/wiki/Ephemeral_port // See dynamic ports: https://en.wikipedia.org/wiki/Ephemeral_port
// So, excluded ranges: 32768..60999 (linux), 49152..65535 (freebsd+vista+win7), 1024..5000 (winsrv2003+bsd) // So, excluded ranges: 32768..60999 (linux), 49152..65535 (freebsd+vista+win7), 1024..5000 (winsrv2003+bsd)
// Output range: [5001..32724], in 4096 steps // Output range: [5001..32724], in 4096 steps
return ((hash & 0xFFF) * 677 / 100 + 5001); return ((hash & 0xFFF) * 677 / 100 + 5001);
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#define UDP_DEBUG 0 #define UDP_DEBUG 0
static int udp_init() { static int udp_init() {
do_once { do_once {
int rc = swrapInit(); // atexit(swrapTerminate); int rc = swrapInit(); // atexit(swrapTerminate);
if( rc ) PANIC("udp_init: swrapInit error"); if( rc ) PANIC("udp_init: swrapInit error");
} }
return 1; return 1;
} }
int udp_open(const char *address, const char *port) { int udp_open(const char *address, const char *port) {
do_once udp_init(); do_once udp_init();
int fd = swrapSocket(SWRAP_UDP, SWRAP_CONNECT, 0, address, port); int fd = swrapSocket(SWRAP_UDP, SWRAP_CONNECT, 0, address, port);
// if( fd == -1 ) PANIC("udp_open: swrapSocket error"); // if( fd == -1 ) PANIC("udp_open: swrapSocket error");
return fd; return fd;
} }
int udp_bind(const char *address, const char *port) { int udp_bind(const char *address, const char *port) {
do_once udp_init(); do_once udp_init();
int fd = swrapSocket(SWRAP_UDP, SWRAP_BIND, 0, address, port); int fd = swrapSocket(SWRAP_UDP, SWRAP_BIND, 0, address, port);
// if( fd == -1 ) PANIC("udp_bind: swrapSocket error"); // if( fd == -1 ) PANIC("udp_bind: swrapSocket error");
return fd; return fd;
} }
int udp_send( int fd, const void *buf, int len ) { // returns bytes sent, or -1 if error int udp_send( int fd, const void *buf, int len ) { // returns bytes sent, or -1 if error
int rc = -1; int rc = -1;
if( fd >= 0 ) for( ;; ) { if( fd >= 0 ) for( ;; ) {
rc = swrapSend(fd, (const char *)buf, len); rc = swrapSend(fd, (const char *)buf, len);
#if is(win32) #if is(win32)
if( rc == -1 && WSAGetLastError() == WSAEINTR ) continue; if( rc == -1 && WSAGetLastError() == WSAEINTR ) continue;
else break; else break;
#else #else
if( rc == -1 && errno == EINTR ) continue; if( rc == -1 && errno == EINTR ) continue;
else break; else break;
#endif #endif
} }
#if UDP_DEBUG #if UDP_DEBUG
if( rc > 0 ) { if( rc > 0 ) {
char host[128], serv[128]; char host[128], serv[128];
int rc2 = swrapAddressInfo(&sa, host, 128, serv, 128 ); int rc2 = swrapAddressInfo(&sa, host, 128, serv, 128 );
if( rc2 != 0 ) PANIC("swrapAddressInfo error"); if( rc2 != 0 ) PANIC("swrapAddressInfo error");
printf("udp_send: %d bytes to %s:%s : %.*s\n", rc, host, serv, rc, buf ); printf("udp_send: %d bytes to %s:%s : %.*s\n", rc, host, serv, rc, buf );
hexdump(buf, rc); hexdump(buf, rc);
} }
#endif #endif
return rc; return rc;
} }
int udp_close( int fd ) { // @todo: expose me? needed? int udp_close( int fd ) { // @todo: expose me? needed?
#if is(win32) #if is(win32)
// closesocket(fd); // closesocket(fd);
#else #else
// close(fd); // close(fd);
#endif #endif
fd = -1; // noop fd = -1; // noop
return 0; return 0;
} }
#if 0 #if 0
// use socket to send data to another address // use socket to send data to another address
int udp_sendto( int fd, const char *ip, const char *port, const void *buf, int len ) { // return number of bytes sent int udp_sendto( int fd, const char *ip, const char *port, const void *buf, int len ) { // return number of bytes sent
#if 0 #if 0
int rc = swrapSendTo(fd, struct swrap_addr*, (const char*)buf, len); int rc = swrapSendTo(fd, struct swrap_addr*, (const char*)buf, len);
if( rc == -1 ) return -1; //PANIC("udp_send: swrapSend error"); if( rc == -1 ) return -1; //PANIC("udp_send: swrapSend error");
return rc; return rc;
#else #else
struct sockaddr_in addr = {0}; struct sockaddr_in addr = {0};
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
// use inet_addr. tcc(win32) wont work otherwise. // use inet_addr. tcc(win32) wont work otherwise.
addr.sin_addr.s_addr = inet_addr(ip); // inet_pton(AF_INET, ip, &addr.sin_addr); addr.sin_addr.s_addr = inet_addr(ip); // inet_pton(AF_INET, ip, &addr.sin_addr);
addr.sin_port = htons(atoi(port)); addr.sin_port = htons(atoi(port));
int n = sendto(fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr)); int n = sendto(fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr));
return n < 0 ? -1 : n; return n < 0 ? -1 : n;
#endif #endif
} }
#endif #endif
int udp_peek( int fd ) { // <0 error, 0 timeout, >0 data int udp_peek( int fd ) { // <0 error, 0 timeout, >0 data
int rc = swrapSelect(fd, 0.00001); int rc = swrapSelect(fd, 0.00001);
if( rc < 0 ) return -1; // PANIC("udp_peek: swrapSelect error"); if( rc < 0 ) return -1; // PANIC("udp_peek: swrapSelect error");
if( rc == 0 ) return 0; // timeout if( rc == 0 ) return 0; // timeout
return 1; //> 0: new data is available return 1; //> 0: new data is available
} }
int udp_recv( int fd, void *buf, int len ) { // <0 error, 0 orderly shutdown, >0 received bytes int udp_recv( int fd, void *buf, int len ) { // <0 error, 0 orderly shutdown, >0 received bytes
struct swrap_addr sa = {0}; struct swrap_addr sa = {0};
int rc = swrapReceiveFrom(fd, &sa, buf, len); int rc = swrapReceiveFrom(fd, &sa, buf, len);
if( rc < 0 ) return -1; // PANIC("udp_recv: swrapReceiveFrom error"); if( rc < 0 ) return -1; // PANIC("udp_recv: swrapReceiveFrom error");
if( rc == 0 ) return 0; // orderly shutdown if( rc == 0 ) return 0; // orderly shutdown
#if UDP_DEBUG #if UDP_DEBUG
char host[128], serv[128]; char host[128], serv[128];
int rc2 = swrapAddressInfo(&sa, host, 128, serv, 128 ); int rc2 = swrapAddressInfo(&sa, host, 128, serv, 128 );
if( rc2 != 0 ) PANIC("swrapAddressInfo error"); if( rc2 != 0 ) PANIC("swrapAddressInfo error");
printf("udp_recv: %d bytes from %s:%s : %.*s\n", rc, host, serv, rc, buf ); printf("udp_recv: %d bytes from %s:%s : %.*s\n", rc, host, serv, rc, buf );
hexdump(buf, rc); hexdump(buf, rc);
#endif #endif
return rc; return rc;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#define TCP_DEBUG 1 #define TCP_DEBUG 1
#if TCP_DEBUG #if TCP_DEBUG
static set(int) tcp_set; static set(int) tcp_set;
#endif #endif
void tcp_init(void) { void tcp_init(void) {
do_once { do_once {
udp_init(); udp_init();
#if TCP_DEBUG #if TCP_DEBUG
set_init(tcp_set, less_int, hash_int); set_init(tcp_set, less_int, hash_int);
#endif #endif
} }
} }
int tcp_open(const char *address, const char *port) { int tcp_open(const char *address, const char *port) {
do_once tcp_init(); do_once tcp_init();
int fd = swrapSocket(SWRAP_TCP, SWRAP_CONNECT, 0/*|SWRAP_NODELAY*/, address, port); int fd = swrapSocket(SWRAP_TCP, SWRAP_CONNECT, 0/*|SWRAP_NODELAY*/, address, port);
return fd; return fd;
} }
int tcp_bind(const char *interface_, const char *port, int backlog) { int tcp_bind(const char *interface_, const char *port, int backlog) {
do_once tcp_init(); do_once tcp_init();
int fd = swrapSocket(SWRAP_TCP, SWRAP_BIND, 0/*|SWRAP_NODELAY*//*|SWRAP_NOBLOCK*/, interface_, port); int fd = swrapSocket(SWRAP_TCP, SWRAP_BIND, 0/*|SWRAP_NODELAY*//*|SWRAP_NOBLOCK*/, interface_, port);
if( fd >= 0 ) swrapListen(fd, backlog); if( fd >= 0 ) swrapListen(fd, backlog);
return fd; return fd;
} }
int tcp_peek(int fd, int(*callback)(int)) { int tcp_peek(int fd, int(*callback)(int)) {
struct swrap_addr sa; struct swrap_addr sa;
int fd2 = swrapAccept(fd, &sa); int fd2 = swrapAccept(fd, &sa);
if( fd2 >= 0 ) return callback(fd2); if( fd2 >= 0 ) return callback(fd2);
return -1; return -1;
} }
int tcp_send(int fd, const void *buf, int len) { int tcp_send(int fd, const void *buf, int len) {
int rc = swrapSend(fd, (const char *)buf, len); int rc = swrapSend(fd, (const char *)buf, len);
#if TCP_DEBUG #if TCP_DEBUG
if( set_find(tcp_set, fd) ) { if( set_find(tcp_set, fd) ) {
printf("send -> %11d (status: %d) %s:%s\n", len, rc, tcp_host(fd), tcp_port(fd)); printf("send -> %11d (status: %d) %s:%s\n", len, rc, tcp_host(fd), tcp_port(fd));
if( rc > 0 ) hexdump(buf, rc); if( rc > 0 ) hexdump(buf, rc);
} }
#endif #endif
return rc; return rc;
} }
int tcp_recv(int fd, void *buf, int len) { int tcp_recv(int fd, void *buf, int len) {
int rc = swrapReceive(fd, (char*)buf, len); int rc = swrapReceive(fd, (char*)buf, len);
#if TCP_DEBUG #if TCP_DEBUG
if( rc != 0 && set_find(tcp_set, fd) ) { if( rc != 0 && set_find(tcp_set, fd) ) {
printf("recv <- %11d (status: %d) %s:%s\n", len, rc, tcp_host(fd), tcp_port(fd)); printf("recv <- %11d (status: %d) %s:%s\n", len, rc, tcp_host(fd), tcp_port(fd));
if( rc > 0 ) hexdump(buf, rc); if( rc > 0 ) hexdump(buf, rc);
} }
#endif #endif
return rc; return rc;
} }
char* tcp_host(int fd) { char* tcp_host(int fd) {
char buf[1024]; char buf[1024];
struct swrap_addr sa; struct swrap_addr sa;
swrapAddress(fd, &sa); swrapAddress(fd, &sa);
swrapAddressInfo(&sa, buf, 512, buf+512, 512); swrapAddressInfo(&sa, buf, 512, buf+512, 512);
return va("%s", buf); return va("%s", buf);
} }
char* tcp_port(int fd) { char* tcp_port(int fd) {
char buf[1024]; char buf[1024];
struct swrap_addr sa; struct swrap_addr sa;
swrapAddress(fd, &sa); swrapAddress(fd, &sa);
swrapAddressInfo(&sa, buf, 512, buf+512, 512); swrapAddressInfo(&sa, buf, 512, buf+512, 512);
return va("%s", buf+512); return va("%s", buf+512);
} }
int tcp_close(int fd) { int tcp_close(int fd) {
swrapClose(fd); swrapClose(fd);
return 0; return 0;
} }
int tcp_debug(int fd) { int tcp_debug(int fd) {
#if TCP_DEBUG #if TCP_DEBUG
if( set_find(tcp_set, fd) ) { if( set_find(tcp_set, fd) ) {
set_erase(tcp_set, fd); set_erase(tcp_set, fd);
return 0; return 0;
} else { } else {
set_insert(tcp_set, fd); set_insert(tcp_set, fd);
return 1; return 1;
} }
#else #else
return 0; return 0;
#endif #endif
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
static void network_init() { static void network_init() {
do_once { do_once {
udp_init(); udp_init();
tcp_init(); tcp_init();
} }
} }

View File

@ -1,49 +1,49 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// network framework // network framework
// - rlyeh, public domain // - rlyeh, public domain
API array(char) download( const char *url ); API array(char) download( const char *url );
API int download_file( FILE *out, const char *url ); API int download_file( FILE *out, const char *url );
API int portname( const char *service_name, unsigned retries ); API int portname( const char *service_name, unsigned retries );
API bool network_tests(); API bool network_tests();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// udp wrapper // udp wrapper
// - rlyeh, public domain. // - rlyeh, public domain.
// server // server
API int udp_bind(const char *address, const char *port); API int udp_bind(const char *address, const char *port);
// client // client
API int udp_open(const char *address, const char *port); API int udp_open(const char *address, const char *port);
// common // common
API int udp_send(int, const void *buf, int len ); // <0 error, >0 bytes sent ok API int udp_send(int, const void *buf, int len ); // <0 error, >0 bytes sent ok
API int udp_sendto(int, const char *ip, const char *port, const void *buf, int len ); // <0 error, >0 bytes sent ok API int udp_sendto(int, const char *ip, const char *port, const void *buf, int len ); // <0 error, >0 bytes sent ok
API int udp_recv(int, void *buf, int len ); // <0 error, 0 orderly shutdown, >0 received bytes API int udp_recv(int, void *buf, int len ); // <0 error, 0 orderly shutdown, >0 received bytes
API int udp_peek(int); // <0 error, 0 timeout, >0 data API int udp_peek(int); // <0 error, 0 timeout, >0 data
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// tcp wrapper // tcp wrapper
// - rlyeh, public domain // - rlyeh, public domain
// client // client
API int tcp_open(const char *address, const char *port); API int tcp_open(const char *address, const char *port);
// server // server
API int tcp_bind(const char *interface_, const char *port, int queue); API int tcp_bind(const char *interface_, const char *port, int queue);
API int tcp_peek(int, int(*callback)(int)); API int tcp_peek(int, int(*callback)(int));
// common // common
API int tcp_send(int, const void* buf, int len); API int tcp_send(int, const void* buf, int len);
API int tcp_recv(int, void* buf, int len); API int tcp_recv(int, void* buf, int len);
API char* tcp_host(int); // info API char* tcp_host(int); // info
API char* tcp_port(int); // info API char* tcp_port(int); // info
API int tcp_close(int); API int tcp_close(int);
// extras // extras
API int tcp_debug(int); // toggle traffic monitoring on/off for given socket API int tcp_debug(int); // toggle traffic monitoring on/off for given socket
//API int tcp_printf(int, const char *fmt, ...); // printf message in remote end //API int tcp_printf(int, const char *fmt, ...); // printf message in remote end
//API int tcp_crypt(int,uint64_t); // set shared secret //API int tcp_crypt(int,uint64_t); // set shared secret

File diff suppressed because it is too large Load Diff

View File

@ -1,364 +1,364 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// factory of handle ids // factory of handle ids
// convert between hard refs (pointers) and weak refs (ids) // convert between hard refs (pointers) and weak refs (ids)
API uintptr_t id_make(void *ptr); API uintptr_t id_make(void *ptr);
API void * id_handle(uintptr_t id); API void * id_handle(uintptr_t id);
API void id_dispose(uintptr_t id); API void id_dispose(uintptr_t id);
API bool id_valid(uintptr_t id); API bool id_valid(uintptr_t id);
// configuration: // configuration:
// ideally, these two should be 32 each. they were changed to fit our OBJHEADER bits // ideally, these two should be 32 each. they were changed to fit our OBJHEADER bits
#ifndef ID_INDEX_BITS #ifndef ID_INDEX_BITS
#define ID_INDEX_BITS 16 #define ID_INDEX_BITS 16
#endif #endif
#ifndef ID_COUNT_BITS #ifndef ID_COUNT_BITS
#define ID_COUNT_BITS 3 #define ID_COUNT_BITS 3
#endif #endif
// C objects framework // C objects framework
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// ## object limitations // ## object limitations
// - 8-byte overhead per object // - 8-byte overhead per object
// - XX-byte overhead per object-entity // - XX-byte overhead per object-entity
// - 32 components max per object-entity // - 32 components max per object-entity
// - 256 classes max per game // - 256 classes max per game
// - 256 references max per object // - 256 references max per object
// - 1024K bytes max per object // - 1024K bytes max per object
// - 8 generations + 64K IDs per running instance (19-bit IDs) // - 8 generations + 64K IDs per running instance (19-bit IDs)
// - support for pragma pack(1) structs not enabled by default. // - support for pragma pack(1) structs not enabled by default.
/* /!\ if you plan to use pragma pack(1) on any struct, you need #define OBJ_MIN_PRAGMAPACK_BITS 0 at the expense of max class size /!\ */ /* /!\ if you plan to use pragma pack(1) on any struct, you need #define OBJ_MIN_PRAGMAPACK_BITS 0 at the expense of max class size /!\ */
#ifndef OBJ_MIN_PRAGMAPACK_BITS #ifndef OBJ_MIN_PRAGMAPACK_BITS
//#define OBJ_MIN_PRAGMAPACK_BITS 3 // allows pragma packs >= 8. objsizew becomes 8<<3, so 2048 bytes max per class (default) //#define OBJ_MIN_PRAGMAPACK_BITS 3 // allows pragma packs >= 8. objsizew becomes 8<<3, so 2048 bytes max per class (default)
#define OBJ_MIN_PRAGMAPACK_BITS 2 // allows pragma packs >= 4. objsizew becomes 8<<2, so 1024 bytes max per class #define OBJ_MIN_PRAGMAPACK_BITS 2 // allows pragma packs >= 4. objsizew becomes 8<<2, so 1024 bytes max per class
//#define OBJ_MIN_PRAGMAPACK_BITS 1 // allows pragma packs >= 2. objsizew becomes 8<<1, so 512 bytes max per class //#define OBJ_MIN_PRAGMAPACK_BITS 1 // allows pragma packs >= 2. objsizew becomes 8<<1, so 512 bytes max per class
//#define OBJ_MIN_PRAGMAPACK_BITS 0 // allows pragma packs >= 1. objsizew becomes 8<<0, so 256 bytes max per class //#define OBJ_MIN_PRAGMAPACK_BITS 0 // allows pragma packs >= 1. objsizew becomes 8<<0, so 256 bytes max per class
#endif #endif
#define OBJHEADER \ #define OBJHEADER \
struct { \ struct { \
ifdef(debug, const char *objname;) \ ifdef(debug, const char *objname;) \
union { \ union { \
uintptr_t objheader; \ uintptr_t objheader; \
struct { \ struct { \
uintptr_t objtype:8; \ uintptr_t objtype:8; \
uintptr_t objsizew:8; \ uintptr_t objsizew:8; \
uintptr_t objrefs:8; \ uintptr_t objrefs:8; \
uintptr_t objheap:1; \ uintptr_t objheap:1; \
uintptr_t objcomps:1; /* << can be removed? check payload ptr instead? */ \ uintptr_t objcomps:1; /* << can be removed? check payload ptr instead? */ \
uintptr_t objunused:64-8-8-8-1-1-ID_INDEX_BITS-ID_COUNT_BITS; /*19*/ \ uintptr_t objunused:64-8-8-8-1-1-ID_INDEX_BITS-ID_COUNT_BITS; /*19*/ \
uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \ uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \
}; \ }; \
}; \ }; \
array(struct obj*) objchildren; \ array(struct obj*) objchildren; \
}; };
#ifndef OBJ #ifndef OBJ
#define OBJ \ #define OBJ \
OBJHEADER OBJHEADER
#endif #endif
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// syntax sugars // syntax sugars
#ifdef OBJTYPE #ifdef OBJTYPE
#undef OBJTYPE #undef OBJTYPE
#endif #endif
#define OBJTYPE(T) \ #define OBJTYPE(T) \
OBJTYPE_##T OBJTYPE_##T
#define OBJTYPEDEF(NAME,N) \ #define OBJTYPEDEF(NAME,N) \
enum { OBJTYPE(NAME) = N }; \ enum { OBJTYPE(NAME) = N }; \
STATIC_ASSERT( N <= 255 ); \ STATIC_ASSERT( N <= 255 ); \
STATIC_ASSERT( sizeof(NAME) == ((sizeof(NAME)>>OBJ_MIN_PRAGMAPACK_BITS)<<OBJ_MIN_PRAGMAPACK_BITS) ); // (sizeof(NAME) & ((1<<OBJ_MIN_PRAGMAPACK_BITS)-1)) == 0 ); STATIC_ASSERT( sizeof(NAME) == ((sizeof(NAME)>>OBJ_MIN_PRAGMAPACK_BITS)<<OBJ_MIN_PRAGMAPACK_BITS) ); // (sizeof(NAME) & ((1<<OBJ_MIN_PRAGMAPACK_BITS)-1)) == 0 );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// objects // objects
#define TYPEDEF_STRUCT(NAME,N,...) \ #define TYPEDEF_STRUCT(NAME,N,...) \
typedef struct NAME { OBJ \ typedef struct NAME { OBJ \
__VA_ARGS__ \ __VA_ARGS__ \
char payload[0]; \ char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N); } NAME; OBJTYPEDEF(NAME,N);
// TYPEDEF_STRUCT(obj,0); // TYPEDEF_STRUCT(obj,0);
typedef struct obj { OBJ } obj; typedef struct obj { OBJ } obj;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// entities // entities
#define OBJCOMPONENTS_MAX 32 #define OBJCOMPONENTS_MAX 32
#define OBJCOMPONENTS_ALL_ENABLED 0xAAAAAAAAAAAAAAAAULL #define OBJCOMPONENTS_ALL_ENABLED 0xAAAAAAAAAAAAAAAAULL
#define OBJCOMPONENTS_ALL_FLAGGED 0x5555555555555555ULL #define OBJCOMPONENTS_ALL_FLAGGED 0x5555555555555555ULL
#define COMPONENTS_ONLY(x) ((x) & ~OBJCOMPONENTS_ALL_FLAGGED) #define COMPONENTS_ONLY(x) ((x) & ~OBJCOMPONENTS_ALL_FLAGGED)
#ifndef ENTITY #ifndef ENTITY
#define ENTITY \ #define ENTITY \
struct { OBJHEADER union { struct { uintptr_t objenabled:OBJCOMPONENTS_MAX, objflagged:OBJCOMPONENTS_MAX; }; uintptr_t cflags; }; void *c[OBJCOMPONENTS_MAX]; }; struct { OBJHEADER union { struct { uintptr_t objenabled:OBJCOMPONENTS_MAX, objflagged:OBJCOMPONENTS_MAX; }; uintptr_t cflags; }; void *c[OBJCOMPONENTS_MAX]; };
#endif #endif
#define TYPEDEF_ENTITY(NAME,N,...) \ #define TYPEDEF_ENTITY(NAME,N,...) \
typedef struct NAME { ENTITY \ typedef struct NAME { ENTITY \
__VA_ARGS__ \ __VA_ARGS__ \
char payload[0]; \ char payload[0]; \
} NAME; OBJTYPEDEF(NAME,N); } NAME; OBJTYPEDEF(NAME,N);
// OBJTYPEDEF(entity,1) // OBJTYPEDEF(entity,1)
typedef struct entity { ENTITY } entity; typedef struct entity { ENTITY } entity;
#define entity_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) #define entity_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__)
#define entity_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) #define entity_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// heap/stack ctor/dtor // heap/stack ctor/dtor
static __thread obj *objtmp; static __thread obj *objtmp;
#define OBJ_CTOR_HDR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE) ( \ #define OBJ_CTOR_HDR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE) ( \
(PTR)->objheader = HEAP ? id_make(PTR) : 0, /*should assign to .objid instead. however, id_make() returns shifted bits already*/ \ (PTR)->objheader = HEAP ? id_make(PTR) : 0, /*should assign to .objid instead. however, id_make() returns shifted bits already*/ \
(PTR)->objtype = (OBJ_TYPE), \ (PTR)->objtype = (OBJ_TYPE), \
(PTR)->objheap = (HEAP), \ (PTR)->objheap = (HEAP), \
(PTR)->objsizew = (SIZEOF_OBJ>>OBJ_MIN_PRAGMAPACK_BITS)) (PTR)->objsizew = (SIZEOF_OBJ>>OBJ_MIN_PRAGMAPACK_BITS))
#define OBJ_CTOR_PTR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE) ( \ #define OBJ_CTOR_PTR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE) ( \
OBJ_CTOR_HDR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE), \ OBJ_CTOR_HDR(PTR,HEAP,SIZEOF_OBJ,OBJ_TYPE), \
obj_ctor(PTR)) obj_ctor(PTR))
#define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \ #define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \
objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \ objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \
*(TYPE*)objtmp = ((TYPE){ {0,}, __VA_ARGS__}), \ *(TYPE*)objtmp = ((TYPE){ {0,}, __VA_ARGS__}), \
((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \ ((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \
( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \ ( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \
OBJ_CTOR_PTR(objtmp, HEAP,sizeof(TYPE),OBJTYPE(TYPE)), \ OBJ_CTOR_PTR(objtmp, HEAP,sizeof(TYPE),OBJTYPE(TYPE)), \
ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \ ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \
obj_setname(objtmp, NAME)) obj_setname(objtmp, NAME))
#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, 0, __VA_ARGS__) #define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, 0, __VA_ARGS__)
#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) #define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__)
#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) #define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__)
void* obj_malloc(unsigned sz); void* obj_malloc(unsigned sz);
void* obj_free(void *o); void* obj_free(void *o);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// obj generics. can be extended. // obj generics. can be extended.
#define obj_ctor(o,...) obj_method(ctor, o, ##__VA_ARGS__) #define obj_ctor(o,...) obj_method(ctor, o, ##__VA_ARGS__)
#define obj_dtor(o,...) obj_method(dtor, o, ##__VA_ARGS__) #define obj_dtor(o,...) obj_method(dtor, o, ##__VA_ARGS__)
#define obj_save(o,...) obj_method(save, o, ##__VA_ARGS__) #define obj_save(o,...) obj_method(save, o, ##__VA_ARGS__)
#define obj_load(o,...) obj_method(load, o, ##__VA_ARGS__) #define obj_load(o,...) obj_method(load, o, ##__VA_ARGS__)
#define obj_test(o,...) obj_method(test, o, ##__VA_ARGS__) #define obj_test(o,...) obj_method(test, o, ##__VA_ARGS__)
#define obj_init(o,...) obj_method(init, o, ##__VA_ARGS__) #define obj_init(o,...) obj_method(init, o, ##__VA_ARGS__)
#define obj_quit(o,...) obj_method(quit, o, ##__VA_ARGS__) #define obj_quit(o,...) obj_method(quit, o, ##__VA_ARGS__)
#define obj_tick(o,...) obj_method(tick, o, ##__VA_ARGS__) #define obj_tick(o,...) obj_method(tick, o, ##__VA_ARGS__)
#define obj_draw(o,...) obj_method(draw, o, ##__VA_ARGS__) #define obj_draw(o,...) obj_method(draw, o, ##__VA_ARGS__)
#define obj_lerp(o,...) obj_method(lerp, o, ##__VA_ARGS__) #define obj_lerp(o,...) obj_method(lerp, o, ##__VA_ARGS__)
#define obj_edit(o,...) obj_method(edit, o, ##__VA_ARGS__) #define obj_edit(o,...) obj_method(edit, o, ##__VA_ARGS__)
#define obj_menu(o,...) obj_method(menu, o, ##__VA_ARGS__) #define obj_menu(o,...) obj_method(menu, o, ##__VA_ARGS__)
#define obj_aabb(o,...) obj_method(aabb, o, ##__VA_ARGS__) #define obj_aabb(o,...) obj_method(aabb, o, ##__VA_ARGS__)
#define obj_icon(o,...) obj_method(icon, o, ##__VA_ARGS__) #define obj_icon(o,...) obj_method(icon, o, ##__VA_ARGS__)
// --- syntax sugars // --- syntax sugars
#define obj_extend(T,method) (obj_##method[OBJTYPE(T)] = (void*)T##_##method) #define obj_extend(T,method) (obj_##method[OBJTYPE(T)] = (void*)T##_##method)
#define obj_extend_t(T,method) (obj_##method[OBJTYPE(T##_t)] = (void*)T##_##method) #define obj_extend_t(T,method) (obj_##method[OBJTYPE(T##_t)] = (void*)T##_##method)
#define obj_method(method,o,...) (obj_##method[((struct obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((struct obj*)(o))->objtype]((o), ##__VA_ARGS__)) #define obj_method(method,o,...) (obj_##method[((struct obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((struct obj*)(o))->objtype]((o), ##__VA_ARGS__))
#define obj_hasmethod(o,method) (obj_typeid(o)[obj_##method]) #define obj_hasmethod(o,method) (obj_typeid(o)[obj_##method])
#define obj_vtable(method,RC,...) RC macro(obj_##method)(){ __VA_ARGS__ }; RC (*obj_##method[256])() = { REPEAT256(macro(obj_##method)) }; #define obj_vtable(method,RC,...) RC macro(obj_##method)(){ __VA_ARGS__ }; RC (*obj_##method[256])() = { REPEAT256(macro(obj_##method)) };
#define obj_vtable_null(method,RC) RC (*obj_##method[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed #define obj_vtable_null(method,RC) RC (*obj_##method[256])() = { 0 }; // null virtual table. will crash unless obj_extend'ed
#define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f ///- #define REPEAT16(f) f,f,f,f,f,f,f,f,f,f,f,f,f,f,f,f ///-
#define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) ///- #define REPEAT64(f) REPEAT16(f),REPEAT16(f),REPEAT16(f),REPEAT16(f) ///-
#define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) ///- #define REPEAT256(f) REPEAT64(f),REPEAT64(f),REPEAT64(f),REPEAT64(f) ///-
#undef EXTEND #undef EXTEND
#define EXTEND(...) EXPAND(EXTEND, __VA_ARGS__) #define EXTEND(...) EXPAND(EXTEND, __VA_ARGS__)
#define EXTEND2(o,F1) obj_extend(o,F1) ///- #define EXTEND2(o,F1) obj_extend(o,F1) ///-
#define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) ///- #define EXTEND3(o,F1,F2) obj_extend(o,F1), obj_extend(o,F2) ///-
#define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) ///- #define EXTEND4(o,F1,F2,F3) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3) ///-
#define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) ///- #define EXTEND5(o,F1,F2,F3,F4) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4) ///-
#define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) ///- #define EXTEND6(o,F1,F2,F3,F4,F5) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5) ///-
#define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) ///- #define EXTEND7(o,F1,F2,F3,F4,F5,F6) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6) ///-
#define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) ///- #define EXTEND8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7) ///-
#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) ///- #define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8) ///-
#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) ///- #define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9) ///-
#define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__) #define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__)
#define EXTEND_T2(o,F1) obj_extend_t(o,F1) ///- #define EXTEND_T2(o,F1) obj_extend_t(o,F1) ///-
#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) ///- #define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2) ///-
#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) ///- #define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3) ///-
#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) ///- #define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4) ///-
#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) ///- #define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5) ///-
#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) ///- #define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6) ///-
#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) ///- #define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7) ///-
#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) ///- #define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8) ///-
#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) ///- #define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9) ///-
// --- declare vtables // --- declare vtables
API extern void (*obj_ctor[256])(); ///- API extern void (*obj_ctor[256])(); ///-
API extern void (*obj_dtor[256])(); ///- API extern void (*obj_dtor[256])(); ///-
API extern char* (*obj_save[256])(); ///- API extern char* (*obj_save[256])(); ///-
API extern bool (*obj_load[256])(); ///- API extern bool (*obj_load[256])(); ///-
API extern int (*obj_test[256])(); ///- API extern int (*obj_test[256])(); ///-
API extern int (*obj_init[256])(); ///- API extern int (*obj_init[256])(); ///-
API extern int (*obj_quit[256])(); ///- API extern int (*obj_quit[256])(); ///-
API extern int (*obj_tick[256])(); ///- API extern int (*obj_tick[256])(); ///-
API extern int (*obj_draw[256])(); ///- API extern int (*obj_draw[256])(); ///-
API extern int (*obj_lerp[256])(); ///- API extern int (*obj_lerp[256])(); ///-
API extern int (*obj_aabb[256])(); ///- API extern int (*obj_aabb[256])(); ///-
API extern int (*obj_edit[256])(); ///- API extern int (*obj_edit[256])(); ///-
API extern int (*obj_menu[256])(); ///- API extern int (*obj_menu[256])(); ///-
API extern char* (*obj_icon[256])(); ///- API extern char* (*obj_icon[256])(); ///-
API extern const char*OBJTYPES[256]; ///- API extern const char*OBJTYPES[256]; ///-
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// core // core
API uintptr_t obj_header(const void *o); API uintptr_t obj_header(const void *o);
API uintptr_t obj_id(const void *o); API uintptr_t obj_id(const void *o);
API const char* obj_type(const void *o); API const char* obj_type(const void *o);
API unsigned obj_typeid(const void *o); API unsigned obj_typeid(const void *o);
API int obj_sizeof(const void *o); API int obj_sizeof(const void *o);
API int obj_size(const void *o); // size of all members together in struct. may include padding bytes. API int obj_size(const void *o); // size of all members together in struct. may include padding bytes.
API char* obj_data(void *o); // pointer to the first member in struct API char* obj_data(void *o); // pointer to the first member in struct
API const char* obj_datac(const void *o); // const pointer to the first struct member API const char* obj_datac(const void *o); // const pointer to the first struct member
API void* obj_payload(const void *o); // pointer right after last member in struct API void* obj_payload(const void *o); // pointer right after last member in struct
API void* obj_zero(void *o); // reset all object members API void* obj_zero(void *o); // reset all object members
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// refcounting // refcounting
API void* obj_ref(void *oo); API void* obj_ref(void *oo);
API void* obj_unref(void *oo); API void* obj_unref(void *oo);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// scene tree // scene tree
#define each_objchild(p,T,o) /*non-recursive*/ \ #define each_objchild(p,T,o) /*non-recursive*/ \
(array(struct obj*)* children = obj_children(p); children; children = 0) \ (array(struct obj*)* children = obj_children(p); children; children = 0) \
for(int _i = 1, _end = array_count(*children); _i < _end; ++_i) \ for(int _i = 1, _end = array_count(*children); _i < _end; ++_i) \
for(T o = (T)((*children)[_i]); o && (obj_parent(o) == p); o = 0) for(T o = (T)((*children)[_i]); o && (obj_parent(o) == p); o = 0)
API obj* obj_detach(void *c); API obj* obj_detach(void *c);
API obj* obj_attach(void *o, void *c); API obj* obj_attach(void *o, void *c);
API obj* obj_root(const void *o); API obj* obj_root(const void *o);
API obj* obj_parent(const void *o); API obj* obj_parent(const void *o);
API array(obj*)*obj_children(const void *o); // child[0]: parent, child[1]: 1st child, child[2]: 2nd child... API array(obj*)*obj_children(const void *o); // child[0]: parent, child[1]: 1st child, child[2]: 2nd child...
API array(obj*)*obj_siblings(const void *o); // child[0]: grandpa, child[1]: sibling1, child[2]: sibling2... API array(obj*)*obj_siblings(const void *o); // child[0]: grandpa, child[1]: sibling1, child[2]: sibling2...
API int obj_dumptree(const void *o); API int obj_dumptree(const void *o);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// metadata // metadata
API void* obj_setmeta(void *o, const char *key, const char *value); API void* obj_setmeta(void *o, const char *key, const char *value);
API const char* obj_meta(const void *o, const char *key); API const char* obj_meta(const void *o, const char *key);
API void* obj_setname(void *o, const char *name); API void* obj_setname(void *o, const char *name);
API const char* obj_name(const void *o); API const char* obj_name(const void *o);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// stl // stl
API void* obj_swap(void *dst, void *src); API void* obj_swap(void *dst, void *src);
API void* obj_copy_fast(void *dst, const void *src); API void* obj_copy_fast(void *dst, const void *src);
API void* obj_copy(void *dst, const void *src); API void* obj_copy(void *dst, const void *src);
API int obj_comp_fast(const void *a, const void *b); API int obj_comp_fast(const void *a, const void *b);
API int obj_comp(const void *a, const void *b); API int obj_comp(const void *a, const void *b);
API int obj_lesser(const void *a, const void *b); API int obj_lesser(const void *a, const void *b);
API int obj_greater(const void *a, const void *b); API int obj_greater(const void *a, const void *b);
API int obj_equal(const void *a, const void *b); API int obj_equal(const void *a, const void *b);
API uint64_t obj_hash(const void *o); API uint64_t obj_hash(const void *o);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// debug // debug
API bool obj_hexdump(const void *oo); API bool obj_hexdump(const void *oo);
API int obj_print(const void *o); API int obj_print(const void *o);
API int obj_printf(const void *o, const char *text); API int obj_printf(const void *o, const char *text);
API int obj_console(const void *o); // obj_output() ? API int obj_console(const void *o); // obj_output() ?
#define obj_printf(o, ...) obj_printf(o, va(__VA_ARGS__)) #define obj_printf(o, ...) obj_printf(o, va(__VA_ARGS__))
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// serialization // serialization
API char* obj_saveini(const void *o); API char* obj_saveini(const void *o);
API obj* obj_mergeini(void *o, const char *ini); API obj* obj_mergeini(void *o, const char *ini);
API obj* obj_loadini(void *o, const char *ini); API obj* obj_loadini(void *o, const char *ini);
API char* obj_savejson(const void *o); API char* obj_savejson(const void *o);
API obj* obj_mergejson(void *o, const char *json); API obj* obj_mergejson(void *o, const char *json);
API obj* obj_loadjson(void *o, const char *json); API obj* obj_loadjson(void *o, const char *json);
API char* obj_savebin(const void *o); API char* obj_savebin(const void *o);
API obj* obj_mergebin(void *o, const char *sav); API obj* obj_mergebin(void *o, const char *sav);
API obj* obj_loadbin(void *o, const char *sav); API obj* obj_loadbin(void *o, const char *sav);
API char* obj_savempack(const void *o); // @todo API char* obj_savempack(const void *o); // @todo
API obj* obj_mergempack(void *o, const char *sav); // @todo API obj* obj_mergempack(void *o, const char *sav); // @todo
API obj* obj_loadmpack(void *o, const char *sav); // @todo API obj* obj_loadmpack(void *o, const char *sav); // @todo
API int obj_push(const void *o); API int obj_push(const void *o);
API int obj_pop(void *o); API int obj_pop(void *o);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// components // components
API bool obj_addcomponent(entity *e, unsigned c, void *ptr); API bool obj_addcomponent(entity *e, unsigned c, void *ptr);
API bool obj_hascomponent(entity *e, unsigned c); API bool obj_hascomponent(entity *e, unsigned c);
API void* obj_getcomponent(entity *e, unsigned c); API void* obj_getcomponent(entity *e, unsigned c);
API bool obj_delcomponent(entity *e, unsigned c); API bool obj_delcomponent(entity *e, unsigned c);
API bool obj_usecomponent(entity *e, unsigned c); API bool obj_usecomponent(entity *e, unsigned c);
API bool obj_offcomponent(entity *e, unsigned c); API bool obj_offcomponent(entity *e, unsigned c);
API char* entity_save(entity *self); API char* entity_save(entity *self);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// reflection // reflection
#define each_objmember(oo,TYPE,NAME,PTR) \ #define each_objmember(oo,TYPE,NAME,PTR) \
(array(reflect_t) *found_ = members_find(obj_type(oo)); found_; found_ = 0) \ (array(reflect_t) *found_ = members_find(obj_type(oo)); found_; found_ = 0) \
for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \ for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \
for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) \ for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) \
for(const char *NAME = R->name, *TYPE = R->type; NAME || TYPE; ) \ for(const char *NAME = R->name, *TYPE = R->type; NAME || TYPE; ) \
for(void *PTR = ((char*)oo) + R->sz ; NAME || TYPE ; NAME = TYPE = 0 ) for(void *PTR = ((char*)oo) + R->sz ; NAME || TYPE ; NAME = TYPE = 0 )
API void* obj_clone(const void *src); API void* obj_clone(const void *src);
API void* obj_merge(void *dst, const void *src); // @testme API void* obj_merge(void *dst, const void *src); // @testme
API void* obj_mutate(void *dst, const void *src); API void* obj_mutate(void *dst, const void *src);
API void* obj_make(const char *str); API void* obj_make(const char *str);
// built-ins // built-ins
typedef enum OBJTYPE_BUILTINS { typedef enum OBJTYPE_BUILTINS {
OBJTYPE_obj = 0, OBJTYPE_obj = 0,
OBJTYPE_entity = 1, OBJTYPE_entity = 1,
OBJTYPE_vec2 = 2, OBJTYPE_vec2 = 2,
OBJTYPE_vec3 = 3, OBJTYPE_vec3 = 3,
OBJTYPE_vec4 = 4, OBJTYPE_vec4 = 4,
OBJTYPE_quat = 5, OBJTYPE_quat = 5,
OBJTYPE_mat33 = 6, OBJTYPE_mat33 = 6,
OBJTYPE_mat34 = 7, OBJTYPE_mat34 = 7,
OBJTYPE_mat44 = 8, OBJTYPE_mat44 = 8,
OBJTYPE_vec2i = 9, OBJTYPE_vec2i = 9,
OBJTYPE_vec3i = 10, OBJTYPE_vec3i = 10,
} OBJTYPE_BUILTINS; } OBJTYPE_BUILTINS;

File diff suppressed because it is too large Load Diff

View File

@ -1,389 +1,389 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// compression api // compression api
enum COMPRESS_FLAGS { enum COMPRESS_FLAGS {
COMPRESS_RAW = 0, COMPRESS_RAW = 0,
COMPRESS_PPP = (1<<4), COMPRESS_PPP = (1<<4),
COMPRESS_ULZ = (2<<4), COMPRESS_ULZ = (2<<4),
COMPRESS_LZ4 = (3<<4), COMPRESS_LZ4 = (3<<4),
COMPRESS_CRUSH = (4<<4), COMPRESS_CRUSH = (4<<4),
COMPRESS_DEFLATE = (5<<4), COMPRESS_DEFLATE = (5<<4),
COMPRESS_LZP1 = (6<<4), COMPRESS_LZP1 = (6<<4),
COMPRESS_LZMA = (7<<4), COMPRESS_LZMA = (7<<4),
COMPRESS_BALZ = (8<<4), COMPRESS_BALZ = (8<<4),
COMPRESS_LZW3 = (9<<4), COMPRESS_LZW3 = (9<<4),
COMPRESS_LZSS = (10<<4), COMPRESS_LZSS = (10<<4),
COMPRESS_BCM = (11<<4), COMPRESS_BCM = (11<<4),
COMPRESS_ZLIB = (12<<4), // same as deflate with header COMPRESS_ZLIB = (12<<4), // same as deflate with header
}; };
API unsigned zbounds(unsigned inlen, unsigned flags); API unsigned zbounds(unsigned inlen, unsigned flags);
API unsigned zencode(void *out, unsigned outlen, const void *in, unsigned inlen, unsigned flags); API unsigned zencode(void *out, unsigned outlen, const void *in, unsigned inlen, unsigned flags);
API unsigned zexcess(unsigned flags); API unsigned zexcess(unsigned flags);
API unsigned zdecode(void *out, unsigned outlen, const void *in, unsigned inlen, unsigned flags); API unsigned zdecode(void *out, unsigned outlen, const void *in, unsigned inlen, unsigned flags);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// array de/interleaving // array de/interleaving
// //
// results: // results:
// R0G0B0 R1G1B1 R2G2B2... -> R0R1R2... B0B1B2... G0G1G2... // R0G0B0 R1G1B1 R2G2B2... -> R0R1R2... B0B1B2... G0G1G2...
// R0G0B0A0 R1G1B1A1 R2G2B2A2... -> R0R1R2... A0A1A2... B0B1B2... G0G1G2... // R0G0B0A0 R1G1B1A1 R2G2B2A2... -> R0R1R2... A0A1A2... B0B1B2... G0G1G2...
API void *interleave( void *out, const void *list, int list_count, int sizeof_item, unsigned columns ); API void *interleave( void *out, const void *list, int list_count, int sizeof_item, unsigned columns );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// cobs en/decoder // cobs en/decoder
API unsigned cobs_bounds(unsigned len); API unsigned cobs_bounds(unsigned len);
API unsigned cobs_encode(const void *in, unsigned inlen, void *out, unsigned outlen); API unsigned cobs_encode(const void *in, unsigned inlen, void *out, unsigned outlen);
API unsigned cobs_decode(const void *in, unsigned inlen, void *out, unsigned outlen); API unsigned cobs_decode(const void *in, unsigned inlen, void *out, unsigned outlen);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// base92 en/decoder // base92 en/decoder
API unsigned base92_encode(const void *in, unsigned inlen, void* out, unsigned outlen); API unsigned base92_encode(const void *in, unsigned inlen, void* out, unsigned outlen);
API unsigned base92_decode(const void *in, unsigned inlen, void* out, unsigned outlen); API unsigned base92_decode(const void *in, unsigned inlen, void* out, unsigned outlen);
API unsigned base92_bounds(unsigned inlen); API unsigned base92_bounds(unsigned inlen);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// netstring en/decoder // netstring en/decoder
API unsigned netstring_bounds(unsigned inlen); API unsigned netstring_bounds(unsigned inlen);
API unsigned netstring_encode(const char *in, unsigned inlen, char *out, unsigned outlen); API unsigned netstring_encode(const char *in, unsigned inlen, char *out, unsigned outlen);
API unsigned netstring_decode(const char *in, unsigned inlen, char *out, unsigned outlen); API unsigned netstring_decode(const char *in, unsigned inlen, char *out, unsigned outlen);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// delta en/decoder // delta en/decoder
API void delta8_encode(void *buffer, unsigned count); API void delta8_encode(void *buffer, unsigned count);
API void delta8_decode(void *buffer, unsigned count); API void delta8_decode(void *buffer, unsigned count);
API void delta16_encode(void *buffer, unsigned count); API void delta16_encode(void *buffer, unsigned count);
API void delta16_decode(void *buffer, unsigned count); API void delta16_decode(void *buffer, unsigned count);
API void delta32_encode(void *buffer, unsigned count); API void delta32_encode(void *buffer, unsigned count);
API void delta32_decode(void *buffer, unsigned count); API void delta32_decode(void *buffer, unsigned count);
API void delta64_encode(void *buffer, unsigned count); API void delta64_encode(void *buffer, unsigned count);
API void delta64_decode(void *buffer, unsigned count); API void delta64_decode(void *buffer, unsigned count);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// zigzag en/decoder // zigzag en/decoder
API uint64_t zig64( int64_t value ); // convert sign|magnitude to magnitude|sign API uint64_t zig64( int64_t value ); // convert sign|magnitude to magnitude|sign
API int64_t zag64( uint64_t value ); // convert magnitude|sign to sign|magnitude API int64_t zag64( uint64_t value ); // convert magnitude|sign to sign|magnitude
API uint32_t enczig32u( int32_t n); API uint32_t enczig32u( int32_t n);
API uint64_t enczig64u( int64_t n); API uint64_t enczig64u( int64_t n);
API int32_t deczig32i(uint32_t n); API int32_t deczig32i(uint32_t n);
API int64_t deczig64i(uint64_t n); API int64_t deczig64i(uint64_t n);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// arc4 en/decryptor // arc4 en/decryptor
API void *arc4( void *buffer, unsigned buflen, const void *pass, unsigned passlen ); API void *arc4( void *buffer, unsigned buflen, const void *pass, unsigned passlen );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// crc64 // crc64
API uint64_t crc64(uint64_t h, const void *ptr, uint64_t len); API uint64_t crc64(uint64_t h, const void *ptr, uint64_t len);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// entropy encoder // entropy encoder
API void entropy( void *buf, unsigned n ); API void entropy( void *buf, unsigned n );
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// semantic versioning in a single byte (octal) // semantic versioning in a single byte (octal)
API int semver( int major, int minor, int patch ); API int semver( int major, int minor, int patch );
API int semvercmp( int v1, int v2 ); API int semvercmp( int v1, int v2 );
#define SEMVER(major,minor,patch) (0100 * (major) + 010 * (minor) + (patch)) #define SEMVER(major,minor,patch) (0100 * (major) + 010 * (minor) + (patch))
#define SEMVERCMP(v1,v2) (((v1) & 0110) - ((v2) & 0110)) #define SEMVERCMP(v1,v2) (((v1) & 0110) - ((v2) & 0110))
#define SEMVERFMT "%03o" #define SEMVERFMT "%03o"
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// storage types. refer to vec2i/3i, vec2/3/4 if you plan to do math operations // storage types. refer to vec2i/3i, vec2/3/4 if you plan to do math operations
typedef struct byte2 { uint8_t x,y; } byte2; typedef struct byte2 { uint8_t x,y; } byte2;
typedef struct byte3 { uint8_t x,y,z; } byte3; typedef struct byte3 { uint8_t x,y,z; } byte3;
typedef struct byte4 { uint8_t x,y,z,w; } byte4; typedef struct byte4 { uint8_t x,y,z,w; } byte4;
typedef struct int2 { int x,y; } int2; typedef struct int2 { int x,y; } int2;
typedef struct int3 { int x,y,z; } int3; typedef struct int3 { int x,y,z; } int3;
typedef struct int4 { int x,y,z,w; } int4; typedef struct int4 { int x,y,z,w; } int4;
typedef struct uint2 { unsigned int x,y; } uint2; typedef struct uint2 { unsigned int x,y; } uint2;
typedef struct uint3 { unsigned int x,y,z; } uint3; typedef struct uint3 { unsigned int x,y,z; } uint3;
typedef struct uint4 { unsigned int x,y,z,w; } uint4; typedef struct uint4 { unsigned int x,y,z,w; } uint4;
typedef struct float2 { float x,y; } float2; typedef struct float2 { float x,y; } float2;
typedef struct float3 { float x,y,z; } float3; typedef struct float3 { float x,y,z; } float3;
typedef struct float4 { float x,y,z,w; } float4; typedef struct float4 { float x,y,z,w; } float4;
typedef struct double2 { double x,y; } double2; typedef struct double2 { double x,y; } double2;
typedef struct double3 { double x,y,z; } double3; typedef struct double3 { double x,y,z; } double3;
typedef struct double4 { double x,y,z,w; } double4; typedef struct double4 { double x,y,z,w; } double4;
#define byte2(x,y) C_CAST(byte2, (uint8_t)(x), (uint8_t)(y) ) #define byte2(x,y) C_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
#define byte3(x,y,z) C_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) ) #define byte3(x,y,z) C_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
#define byte4(x,y,z,w) C_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) ) #define byte4(x,y,z,w) C_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
#define int2(x,y) C_CAST(int2, (int)(x), (int)(y) ) #define int2(x,y) C_CAST(int2, (int)(x), (int)(y) )
#define int3(x,y,z) C_CAST(int3, (int)(x), (int)(y), (int)(z) ) #define int3(x,y,z) C_CAST(int3, (int)(x), (int)(y), (int)(z) )
#define int4(x,y,z,w) C_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) ) #define int4(x,y,z,w) C_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
#define uint2(x,y) C_CAST(uint2, (unsigned)(x), (unsigned)(y) ) #define uint2(x,y) C_CAST(uint2, (unsigned)(x), (unsigned)(y) )
#define uint3(x,y,z) C_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) ) #define uint3(x,y,z) C_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
#define uint4(x,y,z,w) C_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) ) #define uint4(x,y,z,w) C_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
#define float2(x,y) C_CAST(float2, (float)(x), (float)(y) ) #define float2(x,y) C_CAST(float2, (float)(x), (float)(y) )
#define float3(x,y,z) C_CAST(float3, (float)(x), (float)(y), (float)(z) ) #define float3(x,y,z) C_CAST(float3, (float)(x), (float)(y), (float)(z) )
#define float4(x,y,z,w) C_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) ) #define float4(x,y,z,w) C_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
#define double2(x,y) C_CAST(double2, (double)(x), (double)(y) ) #define double2(x,y) C_CAST(double2, (double)(x), (double)(y) )
#define double3(x,y,z) C_CAST(double3, (double)(x), (double)(y), (double)(z) ) #define double3(x,y,z) C_CAST(double3, (double)(x), (double)(y), (double)(z) )
#define double4(x,y,z,w) C_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) ) #define double4(x,y,z,w) C_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// compile-time fourcc, eightcc // compile-time fourcc, eightcc
API char *cc4str(unsigned cc); API char *cc4str(unsigned cc);
API char *cc8str(uint64_t cc); API char *cc8str(uint64_t cc);
enum { enum {
# define _(a,b,c,d,e) cc__##a, cc__##b, cc__##c, cc__##d, cc__##e # define _(a,b,c,d,e) cc__##a, cc__##b, cc__##c, cc__##d, cc__##e
cc__1 = '1', _(2,3,4,5,6),_(7,8,9,0,_), cc__ = ' ', cc__1 = '1', _(2,3,4,5,6),_(7,8,9,0,_), cc__ = ' ',
cc__A = 'A', _(B,C,D,E,F),_(G,H,I,J,K),_(L,M,N,O,P),_(Q,R,S,T,U),_(V,W,X,Y,Z), cc__A = 'A', _(B,C,D,E,F),_(G,H,I,J,K),_(L,M,N,O,P),_(Q,R,S,T,U),_(V,W,X,Y,Z),
cc__a = 'a', _(b,c,d,e,f),_(g,h,i,j,k),_(l,m,n,o,p),_(q,r,s,t,u),_(v,w,x,y,z), cc__a = 'a', _(b,c,d,e,f),_(g,h,i,j,k),_(l,m,n,o,p),_(q,r,s,t,u),_(v,w,x,y,z),
# undef _ # undef _
}; };
#ifdef BIG #ifdef BIG
#define cc4(a,b,c,d) ((uint32_t)(cc__##a<<24) | (cc__##b<<16) | (cc__##c<<8) | (cc__##d<<0)) #define cc4(a,b,c,d) ((uint32_t)(cc__##a<<24) | (cc__##b<<16) | (cc__##c<<8) | (cc__##d<<0))
#define cc8(a,b,c,d,e,f,g,h) (((uint64_t)cc4(a,b,c,d) << 32ULL) | cc4(e,f,g,h)) #define cc8(a,b,c,d,e,f,g,h) (((uint64_t)cc4(a,b,c,d) << 32ULL) | cc4(e,f,g,h))
#else #else
#define cc4(a,b,c,d) ((uint32_t)(cc__##d<<24) | (cc__##c<<16) | (cc__##b<<8) | (cc__##a<<0)) #define cc4(a,b,c,d) ((uint32_t)(cc__##d<<24) | (cc__##c<<16) | (cc__##b<<8) | (cc__##a<<0))
#define cc8(a,b,c,d,e,f,g,h) (((uint64_t)cc4(e,f,g,h) << 32ULL) | cc4(a,b,c,d)) #define cc8(a,b,c,d,e,f,g,h) (((uint64_t)cc4(e,f,g,h) << 32ULL) | cc4(a,b,c,d))
#endif #endif
#define cc3(a,b,c) cc4(,a,b,c) #define cc3(a,b,c) cc4(,a,b,c)
#define cc5(a,b,c,d,e) cc6(,a,b,c,d,e) #define cc5(a,b,c,d,e) cc6(,a,b,c,d,e)
#define cc6(a,b,c,d,e,f) cc7(,a,b,c,d,e,f) #define cc6(a,b,c,d,e,f) cc7(,a,b,c,d,e,f)
#define cc7(a,b,c,d,e,f,g) cc8(,a,b,c,d,e,f,g) #define cc7(a,b,c,d,e,f,g) cc8(,a,b,c,d,e,f,g)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// text conversions // text conversions
API char* ftoa1(float v); API char* ftoa1(float v);
API char* ftoa2(vec2 v); API char* ftoa2(vec2 v);
API char* ftoa3(vec3 v); API char* ftoa3(vec3 v);
API char* ftoa4(vec4 v); API char* ftoa4(vec4 v);
API float atof1(const char *s); API float atof1(const char *s);
API vec2 atof2(const char *s); API vec2 atof2(const char *s);
API vec3 atof3(const char *s); API vec3 atof3(const char *s);
API vec4 atof4(const char *s); API vec4 atof4(const char *s);
API char* itoa1(int v); API char* itoa1(int v);
API char* itoa2(vec2i v); API char* itoa2(vec2i v);
API char* itoa3(vec3i v); API char* itoa3(vec3i v);
API int atoi1(const char *s); API int atoi1(const char *s);
API vec2i atoi2(const char *s); API vec2i atoi2(const char *s);
API vec3i atoi3(const char *s); API vec3i atoi3(const char *s);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// endianness // endianness
API int is_big(); API int is_big();
API int is_little(); API int is_little();
API uint16_t swap16( uint16_t x ); API uint16_t swap16( uint16_t x );
API uint32_t swap32( uint32_t x ); API uint32_t swap32( uint32_t x );
API uint64_t swap64( uint64_t x ); API uint64_t swap64( uint64_t x );
API float swap32f(float n); API float swap32f(float n);
API double swap64f(double n); API double swap64f(double n);
API void swapf(float *a, float *b); API void swapf(float *a, float *b);
API void swapf2(vec2 *a, vec2 *b); API void swapf2(vec2 *a, vec2 *b);
API void swapf3(vec3 *a, vec3 *b); API void swapf3(vec3 *a, vec3 *b);
API void swapf4(vec4 *a, vec4 *b); API void swapf4(vec4 *a, vec4 *b);
API uint16_t lil16(uint16_t n); // swap16 as lil API uint16_t lil16(uint16_t n); // swap16 as lil
API uint32_t lil32(uint32_t n); // swap32 as lil API uint32_t lil32(uint32_t n); // swap32 as lil
API uint64_t lil64(uint64_t n); // swap64 as lil API uint64_t lil64(uint64_t n); // swap64 as lil
API float lil32f(float n); // swap32 as lil API float lil32f(float n); // swap32 as lil
API double lil64f(double n); // swap64 as lil API double lil64f(double n); // swap64 as lil
API uint16_t big16(uint16_t n); // swap16 as big API uint16_t big16(uint16_t n); // swap16 as big
API uint32_t big32(uint32_t n); // swap32 as big API uint32_t big32(uint32_t n); // swap32 as big
API uint64_t big64(uint64_t n); // swap64 as big API uint64_t big64(uint64_t n); // swap64 as big
API float big32f(float n); // swap32 as big API float big32f(float n); // swap32 as big
API double big64f(double n); // swap64 as big API double big64f(double n); // swap64 as big
API uint16_t* lil16p(void *p, int sz); API uint16_t* lil16p(void *p, int sz);
API uint32_t* lil32p(void *p, int sz); API uint32_t* lil32p(void *p, int sz);
API uint64_t* lil64p(void *p, int sz); API uint64_t* lil64p(void *p, int sz);
API float * lil32pf(void *p, int sz); API float * lil32pf(void *p, int sz);
API double * lil64pf(void *p, int sz); API double * lil64pf(void *p, int sz);
API uint16_t* big16p(void *p, int sz); API uint16_t* big16p(void *p, int sz);
API uint32_t* big32p(void *p, int sz); API uint32_t* big32p(void *p, int sz);
API uint64_t* big64p(void *p, int sz); API uint64_t* big64p(void *p, int sz);
API float * big32pf(void *p, int sz); API float * big32pf(void *p, int sz);
API double * big64pf(void *p, int sz); API double * big64pf(void *p, int sz);
#if is(cl) #if is(cl)
#define swap16 _byteswap_ushort #define swap16 _byteswap_ushort
#define swap32 _byteswap_ulong #define swap32 _byteswap_ulong
#define swap64 _byteswap_uint64 #define swap64 _byteswap_uint64
#elif is(gcc) #elif is(gcc)
#define swap16 __builtin_bswap16 #define swap16 __builtin_bswap16
#define swap32 __builtin_bswap32 #define swap32 __builtin_bswap32
#define swap64 __builtin_bswap64 #define swap64 __builtin_bswap64
#endif #endif
#define hton16 big16 #define hton16 big16
#define ntoh16 big16 #define ntoh16 big16
#define hton32 big32 #define hton32 big32
#define ntoh32 big32 #define ntoh32 big32
#define hton64 big64 #define hton64 big64
#define ntoh64 big64 #define ntoh64 big64
#define IS_BIG ((*(uint16_t *)"\0\1") == 1) #define IS_BIG ((*(uint16_t *)"\0\1") == 1)
#define IS_LITTLE ((*(uint16_t *)"\0\1") != 1) #define IS_LITTLE ((*(uint16_t *)"\0\1") != 1)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// half packing // half packing
typedef uint16_t half; typedef uint16_t half;
API float half_to_float(half value); API float half_to_float(half value);
API half float_to_half(float value); API half float_to_half(float value);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// int packing // int packing
// pack16i() -- store a 16-bit int into a char buffer (like htons()) // pack16i() -- store a 16-bit int into a char buffer (like htons())
// pack32i() -- store a 32-bit int into a char buffer (like htonl()) // pack32i() -- store a 32-bit int into a char buffer (like htonl())
// pack64i() -- store a 64-bit int into a char buffer (like htonl()) // pack64i() -- store a 64-bit int into a char buffer (like htonl())
API void pack16i(uint8_t *buf, uint16_t i, int swap); API void pack16i(uint8_t *buf, uint16_t i, int swap);
API void pack32i(uint8_t *buf, uint32_t i, int swap); API void pack32i(uint8_t *buf, uint32_t i, int swap);
API void pack64i(uint8_t *buf, uint64_t i, int swap); API void pack64i(uint8_t *buf, uint64_t i, int swap);
// unpack16i() -- unpack a 16-bit int from a char buffer (like ntohs()) // unpack16i() -- unpack a 16-bit int from a char buffer (like ntohs())
// unpack32i() -- unpack a 32-bit int from a char buffer (like ntohl()) // unpack32i() -- unpack a 32-bit int from a char buffer (like ntohl())
// unpack64i() -- unpack a 64-bit int from a char buffer (like ntohl()) // unpack64i() -- unpack a 64-bit int from a char buffer (like ntohl())
// changes unsigned numbers to signed if needed. // changes unsigned numbers to signed if needed.
API int16_t unpack16i(const uint8_t *buf, int swap); API int16_t unpack16i(const uint8_t *buf, int swap);
API int32_t unpack32i(const uint8_t *buf, int swap); API int32_t unpack32i(const uint8_t *buf, int swap);
API int64_t unpack64i(const uint8_t *buf, int swap); API int64_t unpack64i(const uint8_t *buf, int swap);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// float un/packing: 8 (micro), 16 (half), 32 (float), 64 (double) types // float un/packing: 8 (micro), 16 (half), 32 (float), 64 (double) types
#define pack754_8(f) ( pack754((f), 8, 4)) #define pack754_8(f) ( pack754((f), 8, 4))
#define pack754_16(f) ( pack754((f), 16, 5)) #define pack754_16(f) ( pack754((f), 16, 5))
#define pack754_32(f) ( pack754((f), 32, 8)) #define pack754_32(f) ( pack754((f), 32, 8))
#define pack754_64(f) ( pack754((f), 64, 11)) #define pack754_64(f) ( pack754((f), 64, 11))
#define unpack754_8(u) (unpack754((u), 8, 4)) #define unpack754_8(u) (unpack754((u), 8, 4))
#define unpack754_16(u) (unpack754((u), 16, 5)) #define unpack754_16(u) (unpack754((u), 16, 5))
#define unpack754_32(u) (unpack754((u), 32, 8)) #define unpack754_32(u) (unpack754((u), 32, 8))
#define unpack754_64(u) (unpack754((u), 64, 11)) #define unpack754_64(u) (unpack754((u), 64, 11))
API uint64_t pack754(long double f, unsigned bits, unsigned expbits); API uint64_t pack754(long double f, unsigned bits, unsigned expbits);
API long double unpack754(uint64_t i, unsigned bits, unsigned expbits); API long double unpack754(uint64_t i, unsigned bits, unsigned expbits);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// variable-length integer packing // variable-length integer packing
API uint64_t pack64uv( uint8_t *buffer, uint64_t value ); API uint64_t pack64uv( uint8_t *buffer, uint64_t value );
API uint64_t unpack64uv( const uint8_t *buffer, uint64_t *value ); API uint64_t unpack64uv( const uint8_t *buffer, uint64_t *value );
API uint64_t pack64iv( uint8_t *buffer, int64_t value_ ); API uint64_t pack64iv( uint8_t *buffer, int64_t value_ );
API uint64_t unpack64iv( const uint8_t *buffer, int64_t *value ); API uint64_t unpack64iv( const uint8_t *buffer, int64_t *value );
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// msgpack v5, schema based struct/buffer bitpacking // msgpack v5, schema based struct/buffer bitpacking
// api v2 // api v2
API int msgpack(const char *fmt, ... ); // va arg pack "n,b,u,d/i,s,p,f/g,e,[,{". returns number of written bytes API int msgpack(const char *fmt, ... ); // va arg pack "n,b,u,d/i,s,p,f/g,e,[,{". returns number of written bytes
API int msgunpack(const char *fmt, ... ); // va arg pack "n,b,u,d/i,s,p,f/g,e,[,{". returns number of parsed args API int msgunpack(const char *fmt, ... ); // va arg pack "n,b,u,d/i,s,p,f/g,e,[,{". returns number of parsed args
// api v1 // api v1
API int msgpack_new(uint8_t *w, size_t l); API int msgpack_new(uint8_t *w, size_t l);
API int msgpack_nil(); // write null API int msgpack_nil(); // write null
API int msgpack_chr(bool n); // write boolean API int msgpack_chr(bool n); // write boolean
API int msgpack_uns(uint64_t n); // write unsigned integer API int msgpack_uns(uint64_t n); // write unsigned integer
API int msgpack_int(int64_t n); // write integer API int msgpack_int(int64_t n); // write integer
API int msgpack_str(const char *s); // write string API int msgpack_str(const char *s); // write string
API int msgpack_bin(const char *s, size_t n); // write binary pointer API int msgpack_bin(const char *s, size_t n); // write binary pointer
API int msgpack_flt(double g); // write real API int msgpack_flt(double g); // write real
API int msgpack_ext(uint8_t key, void *val, size_t n); // write extension type API int msgpack_ext(uint8_t key, void *val, size_t n); // write extension type
API int msgpack_arr(uint32_t n); // write array mark for next N items API int msgpack_arr(uint32_t n); // write array mark for next N items
API int msgpack_map(uint32_t n); // write map mark for next N pairs (N keys + N values) API int msgpack_map(uint32_t n); // write map mark for next N pairs (N keys + N values)
API int msgpack_eof(); // write full? API int msgpack_eof(); // write full?
API int msgpack_err(); // write error? API int msgpack_err(); // write error?
API bool msgunpack_new( const void *opaque_or_FILE, size_t bytes ); API bool msgunpack_new( const void *opaque_or_FILE, size_t bytes );
API bool msgunpack_nil(); API bool msgunpack_nil();
API bool msgunpack_chr(bool *chr); API bool msgunpack_chr(bool *chr);
API bool msgunpack_uns(uint64_t *uns); API bool msgunpack_uns(uint64_t *uns);
API bool msgunpack_int(int64_t *sig); API bool msgunpack_int(int64_t *sig);
API bool msgunpack_str(char **str); API bool msgunpack_str(char **str);
API bool msgunpack_bin(void **bin, uint64_t *len); API bool msgunpack_bin(void **bin, uint64_t *len);
API bool msgunpack_flt(float *flt); API bool msgunpack_flt(float *flt);
API bool msgunpack_dbl(double *dbl); API bool msgunpack_dbl(double *dbl);
API bool msgunpack_ext(uint8_t *key, void **val, uint64_t *len); API bool msgunpack_ext(uint8_t *key, void **val, uint64_t *len);
API bool msgunpack_arr(uint64_t *len); API bool msgunpack_arr(uint64_t *len);
API bool msgunpack_map(uint64_t *len); API bool msgunpack_map(uint64_t *len);
API bool msgunpack_eof(); API bool msgunpack_eof();
API bool msgunpack_err(); API bool msgunpack_err();
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Based on code by Brian "Beej Jorgensen" Hall (public domain) [1]. // Based on code by Brian "Beej Jorgensen" Hall (public domain) [1].
// Based on code by Ginger Bill's half<->float (public domain) [2]. // Based on code by Ginger Bill's half<->float (public domain) [2].
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// pack.c -- perl/python-ish pack/unpack functions // pack.c -- perl/python-ish pack/unpack functions
// like printf and scanf, but for binary data. // like printf and scanf, but for binary data.
// //
// format flags: // format flags:
// (<) little endian (>) big endian (! also) (=) native endian // (<) little endian (>) big endian (! also) (=) native endian
// (c) 8-bit char (b) 8-bit byte // (c) 8-bit char (b) 8-bit byte
// (h) 16-bit half (w) 16-bit word // (h) 16-bit half (w) 16-bit word
// (i) 32-bit integer (u) 32-bit unsigned (f) 32-bit float // (i) 32-bit integer (u) 32-bit unsigned (f) 32-bit float
// (l) 64-bit long (q) 64-bit quad (d) 64-bit double // (l) 64-bit long (q) 64-bit quad (d) 64-bit double
// (v) varint // (v) varint
// (s) string (64-bit varint length prepended) // (s) string (64-bit varint length prepended)
// (S) string (32-bit fixed length prepended) // (S) string (32-bit fixed length prepended)
// (m) memblock (64-bit varint length prepended) // (m) memblock (64-bit varint length prepended)
// (M) memblock (32-bit fixed length prepended) // (M) memblock (32-bit fixed length prepended)
// (z) memblock (zeroed) // (z) memblock (zeroed)
// (#) number of arguments processed (only when unpacking) // (#) number of arguments processed (only when unpacking)
// //
// @todo: // @todo:
// - (x) document & test flag // - (x) document & test flag
// @totest: // @totest:
// - (s) string (64-bit variable length automatically prepended) // - (s) string (64-bit variable length automatically prepended)
// - (S) string (32-bit fixed length automatically prepended) // - (S) string (32-bit fixed length automatically prepended)
// - (m) memblock (64-bit variable length automatically prepended) // - (m) memblock (64-bit variable length automatically prepended)
// - (M) memblock (32-bit fixed length automatically prepended) // - (M) memblock (32-bit fixed length automatically prepended)
// - (z) memblock (zeroed) // - (z) memblock (zeroed)
// - (#) number of arguments processed (only when unpacking) // - (#) number of arguments processed (only when unpacking)
// - save data dictated by the format string from the buffer. return: number of bytes written, or 0 if error. // - save data dictated by the format string from the buffer. return: number of bytes written, or 0 if error.
// if first argument is zero, returns number of bytes required for packing. // if first argument is zero, returns number of bytes required for packing.
API int savef(FILE *file, const char *format, ...); API int savef(FILE *file, const char *format, ...);
API int saveb(unsigned char *buf, const char *format, ...); API int saveb(unsigned char *buf, const char *format, ...);
// - load data dictated by the format string into the buffer. return: number of bytes read, or 0 if error. // - load data dictated by the format string into the buffer. return: number of bytes read, or 0 if error.
// if first argument is zero, returns number of bytes required for unpacking. // if first argument is zero, returns number of bytes required for unpacking.
API int loadf(FILE *file, const char *format, ...); API int loadf(FILE *file, const char *format, ...);
API int loadb(const unsigned char *buf, const char *format, ...); API int loadb(const unsigned char *buf, const char *format, ...);

View File

@ -1,55 +1,55 @@
#if ENABLE_PROFILER #if ENABLE_PROFILER
profiler_t profiler; profiler_t profiler;
int profiler_enabled = 1; int profiler_enabled = 1;
void (profiler_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; } void (profiler_init)() { map_init(profiler, less_str, hash_str); profiler_enabled &= !!profiler; }
int (profiler_enable)(bool on) { return profiler_enabled = on; } int (profiler_enable)(bool on) { return profiler_enabled = on; }
void (ui_profiler)() { void (ui_profiler)() {
// @todo: ui_plot() // @todo: ui_plot()
double fps = window_fps(); double fps = window_fps();
profile_setstat("Render.num_fps", fps); profile_setstat("Render.num_fps", fps);
enum { COUNT = 300 }; enum { COUNT = 300 };
static float values[COUNT] = {0}; static int offset = 0; static float values[COUNT] = {0}; static int offset = 0;
values[offset=(offset+1)%COUNT] = fps; values[offset=(offset+1)%COUNT] = fps;
// draw fps-meter: 300 samples, [0..70] range each, 70px height plot ... // draw fps-meter: 300 samples, [0..70] range each, 70px height plot ...
// ... unless filtering is enabled // ... unless filtering is enabled
if( !(ui_filter && ui_filter[0]) ) { if( !(ui_filter && ui_filter[0]) ) {
nk_layout_row_dynamic(ui_ctx, 70, 1); nk_layout_row_dynamic(ui_ctx, 70, 1);
int index = -1; int index = -1;
if( nk_chart_begin(ui_ctx, NK_CHART_LINES, COUNT, 0.f, 70.f) ) { if( nk_chart_begin(ui_ctx, NK_CHART_LINES, COUNT, 0.f, 70.f) ) {
for( int i = 0; i < COUNT; ++i ) { for( int i = 0; i < COUNT; ++i ) {
nk_flags res = nk_chart_push(ui_ctx, (float)values[i]); nk_flags res = nk_chart_push(ui_ctx, (float)values[i]);
if( res & NK_CHART_HOVERING ) index = i; if( res & NK_CHART_HOVERING ) index = i;
if( res & NK_CHART_CLICKED ) index = i; if( res & NK_CHART_CLICKED ) index = i;
} }
nk_chart_end(ui_ctx); nk_chart_end(ui_ctx);
} }
// hightlight 60fps, 36fps and 12fps // hightlight 60fps, 36fps and 12fps
struct nk_rect space; nk_layout_peek(&space, ui_ctx); struct nk_rect space; nk_layout_peek(&space, ui_ctx);
struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx); struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
nk_stroke_line(canvas, space.x+0,space.y-60,space.x+space.w,space.y-60, 1.0, nk_rgba(0,255,0,128)); nk_stroke_line(canvas, space.x+0,space.y-60,space.x+space.w,space.y-60, 1.0, nk_rgba(0,255,0,128));
nk_stroke_line(canvas, space.x+0,space.y-36,space.x+space.w,space.y-36, 1.0, nk_rgba(255,255,0,128)); nk_stroke_line(canvas, space.x+0,space.y-36,space.x+space.w,space.y-36, 1.0, nk_rgba(255,255,0,128));
nk_stroke_line(canvas, space.x+0,space.y-12,space.x+space.w,space.y-12, 1.0, nk_rgba(255,0,0,128)); nk_stroke_line(canvas, space.x+0,space.y-12,space.x+space.w,space.y-12, 1.0, nk_rgba(255,0,0,128));
if( index >= 0 ) { if( index >= 0 ) {
nk_tooltipf(ui_ctx, "%.2f fps", (float)values[index]); nk_tooltipf(ui_ctx, "%.2f fps", (float)values[index]);
} }
} }
for each_map_ptr_sorted(profiler, const char *, key, struct profile_t, val ) { for each_map_ptr_sorted(profiler, const char *, key, struct profile_t, val ) {
if( isnan(val->stat) ) { if( isnan(val->stat) ) {
float v = val->avg/1000.0; float v = val->avg/1000.0;
ui_slider2(*key, &v, va("%.2f ms", val->avg/1000.0)); ui_slider2(*key, &v, va("%.2f ms", val->avg/1000.0));
} else { } else {
float v = val->stat; float v = val->stat;
ui_slider2(*key, &v, va("%.2f", val->stat)); ui_slider2(*key, &v, va("%.2f", val->stat));
val->stat = 0; val->stat = 0;
} }
} }
} }
#endif #endif

View File

@ -1,29 +1,29 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// profiler & stats (@fixme: threadsafe) // profiler & stats (@fixme: threadsafe)
#if !ENABLE_PROFILER #if !ENABLE_PROFILER
# define profile(section) for(int macro(i) = 1; macro(i); macro(i) = 0) # define profile(section) for(int macro(i) = 1; macro(i); macro(i) = 0)
# define profile_incstat(name, accum) do {} while(0) # define profile_incstat(name, accum) do {} while(0)
# define profile_setstat(name, value) do {} while(0) # define profile_setstat(name, value) do {} while(0)
# define profiler_init() do {} while(0) # define profiler_init() do {} while(0)
# define profiler_enable(x) 0 # define profiler_enable(x) 0
# define ui_profiler() do {} while(0) # define ui_profiler() do {} while(0)
#else #else
# define profile(section) for( \ # define profile(section) for( \
struct profile_t *found = profiler_enabled ? \ struct profile_t *found = profiler_enabled ? \
map_find_or_add(profiler, section "@" FILELINE, (struct profile_t){NAN} ) : NULL, \ map_find_or_add(profiler, section "@" FILELINE, (struct profile_t){NAN} ) : NULL, \
*doit = found + ( found ? found->cost = -time_us(), 1 : 1 ); doit; \ *doit = found + ( found ? found->cost = -time_us(), 1 : 1 ); doit; \
doit = found ? found->cost += time_us(), found->avg = found->cost * 0.25 + found->avg * 0.75, NULL : NULL) ///+ doit = found ? found->cost += time_us(), found->avg = found->cost * 0.25 + found->avg * 0.75, NULL : NULL) ///+
# define profile_incstat(name, accum) for( \ # define profile_incstat(name, accum) for( \
struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \ struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \
found; found->stat += accum, found = NULL) ///+ found; found->stat += accum, found = NULL) ///+
# define profile_setstat(name, value) for( \ # define profile_setstat(name, value) for( \
struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \ struct profile_t *found = profiler_enabled ? map_find_or_add(profiler, name, (struct profile_t){0}) : NULL; \
found; found->stat = value, found = NULL) ///+ found; found->stat = value, found = NULL) ///+
API int profiler_enable(bool on); API int profiler_enable(bool on);
struct profile_t { double stat; int32_t cost, avg; }; ///- struct profile_t { double stat; int32_t cost, avg; }; ///-
typedef map(char *, struct profile_t) profiler_t; ///- typedef map(char *, struct profile_t) profiler_t; ///-
extern API profiler_t profiler; ///- extern API profiler_t profiler; ///-
extern API int profiler_enabled; ///- extern API int profiler_enabled; ///-
#endif #endif

View File

@ -1,191 +1,191 @@
// C reflection: enums, functions, structs, members and anotations. // C reflection: enums, functions, structs, members and anotations.
// - rlyeh, public domain // - rlyeh, public domain
// //
// @todo: nested structs? pointers in members? // @todo: nested structs? pointers in members?
// @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/) // @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/)
static map(unsigned, reflect_t) reflects; static map(unsigned, reflect_t) reflects;
static map(unsigned, array(reflect_t)) members; static map(unsigned, array(reflect_t)) members;
void reflect_init() { void reflect_init() {
if(!reflects) map_init_int(reflects); if(!reflects) map_init_int(reflects);
if(!members) map_init_int(members); if(!members) map_init_int(members);
} }
AUTORUN { AUTORUN {
reflect_init(); reflect_init();
} }
const char* symbol_naked(const char *s) { const char* symbol_naked(const char *s) {
if( strbeg(s, "const ") ) s += 6; if( strbeg(s, "const ") ) s += 6;
if( strbeg(s, "union ") ) s += 6; if( strbeg(s, "union ") ) s += 6;
if( strbeg(s, "struct ") ) s += 7; if( strbeg(s, "struct ") ) s += 7;
if(!strstr(s, " *") ) return s; if(!strstr(s, " *") ) return s;
char *copy = va("%s", s); char *copy = va("%s", s);
do strswap(copy," *","*"); while( strstr(copy, " *") ); // char * -> char* do strswap(copy," *","*"); while( strstr(copy, " *") ); // char * -> char*
return (const char*)copy; return (const char*)copy;
} }
void type_inscribe(const char *TY,unsigned TYsz,const char *infos) { void type_inscribe(const char *TY,unsigned TYsz,const char *infos) {
reflect_init(); reflect_init();
unsigned TYid = intern(TY = symbol_naked(TY)); unsigned TYid = intern(TY = symbol_naked(TY));
map_find_or_add(reflects, TYid, ((reflect_t){TYid, 0, TYsz, STRDUP(TY), infos})); // @leak map_find_or_add(reflects, TYid, ((reflect_t){TYid, 0, TYsz, STRDUP(TY), infos})); // @leak
} }
void enum_inscribe(const char *E,unsigned Eval,const char *infos) { void enum_inscribe(const char *E,unsigned Eval,const char *infos) {
reflect_init(); reflect_init();
unsigned Eid = intern(E = symbol_naked(E)); unsigned Eid = intern(E = symbol_naked(E));
map_find_or_add(reflects, Eid, ((reflect_t){Eid,0, Eval, STRDUP(E),infos})); // @leak map_find_or_add(reflects, Eid, ((reflect_t){Eid,0, Eval, STRDUP(E),infos})); // @leak
} }
unsigned enum_find(const char *E) { unsigned enum_find(const char *E) {
reflect_init(); reflect_init();
E = symbol_naked(E); E = symbol_naked(E);
return map_find(reflects, intern(E))->sz; return map_find(reflects, intern(E))->sz;
} }
void function_inscribe(const char *F,void *func,const char *infos) { void function_inscribe(const char *F,void *func,const char *infos) {
reflect_init(); reflect_init();
unsigned Fid = intern(F = symbol_naked(F)); unsigned Fid = intern(F = symbol_naked(F));
map_find_or_add(reflects, Fid, ((reflect_t){Fid,0, 0, STRDUP(F),infos, func})); // @leak map_find_or_add(reflects, Fid, ((reflect_t){Fid,0, 0, STRDUP(F),infos, func})); // @leak
reflect_t *found = map_find(reflects,Fid); reflect_t *found = map_find(reflects,Fid);
} }
void *function_find(const char *F) { void *function_find(const char *F) {
reflect_init(); reflect_init();
F = symbol_naked(F); F = symbol_naked(F);
return map_find(reflects, intern(F))->addr; return map_find(reflects, intern(F))->addr;
} }
void struct_inscribe(const char *T,unsigned Tsz,unsigned OBJTYPEid, const char *infos) { void struct_inscribe(const char *T,unsigned Tsz,unsigned OBJTYPEid, const char *infos) {
reflect_init(); reflect_init();
unsigned Tid = intern(T = symbol_naked(T)); unsigned Tid = intern(T = symbol_naked(T));
map_find_or_add(reflects, Tid, ((reflect_t){Tid, OBJTYPEid, Tsz, STRDUP(T), infos})); // @leak map_find_or_add(reflects, Tid, ((reflect_t){Tid, OBJTYPEid, Tsz, STRDUP(T), infos})); // @leak
} }
void member_inscribe(const char *T, const char *M,unsigned Msz, const char *infos, const char *TYPE, unsigned bytes) { void member_inscribe(const char *T, const char *M,unsigned Msz, const char *infos, const char *TYPE, unsigned bytes) {
reflect_init(); reflect_init();
unsigned Tid = intern(T = symbol_naked(T)); unsigned Tid = intern(T = symbol_naked(T));
unsigned Mid = intern(M = symbol_naked(M)); unsigned Mid = intern(M = symbol_naked(M));
unsigned Xid = intern(TYPE = symbol_naked(TYPE)); unsigned Xid = intern(TYPE = symbol_naked(TYPE));
map_find_or_add(reflects, (Mid<<16)|Tid, ((reflect_t){Mid, 0, Msz, STRDUP(M), infos, NULL, Tid, STRDUP(TYPE) })); // @leak map_find_or_add(reflects, (Mid<<16)|Tid, ((reflect_t){Mid, 0, Msz, STRDUP(M), infos, NULL, Tid, STRDUP(TYPE) })); // @leak
// add member separately as well // add member separately as well
if(!members) map_init_int(members); if(!members) map_init_int(members);
array(reflect_t) *found = map_find_or_add(members, Tid, 0); array(reflect_t) *found = map_find_or_add(members, Tid, 0);
reflect_t data = {Mid, 0, Msz, STRDUP(M), infos, NULL, Tid, STRDUP(TYPE), bytes }; // @leak reflect_t data = {Mid, 0, Msz, STRDUP(M), infos, NULL, Tid, STRDUP(TYPE), bytes }; // @leak
// ensure member has not been added previously // ensure member has not been added previously
#if 1 #if 1
// works, without altering member order // works, without altering member order
reflect_t *index = 0; reflect_t *index = 0;
for(int i = 0, end = array_count(*found); i < end; ++i) { for(int i = 0, end = array_count(*found); i < end; ++i) {
if( (*found)[i].id == Mid ) { index = (*found)+i; break; } if( (*found)[i].id == Mid ) { index = (*found)+i; break; }
} }
if( index ) *index = data; else array_push(*found, data); if( index ) *index = data; else array_push(*found, data);
#else #else
// works, although members get sorted // works, although members get sorted
array_push(*found, data); array_push(*found, data);
array_sort(*found, less_unsigned_ptr); //< first member type in reflect_t is `unsigned id`, so less_unsigned_ptr works array_sort(*found, less_unsigned_ptr); //< first member type in reflect_t is `unsigned id`, so less_unsigned_ptr works
array_unique(*found, less_unsigned_ptr); //< first member type in reflect_t is `unsigned id`, so less_unsigned_ptr works array_unique(*found, less_unsigned_ptr); //< first member type in reflect_t is `unsigned id`, so less_unsigned_ptr works
#endif #endif
} }
reflect_t member_find(const char *T, const char *M) { reflect_t member_find(const char *T, const char *M) {
reflect_init(); reflect_init();
T = symbol_naked(T); T = symbol_naked(T);
M = symbol_naked(M); M = symbol_naked(M);
return *map_find(reflects, (intern(M)<<16)|intern(T)); return *map_find(reflects, (intern(M)<<16)|intern(T));
} }
void *member_findptr(void *obj, const char *T, const char *M) { void *member_findptr(void *obj, const char *T, const char *M) {
reflect_init(); reflect_init();
T = symbol_naked(T); T = symbol_naked(T);
M = symbol_naked(M); M = symbol_naked(M);
return (char*)obj + member_find(T,M).sz; return (char*)obj + member_find(T,M).sz;
} }
array(reflect_t)* members_find(const char *T) { array(reflect_t)* members_find(const char *T) {
reflect_init(); reflect_init();
T = symbol_naked(T); T = symbol_naked(T);
return map_find(members, intern(T)); return map_find(members, intern(T));
} }
static static
void ui_reflect_(const reflect_t *R, const char *filter, int mask) { void ui_reflect_(const reflect_t *R, const char *filter, int mask) {
// debug: // debug:
// ui_label(va("name:%s info:'%s' id:%u objtype:%u sz:%u addr:%p parent:%u type:%s\n", // ui_label(va("name:%s info:'%s' id:%u objtype:%u sz:%u addr:%p parent:%u type:%s\n",
// R->name ? R->name : "", R->info ? R->info : "", R->id, R->objtype, R->sz, R->addr, R->parent, R->type ? R->type : "")); // R->name ? R->name : "", R->info ? R->info : "", R->id, R->objtype, R->sz, R->addr, R->parent, R->type ? R->type : ""));
if( mask == *R->info ) { if( mask == *R->info ) {
static __thread char *buf = 0; static __thread char *buf = 0;
if( buf ) *buf = '\0'; if( buf ) *buf = '\0';
struct nk_context *ui_ctx = (struct nk_context *)ui_handle(); struct nk_context *ui_ctx = (struct nk_context *)ui_handle();
for ui_push_hspace(16) { for ui_push_hspace(16) {
array(reflect_t) *T = map_find(members, intern(R->name)); array(reflect_t) *T = map_find(members, intern(R->name));
/**/ if( T ) {ui_label(strcatf(&buf,"S struct %s@%s", R->name, R->info+1)); /**/ if( T ) {ui_label(strcatf(&buf,"S struct %s@%s", R->name, R->info+1));
for each_array_ptr(*T, reflect_t, it) for each_array_ptr(*T, reflect_t, it)
if(strmatchi(it->name,filter)) { if(strmatchi(it->name,filter)) {
if( !R->type && !strcmp(it->name,R->name) ) // avoid recursion if( !R->type && !strcmp(it->name,R->name) ) // avoid recursion
ui_label(strcatf(&buf,"M %s %s@%s", it->type, it->name, it->info+1)); ui_label(strcatf(&buf,"M %s %s@%s", it->type, it->name, it->info+1));
else else
ui_reflect_(it,filter,'M'); ui_reflect_(it,filter,'M');
} }
} }
else if( R->addr ) ui_label(strcatf(&buf,"F func %s()@%s", R->name, R->info+1)); else if( R->addr ) ui_label(strcatf(&buf,"F func %s()@%s", R->name, R->info+1));
else if( !R->parent ) ui_label(strcatf(&buf,"E enum %s = %d@%s", R->name, R->sz, R->info+1)); else if( !R->parent ) ui_label(strcatf(&buf,"E enum %s = %d@%s", R->name, R->sz, R->info+1));
else ui_label(strcatf(&buf,"M %s %s@%s", R->type, R->name, R->info+1)); else ui_label(strcatf(&buf,"M %s %s@%s", R->type, R->name, R->info+1));
} }
} }
} }
API void *ui_handle(); API void *ui_handle();
int ui_reflect(const char *filter) { int ui_reflect(const char *filter) {
if( !filter ) filter = "*"; if( !filter ) filter = "*";
int enabled = ui_enabled(); int enabled = ui_enabled();
ui_disable(); ui_disable();
// ENUMS, then FUNCTIONS, then STRUCTS // ENUMS, then FUNCTIONS, then STRUCTS
unsigned masks[] = { 'E', 'F', 'S' }; unsigned masks[] = { 'E', 'F', 'S' };
for( int i = 0; i < countof(masks); ++i ) for( int i = 0; i < countof(masks); ++i )
for each_map_ptr(reflects, unsigned, k, reflect_t, R) { for each_map_ptr(reflects, unsigned, k, reflect_t, R) {
if( strmatchi(R->name, filter)) { if( strmatchi(R->name, filter)) {
ui_reflect_(R, filter, masks[i]); ui_reflect_(R, filter, masks[i]);
} }
} }
if( enabled ) ui_enable(); if( enabled ) ui_enable();
return 0; return 0;
} }
// -- tests // -- tests
// type0 is reserved (no type) // type0 is reserved (no type)
// type1 reserved for objs // type1 reserved for objs
// type2 reserved for entities // type2 reserved for entities
// @todo: type3 and 4 likely reserved for components and systems?? // @todo: type3 and 4 likely reserved for components and systems??
// enum { OBJTYPE_vec3 = 0x03 }; // enum { OBJTYPE_vec3 = 0x03 };
AUTOTEST { AUTOTEST {
// register structs, enums and functions. with and without comments+tags // register structs, enums and functions. with and without comments+tags
STRUCT( vec3, float, x ); STRUCT( vec3, float, x );
STRUCT( vec3, float, y ); STRUCT( vec3, float, y );
STRUCT( vec3, float, z, "Up" ); STRUCT( vec3, float, z, "Up" );
ENUM( IMAGE_RGB ); ENUM( IMAGE_RGB );
ENUM( TEXTURE_RGB, "3-channel Red+Green+Blue texture flag" ); ENUM( TEXTURE_RGB, "3-channel Red+Green+Blue texture flag" );
ENUM( TEXTURE_RGBA, "4-channel Red+Green+Blue+Alpha texture flag" ); ENUM( TEXTURE_RGBA, "4-channel Red+Green+Blue+Alpha texture flag" );
FUNCTION( puts ); FUNCTION( puts );
FUNCTION( printf, "function that prints formatted text to stdout" ); FUNCTION( printf, "function that prints formatted text to stdout" );
// verify some reflected infos // verify some reflected infos
test( function_find("puts") == puts ); test( function_find("puts") == puts );
test( function_find("printf") == printf ); test( function_find("printf") == printf );
test( enum_find("TEXTURE_RGB") == TEXTURE_RGB ); test( enum_find("TEXTURE_RGB") == TEXTURE_RGB );
test( enum_find("TEXTURE_RGBA") == TEXTURE_RGBA ); test( enum_find("TEXTURE_RGBA") == TEXTURE_RGBA );
// iterate reflected struct // iterate reflected struct
for each_member("vec3", R) { for each_member("vec3", R) {
//printf("+%s vec3.%s (+%x) // %s\n", R->type, R->name, R->member_offset, R->info); //printf("+%s vec3.%s (+%x) // %s\n", R->type, R->name, R->member_offset, R->info);
} }
//reflect_print("puts"); //reflect_print("puts");
//reflect_print("TEXTURE_RGBA"); //reflect_print("TEXTURE_RGBA");
//reflect_print("vec3"); //reflect_print("vec3");
//reflect_dump("*"); //reflect_dump("*");
} }

View File

@ -1,64 +1,64 @@
// C reflection: enums, functions, structs, members and anotations. // C reflection: enums, functions, structs, members and anotations.
// - rlyeh, public domain // - rlyeh, public domain
// //
// @todo: nested structs? pointers in members? // @todo: nested structs? pointers in members?
// @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/) // @todo: declare TYPEDEF(vec3, float[3]), TYPEDEF(mat4, vec4[4]/*float[16]*/)
#ifndef OBJTYPE #ifndef OBJTYPE
#define OBJTYPE(T) 0 #define OBJTYPE(T) 0
#endif #endif
typedef struct reflect_t { typedef struct reflect_t {
unsigned id, objtype; unsigned id, objtype;
union { union {
unsigned sz; unsigned sz;
unsigned member_offset; unsigned member_offset;
unsigned enum_value; unsigned enum_value;
}; };
const char *name; const char *name;
const char *info; const char *info;
void *addr; void *addr;
unsigned parent; unsigned parent;
const char *type; const char *type;
unsigned bytes; unsigned bytes;
} reflect_t; } reflect_t;
// inscribe api // inscribe api
#define ENUM(V, ...) \ #define ENUM(V, ...) \
enum_inscribe(#V,V, "E" __VA_ARGS__ " ("FILELINE")") enum_inscribe(#V,V, "E" __VA_ARGS__ " ("FILELINE")")
#define FUNCTION(F, ...) \ #define FUNCTION(F, ...) \
function_inscribe(#F,(void*)F, "F" __VA_ARGS__ " ("FILELINE")") function_inscribe(#F,(void*)F, "F" __VA_ARGS__ " ("FILELINE")")
#define STRUCT(T, type, member, ...) \ #define STRUCT(T, type, member, ...) \
struct_inscribe(#T,sizeof(T),OBJTYPE(T),"S" " ("FILELINE")"), \ struct_inscribe(#T,sizeof(T),OBJTYPE(T),"S" " ("FILELINE")"), \
type_inscribe(#type,sizeof(((T){0}).member),"T" __VA_ARGS__ " ("FILELINE")"), \ type_inscribe(#type,sizeof(((T){0}).member),"T" __VA_ARGS__ " ("FILELINE")"), \
member_inscribe(#T, #member,(uintptr_t)&((T*)0)->member, "M" __VA_ARGS__ " ("FILELINE")", #type, sizeof(((T){0}).member) ) member_inscribe(#T, #member,(uintptr_t)&((T*)0)->member, "M" __VA_ARGS__ " ("FILELINE")", #type, sizeof(((T){0}).member) )
// find api // find api
API unsigned enum_find(const char *E); API unsigned enum_find(const char *E);
API void * function_find(const char *F); API void * function_find(const char *F);
API reflect_t member_find(const char *T, const char *M); /// find specific member API reflect_t member_find(const char *T, const char *M); /// find specific member
API void * member_findptr(void *obj, const char *T, const char *M); // @deprecate API void * member_findptr(void *obj, const char *T, const char *M); // @deprecate
API array(reflect_t)* members_find(const char *T); API array(reflect_t)* members_find(const char *T);
// iterate members in a struct // iterate members in a struct
#define each_member(T,R) \ #define each_member(T,R) \
(array(reflect_t) *found_ = members_find(T); found_; found_ = 0) \ (array(reflect_t) *found_ = members_find(T); found_; found_ = 0) \
for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \ for(int it_ = 0, end_ = array_count(*found_); it_ != end_; ++it_ ) \
for(reflect_t *R = &(*found_)[it_]; R; R = 0 ) for(reflect_t *R = &(*found_)[it_]; R; R = 0 )
// private api, still exposed // private api, still exposed
API void type_inscribe(const char *TY,unsigned TYsz,const char *infos); API void type_inscribe(const char *TY,unsigned TYsz,const char *infos);
API void enum_inscribe(const char *E,unsigned Eval,const char *infos); API void enum_inscribe(const char *E,unsigned Eval,const char *infos);
API void struct_inscribe(const char *T,unsigned Tsz,unsigned OBJTYPEid, const char *infos); API void struct_inscribe(const char *T,unsigned Tsz,unsigned OBJTYPEid, const char *infos);
API void member_inscribe(const char *T, const char *M,unsigned Msz, const char *infos, const char *type, unsigned bytes); API void member_inscribe(const char *T, const char *M,unsigned Msz, const char *infos, const char *type, unsigned bytes);
API void function_inscribe(const char *F,void *func,const char *infos); API void function_inscribe(const char *F,void *func,const char *infos);
API const char* symbol_naked(const char *s); API const char* symbol_naked(const char *s);
API int ui_reflect(const char *mask); // *, model* or NULL API int ui_reflect(const char *mask); // *, model* or NULL

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +1,70 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// debugdraw framework // debugdraw framework
// - rlyeh, public domain. // - rlyeh, public domain.
// //
// Credits: Based on work by @glampert https://github.com/glampert/debug-draw (PD) // Credits: Based on work by @glampert https://github.com/glampert/debug-draw (PD)
// [x] grid, axis, frustum, cube, sphere, triangle, square, pentagon, hexagon, circle, normal. // [x] grid, axis, frustum, cube, sphere, triangle, square, pentagon, hexagon, circle, normal.
// [x] arrow, point, text, capsule, aabb, plane, flotilla-style locator, boid, bone, ring // [x] arrow, point, text, capsule, aabb, plane, flotilla-style locator, boid, bone, ring
// [x] line batching // [x] line batching
// [*] line width and stipple // [*] line width and stipple
// [*] (proper) gizmo, // [*] (proper) gizmo,
// [ ] camera, light bulb, light probe, // [ ] camera, light bulb, light probe,
API void ddraw_color(unsigned rgb); API void ddraw_color(unsigned rgb);
API void ddraw_color_push(unsigned rgb); API void ddraw_color_push(unsigned rgb);
API void ddraw_color_pop(); API void ddraw_color_pop();
// //
API void ddraw_ontop(int enabled); API void ddraw_ontop(int enabled);
API void ddraw_ontop_push(int enabled); API void ddraw_ontop_push(int enabled);
API void ddraw_ontop_pop(); API void ddraw_ontop_pop();
// //
API void ddraw_push_2d(); API void ddraw_push_2d();
API void ddraw_pop_2d(); API void ddraw_pop_2d();
// //
API void ddraw_aabb(vec3 minbb, vec3 maxbb); API void ddraw_aabb(vec3 minbb, vec3 maxbb);
API void ddraw_aabb_corners(vec3 minbb, vec3 maxbb); API void ddraw_aabb_corners(vec3 minbb, vec3 maxbb);
API void ddraw_arrow(vec3 begin, vec3 end); API void ddraw_arrow(vec3 begin, vec3 end);
API void ddraw_axis(float units); API void ddraw_axis(float units);
API void ddraw_boid(vec3 pos, vec3 dir); API void ddraw_boid(vec3 pos, vec3 dir);
API void ddraw_bone(vec3 center, vec3 end); // @todo: use me API void ddraw_bone(vec3 center, vec3 end); // @todo: use me
API void ddraw_bounds(const vec3 points[8]); API void ddraw_bounds(const vec3 points[8]);
API void ddraw_box(vec3 center, vec3 extents); API void ddraw_box(vec3 center, vec3 extents);
API void ddraw_capsule(vec3 from, vec3 to, float radius); API void ddraw_capsule(vec3 from, vec3 to, float radius);
API void ddraw_circle(vec3 pos, vec3 n, float radius); API void ddraw_circle(vec3 pos, vec3 n, float radius);
API void ddraw_ring(vec3 pos, vec3 n, float radius); API void ddraw_ring(vec3 pos, vec3 n, float radius);
API void ddraw_cone(vec3 center, vec3 top, float radius); API void ddraw_cone(vec3 center, vec3 top, float radius);
API void ddraw_cube(vec3 center, float radius); API void ddraw_cube(vec3 center, float radius);
API void ddraw_cube33(vec3 center, vec3 radius, mat33 M); API void ddraw_cube33(vec3 center, vec3 radius, mat33 M);
API void ddraw_diamond(vec3 from, vec3 to, float size); API void ddraw_diamond(vec3 from, vec3 to, float size);
API void ddraw_frustum(float projview[16]); API void ddraw_frustum(float projview[16]);
API void ddraw_ground(float scale); API void ddraw_ground(float scale);
API void ddraw_grid(float scale); API void ddraw_grid(float scale);
API void ddraw_hexagon(vec3 pos, float radius); API void ddraw_hexagon(vec3 pos, float radius);
API void ddraw_line(vec3 from, vec3 to); API void ddraw_line(vec3 from, vec3 to);
API void ddraw_line_dashed(vec3 from, vec3 to); API void ddraw_line_dashed(vec3 from, vec3 to);
API void ddraw_line_thin(vec3 from, vec3 to); API void ddraw_line_thin(vec3 from, vec3 to);
API void ddraw_normal(vec3 pos, vec3 n); API void ddraw_normal(vec3 pos, vec3 n);
API void ddraw_pentagon(vec3 pos, float radius); API void ddraw_pentagon(vec3 pos, float radius);
API void ddraw_plane(vec3 p, vec3 n, float scale); API void ddraw_plane(vec3 p, vec3 n, float scale);
API void ddraw_point(vec3 from); API void ddraw_point(vec3 from);
API void ddraw_position(vec3 pos, float radius); API void ddraw_position(vec3 pos, float radius);
API void ddraw_position_dir(vec3 pos, vec3 dir, float radius); API void ddraw_position_dir(vec3 pos, vec3 dir, float radius);
API void ddraw_pyramid(vec3 center, float height, int segments); API void ddraw_pyramid(vec3 center, float height, int segments);
API void ddraw_cylinder(vec3 center, float height, int segments); API void ddraw_cylinder(vec3 center, float height, int segments);
API void ddraw_sphere(vec3 pos, float radius); API void ddraw_sphere(vec3 pos, float radius);
API void ddraw_square(vec3 pos, float radius); API void ddraw_square(vec3 pos, float radius);
API void ddraw_text(vec3 pos, float scale, const char *text); API void ddraw_text(vec3 pos, float scale, const char *text);
API void ddraw_text2d(vec2 pos, const char *text); API void ddraw_text2d(vec2 pos, const char *text);
API void ddraw_triangle(vec3 p1, vec3 p2, vec3 p3); API void ddraw_triangle(vec3 p1, vec3 p2, vec3 p3);
// //
API void ddraw_prism(vec3 center, float radius, float height, vec3 normal, int segments); API void ddraw_prism(vec3 center, float radius, float height, vec3 normal, int segments);
// //
API void ddraw_demo(); API void ddraw_demo();
API void ddraw_flush(); API void ddraw_flush();
API void ddraw_flush_projview(mat44 proj, mat44 view); API void ddraw_flush_projview(mat44 proj, mat44 view);
// transform gizmos // transform gizmos
API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca);
API bool gizmo_active(); API bool gizmo_active();
API bool gizmo_hover(); API bool gizmo_hover();

File diff suppressed because it is too large Load Diff

View File

@ -1,143 +1,143 @@
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// scene framework // scene framework
// - rlyeh, public domain // - rlyeh, public domain
// camera // camera
typedef struct camera_t { typedef struct camera_t {
mat44 view, proj; mat44 view, proj;
vec3 position, updir, lookdir; vec3 position, updir, lookdir;
float yaw, pitch, roll; // mirror of (x,y) lookdir in deg; float yaw, pitch, roll; // mirror of (x,y) lookdir in deg;
float speed, fov; // fov in deg(45) float speed, fov; // fov in deg(45)
float move_friction, move_damping; float move_friction, move_damping;
float look_friction, look_damping; float look_friction, look_damping;
vec3 last_look; vec3 last_move; // used for friction and damping vec3 last_look; vec3 last_move; // used for friction and damping
bool damping; bool damping;
bool orthographic; // 0 perspective, 1 orthographic; when ortho: dimetric[if pitch == -30º], isometric[if pitch == 35.264º] bool orthographic; // 0 perspective, 1 orthographic; when ortho: dimetric[if pitch == -30º], isometric[if pitch == 35.264º]
float distance; // distance to pivot, when orbiting float distance; // distance to pivot, when orbiting
// vec2 polarity = { +1,-1 }; // @todo // vec2 polarity = { +1,-1 }; // @todo
// vec2 sensitivity = { 2,2 }; // @todo // vec2 sensitivity = { 2,2 }; // @todo
} camera_t; } camera_t;
API camera_t camera(); API camera_t camera();
API void camera_teleport(camera_t *cam, vec3 pos); API void camera_teleport(camera_t *cam, vec3 pos);
API void camera_moveby(camera_t *cam, vec3 inc); API void camera_moveby(camera_t *cam, vec3 inc);
API void camera_fov(camera_t *cam, float fov); API void camera_fov(camera_t *cam, float fov);
API void camera_fps(camera_t *cam, float yaw, float pitch); API void camera_fps(camera_t *cam, float yaw, float pitch);
API void camera_fps2(camera_t *cam, float yaw, float pitch, float roll); API void camera_fps2(camera_t *cam, float yaw, float pitch, float roll);
API void camera_orbit(camera_t *cam, float yaw, float pitch, float inc_distance); API void camera_orbit(camera_t *cam, float yaw, float pitch, float inc_distance);
API void camera_lookat(camera_t *cam, vec3 target); API void camera_lookat(camera_t *cam, vec3 target);
API void camera_enable(camera_t *cam); API void camera_enable(camera_t *cam);
API camera_t *camera_get_active(); API camera_t *camera_get_active();
API int ui_camera(camera_t *cam); API int ui_camera(camera_t *cam);
API void ddraw_camera(camera_t *cam); API void ddraw_camera(camera_t *cam);
// object // object
typedef struct object_t { typedef struct object_t {
uint64_t renderbucket; uint64_t renderbucket;
mat44 transform; mat44 transform;
quat rot; quat rot;
vec3 sca, pos, euler, pivot; vec3 sca, pos, euler, pivot;
array(handle) textures; array(handle) textures;
model_t model; model_t model;
anim_t anim; anim_t anim;
float anim_speed; float anim_speed;
aabb bounds; aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool light_cached; //< used by scene to update light data bool light_cached; //< used by scene to update light data
} object_t; } object_t;
API object_t object(); API object_t object();
API void object_rotate(object_t *obj, vec3 euler); API void object_rotate(object_t *obj, vec3 euler);
API void object_pivot(object_t *obj, vec3 euler); API void object_pivot(object_t *obj, vec3 euler);
API void object_teleport(object_t *obj, vec3 pos); API void object_teleport(object_t *obj, vec3 pos);
API void object_move(object_t *obj, vec3 inc); API void object_move(object_t *obj, vec3 inc);
API vec3 object_position(object_t *obj); API vec3 object_position(object_t *obj);
API void object_scale(object_t *obj, vec3 sca); API void object_scale(object_t *obj, vec3 sca);
// //
API void object_model(object_t *obj, model_t model); API void object_model(object_t *obj, model_t model);
API void object_anim(object_t *obj, anim_t anim, float speed); API void object_anim(object_t *obj, anim_t anim, float speed);
API void object_diffuse(object_t *obj, texture_t tex); API void object_diffuse(object_t *obj, texture_t tex);
API void object_diffuse_push(object_t *obj, texture_t tex); API void object_diffuse_push(object_t *obj, texture_t tex);
API void object_diffuse_pop(object_t *obj); API void object_diffuse_pop(object_t *obj);
API void object_billboard(object_t *obj, unsigned mode); API void object_billboard(object_t *obj, unsigned mode);
// object_pose(transform); // @todo // object_pose(transform); // @todo
// light // light
enum LIGHT_TYPE { enum LIGHT_TYPE {
LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL,
LIGHT_POINT, LIGHT_POINT,
LIGHT_SPOT, LIGHT_SPOT,
}; };
enum LIGHT_FLAGS { enum LIGHT_FLAGS {
LIGHT_CAST_SHADOWS = 1, LIGHT_CAST_SHADOWS = 1,
}; };
typedef struct light_t { typedef struct light_t {
char type; char type;
vec3 diffuse, specular, ambient; vec3 diffuse, specular, ambient;
vec3 pos, dir; vec3 pos, dir;
struct { struct {
float constant, linear, quadratic; float constant, linear, quadratic;
} falloff; } falloff;
float specularPower; float specularPower;
float innerCone, outerCone; float innerCone, outerCone;
//@todo: cookie, flare //@todo: cookie, flare
// internals // internals
bool cached; //< used by scene to invalidate cached light data bool cached; //< used by scene to invalidate cached light data
} light_t; } light_t;
API light_t light(); API light_t light();
// API void light_flags(int flags); // API void light_flags(int flags);
API void light_type(light_t* l, char type); API void light_type(light_t* l, char type);
API void light_diffuse(light_t* l, vec3 color); API void light_diffuse(light_t* l, vec3 color);
API void light_specular(light_t* l, vec3 color); API void light_specular(light_t* l, vec3 color);
API void light_ambient(light_t* l, vec3 color); API void light_ambient(light_t* l, vec3 color);
API void light_teleport(light_t* l, vec3 pos); API void light_teleport(light_t* l, vec3 pos);
API void light_dir(light_t* l, vec3 dir); API void light_dir(light_t* l, vec3 dir);
API void light_power(light_t* l, float power); API void light_power(light_t* l, float power);
API void light_falloff(light_t* l, float constant, float linear, float quadratic); API void light_falloff(light_t* l, float constant, float linear, float quadratic);
API void light_cone(light_t* l, float innerCone, float outerCone); API void light_cone(light_t* l, float innerCone, float outerCone);
API void light_update(unsigned num_lights, light_t *lv); API void light_update(unsigned num_lights, light_t *lv);
// scene // scene
enum SCENE_FLAGS { enum SCENE_FLAGS {
SCENE_WIREFRAME = 1, SCENE_WIREFRAME = 1,
SCENE_CULLFACE = 2, SCENE_CULLFACE = 2,
SCENE_BACKGROUND = 4, SCENE_BACKGROUND = 4,
SCENE_FOREGROUND = 8, SCENE_FOREGROUND = 8,
SCENE_UPDATE_SH_COEF = 16, SCENE_UPDATE_SH_COEF = 16,
}; };
typedef struct scene_t { typedef struct scene_t {
array(object_t) objs; array(object_t) objs;
array(light_t) lights; array(light_t) lights;
// special objects below: // special objects below:
skybox_t skybox; skybox_t skybox;
int u_coefficients_sh; int u_coefficients_sh;
} scene_t; } scene_t;
API scene_t* scene_push(); API scene_t* scene_push();
API void scene_pop(); API void scene_pop();
API scene_t* scene_get_active(); API scene_t* scene_get_active();
API int scene_merge(const char *source); API int scene_merge(const char *source);
API void scene_render(int flags); API void scene_render(int flags);
API object_t* scene_spawn(); API object_t* scene_spawn();
API unsigned scene_count(); API unsigned scene_count();
API object_t* scene_index(unsigned index); API object_t* scene_index(unsigned index);
API light_t* scene_spawn_light(); API light_t* scene_spawn_light();
API unsigned scene_count_light(); API unsigned scene_count_light();
API light_t* scene_index_light(unsigned index); API light_t* scene_index_light(unsigned index);

Some files were not shown because too many files have changed in this diff Show More