working dos vga writes!

This commit is contained in:
veclavtlica committed 2026-10-29 22:12:47 +03:00
1 parent 5789cafd4e
commit 55ac075e4d
25 files changed
+454 -149

No files matched your search

+1
View File
@@ -14,5 +14,6 @@ Player/player
Player/player.wasm Player/player.wasm
Player/Cosmo Player/Cosmo
Master/master Master/master
Tools/assets
Player/Out/Cosmo/player* Player/Out/Cosmo/player*
+29
View File
@@ -0,0 +1,29 @@
/*
Simple fixed point bitcrash.
https://github.com/schollz/fpfx
*/
#ifndef COM_SND_BITCRSH_H
#define COM_SND_BITCRSH_H
#include "../fix.h"
#include <stdint.h>
struct com_snd_bitcrsh {
uint8_t bits; /* How much to trim when triggered. */
uint8_t reduce; /* Every Nth sample frame. */
};
static void com_snd_bitcrsh_process(Bitcrush *bitcrush, int32_t *buf,
unsigned int nr_samples) {
for (int i = 0; i < nr_samples; i++) {
if (i % bitcrush->reduce == 0) {
// bitcrush fixedpoint
buf[i] = buf[i] >> (16 - bitcrush->bits) << (16 - bitcrush->bits);
} else {
buf[i] = buf[i - 1];
}
}
}
#endif
+91
View File
@@ -0,0 +1,91 @@
/*
Dinky fixed point oscillators.
https://git.poto.cafe/veclavtalica/stfu/src/branch/master/Source/oscillators.c
*/
#ifndef COM_SND_OSCS_H
#define COM_SND_OSCS_H
#include "../cfg.h"
#include "../fix.h"
#include "../std.h"
#include <stdint.h>
/* Intended to be executed offline with values then embedded in the binary. */
struct com_snd_swave {
uint16_t f, s, c;
};
static struct com_snd_swave
com_snd_swave_init(com_fix_t frequency, uint16_t phase, uint16_t amplitude) {
com_std_assert(frequency > 0);
struct com_snd_swave r;
r.f = 2.f * sinf((float)M_PI * frequency / STFU_AUDIO_FRAME_RATE);
r.s = amplitude * sinf(phase);
r.c = amplitude * cosf(phase);
return r;
}
static inline int16_t com_snd_swave_pump(struct com_snd_swave *wave) {
int16_t const f = com_fix_sin(com_fix_mul(
wave->phase, com_fix_div(com_fix_mul(wave->frequency, COM_FIX_PI2),
COM_CFG_SNDFRMRATE)));
wave->phase += 1;
return f;
}
/* Implemented over sinewave */
// struct com_snd_oscs_sqrtwave {
// struct com_snd_swave w;
// union {
// float f;
// uint32_t u;
// } v;
// } com_snd_oscs_init_sqrtwave(float frequency, float phase, float amplitude) {
// struct com_snd_oscs_sqrtwave r;
// union {
// float f;
// uint32_t u;
// } v, a;
// r.w = com_snd_oscs_init_sinewave(frequency, phase, 1.f);
// v.f = r.w.s;
// a.f = amplitude;
// r.v.u = (a.u & 0x7fffffff) | (v.u & 0x80000000);
// return r;
// }
// /* Use floating point bit representation to infer sign, all other bits are
// set
// * to amplitude */
// struct com_snd_oscs_sqrtwave
// com_snd_oscs_pump_sqrtwave(struct com_snd_oscs_sqrtwave wave) {
// union {
// float f;
// uint32_t u;
// } v;
// com_snd_oscs_pump_sinewave(wave.w);
// v.f = wave.w.s;
// wave.v.u = (wave.v.u & 0x7fffffff) | (v.u & 0x80000000);
// return wave;
// }
// struct com_snd_oscs_sawtooth {
// float v, a, i;
// } com_snd_oscs_init_sawtooth(float frequency, float phase, float amplitude) {
// struct com_snd_oscs_sawtooth r;
// r.v = sinf(phase) * amplitude;
// r.a = amplitude;
// r.i = 2.f * frequency / STFU_AUDIO_FRAME_RATE * amplitude;
// return r;
// }
// /* Simple amplitude overflow check with truncation */
// struct com_snd_oscs_sawtooth
// com_snd_oscs_pump_sawtooth(struct com_snd_oscs_sawtooth wave) {
// wave.v += wave.i;
// if (wave.v > wave.a)
// wave.v -= wave.a * 2.f;
// return wave;
// }
#endif
+2 -1
View File
@@ -1,5 +1,4 @@
#include "../std.h" #include "../std.h"
#include "any.c"
#include <assert.h> #include <assert.h>
#include <poll.h> #include <poll.h>
#include <stdarg.h> #include <stdarg.h>
@@ -10,6 +9,8 @@
#include <sys/un.h> #include <sys/un.h>
#include <tgmath.h> #include <tgmath.h>
#include "any.c"
void *com_std_alloc(void *ptr, size_t size) { void *com_std_alloc(void *ptr, size_t size) {
return size != 0 ? realloc(ptr, size) : (free(ptr), NULL); return size != 0 ? realloc(ptr, size) : (free(ptr), NULL);
} }
+16
View File
@@ -24,6 +24,8 @@ size_t strlen(char const *s) {
return p - s; return p - s;
} }
#if COM_DEF_CPU == COM_DEF_CPU_AMD64 || COM_DEF_CPU == COM_DEF_CPU_X86
double sin(double v) { double sin(double v) {
double r; double r;
__asm__ __volatile__("fsin" : "=t"(r) : "0"(v)); __asm__ __volatile__("fsin" : "=t"(r) : "0"(v));
@@ -49,3 +51,17 @@ double sqrt(double v) {
__asm__ volatile("sqrtss %1, %0" : "=x"(r) : "x"(v)); __asm__ volatile("sqrtss %1, %0" : "=x"(r) : "x"(v));
return r; return r;
} }
#else
double sin(double v) { return __builtin_sin(v); }
double cos(double v) { return __builtin_cos(v); }
void sincos(double v, double *s, double *c) {
return __builtin_sincos(v, s, c);
}
double sqrt(double v) { return __builtin_sqrt(v); }
#endif
+2 -12
View File
@@ -1,23 +1,13 @@
#include "../std.h" #include "../std.h"
#include "any.c" #include "any.c"
#include "nolibc.c"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
void *com_std_alloc(void *ptr, size_t size) { return NULL; } void *com_std_alloc(void *ptr, size_t size) { return NULL; }
double com_std_sqrt(double v) { return __builtin_sqrt(v); }
double com_std_fabs(double v) { return __builtin_fabs(v); }
#if COM_DEF_COMPILER == COM_DEF_COMPILER_CLANG
double com_std_sin(double v) { return __builtin_sin(v); }
double com_std_cos(double v) { return __builtin_cos(v); }
#else
/* TODO: Use fsin/fcos, no matter how slow. */
double com_std_sin(double v) { return 0; }
double com_std_cos(double v) { return 0; }
#endif
com_std_fd com_std_open(char const *path, uint32_t flags) { return NULL; } com_std_fd com_std_open(char const *path, uint32_t flags) { return NULL; }
bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) { bool com_std_write(com_std_fd fd, void const *data, uint32_t bytes) {
return false; return false;
@@ -28,7 +18,7 @@ com_std_fd com_std_socket(bool isnetwork) { return NULL; }
bool com_std_connect(com_std_fd fd, bool isnetwork, char const *address) { bool com_std_connect(com_std_fd fd, bool isnetwork, char const *address) {
return false; return false;
} }
void com_std_exit(uint32_t status) { void com_std_exit(int32_t status) {
__builtin_trap(); __builtin_trap();
while (1) { while (1) {
} }
+54
View File
@@ -0,0 +1,54 @@
/*
Centralized benchmark suite.
*/
#include "fix.h"
#include "std.h"
#include "time.h"
#include <stdint.h>
#define TEST(p_e) \
do { \
if (!(p_e)) { \
com_std_print('c', COM_DEF_STRLIT(p_e) " failed!"); \
anyfail = true; \
} \
} while (0)
static void com_bnch_fix(void) {
uint64_t start = com_timer_count_ns();
for (int i = 5000000; i--;) {
com_fix_t sqrt = com_fix_sqrt(i);
com_def_profile_sink(sqrt);
}
com_timer_profile(start, "fixed: sqrt");
start = com_timer_count_ns();
for (int i = 50000000; i--;) {
com_fix_t sin = com_fix_sin(i);
com_def_profile_sink(sin);
}
com_timer_profile(start, "fixed: sin");
start = com_timer_count_ns();
for (int i = 50000000; i--;) {
com_fix_t cos = com_fix_cos(i);
com_def_profile_sink(cos);
}
com_timer_profile(start, "fixed: cos");
start = com_timer_count_ns();
for (int i = 50000000; i--;) {
com_fix_t sin, cos;
com_fix_sincos(i, &sin, &cos);
com_fix_t sinv = sin;
com_fix_t cosv = cos;
com_def_profile_sink(sinv);
com_def_profile_sink(cosv);
}
com_timer_profile(start, "fixed: sincos");
}
static void com_bnch_run(void) { com_bnch_fix(); }
#undef TEST
+5
View File
@@ -19,4 +19,9 @@
#define COM_CFG_FBSIZE (COM_CFG_WIDTH * COM_CFG_HEIGHT * COM_CFG_COLORS) #define COM_CFG_FBSIZE (COM_CFG_WIDTH * COM_CFG_HEIGHT * COM_CFG_COLORS)
#define COM_CFG_SNDFRMRATE 44100
/* TODO: Generate file with precompiled note frequencies. */
#define COM_CFG_A4FIX (440 << COM_FIX_FRACBITS)
#endif #endif
-34
View File
@@ -70,37 +70,3 @@ com_fix_t com_fix_sqrt(com_fix_t a) {
return final_shift > 0 ? (int32_t)(x << final_shift) return final_shift > 0 ? (int32_t)(x << final_shift)
: (int32_t)(x >> (-final_shift)); : (int32_t)(x >> (-final_shift));
} }
void com_fix_run_bench(void) {
uint64_t start = com_timer_count_ns();
for (int i = 5000000; i--;) {
com_fix_t sqrt = com_fix_sqrt(i);
com_def_profile_sink(sqrt);
}
com_timer_profile(start, "fixed: sqrt");
start = com_timer_count_ns();
for (int i = 50000000; i--;) {
com_fix_t sin = com_fix_sin(i);
com_def_profile_sink(sin);
}
com_timer_profile(start, "fixed: sin");
start = com_timer_count_ns();
for (int i = 50000000; i--;) {
com_fix_t cos = com_fix_cos(i);
com_def_profile_sink(cos);
}
com_timer_profile(start, "fixed: cos");
start = com_timer_count_ns();
for (int i = 50000000; i--;) {
com_fix_t sin, cos;
com_fix_sincos(i, &sin, &cos);
com_fix_t sinv = sin;
com_fix_t cosv = cos;
com_def_profile_sink(sinv);
com_def_profile_sink(cosv);
}
com_timer_profile(start, "fixed: sincos");
}
+5 -5
View File
@@ -23,9 +23,6 @@ typedef int32_t com_fix_t;
extern const uint16_t com_fix_sin_lut[128]; extern const uint16_t com_fix_sin_lut[128];
void com_fix_run_tests(void);
void com_fix_run_bench(void);
static inline com_fix_t com_fix_add(com_fix_t a, com_fix_t b) { return a + b; } static inline com_fix_t com_fix_add(com_fix_t a, com_fix_t b) { return a + b; }
static inline com_fix_t com_fix_sub(com_fix_t a, com_fix_t b) { return a - b; } static inline com_fix_t com_fix_sub(com_fix_t a, com_fix_t b) { return a - b; }
@@ -64,6 +61,7 @@ static inline com_fix_t com_fix_floor(com_fix_t const a) {
com_fix_t com_fix_sqrt(com_fix_t a); com_fix_t com_fix_sqrt(com_fix_t a);
/* Approximated using LUT. */ /* Approximated using LUT. */
/* Integer part only houses sign. */
/* TODO: test whether linearly interpolated version could be default. */ /* TODO: test whether linearly interpolated version could be default. */
/* things like camera movement can be jarring if done without.*/ /* things like camera movement can be jarring if done without.*/
/* https://namoseley.wordpress.com/2015/07/26/sincos-generation-using-table-lookup-and-iterpolation/ /* https://namoseley.wordpress.com/2015/07/26/sincos-generation-using-table-lookup-and-iterpolation/
@@ -90,9 +88,11 @@ static inline com_fix_t com_fix_sin(com_fix_t q) {
} }
} }
static inline com_fix_t com_fix_sin_from_lut(uint8_t l) {
return com_fix_sin_lut[l];
}
/* Implemented over sin, as to share one single LUT. */ /* Implemented over sin, as to share one single LUT. */
/* Additionally, optimizer probably can collapse some math for combined sincos
* case. */
static inline com_fix_t com_fix_cos(com_fix_t a) { static inline com_fix_t com_fix_cos(com_fix_t a) {
return com_fix_sin(a + COM_FIX_PIHALF); return com_fix_sin(a + COM_FIX_PIHALF);
} }
+18 -14
View File
@@ -6,6 +6,8 @@
#ifndef COM_STD_H #ifndef COM_STD_H
#define COM_STD_H #define COM_STD_H
#include "def.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@@ -40,20 +42,6 @@ void com_std_close(com_std_fd fd);
/* Note: Freeing is done by passing 0 size to pointer. */ /* Note: Freeing is done by passing 0 size to pointer. */
void *com_std_alloc(void *ptr, size_t size); void *com_std_alloc(void *ptr, size_t size);
/* Note: Functions listed below are only available for dev builds. */
/* Trigonometry functions are for reference testing of our own fixed point
* implementations. Do not use otherwise. */
#define com_std_assert(p_h) \
do { \
if (!(p_h)) { \
const char msg[] = \
"Assertion failed at "__FILE__ \
":" COM_DEF_STRLIT(__LINE__) ": " COM_DEF_STRLIT(p_h); \
com_std_print_str(msg, sizeof msg, true); \
com_std_exit(-1); \
} \
} while (0)
/* /*
Basic printing utility that doesn't utilize format string. Basic printing utility that doesn't utilize format string.
Instead a vector of arguments is passed and concatenated, based on type. Instead a vector of arguments is passed and concatenated, based on type.
@@ -81,9 +69,25 @@ void com_std_print_(int32_t start, ...);
#define com_std_print(...) com_std_print_(__VA_ARGS__, '.') #define com_std_print(...) com_std_print_(__VA_ARGS__, '.')
void com_std_print_str(char const *str, uint32_t len, bool newline); void com_std_print_str(char const *str, uint32_t len, bool newline);
#define COM_STD_PIF ((float)3.14159265358979323846)
double com_std_sqrt(double v); double com_std_sqrt(double v);
double com_std_fabs(double v); double com_std_fabs(double v);
double com_std_sin(double v); double com_std_sin(double v);
double com_std_cos(double v); double com_std_cos(double v);
/* Note: Functions listed below are only available for dev builds. */
/* Trigonometry functions are for reference testing of our own fixed point
* implementations. Do not use otherwise. */
#define com_std_assert(p_h) \
do { \
if (!(p_h)) { \
const char msg[] = \
"Assertion failed at "__FILE__ \
":" COM_DEF_STRLIT(__LINE__) ": " COM_DEF_STRLIT(p_h); \
com_std_print_str(msg, sizeof msg, true); \
com_std_exit(-1); \
} \
} while (0)
#endif #endif
+1 -1
View File
@@ -49,7 +49,7 @@ static inline int32_t com_str_ext_find_char(char const *s, char ch) {
static inline bool com_str_ext_prefixed(char const *__restrict a, static inline bool com_str_ext_prefixed(char const *__restrict a,
struct com_str const *prefix) { struct com_str const *prefix) {
uint32_t n = prefix->len; uint32_t n = prefix->len;
char *b = prefix->data; char const *b = prefix->data;
while (n && *a && (*a == *b)) { while (n && *a && (*a == *b)) {
++a; ++a;
++b; ++b;
+3
View File
@@ -0,0 +1,3 @@
/*
https://gist.github.com/takaswie/d8a9553c230971d974a3dfc759b2ff67
*/
+22 -31
View File
@@ -1,3 +1,4 @@
#include "../../Common/def.h"
#include "display.h" #include "display.h"
#include <fcntl.h> #include <fcntl.h>
#include <stdbool.h> #include <stdbool.h>
@@ -259,6 +260,17 @@ static inline bool set_segment_rights(uint16_t selector, bool read,
return !carry_clear; return !carry_clear;
} }
static inline intptr_t get_segment_base_address(uint16_t selector) {
bool carry_clear;
uint16_t high, low;
__asm__ volatile("int $0x31"
: "=@ccnc"(carry_clear), "=c"(high), "=d"(low)
: "a"(0x0006), "b"(selector)
: "memory", "cc");
// return carry_clear ? 0 : (((intptr_t)high << 16) | (intptr_t)low);
return ((intptr_t)high << 16) | (intptr_t)low;
}
static inline void use_segment(uint16_t selector) { static inline void use_segment(uint16_t selector) {
__asm__ volatile("" : "=S"(selector)::); __asm__ volatile("" : "=S"(selector)::);
} }
@@ -271,40 +283,19 @@ static inline void print_to_console(char *const str) {
static uint32_t test = 0x1420124; static uint32_t test = 0x1420124;
// extern int plr_display_dos_main(int argc, char *argv[]) {
extern int plr_display_dos_main(void) { extern int plr_display_dos_main(void) {
print_to_console("Fuck you stupid shit"); /* Fat DS trick, see __djgpp_nearptr_enable() */
return -1; unsigned short ds_selector;
asm("movw %%ds, %0" : "=r"(ds_selector));
uint16_t base = alloc_ldt_descriptor(); set_segment_limit(ds_selector, 0xFFFFFFFF);
if (!base) { intptr_t baseaddr = get_segment_base_address(ds_selector);
print_to_console("Cannot allocate LDT descriptor"); if (baseaddr == 0)
return -1; return -1;
}
if (!set_segment_base_address(base, 0xA0000)) { unsigned char *volatile buf =
print_to_console("Cannot set LDT base address"); (unsigned char *)((intptr_t)0xA0000 - baseaddr); // VGA memory address
return -1;
}
if (!set_segment_limit(base, 0x10000)) {
print_to_console("Cannot set LDT limit");
return -1;
}
use_segment(base);
// char *volatile buf = (void *)(intptr_t)0xA0000; // VGA memory address
// char *buf = map_physical_address(0xA0000, 0x10000); // VGA memory
char *buf = map_physical_address(0xA0000, 0x10000); // VGA memory
// address
if (!buf)
return -1;
int x, y;
// if (!buf)
// return -1;
/* TODO: Make VESA work for sweet sweet 640x480. */
// unsigned char saved_mode = get_video_mode(); // Save original mode // unsigned char saved_mode = get_video_mode(); // Save original mode
// set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode // set_vesa_video_mode(MODE_VESA_640_480_8); // Set our VGA mode
set_video_mode(MODE_VGA_320_200_8); // Set our VGA mode set_video_mode(MODE_VGA_320_200_8); // Set our VGA mode
@@ -327,6 +318,7 @@ extern int plr_display_dos_main(void) {
// wait_for_key(); // wait_for_key();
// set_video_mode(saved_mode); // Restore original mode // set_video_mode(saved_mode); // Restore original mode
int x, y;
while (1) { while (1) {
for (y = 0; y < HEIGHT; y++) { for (y = 0; y < HEIGHT; y++) {
for (x = 0; x < WIDTH; x++) { for (x = 0; x < WIDTH; x++) {
@@ -339,7 +331,6 @@ extern int plr_display_dos_main(void) {
} }
} }
// writetest(); // writetest();
__asm__ volatile("int $0x16" : : "a"(0x00) : "memory", "cc");
} }
// dpmi_regs = (struct dpmi_regs){.eax = 0x00004C00}; // dpmi_regs = (struct dpmi_regs){.eax = 0x00004C00};
+22 -16
View File
@@ -126,9 +126,11 @@ static bool plr_x11_handshake(com_std_fd xfd,
if (!com_std_write(xfd, AUTH_ENTRY_MAGIC_COOKIE, if (!com_std_write(xfd, AUTH_ENTRY_MAGIC_COOKIE,
sizeof AUTH_ENTRY_MAGIC_COOKIE - 1)) sizeof AUTH_ENTRY_MAGIC_COOKIE - 1))
return false; return false;
/* Use 2 bytes back for padding. */ /* 2 bytes padding after magic cookie. */
if (!com_std_write(xfd, &auth_entry.auth_data->data[-2], if (!com_std_write(xfd, &request, 2))
auth_entry.auth_data->len + 2)) return false;
if (!com_std_write(xfd, auth_entry.auth_data->data,
auth_entry.auth_data->len))
return false; return false;
struct { struct {
@@ -293,8 +295,8 @@ static uint32_t plr_x11_create_graphical_context(com_std_fd xfd) {
static uint32_t plr_x11_create_window(com_std_fd xfd) { static uint32_t plr_x11_create_window(com_std_fd xfd) {
/* TODO: Use the ones provided in headers ? */ /* TODO: Use the ones provided in headers ? */
#define FLAG_WIN_BG_PIXEL 2 #define FLAG_WIN_BG_PIXEL 0x0002
#define FLAG_WIN_EVENT 0x800 #define FLAG_WIN_EVENT 0x0800
#define EVENT_FLAG_EXPOSURE 0x8000 #define EVENT_FLAG_EXPOSURE 0x8000
#define EVENT_FLAG_KEY_PRESS 0x1 #define EVENT_FLAG_KEY_PRESS 0x1
#define EVENT_FLAG_KEY_RELEASE 0x2 #define EVENT_FLAG_KEY_RELEASE 0x2
@@ -331,7 +333,7 @@ static uint32_t plr_x11_create_window(com_std_fd xfd) {
.class = 1, .class = 1,
.root_visual_id = plr_x11_root_screen.root_visual_id, .root_visual_id = plr_x11_root_screen.root_visual_id,
.bitmask = FLAG_WIN_BG_PIXEL | FLAG_WIN_EVENT, .bitmask = FLAG_WIN_BG_PIXEL | FLAG_WIN_EVENT,
.value1 = 0x00000000, .value1 = 0xff000000,
.value2 = EVENT_FLAG_EXPOSURE | EVENT_FLAG_BUTTON_RELEASE | .value2 = EVENT_FLAG_EXPOSURE | EVENT_FLAG_BUTTON_RELEASE |
EVENT_FLAG_BUTTON_PRESS | EVENT_FLAG_KEY_PRESS | EVENT_FLAG_BUTTON_PRESS | EVENT_FLAG_KEY_PRESS |
EVENT_FLAG_KEY_RELEASE, EVENT_FLAG_KEY_RELEASE,
@@ -419,6 +421,10 @@ static uint8_t plr_x11_query_extension(com_std_fd xfd, com_str const *ext) {
static bool plr_x11_enable_big_requests(com_std_fd xfd) { static bool plr_x11_enable_big_requests(com_std_fd xfd) {
static com_str bigreqext = com_str_lit("BIG-REQUESTS"); static com_str bigreqext = com_str_lit("BIG-REQUESTS");
uint8_t const opcode = plr_x11_query_extension(xfd, &bigreqext); uint8_t const opcode = plr_x11_query_extension(xfd, &bigreqext);
if (!opcode) {
com_std_print('c', "Big request can't accommodate for framebuffer.");
return false;
}
/* Request the thing. */ /* Request the thing. */
struct { struct {
@@ -439,8 +445,8 @@ static bool plr_x11_enable_big_requests(com_std_fd xfd) {
plr_x11_poll_reply(xfd, seq, &response); plr_x11_poll_reply(xfd, seq, &response);
uint32_t const limit = *(uint32_t *)response.reply.pad; uint32_t const limit = *(uint32_t *)response.reply.pad;
com_std_print('c', "Request limit: ", 'u', limit); com_std_print('c', "X11 request limit: ", 'u', limit);
if (limit < COM_CFG_FBSIZE) { if (limit < COM_CFG_FBSIZE / 4) {
com_std_print('c', "Big request can't accommodate for framebuffer."); com_std_print('c', "Big request can't accommodate for framebuffer.");
return false; return false;
} }
@@ -449,7 +455,7 @@ static bool plr_x11_enable_big_requests(com_std_fd xfd) {
} }
static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id, static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id,
uint32_t pixmap_id, uint32_t drawable_id,
uint8_t pixels[COM_CFG_FBSIZE]) { uint8_t pixels[COM_CFG_FBSIZE]) {
uint32_t const padded = com_bits_nalign(COM_CFG_FBSIZE, 4); uint32_t const padded = com_bits_nalign(COM_CFG_FBSIZE, 4);
uint32_t const seq = plr_x11_next_seqid(); uint32_t const seq = plr_x11_next_seqid();
@@ -472,7 +478,7 @@ static bool plr_x11_put_framebuffer(com_std_fd xfd, uint32_t gc_id,
.opcode = 72, .opcode = 72,
.format = 2, // ZPixmap .format = 2, // ZPixmap
.request_length = sizeof request / 4 + padded / 4, .request_length = sizeof request / 4 + padded / 4,
.drawable_id = pixmap_id, .drawable_id = drawable_id,
.gc_id = gc_id, .gc_id = gc_id,
.width = COM_CFG_WIDTH, .width = COM_CFG_WIDTH,
.height = COM_CFG_HEIGHT, .height = COM_CFG_HEIGHT,
@@ -600,11 +606,11 @@ extern int plr_display_x11_main(int argc, char const *const *argv) {
return -1; return -1;
} }
uint32_t const fb = plr_x11_create_pixmap(xfd, win); // uint32_t const fb = plr_x11_create_pixmap(xfd, win);
if (!fb) { // if (!fb) {
com_std_print('c', "Failure to initialize X11"); // com_std_print('c', "Failure to initialize X11");
return -1; // return -1;
} // }
// Display *display = XOpenDisplay(NULL); // Display *display = XOpenDisplay(NULL);
// if (NULL == display) { // if (NULL == display) {
@@ -704,7 +710,7 @@ extern int plr_display_x11_main(int argc, char const *const *argv) {
uint8_t *fbm = plr_draw_get_pixel_buffer(); uint8_t *fbm = plr_draw_get_pixel_buffer();
plr_draw_screen(fbm); plr_draw_screen(fbm);
if (!plr_x11_put_framebuffer(xfd, gc, fb, fbm)) { if (!plr_x11_put_framebuffer(xfd, gc, win, fbm)) {
com_std_print('c', "Failure to drive X11"); com_std_print('c', "Failure to drive X11");
return -1; return -1;
} }
-2
View File
@@ -1,8 +1,6 @@
.section .data .section .data
.align 4 .align 4
# TODO: Make sure it's placed under 1 MiB. # TODO: Make sure it's placed under 1 MiB.
# The DPMI Register Structure (50 bytes total)
# This holds the register states injected into Real Mode.
.section .text .section .text
.global _start .global _start
View File
Whitespace-only changes.
-26
View File
@@ -1,26 +0,0 @@
/*
Inter-process communicating socket, useful for local testing and admin
playing.
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#define MAXBUFFSIZE 4194304 /* 4.0MiB */
int plr_socket_unix_try_connect(const char *filepath) {
int sock = 0;
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("Error creating client UNIX socket: ");
return -1;
}
struct sockaddr_un remote = {0};
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, filepath);
int const remote_len = SUN_LEN(&remote);
return 0;
}
+4 -7
View File
@@ -6,29 +6,26 @@ We do not use abstractions, as the simplicity of the required set of features sh
---- Restrictions ---- ---- Restrictions ----
* Fixed sized paletted frambuffer, defaulted to 640x480. * Fixed sized paletted frambuffer, defaulted to 640x480.
* Deterministic logic via Q15.16 fixed point numbers. * Deterministic logic via Q15.16 fixed point numbers.
* .gam image format, derived from .gif. RLE and Delta Frame Optimiztion is added, palette is predefined. * .gam image format, derived from .gif. Palette is globally predefined.
* Textures are 32x32 pixels. * Textures are 32x32 pixels.
* 30 FPS display rate. * 30 FPS display rate.
* Fonts are in ASCII bitmaps. Tile slicing commands are issued to render them in. * Fonts are in ASCII bitmaps. Tile slicing commands are issued to render them in.
* Audio samples are in our own .sam format (s8 frame delta + lzw). * Audio samples are in our own .sam format (s8 + ulaw + lzw).
* Music pieces are written in our own simple .tam tracker format, using the same .sam sample db. * Music pieces are written in our own simple .tam tracker format, using the same .sam sample db.
* Connections are over TCP and their supersets (like WebSocket). * Connections are over TCP and their supersets (like WebSocket).
* Textbox provides another client-controlled view, with history.
* Content usage has to be predefined, to allow preloading and compilation. * Content usage has to be predefined, to allow preloading and compilation.
---- Building ---- ---- Building ----
==== DOS ==== ==== DOS ====
Open Watcom 2.0 32bit toolchain is used under Linux host. Nothing is needed. Just compile.
Place a copy of DOS4GW.EXE alongside the executable.
Expect to need to configure $INCLUDE and $LIB variables.
---- .sam format ---- ---- .sam format ----
Thin sample compressing scheme tailored for use with .tam tracker. Thin sample compressing scheme tailored for use with .tam tracker.
Leading and tailing silence is stored as number of frames. Leading and tailing silence is stored as number of frames.
Sample data is 1 channel only, but panning can be expressed via graph. Sample data is 1 channel only, but panning can be expressed via graph.
Sample bit format is signed 8 bit delta, first frame is delta against 0. Clamping is allowed. Sample bit format is signed 8 bit delta. Clamping is allowed.
Generic LZW compression is applied as the last step. Generic LZW compression is applied as the last step.
+31
View File
@@ -0,0 +1,31 @@
/*
Tracker program to create awesome music!
Is supposed to only work on Linux, as it's where the development happens.
*/
#include "../../Common/Snd/oscs.h"
#include "../../Common/Std/libc.c"
#include "../../Common/Timer/posix.c"
#include "../../Common/fix.c"
#include <stdint.h>
#include <stdio.h>
int main(int argc, char **argv) {
struct com_snd_swave swave = com_snd_swave_init(COM_CFG_A4FIX, 0, UINT16_MAX);
FILE *f = fopen("test.raw", "w");
if (!f) {
printf("Can't open file %s\n", "test.raw");
return -1;
}
/* Generate 5 seconds of sinwave. */
int16_t frames[COM_CFG_SNDFRMRATE * 5];
for (int i = 0; i < COM_CFG_SNDFRMRATE * 5; ++i)
frames[i] = com_snd_swave_pump(&swave);
fwrite(frames, 2, COM_CFG_SNDFRMRATE * 5, f);
return 0;
}
Binary file not shown.
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
# Compression testing for image data for expected cases of ours.
# TODO: Implement our own CLI tool that uses our LZW implementation, as it differs.
import imageio.v3 as iio
import ncompress
import numpy as np
import sys
uncompressed = iio.imread(sys.argv[1])
compressed = ncompress.compress(uncompressed.tobytes())
print("Uncompressed:", uncompressed.nbytes)
print("Compressed:", len(compressed), len(compressed) / uncompressed.nbytes)
with open(sys.argv[1] + "-indexed.raw", "rb") as file:
raw_bytes = file.read()
indexmapping = {}
indexset = set(raw_bytes)
for idx, value in enumerate(indexset):
indexmapping[value] = idx
print(indexmapping)
indexmap = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.uint8)
for y in range(uncompressed.shape[0]):
for x in range(uncompressed.shape[1]):
indexmap[y * uncompressed.shape[0] + x] = indexmapping[raw_bytes[y * uncompressed.shape[0] + x]]
indexedcompressed = ncompress.compress(indexmap.tobytes())
print("Indexed:", len(indexedcompressed), len(indexedcompressed) / len(raw_bytes))
# https://arxiv.org/html/2006.02639v2
def pixel_art_predictive_filter(image_channel):
"""
Applies a spatial prediction filter to a 2D image matrix
to prepare it for lossless compression.
"""
rows, cols = image_channel.shape
residual_map = np.zeros((rows, cols), dtype=np.int16)
for r in range(rows):
for c in range(cols):
# Handle edge cases (boundaries where neighbors don't exist)
if r == 0 and c == 0:
pred = 0
elif r == 0:
pred = image_channel[r, c-1] # Only Left neighbor exists
elif c == 0:
pred = image_channel[r-1, c] # Only Top neighbor exists
else:
# Core DSP Neighborhood definition
A = image_channel[r, c-1] # Left
B = image_channel[r-1, c] # Top
C = image_channel[r-1, c-1] # Top-Left
# Median Edge Detector logic
if C >= max(A, B):
pred = min(A, B)
elif C <= min(A, B):
pred = max(A, B)
else:
pred = int(A) + int(B) - int(C)
# Map the actual value to the residual difference
residual_map[r, c] = int(image_channel[r, c]) - int(pred)
return residual_map
predictivefilter = pixel_art_predictive_filter(indexmap)
predictivefiltercompressed = ncompress.compress(predictivefilter.tobytes())
print("Predictive filter:", len(predictivefiltercompressed), len(predictivefiltercompressed) / len(raw_bytes))
def encode_zorder_2d(x: int, y: int) -> int:
z = 0
for i in range(16):
z |= ((x & (1 << i)) << i) | ((y & (1 << i)) << (i + 1))
return z
zordered = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.uint8)
for y in range(uncompressed.shape[0]):
for x in range(uncompressed.shape[1]):
idx = encode_zorder_2d(x, y)
zordered[idx] = uncompressed[y, x]
zcompressed = ncompress.compress(zordered.tobytes())
print("Zordered:", len(zcompressed), len(zcompressed) / uncompressed.nbytes)
delta = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.int8)
for y in range(uncompressed.shape[0]):
for x in range(uncompressed.shape[1]):
delta[y * uncompressed.shape[0] + x] = int(uncompressed[y, x]) - int(uncompressed[y, (x + 1) % uncompressed.shape[0]])
deltacompressed = ncompress.compress(delta.tobytes())
print("Delta:", len(deltacompressed), len(deltacompressed) / uncompressed.nbytes)
deltaz = np.zeros((uncompressed.shape[0] * uncompressed.shape[1], 1), dtype=np.int8)
for y in range(uncompressed.shape[0]):
for x in range(uncompressed.shape[1]):
idx = encode_zorder_2d(x, y)
deltaz[idx] = int(uncompressed[y, x]) - int(uncompressed[y, (x + 1) % uncompressed.shape[0]])
deltazcompressed = ncompress.compress(deltaz.tobytes())
print("Deltaz:", len(deltazcompressed), len(deltazcompressed) / uncompressed.nbytes)
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
# Compression testing for sound sample data for expected cases of ours.
# TODO: Implement our own CLI tool that uses our LZW implementation, as it differs.
import ncompress
import sys
import wave
import audioop
import numpy as np
import array
with wave.open(sys.argv[1], 'rb') as wf:
channels = wf.getnchannels()
samplerate = wf.getframerate()
frames = wf.getnframes()
uncompressed = wf.readframes(frames)
depth = wf.getsampwidth()
compressed = ncompress.compress(uncompressed)
print("Uncompressed:", len(uncompressed))
print("Compressed:", len(compressed), len(compressed) / len(uncompressed))
delta = bytearray(uncompressed[0].to_bytes(2, signed=False))
for i in range(len(uncompressed)-1):
delta += (uncompressed[i+1] - uncompressed[i]).to_bytes(2, signed=True)
dtcompressed = ncompress.compress(bytes(delta))
print("Delta:", len(dtcompressed), len(dtcompressed) / len(uncompressed))
assert(len(delta) == len(uncompressed)*2)
ulaw = audioop.lin2ulaw(uncompressed, depth)
ulawcompressed = ncompress.compress(ulaw)
print("Ulaw:", len(ulawcompressed), len(ulawcompressed) / len(uncompressed))
absfold = bytearray()
for i in range(len(uncompressed)):
absfold.append(uncompressed[i] - 128 if uncompressed[i] >= 128 else uncompressed[i])
absfoldulaw = audioop.lin2ulaw(absfold, depth)
absfoldulawcompressed = ncompress.compress(absfoldulaw)
print("Ulawabs:", len(absfoldulawcompressed), len(absfoldulawcompressed) / len(absfold))
with open(sys.argv[1] + ".ulaw", "wb") as file:
file.write(audioop.ulaw2lin(ulaw, depth))
File renamed without changes.
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env python3
magick $1 -resize 32x32 +dither -type Palette -depth 8 -colors 16 PNG8:$1-indexed
magick stream -map r -storage-type char $1-indexed $1-indexed.raw