Git Product home page Git Product logo

reprocessing's Introduction

Reprocessing

Build Status Build status

This is a high-level drawing library, inspired by Processing, allowing you to write code that'll run on the web (using WebGL).

Example

The interactive docs are the simplest way to try reprocessing. (They are generated using redoc!).

The 2nd simplest way to try is to clone reprocessing-example.

See below for projects using Reprocessing!

Getting Started

npm install reprocessing

Code Example

Clone reprocessing-example and follow instructions there to setup a new project.

open Reprocessing;

let setup = (env) => {
  Env.size(~width=200, ~height=200, env);
};

let draw = (_state, env) => {
  Draw.background(Constants.black, env);
  Draw.fill(Constants.red, env);
  Draw.rect(~pos=(50, 50), ~width=100, ~height=100, env)
};

run(~setup, ~draw, ());

Build

npm run build

This will draw a simple red square on a black background. Compare this to reglexampleproject, which takes 200+ lines to do the exact same thing. This difference is even more notable on bigger projects. Check out the code for a draggable red square.

Demo

There are a couple demos inside examples. Run npm i to install all deps and npm run build to build to JS (default). Open index.html in safari (or use python -m SimpleHTTPServer 8000 to spawn a static server and go to localhost:8000 in chrome).

See below for examples!

FAQs

Where do I find x function?

There are a few modules in Reprocessing that store most functions you will want to use. The best way to find one is to use the search on the docs site: https://schmavery.github.io/reprocessing/

In general:

  • Draw contains functions that draw to the screen (and affect drawing), like rect and image.
  • Env contains functions involving the environment (or window) you are running in. For example, mouse and size.
  • Utils contains many static helper functions from Processing such as lerp and dist.
  • Constants contains some mathematical and color-related constants, like pi and green.

Why do some functions have an "f" at the end?

Several utility functions that would otherwise accept either an integer or a float in Processing expose a version with an f suffix, which supports floats. Ex: random vs randomf. This lets you use whichever you prefer without needing to convert all the time.

When do I run loadImage or loadFont?

It is best to run these functions in the setup function. They are fairly expensive to run and setup is usually the easiest place to load your assets once. Then you can keep a reference to them in your state and draw them as many times as you want!

How do I use different fonts when drawing text?

There is a default font in Reprocessing that will be automatically used if you use Draw.text without providing a font. However, you frequently want to have your own font!

The story for using fonts in your Reprocessing app is still under some development to make it nicer. Right now we have support for writing text in a font defined in the Angel Code font format. This is basically a bitmap of packed glyph textures along with a text file that describes it.

★★★ Check out font-generator for a tool that can take any truetype or opentype font and output font files that Reprocessing can use.

In order to use a font once you have the files:

let font = Draw.loadFont(~filename, env);
Draw.text(~font, ~body="Test!!!", ~pos=(10, 10), env);

Why is there no support for 3D drawing?

The original goal for reprocessing was to make something extremely easy to use and build real (2d) games and experiences with in ReasonML. Processing's 2D API does an amazing job at making graphics approachable. It would be really neat to be able to extend this to 3D creations but I do tend to feel that the 3D API is significantly more complex in some ways. It adds several new concepts such as 3d shapes, texture/materials/lighting, and we'd need to extend several functions to optionally support a third dimension. It also doesn't let you avoid the matrix functions which can be counterintuitive and camera logic gets more involved. We may consider trying to add support in the future but it currently isn't on the roadmap.

