Skip to content

Instantly share code, notes, and snippets.

@limzykenneth
Last active February 5, 2024 22:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save limzykenneth/37b52c2bed719a211d7d9f24eb6d47cd to your computer and use it in GitHub Desktop.
Save limzykenneth/37b52c2bed719a211d7d9f24eb6d47cd to your computer and use it in GitHub Desktop.
p5.js JSDoc Tests
/**
* @module Rendering
* @requires constants
*/
/**
* An object that one can draw to and then read as a texture. While similar
* to a p5.Graphics, using a p5.Framebuffer as a texture will generally run
* much faster, as it lives within the same WebGL context as the canvas it
* is created on. It only works in WebGL mode.
*
* @class Framebuffer
* @alias p5.Framebuffer
* @constructor
* @param {p5.Graphics|p5} target A p5 global instance or p5.Graphics
* @param {Object} [settings] A settings object
* @property {Number[]} pixels
*/
export class Framebuffer {
constructor() {
/**
* A <a href='https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference
* /Global_Objects/Uint8ClampedArray' target='_blank'>Uint8ClampedArray</a>
* containing the values for all the pixels in the Framebuffer.
*
* Like the <a href="#/p5/pixels">main canvas pixels property</a>, call
* <a href="#/p5.Framebuffer/loadPixels">loadPixels()</a> before reading
* it, and call <a href="#/p5.Framebuffer.updatePixels">updatePixels()</a>
* afterwards to update its data.
*
* Note that updating pixels via this property will be slower than
* <a href="#/p5.Framebuffer/begin">drawing to the framebuffer directly.</a>
* Consider using a shader instead of looping over pixels.
*
* @type {Number[]}
* @public
*/
this.pixels = [];
}
/**
* Resizes the framebuffer to the given width and height.
*
* @param {Number} width
* @param {Number} height
*
* @example
* <div>
* <code>
* let framebuffer;
* function setup() {
* createCanvas(100, 100, WEBGL);
* framebuffer = createFramebuffer();
* noStroke();
* }
*
* function mouseMoved() {
* framebuffer.resize(
* max(20, mouseX),
* max(20, mouseY)
* );
* }
*
* function draw() {
* // Draw to the framebuffer
* framebuffer.begin();
* background(255);
* normalMaterial();
* sphere(20);
* framebuffer.end();
*
* background(100);
* // Draw the framebuffer to the main canvas
* image(framebuffer, -width/2, -height/2);
* }
* </code>
* </div>
*
* @alt
* A red, green, and blue sphere is drawn in the middle of a white rectangle
* which starts in the top left of the canvas and whose bottom right is at
* the user's mouse
*/
resize(width, height) {
}
/**
* Gets or sets the pixel scaling for high pixel density displays. By
* default, the density will match that of the canvas the framebuffer was
* created on, which will match the display density.
*
* Call this method with no arguments to get the current density, or pass
* in a number to set the density.
*
* @param {Number} [density] A scaling factor for the number of pixels per
* side of the framebuffer
*/
pixelDensity(density) {
}
/**
* Gets or sets whether or not this framebuffer will automatically resize
* along with the canvas it's attached to in order to match its size.
*
* Call this method with no arguments to see if it is currently auto-sized,
* or pass in a boolean to set this property.
*
* @param {Boolean} [autoSized] Whether or not the framebuffer should resize
* along with the canvas it's attached to
*/
autoSized(autoSized) {
}
/**
* Checks the capabilities of the current WebGL environment to see if the
* settings supplied by the user are capable of being fulfilled. If they
* are not, warnings will be logged and the settings will be changed to
* something close that can be fulfilled.
*
* @private
*/
_checkIfFormatsAvailable() {
}
/**
* Creates new textures and renderbuffers given the current size of the
* framebuffer.
*
* @private
*/
_recreateTextures() {
}
/**
* To create a WebGL texture, one needs to supply three pieces of information:
* the type (the data type each channel will be stored as, e.g. int or float),
* the format (the color channels that will each be stored in the previously
* specified type, e.g. rgb or rgba), and the internal format (the specifics
* of how data for each channel, in the aforementioned type, will be packed
* together, such as how many bits to use, e.g. RGBA32F or RGB565.)
*
* The format and channels asked for by the user hint at what these values
* need to be, and the WebGL version affects what options are avaiable.
* This method returns the values for these three properties, given the
* framebuffer's settings.
*
* @private
*/
_glColorFormat() {
}
/**
* To create a WebGL texture, one needs to supply three pieces of information:
* the type (the data type each channel will be stored as, e.g. int or float),
* the format (the color channels that will each be stored in the previously
* specified type, e.g. rgb or rgba), and the internal format (the specifics
* of how data for each channel, in the aforementioned type, will be packed
* together, such as how many bits to use, e.g. RGBA32F or RGB565.)
*
* This method takes into account the settings asked for by the user and
* returns values for these three properties that can be used for the
* texture storing depth information.
*
* @private
*/
_glDepthFormat() {
}
/**
* A method that will be called when recreating textures. If the framebuffer
* is auto-sized, it will update its width, height, and density properties.
*
* @private
*/
_updateSize() {
}
/**
* Called when the canvas that the framebuffer is attached to resizes. If the
* framebuffer is auto-sized, it will update its textures to match the new
* size.
*
* @private
*/
_canvasSizeChanged() {
}
/**
* Called when the size of the framebuffer has changed (either by being
* manually updated or from auto-size updates when its canvas changes size.)
* Old textures and renderbuffers will be deleted, and then recreated with the
* new size.
*
* @private
*/
_handleResize() {
}
/**
* Creates and returns a new
* <a href="#/p5.FramebufferCamera">p5.FramebufferCamera</a> to be used
* while drawing to this framebuffer. The camera will be set as the
* currently active camera.
*
* @returns {p5.Camera} A new camera
*/
createCamera() {
}
/**
* Given a raw texture wrapper, delete its stored texture from WebGL memory,
* and remove it from p5's list of active textures.
*
* @param {p5.FramebufferTexture} texture
* @private
*/
_deleteTexture(texture) {
}
/**
* Removes the framebuffer and frees its resources.
*
* @example
* <div>
* <code>
* let framebuffer;
* function setup() {
* createCanvas(100, 100, WEBGL);
* }
*
* function draw() {
* const useFramebuffer = (frameCount % 120) > 60;
* if (useFramebuffer && !framebuffer) {
* // Create a new framebuffer for us to use
* framebuffer = createFramebuffer();
* } else if (!useFramebuffer && framebuffer) {
* // Free the old framebuffer's resources
* framebuffer.remove();
* framebuffer = undefined;
* }
*
* background(255);
* if (useFramebuffer) {
* // Draw to the framebuffer
* framebuffer.begin();
* background(255);
* rotateX(frameCount * 0.01);
* rotateY(frameCount * 0.01);
* fill(255, 0, 0);
* box(30);
* framebuffer.end();
*
* image(framebuffer, -width/2, -height/2);
* }
* }
* </code>
* </div>
*
* @alt
* A rotating red cube blinks on and off every second.
*/
remove() {
}
/**
* Begin drawing to this framebuffer. Subsequent drawing functions to the
* canvas the framebuffer is attached to will not be immediately visible, and
* will instead be drawn to the framebuffer's texture. Call
* <a href="#/p5.Framebuffer/end">end()</a> when finished to make draw
* functions go right to the canvas again and to be able to read the
* contents of the framebuffer's texture.
*
* @example
* <div>
* <code>
* let framebuffer;
* function setup() {
* createCanvas(100, 100, WEBGL);
* framebuffer = createFramebuffer();
* noStroke();
* }
*
* function draw() {
* // Draw to the framebuffer
* framebuffer.begin();
* background(255);
* translate(0, 10*sin(frameCount * 0.01), 0);
* rotateX(frameCount * 0.01);
* rotateY(frameCount * 0.01);
* fill(255, 0, 0);
* box(50);
* framebuffer.end();
*
* background(100);
* // Draw the framebuffer to the main canvas
* image(framebuffer, -50, -50, 25, 25);
* image(framebuffer, 0, 0, 35, 35);
* }
* </code>
* </div>
*
* @alt
* A video of a floating and rotating red cube is pasted twice on the
* canvas: once in the top left, and again, larger, in the bottom right.
*/
begin() {
}
/**
* When making a p5.Framebuffer active so that it may be drawn to, this method
* returns the underlying WebGL framebuffer that needs to be active to
* support this. Antialiased framebuffers first write to a multisampled
* renderbuffer, while other framebuffers can write directly to their main
* framebuffers.
*
* @private
*/
_framebufferToBind() {
}
/**
* Ensures that the framebuffer is ready to be drawn to
*
* @private
*/
_beforeBegin() {
}
/**
* Ensures that the framebuffer is ready to be read by other framebuffers.
*
* @private
*/
_beforeEnd() {
}
/**
* After having previously called
* <a href="#/p5.Framebuffer/begin">begin()</a>, this method stops drawing
* functions from going to the framebuffer's texture, allowing them to go
* right to the canvas again. After this, one can read from the framebuffer's
* texture.
*/
end() {
}
/**
* Run a function while drawing to the framebuffer rather than to its canvas.
* This is equivalent to calling `framebuffer.begin()`, running the function,
* and then calling `framebuffer.end()`, but ensures that one never
* accidentally forgets `begin` or `end`.
*
* @param {Function} callback A function to run that draws to the canvas. The
* function will immediately be run, but it will draw to the framebuffer
* instead of the canvas.
*
* @example
* <div>
* <code>
* let framebuffer;
* function setup() {
* createCanvas(100, 100, WEBGL);
* framebuffer = createFramebuffer();
* noStroke();
* }
*
* function draw() {
* // Draw to the framebuffer
* framebuffer.draw(function() {
* background(255);
* translate(0, 10*sin(frameCount * 0.01), 0);
* rotateX(frameCount * 0.01);
* rotateY(frameCount * 0.01);
* fill(255, 0, 0);
* box(50);
* });
*
* background(100);
* // Draw the framebuffer to the main canvas
* image(framebuffer, -50, -50, 25, 25);
* image(framebuffer, 0, 0, 35, 35);
* }
* </code>
* </div>
*
* @alt
* A video of a floating and rotating red cube is pasted twice on the
* canvas: once in the top left, and again, larger, in the bottom right.
*/
draw(callback) {
}
/**
* Call this befpre updating <a href="#/p5.Framebuffer/pixels">pixels</a>
* and calling <a href="#/p5.Framebuffer/updatePixels">updatePixels</a>
* to replace the content of the framebuffer with the data in the pixels
* array.
*/
loadPixels() {
}
/**
* Get a region of pixels from the canvas in the form of a
* <a href="#/p5.Image">p5.Image</a>, or a single pixel as an array of
* numbers.
*
* Returns an array of [R,G,B,A] values for any pixel or grabs a section of
* an image. If the Framebuffer has been set up to not store alpha values, then
* only [R,G,B] will be returned. If no parameters are specified, the entire
* image is returned.
* Use the x and y parameters to get the value of one pixel. Get a section of
* the display window by specifying additional w and h parameters. When
* getting an image, the x and y parameters define the coordinates for the
* upper-left corner of the image, regardless of the current <a href="#/p5/imageMode">imageMode()</a>.
*
* @param {Number} x x-coordinate of the pixel
* @param {Number} y y-coordinate of the pixel
* @param {Number} w width of the section to be returned
* @param {Number} h height of the section to be returned
* @return {p5.Image} the rectangle <a href="#/p5.Image">p5.Image</a>
*/
/**
* @return {p5.Image} the whole <a href="#/p5.Image">p5.Image</a>
*/
/**
* @param {Number} x
* @param {Number} y
* @return {Number[]} color of pixel at x,y in array format [R, G, B, A]
*/
get(x, y, w, h) {
}
/**
* Call this after initially calling <a href="#/p5.Framebuffer/loadPixels">
* loadPixels()</a> and updating <a href="#/p5.Framebuffer/pixels">pixels</a>
* to replace the content of the framebuffer with the data in the pixels
* array.
*
* This will also clear the depth buffer so that any future drawing done
* afterwards will go on top.
*
* @example
* <div>
* <code>
* let framebuffer;
* function setup() {
* createCanvas(100, 100, WEBGL);
* framebuffer = createFramebuffer();
* }
* function draw() {
* noStroke();
* lights();
*
* // Draw a sphere to the framebuffer
* framebuffer.begin();
* background(0);
* sphere(25);
* framebuffer.end();
*
* // Load its pixels and draw a gradient over the lower half of the canvas
* framebuffer.loadPixels();
* for (let y = height/2; y < height; y++) {
* for (let x = 0; x < width; x++) {
* const idx = (y * width + x) * 4;
* framebuffer.pixels[idx] = (x / width) * 255;
* framebuffer.pixels[idx + 1] = (y / height) * 255;
* framebuffer.pixels[idx + 2] = 255;
* framebuffer.pixels[idx + 3] = 255;
* }
* }
* framebuffer.updatePixels();
*
* // Draw a cube on top of the pixels we just wrote
* framebuffer.begin();
* push();
* translate(20, 20);
* rotateX(0.5);
* rotateY(0.5);
* box(20);
* pop();
* framebuffer.end();
*
* image(framebuffer, -width/2, -height/2);
* noLoop();
* }
* </code>
* </div>
*
* @alt
* A sphere partly occluded by a gradient from cyan to white to magenta on
* the lower half of the canvas, with a 3D cube drawn on top of that in the
* lower right corner.
*/
updatePixels() {
}
}
@limzykenneth
Copy link
Author

limzykenneth commented Feb 5, 2024

Will share a working minimal example in a bit. In the meantime, notes:

  • @private members are not included in output unless the --access CLI param is used.
  • Overloaded functions will add an additional entry to class members list for each overload signature. (eg. get() have three overloads so there are three entries in the members list with the name get)
  • Module does not work, not sure if documentation.js actually supports modules, although maybe alternative structures can be used instead?

@limzykenneth
Copy link
Author

npx documentation build ./test-class.js -o docs/p5.Framebuffer.json -a "public" -a "private" -a "protected" -a "undefined

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment