Browse Source

SIN: Reformat the whole codebase using tweaked .clang-format

yes, sorry, was actually quite well formatted (clang-format default) ... but its probably just me working on the code ever. So, i will just use my preferences here.
I find it important. visual guy and all other excuses...
master
heck 2 years ago
parent
commit
53575550f0
  1. 37
      .clang-format
  2. 2
      Makefile.conf
  3. 120
      src/base.h
  4. 152
      src/cli_main.c
  5. 289
      src/field.c
  6. 23
      src/field.h
  7. 164
      src/gbuffer.c
  8. 151
      src/gbuffer.h
  9. 426
      src/osc_out.c
  10. 45
      src/osc_out.h
  11. 402
      src/oso.c
  12. 31
      src/oso.h
  13. 1283
      src/sim.c
  14. 11
      src/sim.h
  15. 135
      src/sokol_time.h
  16. 1112
      src/sysmisc.c
  17. 165
      src/sysmisc.h
  18. 1327
      src/term_util.c
  19. 128
      src/term_util.h
  20. 7355
      src/tui_main.c
  21. 65
      src/vmio.c
  22. 67
      src/vmio.h

37
.clang-format

@ -3,3 +3,40 @@ ReflowComments: false
MacroBlockBegin: "^BEGIN_OPERATOR"
MacroBlockEnd: "^END_OPERATOR"
Language: Cpp
DerivePointerAlignment: true
SortIncludes: Never
PointerAlignment: Left
AlignAfterOpenBracket: AlwaysBreak
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
ColumnLimit: 100
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyReturnTypeOnItsOwnLine: 1000000
PenaltyBreakAssignment: 1000000
PenaltyExcessCharacter: 10
IndentCaseLabels: true
IndentWidth: 4
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
SpaceAfterTemplateKeyword: false
AccessModifierOffset: -4
AllowShortBlocksOnASingleLine: Always
IndentPPDirectives: BeforeHash
IndentExternBlock: Indent
Cpp11BracedListStyle: false

2
Makefile.conf

@ -1,4 +1,4 @@
TARGET=tui_main
TARGET=orca_tui
LANG_VERSION=c99

120
src/base.h

