diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rwxr-xr-x | build.sh | 22 | ||||
-rw-r--r-- | src/main.c | 193 | ||||
-rw-r--r-- | src/shell.html | 82 |
4 files changed, 298 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6dd29b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin/
\ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..4b597bb --- /dev/null +++ b/build.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +cd ${0%/*} # go to project root + +FLAGS="-Wall -Wextra -g -pedantic" +RAYLIB_FLAGS="-lraylib -lm -lpthread -lGL -ldl -lrt -lX11" +RAYLIB_SRC="/usr/local/src/raylib/src" + +set -xe + +if ! [[ $1 == "web" ]] &> /dev/null; then + gcc -o bin/main src/main.c $FLAGS $RAYLIB_FLAGS +else + source emsdk_env.sh + + emcc -o bin/proc-gen.html src/main.c \ + $FLAGS -DPLATFORM_WEB -DRAYLIB_SRC="\"$RAYLIB_SRC/raylib.h\"" \ + $RAYLIB_SRC/libraylib.a \ + -I$RAYLIB_SRC/raylib.h \ + -s USE_GLFW=3 -s ASYNCIFY \ + --shell-file src/shell.html +fi diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..6119bd6 --- /dev/null +++ b/src/main.c @@ -0,0 +1,193 @@ +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> + +#ifdef PLATFORM_WEB + #include RAYLIB_SRC +#else + #include <raylib.h> +#endif + +typedef uint32_t u32; + +#define MOONS_CAP 4 +#define PLANETS_CAP 10 + +int SW = 1200; +int SH = 800; + +#define OFF_Y (7*SH/9) + +int sector_len = 16; +u32 seed = 0; + +typedef struct { + int diameter; + u32 color; + bool ring; + int moons[MOONS_CAP]; +} planet_t; + +typedef struct { + int diameter; + u32 color; +} star_t; + +star_t star_gen(); +void planets_gen(planet_t *planets); + +uint32_t lehmer(); +int rnd_int(int max, int min); + +#define HEX_TO_COL(col) {((col) >> 16) & 0xFF, \ + ((col) >> 8) & 0xFF, \ + (col) & 0xFF, 0xFF} + +int main(void) +{ + InitWindow(SW, SH, "Procedural Generation"); + SetTargetFPS(30); + SetWindowState(FLAG_WINDOW_RESIZABLE); + + int offset_x = 0; + int offset_y = 0; + + while (!WindowShouldClose()) + { + SW = GetScreenWidth(); + SH = GetScreenHeight(); + + int sectors_x = SW/sector_len; + int sectors_y = SH/sector_len; + + sector_len += (int)GetMouseWheelMove(); + if(sector_len <= 0) sector_len = 1; + + if(IsKeyDown(KEY_W)) offset_y -= 1; + if(IsKeyDown(KEY_A)) offset_x -= 1; + if(IsKeyDown(KEY_S)) offset_y += 1; + if(IsKeyDown(KEY_D)) offset_x += 1; + + static bool extra_info = false; + star_t info_star; planet_t info_planets[PLANETS_CAP]; + if(IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) extra_info = false; + + BeginDrawing(); + ClearBackground(BLACK); + + // gen each sector + for(int i = 0; i < sectors_x; i++) + for(int j = 0; j < sectors_y; j++) { + seed = ((i+offset_x) & 0xFFFF) << 16 | ((j+offset_y) & 0xFFFF); + if(rnd_int(25, 0) != 0) continue; + + star_t star = star_gen(); + + int x = i * sector_len + (sector_len/2); + int y = j * sector_len + (sector_len/2); + float diam = (float)star.diameter*sector_len/96; + + DrawCircle(x, y, diam, (Color)HEX_TO_COL(star.color)); + + // hover over star + if(GetMouseX()/sector_len == i && GetMouseY()/sector_len == j) { + DrawCircleLines(x, y, diam + 4, (Color)HEX_TO_COL(star.color)); + + // click on star + if(IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { + extra_info = true; + info_star = star; + planets_gen(info_planets); + } + } + } + + // extra info rec + if(extra_info) { + DrawRectangle(0, 2*SH/3, SW, SH/3, BLUE); + + // draw star + int body_offset = 50 + info_star.diameter; + DrawCircle(body_offset, OFF_Y, info_star.diameter, + (Color)HEX_TO_COL(info_star.color)); + body_offset += 90 + info_star.diameter; + + // draw planets + for(int i = 0; i < PLANETS_CAP; i++) { + if(info_planets[i].diameter == 0) continue; + + body_offset += info_planets[i].diameter; + DrawCircle(body_offset, OFF_Y, info_planets[i].diameter, + (Color)HEX_TO_COL(info_planets[i].color)); + + if(info_planets[i].ring) { + DrawCircleLines(body_offset, OFF_Y, + info_planets[i].diameter + 6, + (Color)HEX_TO_COL(info_planets[i].color)); + DrawCircleLines(body_offset, OFF_Y, + info_planets[i].diameter + 7, + (Color)HEX_TO_COL(info_planets[i].color)); + } + + // draw moons + int y_off = info_planets[i].diameter + 10; + for(int j = 0; j < MOONS_CAP; j++) { + if(info_planets[i].moons[j] == 0) continue; + + y_off += info_planets[i].moons[j]; + DrawCircle(body_offset, OFF_Y + y_off, + info_planets[i].moons[j], GRAY); + y_off += 10 + info_planets[i].moons[j]; + } + + body_offset += 50 + info_planets[i].diameter; + } + } + + DrawFPS(10, 10); + EndDrawing(); + } + CloseWindow(); +} + +star_t star_gen() +{ + star_t star; + star.diameter = rnd_int(80, 20); + star.color = rnd_int(0xFFFFFF, 0); + return star; +} + +void planets_gen(planet_t *planets) +{ + int n = rnd_int(PLANETS_CAP, 0); + for(int i = 0; i < PLANETS_CAP; i++) { + if(i >= n) { + planets[i].diameter = 0; + continue; + } + + planets[i].diameter = rnd_int(40, 10); + planets[i].color = rnd_int(0xFFFFFF, 0); + planets[i].ring = (rnd_int(5, 0) == 1); + + for(int j = 0; j < MOONS_CAP; j++) + planets[i].moons[j] = rnd_int(15, 0); + } +} + +uint32_t lehmer() +{ + seed += 0xe120fc15; + uint64_t tmp; + tmp = (uint64_t)seed * 0x4a39b70d; + uint32_t m1 = (tmp >> 32) ^ tmp; + tmp = (uint64_t)m1 * 0x12fad5c9; + uint32_t m2 = (tmp >> 32) ^ tmp; + return m2; +} + +int rnd_int(int max, int min) +{ + return (lehmer() % (max - min)) + min; +} diff --git a/src/shell.html b/src/shell.html new file mode 100644 index 0000000..2188465 --- /dev/null +++ b/src/shell.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<html lang="en-us"> + <head> + <meta charset="utf-8"> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>Pendulum</title> + <style> + .el { margin: 5px; } + div.el { float: left; } + textarea.el { font-family: monospace; width: 100%; } + canvas.el { border: 0px none; background-color: black; } + </style> + </head> + <body> + <div class="el" id="status">Downloading...</div> + + <div class="el"> + <canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> + </div> + + <textarea class="el" id="output" rows="12"></textarea> + + <script type='text/javascript'> + var statusElement = document.getElementById('status'); + + var Module = { + attachGLFWEventsToCanvas: true, + preRun: [], + postRun: [], + arguments: [], + print: (function() { + var element = document.getElementById('output'); + if (element) element.value = ''; // clear browser cache + return function(text) { + if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); + // These replacements are necessary if you render to raw HTML + //text = text.replace(/&/g, "&"); + //text = text.replace(/</g, "<"); + //text = text.replace(/>/g, ">"); + //text = text.replace('\n', '<br>', 'g'); + console.log(text); + if (element) { + element.value += text + "\n"; + element.scrollTop = element.scrollHeight; // focus on bottom + } + }; + })(), + canvas: (function() { + var canvas = document.getElementById('canvas'); + + // As a default initial behavior, pop up an alert when webgl context is lost. To make your + // application robust, you may want to override this behavior before shipping! + // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 + canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); + + return canvas; + })(), + setStatus: function(text) { + if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; + if (text === Module.setStatus.last.text) return; + var now = Date.now(); + Module.setStatus.last.time = now; + Module.setStatus.last.text = text; + statusElement.innerHTML = text; + }, + totalDependencies: 0, + monitorRunDependencies: function(left) { + this.totalDependencies = Math.max(this.totalDependencies, left); + Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); + } + }; + Module.setStatus('Downloading...'); + window.onerror = function() { + Module.setStatus('Exception thrown, see JavaScript console'); + Module.setStatus = function(text) { + if (text) console.error('[post-exception status] ' + text); + }; + }; + </script> + {{{ SCRIPT }}} + </body> +</html> |