Some Differences from Processing

  • For state management, we encourage the use of the state value that Reprocessing manages for the user. To use this, decide on a datatype representing the state and return the initial value from setup. This will be persisted behind the scenes and passed to every callback (such as draw and mouseDown). Each callback should return the new value of the state (or the old value if it doesn't change).

  • There are no built-in variables like width and mouseX. Instead, these are functions that are called, passing in an environment object that is always provided.

open Reprocessing;
let draw = (state, env) => {
  let w = Env.width(env);
  print_endline("The current width is:" ++ string_of_int(w))
};
  • The builtin map function is called remap instead to avoid confusion with the well-known List.map function which maps over a list of values. As, according to the Processing docs, this function "Re-maps a number from one range to another.", this naming seems appropriate.

  • Points are expressed as tuples. Instead of exposing a mouseX and mouseY, there is a mouse, which is a tuple of x and y values.

open Reprocessing;
let draw = (state, env) => {
  let (x, y) = Env.mouse(env);
  print_endline("The current mouse position is:" ++ (string_of_int(x) ++ string_of_int(y)))
};

Projects using Reprocessing

Talks and articles about Reprocessing

Please open a PR to add any cool projects, talks or articles about Reprocessing that are missing above!

reprocessing's People

Contributors

bsansouci avatar ekosz avatar glennsl avatar jaredly avatar rawtoast avatar ryanartecona avatar schmavery avatar sodacookie avatar sscaff1 avatar wokalski avatar zploskey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reprocessing's Issues

Add ability to create and draw on images

It's not very difficult to run into performance issues when running reprocessing on mobile web on Android, and we'd like to ensure that Reprocessing isn't too often the bottleneck.
After talking to @jaredly and @Schmavery it seems like a powerful tool would be to allow saving draw calls onto a texture which could then be drawn in one shot (2 triangles).

This would look like:

let init = (env) => {
  { background: Draw.createTexture() }
};

let render = (state, env) => {
  /* This function would check if state.background is "null" and call the function if yes, otherwise it'll do nothing. This allows the user to write code with the mindset that everything inside render is executed at all points in time. Also it is a very easy upgrade from the draw calls you'd do normally to this. */
  Draw.updateTextureIfNull(state.background, (env) => {
    /* The env would be automatically set such that all draw calls inside here would be drawing onto the   
       texture buffer passed to updateTextureIfNull. */
    Draw.drawRect(..., env);
  });
  Draw.drawTexture(state.background);
};

Another idea is based on the observation that 2D games generally have different and separate layers, such that most objects in one layer stays in that layer, even if it moves inside that layer.
We could image having a first class layer concept which would allow the user to create a layer, make draw calls that are associated with the layer and then draw the layer.
I'm not exactly sure what this would look like. It might be a very similar API but would be higher level than "textures".

Linux support

Unfortunately reasongl doesn't seem to be building on linux. Happy to help anyone who wants to try and figure out a solution to this, otherwise, hope I do soon.
bsansouci/reasongl#2

Stuff that gets drawn during setup flickers

@bsansouci any ideas

example:

open Reprocessing;
open P;
open PUtils;

let setup env => {
  size env 600 600;
  fill env (color 0 255 0);
  rect env 10 10 300 300;
};

let draw user env => {
  fill env (color 255 0 0);
  rect env 100 100 300 300;
  user
};

ReProcessor.run ::setup ::draw ();

Green square flickers and red one doesn't. Are we somehow clearing the screen and redrawing... seems craaazy.

Eh... on web the green doesn't show up at all.

I probably copy pasted the rect code without understanding exactly how it works.

The arc implementation is janky

image

^ in the middle is supposed to be 4 even quarters of a pie, w/ no space between them. Also the pink ring is done w/ ellipse -- there's not supposed to be a gap.

image

and this is supposed to be two halves of a pie.

image

also see the overlap ^ where the dot on the right is brighter. This is an ellipse that's semitransparent.

cc @bsansouci

Cleanup API

  • Expose everything from one module Reprocessing. This should help with files conflicting with those in the local project scope. General proposed structure:
  • Reprocessing
    • run function
    • Env (alternate names: Draw, P)
      • Contains functions that require env. Usually these draw, but not always. (ex: rect, line, mousePressed)
    • Utils
      • Contains (mostly) stateless utility functions that don't require env. (ex: lerp, dist, noise)
    • Constants
      • Contains constants exposed by processing. (ex: pi, white, black)

Alternately, Utils and Env could be merged if that's more intuitive. I'd love to keep Utils separate (and stateless), but I'm tending towards merging them, especially since there might be a bit of a discoverability problem here, where it can be hard for users to know what will require env while they're looking for a particular function. No idea what to call the merged module. We could even just shove them all into the Reprocessing namespace, though then opening that module puts a loooot of stuff into the namespace (and it puts it right next to run, which is fairly different from the other functions). In this case, it would probably be best for people to just alias Reprocessing to something small and explicitly qualify all accesses to the internal functions.

  • Labelled arguments #20
  • Add docs
  • Remove builtin OCaml functions from Utils when they are named the same in OCaml. Open to suggestion here. (ex: max, min, sqrt, sin)

Can't build native or bytecode versions due to problem with tsdl

I've seen this and so has ryyppy on discord. Repros on yarn and npm.

Bytecode:

schmave ~/git/reprocessing 18s → bsb-mw -backend bytecode
[8/8] Building src/RGLInterface.mlast.d
[5/5] Building lib.cma
[2/2] Building fake_src/sdl_index.mlast.d
[2/2] Building lib.cma
[3/3] Building build.ninja
make: Nothing to be done for `lib'.
[2/2] Building lib.cma
FAILED: lib.cma
/Users/schmave/Documents/git/reprocessing/node_modules/bs-platform/bin/bsb_helper.exe -add-ocaml-dependency bigarray -add-ocaml-dependency dynlink -add-ocaml-dependency nums -add-ocaml-dependency str -add-ocaml-dependency threads -add-ocaml-dependency unix -w -30-40+6+7+27+32..39+44+45+101  -bs-super-errors   -I /Users/schmave/Documents/git/reprocessing/node_modules/sdl2/lib/ocaml/bytecode -I src  src/tsdl_new.cmo -pack-bytecode-library

  We've found a bug for you!
  (No file name)

  Error while linking src/tsdl_new.cmo:
The external function `TSDL_GetError' is not available

ninja: build stopped: subcommand failed.
Failure: /Users/schmave/Documents/git/reprocessing/node_modules/bs-platform/bin/ninja.exe
 Location: /Users/schmave/Documents/git/reprocessing/node_modules/Tsdl/lib/bs/bytecode
schmave ~/git/reprocessing 1s →

Native:

schmave ~/git/reprocessing 0s → bsb-mw
[8/8] Building src/RGLInterface.mlast.d
[5/5] Building lib.cmxa
[2/2] Building fake_src/sdl_index.mlast.d
[2/2] Building lib.cmxa
[3/3] Building build.ninja
ocamlopt.opt -c -ccopt -I -ccopt ../sdl2/include/ src/tsdl_new.c
[2/2] Building lib.cmxa
FAILED: lib.cmxa
/Users/schmave/Documents/git/reprocessing/node_modules/bs-platform/bin/bsb_helper.exe -add-ocaml-dependency bigarray -add-ocaml-dependency dynlink -add-ocaml-dependency nums -add-ocaml-dependency str -add-ocaml-dependency threads -add-ocaml-dependency unix -w -30-40+6+7+27+32..39+44+45+101  -bs-super-errors   -I /Users/schmave/Documents/git/reprocessing/node_modules/sdl2/lib/ocaml/native -I src  src/tsdl_new.cmx -pack-native-library
Undefined symbols for architecture x86_64:
  "_TGetTimeDiff", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_BlitSurface", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_CreateWindow_native", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_Delay", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_DestroyWindow", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GL_CreateContext", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GL_GetDrawableSize", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GL_MakeCurrent", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GL_SetAttribute", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GL_SwapWindow", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GetDisplayDPI", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GetError", referenced from:
      .L101 in tsdl_new.o
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GetPerformanceCounter", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GetWindowSize", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_GetWindowSurface", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_Init", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_LoadBMP", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_PollEvent", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_Quit", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_SetWindowSize", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_TSDL_UpdateWindowSurface", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
  "_T_or", referenced from:
      _camlTsdl_new__4 in tsdl_new.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

  We've found a bug for you!
  caml_startup

  Error during linking

ninja: build stopped: subcommand failed.
Failure: /Users/schmave/Documents/git/reprocessing/node_modules/bs-platform/bin/ninja.exe
 Location: /Users/schmave/Documents/git/reprocessing/node_modules/Tsdl/lib/bs/native

Errors in native/bytecode

I haven't been able to diagnose the cause of this yet, but the rain demo doesn't run for me in native/byte.

I get Fatal error: exception Invalid_argument("index out of bounds").

I've also gotten Bus error: 10, but that's even less reproducible.

Can't run bytecode or native

`❯ ./lib/bs/bytecode/indexhot.byte

dyld: Library not loaded: /Users/Jack/Desktop/regl/node_modules/sdl2/libSDL2-2.0.0.dylib
Referenced from: /Users/Jack/Desktop/reprocessing-example/./lib/bs/bytecode/indexhot.byte
Reason: image not found
[1] 79641 abort ./lib/bs/bytecode/indexhot.byte`

same error for byte and native, not sure why it's pointing to a regl directory?

Support keyboard events

The following Processing functionality:
key
keyCode
keyPressed()
keyPressed
keyReleased()
keyTyped()

build:web "missing script"

hi, i am excited about this project, it is getting me to try out Reason. :-) but, clueless newb here...

  • ubuntu 16.04
  • mkdir Test && cd Test
  • npm init
  • npm install --save schmavery/reprocessing (er, is it bad to use that flag? but should i not maintain a dependency on reprocessing somehow?)
  • i created ./src/Test.re
  • npm run build:web (like the README.md told me to)
  • npm ERR! missing script: build:web

