/*
This file was derived from the p5.js source code at
https://github.com/processing/p5.js
Copyright (c) the p5.js contributors and Andre Seidelt <superilu@yahoo.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* This module provides compatibility with p5js. Use Include('p5'); on the first line of your script to activate.
*
* @module p5compat
*/
Include('jsboot/p5const.js');
Include('jsboot/p5color.js');
Include('jsboot/p5env.js');
Include('jsboot/p5input.js');
Include('jsboot/p5math.js');
Include('jsboot/p5shape.js');
Include('jsboot/p5typo.js');
Include('jsboot/p5util.js');
Include('jsboot/p5vect.js');
Include('jsboot/p5trans.js');
exports._loop = true;
exports._lastButtons = 0;
exports._env = [];
exports._currentEnv = {
_fill: EGA.WHITE,
_stroke: EGA.BLACK,
_colorMode: RGB,
_colorMaxes: {
rgb: [255, 255, 255, 255],
hsb: [360, 100, 100, 1],
hsl: [360, 100, 100, 1]
},
_txtAlignX: LEFT,
_txtAlignY: TOP,
_font: new Font(),
_rectMode: CORNER,
_ellipseMode: CENTER,
_imageMode: CORNER,
_strokeWeight: 1,
_matrix: null
};
// TODO: implement matrix preservation for setup() and draw()
/**
* deep copy the current environment.
*/
exports._cloneEnv = function () {
if (_currentEnv._matrix) {
// deep copy matrix
var matrix = [
_currentEnv._matrix[0].slice(0),
_currentEnv._matrix[1].slice(0),
_currentEnv._matrix[2].slice(0)
]
} else {
var matrix = null;
}
return {
_fill: _currentEnv._fill,
_stroke: _currentEnv._stroke,
_colorMode: _currentEnv._colorMode,
_colorMaxes: {
// deep copy color settings
rgb: _currentEnv._colorMaxes.rgb.slice(0),
hsb: _currentEnv._colorMaxes.hsb.slice(0),
hsl: _currentEnv._colorMaxes.hsl.slice(0)
},
_txtAlignX: _currentEnv._txtAlignX,
_txtAlignY: _currentEnv._txtAlignY,
_font: _currentEnv._font,
_rectMode: _currentEnv._rectMode,
_ellipseMode: _currentEnv._ellipseMode,
_imageMode: _currentEnv._imageMode,
_strokeWeight: _currentEnv._strokeWeight,
_matrix: matrix
};
}
/*
* not documented here.
*/
exports.Setup = function () {
windowWidth = displayWidth = width = SizeX();
windowHeight = displayHeight = height = SizeY();
frameCount = 0;
_hasMouseInteracted = false;
mouseX = pmouseX = winMouseX = pwinMouseX = SizeX();
mouseY = pmouseY = winMouseY = pwinMouseY = SizeY();
MouseWarp(mouseX, mouseY);
frameRate(60);
setup();
};
/*
* not documented here.
*/
exports.Loop = function () {
if (_loop) {
redraw();
}
if (keyIsPressed) {
keyIsPressed = false;
if (typeof global['keyReleased'] != 'undefined') {
keyReleased();
}
}
};
/*
* not documented here.
*/
exports.Input = function (e) {
// update mouse coordinates
pwinMouseX = pmouseX = mouseX;
pwinMouseY = pmouseY = mouseY;
winMouseX = mouseX = e.x;
winMouseY = mouseY = e.y;
_hasMouseInteracted = true;
if (typeof global['mouseMoved'] != 'undefined') {
mouseMoved(e);
}
if (mouseIsPressed) {
if (typeof global['mouseDragged'] != 'undefined') {
mouseDragged(e);
}
}
if (e.buttons > _lastButtons) {
if (typeof global['mousePressed'] != 'undefined') {
mousePressed(e);
}
mouseIsPressed = true;
if (e.button & MOUSE.Buttons.LEFT) {
mouseButton = LEFT;
}
if (e.button & MOUSE.Buttons.MIDDLE) {
mouseButton = MIDDLE;
}
if (e.button & MOUSE.Buttons.RIGHT) {
mouseButton = RIGHT;
}
}
if (e.buttons < _lastButtons) {
mouseButton = 0;
if (mouseIsPressed && typeof global['mouseReleased'] != 'undefined') {
mouseReleased(e);
}
if (mouseIsPressed && typeof global['mouseClicked'] != 'undefined') {
mouseClicked(e);
}
mouseIsPressed = false;
}
_lastButtons = e.buttons;
// this does not work like with p5 as we don't get a key release
if (e.key != -1) {
key = e.key & 0xFF; // TODO:
keyCode = e.key; // TODO:
if (typeof global['keyPressed'] != 'undefined') {
keyPressed(e);
}
if (typeof global['keyTyped'] != 'undefined') {
keyTyped(e);
}
keyIsPressed = true;
}
};
/**
* ignored
*/
exports.size = function () { };
/**
* ignored
*/
exports.createCanvas = function () { };
/**
* ignored
*/
exports.smooth = function () { };
/**
* ignored
*/
exports.noSmooth = function () { };
/**
* ignored
*/
exports.settings = function () { };
/**
* ignored
*/
exports.tint = function () { };
/**
* ignored
*/
exports.noTint = function () { };
/**
* exit the script after the current Loop().
*/
exports.exit = function () {
Stop();
};
/**
* By default, p5.js loops through draw() continuously, executing the code
* within it. However, the draw() loop may be stopped by calling noLoop().
* In that case, the draw() loop can be resumed with loop().
*
* Avoid calling loop() from inside setup().
*
* @method loop
* @example
* let x = 0;
* function setup() {
* createCanvas(100, 100);
* noLoop();
* }
*
* function draw() {
* background(204);
* x = x + 0.1;
* if (x > width) {
* x = 0;
* }
* line(x, 0, x, height);
* }
*
* function mousePressed() {
* loop();
* }
*
* function mouseReleased() {
* noLoop();
* }
*/
exports.loop = function () {
_loop = true;
};
/**
* Stops p5.js from continuously executing the code within draw().
* If loop() is called, the code in draw() begins to run continuously again.
* If using noLoop() in setup(), it should be the last line inside the block.
* <br><br>
* When noLoop() is used, it's not possible to manipulate or access the
* screen inside event handling functions such as mousePressed() or
* keyPressed(). Instead, use those functions to call redraw() or loop(),
* which will run draw(), which can update the screen properly. This means
* that when noLoop() has been called, no drawing can happen, and functions
* like saveFrame() or loadPixels() may not be used.
* <br><br>
* Note that if the sketch is resized, redraw() will be called to update
* the sketch, even after noLoop() has been specified. Otherwise, the sketch
* would enter an odd state until loop() was called.
*
* @method noLoop
* @example
* function setup() {
* createCanvas(100, 100);
* background(200);
* noLoop();
* }
*
* function draw() {
* line(10, 10, 90, 90);
* }
*
* let x = 0;
* function setup() {
* createCanvas(100, 100);
* }
*
* function draw() {
* background(204);
* x = x + 0.1;
* if (x > width) {
* x = 0;
* }
* line(x, 0, x, height);
* }
*
* function mousePressed() {
* noLoop();
* }
*
* function mouseReleased() {
* loop();
* }
*/
exports.noLoop = function () {
_loop = false;
};
/**
*
* Executes the code within draw() one time. This functions allows the
* program to update the display window only when necessary, for example
* when an event registered by mousePressed() or keyPressed() occurs.
* <br><br>
* In structuring a program, it only makes sense to call redraw() within
* events such as mousePressed(). This is because redraw() does not run
* draw() immediately (it only sets a flag that indicates an update is
* needed).
* <br><br>
* The redraw() function does not work properly when called inside draw().
* To enable/disable animations, use loop() and noLoop().
* <br><br>
* In addition you can set the number of redraws per method call. Just
* add an integer as single parameter for the number of redraws.
*
* @method redraw
* @param {Integer} [n] Redraw for n-times. The default value is 1.
* @example
* let x = 0;
*
* function setup() {
* createCanvas(100, 100);
* noLoop();
* }
*
* function draw() {
* background(204);
* line(x, 0, x, height);
* }
*
* function mousePressed() {
* x += 1;
* redraw();
* }
*
* let x = 0;
*
* function setup() {
* createCanvas(100, 100);
* noLoop();
* }
*
* function draw() {
* background(204);
* x += 1;
* line(x, 0, x, height);
* }
*
* function mousePressed() {
* redraw(5);
* }
*/
exports.redraw = function () {
resetMatrix(); // TODO: fix!
draw();
frameCount++;
};
/**
* Returns the pixel density of the current display the sketch is running on (always 1 for DOjS).
*
* @method displayDensity
* @returns {Number} current pixel density of the display
* @example
* function setup() {
* let density = displayDensity();
* pixelDensity(density);
* createCanvas(100, 100);
* background(200);
* ellipse(width / 2, height / 2, 50, 50);
* }
*/
exports.displayDensity = function () {
return 1;
};
exports.cursor = function () {
MouseShowCursor(true);
};
/**
* Hides the cursor from view.
*
* @method noCursor
* @example
* function setup() {
* noCursor();
* }
*
* function draw() {
* background(200);
* ellipse(mouseX, mouseY, 10, 10);
* }
*/
exports.noCursor = function () {
MouseShowCursor(false);
};
exports.delay = function (ms) {
Sleep(ms);
};
exports.printArray = function (what) {
for (var i = 0; i < what.length; i++) {
Println("[" + i + "] " + what[i]);
}
};
/**
* Writes an array of Strings to a text file, one line per String.
* The file saving process and location of the saved file will
* vary between web browsers.
*
* @method saveStrings
* @param {String[]} list string array to be written
* @param {String} filename filename for output
* @param {String} [extension] the filename's extension
* @example
* let words = 'apple bear cat dog';
*
* // .split() outputs an Array
* let list = split(words, ' ');
*
* function setup() {
* createCanvas(100, 100);
* background(200);
* text('click here to save', 10, 10, 70, 80);
* }
*
* function mousePressed() {
* if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
* saveStrings(list, 'nouns.txt');
* }
* }
*
* // Saves the following to a file called 'nouns.txt':
* //
* // apple
* // bear
* // cat
* // dog
*/
exports.saveStrings = function (fname, data) {
var f = new File();
data.forEach(function (d) {
f.WriteLine(d);
});
f.Close();
};
exports.saveBytes = function (fname, data) {
var f = new File();
data.forEach(function (d) {
f.WriteByte(d);
});
f.Close();
};
/**
* Reads the contents of a file and creates a String array of its individual
* lines. If the name of the file is used as the parameter, as in the above
* example, the file must be located in the sketch directory/folder.
* <br><br>
* Alternatively, the file maybe be loaded from anywhere on the local
* computer using an absolute path (something that starts with / on Unix and
* Linux, or a drive letter on Windows), or the filename parameter can be a
* URL for a file found on a network.
* <br><br>
* This method is asynchronous, meaning it may not finish before the next
* line in your sketch is executed.
*
* This method is suitable for fetching files up to size of 64MB.
* @method loadStrings
* @param {String} filename name of the file or url to load
* @return {String[]} Array of Strings
* @example
*
* let result;
* function preload() {
* result = loadStrings('assets/test.txt');
* }
* function setup() {
* background(200);
* let ind = floor(random(result.length));
* text(result[ind], 10, 10, 80, 80);
* }
*
* function setup() {
* loadStrings('assets/test.txt', pickString);
* }
*
* function pickString(result) {
* background(200);
* let ind = floor(random(result.length));
* text(result[ind], 10, 10, 80, 80);
* }
*/
exports.loadStrings = function (fname) {
try {
var ret = [];
var f = new File(fname);
var l = f.ReadLine();
while (l != null) {
ret.push(l);
l = f.ReadLine();
}
f.Close();
return ret;
} catch (e) {
Println(e);
return null;
}
};
/**
* This method is suitable for fetching files up to size of 64MB.
* @method loadBytes
* @param {string} file name of the file or URL to load
* @returns {number[]} an object whose 'bytes' property will be the loaded buffer
*
* @example
* let data;
*
* function preload() {
* data = loadBytes('assets/mammals.xml');
* }
*
* function setup() {
* for (let i = 0; i < 5; i++) {
* console.log(data.bytes[i].toString(16));
* }
* }
*/
exports.loadBytes = function (fname) {
try {
var ret = [];
var f = new File(fname);
var ch = g.ReadByte();
while (ch != null) {
ret.push(ch);
ch = f.ReadByte();
}
f.Close();
return ret;
} catch (e) {
Println(e);
return null;
}
};
/**
* The push() function saves the current drawing style settings and
* transformations, while pop() restores these settings. Note that these
* functions are always used together. They allow you to change the style
* and transformation settings and later return to what you had. When a new
* state is started with push(), it builds on the current style and transform
* information. The push() and pop() functions can be embedded to provide
* more control. (See the second example for a demonstration.)
* <br><br>
* push() stores information related to the current transformation state
* and style settings controlled by the following functions: fill(),
* stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(),
* imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(),
* textFont(), textSize(), textLeading().
*
* @method push
* @example
* ellipse(0, 50, 33, 33); // Left circle
*
* push(); // Start a new drawing state
* strokeWeight(10);
* fill(204, 153, 0);
* translate(50, 0);
* ellipse(0, 50, 33, 33); // Middle circle
* pop(); // Restore original state
*
* ellipse(100, 50, 33, 33); // Right circle
* </code>
* </div>
* <div>
* <code>
* ellipse(0, 50, 33, 33); // Left circle
*
* push(); // Start a new drawing state
* strokeWeight(10);
* fill(204, 153, 0);
* ellipse(33, 50, 33, 33); // Left-middle circle
*
* push(); // Start another new drawing state
* stroke(0, 102, 153);
* ellipse(66, 50, 33, 33); // Right-middle circle
* pop(); // Restore previous state
*
* pop(); // Restore original state
*
* ellipse(100, 50, 33, 33); // Right circle
*/
exports.push = function () {
_env.push(_cloneEnv());
};
/**
* The push() function saves the current drawing style settings and
* transformations, while pop() restores these settings. Note that these
* functions are always used together. They allow you to change the style
* and transformation settings and later return to what you had. When a new
* state is started with push(), it builds on the current style and transform
* information. The push() and pop() functions can be embedded to provide
* more control. (See the second example for a demonstration.)
* <br><br>
* push() stores information related to the current transformation state
* and style settings controlled by the following functions: fill(),
* stroke(), tint(), strokeWeight(), strokeCap(), strokeJoin(),
* imageMode(), rectMode(), ellipseMode(), colorMode(), textAlign(),
* textFont(), textSize(), textLeading().
*
* @method pop
* @example
* ellipse(0, 50, 33, 33); // Left circle
*
* push(); // Start a new drawing state
* translate(50, 0);
* strokeWeight(10);
* fill(204, 153, 0);
* ellipse(0, 50, 33, 33); // Middle circle
* pop(); // Restore original state
*
* ellipse(100, 50, 33, 33); // Right circle
* </code>
* </div>
* <div>
* <code>
* ellipse(0, 50, 33, 33); // Left circle
*
* push(); // Start a new drawing state
* strokeWeight(10);
* fill(204, 153, 0);
* ellipse(33, 50, 33, 33); // Left-middle circle
*
* push(); // Start another new drawing state
* stroke(0, 102, 153);
* ellipse(66, 50, 33, 33); // Right-middle circle
* pop(); // Restore previous state
*
* pop(); // Restore original state
*
* ellipse(100, 50, 33, 33); // Right circle
*/
exports.pop = function () {
if (_env.length > 0) {
_currentEnv = _env.pop();
} else {
console.warn('pop() was called without matching push()');
}
};
// exports. = function () {
// };
Source