diff options
| -rw-r--r-- | README.md | 2 | ||||
| -rwxr-xr-x | build.sh | 35 | ||||
| -rw-r--r-- | src/display.c | 19 | ||||
| -rw-r--r-- | src/display.h | 9 | ||||
| -rw-r--r-- | src/main.c | 55 | ||||
| -rw-r--r-- | src/shell.html | 109 | 
6 files changed, 196 insertions, 33 deletions
| @@ -1,3 +1,3 @@  ### Pendulum -This is a simple pendulum c program that uses raylib +This is a simple pendulum simulation in C that uses raylib. [Demo](https://batnako.net/demos/pendulum.html) @@ -7,9 +7,13 @@ FLAGS_DISPLAY="-lraylib -lm -lpthread -lGL -ldl -lrt -lX11"  SRC="src"  BIN="bin"  OBJ="obj" +  RUN=0  VALGRIND="" +WEB=0 +RAYLIB_SRC="/usr/local/src/raylib/src" #for web only +  function __run__ {      RUN=1  } @@ -25,6 +29,10 @@ function __clean__ {      kill $( ps -q $$ -o pgid= ) # exit  } +function __web__ { +    WEB=1 +} +  set -xe  if ! { [[ $# -eq 0 ]]; } 2> /dev/null @@ -36,11 +44,26 @@ fi  mkdir -p $BIN  mkdir -p $OBJ -gcc -c -o $OBJ/main.o      $SRC/main.c -gcc -c -o $OBJ/display.o   $SRC/display.c -gcc -o $BIN/main $OBJ/main.o $OBJ/display.o $FLAGS $FLAGS_DISPLAY - -if ! { [[ $RUN -eq 0 ]]; } 2> /dev/null +if { [[ $WEB -eq 0 ]]; } 2> /dev/null  then -    $BIN/main +    gcc -c -o $OBJ/main.o      $SRC/main.c +    gcc -c -o $OBJ/display.o   $SRC/display.c +    gcc -o $BIN/main $OBJ/main.o $OBJ/display.o $FLAGS $FLAGS_DISPLAY + +    if ! { [[ $RUN -eq 0 ]]; } 2> /dev/null +    then +        $BIN/main +    fi +else +    source emsdk_env.sh + +    emcc -o $BIN/pendulum.html $SRC/main.c $SRC/display.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 + +    # delete e line that blocks backspace and tab +    sed -i $(($(grep "keyCode === 8" $BIN/pendulum.js -n | cut -d : -f 1)+1))d $BIN/pendulum.js > /dev/null  fi diff --git a/src/display.c b/src/display.c index 2a46493..9ecb6cb 100644 --- a/src/display.c +++ b/src/display.c @@ -1,4 +1,9 @@ -#include <raylib.h> +#ifdef PLATFORM_WEB +  #include RAYLIB_SRC +#else +  #include <raylib.h> +#endif +  #include "display.h"  static dspl_createinfo info; @@ -7,7 +12,7 @@ void dspl_create(dspl_createinfo createinfo)  {      info = createinfo;  } -void dspl_start() +void dspl_start(void)  {      InitWindow(info.width, info.height, info.name);      SetTargetFPS(info.fps); @@ -22,21 +27,17 @@ void dspl_start()      }  } -void dspl_destroy() +void dspl_destroy(void)  {      CloseWindow();  }  void dspl_draw_circle(int cx, int cy, int r)  { -    int offsetx = (info.width/2); -    int offsety = (info.height/4); -    DrawCircle(offsetx + cx, offsety + cy, r, RED); +    DrawCircle(OFFSETX + cx, OFFSETY + cy, r, RED);  }  void dspl_draw_line(int x1, int y1, int x2, int y2, int c)  { -    int offsetx = (info.width/2); -    int offsety = (info.height/4); -    DrawLine(offsetx + x1, offsety + y1, offsetx + x2, offsety + y2 , (c == 0) ? BLUE : RED); +    DrawLine(OFFSETX + x1, OFFSETY + y1, OFFSETX + x2, OFFSETY + y2 , (c == 0) ? BLUE : RED);  } diff --git a/src/display.h b/src/display.h index 088feb7..1dadb0f 100644 --- a/src/display.h +++ b/src/display.h @@ -6,12 +6,15 @@ typedef struct dspl_createinfo {      int height;      char *name;      int fps; -    void (*update_func)(); +    void (*update_func)(void);  } dspl_createinfo; +#define OFFSETX (info.width/2) +#define OFFSETY (info.height/8) +  void dspl_create(dspl_createinfo info); -void dspl_start(); -void dspl_destroy(); +void dspl_start(void); +void dspl_destroy(void);  void dspl_draw_line(int x1, int y1, int x2, int y2, int c);  void dspl_draw_circle(int cx, int cy, int r); @@ -1,27 +1,36 @@  #include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h>  #include <math.h>  #include "display.h" -#define W 1600 -#define H 900 -#define FPS 1000 -#define SCALE 1000 -#define SWING_SCALE 15 +#define W 800 +#define H 600 + +#ifndef PLATFORM_WEB +  #define FPS 120 +#else +  #define FPS 60 +#endif + +#define SCALE 800 +#define CYCLES 5  #define RFPS 1/FPS  #define PI 3.141592654 +#define g -9.81f * SCALE -const float s = (PI/180 * 25); // rad -const float l = 0.5 * SCALE; // m -const int m = 7;  // kg -const float g = -9.81f * SCALE; // m/s^2 +float s = 25;   // starting agnle +float l = 0.5;  // lenght +float m = 0.01; // mass in kg  float t;  float v;  float a;  float secs = 0.0f; -int swings = 2 * SWING_SCALE; +int swings = 2 * CYCLES;  int has_reached_starting_amp(float old_t)  { @@ -34,17 +43,22 @@ int has_reached_starting_amp(float old_t)  void update()  { +    if(secs == 0.0f) { +        printf("\nStarting angle: %f", s/(PI/180)); +        printf("\nLenght:         %f", l/SCALE); +        printf("\nMass:           %f\n", m/SCALE); +    } +      float old_t = t;      a = (g/l) * sinf(t);      v += a * RFPS;      t += v * RFPS;      if(has_reached_starting_amp(old_t)) { -        puts("new swing");          swings += 1;      } -    if(swings >= 2 * SWING_SCALE) { -        printf("period: %f\n", secs/SWING_SCALE); +    if(swings >= 2 * CYCLES) { +        printf("period: %f\n", secs/CYCLES);          secs = 0.0f;          swings = 0;      } @@ -57,8 +71,21 @@ void update()      dspl_draw_circle(px, py, m);  } -int main(void) +int main(int argc, char **argv)  { +    if(argc != 1 && argc != 4) { +        puts("Please provide either 0 or 3 arguments:\n\t1st is starting angle in degrees\n\t2nd is lenght in meters\n\t3rd is mass in kilograms"); +        return 1; +    } + +    float arg_s = strtof(argv[1], NULL); +    float arg_l = strtof(argv[2], NULL); +    float arg_m = strtof(argv[3], NULL); + +    s = ((arg_s == 0.0f) ? s : arg_s) * PI/180; +    l = ((arg_l == 0.0f) ? l : arg_l) * SCALE; +    m = ((arg_m == 0.0f) ? m : arg_m) * SCALE; +      t = s;      v = 0;      a = 0; diff --git a/src/shell.html b/src/shell.html new file mode 100644 index 0000000..f8e31a8 --- /dev/null +++ b/src/shell.html @@ -0,0 +1,109 @@ +<!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> + +    <div class="el"> +      <label>Angle (deg):</label> <br> +      <input type="text" id="s_input"> <br> +      <label>Lenght (m):</label> <br> +      <input type="text" id="l_input"> <br> +      <label>Mass (kg):</label> <br> +      <input type="text" id="m_input"> <br> +      <button onclick="loadParams();">Submit</button> +    </div> + +    <textarea class="el" id="output" rows="12"></textarea> + + +    <script type='text/javascript'> +      let params = new URLSearchParams(location.search); +      let s = params.get('s'); s = (s == null) ? 0 : s; +      let l = params.get('l'); l = (l == null) ? 0 : l; +      let m = params.get('m'); m = (m == null) ? 0 : m; + +      document.getElementById('s_input').value = s; +      document.getElementById('l_input').value = l; +      document.getElementById('m_input').value = m; + +      function loadParams() { +        let ns = document.getElementById('s_input').value; +        let nl = document.getElementById('l_input').value; +        let nm = document.getElementById('m_input').value; +        window.location.href = `?s=${ns}&l=${nl}&m=${nm}`; +      } + +      var statusElement = document.getElementById('status'); + +      var Module = { +        attachGLFWEventsToCanvas: true, +        preRun: [], +        postRun: [], +        arguments: [s, l, m], +        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> | 