when i look at your https://github.com/Schmavery/reprocessing/blob/master/package.json I do not see build:web in there as a script, if that is relevant? although "npm run build" doesn't work for me either. (what is the diff between "build" vs. "build:web" anyhoo?)

Linux 4.4.0-112-generic
argv "/usr/bin/node" "/usr/bin/npm" "run" "build:web"
node v9.5.0
npm v5.6.0

Better perf on web editor environment

@bsansouci did an awesome job building a reprocessing web demo environment, but unfortunately it's very slow and blocks the UI for 5-10 seconds while compiling, so we can't really show it off. Opening this issue to track progress towards trying to fix this. It's possible that the only approach is to have a server-side compiler doing the work but this would make me sad 😢

Putting it on a server might also be an ok stopgap solution.

Things to try:

  • Getting bsc to compile using bsc.
  • Given the first, optimize bsc stdlib (map etc).
  • Fiiine we'll put it on a server.

Update: The solution we went for was compiling reprocessing to a standalone JS lib and then browserifying it and shoving a reference to it onto the dom. Then we create a bsc externals file that exposes the same reprocessing interface. Instead of concatenating all of bspacked reprocessing to the user program before building (which took a long time), we just attach this small (~200 line) externals file. This builds way faster.

Manage deps

The #bsb-support-new branch has very fast install times (~5 min npm install, 1s make-world) with not too many dependencies. It's tested to work with the latest supported reason-cli.
There is still a dependency on:

  • pkg-config

Artifact when rendering textures

let setup env => {
  size env 640 360;
  loadImage env "assets/img_test.png"
};

let draw img env => {
  background env (color 230 230 250);
  image env img 50 50;
  img
};

ReProcessor.run ::setup ::draw ();

screen shot 2017-01-03 at 4 41 41 pm

Add some helpers for handling key presses

When writing some interactive demo or game, I frequently end up having to create some record in user code to track which keys are being pressed (one common example is when moving things with the arrow keys).
Example (with setup and run functions omitted for brevity) :

type stateT = {pos: (float, float), left: bool, right: bool};

let keyPressed state env => switch (Env.keycode env) {
  | Left => {...state, left: true}
  | Right => {...state, right: true}
}

let keyReleased state env => switch (Env.keycode env) {
  | Left => {...state, left: false}
  | Right => {...state, right: false}
}

let getDirection state => switch state {
  | {left: true, right: false} => -1.
  | {left: false, right: true} => 1.
  | _ => 0.
};

