Skip to content

Commit

Permalink
Large refactor (#29)
Browse files Browse the repository at this point in the history
- Namespacing files under Reprocessing_
- Add module signature files
- Add docs
- Convert to named arguments
- Do some cleanup to the examples
- Update README

Now all required functions/values/types should be accessible from Reprocessing.re
  • Loading branch information
Schmavery authored Jun 26, 2017
1 parent cb687b4 commit 642c701
Show file tree
Hide file tree
Showing 30 changed files with 1,644 additions and 932 deletions.
21 changes: 9 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@
# ReProcessing

This is a high-level drawing library, heavily inspired by [Processing](https://processing.org) and built on top of [bsansouci/reasongl](https://github.com/bsansouci/reasongl). This means you can write graphics code once, and have the (exact) same code compile to run on web (webgl) and native (opengl).
Everything you need should be accessible from the Reprocessing module.

### Example:
```reason
open Reprocessing;
open P;
open PUtils;
let setup env => {
size 600 600 env;
fill (color 255 0 0) env
Env.size width::600 height::600 env;
Draw.fill Constants.red env
};
let draw state env => {
background (color 0 0 0) env;
rect 150 150 300 300 env
Draw.background Constants.black env;
Draw.rect pos::(150, 150) width::300 height::300 env
};
ReProcessor.run ::setup ::draw ();
run ::setup ::draw ();
```
This will draw a simple red square on a black background. Compare this to [reglexampleproject](https://github.com/bsansouci/reglexampleproject/blob/master/src/index.re), 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](https://github.com/Schmavery/reprocessing/blob/master/src/redsquare.re).

# Differences from Processing
# Some Differences from Processing
- There is no magic - everything is proper Reason code. This means that you have to call `ReProcessor.run` with the functions that you want to use. You also have a couple of options about which utility modules to open. It is recommended to `open Reprocessing` at the top, and then you can optionally open `P` and `PUtils` to gain more functionality and make it look more like Processing code. An example of this can be seen above.

- You have a couple of options for state management, but we encourage the use of the `state` value that ReProcessing will manage 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). This will allow you to write event-driven code with no knowledge of reference types.

- There are no built-in variables like `width` and `mouseX`. Instead, these are functions that are called on an environment object that is always provided.
```reason
let draw state env => {
let w = P.width env;
let w = Env.width env;
print_endline ("The current width is:" ^ string_of_int w)
};
```
Expand All @@ -44,7 +41,7 @@ let draw state env => {
- 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.
```reason
let draw state env => {
let (x, y) = P.mouse env;
let (x, y) = Env.mouse env;
print_endline ("The current mouse position is:" ^ string_of_int x ^ string_of_int y)
};
```
Expand Down
7 changes: 5 additions & 2 deletions bsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"name" : "reprocessing",
"sources" : "src",
"name" : "Reprocessing",
"sources" :[
{ "dir": "src" },
{ "dir": "examples", "type": "dev"}
],
"bs-dependencies": ["ReasonglInterface", "ReasonglWeb", "ReasonglNative"],
"entries": [{"kind": "js", "main": "Index"}],
}
Expand Down
90 changes: 90 additions & 0 deletions examples/index.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
open Reprocessing;

/* https://www.youtube.com/watch?v=KkyIDI6rQJI
Purple rain processing demo */
type dropT = {
x: int,
y: int,
z: int,
len: int,
yspeed: int,
color: colorT,
time: int
};

let make w (ymin, ymax) time => {
let z = Utils.random min::0 max::20;
{
x: Utils.random min::0 max::w,
y: Utils.random min::ymin max::ymax,
z,
len: Utils.remap value::z low1::0 high1::20 low2::10 high2::20,
yspeed: Utils.remap value::z low1::0 high1::20 low2::5 high2::15,
color:
Utils.lerpColor
low::Constants.white
high::(Utils.color r::138 g::43 b::226)
amt::(Utils.randomf min::0.3 max::1.),
time
}
};

type state = {
lst: array dropT,
running: bool,
time: int
};

let setup env => {
Env.size width::640 height::360 env;
Draw.fill (Utils.color r::255 g::0 b::0) env;
Draw.noStroke env;
let lst = Array.init 500 (fun _ => make (Env.width env) ((-500), (-50)) 0);
{lst, time: 0, running: true}
};

let draw {lst, running, time} env => {
Draw.background (Utils.color r::230 g::230 b::250) env;
Draw.fill (Utils.color r::255 g::0 b::0) env;
Utils.randomSeed time;
let lst =
Array.map
(
fun drop =>
switch (drop.y + drop.yspeed * (time - drop.time)) {
| y when y > Env.height env + 500 =>
make (Env.width env) ((-500), (-50)) time
| y when y < (-500) =>
make
(Env.width env) (Env.height env + 50, Env.height env + 500) time
| _ => drop
}
)
lst;
Array.iter
(
fun drop => {
Draw.fill drop.color env;
Draw.ellipse
center::(drop.x, drop.y + drop.yspeed * (time - drop.time))
radx::(Utils.remap value::drop.z low1::0 high1::20 low2::1 high2::3)
rady::drop.yspeed
env
}
)
lst;
{lst, running, time: running ? time + 1 : time}
};

let mouseDown state _env => {...state, running: false};

let mouseUp state _env => {...state, running: true};

let mouseDragged ({time} as state) env => {
let (pmouseX, _) = Env.pmouse env;
let (mouseX, _) = Env.mouse env;
let newTime = time - (pmouseX - mouseX);
{...state, time: newTime}
};

run ::setup ::draw ::mouseDown ::mouseUp ::mouseDragged ();
34 changes: 34 additions & 0 deletions examples/noise.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
open Reprocessing.Utils;
open Reprocessing.Draw;
open Reprocessing.Env;
open Reprocessing.Constants;

let setup env => {
size width::640 height::640 env;
noStroke env;
0.01
};

let draw z env => {
background (color r::230 g::230 b::250) env;
let res = 100;
let w = float_of_int (width env) /. float_of_int res;
let h = float_of_int (height env) /. float_of_int res;
for i in 0 to (res - 1) {
for j in 0 to (res - 1) {
fill
(
lerpColor
white
black
(noise (0.03 *. float_of_int i) (0.03 *. float_of_int j) z)
)
env;
rectf
pos::(float_of_int i *. w, float_of_int j *. h) width::w height::h env
}
};
z +. 0.05
};

Reprocessing.run ::setup ::draw ();
35 changes: 35 additions & 0 deletions examples/redsquare.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
open Reprocessing.Draw;
open Reprocessing.Env;
open Reprocessing.Utils;

type state = (int, int);

let squareSize = 300;

let setup env => {
size width::600 height::600 env;
fill Reprocessing.Constants.red env;
(0, 0)
};

let draw squarePos env => {
background (color r::150 g::255 b::255) env;
let (sx, sy) = squarePos;
let (px, py) = pmouse env;
let (x, y) as squarePos =
if (
mousePressed env &&
px > sx && px < sx + squareSize && py > sy && py < sy + squareSize
) {
let (mx, my) = mouse env;
let dx = mx - px;
let dy = my - py;
(sx + dx, sy + dy)
} else {
squarePos
};
rect pos::(x, y) width::squareSize height::squareSize env;
squarePos
};

Reprocessing.run ::setup ::draw ();
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
<title>ReGl Example Project</title>
</head>
<body>
<script src="./require_polyfill.js" data-main="lib/js/src/index.js" data-project-root="./"></script>
<script src="./require_polyfill.js" data-main="lib/js/examples/index.js" data-project-root="./"></script>
</body>
</html>
37 changes: 37 additions & 0 deletions src/Reprocessing.rei
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/** Contains functions having to do with drawing to the screen */
module Draw = Reprocessing_Draw;

/** Contains functions having to do with the environment:
* ie window properties, user input
*/
module Env = Reprocessing_Env;

/** Contains types for events. */
module Events = Reasongl.Gl.Events;

/** Contains utility functions */
module Utils = Reprocessing_Utils;

/** Contains useful constants */
module Constants = Reprocessing_Constants;

include Reprocessing_Types.TypesT;

/** Entrypoint to the graphics library. The system
* is designed for you to return a self-defined 'state'
* object from setup, which will then be passed to every
* callback you choose to implement. Updating the state
* is done by returning a different value from the callback.
*/
let run:
setup::(glEnvT => 'a) =>
draw::('a => glEnvT => 'a)? =>
mouseMove::('a => glEnvT => 'a)? =>
mouseDragged::('a => glEnvT => 'a)? =>
mouseDown::('a => glEnvT => 'a)? =>
mouseUp::('a => glEnvT => 'a)? =>
keyPressed::('a => glEnvT => 'a)? =>
keyReleased::('a => glEnvT => 'a)? =>
keyTyped::('a => glEnvT => 'a)? =>
unit =>
unit;
11 changes: 10 additions & 1 deletion src/common.re → src/Reprocessing_Common.re
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
open Glloader;
open Reasongl;

module Constants = RGLConstants;

Expand Down Expand Up @@ -120,3 +120,12 @@ let read (name: string) => {
};

let append_char (s: string) (c: char) :string => s ^ String.make 1 c;

let rec split stream sep accstr acc =>
switch (Stream.peekch stream) {
| Some c when c == sep => split (Stream.popch stream) sep "" [accstr, ...acc]
| Some c => split (Stream.popch stream) sep (append_char accstr c) acc
| None => List.rev [accstr, ...acc]
};

let split str ::sep => split (Stream.create str) sep "" [];
21 changes: 21 additions & 0 deletions src/Reprocessing_Constants.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
open Reprocessing_Common;

let white = {r: 255, g: 255, b: 255};

let black = {r: 0, g: 0, b: 0};

let red = {r: 255, g: 0, b: 0};

let green = {r: 0, g: 255, b: 0};

let blue = {r: 0, g: 0, b: 255};

let pi = 4.0 *. atan 1.0;

let two_pi = 2.0 *. pi;

let half_pi = 0.5 *. pi;

let quarter_pi = 0.25 *. pi;

let tau = two_pi;
42 changes: 42 additions & 0 deletions src/Reprocessing_Constants.rei
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/** Convenience constant for the color white */
let white: Reprocessing_Common.colorT;

/** Convenience constant for the color black */
let black: Reprocessing_Common.colorT;

/** Convenience constant for the color red */
let red: Reprocessing_Common.colorT;

/** Convenience constant for the color green */
let green: Reprocessing_Common.colorT;

/** Convenience constant for the color blue */
let blue: Reprocessing_Common.colorT;

/** pi is a mathematical constant with the value 3.1415927. It is the ratio of
* the circumference of a circle to its diameter. It is useful in combination
* with the trigonometric functions `sin` and `cos`.
*/
let pi: float;

/** half_pi is a mathematical constant with the value 1.5707964. It is half
* the ratio of the circumference of a circle to its diameter
*/
let half_pi: float;

/** quarter_pi is a mathematical constant with the value 0.7853982. It is one
* quarter the ratio of the circumference of a circle to its diameter.
*/
let quarter_pi: float;

/** two_pi is a mathematical constant with the value 6.2831855. It is twice the
* ratio of the circumference of a circle to its diameter.
*/
let two_pi: float;

/** tau is a mathematical constant with the value 6.2831855. It is the circle
* constant relating the circumference of a circle to its linear dimension, the
* ratio of the circumference of a circle to its radius. It has the same value
* as two_pi.
*/
let tau: float;
Loading

0 comments on commit 642c701

Please sign in to comment.