From 44566ce1a380480a80fce000c3e5f5d2b155676a Mon Sep 17 00:00:00 2001 From: Bartek Zbytniewski Date: Thu, 17 Apr 2025 20:03:42 +0200 Subject: [PATCH] new commented examples --- examples/curlywas/cube_wireframe.cwa | 254 +++++++++++++++++++++++++++ examples/curlywas/plasma.cwa | 51 ++++++ examples/curlywas/plasma_chars.cwa | 168 ++++++++++++++++++ 3 files changed, 473 insertions(+) create mode 100644 examples/curlywas/cube_wireframe.cwa create mode 100644 examples/curlywas/plasma.cwa create mode 100644 examples/curlywas/plasma_chars.cwa diff --git a/examples/curlywas/cube_wireframe.cwa b/examples/curlywas/cube_wireframe.cwa new file mode 100644 index 0000000..a7b9de8 --- /dev/null +++ b/examples/curlywas/cube_wireframe.cwa @@ -0,0 +1,254 @@ +/* + This program renders a rotating 3D wireframe cube on a 2D screen using the MicroW8 platform. + + code : zbyti + date : 2025.04.15 + platform : MicroW8 0.4.1 + + https://exoticorn.github.io/microw8/ + https://exoticorn.github.io/microw8/docs/ + + https://github.com/exoticorn/microw8 + https://github.com/exoticorn/curlywas + + https://developer.mozilla.org/en-US/docs/WebAssembly + + https://en.wikipedia.org/wiki/Rotation_matrix +*/ + +//----------------------------------------------------------------------------- +// MicroW8 API +//----------------------------------------------------------------------------- + +//include "../include/microw8-api.cwa" + +// Import memory allocation: 4 pages (64KB) of memory (256KB total) +import "env.memory" memory(4); + +// Import MicroW8 API functions for graphics and math operations +import "env.cls" fn cls(i32); // Clears the screen +import "env.time" fn time() -> f32; // Returns the current time as a float for animation +import "env.sin" fn sin(f32) -> f32; // Computes the sine of an angle (in radians) +import "env.cos" fn cos(f32) -> f32; // Computes the cosine of an angle (in radians) +import "env.line" fn line(f32, f32, f32, f32, i32); // Draws a line between two 2D points with a color + +// Define the starting address for user memory +const USER_MEM = 0x14000; + +//----------------------------------------------------------------------------- +// CONSTANTS +//----------------------------------------------------------------------------- + +// Screen and rendering constants +const CENTER_X = 320.0 / 2.0; // X-coordinate of the screen center (320px width) +const CENTER_Y = 240.0 / 2.0; // Y-coordinate of the screen center (240px height) +const ROTATE_SPEED = 0.5; // Speed at which the cube rotates +const PI = 3.14159265; // Mathematical constant Pi for angle conversions +const RADIAN = PI / 180.0; // Conversion factor from degrees to radians +const SCALE = 65.0; // Scaling factor to adjust the size of the cube on screen +const PERSPECTIVE = SCALE * 0.5; // Perspective factor +const LINE_COLOR = 0xBF; // Color value for drawing the cube's edges (hexadecimal) + +// Memory layout for vertex data +const V_BASE = USER_MEM; // Base vertices stored as 8-bit integers (i8) +const V_ROT = V_BASE + (3 * 8); // Rotated vertices stored as 32-bit floats (f32), offset after V_BASE + +// Offsets for accessing X, Y, Z coordinates in memory (in bytes) +const X = 0; // Offset for X coordinate +const Y = 4; // Offset for Y coordinate +const Z = 8; // Offset for Z coordinate + +// Memory offsets for each rotated vertex (8 vertices, 3 floats each, 12 bytes per vertex) +const VA = V_ROT + (0 * 3 * 4); // Vertex A (front-top-left) +const VB = V_ROT + (1 * 3 * 4); // Vertex B (front-top-right) +const VC = V_ROT + (2 * 3 * 4); // Vertex C (front-bottom-right) +const VD = V_ROT + (3 * 3 * 4); // Vertex D (front-bottom-left) +const VE = V_ROT + (4 * 3 * 4); // Vertex E (back-top-left) +const VF = V_ROT + (5 * 3 * 4); // Vertex F (back-top-right) +const VG = V_ROT + (6 * 3 * 4); // Vertex G (back-bottom-right) +const VH = V_ROT + (7 * 3 * 4); // Vertex H (back-bottom-left) + +//----------------------------------------------------------------------------- +// Function to rotate the cube around X, Y, and Z axes based on time +//----------------------------------------------------------------------------- + +fn rotate() { + // Calculate the rotation angle using the current time for continuous animation + let angle = time() * ROTATE_SPEED; + + // Precompute sine and cosine values once for efficiency + let sn = sin(angle); + let cs = cos(angle); + + let calc = 0; + loop calc { // Iterate over all 8 vertices + // Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z) + let v = calc * 12; + let inline vX = v + X; + let inline vY = v + Y; + let inline vZ = v + Z; + + // Load original vertex coordinates from V_BASE (stored as i8, converted to f32) + let x = i32.load8_s(V_BASE+(calc * 3 + 0)) as f32; // X coordinate + let y = i32.load8_s(V_BASE+(calc * 3 + 1)) as f32; // Y coordinate + let z = i32.load8_s(V_BASE+(calc * 3 + 2)) as f32; // Z coordinate + + // Rotate around Z-axis: updates X and Y, Z stays the same + (vX)$V_ROT = x * cs - y * sn; + (vY)$V_ROT = x * sn + y * cs; + (vZ)$V_ROT = z; + + // Rotate around Y-axis: updates X and Z, Y stays the same + x = (vX)$V_ROT; + z = (vZ)$V_ROT; + (vX)$V_ROT = x * cs + z * sn; + (vZ)$V_ROT = z * cs - x * sn; + + // Rotate around X-axis: updates Y and Z, X stays the same + y = (vY)$V_ROT; + z = (vZ)$V_ROT; + (vY)$V_ROT = y * cs - z * sn; + (vZ)$V_ROT = y * sn + z * cs; + + // Move to the next vertex until all 8 are processed + branch_if (calc +:= 1) < 8: calc; + } +} + +//----------------------------------------------------------------------------- +// Function to project 3D vertices to 2D screen space and draw the cube's edges +//----------------------------------------------------------------------------- + +fn drawLines() { + let scale = 0; + loop scale { // Scale and center each vertex for 2D projection + // Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z) + let v = scale * 12; + let inline vX = v + X; + let inline vY = v + Y; + + // Load Z coordinate of current vertex (from rotated vertex data) + let inline z = (v + Z)$V_ROT; + + // Calculate perspective factor: + // - When z=0 (midpoint), factor=1.0 (no scaling) + // - Positive z (farther away) → factor<1.0 (objects appear smaller) + // - Negative z (closer) → factor>1.0 (objects appear larger) + let lazy factor = PERSPECTIVE / (PERSPECTIVE + z) * SCALE; + + // Apply perspective projection, scaling and shift to center for X and Y coordinats: + // 1. Multiply by perspective factor + // 2. Apply global scaling (SCALE constant) + // 3. Center on screen (CENTER_X, CENTER_Y) + (vX)$V_ROT = (vX)$V_ROT * factor + CENTER_X; // X + (vY)$V_ROT = (vY)$V_ROT * factor + CENTER_Y; // Y + + // Continue until all 8 vertices are scaled + branch_if (scale +:= 1) < 8: scale; + } + + // Draw the front face of the cube (vertices A-B-C-D) + line(VA$X, VA$Y, VB$X, VB$Y, LINE_COLOR); + line(VB$X, VB$Y, VC$X, VC$Y, LINE_COLOR); + line(VC$X, VC$Y, VD$X, VD$Y, LINE_COLOR); + line(VD$X, VD$Y, VA$X, VA$Y, LINE_COLOR); + + // Draw the back face of the cube (vertices E-F-G-H) + line(VE$X, VE$Y, VF$X, VF$Y, LINE_COLOR); + line(VF$X, VF$Y, VG$X, VG$Y, LINE_COLOR); + line(VG$X, VG$Y, VH$X, VH$Y, LINE_COLOR); + line(VH$X, VH$Y, VE$X, VE$Y, LINE_COLOR); + + // Draw edges connecting front and back faces + line(VA$X, VA$Y, VE$X, VE$Y, LINE_COLOR); + line(VB$X, VB$Y, VF$X, VF$Y, LINE_COLOR); + line(VC$X, VC$Y, VG$X, VG$Y, LINE_COLOR); + line(VD$X, VD$Y, VH$X, VH$Y, LINE_COLOR); +} + +//----------------------------------------------------------------------------- +// Entry point for INIT type function, starts first +//----------------------------------------------------------------------------- + +/* +export fn start() { + let init = 0; + loop init { + // Calculate memory offset for current vertex (12 bytes per vertex: 4 bytes each for X, Y, Z) + let v = init * 12; + + (v + X)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 0) as f32; + (v + Y)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 1) as f32; + (v + Z)$V_ROT = i32.load8_s(V_BASE+(init * 3) + 2) as f32; + branch_if (init +:= 1) < 8: init; + } +} +*/ + +//----------------------------------------------------------------------------- +// Main update function called every frame to refresh the screen +//----------------------------------------------------------------------------- + +export fn upd() { + cls(0); // Clear the screen with color 0 (black) + rotate(); // Perform cube rotation calculations + drawLines(); // Draw the rotated cube on the screen +} + +//----------------------------------------------------------------------------- +// DATA +//----------------------------------------------------------------------------- + +/* + Initial vertex data for the cube (8 vertices, each with X, Y, Z as 8-bit signed integers) + Each vertex represents a corner of a unit cube centered at the origin + + F - front, B - back, L - left, R - right, U - up, D - down +*/ +data V_BASE { // 3 * 8 -> 3 bytes per vertex * 8 vertices = 24 bytes + i8( + // X Y Z + -1, -1, 1, // FLU Vertex A + 1, -1, 1, // FRU Vertex B + 1, 1, 1, // FRD Vertex C + -1, 1, 1, // FLD Vertex D + -1, -1, -1, // BLU Vertex E + 1, -1, -1, // BRU Vertex F + 1, 1, -1, // BRD Vertex G + -1, 1, -1 // BLD Vertex H + ) +} + +//----------------------------------------------------------------------------- + +/* + Storage for rotated vertex data (8 vertices, each with X, Y, Z as 32-bit signed floats) + Initialized to zero and updated during rotation +*/ +data V_ROT { // 4 * 3 * 8 -> 12 bytes per vertex * 8 vertices = 96 bytes + f32( + // X Y Z + 0.0, 0.0, 0.0, // VA -> Vertex A + 0.0, 0.0, 0.0, // VB -> Vertex B + 0.0, 0.0, 0.0, // VC -> Vertex C + 0.0, 0.0, 0.0, // VD -> Vertex D + 0.0, 0.0, 0.0, // VE -> Vertex E + 0.0, 0.0, 0.0, // VF -> Vertex F + 0.0, 0.0, 0.0, // VG -> Vertex G + 0.0, 0.0, 0.0 // VH -> Vertex H + ) +} + +//----------------------------------------------------------------------------- +// SNIPPETS +//----------------------------------------------------------------------------- + +/* + let tmp: f32; + tmp = -123.0; + f32.store(tmp, V_ROT); + tmp = f32.load(V_ROT); + printInt(tmp as i32); +*/ + +//----------------------------------------------------------------------------- diff --git a/examples/curlywas/plasma.cwa b/examples/curlywas/plasma.cwa new file mode 100644 index 0000000..4db0350 --- /dev/null +++ b/examples/curlywas/plasma.cwa @@ -0,0 +1,51 @@ +/* + Plasma effect (sizecoding) + + Combines sine waves to create a 2D pixel pattern with intensity-based colors. + + code : zbyti & Grok 3 + date : 2025.04.17 + platform : MicroW8 0.4.1 +*/ + +include "../include/microw8-api.cwa" + +// Constants for color, math, and screen dimensions +const BASE_COLOR = 0xF0; // Base color value for pixel coloring +const PI = 3.14159265; // Mathematical constant π +const RAD = PI / 180.0; // Conversion factor from degrees to radians +const SCR_X = 320; // Screen width in pixels +const SCR_Y = 240; // Screen height in pixels +const SCR_SIZE = SCR_X * SCR_Y; // Screen size in bytes + +// Global variables to track animation phases +global mut phaseX = 0; // Phase offset for X-axis wave animation +global mut phaseY = 0; // Phase offset for Y-axis wave animation + +// Update function called each frame to render the plasma effect +export fn upd() { + let i = 0; + loop i { + // Calculate pixel coordinates from linear index + let lazy x = i % SCR_X; // X-coordinate (column) + let lazy y = i / SCR_X; // Y-coordinate (row) + + // Compute three sine waves with different frequencies and phases + let inline val1 = sin(RAD * 2.25 * (x + phaseX) as f32); // Wave along X-axis + let inline val2 = sin(RAD * 3.25 * (y + phaseY) as f32); // Wave along Y-axis + let inline val3 = sin(RAD * 1.25 * (x + y + phaseX) as f32); // Diagonal wave + + // Combine waves, scale to color range, and convert to integer + let inline c = BASE_COLOR + ((val1 + val2 + val3) * 4.75) as i32; + + // Set pixel color based on computed intensity + setPixel(x, y, c); + + // Continue loop until all pixels are processed + branch_if (i +:= 1) < (SCR_SIZE): i; + } + + // Update phase offsets for animation (different speeds for dynamic effect) + phaseX += 1; // Increment X-phase for horizontal wave movement + phaseY += 2; // Increment Y-phase for vertical wave movement +} \ No newline at end of file diff --git a/examples/curlywas/plasma_chars.cwa b/examples/curlywas/plasma_chars.cwa new file mode 100644 index 0000000..f2f1e5e --- /dev/null +++ b/examples/curlywas/plasma_chars.cwa @@ -0,0 +1,168 @@ +/* + Plasma effect (chars) + + Combines sine waves to create a 2D pattern, maps to custom characters, + and renders to the 40x30 character grid with intensity-based colors. + + code : zbyti (conversion & optimizations) + original : https://github.com/tebe6502/Mad-Pascal/blob/origin/samples/a8/demoeffects/plasma_2.pas + date : 2025.04.16 + platform : MicroW8 0.4.1 +*/ + +include "../include/microw8-api.cwa" + +//----------------------------------------------------------------------------- +// Constants defining memory layout, screen dimensions, and effect parameters +//----------------------------------------------------------------------------- + +const MEM_END = 0x40000; + +const CUSTOM_FONT = FONT + 0x100; +const CHARS = 0x20; +const BASE_COLOR = 0xF0; + +const PI = 3.14159265; +const RAD = PI / 180.0; + +const SCR_X = 320; +const SCR_Y = 240; +const SCR_W = SCR_X / 8; // 40 +const SCR_H = SCR_Y / 8; // 30 +const SCR_SIZE = SCR_X * SCR_Y; + +const SIN_TABLE_SIZE = 128; // Number of entries in the sine lookup table +const SIN_TABLE_MASK = SIN_TABLE_SIZE - 1; + +const SIN_TABLE = MEM_END - SIN_TABLE_SIZE; // Memory address for sine table +const ROW_BUFFER = SIN_TABLE - SCR_W; // Memory address for precomputed row buffer + +//----------------------------------------------------------------------------- +// Global variables to track animation state +//----------------------------------------------------------------------------- + +global mut phaseA = 1; // Phase offset for the first sine wave, controls animation +global mut phaseB = 5; // Phase offset for the second sine wave, controls animation + +//----------------------------------------------------------------------------- + +/* + Logs a value to the console (STDOUT) with a prefix for debugging purposes + + Args: + prefix : 4-character identifier (i32) to label the output + log : Integer value to log (i32) + + Prints to console and returns to screen output +*/ +fn console(prefix: i32, log: i32) { + printChar('\6'); // Switch output to console + printChar(prefix); // Print the prefix + printInt(log); // Print the integer value + printChar('\n\4'); // Print newline and switch back to screen output +} + +//------------------------------------- + +/* + Fills a sine table with precomputed values for fast lookups + + Args: + adr : Memory address where the sine table is stored + size : Number of entries in the table + + Computes: sin(i * 180/size * radians) * 255 for i = 0 to size-1, scaled to 0-255 +*/ +fn fillSin(adr: i32, size: i32) { + let i = 0; + let inline f = 180.00 / size as f32 * RAD; + loop i { + (adr+i)?0 = (sin(f * i as f32) * 255.0) as i32; + branch_if (i +:= 1) < size: i; + } +} + +//----------------------------------------------------------------------------- + +/* + Initialization function called when the program starts +*/ +export fn start() { + // Populate the sine table with values for fast wave calculations + fillSin(SIN_TABLE, SIN_TABLE_SIZE); +} + +//------------------------------------- + +/* + Update function called each frame to render the plasma effect +*/ +export fn upd() { + let pA = phaseA; // Local copy of phaseA to avoid modifying global during frame + let pB = phaseB; // Local copy of phaseB for the same reason + + let i = 0; + loop i { + // Wrap phase values to stay within sine table bounds using bitwise AND + pA &= SIN_TABLE_MASK; + pB &= SIN_TABLE_MASK; + + // Combine two sine waves and store in row buffer + i?ROW_BUFFER = pA?SIN_TABLE + pB?SIN_TABLE; + + pA += 3; // Shift phase for first sine wave (controls wave speed) + pB += 7; // Shift phase for second sine wave (different speed for variety) + + branch_if (i +:= 1) < SCR_W: i; + } + + i = 0; + loop i { + let j = 0; + loop j { + // Combine wave values from row buffer for current position + // Use bitwise AND to clamp to 0-255, then scale to 0-15 for character index + let c = ((j?ROW_BUFFER + i?ROW_BUFFER) & 255) >> 4; + + // Set text color based on intensity (base color + scaled value) + setTextColor(BASE_COLOR + c); + // Draw custom character corresponding to intensity + printChar(CHARS + c); + + branch_if (j +:= 1) < SCR_W: j; + } + branch_if (i +:= 1) < SCR_H: i; + } + + // Update global phase offsets for the next frame to animate the pattern + phaseA += 0; // Increment phaseA to shift the pattern (+/- speed move) + phaseB += 1; // Increment phaseB to shift the pattern (+/- right/left move) +} + +//----------------------------------------------------------------------------- + +/* + Custom font data defining 16 characters (8x8 pixels each) + Each character represents a different intensity level for the plasma effect + Pixels range from empty (0x00) to nearly full (0xFE or 0x7F) to simulate gradients +*/ +data CUSTOM_FONT { + i8( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, + 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, + 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, + 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x38, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ) +}