let draw state env => {
  Draw.rect pos::state.pos height::20. width::20. env;
  let (x, y) = state.pos;
  {...state, pos: (x +. ((getDirection state) *. 5.), y)}
}

This seems like an awful lot of boilerplate just to get something moving left and right with the arrow keys. It gets even more complicated if I want some things to happen only when the key is initially pressed.

Unity (and other libs) provide helper functions that track internally the up or down state of all keys and allow you to query them at any time.
Unity provides 3 helpers:

Input.GetKey(key); // True if key is currently held down
Input.GetKeyDown(key); // True during the frame the user starts pressing down the key
Input.GetKeyUp(key); // True during the frame the user releases the key

We could implement these in Reprocessing as the following (to keep consistency with existing event handling function names):

Env.key key;
Env.keyPressed key;
Env.keyReleased key;

You can then write the initial example as follows:

type stateT = (float, float);

let getDirection env => switch (Env.key Left, Env.key Right) {
  | (true, false) => -1.
  | (false, true) => 1.
  | _ => 0.
};

let draw (x, y) env => {
  Draw.rect pos::(x, y) height::20. width::20. env;
  (x +. ((getDirection env) *. 5.), y)
}

Native/bytecode executables segfault on Linux when running on a Wayland compositor

This happens every time. Here's the log from a clean build of the example repo:

zach@znbk:~/src/reprocessing-example$ npm run build

> reprocessing-example@ build /home/zach/src/reprocessing-example
> bsb -make-world

[2/2] Building fake_src/sdl_index.mlast.d
[2/2] Building lib.cma
[4/4] Building run_build_script
[3/3] Building lib.cma
[4/4] Building run_build_script
[3/3] Building lib.cma
[18/18] Building run_build_script
[10/10] Building lib.cma
[42/42] Building src/Reprocessing_Internal.mlast.d
[22/22] Building lib.cma
ninja: Entering directory `lib/bs/bytecode'
[4/4] Building src/IndexHot.mlast.d
[3/3] Building indexhot.byte
zach@znbk:~/src/reprocessing-example$ npm run start

> reprocessing-example@ start /home/zach/src/reprocessing-example
> ./lib/bs/bytecode/indexhot.byte

Rebuilding hotloaded module
Succesfully changed functions
Segmentation fault (core dumped)

Note this happens almost immediately, no chance to edit anything.

Labeled functions

Does it make sense to expose labeled functions as the public API?
I really like the ergonomics of labeled args for this kind of UI programming

let rectf x y width height env => /* ... */

let rectf ::x ::y ::width ::height env => /* ... */

Rendering non-power-of-2 images doesn't work on web.

Looks like this (black squares instead of images)
screenshot 2017-02-27 09 03 52

And we get errors in the console:

WebGL: drawElements: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete', or it is a float/half-float type with linear filtering and without the relevant float/half-float linear extension enabled.

Make sure install process is super clean.

A couple issues here

  • Push Pmod_extension fix to refmt (this fix @bsansouci)
  • Get the PR merged...
  • Make sure matchenv ppx gets added to .merlin automatically.
  • Publish recent changes to regl in order to stop merlin from complaining about types (this). (@bsansouci)
  • Update docs, clean up api
  • Test using reprocessing as a dependency.

Solve the mystery of cross-platform color display

Will fill this with more details and examples later tonight, but basically the idea is that web and native seem to display colors differently.

You can see this by building https://github.com/bsansouci/ludum-dare-40 to web and native and looking at the transition between the trees and outer background. This difference should be much more obvious on one platform (there's also the fact that it's different at all -- for some reason setting it to the pixel color values in the image didn't work).

image

Arc rendering is broken when scaled

Draw.scale(~x=1.2, ~y=1.2, env);
/* do an arc */

The circle is in the right place, but the one of the arcs drawn is quite sad. Also the 4 dots in the upper left are not supposed to be there.

image

Missing license

In the spirit of Open Source, I implore you to consider adding an appropriate license to the project. As it is, the project must be considered proprietary and can't be used without first asking for your permission.

I'd recommend an MIT license. It's what reprocessing.js and most Reason projects use.
See https://help.github.com/articles/licensing-a-repository/ for more information.

Issue with ellipse and stroke

When I comment out noStroke env for the rain demo, I get a big slowdown and eventually an Fatal error: exception Invalid_argument("index out of bounds") (only on native, and web just happily continues but at a low framerate).

Improve web environment

There are a couple things we could still improve

  • Support reason v3!
  • Add refmt ability (what's peoples' favourite shortcut?)
  • Cleanup opengl contexts, right now we get a warning in the console after a couple of recompiles. Maybe we can fix this the same way @bsansouci implemented cancelling the setTimeout?

Also:

  • Add ability to easily build new versions of bsc/refmt (copying them from an existing repo that does this is fine 😄)
  • Travis autodeploy???

Make demo page pretty

Can we get some gh-pages demos so that people don't need to install to see what you can do with very little code?

Support curves

Tracking support for bezier() and curve(). We can skip begin/endContour and begin/endShape for now.

cc @SodaCookie

Generate Reprocessing_Ext

This is a file that is used for the web environment to allow user code to use a prebuilt version of reprocessing. Essentially it allows us to bundle reprocessing separately from the user app and shove it onto window, where it can then be "linked" to using an interface file which is all externals.

Very cool and currently very hacky and handwritten, but it would be great if this sort of thing could be easier at some point.

Here's a slightly outdated version of the file:
https://github.com/Schmavery/reprocessing/blob/master/webenv-artifacts/Reprocessing_Ext.re

Building using BuckleScript

I saw that all examples using reprocessing are using bsansouci/bsb-native instead of normal BuckleScript. I'm interested in building only for web. Is it possible to build it using normal bsb -make-world without entries in .bsconfig.json and bsansouci/bsb-native as bs-platform?

When I wanted to play with this library I've just went with:

npm install schmavery/reprocessing

to add it to existing project in which I was playing with Reason in general. After the build fail there was this error:

[1/4] Building src/events.mlast
FAILED: src/events.mlast
/Users/baransu/Documents/Reason/game-test/node_modules/bs-platform/lib/bsc.exe    -w -30-40+6+7+27+32..39+44+45+101-44 -nostdlib -I '/Users/baransu/Documents/Reason/game-test/node_modules/bs-platform/lib/ocaml' -no-alias-deps -color always -c -o src/events.mlast -bs-syntax-only -bs-binary-ast /Users/baransu/Documents/Reason/game-test/node_modules/Reasongl/src/events.ml
File "/Users/baransu/Documents/Reason/game-test/node_modules/Reasongl/src/events.ml", line 1, characters 18-22:
Error: Conditional expression type mismatch (bool,string)
[2/4] Building src/reasongl.mlast
FAILED: src/reasongl.mlast
/Users/baransu/Documents/Reason/game-test/node_modules/bs-platform/lib/bsc.exe    -w -30-40+6+7+27+32..39+44+45+101-44 -nostdlib -I '/Users/baransu/Documents/Reason/game-test/node_modules/bs-platform/lib/ocaml' -no-alias-deps -color always -c -o src/reasongl.mlast -bs-syntax-only -bs-binary-ast /Users/baransu/Documents/Reason/game-test/node_modules/Reasongl/src/reasongl.ml
File "/Users/baransu/Documents/Reason/game-test/node_modules/Reasongl/src/reasongl.ml", line 1, characters 18-22:
Error: Conditional expression type mismatch (bool,string)
ninja: error: rebuilding 'build.ninja': subcommand failed
Failure: /Users/baransu/Documents/Reason/game-test/node_modules/bs-platform/lib/ninja.exe
 Location: /Users/baransu/Documents/Reason/game-test/node_modules/Reasongl/lib/bs
>>>> Start compiling
Rebuilding since just get started
ninja: Entering directory `lib/bs'
[1/1] Building src/index.cmj
FAILED: src/index.cmj /Users/baransu/Documents/Reason/game-test/src/index.bs.js src/index.cmi
/Users/baransu/Documents/Reason/game-test/node_modules/bs-platform/lib/bsc.exe -bs-package-name reason-scripts  -bs-package-output es6:src -bs-assume-no-mli -bs-no-builtin-ppx-ml -bs-no-implicit-include -I /Users/baransu/Documents/Reason/game-test/node_modules/reprocessing/lib/ocaml -I src  -w -30-40+6+7+27+32..39+44+45+101 -bs-suffix -nostdlib -I '/Users/baransu/Documents/Reason/game-test/node_modules/bs-platform/lib/ocaml' -bs-super-errors -no-alias-deps -color always -bs-re-out -bs-super-errors -o src/index.cmj -c  src/index.mlast

  We've found a bug for you!
  /Users/baransu/Documents/Reason/game-test/src/index.re 4:6-17

  2 │ Js.log("boooom Hello world");
  3 │
  4 │ open Reprocessing;
  5 │
  6 │ let setup = env => Env.size(~width=600, ~height=600, env);

  The module or file Reprocessing can't be found.

  - If it's a third-party dependency:
    - Did you list it in bsconfig.json?
    - Did you run `bsb` instead of `bsb -make-world`
      (latter builds third-parties)?
  - Did you include the file's directory in bsconfig.json?

