From c25c52faa0367615591c31ea3c5ab805dcf3de7f Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 11 Feb 2025 00:18:29 -0600 Subject: [PATCH] rework guide documentation --- docs/actors.md | 94 ++++++------------- docs/exporting.md | 52 +---------- docs/index.md | 23 +++-- docs/input.md | 7 +- docs/rendering.md | 200 +++++------------------------------------ docs/resources.md | 52 ++--------- scripts/modules/doc.js | 36 +++++++- 7 files changed, 111 insertions(+), 353 deletions(-) diff --git a/docs/actors.md b/docs/actors.md index 5ee876d4..01517cf0 100644 --- a/docs/actors.md +++ b/docs/actors.md @@ -1,8 +1,6 @@ -# Programs: Actors and Modules +# Programs: Programs and Modules -Prosperon organizes your code into two broad categories: **modules** and **actors**. This page explains how they work, how they fit together, and some of their unique quirks. We’ll also touch on **doc.js**, which uses special docstring notation to automatically generate documentation for your modules, actors, and C types. - ---- +Prosperon organizes your code into two broad categories: **modules** and **programs**. Modules are used to extend programs with new functionality, while programs are used to spawn actors. ## Modules @@ -16,33 +14,33 @@ Use the built-in `use` function to import a module by file path (or by name if r var myModule = use('scripts/modules/myModule') ``` -`use('myModule')` returns the **exact** same object if called multiple times, since modules are cached and not re-run. +`use('module')` returns the **exact** same object if called multiple times, since modules are cached and not re-run. Dull based modules are resolved by searching for them from the `prosperon.PATH` array. Engine modules are stored under `scripts/modules`, which is already added to the PATH for you. Prosperon can also load C based modules. If two modules have the same path resolution, the C based library will be imported. -## Actors +## Programs -An **actor** is created from a file that **does not** return a value. Instead, the file’s contents run top to bottom as soon as the actor is spawned. Actors are your game’s “live” scripts: each actor can hold its own state and logic, spawn sub-actors, schedule timed tasks, and eventually **kill** itself (or be killed) when it’s done. +An **program** is a file that **does not** return a value. Instead, the file’s contents run top to bottom as soon as the program is spawned. Programs are your game’s “live” scripts: each program can hold its own state and logic, spawn sub-programs, schedule timed tasks, and eventually **kill** itself (or be killed) when it’s done. -### Actor Intrinsic Functions +### Program Intrinsic Functions -Certain functions are intrinsic to the actor and cannot be overridden. They’re assigned to each new actor instance at spawn time: +Certain functions are intrinsic to the program and cannot be overridden. They’re assigned to each new program instance at spawn time: 1. **`spawn(script, config, callback)`** - Creates (spawns) a new actor from another script file. - - **`script`**: Path to the actor script (a file containing statements, not returning anything). - - **`config`**: Optional object of extra properties to assign to the new actor. - - **`callback(underling, info)`**: Optional function invoked right after the actor is instantiated but before it fully initializes. + Creates (spawns) a new program from another script file. + - **`script`**: Path to the program script (a file containing statements, not returning anything). + - **`config`**: Optional object of extra properties to assign to the new program. + - **`callback(underling, info)`**: Optional function invoked right after the program is instantiated but before it fully initializes. - The newly spawned actor: - - Receives a reference to its parent (the `overling`) and can store child actors (the `underlings`). + The newly spawned program: + - Receives a reference to its parent (the `overling`) and can store child programs (the `underlings`). - Automatically calls `awake()` if that function is defined, after basic setup completes. - Registers any recognized event handlers (like `update`, `draw`, etc.) if they exist. 2. **`kill()`** - Destroys the actor, all of its timers, and recursively kills any underling (child) actors. If the actor has a parent, it is removed from the parent’s `underlings` set. + Destroys the program, all of its timers, and recursively kills any underling (child) programs. If the program has a parent, it is removed from the parent’s `underlings` set. 3. **`delay(fn, seconds)`** Runs the given function `fn` after `seconds`. This is implemented under the hood with a timer that automatically clears itself once it fires. @@ -54,64 +52,26 @@ Certain functions are intrinsic to the actor and cannot be overridden. They’re ``` 4. **`clear()`** - Recursively kills all child actors, clearing your immediate `underlings` set. This is not called automatically. You can use it to manually clean up all children without necessarily killing the actor itself. + Recursively kills all child programs, clearing your immediate `underlings` set. This is not called automatically. You can use it to manually clean up all children without necessarily killing the program itself. -### The Actor Lifecycle +### The program Lifecycle -1. **Creation**: An actor is spawned by calling `spawn(script, config)`. The script is loaded (unless already cached), then runs its program code. -2. **Awake**: If the new actor defines `awake()`, Prosperon calls it after the script finishes its top-level execution. This is a common place to do initialization. -3. **Registration**: If the actor has functions named `update`, `draw`, `physupdate`, etc., Prosperon automatically registers them. These can be used for per-frame logic, physics updates, or rendering. -4. **Garbage**: When the actor is killed, if it has a `garbage()` function, Prosperon calls it before final removal (useful for cleanup). -5. **Then**: If the actor has a `then()` function, Prosperon calls it at the very end of the kill process, allowing any final statements after your `garbage()` logic completes. +Specific hooks can be set on a program when it is initialized. + +- **Awake**: If the new program defines `awake()`, Prosperon calls it after the script finishes its top-level execution. This is a common place to do initialization. +- **Garbage**: When the program is killed, if it has a `garbage()` function, Prosperon calls it before final removal. +- **Then**: If the program has a `then()` function, Prosperon calls it at the very end of the kill process, allowing any final statements after your `garbage()` logic completes. +- **Registration**: In addition, if the object has **any** function named the same thing as a hook created with **prosperon.on**, that function will be registered with it after initialization. ### Overlings and Underlings -- **`this.overling`** is the parent actor that spawned the current one. -- **`this.underlings`** is a set of child actors that the current actor has spawned. -- Killing a parent automatically kills all of its underlings, which in turn can kill their own underlings, and so on. +Programs have access to its creator and other programs created underneath it, termed its overling and underlings. -### Event Registration (REGGIES) +- **`this.overling`** is the parent program that spawned the current one. +- **`this.underlings`** is a set of child programs that the current program has spawned. -Inside `engine.js`, there’s a “registry” system for events like `update`, `physupdate`, `draw`, etc. An actor with a function named one of these triggers automatically registers that function. Prosperon calls all registered functions in order, every frame or whenever the corresponding event fires. - -Because this happens automatically: -- Simply declare `this.update = function() { ... }` in your actor script, and Prosperon will call that every frame without manual event hookup. -- If you want to remove or replace an event handler, you can reassign or delete the function—though once the actor is created, it’s best to keep the same name. - -### Actor Quirks - -1. **Cannot Return a Value** - By definition, an actor script has no final `return` statement. If a script does have a return, it’s treated as a **module** instead. -2. **Cached Program** - Although an actor script is not a module, Prosperon still parses and caches it. Spawning an actor multiple times from the same script reuses the same parsed code, but each spawn yields a fresh actor instance. -3. **No Overriding Intrinsic** - Actor methods like `spawn`, `kill`, or `delay` can’t be replaced. If you attempt to reassign them, Prosperon prevents it. -4. **Immediate Kill Restriction** - You can’t kill an actor inside its own spawn-time code. Doing so throws an error. If you need to kill yourself immediately, use a small `delay` of zero, or let your `awake()` method handle it safely. +Killing a parent automatically kills all of its underlings, which in turn can kill their own underlings, and so on. ## Program Documentation -Prosperon includes a module called `doc.js` which helps generate documentation for your modules and actors. This is done by scanning: -1. **Top-level docstring**: If an object has a property `object[prosperon.DOC]` or `object.doc`, doc.js treats it as descriptive text. -2. **Function docstrings**: If a function has `functionName.doc = "some text"`, doc.js records that text as the function’s documentation. -3. **Sphinx-like directives**: doc.js looks for lines like `:param name: description` or `:return: something` inside docstrings. It transforms them into more readable bullet points in the final output. - -It is highly recommended to add documentation to your game's modules and actors, so prosperon can generate documentation for your project to keep everybody on the same page. - -### How to Add Docs - -```js -// Suppose we have a module that returns a function -function greet(name) { console.log("Hello, " + name) } - -// We can attach a docstring -greet.doc = ` -Greets the user by name. -:param name: The name of the person to greet. -` - -// A single function is a valid return! -return greet -``` - -When doc.js runs, it picks up this text and generates a Markdown file containing details like the function signature and your docstring. This is especially helpful for large projects or for building a reference of all available modules and methods. +Prosperon includes a module called `doc.js` which helps generate documentation for your modules and programs. Any function and value can be assigned a docstring, and prosperon will then be able to generate documentation for it via doc.js. Look under the module API for more info. diff --git a/docs/exporting.md b/docs/exporting.md index 8c4423d7..ade95f29 100644 --- a/docs/exporting.md +++ b/docs/exporting.md @@ -1,53 +1,3 @@ # Building & Releasing -Prosperon is a multiplatform engine. Bundling your game for these platforms essentially involves three steps: - -- Baking static content -- Conversion of assets -- Packing into a CDB - -To distribute your game for a given platform, run `prosperon build {platform}`. - -| platform | -|----------| -| Linux | -| MacOS | -| Windows | - -You will find your game ready to go. Rename the executable to the name of your game and run it to play. Congratulations! - -## Building static content -Static content creation involves any number of optimizations. - -- Bitmap font creation -- Texture map creation - -Creation of these assets is invisible. Prosperon updates its understanding of how to pull assets based on the existance of these packed ones. - -## Converting assets -Images, videos, and sounds, are converted to assets most suitable for the target platform. This may be for speed or simple compatability. *You do not need to do anything*. Use your preferred asset types during production. - -## Packing into a CDB -A *cdb* is known as a "constant database". It is a write once type of database, with extremely fast retrieval times. Packing your game into a cdb means to create a database with key:value pairs of the filenames of your game. The Prosperon executable is already packed with a core cdb. Your game assets are packed alongside it as the game cdb. - -You can create your game's cdb by running `prosperon -b`. You will find a *game.cdb* in the root directory. - -* Modding & Patching -When an asset is requested in Prosperon, it is searched for in the following manner. - -1. The cwd -2. The game cdb (not necessarily present) -3. The core cdb - -Game modification is trivial using this described system. By putting an asset in the same path as the asset's location in the game cdb, when that asset is requested it will be pulled from the file system instead of the game cdb. - -Given a Prosperon-built game, you can unpack its content into a directory by running `prosperon unpack {game}`. - -## Shipping -Once a game's assets are modified, it may be desirable to ship them. Run `prosperon patch create {game}` to create a /patch.cdb/ filled only with the files that are different compared to those found in the /game.cdb/ in the /game/. - -To update /game/ to use the new patch, run `prosperon patch apply {patch}`, replacing /patch/ with the name of the cdb file generated above. - -Many patches can be bundled by running `prosperon patch bundle {list of patches}`. This creates a patch that will update the game as if the user had updated each patch in order. - -Mods can be distributed with the same idea. +To build and release your game, simply put all of your game assets in the folder into a zip (not including prosperon itself!) named `game.zip`, and ship it in the same folder as the `prosperon` executable for the given platform. `game.zip` is mounted, if present, before any other path, so it will be explored first for assets; in effect, anything in the folder is a 'mod' for a present `game.zip`! diff --git a/docs/index.md b/docs/index.md index 1ed7a014..d04be64b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,23 +5,28 @@ Prosperon is based around a Javascript-like language, DullJS, termed henceforth "dull", engineered to be the quickest way to make computer games. "Dull" will be explored in more detail, but for all intents and purposes it **is** Javascript, with a handful of ES6 features removed. We've given it its own name to crush from the outset any idea that what you're dealing with a web styled Javascript environment! ## The Vision -The less lines of code it takes to do something, the less your program does. The less your program does, the faster it is, and the fewer bugs it has. Prosperon is designed to achieve a minimal number of lines of code when creating a game. Prosperon is designed to be the **best** way to make computer games, quickly. +The less lines of code it takes to do something, the less your program does. The less your program does, the faster it is, and the fewer bugs it has. And, the less the developer needs to keep in their head, the less bugs and more understandable a program is. -1. **Duck typing** +Prosperon is designed to achieve a minimal number of lines of code when creating a game. Prosperon is designed to be the **best** way to make computer games, quickly. + +1. **Flexible API** 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! This means that if you create an enemy in the game, you may be able to pass it in to render, while in other more strict languages, you might need to create an intermediate "sprite" object. -2. **Gradual performance** -However, there are fast paths on nearly everything for well defined objects. For most use cases, the flexible, duck typing works. But in specific circumstances, where speed is required, it's possible. +2. **Uniformity** +Javascript has the brilliant object idea, which is used and abused everywhere in prosperon. Objects allow for a huge variety of ideas to be expressed, and act as an ideal transferring tool between the disparate parts of a computer game. Dull, our dumbed down javascript, uses objects and closures to a greater extent than modern javascript, **without** losing any of the features. There is less syntax to remember, meaning it is quicker to get code down. -3. **Uniformity** -Uniformity is prioritized. Javascript allows for a powerful abstraction - the object - which Prosperon makes much use of. It allows for another - the arraybuffer - which makes it simple to plug different parts of the engine into each other. +3. **Highly reflective** +Built in tools to give an overview of your game. Prosperon can tell you where and how many certain entities are created, how much space they use, and so on. Prosperon can generate an textual overview of your game, resulting in documentation. -4. **AI** -Prosperon is packed with tools to make it easy to work with AI. AI is an incredible productivity boost for programming, but it has a difficult time dealing with game engines like Unity and Unreal. Prosperon can, for example, generate an overview of your game, which you can plug into an AI for context so it will have an easy time helping with what you're stuck on. +4. **Text based** +Prosperon is totally text based. It uses a script based scene structure, where scripts spawn each other and concatenate onto each other to create objects in a scene in a flexible way. This allows for a first class experience with SCM tools, and allows for easy multi user collaboration. + +4. **Gradual Performance** +There are fast paths on nearly everything for well defined objects. For most use cases, the flexible, duck typing works. But in specific circumstances, where speed is required, it's possible. 5. **Interactive** Whenever there is a question of feature, Prosperon chooses the interactive path. Games are interactive. That means you want it to be totally dynamic and fast. Prosperon is designed to favor, for example, generated MIDI music, which you might be able to sync to goblin death animations, over static MP3 files. ## Installation -Just grab the prosperon build for your platform, drop it in a folder, and run it. Prosperon is a tiny executable - usually less than 2MB - so it's recommended to version it with your project. +Just grab the prosperon build for your platform, drop it in a folder, and run it. Prosperon is a tiny executable, so it's recommended to version it with your project. diff --git a/docs/input.md b/docs/input.md index 24f188aa..705fb689 100644 --- a/docs/input.md +++ b/docs/input.md @@ -1,6 +1,6 @@ # Program events and an example input system -Input is done in a highly generic and customizable manner. *players* can take control of any object (actor or otherwise) in Prosperon, after which it is referred to as a *pawn* of a player. If the object has a defined *input* object, it is a valid pawn. One player can have many pawns, but each pawn may have only one player. +Prosperon provides a handy `input` module. Input is done in a highly generic and customizable manner. *players* can take control of any object (actor or otherwise) in Prosperon, after which it is referred to as a *pawn* of a player. If the object has a defined *input* object, it is a valid pawn. One player can have many pawns, but each pawn may have only one player. Pawns are added as a stack, with the newest ones getting priority, and handled first. It is possible for pawns to block input to lower pawns on the stack. @@ -27,12 +27,13 @@ The editor input style defines keystrokes. It is good for custom editors, or any | S | super | ``` -var orc = Primum.spawn(ur.orc); +var input = use('input') +var orc = this.spawn('orc'); orc.inputs = {}; orc.inputs.a = function() { ... }; orc.inputs.A = function() { ... }; /* This is only called with a capital A! */ orc.inputs['C-a'] = function() { ... }; /* Control-a */ -Player.players[0].control(orc); /* player 0 is now in control of the orc */ +input.players[0].control(orc); /* player 0 is now in control of the orc */ ``` The input object can be modified to customize how it handles input. diff --git a/docs/rendering.md b/docs/rendering.md index 90481887..eb4c6a09 100644 --- a/docs/rendering.md +++ b/docs/rendering.md @@ -1,190 +1,36 @@ # Rendering, the camera & the world -- **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. +Prosperon is rendered via a single camera, defined on `prosperon.camera`. Examine the `camera` object in the API for detail about its properties. ---- +The camera has a width and a height, which defines the resolution of the rendered game. The camera also has a transform `prosperon.camera.transform`, which should be used to move it. The camera's position can also be set via `prosperon.camera.pos`. ## Coordinate System +There are two important coordinate systems in Prosperon: world and hud. Both coordinate systems are measured in pixels, with X+ going to the right, and Y+ going up. -- **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. +**World space** is the game world, and is what the camera "sees". The center of the camera is the coordinate it is viewing; so, for example, if the camera is at position [100,100], the pixel at the center of the screen is whatever pixel is at world space [100,100]. ---- +**Hud space** can be thought of as the screen itself, or the lens of the camera. The bottom left of the viewing window is [0,0], and the top right is [camera.width, camera.height]. -## Rendering Pipeline +## The render module & queues +Internally, prosperon keeps a rendering queue as draw commands are issued throughout the frame. It keeps two: 'draw' and 'hud'. At the end of the frame, draw commands are sorted and issued to the GPU: first the 'draw' queue, and then the 'hud' queue, so that it overlays. -- **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. +The render module contains functionality for low level rendering. It includes commands like 'scissor' and 'viewport', it is more recommended to use the 'draw2d' module to do the majority of the drawing. -- **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"`). +## Draw2d +The easiest way to draw with prosperon is to use the 'draw2d' module. Prosperon defines two events via `prosperon.on`: `draw` and `hud`. During a frame, the `render` module sets its internal queue to `draw`, and then the `draw` event is issued. Then it does the same for `hud`. The 'draw2d' module is a high level way to issue drawing commands to the current queue. So, a simple example: ---- +``` +var draw = use('draw2d') +// main.js +var rect = {x:0,y:0,width:100,height:100} // a 100x100 square at [0,0] +this.draw = function() { + draw.rectangle(rect) // this will draw with the bottom left corner at the center of the screen +} -## Shader Creation and Reflection +this.hud = function() { + draw.rectangle(rect) // this draws a rectangle at the botomm left corner of the screen +} +``` -- **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. +## Imgui +Prosperon includes imgui. Another event is the `imgui` event, where you can issue imguie commands via the 'imgui' module. Examine the 'imgui' API for more info. diff --git a/docs/resources.md b/docs/resources.md index b67b7cb1..29a63373 100644 --- a/docs/resources.md +++ b/docs/resources.md @@ -1,51 +1,17 @@ # Resources & Data -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. +Prosperon, being text based, encourages you to reference assets - images, sounds, etc - as strings. ---- +## Module Loading and Discovery -## 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. +**prosperon.PATH** is an array which is a list of directories in which it looks for resources. Developers can add or remove entries from this list, controlling where the engine will search. Assets are searched from `prosperon.PATH[0]` first. -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. +**Extension Matching:** Assets should be referenced without a file extension. Based on the context of what asset is being searched for, a list of file extensions are iterated through to find the asset. When setting a sprite's texture, for example, first a 'png' may be searched for, then a 'gif', and so on. If a specific extension is requested, that specific extension - and only that one - will be searched for. it's very useful to not specify extensions at all, because that enables prosperon to optimize assets and replace them with backend specific ones, and the game will still work. -Prosperon **caches** each loaded module so it is only created once. Subsequent requests for the same module return the same instance. +Prosperon **caches** each loaded assets. When a sprite references a 'png', if another one does, it uses the same GPU texture. ---- +## Mounts +Prosperon uses the idea of file mounting for all io operations. To start with, the write directory is set to the folder prosperon is ran from. That same folder is also mounted as a read directory, as well as the executable itself, which contains a zip file of the engine's core assets. -## 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. +Folders or archives like zip records can be mounted, allowing for an easy way to overwrite specific files with new ones. Because prosperon deals with file systems and strings for its operations, this makes modding easy. For example, a mod `mod.zip` may have a file `sprites/bug.png`. Once mounted, when your game loads `bug` as a sprite, that would be grabbed instead of your game's natives `bug`. diff --git a/scripts/modules/doc.js b/scripts/modules/doc.js index 6cae61b9..593dc49a 100644 --- a/scripts/modules/doc.js +++ b/scripts/modules/doc.js @@ -276,6 +276,36 @@ function writeDataProperty(lines, parentObj, prop, val, level) { // Provide a doc string for writeDocFile writeDocFile[prosperon.DOC] = `Return a markdown string for a given obj, with an optional title.`; -return { - writeDocFile: writeDocFile -}; +var doc = {writeDocFile: writeDocFile} +doc[prosperon.DOC] = ` +Provides a consistent way to create documentation for prosperon elements. Objects are documented by adding docstrings directly to object-like things (functions, objects, ...), or to an object's own "doc object". + +Docstrings are set to the symbol `prosperon.DOC` + +```js +// Suppose we have a module that returns a function +function greet(name) { console.log("Hello, " + name) } + +// We can attach a docstring +greet.doc = ` +Greets the user by name. +:param name: The name of the person to greet. +` + +// A single function is a valid return! +return greet +``` + +```js +// Another way is to add a docstring object to an object +var greet = { + hello() { console.log('hello!') } +} + +greet[prosperon.DOC] = {} +greet[prosperon.DOC][prosperon.DOC] = 'An object full of different greeter functions' +greet[prosperon.DOC].hello = 'A greeter that says, "hello!"' +``` +` + +return doc