diff options
author | Olivia Mackintosh <livvy@base.nu> | 2020-04-21 18:33:32 +0100 |
---|---|---|
committer | Olivia Mackintosh <livvy@base.nu> | 2020-04-21 18:33:32 +0100 |
commit | ddd234ea1ff2924e587372aa12c4d5cda99a0ce0 (patch) | |
tree | f5c6f28a18b726d04fcbb351341df4fb05714385 /src | |
download | tiny-ddd234ea1ff2924e587372aa12c4d5cda99a0ce0.tar.gz |
Initial commit
Diffstat (limited to 'src')
-rw-r--r-- | src/base.h | 35 | ||||
-rw-r--r-- | src/config.json | 41 | ||||
-rw-r--r-- | src/device.c | 522 | ||||
-rw-r--r-- | src/device.h | 54 | ||||
-rw-r--r-- | src/shader.frag | 185 | ||||
-rw-r--r-- | src/sync.h | 55 | ||||
-rw-r--r-- | src/tiny.c | 216 | ||||
-rw-r--r-- | src/track.c | 121 | ||||
-rw-r--r-- | src/track.h | 47 |
9 files changed, 1276 insertions, 0 deletions
diff --git a/src/base.h b/src/base.h new file mode 100644 index 0000000..44683c9 --- /dev/null +++ b/src/base.h @@ -0,0 +1,35 @@ +#ifndef SYNC_BASE_H +#define SYNC_BASE_H + +#ifdef _MSC_VER + #define _CRT_SECURE_NO_WARNINGS 1 + #define _CRT_NONSTDC_NO_DEPRECATE 1 +#endif + +#include <stddef.h> + +/* configure inline keyword */ +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)) && !defined(__cplusplus) + #if defined(_MSC_VER) || defined(__GNUC__) || defined(__SASC) + #define inline __inline + #else + /* compiler does not support inline */ + #define inline + #endif +#endif + +/* configure lacking CRT features */ +#ifdef _MSC_VER + #if _MSC_VER < 1900 + #define snprintf _snprintf + #endif + /* int is 32-bit for both x86 and x64 */ + typedef unsigned int uint32_t; + #define UINT32_MAX UINT_MAX +#elif defined(__GNUC__) + #include <stdint.h> +#elif defined(M68000) + typedef unsigned int uint32_t; +#endif + +#endif /* SYNC_BASE_H */ diff --git a/src/config.json b/src/config.json new file mode 100644 index 0000000..30ae9b9 --- /dev/null +++ b/src/config.json @@ -0,0 +1,41 @@ +{ + "window":{ // default window size / state, if there's a setup dialog, it will override it + "width":1920, + "height":1080, + "fullscreen":true + }, + "font":{ // all paths in the file are also relative to the binary, but again, can be absolute paths if that's more convenient + "file":"Input-Regular_(InputMono-Medium).ttf", + "size":16 + }, + "rendering":{ + "fftSmoothFactor": 0.9, // 0.0 means there's no smoothing at all, 1.0 means the FFT is completely smoothed flat + "fftAmplification": 1.0, // 1.0 means no change, larger values will result in brighter/stronger bands, smaller values in darker/weaker ones + }, + "textures":{ // the keys below will become the shader variable names + "texChecker":"textures/checker.png", + "texNoise":"textures/noise.png", + "texTex1":"textures/tex1.jpg" + }, + "gui":{ + "outputHeight": 200, + "opacity": 192, // 255 means the editor occludes the effect completely, 0 means the editor is fully transparent + "texturePreviewWidth": 64, + "spacesForTabs": false, + "tabSize": 8, + "visibleWhitespace": true, + "autoIndent": "smart", // can be "none", "preserve" or "smart" + }, + "midi":{ // the keys below will become the shader variable names, the values are the CC numbers + "fMidiKnob": 16, // e.g. this would be CC#16, i.e. by default the leftmost knob on a nanoKONTROL 2 + }, + // this section is if you want to enable NDI streaming; otherwise just ignore it + "ndi":{ + "enabled": true, + "connectionString": "<ndi_product something=\"123\"/>", // metadata sent to the receiver; completely optional + "identifier": "hello!", // additional string to the device name; helps source discovery/identification in the receiver if there are multiple sources on the network + "frameRate": 60.0, // frames per second + "progressive": true, // progressive or interleaved? + }, + "postExitCmd":"copy_to_dropbox.bat" // this command gets ran when you quit Bonzomatic, and the shader filename gets passed to it as first parameter. Use this to take regular backups. +} diff --git a/src/device.c b/src/device.c new file mode 100644 index 0000000..879d2a0 --- /dev/null +++ b/src/device.c @@ -0,0 +1,522 @@ +#include "device.h" +#include "track.h" +#include <assert.h> +#include <ctype.h> +#include <math.h> +#include <stdio.h> +#include <string.h> + +static int find_track(struct sync_device *d, const char *name) +{ + int i; + for (i = 0; i < (int)d->num_tracks; ++i) + if (!strcmp(name, d->tracks[i]->name)) + return i; + return -1; /* not found */ +} + +static const char *path_encode(const char *path) +{ + static char temp[FILENAME_MAX]; + int i, pos = 0; + int path_len = (int)strlen(path); + for (i = 0; i < path_len; ++i) { + int ch = path[i]; + if (isalnum(ch) || ch == '.' || ch == '_') { + if (pos >= sizeof(temp) - 1) + break; + + temp[pos++] = (char)ch; + } else { + if (pos >= sizeof(temp) - 3) + break; + + temp[pos++] = '-'; + temp[pos++] = "0123456789ABCDEF"[(ch >> 4) & 0xF]; + temp[pos++] = "0123456789ABCDEF"[ch & 0xF]; + } + } + + temp[pos] = '\0'; + return temp; +} + +static const char *sync_track_path(const char *base, const char *name) +{ + static char temp[FILENAME_MAX]; + strncpy(temp, base, sizeof(temp) - 1); + temp[sizeof(temp) - 1] = '\0'; + strncat(temp, "_", sizeof(temp) - strlen(temp) - 1); + strncat(temp, path_encode(name), sizeof(temp) - strlen(temp) - 1); + strncat(temp, ".track", sizeof(temp) - strlen(temp) - 1); + return temp; +} + +#ifndef SYNC_PLAYER + +#define CLIENT_GREET "hello, synctracker!" +#define SERVER_GREET "hello, demo!" + +enum { + SET_KEY = 0, + DELETE_KEY = 1, + GET_TRACK = 2, + SET_ROW = 3, + PAUSE = 4, + SAVE_TRACKS = 5 +}; + +static inline int socket_poll(SOCKET socket) +{ + struct timeval to = { 0, 0 }; + fd_set fds; + + FD_ZERO(&fds); + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4127) +#endif + FD_SET(socket, &fds); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + return select((int)socket + 1, &fds, NULL, NULL, &to) > 0; +} + +static inline int xsend(SOCKET s, const void *buf, size_t len, int flags) +{ +#ifdef WIN32 + assert(len <= INT_MAX); + return send(s, (const char *)buf, (int)len, flags) != (int)len; +#else + return send(s, (const char *)buf, len, flags) != (int)len; +#endif +} + +static inline int xrecv(SOCKET s, void *buf, size_t len, int flags) +{ +#ifdef WIN32 + assert(len <= INT_MAX); + return recv(s, (char *)buf, (int)len, flags) != (int)len; +#else + return recv(s, (char *)buf, len, flags) != (int)len; +#endif +} + +#ifdef USE_AMITCP +static struct Library *socket_base = NULL; +#endif + +static SOCKET server_connect(const char *host, unsigned short nport) +{ + SOCKET sock = INVALID_SOCKET; +#ifdef USE_GETADDRINFO + struct addrinfo *addr, *curr; + char port[6]; +#else + struct hostent *he; + char **ap; +#endif + +#ifdef WIN32 + static int need_init = 1; + if (need_init) { + WSADATA wsa; + if (WSAStartup(MAKEWORD(2, 0), &wsa)) + return INVALID_SOCKET; + need_init = 0; + } +#elif defined(USE_AMITCP) + if (!socket_base) { + socket_base = OpenLibrary("bsdsocket.library", 4); + if (!socket_base) + return INVALID_SOCKET; + } +#endif + +#ifdef USE_GETADDRINFO + + snprintf(port, sizeof(port), "%u", nport); + if (getaddrinfo(host, port, 0, &addr) != 0) + return INVALID_SOCKET; + + for (curr = addr; curr; curr = curr->ai_next) { + int family = curr->ai_family; + struct sockaddr *sa = curr->ai_addr; + int sa_len = (int)curr->ai_addrlen; + +#else + + he = gethostbyname(host); + if (!he) + return INVALID_SOCKET; + + for (ap = he->h_addr_list; *ap; ++ap) { + int family = he->h_addrtype; + struct sockaddr_in sin; + struct sockaddr *sa = (struct sockaddr *)&sin; + int sa_len = sizeof(*sa); + + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(nport); + memcpy(&sin.sin_addr, *ap, he->h_length); + memset(&sin.sin_zero, 0, sizeof(sin.sin_zero)); + +#endif + + sock = socket(family, SOCK_STREAM, 0); + if (sock == INVALID_SOCKET) + continue; + + if (connect(sock, sa, sa_len) >= 0) { + char greet[128]; + + if (xsend(sock, CLIENT_GREET, strlen(CLIENT_GREET), 0) || + xrecv(sock, greet, strlen(SERVER_GREET), 0)) { + closesocket(sock); + sock = INVALID_SOCKET; + continue; + } + + if (!strncmp(SERVER_GREET, greet, strlen(SERVER_GREET))) + break; + } + + closesocket(sock); + sock = INVALID_SOCKET; + } + +#ifdef USE_GETADDRINFO + freeaddrinfo(addr); +#endif + + return sock; +} + +#else + +void sync_set_io_cb(struct sync_device *d, struct sync_io_cb *cb) +{ + d->io_cb.open = cb->open; + d->io_cb.read = cb->read; + d->io_cb.close = cb->close; +} + +#endif + +#ifdef NEED_STRDUP +static inline char *rocket_strdup(const char *str) +{ + char *ret = malloc(strlen(str) + 1); + if (ret) + strcpy(ret, str); + return ret; +} +#define strdup rocket_strdup +#endif + +struct sync_device *sync_create_device(const char *base) +{ + struct sync_device *d = malloc(sizeof(*d)); + if (!d) + return NULL; + + d->base = strdup(path_encode(base)); + if (!d->base) { + free(d); + return NULL; + } + + d->tracks = NULL; + d->num_tracks = 0; + +#ifndef SYNC_PLAYER + d->row = -1; + d->sock = INVALID_SOCKET; +#endif + + d->io_cb.open = (void *(*)(const char *, const char *))fopen; + d->io_cb.read = (size_t (*)(void *, size_t, size_t, void *))fread; + d->io_cb.close = (int (*)(void *))fclose; + + return d; +} + +void sync_destroy_device(struct sync_device *d) +{ + int i; + +#ifndef SYNC_PLAYER + if (d->sock != INVALID_SOCKET) + closesocket(d->sock); +#endif + + for (i = 0; i < (int)d->num_tracks; ++i) { + free(d->tracks[i]->name); + free(d->tracks[i]->keys); + free(d->tracks[i]); + } + free(d->tracks); + free(d->base); + free(d); + +#if defined(USE_AMITCP) && !defined(SYNC_PLAYER) + if (socket_base) { + CloseLibrary(socket_base); + socket_base = NULL; + } +#endif +} + +static int read_track_data(struct sync_device *d, struct sync_track *t) +{ + int i; + void *fp = d->io_cb.open(sync_track_path(d->base, t->name), "rb"); + if (!fp) + return -1; + + d->io_cb.read(&t->num_keys, sizeof(int), 1, fp); + t->keys = malloc(sizeof(struct track_key) * t->num_keys); + if (!t->keys) + return -1; + + for (i = 0; i < (int)t->num_keys; ++i) { + struct track_key *key = t->keys + i; + char type; + d->io_cb.read(&key->row, sizeof(int), 1, fp); + d->io_cb.read(&key->value, sizeof(float), 1, fp); + d->io_cb.read(&type, sizeof(char), 1, fp); + key->type = (enum key_type)type; + } + + d->io_cb.close(fp); + return 0; +} + +static int save_track(const struct sync_track *t, const char *path) +{ + int i; + FILE *fp = fopen(path, "wb"); + if (!fp) + return -1; + + fwrite(&t->num_keys, sizeof(int), 1, fp); + for (i = 0; i < (int)t->num_keys; ++i) { + char type = (char)t->keys[i].type; + fwrite(&t->keys[i].row, sizeof(int), 1, fp); + fwrite(&t->keys[i].value, sizeof(float), 1, fp); + fwrite(&type, sizeof(char), 1, fp); + } + + fclose(fp); + return 0; +} + +void sync_save_tracks(const struct sync_device *d) +{ + int i; + for (i = 0; i < (int)d->num_tracks; ++i) { + const struct sync_track *t = d->tracks[i]; + save_track(t, sync_track_path(d->base, t->name)); + } +} + +#ifndef SYNC_PLAYER + +static int fetch_track_data(struct sync_device *d, struct sync_track *t) +{ + unsigned char cmd = GET_TRACK; + uint32_t name_len; + + assert(strlen(t->name) <= UINT32_MAX); + name_len = htonl((uint32_t)strlen(t->name)); + + /* send request data */ + if (xsend(d->sock, (char *)&cmd, 1, 0) || + xsend(d->sock, (char *)&name_len, sizeof(name_len), 0) || + xsend(d->sock, t->name, (int)strlen(t->name), 0)) + { + closesocket(d->sock); + d->sock = INVALID_SOCKET; + return -1; + } + + return 0; +} + +static int handle_set_key_cmd(SOCKET sock, struct sync_device *data) +{ + uint32_t track, row; + union { + float f; + uint32_t i; + } v; + struct track_key key; + unsigned char type; + + if (xrecv(sock, (char *)&track, sizeof(track), 0) || + xrecv(sock, (char *)&row, sizeof(row), 0) || + xrecv(sock, (char *)&v.i, sizeof(v.i), 0) || + xrecv(sock, (char *)&type, 1, 0)) + return -1; + + track = ntohl(track); + v.i = ntohl(v.i); + + key.row = ntohl(row); + key.value = v.f; + + assert(type < KEY_TYPE_COUNT); + assert(track < data->num_tracks); + key.type = (enum key_type)type; + return sync_set_key(data->tracks[track], &key); +} + +static int handle_del_key_cmd(SOCKET sock, struct sync_device *data) +{ + uint32_t track, row; + + if (xrecv(sock, (char *)&track, sizeof(track), 0) || + xrecv(sock, (char *)&row, sizeof(row), 0)) + return -1; + + track = ntohl(track); + row = ntohl(row); + + assert(track < data->num_tracks); + return sync_del_key(data->tracks[track], row); +} + +int sync_tcp_connect(struct sync_device *d, const char *host, unsigned short port) +{ + int i; + if (d->sock != INVALID_SOCKET) + closesocket(d->sock); + + d->sock = server_connect(host, port); + if (d->sock == INVALID_SOCKET) + return -1; + + for (i = 0; i < (int)d->num_tracks; ++i) { + free(d->tracks[i]->keys); + d->tracks[i]->keys = NULL; + d->tracks[i]->num_keys = 0; + } + + for (i = 0; i < (int)d->num_tracks; ++i) { + if (fetch_track_data(d, d->tracks[i])) { + closesocket(d->sock); + d->sock = INVALID_SOCKET; + return -1; + } + } + return 0; +} + +int sync_connect(struct sync_device *d, const char *host, unsigned short port) +{ + return sync_tcp_connect(d, host, port); +} + +int sync_update(struct sync_device *d, int row, struct sync_cb *cb, + void *cb_param) +{ + if (d->sock == INVALID_SOCKET) + return -1; + + /* look for new commands */ + while (socket_poll(d->sock)) { + unsigned char cmd = 0, flag; + uint32_t new_row; + if (xrecv(d->sock, (char *)&cmd, 1, 0)) + goto sockerr; + + switch (cmd) { + case SET_KEY: + if (handle_set_key_cmd(d->sock, d)) + goto sockerr; + break; + case DELETE_KEY: + if (handle_del_key_cmd(d->sock, d)) + goto sockerr; + break; + case SET_ROW: + if (xrecv(d->sock, (char *)&new_row, sizeof(new_row), 0)) + goto sockerr; + if (cb && cb->set_row) + cb->set_row(cb_param, ntohl(new_row)); + break; + case PAUSE: + if (xrecv(d->sock, (char *)&flag, 1, 0)) + goto sockerr; + if (cb && cb->pause) + cb->pause(cb_param, flag); + break; + case SAVE_TRACKS: + sync_save_tracks(d); + break; + default: + fprintf(stderr, "unknown cmd: %02x\n", cmd); + goto sockerr; + } + } + + if (cb && cb->is_playing && cb->is_playing(cb_param)) { + if (d->row != row && d->sock != INVALID_SOCKET) { + unsigned char cmd = SET_ROW; + uint32_t nrow = htonl(row); + if (xsend(d->sock, (char*)&cmd, 1, 0) || + xsend(d->sock, (char*)&nrow, sizeof(nrow), 0)) + goto sockerr; + d->row = row; + } + } + return 0; + +sockerr: + closesocket(d->sock); + d->sock = INVALID_SOCKET; + return -1; +} + +#endif /* !defined(SYNC_PLAYER) */ + +static int create_track(struct sync_device *d, const char *name) +{ + struct sync_track *t; + assert(find_track(d, name) < 0); + + t = malloc(sizeof(*t)); + t->name = strdup(name); + t->keys = NULL; + t->num_keys = 0; + + d->num_tracks++; + d->tracks = realloc(d->tracks, sizeof(d->tracks[0]) * d->num_tracks); + d->tracks[d->num_tracks - 1] = t; + + return (int)d->num_tracks - 1; +} + +const struct sync_track *sync_get_track(struct sync_device *d, + const char *name) +{ + struct sync_track *t; + int idx = find_track(d, name); + if (idx >= 0) + return d->tracks[idx]; + + idx = create_track(d, name); + t = d->tracks[idx]; + +#ifndef SYNC_PLAYER + if (d->sock != INVALID_SOCKET) + fetch_track_data(d, t); + else +#endif + read_track_data(d, t); + + return t; +} diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..93b9802 --- /dev/null +++ b/src/device.h @@ -0,0 +1,54 @@ +#ifndef SYNC_DEVICE_H +#define SYNC_DEVICE_H + +#include "base.h" +#include "sync.h" + +#ifndef SYNC_PLAYER + +/* configure socket-stack */ +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #define USE_GETADDRINFO + #ifndef NOMINMAX + #define NOMINMAX + #endif + #include <winsock2.h> + #include <ws2tcpip.h> + #include <windows.h> + #include <limits.h> +#elif defined(USE_AMITCP) + #include <sys/socket.h> + #include <proto/exec.h> + #include <proto/socket.h> + #include <netdb.h> + #define SOCKET int + #define INVALID_SOCKET -1 + #define select(n,r,w,e,t) WaitSelect(n,r,w,e,t,0) + #define closesocket(x) CloseSocket(x) +#else + #include <sys/socket.h> + #include <sys/time.h> + #include <netinet/in.h> + #include <netdb.h> + #include <unistd.h> + #define SOCKET int + #define INVALID_SOCKET -1 + #define closesocket(x) close(x) +#endif + +#endif /* !defined(SYNC_PLAYER) */ + +struct sync_device { + char *base; + struct sync_track **tracks; + size_t num_tracks; + +#ifndef SYNC_PLAYER + int row; + SOCKET sock; +#endif + struct sync_io_cb io_cb; +}; + +#endif /* SYNC_DEVICE_H */ diff --git a/src/shader.frag b/src/shader.frag new file mode 100644 index 0000000..b4cabf9 --- /dev/null +++ b/src/shader.frag @@ -0,0 +1,185 @@ +#version 410 core + +uniform vec2 u_resolution; // viewport resolution (in pixels) +uniform float u_time; // in seconds +uniform float u_xrot; +uniform float u_yrot; +uniform float u_zrot; +uniform sampler1D texFFT; + +layout(location = 0) out vec4 out_color; // out_color must be written in order to see anything + +const int MAX_STEP = 255; +const float MIN_DIST = 0.0; +const float MAX_DIST = 100.0; +const float EPSILON = 0.0001; + +float f(float x, float z) +{ + return 2.0; +} + + +// transformations +mat4 rotateX(float theta) +{ + float c = cos(theta); + float s = sin(theta); + + return mat4( + vec4(1, 0, 0, 0), + vec4(0, c, s, 0), + vec4(0, -s, c, 0), + vec4(0, 0, 0, 1) + ); +} + +// transformations +mat4 rotateY(float theta) +{ + float c = cos(theta); + float s = sin(theta); + + return mat4( + vec4(c, 0, s, 0), + vec4(0, 1, 0, 0), + vec4(-s, 0, c, 0), + vec4(0, 0, 0, 1) + ); +} + +// transformations +mat4 rotateZ(float theta) +{ + float c = cos(theta); + float s = sin(theta); + + return mat4( + vec4(c, s, 0, 0), + vec4(-s, c, 0, 0), + vec4(0, 0, 1, 0), + vec4(0, 0, 0, 1) + ); +} + +float tHeight(vec2 p) +{ + return smoothstep(0.0, 200.0, p.y*20000)*5; +} + +float torusSDF( vec3 p, vec2 t ) +{ + vec2 q = vec2(length(p.xz)-t.x,p.y); + float d1 = length(p)-0.4; + float d2 = tHeight(p.xy)*0.45; + return d1 + (d2/20); +} + +vec3 transformScene(vec3 p) +{ + //p = (inverse(rotateX(u_time*3)) * vec4(p, 1.0)).xyz; + p = (inverse(rotateX(u_xrot)) * + inverse(rotateY(u_yrot)) * + inverse(rotateZ(u_zrot)) * vec4(p, 1.0)).xyz; + return p; +} + +// Standard distance function for the whole scene! +float sceneSDF(vec3 p) +{ + p = transformScene(p); + //p = p * vec3(1.0, sin(u_time),1.0); + return torusSDF(p, vec2(0.3, 0.1)); +} + +vec3 estNormal(vec3 p) +{ + return normalize(vec3( + sceneSDF(vec3(p.x + EPSILON, p.y, p.z)) - sceneSDF(vec3(p.x - EPSILON, p.y, p.z)), + sceneSDF(vec3(p.x, p.y + EPSILON, p.z)) - sceneSDF(vec3(p.x, p.y - EPSILON, p.z)), + sceneSDF(vec3(p.x, p.y, p.z + EPSILON)) - sceneSDF(vec3(p.x, p.y, p.z - EPSILON)) + )); +} + +vec3 rayDirection(float fov, vec2 size, vec2 fragCoord) +{ + vec2 xy = fragCoord - size / 2.0; + float z = size.y / tan(radians(fov) / 2.0); + return normalize(vec3(xy, -z)); +} + +// Raymarcher! +float march(vec3 eye, vec3 dir, float start, float end) +{ + float depth = start; + for (int i=0; i<MAX_STEP; i++) { + float dist = sceneSDF(eye + depth * dir); + if (dist < 0.0001) { + return depth; // we're inside the scene + } + depth+=dist; + if (depth >= end) { + return end; // gone too far! + } + } +} + +// Does something related to phong for each light that we want +vec3 phongLightContrib(vec3 kd, vec3 ks, float alpha, vec3 p, vec3 eye, vec3 lightPos, vec3 lightInt) +{ + vec3 N = estNormal(p); + vec3 L = normalize(lightPos - p); + vec3 V = normalize(eye - p); + vec3 R = normalize(reflect(-L, N)); + + float dotLN = dot(L, N); + float dotRV = dot(R, V); + + if (dotLN < 0.0) {return vec3(0.0);} + if (dotRV < 0.0) {return lightInt * (kd * dotLN);} + return lightInt * (kd * dotLN + ks * pow(dotRV, alpha)); +} + +vec3 phong(vec3 ka, vec3 kd, vec3 ks, float alpha, vec3 p, vec3 eye) +{ + const vec3 ambientLux = vec3(0.3); + vec3 colour = ambientLux * ka; + + vec3 light1Pos = vec3(-1.0, -1.2, 0.7); + vec3 light1Int = vec3(0.2); + + vec3 light2Pos = vec3(0.8, 0.8, 1.2); + vec3 light2Int = vec3(0.55); + + colour += phongLightContrib(kd, ks, alpha, p, eye, light1Pos, light1Int); + colour += phongLightContrib(kd, ks, alpha, p, eye, light2Pos, light2Int); + return colour; +} + +void main(void) +{ + vec3 dir = rayDirection(45.0, u_resolution.xy, gl_FragCoord.xy); + vec3 eye = vec3(0.0,0.0,5.0); + float dist = march(eye, dir, MIN_DIST, MAX_DIST); + + if (dist > MAX_DIST - EPSILON) {out_color = vec4(0.1); return;} + + vec3 p = eye + dist * dir; + vec3 colour; + + vec3 Ka = vec3(0.0, 0.729, 0.745)*texture(texFFT, 0.123).r*1000; // ambient reflection constant + vec3 Kd = vec3(0.0, 0.467, 0.745); // diffuse reflection constant + vec3 Ks = vec3(0.0, 0.0, 0.0); // specular reflection constant + float shininess = 1.0; + colour = phong(Ka, Kd, Ks, shininess, p, eye); + + if (transformScene(p).y< 0) { + vec3 Ka = vec3(0.2); // ambient reflection constant + vec3 Kd = vec3(0.95, 0.2, 0.1); // diffuse reflection constant + vec3 Ks = vec3(0.95, 0.2, 0.1); // specular reflection constant + float shininess = 300.0; + colour = phong(Ka, Kd, Ks, shininess, p, eye); + } + + out_color = vec4(colour, 1.0); +} diff --git a/src/sync.h b/src/sync.h new file mode 100644 index 0000000..2d5df42 --- /dev/null +++ b/src/sync.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2010 Contributors + * For conditions of distribution and use, see copyright notice in COPYING + */ + +#ifndef SYNC_H +#define SYNC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + +#ifdef __GNUC__ +#define SYNC_DEPRECATED(msg) __attribute__ ((deprecated(msg))) +#elif defined(_MSC_VER) +#define SYNC_DEPRECATED(msg) __declspec(deprecated("is deprecated: " msg)) +#else +#define SYNC_DEPRECATED(msg) +#endif + +struct sync_device; +struct sync_track; + +struct sync_device *sync_create_device(const char *); +void sync_destroy_device(struct sync_device *); + +#ifndef SYNC_PLAYER +struct sync_cb { + void (*pause)(void *, int); + void (*set_row)(void *, int); + int (*is_playing)(void *); +}; +#define SYNC_DEFAULT_PORT 1338 +int sync_tcp_connect(struct sync_device *, const char *, unsigned short); +int SYNC_DEPRECATED("use sync_tcp_connect instead") sync_connect(struct sync_device *, const char *, unsigned short); +int sync_update(struct sync_device *, int, struct sync_cb *, void *); +void sync_save_tracks(const struct sync_device *); +#endif /* defined(SYNC_PLAYER) */ + +struct sync_io_cb { + void *(*open)(const char *filename, const char *mode); + size_t (*read)(void *ptr, size_t size, size_t nitems, void *stream); + int (*close)(void *stream); +}; +void sync_set_io_cb(struct sync_device *d, struct sync_io_cb *cb); + +const struct sync_track *sync_get_track(struct sync_device *, const char *); +double sync_get_val(const struct sync_track *, double); + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(SYNC_H) */ diff --git a/src/tiny.c b/src/tiny.c new file mode 100644 index 0000000..11b7e65 --- /dev/null +++ b/src/tiny.c @@ -0,0 +1,216 @@ +#define GL_GLEXT_PROTOTYPES why +//#include<stdio.h> +//#include<stdbool.h> +//#include<stdlib.h> +//#include<stdint.h> + +#include <glib.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include <GL/gl.h> +#include <GL/glx.h> +#include <GL/glu.h> +#include <GL/glext.h> +#include "shader.h" +#include "sync.h" +static char* vshader = "#version 450\nvec2 y=vec2(1.,-1);vec4 x[4]={y.yyxx,y.xyxx,y.yxxx,y.xxxx};void main(){gl_Position=x[gl_VertexID];}"; + +#define CANVAS_WIDTH 1920 +#define CANVAS_HEIGHT 1080 +//#define DEBUG + +GLuint vao; +GLuint p; + +// <sync stuff +int curtime_ms = 0; +int is_playing = 1; +int rps = 24; +static struct sync_device *device; +#if !defined(SYNC_PLAYER) +static struct sync_cb cb; +#endif +static const char* s_trackNames[] = {"cam_x", "cam_y", "cam_z"}; +static const struct sync_track* s_tracks[3]; + +static int row_to_ms_round(int row, float rps){ + const float newTime = (float) row / rps; + return (floor(newTime * 1000.0f + 0.5f)); +} +static float ms_to_row_f(int time_ms, float rps) { + return rps * ((float) time_ms) * 1.0f/1000.0f; +} +static int ms_to_row_round(int time_ms, float rps){ + const float r = ms_to_row_f(time_ms, rps); + return (int) (floor(r + 0.5f)); +} +#if !defined(SYNC_PLAYER) +static void xpause(void* data, int flag) +{ + (void)data; + if (flag) + is_playing = 0; + else + is_playing = 1; +} +static void xset_row(void* data, int row) +{ + int newtime_ms = row_to_ms_round(row, rps); + curtime_ms = newtime_ms; + (void)data; +} +static int xis_playing(void* data) +{ + (void)data; + return is_playing; +} +#endif +static int rocket_update(){ + if(is_playing) curtime_ms += 16; + #if !defined( SYNC_PLAYER ) + int row = ms_to_row_round(curtime_ms, rps); + if (sync_update(device,row,&cb,0)) + sync_tcp_connect(device, "localhost", SYNC_DEFAULT_PORT); + #endif + return -1; +} +// sync stuff> + +static gboolean +on_render (GtkGLArea *glarea, GdkGLContext *context) +{ + glUseProgram(p); + float row_f = ms_to_row_f(curtime_ms, rps); + glProgramUniform1f(p, 0, curtime_ms/1000.0f); + glProgramUniform1f(p, 1, sync_get_val(s_tracks[0], row_f)); + glProgramUniform1f(p, 2, sync_get_val(s_tracks[1], row_f)); + glProgramUniform1f(p, 3, sync_get_val(s_tracks[2], row_f)); + glBindVertexArray(vao); + glVertexAttrib1f(0, 0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + rocket_update(); + return TRUE; +} + +static void on_realize(GtkGLArea *glarea) +{ + gtk_gl_area_make_current(glarea); + + device = sync_create_device("data/sync"); + for (int i = 0; i < 3; ++i) + s_tracks[i] = sync_get_track(device, s_trackNames[i]); + #if !defined( SYNC_PLAYER ) + sync_tcp_connect(device, "localhost", SYNC_DEFAULT_PORT); + cb.is_playing = xis_playing; + cb.pause = xpause; + cb.set_row = xset_row; + #endif + + // compile shader + GLuint f = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(f, 1, &shader_frag, NULL); + glCompileShader(f); + + #ifdef DEBUG + GLint isCompiled = 0; + glGetShaderiv(f, GL_COMPILE_STATUS, &isCompiled); + if(isCompiled == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(f, GL_INFO_LOG_LENGTH, &maxLength); + + char* error = malloc(maxLength); + glGetShaderInfoLog(f, maxLength, &maxLength, error); + printf("%s\n", error); + + exit(-10); + } + #endif + + GLuint v = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(v, 1, &vshader, NULL); + glCompileShader(v); + + #ifdef DEBUG + GLint isCompiled2 = 0; + glGetShaderiv(v, GL_COMPILE_STATUS, &isCompiled2); + if(isCompiled2 == GL_FALSE) { + GLint maxLength = 0; + glGetShaderiv(v, GL_INFO_LOG_LENGTH, &maxLength); + + char* error = malloc(maxLength); + glGetShaderInfoLog(v, maxLength, &maxLength, error); + printf("%s\n", error); + + exit(-10); + } + #endif + + // link shader + p = glCreateProgram(); + glAttachShader(p,v); + glAttachShader(p,f); + glLinkProgram(p); + + #ifdef DEBUG + GLint isLinked = 0; + glGetProgramiv(p, GL_LINK_STATUS, (int *)&isLinked); + if (isLinked == GL_FALSE) { + GLint maxLength = 0; + glGetProgramiv(p, GL_INFO_LOG_LENGTH, &maxLength); + + char* error = malloc(maxLength); + glGetProgramInfoLog(p, maxLength, &maxLength,error); + printf("%s\n", error); + + exit(-10); + } + #endif + + glProgramUniform2f(p, 0, CANVAS_WIDTH, CANVAS_HEIGHT); + glGenVertexArrays(1, &vao); + + // if you want to continuously render the shader once per frame + GdkGLContext *context = gtk_gl_area_get_context(glarea); + GdkWindow *glwindow = gdk_gl_context_get_window(context); + GdkFrameClock *frame_clock = gdk_window_get_frame_clock(glwindow); + + // Connect update signal: + g_signal_connect_swapped(frame_clock, "update", G_CALLBACK(gtk_gl_area_queue_render), glarea); + + // Start updating: + gdk_frame_clock_begin_updating(frame_clock); +} + +void _start() { + asm volatile("sub $8, %rsp\n"); + + typedef void (*voidWithOneParam)(int*); + voidWithOneParam gtk_init_one_param = (voidWithOneParam)gtk_init; + (*gtk_init_one_param)(NULL); + + GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL); + GtkWidget *glarea = gtk_gl_area_new(); + gtk_container_add(GTK_CONTAINER(win), glarea); + + g_signal_connect(win, "destroy", gtk_main_quit, NULL); + g_signal_connect(glarea, "realize", G_CALLBACK(on_realize), NULL); + g_signal_connect(glarea, "render", G_CALLBACK(on_render), NULL); + + gtk_widget_show_all (win); + + //gtk_window_fullscreen((GtkWindow*)win); + GdkWindow* window = gtk_widget_get_window(win); + GdkCursor* Cursor = gdk_cursor_new(GDK_BLANK_CURSOR); + gdk_window_set_cursor(window, Cursor); + + gtk_main(); + + asm volatile(".intel_syntax noprefix"); + asm volatile("push 231"); //exit_group + asm volatile("pop rax"); + // asm volatile("xor edi, edi"); + asm volatile("syscall"); + asm volatile(".att_syntax prefix"); + __builtin_unreachable(); + // return 0; +} diff --git a/src/track.c b/src/track.c new file mode 100644 index 0000000..e0bbe9c --- /dev/null +++ b/src/track.c @@ -0,0 +1,121 @@ +#include <stdlib.h> +#include <assert.h> +#include <math.h> + +#include "sync.h" +#include "track.h" +#include "base.h" + +static double key_linear(const struct track_key k[2], double row) +{ + double t = (row - k[0].row) / (k[1].row - k[0].row); + return k[0].value + (k[1].value - k[0].value) * t; +} + +static double key_smooth(const struct track_key k[2], double row) +{ + double t = (row - k[0].row) / (k[1].row - k[0].row); + t = t * t * (3 - 2 * t); + return k[0].value + (k[1].value - k[0].value) * t; +} + +static double key_ramp(const struct track_key k[2], double row) +{ + double t = (row - k[0].row) / (k[1].row - k[0].row); + t = pow(t, 2.0); + return k[0].value + (k[1].value - k[0].value) * t; +} + +double sync_get_val(const struct sync_track *t, double row) +{ + int idx, irow; + + /* If we have no keys at all, return a constant 0 */ + if (!t->num_keys) + return 0.0f; + + irow = (int)floor(row); + idx = key_idx_floor(t, irow); + + /* at the edges, return the first/last value */ + if (idx < 0) + return t->keys[0].value; + if (idx > (int)t->num_keys - 2) + return t->keys[t->num_keys - 1].value; + + /* interpolate according to key-type */ + switch (t->keys[idx].type) { + case KEY_STEP: + return t->keys[idx].value; + case KEY_LINEAR: + return key_linear(t->keys + idx, row); + case KEY_SMOOTH: + return key_smooth(t->keys + idx, row); + case KEY_RAMP: + return key_ramp(t->keys + idx, row); + default: + assert(0); + return 0.0f; + } +} + +int sync_find_key(const struct sync_track *t, int row) +{ + int lo = 0, hi = t->num_keys; + + /* binary search, t->keys is sorted by row */ + while (lo < hi) { + int mi = (lo + hi) / 2; + assert(mi != hi); + + if (t->keys[mi].row < row) + lo = mi + 1; + else if (t->keys[mi].row > row) + hi = mi; + else + return mi; /* exact hit */ + } + assert(lo == hi); + + /* return first key after row, negated and biased (to allow -0) */ + return -lo - 1; +} + +#ifndef SYNC_PLAYER +int sync_set_key(struct sync_track *t, const struct track_key *k) +{ + int idx = sync_find_key(t, k->row); + if (idx < 0) { + /* no exact hit, we need to allocate a new key */ + void *tmp; + idx = -idx - 1; + tmp = realloc(t->keys, sizeof(struct track_key) * + (t->num_keys + 1)); + if (!tmp) + return -1; + t->num_keys++; + t->keys = tmp; + memmove(t->keys + idx + 1, t->keys + idx, + sizeof(struct track_key) * (t->num_keys - idx - 1)); + } + t->keys[idx] = *k; + return 0; +} + +int sync_del_key(struct sync_track *t, int pos) +{ + void *tmp; + int idx = sync_find_key(t, pos); + assert(idx >= 0); + memmove(t->keys + idx, t->keys + idx + 1, + sizeof(struct track_key) * (t->num_keys - idx - 1)); + assert(t->keys); + tmp = realloc(t->keys, sizeof(struct track_key) * + (t->num_keys - 1)); + if (t->num_keys != 1 && !tmp) + return -1; + t->num_keys--; + t->keys = tmp; + return 0; +} +#endif diff --git a/src/track.h b/src/track.h new file mode 100644 index 0000000..fd59ded --- /dev/null +++ b/src/track.h @@ -0,0 +1,47 @@ +#ifndef SYNC_TRACK_H +#define SYNC_TRACK_H + +#include <string.h> +#include <stdlib.h> +#include "base.h" + +enum key_type { + KEY_STEP, /* stay constant */ + KEY_LINEAR, /* lerp to the next value */ + KEY_SMOOTH, /* smooth curve to the next value */ + KEY_RAMP, + KEY_TYPE_COUNT +}; + +struct track_key { + int row; + float value; + enum key_type type; +}; + +struct sync_track { + char *name; + struct track_key *keys; + int num_keys; +}; + +int sync_find_key(const struct sync_track *, int); +static inline int key_idx_floor(const struct sync_track *t, int row) +{ + int idx = sync_find_key(t, row); + if (idx < 0) + idx = -idx - 2; + return idx; +} + +#ifndef SYNC_PLAYER +int sync_set_key(struct sync_track *, const struct track_key *); +int sync_del_key(struct sync_track *, int); +static inline int is_key_frame(const struct sync_track *t, int row) +{ + return sync_find_key(t, row) >= 0; +} + +#endif /* !defined(SYNC_PLAYER) */ + +#endif /* SYNC_TRACK_H */ |