It would be great to have more info about it in README.md. Why not normal bsb and why forming reprocessing-example is the best solution when starting.

Make reprocessing build again

Recent conversion of regl to use esy has broken reprocessing.
Working on getting it building again, but we can't just use all the existing #esy forks of dependencies because we have some of our own forks.

  • rebel#add-env-vars
  • matchenv esy fork needs to be created
  • Update reprocessing docs
  • Update reprocessing package.json

Support matrix operations

We currently have no equivalent to any of the Processing matrix operations. I would like to get a few of these before we "release".
popMatrix()
pushMatrix()
resetMatrix()
rotate()
scale()
translate()

Unfortunately due to our current rendering strategy, we would either have to flush on pop/resetMatrix, or we'd have to do this computation on the CPU. I'd tend towards the second as the better option, but I'm open to suggestions.

Drawing interface design

Hello! Thank you for this excellent library. I had some thoughts on API design that I'd love to discuss.

The original processing library works by mutating some global state.

pushMatrix();
translate(xSize, xSize, env);
rotate(45);
translate(xSize, ySize);
rect(xSize, ySize, env);
popMatrix(env)

In this library we have removed the global mutable state by passing around an env data structure.

Draw.pushMatrix(env);
Draw.translate(~x=xSize, ~y=xSize, env);
Draw.rotate(45, env);
Draw.translate(~x=xSize, ~y=ySize, env);
Draw.rect(~width=xSize, ~height=ySize, env);
Draw.popMatrix(env);