@ -9,54 +9,52 @@
// clang or gcc or other
#if defined(__clang__)
#define ORCA_OPT_MINSIZE __attribute__((minsize))
#define ORCA_OPT_MINSIZE __attribute__((minsize))
#elif defined(__GNUC__)
#define ORCA_OPT_MINSIZE __attribute__((optimize("Os")))
#define ORCA_OPT_MINSIZE __attribute__((optimize("Os")))
#else
#define ORCA_OPT_MINSIZE
#define ORCA_OPT_MINSIZE
#endif
// (gcc / clang) or msvc or other
#if defined(__GNUC__) || defined(__clang__)
#define ORCA_FORCEINLINE __attribute__((always_inline)) inline
#define ORCA_NOINLINE __attribute__((noinline))
#define ORCA_FORCEINLINE __attribute__((always_inline)) inline
#define ORCA_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define ORCA_FORCEINLINE __forceinline
#define ORCA_NOINLINE __declspec(noinline)
#define ORCA_FORCEINLINE __forceinline
#define ORCA_NOINLINE __declspec(noinline)
#else
#define ORCA_FORCEINLINE inline
#define ORCA_NOINLINE
#define ORCA_FORCEINLINE inline
#define ORCA_NOINLINE
#endif
// (gcc / clang) or other
#if defined(__GNUC__) || defined(__clang__)
#define ORCA_ASSUME_ALIGNED(_ptr, _alignment) \
__builtin_assume_aligned(_ptr, _alignment)
#define ORCA_PURE __attribute__((pure))
#define ORCA_LIKELY(_x) __builtin_expect(_x, 1)
#define ORCA_UNLIKELY(_x) __builtin_expect(_x, 0)
#define ORCA_OK_IF_UNUSED __attribute__((unused))
#define ORCA_UNREACHABLE __builtin_unreachable()
#define ORCA_ASSUME_ALIGNED(_ptr, _alignment) __builtin_assume_aligned(_ptr, _alignment)
#define ORCA_PURE __attribute__((pure))
#define ORCA_LIKELY(_x) __builtin_expect(_x, 1)
#define ORCA_UNLIKELY(_x) __builtin_expect(_x, 0)
#define ORCA_OK_IF_UNUSED __attribute__((unused))
#define ORCA_UNREACHABLE __builtin_unreachable()
#else
#define ORCA_ASSUME_ALIGNED(_ptr, _alignment) (_ptr)
#define ORCA_PURE
#define ORCA_LIKELY(_x) (_x)
#define ORCA_UNLIKELY(_x) (_x)
#define ORCA_OK_IF_UNUSED
#define ORCA_UNREACHABLE assert(false)
#define ORCA_ASSUME_ALIGNED(_ptr, _alignment) (_ptr)
#define ORCA_PURE
#define ORCA_LIKELY(_x) (_x)
#define ORCA_UNLIKELY(_x) (_x)
#define ORCA_OK_IF_UNUSED
#define ORCA_UNREACHABLE assert(false)
#endif
// array count, safer on gcc/clang
#if defined(__GNUC__) || defined(__clang__)
#define ORCA_ASSERT_IS_ARRAY(_array) \
(sizeof(char[1 - 2 * __builtin_types_compatible_p( \
__typeof(_array), __typeof(&(_array)[0]))]) - \
1)
#define ORCA_ARRAY_COUNTOF(_array) \
(sizeof(_array) / sizeof((_array)[0]) + ORCA_ASSERT_IS_ARRAY(_array))
#define ORCA_ASSERT_IS_ARRAY(_array) \
(sizeof(char[1 - 2 * __builtin_types_compatible_p(__typeof(_array), __typeof(&(_array)[0]))]) - \
1)
#define ORCA_ARRAY_COUNTOF(_array) \
(sizeof(_array) / sizeof((_array)[0]) + ORCA_ASSERT_IS_ARRAY(_array))
#else
// pray
#define ORCA_ARRAY_COUNTOF(_array) (sizeof(_array) / sizeof(_array[0]))
// pray
#define ORCA_ARRAY_COUNTOF(_array) (sizeof(_array) / sizeof(_array[0]))
#endif
#define ORCA_Y_MAX UINT16_MAX
@ -76,39 +74,41 @@ typedef ssize_t Isz;
typedef char Glyph;
typedef U8 Mark;
ORCA_FORCEINLINE static Usz orca_round_up_power2(Usz x) {
assert(x <= SIZE_MAX / 2 + 1);
x -= 1;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
ORCA_FORCEINLINE static Usz orca_round_up_power2(Usz x)
{
assert(x <= SIZE_MAX / 2 + 1);
x -= 1;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
#if SIZE_MAX > UINT32_MAX
x |= x >> 32;
x |= x >> 32;
#endif
return x + 1;
return x + 1;
}
ORCA_OK_IF_UNUSED
static bool orca_is_valid_glyph(Glyph c) {
if (c >= '0' && c <= '9')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c >= 'a' && c <= 'z')
return true;
switch (c) {
case '!':
case '#':
case '%':
case '*':
case '.':
case ':':
case ';':
case '=':
case '?':
return true;
}
return false;
static bool orca_is_valid_glyph(Glyph c)
{
if (c >= '0' && c <= '9')
return true;
if (c >= 'A' && c <= 'Z')
return true;
if (c >= 'a' && c <= 'z')
return true;
switch (c) {
case '!':
case '#':
case '%':
case '*':
case '.':
case ':':
case ';':
case '=':
case '?':
return true;
}
return false;
}

152
src/cli_main.c

@ -5,7 +5,8 @@
#include "vmio.h"
#include <getopt.h>
static ORCA_NOINLINE void usage(void) { // clang-format off
static ORCA_NOINLINE void usage(void)
{ // clang-format off
fprintf(stderr,
"Usage: cli [options] infile\n\n"
"Options:\n"
@ -16,85 +17,86 @@ fprintf(stderr,
" -h or --help Print this message and exit.\n"
);} // clang-format on
int main(int argc, char **argv) {
static struct option cli_options[] = {{"help", no_argument, 0, 'h'},
{"quiet", no_argument, 0, 'q'},
{NULL, 0, NULL, 0}};
int main(int argc, char **argv)
{
static struct option cli_options[] = { { "help", no_argument, 0, 'h' },
{ "quiet", no_argument, 0, 'q' },
{ NULL, 0, NULL, 0 } };
char *input_file = NULL;
int ticks = 1;
bool print_output = true;
char *input_file = NULL;
int ticks = 1;
bool print_output = true;
for (;;) {
int c = getopt_long(argc, argv, "t:qh", cli_options, NULL);
if (c == -1)
break;
switch (c) {
case 't':
ticks = atoi(optarg);
if (ticks == 0 && strcmp(optarg, "0")) {
fprintf(stderr,
"Bad timestep argument %s.\n"
"Must be 0 or a positive integer.\n",
optarg);
return 1;
}
break;
case 'q':
print_output = false;
break;
case 'h':
usage();
return 0;
case '?':
usage();
return 1;
for (;;) {
int c = getopt_long(argc, argv, "t:qh", cli_options, NULL);
if (c == -1)
break;
switch (c) {
case 't':
ticks = atoi(optarg);
if (ticks == 0 && strcmp(optarg, "0")) {
fprintf(
stderr,
"Bad timestep argument %s.\n"
"Must be 0 or a positive integer.\n",
optarg);
return 1;
}
break;
case 'q':
print_output = false;
break;
case 'h':
usage();
return 0;
case '?':
usage();
return 1;
}
}
}
if (optind == argc - 1) {
input_file = argv[optind];
} else if (optind < argc - 1) {
fprintf(stderr, "Expected only 1 file argument.\n");
usage();
return 1;
}
if (optind == argc - 1) {
input_file = argv[optind];
} else if (optind < argc - 1) {
fprintf(stderr, "Expected only 1 file argument.\n");
usage();
return 1;
}
if (input_file == NULL) {
fprintf(stderr, "No input file.\n");
usage();
return 1;
}
if (ticks < 0) {
fprintf(stderr, "Time must be >= 0.\n");
usage();
return 1;
}
if (input_file == NULL) {
fprintf(stderr, "No input file.\n");
usage();
return 1;
}
if (ticks < 0) {
fprintf(stderr, "Time must be >= 0.\n");
usage();
return 1;
}
Field field;
field_init(&field);
Field_load_error fle = field_load_file(input_file, &field);
if (fle != Field_load_error_ok) {
Field field;
field_init(&field);
Field_load_error fle = field_load_file(input_file, &field);
if (fle != Field_load_error_ok) {
field_deinit(&field);
fprintf(stderr, "File load error: %s.\n", field_load_error_string(fle));
return 1;
}
Mbuf_reusable mbuf_r;
mbuf_reusable_init(&mbuf_r);
mbuf_reusable_ensure_size(&mbuf_r, field.height, field.width);
Oevent_list oevent_list;
oevent_list_init(&oevent_list);
Usz max_ticks = (Usz)ticks;
for (Usz i = 0; i < max_ticks; ++i) {
mbuffer_clear(mbuf_r.buffer, field.height, field.width);
oevent_list_clear(&oevent_list);
orca_run(field.buffer, mbuf_r.buffer, field.height, field.width, i, &oevent_list, 0);
}
mbuf_reusable_deinit(&mbuf_r);
oevent_list_deinit(&oevent_list);
if (print_output)
field_fput(&field, stdout);
field_deinit(&field);
fprintf(stderr, "File load error: %s.\n", field_load_error_string(fle));
return 1;
}
Mbuf_reusable mbuf_r;
mbuf_reusable_init(&mbuf_r);
mbuf_reusable_ensure_size(&mbuf_r, field.height, field.width);
Oevent_list oevent_list;
oevent_list_init(&oevent_list);
Usz max_ticks = (Usz)ticks;
for (Usz i = 0; i < max_ticks; ++i) {
mbuffer_clear(mbuf_r.buffer, field.height, field.width);
oevent_list_clear(&oevent_list);
orca_run(field.buffer, mbuf_r.buffer, field.height, field.width, i,
&oevent_list, 0);
}
mbuf_reusable_deinit(&mbuf_r);
oevent_list_deinit(&oevent_list);
if (print_output)
field_fput(&field, stdout);
field_deinit(&field);
return 0;
return 0;
}

289
src/field.c

@ -2,156 +2,191 @@
#include "gbuffer.h"
#include <ctype.h>
void field_init(Field *f) {
f->buffer = NULL;
f->height = 0;
f->width = 0;
void field_init(Field *f)
{
f->buffer = NULL;
f->height = 0;
f->width = 0;
}
void field_init_fill(Field *f, Usz height, Usz width, Glyph fill_char) {
assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX);
Usz num_cells = height * width;
f->buffer = malloc(num_cells * sizeof(Glyph));
memset(f->buffer, fill_char, num_cells);
f->height = (U16)height;
f->width = (U16)width;
void field_init_fill(Field *f, Usz height, Usz width, Glyph fill_char)
{
assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX);
Usz num_cells = height * width;
f->buffer = malloc(num_cells * sizeof(Glyph));
memset(f->buffer, fill_char, num_cells);
f->height = (U16)height;
f->width = (U16)width;
}
void field_deinit(Field *f) { free(f->buffer); }
void field_deinit(Field *f)
{
free(f->buffer);
}
void field_resize_raw(Field *f, Usz height, Usz width) {
assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX);
Usz cells = height * width;
f->buffer = realloc(f->buffer, cells * sizeof(Glyph));
f->height = (U16)height;
f->width = (U16)width;
void field_resize_raw(Field *f, Usz height, Usz width)
{
assert(height <= ORCA_Y_MAX && width <= ORCA_X_MAX);
Usz cells = height * width;
f->buffer = realloc(f->buffer, cells * sizeof(Glyph));
f->height = (U16)height;
f->width = (U16)width;
}
void field_resize_raw_if_necessary(Field *field, Usz height, Usz width) {
if (field->height != height || field->width != width) {
field_resize_raw(field, height, width);
}
void field_resize_raw_if_necessary(Field *field, Usz height, Usz width)
{
if (field->height != height || field->width != width) {
field_resize_raw(field, height, width);
}
}
void field_copy(Field *src, Field *dest) {
field_resize_raw_if_necessary(dest, src->height, src->width);
gbuffer_copy_subrect(src->buffer, dest->buffer, src->height, src->width,
dest->height, dest->width, 0, 0, 0, 0, src->height,
src->width);
void field_copy(Field *src, Field *dest)
{
field_resize_raw_if_necessary(dest, src->height, src->width);
gbuffer_copy_subrect(
src->buffer,
dest->buffer,
src->height,
src->width,
dest->height,
dest->width,
0,
0,
0,
0,
src->height,
src->width);
}
static inline bool glyph_char_is_valid(char c) { return c >= '!' && c <= '~'; }
static inline bool glyph_char_is_valid(char c)
{
return c >= '!' && c <= '~';
}
void field_fput(Field *f, FILE *stream) {
enum { Column_buffer_count = 4096 };
char out_buffer[Column_buffer_count];
Usz f_height = f->height;
Usz f_width = f->width;
Glyph *f_buffer = f->buffer;
if (f_width > Column_buffer_count - 2)
return;
for (Usz iy = 0; iy < f_height; ++iy) {
Glyph *row_p = f_buffer + f_width * iy;
for (Usz ix = 0; ix < f_width; ++ix) {
char c = row_p[ix];
out_buffer[ix] = glyph_char_is_valid(c) ? c : '?';
void field_fput(Field *f, FILE *stream)
{
enum
{
Column_buffer_count = 4096
};
char out_buffer[Column_buffer_count];
Usz f_height = f->height;
Usz f_width = f->width;
Glyph *f_buffer = f->buffer;
if (f_width > Column_buffer_count - 2)
return;
for (Usz iy = 0; iy < f_height; ++iy) {
Glyph *row_p = f_buffer + f_width * iy;
for (Usz ix = 0; ix < f_width; ++ix) {
char c = row_p[ix];
out_buffer[ix] = glyph_char_is_valid(c) ? c : '?';
}
out_buffer[f_width] = '\n';
out_buffer[f_width + 1] = '\0';
fputs(out_buffer, stream);
}
out_buffer[f_width] = '\n';
out_buffer[f_width + 1] = '\0';
fputs(out_buffer, stream);
}
}
Field_load_error field_load_file(char const *filepath, Field *field) {
FILE *file = fopen(filepath, "r");
if (file == NULL) {
return Field_load_error_cant_open_file;
}
enum { Bufsize = 4096 };
char buf[Bufsize];
Usz first_row_columns = 0;
Usz rows = 0;
for (;;) {
char *s = fgets(buf, Bufsize, file);
if (s == NULL)
break;
if (rows == ORCA_Y_MAX) {
fclose(file);
return Field_load_error_too_many_rows;
}
Usz len = strlen(buf);
if (len == Bufsize - 1 && buf[len - 1] != '\n' && !feof(file)) {
fclose(file);
return Field_load_error_too_many_columns;
Field_load_error field_load_file(char const *filepath, Field *field)
{
FILE *file = fopen(filepath, "r");
if (file == NULL) {
return Field_load_error_cant_open_file;
}
enum
{
Bufsize = 4096
};
char buf[Bufsize];
Usz first_row_columns = 0;
Usz rows = 0;
for (;;) {
if (len == 0)
break;
if (!isspace(buf[len - 1]))
break;
--len;
}
if (len == 0)
continue;
if (len >= ORCA_X_MAX) {
fclose(file);
return Field_load_error_too_many_columns;
char *s = fgets(buf, Bufsize, file);
if (s == NULL)
break;
if (rows == ORCA_Y_MAX) {
fclose(file);
return Field_load_error_too_many_rows;
}
Usz len = strlen(buf);
if (len == Bufsize - 1 && buf[len - 1] != '\n' && !feof(file)) {
fclose(file);
return Field_load_error_too_many_columns;
}
for (;;) {
if (len == 0)
break;
if (!isspace(buf[len - 1]))
break;
--len;
}
if (len == 0)
continue;
if (len >= ORCA_X_MAX) {
fclose(file);
return Field_load_error_too_many_columns;
}
// quick hack until we use a proper scanner
if (rows == 0) {
first_row_columns = len;
} else if (len != first_row_columns) {
fclose(file);
return Field_load_error_not_a_rectangle;
}
field_resize_raw(field, rows + 1, first_row_columns);
Glyph *rowbuff = field->buffer + first_row_columns * rows;
for (Usz i = 0; i < len; ++i) {
char c = buf[i];
rowbuff[i] = glyph_char_is_valid(c) ? c : '.';
}
++rows;
}
// quick hack until we use a proper scanner
if (rows == 0) {
first_row_columns = len;
} else if (len != first_row_columns) {
fclose(file);
return Field_load_error_not_a_rectangle;
}
field_resize_raw(field, rows + 1, first_row_columns);
Glyph *rowbuff = field->buffer + first_row_columns * rows;
for (Usz i = 0; i < len; ++i) {
char c = buf[i];
rowbuff[i] = glyph_char_is_valid(c) ? c : '.';
}
++rows;
}
fclose(file);
return Field_load_error_ok;
fclose(file);
return Field_load_error_ok;
}
char const *field_load_error_string(Field_load_error fle) {
char const *errstr = "Unknown";
switch (fle) {
case Field_load_error_ok:
errstr = "OK";
break;
case Field_load_error_cant_open_file:
errstr = "Unable to open file";
break;
case Field_load_error_too_many_columns:
errstr = "Grid file has too many columns";
break;
case Field_load_error_too_many_rows:
errstr = "Grid file has too many rows";
break;
case Field_load_error_no_rows_read:
errstr = "Grid file has no rows";
break;
case Field_load_error_not_a_rectangle:
errstr = "Grid file is not a rectangle";
break;
}
return errstr;
char const *field_load_error_string(Field_load_error fle)
{
char const *errstr = "Unknown";
switch (fle) {
case Field_load_error_ok:
errstr = "OK";
break;
case Field_load_error_cant_open_file:
errstr = "Unable to open file";
break;
case Field_load_error_too_many_columns:
errstr = "Grid file has too many columns";
break;
case Field_load_error_too_many_rows:
errstr = "Grid file has too many rows";
break;
case Field_load_error_no_rows_read:
errstr = "Grid file has no rows";
break;
case Field_load_error_not_a_rectangle:
errstr = "Grid file is not a rectangle";
break;
}
return errstr;
}
void mbuf_reusable_init(Mbuf_reusable *mbr) {
mbr->buffer = NULL;
mbr->capacity = 0;
void mbuf_reusable_init(Mbuf_reusable *mbr)
{
mbr->buffer = NULL;
mbr->capacity = 0;
}
void mbuf_reusable_ensure_size(Mbuf_reusable *mbr, Usz height, Usz width) {
Usz capacity = height * width;
if (mbr->capacity < capacity) {
mbr->buffer = realloc(mbr->buffer, capacity);
mbr->capacity = capacity;
}
void mbuf_reusable_ensure_size(Mbuf_reusable *mbr, Usz height, Usz width)
{
Usz capacity = height * width;
if (mbr->capacity < capacity) {
mbr->buffer = realloc(mbr->buffer, capacity);
mbr->capacity = capacity;
}
}
void mbuf_reusable_deinit(Mbuf_reusable *mbr) { free(mbr->buffer); }
void mbuf_reusable_deinit(Mbuf_reusable *mbr)
{
free(mbr->buffer);
}

23
src/field.h

@ -7,8 +7,8 @@
// might want to do. Not used by the VM.
typedef struct {
Glyph *buffer;
U16 width, height;
Glyph *buffer;
U16 width, height;
} Field;
void field_init(Field *field);
@ -19,13 +19,14 @@ void field_resize_raw_if_necessary(Field *field, Usz height, Usz width);
void field_copy(Field *src, Field *dest);
void field_fput(Field *field, FILE *stream);
typedef enum {
Field_load_error_ok = 0,
Field_load_error_cant_open_file = 1,
Field_load_error_too_many_columns = 2,
Field_load_error_too_many_rows = 3,
Field_load_error_no_rows_read = 4,
Field_load_error_not_a_rectangle = 5,
typedef enum
{
Field_load_error_ok = 0,
Field_load_error_cant_open_file = 1,
Field_load_error_too_many_columns = 2,
Field_load_error_too_many_rows = 3,
Field_load_error_no_rows_read = 4,
Field_load_error_not_a_rectangle = 5,
} Field_load_error;
Field_load_error field_load_file(char const *filepath, Field *field);
@ -41,8 +42,8 @@ char const *field_load_error_string(Field_load_error fle);
// that functionality.
typedef struct Mbuf_reusable {
Mark *buffer;
Usz capacity;
Mark *buffer;
Usz capacity;
} Mbuf_reusable;
void mbuf_reusable_init(Mbuf_reusable *mbr);

164
src/gbuffer.c

@ -1,80 +1,98 @@
#include "gbuffer.h"
void gbuffer_copy_subrect(Glyph *src, Glyph *dest, Usz src_height,
Usz src_width, Usz dest_height, Usz dest_width,
Usz src_y, Usz src_x, Usz dest_y, Usz dest_x,
Usz height, Usz width) {
if (src_height <= src_y || src_width <= src_x || dest_height <= dest_y ||
dest_width <= dest_x)
return;
Usz ny_0 = src_height - src_y;
Usz ny_1 = dest_height - dest_y;
Usz ny = height;
if (ny_0 < ny)
ny = ny_0;
if (ny_1 < ny)
ny = ny_1;
if (ny == 0)
return;
Usz row_copy_0 = src_width - src_x;
Usz row_copy_1 = dest_width - dest_x;
Usz row_copy = width;
if (row_copy_0 < row_copy)
row_copy = row_copy_0;
if (row_copy_1 < row_copy)
row_copy = row_copy_1;
Usz copy_bytes = row_copy * sizeof(Glyph);
Glyph *src_p = src + src_y * src_width + src_x;
Glyph *dest_p = dest + dest_y * dest_width + dest_x;
Isz src_stride;
Isz dest_stride;
if (src_y >= dest_y) {
src_stride = (Isz)src_width;
dest_stride = (Isz)dest_width;
} else {
src_p += (ny - 1) * src_width;
dest_p += (ny - 1) * dest_width;
src_stride = -(Isz)src_width;
dest_stride = -(Isz)dest_width;
}
Usz iy = 0;
for (;;) {
memmove(dest_p, src_p, copy_bytes);
++iy;
if (iy == ny)
break;
src_p += src_stride;
dest_p += dest_stride;
}
void gbuffer_copy_subrect(
Glyph *src,
Glyph *dest,
Usz src_height,
Usz src_width,
Usz dest_height,
Usz dest_width,
Usz src_y,
Usz src_x,
Usz dest_y,
Usz dest_x,
Usz height,
Usz width)
{
if (src_height <= src_y || src_width <= src_x || dest_height <= dest_y || dest_width <= dest_x)
return;
Usz ny_0 = src_height - src_y;
Usz ny_1 = dest_height - dest_y;
Usz ny = height;
if (ny_0 < ny)
ny = ny_0;
if (ny_1 < ny)
ny = ny_1;
if (ny == 0)
return;
Usz row_copy_0 = src_width - src_x;
Usz row_copy_1 = dest_width - dest_x;
Usz row_copy = width;
if (row_copy_0 < row_copy)
row_copy = row_copy_0;
if (row_copy_1 < row_copy)
row_copy = row_copy_1;
Usz copy_bytes = row_copy * sizeof(Glyph);
Glyph *src_p = src + src_y * src_width + src_x;
Glyph *dest_p = dest + dest_y * dest_width + dest_x;
Isz src_stride;
Isz dest_stride;
if (src_y >= dest_y) {
src_stride = (Isz)src_width;
dest_stride = (Isz)dest_width;
} else {
src_p += (ny - 1) * src_width;
dest_p += (ny - 1) * dest_width;
src_stride = -(Isz)src_width;
dest_stride = -(Isz)dest_width;
}
Usz iy = 0;
for (;;) {
memmove(dest_p, src_p, copy_bytes);
++iy;
if (iy == ny)
break;
src_p += src_stride;
dest_p += dest_stride;
}
}
void gbuffer_fill_subrect(Glyph *gbuffer, Usz f_height, Usz f_width, Usz y,
Usz x, Usz height, Usz width, Glyph fill_char) {
if (y >= f_height || x >= f_width)
return;
Usz rows_0 = f_height - y;
Usz rows = height;
if (rows_0 < rows)
rows = rows_0;
if (rows == 0)
return;
Usz columns_0 = f_width - x;
Usz columns = width;
if (columns_0 < columns)
columns = columns_0;
Usz fill_bytes = columns * sizeof(Glyph);
Glyph *p = gbuffer + y * f_width + x;
Usz iy = 0;
for (;;) {
memset(p, fill_char, fill_bytes);
++iy;
if (iy == rows)
break;
p += f_width;
}
void gbuffer_fill_subrect(
Glyph *gbuffer,
Usz f_height,
Usz f_width,
Usz y,
Usz x,
Usz height,
Usz width,
Glyph fill_char)
{
if (y >= f_height || x >= f_width)
return;
Usz rows_0 = f_height - y;
Usz rows = height;
if (rows_0 < rows)
rows = rows_0;
if (rows == 0)
return;
Usz columns_0 = f_width - x;
Usz columns = width;
if (columns_0 < columns)
columns = columns_0;
Usz fill_bytes = columns * sizeof(Glyph);
Glyph *p = gbuffer + y * f_width + x;
Usz iy = 0;
for (;;) {
memset(p, fill_char, fill_bytes);
++iy;
if (iy == rows)
break;
p += f_width;
}
}
void mbuffer_clear(Mark *mbuf, Usz height, Usz width) {
Usz cleared_size = height * width;
memset(mbuf, 0, cleared_size);
void mbuffer_clear(Mark *mbuf, Usz height, Usz width)
{
Usz cleared_size = height * width;
memset(mbuf, 0, cleared_size);
}

151
src/gbuffer.h

@ -1,85 +1,122 @@
#pragma once
#include "base.h"
ORCA_PURE static inline Glyph gbuffer_peek_relative(Glyph *gbuf, Usz height,
Usz width, Usz y, Usz x,
Isz delta_y, Isz delta_x) {
Isz y0 = (Isz)y + delta_y;
Isz x0 = (Isz)x + delta_x;
if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width)
return '.';
return gbuf[(Usz)y0 * width + (Usz)x0];
ORCA_PURE static inline Glyph gbuffer_peek_relative(
Glyph *gbuf,
Usz height,
Usz width,
Usz y,
Usz x,
Isz delta_y,
Isz delta_x)
{
Isz y0 = (Isz)y + delta_y;
Isz x0 = (Isz)x + delta_x;
if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width)
return '.';
return gbuf[(Usz)y0 * width + (Usz)x0];
}
static inline void gbuffer_poke(Glyph *gbuf, Usz height, Usz width, Usz y,
Usz x, Glyph g) {
assert(y < height && x < width);
(void)height;
gbuf[y * width + x] = g;
static inline void gbuffer_poke(Glyph *gbuf, Usz height, Usz width, Usz y, Usz x, Glyph g)
{
assert(y < height && x < width);
(void)height;
gbuf[y * width + x] = g;
}
static inline void gbuffer_poke_relative(Glyph *gbuf, Usz height, Usz width,
Usz y, Usz x, Isz delta_y, Isz delta_x,
Glyph g) {
Isz y0 = (Isz)y + delta_y;
Isz x0 = (Isz)x + delta_x;
if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width)
return;
gbuf[(Usz)y0 * width + (Usz)x0] = g;
static inline void gbuffer_poke_relative(
Glyph *gbuf,
Usz height,
Usz width,
Usz y,
Usz x,
Isz delta_y,
Isz delta_x,
Glyph g)
{
Isz y0 = (Isz)y + delta_y;
Isz x0 = (Isz)x + delta_x;
if (y0 < 0 || x0 < 0 || (Usz)y0 >= height || (Usz)x0 >= width)
return;
gbuf[(Usz)y0 * width + (Usz)x0] = g;
}
ORCA_NOINLINE
void gbuffer_copy_subrect(Glyph *src, Glyph *dest, Usz src_grid_h,
Usz src_grid_w, Usz dest_grid_h, Usz dest_grid_w,
Usz src_y, Usz src_x, Usz dest_y, Usz dest_x,
Usz height, Usz width);
void gbuffer_copy_subrect(
Glyph *src,
Glyph *dest,
Usz src_grid_h,
Usz src_grid_w,
Usz dest_grid_h,
Usz dest_grid_w,
Usz src_y,
Usz src_x,
Usz dest_y,
Usz dest_x,
Usz height,
Usz width);
ORCA_NOINLINE
void gbuffer_fill_subrect(Glyph *gbuf, Usz grid_h, Usz grid_w, Usz y, Usz x,
Usz height, Usz width, Glyph fill_char);
void gbuffer_fill_subrect(
Glyph *gbuf,
Usz grid_h,
Usz grid_w,
Usz y,
Usz x,
Usz height,
Usz width,
Glyph fill_char);
typedef enum {
Mark_flag_none = 0,
Mark_flag_input = 1 << 0,
Mark_flag_output = 1 << 1,
Mark_flag_haste_input = 1 << 2,
Mark_flag_lock = 1 << 3,
Mark_flag_sleep = 1 << 4,
typedef enum
{
Mark_flag_none = 0,
Mark_flag_input = 1 << 0,
Mark_flag_output = 1 << 1,
Mark_flag_haste_input = 1 << 2,
Mark_flag_lock = 1 << 3,
Mark_flag_sleep = 1 << 4,
} Mark_flags;
ORCA_OK_IF_UNUSED
static Mark_flags mbuffer_peek(Mark *mbuf, Usz height, Usz width, Usz y,
Usz x) {
(void)height;
return mbuf[y * width + x];
static Mark_flags mbuffer_peek(Mark *mbuf, Usz height, Usz width, Usz y, Usz x)
{
(void)height;
return mbuf[y * width + x];
}
ORCA_OK_IF_UNUSED
static Mark_flags mbuffer_peek_relative(Mark *mbuf, Usz height, Usz width,
Usz y, Usz x, Isz offs_y, Isz offs_x) {
Isz y0 = (Isz)y + offs_y;
Isz x0 = (Isz)x + offs_x;
if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0)
return Mark_flag_none;
return mbuf[(Usz)y0 * width + (Usz)x0];
static Mark_flags mbuffer_peek_relative(Mark *mbuf, Usz height, Usz width, Usz y, Usz x, Isz offs_y, Isz offs_x)
{
Isz y0 = (Isz)y + offs_y;
Isz x0 = (Isz)x + offs_x;
if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0)
return Mark_flag_none;
return mbuf[(Usz)y0 * width + (Usz)x0];
}
ORCA_OK_IF_UNUSED
static void mbuffer_poke_flags_or(Mark *mbuf, Usz height, Usz width, Usz y,
Usz x, Mark_flags flags) {
(void)height;
mbuf[y * width + x] |= (Mark)flags;
static void mbuffer_poke_flags_or(Mark *mbuf, Usz height, Usz width, Usz y, Usz x, Mark_flags flags)
{
(void)height;
mbuf[y * width + x] |= (Mark)flags;
}
ORCA_OK_IF_UNUSED
static void mbuffer_poke_relative_flags_or(Mark *mbuf, Usz height, Usz width,
Usz y, Usz x, Isz offs_y, Isz offs_x,
Mark_flags flags) {
Isz y0 = (Isz)y + offs_y;
Isz x0 = (Isz)x + offs_x;
if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0)
return;
mbuf[(Usz)y0 * width + (Usz)x0] |= (Mark)flags;
static void mbuffer_poke_relative_flags_or(
Mark *mbuf,
Usz height,
Usz width,
Usz y,
Usz x,
Isz offs_y,
Isz offs_x,
Mark_flags flags)
{
Isz y0 = (Isz)y + offs_y;
Isz x0 = (Isz)x + offs_x;
if (y0 >= (Isz)height || x0 >= (Isz)width || y0 < 0 || x0 < 0)
return;
mbuf[(Usz)y0 * width + (Usz)x0] |= (Mark)flags;
}
void mbuffer_clear(Mark *mbuf, Usz height, Usz width);

426
src/osc_out.c

@ -8,51 +8,50 @@
#include <sys/types.h>
struct Oosc_dev {
int fd;
// Just keep the whole list around, since juggling the strict-aliasing
// problems with sockaddr_storage is not worth it.
struct addrinfo *chosen;
struct addrinfo *head;
int fd;
// Just keep the whole list around, since juggling the strict-aliasing
// problems with sockaddr_storage is not worth it.
struct addrinfo *chosen;
struct addrinfo *head;
};
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr,
char const *dest_addr,
char const *dest_port) {
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
struct addrinfo *chosen = NULL;
struct addrinfo *head = NULL;
int err = getaddrinfo(dest_addr, dest_port, &hints, &head);
if (err != 0) {
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr, char const *dest_addr, char const *dest_port)
{
struct addrinfo hints = { 0 };
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
struct addrinfo *chosen = NULL;
struct addrinfo *head = NULL;
int err = getaddrinfo(dest_addr, dest_port, &hints, &head);
if (err != 0) {
#if 0
fprintf(stderr, "Failed to get address info, error: %d\n", errno);
#endif
return Oosc_udp_create_error_getaddrinfo_failed;
}
// Special behavior: if no hostname was provided, we'll get loopback(s) from
// getaddrinfo. Which is good. But on systems with both an ipv4 and ipv6
// address, we might get the ipv6 address listed first. And the OSC server,
// for example Plogue Bidule, might not support ipv6. And defaulting to the
// ipv6 loopback wouldn't work, in that case. So if there's no hostname, and
// we find an ipv4 address in the results, prefer to use that.
//
// Actually let's just prefer ipv4 completely for now
return Oosc_udp_create_error_getaddrinfo_failed;
}
// Special behavior: if no hostname was provided, we'll get loopback(s) from
// getaddrinfo. Which is good. But on systems with both an ipv4 and ipv6
// address, we might get the ipv6 address listed first. And the OSC server,
// for example Plogue Bidule, might not support ipv6. And defaulting to the
// ipv6 loopback wouldn't work, in that case. So if there's no hostname, and
// we find an ipv4 address in the results, prefer to use that.
//
// Actually let's just prefer ipv4 completely for now
#if 0
if (!dest_addr) {
#endif
{
for (struct addrinfo *a = head; a; a = a->ai_next) {
if (a->ai_family != AF_INET)
continue;
chosen = a;
break;
{
for (struct addrinfo *a = head; a; a = a->ai_next) {
if (a->ai_family != AF_INET)
continue;
chosen = a;
break;
}
}
}
if (!chosen)
chosen = head;
if (!chosen)
chosen = head;
#if 0
for (struct addrinfo* a = head; a; a = a->ai_next) {
char buff[INET6_ADDRSTRLEN];
@ -71,34 +70,34 @@ Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr,
}
}
#endif
int udpfd =
socket(chosen->ai_family, chosen->ai_socktype, chosen->ai_protocol);
if (udpfd < 0) {
int udpfd = socket(chosen->ai_family, chosen->ai_socktype, chosen->ai_protocol);
if (udpfd < 0) {
#if 0
fprintf(stderr, "Failed to open UDP socket, error number: %d\n", errno);
#endif
freeaddrinfo(head);
return Oosc_udp_create_error_couldnt_open_socket;
}
Oosc_dev *dev = malloc(sizeof(Oosc_dev));
dev->fd = udpfd;
dev->chosen = chosen;
dev->head = head;
*out_ptr = dev;
return Oosc_udp_create_error_ok;
freeaddrinfo(head);
return Oosc_udp_create_error_couldnt_open_socket;
}
Oosc_dev *dev = malloc(sizeof(Oosc_dev));
dev->fd = udpfd;
dev->chosen = chosen;
dev->head = head;
*out_ptr = dev;
return Oosc_udp_create_error_ok;
}
void oosc_dev_destroy(Oosc_dev *dev) {
close(dev->fd);
freeaddrinfo(dev->head);
free(dev);
void oosc_dev_destroy(Oosc_dev *dev)
{
close(dev->fd);
freeaddrinfo(dev->head);
free(dev);
}
void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size) {
ssize_t res = sendto(dev->fd, data, size, 0, dev->chosen->ai_addr,
dev->chosen->ai_addrlen);
(void)res;
// TODO handle this in UI somehow
void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size)
{
ssize_t res = sendto(dev->fd, data, size, 0, dev->chosen->ai_addr, dev->chosen->ai_addrlen);
(void)res;
// TODO handle this in UI somehow
#if 0
if (res < 0) {
fprintf(stderr, "UDP message send failed\n");
@ -107,167 +106,188 @@ void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size) {
#endif
}
static bool oosc_write_strn(char *restrict buffer, Usz buffer_size,
Usz *buffer_pos, char const *restrict in_str,
Usz in_str_len) {
// no overflow check, should be fine
Usz in_plus_null = in_str_len + 1;
Usz null_pad = (4 - in_plus_null % 4) % 4;
Usz needed = in_plus_null + null_pad;
Usz cur_pos = *buffer_pos;
if (cur_pos + needed >= buffer_size)
return false;
for (Usz i = 0; i < in_str_len; ++i) {
buffer[cur_pos + i] = in_str[i];
}
buffer[cur_pos + in_str_len] = 0;
cur_pos += in_plus_null;
for (Usz i = 0; i < null_pad; ++i) {
buffer[cur_pos + i] = 0;
}
*buffer_pos = cur_pos + null_pad;
return true;
static bool oosc_write_strn(
char *restrict buffer,
Usz buffer_size,
Usz *buffer_pos,
char const *restrict in_str,
Usz in_str_len)
{
// no overflow check, should be fine
Usz in_plus_null = in_str_len + 1;
Usz null_pad = (4 - in_plus_null % 4) % 4;
Usz needed = in_plus_null + null_pad;
Usz cur_pos = *buffer_pos;
if (cur_pos + needed >= buffer_size)
return false;
for (Usz i = 0; i < in_str_len; ++i) {
buffer[cur_pos + i] = in_str[i];
}
buffer[cur_pos + in_str_len] = 0;
cur_pos += in_plus_null;
for (Usz i = 0; i < null_pad; ++i) {
buffer[cur_pos + i] = 0;
}
*buffer_pos = cur_pos + null_pad;
return true;
}
void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals,
Usz count) {
char buffer[2048];
Usz buf_pos = 0;
if (!oosc_write_strn(buffer, sizeof(buffer), &buf_pos, osc_address,
strlen(osc_address)))
return;
Usz typetag_str_size = 1 + count + 1; // comma, 'i'... , null
Usz typetag_str_null_pad = (4 - typetag_str_size % 4) % 4;
if (buf_pos + typetag_str_size + typetag_str_null_pad > sizeof(buffer))
return;
buffer[buf_pos] = ',';
++buf_pos;
for (Usz i = 0; i < count; ++i) {
buffer[buf_pos + i] = 'i';
}
buffer[buf_pos + count] = 0;
buf_pos += count + 1;
for (Usz i = 0; i < typetag_str_null_pad; ++i) {
buffer[buf_pos + i] = 0;
}
buf_pos += typetag_str_null_pad;
Usz ints_size = count * sizeof(I32);
if (buf_pos + ints_size > sizeof(buffer))
return;
for (Usz i = 0; i < count; ++i) {
union {
I32 i;
U32 u;
} pun;
pun.i = vals[i];
U32 u_ne = htonl(pun.u);
memcpy(buffer + buf_pos, &u_ne, sizeof(u_ne));
buf_pos += sizeof(u_ne);
}
oosc_send_datagram(dev, buffer, buf_pos);
void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals, Usz count)
{
char buffer[2048];
Usz buf_pos = 0;
if (!oosc_write_strn(buffer, sizeof(buffer), &buf_pos, osc_address, strlen(osc_address)))
return;
Usz typetag_str_size = 1 + count + 1; // comma, 'i'... , null
Usz typetag_str_null_pad = (4 - typetag_str_size % 4) % 4;
if (buf_pos + typetag_str_size + typetag_str_null_pad > sizeof(buffer))
return;
buffer[buf_pos] = ',';
++buf_pos;
for (Usz i = 0; i < count; ++i) {
buffer[buf_pos + i] = 'i';
}
buffer[buf_pos + count] = 0;
buf_pos += count + 1;
for (Usz i = 0; i < typetag_str_null_pad; ++i) {
buffer[buf_pos + i] = 0;
}
buf_pos += typetag_str_null_pad;
Usz ints_size = count * sizeof(I32);
if (buf_pos + ints_size > sizeof(buffer))
return;
for (Usz i = 0; i < count; ++i) {
union {
I32 i;
U32 u;
} pun;
pun.i = vals[i];
U32 u_ne = htonl(pun.u);
memcpy(buffer + buf_pos, &u_ne, sizeof(u_ne));
buf_pos += sizeof(u_ne);
}
oosc_send_datagram(dev, buffer, buf_pos);
}
void susnote_list_init(Susnote_list *sl) {
sl->buffer = NULL;
sl->count = 0;
sl->capacity = 0;
void susnote_list_init(Susnote_list *sl)
{
sl->buffer = NULL;
sl->count = 0;
sl->capacity = 0;
}
void susnote_list_deinit(Susnote_list *sl) { free(sl->buffer); }
void susnote_list_deinit(Susnote_list *sl)
{
free(sl->buffer);
}
void susnote_list_clear(Susnote_list *sl) { sl->count = 0; }
void susnote_list_clear(Susnote_list *sl)
{
sl->count = 0;
}
void susnote_list_add_notes(Susnote_list *sl, Susnote const *restrict notes,
Usz added_count, Usz *restrict start_removed,
Usz *restrict end_removed) {
Susnote *buffer = sl->buffer;
Usz count = sl->count;
Usz cap = sl->capacity;
Usz rem = count + added_count;
Usz needed_cap = rem + added_count;
if (cap < needed_cap) {
cap = needed_cap < 16 ? 16 : orca_round_up_power2(needed_cap);
buffer = realloc(buffer, cap * sizeof(Susnote));
sl->capacity = cap;
sl->buffer = buffer;
}
*start_removed = rem;
Usz i_in = 0;
for (; i_in < added_count; ++i_in) {
Susnote this_in = notes[i_in];
for (Usz i_old = 0; i_old < count; ++i_old) {
Susnote this_old = buffer[i_old];
if (this_old.chan_note == this_in.chan_note) {
buffer[i_old] = this_in;
buffer[rem] = this_old;
++rem;
goto next_in;
}
void susnote_list_add_notes(
Susnote_list *sl,
Susnote const *restrict notes,
Usz added_count,
Usz *restrict start_removed,
Usz *restrict end_removed)
{
Susnote *buffer = sl->buffer;
Usz count = sl->count;
Usz cap = sl->capacity;
Usz rem = count + added_count;
Usz needed_cap = rem + added_count;
if (cap < needed_cap) {
cap = needed_cap < 16 ? 16 : orca_round_up_power2(needed_cap);
buffer = realloc(buffer, cap * sizeof(Susnote));
sl->capacity = cap;
sl->buffer = buffer;
}
buffer[count] = this_in;
++count;
next_in:;
}
sl->count = count;
*end_removed = rem;
*start_removed = rem;
Usz i_in = 0;
for (; i_in < added_count; ++i_in) {
Susnote this_in = notes[i_in];
for (Usz i_old = 0; i_old < count; ++i_old) {
Susnote this_old = buffer[i_old];
if (this_old.chan_note == this_in.chan_note) {
buffer[i_old] = this_in;
buffer[rem] = this_old;
++rem;
goto next_in;
}
}
buffer[count] = this_in;
++count;
next_in:;
}
sl->count = count;
*end_removed = rem;
}
void susnote_list_advance_time(Susnote_list *sl, double delta_time,
Usz *restrict start_removed,
Usz *restrict end_removed,
double *soonest_deadline) {
Susnote *restrict buffer = sl->buffer;
Usz count = sl->count;
*end_removed = count;
float delta_float = (float)delta_time;
float soonest = 1.0f;
for (Usz i = 0; i < count;) {
Susnote sn = buffer[i];
sn.remaining -= delta_float;
if (sn.remaining > 0.001) {
if (sn.remaining < soonest)
soonest = sn.remaining;
buffer[i].remaining = sn.remaining;
++i;
} else {
--count;
buffer[i] = buffer[count];
buffer[count] = sn;
void susnote_list_advance_time(
Susnote_list *sl,
double delta_time,
Usz *restrict start_removed,
Usz *restrict end_removed,
double *soonest_deadline)
{
Susnote *restrict buffer = sl->buffer;
Usz count = sl->count;
*end_removed = count;
float delta_float = (float)delta_time;
float soonest = 1.0f;
for (Usz i = 0; i < count;) {
Susnote sn = buffer[i];
sn.remaining -= delta_float;
if (sn.remaining > 0.001) {
if (sn.remaining < soonest)
soonest = sn.remaining;
buffer[i].remaining = sn.remaining;
++i;
} else {
--count;
buffer[i] = buffer[count];
buffer[count] = sn;
}
}
}
*start_removed = count;
*soonest_deadline = (double)soonest;
sl->count = count;
*start_removed = count;
*soonest_deadline = (double)soonest;
sl->count = count;
}
void susnote_list_remove_by_chan_mask(Susnote_list *sl, Usz chan_mask,
Usz *restrict start_removed,
Usz *restrict end_removed) {
Susnote *restrict buffer = sl->buffer;
Usz count = sl->count;
*end_removed = count;
for (Usz i = 0; i < count;) {
Susnote sn = buffer[i];
Usz chan = sn.chan_note >> 8;
if (chan_mask & 1u << chan) {
--count;
buffer[i] = buffer[count];
buffer[count] = sn;
} else {
++i;
void susnote_list_remove_by_chan_mask(
Susnote_list *sl,
Usz chan_mask,
Usz *restrict start_removed,
Usz *restrict end_removed)
{
Susnote *restrict buffer = sl->buffer;
Usz count = sl->count;
*end_removed = count;
for (Usz i = 0; i < count;) {
Susnote sn = buffer[i];
Usz chan = sn.chan_note >> 8;
if (chan_mask & 1u << chan) {
--count;
buffer[i] = buffer[count];
buffer[count] = sn;
} else {
++i;
}
}
}
*start_removed = count;
sl->count = count;
*start_removed = count;
sl->count = count;
}
double susnote_list_soonest_deadline(Susnote_list const *sl) {
float soonest = 1.0f;
Susnote const *buffer = sl->buffer;
for (Usz i = 0, n = sl->count; i < n; ++i) {
float rem = buffer[i].remaining;
if (rem < soonest)
soonest = rem;
}
return (double)soonest;
double susnote_list_soonest_deadline(Susnote_list const *sl)
{
float soonest = 1.0f;
Susnote const *buffer = sl->buffer;
for (Usz i = 0, n = sl->count; i < n; ++i) {
float rem = buffer[i].remaining;
if (rem < soonest)
soonest = rem;
}
return (double)soonest;
}

45
src/osc_out.h

@ -3,15 +3,14 @@
typedef struct Oosc_dev Oosc_dev;
typedef enum {
Oosc_udp_create_error_ok = 0,
Oosc_udp_create_error_getaddrinfo_failed = 1,
Oosc_udp_create_error_couldnt_open_socket = 2,
typedef enum
{
Oosc_udp_create_error_ok = 0,
Oosc_udp_create_error_getaddrinfo_failed = 1,
Oosc_udp_create_error_couldnt_open_socket = 2,
} Oosc_udp_create_error;
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr,
char const *dest_addr,
char const *dest_port);
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev **out_ptr, char const *dest_addr, char const *dest_port);
void oosc_dev_destroy(Oosc_dev *dev);
// Send a raw UDP datagram.
@ -19,8 +18,7 @@ void oosc_send_datagram(Oosc_dev *dev, char const *data, Usz size);
// Send a list/array of 32-bit integers in OSC format to the specified "osc
// address" (a path like /foo) as a UDP datagram.
void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals,
Usz count);
void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals, Usz count);
// Susnote is for handling MIDI note sustains -- each MIDI on event should be
// matched with a MIDI note-off event. The duration/sustain length of a MIDI
@ -28,29 +26,36 @@ void oosc_send_int32s(Oosc_dev *dev, char const *osc_address, I32 const *vals,
// responsible for sending the note-off event. We keep a list of currently 'on'
// notes so that they can have a matching 'off' sent at the correct time.
typedef struct {
float remaining;
U16 chan_note;
float remaining;
U16 chan_note;
} Susnote;
typedef struct {
Susnote *buffer;
Usz count, capacity;
Susnote *buffer;
Usz count, capacity;
} Susnote_list;
void susnote_list_init(Susnote_list *sl);
void susnote_list_deinit(Susnote_list *sl);
void susnote_list_clear(Susnote_list *sl);
void susnote_list_add_notes(Susnote_list *sl, Susnote const *restrict notes,
Usz count, Usz *restrict start_removed,
Usz *restrict end_removed);
void susnote_list_add_notes(
Susnote_list *sl,
Susnote const *restrict notes,
Usz count,
Usz *restrict start_removed,
Usz *restrict end_removed);
void susnote_list_advance_time(
Susnote_list *sl, double delta_time, Usz *restrict start_removed,
Susnote_list *sl,
double delta_time,
Usz *restrict start_removed,
Usz *restrict end_removed,
// 1.0 if no notes remain or none are shorter than 1.0
double *soonest_deadline);
void susnote_list_remove_by_chan_mask(Susnote_list *sl, Usz chan_mask,
Usz *restrict start_removed,
Usz *restrict end_removed);
void susnote_list_remove_by_chan_mask(
Susnote_list *sl,
Usz chan_mask,
Usz *restrict start_removed,
Usz *restrict end_removed);
// Returns 1.0 if no notes remain or none are shorter than 1.0
double susnote_list_soonest_deadline(Susnote_list const *sl);

402
src/oso.c

@ -5,16 +5,16 @@
#include <string.h>
#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
#if __has_attribute(noinline) && __has_attribute(noclone)
#define OSO_NOINLINE __attribute__((noinline, noclone))
#elif __has_attribute(noinline)
#define OSO_NOINLINE __attribute__((noinline))
#endif
#if __has_attribute(noinline) && __has_attribute(noclone)
#define OSO_NOINLINE __attribute__((noinline, noclone))
#elif __has_attribute(noinline)
#define OSO_NOINLINE __attribute__((noinline))
#endif
#elif defined(_MSC_VER)
#define OSO_NOINLINE __declspec(noinline)
#define OSO_NOINLINE __declspec(noinline)
#endif
#ifndef OSO_NOINLINE
#define OSO_NOINLINE
#define OSO_NOINLINE
#endif
#define OSO_INTERNAL OSO_NOINLINE static
@ -22,208 +22,240 @@
#define OSO_CAP_MAX (SIZE_MAX - (sizeof(oso_header) + 1))
typedef struct oso {
size_t len, cap;
size_t len, cap;
} oso_header;
OSO_INTERNAL oso *oso_impl_reallochdr(oso_header *hdr, size_t new_cap) {
if (hdr) {
oso_header *new_hdr = realloc(hdr, sizeof(oso_header) + new_cap + 1);
if (!new_hdr) {
free(hdr);
return NULL;
OSO_INTERNAL oso *oso_impl_reallochdr(oso_header *hdr, size_t new_cap)
{
if (hdr) {
oso_header *new_hdr = realloc(hdr, sizeof(oso_header) + new_cap + 1);
if (!new_hdr) {
free(hdr);
return NULL;
}
new_hdr->cap = new_cap;
return new_hdr + 1;
}
new_hdr->cap = new_cap;
return new_hdr + 1;
}
hdr = malloc(sizeof(oso_header) + new_cap + 1);
if (!hdr)
return NULL;
hdr->len = 0;
hdr->cap = new_cap;
((char *)(hdr + 1))[0] = '\0';
return hdr + 1;
}
OSO_INTERNAL oso *oso_impl_catvprintf(oso *s, char const *fmt, va_list ap) {
size_t old_len;
int required;
va_list cpy;
va_copy(cpy, ap);
required = vsnprintf(NULL, 0, fmt, cpy);
va_end(cpy);
osomakeroomfor(&s, (size_t)required);
if (!s)
return NULL;
old_len = OSO_HDR(s)->len;
vsnprintf((char *)s + old_len, (size_t)required + 1, fmt, ap);
OSO_HDR(s)->len = old_len + (size_t)required;
return s;
hdr = malloc(sizeof(oso_header) + new_cap + 1);
if (!hdr)
return NULL;
hdr->len = 0;
hdr->cap = new_cap;
((char *)(hdr + 1))[0] = '\0';
return hdr + 1;
}
OSO_INTERNAL oso *oso_impl_catvprintf(oso *s, char const *fmt, va_list ap)
{
size_t old_len;
int required;
va_list cpy;
va_copy(cpy, ap);
required = vsnprintf(NULL, 0, fmt, cpy);
va_end(cpy);
osomakeroomfor(&s, (size_t)required);
if (!s)
return NULL;
old_len = OSO_HDR(s)->len;
vsnprintf((char *)s + old_len, (size_t)required + 1, fmt, ap);
OSO_HDR(s)->len = old_len + (size_t)required;
return s;
}
OSO_NOINLINE
void osoensurecap(oso **p, size_t new_cap) {
oso *s = *p;
if (new_cap > OSO_CAP_MAX) {
void osoensurecap(oso **p, size_t new_cap)
{
oso *s = *p;
if (new_cap > OSO_CAP_MAX) {
if (s) {
free(OSO_HDR(s));
*p = NULL;
}
return;
}
oso_header *hdr = NULL;
if (s) {
free(OSO_HDR(s));
*p = NULL;
hdr = OSO_HDR(s);
if (hdr->cap >= new_cap)
return;
}
return;
}
oso_header *hdr = NULL;
if (s) {
hdr = OSO_HDR(s);
if (hdr->cap >= new_cap)
return;
}
*p = oso_impl_reallochdr(hdr, new_cap);
*p = oso_impl_reallochdr(hdr, new_cap);
}
OSO_NOINLINE
void osomakeroomfor(oso **p, size_t add_len) {
oso *s = *p;
oso_header *hdr = NULL;
size_t new_cap;
if (s) {
hdr = OSO_HDR(s);
size_t len = hdr->len, cap = hdr->cap;
if (len > OSO_CAP_MAX - add_len) { // overflow, goodnight
free(hdr);
*p = NULL;
return;
void osomakeroomfor(oso **p, size_t add_len)
{
oso *s = *p;
oso_header *hdr = NULL;
size_t new_cap;
if (s) {
hdr = OSO_HDR(s);
size_t len = hdr->len, cap = hdr->cap;
if (len > OSO_CAP_MAX - add_len) { // overflow, goodnight
free(hdr);
*p = NULL;
return;
}
new_cap = len + add_len;
if (cap >= new_cap)
return;
} else {
if (add_len > OSO_CAP_MAX)
return;
new_cap = add_len;
}
new_cap = len + add_len;
if (cap >= new_cap)
return;
} else {
if (add_len > OSO_CAP_MAX)
return;
new_cap = add_len;
}
*p = oso_impl_reallochdr(hdr, new_cap);
*p = oso_impl_reallochdr(hdr, new_cap);
}
void osoput(oso **p, char const *restrict cstr) {
osoputlen(p, cstr, strlen(cstr));
void osoput(oso **p, char const *restrict cstr)
{
osoputlen(p, cstr, strlen(cstr));
}
OSO_NOINLINE
void osoputlen(oso **p, char const *restrict cstr, size_t len) {
oso *s = *p;
osoensurecap(&s, len);
if (s) {
OSO_HDR(s)->len = len;
memcpy((char *)s, cstr, len);
((char *)s)[len] = '\0';
}
*p = s;
}
void osoputoso(oso **p, oso const *other) {
if (!other)
return;
osoputlen(p, (char const *)other, OSO_HDR(other)->len);
}
void osoputvprintf(oso **p, char const *fmt, va_list ap) {
oso *s = *p;
if (s) {
OSO_HDR(s)->len = 0;
((char *)s)[0] = '\0';
}
*p = oso_impl_catvprintf(s, fmt, ap);
void osoputlen(oso **p, char const *restrict cstr, size_t len)
{
oso *s = *p;
osoensurecap(&s, len);
if (s) {
OSO_HDR(s)->len = len;
memcpy((char *)s, cstr, len);
((char *)s)[len] = '\0';
}
*p = s;
}
void osoputprintf(oso **p, char const *fmt, ...) {
oso *s = *p;
if (s) {
void osoputoso(oso **p, oso const *other)
{
if (!other)
return;
osoputlen(p, (char const *)other, OSO_HDR(other)->len);
}
void osoputvprintf(oso **p, char const *fmt, va_list ap)
{
oso *s = *p;
if (s) {
OSO_HDR(s)->len = 0;
((char *)s)[0] = '\0';
}
*p = oso_impl_catvprintf(s, fmt, ap);
}
void osoputprintf(oso **p, char const *fmt, ...)
{
oso *s = *p;
if (s) {
OSO_HDR(s)->len = 0;
((char *)s)[0] = '\0';
}
va_list ap;
va_start(ap, fmt);
*p = oso_impl_catvprintf(s, fmt, ap);
va_end(ap);
}
void osocat(oso **p, char const *cstr)
{
osocatlen(p, cstr, strlen(cstr));
}
OSO_NOINLINE
void osocatlen(oso **p, char const *cstr, size_t len)
{
oso *s = *p;
osomakeroomfor(&s, len);
if (s) {
oso_header *hdr = OSO_HDR(s);
size_t curr_len = hdr->len;
memcpy((char *)s + curr_len, cstr, len);
((char *)s)[curr_len + len] = '\0';
hdr->len = curr_len + len;
}
*p = s;
}
void osocatoso(oso **p, oso const *other)
{
if (!other)
return;
osocatlen(p, (char const *)other, OSO_HDR(other)->len);
}
void osocatvprintf(oso **p, char const *fmt, va_list ap)
{
*p = oso_impl_catvprintf(*p, fmt, ap);
}
void osocatprintf(oso **p, char const *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
*p = oso_impl_catvprintf(*p, fmt, ap);
va_end(ap);
}
void osoclear(oso **p)
{
oso *s = *p;
if (!s)
return;
OSO_HDR(s)->len = 0;
((char *)s)[0] = '\0';
}
va_list ap;
va_start(ap, fmt);
*p = oso_impl_catvprintf(s, fmt, ap);
va_end(ap);
}
void osocat(oso **p, char const *cstr) { osocatlen(p, cstr, strlen(cstr)); }
OSO_NOINLINE
void osocatlen(oso **p, char const *cstr, size_t len) {
oso *s = *p;
osomakeroomfor(&s, len);
if (s) {
void osofree(oso *s)
{
if (s)
free(OSO_HDR(s));
}
void osowipe(oso **p)
{
osofree(*p);
*p = NULL;
}
void ososwap(oso **a, oso **b)
{
oso *tmp = *a;
*a = *b;
*b = tmp;
}
void osopokelen(oso *s, size_t len)
{
OSO_HDR(s)->len = len;
}
size_t osolen(oso const *s)
{
return s ? OSO_HDR(s)->len : 0;
}
size_t osocap(oso const *s)
{
return s ? OSO_HDR(s)->cap : 0;
}
void osolencap(oso const *s, size_t *out_len, size_t *out_cap)
{
if (!s) {
*out_len = 0;
*out_cap = 0;
return;
}
oso_header *hdr = OSO_HDR(s);
size_t curr_len = hdr->len;
memcpy((char *)s + curr_len, cstr, len);
((char *)s)[curr_len + len] = '\0';
hdr->len = curr_len + len;
}
*p = s;
}
void osocatoso(oso **p, oso const *other) {
if (!other)
return;
osocatlen(p, (char const *)other, OSO_HDR(other)->len);
}
void osocatvprintf(oso **p, char const *fmt, va_list ap) {
*p = oso_impl_catvprintf(*p, fmt, ap);
}
void osocatprintf(oso **p, char const *fmt, ...) {
va_list ap;
va_start(ap, fmt);
*p = oso_impl_catvprintf(*p, fmt, ap);
va_end(ap);
}
void osoclear(oso **p) {
oso *s = *p;
if (!s)
return;
OSO_HDR(s)->len = 0;
((char *)s)[0] = '\0';
}
void osofree(oso *s) {
if (s)
free(OSO_HDR(s));
}
void osowipe(oso **p) {
osofree(*p);
*p = NULL;
}
void ososwap(oso **a, oso **b) {
oso *tmp = *a;
*a = *b;
*b = tmp;
}
void osopokelen(oso *s, size_t len) { OSO_HDR(s)->len = len; }
size_t osolen(oso const *s) { return s ? OSO_HDR(s)->len : 0; }
size_t osocap(oso const *s) { return s ? OSO_HDR(s)->cap : 0; }
void osolencap(oso const *s, size_t *out_len, size_t *out_cap) {
if (!s) {
*out_len = 0;
*out_cap = 0;
return;
}
oso_header *hdr = OSO_HDR(s);
*out_len = hdr->len;
*out_cap = hdr->cap;
}
size_t osoavail(oso const *s) {
if (!s)
return 0;
oso_header *h = OSO_HDR(s);
return h->cap - h->len;
*out_len = hdr->len;
*out_cap = hdr->cap;
}
size_t osoavail(oso const *s)
{
if (!s)
return 0;
oso_header *h = OSO_HDR(s);
return h->cap - h->len;
}
void osotrim(oso *restrict s, char const *restrict cut_set) {
if (!s)
return;
char *str, *end, *start_pos, *end_pos;
start_pos = str = (char *)s;
end_pos = end = str + OSO_HDR(s)->len - 1;
while (start_pos <= end && strchr(cut_set, *start_pos))
start_pos++;
while (end_pos > start_pos && strchr(cut_set, *end_pos))
end_pos--;
size_t len = (start_pos > end_pos) ? 0 : ((size_t)(end_pos - start_pos) + 1);
OSO_HDR(s)->len = len;
if (str != start_pos)
memmove(str, start_pos, len);
str[len] = '\0';
void osotrim(oso *restrict s, char const *restrict cut_set)
{
if (!s)
return;
char *str, *end, *start_pos, *end_pos;
start_pos = str = (char *)s;
end_pos = end = str + OSO_HDR(s)->len - 1;
while (start_pos <= end && strchr(cut_set, *start_pos))
start_pos++;
while (end_pos > start_pos && strchr(cut_set, *end_pos))
end_pos--;
size_t len = (start_pos > end_pos) ? 0 : ((size_t)(end_pos - start_pos) + 1);
OSO_HDR(s)->len = len;
if (str != start_pos)
memmove(str, start_pos, len);
str[len] = '\0';
}
#undef OSO_HDR

31
src/oso.h

@ -92,18 +92,18 @@
#include <stddef.h>
#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
#if __has_attribute(format)
#define OSO_PRINTF(...) __attribute__((format(printf, __VA_ARGS__)))
#endif
#if __has_attribute(nonnull)
#define OSO_NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
#endif
#if __has_attribute(format)
#define OSO_PRINTF(...) __attribute__((format(printf, __VA_ARGS__)))
#endif
#if __has_attribute(nonnull)
#define OSO_NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
#endif
#endif
#ifndef OSO_PRINTF
#define OSO_PRINTF(...)
#define OSO_PRINTF(...)
#endif
#ifndef OSO_NONNULL
#define OSO_NONNULL(...)
#define OSO_NONNULL(...)
#endif
typedef struct oso oso;
@ -122,19 +122,15 @@ void osoputlen(oso **p, char const *cstr, size_t len) OSO_NONNULL();
void osoputoso(oso **p, oso const *other) OSO_NONNULL(1);
// ^- Same as above, but using another `oso`. `*p` and `other` must not point
// to overlapping memory.
void osoputvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2)
OSO_PRINTF(2, 0);
void osoputprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2)
OSO_PRINTF(2, 3);
void osoputvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2) OSO_PRINTF(2, 0);
void osoputprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2) OSO_PRINTF(2, 3);
// ^- Same as above, but do it by using printf.
void osocat(oso **p, char const *cstr) OSO_NONNULL();
void osocatlen(oso **p, char const *cstr, size_t len) OSO_NONNULL();
void osocatoso(oso **p, oso const *other) OSO_NONNULL(1);
void osocatvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2)
OSO_PRINTF(2, 0);
void osocatprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2)
OSO_PRINTF(2, 3);
void osocatvprintf(oso **p, char const *fmt, va_list ap) OSO_NONNULL(1, 2) OSO_PRINTF(2, 0);
void osocatprintf(oso **p, char const *fmt, ...) OSO_NONNULL(1, 2) OSO_PRINTF(2, 3);
// ^- Append string to oso string. Same rules as `osoput` family.
void osoensurecap(oso **p, size_t cap) OSO_NONNULL();
@ -169,8 +165,7 @@ size_t osolen(oso const *s);
// ^- Bytes in use by the string (not including the '\0' character.)
size_t osocap(oso const *s);
// ^- Bytes allocated on heap (not including the '\0' terminator.)
void osolencap(oso const *s, size_t *out_len, size_t *out_cap)
OSO_NONNULL(2, 3);
void osolencap(oso const *s, size_t *out_len, size_t *out_cap) OSO_NONNULL(2, 3);
// ^- Get both the len and the cap in one call.
size_t osoavail(oso const *s);
// ^- osocap(s) - osolen(s)

1283
src/sim.c

File diff suppressed because it is too large

11
src/sim.h

@ -2,6 +2,11 @@
#include "base.h"
#include "vmio.h"
void orca_run(Glyph *restrict gbuffer, Mark *restrict mbuffer, Usz height,
Usz width, Usz tick_number, Oevent_list *oevent_list,
Usz random_seed);
void orca_run(
Glyph *restrict gbuffer,
Mark *restrict mbuffer,
Usz height,
Usz width,
Usz tick_number,
Oevent_list *oevent_list,
Usz random_seed);

135
src/sokol_time.h

@ -89,15 +89,15 @@
extern "C" {
#endif
SOKOL_API_DECL void stm_setup(void);
SOKOL_API_DECL uint64_t stm_now(void);
SOKOL_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks);
SOKOL_API_DECL uint64_t stm_since(uint64_t start_ticks);
SOKOL_API_DECL uint64_t stm_laptime(uint64_t* last_time);
SOKOL_API_DECL double stm_sec(uint64_t ticks);
SOKOL_API_DECL double stm_ms(uint64_t ticks);
SOKOL_API_DECL double stm_us(uint64_t ticks);
SOKOL_API_DECL double stm_ns(uint64_t ticks);
SOKOL_API_DECL void stm_setup(void);
SOKOL_API_DECL uint64_t stm_now(void);
SOKOL_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks);
SOKOL_API_DECL uint64_t stm_since(uint64_t start_ticks);
SOKOL_API_DECL uint64_t stm_laptime(uint64_t *last_time);
SOKOL_API_DECL double stm_sec(uint64_t ticks);
SOKOL_API_DECL double stm_ms(uint64_t ticks);
SOKOL_API_DECL double stm_us(uint64_t ticks);
SOKOL_API_DECL double stm_ns(uint64_t ticks);
#ifdef __cplusplus
} /* extern "C" */
@ -106,99 +106,103 @@ SOKOL_API_DECL double stm_ns(uint64_t ticks);
/*-- IMPLEMENTATION ----------------------------------------------------------*/
#ifdef SOKOL_IMPL
#ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL
#endif
#ifndef SOKOL_ASSERT
#include <assert.h>
#define SOKOL_ASSERT(c) assert(c)
#endif
#ifndef _SOKOL_PRIVATE
#if defined(__GNUC__)
#define _SOKOL_PRIVATE __attribute__((unused)) static
#else
#define _SOKOL_PRIVATE static
#ifndef SOKOL_API_IMPL
#define SOKOL_API_IMPL
#endif
#ifndef SOKOL_ASSERT
#include <assert.h>
#define SOKOL_ASSERT(c) assert(c)
#endif
#ifndef _SOKOL_PRIVATE
#if defined(__GNUC__)
#define _SOKOL_PRIVATE __attribute__((unused)) static
#else
#define _SOKOL_PRIVATE static
#endif
#endif
#endif
static int _stm_initialized;
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
static LARGE_INTEGER _stm_win_freq;
static LARGE_INTEGER _stm_win_start;
#elif defined(__APPLE__) && defined(__MACH__)
#include <mach/mach_time.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <mach/mach_time.h>
static mach_timebase_info_data_t _stm_osx_timebase;
static uint64_t _stm_osx_start;
#else /* anything else, this will need more care for non-Linux platforms */
#include <time.h>
#else /* anything else, this will need more care for non-Linux platforms */
#include <time.h>
static uint64_t _stm_posix_start;
#endif
#endif
/* prevent 64-bit overflow when computing relative timestamp
/* prevent 64-bit overflow when computing relative timestamp
see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3
*/
#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
_SOKOL_PRIVATE int64_t int64_muldiv(int64_t value, int64_t numer, int64_t denom) {
#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__))
_SOKOL_PRIVATE int64_t int64_muldiv(int64_t value, int64_t numer, int64_t denom)
{
int64_t q = value / denom;
int64_t r = value % denom;
return q * numer + r * numer / denom;
}
#endif
#endif
SOKOL_API_IMPL void stm_setup(void) {
SOKOL_API_IMPL void stm_setup(void)
{
SOKOL_ASSERT(0 == _stm_initialized);
_stm_initialized = 1;
#if defined(_WIN32)
QueryPerformanceFrequency(&_stm_win_freq);
QueryPerformanceCounter(&_stm_win_start);
QueryPerformanceFrequency(&_stm_win_freq);
QueryPerformanceCounter(&_stm_win_start);
#elif defined(__APPLE__) && defined(__MACH__)
mach_timebase_info(&_stm_osx_timebase);
_stm_osx_start = mach_absolute_time();
mach_timebase_info(&_stm_osx_timebase);
_stm_osx_start = mach_absolute_time();
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
_stm_posix_start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
_stm_posix_start = (uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec;
#endif
}
SOKOL_API_IMPL uint64_t stm_now(void) {
SOKOL_API_IMPL uint64_t stm_now(void)
{
SOKOL_ASSERT(_stm_initialized);
uint64_t now;
#if defined(_WIN32)
LARGE_INTEGER qpc_t;
QueryPerformanceCounter(&qpc_t);
now = int64_muldiv(qpc_t.QuadPart - _stm_win_start.QuadPart, 1000000000, _stm_win_freq.QuadPart);
LARGE_INTEGER qpc_t;
QueryPerformanceCounter(&qpc_t);
now = int64_muldiv(qpc_t.QuadPart - _stm_win_start.QuadPart, 1000000000, _stm_win_freq.QuadPart);
#elif defined(__APPLE__) && defined(__MACH__)
const uint64_t mach_now = mach_absolute_time() - _stm_osx_start;
now = int64_muldiv(mach_now, _stm_osx_timebase.numer, _stm_osx_timebase.denom);
const uint64_t mach_now = mach_absolute_time() - _stm_osx_start;
now = int64_muldiv(mach_now, _stm_osx_timebase.numer, _stm_osx_timebase.denom);
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm_posix_start;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
now = ((uint64_t)ts.tv_sec * 1000000000 + (uint64_t)ts.tv_nsec) - _stm_posix_start;
#endif
return now;
}
SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) {
SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks)
{
if (new_ticks > old_ticks) {
return new_ticks - old_ticks;
}
else {
} else {
/* FIXME: this should be a value that converts to a non-null double */
return 1;
}
}
SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) {
SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks)
{
return stm_diff(stm_now(), start_ticks);
}
SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) {
SOKOL_API_IMPL uint64_t stm_laptime(uint64_t *last_time)
{
SOKOL_ASSERT(last_time);
uint64_t dt = 0;
uint64_t now = stm_now();
@ -209,20 +213,23 @@ SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) {
return dt;
}
SOKOL_API_IMPL double stm_sec(uint64_t ticks) {
SOKOL_API_IMPL double stm_sec(uint64_t ticks)
{
return (double)ticks / 1000000000.0;
}
SOKOL_API_IMPL double stm_ms(uint64_t ticks) {
SOKOL_API_IMPL double stm_ms(uint64_t ticks)
{
return (double)ticks / 1000000.0;
}
SOKOL_API_IMPL double stm_us(uint64_t ticks) {
SOKOL_API_IMPL double stm_us(uint64_t ticks)
{
return (double)ticks / 1000.0;
}
SOKOL_API_IMPL double stm_ns(uint64_t ticks) {
SOKOL_API_IMPL double stm_ns(uint64_t ticks)
{
return (double)ticks;
}
#endif /* SOKOL_IMPL */

1112
src/sysmisc.c

File diff suppressed because it is too large

165
src/sysmisc.h

@ -5,59 +5,78 @@ struct oso;
void expand_home_tilde(struct oso **path);
typedef enum {
Cboard_error_none = 0,
Cboard_error_unavailable,
Cboard_error_popen_failed,
Cboard_error_process_exit_error,
typedef enum
{
Cboard_error_none = 0,
Cboard_error_unavailable,
Cboard_error_popen_failed,
Cboard_error_process_exit_error,
} Cboard_error;
Cboard_error cboard_copy(Glyph const *gbuffer, Usz field_height,
Usz field_width, Usz rect_y, Usz rect_x, Usz rect_h,
Usz rect_w);
Cboard_error cboard_paste(Glyph *gbuffer, Usz height, Usz width, Usz y, Usz x,
Usz *out_h, Usz *out_w);
typedef enum {
Conf_read_left_and_right = 0, // left and right will be set
Conf_read_irrelevant, // only left will be set
Conf_read_buffer_too_small, // neither will be set
Conf_read_eof, // "
Conf_read_io_error, // "
Cboard_error cboard_copy(
Glyph const *gbuffer,
Usz field_height,
Usz field_width,
Usz rect_y,
Usz rect_x,
Usz rect_h,
Usz rect_w);
Cboard_error cboard_paste(Glyph *gbuffer, Usz height, Usz width, Usz y, Usz x, Usz *out_h, Usz *out_w);
typedef enum
{
Conf_read_left_and_right = 0, // left and right will be set
Conf_read_irrelevant, // only left will be set
Conf_read_buffer_too_small, // neither will be set
Conf_read_eof, // "
Conf_read_io_error, // "
} Conf_read_result;
Conf_read_result conf_read_line(FILE *file, char *buf, Usz bufsize,
char **out_left, Usz *out_leftlen,
char **out_right, Usz *out_rightlen);
bool conf_read_match(FILE **pfile, char const *const *names, Usz nameslen,
char *buf, Usz bufsize, Usz *out_index, char **out_value);
Conf_read_result conf_read_line(
FILE *file,
char *buf,
Usz bufsize,
char **out_left,
Usz *out_leftlen,
char **out_right,
Usz *out_rightlen);
bool conf_read_match(
FILE **pfile,
char const *const *names,
Usz nameslen,
char *buf,
Usz bufsize,
Usz *out_index,
char **out_value);
FILE *conf_file_open_for_reading(char const *conf_file_name);
typedef struct {
FILE *origfile, *tempfile;
struct oso *canonpath, *temppath;
FILE *origfile, *tempfile;
struct oso *canonpath, *temppath;
} Conf_save;
typedef enum {
Conf_save_start_ok = 0,
Conf_save_start_bad_conf_name,
Conf_save_start_alloc_failed,
Conf_save_start_no_home,
Conf_save_start_mkdir_failed,
Conf_save_start_conf_dir_not_dir,
Conf_save_start_temp_file_perm_denied,
Conf_save_start_old_temp_file_stuck,
Conf_save_start_temp_file_open_failed,
typedef enum
{
Conf_save_start_ok = 0,
Conf_save_start_bad_conf_name,
Conf_save_start_alloc_failed,
Conf_save_start_no_home,
Conf_save_start_mkdir_failed,
Conf_save_start_conf_dir_not_dir,
Conf_save_start_temp_file_perm_denied,
Conf_save_start_old_temp_file_stuck,
Conf_save_start_temp_file_open_failed,
} Conf_save_start_error;
typedef enum {
Conf_save_commit_ok = 0,
Conf_save_commit_temp_fsync_failed,
Conf_save_commit_temp_close_failed,
Conf_save_commit_rename_failed,
typedef enum
{
Conf_save_commit_ok = 0,
Conf_save_commit_temp_fsync_failed,
Conf_save_commit_temp_close_failed,
Conf_save_commit_rename_failed,
} Conf_save_commit_error;
Conf_save_start_error conf_save_start(Conf_save *p, char const *conf_file_name);
@ -85,52 +104,52 @@ Conf_save_commit_error conf_save_commit(Conf_save *p);
// Just playing around with this design
typedef struct {
FILE *file;
Usz index;
char *value;
char buffer[1024];
FILE *file;
Usz index;
char *value;
char buffer[1024];
} Ezconf_r;
void ezconf_r_start(Ezconf_r *ezcr, char const *conf_file_name);
bool ezconf_r_step(Ezconf_r *ezcr, char const *const *names, Usz nameslen);
typedef enum {
Ezconf_w_ok = 0,
Ezconf_w_bad_conf_name,
Ezconf_w_oom,
Ezconf_w_no_home,
Ezconf_w_mkdir_failed,
Ezconf_w_conf_dir_not_dir,
Ezconf_w_old_temp_file_stuck,
Ezconf_w_temp_file_perm_denied,
Ezconf_w_temp_open_failed,
Ezconf_w_temp_fsync_failed,
Ezconf_w_temp_close_failed,
Ezconf_w_rename_failed,
Ezconf_w_line_too_long,
Ezconf_w_existing_read_error,
Ezconf_w_unknown_error,
typedef enum
{
Ezconf_w_ok = 0,
Ezconf_w_bad_conf_name,
Ezconf_w_oom,
Ezconf_w_no_home,
Ezconf_w_mkdir_failed,
Ezconf_w_conf_dir_not_dir,
Ezconf_w_old_temp_file_stuck,
Ezconf_w_temp_file_perm_denied,
Ezconf_w_temp_open_failed,
Ezconf_w_temp_fsync_failed,
Ezconf_w_temp_close_failed,
Ezconf_w_rename_failed,
Ezconf_w_line_too_long,
Ezconf_w_existing_read_error,
Ezconf_w_unknown_error,
} Ezconf_w_error;
char const *ezconf_w_errorstring(Ezconf_w_error error);
typedef struct {
char const *name;
intptr_t id;
uint8_t flags;
char const *name;
intptr_t id;
uint8_t flags;
} Ezconf_opt;
typedef struct {
Conf_save save;
Ezconf_opt *opts;
size_t optscount, optscap;
intptr_t optid;
FILE *file;
Ezconf_w_error error;
uint32_t stateflags;
Conf_save save;
Ezconf_opt *opts;
size_t optscount, optscap;
intptr_t optid;
FILE *file;
Ezconf_w_error error;
uint32_t stateflags;
} Ezconf_w;
void ezconf_w_start(Ezconf_w *ezcw, Ezconf_opt *optsbuffer, size_t buffercap,
char const *conf_file_name);
void ezconf_w_start(Ezconf_w *ezcw, Ezconf_opt *optsbuffer, size_t buffercap, char const *conf_file_name);
void ezconf_w_addopt(Ezconf_w *ezcw, char const *key, intptr_t id);
bool ezconf_w_step(Ezconf_w *ezcw);

1327
src/term_util.c

File diff suppressed because it is too large

128
src/term_util.h

@ -3,116 +3,124 @@
#include <ncurses.h>
#if (defined(__GNUC__) || defined(__clang__)) && defined(__has_attribute)
#if __has_attribute(format)
#define ORCA_TERM_UTIL_PRINTF(...) __attribute__((format(printf, __VA_ARGS__)))
#endif
#if __has_attribute(format)
#define ORCA_TERM_UTIL_PRINTF(...) __attribute__((format(printf, __VA_ARGS__)))
#endif
#endif
#ifndef ORCA_TERM_UTIL_PRINTF
#define ORCA_TERM_UTIL_PRINTF(...)
#define ORCA_TERM_UTIL_PRINTF(...)
#endif
#define CTRL_PLUS(c) ((c)&037)
struct oso;
typedef enum {
C_natural,
C_black,
C_red,
C_green,
C_yellow,
C_blue,
C_magenta,
C_cyan,
C_white,
typedef enum
{
C_natural,
C_black,
C_red,
C_green,
C_yellow,
C_blue,
C_magenta,
C_cyan,
C_white,
} Color_name;
enum {
Colors_count = C_white + 1,
enum
{
Colors_count = C_white + 1,
};
enum {
Cdef_normal = COLOR_PAIR(1),
enum
{
Cdef_normal = COLOR_PAIR(1),
};
typedef enum {
A_normal = A_NORMAL,
A_bold = A_BOLD,
A_dim = A_DIM,
A_standout = A_STANDOUT,
A_reverse = A_REVERSE,
typedef enum
{
A_normal = A_NORMAL,
A_bold = A_BOLD,
A_dim = A_DIM,
A_standout = A_STANDOUT,
A_reverse = A_REVERSE,
} Term_attr;
static ORCA_FORCEINLINE ORCA_OK_IF_UNUSED attr_t fg_bg(Color_name fg,
Color_name bg) {
return COLOR_PAIR(1 + fg * Colors_count + bg);
static ORCA_FORCEINLINE ORCA_OK_IF_UNUSED attr_t fg_bg(Color_name fg, Color_name bg)
{
return COLOR_PAIR(1 + fg * Colors_count + bg);
}
void term_util_init_colors(void);
typedef enum {
Qblock_type_qmsg,
Qblock_type_qmenu,
Qblock_type_qform,
typedef enum
{
Qblock_type_qmsg,
Qblock_type_qmenu,
Qblock_type_qform,
} Qblock_type_tag;
typedef struct Qblock {
Qblock_type_tag tag;
WINDOW *outer_window, *content_window;
char const *title;
struct Qblock *down, *up;
int y, x;
Qblock_type_tag tag;
WINDOW *outer_window, *content_window;
char const *title;
struct Qblock *down, *up;
int y, x;
} Qblock;
typedef struct {
Qblock *top, *bottom;
bool occlusion_dirty;
Qblock *top, *bottom;
bool occlusion_dirty;
} Qnav_stack;
typedef struct Qmsg Qmsg;
typedef struct Qmenu Qmenu;
typedef enum {
Qmenu_action_type_canceled,
Qmenu_action_type_picked,
typedef enum
{
Qmenu_action_type_canceled,
Qmenu_action_type_picked,
} Qmenu_action_type;
typedef struct {
Qmenu_action_type type;
Qmenu_action_type type;
} Qmenu_action_any;
typedef struct {
Qmenu_action_type type;
int id;
Qmenu_action_type type;
int id;
} Qmenu_action_picked;
typedef union {
Qmenu_action_any any;
Qmenu_action_picked picked;
Qmenu_action_any any;
Qmenu_action_picked picked;
} Qmenu_action;
typedef struct Qform Qform;
typedef enum {
Qform_action_type_canceled,
Qform_action_type_submitted,
typedef enum
{
Qform_action_type_canceled,
Qform_action_type_submitted,
} Qform_action_type;
typedef struct {
Qform_action_type type;
Qform_action_type type;
} Qform_action_any;
typedef union {
Qform_action_any any;
Qform_action_any any;
} Qform_action;
typedef enum {
Qmsg_dismiss_mode_explicitly, // Space, return, escape dismisses. Default.
Qmsg_dismiss_mode_easily, // Any key dismisses.
Qmsg_dismiss_mode_passthrough, // Easily, and pass through key event.
typedef enum
{
Qmsg_dismiss_mode_explicitly, // Space, return, escape dismisses. Default.
Qmsg_dismiss_mode_easily, // Any key dismisses.
Qmsg_dismiss_mode_passthrough, // Easily, and pass through key event.
} Qmsg_dismiss_mode;
typedef struct {
bool dismiss : 1, passthrough : 1;
bool dismiss : 1, passthrough : 1;
} Qmsg_action;
void qnav_init(void);
@ -126,8 +134,7 @@ void qblock_print_frame(Qblock *qb, bool active);
void qblock_set_title(Qblock *qb, char const *title);
Qmsg *qmsg_push(int height, int width);
Qmsg *qmsg_printf_push(char const *title, char const *fmt, ...)
ORCA_TERM_UTIL_PRINTF(2, 3);
Qmsg *qmsg_printf_push(char const *title, char const *fmt, ...) ORCA_TERM_UTIL_PRINTF(2, 3);
WINDOW *qmsg_window(Qmsg *qm);
void qmsg_set_title(Qmsg *qm, char const *title);
void qmsg_set_dismiss_mode(Qmsg *qm, Qmsg_dismiss_mode mode);
@ -142,8 +149,7 @@ void qmenu_destroy(Qmenu *qm);
int qmenu_id(Qmenu const *qm);
void qmenu_set_title(Qmenu *qm, char const *title);
void qmenu_add_choice(Qmenu *qm, int id, char const *text);
void qmenu_add_printf(Qmenu *qm, int id, char const *fmt, ...)
ORCA_TERM_UTIL_PRINTF(3, 4);
void qmenu_add_printf(Qmenu *qm, int id, char const *fmt, ...) ORCA_TERM_UTIL_PRINTF(3, 4);
void qmenu_add_spacer(Qmenu *qm);
void qmenu_set_current_item(Qmenu *qm, int id);
void qmenu_push_to_nav(Qmenu *qm);
@ -158,7 +164,7 @@ Qform *qform_of(Qblock *qb);
void qform_set_title(Qform *qf, char const *title);
void qform_add_line_input(Qform *qf, int id, char const *initial);
void qform_push_to_nav(Qform *qf);
void qform_single_line_input(int id, char const *title, char const* initial);
void qform_single_line_input(int id, char const *title, char const *initial);
bool qform_drive(Qform *qf, int key, Qform_action *out_action);
bool qform_get_text_line(Qform const *qf, int id, struct oso **out);
bool qform_get_single_text_line(Qform const *qf, struct oso **out);

7355
src/tui_main.c

File diff suppressed because it is too large

65
src/vmio.c

@ -1,33 +1,42 @@
#include "vmio.h"
void oevent_list_init(Oevent_list *olist) {
olist->buffer = NULL;
olist->count = 0;
olist->capacity = 0;
void oevent_list_init(Oevent_list *olist)
{
olist->buffer = NULL;
olist->count = 0;
olist->capacity = 0;
}
void oevent_list_deinit(Oevent_list *olist) { free(olist->buffer); }
void oevent_list_clear(Oevent_list *olist) { olist->count = 0; }
void oevent_list_copy(Oevent_list const *src, Oevent_list *dest) {
Usz src_count = src->count;
if (dest->capacity < src_count) {
Usz new_cap = orca_round_up_power2(src_count);
dest->buffer = realloc(dest->buffer, new_cap * sizeof(Oevent));
dest->capacity = new_cap;
}
memcpy(dest->buffer, src->buffer, src_count * sizeof(Oevent));
dest->count = src_count;
void oevent_list_deinit(Oevent_list *olist)
{
free(olist->buffer);
}
Oevent *oevent_list_alloc_item(Oevent_list *olist) {
Usz count = olist->count;
if (olist->capacity == count) {
// Note: no overflow check, but you're probably out of memory if this
// happens anyway. Like other uses of realloc in orca, we also don't check
// for a failed allocation.
Usz capacity = count < 16 ? 16 : orca_round_up_power2(count + 1);
olist->buffer = realloc(olist->buffer, capacity * sizeof(Oevent));
olist->capacity = capacity;
}
Oevent *result = olist->buffer + count;
olist->count = count + 1;
return result;
void oevent_list_clear(Oevent_list *olist)
{
olist->count = 0;
}
void oevent_list_copy(Oevent_list const *src, Oevent_list *dest)
{
Usz src_count = src->count;
if (dest->capacity < src_count) {
Usz new_cap = orca_round_up_power2(src_count);
dest->buffer = realloc(dest->buffer, new_cap * sizeof(Oevent));
dest->capacity = new_cap;
}
memcpy(dest->buffer, src->buffer, src_count * sizeof(Oevent));
dest->count = src_count;
}
Oevent *oevent_list_alloc_item(Oevent_list *olist)
{
Usz count = olist->count;
if (olist->capacity == count) {
// Note: no overflow check, but you're probably out of memory if this
// happens anyway. Like other uses of realloc in orca, we also don't check
// for a failed allocation.
Usz capacity = count < 16 ? 16 : orca_round_up_power2(count + 1);
olist->buffer = realloc(olist->buffer, capacity * sizeof(Oevent));
olist->capacity = capacity;
}
Oevent *result = olist->buffer + count;
olist->count = count + 1;
return result;
}

67
src/vmio.h

@ -1,62 +1,69 @@
#pragma once
#include "base.h"
typedef enum {
Oevent_type_midi_note,
Oevent_type_midi_cc,
Oevent_type_midi_pb,
Oevent_type_osc_ints,
Oevent_type_udp_string,
typedef enum
{
Oevent_type_midi_note,
Oevent_type_midi_cc,
Oevent_type_midi_pb,
Oevent_type_osc_ints,
Oevent_type_udp_string,
} Oevent_types;
typedef struct {
U8 oevent_type;
U8 oevent_type;
} Oevent_any;
typedef struct {
U8 oevent_type;
U8 channel, octave, note, velocity, duration : 7, mono : 1;
U8 oevent_type;
U8 channel, octave, note, velocity, duration : 7, mono : 1;
} Oevent_midi_note;
typedef struct {
U8 oevent_type;
U8 channel, control, value;
U8 oevent_type;
U8 channel, control, value;
} Oevent_midi_cc;
typedef struct {
U8 oevent_type;
U8 channel, lsb, msb;
U8 oevent_type;
U8 channel, lsb, msb;
} Oevent_midi_pb;
enum { Oevent_osc_int_count = 35 };
enum
{
Oevent_osc_int_count = 35
};
typedef struct {
U8 oevent_type;
Glyph glyph;
U8 count;
U8 numbers[Oevent_osc_int_count];
U8 oevent_type;
Glyph glyph;
U8 count;
U8 numbers[Oevent_osc_int_count];
} Oevent_osc_ints;
enum { Oevent_udp_string_count = 16 };
enum
{
Oevent_udp_string_count = 16
};
typedef struct {
U8 oevent_type;
U8 count;
char chars[Oevent_udp_string_count];
U8 oevent_type;
U8 count;
char chars[Oevent_udp_string_count];
} Oevent_udp_string;
typedef union {
Oevent_any any;
Oevent_midi_note midi_note;
Oevent_midi_cc midi_cc;
Oevent_midi_pb midi_pb;
Oevent_osc_ints osc_ints;
Oevent_udp_string udp_string;
Oevent_any any;
Oevent_midi_note midi_note;
Oevent_midi_cc midi_cc;
Oevent_midi_pb midi_pb;
Oevent_osc_ints osc_ints;
Oevent_udp_string udp_string;
} Oevent;
typedef struct {
Oevent *buffer;
Usz count, capacity;
Oevent *buffer;
Usz count, capacity;
} Oevent_list;
void oevent_list_init(Oevent_list *olist);

Loading…
Cancel
Save