diff --git a/docs/.pages b/docs/.pages new file mode 100644 index 00000000..e6266303 --- /dev/null +++ b/docs/.pages @@ -0,0 +1,11 @@ +nav: + - index.md + - dull.md + - actors.md + - rendering.md + - resources.md + - input.md + - exporting.md + - ... + - api + \ No newline at end of file diff --git a/docs/actors.md b/docs/actors.md new file mode 100644 index 00000000..86538228 --- /dev/null +++ b/docs/actors.md @@ -0,0 +1,235 @@ +#Actor & Module System + +• main.js is the first program started by the engine. Once main.js ends (is killed), the engine exits + (equivalent to clicking the window’s “X”). +• Files that do not return anything (i.e. do not include a “return …;” statement) are considered programs. +• Files that do return a single object are modules, imported via the use('filename') function. +• Actors are running program objects. They can spawn new actors as underlings, with the spawner acting as + their overling. + +Modules +------- +You can import a module by calling: + use('some_module') +This function searches through the engine’s path list (prosperon.PATH) for files such as some_module.js or +some_module.jsc (among other supported extensions). If found, the module portion is executed once and its +return value is cached; subsequent calls to use(...) with the same name return the cached object. + +Key rules: + 1. A module must end with a “return something;” statement. + 2. The value returned by a module is typically an object containing functions or configuration. + 3. A module is loaded at most once per engine run; later use(...) calls return the same module object. + +Example (config.js): +--------------------- + // config.js + --- + return { + width: 800, + height: 600 + } + +In your program you might write: + var config = use('config.js') + console.log(config.width) // Outputs: 800 + +Programs +-------- +Prosperon distinguishes programs from modules by whether they return a value: + +• If a file does not include a “return …;” statement, it is considered a program. +• A program can be spawned as an actor. +• main.js is the special “root” program; when it terminates (or is killed), the engine quits. + +Mixed Files (Modules + Programs) +---------------------------------- +A single file can contain both module code and program code if the two sections are separated by a line +containing just: + --- +If the first part includes a “return …;” statement, it is treated as the module portion, while the second +part is treated as the program portion. This design allows one file to serve as both a module (exposing an API) +and an actor script. + +Example structure in one file: +-------------------------------- + // Module portion + return { + someUtility() { /* … */ } + } + --- + // Program portion + this.start = function() { + console.log("Hello from the actor part!"); + } + +The engine will parse and load the module portion when use('file') is called; if the file is spawned as a +program, the program portion is executed on the actor. + +Actor System +------------ +Creating Actors: +---------------- +Any running actor can create an underling by calling its built-in spawn method. For example, in main.js +(the root program): + + // In main.js + var child = this.spawn('child.js', { name: "ChildActor" }) + +spawn accepts the following arguments: + 1. script (string): The file name or path to another program file. + 2. config (optional object): Properties to merge into the spawned actor. + 3. callback (optional function): Invoked immediately after creation with (underling, info). + +The spawned actor’s “overling” is the actor that called spawn. The new actor is recorded in the overling’s set +of underlings. + +Overling & Underlings: +---------------------- +• Overling: The actor that spawns another actor. +• Underling: An actor that is spawned by an overling. + +Each actor has: + – this.overling (read-only): The actor that spawned it. + – this.underlings (read-only): A set of its child actors. + +Actor Lifecycle & kill() +------------------------ +An actor can be removed from the world by calling kill(). For example: + + child.kill() + +Killing an actor automatically terminates all of its underlings (recursively). Once killed, an actor is marked +as dead and will no longer process any calls. When the root actor (main.js) calls kill() on itself or is terminated, +the entire engine shuts down. + +Hooks and Functions: +-------------------- +When an actor is spawned, the engine looks for special hook functions. These functions are optional, but if present, +they are called at specific times: + +• awake() – Called immediately after the actor is fully set up and registered with engine updates. +• garbage() – Called just before the actor is removed; use this to free resources or unhook active listeners. +• then() – Also called just before removal; can be used for additional cleanup or business logic. + +Example (child.js): +------------------- + // child.js + this.awake = function() { + console.log("Awake! My overling is " + this.overling); + } + + this.garbage = function() { + console.log("Time to go away."); + } + +Delayed Calls: +-------------- +To schedule a function to be called in the future on the actor, use: + this.delay(fn, seconds) +For example: + + this.delay(function() { + console.log("Called after 2 seconds"); + }, 2) + +The function will be called with “this” bound to the actor. If the actor is killed before the delay expires, +the scheduled function will not be executed. + +Actor Registration & Events: +---------------------------- +Actors can automatically register to receive engine-wide events such as update, gui, etc. If an actor defines +a function with one of these names, it is registered automatically when the actor is created. + +Some common event hooks include: + – update(): Called once per frame. + – gui(): Called when GUI elements are drawn. + – draw(): Called when the scene is rendered. +(Additional events such as appupdate or physupdate may also be supported based on engine configuration.) + +Example Actor (child.js): +------------------------- + // child.js + this.awake = function() { + console.log("Child actor awake."); + } + + this.update = function() { + // Called every frame + console.log("Child actor update."); + } + + this.garbage = function() { + console.log("Child actor is being removed."); + } + +When another actor (including main.js) calls spawn("child.js"), the above code executes on the new actor. + +main.js and the Engine Entry Point +------------------------------------ +• Prosperon begins by loading and running main.js as the root actor. +• When main.js terminates or calls kill(), the entire engine shuts down. + +Example (main.js): +------------------ + // main.js + console.log("Hello from main.js"); + + this.awake = function() { + // Called once when the engine starts up + var child = this.spawn("child.js", { name: "ChildOne" }); + console.log("Spawned a child actor."); + } + + this.update = function() { + // Called every frame + // … + } + + this.stopGame = function() { + // Call this function to exit the game + this.kill(); + } + +Logging and Console +------------------- +Prosperon provides several console logging methods: + + • console.log(msg) – Info-level output (printed to both the log and console). + • console.debug(msg) – Debug-level output. + • console.warn(msg) – Warning-level messages. + • console.error(err) – Error-level messages, including stack traces. + +A fatal error will print a stack trace and trigger an engine shutdown. + +Signals & Engine Shutdown +------------------------- +Internally, Prosperon listens for signals such as SIGINT, SIGABRT, SIGSEGV, etc. When these signals occur, +the engine will exit immediately. This behavior is a safety measure; scripting code typically does not need to handle +these signals directly. + +Summary of Key API +------------------ +this.spawn(script, config, callback) + • Creates a new actor from the specified program script. + • Optionally merges properties from the config object into the new actor. + • Invokes the callback (if provided) with (actor, { message: "created" }). + +this.kill() + • Immediately terminates the actor and all its underlings. + • Calls any garbage/then hooks defined on the actor. + +this.delay(fn, seconds) + • Schedules the function fn to be called after the specified number of seconds, provided the actor remains alive. + +Lifecycle Hooks: + • awake() – Called immediately after an actor is spawned. + • garbage() – Called just before the actor is removed. + • then() – An additional cleanup callback before removal. + +Event Hooks (automatically registered if defined): + • update() – Called once per frame. + • gui(), draw(), appupdate(), etc. + +Modules: + • Use modules by calling use('filename'). A module must return a single object from the module portion (i.e. the code + before the optional '---' if the file also contains a program portion). diff --git a/docs/api/imgui.md b/docs/api/imgui.md index 1a98c7e1..b00474ac 100644 --- a/docs/api/imgui.md +++ b/docs/api/imgui.md @@ -1,1092 +1 @@ # imgui - -## windowpos() - -Return the position of the current ImGui window as an ImVec2. - -**Returns**: A 2-element array [x, y] representing the top-left corner of the current window in screen coordinates. - - - -## plot2pixels(coords) - -Convert a point from plot coordinates to pixel coordinates in the current ImPlot. - -**coords**: A 2-element array [x, y] in plot coordinates. - -**Returns**: A 2-element array [x, y] in pixel coordinates, mapped from the current ImPlot. - - - -## plotpos() - -Return the top-left corner of the current ImPlot region in screen (pixel) coordinates. - -**Returns**: A 2-element array [x, y] representing the position of the current ImPlot in screen coordinates. - - - -## plotlimits() - -Retrieve the current plot’s axis limits (min/max) for both X and Y axes. - -**Returns**: An object { x: { min, max }, y: { min, max } } describing the current plot’s visible axis ranges. - - - -## setaxes(xAxis, yAxis) - -Switch the active axes in ImPlot (useful if multiple axes exist). - -**xAxis**: The x-axis index (0..2). - -**yAxis**: The y-axis index (0..2). - -**Returns**: None - - - -## setupaxis(axis) - -Setup the specified axis in the current ImPlot (e.g., for customizing tick labels). - -**axis**: The numeric index of the axis (0..2). - -**Returns**: None - - - -## inplot(coords) - -Check if the given point is within the current ImPlot's visible region. - -**coords**: A 2-element array [x, y] in plot coordinates. - -**Returns**: True if the point is within the visible plot region, otherwise false. - - - -## window(title, callback) - -Create a new ImGui window with the given title and invoke the callback to render inside it. - -**title**: The text displayed as the window title. - -**callback**: A function called to render the contents of the window. - -**Returns**: A boolean indicating if the window is still active (open) after rendering. - - - -## menu(label, callback) - -Create a new menu entry in a menu bar or menu. The callback is invoked to populate the menu if opened. - -**label**: The label of the menu (visible in the menubar). - -**callback**: A function called to render menu items when the menu is open. - -**Returns**: None - - - -## sameline(offset) - -Place the next widget on the same line, optionally specifying a horizontal offset. - -**offset**: A float offset from the current cursor position. If omitted, defaults to 0. - -**Returns**: None - - - -## int(label, value) - -Display an integer input box with a label. - -**label**: The label text for the input. - -**value**: The initial integer value. - -**Returns**: The updated integer value after user edits. - - - -## pushid(id) - -Push an integer ID onto the ImGui ID stack. - -**id**: An integer used to differentiate widgets/items with the same label. - -**Returns**: None - - - -## popid() - -Pop an ID off the ImGui ID stack. - -**Returns**: None - - - -## slider(label, value, minValue, maxValue) - -Create a float slider (or multi-float sliders if given an array) within the specified range. - -**label**: The slider label text. - -**value**: A single float or an array of floats (e.g., [r,g,b,a]). - -**minValue**: The minimum slider value. - -**maxValue**: The maximum slider value. - -**Returns**: The updated float or array of floats after user adjustment. - - - -## intslider(label, value, minValue, maxValue) - -Create an integer slider (or multiple integer sliders if given a typed array) in the specified range. - -**label**: The slider label text. - -**value**: A single integer or a typed array of integers (for multi-component sliders). - -**minValue**: The minimum integer value. - -**maxValue**: The maximum integer value. - -**Returns**: The updated integer or array of integers after user adjustment. - - - -## menubar(callback) - -Begin rendering a menubar. The callback is invoked to create menu items. Ends automatically. - -**callback**: A function that creates menu items within the menubar. - -**Returns**: None - - - -## mainmenubar(callback) - -Create the main menu bar at the top of the screen. The callback is invoked for populating it. - -**callback**: A function to render items in the main menu bar. - -**Returns**: None - - - -## menuitem(label, shortcut, callback, selected) - -Create a menu item that can optionally be toggled. If selected, calls the provided callback. - -**label**: The text label of the menu item. - -**shortcut**: An optional shortcut text to display (e.g. "Ctrl+S"). - -**callback**: A function called if the user clicks or activates this item. - -**selected**: A boolean indicating whether this menu item is toggled or not. - -**Returns**: A boolean reflecting the toggled state. - - - -## radio(label, active) - -Create a radio button. - -**label**: The text label for the radio button. - -**active**: Whether this radio button is currently selected. - -**Returns**: True if this radio button is now selected by the user, otherwise false. - - - -## image(texture) - -Render a texture as an image at a default size (100x100). - -**texture**: The GPU texture to display. - -**Returns**: None - - - -## imagebutton(label, texture, callback) - -Create an ImageButton widget which displays a texture; calls the callback when clicked. - -**label**: A string identifier (not visually used). - -**texture**: The GPU texture to display on the button. - -**callback**: A function called when the button is clicked. - -**Returns**: None - - - -## textinput(label, text) - -Show a single-line text input widget. - -**label**: The label text next to the input box. - -**text**: The current text. If undefined, the box starts empty. - -**Returns**: The updated text string after user editing. - - - -## textbox(label, text) - -Show a multi-line text input widget. - -**label**: The label text next to the input box. - -**text**: The current multi-line text. If undefined, starts empty. - -**Returns**: The updated text after user editing. - - - -## button(label, callback) - -Create a button. The callback fires if the user clicks it. - -**label**: The text displayed on the button. - -**callback**: The function called on click. - -**Returns**: None - - - -## checkbox(label, checked) - -Create a checkbox to toggle a boolean value. - -**label**: The text label for the checkbox. - -**checked**: The current boolean state. - -**Returns**: The updated boolean state after user toggle. - - - -## text(text) - -Render a line of text in the ImGui window. - -**text**: The string to display. - -**Returns**: None - - - -## plot(title, callback) - -Begin a new ImPlot region with the specified title. Calls the callback to render plot contents. - -**title**: The title (label) of the plot. - -**callback**: A function that sets up and draws within the ImPlot region. - -**Returns**: None - - - -## lineplot(label, data, shaded, lastPoint) - -Plot a line graph in the current ImPlot. - -**label**: The label for the line plot. - -**data**: An array of [x,y] points or a single array of y-values. - -**shaded**: Boolean indicating if the area under the line should be filled. - -**lastPoint**: (Optional) Additional point or frame usage. (Currently partial/placeholder in code.) - -**Returns**: None - - - -## scatterplot(label, data, shaded, lastPoint) - -Plot a scatter graph in the current ImPlot. - -**label**: The label for the scatter plot. - -**data**: An array of [x,y] points or a single array of y-values. - -**shaded**: Typically unused for scatter. - -**lastPoint**: (Optional) Additional param if needed. - -**Returns**: None - - - -## stairplot(label, data, shaded, lastPoint) - -Plot a stair-step graph in the current ImPlot. - -**label**: The label for the stair plot. - -**data**: An array of [x,y] points or a single array of y-values. - -**shaded**: A boolean to fill under the stair-step line. - -**lastPoint**: (Optional) Extended data usage if needed. - -**Returns**: None - - - -## digitalplot(label, data, shaded, lastPoint) - -Plot a digital (step-like) graph in the current ImPlot. - -**label**: The label for the digital plot. - -**data**: An array of [x,y] points or a single array of y-values. - -**shaded**: Typically not used for digital plots. - -**lastPoint**: (Optional) Extended data usage if needed. - -**Returns**: None - - - -## barplot(label, data, width) - -Plot a bar chart in the current ImPlot. - -**label**: The label for the bar series. - -**data**: An array of [x,y] points or just an array of y-values. - -**width**: The width of each bar in plot units. - -**Returns**: None - - - -## pieplot(labels, values, x, y, radius) - -Plot a pie chart in the current ImPlot. - -**labels**: An array of label strings for each slice. - -**values**: An array of numeric values corresponding to each slice. - -**x**: The x position of the pie’s center. - -**y**: The y position of the pie’s center. - -**radius**: The radius of the pie chart. - -**Returns**: None - - - -## textplot(text, coords) - -Render text at the specified coordinates in plot space. - -**text**: The string to render. - -**coords**: A 2-element array [x, y] in plot coordinates. - -**Returns**: None - - - -## histogramplot(label, data) - -Plot a histogram from the given data array/typed array in the current ImPlot. - -**label**: The label for the histogram. - -**data**: A typed array (or numeric array) containing the values to bin/display. - -**Returns**: None - - - -## plotaxes(xLabel, yLabel) - -Set up labels for the X and Y axes of the current ImPlot. - -**xLabel**: The label for the x-axis. - -**yLabel**: The label for the y-axis. - -**Returns**: None - - - -## plotmousepos() - -Get the mouse cursor’s position in the current plot’s coordinate system. - -**Returns**: A 2-element array [x, y] representing the mouse position in plot coordinates. - - - -## plothovered() - -Check if the mouse is hovering over the current ImPlot. - -**Returns**: True if the plot area is hovered, otherwise false. - - - -## axeslimits(xMin, xMax, yMin, yMax) - -Set up the visible axis limits in the current ImPlot. - -**xMin**: The left (min) bound of the x-axis. - -**xMax**: The right (max) bound of the x-axis. - -**yMin**: The bottom (min) bound of the y-axis. - -**yMax**: The top (max) bound of the y-axis. - -**Returns**: None - - - -## prepend(commandBuffer) - -Prepare ImGui draw data for rendering, typically called after ImGui::Render(). - -**commandBuffer**: The SDL GPU command buffer where draw data will be queued. - -**Returns**: None - - - -## fitaxis(axis) - -Fit either the x-axis or y-axis to its data range on the next plot frame. - -**axis**: 0 for X-axis, 1 for Y-axis. - -**Returns**: None - - - -## columns(count) - -Switch the layout to use a specified number of columns. - -**count**: The number of columns to layout in the current region. - -**Returns**: None - - - -## nextcolumn() - -Advance to the next column in a multi-column layout. - -**Returns**: None - - - -## collapsingheader(label) - -Create a collapsible header. Returns true if it is open (expanded). - -**label**: The text label of the header. - -**Returns**: True if the header is expanded, otherwise false. - - - -## tree(label, callback) - -Create a tree node. If opened, calls the callback for nested content. - -**label**: The label for the tree node. - -**callback**: A function called if the node is expanded. - -**Returns**: None - - - -## listbox(label, items, selectedIndex) - -Create a list box widget to select from a list of strings. - -**label**: The label next to the list box. - -**items**: An array of strings to display. - -**selectedIndex**: The currently selected index. - -**Returns**: The updated selected index after user selection. - - - -## axisfmt(axis, callback) - -Set a custom formatter for a specified y-axis in ImPlot. - -**axis**: The y-axis index (0..2) to format. - -**callback**: A function(value) => string that converts axis values to text. - -**Returns**: None - - - -## tabbar(label, callback) - -Begin a tab bar container. The callback is invoked to create tabs. - -**label**: The identifier label of the tab bar. - -**callback**: A function that creates tab items. - -**Returns**: None - - - -## tab(label, callback) - -Create a tab item. If selected, calls the callback for tab content. - -**label**: The name of the tab. - -**callback**: A function to render the tab’s content if active. - -**Returns**: None - - - -## open_popup(label) - -Open a popup by its identifier. - -**label**: The identifier of the popup to open. - -**Returns**: None - - - -## modal(label, callback) - -Begin a modal popup. The callback is invoked to display contents if the modal is open. - -**label**: The identifier of the modal popup. - -**callback**: A function for rendering the modal’s UI if open. - -**Returns**: None - - - -## popup(label, callback) - -Begin a popup. The callback is invoked if the popup is open. - -**label**: The identifier of the popup. - -**callback**: A function for rendering the popup’s UI. - -**Returns**: None - - - -## close_popup() - -Close the current popup. - -**Returns**: None - - - -## context(label, callback) - -Create a popup context menu. The callback is invoked if the menu opens. - -**label**: The identifier for the context menu. - -**callback**: A function that renders menu items in the context. - -**Returns**: None - - - -## table(label, columns, callback, sortCallback) - -Create a table with multiple columns. Optionally enable sorting and pass a sort callback. - -**label**: The identifier for the table. - -**columns**: The number of columns. - -**callback**: A function to populate the table (rows/cells). - -**sortCallback**: An optional function(columnIndex, ascending) called if user sorts a column. - -**Returns**: None - - - -## tablenextcolumn() - -Move to the next column in a table row. - -**Returns**: None - - - -## tablenextrow() - -Move to the next row in a table. - -**Returns**: None - - - -## tableheadersrow() - -Create a row of headers in the current table (should be called once after column setup). - -**Returns**: None - - - -## tableangledheadersrow() - -Create an angled header row (for advanced usage). Typically not used as often. - -**Returns**: None - - - -## tablesetupcolumn(label) - -Setup configuration for a single column in the table. - -**label**: The label/header text for this column. - -**Returns**: None - - - -## dnd(type, payload, callback) - -Begin a drag source for custom data payload. - -**type**: A string identifier for the drag-drop payload type. - -**payload**: A numeric payload stored in the drag-drop. - -**callback**: (Currently unused) Placeholder if you want to do extra on drag start. - -**Returns**: None - - - -## dndtarget(type, callback) - -Create a drop target for matching drag-drop payload type. Invokes callback on drop. - -**type**: A string identifier for the drag-drop payload type to accept. - -**callback**: A function(payloadNumber) called when a matching payload is dropped. - -**Returns**: None - - - -## color(label, color) - -Create a color editor (3 or 4 floats). Returns the updated color. - -**label**: The label for the color editor. - -**color**: An array [r,g,b] or [r,g,b,a]. - -**Returns**: Updated color array after user input. - - - -## startnode(callback, linkCreatedCallback, nodeHoveredCallback, linkHoveredCallback) - -Begin a node editor session with ImNodes. The callback defines nodes. -Additional callbacks handle link creation and hover events. - -**callback**: A function to define node editor contents (adding nodes, etc). - -**linkCreatedCallback**: A function(startAttr, endAttr) called when a new link is created. - -**nodeHoveredCallback**: A function(nodeId) called when a node is hovered. - -**linkHoveredCallback**: A function(linkId) called when a link is hovered. - -**Returns**: None - - - -## node(nodeId, callback) - -Begin a node with a unique ID, then call the callback to define its contents. - -**nodeId**: A unique integer ID for this node. - -**callback**: A function that populates the node’s UI. - -**Returns**: None - - - -## nodein(attributeId, callback) - -Create an input attribute in the current node. - -**attributeId**: The attribute ID for this input. - -**callback**: A function that defines the UI within the input attribute. - -**Returns**: None - - - -## nodeout(attributeId, callback) - -Create an output attribute in the current node. - -**attributeId**: The attribute ID for this output. - -**callback**: A function that defines the UI within the output attribute. - -**Returns**: None - - - -## nodelink(linkId, startAttributeId, endAttributeId) - -Link two node attributes by their IDs. - -**linkId**: A unique integer ID for this link. - -**startAttributeId**: The attribute ID where the link starts. - -**endAttributeId**: The attribute ID where the link ends. - -**Returns**: None - - - -## nodemini(size) - -Show a minimap for the current node editor. - -**size**: A float controlling the minimap size ratio. - -**Returns**: None - - - -## mousehoveringrect(min, max) - -Check if the mouse is hovering within the given rectangle. - -**min**: A 2-element array [x, y] for the top-left corner. - -**max**: A 2-element array [x, y] for the bottom-right corner. - -**Returns**: True if the mouse is within that rectangle, otherwise false. - - - -## mouseclicked(button) - -Check if a specific mouse button was clicked (went from up to down) this frame. - -**button**: An integer for the mouse button index (0 = left, 1 = right, etc). - -**Returns**: True if the button was clicked, otherwise false. - - - -## mousedown(button) - -Check if the specified mouse button is currently held down. - -**button**: The mouse button index. - -**Returns**: True if the button is down, otherwise false. - - - -## mousereleased(button) - -Check if the specified mouse button was released this frame. - -**button**: The mouse button index. - -**Returns**: True if the button was released, otherwise false. - - - -## mousedragging(button) - -Check if the mouse is being dragged with the specified button. - -**button**: The mouse button index. - -**Returns**: True if the mouse is dragging, otherwise false. - - - -## mousedelta() - -Get the mouse movement delta (difference) for the current frame. - -**Returns**: A 2-element array [dx, dy] representing the mouse movement. - - - -## rect(pMin, pMax, color) - -Draw a rectangle outline in the current window’s draw list. - -**pMin**: A 2-element array [x, y] for the top-left corner. - -**pMax**: A 2-element array [x, y] for the bottom-right corner. - -**color**: A 4-element array [r, g, b, a] specifying the outline color. - -**Returns**: None - - - -## rectfilled(pMin, pMax, color) - -Draw a filled rectangle in the current window’s draw list. - -**pMin**: [x, y] for the top-left corner. - -**pMax**: [x, y] for the bottom-right corner. - -**color**: [r, g, b, a] fill color. - -**Returns**: None - - - -## line(p1, p2, color) - -Draw a line between two points in the current window’s draw list. - -**p1**: [x, y] start position. - -**p2**: [x, y] end position. - -**color**: [r, g, b, a] line color. - -**Returns**: None - - - -## bezierquad(p1, p2, p3, color, thickness) - -Draw a quadratic bezier curve. - -**p1**: [x, y] start point. - -**p2**: [x, y] control point. - -**p3**: [x, y] end point. - -**color**: [r, g, b, a] color. - -**thickness**: Line thickness. - -**Returns**: None - - - -## beziercubic(p1, p2, p3, p4, color, thickness) - -Draw a cubic bezier curve. - -**p1**: [x, y] start point. - -**p2**: [x, y] first control point. - -**p3**: [x, y] second control point. - -**p4**: [x, y] end point. - -**color**: [r, g, b, a] color. - -**thickness**: Line thickness. - -**Returns**: None - - - -## point(center, radius, color) - -Draw a filled circle (point) in the current window’s draw list. - -**center**: [x, y] center of the circle. - -**radius**: The radius of the circle. - -**color**: [r, g, b, a] fill color. - -**Returns**: None - - - -## drawtext(text, position, color) - -Draw text at the given screen position with a specified color. - -**text**: The string to draw. - -**position**: [x, y] in screen coordinates. - -**color**: [r, g, b, a] text color. - -**Returns**: None - - - -## cursorscreenpos() - -Get the current ImGui cursor screen position. - -**Returns**: A 2-element array [x, y] in screen coordinates. - - - -## setcursorscreenpos(position) - -Set the ImGui cursor screen position. - -**position**: A 2-element array [x, y] in screen coordinates. - -**Returns**: None - - - -## contentregionavail() - -Return the available space in the current window’s content region. - -**Returns**: A 2-element array [width, height] of available space. - - - -## dummy(size) - -Add a dummy item (invisible) of the specified size to the layout. - -**size**: A 2-element array [width, height]. - -**Returns**: None - - - -## invisiblebutton(label, size) - -Create an invisible button that occupies a given size and can catch clicks. - -**label**: The identifier for the button. - -**size**: [width, height] specifying the button area. - -**Returns**: None - - - -## width(width) - -Set the width of the next item in the layout. - -**width**: The width (in pixels) for the next item. - -**Returns**: None - - - -## setclipboard(text) - -Set the system clipboard text. - -**text**: The string to put into the clipboard. - -**Returns**: None - - - -## newframe() - -Start a new ImGui frame. Should be called once per frame before rendering UI elements. - -**Returns**: None - - - -## endframe(commandBuffer, renderPass) - -Finalize and render the ImGui draw data to the specified command buffer and render pass. - -**commandBuffer**: The SDL GPU command buffer to render into. - -**renderPass**: The SDL GPU render pass used to draw ImGui data. - -**Returns**: None - - - -## wantmouse() - -Check if ImGui wants to capture the mouse (e.g., if a window or widget needs mouse events). - -**Returns**: True if ImGui is capturing the mouse, otherwise false. - - - -## wantkeys() - -Check if ImGui wants to capture the keyboard (e.g., if a text input is active). - -**Returns**: True if ImGui is capturing the keyboard, otherwise false. - - - -## init(gpuDevice, window) - -Initialize ImGui with SDL and SDL_gpu, creating the ImGui context and configuring it. - -**gpuDevice**: The SDL_GPUDevice object. - -**window**: The SDL_Window object to attach ImGui onto. - -**Returns**: None - - - -## prosperon_menu() diff --git a/docs/api/input.md b/docs/api/input.md index bc8ff748..0c2a27fa 100644 --- a/docs/api/input.md +++ b/docs/api/input.md @@ -1,27 +1,62 @@ # input -## mouse_show() +## mouse_show(show) Show or hide the mouse cursor. Pass true to show, false to hide. -## mouse_lock() +**show**: Boolean. True to show, false to hide. -Capture or release the mouse. Pass true to lock, false to unlock. +**Returns**: None -## cursor_set() + + +## mouse_lock(lock) + +Capture or release the mouse, confining it within the window if locked. + +**lock**: Boolean. True to lock, false to unlock. + +**Returns**: None + + + +## cursor_set(cursor) Set the given cursor (created by os.make_cursor) as the active mouse cursor. -## keyname() +**cursor**: The cursor to set. + +**Returns**: None + + + +## keyname(keycode) Given a numeric keycode, return the corresponding key name (e.g., from SDL). +**keycode**: A numeric SDL keycode. + +**Returns**: A string with the key name. + + + ## keymod() Return an object describing the current modifier keys, e.g. {shift:true, ctrl:true}. +**Returns**: An object with boolean fields for each modifier key. + + + ## mousestate() +Return an object describing the current mouse state, including x,y coordinates +and booleans for pressed buttons (left, middle, right, x1, x2). + +**Returns**: Object { x, y, left, middle, right, x1, x2 } + + + ## print_pawn_kbm(pawn) ## procdown() diff --git a/docs/dull.md b/docs/dull.md index 22e37685..a4a221e5 100644 --- a/docs/dull.md +++ b/docs/dull.md @@ -1,19 +1,13 @@ # Dull -The language is dubbed "dull". Dull, because it is a less featureful ES6. Where does it differ from ES6? +The language is dubbed "dull". Dull, because it is a less featureful Javascript. Where does it differ? -- No 'with' -- No 'eval' - No promises, async, await, generators ... -- Names can include any character -- Automatic tail call optimization -- No class syntax, at all -- No null; only undefined - No import/export syntax; 'use' instead - No proxies -- Strings demarked with "" or `` only; ' is reserved for symbols, akin to scheme. 'ok is shorthand for Symbol.for("ok") -Eventually, it could be JIT'd, but another trait of dull is that it is easy to integrate C code into. +We gave it this name to make very clear this is NOT the javascript of the web. This is its own thing, with its own ideas. -Dull is based on Javascript, and has C-like syntax, because that makes it trivial to push code from it into a real C file. Numerous times I've been able to nearly copy and paste some dull code into a C file and get an immediate 50x speed improvement. +Eventually, it could be JIT'd, but another trait of dull is that it is easy to integrate C code into. That is preferred over doing stuff strictly in dull. +Dull has C-like syntax, because that makes it trivial to push code from it into a real C file. \ No newline at end of file diff --git a/docs/engine_tour/actors.md b/docs/engine_tour/actors.md deleted file mode 100644 index 1daf4e13..00000000 --- a/docs/engine_tour/actors.md +++ /dev/null @@ -1,180 +0,0 @@ -# Actors - - -The fundamental tool for building in Prosperon is the actor system. Actors run independently from each other. Actors are defined by a combination of code and data. All actors have a *master* which controls certain properties of the actor. - -The most masterful actor is the *Empyrean*. The first actor you create will have the Empyrean as its master. Subsequent actors can use any other actor as its master. - -| fn | description | -|---------------------|----------------------------------------------------------| -| spawn(text, config) | Creates an actor as the padawan of this one, using text | -| kill() | Kills an actor | -| delay(fn, seconds) | Calls 'fn' after 'seconds' with the context of the actor | - -### Actor Lifetime -When an actor dies, all of the actors that have it as their master will die as well. - -### Turns -Actors get fragments of time called a *turn*. Actors which belong to different systems can have different lengths of turns. - -### Actor files -Actor files end with the extension *.jso*. They list a series of functions to call on a newly formed actor. Actors have a number of useful functions which are called as defined. - -| function | call time | -|----------|----------------------------------------------------------| -| start | The first function called when the actor is in the world | -| update | Called once per turn | -| gui | Called on GUI draw | -| stop | Called when the actor is killed | -| gizmo | Called by the editor when the entity is selected | - -!!! scholium - Create a new actor, then kill it. - ``` - var act_die_call = function() { - console.log(`Actor ${this.id} has died.`); - } - var act1 = Empyrean.spawn(); - var act2 = actor1.spawn(); - act1.stop = act_die_call; - act2.stop = act_die_call; - Empyrean.kill(); /* Error: The Empyrean cannot be killed */ - act1.kill(); - act2.kill(); /* Error: act2 has been killed because act1 was */ - ``` - -!!! scholium - Now simplify by putting the code into a file named *hello.jso*. - ``` - this.stop = function() { - console.log(`Actor ${this.id} has died.`); - } - ``` - Now spawn two actors using it. - ``` - var act1 = Empyrean.spawn("hello.jso"); - var act2 = act1.spawn("hello.jso"); - ``` - - -### Actor configuration -Actors can be created using an optional configuration file. A configuration file is one of any accepted data types. Currently, JSON or [[https://www.crockford.com/nota.html][Nota]]. Configuration files are loaded after an actor's script file, overwriting any defined values on it. - -!!! scholium - Add a name for the actor to take on using a configuration file named *hello.json*. - ``` - { - "name": "Actor 1" - } - ``` - Now create *hello.jso* to use it. - ``` - this.start = function() { console.log(`I, ${this.name}, have been created.`); } - ``` - - -## Entities -Game worlds are made of entities. Entities are a type of actor with a number of useful properties. Entities can only be created on the actor named *Primum*. The Primum is the outermost actor with a physical space. While Actors are more abstract, Entities exist in a definite space, with a position, rotation, and so on. Entities can respond to physics and play sounds. Anything which can be thought of as having a position in space should be an entitiy. - -!!! scholium - The first and most masterful entity is the Primum. The Primum has no components, and its rotation and position are zero. It defines the center of the game. - -In editor mode, when an entity moves, all of its *padawans* also move. - -When the game is actively simulating, this only holds if there are physical constraints between them. - -Prosperon automatically generates physical pin constraints between objects with the appropriate physical properties. - -### Adding Components -Entities can have *components*. Components are essentially javascript wrappers over C code into the engine. Scripting is done to set the components up on entities, after which most of the work is done by the C plugin. - -!!! scholium - For example, to render an image, set up a *sprite* component on an entity and point its path to an image on your harddrive. - ``` - var ent = Empyrean.spawn(); - var spr = ent.add_component(component.sprite); - spr.path = "image.png"; - ``` - Put that into your config file and run `prosperon`. You should see the contents of "image.png" on the screen. - - Try using an animated gif. Prosperon has native support for gif animations! - - -Components only work in the context of an entity. They have no meaning outside of a physical object in the world. They have no inherent scripting capabilities. - -While components can be added via scripting, it is easier to add them via the editor, as we will later see. - -### Ur system -When prosperon starts, it searches for urs by name. Any file ending in ".jso" or ".json" will be interpereted as an ur, with same named jso and json being applied as (text, config) for an ur. A jso or json alone also constitute an ur. - -An ur can also be defined by a json file. If an ur is found, it takes predecent over auto generated urs. The json of an ur looks like this: - -| field | description | -|----|----| -| text | Path to a script file, or array of script files, to apply to the object | -| data | Path to a json file, or array of json files, to apply to the object | - -Any ur file with this sort of json creates an ur which can be created in the game. A file named "box.ur" will be ingested and be available as "ur.box". When saving differences, it creates a json file with the same name as an ur (in this case, "box.json"). - -!!! scholium - Create an ur from the *hello* files above, and then spawn it. - ``` - ur.create("hello", "hello.jso", "hello.json"); - Primum.spawn(ur.hello); - ``` - When creating an actor from source files, all of its setup must take place. In this example, the setup happens during *ur.create*, and spawning is simply a matter of prototyping it. - -This method allows high composability of game objects. - -If an entity is created without an ur, is ur is defined as its given text and data. It cannot be saved. It must be given a new ur name. - -Objects can be composed on the fly by stringing together urs. For example, a "2x.json" might define scale as 2x. Then, you can create a goblin with `ur.goblin`, or a large goblin with `ur.goblin.2x`. This creates a goblin object, and then applies the 2x scripts and jsons onto the object. - -### Urs in game - -Each ur has the following fields. - -| field | description | -|-----------|-------------------------------------------------------------| -| instances | An array of instances of this ur | -| name | Name of the ur | -| text | Path to the script file | -| data | Object to write to a newly generated actor | -| proto | An object that looks like a freshly made entity from the ur | - -An *ur* has a full path given like `ur.goblin.big`. `goblin` and `big` can both possibly have a *.jso* script as well as a *data* file. - -When `goblin.big` is created, the new object has the `goblin` script run on it, followed by the `big` script. The `data` fields consist of objects prototyped from each other, so that the `__proto__` of `big.data` is `goblin.data`. All fields of this objects are assigned to the `big goblin`. - -The unaltered form of every ur-based-entity is saved in the ur's `proto` field. As you edit objects, the differences between how your object is now, compared to its `ur.proto` is a list of differences. These differences can be rolled into the `ur`, or saved as a subtype. - -### Prototyping Entities -Ur types are the prototype of created entities. This makes it trivial to change huge swathes of the game, or make tiny adjustments to single objects, in a natural and intuitive way. When a value is changed on an entity, it is private. When a value is changed on an ur, it propogates to all entities. Values cannot be added or removed in subtypes. - -Entities all have the following functions to assist with this: - -| function | use | -|---------------|---------------------------------------------| -| clone(parent) | Create an entity prototyped from the parent | -| dup(parent) | Create an exact duplicate of the parent | -| revert() | Removes all local changes on the entity | - -Speaking of practical experience, is best for ur prototype chains to be shallow. - -### Spawning -Actor data and ur types can remember which entities were contained in it when saving. They are stored in the *objects* field. When an entity with an *objects* field is spawned, it spawns all of the objects listed in turn. - -When an entity is spawned, it is addressable directly through its master entity. Its name is generated from its file or ur type name. - -!!! scholium - Let's take a simple RPG game. - ``` - Primum - level1 - orc - goblin - human - sword - ui - ``` - The orc, for example, is addressable by `Primum.level1.orc`. The `human` has a `sword` spawned underneath it. When he is killed, his sword also disappears. diff --git a/docs/engine_tour/editor.md b/docs/engine_tour/editor.md deleted file mode 100644 index d1c3738f..00000000 --- a/docs/engine_tour/editor.md +++ /dev/null @@ -1,57 +0,0 @@ -# Editor -Prosperon's visual editor is an assistant for the creation and editing of your game entities and actors. In the editor, all ur types are loaded, and assets are constantly monitored for changes for hot reloading. - -To initiate it, execute `prosperon`. - -## Editing entities -The desktop is the topmost entity that exists in the editor. Instead of editing specific files, you simply load them into your desktop, and go from there. This makes it easier to see two different entities simultaneously so you can ensure changes to one are congruous with the vision for the others. - -The main editor view is made up of entities. Each entity can have a number of components attached to it. When an entity is selected, its name, position, and list of components are listed. - -Basic use of the editor involves spawning new entities, or ones from already made ur types, editing them, and then saving them as new ur types or overwriting the ones they spawned from. Specific tools have been written to make editing components and levels easier than with a text editor, and the editor is easily extendable for your own purposes. - -Assign the entity's *gizmo* property to a function to have that function called each gui rendering frame. - -## The REPL -The REPL lets you poke around in the game. It makes iteration and experimentation fast, fun, and easy. - -The symbol `$` references the current REPL entity. If no entity is selected, the REPL entity is the currently edited one. Otherwise, it is the selected entity, or group of entities, as an array. - -!!! scholium - Easily run commands on multiple entities using Javascript functions like for each. - ``` - $.forEach(e => console.log(e.pos)); - ``` - -The REPL is a powerful tool for editing your game. Arbitrary code can be ran in it, meaning any esoteric activity you need done for your game can be done easily. Commonly used functions should be copied into your /editorconfig.js/ to be called and used at will. - -## Playing the game -Playing the game involves running the game from a special /debug.js/ file, or from the beginning, as if the game were packaged and shipped. - -| key | action | -|-------|-----------------------------------------------------| -| f5 | Play the game, starting with entry point /debug.js/ | -| f6 | Play the game from the beginning | - -While playing the game, a limited editor is available that allows for simple debugging tasks. - -| key | action | -|-----|-----------------------------| -| C-p | Pause | -| M-p | One time step | -| C-q | Quit play, return to editor | - -## Script Editor -Prosperon comes with an in-engine script editor. It implements a subset of emacs, and adds a few engine specific features. - -### Syntax coloring? ... nope! -The editor that ships with Prosperon has *context coloring*, which is a good deal more useful than syntax coloring. - -## Debugging -Debugging functions are mapped to the F buttons, and are available in any debug build of the game. Pressing the specified key toggles the feature; pressing it with /alt/ shows a legend for that feature. - -| key | description | -|-----|----------------------------| -| F1 | Draw physics info | -| F3 | Draw bounding boxes | -| F12 | Draw gui info | diff --git a/docs/engine_tour/gui.md b/docs/engine_tour/gui.md deleted file mode 100644 index f58b31a6..00000000 --- a/docs/engine_tour/gui.md +++ /dev/null @@ -1,9 +0,0 @@ -# GUI -Game GUIs are written by registering an entity's `gui` property to a function, or its `hud` property. - -`gui` draws in window space, where the bottom left corner is `[0,0]`. `hud` draws in screen space. In either of these, you can call "render" functions directly. - -`draw` draws in world space, and mum functions can equally be used there. - -## MUM -The GUI system which ships with Prosperon is called *MUM*. MUM is a declarative, immediate mode HUD system. While Imgui is designed to make it easy to make editor-like controls, mum is designed to be easy to make video game huds. diff --git a/docs/engine_tour/index.md b/docs/engine_tour/index.md deleted file mode 100644 index 5b1aff2f..00000000 --- a/docs/engine_tour/index.md +++ /dev/null @@ -1,43 +0,0 @@ -# Getting Started - -This guide explains how to set up a minimal Prosperon project and run it. - -## Installation - -1. **Download/Install Prosperon**: -(Describe your installation steps or where to get Prosperon.) - -2. **Folder Structure**: -A typical project might have: - ``` - my-game/ - game.js <-- main entry script - config.js <-- runs at engine startup, sets up environment - scripts/ <-- .js, .jso, or actor-based script files - assets/ <-- images, sounds, etc. - ``` - -3. **Run the Engine**: -From your project folder, run: - ``` - prosperon - ``` -By default, it will look for `config.js` (if present), then `main.js` (or editor scripts) to start. - -## Hello World Example - -1. Create a file named `config.js` in your project folder: - ```js - console.log("Hello from Prosperon!") - this.kill() // quits immediately after printing - ``` - -2. Run `prosperon` in that folder: - ``` - prosperon - ``` - You’ll see `"Hello from Prosperon!"` in the console, and then the engine exits. - -That’s it! Next, we’ll explore writing more complex logic with actors, spawning objects, and drawing a game screen. - - diff --git a/docs/engine_tour/resources.md b/docs/engine_tour/resources.md deleted file mode 100644 index b38f2e3e..00000000 --- a/docs/engine_tour/resources.md +++ /dev/null @@ -1,57 +0,0 @@ -# Resources -Assets can generally be used simply with their filename. Assets can be modified with a sidecar file named *filename.asset*, so, a file `ball.png` can have additional parameters through its `ball.png.asset` file. - -| sigil | meaning | -|--------|------------------------| -| \slash | root of project | -| @ | root of save directory | -| # | root of link | - -Resources can be referenced in a relative manner by actor scripts. When it comes to actors using assets, relative filepaths are useful and encouraged. - -``` -/ - score.wav - /bumper - hit.wav - bumper.jso - /ball - hit.wav - ball.jso -``` - -Path resolution occurs during actor creation. In effect, a reference to *hit.wav* in *bumper.jso* will resolve to the absolute path */bumper/hit.wav*. - -If the asset is not found, it is searched for until the project root is reached. The bumper can reference *score.wav* and have the path resolution take place. Later, if the it is decided for the bumper to have a unique score sound, a new /score.wav/ can be placed in its folder and it will work without changing any code. - -!!! caution - Because the path is resolved during object load, you will need to fresh the bumper's ur or spawn a new bumper for it to use the newly placed /score.wav/. - -#### Links -Links can be specified using the "#" sign. These are shortcuts you can specify for large projects. Specify them in the array `Resources.links`. - -An example is of the form `trees:/world/assets/nature/trees`. Links are called with `#`, so you can now make a "fern" with `Primum.spawn("#trees/fern.jso")`. - -### Ur auto creation -Instead of coding all the ur type creation by hand, Prosperon can automatically search your project's folder and create the ur types for you. Any /[name].jso/ file is converted into an ur with the name. Any /[name].json/ file is then applied over it, should it exist. If there is a /.json/ file without a corresponding /.jso/, it can still be turned into an ur, if it is a valid ur format. - -Folders and files beginning with a '.' (hidden) or a '_' will be ignored for ur creation. - -The folder hierarchy of your file system determines the ur prototype chain. /.jso/ files inside of a folder will be subtyped off the folder ur name. - -Only one ur of any name can be created. - -``` -@/ - flipper.js - flipper/ - left.js - -@/ - flipper/ - flipper.js - left/ - left.js -``` - -`prototypes.generate_ur(path)` will generate all ur-types for a given path. You can preload specific levels this way, or the entire game using `prototypes.generate_ur('.')`. If your game is small enough, this can have a massive runtime improvement. diff --git a/docs/engine_tour/scripting.md b/docs/engine_tour/scripting.md deleted file mode 100644 index adb70a87..00000000 --- a/docs/engine_tour/scripting.md +++ /dev/null @@ -1,61 +0,0 @@ -# Scripting -The scripting language used in Prosperon is Javascript, with QuickJS. It is ES2023 compliant. It is fast. - -!!! scholium - Javascript is used here mostly to set up objects and tear them down. Although computationally expensive tasks can be done using QuickJS, Prosperon makes it easy to extend with raw C. - -### How Prosperon games are structured -Prosperon schews the CommonJS and ES module systems for a custom one suitable for a computer game actor model. It is more restricted than either system, while retaining their full power. - -Prosperon games are structured into two types of source files: -- scripts -- actors - -Scripts end with a return statement. A script can return a function, an object of functions, or any other sort of value. - -!!! scholium - It is a common requirement to add some amount of functionality to an object. It can be easily done with a script file. - - ``` - *script.js* - function hello() { say("hello"); }; - return hello; - ``` - - ``` - var o = {}; - o.use("hello.js"); - o.hello(); - ``` - - The `use` function on any object loads a module, and `assign`s its return to the object. - -Scripts are loaded into memory only once. Further `use` statements only generate references to the statements. Because *scripts* are executed in a lambda environment, any `var` declared inside the script files are effectively private variables, persistent variables. - -In a *script*, `this` refers to `undefined`. It is nothng. - -In an *actor* source file, `this` refers to the actor. Actors do not end in a `return` statement. *actor* source is intended to set up a new agent in your game. Set up the new entity by loading modules and assigning functions to `this`. - -### Script entry points -The first way you can customize Prosperon is by adding scripts to the folder you're running it from. Any file ending with *.js* is a *script* which can be ran by Prosperon. - -| script | When called | -|-----------------|---------------------------------------------| -| config.js | First script on Prosperon load | -| game.js | Entry point for running the game | -| editorconfig.js | Entry point for running the editor | -| predbg.js | Called before running debug | -| debug.js | Debug set up | -| dbgret.js | After stopping debug mode, used for cleanup | - -!!! scholium - Try it out. Add a script called `config.js` to your folder, with this. - - ``` - console.log("Hello world!"); - Game.quit(); - ``` - Run `prosperon`. You will see "Hello world!" in the console, and it shuts down. - - -Using `config.js` and `game.js`, you can write an entire game, without reaching any further. When you want to populate a world with independent actors, entities are what you will reach for. diff --git a/docs/engine_tour/exporting.md b/docs/exporting.md similarity index 100% rename from docs/engine_tour/exporting.md rename to docs/exporting.md diff --git a/docs/index.md b/docs/index.md index 2ae66d76..5cd0099d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,8 +1,10 @@ -# Prosperon Docs +# Getting Started -Prosperon is based around a Javascript-like language, made to enable the fastest way to make computer games, in a cross platform way. +Prosperon is based around a Javascript-like language, named "dull", engineered to be the quickest way to make computer games. -This was done to make programs simpler, faster, and easier to maintain. Much Javascript code from before ES6 is compatible. +## Installation + +## A quick example ## API usage A lot of the API usage is informed from 'duck typing'. If something "looks" like a camera - it can be used like one! If something "looks" like a sprite, it can be used like one! There are fast paths on nearly everything for well defined objects diff --git a/docs/engine_tour/input.md b/docs/input.md similarity index 100% rename from docs/engine_tour/input.md rename to docs/input.md diff --git a/docs/rendering.md b/docs/rendering.md new file mode 100644 index 00000000..2f14fe0d --- /dev/null +++ b/docs/rendering.md @@ -0,0 +1,190 @@ +# Rendering System + +- **Pipeline & Shader Setup:** + The engine defines a base rendering pipeline and derives specialized pipelines (e.g. for sprites) by modifying properties such as blend state, stencil settings, and target textures. +- **Command Buffers & Uploads:** + Data (vertex buffers, index buffers, UBOs, etc.) is uploaded via command buffers obtained from the GPU context. +- **Render Queues:** + There are separate queues for the main scene and for HUD elements. +- **Camera & Render Passes:** + A camera is created with its size set from configuration (width and height). Rendering is performed by executing a render pass for the scene, then a separate HUD pass. +- **Presentation:** + After rendering, the engine performs a blit from the camera’s render target to the swapchain (the actual computer screen) and optionally renders an ImGui pass. + +--- + +## Coordinate System + +- **World Space:** + - **Y-Axis Direction:** Y always goes up. + - **Camera Centering:** In world space, when viewing through a camera, the camera's center (i.e. coordinate (0,0)) corresponds to the center of the computer screen. + _Example:_ If the camera is at (0,0), a sprite positioned at (0,0) will be drawn at the center of the screen. +- **HUD Space:** + - The HUD pass is rendered in a fixed coordinate space where (0,0) is at the bottom left of the computer screen. This coordinate system is independent of the world space camera. + +--- + +## Rendering Pipeline + +- **Base Pipeline:** + A base pipeline is defined with the following key properties: + - **Shaders:** + - Vertex shader: `"sprite.vert"` + - Fragment shader: `"sprite.frag"` + - **Primitive Type:** `"triangle"` + - **Fill Mode:** Filled (set by `fill: true` for solid rendering; can be switched to lines for wireframe) + - **Depth & Stencil:** + - Depth testing is configured but often disabled (`test: false`). + - Stencil is enabled with a default compare mode of `"equal"`. + - **Blending:** + The base pipeline has blending disabled, but specialized pipelines (e.g., the sprite pipeline) enable blending with parameters using source alpha and one-minus source alpha. + +- **Sprite Pipeline:** + Derived from the base pipeline, the sprite pipeline: + - Enables blending. + - Sets the target render output with a color target (format `"rgba8"`) and a depth target (format `"d32 float s8"`). + +--- + +## Shader Creation and Reflection + +- **Shader Loading:** + Shaders are loaded from disk based on a platform-dependent shader format (e.g. Vulkan, Metal). The function `make_shader`: + - Constructs the file path from a base name and shader type. + - Loads shader code and accompanying reflection metadata (from a JSON file). + - Compiles the shader and caches the result. + +- **Reflection Data:** + The reflection metadata is used to: + - Determine the required number and type of uniform buffers. + - Build vertex buffer descriptions and attribute bindings dynamically by inspecting the shader’s input definitions. + - Calculate the byte size for various float-based types (e.g. `float`, `vec2`, `vec3`, `vec4`, `mat4`). + +--- + +## Render Queues and Model Uploading + +- **Render Queues:** + - **Scene Render Queue (`render_queue`):** Used for normal scene drawing. + - **HUD Render Queue (`hud_queue`):** Used for drawing HUD elements. + + Commands are enqueued into these queues using helper functions. Later, during the render pass, these commands are processed in batches. + +- **Buffer Uploads:** + The function `full_upload(buffers)`: + - Acquires a command buffer. + - Uploads an array of data buffers (e.g. vertex, color, UV, and index buffers) to the GPU. + - Submits the command buffer. + +- **Model Binding:** + Functions such as `bind_model` and `bind_mat`: + - Bind a model’s vertex and index buffers to the pipeline. + - Bind material textures and their samplers to the fragment shader based on reflection data. + +- **Grouping Sprites:** + The helper `group_sprites_by_texture` assigns each sprite a mesh and sets its index range (assuming 6 indices per sprite). This simplifies rendering multiple sprites with a single draw call. + +--- + +## Camera and Render Passes + +- **Camera Setup:** + - A camera is created and its size is set from the configuration (typically matching the window dimensions). + - In world space, the camera centers rendering so that objects at (0,0) appear at the center of the screen. + +- **Render Pass (`render_camera`):** + The function `render_camera` performs the following: + - **Target Setup:** + If the camera does not already have a render target, one is created with a color texture (cleared to a cornflower blue) and a depth-stencil texture. + - **Buffer Collection:** + Gathers all buffers from both the scene and HUD render queues. + - **Uniform Data:** + Sets up camera and model uniform buffers using reflection data (e.g. for transformation matrices). + - **Drawing:** + Iterates over the render queue and draws each group using indexed drawing commands. + - **HUD Pass:** + After drawing the main scene, a separate HUD pass is executed. In the HUD pass, a helper (e.g. `cmds.hud`) is used so that coordinates are fixed with (0,0) at the bottom left. + +--- + +## Presentation and Swapchain + +- **Blitting to Screen:** + After the render passes are complete, the function `gpupresent`: + - Acquires a swapchain texture. + - Uses a blit operation to copy the rendered image from the camera’s render target to the swapchain, taking into account the camera’s draw rectangle. + +- **Optional ImGui Rendering:** + If ImGui is enabled, an additional render pass is executed to draw UI elements on top of the swapchain image. + +- **Submission:** + Finally, the command buffer is submitted to the GPU, completing the frame. + +--- + +## Device Profiles + +A set of predefined device profiles is provided (e.g., for PC, MacBook, Nintendo Switch, Game Boy, etc.) with resolution and diagonal size in inches. These profiles are useful for testing how content will appear on different screens. + +--- + +## Advanced Topics + +- **Stencil Operations & Masks:** + - Functions such as `stencil_writer`, `fillmask`, and `mask` allow for advanced stencil buffer operations. + - These are used to control where drawing occurs (for example, drawing a fullscreen shape to populate the stencil buffer or masking specific areas with an image). + +- **Viewport and Scissor:** + - `render.viewport` and its alias `render.scissor` set the active drawing rectangle on the GPU. + +- **Uniform Buffer Object (UBO) Management:** + - Functions such as `ubo_obj_to_array` convert objects into ArrayBuffers that match the UBO structure defined by the shader’s reflection data. + - The helper `get_pipeline_ubo_slot` retrieves the correct slot for UBO data based on name suffix matching. + +--- + +## Useful Functions Summary + +- **full_upload(buffers):** + Uploads an array of buffers to the GPU. + +- **bind_pipeline(pass, pipeline):** + Ensures a pipeline is created and binds it to a render pass. + +- **make_pipeline(pipeline):** + Creates a GPU pipeline based on shader reflection data and input attribute descriptions. + +- **make_shader(sh_file):** + Loads, compiles, and caches a shader, including its reflection metadata. + +- **bind_model(pass, pipeline, model):** + Binds vertex and index buffers for a model. + +- **bind_mat(pass, pipeline, mat):** + Binds textures and samplers to the fragment shader. + +- **render_camera(cmds, camera):** + Executes a complete render pass for a given camera, drawing both scene and HUD elements. + +- **gpupresent():** + Acquires the swapchain texture, performs blitting, and submits the final frame. + +--- + +## Key Points for Developers + +- **Coordinate Systems:** + - In world space, the camera’s center is (0,0); objects are drawn relative to this center. + - In the HUD pass, (0,0) is fixed at the bottom left of the screen. + +- **Y-Axis Orientation:** + Y always increases upward. + +- **Pipeline Customization:** + The base pipeline can be adapted by modifying shader files, blend states, depth/stencil settings, and more. + +- **Shader Reflection:** + Utilize reflection data to automatically set up vertex attributes and UBO bindings. This minimizes manual configuration when updating shaders. + +- **Device Adaptation:** + Use the predefined device profiles to test and optimize your rendering for various screen resolutions and aspect ratios. diff --git a/docs/resources.md b/docs/resources.md new file mode 100644 index 00000000..27b39a90 --- /dev/null +++ b/docs/resources.md @@ -0,0 +1,51 @@ +# Resource & I/O System Overview + +This document provides a **high-level** explanation of how Prosperon handles resource loading, module discovery, and general file I/O. It is intended to give you insight into the **concepts and architecture** behind these systems, without detailing individual function calls. + +--- + +## 1. Module Loading and Discovery + +Prosperon uses a set of **search paths** to locate modules. Each path in this list is consulted in order, and the first matching module file is loaded. +- **Paths Array:** The engine maintains a list of directories in which it looks for modules. Developers can add or remove entries from this list, controlling where the engine will search. +- **Extension Matching:** When asked to load a particular module by name, Prosperon tries recognized file extensions until it finds a suitable file. This means you do not have to specify the file’s extension; the engine infers it from a known set of possibilities. +- **Shadowing:** If your local module happens to have the same name as a built-in module, and is found first in the search path, it overrides the built-in. This can be used to replace or augment default behaviors. + +Prosperon **caches** each loaded module so it is only created once. Subsequent requests for the same module return the same instance. + +--- + +## 2. Resource System + +Beyond modules, Prosperon categorizes other assets (images, sounds, fonts, etc.) by **common file extensions**. +- **Extension Lists:** Internally, there are sets of recognized extensions for each resource type (e.g., for images or sound files). These lists drive how Prosperon locates the actual file you intended to load. +- **Canonical Paths:** Whenever a resource is identified, its path is transformed into a “real” path on the host filesystem. This ensures the engine is working with unambiguous directory references, even if virtual or mounted paths are involved. +- **Consistency:** This approach keeps naming consistent across different platforms, so developers don’t need to worry about exact extension casing or platform-specific directory structures. + +--- + +## 3. High-Level I/O Flow + +Prosperon’s I/O subsystem provides a **unified interface** for reading and writing files, managing directories, and working with mounted filesystems or archives. While the specific operations vary (creating directories, checking file existence, enumerating directories, etc.), they are all handled through a single engine-provided interface. Key points include: +- **Mounting & Write Paths:** Prosperon can mount external directories or archives into its virtual filesystem, and can direct all “write” operations to a particular directory. +- **Metadata & Enumeration:** The engine tracks file metadata and can list contents of directories (including optional recursion into subdirectories). +- **Wildcard & Glob Patterns:** Certain patterns can be used to include or exclude files from an operation, helping developers filter out files easily. + +By keeping resource lookups and filesystem interactions centralized, Prosperon’s I/O system fosters portability across different environments and platforms. + +--- + +## 4. Integration in the Engine + +From the moment Prosperon starts up, it initializes the module and resource systems. This guarantees that: +1. **Core Modules** (e.g., for rendering or audio) are found in known paths. +2. **Developer-Defined Modules** are discovered if they are placed in the search paths configured by the engine. +3. **Resource Operations** (like finding the correct variant of an image or script) are uniform, relying on known extension lists and standardized directory lookups. + +Since everything is cached and resolved through the same system, developers can **easily control** how their projects load assets, override default modules, or customize file storage locations, without needing to replicate or reinvent these mechanisms. + +--- + +## 5. Summary + +Overall, Prosperon’s module system and resource loader work together to provide a **flexible, extensible** approach for organizing a project’s code and data. By adjusting the search paths and extension lists, developers can adapt the engine to a wide variety of use cases—while the I/O subsystem ensures that common file management patterns (mounting, enumerating, reading, and writing) all behave in a consistent manner across platforms and deployment scenarios. diff --git a/mkdocs.yml b/mkdocs.yml index be41c568..87a749b4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,11 +3,12 @@ edit_uri: edit/master/doc/docs plugins: - search - - with-pdf + - awesome-pages extra_css: - style.css + theme: name: material navigation_depth: 3 diff --git a/scripts/modules/imgui.js b/scripts/modules/imgui.js index 1224ea4b..cd71264f 100644 --- a/scripts/modules/imgui.js +++ b/scripts/modules/imgui.js @@ -725,4 +725,4 @@ imgui.init[prosperon.DOC] = `Initialize ImGui with SDL and SDL_gpu, creating the :return: None `; -return imgui; +return false diff --git a/scripts/modules/input.js b/scripts/modules/input.js index 0831b6a1..04801578 100644 --- a/scripts/modules/input.js +++ b/scripts/modules/input.js @@ -1,9 +1,38 @@ var input = this -input.mouse_show[prosperon.DOC] = "Show or hide the mouse cursor. Pass true to show, false to hide." -input.mouse_lock[prosperon.DOC] = "Capture or release the mouse. Pass true to lock, false to unlock." -input.cursor_set[prosperon.DOC] = "Set the given cursor (created by os.make_cursor) as the active mouse cursor." -input.keyname[prosperon.DOC] = "Given a numeric keycode, return the corresponding key name (e.g., from SDL)." -input.keymod[prosperon.DOC] = "Return an object describing the current modifier keys, e.g. {shift:true, ctrl:true}." +input.mouse_show[prosperon.DOC] = `Show or hide the mouse cursor. Pass true to show, false to hide. -return input \ No newline at end of file +:param show: Boolean. True to show, false to hide. +:return: None +` + +input.mouse_lock[prosperon.DOC] = `Capture or release the mouse, confining it within the window if locked. + +:param lock: Boolean. True to lock, false to unlock. +:return: None +` + +input.cursor_set[prosperon.DOC] = `Set the given cursor (created by os.make_cursor) as the active mouse cursor. + +:param cursor: The cursor to set. +:return: None +` + +input.keyname[prosperon.DOC] = `Given a numeric keycode, return the corresponding key name (e.g., from SDL). + +:param keycode: A numeric SDL keycode. +:return: A string with the key name. +` + +input.keymod[prosperon.DOC] = `Return an object describing the current modifier keys, e.g. {shift:true, ctrl:true}. + +:return: An object with boolean fields for each modifier key. +` + +input.mousestate[prosperon.DOC] = `Return an object describing the current mouse state, including x,y coordinates +and booleans for pressed buttons (left, middle, right, x1, x2). + +:return: Object { x, y, left, middle, right, x1, x2 } +` + +return input diff --git a/scripts/modules/loop.js b/scripts/modules/loop.js index c92e8957..55a87739 100644 --- a/scripts/modules/loop.js +++ b/scripts/modules/loop.js @@ -5,7 +5,7 @@ var input = use('input') var emitter = use('emitter') var os = use('os') var event = use('event') -//var imgui = use('imgui') +var imgui = use('imgui') var waittime = 1/240 var last_frame_time = 0 @@ -34,7 +34,7 @@ function step() { render.setup_draw() render.setup_hud() - //if (imgui) imgui.prosperon_menu(); + if (imgui) imgui.prosperon_menu(); // Now do the GPU present (calls gpupresent in render.js) render._main.present() diff --git a/scripts/modules/render.js b/scripts/modules/render.js index 6470602e..22169d47 100644 --- a/scripts/modules/render.js +++ b/scripts/modules/render.js @@ -650,7 +650,7 @@ render_camera[prosperon.DOC] = `Render a scene using the provided camera, drawin :return: None ` -var imgui //= use('imgui') +var imgui = use('imgui') if (imgui) imgui.init(render._main, prosperon.window); var swaps = []; diff --git a/source/jsffi.c b/source/jsffi.c index fb3b9bed..7d5c43dd 100644 --- a/source/jsffi.c +++ b/source/jsffi.c @@ -6030,12 +6030,16 @@ JSC_CCALL(io_globfs, globs[globs_len] = NULL; data.globs = globs; - PHYSFS_enumerate("", globfs_cb, &data); + const char *path = NULL; + if (!JS_IsUndefined(argv[1])) path = JS_ToCString(js,argv[1]); + printf("LOOKING INTO %s\n", path); + PHYSFS_enumerate(path, globfs_cb, &data); for (int i = 0; i < globs_len; i++) JS_FreeCString(js,globs[i]); ret = data.arr; + JS_FreeCString(js,path); ) static int enumerate_cb(void *udata, const char *dir, const char *fname) @@ -6123,7 +6127,7 @@ static const JSCFunctionListEntry js_io_funcs[] = { MIST_FUNC_DEF(io, rm, 1), MIST_FUNC_DEF(io, mkdir, 1), MIST_FUNC_DEF(io,stat,1), - MIST_FUNC_DEF(io, globfs, 1), + MIST_FUNC_DEF(io, globfs, 2), MIST_FUNC_DEF(io, match, 2), MIST_FUNC_DEF(io, exists, 1), MIST_FUNC_DEF(io, mount, 2), diff --git a/source/prosperon.c b/source/prosperon.c index 7423460f..d880144e 100644 --- a/source/prosperon.c +++ b/source/prosperon.c @@ -89,12 +89,15 @@ int main(int argc, char **argv) { PHYSFS_init(argv[0]); char *base = PHYSFS_getBaseDir(); PHYSFS_setWriteDir(base); - PHYSFS_mount(base, NULL, 0); - PHYSFS_mount(base, "/", 0); - int ret = PHYSFS_mountMemory(zip_buffer_global + zip_offset, appended_zip_size, free_zip, - "core.zip", "/", 0); - if (!ret) printf("COULD NOT MOUNT! Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + PHYSFS_mount(base, "/", 0); + int ret = PHYSFS_mountMemory(zip_buffer_global + zip_offset, appended_zip_size, free_zip, "core.zip", NULL, 0); + + if (!ret) { + printf("COULD NOT MOUNT! Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); + return 1; + } + script_startup(argc, argv); // runs engine.js return 0; } diff --git a/docs/graphics.md b/todo/graphics.md similarity index 93% rename from docs/graphics.md rename to todo/graphics.md index ce527006..22026a62 100644 --- a/docs/graphics.md +++ b/todo/graphics.md @@ -150,9 +150,3 @@ game.image("frog.walk.0") ==> retrieve metallic - a metal/smoothness map specular - specular map, alternative for the metallic workflow */ - -// world coordinates, the "actual" view relative to the game's universe -// camera coordinates, normalized from 0 to 1 inside of a camera's viewport, bottom left is 0,0, top right is 1,1 -// screen coordinates, pixels, 0,0 at the top left of the window and [w,h] at the bottom right of the window -// hud coordinates, same as screen coordinates but the top left is 0,0 - diff --git a/docs/ops.md b/todo/ops.md similarity index 100% rename from docs/ops.md rename to todo/ops.md