This is great because we've removed the global mutable state, but we still have localised mutable state and an API that is near identical to the procedural Java-style Processing API.

I'd like to propose that we remove the env state and adopt a pure functional and composable API.

Peter Henderson's 1982 paper "Functional Geometry" (here explained in John Hughes and Mary Sheeran's Lambda Days keynote https://youtu.be/1qBHf8DrWR8?t=1030) shows us how we build an equally powerful interface with just pure functions.

Elm's Graphics library (which predates Elm the language, interestingly) provides a similar API.

The above code re-designed could look something like this:

let shape =
  Draw.rect(~width=xSize, ~height=ySize)
  |> Draw.translate(~x=xSize, ~y=xSize)
  |> Draw.rotate(45)
  |> Draw.translate(~x=xSize, ~y=ySize);
Draw.render(shape);

Here Draw.rect doesn't plot a rectangle, instead it just returns a data shape structure. Each function that sets a colour, changes the drawing position, or transforms the drawing just immutably update that structure. Finally we give it to a render function which iterates the data structure and then mutates the canvas or whatever we're drawing to.

To me this seems like a much friendlier API. The definition of the drawing has been split from the implementation, and we can use all the nice properties of persistent immutable data structures that we enjoy elsewhere in our Reason code.

Thanks for reading! What are you thoughts? :)

Missing files after npm install?

Following up after #34, I ran into some trouble after doing npm update Reprocessing.

My bsb -clean-world -make-world -w gave me this error:

[1/18] Building src/Reprocessing_ClientWrapper.c...ssing_ClientWrapper.js src/Reprocessing_ClientWrapper.cmi
FAILED: src/Reprocessing_ClientWrapper.cmj /Users/ryanartecona/Code/Reason/fitzhugh/node_modules/Reprocessing/lib/js/src/Reprocessing_ClientWrapper.js src/Reprocessing_ClientWrapper.cmi
/Users/ryanartecona/Code/Reason/fitzhugh/node_modules/bs-platform/bin/bsc.exe -bs-package-name Reprocessing  -bs-package-output commonjs:lib/js/src -bs-assume-no-mli -bs-no-builtin-ppx-ml -bs-no-implicit-include -I /Users/ryanartecona/Code/Reason/fitzhugh/node_modules/ReasonglInterface/lib/ocaml -I /Users/ryanartecona/Code/Reason/fitzhugh/node_modules/ReasonglWeb/lib/ocaml -I /Users/ryanartecona/Code/Reason/fitzhugh/node_modules/ReasonglNative/lib/ocaml -I src  -nostdlib -I '/Users/ryanartecona/Code/Reason/fitzhugh/node_modules/bs-platform/lib/ocaml' -no-alias-deps -color always -w -40+6+7+27+32..39+44+45 -o src/Reprocessing_ClientWrapper.mlast -c  src/Reprocessing_ClientWrapper.mlast
File "/Users/ryanartecona/Code/Reason/fitzhugh/node_modules/Reprocessing/src/Reprocessing_ClientWrapper.re", line 1, characters 11-25:
Error: Unbound module Gl
[4/18] Building src/Reprocessing_Events.cmj /Use...js/src/Reprocessing_Events.js src/Reprocessing_Events.cmi
ninja: build stopped: subcommand failed.

And my webpack was also unhappy:

ERROR in ./lib/js/src/main.js
Module not found: Error: Can't resolve 'Reprocessing/lib/js/src/reprocessing.js' in '/Users/ryanartecona/Code/Reason/fitzhugh/lib/js/src'
 @ ./lib/js/src/main.js 6:29-79
 @ multi (webpack)-dev-server/client?http://localhost:8000 ./lib/js/src/main

ERROR in ./lib/js/src/main.js
Module not found: Error: Can't resolve 'Reprocessing/lib/js/src/reprocessing_Env.js' in '/Users/ryanartecona/Code/Reason/fitzhugh/lib/js/src'
 @ ./lib/js/src/main.js 7:29-83
 @ multi (webpack)-dev-server/client?http://localhost:8000 ./lib/js/src/main

ERROR in ./lib/js/src/main.js
Module not found: Error: Can't resolve 'Reprocessing/lib/js/src/reprocessing_Draw.js' in '/Users/ryanartecona/Code/Reason/fitzhugh/lib/js/src'
 @ ./lib/js/src/main.js 8:29-84
 @ multi (webpack)-dev-server/client?http://localhost:8000 ./lib/js/src/main

ERROR in ./lib/js/src/main.js
Module not found: Error: Can't resolve 'Reprocessing/lib/js/src/reprocessing_Constants.js' in '/Users/ryanartecona/Code/Reason/fitzhugh/lib/js/src'
 @ ./lib/js/src/main.js 9:29-89
 @ multi (webpack)-dev-server/client?http://localhost:8000 ./lib/js/src/main
webpack: Failed to compile.

Looking into it a tiny bit, it appears those files are indeed missing inside my node_modules dir:

