update documentation
This commit is contained in:
@@ -1,19 +1,77 @@
|
|||||||
# actor
|
# actor
|
||||||
|
|
||||||
## all_objects(fn, startobj = world)
|
# actor
|
||||||
|
|
||||||
|
|
||||||
## find_object(fn, startobj = world)
|
A set of utilities for iterating over a hierarchy of actor-like objects, as well
|
||||||
|
as managing tag-based lookups. Objects are assumed to have a "objects" property,
|
||||||
|
pointing to children or sub-objects, forming a tree.
|
||||||
|
|
||||||
|
|
||||||
|
## all_objects(fn, startobj)
|
||||||
|
|
||||||
|
|
||||||
|
**fn**: A callback function that receives each object. If it returns a truthy value, iteration stops and that value is returned.
|
||||||
|
|
||||||
|
**startobj**: The root object at which iteration begins, default is the global "world".
|
||||||
|
|
||||||
|
**Returns**: The first truthy value returned by fn, or undefined if none.
|
||||||
|
|
||||||
|
Iterate over each object (and its sub-objects) in the hierarchy, calling fn for each one.
|
||||||
|
|
||||||
|
|
||||||
|
## find_object(fn, startobj)
|
||||||
|
|
||||||
|
|
||||||
|
**fn**: A callback or criteria to locate a particular object.
|
||||||
|
|
||||||
|
**startobj**: The root object at which search begins, default "world".
|
||||||
|
|
||||||
|
**Returns**: Not yet implemented.
|
||||||
|
|
||||||
|
Intended to find a matching object within the hierarchy.
|
||||||
|
|
||||||
|
|
||||||
## tag_add(tag, obj)
|
## tag_add(tag, obj)
|
||||||
|
|
||||||
|
|
||||||
|
**tag**: A string tag to associate with the object.
|
||||||
|
|
||||||
|
**obj**: The object to add under this tag.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
Associate the given object with the specified tag. Creates a new tag set if it does not exist.
|
||||||
|
|
||||||
|
|
||||||
## tag_rm(tag, obj)
|
## tag_rm(tag, obj)
|
||||||
|
|
||||||
|
|
||||||
|
**tag**: The tag to remove the object from.
|
||||||
|
|
||||||
|
**obj**: The object to remove from the tag set.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
Remove the given object from the specified tag’s set, if it exists.
|
||||||
|
|
||||||
|
|
||||||
## tag_clear_guid(obj)
|
## tag_clear_guid(obj)
|
||||||
|
|
||||||
|
|
||||||
|
**obj**: The object whose tags should be cleared.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
Remove the object from all tag sets.
|
||||||
|
|
||||||
|
|
||||||
## objects_with_tag(tag)
|
## objects_with_tag(tag)
|
||||||
|
|
||||||
|
|
||||||
|
**tag**: A string tag to look up.
|
||||||
|
|
||||||
|
**Returns**: An array of objects associated with the given tag.
|
||||||
|
|
||||||
|
Retrieve all objects currently tagged with the specified tag.
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1 @@
|
|||||||
# color
|
# color
|
||||||
|
|
||||||
## Color
|
|
||||||
|
|
||||||
|
|
||||||
## esc
|
|
||||||
|
|
||||||
|
|
||||||
## ColorMap
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,8 @@
|
|||||||
|
|
||||||
## print_api(obj)
|
## print_api(obj)
|
||||||
|
|
||||||
|
|
||||||
## print_modules()
|
## print_modules()
|
||||||
|
|
||||||
|
|
||||||
## write_modules()
|
## write_modules()
|
||||||
|
|
||||||
|
|
||||||
## write_c_types()
|
## write_c_types()
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +1,206 @@
|
|||||||
# draw2d
|
# draw2d
|
||||||
|
|
||||||
## point(pos, size, color = Color.blue)
|
# draw2d
|
||||||
|
|
||||||
|
|
||||||
## line(points, color = Color.white, thickness = 1, pipeline)
|
A collection of 2D drawing functions that operate in screen space. Provides primitives
|
||||||
|
for lines, rectangles, text, sprite drawing, etc.
|
||||||
|
|
||||||
|
|
||||||
## cross(pos, size, color = Color.red, thickness = 1, pipe)
|
## point(pos, size, color)
|
||||||
|
|
||||||
|
|
||||||
## arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10, pipe)
|
**pos**: A 2D position ([x, y]) where the point should be drawn.
|
||||||
|
|
||||||
|
**size**: The size of the point (not currently affecting rendering).
|
||||||
|
|
||||||
|
**color**: The color of the point, defaults to Color.blue.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
## rectangle(rect, color = Color.white, pipeline)
|
|
||||||
|
## line(points, color, thickness, pipeline)
|
||||||
|
|
||||||
|
|
||||||
## tile(image, rect, color = Color.white, tile = tile_def, pipeline)
|
**points**: An array of 2D positions representing the line vertices.
|
||||||
|
|
||||||
|
**color**: The color of the line, default Color.white.
|
||||||
|
|
||||||
|
**thickness**: The line thickness, default 1.
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
## slice9(image, rect = [0,0], slice = 0, color = Color.white, info = slice9_info, pipeline)
|
|
||||||
|
## cross(pos, size, color, thickness, pipe)
|
||||||
|
|
||||||
|
|
||||||
## image(image, rect = [0,0], rotation = 0, color, pipeline)
|
**pos**: The center of the cross as a 2D position ([x, y]).
|
||||||
|
|
||||||
|
**size**: Half the size of each cross arm.
|
||||||
|
|
||||||
|
**color**: The color of the cross, default Color.red.
|
||||||
|
|
||||||
|
**thickness**: The thickness of each line, default 1.
|
||||||
|
|
||||||
|
**pipe**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## arrow(start, end, color, wingspan, wingangle, pipe)
|
||||||
|
|
||||||
|
|
||||||
|
**start**: The start position of the arrow ([x, y]).
|
||||||
|
|
||||||
|
**end**: The end (tip) position of the arrow ([x, y]).
|
||||||
|
|
||||||
|
**color**: The color, default Color.red.
|
||||||
|
|
||||||
|
**wingspan**: The length of each arrowhead 'wing', default 4.
|
||||||
|
|
||||||
|
**wingangle**: Wing rotation in degrees, default 10.
|
||||||
|
|
||||||
|
**pipe**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## rectangle(rect, color, pipeline)
|
||||||
|
|
||||||
|
|
||||||
|
**rect**: A rectangle object with {x, y, width, height}.
|
||||||
|
|
||||||
|
**color**: The fill color, default Color.white.
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## tile(image, rect, color, tile, pipeline)
|
||||||
|
|
||||||
|
|
||||||
|
**image**: An image object or string path to a texture.
|
||||||
|
|
||||||
|
**rect**: A rectangle specifying draw location/size ({x, y, width, height}).
|
||||||
|
|
||||||
|
**color**: The color tint, default Color.white.
|
||||||
|
|
||||||
|
**tile**: A tiling definition ({repeat_x, repeat_y}), default tile_def.
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
|
||||||
|
|
||||||
|
## slice9(image, rect, slice, color, info, pipeline)
|
||||||
|
|
||||||
|
|
||||||
|
**image**: An image object or string path to a texture.
|
||||||
|
|
||||||
|
**rect**: A rectangle specifying draw location/size, default [0, 0].
|
||||||
|
|
||||||
|
**slice**: The pixel inset or spacing for the 9-slice (number or object).
|
||||||
|
|
||||||
|
**color**: The color tint, default Color.white.
|
||||||
|
|
||||||
|
**info**: A slice9 info object controlling tiling of edges/corners.
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
|
||||||
|
|
||||||
|
## image(image, rect, rotation, color, pipeline)
|
||||||
|
|
||||||
|
|
||||||
|
**image**: An image object or string path to a texture.
|
||||||
|
|
||||||
|
**rect**: A rectangle specifying draw location/size, default [0,0]; width/height default to image size.
|
||||||
|
|
||||||
|
**rotation**: Rotation in degrees (not currently used).
|
||||||
|
|
||||||
|
**color**: The color tint, default none.
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: A sprite object that was created for this draw call.
|
||||||
|
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
|
||||||
|
|
||||||
## images(image, rects, config)
|
## images(image, rects, config)
|
||||||
|
|
||||||
|
|
||||||
## sprites(sprites, sort = 0, pipeline)
|
**image**: An image object or string path to a texture.
|
||||||
|
|
||||||
|
**rects**: An array of rectangle objects ({x, y, width, height}) to draw.
|
||||||
|
|
||||||
|
**config**: (Unused) Additional config data if needed.
|
||||||
|
|
||||||
|
**Returns**: An array of sprite objects created and queued for rendering.
|
||||||
|
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
|
||||||
|
|
||||||
## circle(pos, radius, color, inner_radius = 1, pipeline)
|
## sprites(sprites, sort, pipeline)
|
||||||
|
|
||||||
|
|
||||||
## text(text, rect, font = sysfont, size = 0, color = Color.white, wrap = 0, pipeline)
|
**sprites**: An array of sprite objects to draw.
|
||||||
|
|
||||||
|
**sort**: Sorting mode or order, default 0.
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## circle(pos, radius, color, inner_radius, pipeline)
|
||||||
|
|
||||||
|
|
||||||
|
**pos**: Center of the circle ([x, y]).
|
||||||
|
|
||||||
|
**radius**: The circle radius.
|
||||||
|
|
||||||
|
**color**: The fill color of the circle, default none.
|
||||||
|
|
||||||
|
**inner_radius**: (Unused) Possibly ring thickness, default 1.
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## text(text, rect, font, size, color, wrap, pipeline)
|
||||||
|
|
||||||
|
|
||||||
|
**text**: The string to draw.
|
||||||
|
|
||||||
|
**rect**: A rectangle specifying draw position (and possibly wrapping area).
|
||||||
|
|
||||||
|
**font**: A font object or string path, default sysfont.
|
||||||
|
|
||||||
|
**size**: (Unused) Possibly intended for scaling the font size.
|
||||||
|
|
||||||
|
**color**: The text color, default Color.white.
|
||||||
|
|
||||||
|
**wrap**: Pixel width for text wrapping, default 0 (no wrap).
|
||||||
|
|
||||||
|
**pipeline**: (Optional) A pipeline or rendering state object.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ Push a custom user event into SDL's queue, passing a callback function.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## engine_input(callback)
|
## engine_input(callback)
|
||||||
|
|
||||||
Poll all system events (keyboard, mouse, etc.) and call the given function with each event object.
|
Poll all system events (keyboard, mouse, etc.) and call the given function with each event object.
|
||||||
@@ -20,4 +19,3 @@ Poll all system events (keyboard, mouse, etc.) and call the given function with
|
|||||||
**Returns**: None
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +1,248 @@
|
|||||||
# geometry
|
# geometry
|
||||||
|
|
||||||
## rect_intersection()
|
# geometry
|
||||||
|
|
||||||
Return the intersection of two rectangles (x,y,w,h). The result may be empty if no intersection.
|
|
||||||
|
|
||||||
|
|
||||||
## rect_intersects()
|
A collection of geometry-related functions for circles, spheres, boxes, polygons,
|
||||||
|
and rectangle utilities. Some functionality is implemented in C and exposed here.
|
||||||
Return a boolean indicating if two rectangles overlap.
|
|
||||||
|
|
||||||
|
|
||||||
## rect_expand()
|
## rect_intersection(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
**a**: The first rectangle as {x, y, w, h}.
|
||||||
|
|
||||||
|
**b**: The second rectangle as {x, y, w, h}.
|
||||||
|
|
||||||
|
**Returns**: A rectangle that is the intersection of the two. May have zero width/height if no overlap.
|
||||||
|
|
||||||
|
Return the intersection of two rectangles. The result may be empty if no intersection.
|
||||||
|
|
||||||
|
|
||||||
|
## rect_intersects(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
**a**: Rectangle {x,y,w,h}.
|
||||||
|
|
||||||
|
**b**: Rectangle {x,y,w,h}.
|
||||||
|
|
||||||
|
**Returns**: A boolean indicating whether the two rectangles overlap.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## rect_expand(a, b)
|
||||||
|
|
||||||
|
|
||||||
|
**a**: Rectangle {x,y,w,h}.
|
||||||
|
|
||||||
|
**b**: Rectangle {x,y,w,h}.
|
||||||
|
|
||||||
|
**Returns**: A new rectangle that covers the bounds of both input rectangles.
|
||||||
|
|
||||||
Merge or combine two rectangles, returning their bounding rectangle.
|
Merge or combine two rectangles, returning their bounding rectangle.
|
||||||
|
|
||||||
|
|
||||||
## rect_inside()
|
## rect_inside(inner, outer)
|
||||||
|
|
||||||
Return true if the first rectangle is completely inside the second.
|
|
||||||
|
|
||||||
|
|
||||||
## rect_random()
|
**inner**: A rectangle to test.
|
||||||
|
|
||||||
Return a random point within the given rectangle (uniform distribution).
|
**outer**: A rectangle that may contain 'inner'.
|
||||||
|
|
||||||
|
**Returns**: True if 'inner' is completely inside 'outer', otherwise false.
|
||||||
|
|
||||||
|
|
||||||
## cwh2rect()
|
|
||||||
|
## rect_random(rect)
|
||||||
|
|
||||||
|
|
||||||
|
**rect**: A rectangle {x,y,w,h}.
|
||||||
|
|
||||||
|
**Returns**: A random point within the rectangle (uniform distribution).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## cwh2rect(center, wh)
|
||||||
|
|
||||||
|
|
||||||
|
**center**: A 2D point [cx, cy].
|
||||||
|
|
||||||
|
**wh**: A 2D size [width, height].
|
||||||
|
|
||||||
|
**Returns**: A rectangle {x, y, w, h} with x,y set to center and w,h set to the given size.
|
||||||
|
|
||||||
Helper: convert a center point and width/height vector to a rect object.
|
Helper: convert a center point and width/height vector to a rect object.
|
||||||
|
|
||||||
|
|
||||||
## rect_point_inside()
|
## rect_point_inside(rect, point)
|
||||||
|
|
||||||
Return true if the given point is inside the given rectangle.
|
|
||||||
|
|
||||||
|
|
||||||
## rect_pos()
|
**rect**: A rectangle {x,y,w,h}.
|
||||||
|
|
||||||
Return just the (x,y) position of a rectangle as a 2D array.
|
**point**: A 2D point [px, py].
|
||||||
|
|
||||||
|
**Returns**: True if the point lies inside the rectangle, otherwise false.
|
||||||
|
|
||||||
|
|
||||||
## rect_move()
|
|
||||||
|
|
||||||
Offset a rectangle by a 2D vector.
|
## rect_pos(rect)
|
||||||
|
|
||||||
|
|
||||||
|
**rect**: A rectangle {x,y,w,h}.
|
||||||
|
|
||||||
|
**Returns**: A 2D vector [x,y] giving the rectangle's position.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## rect_move(rect, offset)
|
||||||
|
|
||||||
|
|
||||||
|
**rect**: A rectangle {x,y,w,h}.
|
||||||
|
|
||||||
|
**offset**: A 2D vector to add to the rectangle's position.
|
||||||
|
|
||||||
|
**Returns**: A new rectangle with updated x,y offset.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## box(w, h)
|
## box(w, h)
|
||||||
|
|
||||||
|
|
||||||
|
**w**: The width of the box.
|
||||||
|
|
||||||
|
**h**: The height of the box.
|
||||||
|
|
||||||
|
**Returns**: An array of four 2D points representing the corners of a rectangle centered at [0,0].
|
||||||
|
|
||||||
|
Construct a box centered at the origin with the given width and height. This overrides the box object above.
|
||||||
|
|
||||||
|
|
||||||
## sphere
|
## sphere
|
||||||
|
|
||||||
|
|
||||||
|
Sphere-related geometry functions:
|
||||||
|
- volume(r): Return the volume of a sphere with radius r.
|
||||||
|
- random(r, theta, phi): Return a random point on or inside a sphere.
|
||||||
|
|
||||||
|
|
||||||
|
### volume(r)
|
||||||
|
|
||||||
|
|
||||||
|
**r**: The sphere radius.
|
||||||
|
|
||||||
|
**Returns**: The volume of the sphere, calculated as (4/3) * pi * r^3.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### random(r, theta, phi)
|
||||||
|
|
||||||
|
|
||||||
|
**r**: A single number (radius) or a 2-element array [minRadius, maxRadius].
|
||||||
|
|
||||||
|
**theta**: A single number or 2-element array defining the range in turns for the theta angle, default [0,1].
|
||||||
|
|
||||||
|
**phi**: A single number or 2-element array defining the range in turns for the phi angle, default [-0.5,0.5].
|
||||||
|
|
||||||
|
**Returns**: A 3D point (x,y,z) randomly placed within a sphere.
|
||||||
|
|
||||||
|
Generate a random point inside a sphere of variable radius, distributing angles in the specified ranges.
|
||||||
|
|
||||||
|
|
||||||
## circle
|
## circle
|
||||||
|
|
||||||
|
|
||||||
|
Circle-related geometry functions:
|
||||||
|
- area(r): Return the area of a circle with radius r.
|
||||||
|
- random(r, theta): Return a random 2D point on a circle; uses sphere.random internally and extracts x,z.
|
||||||
|
|
||||||
|
|
||||||
|
### area(r)
|
||||||
|
|
||||||
|
|
||||||
|
**r**: Radius of the circle.
|
||||||
|
|
||||||
|
**Returns**: The area, pi * r^2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### random(r, theta)
|
||||||
|
|
||||||
|
|
||||||
|
**r**: A radius or [minRadius, maxRadius].
|
||||||
|
|
||||||
|
**theta**: Angle range in turns (single number or [min,max]).
|
||||||
|
|
||||||
|
**Returns**: A 2D point (x,z) in the circle, using the sphere random generator and ignoring y.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### points(radius, n)
|
||||||
|
|
||||||
|
|
||||||
|
**radius**: The circle's radius.
|
||||||
|
|
||||||
|
**n**: Number of points around the circle.
|
||||||
|
|
||||||
|
**Returns**: An array of 2D points equally spaced around a full 360-degree circle.
|
||||||
|
|
||||||
|
Shortcut for geometry.arc(radius, 360, n).
|
||||||
|
|
||||||
|
|
||||||
## ngon(radius, n)
|
## ngon(radius, n)
|
||||||
|
|
||||||
|
|
||||||
## arc(radius, angle, n, start = 0)
|
**radius**: The radius of the n-gon from center to each vertex.
|
||||||
|
|
||||||
|
**n**: Number of sides/vertices.
|
||||||
|
|
||||||
|
**Returns**: An array of 2D points forming a regular n-gon.
|
||||||
|
|
||||||
|
Generates a regular n-gon by calling geometry.arc with full 360 degrees.
|
||||||
|
|
||||||
|
|
||||||
|
## arc(radius, angle, n, start)
|
||||||
|
|
||||||
|
|
||||||
|
**radius**: The distance from center to the arc points.
|
||||||
|
|
||||||
|
**angle**: The total angle (in degrees) over which points are generated, capped at 360.
|
||||||
|
|
||||||
|
**n**: Number of segments (if <=1, empty array is returned).
|
||||||
|
|
||||||
|
**start**: Starting angle (in degrees), default 0.
|
||||||
|
|
||||||
|
**Returns**: An array of 2D points along the arc.
|
||||||
|
|
||||||
|
Generate an arc (or partial circle) of n points, each angle spread equally over 'angle' degrees from 'start'.
|
||||||
|
|
||||||
|
|
||||||
## corners2points(ll, ur)
|
## corners2points(ll, ur)
|
||||||
|
|
||||||
|
|
||||||
|
**ll**: Lower-left 2D coordinate.
|
||||||
|
|
||||||
|
**ur**: Upper-right 2D coordinate (relative offset in x,y).
|
||||||
|
|
||||||
|
**Returns**: A four-point array of corners [ll, lower-right, upper-right, upper-left].
|
||||||
|
|
||||||
|
Similar to box.points, but calculates differently.
|
||||||
|
|
||||||
|
|
||||||
## sortpointsccw(points)
|
## sortpointsccw(points)
|
||||||
|
|
||||||
|
|
||||||
|
**points**: An array of 2D points.
|
||||||
|
|
||||||
|
**Returns**: A new array of the same points, sorted counterclockwise around their centroid.
|
||||||
|
|
||||||
|
Sort an array of points in CCW order based on their angles from the centroid.
|
||||||
|
|
||||||
|
|
||||||
## points2cm(points)
|
## points2cm(points)
|
||||||
|
|
||||||
|
|
||||||
|
**points**: An array of 2D points.
|
||||||
|
|
||||||
|
**Returns**: The centroid (average x,y) of the given points.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +1,242 @@
|
|||||||
# graphics
|
# graphics
|
||||||
|
|
||||||
## make_sprite_mesh()
|
# graphics
|
||||||
|
|
||||||
|
|
||||||
|
Provides functionality for loading and managing images, fonts, textures, and sprite meshes.
|
||||||
|
Includes both JavaScript and C-implemented routines for creating geometry buffers, performing
|
||||||
|
rectangle packing, etc.
|
||||||
|
|
||||||
|
|
||||||
|
## make_sprite_mesh(sprites)
|
||||||
|
|
||||||
|
|
||||||
|
**sprites**: An array of sprite objects, each containing .rect (or transform), .src (UV region), .color, etc.
|
||||||
|
|
||||||
|
:param oldMesh (optional): An existing mesh object to reuse/resize if possible.
|
||||||
|
**Returns**: A GPU mesh object with pos, uv, color, and indices buffers for all sprites.
|
||||||
|
|
||||||
Given an array of sprites, build a single geometry mesh for rendering them.
|
Given an array of sprites, build a single geometry mesh for rendering them.
|
||||||
|
|
||||||
|
|
||||||
## make_sprite_queue()
|
## make_sprite_queue(sprites, camera, pipeline, sort)
|
||||||
|
|
||||||
Given an array of sprites, optionally sort them and build a queue of pipeline commands.
|
|
||||||
|
|
||||||
|
|
||||||
## make_text_buffer()
|
**sprites**: An array of sprite objects.
|
||||||
|
|
||||||
|
**camera**: (unused in the C code example) Typically a camera or transform for sorting?
|
||||||
|
|
||||||
|
**pipeline**: A pipeline object for rendering.
|
||||||
|
|
||||||
|
**sort**: An integer or boolean for whether to sort sprites; if truthy, sorts by layer & texture.
|
||||||
|
|
||||||
|
**Returns**: An array of pipeline commands: geometry with mesh references, grouped by image.
|
||||||
|
|
||||||
|
Given an array of sprites, optionally sort them, then build a queue of pipeline commands.
|
||||||
|
Each group with a shared image becomes one command.
|
||||||
|
|
||||||
|
|
||||||
|
## make_text_buffer(text, rect, angle, color, wrap, font)
|
||||||
|
|
||||||
|
|
||||||
|
**text**: The string to render.
|
||||||
|
|
||||||
|
**rect**: A rectangle specifying position and possibly wrapping.
|
||||||
|
|
||||||
|
**angle**: Rotation angle (unused or optional).
|
||||||
|
|
||||||
|
**color**: A color for the text (could be a vec4).
|
||||||
|
|
||||||
|
**wrap**: The width in pixels to wrap text, or 0 for no wrap.
|
||||||
|
|
||||||
|
**font**: A font object created by graphics.make_font or graphics.get_font.
|
||||||
|
|
||||||
|
**Returns**: A geometry buffer mesh (pos, uv, color, indices) for rendering text.
|
||||||
|
|
||||||
Generate a GPU buffer mesh of text quads for rendering with a font, etc.
|
Generate a GPU buffer mesh of text quads for rendering with a font, etc.
|
||||||
|
|
||||||
|
|
||||||
## rectpack()
|
## rectpack(width, height, sizes)
|
||||||
|
|
||||||
|
|
||||||
|
**width**: The width of the area to pack into.
|
||||||
|
|
||||||
|
**height**: The height of the area to pack into.
|
||||||
|
|
||||||
|
**sizes**: An array of [w,h] pairs for the rectangles to pack.
|
||||||
|
|
||||||
|
**Returns**: An array of [x,y] coordinates placing each rect, or null if they don't fit.
|
||||||
|
|
||||||
Perform a rectangle packing using the stbrp library. Return positions for each rect.
|
Perform a rectangle packing using the stbrp library. Return positions for each rect.
|
||||||
|
|
||||||
|
|
||||||
## make_rtree()
|
## make_rtree()
|
||||||
|
|
||||||
Create a new R-Tree for quickly querying many rectangles or sprite bounds.
|
|
||||||
|
**Returns**: An R-Tree object for quickly querying many rectangles or sprite bounds.
|
||||||
|
|
||||||
|
Create a new R-Tree for geometry queries.
|
||||||
|
|
||||||
|
|
||||||
## make_texture()
|
## make_texture(data)
|
||||||
|
|
||||||
Convert raw image bytes (PNG, JPG) into an SDL_Surface object.
|
|
||||||
|
|
||||||
|
|
||||||
## make_gif()
|
**data**: Raw image bytes (PNG, JPG, etc.) as an ArrayBuffer.
|
||||||
|
|
||||||
Load a GIF from an array of bytes, returning an object with frames[] of surfaces.
|
**Returns**: An SDL_Surface object representing the decoded image in RAM, for use with GPU or software rendering.
|
||||||
|
|
||||||
|
Convert raw image bytes into an SDL_Surface object.
|
||||||
|
|
||||||
|
|
||||||
## make_aseprite()
|
## make_gif(data)
|
||||||
|
|
||||||
|
|
||||||
|
**data**: An ArrayBuffer containing GIF data.
|
||||||
|
|
||||||
|
**Returns**: An object with frames[], each frame having its own .surface. Some also have a .texture for GPU use.
|
||||||
|
|
||||||
|
Load a GIF, returning its frames. If it's a single-frame GIF, the result may have .surface only.
|
||||||
|
|
||||||
|
|
||||||
|
## make_aseprite(data)
|
||||||
|
|
||||||
|
|
||||||
|
**data**: An ArrayBuffer containing Aseprite (ASE) file data.
|
||||||
|
|
||||||
|
**Returns**: An object containing frames or animations, each with .surface. May also have top-level .surface for a single-layer case.
|
||||||
|
|
||||||
Load an Aseprite/ASE file from an array of bytes, returning frames or animations.
|
Load an Aseprite/ASE file from an array of bytes, returning frames or animations.
|
||||||
|
|
||||||
|
|
||||||
## cull_sprites()
|
## cull_sprites(sprites, camera)
|
||||||
|
|
||||||
Filter an array of sprites to only those visible in the provided camera's view.
|
|
||||||
|
|
||||||
|
|
||||||
## rects_to_sprites()
|
**sprites**: An array of sprite objects (each has rect or transform).
|
||||||
|
|
||||||
Convert an array of rect coords into sprite objects referencing an image.
|
**camera**: A camera or bounding rectangle defining the view area.
|
||||||
|
|
||||||
|
**Returns**: A new array of sprites that are visible in the camera's view.
|
||||||
|
|
||||||
|
Filter an array of sprites to only those visible in the provided camera’s view.
|
||||||
|
|
||||||
|
|
||||||
## make_surface()
|
## rects_to_sprites(rects, image)
|
||||||
|
|
||||||
Create a blank RGBA surface with the given dimensions. For software rendering or icons.
|
|
||||||
|
|
||||||
|
|
||||||
## make_cursor()
|
**rects**: An array of rect coords or objects.
|
||||||
|
|
||||||
Create an SDL_Cursor from an existing surface and a given hotspot location.
|
**image**: An image object (with .texture).
|
||||||
|
|
||||||
|
**Returns**: An array of sprite objects referencing the 'image' and each rect for UV or position.
|
||||||
|
|
||||||
|
Convert an array of rect coords into sprite objects referencing a single image.
|
||||||
|
|
||||||
|
|
||||||
## make_font()
|
## make_surface(dimensions)
|
||||||
|
|
||||||
Load a font from TTF/OTF data (an ArrayBuffer) at the given pixel size.
|
|
||||||
|
**dimensions**: The size object {width, height}, or an array [w,h].
|
||||||
|
|
||||||
|
**Returns**: A blank RGBA surface with the given dimensions, typically for software rendering or icons.
|
||||||
|
|
||||||
|
Create a blank surface in RAM.
|
||||||
|
|
||||||
|
|
||||||
|
## make_cursor(opts)
|
||||||
|
|
||||||
|
|
||||||
|
**opts**: An object with {surface, hotx, hoty} or similar.
|
||||||
|
|
||||||
|
**Returns**: An SDL_Cursor object referencing the given surface for a custom mouse cursor.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## make_font(data, size)
|
||||||
|
|
||||||
|
|
||||||
|
**data**: TTF/OTF file data as an ArrayBuffer.
|
||||||
|
|
||||||
|
**size**: Pixel size for rendering glyphs.
|
||||||
|
|
||||||
|
**Returns**: A font object with surface, texture, and glyph data, for text rendering with make_text_buffer.
|
||||||
|
|
||||||
|
Load a font from TTF/OTF data at the given size.
|
||||||
|
|
||||||
|
|
||||||
## make_sprite()
|
## make_sprite()
|
||||||
|
|
||||||
Create a new sprite object, which has rect, color, layer, and image references.
|
|
||||||
|
**Returns**: A new sprite object, which typically has .rect, .color, .layer, .image, etc.
|
||||||
|
|
||||||
|
Create a new sprite object, storing default properties.
|
||||||
|
|
||||||
|
|
||||||
## make_line_prim()
|
## make_line_prim(points, thickness, startCap, endCap, color)
|
||||||
|
|
||||||
Build a GPU mesh representing a thick polyline from an array of points, using parsl.
|
|
||||||
|
**points**: An array of [x,y] points forming the line.
|
||||||
|
|
||||||
|
**thickness**: The thickness (width) of the polyline.
|
||||||
|
|
||||||
|
**startCap**: (Unused) Possibly the type of cap for the start.
|
||||||
|
|
||||||
|
**endCap**: (Unused) Possibly the type of cap for the end.
|
||||||
|
|
||||||
|
**color**: A color to apply to the line.
|
||||||
|
|
||||||
|
**Returns**: A geometry mesh object suitable for rendering the line via a pipeline command.
|
||||||
|
|
||||||
|
Build a GPU mesh representing a thick polyline from an array of points, using parsl or a similar library under the hood.
|
||||||
|
|
||||||
|
|
||||||
## is_image(obj)
|
## is_image(obj)
|
||||||
|
|
||||||
|
|
||||||
|
**obj**: An object to check.
|
||||||
|
|
||||||
|
**Returns**: True if 'obj' has a .texture and a .rect property, indicating it's an image object.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## texture(path)
|
## texture(path)
|
||||||
|
|
||||||
|
|
||||||
|
**path**: A string path to an image file or an already-loaded image object.
|
||||||
|
|
||||||
|
**Returns**: An image object with {surface, texture, frames?, etc.} depending on the format.
|
||||||
|
|
||||||
|
Load or retrieve a cached image, converting it into a GPU texture. If 'path' is already an object, it’s returned directly.
|
||||||
|
|
||||||
|
|
||||||
## tex_hotreload(file)
|
## tex_hotreload(file)
|
||||||
|
|
||||||
|
|
||||||
## get_font(path,size)
|
**file**: The file path that was changed on disk.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
Reload the image for the given file, updating the cached copy in memory and GPU.
|
||||||
|
|
||||||
|
|
||||||
|
## get_font(path, size)
|
||||||
|
|
||||||
|
|
||||||
|
**path**: A string path to a font file, optionally with ".size" appended.
|
||||||
|
|
||||||
|
**size**: Pixel size of the font, if not included in 'path'.
|
||||||
|
|
||||||
|
**Returns**: A font object with .surface and .texture for rendering text.
|
||||||
|
|
||||||
|
Load a font from file if not cached, or retrieve from cache if already loaded.
|
||||||
|
|
||||||
|
|
||||||
## queue_sprite_mesh(queue)
|
## queue_sprite_mesh(queue)
|
||||||
|
|
||||||
|
|
||||||
|
**queue**: An array of draw commands, some of which are {type:'sprite'} objects.
|
||||||
|
|
||||||
|
**Returns**: An array of references to GPU buffers [pos,uv,color,indices].
|
||||||
|
|
||||||
|
Builds a single geometry mesh for all sprite-type commands in the queue, storing first_index/num_indices
|
||||||
|
so they can be rendered in one draw call.
|
||||||
|
|
||||||
|
|||||||
1092
docs/api/imgui.md
Normal file
1092
docs/api/imgui.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,53 +4,32 @@
|
|||||||
|
|
||||||
Show or hide the mouse cursor. Pass true to show, false to hide.
|
Show or hide the mouse cursor. Pass true to show, false to hide.
|
||||||
|
|
||||||
|
|
||||||
## mouse_lock()
|
## mouse_lock()
|
||||||
|
|
||||||
Capture or release the mouse. Pass true to lock, false to unlock.
|
Capture or release the mouse. Pass true to lock, false to unlock.
|
||||||
|
|
||||||
|
|
||||||
## cursor_set()
|
## cursor_set()
|
||||||
|
|
||||||
Set the given cursor (created by os.make_cursor) as the active mouse cursor.
|
Set the given cursor (created by os.make_cursor) as the active mouse cursor.
|
||||||
|
|
||||||
|
|
||||||
## keyname()
|
## keyname()
|
||||||
|
|
||||||
Given a numeric keycode, return the corresponding key name (e.g., from SDL).
|
Given a numeric keycode, return the corresponding key name (e.g., from SDL).
|
||||||
|
|
||||||
|
|
||||||
## keymod()
|
## keymod()
|
||||||
|
|
||||||
Return an object describing the current modifier keys, e.g. {shift:true, ctrl:true}.
|
Return an object describing the current modifier keys, e.g. {shift:true, ctrl:true}.
|
||||||
|
|
||||||
|
## mousestate()
|
||||||
## mouse
|
|
||||||
|
|
||||||
|
|
||||||
## keyboard
|
|
||||||
|
|
||||||
|
|
||||||
## print_pawn_kbm(pawn)
|
## print_pawn_kbm(pawn)
|
||||||
|
|
||||||
|
|
||||||
## procdown()
|
## procdown()
|
||||||
|
|
||||||
|
|
||||||
## print_md_kbm(pawn)
|
## print_md_kbm(pawn)
|
||||||
|
|
||||||
|
|
||||||
## has_bind(pawn, bind)
|
## has_bind(pawn, bind)
|
||||||
|
|
||||||
|
|
||||||
## action
|
|
||||||
|
|
||||||
|
|
||||||
## tabcomplete(val, list)
|
## tabcomplete(val, list)
|
||||||
|
|
||||||
|
|
||||||
## do_uncontrol(pawn)
|
## do_uncontrol(pawn)
|
||||||
|
|
||||||
|
|
||||||
## player
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ Remove the file or empty directory at the given path.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## mkdir(path)
|
## mkdir(path)
|
||||||
|
|
||||||
Create a directory at the given path.
|
Create a directory at the given path.
|
||||||
@@ -21,7 +20,6 @@ Create a directory at the given path.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## stat(path)
|
## stat(path)
|
||||||
|
|
||||||
Return an object describing file metadata for the given path. The object includes
|
Return an object describing file metadata for the given path. The object includes
|
||||||
@@ -33,7 +31,6 @@ filesize, modtime, createtime, and accesstime. Throw an error if the path does n
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## globfs(patterns)
|
## globfs(patterns)
|
||||||
|
|
||||||
Return an array of files that do not match any of the provided glob patterns. It
|
Return an array of files that do not match any of the provided glob patterns. It
|
||||||
@@ -46,7 +43,6 @@ recursively enumerates the filesystem within PHYSFS. Each pattern is treated as
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## match(pattern, string)
|
## match(pattern, string)
|
||||||
|
|
||||||
Return boolean indicating whether the given wildcard pattern matches the provided
|
Return boolean indicating whether the given wildcard pattern matches the provided
|
||||||
@@ -69,7 +65,6 @@ Patterns can incorporate:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## exists(path)
|
## exists(path)
|
||||||
|
|
||||||
Return a boolean indicating whether the file or directory at the given path exists.
|
Return a boolean indicating whether the file or directory at the given path exists.
|
||||||
@@ -80,7 +75,6 @@ Return a boolean indicating whether the file or directory at the given path exis
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## mount(archiveOrDir, mountPoint)
|
## mount(archiveOrDir, mountPoint)
|
||||||
|
|
||||||
Mount a directory or archive at the specified mount point. An undefined mount
|
Mount a directory or archive at the specified mount point. An undefined mount
|
||||||
@@ -94,7 +88,6 @@ point mounts to '/'. Throw on error.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## unmount(path)
|
## unmount(path)
|
||||||
|
|
||||||
Unmount a previously mounted directory or archive. Throw on error.
|
Unmount a previously mounted directory or archive. Throw on error.
|
||||||
@@ -105,7 +98,6 @@ Unmount a previously mounted directory or archive. Throw on error.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## slurp(path)
|
## slurp(path)
|
||||||
|
|
||||||
Read the entire file at the given path as a string. Throw on error.
|
Read the entire file at the given path as a string. Throw on error.
|
||||||
@@ -116,7 +108,6 @@ Read the entire file at the given path as a string. Throw on error.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## slurpbytes(path)
|
## slurpbytes(path)
|
||||||
|
|
||||||
Read the entire file at the given path as a raw ArrayBuffer. Throw on error.
|
Read the entire file at the given path as a raw ArrayBuffer. Throw on error.
|
||||||
@@ -127,7 +118,6 @@ Read the entire file at the given path as a raw ArrayBuffer. Throw on error.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## slurpwrite(data, path)
|
## slurpwrite(data, path)
|
||||||
|
|
||||||
Write data (string or ArrayBuffer) to the given file path. Overwrite if it exists.
|
Write data (string or ArrayBuffer) to the given file path. Overwrite if it exists.
|
||||||
@@ -141,7 +131,6 @@ Throw on error.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## writepath(path)
|
## writepath(path)
|
||||||
|
|
||||||
Set the write directory. Subsequent writes will go here by default. Throw on error.
|
Set the write directory. Subsequent writes will go here by default. Throw on error.
|
||||||
@@ -152,7 +141,6 @@ Set the write directory. Subsequent writes will go here by default. Throw on err
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## basedir()
|
## basedir()
|
||||||
|
|
||||||
Return the application's base directory (where the executable is located).
|
Return the application's base directory (where the executable is located).
|
||||||
@@ -161,7 +149,6 @@ Return the application's base directory (where the executable is located).
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## userdir()
|
## userdir()
|
||||||
|
|
||||||
Return the user's directory, often used for saving data.
|
Return the user's directory, often used for saving data.
|
||||||
@@ -170,7 +157,6 @@ Return the user's directory, often used for saving data.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## realdir(path)
|
## realdir(path)
|
||||||
|
|
||||||
Return the actual, real directory (on the host filesystem) that contains the given
|
Return the actual, real directory (on the host filesystem) that contains the given
|
||||||
@@ -182,7 +168,6 @@ file path. Return undefined if not found.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## open(path)
|
## open(path)
|
||||||
|
|
||||||
Open a file for writing, returning a file object that can be used for further
|
Open a file for writing, returning a file object that can be used for further
|
||||||
@@ -194,7 +179,6 @@ operations. Throw on error.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## searchpath()
|
## searchpath()
|
||||||
|
|
||||||
Return an array of all directories in the current paths.
|
Return an array of all directories in the current paths.
|
||||||
@@ -203,7 +187,6 @@ Return an array of all directories in the current paths.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## enumerate(path, recurse)
|
## enumerate(path, recurse)
|
||||||
|
|
||||||
Return an array of files within the given directory, optionally recursing into
|
Return an array of files within the given directory, optionally recursing into
|
||||||
@@ -216,4 +199,3 @@ subdirectories.
|
|||||||
**Returns**: An array of file (and directory) paths found.
|
**Returns**: An array of file (and directory) paths found.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
136
docs/api/js.md
136
docs/api/js.md
@@ -1,56 +1,156 @@
|
|||||||
# js
|
# js
|
||||||
|
|
||||||
## dump_mem()
|
# js
|
||||||
|
|
||||||
Return a string summarizing memory usage in the QuickJS runtime.
|
|
||||||
|
Provides functions for introspecting and configuring the QuickJS runtime engine.
|
||||||
|
Includes debug info, memory usage, GC controls, code evaluation, etc.
|
||||||
|
|
||||||
|
|
||||||
|
## cycle_hook(callback)
|
||||||
|
|
||||||
|
|
||||||
|
**callback**: A function to call each time QuickJS completes a "cycle" (internal VM loop),
|
||||||
|
|
||||||
|
or undefined to remove the callback.
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
Register or remove a hook function that QuickJS calls once per execution cycle. If the callback
|
||||||
|
is set, it receives a single argument (an optional object/value describing the cycle). If callback
|
||||||
|
is undefined, the hook is removed.
|
||||||
|
|
||||||
|
|
||||||
## dump_shapes()
|
## dump_shapes()
|
||||||
|
|
||||||
Return a debug string describing the internal shape hierarchy used by QuickJS.
|
|
||||||
|
**Returns**: A debug string describing the internal shape hierarchy used by QuickJS.
|
||||||
|
|
||||||
|
Use this for internal debugging of object shapes.
|
||||||
|
|
||||||
|
|
||||||
## dump_atoms()
|
## dump_atoms()
|
||||||
|
|
||||||
Return a debug string describing all currently registered atoms in the QuickJS runtime.
|
|
||||||
|
**Returns**: A debug string listing all currently registered atoms (internal property keys/symbols)
|
||||||
|
|
||||||
|
known by QuickJS. Helpful for diagnosing memory usage or potential key collisions.
|
||||||
|
|
||||||
|
|
||||||
## calc_mem()
|
## dump_class()
|
||||||
|
|
||||||
Return the approximate memory usage of a single JS value.
|
|
||||||
|
**Returns**: A debug string describing the distribution of JS object classes in the QuickJS runtime.
|
||||||
|
|
||||||
|
Shows how many objects of each class exist, useful for advanced memory or performance profiling.
|
||||||
|
|
||||||
|
|
||||||
|
## dump_objects()
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**: A debug string listing certain internal QuickJS objects and their references,
|
||||||
|
|
||||||
|
useful for debugging memory leaks or object lifetimes.
|
||||||
|
|
||||||
|
|
||||||
|
## dump_type_overheads()
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**: A debug string describing the overheads for various JS object types in QuickJS.
|
||||||
|
|
||||||
|
Displays memory usage breakdown for different internal object types.
|
||||||
|
|
||||||
|
|
||||||
|
## stack_info()
|
||||||
|
|
||||||
|
|
||||||
|
**Returns**: An object or string describing the runtime's current stack usage and capacity.
|
||||||
|
|
||||||
|
Internal debugging utility to examine call stack details.
|
||||||
|
|
||||||
|
|
||||||
|
## calc_mem(value)
|
||||||
|
|
||||||
|
|
||||||
|
**value**: A JavaScript value to analyze.
|
||||||
|
|
||||||
|
**Returns**: Approximate memory usage (in bytes) of that single value.
|
||||||
|
|
||||||
|
|
||||||
|
Compute the approximate size of a single JS value in memory. This is a best-effort estimate.
|
||||||
|
|
||||||
|
|
||||||
## mem()
|
## mem()
|
||||||
|
|
||||||
Return a comprehensive memory usage object for the current QuickJS runtime.
|
|
||||||
|
**Returns**: An object containing a comprehensive snapshot of memory usage for the current QuickJS runtime,
|
||||||
|
|
||||||
|
including total allocated bytes, object counts, and more.
|
||||||
|
|
||||||
|
Retrieve an overview of the runtime’s memory usage.
|
||||||
|
|
||||||
|
|
||||||
## mem_limit()
|
## mem_limit(bytes)
|
||||||
|
|
||||||
Set (in bytes) the maximum memory the QuickJS runtime will attempt to use.
|
|
||||||
|
|
||||||
|
|
||||||
## gc_threshold()
|
**bytes**: The maximum memory (in bytes) QuickJS is allowed to use.
|
||||||
|
|
||||||
Set the threshold at which garbage collection triggers automatically, in bytes.
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
## max_stacksize()
|
Set the upper memory limit for the QuickJS runtime. Exceeding this limit may cause operations to
|
||||||
|
fail or throw errors.
|
||||||
|
|
||||||
Set the maximum allowed stack size for QuickJS. Exceeding it can cause errors.
|
|
||||||
|
## gc_threshold(bytes)
|
||||||
|
|
||||||
|
|
||||||
|
**bytes**: The threshold (in bytes) at which the engine triggers automatic garbage collection.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
Set the threshold (in bytes) for QuickJS to perform an automatic GC pass when memory usage surpasses it.
|
||||||
|
|
||||||
|
|
||||||
|
## max_stacksize(bytes)
|
||||||
|
|
||||||
|
|
||||||
|
**bytes**: The maximum allowed stack size (in bytes) for QuickJS.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
Set the maximum stack size for QuickJS. If exceeded, the runtime may throw a stack overflow error.
|
||||||
|
|
||||||
|
|
||||||
## memstate()
|
## memstate()
|
||||||
|
|
||||||
Return simpler memory usage (malloc sizes, etc.) for the QuickJS runtime.
|
|
||||||
|
**Returns**: A simpler memory usage object (malloc sizes, etc.) for the QuickJS runtime.
|
||||||
|
|
||||||
|
|
||||||
|
Gives a quick overview of the memory usage, including malloc size and other allocations.
|
||||||
|
|
||||||
|
|
||||||
## gc()
|
## gc()
|
||||||
|
|
||||||
Force a full garbage collection immediately.
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
## eval()
|
Force an immediate, full garbage collection pass, reclaiming unreachable memory.
|
||||||
|
|
||||||
Evaluate the given JavaScript source string with an optional filename, returning the result.
|
|
||||||
|
## eval(src, filename)
|
||||||
|
|
||||||
|
|
||||||
|
**src**: A string of JavaScript source code to evaluate.
|
||||||
|
|
||||||
|
**filename**: (Optional) A string for the filename or label, used in debugging or stack traces.
|
||||||
|
|
||||||
|
**Returns**: The result of evaluating the given source code.
|
||||||
|
|
||||||
|
|
||||||
|
Execute a string of JavaScript code in the current QuickJS context.
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,8 @@ If the record does not have a json() method, and if whitelist is a record, then
|
|||||||
|
|
||||||
If the space input is true, then line breaks and extra whitespace will be included in the text.
|
If the space input is true, then line breaks and extra whitespace will be included in the text.
|
||||||
|
|
||||||
|
|
||||||
## decode(text,reviver)
|
## decode(text,reviver)
|
||||||
|
|
||||||
The text text is parsed, and the resulting value (usually a record or an array) is returned.
|
The text text is parsed, and the resulting value (usually a record or an array) is returned.
|
||||||
|
|
||||||
The optional reviver input is a method that will be called for every key and value at every level of the result. Each value will be replaced by the result of the reviver function. This can be used to reform data-only records into method-bearing records, or to transform date strings into seconds.
|
The optional reviver input is a method that will be called for every key and value at every level of the result. Each value will be replaced by the result of the reviver function. This can be used to reform data-only records into method-bearing records, or to transform date strings into seconds.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# loop
|
# loop
|
||||||
|
|
||||||
## step()
|
## step()
|
||||||
|
|
||||||
|
|||||||
@@ -4,144 +4,110 @@
|
|||||||
|
|
||||||
Compute the dot product between two numeric arrays, returning a scalar. Extra elements are ignored.
|
Compute the dot product between two numeric arrays, returning a scalar. Extra elements are ignored.
|
||||||
|
|
||||||
|
|
||||||
## project()
|
## project()
|
||||||
|
|
||||||
Project one vector onto another, returning a new array of the same dimension.
|
Project one vector onto another, returning a new array of the same dimension.
|
||||||
|
|
||||||
|
|
||||||
## rotate()
|
## rotate()
|
||||||
|
|
||||||
Rotate a 2D point (or array of length 2) by the given angle (in turns) around an optional pivot.
|
Rotate a 2D point (or array of length 2) by the given angle (in turns) around an optional pivot.
|
||||||
|
|
||||||
|
|
||||||
## midpoint()
|
## midpoint()
|
||||||
|
|
||||||
Compute the midpoint of two arrays of numbers. Only the first two entries are used if 2D is intended.
|
Compute the midpoint of two arrays of numbers. Only the first two entries are used if 2D is intended.
|
||||||
|
|
||||||
|
|
||||||
## reflect()
|
## reflect()
|
||||||
|
|
||||||
Reflect a vector across a plane normal. Both arguments must be numeric arrays.
|
Reflect a vector across a plane normal. Both arguments must be numeric arrays.
|
||||||
|
|
||||||
|
|
||||||
## distance()
|
## distance()
|
||||||
|
|
||||||
Compute the Euclidean distance between two numeric arrays of matching length.
|
Compute the Euclidean distance between two numeric arrays of matching length.
|
||||||
|
|
||||||
|
|
||||||
## direction()
|
## direction()
|
||||||
|
|
||||||
Compute the normalized direction vector from the first array to the second.
|
Compute the normalized direction vector from the first array to the second.
|
||||||
|
|
||||||
|
|
||||||
## angle()
|
## angle()
|
||||||
|
|
||||||
Given a 2D vector, return its angle from the X-axis in radians or some chosen units.
|
Given a 2D vector, return its angle from the X-axis in radians or some chosen units.
|
||||||
|
|
||||||
|
|
||||||
## norm()
|
## norm()
|
||||||
|
|
||||||
Return a normalized copy of the given numeric array. For 2D/3D/4D or arbitrary length.
|
Return a normalized copy of the given numeric array. For 2D/3D/4D or arbitrary length.
|
||||||
|
|
||||||
|
|
||||||
## angle_between()
|
## angle_between()
|
||||||
|
|
||||||
Compute the angle between two vectors (2D/3D/4D).
|
Compute the angle between two vectors (2D/3D/4D).
|
||||||
|
|
||||||
|
|
||||||
## lerp()
|
## lerp()
|
||||||
|
|
||||||
Linear interpolation between two numbers: lerp(a, b, t).
|
Linear interpolation between two numbers: lerp(a, b, t).
|
||||||
|
|
||||||
|
|
||||||
## gcd()
|
## gcd()
|
||||||
|
|
||||||
Compute the greatest common divisor of two integers.
|
Compute the greatest common divisor of two integers.
|
||||||
|
|
||||||
|
|
||||||
## lcm()
|
## lcm()
|
||||||
|
|
||||||
Compute the least common multiple of two integers.
|
Compute the least common multiple of two integers.
|
||||||
|
|
||||||
|
|
||||||
## clamp()
|
## clamp()
|
||||||
|
|
||||||
Clamp a number between low and high. clamp(value, low, high).
|
Clamp a number between low and high. clamp(value, low, high).
|
||||||
|
|
||||||
|
|
||||||
## angledist()
|
## angledist()
|
||||||
|
|
||||||
Compute the signed distance between two angles in 'turn' units, e.g. 0..1 range.
|
Compute the signed distance between two angles in 'turn' units, e.g. 0..1 range.
|
||||||
|
|
||||||
|
|
||||||
## jitter()
|
## jitter()
|
||||||
|
|
||||||
Apply a random +/- percentage noise to a number. Example: jitter(100, 0.05) -> ~95..105.
|
Apply a random +/- percentage noise to a number. Example: jitter(100, 0.05) -> ~95..105.
|
||||||
|
|
||||||
|
|
||||||
## mean()
|
## mean()
|
||||||
|
|
||||||
Compute the arithmetic mean of an array of numbers.
|
Compute the arithmetic mean of an array of numbers.
|
||||||
|
|
||||||
|
|
||||||
## sum()
|
## sum()
|
||||||
|
|
||||||
Sum all elements of an array of numbers.
|
Sum all elements of an array of numbers.
|
||||||
|
|
||||||
|
|
||||||
## sigma()
|
## sigma()
|
||||||
|
|
||||||
Compute standard deviation of an array of numbers.
|
Compute standard deviation of an array of numbers.
|
||||||
|
|
||||||
|
|
||||||
## median()
|
## median()
|
||||||
|
|
||||||
Compute the median of an array of numbers.
|
Compute the median of an array of numbers.
|
||||||
|
|
||||||
|
|
||||||
## length()
|
## length()
|
||||||
|
|
||||||
Return the length of a vector (i.e. sqrt of sum of squares).
|
Return the length of a vector (i.e. sqrt of sum of squares).
|
||||||
|
|
||||||
|
|
||||||
## from_to()
|
## from_to()
|
||||||
|
|
||||||
Return an array of points from a start to an end, spaced out by a certain distance.
|
Return an array of points from a start to an end, spaced out by a certain distance.
|
||||||
|
|
||||||
|
|
||||||
## rand()
|
## rand()
|
||||||
|
|
||||||
Return a random float in [0,1).
|
Return a random float in [0,1).
|
||||||
|
|
||||||
|
|
||||||
## randi()
|
## randi()
|
||||||
|
|
||||||
Return a random 32-bit integer.
|
Return a random 32-bit integer.
|
||||||
|
|
||||||
|
|
||||||
## srand()
|
## srand()
|
||||||
|
|
||||||
Seed the random number generator with the given integer, or with current time if none.
|
Seed the random number generator with the given integer, or with current time if none.
|
||||||
|
|
||||||
|
|
||||||
## TAU
|
|
||||||
|
|
||||||
|
|
||||||
## deg2rad(deg)
|
## deg2rad(deg)
|
||||||
|
|
||||||
|
|
||||||
## rad2deg(rad)
|
## rad2deg(rad)
|
||||||
|
|
||||||
|
|
||||||
## turn2rad(x)
|
## turn2rad(x)
|
||||||
|
|
||||||
|
|
||||||
## rad2turn(x)
|
## rad2turn(x)
|
||||||
|
|
||||||
|
|
||||||
## turn2deg(x)
|
## turn2deg(x)
|
||||||
|
|
||||||
|
|
||||||
## deg2turn(x)
|
## deg2turn(x)
|
||||||
|
|
||||||
|
|||||||
@@ -4,123 +4,98 @@
|
|||||||
|
|
||||||
Create a new transform object that can be used for 2D/3D positioning, scaling, and rotation.
|
Create a new transform object that can be used for 2D/3D positioning, scaling, and rotation.
|
||||||
|
|
||||||
|
|
||||||
## clean_transforms()
|
## clean_transforms()
|
||||||
|
|
||||||
Force an update on all transforms to remove dangling references or perform house-keeping.
|
Force an update on all transforms to remove dangling references or perform house-keeping.
|
||||||
|
|
||||||
|
|
||||||
## platform()
|
## platform()
|
||||||
|
|
||||||
Return a string with the underlying platform name, like 'Windows', 'Linux', or 'macOS'.
|
Return a string with the underlying platform name, like 'Windows', 'Linux', or 'macOS'.
|
||||||
|
|
||||||
|
|
||||||
## arch()
|
## arch()
|
||||||
|
|
||||||
Return the CPU architecture string for this system (e.g. 'x64', 'arm64').
|
Return the CPU architecture string for this system (e.g. 'x64', 'arm64').
|
||||||
|
|
||||||
|
|
||||||
## totalmem()
|
## totalmem()
|
||||||
|
|
||||||
Return the total system RAM in bytes.
|
Return the total system RAM in bytes.
|
||||||
|
|
||||||
|
|
||||||
## freemem()
|
## freemem()
|
||||||
|
|
||||||
Return the amount of free system RAM in bytes, if known.
|
Return the amount of free system RAM in bytes, if known.
|
||||||
|
|
||||||
|
|
||||||
## hostname()
|
## hostname()
|
||||||
|
|
||||||
Return the system's hostname, or an empty string if not available.
|
Return the system's hostname, or an empty string if not available.
|
||||||
|
|
||||||
|
|
||||||
## version()
|
## version()
|
||||||
|
|
||||||
Return the OS or kernel version string, if the platform provides it.
|
Return the OS or kernel version string, if the platform provides it.
|
||||||
|
|
||||||
|
|
||||||
## kill()
|
## kill()
|
||||||
|
|
||||||
Send a signal (e.g., 'SIGINT', 'SIGTERM', etc.) to the current process.
|
Send a signal (e.g., 'SIGINT', 'SIGTERM', etc.) to the current process.
|
||||||
|
|
||||||
|
|
||||||
## exit()
|
## exit()
|
||||||
|
|
||||||
Exit the application with the specified exit code.
|
Exit the application with the specified exit code.
|
||||||
|
|
||||||
|
|
||||||
## now()
|
## now()
|
||||||
|
|
||||||
Return current time (in seconds as a float) with high resolution.
|
Return current time (in seconds as a float) with high resolution.
|
||||||
|
|
||||||
|
|
||||||
## openurl()
|
## openurl()
|
||||||
|
|
||||||
Open the provided URL in the default web browser, if possible.
|
Open the provided URL in the default web browser, if possible.
|
||||||
|
|
||||||
|
|
||||||
## make_timer()
|
## make_timer()
|
||||||
|
|
||||||
Create a new timer object that will call a specified function after a certain delay.
|
Create a new timer object that will call a specified function after a certain delay.
|
||||||
|
|
||||||
|
|
||||||
## update_timers()
|
## update_timers()
|
||||||
|
|
||||||
Advance all timers by the provided time delta (in seconds).
|
Advance all timers by the provided time delta (in seconds).
|
||||||
|
|
||||||
|
|
||||||
## sleep()
|
## sleep()
|
||||||
|
|
||||||
Block execution for the specified number of seconds.
|
Block execution for the specified number of seconds.
|
||||||
|
|
||||||
|
|
||||||
## battery_pct()
|
## battery_pct()
|
||||||
|
|
||||||
Return the battery level (percentage) or negative if unknown.
|
Return the battery level (percentage) or negative if unknown.
|
||||||
|
|
||||||
|
|
||||||
## battery_voltage()
|
## battery_voltage()
|
||||||
|
|
||||||
Return the current battery voltage in volts, if available.
|
Return the current battery voltage in volts, if available.
|
||||||
|
|
||||||
|
|
||||||
## battery_seconds()
|
## battery_seconds()
|
||||||
|
|
||||||
Return the estimated remaining battery time in seconds, or negative if unknown.
|
Return the estimated remaining battery time in seconds, or negative if unknown.
|
||||||
|
|
||||||
|
|
||||||
## power_state()
|
## power_state()
|
||||||
|
|
||||||
Return a string describing power status: 'on battery', 'charging', 'charged', etc.
|
Return a string describing power status: 'on battery', 'charging', 'charged', etc.
|
||||||
|
|
||||||
|
|
||||||
## on()
|
## on()
|
||||||
|
|
||||||
Register a global callback for certain engine-wide or system-level events.
|
Register a global callback for certain engine-wide or system-level events.
|
||||||
|
|
||||||
|
|
||||||
## rt_info()
|
## rt_info()
|
||||||
|
|
||||||
Return internal QuickJS runtime info, such as object counts.
|
Return internal QuickJS runtime info, such as object counts.
|
||||||
|
|
||||||
|
|
||||||
## rusage()
|
## rusage()
|
||||||
|
|
||||||
Return resource usage stats for this process, if the platform supports it.
|
Return resource usage stats for this process, if the platform supports it.
|
||||||
|
|
||||||
|
|
||||||
## mallinfo()
|
## mallinfo()
|
||||||
|
|
||||||
Return detailed memory allocation info (arena size, free blocks, etc.) on some platforms.
|
Return detailed memory allocation info (arena size, free blocks, etc.) on some platforms.
|
||||||
|
|
||||||
|
|
||||||
## env()
|
## env()
|
||||||
|
|
||||||
Fetch the value of a given environment variable, or undefined if it doesn't exist.
|
Fetch the value of a given environment variable, or undefined if it doesn't exist.
|
||||||
|
|
||||||
|
|
||||||
## system()
|
## system()
|
||||||
|
|
||||||
Execute a shell command using the system() call. Returns the command's exit code.
|
Execute a shell command using the system() call. Returns the command's exit code.
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +1,85 @@
|
|||||||
# render
|
# render
|
||||||
|
|
||||||
## _main
|
### present()
|
||||||
|
|
||||||
|
Perform the per-frame rendering and present the final swapchain image, including imgui pass if available.
|
||||||
|
|
||||||
## device
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
## toggles
|
|
||||||
|
|
||||||
|
|
||||||
## stencil_writer(...args)
|
## stencil_writer(...args)
|
||||||
|
|
||||||
|
|
||||||
## fillmask(ref)
|
## fillmask(ref)
|
||||||
|
|
||||||
|
Draw a fullscreen shape using a 'screenfill' shader to populate the stencil buffer with a given reference.
|
||||||
|
|
||||||
|
**ref**: The stencil reference value to write.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## mask(image, pos, scale, rotation, ref)
|
||||||
|
|
||||||
|
Draw an image to the stencil buffer, marking its area with a specified reference value.
|
||||||
|
|
||||||
|
**image**: A texture or string path (which is converted to a texture).
|
||||||
|
|
||||||
|
**pos**: The translation (x, y) for the image placement.
|
||||||
|
|
||||||
|
**scale**: Optional scaling applied to the texture.
|
||||||
|
|
||||||
|
**rotation**: Optional rotation in radians (unused by default).
|
||||||
|
|
||||||
|
**ref**: The stencil reference value to write.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
## mask(image, pos, scale, rotation = 0, ref = 1)
|
|
||||||
|
|
||||||
|
|
||||||
## viewport(rect)
|
## viewport(rect)
|
||||||
|
|
||||||
|
Set the GPU viewport to the specified rectangle.
|
||||||
|
|
||||||
|
**rect**: A rectangle [x, y, width, height].
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## scissor(rect)
|
## scissor(rect)
|
||||||
|
|
||||||
|
Set the GPU scissor region to the specified rectangle (alias of render.viewport).
|
||||||
|
|
||||||
|
**rect**: A rectangle [x, y, width, height].
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## queue(cmd)
|
## queue(cmd)
|
||||||
|
|
||||||
|
Enqueue one or more draw commands. These commands are batched until render_camera is called.
|
||||||
|
|
||||||
|
**cmd**: Either a single command object or an array of command objects.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## setup_draw()
|
## setup_draw()
|
||||||
|
|
||||||
|
Switch the current queue to the primary scene render queue, then invoke 'prosperon.draw' if defined.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## setup_hud()
|
## setup_hud()
|
||||||
|
|
||||||
|
Switch the current queue to the HUD render queue, then invoke 'prosperon.hud' if defined.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,11 @@
|
|||||||
# resources
|
# resources
|
||||||
|
|
||||||
## scripts
|
|
||||||
|
|
||||||
|
|
||||||
## images
|
|
||||||
|
|
||||||
|
|
||||||
## sounds
|
|
||||||
|
|
||||||
|
|
||||||
## fonts
|
|
||||||
|
|
||||||
|
|
||||||
## lib
|
|
||||||
|
|
||||||
|
|
||||||
## canonical(file)
|
## canonical(file)
|
||||||
|
|
||||||
|
|
||||||
## find_image(...args)
|
## find_image(...args)
|
||||||
|
|
||||||
|
|
||||||
## find_sound(...args)
|
## find_sound(...args)
|
||||||
|
|
||||||
|
|
||||||
## find_script(...args)
|
## find_script(...args)
|
||||||
|
|
||||||
|
|
||||||
## find_font(...args)
|
## find_font(...args)
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
# sound
|
# sound
|
||||||
|
|
||||||
## undefined
|
|
||||||
|
|
||||||
|
|
||||||
## pcm(file)
|
## pcm(file)
|
||||||
|
|
||||||
|
|
||||||
## play(file)
|
## play(file)
|
||||||
|
|
||||||
|
|
||||||
## cry(file)
|
## cry(file)
|
||||||
|
|
||||||
|
|
||||||
## music(file, fade = 0.5)
|
## music(file, fade = 0.5)
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
Perform Catmull-Rom spline sampling on an array of 2D points, returning an array of samples.
|
Perform Catmull-Rom spline sampling on an array of 2D points, returning an array of samples.
|
||||||
|
|
||||||
|
|
||||||
## bezier()
|
## bezier()
|
||||||
|
|
||||||
Perform a Bezier spline (or catmull) sampling on 2D points, returning an array of sampled points.
|
Perform a Bezier spline (or catmull) sampling on 2D points, returning an array of sampled points.
|
||||||
|
|
||||||
|
|||||||
@@ -1,85 +1,57 @@
|
|||||||
# time
|
# time
|
||||||
|
|
||||||
|
# time
|
||||||
|
|
||||||
|
The main time object, handling date/time utilities in earth-seconds.
|
||||||
|
|
||||||
## now()
|
## now()
|
||||||
|
|
||||||
Return the current system time as a floating-point number of seconds with microsecond precision.
|
Return the current system time in seconds (implemented in C extension).
|
||||||
|
|
||||||
|
|
||||||
## computer_dst()
|
## computer_dst()
|
||||||
|
|
||||||
Return true if the local system time is currently in Daylight Savings Time, otherwise false.
|
Return true if local system time is currently in DST (implemented in C extension).
|
||||||
|
|
||||||
|
|
||||||
## computer_zone()
|
## computer_zone()
|
||||||
|
|
||||||
Return the local time zone offset from UTC in hours, e.g. -5 for EST.
|
Return local time zone offset from UTC in hours (implemented in C extension).
|
||||||
|
|
||||||
|
|
||||||
## hour2minute()
|
## hour2minute()
|
||||||
|
|
||||||
|
Return the ratio of hour to minute in seconds, e.g. 3600 / 60 => 60.
|
||||||
|
|
||||||
## day2hour()
|
## day2hour()
|
||||||
|
|
||||||
|
Return the ratio of day to hour in seconds, e.g. 86400 / 3600 => 24.
|
||||||
|
|
||||||
## minute2second()
|
## minute2second()
|
||||||
|
|
||||||
|
Return the ratio of minute to second in seconds, e.g. 60 / 1 => 60.
|
||||||
|
|
||||||
## week2day()
|
## week2day()
|
||||||
|
|
||||||
|
Return the ratio of week to day in seconds, e.g. 604800 / 86400 => 7.
|
||||||
## strparse
|
|
||||||
|
|
||||||
|
|
||||||
## doc
|
|
||||||
|
|
||||||
|
|
||||||
## second
|
|
||||||
|
|
||||||
|
|
||||||
## minute
|
|
||||||
|
|
||||||
|
|
||||||
## hour
|
|
||||||
|
|
||||||
|
|
||||||
## day
|
|
||||||
|
|
||||||
|
|
||||||
## week
|
|
||||||
|
|
||||||
|
|
||||||
## weekdays
|
|
||||||
|
|
||||||
|
|
||||||
## monthstr
|
|
||||||
|
|
||||||
|
|
||||||
## epoch
|
|
||||||
|
|
||||||
|
|
||||||
## isleap(year)
|
## isleap(year)
|
||||||
|
|
||||||
|
Return true if a given year is leap, based on whether it has 366 days.
|
||||||
|
|
||||||
## yearsize(y)
|
## yearsize(y)
|
||||||
|
|
||||||
|
Given a year, return 365 or 366 depending on leap-year rules.
|
||||||
|
|
||||||
## timecode(t, fps = 24)
|
## timecode(t, fps = 24)
|
||||||
|
|
||||||
|
Convert seconds into a "S:frames" timecode string, with optional FPS (default 24).
|
||||||
## monthdays
|
|
||||||
|
|
||||||
|
|
||||||
## zones
|
|
||||||
|
|
||||||
|
|
||||||
## record(num, zone = this.computer_zone()
|
## record(num, zone = this.computer_zone()
|
||||||
|
|
||||||
|
Convert a timestamp (in seconds) into a record with fields like day, month, year, etc.
|
||||||
|
|
||||||
## number(rec)
|
## number(rec)
|
||||||
|
|
||||||
|
Convert a record back into a numeric timestamp (seconds).
|
||||||
## fmt
|
|
||||||
|
|
||||||
|
|
||||||
## text(num, fmt = this.fmt, zone)
|
## text(num, fmt = this.fmt, zone)
|
||||||
|
|
||||||
|
Format a numeric or record time into a string using a format pattern, e.g. 'hh:nn:ss'.
|
||||||
|
|||||||
@@ -3,8 +3,74 @@
|
|||||||
## Tween
|
## Tween
|
||||||
|
|
||||||
|
|
||||||
|
An object providing methods to create and control tweens with additional features
|
||||||
|
like looping, custom easing, multiple stages, etc.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
- default: A template object with loop/time/ease/whole/cb properties.
|
||||||
|
Methods:
|
||||||
|
- start(obj, target, tvals, options): Create a tween over multiple target values.
|
||||||
|
- make: Alias of start.
|
||||||
|
|
||||||
|
|
||||||
|
### start(obj, target, tvals, options)
|
||||||
|
|
||||||
|
|
||||||
|
Alias of Tween.start. See Tween.start for usage details.
|
||||||
|
|
||||||
|
|
||||||
|
### make(obj, target, tvals, options)
|
||||||
|
|
||||||
|
|
||||||
|
Alias of Tween.start. See Tween.start for usage details.
|
||||||
|
|
||||||
|
|
||||||
## Ease
|
## Ease
|
||||||
|
|
||||||
|
|
||||||
|
This object provides multiple easing functions that remap a 0..1 input to produce
|
||||||
|
a smoothed or non-linear output. They can be used standalone or inside tweens.
|
||||||
|
|
||||||
|
Available functions:
|
||||||
|
- linear(t)
|
||||||
|
- in(t), out(t), inout(t)
|
||||||
|
- quad.in, quad.out, quad.inout
|
||||||
|
- cubic.in, cubic.out, cubic.inout
|
||||||
|
- quart.in, quart.out, quart.inout
|
||||||
|
- quint.in, quint.out, quint.inout
|
||||||
|
- expo.in, expo.out, expo.inout
|
||||||
|
- bounce.in, bounce.out, bounce.inout
|
||||||
|
- sine.in, sine.out, sine.inout
|
||||||
|
- elastic.in, elastic.out, elastic.inout
|
||||||
|
|
||||||
|
All easing functions expect t in [0..1] and return a remapped value in [0..1].
|
||||||
|
|
||||||
|
|
||||||
|
### linear(t)
|
||||||
|
|
||||||
|
### in(t)
|
||||||
|
|
||||||
|
### out(t)
|
||||||
|
|
||||||
|
### inout(t)
|
||||||
|
|
||||||
## tween(from, to, time, fn, cb)
|
## tween(from, to, time, fn, cb)
|
||||||
|
|
||||||
|
|
||||||
|
**from**: The starting object or value to interpolate from.
|
||||||
|
|
||||||
|
**to**: The ending object or value to interpolate to.
|
||||||
|
|
||||||
|
**time**: The total duration of the tween in milliseconds or some time unit.
|
||||||
|
|
||||||
|
**fn**: A callback function that receives the interpolated value at each update.
|
||||||
|
|
||||||
|
**cb**: (Optional) A callback invoked once the tween completes.
|
||||||
|
|
||||||
|
**Returns**: A function that, when called, cleans up and stops the tween.
|
||||||
|
|
||||||
|
|
||||||
|
Creates a simple tween that linearly interpolates from "from" to "to" over "time"
|
||||||
|
and calls "fn" with each interpolated value. Once finished, "fn" is called with "to",
|
||||||
|
then "cb" is invoked if provided, and the tween is cleaned up.
|
||||||
|
|
||||||
|
|||||||
139
docs/api/util.md
139
docs/api/util.md
@@ -1,44 +1,169 @@
|
|||||||
# util
|
# util
|
||||||
|
|
||||||
|
# util
|
||||||
|
|
||||||
|
|
||||||
|
A collection of general-purpose utility functions for object manipulation, merging,
|
||||||
|
deep copying, safe property access, etc.
|
||||||
|
|
||||||
|
|
||||||
## guid()
|
## guid()
|
||||||
|
|
||||||
Return a random 32-character hexadecimal UUID-like string.
|
|
||||||
|
**Returns**: A random 32-character string (hex).
|
||||||
|
|
||||||
|
Return a random 32-character hexadecimal UUID-like string (not guaranteed RFC4122-compliant).
|
||||||
|
|
||||||
|
|
||||||
## insertion_sort()
|
## insertion_sort(arr, cmp)
|
||||||
|
|
||||||
In-place insertion sort of an array using a comparison function cmp(a,b)->Number.
|
|
||||||
|
**arr**: The array to be sorted in-place.
|
||||||
|
|
||||||
|
**cmp**: Comparison function cmp(a,b)->Number.
|
||||||
|
|
||||||
|
**Returns**: The same array, sorted in-place.
|
||||||
|
|
||||||
|
In-place insertion sort of an array using cmp(a,b)->Number for ordering.
|
||||||
|
|
||||||
|
|
||||||
## deepfreeze(obj)
|
## deepfreeze(obj)
|
||||||
|
|
||||||
|
|
||||||
|
**obj**: The object to recursively freeze.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
Recursively freeze an object and all of its nested objects so they cannot be modified.
|
||||||
|
|
||||||
|
|
||||||
## dainty_assign(target, source)
|
## dainty_assign(target, source)
|
||||||
|
|
||||||
|
|
||||||
|
**target**: The target object whose keys may be updated.
|
||||||
|
|
||||||
|
**source**: The source object containing new values.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
Copy non-function properties from source into matching keys of target without overwriting
|
||||||
|
keys that don't exist in target. Arrays are deep-copied, and objects are recursively assigned.
|
||||||
|
|
||||||
|
|
||||||
## get(obj, path, defValue)
|
## get(obj, path, defValue)
|
||||||
|
|
||||||
|
|
||||||
|
**obj**: The object to traverse.
|
||||||
|
|
||||||
|
**path**: A string like "a.b.c" or an array of path segments.
|
||||||
|
|
||||||
|
**defValue**: The default value if the property is undefined.
|
||||||
|
|
||||||
|
**Returns**: The nested property or defValue.
|
||||||
|
|
||||||
|
Safely retrieve a nested property from obj at path (array or dot-string).
|
||||||
|
Returns defValue if the property is undefined.
|
||||||
|
|
||||||
|
|
||||||
## isEmpty(o)
|
## isEmpty(o)
|
||||||
|
|
||||||
|
|
||||||
## dig(obj, path, def = {})
|
**o**: The object to check.
|
||||||
|
|
||||||
|
**Returns**: Boolean indicating if the object is empty.
|
||||||
|
|
||||||
|
Return true if the object has no own properties, otherwise false.
|
||||||
|
|
||||||
|
|
||||||
|
## dig(obj, path, def)
|
||||||
|
|
||||||
|
|
||||||
|
**obj**: The root object to modify.
|
||||||
|
|
||||||
|
**path**: A dot-string specifying nested objects to create.
|
||||||
|
|
||||||
|
**def**: The value to store in the final path component, default {}.
|
||||||
|
|
||||||
|
**Returns**: The assigned final value.
|
||||||
|
|
||||||
|
Ensure a nested path of objects exists inside obj; create objects if missing, and set
|
||||||
|
the final path component to def.
|
||||||
|
|
||||||
|
|
||||||
## access(obj, name)
|
## access(obj, name)
|
||||||
|
|
||||||
|
|
||||||
|
**obj**: The object to traverse.
|
||||||
|
|
||||||
|
**name**: A dot-string path (e.g. "foo.bar.baz").
|
||||||
|
|
||||||
|
**Returns**: The value at that path, or undefined if missing.
|
||||||
|
|
||||||
|
Traverse obj by dot-separated path name, returning the final value or undefined
|
||||||
|
if any step is missing.
|
||||||
|
|
||||||
|
|
||||||
## mergekey(o1, o2, k)
|
## mergekey(o1, o2, k)
|
||||||
|
|
||||||
|
|
||||||
## merge(target, ...objs)
|
**o1**: The target object.
|
||||||
|
|
||||||
|
**o2**: The source object.
|
||||||
|
|
||||||
|
**k**: The key to merge.
|
||||||
|
|
||||||
|
**Returns**: None
|
||||||
|
|
||||||
|
Helper for merge, updating key k from o2 into o1. Arrays are deep-copied and objects are
|
||||||
|
recursively merged.
|
||||||
|
|
||||||
|
|
||||||
## copy(proto, ...objs)
|
## merge(target, objs)
|
||||||
|
|
||||||
|
|
||||||
## obj_lerp(a,b,t)
|
**target**: The target object.
|
||||||
|
|
||||||
|
**objs**: One or more objects to merge into target.
|
||||||
|
|
||||||
|
**Returns**: The updated target object.
|
||||||
|
|
||||||
|
Merge all passed objects into target, copying or merging each key as needed.
|
||||||
|
Arrays are deep-copied, objects are recursively merged, etc.
|
||||||
|
|
||||||
|
|
||||||
|
## copy(proto, objs)
|
||||||
|
|
||||||
|
|
||||||
|
**proto**: The prototype object for the new object.
|
||||||
|
|
||||||
|
**objs**: One or more objects whose properties will be mixed in.
|
||||||
|
|
||||||
|
**Returns**: The newly created object.
|
||||||
|
|
||||||
|
Create a new object with proto as its prototype, then mix in additional objects’ properties.
|
||||||
|
|
||||||
|
|
||||||
|
## obj_lerp(a, b, t)
|
||||||
|
|
||||||
|
|
||||||
|
**a**: The start object (its properties must have .lerp()).
|
||||||
|
|
||||||
|
**b**: The end object (matching properties).
|
||||||
|
|
||||||
|
**t**: Interpolation factor (0..1).
|
||||||
|
|
||||||
|
**Returns**: A new object with interpolated properties.
|
||||||
|
|
||||||
|
Linearly interpolate between two objects a and b by factor t, assuming each property
|
||||||
|
supports .lerp().
|
||||||
|
|
||||||
|
|
||||||
## normalizeSpacing(spacing)
|
## normalizeSpacing(spacing)
|
||||||
|
|
||||||
|
|
||||||
|
**spacing**: A number, an array of length 2 or 4, or an object with l/r/t/b.
|
||||||
|
|
||||||
|
**Returns**: An object {l, r, t, b}.
|
||||||
|
|
||||||
|
Normalize any spacing input into a {l, r, t, b} object.
|
||||||
|
|
||||||
|
|||||||
@@ -3,4 +3,3 @@
|
|||||||
## make_video()
|
## make_video()
|
||||||
|
|
||||||
Decode a video file (MPEG, etc.) from an ArrayBuffer, returning a datastream object.
|
Decode a video file (MPEG, etc.) from an ArrayBuffer, returning a datastream object.
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ edit_uri: edit/master/doc/docs
|
|||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- search
|
- search
|
||||||
|
- with-pdf
|
||||||
|
|
||||||
extra_css:
|
extra_css:
|
||||||
- style.css
|
- style.css
|
||||||
|
|||||||
@@ -1,37 +1,78 @@
|
|||||||
var ex = {}
|
var ex = {}
|
||||||
|
ex[prosperon.DOC] = `
|
||||||
|
A set of utilities for iterating over a hierarchy of actor-like objects, as well
|
||||||
|
as managing tag-based lookups. Objects are assumed to have a "objects" property,
|
||||||
|
pointing to children or sub-objects, forming a tree.
|
||||||
|
`
|
||||||
|
|
||||||
var eachobj = function (obj, fn) {
|
function eachobj(obj, fn) {
|
||||||
var val = fn(obj);
|
var val = fn(obj)
|
||||||
if (val) return val;
|
if (val) return val
|
||||||
for (var o in obj.objects) {
|
for (var o in obj.objects) {
|
||||||
if (obj.objects[o] === obj) console.error(`Object ${obj.toString()} is referenced by itself.`);
|
if (obj.objects[o] === obj) console.error(`Object ${obj.toString()} is referenced by itself.`)
|
||||||
val = eachobj(obj.objects[o], fn);
|
val = eachobj(obj.objects[o], fn)
|
||||||
if (val) return val;
|
if (val) return val
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
ex.all_objects = function (fn, startobj = world) {
|
ex.all_objects = function (fn, startobj = world) {
|
||||||
return eachobj(startobj, fn);
|
return eachobj(startobj, fn)
|
||||||
};
|
}
|
||||||
ex.find_object = function (fn, startobj = world) {};
|
ex.all_objects[prosperon.DOC] = `
|
||||||
|
:param fn: A callback function that receives each object. If it returns a truthy value, iteration stops and that value is returned.
|
||||||
|
:param startobj: The root object at which iteration begins, default is the global "world".
|
||||||
|
:return: The first truthy value returned by fn, or undefined if none.
|
||||||
|
Iterate over each object (and its sub-objects) in the hierarchy, calling fn for each one.
|
||||||
|
`
|
||||||
|
|
||||||
|
ex.find_object = function (fn, startobj = world) {}
|
||||||
|
ex.find_object[prosperon.DOC] = `
|
||||||
|
:param fn: A callback or criteria to locate a particular object.
|
||||||
|
:param startobj: The root object at which search begins, default "world".
|
||||||
|
:return: Not yet implemented.
|
||||||
|
Intended to find a matching object within the hierarchy.
|
||||||
|
`
|
||||||
|
|
||||||
|
var gtags = {}
|
||||||
|
|
||||||
var gtags = {};
|
|
||||||
ex.tag_add = function (tag, obj) {
|
ex.tag_add = function (tag, obj) {
|
||||||
gtags[tag] ??= new Set();
|
gtags[tag] ??= new Set()
|
||||||
gtags[tag].add(obj)
|
gtags[tag].add(obj)
|
||||||
};
|
}
|
||||||
|
ex.tag_add[prosperon.DOC] = `
|
||||||
|
:param tag: A string tag to associate with the object.
|
||||||
|
:param obj: The object to add under this tag.
|
||||||
|
:return: None
|
||||||
|
Associate the given object with the specified tag. Creates a new tag set if it does not exist.
|
||||||
|
`
|
||||||
|
|
||||||
ex.tag_rm = function (tag, obj) {
|
ex.tag_rm = function (tag, obj) {
|
||||||
delete gtags[tag].delete(obj)
|
delete gtags[tag].delete(obj)
|
||||||
};
|
}
|
||||||
|
ex.tag_rm[prosperon.DOC] = `
|
||||||
|
:param tag: The tag to remove the object from.
|
||||||
|
:param obj: The object to remove from the tag set.
|
||||||
|
:return: None
|
||||||
|
Remove the given object from the specified tag’s set, if it exists.
|
||||||
|
`
|
||||||
|
|
||||||
ex.tag_clear_guid = function (obj) {
|
ex.tag_clear_guid = function (obj) {
|
||||||
for (var tag in gtags) gtags[tag].delete(obj)
|
for (var tag in gtags) gtags[tag].delete(obj)
|
||||||
};
|
}
|
||||||
|
ex.tag_clear_guid[prosperon.DOC] = `
|
||||||
|
:param obj: The object whose tags should be cleared.
|
||||||
|
:return: None
|
||||||
|
Remove the object from all tag sets.
|
||||||
|
`
|
||||||
|
|
||||||
ex.objects_with_tag = function (tag) {
|
ex.objects_with_tag = function (tag) {
|
||||||
if (!gtags[tag]) return [];
|
if (!gtags[tag]) return []
|
||||||
return Array.from(gtags[tag])
|
return Array.from(gtags[tag])
|
||||||
};
|
}
|
||||||
|
ex.objects_with_tag[prosperon.DOC] = `
|
||||||
|
:param tag: A string tag to look up.
|
||||||
|
:return: An array of objects associated with the given tag.
|
||||||
|
Retrieve all objects currently tagged with the specified tag.
|
||||||
|
`
|
||||||
|
|
||||||
return ex
|
return ex
|
||||||
|
|||||||
@@ -253,16 +253,9 @@ Cmdline.register_order(
|
|||||||
Cmdline.register_order(
|
Cmdline.register_order(
|
||||||
"api",
|
"api",
|
||||||
function (obj) {
|
function (obj) {
|
||||||
if (!obj[0]) {
|
var doc = use('doc')
|
||||||
Cmdline.print_order("api");
|
doc.write_modules()
|
||||||
return;
|
doc.write_c_types()
|
||||||
}
|
|
||||||
|
|
||||||
use("editor.js");
|
|
||||||
var api = debug.api.print_doc(obj[0]);
|
|
||||||
if (!api) return;
|
|
||||||
|
|
||||||
console.print(api);
|
|
||||||
},
|
},
|
||||||
"Print the API for an object as markdown. Give it a file to save the output to.",
|
"Print the API for an object as markdown. Give it a file to save the output to.",
|
||||||
"OBJECT",
|
"OBJECT",
|
||||||
@@ -301,14 +294,13 @@ Cmdline.print_order = function (fn) {
|
|||||||
if (typeof fn === "string") fn = Cmdline.orders[fn];
|
if (typeof fn === "string") fn = Cmdline.orders[fn];
|
||||||
|
|
||||||
if (!fn) return;
|
if (!fn) return;
|
||||||
console.print(`Usage: prosperon ${fn.usage}`);
|
console.print(`Usage: prosperon ${fn.usage}` + "\n");
|
||||||
console.print(fn.doc);
|
console.print(fn.doc + "\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
Cmdline.register_order(
|
Cmdline.register_order(
|
||||||
"help",
|
"help",
|
||||||
function (order) {
|
function (order) {
|
||||||
|
|
||||||
if (!util.isEmpty(order)) {
|
if (!util.isEmpty(order)) {
|
||||||
var orfn = Cmdline.orders[order];
|
var orfn = Cmdline.orders[order];
|
||||||
|
|
||||||
@@ -323,7 +315,7 @@ Cmdline.register_order(
|
|||||||
|
|
||||||
Cmdline.print_order("help");
|
Cmdline.print_order("help");
|
||||||
|
|
||||||
for (var cmd of Object.keys(Cmdline.orders).sort()) console.print(cmd);
|
for (var cmd of Object.keys(Cmdline.orders).sort()) console.print(cmd + "\n");
|
||||||
|
|
||||||
Cmdline.orders.version();
|
Cmdline.orders.version();
|
||||||
},
|
},
|
||||||
@@ -340,7 +332,7 @@ Cmdline.register_order(
|
|||||||
);
|
);
|
||||||
|
|
||||||
function cmd_args(cmds) {
|
function cmd_args(cmds) {
|
||||||
var play = false;
|
cmds.shift()
|
||||||
if (cmds.length === 0) cmds[0] = "play";
|
if (cmds.length === 0) cmds[0] = "play";
|
||||||
else if (!Cmdline.orders[cmds[0]]) {
|
else if (!Cmdline.orders[cmds[0]]) {
|
||||||
console.warn(`Command ${cmds[0]} not found. Playing instead.`);
|
console.warn(`Command ${cmds[0]} not found. Playing instead.`);
|
||||||
|
|||||||
@@ -3,17 +3,139 @@ var ret = {}
|
|||||||
|
|
||||||
var io = use('io')
|
var io = use('io')
|
||||||
|
|
||||||
|
// Helper: Given an object `obj`, return either:
|
||||||
|
// - If there's no prosperon.DOC, return ''.
|
||||||
|
// - If obj[prosperon.DOC] is a string, return that (unless a sub-property was requested).
|
||||||
|
// - If obj[prosperon.DOC] is an object, return its .doc field if no prop, or doc for that prop if provided.
|
||||||
|
var docOf = function(obj, prop) {
|
||||||
|
var block = obj[prosperon.DOC]
|
||||||
|
if (typeof block === 'string') {
|
||||||
|
if (prop) return ''
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
if (!block || typeof block !== 'object') return ''
|
||||||
|
if (!prop) return block.doc || ''
|
||||||
|
return block[prop] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reusable doc parsing logic for rewriting :param and :return.
|
||||||
|
function parseDocStr(docStr) {
|
||||||
|
var out = []
|
||||||
|
if (!docStr) return out
|
||||||
|
|
||||||
|
var docLines = docStr.split('\n')
|
||||||
|
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
||||||
|
var returnRe = /^:return:\s*(.*)$/
|
||||||
|
|
||||||
|
for (var j = 0; j < docLines.length; j++) {
|
||||||
|
var line = docLines[j]
|
||||||
|
var pm = paramRe.exec(line)
|
||||||
|
var rm = returnRe.exec(line)
|
||||||
|
|
||||||
|
if (pm) {
|
||||||
|
out.push('**' + pm[1] + '**: ' + pm[2])
|
||||||
|
out.push('')
|
||||||
|
} else if (rm) {
|
||||||
|
out.push('**Returns**: ' + rm[1])
|
||||||
|
out.push('')
|
||||||
|
} else {
|
||||||
|
out.push(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively write docs for an object and its sub-objects.
|
||||||
|
// level -> how many '#' in our markdown heading
|
||||||
|
// name -> the name of this object in the heading
|
||||||
|
function writeDocsForObject(obj, lines, level, name) {
|
||||||
|
var docStr = docOf(obj)
|
||||||
|
if (docStr) {
|
||||||
|
// Print heading for the object itself
|
||||||
|
var headingLine = Array(level + 1).join('#') + ' ' + name + '\n'
|
||||||
|
lines.push(headingLine)
|
||||||
|
var docOut = parseDocStr(docStr)
|
||||||
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate properties
|
||||||
|
for (var prop in obj) {
|
||||||
|
if (!obj.hasOwnProperty(prop)) continue
|
||||||
|
var val = obj[prop]
|
||||||
|
var valDoc = val && (val[prosperon.DOC] || docOf(obj, prop)) || ''
|
||||||
|
|
||||||
|
// If it's a function, print a heading like "## area(r)"
|
||||||
|
if (typeof val === 'function') {
|
||||||
|
var paramMatches = []
|
||||||
|
var docLines = valDoc.split('\n')
|
||||||
|
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
||||||
|
for (var j = 0; j < docLines.length; j++) {
|
||||||
|
var pm = paramRe.exec(docLines[j])
|
||||||
|
if (pm) paramMatches.push(pm[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
var fnHeading = Array(level + 2).join('#') + ' ' + prop
|
||||||
|
// If paramMatches is not empty, list them in the heading
|
||||||
|
if (paramMatches.length > 0) fnHeading += '(' + paramMatches.join(', ') + ')\n'
|
||||||
|
else {
|
||||||
|
// fallback: parse from function signature
|
||||||
|
var m = val.toString().match(/\(([^)]*)\)/)
|
||||||
|
if (m) fnHeading += '(' + m[1].trim() + ')\n'
|
||||||
|
else fnHeading += '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push(fnHeading)
|
||||||
|
var parsed = parseDocStr(valDoc)
|
||||||
|
if (parsed.length > 0) lines.push(parsed.join('\n') + '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a nested object, recursively write docs for it
|
||||||
|
else if (val && typeof val === 'object') {
|
||||||
|
// We only bother if the sub-object has any doc
|
||||||
|
// or if there's a good reason to drill deeper.
|
||||||
|
// If we want to always print sub-objects, remove the doc check.
|
||||||
|
var subObjDoc = docOf(val)
|
||||||
|
if (subObjDoc) {
|
||||||
|
writeDocsForObject(val, lines, level + 1, prop)
|
||||||
|
}
|
||||||
|
// If subObjDoc is empty but the object might contain sub-doc for
|
||||||
|
// its methods, you may want to call writeDocsForObject anyway.
|
||||||
|
else {
|
||||||
|
// We can still check if any child function has a doc:
|
||||||
|
var hasChildWithDoc = false
|
||||||
|
for (var sp in val) {
|
||||||
|
if (!val.hasOwnProperty(sp)) continue
|
||||||
|
var subVal = val[sp]
|
||||||
|
if (subVal && typeof subVal === 'function' && (subVal[prosperon.DOC] || docOf(val, sp))) {
|
||||||
|
hasChildWithDoc = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasChildWithDoc) writeDocsForObject(val, lines, level + 1, prop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else (if it's something else, e.g. number/string) you might skip it or do something special
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var docs = io.enumerate("scripts/modules", 0)
|
var docs = io.enumerate("scripts/modules", 0)
|
||||||
docs = docs.filter(x => io.match("**/*.js", x)).map(x => x.name())
|
docs = docs.filter(x => io.match("**/*.js", x)).map(x => x.name())
|
||||||
|
|
||||||
var APIPATH = '.src/docs/api/'
|
var APIPATH = '.src/docs/api/'
|
||||||
|
|
||||||
ret.print_api = function(obj) {
|
ret.print_api = function(obj) {
|
||||||
|
// Old console-based printing. We'll leave as-is or minimal changes if desired.
|
||||||
|
var topDoc = docOf(obj)
|
||||||
|
if (topDoc) console.log(' doc: ' + topDoc)
|
||||||
|
|
||||||
for (var prop in obj) {
|
for (var prop in obj) {
|
||||||
if (!obj.hasOwnProperty(prop)) continue
|
if (!obj.hasOwnProperty(prop)) continue
|
||||||
var val = obj[prop]
|
var val = obj[prop]
|
||||||
console.log(prop)
|
console.log(prop)
|
||||||
if (val[prosperon.DOC]) console.log(' doc: ' + val[prosperon.DOC])
|
|
||||||
|
var docStr = val[prosperon.DOC] || docOf(obj, prop)
|
||||||
|
if (docStr) console.log(' doc: ' + docStr)
|
||||||
|
|
||||||
if (typeof val === 'function') {
|
if (typeof val === 'function') {
|
||||||
var m = val.toString().match(/\(([^)]*)\)/)
|
var m = val.toString().match(/\(([^)]*)\)/)
|
||||||
if (m) console.log(' function: ' + prop + '(' + m[1].trim() + ')')
|
if (m) console.log(' function: ' + prop + '(' + m[1].trim() + ')')
|
||||||
@@ -26,7 +148,8 @@ ret.print_modules = function() {
|
|||||||
var name = docs[i]
|
var name = docs[i]
|
||||||
var mod = use(name)
|
var mod = use(name)
|
||||||
console.log('MODULE: ' + name)
|
console.log('MODULE: ' + name)
|
||||||
if (mod[prosperon.DOC]) console.log(' doc: ' + mod[prosperon.DOC])
|
var modDoc = docOf(mod)
|
||||||
|
if (modDoc) console.log(' doc: ' + modDoc)
|
||||||
ret.print_api(mod)
|
ret.print_api(mod)
|
||||||
console.log('')
|
console.log('')
|
||||||
}
|
}
|
||||||
@@ -46,76 +169,11 @@ ret.write_modules = function() {
|
|||||||
var mod = use(name)
|
var mod = use(name)
|
||||||
var lines = []
|
var lines = []
|
||||||
|
|
||||||
|
// Top-level heading for module
|
||||||
lines.push('# ' + name + '\n')
|
lines.push('# ' + name + '\n')
|
||||||
|
|
||||||
// If the module itself has a docstring, include it
|
// Recursively write docs for the module at heading level 1
|
||||||
if (mod[prosperon.DOC]) lines.push(mod[prosperon.DOC] + '\n')
|
writeDocsForObject(mod, lines, 1, name)
|
||||||
|
|
||||||
// Now list out each property/method
|
|
||||||
for (var prop in mod) {
|
|
||||||
if (!mod.hasOwnProperty(prop)) continue
|
|
||||||
var val = mod[prop]
|
|
||||||
var docStr = val[prosperon.DOC] || ''
|
|
||||||
|
|
||||||
// Gather param names if it's a function
|
|
||||||
var paramMatches = []
|
|
||||||
if (typeof val === 'function') {
|
|
||||||
// First, parse docstring lines to see if we have any :param info
|
|
||||||
var docLines = docStr.split('\n')
|
|
||||||
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
|
||||||
for (var j = 0; j < docLines.length; j++) {
|
|
||||||
var pm = paramRe.exec(docLines[j])
|
|
||||||
if (pm) paramMatches.push(pm[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the heading
|
|
||||||
if (typeof val === 'function') {
|
|
||||||
// If we have paramMatches, use them; otherwise fall back to the function’s source
|
|
||||||
if (paramMatches.length > 0) {
|
|
||||||
lines.push('## ' + prop + '(' + paramMatches.join(', ') + ')\n')
|
|
||||||
} else {
|
|
||||||
var m = val.toString().match(/\(([^)]*)\)/)
|
|
||||||
if (m) lines.push('## ' + prop + '(' + m[1].trim() + ')\n')
|
|
||||||
else lines.push('## ' + prop + '\n') // fallback if no match
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Just a property (not a function)
|
|
||||||
lines.push('## ' + prop + '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process doc lines to rewrite :param and :return lines
|
|
||||||
var docOut = []
|
|
||||||
if (docStr) {
|
|
||||||
var docLines = docStr.split('\n')
|
|
||||||
|
|
||||||
// Regex for param lines and return lines
|
|
||||||
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
|
||||||
var returnRe = /^:return:\s*(.*)$/
|
|
||||||
|
|
||||||
for (var j = 0; j < docLines.length; j++) {
|
|
||||||
var line = docLines[j]
|
|
||||||
var pm = paramRe.exec(line)
|
|
||||||
var rm = returnRe.exec(line)
|
|
||||||
|
|
||||||
if (pm) {
|
|
||||||
docOut.push('**' + pm[1] + '**: ' + pm[2])
|
|
||||||
docOut.push('') // blank line after each param
|
|
||||||
} else if (rm) {
|
|
||||||
docOut.push('**Returns**: ' + rm[1])
|
|
||||||
docOut.push('') // blank line after the return line
|
|
||||||
} else {
|
|
||||||
docOut.push(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the doc text
|
|
||||||
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
|
||||||
|
|
||||||
// Add a trailing blank line
|
|
||||||
lines.push('')
|
|
||||||
}
|
|
||||||
|
|
||||||
var out = lines.join('\n')
|
var out = lines.join('\n')
|
||||||
io.slurpwrite(APIPATH + '/' + name + '.md', out)
|
io.slurpwrite(APIPATH + '/' + name + '.md', out)
|
||||||
@@ -140,47 +198,33 @@ ret.write_c_types = function() {
|
|||||||
// Title
|
// Title
|
||||||
lines.push('# ' + name + '\n')
|
lines.push('# ' + name + '\n')
|
||||||
|
|
||||||
// If the ctype itself has a docstring, include it
|
// If the ctype itself has a docstring (string or object.doc), include it
|
||||||
if (ctype[prosperon.DOC]) lines.push(ctype[prosperon.DOC] + '\n')
|
var ctypeDoc = docOf(ctype)
|
||||||
|
if (ctypeDoc) lines.push(ctypeDoc + '\n')
|
||||||
|
|
||||||
// Enumerate all own properties on the prototype (so we don't trigger getters)
|
// Enumerate all own properties on the prototype (so we don't trigger getters)
|
||||||
var props = Object.getOwnPropertyNames(ctype)
|
var props = Object.getOwnPropertyNames(ctype)
|
||||||
|
|
||||||
for (var p = 0; p < props.length; p++) {
|
for (var p = 0; p < props.length; p++) {
|
||||||
var propName = props[p]
|
var propName = props[p]
|
||||||
// Often the 'constructor' is on the prototype, but skip it
|
|
||||||
if (propName === 'constructor') continue
|
if (propName === 'constructor') continue
|
||||||
|
|
||||||
// Retrieve the descriptor so we don't call any getter
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(ctype, propName)
|
var desc = Object.getOwnPropertyDescriptor(ctype, propName)
|
||||||
|
|
||||||
if (!desc) continue
|
if (!desc) continue
|
||||||
|
|
||||||
// If it's a regular method (desc.value is a function)
|
if (typeof desc.value === 'function') writeMethod(lines, propName, desc.value, ctype)
|
||||||
if (typeof desc.value === 'function') {
|
if (typeof desc.get === 'function') writeGetter(lines, propName, desc.get, ctype)
|
||||||
writeMethod(lines, propName, desc.value)
|
if (typeof desc.set === 'function') writeSetter(lines, propName, desc.set, ctype)
|
||||||
}
|
|
||||||
|
|
||||||
// If there's a getter
|
|
||||||
if (typeof desc.get === 'function') {
|
|
||||||
writeGetter(lines, propName, desc.get)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's a setter
|
|
||||||
if (typeof desc.set === 'function') {
|
|
||||||
writeSetter(lines, propName, desc.set)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var out = lines.join('\n')
|
var out = lines.join('\n')
|
||||||
io.slurpwrite(CTYPEPATH + '/' + name + '.md', out)
|
io.slurpwrite(CTYPEPATH + '/' + name + '.md', out)
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeMethod(lines, prop, fn) {
|
function writeMethod(lines, prop, fn, parent) {
|
||||||
var docStr = fn[prosperon.DOC] || ''
|
var docStr = fn[prosperon.DOC] || docOf(parent, prop) || ''
|
||||||
var paramMatches = []
|
var paramMatches = []
|
||||||
|
|
||||||
// Attempt to find param declarations in docstring
|
|
||||||
if (typeof fn === 'function') {
|
if (typeof fn === 'function') {
|
||||||
var docLines = docStr.split('\n')
|
var docLines = docStr.split('\n')
|
||||||
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
||||||
@@ -190,33 +234,30 @@ ret.write_c_types = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build heading line
|
var heading = '## ' + prop
|
||||||
if (paramMatches.length > 0) {
|
if (paramMatches.length > 0) heading += '(' + paramMatches.join(', ') + ')\n'
|
||||||
lines.push('## ' + prop + '(' + paramMatches.join(', ') + ')\n')
|
else {
|
||||||
} else {
|
|
||||||
// Fallback: look at fn.toString()
|
|
||||||
var m = fn.toString().match(/\(([^)]*)\)/)
|
var m = fn.toString().match(/\(([^)]*)\)/)
|
||||||
if (m) lines.push('## ' + prop + '(' + m[1].trim() + ')\n')
|
if (m) heading += '(' + m[1].trim() + ')\n'
|
||||||
else lines.push('## ' + prop + '\n')
|
else heading += '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push doc lines
|
lines.push(heading)
|
||||||
var docOut = parseDocStr(docStr)
|
var docOut = parseDocStr(docStr)
|
||||||
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
||||||
|
|
||||||
lines.push('')
|
lines.push('')
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeGetter(lines, prop, getterFn) {
|
function writeGetter(lines, prop, getterFn, parent) {
|
||||||
lines.push('## get ' + prop + '\n')
|
lines.push('## get ' + prop + '\n')
|
||||||
var docStr = getterFn[prosperon.DOC] || ''
|
var docStr = getterFn[prosperon.DOC] || docOf(parent, prop) || ''
|
||||||
var docOut = parseDocStr(docStr)
|
var docOut = parseDocStr(docStr)
|
||||||
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
||||||
lines.push('')
|
lines.push('')
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeSetter(lines, prop, setterFn) {
|
function writeSetter(lines, prop, setterFn, parent) {
|
||||||
var docStr = setterFn[prosperon.DOC] || ''
|
var docStr = setterFn[prosperon.DOC] || docOf(parent, prop) || ''
|
||||||
var paramMatches = []
|
var paramMatches = []
|
||||||
|
|
||||||
if (typeof setterFn === 'function') {
|
if (typeof setterFn === 'function') {
|
||||||
@@ -228,47 +269,19 @@ ret.write_c_types = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paramMatches.length > 0) {
|
var heading = '## set ' + prop
|
||||||
lines.push('## set ' + prop + '(' + paramMatches.join(', ') + ')\n')
|
if (paramMatches.length > 0) heading += '(' + paramMatches.join(', ') + ')\n'
|
||||||
} else {
|
else {
|
||||||
// Fallback from function signature
|
|
||||||
var m = setterFn.toString().match(/\(([^)]*)\)/)
|
var m = setterFn.toString().match(/\(([^)]*)\)/)
|
||||||
if (m) lines.push('## set ' + prop + '(' + m[1].trim() + ')\n')
|
if (m) heading += '(' + m[1].trim() + ')\n'
|
||||||
else lines.push('## set ' + prop + '\n')
|
else heading += '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lines.push(heading)
|
||||||
var docOut = parseDocStr(docStr)
|
var docOut = parseDocStr(docStr)
|
||||||
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
||||||
lines.push('')
|
lines.push('')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same param/return rewriting logic used in write_modules
|
|
||||||
function parseDocStr(docStr) {
|
|
||||||
var out = []
|
|
||||||
if (!docStr) return out
|
|
||||||
|
|
||||||
var docLines = docStr.split('\n')
|
|
||||||
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
|
||||||
var returnRe = /^:return:\s*(.*)$/
|
|
||||||
|
|
||||||
for (var j = 0; j < docLines.length; j++) {
|
|
||||||
var line = docLines[j]
|
|
||||||
var pm = paramRe.exec(line)
|
|
||||||
var rm = returnRe.exec(line)
|
|
||||||
|
|
||||||
if (pm) {
|
|
||||||
out.push('**' + pm[1] + '**: ' + pm[2])
|
|
||||||
out.push('')
|
|
||||||
} else if (rm) {
|
|
||||||
out.push('**Returns**: ' + rm[1])
|
|
||||||
out.push('')
|
|
||||||
} else {
|
|
||||||
out.push(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -5,64 +5,102 @@ var util = use('util')
|
|||||||
var os = use('os')
|
var os = use('os')
|
||||||
|
|
||||||
var draw = {}
|
var draw = {}
|
||||||
|
draw[prosperon.DOC] = `
|
||||||
|
A collection of 2D drawing functions that operate in screen space. Provides primitives
|
||||||
|
for lines, rectangles, text, sprite drawing, etc.
|
||||||
|
`
|
||||||
|
|
||||||
var whiteimage = {}
|
var whiteimage = {}
|
||||||
whiteimage.surface = graphics.make_surface([1,1])
|
whiteimage.surface = graphics.make_surface([1,1])
|
||||||
whiteimage.surface.rect({x:0,y:0,width:1,height:1}, [1,1,1,1])
|
whiteimage.surface.rect({x:0,y:0,width:1,height:1}, [1,1,1,1])
|
||||||
whiteimage.texture = prosperon.gpu.load_texture(whiteimage.surface)
|
whiteimage.texture = prosperon.gpu.load_texture(whiteimage.surface)
|
||||||
|
|
||||||
/* All draw in screen space */
|
|
||||||
draw.point = function (pos, size, color = Color.blue) {
|
draw.point = function (pos, size, color = Color.blue) {
|
||||||
render._main.point(pos,color);
|
render._main.point(pos, color)
|
||||||
};
|
}
|
||||||
|
draw.point[prosperon.DOC] = `
|
||||||
|
:param pos: A 2D position ([x, y]) where the point should be drawn.
|
||||||
|
:param size: The size of the point (not currently affecting rendering).
|
||||||
|
:param color: The color of the point, defaults to Color.blue.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
draw.line = function render_line(points, color = Color.white, thickness = 1, pipeline) {
|
draw.line = function render_line(points, color = Color.white, thickness = 1, pipeline) {
|
||||||
var mesh = graphics.make_line_prim(points,thickness, 0,0,color);
|
var mesh = graphics.make_line_prim(points, thickness, 0, 0, color)
|
||||||
render.queue({
|
render.queue({
|
||||||
type: 'geometry',
|
type: 'geometry',
|
||||||
mesh,
|
mesh,
|
||||||
pipeline,
|
pipeline,
|
||||||
first_index:0,
|
first_index: 0,
|
||||||
num_indices:mesh.num_indices
|
num_indices: mesh.num_indices
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
draw.line[prosperon.DOC] = `
|
||||||
|
:param points: An array of 2D positions representing the line vertices.
|
||||||
|
:param color: The color of the line, default Color.white.
|
||||||
|
:param thickness: The line thickness, default 1.
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
draw.cross = function render_cross(pos, size, color = Color.red, thickness = 1, pipe) {
|
draw.cross = function render_cross(pos, size, color = Color.red, thickness = 1, pipe) {
|
||||||
var a = [pos.add([0, size]), pos.add([0, -size])];
|
var a = [pos.add([0, size]), pos.add([0, -size])]
|
||||||
var b = [pos.add([size, 0]), pos.add([-size, 0])];
|
var b = [pos.add([size, 0]), pos.add([-size, 0])]
|
||||||
draw.line(a, color, thickness);
|
draw.line(a, color, thickness)
|
||||||
draw.line(b, color, thickness);
|
draw.line(b, color, thickness)
|
||||||
};
|
}
|
||||||
|
draw.cross[prosperon.DOC] = `
|
||||||
|
:param pos: The center of the cross as a 2D position ([x, y]).
|
||||||
|
:param size: Half the size of each cross arm.
|
||||||
|
:param color: The color of the cross, default Color.red.
|
||||||
|
:param thickness: The thickness of each line, default 1.
|
||||||
|
:param pipe: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
draw.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10, pipe) {
|
draw.arrow = function render_arrow(start, end, color = Color.red, wingspan = 4, wingangle = 10, pipe) {
|
||||||
var dir = math.norm(end.sub(start))
|
var dir = math.norm(end.sub(start))
|
||||||
var wing1 = [math.rotate(dir, wingangle).scale(wingspan).add(end), end];
|
var wing1 = [math.rotate(dir, wingangle).scale(wingspan).add(end), end]
|
||||||
var wing2 = [math.rotate(dir, -wingangle).scale(wingspan).add(end), end];
|
var wing2 = [math.rotate(dir, -wingangle).scale(wingspan).add(end), end]
|
||||||
render.line([start, end], color);
|
render.line([start, end], color)
|
||||||
render.line(wing1, color);
|
render.line(wing1, color)
|
||||||
render.line(wing2, color);
|
render.line(wing2, color)
|
||||||
};
|
}
|
||||||
|
draw.arrow[prosperon.DOC] = `
|
||||||
|
:param start: The start position of the arrow ([x, y]).
|
||||||
|
:param end: The end (tip) position of the arrow ([x, y]).
|
||||||
|
:param color: The color, default Color.red.
|
||||||
|
:param wingspan: The length of each arrowhead 'wing', default 4.
|
||||||
|
:param wingangle: Wing rotation in degrees, default 10.
|
||||||
|
:param pipe: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
draw.rectangle = function render_rectangle(rect, color = Color.white, pipeline) {
|
draw.rectangle = function render_rectangle(rect, color = Color.white, pipeline) {
|
||||||
var T = os.make_transform();
|
var T = os.make_transform()
|
||||||
T.rect(rect);
|
T.rect(rect)
|
||||||
render.queue({
|
render.queue({
|
||||||
type:'sprite',
|
type: 'sprite',
|
||||||
transform:T,
|
transform: T,
|
||||||
color,
|
color,
|
||||||
pipeline,
|
pipeline,
|
||||||
image:whiteimage
|
image: whiteimage
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
draw.rectangle[prosperon.DOC] = `
|
||||||
|
:param rect: A rectangle object with {x, y, width, height}.
|
||||||
|
:param color: The fill color, default Color.white.
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
var tile_def = {repeat_x:true, repeat_y:true};
|
var tile_def = {repeat_x:true, repeat_y:true}
|
||||||
draw.tile = function(image, rect, color = Color.white, tile = tile_def, pipeline)
|
|
||||||
{
|
draw.tile = function(image, rect, color = Color.white, tile = tile_def, pipeline) {
|
||||||
if (!image) throw Error ('Need an image to render.')
|
if (!image) throw Error('Need an image to render.')
|
||||||
if (typeof image === "string")
|
if (typeof image === "string")
|
||||||
image = graphics.texture(image);
|
image = graphics.texture(image)
|
||||||
|
var mesh = render._main.tile(image.texture, {x:0,y:0,width:image.texture.width,height:image.texture.height}, rect, tile)
|
||||||
var mesh = render._main.tile(image.texture, {x:0,y:0,width:image.texture.width,height:image.texture.height}, rect, tile);
|
|
||||||
render.queue({
|
render.queue({
|
||||||
type:'geometry',
|
type:'geometry',
|
||||||
mesh,
|
mesh,
|
||||||
@@ -70,10 +108,18 @@ draw.tile = function(image, rect, color = Color.white, tile = tile_def, pipeline
|
|||||||
pipeline,
|
pipeline,
|
||||||
first_index:0,
|
first_index:0,
|
||||||
num_indices:mesh.num_indices
|
num_indices:mesh.num_indices
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
draw.tile[prosperon.DOC] = `
|
||||||
|
:param image: An image object or string path to a texture.
|
||||||
|
:param rect: A rectangle specifying draw location/size ({x, y, width, height}).
|
||||||
|
:param color: The color tint, default Color.white.
|
||||||
|
:param tile: A tiling definition ({repeat_x, repeat_y}), default tile_def.
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
`
|
||||||
|
|
||||||
// slice is given in pixels
|
|
||||||
var slice9_info = {
|
var slice9_info = {
|
||||||
tile_top:true,
|
tile_top:true,
|
||||||
tile_bottom:true,
|
tile_bottom:true,
|
||||||
@@ -81,13 +127,13 @@ var slice9_info = {
|
|||||||
tile_right:true,
|
tile_right:true,
|
||||||
tile_center_x:true,
|
tile_center_x:true,
|
||||||
tile_center_right:true
|
tile_center_right:true
|
||||||
};
|
}
|
||||||
|
|
||||||
draw.slice9 = function slice9(image, rect = [0,0], slice = 0, color = Color.white, info = slice9_info, pipeline) {
|
draw.slice9 = function slice9(image, rect = [0,0], slice = 0, color = Color.white, info = slice9_info, pipeline) {
|
||||||
if (!image) throw Error ('Need an image to render.')
|
if (!image) throw Error('Need an image to render.')
|
||||||
if (typeof image === "string")
|
if (typeof image === "string")
|
||||||
image = graphics.texture(image);
|
image = graphics.texture(image)
|
||||||
|
var mesh = render._main.slice9(image.texture, rect, util.normalizeSpacing(slice), info)
|
||||||
var mesh = render._main.slice9(image.texture, rect, util.normalizeSpacing(slice), info);
|
|
||||||
render.queue({
|
render.queue({
|
||||||
type: 'geometry',
|
type: 'geometry',
|
||||||
mesh,
|
mesh,
|
||||||
@@ -95,87 +141,123 @@ draw.slice9 = function slice9(image, rect = [0,0], slice = 0, color = Color.whit
|
|||||||
pipeline,
|
pipeline,
|
||||||
first_index:0,
|
first_index:0,
|
||||||
num_indices:mesh.num_indices
|
num_indices:mesh.num_indices
|
||||||
});
|
})
|
||||||
};
|
|
||||||
|
|
||||||
var std_sprite_cmd = {
|
|
||||||
type: 'sprite',
|
|
||||||
color: [1,1,1,1]
|
|
||||||
}
|
}
|
||||||
|
draw.slice9[prosperon.DOC] = `
|
||||||
|
:param image: An image object or string path to a texture.
|
||||||
|
:param rect: A rectangle specifying draw location/size, default [0, 0].
|
||||||
|
:param slice: The pixel inset or spacing for the 9-slice (number or object).
|
||||||
|
:param color: The color tint, default Color.white.
|
||||||
|
:param info: A slice9 info object controlling tiling of edges/corners.
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
`
|
||||||
|
|
||||||
|
var std_sprite_cmd = {type:'sprite', color:[1,1,1,1]}
|
||||||
|
|
||||||
draw.image = function image(image, rect = [0,0], rotation = 0, color, pipeline) {
|
draw.image = function image(image, rect = [0,0], rotation = 0, color, pipeline) {
|
||||||
if (!image) throw Error ('Need an image to render.')
|
if (!image) throw Error('Need an image to render.')
|
||||||
if (typeof image === "string")
|
if (typeof image === "string")
|
||||||
image = graphics.texture(image);
|
image = graphics.texture(image)
|
||||||
|
rect.width ??= image.texture.width
|
||||||
rect.width ??= image.texture.width;
|
rect.height ??= image.texture.height
|
||||||
rect.height ??= image.texture.height;
|
var cmd = Object.create(std_sprite_cmd)
|
||||||
var cmd = Object.create(std_sprite_cmd);
|
cmd.image = image
|
||||||
cmd.image = image;
|
cmd.rect = rect
|
||||||
cmd.rect = rect;
|
if (pipeline) cmd.pipeline = pipeline
|
||||||
if (pipeline) cmd.pipeline = pipeline;
|
if (color) cmd.color = color
|
||||||
if (color) cmd.color = color;
|
|
||||||
render.queue(cmd)
|
render.queue(cmd)
|
||||||
|
var sprite = graphics.make_sprite()
|
||||||
|
sprite.set_image(image)
|
||||||
|
sprite.set_rect(rect)
|
||||||
|
return sprite
|
||||||
|
}
|
||||||
|
draw.image[prosperon.DOC] = `
|
||||||
|
:param image: An image object or string path to a texture.
|
||||||
|
:param rect: A rectangle specifying draw location/size, default [0,0]; width/height default to image size.
|
||||||
|
:param rotation: Rotation in degrees (not currently used).
|
||||||
|
:param color: The color tint, default none.
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: A sprite object that was created for this draw call.
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
`
|
||||||
|
|
||||||
var sprite = graphics.make_sprite();
|
draw.images = function images(image, rects, config) {
|
||||||
sprite.set_image(image);
|
if (!image) throw Error('Need an image to render.')
|
||||||
sprite.set_rect(rect);
|
if (typeof image === "string") image = graphics.texture(image)
|
||||||
return sprite;
|
var bb = []
|
||||||
};
|
bb.width = image.texture.width
|
||||||
|
bb.height = image.texture.height
|
||||||
draw.images = function images(image, rects, config)
|
var sprites = []
|
||||||
{
|
|
||||||
if (!image) throw Error ('Need an image to render.');
|
|
||||||
if (typeof image === "string") image = graphics.texture(image);
|
|
||||||
|
|
||||||
var bb = [];
|
|
||||||
bb.width = image.texture.width;
|
|
||||||
bb.height = image.texture.height;
|
|
||||||
|
|
||||||
var sprites = [];
|
|
||||||
for (var rect of rects) {
|
for (var rect of rects) {
|
||||||
// get sprite from sprite_buf, or make a new one
|
rect.__proto__ = bb
|
||||||
rect.__proto__ = bb;
|
var sprite = graphics.make_sprite()
|
||||||
var sprite = graphics.make_sprite();
|
sprite.set_rect(rect)
|
||||||
sprite.set_rect(rect);
|
sprite.set_image(image)
|
||||||
sprite.set_image(image);
|
|
||||||
sprites.push(sprite)
|
sprites.push(sprite)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmds = graphics.make_sprite_queue(sprites, prosperon.camera, undefined)
|
var cmds = graphics.make_sprite_queue(sprites, prosperon.camera, undefined)
|
||||||
for (var i = 0; i < cmds.length; i++)
|
for (var i = 0; i < cmds.length; i++)
|
||||||
render.queue(cmds[i])
|
render.queue(cmds[i])
|
||||||
|
return sprites
|
||||||
return sprites;
|
|
||||||
}
|
}
|
||||||
|
draw.images[prosperon.DOC] = `
|
||||||
|
:param image: An image object or string path to a texture.
|
||||||
|
:param rects: An array of rectangle objects ({x, y, width, height}) to draw.
|
||||||
|
:param config: (Unused) Additional config data if needed.
|
||||||
|
:return: An array of sprite objects created and queued for rendering.
|
||||||
|
:raises Error: If no image is provided.
|
||||||
|
`
|
||||||
|
|
||||||
draw.sprites = function(sprites, sort = 0, pipeline)
|
draw.sprites = function(sprites, sort = 0, pipeline) {
|
||||||
{
|
var cmds = graphics.make_sprite_queue(sprites, prosperon.camera, pipeline, sort)
|
||||||
var cmds = graphics.make_sprite_queue(sprites, prosperon.camera, pipeline, sort);
|
|
||||||
for (var i = 0; i < cmds.length; i++)
|
for (var i = 0; i < cmds.length; i++)
|
||||||
render.queue(cmds[i]);
|
render.queue(cmds[i])
|
||||||
}
|
}
|
||||||
|
draw.sprites[prosperon.DOC] = `
|
||||||
|
:param sprites: An array of sprite objects to draw.
|
||||||
|
:param sort: Sorting mode or order, default 0.
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
draw.circle = function render_circle(pos, radius, color, inner_radius = 1, pipeline) {
|
draw.circle = function render_circle(pos, radius, color, inner_radius = 1, pipeline) {
|
||||||
render.rectangle({x:pos.x, y:pos.y, width:radius*2,height:radius*2}, color, circle_pipeline);
|
render.rectangle({x:pos.x, y:pos.y, width:radius*2,height:radius*2}, color, circle_pipeline)
|
||||||
};
|
}
|
||||||
|
draw.circle[prosperon.DOC] = `
|
||||||
|
:param pos: Center of the circle ([x, y]).
|
||||||
|
:param radius: The circle radius.
|
||||||
|
:param color: The fill color of the circle, default none.
|
||||||
|
:param inner_radius: (Unused) Possibly ring thickness, default 1.
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
var sysfont = graphics.get_font('fonts/c64.ttf', 8);
|
var sysfont = graphics.get_font('fonts/c64.ttf', 8)
|
||||||
|
|
||||||
draw.text = function text(text, rect, font = sysfont, size = 0, color = Color.white, wrap = 0, pipeline) {
|
draw.text = function text(text, rect, font = sysfont, size = 0, color = Color.white, wrap = 0, pipeline) {
|
||||||
if (typeof font === 'string')
|
if (typeof font === 'string') font = graphics.get_font(font)
|
||||||
font = graphics.get_font(font)
|
var mesh = graphics.make_text_buffer(text, rect, 0, color, wrap, font)
|
||||||
var mesh = graphics.make_text_buffer(text, rect, 0, color, wrap, font);
|
|
||||||
|
|
||||||
render.queue({
|
render.queue({
|
||||||
type: 'geometry',
|
type: 'geometry',
|
||||||
mesh,
|
mesh,
|
||||||
image: font,
|
image: font,
|
||||||
texture:font.texture,
|
texture: font.texture,
|
||||||
pipeline,
|
pipeline,
|
||||||
first_index:0,
|
first_index:0,
|
||||||
num_indices:mesh.num_indices
|
num_indices:mesh.num_indices
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
draw.text[prosperon.DOC] = `
|
||||||
|
:param text: The string to draw.
|
||||||
|
:param rect: A rectangle specifying draw position (and possibly wrapping area).
|
||||||
|
:param font: A font object or string path, default sysfont.
|
||||||
|
:param size: (Unused) Possibly intended for scaling the font size.
|
||||||
|
:param color: The text color, default Color.white.
|
||||||
|
:param wrap: Pixel width for text wrapping, default 0 (no wrap).
|
||||||
|
:param pipeline: (Optional) A pipeline or rendering state object.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
return draw
|
return draw
|
||||||
|
|||||||
@@ -1,114 +1,248 @@
|
|||||||
var geometry = this
|
var geometry = this
|
||||||
|
geometry[prosperon.DOC] = `
|
||||||
|
A collection of geometry-related functions for circles, spheres, boxes, polygons,
|
||||||
|
and rectangle utilities. Some functionality is implemented in C and exposed here.
|
||||||
|
`
|
||||||
|
|
||||||
var math = use('math')
|
var math = use('math')
|
||||||
|
|
||||||
geometry.box = {};
|
geometry.box = {}
|
||||||
geometry.box.points = function (ll, ur) {
|
geometry.box[prosperon.DOC] = `
|
||||||
return [ll, ll.add([ur.x - ll.x, 0]), ur, ll.add([0, ur.y - ll.y])];
|
An object for box-related operations. Overridden later by a function definition, so
|
||||||
};
|
its direct usage is overshadowed. Contains:
|
||||||
geometry.sphere = {};
|
- points(ll, ur): Return an array of four 2D points for a box from ll (lower-left) to ur (upper-right).
|
||||||
geometry.circle = {};
|
`
|
||||||
geometry.sphere.volume = function (r) {
|
|
||||||
return (Math.pi * r * r * r * 4) / 3;
|
|
||||||
};
|
|
||||||
geometry.sphere.random = function (r, theta = [0, 1], phi = [-0.5, 0.5]) {
|
|
||||||
if (typeof r === "number") r = [r, r];
|
|
||||||
if (typeof theta === "number") theta = [theta, theta];
|
|
||||||
if (typeof phi === "number") phi = [phi, phi];
|
|
||||||
|
|
||||||
var ra = Math.random_range(r[0], r[1]);
|
geometry.box.points = function (ll, ur) {
|
||||||
var ta = Math.turn2rad(Math.random_range(theta[0], theta[1]));
|
return [ll, ll.add([ur.x - ll.x, 0]), ur, ll.add([0, ur.y - ll.y])]
|
||||||
var pa = Math.turn2rad(Math.random_range(phi[0], phi[1]));
|
}
|
||||||
return [ra * Math.sin(ta) * Math.cos(pa), ra * Math.sin(ta) * Math.sin(pa), ra * Math.cos(ta)];
|
geometry.box.points[prosperon.DOC] = `
|
||||||
};
|
:param ll: Lower-left coordinate as a 2D vector (x,y).
|
||||||
|
:param ur: Upper-right coordinate as a 2D vector (x,y).
|
||||||
|
:return: An array of four points forming the corners of the box in order [ll, lower-right, ur, upper-left].
|
||||||
|
Compute the four corners of a box given lower-left and upper-right corners.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.sphere = {}
|
||||||
|
geometry.sphere[prosperon.DOC] = `
|
||||||
|
Sphere-related geometry functions:
|
||||||
|
- volume(r): Return the volume of a sphere with radius r.
|
||||||
|
- random(r, theta, phi): Return a random point on or inside a sphere.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.circle = {}
|
||||||
|
geometry.circle[prosperon.DOC] = `
|
||||||
|
Circle-related geometry functions:
|
||||||
|
- area(r): Return the area of a circle with radius r.
|
||||||
|
- random(r, theta): Return a random 2D point on a circle; uses sphere.random internally and extracts x,z.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.sphere.volume = function (r) {
|
||||||
|
return (Math.pi * r * r * r * 4) / 3
|
||||||
|
}
|
||||||
|
geometry.sphere.volume[prosperon.DOC] = `
|
||||||
|
:param r: The sphere radius.
|
||||||
|
:return: The volume of the sphere, calculated as (4/3) * pi * r^3.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.sphere.random = function (r, theta = [0, 1], phi = [-0.5, 0.5]) {
|
||||||
|
if (typeof r === "number") r = [r, r]
|
||||||
|
if (typeof theta === "number") theta = [theta, theta]
|
||||||
|
if (typeof phi === "number") phi = [phi, phi]
|
||||||
|
|
||||||
|
var ra = Math.random_range(r[0], r[1])
|
||||||
|
var ta = Math.turn2rad(Math.random_range(theta[0], theta[1]))
|
||||||
|
var pa = Math.turn2rad(Math.random_range(phi[0], phi[1]))
|
||||||
|
return [ra * Math.sin(ta) * Math.cos(pa), ra * Math.sin(ta) * Math.sin(pa), ra * Math.cos(ta)]
|
||||||
|
}
|
||||||
|
geometry.sphere.random[prosperon.DOC] = `
|
||||||
|
:param r: A single number (radius) or a 2-element array [minRadius, maxRadius].
|
||||||
|
:param theta: A single number or 2-element array defining the range in turns for the theta angle, default [0,1].
|
||||||
|
:param phi: A single number or 2-element array defining the range in turns for the phi angle, default [-0.5,0.5].
|
||||||
|
:return: A 3D point (x,y,z) randomly placed within a sphere.
|
||||||
|
Generate a random point inside a sphere of variable radius, distributing angles in the specified ranges.
|
||||||
|
`
|
||||||
|
|
||||||
geometry.circle.area = function (r) {
|
geometry.circle.area = function (r) {
|
||||||
return Math.pi * r * r;
|
return Math.pi * r * r
|
||||||
};
|
}
|
||||||
|
geometry.circle.area[prosperon.DOC] = `
|
||||||
|
:param r: Radius of the circle.
|
||||||
|
:return: The area, pi * r^2.
|
||||||
|
`
|
||||||
|
|
||||||
geometry.circle.random = function (r, theta) {
|
geometry.circle.random = function (r, theta) {
|
||||||
return geometry.sphere.random(r, theta).xz;
|
return geometry.sphere.random(r, theta).xz
|
||||||
};
|
}
|
||||||
|
geometry.circle.random[prosperon.DOC] = `
|
||||||
|
:param r: A radius or [minRadius, maxRadius].
|
||||||
|
:param theta: Angle range in turns (single number or [min,max]).
|
||||||
|
:return: A 2D point (x,z) in the circle, using the sphere random generator and ignoring y.
|
||||||
|
`
|
||||||
|
|
||||||
geometry.box = function (w, h) {
|
geometry.box = function (w, h) {
|
||||||
w /= 2;
|
w /= 2
|
||||||
h /= 2;
|
h /= 2
|
||||||
|
|
||||||
var points = [
|
var points = [
|
||||||
[w, h],
|
[w, h],
|
||||||
[-w, h],
|
[-w, h],
|
||||||
[-w, -h],
|
[-w, -h],
|
||||||
[w, -h],
|
[w, -h],
|
||||||
];
|
]
|
||||||
|
return points
|
||||||
return points;
|
}
|
||||||
};
|
geometry.box[prosperon.DOC] = `
|
||||||
|
:param w: The width of the box.
|
||||||
|
:param h: The height of the box.
|
||||||
|
:return: An array of four 2D points representing the corners of a rectangle centered at [0,0].
|
||||||
|
Construct a box centered at the origin with the given width and height. This overrides the box object above.
|
||||||
|
`
|
||||||
|
|
||||||
geometry.ngon = function (radius, n) {
|
geometry.ngon = function (radius, n) {
|
||||||
return geometry.arc(radius, 360, n);
|
return geometry.arc(radius, 360, n)
|
||||||
};
|
}
|
||||||
|
geometry.ngon[prosperon.DOC] = `
|
||||||
|
:param radius: The radius of the n-gon from center to each vertex.
|
||||||
|
:param n: Number of sides/vertices.
|
||||||
|
:return: An array of 2D points forming a regular n-gon.
|
||||||
|
Generates a regular n-gon by calling geometry.arc with full 360 degrees.
|
||||||
|
`
|
||||||
|
|
||||||
geometry.arc = function (radius, angle, n, start = 0) {
|
geometry.arc = function (radius, angle, n, start = 0) {
|
||||||
start = Math.deg2rad(start);
|
start = Math.deg2rad(start)
|
||||||
if (angle >= 360) angle = 360;
|
if (angle >= 360) angle = 360
|
||||||
|
if (n <= 1) return []
|
||||||
if (n <= 1) return [];
|
var points = []
|
||||||
var points = [];
|
angle = Math.deg2rad(angle)
|
||||||
|
var arclen = angle / n
|
||||||
angle = Math.deg2rad(angle);
|
for (var i = 0; i < n; i++) points.push(math.rotate([radius, 0], start + arclen * i))
|
||||||
var arclen = angle / n;
|
return points
|
||||||
for (var i = 0; i < n; i++) points.push(math.rotate([radius, 0], start + arclen * i));
|
}
|
||||||
|
geometry.arc[prosperon.DOC] = `
|
||||||
return points;
|
:param radius: The distance from center to the arc points.
|
||||||
};
|
:param angle: The total angle (in degrees) over which points are generated, capped at 360.
|
||||||
|
:param n: Number of segments (if <=1, empty array is returned).
|
||||||
|
:param start: Starting angle (in degrees), default 0.
|
||||||
|
:return: An array of 2D points along the arc.
|
||||||
|
Generate an arc (or partial circle) of n points, each angle spread equally over 'angle' degrees from 'start'.
|
||||||
|
`
|
||||||
|
|
||||||
geometry.circle.points = function (radius, n) {
|
geometry.circle.points = function (radius, n) {
|
||||||
if (n <= 1) return [];
|
if (n <= 1) return []
|
||||||
return geometry.arc(radius, 360, n);
|
return geometry.arc(radius, 360, n)
|
||||||
};
|
}
|
||||||
|
geometry.circle.points[prosperon.DOC] = `
|
||||||
|
:param radius: The circle's radius.
|
||||||
|
:param n: Number of points around the circle.
|
||||||
|
:return: An array of 2D points equally spaced around a full 360-degree circle.
|
||||||
|
Shortcut for geometry.arc(radius, 360, n).
|
||||||
|
`
|
||||||
|
|
||||||
geometry.corners2points = function (ll, ur) {
|
geometry.corners2points = function (ll, ur) {
|
||||||
return [ll, ll.add([ur.x, 0]), ur, ll.add([0, ur.y])];
|
return [ll, ll.add([ur.x, 0]), ur, ll.add([0, ur.y])]
|
||||||
};
|
}
|
||||||
|
geometry.corners2points[prosperon.DOC] = `
|
||||||
for (var i in geometry)
|
:param ll: Lower-left 2D coordinate.
|
||||||
geometry[i] = geometry[i]
|
:param ur: Upper-right 2D coordinate (relative offset in x,y).
|
||||||
|
:return: A four-point array of corners [ll, lower-right, upper-right, upper-left].
|
||||||
|
Similar to box.points, but calculates differently.
|
||||||
|
`
|
||||||
|
|
||||||
geometry.sortpointsccw = function (points) {
|
geometry.sortpointsccw = function (points) {
|
||||||
var cm = points2cm(points);
|
var cm = points2cm(points)
|
||||||
var cmpoints = points.map(function (x) {
|
var cmpoints = points.map(function (x) { return x.sub(cm) })
|
||||||
return x.sub(cm);
|
|
||||||
});
|
|
||||||
var ccw = cmpoints.sort(function (a, b) {
|
var ccw = cmpoints.sort(function (a, b) {
|
||||||
var aatan = Math.atan2(a.y, a.x);
|
var aatan = Math.atan2(a.y, a.x)
|
||||||
var batan = Math.atan2(b.y, b.x);
|
var batan = Math.atan2(b.y, b.x)
|
||||||
return aatan - batan;
|
return aatan - batan
|
||||||
});
|
})
|
||||||
|
return ccw.map(function (x) { return x.add(cm) })
|
||||||
|
}
|
||||||
|
geometry.sortpointsccw[prosperon.DOC] = `
|
||||||
|
:param points: An array of 2D points.
|
||||||
|
:return: A new array of the same points, sorted counterclockwise around their centroid.
|
||||||
|
Sort an array of points in CCW order based on their angles from the centroid.
|
||||||
|
`
|
||||||
|
|
||||||
return ccw.map(function (x) {
|
function points2cm(pts) {
|
||||||
return x.add(cm);
|
var x = 0
|
||||||
});
|
var y = 0
|
||||||
};
|
var n = pts.length
|
||||||
|
pts.forEach(function (p) {
|
||||||
geometry.points2cm = function(points)
|
x += p[0]
|
||||||
{
|
y += p[1]
|
||||||
var x = 0;
|
})
|
||||||
var y = 0;
|
return [x / n, y / n]
|
||||||
var n = points.length;
|
|
||||||
points.forEach(function (p) {
|
|
||||||
x = x + p[0];
|
|
||||||
y = y + p[1];
|
|
||||||
});
|
|
||||||
|
|
||||||
return [x / n, y / n];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
geometry.rect_intersection[prosperon.DOC] = "Return the intersection of two rectangles (x,y,w,h). The result may be empty if no intersection."
|
geometry.points2cm = function(points) {
|
||||||
geometry.rect_intersects[prosperon.DOC] = "Return a boolean indicating if two rectangles overlap."
|
var x = 0
|
||||||
geometry.rect_expand[prosperon.DOC] = "Merge or combine two rectangles, returning their bounding rectangle."
|
var y = 0
|
||||||
geometry.rect_inside[prosperon.DOC] = "Return true if the first rectangle is completely inside the second."
|
var n = points.length
|
||||||
geometry.rect_random[prosperon.DOC] = "Return a random point within the given rectangle (uniform distribution)."
|
points.forEach(function (p) {
|
||||||
geometry.cwh2rect[prosperon.DOC] = "Helper: convert a center point and width/height vector to a rect object."
|
x += p[0]
|
||||||
geometry.rect_point_inside[prosperon.DOC] = "Return true if the given point is inside the given rectangle."
|
y += p[1]
|
||||||
geometry.rect_pos[prosperon.DOC] = "Return just the (x,y) position of a rectangle as a 2D array."
|
})
|
||||||
geometry.rect_move[prosperon.DOC] = "Offset a rectangle by a 2D vector."
|
return [x / n, y / n]
|
||||||
|
}
|
||||||
|
geometry.points2cm[prosperon.DOC] = `
|
||||||
|
:param points: An array of 2D points.
|
||||||
|
:return: The centroid (average x,y) of the given points.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_intersection[prosperon.DOC] = `
|
||||||
|
:param a: The first rectangle as {x, y, w, h}.
|
||||||
|
:param b: The second rectangle as {x, y, w, h}.
|
||||||
|
:return: A rectangle that is the intersection of the two. May have zero width/height if no overlap.
|
||||||
|
Return the intersection of two rectangles. The result may be empty if no intersection.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_intersects[prosperon.DOC] = `
|
||||||
|
:param a: Rectangle {x,y,w,h}.
|
||||||
|
:param b: Rectangle {x,y,w,h}.
|
||||||
|
:return: A boolean indicating whether the two rectangles overlap.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_expand[prosperon.DOC] = `
|
||||||
|
:param a: Rectangle {x,y,w,h}.
|
||||||
|
:param b: Rectangle {x,y,w,h}.
|
||||||
|
:return: A new rectangle that covers the bounds of both input rectangles.
|
||||||
|
Merge or combine two rectangles, returning their bounding rectangle.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_inside[prosperon.DOC] = `
|
||||||
|
:param inner: A rectangle to test.
|
||||||
|
:param outer: A rectangle that may contain 'inner'.
|
||||||
|
:return: True if 'inner' is completely inside 'outer', otherwise false.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_random[prosperon.DOC] = `
|
||||||
|
:param rect: A rectangle {x,y,w,h}.
|
||||||
|
:return: A random point within the rectangle (uniform distribution).
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.cwh2rect[prosperon.DOC] = `
|
||||||
|
:param center: A 2D point [cx, cy].
|
||||||
|
:param wh: A 2D size [width, height].
|
||||||
|
:return: A rectangle {x, y, w, h} with x,y set to center and w,h set to the given size.
|
||||||
|
Helper: convert a center point and width/height vector to a rect object.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_point_inside[prosperon.DOC] = `
|
||||||
|
:param rect: A rectangle {x,y,w,h}.
|
||||||
|
:param point: A 2D point [px, py].
|
||||||
|
:return: True if the point lies inside the rectangle, otherwise false.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_pos[prosperon.DOC] = `
|
||||||
|
:param rect: A rectangle {x,y,w,h}.
|
||||||
|
:return: A 2D vector [x,y] giving the rectangle's position.
|
||||||
|
`
|
||||||
|
|
||||||
|
geometry.rect_move[prosperon.DOC] = `
|
||||||
|
:param rect: A rectangle {x,y,w,h}.
|
||||||
|
:param offset: A 2D vector to add to the rectangle's position.
|
||||||
|
:return: A new rectangle with updated x,y offset.
|
||||||
|
`
|
||||||
|
|
||||||
return geometry
|
return geometry
|
||||||
|
|||||||
@@ -1,215 +1,308 @@
|
|||||||
var graphics = this
|
var graphics = this
|
||||||
|
graphics[prosperon.DOC] = `
|
||||||
|
Provides functionality for loading and managing images, fonts, textures, and sprite meshes.
|
||||||
|
Includes both JavaScript and C-implemented routines for creating geometry buffers, performing
|
||||||
|
rectangle packing, etc.
|
||||||
|
`
|
||||||
|
|
||||||
var io = use('io')
|
var io = use('io')
|
||||||
var res = use('resources')
|
var res = use('resources')
|
||||||
|
|
||||||
function calc_image_size(img)
|
function calc_image_size(img) {
|
||||||
{
|
if (!img.texture || !img.rect) return
|
||||||
if (!img.texture || !img.rect) return;
|
return [img.texture.width * img.rect.width, img.texture.height * img.rect.height]
|
||||||
return [img.texture.width*img.rect.width, img.texture.height*img.rect.height];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function create_image(path)
|
/**
|
||||||
{
|
Internally loads image data from disk and prepares a GPU texture. Used by graphics.texture().
|
||||||
var data = io.slurpbytes(path);
|
Not intended for direct user calls.
|
||||||
var newimg;
|
*/
|
||||||
switch(path.ext()) {
|
function create_image(path) {
|
||||||
|
var data = io.slurpbytes(path)
|
||||||
|
var newimg
|
||||||
|
switch (path.ext()) {
|
||||||
case 'gif':
|
case 'gif':
|
||||||
newimg = graphics.make_gif(data);
|
newimg = graphics.make_gif(data)
|
||||||
if (newimg.surface)
|
if (newimg.surface)
|
||||||
newimg.texture = prosperon.gpu.load_texture(newimg.surface);
|
newimg.texture = prosperon.gpu.load_texture(newimg.surface)
|
||||||
else
|
else
|
||||||
for (var frame of newimg.frames)
|
for (var frame of newimg.frames)
|
||||||
frame.texture = prosperon.gpu.load_texture(frame.surface);
|
frame.texture = prosperon.gpu.load_texture(frame.surface)
|
||||||
break;
|
break
|
||||||
case 'ase':
|
case 'ase':
|
||||||
case 'aseprite':
|
case 'aseprite':
|
||||||
newimg = graphics.make_aseprite(data);
|
newimg = graphics.make_aseprite(data)
|
||||||
if (newimg.surface)
|
if (newimg.surface)
|
||||||
newimg.texture = prosperon.gpu.load_texture(newimg.surface);
|
newimg.texture = prosperon.gpu.load_texture(newimg.surface)
|
||||||
else {
|
else {
|
||||||
for (var anim in newimg) {
|
for (var anim in newimg) {
|
||||||
var a = newimg[anim];
|
var a = newimg[anim]
|
||||||
for (var frame of a.frames)
|
for (var frame of a.frames)
|
||||||
frame.texture = prosperon.gpu.load_texture(frame.surface);
|
frame.texture = prosperon.gpu.load_texture(frame.surface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break
|
||||||
default:
|
default:
|
||||||
newimg = {
|
newimg = {
|
||||||
surface: graphics.make_texture(data)
|
surface: graphics.make_texture(data)
|
||||||
};
|
}
|
||||||
newimg.texture = prosperon.gpu.load_texture(newimg.surface);
|
newimg.texture = prosperon.gpu.load_texture(newimg.surface)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
return newimg;
|
return newimg
|
||||||
}
|
}
|
||||||
|
|
||||||
var image = {};
|
var image = {}
|
||||||
image.dimensions = function()
|
image.dimensions = function() {
|
||||||
{
|
return [this.texture.width, this.texture.height].scale([this.rect[2], this.rect[3]])
|
||||||
return [this.texture.width, this.texture.height].scale([this.rect[2], this.rect[3]]);
|
}
|
||||||
|
image.dimensions[prosperon.DOC] = `
|
||||||
|
:return: A 2D array [width, height] that is the scaled size of this image (texture size * rect size).
|
||||||
|
`
|
||||||
|
|
||||||
|
var spritesheet
|
||||||
|
var sheet_frames = []
|
||||||
|
var sheetsize = 1024
|
||||||
|
|
||||||
|
/**
|
||||||
|
Pack multiple images into a single texture sheet for efficiency.
|
||||||
|
Currently unimplemented (returns immediately).
|
||||||
|
*/
|
||||||
|
function pack_into_sheet(images) {
|
||||||
|
return
|
||||||
|
// This code is currently disabled with an immediate return.
|
||||||
|
// Implementation details commented out below.
|
||||||
}
|
}
|
||||||
|
|
||||||
var spritesheet;
|
graphics.is_image = function(obj) {
|
||||||
var sheet_frames = [];
|
if (obj.texture && obj.rect) return true
|
||||||
var sheetsize = 1024;
|
|
||||||
|
|
||||||
function pack_into_sheet(images)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
if (!Array.isArray(images)) images = [images];
|
|
||||||
if (images[0].texture.width > 300 && images[0].texture.height > 300) return;
|
|
||||||
sheet_frames = sheet_frames.concat(images);
|
|
||||||
var sizes = sheet_frames.map(x => [x.rect.width*x.texture.width, x.rect.height*x.texture.height]);
|
|
||||||
var pos = graphics.rectpack(sheetsize, sheetsize, sizes);
|
|
||||||
if (!pos) {
|
|
||||||
console.error(`did not make spritesheet properly from images ${images}`);
|
|
||||||
console.info(sizes);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var newsheet = graphics.make_tex_data(sheetsize,sheetsize);
|
|
||||||
|
|
||||||
for (var i = 0; i < pos.length; i++) {
|
|
||||||
// Copy the texture to the new sheet
|
|
||||||
newsheet.copy(sheet_frames[i].texture, pos[i], sheet_frames[i].rect);
|
|
||||||
|
|
||||||
// Update the frame's rect to the new position in normalized coordinates
|
|
||||||
sheet_frames[i].rect.x = pos[i][0] / newsheet.width;
|
|
||||||
sheet_frames[i].rect.y = pos[i][1] / newsheet.height;
|
|
||||||
sheet_frames[i].rect.width = sizes[i][0] / newsheet.width;
|
|
||||||
sheet_frames[i].rect.height = sizes[i][1] / newsheet.height;
|
|
||||||
sheet_frames[i].texture = newsheet;
|
|
||||||
}
|
|
||||||
|
|
||||||
newsheet.load_gpu();
|
|
||||||
spritesheet = newsheet;
|
|
||||||
return spritesheet;
|
|
||||||
}
|
}
|
||||||
|
graphics.is_image[prosperon.DOC] = `
|
||||||
|
:param obj: An object to check.
|
||||||
|
:return: True if 'obj' has a .texture and a .rect property, indicating it's an image object.
|
||||||
|
`
|
||||||
|
|
||||||
graphics.is_image = function(obj)
|
|
||||||
{
|
|
||||||
if (obj.texture && obj.rect) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any request to it returns an image, which is a texture and rect.
|
|
||||||
graphics.texture = function texture(path) {
|
graphics.texture = function texture(path) {
|
||||||
if (typeof path !== 'string') {
|
if (typeof path !== 'string') {
|
||||||
return path;
|
return path // fallback if already an image object
|
||||||
throw new Error('need a string for graphics.texture')
|
throw new Error('need a string for graphics.texture')
|
||||||
}
|
}
|
||||||
var parts = path.split(':');
|
var parts = path.split(':')
|
||||||
var ipath = res.find_image(parts[0]);
|
var ipath = res.find_image(parts[0])
|
||||||
|
graphics.texture.cache[ipath] ??= create_image(ipath)
|
||||||
graphics.texture.cache[ipath] ??= create_image(ipath);
|
return graphics.texture.cache[ipath]
|
||||||
return graphics.texture.cache[ipath];
|
|
||||||
}
|
}
|
||||||
|
graphics.texture[prosperon.DOC] = `
|
||||||
|
:param path: A string path to an image file or an already-loaded image object.
|
||||||
|
:return: An image object with {surface, texture, frames?, etc.} depending on the format.
|
||||||
|
Load or retrieve a cached image, converting it into a GPU texture. If 'path' is already an object, it’s returned directly.
|
||||||
|
`
|
||||||
|
|
||||||
graphics.texture.cache = {};
|
graphics.texture.cache = {}
|
||||||
graphics.texture.time_cache = {};
|
graphics.texture.time_cache = {}
|
||||||
|
|
||||||
graphics.texture.total_size = function()
|
graphics.texture.total_size = function() {
|
||||||
{
|
var size = 0
|
||||||
var size = 0;
|
// Not yet implemented, presumably sum of (texture.width * texture.height * 4) for images in RAM
|
||||||
// Object.values(graphics.texture.cache).forEach(x => size += x.texture.inram() ? x..texture.width*x.texture.height*4 : 0);
|
return size
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
graphics.texture.total_size[prosperon.DOC] = `
|
||||||
|
:return: The total estimated memory size of all cached textures in RAM, in bytes. (Not yet implemented.)
|
||||||
|
`
|
||||||
|
|
||||||
graphics.texture.total_vram = function()
|
graphics.texture.total_vram = function() {
|
||||||
{
|
var vram = 0
|
||||||
var vram = 0;
|
// Not yet implemented, presumably sum of GPU memory usage
|
||||||
// Object.values(graphics.texture.cache).forEach(x => vram += x.vram);
|
return vram
|
||||||
return vram;
|
|
||||||
}
|
|
||||||
|
|
||||||
function merge_objects(ov,nv,arr)
|
|
||||||
{
|
|
||||||
arr.forEach(x => ov[x] = nv[x])
|
|
||||||
}
|
}
|
||||||
|
graphics.texture.total_vram[prosperon.DOC] = `
|
||||||
|
:return: The total estimated GPU memory usage of all cached textures, in bytes. (Not yet implemented.)
|
||||||
|
`
|
||||||
|
|
||||||
graphics.tex_hotreload = function tex_hotreload(file) {
|
graphics.tex_hotreload = function tex_hotreload(file) {
|
||||||
console.log(`hot reloading ${file}`)
|
console.log(`hot reloading ${file}`)
|
||||||
if (!(file in graphics.texture.cache)) return;
|
if (!(file in graphics.texture.cache)) return
|
||||||
console.log('really doing it')
|
console.log('really doing it')
|
||||||
|
|
||||||
var img = create_image(file);
|
var img = create_image(file)
|
||||||
var oldimg = graphics.texture.cache[file];
|
var oldimg = graphics.texture.cache[file]
|
||||||
console.log(`new image:${json.encode(img)}`)
|
console.log(`new image:${json.encode(img)}`)
|
||||||
console.log(`old image: ${json.encode(oldimg)}`)
|
console.log(`old image: ${json.encode(oldimg)}`)
|
||||||
|
|
||||||
merge_objects(oldimg,img, ['surface', 'texture', 'loop', 'time']);
|
|
||||||
// graphics.texture.cache[file] = img;
|
|
||||||
};
|
|
||||||
|
|
||||||
function make_spritesheet(paths, width, height)
|
merge_objects(oldimg, img, ['surface', 'texture', 'loop', 'time'])
|
||||||
{
|
}
|
||||||
|
graphics.tex_hotreload[prosperon.DOC] = `
|
||||||
|
:param file: The file path that was changed on disk.
|
||||||
|
:return: None
|
||||||
|
Reload the image for the given file, updating the cached copy in memory and GPU.
|
||||||
|
`
|
||||||
|
|
||||||
|
/**
|
||||||
|
Merges specific properties from nv into ov, using an array of property names.
|
||||||
|
*/
|
||||||
|
function merge_objects(ov, nv, arr) {
|
||||||
|
arr.forEach(x => ov[x] = nv[x])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Unimplemented function for creating a spritesheet out of multiple images.
|
||||||
|
*/
|
||||||
|
function make_spritesheet(paths, width, height) {
|
||||||
return
|
return
|
||||||
var textures = paths.map(path => graphics.texture(path));
|
|
||||||
var sizes = textures.map(tex => [tex.width, tex.height]);
|
|
||||||
var pos = graphics.rectpack(width, height, sizes);
|
|
||||||
if (!pos) return;
|
|
||||||
|
|
||||||
var sheet = graphics.make_tex_data(width,height);
|
|
||||||
|
|
||||||
var st = profile.now();
|
|
||||||
for (var i = 0; i < pos.length; i++)
|
|
||||||
sheet.copy(textures[i], pos[i].x, pos[i].y);
|
|
||||||
|
|
||||||
sheet.save("spritesheet.qoi");
|
|
||||||
|
|
||||||
sheet.load_gpu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var fontcache = {};
|
/**
|
||||||
var datas= [];
|
Stores previously loaded fonts. Keyed by e.g. "path.ttf.16" -> fontObject.
|
||||||
graphics.get_font = function get_font(path,size)
|
*/
|
||||||
{
|
var fontcache = {}
|
||||||
var parts = path.split('.');
|
var datas = []
|
||||||
|
|
||||||
|
graphics.get_font = function get_font(path, size) {
|
||||||
|
var parts = path.split('.')
|
||||||
if (!isNaN(parts[1])) {
|
if (!isNaN(parts[1])) {
|
||||||
path = parts[0];
|
path = parts[0]
|
||||||
size = Number(parts[1]);
|
size = Number(parts[1])
|
||||||
}
|
}
|
||||||
var fullpath = res.find_font(path);
|
var fullpath = res.find_font(path)
|
||||||
if (!fullpath) throw new Error(`Cannot load font ${path}`)
|
if (!fullpath) throw new Error(`Cannot load font ${path}`)
|
||||||
|
|
||||||
var fontstr = `${fullpath}.${size}`;
|
|
||||||
if (fontcache[fontstr]) return fontcache[fontstr];
|
|
||||||
|
|
||||||
var data = io.slurpbytes(fullpath);
|
|
||||||
fontcache[fontstr] = graphics.make_font(data,size);
|
|
||||||
fontcache[fontstr].texture = prosperon.gpu.load_texture(fontcache[fontstr].surface);
|
|
||||||
return fontcache[fontstr];
|
|
||||||
}
|
|
||||||
|
|
||||||
graphics.queue_sprite_mesh = function(queue)
|
var fontstr = `${fullpath}.${size}`
|
||||||
{
|
if (fontcache[fontstr]) return fontcache[fontstr]
|
||||||
var sprites = queue.filter(x => x.type === 'sprite');
|
|
||||||
if (sprites.length === 0) return [];
|
var data = io.slurpbytes(fullpath)
|
||||||
var mesh = graphics.make_sprite_mesh(sprites);
|
fontcache[fontstr] = graphics.make_font(data, size)
|
||||||
|
fontcache[fontstr].texture = prosperon.gpu.load_texture(fontcache[fontstr].surface)
|
||||||
|
return fontcache[fontstr]
|
||||||
|
}
|
||||||
|
graphics.get_font[prosperon.DOC] = `
|
||||||
|
:param path: A string path to a font file, optionally with ".size" appended.
|
||||||
|
:param size: Pixel size of the font, if not included in 'path'.
|
||||||
|
:return: A font object with .surface and .texture for rendering text.
|
||||||
|
Load a font from file if not cached, or retrieve from cache if already loaded.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.queue_sprite_mesh = function(queue) {
|
||||||
|
var sprites = queue.filter(x => x.type === 'sprite')
|
||||||
|
if (sprites.length === 0) return []
|
||||||
|
var mesh = graphics.make_sprite_mesh(sprites)
|
||||||
for (var i = 0; i < sprites.length; i++) {
|
for (var i = 0; i < sprites.length; i++) {
|
||||||
sprites[i].mesh = mesh;
|
sprites[i].mesh = mesh
|
||||||
sprites[i].first_index = i*6;
|
sprites[i].first_index = i*6
|
||||||
sprites[i].num_indices = 6;
|
sprites[i].num_indices = 6
|
||||||
}
|
}
|
||||||
|
return [mesh.pos, mesh.uv, mesh.color, mesh.indices]
|
||||||
return [mesh.pos,mesh.uv,mesh.color,mesh.indices]
|
|
||||||
}
|
}
|
||||||
|
graphics.queue_sprite_mesh[prosperon.DOC] = `
|
||||||
|
:param queue: An array of draw commands, some of which are {type:'sprite'} objects.
|
||||||
|
:return: An array of references to GPU buffers [pos,uv,color,indices].
|
||||||
|
Builds a single geometry mesh for all sprite-type commands in the queue, storing first_index/num_indices
|
||||||
|
so they can be rendered in one draw call.
|
||||||
|
`
|
||||||
|
|
||||||
graphics.make_sprite_mesh[prosperon.DOC] = "Given an array of sprites, build a single geometry mesh for rendering them."
|
graphics.make_sprite_mesh[prosperon.DOC] = `
|
||||||
graphics.make_sprite_queue[prosperon.DOC] = "Given an array of sprites, optionally sort them and build a queue of pipeline commands."
|
:param sprites: An array of sprite objects, each containing .rect (or transform), .src (UV region), .color, etc.
|
||||||
graphics.make_text_buffer[prosperon.DOC] = "Generate a GPU buffer mesh of text quads for rendering with a font, etc."
|
:param oldMesh (optional): An existing mesh object to reuse/resize if possible.
|
||||||
graphics.rectpack[prosperon.DOC] = "Perform a rectangle packing using the stbrp library. Return positions for each rect."
|
:return: A GPU mesh object with pos, uv, color, and indices buffers for all sprites.
|
||||||
graphics.make_rtree[prosperon.DOC] = "Create a new R-Tree for quickly querying many rectangles or sprite bounds."
|
Given an array of sprites, build a single geometry mesh for rendering them.
|
||||||
graphics.make_texture[prosperon.DOC] = "Convert raw image bytes (PNG, JPG) into an SDL_Surface object."
|
`
|
||||||
graphics.make_gif[prosperon.DOC] = "Load a GIF from an array of bytes, returning an object with frames[] of surfaces."
|
|
||||||
graphics.make_aseprite[prosperon.DOC] = "Load an Aseprite/ASE file from an array of bytes, returning frames or animations."
|
|
||||||
graphics.cull_sprites[prosperon.DOC] = "Filter an array of sprites to only those visible in the provided camera's view."
|
|
||||||
graphics.rects_to_sprites[prosperon.DOC] = "Convert an array of rect coords into sprite objects referencing an image."
|
|
||||||
graphics.make_surface[prosperon.DOC] = "Create a blank RGBA surface with the given dimensions. For software rendering or icons."
|
|
||||||
graphics.make_cursor[prosperon.DOC] = "Create an SDL_Cursor from an existing surface and a given hotspot location."
|
|
||||||
graphics.make_font[prosperon.DOC] = "Load a font from TTF/OTF data (an ArrayBuffer) at the given pixel size."
|
|
||||||
graphics.make_sprite[prosperon.DOC] = "Create a new sprite object, which has rect, color, layer, and image references."
|
|
||||||
graphics.make_line_prim[prosperon.DOC] = "Build a GPU mesh representing a thick polyline from an array of points, using parsl."
|
|
||||||
|
|
||||||
|
graphics.make_sprite_queue[prosperon.DOC] = `
|
||||||
|
:param sprites: An array of sprite objects.
|
||||||
|
:param camera: (unused in the C code example) Typically a camera or transform for sorting?
|
||||||
|
:param pipeline: A pipeline object for rendering.
|
||||||
|
:param sort: An integer or boolean for whether to sort sprites; if truthy, sorts by layer & texture.
|
||||||
|
:return: An array of pipeline commands: geometry with mesh references, grouped by image.
|
||||||
|
Given an array of sprites, optionally sort them, then build a queue of pipeline commands.
|
||||||
|
Each group with a shared image becomes one command.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_text_buffer[prosperon.DOC] = `
|
||||||
|
:param text: The string to render.
|
||||||
|
:param rect: A rectangle specifying position and possibly wrapping.
|
||||||
|
:param angle: Rotation angle (unused or optional).
|
||||||
|
:param color: A color for the text (could be a vec4).
|
||||||
|
:param wrap: The width in pixels to wrap text, or 0 for no wrap.
|
||||||
|
:param font: A font object created by graphics.make_font or graphics.get_font.
|
||||||
|
:return: A geometry buffer mesh (pos, uv, color, indices) for rendering text.
|
||||||
|
Generate a GPU buffer mesh of text quads for rendering with a font, etc.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.rectpack[prosperon.DOC] = `
|
||||||
|
:param width: The width of the area to pack into.
|
||||||
|
:param height: The height of the area to pack into.
|
||||||
|
:param sizes: An array of [w,h] pairs for the rectangles to pack.
|
||||||
|
:return: An array of [x,y] coordinates placing each rect, or null if they don't fit.
|
||||||
|
Perform a rectangle packing using the stbrp library. Return positions for each rect.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_rtree[prosperon.DOC] = `
|
||||||
|
:return: An R-Tree object for quickly querying many rectangles or sprite bounds.
|
||||||
|
Create a new R-Tree for geometry queries.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_texture[prosperon.DOC] = `
|
||||||
|
:param data: Raw image bytes (PNG, JPG, etc.) as an ArrayBuffer.
|
||||||
|
:return: An SDL_Surface object representing the decoded image in RAM, for use with GPU or software rendering.
|
||||||
|
Convert raw image bytes into an SDL_Surface object.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_gif[prosperon.DOC] = `
|
||||||
|
:param data: An ArrayBuffer containing GIF data.
|
||||||
|
:return: An object with frames[], each frame having its own .surface. Some also have a .texture for GPU use.
|
||||||
|
Load a GIF, returning its frames. If it's a single-frame GIF, the result may have .surface only.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_aseprite[prosperon.DOC] = `
|
||||||
|
:param data: An ArrayBuffer containing Aseprite (ASE) file data.
|
||||||
|
:return: An object containing frames or animations, each with .surface. May also have top-level .surface for a single-layer case.
|
||||||
|
Load an Aseprite/ASE file from an array of bytes, returning frames or animations.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.cull_sprites[prosperon.DOC] = `
|
||||||
|
:param sprites: An array of sprite objects (each has rect or transform).
|
||||||
|
:param camera: A camera or bounding rectangle defining the view area.
|
||||||
|
:return: A new array of sprites that are visible in the camera's view.
|
||||||
|
Filter an array of sprites to only those visible in the provided camera’s view.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.rects_to_sprites[prosperon.DOC] = `
|
||||||
|
:param rects: An array of rect coords or objects.
|
||||||
|
:param image: An image object (with .texture).
|
||||||
|
:return: An array of sprite objects referencing the 'image' and each rect for UV or position.
|
||||||
|
Convert an array of rect coords into sprite objects referencing a single image.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_surface[prosperon.DOC] = `
|
||||||
|
:param dimensions: The size object {width, height}, or an array [w,h].
|
||||||
|
:return: A blank RGBA surface with the given dimensions, typically for software rendering or icons.
|
||||||
|
Create a blank surface in RAM.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_cursor[prosperon.DOC] = `
|
||||||
|
:param opts: An object with {surface, hotx, hoty} or similar.
|
||||||
|
:return: An SDL_Cursor object referencing the given surface for a custom mouse cursor.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_font[prosperon.DOC] = `
|
||||||
|
:param data: TTF/OTF file data as an ArrayBuffer.
|
||||||
|
:param size: Pixel size for rendering glyphs.
|
||||||
|
:return: A font object with surface, texture, and glyph data, for text rendering with make_text_buffer.
|
||||||
|
Load a font from TTF/OTF data at the given size.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_sprite[prosperon.DOC] = `
|
||||||
|
:return: A new sprite object, which typically has .rect, .color, .layer, .image, etc.
|
||||||
|
Create a new sprite object, storing default properties.
|
||||||
|
`
|
||||||
|
|
||||||
|
graphics.make_line_prim[prosperon.DOC] = `
|
||||||
|
:param points: An array of [x,y] points forming the line.
|
||||||
|
:param thickness: The thickness (width) of the polyline.
|
||||||
|
:param startCap: (Unused) Possibly the type of cap for the start.
|
||||||
|
:param endCap: (Unused) Possibly the type of cap for the end.
|
||||||
|
:param color: A color to apply to the line.
|
||||||
|
:return: A geometry mesh object suitable for rendering the line via a pipeline command.
|
||||||
|
Build a GPU mesh representing a thick polyline from an array of points, using parsl or a similar library under the hood.
|
||||||
|
`
|
||||||
|
|
||||||
return graphics
|
return graphics
|
||||||
|
|||||||
728
scripts/modules/imgui.js
Normal file
728
scripts/modules/imgui.js
Normal file
@@ -0,0 +1,728 @@
|
|||||||
|
var imgui = this;
|
||||||
|
|
||||||
|
var debug = {}
|
||||||
|
|
||||||
|
function imtoggle(name, obj, field) {
|
||||||
|
var changed = false;
|
||||||
|
var old = obj[field];
|
||||||
|
obj[field] = imgui.checkbox(name, obj[field]);
|
||||||
|
if (old !== obj[field]) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
imgui.prosperon_menu = function prosperon_menu() {
|
||||||
|
imgui.newframe();
|
||||||
|
|
||||||
|
if (debug.console)
|
||||||
|
debug.console = imgui.window("console", _ => {
|
||||||
|
imgui.text(console.transcript);
|
||||||
|
replstr = imgui.textinput(undefined, replstr);
|
||||||
|
imgui.button("submit", _ => {
|
||||||
|
eval(replstr);
|
||||||
|
replstr = "";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
imgui.mainmenubar(_ => {
|
||||||
|
imgui.menu("File", _ => {
|
||||||
|
imgui.menu("Game settings", _ => {
|
||||||
|
prosperon.title = imgui.textinput("Title", prosperon.title);
|
||||||
|
prosperon.icon = imgui.textinput("Icon", prosperon.icon);
|
||||||
|
imgui.button("Refresh window", _ => {
|
||||||
|
prosperon.set_icon(graphics.texture(prosperon.icon));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
imgui.button("quit", os.exit);
|
||||||
|
});
|
||||||
|
imgui.menu("Debug", imdebug);
|
||||||
|
imgui.menu("View", _ => {
|
||||||
|
imtoggle("Terminal out", debug, "termout");
|
||||||
|
imtoggle("Meta [f7]", debug, "meta");
|
||||||
|
imtoggle("Cheats [f8]", debug, "cheat");
|
||||||
|
imtoggle("Console [f9]", debug, "console");
|
||||||
|
});
|
||||||
|
|
||||||
|
imgui.sokol_gfx();
|
||||||
|
|
||||||
|
imgui.menu("Graphics", _ => {
|
||||||
|
imtoggle("Draw sprites", render, "draw_sprites");
|
||||||
|
imtoggle("Draw particles", render, "draw_particles");
|
||||||
|
imtoggle("Draw HUD", render, "draw_hud");
|
||||||
|
imtoggle("Draw GUI", render, "draw_gui");
|
||||||
|
|
||||||
|
imgui.menu("Window", _ => {
|
||||||
|
prosperon.fullscreen = imgui.checkbox("fullscreen", prosperon.fullscreen);
|
||||||
|
// prosperon.vsync = imgui.checkbox("vsync", prosperon.vsync);
|
||||||
|
imgui.menu("MSAA", _ => {
|
||||||
|
for (var msaa of gamestate.msaa) imgui.button(msaa + "x", _ => (prosperon.sample_count = msaa));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (observed_tex) {
|
||||||
|
imgui.window("texture", _ => {
|
||||||
|
imgui.image(observed_tex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var texs = {};
|
||||||
|
for (var path in graphics.texture.cache) {
|
||||||
|
var image = graphics.texture.cache[path];
|
||||||
|
if (image.texture && !texs[image.texture])
|
||||||
|
texs[image.texture] = image.texture;
|
||||||
|
}
|
||||||
|
imgui.window("textures", _ => {
|
||||||
|
for (var img in texs) {
|
||||||
|
imgui.button(img, _ => {
|
||||||
|
observed_tex = texs[img];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
// prosperon.imgui();
|
||||||
|
|
||||||
|
imgui.endframe(render._main);
|
||||||
|
};
|
||||||
|
|
||||||
|
imgui.windowpos[prosperon.DOC] = `Return the position of the current ImGui window as an ImVec2.
|
||||||
|
|
||||||
|
:return: A 2-element array [x, y] representing the top-left corner of the current window in screen coordinates.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.plot2pixels[prosperon.DOC] = `Convert a point from plot coordinates to pixel coordinates in the current ImPlot.
|
||||||
|
|
||||||
|
:param coords: A 2-element array [x, y] in plot coordinates.
|
||||||
|
:return: A 2-element array [x, y] in pixel coordinates, mapped from the current ImPlot.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.plotpos[prosperon.DOC] = `Return the top-left corner of the current ImPlot region in screen (pixel) coordinates.
|
||||||
|
|
||||||
|
:return: A 2-element array [x, y] representing the position of the current ImPlot in screen coordinates.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.plotlimits[prosperon.DOC] = `Retrieve the current plot’s axis limits (min/max) for both X and Y axes.
|
||||||
|
|
||||||
|
:return: An object { x: { min, max }, y: { min, max } } describing the current plot’s visible axis ranges.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.setaxes[prosperon.DOC] = `Switch the active axes in ImPlot (useful if multiple axes exist).
|
||||||
|
|
||||||
|
:param xAxis: The x-axis index (0..2).
|
||||||
|
:param yAxis: The y-axis index (0..2).
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.setupaxis[prosperon.DOC] = `Setup the specified axis in the current ImPlot (e.g., for customizing tick labels).
|
||||||
|
|
||||||
|
:param axis: The numeric index of the axis (0..2).
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.inplot[prosperon.DOC] = `Check if the given point is within the current ImPlot's visible region.
|
||||||
|
|
||||||
|
:param coords: A 2-element array [x, y] in plot coordinates.
|
||||||
|
:return: True if the point is within the visible plot region, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.window[prosperon.DOC] = `Create a new ImGui window with the given title and invoke the callback to render inside it.
|
||||||
|
|
||||||
|
:param title: The text displayed as the window title.
|
||||||
|
:param callback: A function called to render the contents of the window.
|
||||||
|
:return: A boolean indicating if the window is still active (open) after rendering.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.menu[prosperon.DOC] = `Create a new menu entry in a menu bar or menu. The callback is invoked to populate the menu if opened.
|
||||||
|
|
||||||
|
:param label: The label of the menu (visible in the menubar).
|
||||||
|
:param callback: A function called to render menu items when the menu is open.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.sameline[prosperon.DOC] = `Place the next widget on the same line, optionally specifying a horizontal offset.
|
||||||
|
|
||||||
|
:param offset: A float offset from the current cursor position. If omitted, defaults to 0.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.int[prosperon.DOC] = `Display an integer input box with a label.
|
||||||
|
|
||||||
|
:param label: The label text for the input.
|
||||||
|
:param value: The initial integer value.
|
||||||
|
:return: The updated integer value after user edits.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.pushid[prosperon.DOC] = `Push an integer ID onto the ImGui ID stack.
|
||||||
|
|
||||||
|
:param id: An integer used to differentiate widgets/items with the same label.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.popid[prosperon.DOC] = `Pop an ID off the ImGui ID stack.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.slider[prosperon.DOC] = `Create a float slider (or multi-float sliders if given an array) within the specified range.
|
||||||
|
|
||||||
|
:param label: The slider label text.
|
||||||
|
:param value: A single float or an array of floats (e.g., [r,g,b,a]).
|
||||||
|
:param minValue: The minimum slider value.
|
||||||
|
:param maxValue: The maximum slider value.
|
||||||
|
:return: The updated float or array of floats after user adjustment.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.intslider[prosperon.DOC] = `Create an integer slider (or multiple integer sliders if given a typed array) in the specified range.
|
||||||
|
|
||||||
|
:param label: The slider label text.
|
||||||
|
:param value: A single integer or a typed array of integers (for multi-component sliders).
|
||||||
|
:param minValue: The minimum integer value.
|
||||||
|
:param maxValue: The maximum integer value.
|
||||||
|
:return: The updated integer or array of integers after user adjustment.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.menubar[prosperon.DOC] = `Begin rendering a menubar. The callback is invoked to create menu items. Ends automatically.
|
||||||
|
|
||||||
|
:param callback: A function that creates menu items within the menubar.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.mainmenubar[prosperon.DOC] = `Create the main menu bar at the top of the screen. The callback is invoked for populating it.
|
||||||
|
|
||||||
|
:param callback: A function to render items in the main menu bar.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.menuitem[prosperon.DOC] = `Create a menu item that can optionally be toggled. If selected, calls the provided callback.
|
||||||
|
|
||||||
|
:param label: The text label of the menu item.
|
||||||
|
:param shortcut: An optional shortcut text to display (e.g. "Ctrl+S").
|
||||||
|
:param callback: A function called if the user clicks or activates this item.
|
||||||
|
:param selected: A boolean indicating whether this menu item is toggled or not.
|
||||||
|
:return: A boolean reflecting the toggled state.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.radio[prosperon.DOC] = `Create a radio button.
|
||||||
|
|
||||||
|
:param label: The text label for the radio button.
|
||||||
|
:param active: Whether this radio button is currently selected.
|
||||||
|
:return: True if this radio button is now selected by the user, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.image[prosperon.DOC] = `Render a texture as an image at a default size (100x100).
|
||||||
|
|
||||||
|
:param texture: The GPU texture to display.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.imagebutton[prosperon.DOC] = `Create an ImageButton widget which displays a texture; calls the callback when clicked.
|
||||||
|
|
||||||
|
:param label: A string identifier (not visually used).
|
||||||
|
:param texture: The GPU texture to display on the button.
|
||||||
|
:param callback: A function called when the button is clicked.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.textinput[prosperon.DOC] = `Show a single-line text input widget.
|
||||||
|
|
||||||
|
:param label: The label text next to the input box.
|
||||||
|
:param text: The current text. If undefined, the box starts empty.
|
||||||
|
:return: The updated text string after user editing.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.textbox[prosperon.DOC] = `Show a multi-line text input widget.
|
||||||
|
|
||||||
|
:param label: The label text next to the input box.
|
||||||
|
:param text: The current multi-line text. If undefined, starts empty.
|
||||||
|
:return: The updated text after user editing.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.button[prosperon.DOC] = `Create a button. The callback fires if the user clicks it.
|
||||||
|
|
||||||
|
:param label: The text displayed on the button.
|
||||||
|
:param callback: The function called on click.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.checkbox[prosperon.DOC] = `Create a checkbox to toggle a boolean value.
|
||||||
|
|
||||||
|
:param label: The text label for the checkbox.
|
||||||
|
:param checked: The current boolean state.
|
||||||
|
:return: The updated boolean state after user toggle.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.text[prosperon.DOC] = `Render a line of text in the ImGui window.
|
||||||
|
|
||||||
|
:param text: The string to display.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.plot[prosperon.DOC] = `Begin a new ImPlot region with the specified title. Calls the callback to render plot contents.
|
||||||
|
|
||||||
|
:param title: The title (label) of the plot.
|
||||||
|
:param callback: A function that sets up and draws within the ImPlot region.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.lineplot[prosperon.DOC] = `Plot a line graph in the current ImPlot.
|
||||||
|
|
||||||
|
:param label: The label for the line plot.
|
||||||
|
:param data: An array of [x,y] points or a single array of y-values.
|
||||||
|
:param shaded: Boolean indicating if the area under the line should be filled.
|
||||||
|
:param lastPoint: (Optional) Additional point or frame usage. (Currently partial/placeholder in code.)
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.scatterplot[prosperon.DOC] = `Plot a scatter graph in the current ImPlot.
|
||||||
|
|
||||||
|
:param label: The label for the scatter plot.
|
||||||
|
:param data: An array of [x,y] points or a single array of y-values.
|
||||||
|
:param shaded: Typically unused for scatter.
|
||||||
|
:param lastPoint: (Optional) Additional param if needed.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.stairplot[prosperon.DOC] = `Plot a stair-step graph in the current ImPlot.
|
||||||
|
|
||||||
|
:param label: The label for the stair plot.
|
||||||
|
:param data: An array of [x,y] points or a single array of y-values.
|
||||||
|
:param shaded: A boolean to fill under the stair-step line.
|
||||||
|
:param lastPoint: (Optional) Extended data usage if needed.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.digitalplot[prosperon.DOC] = `Plot a digital (step-like) graph in the current ImPlot.
|
||||||
|
|
||||||
|
:param label: The label for the digital plot.
|
||||||
|
:param data: An array of [x,y] points or a single array of y-values.
|
||||||
|
:param shaded: Typically not used for digital plots.
|
||||||
|
:param lastPoint: (Optional) Extended data usage if needed.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.barplot[prosperon.DOC] = `Plot a bar chart in the current ImPlot.
|
||||||
|
|
||||||
|
:param label: The label for the bar series.
|
||||||
|
:param data: An array of [x,y] points or just an array of y-values.
|
||||||
|
:param width: The width of each bar in plot units.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.pieplot[prosperon.DOC] = `Plot a pie chart in the current ImPlot.
|
||||||
|
|
||||||
|
:param labels: An array of label strings for each slice.
|
||||||
|
:param values: An array of numeric values corresponding to each slice.
|
||||||
|
:param x: The x position of the pie’s center.
|
||||||
|
:param y: The y position of the pie’s center.
|
||||||
|
:param radius: The radius of the pie chart.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.textplot[prosperon.DOC] = `Render text at the specified coordinates in plot space.
|
||||||
|
|
||||||
|
:param text: The string to render.
|
||||||
|
:param coords: A 2-element array [x, y] in plot coordinates.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.histogramplot[prosperon.DOC] = `Plot a histogram from the given data array/typed array in the current ImPlot.
|
||||||
|
|
||||||
|
:param label: The label for the histogram.
|
||||||
|
:param data: A typed array (or numeric array) containing the values to bin/display.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.plotaxes[prosperon.DOC] = `Set up labels for the X and Y axes of the current ImPlot.
|
||||||
|
|
||||||
|
:param xLabel: The label for the x-axis.
|
||||||
|
:param yLabel: The label for the y-axis.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.plotmousepos[prosperon.DOC] = `Get the mouse cursor’s position in the current plot’s coordinate system.
|
||||||
|
|
||||||
|
:return: A 2-element array [x, y] representing the mouse position in plot coordinates.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.plothovered[prosperon.DOC] = `Check if the mouse is hovering over the current ImPlot.
|
||||||
|
|
||||||
|
:return: True if the plot area is hovered, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.axeslimits[prosperon.DOC] = `Set up the visible axis limits in the current ImPlot.
|
||||||
|
|
||||||
|
:param xMin: The left (min) bound of the x-axis.
|
||||||
|
:param xMax: The right (max) bound of the x-axis.
|
||||||
|
:param yMin: The bottom (min) bound of the y-axis.
|
||||||
|
:param yMax: The top (max) bound of the y-axis.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.prepend[prosperon.DOC] = `Prepare ImGui draw data for rendering, typically called after ImGui::Render().
|
||||||
|
|
||||||
|
:param commandBuffer: The SDL GPU command buffer where draw data will be queued.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.fitaxis[prosperon.DOC] = `Fit either the x-axis or y-axis to its data range on the next plot frame.
|
||||||
|
|
||||||
|
:param axis: 0 for X-axis, 1 for Y-axis.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.columns[prosperon.DOC] = `Switch the layout to use a specified number of columns.
|
||||||
|
|
||||||
|
:param count: The number of columns to layout in the current region.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.nextcolumn[prosperon.DOC] = `Advance to the next column in a multi-column layout.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.collapsingheader[prosperon.DOC] = `Create a collapsible header. Returns true if it is open (expanded).
|
||||||
|
|
||||||
|
:param label: The text label of the header.
|
||||||
|
:return: True if the header is expanded, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tree[prosperon.DOC] = `Create a tree node. If opened, calls the callback for nested content.
|
||||||
|
|
||||||
|
:param label: The label for the tree node.
|
||||||
|
:param callback: A function called if the node is expanded.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.listbox[prosperon.DOC] = `Create a list box widget to select from a list of strings.
|
||||||
|
|
||||||
|
:param label: The label next to the list box.
|
||||||
|
:param items: An array of strings to display.
|
||||||
|
:param selectedIndex: The currently selected index.
|
||||||
|
:return: The updated selected index after user selection.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.axisfmt[prosperon.DOC] = `Set a custom formatter for a specified y-axis in ImPlot.
|
||||||
|
|
||||||
|
:param axis: The y-axis index (0..2) to format.
|
||||||
|
:param callback: A function(value) => string that converts axis values to text.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tabbar[prosperon.DOC] = `Begin a tab bar container. The callback is invoked to create tabs.
|
||||||
|
|
||||||
|
:param label: The identifier label of the tab bar.
|
||||||
|
:param callback: A function that creates tab items.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tab[prosperon.DOC] = `Create a tab item. If selected, calls the callback for tab content.
|
||||||
|
|
||||||
|
:param label: The name of the tab.
|
||||||
|
:param callback: A function to render the tab’s content if active.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.open_popup[prosperon.DOC] = `Open a popup by its identifier.
|
||||||
|
|
||||||
|
:param label: The identifier of the popup to open.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.modal[prosperon.DOC] = `Begin a modal popup. The callback is invoked to display contents if the modal is open.
|
||||||
|
|
||||||
|
:param label: The identifier of the modal popup.
|
||||||
|
:param callback: A function for rendering the modal’s UI if open.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.popup[prosperon.DOC] = `Begin a popup. The callback is invoked if the popup is open.
|
||||||
|
|
||||||
|
:param label: The identifier of the popup.
|
||||||
|
:param callback: A function for rendering the popup’s UI.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.close_popup[prosperon.DOC] = `Close the current popup.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.context[prosperon.DOC] = `Create a popup context menu. The callback is invoked if the menu opens.
|
||||||
|
|
||||||
|
:param label: The identifier for the context menu.
|
||||||
|
:param callback: A function that renders menu items in the context.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.table[prosperon.DOC] = `Create a table with multiple columns. Optionally enable sorting and pass a sort callback.
|
||||||
|
|
||||||
|
:param label: The identifier for the table.
|
||||||
|
:param columns: The number of columns.
|
||||||
|
:param callback: A function to populate the table (rows/cells).
|
||||||
|
:param sortCallback: An optional function(columnIndex, ascending) called if user sorts a column.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tablenextcolumn[prosperon.DOC] = `Move to the next column in a table row.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tablenextrow[prosperon.DOC] = `Move to the next row in a table.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tableheadersrow[prosperon.DOC] = `Create a row of headers in the current table (should be called once after column setup).
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tableangledheadersrow[prosperon.DOC] = `Create an angled header row (for advanced usage). Typically not used as often.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.tablesetupcolumn[prosperon.DOC] = `Setup configuration for a single column in the table.
|
||||||
|
|
||||||
|
:param label: The label/header text for this column.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.dnd[prosperon.DOC] = `Begin a drag source for custom data payload.
|
||||||
|
|
||||||
|
:param type: A string identifier for the drag-drop payload type.
|
||||||
|
:param payload: A numeric payload stored in the drag-drop.
|
||||||
|
:param callback: (Currently unused) Placeholder if you want to do extra on drag start.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.dndtarget[prosperon.DOC] = `Create a drop target for matching drag-drop payload type. Invokes callback on drop.
|
||||||
|
|
||||||
|
:param type: A string identifier for the drag-drop payload type to accept.
|
||||||
|
:param callback: A function(payloadNumber) called when a matching payload is dropped.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.color[prosperon.DOC] = `Create a color editor (3 or 4 floats). Returns the updated color.
|
||||||
|
|
||||||
|
:param label: The label for the color editor.
|
||||||
|
:param color: An array [r,g,b] or [r,g,b,a].
|
||||||
|
:return: Updated color array after user input.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.startnode[prosperon.DOC] = `Begin a node editor session with ImNodes. The callback defines nodes.
|
||||||
|
Additional callbacks handle link creation and hover events.
|
||||||
|
|
||||||
|
:param callback: A function to define node editor contents (adding nodes, etc).
|
||||||
|
:param linkCreatedCallback: A function(startAttr, endAttr) called when a new link is created.
|
||||||
|
:param nodeHoveredCallback: A function(nodeId) called when a node is hovered.
|
||||||
|
:param linkHoveredCallback: A function(linkId) called when a link is hovered.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.node[prosperon.DOC] = `Begin a node with a unique ID, then call the callback to define its contents.
|
||||||
|
|
||||||
|
:param nodeId: A unique integer ID for this node.
|
||||||
|
:param callback: A function that populates the node’s UI.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.nodein[prosperon.DOC] = `Create an input attribute in the current node.
|
||||||
|
|
||||||
|
:param attributeId: The attribute ID for this input.
|
||||||
|
:param callback: A function that defines the UI within the input attribute.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.nodeout[prosperon.DOC] = `Create an output attribute in the current node.
|
||||||
|
|
||||||
|
:param attributeId: The attribute ID for this output.
|
||||||
|
:param callback: A function that defines the UI within the output attribute.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.nodelink[prosperon.DOC] = `Link two node attributes by their IDs.
|
||||||
|
|
||||||
|
:param linkId: A unique integer ID for this link.
|
||||||
|
:param startAttributeId: The attribute ID where the link starts.
|
||||||
|
:param endAttributeId: The attribute ID where the link ends.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.nodemini[prosperon.DOC] = `Show a minimap for the current node editor.
|
||||||
|
|
||||||
|
:param size: A float controlling the minimap size ratio.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.mousehoveringrect[prosperon.DOC] = `Check if the mouse is hovering within the given rectangle.
|
||||||
|
|
||||||
|
:param min: A 2-element array [x, y] for the top-left corner.
|
||||||
|
:param max: A 2-element array [x, y] for the bottom-right corner.
|
||||||
|
:return: True if the mouse is within that rectangle, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.mouseclicked[prosperon.DOC] = `Check if a specific mouse button was clicked (went from up to down) this frame.
|
||||||
|
|
||||||
|
:param button: An integer for the mouse button index (0 = left, 1 = right, etc).
|
||||||
|
:return: True if the button was clicked, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.mousedown[prosperon.DOC] = `Check if the specified mouse button is currently held down.
|
||||||
|
|
||||||
|
:param button: The mouse button index.
|
||||||
|
:return: True if the button is down, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.mousereleased[prosperon.DOC] = `Check if the specified mouse button was released this frame.
|
||||||
|
|
||||||
|
:param button: The mouse button index.
|
||||||
|
:return: True if the button was released, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.mousedragging[prosperon.DOC] = `Check if the mouse is being dragged with the specified button.
|
||||||
|
|
||||||
|
:param button: The mouse button index.
|
||||||
|
:return: True if the mouse is dragging, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.mousedelta[prosperon.DOC] = `Get the mouse movement delta (difference) for the current frame.
|
||||||
|
|
||||||
|
:return: A 2-element array [dx, dy] representing the mouse movement.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.rect[prosperon.DOC] = `Draw a rectangle outline in the current window’s draw list.
|
||||||
|
|
||||||
|
:param pMin: A 2-element array [x, y] for the top-left corner.
|
||||||
|
:param pMax: A 2-element array [x, y] for the bottom-right corner.
|
||||||
|
:param color: A 4-element array [r, g, b, a] specifying the outline color.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.rectfilled[prosperon.DOC] = `Draw a filled rectangle in the current window’s draw list.
|
||||||
|
|
||||||
|
:param pMin: [x, y] for the top-left corner.
|
||||||
|
:param pMax: [x, y] for the bottom-right corner.
|
||||||
|
:param color: [r, g, b, a] fill color.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.line[prosperon.DOC] = `Draw a line between two points in the current window’s draw list.
|
||||||
|
|
||||||
|
:param p1: [x, y] start position.
|
||||||
|
:param p2: [x, y] end position.
|
||||||
|
:param color: [r, g, b, a] line color.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.bezierquad[prosperon.DOC] = `Draw a quadratic bezier curve.
|
||||||
|
|
||||||
|
:param p1: [x, y] start point.
|
||||||
|
:param p2: [x, y] control point.
|
||||||
|
:param p3: [x, y] end point.
|
||||||
|
:param color: [r, g, b, a] color.
|
||||||
|
:param thickness: Line thickness.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.beziercubic[prosperon.DOC] = `Draw a cubic bezier curve.
|
||||||
|
|
||||||
|
:param p1: [x, y] start point.
|
||||||
|
:param p2: [x, y] first control point.
|
||||||
|
:param p3: [x, y] second control point.
|
||||||
|
:param p4: [x, y] end point.
|
||||||
|
:param color: [r, g, b, a] color.
|
||||||
|
:param thickness: Line thickness.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.point[prosperon.DOC] = `Draw a filled circle (point) in the current window’s draw list.
|
||||||
|
|
||||||
|
:param center: [x, y] center of the circle.
|
||||||
|
:param radius: The radius of the circle.
|
||||||
|
:param color: [r, g, b, a] fill color.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.drawtext[prosperon.DOC] = `Draw text at the given screen position with a specified color.
|
||||||
|
|
||||||
|
:param text: The string to draw.
|
||||||
|
:param position: [x, y] in screen coordinates.
|
||||||
|
:param color: [r, g, b, a] text color.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.cursorscreenpos[prosperon.DOC] = `Get the current ImGui cursor screen position.
|
||||||
|
|
||||||
|
:return: A 2-element array [x, y] in screen coordinates.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.setcursorscreenpos[prosperon.DOC] = `Set the ImGui cursor screen position.
|
||||||
|
|
||||||
|
:param position: A 2-element array [x, y] in screen coordinates.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.contentregionavail[prosperon.DOC] = `Return the available space in the current window’s content region.
|
||||||
|
|
||||||
|
:return: A 2-element array [width, height] of available space.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.dummy[prosperon.DOC] = `Add a dummy item (invisible) of the specified size to the layout.
|
||||||
|
|
||||||
|
:param size: A 2-element array [width, height].
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.invisiblebutton[prosperon.DOC] = `Create an invisible button that occupies a given size and can catch clicks.
|
||||||
|
|
||||||
|
:param label: The identifier for the button.
|
||||||
|
:param size: [width, height] specifying the button area.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.width[prosperon.DOC] = `Set the width of the next item in the layout.
|
||||||
|
|
||||||
|
:param width: The width (in pixels) for the next item.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.setclipboard[prosperon.DOC] = `Set the system clipboard text.
|
||||||
|
|
||||||
|
:param text: The string to put into the clipboard.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.newframe[prosperon.DOC] = `Start a new ImGui frame. Should be called once per frame before rendering UI elements.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.endframe[prosperon.DOC] = `Finalize and render the ImGui draw data to the specified command buffer and render pass.
|
||||||
|
|
||||||
|
:param commandBuffer: The SDL GPU command buffer to render into.
|
||||||
|
:param renderPass: The SDL GPU render pass used to draw ImGui data.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.wantmouse[prosperon.DOC] = `Check if ImGui wants to capture the mouse (e.g., if a window or widget needs mouse events).
|
||||||
|
|
||||||
|
:return: True if ImGui is capturing the mouse, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.wantkeys[prosperon.DOC] = `Check if ImGui wants to capture the keyboard (e.g., if a text input is active).
|
||||||
|
|
||||||
|
:return: True if ImGui is capturing the keyboard, otherwise false.
|
||||||
|
`;
|
||||||
|
|
||||||
|
imgui.init[prosperon.DOC] = `Initialize ImGui with SDL and SDL_gpu, creating the ImGui context and configuring it.
|
||||||
|
|
||||||
|
:param gpuDevice: The SDL_GPUDevice object.
|
||||||
|
:param window: The SDL_Window object to attach ImGui onto.
|
||||||
|
:return: None
|
||||||
|
`;
|
||||||
|
|
||||||
|
return imgui;
|
||||||
@@ -1,14 +1,103 @@
|
|||||||
var js = this
|
var js = this
|
||||||
|
js[prosperon.DOC] = `
|
||||||
|
Provides functions for introspecting and configuring the QuickJS runtime engine.
|
||||||
|
Includes debug info, memory usage, GC controls, code evaluation, etc.
|
||||||
|
`
|
||||||
|
|
||||||
js.dump_shapes[prosperon.DOC] = "Return a debug string describing the internal shape hierarchy used by QuickJS."
|
js.dump_shapes[prosperon.DOC] = `
|
||||||
js.dump_atoms[prosperon.DOC] = "Return a debug string describing all currently registered atoms in the QuickJS runtime."
|
:return: A debug string describing the internal shape hierarchy used by QuickJS.
|
||||||
js.calc_mem[prosperon.DOC] = "Return the approximate memory usage of a single JS value."
|
Use this for internal debugging of object shapes.
|
||||||
js.mem[prosperon.DOC] = "Return a comprehensive memory usage object for the current QuickJS runtime."
|
`
|
||||||
js.mem_limit[prosperon.DOC] = "Set (in bytes) the maximum memory the QuickJS runtime will attempt to use."
|
|
||||||
js.gc_threshold[prosperon.DOC] = "Set the threshold at which garbage collection triggers automatically, in bytes."
|
js.dump_atoms[prosperon.DOC] = `
|
||||||
js.max_stacksize[prosperon.DOC] = "Set the maximum allowed stack size for QuickJS. Exceeding it can cause errors."
|
:return: A debug string listing all currently registered atoms (internal property keys/symbols)
|
||||||
js.memstate[prosperon.DOC] = "Return simpler memory usage (malloc sizes, etc.) for the QuickJS runtime."
|
known by QuickJS. Helpful for diagnosing memory usage or potential key collisions.
|
||||||
js.gc[prosperon.DOC] = "Force a full garbage collection immediately."
|
`
|
||||||
js.eval[prosperon.DOC] = "Evaluate the given JavaScript source string with an optional filename, returning the result."
|
|
||||||
|
js.dump_class[prosperon.DOC] = `
|
||||||
|
:return: A debug string describing the distribution of JS object classes in the QuickJS runtime.
|
||||||
|
Shows how many objects of each class exist, useful for advanced memory or performance profiling.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.dump_type_overheads[prosperon.DOC] = `
|
||||||
|
:return: A debug string describing the overheads for various JS object types in QuickJS.
|
||||||
|
Displays memory usage breakdown for different internal object types.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.dump_objects[prosperon.DOC] = `
|
||||||
|
:return: A debug string listing certain internal QuickJS objects and their references,
|
||||||
|
useful for debugging memory leaks or object lifetimes.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.stack_info[prosperon.DOC] = `
|
||||||
|
:return: An object or string describing the runtime's current stack usage and capacity.
|
||||||
|
Internal debugging utility to examine call stack details.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.cycle_hook[prosperon.DOC] = `
|
||||||
|
:param callback: A function to call each time QuickJS completes a "cycle" (internal VM loop),
|
||||||
|
or undefined to remove the callback.
|
||||||
|
:return: None
|
||||||
|
|
||||||
|
Register or remove a hook function that QuickJS calls once per execution cycle. If the callback
|
||||||
|
is set, it receives a single argument (an optional object/value describing the cycle). If callback
|
||||||
|
is undefined, the hook is removed.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.calc_mem[prosperon.DOC] = `
|
||||||
|
:param value: A JavaScript value to analyze.
|
||||||
|
:return: Approximate memory usage (in bytes) of that single value.
|
||||||
|
|
||||||
|
Compute the approximate size of a single JS value in memory. This is a best-effort estimate.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.mem[prosperon.DOC] = `
|
||||||
|
:return: An object containing a comprehensive snapshot of memory usage for the current QuickJS runtime,
|
||||||
|
including total allocated bytes, object counts, and more.
|
||||||
|
|
||||||
|
Retrieve an overview of the runtime’s memory usage.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.mem_limit[prosperon.DOC] = `
|
||||||
|
:param bytes: The maximum memory (in bytes) QuickJS is allowed to use.
|
||||||
|
:return: None
|
||||||
|
|
||||||
|
Set the upper memory limit for the QuickJS runtime. Exceeding this limit may cause operations to
|
||||||
|
fail or throw errors.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.gc_threshold[prosperon.DOC] = `
|
||||||
|
:param bytes: The threshold (in bytes) at which the engine triggers automatic garbage collection.
|
||||||
|
:return: None
|
||||||
|
|
||||||
|
Set the threshold (in bytes) for QuickJS to perform an automatic GC pass when memory usage surpasses it.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.max_stacksize[prosperon.DOC] = `
|
||||||
|
:param bytes: The maximum allowed stack size (in bytes) for QuickJS.
|
||||||
|
:return: None
|
||||||
|
|
||||||
|
Set the maximum stack size for QuickJS. If exceeded, the runtime may throw a stack overflow error.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.memstate[prosperon.DOC] = `
|
||||||
|
:return: A simpler memory usage object (malloc sizes, etc.) for the QuickJS runtime.
|
||||||
|
|
||||||
|
Gives a quick overview of the memory usage, including malloc size and other allocations.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.gc[prosperon.DOC] = `
|
||||||
|
:return: None
|
||||||
|
|
||||||
|
Force an immediate, full garbage collection pass, reclaiming unreachable memory.
|
||||||
|
`
|
||||||
|
|
||||||
|
js.eval[prosperon.DOC] = `
|
||||||
|
:param src: A string of JavaScript source code to evaluate.
|
||||||
|
:param filename: (Optional) A string for the filename or label, used in debugging or stack traces.
|
||||||
|
:return: The result of evaluating the given source code.
|
||||||
|
|
||||||
|
Execute a string of JavaScript code in the current QuickJS context.
|
||||||
|
`
|
||||||
|
|
||||||
return js
|
return js
|
||||||
|
|||||||
@@ -13,14 +13,6 @@ var frame_t = 0
|
|||||||
var fpses = []
|
var fpses = []
|
||||||
var timescale = 1
|
var timescale = 1
|
||||||
|
|
||||||
// This was originally your 'imgui_fn' in render.js
|
|
||||||
function imgui_fn() {
|
|
||||||
imgui.newframe()
|
|
||||||
// ... your debug menus, etc. ...
|
|
||||||
prosperon.imgui()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull your old 'render.process' logic here:
|
|
||||||
function step() {
|
function step() {
|
||||||
var now = os.now()
|
var now = os.now()
|
||||||
var dt = now - last_frame_time
|
var dt = now - last_frame_time
|
||||||
@@ -30,24 +22,19 @@ function step() {
|
|||||||
dt = last_frame_time - frame_t
|
dt = last_frame_time - frame_t
|
||||||
frame_t = last_frame_time
|
frame_t = last_frame_time
|
||||||
|
|
||||||
// Input & events
|
|
||||||
event.engine_input(e => prosperon.dispatch(e.type, e))
|
event.engine_input(e => prosperon.dispatch(e.type, e))
|
||||||
layout.newframe()
|
layout.newframe()
|
||||||
|
|
||||||
// Game logic
|
|
||||||
prosperon.appupdate(dt)
|
prosperon.appupdate(dt)
|
||||||
input.procdown()
|
input.procdown()
|
||||||
emitter.update(dt * timescale)
|
emitter.update(dt * timescale)
|
||||||
os.update_timers(dt * timescale)
|
os.update_timers(dt * timescale)
|
||||||
prosperon.update(dt * timescale)
|
prosperon.update(dt * timescale)
|
||||||
|
|
||||||
// Scenes or “draw” hooks
|
|
||||||
// We point to whichever queue we want
|
|
||||||
render.setup_draw()
|
render.setup_draw()
|
||||||
render.setup_hud()
|
render.setup_hud()
|
||||||
|
|
||||||
// Show your UI or debug
|
//if (imgui) imgui.prosperon_menu();
|
||||||
// imgui_fn()
|
|
||||||
|
|
||||||
// Now do the GPU present (calls gpupresent in render.js)
|
// Now do the GPU present (calls gpupresent in render.js)
|
||||||
render._main.present()
|
render._main.present()
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
var render = {}
|
var render = {}
|
||||||
|
|
||||||
var math = use('math')
|
|
||||||
var io = use('io')
|
var io = use('io')
|
||||||
var os = use('os')
|
var os = use('os')
|
||||||
var util = use('util')
|
|
||||||
var emitter = use('emitter')
|
|
||||||
var controller = use('controller')
|
var controller = use('controller')
|
||||||
var event = use('event')
|
|
||||||
var imgui = use('imgui')
|
|
||||||
var sprite = use('sprite')
|
|
||||||
var graphics = use('graphics')
|
var graphics = use('graphics')
|
||||||
|
|
||||||
var config = use('config.js')
|
var config = use('config.js')
|
||||||
@@ -150,26 +145,36 @@ cur.images = [];
|
|||||||
cur.samplers = [];
|
cur.samplers = [];
|
||||||
|
|
||||||
var tbuffer;
|
var tbuffer;
|
||||||
function full_upload(buffers)
|
function full_upload(buffers) {
|
||||||
{
|
|
||||||
var cmds = render._main.acquire_cmd_buffer();
|
var cmds = render._main.acquire_cmd_buffer();
|
||||||
tbuffer = render._main.upload(cmds, buffers, tbuffer);
|
tbuffer = render._main.upload(cmds, buffers, tbuffer);
|
||||||
cmds.submit();
|
cmds.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function bind_pipeline(pass, pipeline)
|
full_upload[prosperon.DOC] = `Acquire a command buffer and upload the provided data buffers to the GPU, then submit.
|
||||||
{
|
|
||||||
|
:param buffers: An array of data buffers to be uploaded.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
function bind_pipeline(pass, pipeline) {
|
||||||
make_pipeline(pipeline)
|
make_pipeline(pipeline)
|
||||||
pass.bind_pipeline(pipeline.gpu)
|
pass.bind_pipeline(pipeline.gpu)
|
||||||
pass.pipeline = pipeline;
|
pass.pipeline = pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bind_pipeline[prosperon.DOC] = `Ensure the specified pipeline is created on the GPU and bind it to the given render pass.
|
||||||
|
|
||||||
|
:param pass: The current render pass to bind the pipeline to.
|
||||||
|
:param pipeline: The pipeline object containing shader and state info.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
var main_pass;
|
var main_pass;
|
||||||
|
|
||||||
var cornflower = [62/255,96/255,113/255,1];
|
var cornflower = [62/255,96/255,113/255,1];
|
||||||
|
|
||||||
function get_pipeline_ubo_slot(pipeline, name)
|
function get_pipeline_ubo_slot(pipeline, name) {
|
||||||
{
|
|
||||||
if (!pipeline.vertex.reflection.ubos) return;
|
if (!pipeline.vertex.reflection.ubos) return;
|
||||||
for (var i = 0; i < pipeline.vertex.reflection.ubos.length; i++) {
|
for (var i = 0; i < pipeline.vertex.reflection.ubos.length; i++) {
|
||||||
var ubo = pipeline.vertex.reflection.ubos[i];
|
var ubo = pipeline.vertex.reflection.ubos[i];
|
||||||
@@ -179,6 +184,13 @@ function get_pipeline_ubo_slot(pipeline, name)
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_pipeline_ubo_slot[prosperon.DOC] = `Return the index of a uniform buffer block within the pipeline's vertex reflection data by name suffix.
|
||||||
|
|
||||||
|
:param pipeline: The pipeline whose vertex reflection is inspected.
|
||||||
|
:param name: A string suffix to match against the uniform buffer block name.
|
||||||
|
:return: The integer index of the matching UBO, or undefined if not found.
|
||||||
|
`
|
||||||
|
|
||||||
function transpose4x4(val) {
|
function transpose4x4(val) {
|
||||||
var out = [];
|
var out = [];
|
||||||
out[0] = val[0]; out[1] = val[4]; out[2] = val[8]; out[3] = val[12];
|
out[0] = val[0]; out[1] = val[4]; out[2] = val[8]; out[3] = val[12];
|
||||||
@@ -188,8 +200,13 @@ function transpose4x4(val) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ubo_obj_to_array(pipeline, name, obj)
|
transpose4x4[prosperon.DOC] = `Return a new 4x4 matrix array that is the transpose of the passed matrix.
|
||||||
{
|
|
||||||
|
:param val: An array of length 16 representing a 4x4 matrix in row-major format.
|
||||||
|
:return: A new array of length 16 representing the transposed matrix.
|
||||||
|
`
|
||||||
|
|
||||||
|
function ubo_obj_to_array(pipeline, name, obj) {
|
||||||
var ubo;
|
var ubo;
|
||||||
for (var i = 0; i < pipeline.vertex.reflection.ubos.length; i++) {
|
for (var i = 0; i < pipeline.vertex.reflection.ubos.length; i++) {
|
||||||
ubo = pipeline.vertex.reflection.ubos[i];
|
ubo = pipeline.vertex.reflection.ubos[i];
|
||||||
@@ -216,25 +233,31 @@ function ubo_obj_to_array(pipeline, name, obj)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
function type_to_byte_count(type)
|
ubo_obj_to_array[prosperon.DOC] = `Construct an ArrayBuffer containing UBO data from the provided object, matching the pipeline's reflection info.
|
||||||
{
|
|
||||||
|
:param pipeline: The pipeline whose vertex reflection is read for UBO structure.
|
||||||
|
:param name: The name suffix that identifies the target UBO in the reflection data.
|
||||||
|
:param obj: An object whose properties match the UBO members.
|
||||||
|
:return: An ArrayBuffer containing packed UBO data.
|
||||||
|
`
|
||||||
|
|
||||||
|
function type_to_byte_count(type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'float':
|
case 'float': return 4;
|
||||||
return 4;
|
case 'vec2': return 8;
|
||||||
case 'vec2':
|
case 'vec3': return 12;
|
||||||
return 8;
|
case 'vec4': return 16;
|
||||||
case 'vec3':
|
case 'mat4': return 64;
|
||||||
return 12;
|
default: throw new Error("Unknown or unsupported float-based type: " + type);
|
||||||
case 'vec4':
|
|
||||||
return 16;
|
|
||||||
case 'mat4':
|
|
||||||
return 64;
|
|
||||||
// Add cases as needed
|
|
||||||
default:
|
|
||||||
throw new Error("Unknown or unsupported float-based type: " + type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type_to_byte_count[prosperon.DOC] = `Return the byte size for known float-based types.
|
||||||
|
|
||||||
|
:param type: A string type identifier (e.g., 'float', 'vec2', 'vec3', 'vec4', 'mat4').
|
||||||
|
:return: Integer number of bytes.
|
||||||
|
`
|
||||||
|
|
||||||
var sprite_model_ubo = {
|
var sprite_model_ubo = {
|
||||||
model: unit_transform,
|
model: unit_transform,
|
||||||
color: [1,1,1,1]
|
color: [1,1,1,1]
|
||||||
@@ -262,16 +285,14 @@ function make_pipeline(pipeline) {
|
|||||||
var buffer_descriptions = []
|
var buffer_descriptions = []
|
||||||
var attributes = []
|
var attributes = []
|
||||||
|
|
||||||
// 2) For each input in the reflection, build one buffer + attribute
|
// 2) Build buffer + attribute for each reflection input
|
||||||
// (Simplest approach: each input is stored in its own slot, offset=0)
|
|
||||||
for (var i = 0; i < inputs.length; i++) {
|
for (var i = 0; i < inputs.length; i++) {
|
||||||
var inp = inputs[i]
|
var inp = inputs[i]
|
||||||
var typeStr = inp.type
|
var typeStr = inp.type
|
||||||
var nameStr = (inp.name || "").toUpperCase()
|
var nameStr = (inp.name || "").toUpperCase()
|
||||||
var pitch = 4 // fallback if unknown
|
var pitch = 4
|
||||||
var fmt = "float1"
|
var fmt = "float1"
|
||||||
|
|
||||||
// Decide pitch & format based on 'type'
|
|
||||||
if (typeStr == "vec2") {
|
if (typeStr == "vec2") {
|
||||||
pitch = 8
|
pitch = 8
|
||||||
fmt = "float2"
|
fmt = "float2"
|
||||||
@@ -279,17 +300,15 @@ function make_pipeline(pipeline) {
|
|||||||
pitch = 12
|
pitch = 12
|
||||||
fmt = "float3"
|
fmt = "float3"
|
||||||
} else if (typeStr == "vec4") {
|
} else if (typeStr == "vec4") {
|
||||||
// Special case: if "COLOR" is in the name, treat it as packed bytes
|
|
||||||
if (nameStr.indexOf("COLOR") >= 0) {
|
if (nameStr.indexOf("COLOR") >= 0) {
|
||||||
pitch = 16
|
pitch = 16
|
||||||
fmt = "color" // signals engine to use SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4NORM
|
fmt = "color"
|
||||||
} else {
|
} else {
|
||||||
pitch = 16
|
pitch = 16
|
||||||
fmt = "float4"
|
fmt = "float4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a buffer description for this input
|
|
||||||
buffer_descriptions.push({
|
buffer_descriptions.push({
|
||||||
slot: i,
|
slot: i,
|
||||||
pitch: pitch,
|
pitch: pitch,
|
||||||
@@ -298,7 +317,6 @@ function make_pipeline(pipeline) {
|
|||||||
name:inp.name.split(".").pop()
|
name:inp.name.split(".").pop()
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create a matching vertex attribute
|
|
||||||
attributes.push({
|
attributes.push({
|
||||||
location: inp.location,
|
location: inp.location,
|
||||||
buffer_slot: i,
|
buffer_slot: i,
|
||||||
@@ -307,21 +325,25 @@ function make_pipeline(pipeline) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Attach these arrays onto the pipeline object
|
|
||||||
pipeline.vertex_buffer_descriptions = buffer_descriptions
|
pipeline.vertex_buffer_descriptions = buffer_descriptions
|
||||||
pipeline.vertex_attributes = attributes
|
pipeline.vertex_attributes = attributes
|
||||||
|
|
||||||
// 4) Hand off the pipeline to native code
|
|
||||||
pipeline.gpu = render._main.make_pipeline(pipeline);
|
pipeline.gpu = render._main.make_pipeline(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_pipeline[prosperon.DOC] = `Create and store a GPU pipeline object if it has not already been created.
|
||||||
|
|
||||||
|
:param pipeline: An object describing the pipeline state, shaders, and reflection data.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
var shader_type;
|
var shader_type;
|
||||||
|
|
||||||
function make_shader(sh_file) {
|
function make_shader(sh_file) {
|
||||||
var file = `shaders/${shader_type}/${sh_file}.${shader_type}`
|
var file = `shaders/${shader_type}/${sh_file}.${shader_type}`
|
||||||
if (shader_cache[file]) return shader_cache[file]
|
if (shader_cache[file]) return shader_cache[file]
|
||||||
var refl = json.decode(io.slurp(`shaders/reflection/${sh_file}.json`))
|
var refl = json.decode(io.slurp(`shaders/reflection/${sh_file}.json`))
|
||||||
|
|
||||||
var shader = {
|
var shader = {
|
||||||
code: io.slurpbytes(file),
|
code: io.slurpbytes(file),
|
||||||
format: shader_type,
|
format: shader_type,
|
||||||
@@ -341,46 +363,54 @@ function make_shader(sh_file) {
|
|||||||
return shader
|
return shader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
make_shader[prosperon.DOC] = `Load and compile a shader from disk, caching the result. Reflective metadata is also loaded.
|
||||||
|
|
||||||
|
:param sh_file: The base filename (without extension) of the shader to compile.
|
||||||
|
:return: A shader object with GPU and reflection data attached.
|
||||||
|
`
|
||||||
|
|
||||||
|
// helpful render devices. width and height in pixels; diagonal in inches.
|
||||||
render.device = {
|
render.device = {
|
||||||
pc: [1920, 1080],
|
pc: { width: 1920, height: 1080 },
|
||||||
macbook_m2: [2560, 1664, 13.6],
|
macbook_m2: { width: 2560, height: 1664, diagonal: 13.6 },
|
||||||
ds_top: [400, 240, 3.53],
|
ds_top: { width: 400, height: 240, diagonal: 3.53 },
|
||||||
ds_bottom: [320, 240, 3.02],
|
ds_bottom: { width: 320, height: 240, diagonal: 3.02 },
|
||||||
playdate: [400, 240, 2.7],
|
playdate: { width: 400, height: 240, diagonal: 2.7 },
|
||||||
switch: [1280, 720, 6.2],
|
switch: { width: 1280, height: 720, diagonal: 6.2 },
|
||||||
switch_lite: [1280, 720, 5.5],
|
switch_lite: { width: 1280, height: 720, diagonal: 5.5 },
|
||||||
switch_oled: [1280, 720, 7],
|
switch_oled: { width: 1280, height: 720, diagonal: 7 },
|
||||||
dsi: [256, 192, 3.268],
|
dsi: { width: 256, height: 192, diagonal: 3.268 },
|
||||||
ds: [256, 192, 3],
|
ds: { width: 256, height: 192, diagonal: 3 },
|
||||||
dsixl: [256, 192, 4.2],
|
dsixl: { width: 256, height: 192, diagonal: 4.2 },
|
||||||
ipad_air_m2: [2360, 1640, 11.97],
|
ipad_air_m2: { width: 2360, height: 1640, diagonal: 11.97 },
|
||||||
iphone_se: [1334, 750, 4.7],
|
iphone_se: { width: 1334, height: 750, diagonal: 4.7 },
|
||||||
iphone_12_pro: [2532, 1170, 6.06],
|
iphone_12_pro: { width: 2532, height: 1170, diagonal: 6.06 },
|
||||||
iphone_15: [2556, 1179, 6.1],
|
iphone_15: { width: 2556, height: 1179, diagonal: 6.1 },
|
||||||
gba: [240, 160, 2.9],
|
gba: { width: 240, height: 160, diagonal: 2.9 },
|
||||||
gameboy: [160, 144, 2.48],
|
gameboy: { width: 160, height: 144, diagonal: 2.48 },
|
||||||
gbc: [160, 144, 2.28],
|
gbc: { width: 160, height: 144, diagonal: 2.28 },
|
||||||
steamdeck: [1280, 800, 7],
|
steamdeck: { width: 1280, height: 800, diagonal: 7 },
|
||||||
vita: [960, 544, 5],
|
vita: { width: 960, height: 544, diagonal: 5 },
|
||||||
psp: [480, 272, 4.3],
|
psp: { width: 480, height: 272, diagonal: 4.3 },
|
||||||
imac_m3: [4480, 2520, 23.5],
|
imac_m3: { width: 4480, height: 2520, diagonal: 23.5 },
|
||||||
macbook_pro_m3: [3024, 1964, 14.2],
|
macbook_pro_m3: { width: 3024, height: 1964, diagonal: 14.2 },
|
||||||
ps1: [320, 240, 5],
|
ps1: { width: 320, height: 240, diagonal: 5 },
|
||||||
ps2: [640, 480],
|
ps2: { width: 640, height: 480 },
|
||||||
snes: [256, 224],
|
snes: { width: 256, height: 224 },
|
||||||
gamecube: [640, 480],
|
gamecube: { width: 640, height: 480 },
|
||||||
n64: [320, 240],
|
n64: { width: 320, height: 240 },
|
||||||
c64: [320, 200],
|
c64: { width: 320, height: 200 },
|
||||||
macintosh: [512, 342, 9],
|
macintosh: { width: 512, height: 342 },
|
||||||
gamegear: [160, 144, 3.2],
|
gamegear: { width: 160, height: 144, diagonal: 3.2 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
|
||||||
|
|
||||||
var render_queue = [];
|
var render_queue = [];
|
||||||
var hud_queue = [];
|
var hud_queue = [];
|
||||||
|
|
||||||
var current_queue = render_queue;
|
var current_queue = render_queue;
|
||||||
|
|
||||||
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
|
|
||||||
var std_sampler = {
|
var std_sampler = {
|
||||||
min_filter: "nearest",
|
min_filter: "nearest",
|
||||||
mag_filter: "nearest",
|
mag_filter: "nearest",
|
||||||
@@ -397,10 +427,7 @@ var std_sampler = {
|
|||||||
compare: false
|
compare: false
|
||||||
};
|
};
|
||||||
|
|
||||||
var tbuffer;
|
function upload_model(model) {
|
||||||
|
|
||||||
function upload_model(model)
|
|
||||||
{
|
|
||||||
var bufs = [];
|
var bufs = [];
|
||||||
for (var i in model) {
|
for (var i in model) {
|
||||||
if (typeof model[i] !== 'object') continue;
|
if (typeof model[i] !== 'object') continue;
|
||||||
@@ -409,39 +436,56 @@ function upload_model(model)
|
|||||||
render._main.upload(this, bufs);
|
render._main.upload(this, bufs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bind_model(pass,pipeline,model)
|
upload_model[prosperon.DOC] = `Upload all buffer-like properties of the given model to the GPU.
|
||||||
{
|
|
||||||
|
:param model: An object whose buffer properties are to be uploaded.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
function bind_model(pass, pipeline, model) {
|
||||||
var buffers = pipeline.vertex_buffer_descriptions;
|
var buffers = pipeline.vertex_buffer_descriptions;
|
||||||
var bufs = [];
|
var bufs = [];
|
||||||
if (buffers)
|
if (buffers)
|
||||||
for (var b of buffers) {
|
for (var b of buffers) {
|
||||||
if (b.name in model)
|
if (b.name in model) bufs.push(model[b.name])
|
||||||
bufs.push(model[b.name])
|
else throw Error (`could not find buffer ${b.name} on model`);
|
||||||
else
|
}
|
||||||
throw Error (`could not find buffer ${b.name} on model`);
|
|
||||||
}
|
|
||||||
pass.bind_buffers(0,bufs);
|
pass.bind_buffers(0,bufs);
|
||||||
pass.bind_index_buffer(model.indices);
|
pass.bind_index_buffer(model.indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bind_mat(pass, pipeline, mat)
|
bind_model[prosperon.DOC] = `Bind the model's vertex and index buffers for the given pipeline and render pass.
|
||||||
{
|
|
||||||
|
:param pass: The current render pass.
|
||||||
|
:param pipeline: The pipeline object with vertex buffer descriptions.
|
||||||
|
:param model: The model object containing matching buffers and an index buffer.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
function bind_mat(pass, pipeline, mat) {
|
||||||
var imgs = [];
|
var imgs = [];
|
||||||
var refl = pipeline.fragment.reflection;
|
var refl = pipeline.fragment.reflection;
|
||||||
if (refl.separate_images) {
|
if (refl.separate_images) {
|
||||||
for (var i of refl.separate_images) {
|
for (var i of refl.separate_images) {
|
||||||
if (i.name in mat) {
|
if (i.name in mat) {
|
||||||
var tex = mat[i.name];
|
var tex = mat[i.name];
|
||||||
imgs.push({texture:tex.texture, sampler:tex.sampler});
|
imgs.push({texture:tex.texture, sampler:tex.sampler});
|
||||||
} else
|
} else
|
||||||
throw Error (`could not find all necessary images: ${i.name}`)
|
throw Error (`could not find all necessary images: ${i.name}`)
|
||||||
}
|
}
|
||||||
pass.bind_samplers(false, 0,imgs);
|
pass.bind_samplers(false, 0,imgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function group_sprites_by_texture(sprites, mesh)
|
bind_mat[prosperon.DOC] = `Bind the material images and samplers needed by the pipeline's fragment shader.
|
||||||
{
|
|
||||||
|
:param pass: The current render pass.
|
||||||
|
:param pipeline: The pipeline whose fragment shader reflection indicates required textures.
|
||||||
|
:param mat: An object mapping the required image names to {texture, sampler}.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
function group_sprites_by_texture(sprites, mesh) {
|
||||||
if (sprites.length === 0) return;
|
if (sprites.length === 0) return;
|
||||||
for (var i = 0; i < sprites.length; i++) {
|
for (var i = 0; i < sprites.length; i++) {
|
||||||
sprites[i].mesh = mesh;
|
sprites[i].mesh = mesh;
|
||||||
@@ -449,6 +493,8 @@ function group_sprites_by_texture(sprites, mesh)
|
|||||||
sprites[i].num_indices = 6;
|
sprites[i].num_indices = 6;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
// The code below is an alternate approach to grouping by image. Currently not in use.
|
||||||
|
/*
|
||||||
var groups = [];
|
var groups = [];
|
||||||
var group = {image:sprites[0].image, first_index:0};
|
var group = {image:sprites[0].image, first_index:0};
|
||||||
var count = 1;
|
var count = 1;
|
||||||
@@ -463,12 +509,18 @@ function group_sprites_by_texture(sprites, mesh)
|
|||||||
groups.push(group);
|
groups.push(group);
|
||||||
count=1;
|
count=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
group.num_indices = count*6;
|
group.num_indices = count*6;
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group_sprites_by_texture[prosperon.DOC] = `Assign each sprite to the provided mesh, generating index data as needed.
|
||||||
|
|
||||||
|
:param sprites: An array of sprite objects.
|
||||||
|
:param mesh: A mesh object (pos, color, uv, indices, etc.) to link to each sprite.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
var main_color = {
|
var main_color = {
|
||||||
type:"2d",
|
type:"2d",
|
||||||
format: "rgba8",
|
format: "rgba8",
|
||||||
@@ -489,8 +541,7 @@ var main_depth = {
|
|||||||
depth_target:true
|
depth_target:true
|
||||||
};
|
};
|
||||||
|
|
||||||
function render_camera(cmds, camera)
|
function render_camera(cmds, camera) {
|
||||||
{
|
|
||||||
var pass;
|
var pass;
|
||||||
delete camera.target // TODO: HORRIBLE
|
delete camera.target // TODO: HORRIBLE
|
||||||
if (!camera.target) {
|
if (!camera.target) {
|
||||||
@@ -504,14 +555,13 @@ function render_camera(cmds, camera)
|
|||||||
load:"clear",
|
load:"clear",
|
||||||
store:"store",
|
store:"store",
|
||||||
clear: cornflower
|
clear: cornflower
|
||||||
}
|
}],
|
||||||
],
|
|
||||||
depth_stencil: {
|
depth_stencil: {
|
||||||
texture: render._main.texture(main_depth),
|
texture: render._main.texture(main_depth),
|
||||||
clear:1,
|
clear:1,
|
||||||
load:"dont_care", // if clear, crash on dx12
|
load:"dont_care",
|
||||||
store:"dont_care",
|
store:"dont_care",
|
||||||
stencil_load:"dont_care", // ditto
|
stencil_load:"dont_care",
|
||||||
stencil_store:"dont_care",
|
stencil_store:"dont_care",
|
||||||
stencil_clear:0
|
stencil_clear:0
|
||||||
}
|
}
|
||||||
@@ -522,11 +572,11 @@ function render_camera(cmds, camera)
|
|||||||
buffers = buffers.concat(graphics.queue_sprite_mesh(render_queue));
|
buffers = buffers.concat(graphics.queue_sprite_mesh(render_queue));
|
||||||
var unique_meshes = [...new Set(render_queue.map(x => x.mesh))];
|
var unique_meshes = [...new Set(render_queue.map(x => x.mesh))];
|
||||||
for (var q of unique_meshes)
|
for (var q of unique_meshes)
|
||||||
buffers = buffers.concat([q.pos, q.color,q.uv,q.indices]);
|
buffers = buffers.concat([q.pos, q.color, q.uv, q.indices]);
|
||||||
|
|
||||||
buffers = buffers.concat(graphics.queue_sprite_mesh(hud_queue));
|
buffers = buffers.concat(graphics.queue_sprite_mesh(hud_queue));
|
||||||
for (var q of hud_queue)
|
for (var q of hud_queue)
|
||||||
if (q.type === 'geometry') buffers = buffers.concat([q.mesh.pos, q.mesh.color,q.mesh.uv,q.mesh.indices]);
|
if (q.type === 'geometry') buffers = buffers.concat([q.mesh.pos, q.mesh.color, q.mesh.uv, q.mesh.indices]);
|
||||||
|
|
||||||
full_upload(buffers)
|
full_upload(buffers)
|
||||||
|
|
||||||
@@ -552,7 +602,7 @@ function render_camera(cmds, camera)
|
|||||||
cmds.push_debug_group("draw")
|
cmds.push_debug_group("draw")
|
||||||
for (var group of render_queue) {
|
for (var group of render_queue) {
|
||||||
if (mesh != group.mesh) {
|
if (mesh != group.mesh) {
|
||||||
mesh = group.mesh;
|
mesh = group.mesh;
|
||||||
bind_model(pass,pipeline,mesh);
|
bind_model(pass,pipeline,mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,13 +617,13 @@ function render_camera(cmds, camera)
|
|||||||
cmds.pop_debug_group()
|
cmds.pop_debug_group()
|
||||||
|
|
||||||
cmds.push_debug_group("hud")
|
cmds.push_debug_group("hud")
|
||||||
var camslot = get_pipeline_ubo_slot(pipeline, 'TransformBuffer');
|
var camslot = get_pipeline_ubo_slot(pipeline, 'TransformBuffer');
|
||||||
if (typeof camslot !== 'undefined')
|
if (typeof camslot !== 'undefined')
|
||||||
cmds.hud(camera.size, camslot);
|
cmds.hud(camera.size, camslot);
|
||||||
|
|
||||||
for (var group of hud_queue) {
|
for (var group of hud_queue) {
|
||||||
if (mesh != group.mesh) {
|
if (mesh != group.mesh) {
|
||||||
mesh = group.mesh;
|
mesh = group.mesh;
|
||||||
bind_model(pass,pipeline,mesh);
|
bind_model(pass,pipeline,mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,45 +643,53 @@ function render_camera(cmds, camera)
|
|||||||
hud_queue = [];
|
hud_queue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
var swaps = [];
|
render_camera[prosperon.DOC] = `Render a scene using the provided camera, drawing both render queue and HUD queue items.
|
||||||
function gpupresent()
|
|
||||||
{
|
|
||||||
os.clean_transforms();
|
|
||||||
var cmds = render._main.acquire_cmd_buffer();
|
|
||||||
render_camera(cmds, prosperon.camera);
|
|
||||||
var swapchain_tex = cmds.acquire_swapchain();
|
|
||||||
if (!swapchain_tex)
|
|
||||||
cmds.cancel();
|
|
||||||
else {
|
|
||||||
var torect = prosperon.camera.draw_rect(prosperon.window.size);
|
|
||||||
torect.texture = swapchain_tex;
|
|
||||||
if (swapchain_tex) {
|
|
||||||
cmds.blit({
|
|
||||||
src: prosperon.camera.target.color_targets[0].texture,
|
|
||||||
dst: torect,
|
|
||||||
filter:"nearest",
|
|
||||||
load: "clear"
|
|
||||||
});
|
|
||||||
|
|
||||||
// imgui
|
:param cmds: A command buffer obtained from the GPU context.
|
||||||
/* cmds.push_debug_group("imgui")
|
:param camera: The camera object (with size, optional target, etc.).
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
var imgui //= use('imgui')
|
||||||
|
if (imgui) imgui.init(render._main, prosperon.window);
|
||||||
|
|
||||||
|
var swaps = [];
|
||||||
|
function gpupresent() {
|
||||||
|
os.clean_transforms();
|
||||||
|
var cmds = render._main.acquire_cmd_buffer();
|
||||||
|
render_camera(cmds, prosperon.camera);
|
||||||
|
var swapchain_tex = cmds.acquire_swapchain();
|
||||||
|
if (!swapchain_tex)
|
||||||
|
cmds.cancel();
|
||||||
|
else {
|
||||||
|
var torect = prosperon.camera.draw_rect(prosperon.window.size);
|
||||||
|
torect.texture = swapchain_tex;
|
||||||
|
if (swapchain_tex) {
|
||||||
|
cmds.blit({
|
||||||
|
src: prosperon.camera.target.color_targets[0].texture,
|
||||||
|
dst: torect,
|
||||||
|
filter:"nearest",
|
||||||
|
load: "clear"
|
||||||
|
});
|
||||||
|
|
||||||
|
if (imgui) {
|
||||||
|
cmds.push_debug_group("imgui")
|
||||||
imgui.prepend(cmds);
|
imgui.prepend(cmds);
|
||||||
var pass = cmds.render_pass({
|
var pass = cmds.render_pass({
|
||||||
color_targets:[{texture:swapchain_tex}]});
|
color_targets:[{texture:swapchain_tex}]});
|
||||||
imgui.endframe(cmds,pass);
|
imgui.endframe(cmds,pass);
|
||||||
pass.end();
|
pass.end();
|
||||||
cmds.pop_debug_group()*/
|
cmds.pop_debug_group()
|
||||||
}
|
}
|
||||||
cmds.submit()
|
|
||||||
}
|
}
|
||||||
|
cmds.submit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render.toggles = {
|
gpupresent[prosperon.DOC] = `Perform the per-frame rendering and present the final swapchain image, including imgui pass if available.
|
||||||
draw_sprites:true,
|
|
||||||
draw_particles:true,
|
:return: None
|
||||||
draw_hud:true,
|
`
|
||||||
draw_gui:true
|
|
||||||
}
|
|
||||||
|
|
||||||
var stencil_write = {
|
var stencil_write = {
|
||||||
compare: "always",
|
compare: "always",
|
||||||
@@ -640,8 +698,7 @@ var stencil_write = {
|
|||||||
pass_op: "replace"
|
pass_op: "replace"
|
||||||
};
|
};
|
||||||
|
|
||||||
var stencil_writer = function stencil_writer(ref)
|
var stencil_writer = function stencil_writer(ref) {
|
||||||
{
|
|
||||||
var pipe = Object.create(base_pipeline);
|
var pipe = Object.create(base_pipeline);
|
||||||
Object.assign(pipe, {
|
Object.assign(pipe, {
|
||||||
stencil: {
|
stencil: {
|
||||||
@@ -660,13 +717,18 @@ var stencil_writer = function stencil_writer(ref)
|
|||||||
render.stencil_writer = stencil_writer;
|
render.stencil_writer = stencil_writer;
|
||||||
|
|
||||||
// objects by default draw where the stencil buffer is 0
|
// objects by default draw where the stencil buffer is 0
|
||||||
render.fillmask = function fillmask(ref)
|
render.fillmask = function fillmask(ref) {
|
||||||
{
|
|
||||||
var pipe = stencil_writer(ref);
|
var pipe = stencil_writer(ref);
|
||||||
render.use_shader('screenfill.cg', pipe);
|
render.use_shader('screenfill.cg', pipe);
|
||||||
render.draw(shape.quad);
|
render.draw(shape.quad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render.fillmask[prosperon.DOC] = `Draw a fullscreen shape using a 'screenfill' shader to populate the stencil buffer with a given reference.
|
||||||
|
|
||||||
|
:param ref: The stencil reference value to write.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
var stencil_invert = {
|
var stencil_invert = {
|
||||||
compare: "always",
|
compare: "always",
|
||||||
fail_op: "invert",
|
fail_op: "invert",
|
||||||
@@ -674,20 +736,18 @@ var stencil_invert = {
|
|||||||
pass_op: "invert"
|
pass_op: "invert"
|
||||||
};
|
};
|
||||||
|
|
||||||
render.mask = function mask(image, pos, scale, rotation = 0, ref = 1)
|
render.mask = function mask(image, pos, scale, rotation = 0, ref = 1) {
|
||||||
{
|
|
||||||
if (typeof image === 'string')
|
if (typeof image === 'string')
|
||||||
image = graphics.texture(image);
|
image = graphics.texture(image);
|
||||||
|
|
||||||
var tex = image.texture;
|
var tex = image.texture;
|
||||||
|
if (scale) scale = scale.div([tex.width,tex.height]);
|
||||||
if (scale) scale = sacle.div([tex.width,tex.height]);
|
|
||||||
else scale = [1,1,1]
|
else scale = [1,1,1]
|
||||||
|
|
||||||
var pipe = stencil_writer(ref);
|
var pipe = stencil_writer(ref);
|
||||||
render.use_shader('sprite.cg', pipe);
|
render.use_shader('sprite.cg', pipe);
|
||||||
var t = os.make_transform();
|
var t = os.make_transform();
|
||||||
t.trs(pos, undefined,scale);
|
t.trs(pos, undefined, scale);
|
||||||
set_model(t);
|
set_model(t);
|
||||||
render.use_mat({
|
render.use_mat({
|
||||||
diffuse:image.texture,
|
diffuse:image.texture,
|
||||||
@@ -697,26 +757,35 @@ render.mask = function mask(image, pos, scale, rotation = 0, ref = 1)
|
|||||||
render.draw(shape.quad);
|
render.draw(shape.quad);
|
||||||
}
|
}
|
||||||
|
|
||||||
render.viewport = function(rect)
|
render.mask[prosperon.DOC] = `Draw an image to the stencil buffer, marking its area with a specified reference value.
|
||||||
{
|
|
||||||
|
:param image: A texture or string path (which is converted to a texture).
|
||||||
|
:param pos: The translation (x, y) for the image placement.
|
||||||
|
:param scale: Optional scaling applied to the texture.
|
||||||
|
:param rotation: Optional rotation in radians (unused by default).
|
||||||
|
:param ref: The stencil reference value to write.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
render.viewport = function(rect) {
|
||||||
render._main.viewport(rect);
|
render._main.viewport(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
render.scissor = function(rect)
|
render.viewport[prosperon.DOC] = `Set the GPU viewport to the specified rectangle.
|
||||||
{
|
|
||||||
|
:param rect: A rectangle [x, y, width, height].
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
render.scissor = function(rect) {
|
||||||
render.viewport(rect)
|
render.viewport(rect)
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////
|
|
||||||
var screencolor;
|
|
||||||
|
|
||||||
function imtoggle(name, obj, field) {
|
render.scissor[prosperon.DOC] = `Set the GPU scissor region to the specified rectangle (alias of render.viewport).
|
||||||
var changed = false;
|
|
||||||
var old = obj[field];
|
:param rect: A rectangle [x, y, width, height].
|
||||||
obj[field] = imgui.checkbox(name, obj[field]);
|
:return: None
|
||||||
if (old !== obj[field]) return true;
|
`
|
||||||
return false;
|
|
||||||
};
|
|
||||||
var replstr = "";
|
|
||||||
|
|
||||||
var imdebug = function imdebug() {
|
var imdebug = function imdebug() {
|
||||||
imtoggle("Physics", debug, "draw_phys");
|
imtoggle("Physics", debug, "draw_phys");
|
||||||
@@ -731,82 +800,6 @@ var observed_tex = undefined;
|
|||||||
|
|
||||||
var debug = {}
|
var debug = {}
|
||||||
debug.console = false
|
debug.console = false
|
||||||
var imgui_fn = function imgui_fn() {
|
|
||||||
return;
|
|
||||||
imgui.newframe();
|
|
||||||
if (debug.console)
|
|
||||||
debug.console = imgui.window("console", _ => {
|
|
||||||
imgui.text(console.transcript);
|
|
||||||
replstr = imgui.textinput(undefined, replstr);
|
|
||||||
imgui.button("submit", _ => {
|
|
||||||
eval(replstr);
|
|
||||||
replstr = "";
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
imgui.mainmenubar(_ => {
|
|
||||||
imgui.menu("File", _ => {
|
|
||||||
imgui.menu("Game settings", _ => {
|
|
||||||
prosperon.title = imgui.textinput("Title", prosperon.title);
|
|
||||||
prosperon.icon = imgui.textinput("Icon", prosperon.icon);
|
|
||||||
imgui.button("Refresh window", _ => {
|
|
||||||
prosperon.set_icon(graphics.texture(prosperon.icon));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
imgui.button("quit", os.exit);
|
|
||||||
});
|
|
||||||
imgui.menu("Debug", imdebug);
|
|
||||||
imgui.menu("View", _ => {
|
|
||||||
imtoggle("Terminal out", debug, "termout");
|
|
||||||
imtoggle("Meta [f7]", debug, "meta");
|
|
||||||
imtoggle("Cheats [f8]", debug, "cheat");
|
|
||||||
imtoggle("Console [f9]", debug, "console");
|
|
||||||
});
|
|
||||||
|
|
||||||
imgui.sokol_gfx();
|
|
||||||
|
|
||||||
imgui.menu("Graphics", _ => {
|
|
||||||
imtoggle("Draw sprites", render, "draw_sprites");
|
|
||||||
imtoggle("Draw particles", render, "draw_particles");
|
|
||||||
imtoggle("Draw HUD", render, "draw_hud");
|
|
||||||
imtoggle("Draw GUI", render, "draw_gui");
|
|
||||||
|
|
||||||
imgui.menu("Window", _ => {
|
|
||||||
prosperon.fullscreen = imgui.checkbox("fullscreen", prosperon.fullscreen);
|
|
||||||
// prosperon.vsync = imgui.checkbox("vsync", prosperon.vsync);
|
|
||||||
imgui.menu("MSAA", _ => {
|
|
||||||
for (var msaa of gamestate.msaa) imgui.button(msaa + "x", _ => (prosperon.sample_count = msaa));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
prosperon.menu_hook?.();
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (observed_tex) {
|
|
||||||
imgui.window("texture", _ => {
|
|
||||||
imgui.image(observed_tex);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var texs = {};
|
|
||||||
for (var path in graphics.texture.cache) {
|
|
||||||
var image = graphics.texture.cache[path];
|
|
||||||
if (image.texture && !texs[image.texture])
|
|
||||||
texs[image.texture] = image.texture;
|
|
||||||
}
|
|
||||||
imgui.window("textures", _ => {
|
|
||||||
for (var img in texs) {
|
|
||||||
imgui.button(img, _ => {
|
|
||||||
observed_tex = texs[img];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
// prosperon.imgui();
|
|
||||||
// imgui.endframe(render._main);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Some initialization
|
// Some initialization
|
||||||
shader_type = render._main.shader_format()[0];
|
shader_type = render._main.shader_format()[0];
|
||||||
@@ -821,18 +814,40 @@ std_sampler = render._main.make_sampler({
|
|||||||
});
|
});
|
||||||
|
|
||||||
render._main.present = gpupresent;
|
render._main.present = gpupresent;
|
||||||
//imgui.init(render._main, prosperon.window);
|
|
||||||
tracy.gpu_init()
|
tracy.gpu_init()
|
||||||
|
|
||||||
render.queue = function(cmd)
|
render.queue = function(cmd) {
|
||||||
{
|
|
||||||
if (Array.isArray(cmd))
|
if (Array.isArray(cmd))
|
||||||
for (var i of cmd) current_queue.push(i)
|
for (var i of cmd) current_queue.push(i)
|
||||||
else
|
else
|
||||||
current_queue.push(cmd)
|
current_queue.push(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
render.setup_draw = function() { current_queue = render_queue; prosperon.draw() }
|
render.queue[prosperon.DOC] = `Enqueue one or more draw commands. These commands are batched until render_camera is called.
|
||||||
render.setup_hud = function() { current_queue = hud_queue; prosperon.hud() }
|
|
||||||
|
|
||||||
return render
|
:param cmd: Either a single command object or an array of command objects.
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
render.setup_draw = function() {
|
||||||
|
current_queue = render_queue;
|
||||||
|
prosperon.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
render.setup_draw[prosperon.DOC] = `Switch the current queue to the primary scene render queue, then invoke 'prosperon.draw' if defined.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
render.setup_hud = function() {
|
||||||
|
current_queue = hud_queue;
|
||||||
|
prosperon.hud();
|
||||||
|
}
|
||||||
|
|
||||||
|
render.setup_hud[prosperon.DOC] = `Switch the current queue to the HUD render queue, then invoke 'prosperon.hud' if defined.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
`
|
||||||
|
|
||||||
|
return render
|
||||||
@@ -1,20 +1,30 @@
|
|||||||
var time = this
|
var time = this;
|
||||||
|
|
||||||
/* Time values are always expressed in terms of real earth-seconds */
|
time.second = 1;
|
||||||
Object.assign(time, {
|
time.minute = 60;
|
||||||
hour2minute() {
|
time.hour = 3600;
|
||||||
return this.hour / this.minute;
|
time.day = 86400;
|
||||||
},
|
time.week = 604800;
|
||||||
day2hour() {
|
time.weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
||||||
return this.day / this.hour;
|
time.monthstr = ["January", "February", "March", "April", "May", "June",
|
||||||
},
|
"July", "August", "September", "October", "November", "December"];
|
||||||
minute2second() {
|
time.epoch = 1970;
|
||||||
return this.minute / this.second;
|
|
||||||
},
|
time.hour2minute = function() {
|
||||||
week2day() {
|
return this.hour / this.minute;
|
||||||
return this.week / this.day;
|
};
|
||||||
},
|
|
||||||
});
|
time.day2hour = function() {
|
||||||
|
return this.day / this.hour;
|
||||||
|
};
|
||||||
|
|
||||||
|
time.minute2second = function() {
|
||||||
|
return this.minute / this.second;
|
||||||
|
};
|
||||||
|
|
||||||
|
time.week2day = function() {
|
||||||
|
return this.week / this.day;
|
||||||
|
};
|
||||||
|
|
||||||
time.strparse = {
|
time.strparse = {
|
||||||
yyyy: "year",
|
yyyy: "year",
|
||||||
@@ -32,62 +42,28 @@ time.strparse = {
|
|||||||
s: "second",
|
s: "second",
|
||||||
};
|
};
|
||||||
|
|
||||||
time.now[prosperon.DOC] = "Return the current system time as a floating-point number of seconds with microsecond precision."
|
time.isleap = function(year) {
|
||||||
time.computer_dst[prosperon.DOC] = "Return true if the local system time is currently in Daylight Savings Time, otherwise false."
|
|
||||||
time.computer_zone[prosperon.DOC] = "Return the local time zone offset from UTC in hours, e.g. -5 for EST."
|
|
||||||
|
|
||||||
time.doc = {
|
|
||||||
doc: "Functions for manipulating time.",
|
|
||||||
second: "Earth-seconds in a second.",
|
|
||||||
minute: "Seconds in a minute.",
|
|
||||||
hour: "Seconds in an hour.",
|
|
||||||
day: "Seconds in a day.",
|
|
||||||
week: "Seconds in a week.",
|
|
||||||
weekdays: "Names of the days of the week.",
|
|
||||||
monthstr: "Full names of the months of the year.",
|
|
||||||
epoch: "Times are expressed in terms of day 0 at hms 0 of this year.",
|
|
||||||
now: "Get the time now.",
|
|
||||||
computer_zone: "Get the time zone of the running computer.",
|
|
||||||
computer_dst: "Return true if the computer is in daylight savings.",
|
|
||||||
yearsize: "Given a year, return the number of days in that year.",
|
|
||||||
monthdays: "Number of days in each month.",
|
|
||||||
fmt: "Default format for time.",
|
|
||||||
record: "Given a time, return an object with time fields.",
|
|
||||||
number: "Return the number representation of a given time.",
|
|
||||||
text: "Return a text formatted time.",
|
|
||||||
};
|
|
||||||
|
|
||||||
time.second = 1;
|
|
||||||
time.minute = 60;
|
|
||||||
time.hour = 3_600;
|
|
||||||
time.day = 86_400;
|
|
||||||
time.week = 604_800;
|
|
||||||
time.weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
||||||
time.monthstr = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
||||||
|
|
||||||
time.epoch = 1970;
|
|
||||||
time.isleap = function (year) {
|
|
||||||
return this.yearsize(year) === 366;
|
return this.yearsize(year) === 366;
|
||||||
};
|
};
|
||||||
time.isleap.doc = "Return true if the given year is a leapyear.";
|
|
||||||
|
|
||||||
time.yearsize = function (y) {
|
time.yearsize = function(y) {
|
||||||
if (y % 4 === 0 && (y % 100 != 0 || y % 400 === 0)) return 366;
|
if (y % 4 === 0 && (y % 100 !== 0 || y % 400 === 0)) return 366;
|
||||||
return 365;
|
return 365;
|
||||||
};
|
};
|
||||||
|
|
||||||
time.timecode = function (t, fps = 24) {
|
time.timecode = function(t, fps = 24) {
|
||||||
var s = Math.trunc(t);
|
var s = Math.trunc(t);
|
||||||
t -= s;
|
t -= s;
|
||||||
return `${s}:${Math.trunc(fps * s)}`;
|
return `${s}:${Math.trunc(fps * s)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
time.monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||||
time.zones = {};
|
time.zones = { "-12": "IDLW" };
|
||||||
time.zones["-12"] = "IDLW";
|
|
||||||
time.record = function (num, zone = this.computer_zone()) {
|
time.record = function(num, zone = this.computer_zone()) {
|
||||||
if (typeof num === "object") return num;
|
if (typeof num === "object") {
|
||||||
else if (typeof num === "number") {
|
return num;
|
||||||
|
} else if (typeof num === "number") {
|
||||||
var monthdays = this.monthdays.slice();
|
var monthdays = this.monthdays.slice();
|
||||||
var rec = {
|
var rec = {
|
||||||
second: 0,
|
second: 0,
|
||||||
@@ -99,10 +75,8 @@ time.record = function (num, zone = this.computer_zone()) {
|
|||||||
};
|
};
|
||||||
rec.zone = zone;
|
rec.zone = zone;
|
||||||
num += zone * this.hour;
|
num += zone * this.hour;
|
||||||
|
|
||||||
var hms = num % this.day;
|
var hms = num % this.day;
|
||||||
var day = parseInt(num / this.day);
|
var day = Math.floor(num / this.day);
|
||||||
|
|
||||||
if (hms < 0) {
|
if (hms < 0) {
|
||||||
hms += this.day;
|
hms += this.day;
|
||||||
day--;
|
day--;
|
||||||
@@ -110,48 +84,55 @@ time.record = function (num, zone = this.computer_zone()) {
|
|||||||
rec.second = hms % this.minute;
|
rec.second = hms % this.minute;
|
||||||
var d1 = Math.floor(hms / this.minute);
|
var d1 = Math.floor(hms / this.minute);
|
||||||
rec.minute = d1 % this.minute;
|
rec.minute = d1 % this.minute;
|
||||||
rec.hour = Math.floor(d1 / this.minute);
|
rec.hour = Math.floor(d1 / this.minute);
|
||||||
|
|
||||||
/* addend%7 is 4 */
|
|
||||||
rec.weekday = (day + 4503599627370496 + 2) % 7;
|
rec.weekday = (day + 4503599627370496 + 2) % 7;
|
||||||
|
var yIter = this.epoch;
|
||||||
var d1 = this.epoch;
|
if (day >= 0) {
|
||||||
if (day >= 0) for (d1 = this.epoch; day >= this.yearsize(d1); d1++) day -= this.yearsize(d1);
|
for (yIter = this.epoch; day >= this.yearsize(yIter); yIter++) {
|
||||||
else for (d1 = this.epoch; day < 0; d1--) day += this.yearsize(d1 - 1);
|
day -= this.yearsize(yIter);
|
||||||
|
}
|
||||||
rec.year = d1;
|
} else {
|
||||||
if (rec.year <= 0) rec.ce = "BC";
|
for (yIter = this.epoch; day < 0; yIter--) {
|
||||||
else rec.ce = "AD";
|
day += this.yearsize(yIter - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rec.year = yIter;
|
||||||
|
rec.ce = (rec.year <= 0) ? "BC" : "AD";
|
||||||
rec.yday = day;
|
rec.yday = day;
|
||||||
|
if (this.yearsize(yIter) === 366) {
|
||||||
if (this.yearsize(d1) === 366) monthdays[1] = 29;
|
monthdays[1] = 29;
|
||||||
|
}
|
||||||
var d0 = day;
|
var d0 = day;
|
||||||
for (d1 = 0; d0 >= monthdays[d1]; d1++) d0 -= monthdays[d1];
|
for (d1 = 0; d0 >= monthdays[d1]; d1++) {
|
||||||
|
d0 -= monthdays[d1];
|
||||||
|
}
|
||||||
monthdays[1] = 28;
|
monthdays[1] = 28;
|
||||||
rec.day = d0 + 1;
|
rec.day = d0 + 1;
|
||||||
|
|
||||||
rec.month = d1;
|
rec.month = d1;
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
time.number = function (rec) {
|
time.number = function(rec) {
|
||||||
if (typeof rec === "number") return rec;
|
if (typeof rec === "number") {
|
||||||
else if (typeof rec === "object") {
|
return rec;
|
||||||
|
} else if (typeof rec === "object") {
|
||||||
var c = 0;
|
var c = 0;
|
||||||
var year = rec.year ? rec.year : 0;
|
var year = rec.year || 0;
|
||||||
var hour = rec.hour ? rec.hour : 0;
|
var hour = rec.hour || 0;
|
||||||
var minute = rec.minute ? rec.minute : 0;
|
var minute = rec.minute || 0;
|
||||||
var second = rec.second ? rec.second : 0;
|
var second = rec.second || 0;
|
||||||
var zone = rec.zone ? rec.zone : 0;
|
var zone = rec.zone || 0;
|
||||||
|
var yday = rec.yday || 0;
|
||||||
if (year > this.epoch) for (var i = this.epoch; i < year; i++) c += this.day * this.yearsize(i);
|
|
||||||
else if (year < this.epoch) {
|
|
||||||
for (var i = this.epoch - 1; i > year; i--) c += this.day * this.yearsize(i);
|
|
||||||
|
|
||||||
|
if (year > this.epoch) {
|
||||||
|
for (var i = this.epoch; i < year; i++) {
|
||||||
|
c += this.day * this.yearsize(i);
|
||||||
|
}
|
||||||
|
} else if (year < this.epoch) {
|
||||||
|
for (var i = this.epoch - 1; i > year; i--) {
|
||||||
|
c += this.day * this.yearsize(i);
|
||||||
|
}
|
||||||
c += (this.yearsize(year) - yday - 1) * this.day;
|
c += (this.yearsize(year) - yday - 1) * this.day;
|
||||||
c += (this.day2hour() - hour - 1) * this.hour;
|
c += (this.day2hour() - hour - 1) * this.hour;
|
||||||
c += (this.hour2minute() - minute - 1) * this.minute;
|
c += (this.hour2minute() - minute - 1) * this.minute;
|
||||||
@@ -163,85 +144,89 @@ time.number = function (rec) {
|
|||||||
|
|
||||||
c += second;
|
c += second;
|
||||||
c += minute * this.minute;
|
c += minute * this.minute;
|
||||||
c += hour * this.hour;
|
c += hour * this.hour;
|
||||||
c += yday * this.day;
|
c += yday * this.day;
|
||||||
c -= zone * this.hour;
|
c -= zone * this.hour;
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Time formatting
|
|
||||||
yyyy - year in a 4 digit field
|
|
||||||
y - as many digits as necessary
|
|
||||||
mm - month (1-12)
|
|
||||||
mB - month name
|
|
||||||
mb - abbreviated month name
|
|
||||||
dd - day (1-31)
|
|
||||||
d
|
|
||||||
c - if the year is <= 0, BC. Otherwise, AD.
|
|
||||||
hh - hour
|
|
||||||
h
|
|
||||||
nn - minutes
|
|
||||||
n
|
|
||||||
ss - seconds
|
|
||||||
s
|
|
||||||
v - day of the week (0-6)
|
|
||||||
vB - weekday name
|
|
||||||
vb - abbreviated weekday name
|
|
||||||
a - am/pm
|
|
||||||
z - zone, -12 to +11
|
|
||||||
*/
|
|
||||||
|
|
||||||
time.fmt = "vB mB d h:nn:ss TZz a y c";
|
time.fmt = "vB mB d h:nn:ss TZz a y c";
|
||||||
|
|
||||||
/* If num is a number, converts to a rec first. */
|
time.text = function(num, fmt = this.fmt, zone) {
|
||||||
time.text = function (num, fmt = this.fmt, zone) {
|
var rec = (typeof num === "number") ? time.record(num, zone) : num;
|
||||||
var rec = num;
|
|
||||||
|
|
||||||
if (typeof rec === "number") rec = time.record(num, zone);
|
|
||||||
|
|
||||||
zone = rec.zone;
|
zone = rec.zone;
|
||||||
|
|
||||||
if (fmt.match("a")) {
|
if (fmt.match("a")) {
|
||||||
if (rec.hour >= 13) {
|
if (rec.hour >= 13) {
|
||||||
rec.hour -= 12;
|
rec.hour -= 12;
|
||||||
fmt = fmt.replaceAll("a", "PM");
|
fmt = fmt.replaceAll("a", "PM");
|
||||||
} else if (rec.hour === 12) fmt = fmt.replaceAll("a", "PM");
|
} else if (rec.hour === 12) {
|
||||||
else if (rec.hour === 0) {
|
fmt = fmt.replaceAll("a", "PM");
|
||||||
|
} else if (rec.hour === 0) {
|
||||||
rec.hour = 12;
|
rec.hour = 12;
|
||||||
fmt = fmt.replaceAll("a", "AM");
|
fmt = fmt.replaceAll("a", "AM");
|
||||||
} else fmt = fmt.replaceAll("a", "AM");
|
} else {
|
||||||
|
fmt = fmt.replaceAll("a", "AM");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var year = rec.year > 0 ? rec.year : rec.year - 1;
|
var year = rec.year > 0 ? rec.year : (rec.year - 1);
|
||||||
if (fmt.match("c")) {
|
if (fmt.match("c")) {
|
||||||
if (year < 0) {
|
if (year < 0) {
|
||||||
year = Math.abs(year);
|
year = Math.abs(year);
|
||||||
fmt = fmt.replaceAll("c", "BC");
|
fmt = fmt.replaceAll("c", "BC");
|
||||||
} else fmt = fmt.replaceAll("c", "AD");
|
} else {
|
||||||
|
fmt = fmt.replaceAll("c", "AD");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt = fmt.replaceAll("yyyy", year.toString().padStart(4, "0"));
|
fmt = fmt.replaceAll("yyyy", year.toString().padStart(4, "0"));
|
||||||
fmt = fmt.replaceAll("y", year);
|
fmt = fmt.replaceAll("y", year);
|
||||||
fmt = fmt.replaceAll("eee", rec.yday + 1);
|
fmt = fmt.replaceAll("eee", rec.yday + 1);
|
||||||
fmt = fmt.replaceAll("dd", rec.day.toString().padStart(2, "0"));
|
fmt = fmt.replaceAll("dd", rec.day.toString().padStart(2, "0"));
|
||||||
fmt = fmt.replaceAll("d", rec.day);
|
fmt = fmt.replaceAll("d", rec.day);
|
||||||
fmt = fmt.replaceAll("hh", rec.hour.toString().padStart(2, "0"));
|
fmt = fmt.replaceAll("hh", rec.hour.toString().padStart(2, "0"));
|
||||||
fmt = fmt.replaceAll("h", rec.hour);
|
fmt = fmt.replaceAll("h", rec.hour);
|
||||||
fmt = fmt.replaceAll("nn", rec.minute.toString().padStart(2, "0"));
|
fmt = fmt.replaceAll("nn", rec.minute.toString().padStart(2, "0"));
|
||||||
fmt = fmt.replaceAll("n", rec.minute);
|
fmt = fmt.replaceAll("n", rec.minute);
|
||||||
fmt = fmt.replaceAll("ss", rec.second.toString().padStart(2, "0"));
|
fmt = fmt.replaceAll("ss", rec.second.toString().padStart(2, "0"));
|
||||||
fmt = fmt.replaceAll("s", rec.second);
|
fmt = fmt.replaceAll("s", rec.second);
|
||||||
fmt = fmt.replaceAll("z", zone >= 0 ? "+" + zone : zone);
|
fmt = fmt.replaceAll("z", zone >= 0 ? "+" + zone : zone);
|
||||||
fmt = fmt.replaceAll(/mm[^bB]/g, rec.month + 1);
|
fmt = fmt.replaceAll(/mm[^bB]/g, rec.month + 1);
|
||||||
fmt = fmt.replaceAll(/m[^bB]/g, rec.month + 1);
|
fmt = fmt.replaceAll(/m[^bB]/g, rec.month + 1);
|
||||||
fmt = fmt.replaceAll(/v[^bB]/g, rec.weekday);
|
fmt = fmt.replaceAll(/v[^bB]/g, rec.weekday);
|
||||||
fmt = fmt.replaceAll("mb", this.monthstr[rec.month].slice(0, 3));
|
fmt = fmt.replaceAll("mb", this.monthstr[rec.month].slice(0, 3));
|
||||||
fmt = fmt.replaceAll("mB", this.monthstr[rec.month]);
|
fmt = fmt.replaceAll("mB", this.monthstr[rec.month]);
|
||||||
fmt = fmt.replaceAll("vB", this.weekdays[rec.weekday]);
|
fmt = fmt.replaceAll("vB", this.weekdays[rec.weekday]);
|
||||||
fmt = fmt.replaceAll("vb", this.weekdays[rec.weekday].slice(0, 3));
|
fmt = fmt.replaceAll("vb", this.weekdays[rec.weekday].slice(0, 3));
|
||||||
|
|
||||||
return fmt;
|
return fmt;
|
||||||
};
|
};
|
||||||
|
|
||||||
return time
|
time[prosperon.DOC] = {
|
||||||
|
doc: `The main time object, handling date/time utilities in earth-seconds.`,
|
||||||
|
second: `Number of seconds in a (real) second (always 1).`,
|
||||||
|
minute: `Number of seconds in a minute (60).`,
|
||||||
|
hour: `Number of seconds in an hour (3600).`,
|
||||||
|
day: `Number of seconds in a day (86400).`,
|
||||||
|
week: `Number of seconds in a week (604800).`,
|
||||||
|
weekdays: `Names of the days of the week, Sunday through Saturday.`,
|
||||||
|
monthstr: `Full names of the months of the year, January through December.`,
|
||||||
|
epoch: `Base epoch year, from which day 0 is calculated (default 1970).`,
|
||||||
|
hour2minute: `Return the ratio of hour to minute in seconds, e.g. 3600 / 60 => 60.`,
|
||||||
|
day2hour: `Return the ratio of day to hour in seconds, e.g. 86400 / 3600 => 24.`,
|
||||||
|
minute2second: `Return the ratio of minute to second in seconds, e.g. 60 / 1 => 60.`,
|
||||||
|
week2day: `Return the ratio of week to day in seconds, e.g. 604800 / 86400 => 7.`,
|
||||||
|
strparse: `Mapping of format tokens (yyyy, mm, dd, etc.) to time fields (year, month, day...).`,
|
||||||
|
isleap: `Return true if a given year is leap, based on whether it has 366 days.`,
|
||||||
|
yearsize: `Given a year, return 365 or 366 depending on leap-year rules.`,
|
||||||
|
timecode: `Convert seconds into a "S:frames" timecode string, with optional FPS (default 24).`,
|
||||||
|
monthdays: `An array of days in each month for a non-leap year.`,
|
||||||
|
zones: `Table of recognized time zone abbreviations, with offsets (e.g., "-12" -> "IDLW").`,
|
||||||
|
record: `Convert a timestamp (in seconds) into a record with fields like day, month, year, etc.`,
|
||||||
|
number: `Convert a record back into a numeric timestamp (seconds).`,
|
||||||
|
fmt: `Default format string for time.text(), containing tokens like 'yyyy', 'dd', 'hh', etc.`,
|
||||||
|
text: `Format a numeric or record time into a string using a format pattern, e.g. 'hh:nn:ss'.`,
|
||||||
|
now: `Return the current system time in seconds (implemented in C extension).`,
|
||||||
|
computer_dst: `Return true if local system time is currently in DST (implemented in C extension).`,
|
||||||
|
computer_zone: `Return local time zone offset from UTC in hours (implemented in C extension).`
|
||||||
|
};
|
||||||
|
|
||||||
|
return time;
|
||||||
|
|||||||
@@ -1,118 +1,127 @@
|
|||||||
var util = use('util')
|
var util = use('util')
|
||||||
|
|
||||||
/* Take numbers from 0 to 1 and remap them to easing functions */
|
|
||||||
var Ease = {
|
var Ease = {
|
||||||
linear(t) {
|
linear(t) {
|
||||||
return t;
|
return t
|
||||||
},
|
},
|
||||||
|
|
||||||
in(t) {
|
in(t) {
|
||||||
return t * t;
|
return t * t
|
||||||
},
|
},
|
||||||
|
|
||||||
out(t) {
|
out(t) {
|
||||||
var d = 1 - t;
|
var d = 1 - t
|
||||||
return 1 - d * d;
|
return 1 - d * d
|
||||||
},
|
},
|
||||||
|
|
||||||
inout(t) {
|
inout(t) {
|
||||||
var d = -2 * t + 2;
|
var d = -2 * t + 2
|
||||||
return t < 0.5 ? 2 * t * t : 1 - (d * d) / 2;
|
return t < 0.5 ? 2 * t * t : 1 - (d * d) / 2
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
function make_easing_fns(num) {
|
|
||||||
var obj = {};
|
|
||||||
|
|
||||||
obj.in = function (t) {
|
|
||||||
return Math.pow(t, num);
|
|
||||||
};
|
|
||||||
|
|
||||||
obj.out = function (t) {
|
|
||||||
return 1 - Math.pow(1 - t, num);
|
|
||||||
};
|
|
||||||
|
|
||||||
var mult = Math.pow(2, num - 1);
|
|
||||||
|
|
||||||
obj.inout = function (t) {
|
|
||||||
return t < 0.5 ? mult * Math.pow(t, num) : 1 - Math.pow(-2 * t + 2, num) / 2;
|
|
||||||
};
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ease.quad = make_easing_fns(2);
|
function make_easing_fns(num) {
|
||||||
Ease.cubic = make_easing_fns(3);
|
var obj = {}
|
||||||
Ease.quart = make_easing_fns(4);
|
|
||||||
Ease.quint = make_easing_fns(5);
|
obj.in = function (t) {
|
||||||
|
return Math.pow(t, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.out = function (t) {
|
||||||
|
return 1 - Math.pow(1 - t, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mult = Math.pow(2, num - 1)
|
||||||
|
obj.inout = function (t) {
|
||||||
|
return t < 0.5 ? mult * Math.pow(t, num) : 1 - Math.pow(-2 * t + 2, num) / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
Ease.quad = make_easing_fns(2)
|
||||||
|
Ease.cubic = make_easing_fns(3)
|
||||||
|
Ease.quart = make_easing_fns(4)
|
||||||
|
Ease.quint = make_easing_fns(5)
|
||||||
|
|
||||||
Ease.expo = {
|
Ease.expo = {
|
||||||
in(t) {
|
in(t) {
|
||||||
return t === 0 ? 0 : Math.pow(2, 10 * t - 10);
|
return t === 0 ? 0 : Math.pow(2, 10 * t - 10)
|
||||||
},
|
},
|
||||||
|
|
||||||
out(t) {
|
out(t) {
|
||||||
return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
|
return t === 1 ? 1 : 1 - Math.pow(2, -10 * t)
|
||||||
},
|
},
|
||||||
|
|
||||||
inout(t) {
|
inout(t) {
|
||||||
return t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;
|
return t === 0
|
||||||
|
? 0
|
||||||
|
: t === 1
|
||||||
|
? 1
|
||||||
|
: t < 0.5
|
||||||
|
? Math.pow(2, 20 * t - 10) / 2
|
||||||
|
: (2 - Math.pow(2, -20 * t + 10)) / 2
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
Ease.bounce = {
|
Ease.bounce = {
|
||||||
in(t) {
|
in(t) {
|
||||||
return 1 - this.out(t - 1);
|
return 1 - this.out(t - 1)
|
||||||
},
|
},
|
||||||
|
|
||||||
out(t) {
|
out(t) {
|
||||||
var n1 = 7.5625;
|
var n1 = 7.5625
|
||||||
var d1 = 2.75;
|
var d1 = 2.75
|
||||||
|
|
||||||
if (t < 1 / d1) {
|
if (t < 1 / d1) {
|
||||||
return n1 * t * t;
|
return n1 * t * t
|
||||||
} else if (t < 2 / d1) {
|
} else if (t < 2 / d1) {
|
||||||
return n1 * (t -= 1.5 / d1) * t + 0.75;
|
return n1 * (t -= 1.5 / d1) * t + 0.75
|
||||||
} else if (t < 2.5 / d1) {
|
} else if (t < 2.5 / d1) {
|
||||||
return n1 * (t -= 2.25 / d1) * t + 0.9375;
|
return n1 * (t -= 2.25 / d1) * t + 0.9375
|
||||||
} else return n1 * (t -= 2.625 / d1) * t + 0.984375;
|
} else return n1 * (t -= 2.625 / d1) * t + 0.984375
|
||||||
},
|
},
|
||||||
|
|
||||||
inout(t) {
|
inout(t) {
|
||||||
return t < 0.5 ? (1 - this.out(1 - 2 * t)) / 2 : (1 + this.out(2 * t - 1)) / 2;
|
return t < 0.5 ? (1 - this.out(1 - 2 * t)) / 2 : (1 + this.out(2 * t - 1)) / 2
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
Ease.sine = {
|
Ease.sine = {
|
||||||
in(t) {
|
in(t) {
|
||||||
return 1 - Math.cos((t * Math.PI) / 2);
|
return 1 - Math.cos((t * Math.PI) / 2)
|
||||||
},
|
},
|
||||||
|
|
||||||
out(t) {
|
out(t) {
|
||||||
return Math.sin((t * Math.PI) / 2);
|
return Math.sin((t * Math.PI) / 2)
|
||||||
},
|
},
|
||||||
|
|
||||||
inout(t) {
|
inout(t) {
|
||||||
return -(Math.cos(Math.PI * t) - 1) / 2;
|
return -(Math.cos(Math.PI * t) - 1) / 2
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
Ease.elastic = {
|
Ease.elastic = {
|
||||||
in(t) {
|
in(t) {
|
||||||
return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * this.c4);
|
return t === 0
|
||||||
|
? 0
|
||||||
|
: t === 1
|
||||||
|
? 1
|
||||||
|
: -Math.pow(2, 10 * t - 10) *
|
||||||
|
Math.sin((t * 10 - 10.75) * this.c4)
|
||||||
},
|
},
|
||||||
|
|
||||||
out(t) {
|
out(t) {
|
||||||
return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * this.c4) + 1;
|
return t === 0
|
||||||
|
? 0
|
||||||
|
: t === 1
|
||||||
|
? 1
|
||||||
|
: Math.pow(2, -10 * t) *
|
||||||
|
Math.sin((t * 10 - 0.75) * this.c4) +
|
||||||
|
1
|
||||||
},
|
},
|
||||||
|
|
||||||
inout(t) {
|
inout(t) {
|
||||||
t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 : (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + 1;
|
t === 0
|
||||||
|
? 0
|
||||||
|
: t === 1
|
||||||
|
? 1
|
||||||
|
: t < 0.5
|
||||||
|
? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2
|
||||||
|
: (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + 1
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
Ease.elastic.c4 = (2 * Math.PI) / 3;
|
Ease.elastic.c4 = (2 * Math.PI) / 3
|
||||||
Ease.elastic.c5 = (2 * Math.PI) / 4.5;
|
Ease.elastic.c5 = (2 * Math.PI) / 4.5
|
||||||
|
|
||||||
var tween = function (from, to, time, fn, cb) {
|
var tween = function (from, to, time, fn, cb) {
|
||||||
var start = os.now()
|
var start = os.now()
|
||||||
@@ -126,103 +135,147 @@ var tween = function (from, to, time, fn, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var update = function tween_update(dt) {
|
var update = function tween_update(dt) {
|
||||||
var elapsed = os.now() - start;
|
var elapsed = os.now() - start
|
||||||
fn(util.obj_lerp(from,to,elapsed/time));
|
fn(util.obj_lerp(from, to, elapsed / time))
|
||||||
if (elapsed >= time) {
|
if (elapsed >= time) {
|
||||||
fn(to)
|
fn(to)
|
||||||
cb?.()
|
cb?.()
|
||||||
cleanup()
|
cleanup()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
var stop = Register.update.register(update);
|
var stop = Register.update.register(update)
|
||||||
return cleanup
|
return cleanup
|
||||||
};
|
}
|
||||||
|
|
||||||
var Tween = {
|
var Tween = {
|
||||||
default: {
|
default: {
|
||||||
loop: "hold",
|
loop: "hold",
|
||||||
/*
|
time: 1,
|
||||||
loop types
|
|
||||||
none: when done, return to first value
|
|
||||||
hold: hold last value of tween
|
|
||||||
restart: restart at beginning, looping
|
|
||||||
yoyo: go up and then back down
|
|
||||||
circle: go up and back down, looped
|
|
||||||
*/
|
|
||||||
time: 1 /* seconds to do */,
|
|
||||||
ease: Ease.linear,
|
ease: Ease.linear,
|
||||||
whole: true /* True if time is for the entire tween, false if each stage */,
|
whole: true,
|
||||||
cb: function () {},
|
cb: function () {},
|
||||||
},
|
},
|
||||||
|
|
||||||
start(obj, target, tvals, options) {
|
start(obj, target, tvals, options) {
|
||||||
var defn = Object.create(this.default);
|
var defn = Object.create(this.default)
|
||||||
Object.assign(defn, options);
|
Object.assign(defn, options)
|
||||||
|
|
||||||
if (defn.loop === "circle") tvals.push(tvals[0]);
|
if (defn.loop === "circle") tvals.push(tvals[0])
|
||||||
else if (defn.loop === "yoyo") {
|
else if (defn.loop === "yoyo") {
|
||||||
for (var i = tvals.length - 2; i >= 0; i--) tvals.push(tvals[i]);
|
for (var i = tvals.length - 2; i >= 0; i--) tvals.push(tvals[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
defn.accum = 0;
|
defn.accum = 0
|
||||||
|
var slices = tvals.length - 1
|
||||||
var slices = tvals.length - 1;
|
var slicelen = 1 / slices
|
||||||
var slicelen = 1 / slices;
|
|
||||||
|
|
||||||
defn.fn = function (dt) {
|
defn.fn = function (dt) {
|
||||||
defn.accum += dt;
|
defn.accum += dt
|
||||||
if (defn.accum >= defn.time && defn.loop === "hold") {
|
if (defn.accum >= defn.time && defn.loop === "hold") {
|
||||||
if (typeof target === "string") obj[target] = tvals[tvals.length - 1];
|
if (typeof target === "string") obj[target] = tvals[tvals.length - 1]
|
||||||
else target(tvals[tvals.length - 1]);
|
else target(tvals[tvals.length - 1])
|
||||||
|
defn.pause()
|
||||||
defn.pause();
|
defn.cb.call(obj)
|
||||||
defn.cb.call(obj);
|
return
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
defn.pct = (defn.accum % defn.time) / defn.time
|
||||||
|
if (defn.loop === "none" && defn.accum >= defn.time) defn.stop()
|
||||||
|
|
||||||
defn.pct = (defn.accum % defn.time) / defn.time;
|
var t = defn.whole ? defn.ease(defn.pct) : defn.pct
|
||||||
if (defn.loop === "none" && defn.accum >= defn.time) defn.stop();
|
var nval = t / slicelen
|
||||||
|
var i = Math.trunc(nval)
|
||||||
|
nval -= i
|
||||||
|
if (!defn.whole) nval = defn.ease(nval)
|
||||||
|
|
||||||
var t = defn.whole ? defn.ease(defn.pct) : defn.pct;
|
if (typeof target === "string") obj[target] = tvals[i].lerp(tvals[i + 1], nval)
|
||||||
|
else target(tvals[i].lerp(tvals[i + 1], nval))
|
||||||
|
}
|
||||||
|
|
||||||
var nval = t / slicelen;
|
var playing = false
|
||||||
var i = Math.trunc(nval);
|
|
||||||
nval -= i;
|
|
||||||
|
|
||||||
if (!defn.whole) nval = defn.ease(nval);
|
|
||||||
|
|
||||||
if (typeof target === "string") obj[target] = tvals[i].lerp(tvals[i + 1], nval);
|
|
||||||
else target(tvals[i].lerp(tvals[i + 1], nval));
|
|
||||||
};
|
|
||||||
|
|
||||||
var playing = false;
|
|
||||||
|
|
||||||
defn.play = function () {
|
defn.play = function () {
|
||||||
if (playing) return;
|
if (playing) return
|
||||||
defn._end = Register.update.register(defn.fn.bind(defn));
|
defn._end = Register.update.register(defn.fn.bind(defn))
|
||||||
playing = true;
|
playing = true
|
||||||
};
|
}
|
||||||
defn.restart = function () {
|
defn.restart = function () {
|
||||||
defn.accum = 0;
|
defn.accum = 0
|
||||||
if (typeof target === "string") obj[target] = tvals[0];
|
if (typeof target === "string") obj[target] = tvals[0]
|
||||||
else target(tvals[0]);
|
else target(tvals[0])
|
||||||
};
|
}
|
||||||
defn.stop = function () {
|
defn.stop = function () {
|
||||||
if (!playing) return;
|
if (!playing) return
|
||||||
defn.pause();
|
defn.pause()
|
||||||
defn.restart();
|
defn.restart()
|
||||||
};
|
}
|
||||||
defn.pause = function () {
|
defn.pause = function () {
|
||||||
defn._end();
|
defn._end()
|
||||||
if (!playing) return;
|
if (!playing) return
|
||||||
|
playing = false
|
||||||
|
}
|
||||||
|
|
||||||
playing = false;
|
return defn
|
||||||
};
|
|
||||||
|
|
||||||
return defn;
|
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
Tween.make = Tween.start;
|
Tween.make = Tween.start
|
||||||
|
|
||||||
return { Tween, Ease, tween };
|
Ease[prosperon.DOC] = `
|
||||||
|
This object provides multiple easing functions that remap a 0..1 input to produce
|
||||||
|
a smoothed or non-linear output. They can be used standalone or inside tweens.
|
||||||
|
|
||||||
|
Available functions:
|
||||||
|
- linear(t)
|
||||||
|
- in(t), out(t), inout(t)
|
||||||
|
- quad.in, quad.out, quad.inout
|
||||||
|
- cubic.in, cubic.out, cubic.inout
|
||||||
|
- quart.in, quart.out, quart.inout
|
||||||
|
- quint.in, quint.out, quint.inout
|
||||||
|
- expo.in, expo.out, expo.inout
|
||||||
|
- bounce.in, bounce.out, bounce.inout
|
||||||
|
- sine.in, sine.out, sine.inout
|
||||||
|
- elastic.in, elastic.out, elastic.inout
|
||||||
|
|
||||||
|
All easing functions expect t in [0..1] and return a remapped value in [0..1].
|
||||||
|
`
|
||||||
|
|
||||||
|
tween[prosperon.DOC] = `
|
||||||
|
:param from: The starting object or value to interpolate from.
|
||||||
|
:param to: The ending object or value to interpolate to.
|
||||||
|
:param time: The total duration of the tween in milliseconds or some time unit.
|
||||||
|
:param fn: A callback function that receives the interpolated value at each update.
|
||||||
|
:param cb: (Optional) A callback invoked once the tween completes.
|
||||||
|
:return: A function that, when called, cleans up and stops the tween.
|
||||||
|
|
||||||
|
Creates a simple tween that linearly interpolates from "from" to "to" over "time"
|
||||||
|
and calls "fn" with each interpolated value. Once finished, "fn" is called with "to",
|
||||||
|
then "cb" is invoked if provided, and the tween is cleaned up.
|
||||||
|
`
|
||||||
|
|
||||||
|
Tween[prosperon.DOC] = `
|
||||||
|
An object providing methods to create and control tweens with additional features
|
||||||
|
like looping, custom easing, multiple stages, etc.
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
- default: A template object with loop/time/ease/whole/cb properties.
|
||||||
|
Methods:
|
||||||
|
- start(obj, target, tvals, options): Create a tween over multiple target values.
|
||||||
|
- make: Alias of start.
|
||||||
|
`
|
||||||
|
|
||||||
|
Tween.start[prosperon.DOC] = `
|
||||||
|
:param obj: The object whose property is being tweened, or context for the callback.
|
||||||
|
:param target: A string property name in obj or a callback function receiving interpolated values.
|
||||||
|
:param tvals: An array of values to tween through (each must support .lerp()).
|
||||||
|
:param options: An optional object overriding defaults (loop type, time, ease, etc.).
|
||||||
|
:return: A tween definition object with .play(), .pause(), .stop(), .restart(), etc.
|
||||||
|
|
||||||
|
Set up a multi-stage tween. You can specify looping modes (none, hold, restart, yoyo, circle),
|
||||||
|
time is the total duration, and "ease" can be any function from Ease. Once started, it updates
|
||||||
|
every frame until completion or stop/pause is called.
|
||||||
|
`
|
||||||
|
|
||||||
|
Tween.make[prosperon.DOC] = `
|
||||||
|
Alias of Tween.start. See Tween.start for usage details.
|
||||||
|
`
|
||||||
|
|
||||||
|
return { Tween, Ease, tween }
|
||||||
|
|||||||
@@ -1,118 +1,191 @@
|
|||||||
var util = this
|
var util = this
|
||||||
|
util[prosperon.DOC] = `
|
||||||
|
A collection of general-purpose utility functions for object manipulation, merging,
|
||||||
|
deep copying, safe property access, etc.
|
||||||
|
`
|
||||||
|
|
||||||
util.deepfreeze = function (obj) {
|
util.deepfreeze = function (obj) {
|
||||||
for (var key in obj) {
|
for (var key in obj) {
|
||||||
if (typeof obj[key] === "object") Object.deepfreeze(obj[key]);
|
if (typeof obj[key] === "object") Object.deepfreeze(obj[key])
|
||||||
}
|
}
|
||||||
Object.freeze(obj);
|
Object.freeze(obj)
|
||||||
};
|
}
|
||||||
|
util.deepfreeze[prosperon.DOC] = `
|
||||||
|
:param obj: The object to recursively freeze.
|
||||||
|
:return: None
|
||||||
|
Recursively freeze an object and all of its nested objects so they cannot be modified.
|
||||||
|
`
|
||||||
|
|
||||||
util.dainty_assign = function (target, source) {
|
util.dainty_assign = function (target, source) {
|
||||||
Object.keys(source).forEach(function (k) {
|
Object.keys(source).forEach(function (k) {
|
||||||
if (typeof source[k] === "function") return;
|
if (typeof source[k] === "function") return
|
||||||
if (!(k in target)) return;
|
if (!(k in target)) return
|
||||||
if (Array.isArray(source[k])) target[k] = deep_copy(source[k]);
|
if (Array.isArray(source[k])) target[k] = deep_copy(source[k])
|
||||||
else if (Object.isObject(source[k])) Object.dainty_assign(target[k], source[k]);
|
else if (Object.isObject(source[k])) Object.dainty_assign(target[k], source[k])
|
||||||
else target[k] = source[k];
|
else target[k] = source[k]
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
util.dainty_assign[prosperon.DOC] = `
|
||||||
|
:param target: The target object whose keys may be updated.
|
||||||
|
:param source: The source object containing new values.
|
||||||
|
:return: None
|
||||||
|
Copy non-function properties from source into matching keys of target without overwriting
|
||||||
|
keys that don't exist in target. Arrays are deep-copied, and objects are recursively assigned.
|
||||||
|
`
|
||||||
|
|
||||||
util.get = function (obj, path, defValue) {
|
util.get = function (obj, path, defValue) {
|
||||||
if (!path) return undefined;
|
if (!path) return undefined
|
||||||
// Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
|
var pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)
|
||||||
var pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g);
|
var result = pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj)
|
||||||
var result = pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj);
|
return result === undefined ? defValue : result
|
||||||
return result === undefined ? defValue : result;
|
|
||||||
}
|
}
|
||||||
|
util.get[prosperon.DOC] = `
|
||||||
|
:param obj: The object to traverse.
|
||||||
|
:param path: A string like "a.b.c" or an array of path segments.
|
||||||
|
:param defValue: The default value if the property is undefined.
|
||||||
|
:return: The nested property or defValue.
|
||||||
|
Safely retrieve a nested property from obj at path (array or dot-string).
|
||||||
|
Returns defValue if the property is undefined.
|
||||||
|
`
|
||||||
|
|
||||||
util.isEmpty = function(o) {
|
util.isEmpty = function(o) {
|
||||||
return Object.keys(obj).length === 0;
|
return Object.keys(o).length === 0
|
||||||
}
|
}
|
||||||
|
util.isEmpty[prosperon.DOC] = `
|
||||||
|
:param o: The object to check.
|
||||||
|
:return: Boolean indicating if the object is empty.
|
||||||
|
Return true if the object has no own properties, otherwise false.
|
||||||
|
`
|
||||||
|
|
||||||
util.dig = function (obj, path, def = {}) {
|
util.dig = function (obj, path, def = {}) {
|
||||||
var pp = path.split(".");
|
var pp = path.split(".")
|
||||||
for (var i = 0; i < pp.length - 1; i++) {
|
for (var i = 0; i < pp.length - 1; i++) {
|
||||||
obj = obj[pp[i]] = obj[pp[i]] || {};
|
obj = obj[pp[i]] = obj[pp[i]] || {}
|
||||||
}
|
}
|
||||||
obj[pp[pp.length - 1]] = def;
|
obj[pp[pp.length - 1]] = def
|
||||||
return def;
|
return def
|
||||||
};
|
}
|
||||||
|
util.dig[prosperon.DOC] = `
|
||||||
|
:param obj: The root object to modify.
|
||||||
|
:param path: A dot-string specifying nested objects to create.
|
||||||
|
:param def: The value to store in the final path component, default {}.
|
||||||
|
:return: The assigned final value.
|
||||||
|
Ensure a nested path of objects exists inside obj; create objects if missing, and set
|
||||||
|
the final path component to def.
|
||||||
|
`
|
||||||
|
|
||||||
util.access = function (obj, name) {
|
util.access = function (obj, name) {
|
||||||
var dig = name.split(".");
|
var dig = name.split(".")
|
||||||
|
|
||||||
for (var i of dig) {
|
for (var i of dig) {
|
||||||
obj = obj[i];
|
obj = obj[i]
|
||||||
if (!obj) return undefined;
|
if (!obj) return undefined
|
||||||
}
|
}
|
||||||
|
return obj
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
function deep_copy(from) {
|
|
||||||
return json.decode(json.encode(from));
|
|
||||||
}
|
}
|
||||||
|
util.access[prosperon.DOC] = `
|
||||||
|
:param obj: The object to traverse.
|
||||||
|
:param name: A dot-string path (e.g. "foo.bar.baz").
|
||||||
|
:return: The value at that path, or undefined if missing.
|
||||||
|
Traverse obj by dot-separated path name, returning the final value or undefined
|
||||||
|
if any step is missing.
|
||||||
|
`
|
||||||
|
|
||||||
util.mergekey = function (o1, o2, k) {
|
util.mergekey = function (o1, o2, k) {
|
||||||
if (!o2) return;
|
if (!o2) return
|
||||||
if (typeof o2[k] === "object") {
|
if (typeof o2[k] === "object") {
|
||||||
if (Array.isArray(o2[k])) o1[k] = deep_copy(o2[k]);
|
if (Array.isArray(o2[k])) o1[k] = deep_copy(o2[k])
|
||||||
else {
|
else {
|
||||||
if (!o1[k]) o1[k] = {};
|
if (!o1[k]) o1[k] = {}
|
||||||
if (typeof o1[k] === "object") util.merge(o1[k], o2[k]);
|
if (typeof o1[k] === "object") util.merge(o1[k], o2[k])
|
||||||
else o1[k] = o2[k];
|
else o1[k] = o2[k]
|
||||||
}
|
}
|
||||||
} else o1[k] = o2[k];
|
} else o1[k] = o2[k]
|
||||||
};
|
}
|
||||||
|
util.mergekey[prosperon.DOC] = `
|
||||||
|
:param o1: The target object.
|
||||||
|
:param o2: The source object.
|
||||||
|
:param k: The key to merge.
|
||||||
|
:return: None
|
||||||
|
Helper for merge, updating key k from o2 into o1. Arrays are deep-copied and objects are
|
||||||
|
recursively merged.
|
||||||
|
`
|
||||||
|
|
||||||
/* Same as merge from Ruby */
|
|
||||||
/* Adds objs key by key to target */
|
|
||||||
util.merge = function (target, ...objs) {
|
util.merge = function (target, ...objs) {
|
||||||
for (var obj of objs) for (var key of Object.keys(obj)) util.mergekey(target, obj, key);
|
for (var obj of objs) for (var key of Object.keys(obj)) util.mergekey(target, obj, key)
|
||||||
|
return target
|
||||||
return target;
|
}
|
||||||
};
|
util.merge[prosperon.DOC] = `
|
||||||
|
:param target: The target object.
|
||||||
|
:param objs: One or more objects to merge into target.
|
||||||
|
:return: The updated target object.
|
||||||
|
Merge all passed objects into target, copying or merging each key as needed.
|
||||||
|
Arrays are deep-copied, objects are recursively merged, etc.
|
||||||
|
`
|
||||||
|
|
||||||
util.copy = function (proto, ...objs) {
|
util.copy = function (proto, ...objs) {
|
||||||
var c = Object.create(proto);
|
var c = Object.create(proto)
|
||||||
for (var obj of objs) Object.mixin(c, obj);
|
for (var obj of objs) Object.mixin(c, obj)
|
||||||
return c;
|
return c
|
||||||
};
|
|
||||||
|
|
||||||
util.obj_lerp = function(a,b,t)
|
|
||||||
{
|
|
||||||
if (a.lerp)
|
|
||||||
return a.lerp(b,t);
|
|
||||||
|
|
||||||
var obj = {};
|
|
||||||
|
|
||||||
Object.keys(a).forEach(function (key) {
|
|
||||||
obj[key] = a[key].lerp(b[key], t);
|
|
||||||
});
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
util.copy[prosperon.DOC] = `
|
||||||
|
:param proto: The prototype object for the new object.
|
||||||
|
:param objs: One or more objects whose properties will be mixed in.
|
||||||
|
:return: The newly created object.
|
||||||
|
Create a new object with proto as its prototype, then mix in additional objects’ properties.
|
||||||
|
`
|
||||||
|
|
||||||
|
util.obj_lerp = function(a,b,t) {
|
||||||
|
if (a.lerp) return a.lerp(b, t)
|
||||||
|
var obj = {}
|
||||||
|
Object.keys(a).forEach(function (key) {
|
||||||
|
obj[key] = a[key].lerp(b[key], t)
|
||||||
|
})
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
util.obj_lerp[prosperon.DOC] = `
|
||||||
|
:param a: The start object (its properties must have .lerp()).
|
||||||
|
:param b: The end object (matching properties).
|
||||||
|
:param t: Interpolation factor (0..1).
|
||||||
|
:return: A new object with interpolated properties.
|
||||||
|
Linearly interpolate between two objects a and b by factor t, assuming each property
|
||||||
|
supports .lerp().
|
||||||
|
`
|
||||||
|
|
||||||
util.normalizeSpacing = function normalizeSpacing(spacing) {
|
util.normalizeSpacing = function normalizeSpacing(spacing) {
|
||||||
if (typeof spacing === 'number') {
|
if (typeof spacing === 'number') {
|
||||||
return {l: spacing, r: spacing, t: spacing, b: spacing};
|
return {l: spacing, r: spacing, t: spacing, b: spacing}
|
||||||
} else if (Array.isArray(spacing)) {
|
} else if (Array.isArray(spacing)) {
|
||||||
if (spacing.length === 2) {
|
if (spacing.length === 2) {
|
||||||
return {l: spacing[0], r: spacing[0], t: spacing[1], b: spacing[1]};
|
return {l: spacing[0], r: spacing[0], t: spacing[1], b: spacing[1]}
|
||||||
} else if (spacing.length === 4) {
|
} else if (spacing.length === 4) {
|
||||||
return {l: spacing[0], r: spacing[1], t: spacing[2], b: spacing[3]};
|
return {l: spacing[0], r: spacing[1], t: spacing[2], b: spacing[3]}
|
||||||
}
|
}
|
||||||
} else if (typeof spacing === 'object') {
|
} else if (typeof spacing === 'object') {
|
||||||
return {l: spacing.l || 0, r: spacing.r || 0, t: spacing.t || 0, b: spacing.b || 0};
|
return {l: spacing.l || 0, r: spacing.r || 0, t: spacing.t || 0, b: spacing.b || 0}
|
||||||
} else {
|
} else {
|
||||||
return {l:0, r:0, t:0, b:0};
|
return {l:0, r:0, t:0, b:0}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
util.normalizeSpacing[prosperon.DOC] = `
|
||||||
|
:param spacing: A number, an array of length 2 or 4, or an object with l/r/t/b.
|
||||||
|
:return: An object {l, r, t, b}.
|
||||||
|
Normalize any spacing input into a {l, r, t, b} object.
|
||||||
|
`
|
||||||
|
|
||||||
util.guid[prosperon.DOC] = "Return a random 32-character hexadecimal UUID-like string."
|
util.guid[prosperon.DOC] = `
|
||||||
util.insertion_sort[prosperon.DOC] = "In-place insertion sort of an array using a comparison function cmp(a,b)->Number."
|
:return: A random 32-character string (hex).
|
||||||
|
Return a random 32-character hexadecimal UUID-like string (not guaranteed RFC4122-compliant).
|
||||||
|
`
|
||||||
|
|
||||||
|
util.insertion_sort[prosperon.DOC] = `
|
||||||
|
:param arr: The array to be sorted in-place.
|
||||||
|
:param cmp: Comparison function cmp(a,b)->Number.
|
||||||
|
:return: The same array, sorted in-place.
|
||||||
|
In-place insertion sort of an array using cmp(a,b)->Number for ordering.
|
||||||
|
`
|
||||||
|
|
||||||
|
function deep_copy(from) {
|
||||||
|
return json.decode(json.encode(from))
|
||||||
|
}
|
||||||
|
|
||||||
return util
|
return util
|
||||||
|
|||||||
@@ -7260,7 +7260,7 @@ JSC_CCALL(js_cycle_hook,
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(js_stack_info, return js_dump_stack_info())
|
JSC_CCALL(js_stack_info, return js_dump_stack_info(js))
|
||||||
|
|
||||||
static const JSCFunctionListEntry js_js_funcs[] = {
|
static const JSCFunctionListEntry js_js_funcs[] = {
|
||||||
MIST_FUNC_DEF(js, cycle_hook,1),
|
MIST_FUNC_DEF(js, cycle_hook,1),
|
||||||
|
|||||||
Reference in New Issue
Block a user