tree node_modules/Reprocessing ``` $ tree node_modules/Reprocessing node_modules/Reprocessing/ ├── README.md ├── assets │   ├── font │   │   ├── font.fnt │   │   └── font.png │   └── img_test.png ├── bsconfig.json ├── deploy.sh ├── examples │   ├── index.re │   ├── noise.re │   └── redsquare.re ├── index.html ├── lib │   ├── bs │   │   ├── build.ninja │   │   └── src │   │   ├── Reprocessing.mlast │   │   ├── Reprocessing.mlast.d │   │   ├── Reprocessing.mliast │   │   ├── Reprocessing.mliast.d │   │   ├── Reprocessing_ClientWrapper.cmt │   │   ├── Reprocessing_ClientWrapper.mlast │   │   ├── Reprocessing_ClientWrapper.mlast.d │   │   ├── Reprocessing_Common.mlast │   │   ├── Reprocessing_Common.mlast.d │   │   ├── Reprocessing_Constants.mlast │   │   ├── Reprocessing_Constants.mlast.d │   │   ├── Reprocessing_Constants.mliast │   │   ├── Reprocessing_Constants.mliast.d │   │   ├── Reprocessing_Draw.mlast │   │   ├── Reprocessing_Draw.mlast.d │   │   ├── Reprocessing_Draw.mliast │   │   ├── Reprocessing_Draw.mliast.d │   │   ├── Reprocessing_Env.mlast │   │   ├── Reprocessing_Env.mlast.d │   │   ├── Reprocessing_Env.mliast │   │   ├── Reprocessing_Env.mliast.d │   │   ├── Reprocessing_Events.cmi │   │   ├── Reprocessing_Events.cmj │   │   ├── Reprocessing_Events.cmt │   │   ├── Reprocessing_Events.mlast │   │   ├── Reprocessing_Events.mlast.d │   │   ├── Reprocessing_Font.mlast │   │   ├── Reprocessing_Font.mlast.d │   │   ├── Reprocessing_Internal.mlast │   │   ├── Reprocessing_Internal.mlast.d │   │   ├── Reprocessing_Matrix.cmi │   │   ├── Reprocessing_Matrix.cmj │   │   ├── Reprocessing_Matrix.cmt │   │   ├── Reprocessing_Matrix.mlast │   │   ├── Reprocessing_Matrix.mlast.d │   │   ├── Reprocessing_Shaders.cmi │   │   ├── Reprocessing_Shaders.cmj │   │   ├── Reprocessing_Shaders.cmt │   │   ├── Reprocessing_Shaders.mlast │   │   ├── Reprocessing_Shaders.mlast.d │   │   ├── Reprocessing_Types.mlast │   │   ├── Reprocessing_Types.mlast.d │   │   ├── Reprocessing_Utils.mlast │   │   ├── Reprocessing_Utils.mlast.d │   │   ├── Reprocessing_Utils.mliast │   │   └── Reprocessing_Utils.mliast.d │   └── js │   └── src │   ├── reprocessing_Events.js │   ├── reprocessing_Matrix.js │   └── reprocessing_Shaders.js ├── package.json ├── require_polyfill.js ├── src │   ├── Reprocessing.re │   ├── Reprocessing.rei │   ├── Reprocessing_ClientWrapper.re │   ├── Reprocessing_Common.re │   ├── Reprocessing_Constants.re │   ├── Reprocessing_Constants.rei │   ├── Reprocessing_Draw.re │   ├── Reprocessing_Draw.rei │   ├── Reprocessing_Env.re │   ├── Reprocessing_Env.rei │   ├── Reprocessing_Events.re │   ├── Reprocessing_Font.re │   ├── Reprocessing_Internal.re │   ├── Reprocessing_Matrix.re │   ├── Reprocessing_Shaders.re │   ├── Reprocessing_Types.re │   ├── Reprocessing_Utils.re │   └── Reprocessing_Utils.rei └── webenv-artifacts ├── Reprocessing_ClientWrapper.re ├── Reprocessing_Ext.re ├── deploy.sh ├── entrypoint.js └── reprocessing-bundle.js

10 directories, 85 files

</details>

Create pretty docs

There are a lot of ocaml docs generators...
Unfortunately no one has put one on npm yet.
Options to experiment with:

  • Can ocamldoc maybe be exposed by the reason-cli? If so, this might be the easiest option.
  • odoc -- doesn't seem to have much documentation.
  • codoc -- more documentation.. less widely used? Really hard to tell.
  • https://github.com/smondet/oredoc -- a bit of a wildcard, but looks very simple... Either port to npm or use as a pattern to implement out own...
  • ???

Antialiasing

We have anti-aliasing automatically on web, but not on native. Can we fix this? Probably something that should be fixed at the regl level.

Publish reprocessing to npm

This includes testing the flow of including reprocessing as a dependency in npm. I don't want people to have to clone the repo to use it.

Remove accidental hard dependency on libpulse on linux

As you can see here: bsansouci/reprocessing-example#2, we currently require libpulse-dev to be installed when on linux.

This is a mistake due to some badly specified dependencies here: https://github.com/bsansouci/SDL-mirror/blob/2f5920d702e435f4a2b21c263ff5becae796a591/postinstall.js#L135

This list of dependencies comes from the Libs.private section of the sdl2.pc file that gets generated during the build of sdl2.

I believe the presence of these audio libraries is an artifact of when we were attempting to statically link audio libraries on linux, and that we have since enabled dynamic linking of them and can afford to not specify -lpulse and -lpulse-simple in the link step. We would need someone on linux to verify this.

Alternatively, we need the postinstall.js script to parse the generated sdl2.pc file and use its list of static libraries when generating the bsconfig.json.

Ideally, the end result here is that on linux, the sdl2 configure script determines how best to access audio devices on your platform and is able to set up the build accordingly. Anyone who is interested in improving this should feel free to ask any additional questions necessary to give it a shot 😄

cc @zploskey

Hotreload

A pretty slick feature in the works that will probably involve a slight signature change / alternate invocation of reprocessing.
It will rely on your reprocessing file to be a module with type

{
    type state;
    let setup: Reprocessing.env => state;
    let draw: state => Reprocessing.env => state;
    let keyPressed: state => Reprocessing.env => state;
    ... other things
}

In practice, this is almost already the case as in all the examples, the draw function is actually called "draw" etc even though it's not required.

This still requires a little fiddling to get nice to use, as it would require every function to be specified. It's conceivable that we could provide some sort of default module to include but it will need to play nice with state etc.

@bsansouci

Interaction with vscode-reasonml causes hot reload crash

Hi! Thanks for an exiting project! I'm trying out the reprocessing-example, it builds, but crashes when trying to hot reload. The steps are:

npm run build

> reprocessing-example@ build /Users/xxx/code/reason/processing/reprocessing-example
> bsb -make-world

[2/2] Building fake_src/sdl_index.mlast.d
[2/2] Building lib.cma
[4/4] Building run_build_script
[3/3] Building lib.cma
[4/4] Building run_build_script
[3/3] Building lib.cma
[18/18] Building run_build_script
[10/10] Building lib.cma
ninja: no work to do.
ninja: Entering directory `lib/bs/bytecode'
[4/4] Building src/index.mlast.d
[3/3] Building indexhot.byte

This process finishes and then I run:

npm start

> reprocessing-example@ start /Users/xxx/code/reason/processing/reprocessing-example
> ./lib/bs/bytecode/indexhot.byte

Rebuilding hotloaded module
Succesfully changed functions
Rebuilding hotloaded module
Succesfully changed functions
Rebuilding hotloaded module
Succesfully changed functions
Rebuilding hotloaded module
File "src/index.re", line 1:
Error: I/O error: lib/bs/bytecode/src/index.re.cmi: No such file or directory
Hotreload failed
Fatal error: exception Failure("Unknown error while loading plugin")
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! reprocessing-example@ start: `./lib/bs/bytecode/indexhot.byte`
npm ERR! Exit status 2 reprocessing-example master

It builds successfully and the first hot reload works, but after a second change in src/index.re it crashes with the exception above

Add helpers for handling intersection logic

One common problem I (and @bsansouci) have run into issues with detecting intersections/collisions between simple shapes.

Even rect/rect collision has enough little edge cases that implementing it usually takes me a couple tries to get right. Maybe this is just me, lmk if you don't think this is complex enough to warrant helper code.

I was considering adding one or two Utils functions that will implement detection of intersections between simple shapes (ellipses, rects).

let intersectRectRect ::pos1 ::w1 ::h1 ::pos2 ::w2 ::h2;
let intersectRectEllipse ::pos1 ::w1 ::h1 ::center2 ::radX2 ::radY2;
let intersectEllipseEllipse ::center1 ::radX1 ::radY1 ::center2 ::radX2 ::radY2;

There are 2 problems that I see here.

  1. Each function has many arguments. This is made slightly easier to reason about by named args.
  2. This can combinatorially blow up with the number of types of things you want to test intersection for.

This led me to a second idea:

type shapeT = 
| Rect {x: float, y: float, w: float, h: float}
| Ellipse {x: float, y: float, radx: float, rady: float};

let intersect (s1 : shapeT) (s2 : shapeT);

This has the advantage of only needing one function to do any type of intersection, but the disadvantage of needing to allocate 2 records/variants every time you want to test intersection. I'm not sure if this is enough overhead to matter, really.

One thing I'm not sure it's useful to note is that the shapes that are being intersected will frequently (in my experience) be the same as some shapes that are being drawn. I'm not sure how often this is actually the case though, as many slightly more involved demos/games will probably use sprites/images rather than rect while still checking intersection using rects.

I'm not sure if idea 1 or idea 2 are better, they seem to have tradeoffs. Thoughts?

Strokes don't transform properly

Given this example program:

open Reprocessing;

let setup env => {
  Env.size width::600 height::400 env;
  ()
};

let draw () env => {
  let (width, height) = (Env.width env, Env.height env);
  Draw.background Constants.black env;
  Draw.stroke Constants.red env;
  Draw.fill Constants.blue env;
  Draw.translate x::150. y::150. env;
  Draw.rotate (Constants.pi /. 60.) env;
  Draw.rect pos::((-100), (-100)) width::200 height::200 env;
  ()
};

run ::setup ::draw ();

I get this output (in the browser, so using reason-web):
image

It looks to me like the current transform is getting applied once for the fill and twice for the stroke? The center of the red stroke is twice as far away from the top left origin than the blue fill, and it's also rotated more.

Possibly related, if I don't have a stroke at all (e.g. comment out the Draw.stroke line from the above example), the corners of a rect fill get clipped awkwardly:

image

Not sure if this is intentional or not, but it's at least unexpected for me as a newcomer. I can make the clipping go away by setting the stroke width to 0, but if there is no stroke color by default, why does my fill get clipped?

Add matrix functionality to images/fonts

Just realized that drawing images doesn't support matrix operations.
Neither do fonts (because they're just images).
Will finish hooking this up today hopefully.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.