ppu rendering

This commit is contained in:
2025-08-01 05:46:33 -05:00
parent 6a9a1a90dd
commit 625503e654
6 changed files with 152 additions and 57 deletions

View File

@@ -102,13 +102,13 @@ draw.arrow = function render_arrow(start, end, wingspan = 4, wingangle = 10, def
draw.line(wing2, defl, material)
}
draw.rectangle = function render_rectangle(rect, defl, material) {
draw.rectangle = function render_rectangle(rect, defl, material = {color:{r:1,g:1,b:1,a:1}}) {
var opt = defl ? {...rect_def, ...defl} : rect_def
add_command("draw_rect", {
rect: rect,
opt: opt,
material: material
rect,
opt,
material
})
}

View File

@@ -23,22 +23,19 @@ function makeOrthoMetal(l,r,b,t,n,f){
}
function make_camera_pblob(camera) {
def zoom = camera.zoom;
// Use surface dimensions if rendering to a surface, otherwise window dimensions
def cw = camera.surface ? camera.surface.width : win_size.width;
def ch = camera.surface ? camera.surface.height : win_size.height;
// how big is the world window?
def world_w = cw / zoom;
def world_h = ch / zoom;
def cw = camera.surface ? camera.surface.width : win_size.width;
def ch = camera.surface ? camera.surface.height : win_size.height;
def zoom = camera.zoom || ch
def world_h = zoom;
def world_w = zoom * cw / ch;
// compute worldspace bounds so that camera.pos lands at the anchor
// anchor.x = 0 → origin at left; 1 → origin at right
def l = camera.pos[0] - camera.anchor[0] * world_w;
def b = camera.pos[1] - camera.anchor[1] * world_h;
def r = l + world_w;
def t = b + world_h;
// now build the Metal/Vulkanstyle ortho (z ∈ [0,1])
def mat = makeOrthoMetal(l, r, b, t, 0, 1);
return geometry.array_blob(mat);
}
@@ -150,6 +147,29 @@ win_config.__proto__ = default_window
win_config.metal = true
var window = new video.window(win_config)
var win_proto = window.__proto__
win_proto.toJSON = function()
{
var flags = this.flags
var ret = {
title: this.title,
size: this.size,
pixel_size: this.sizeInPixels,
display_scale: this.displayScale,
pixel_density: this.pixelDensity,
pos: this.position,
opacity: this.opacity,
fullscreen: this.fullscreen,
safe_area: this.safe_area(),
}
for (var i in flags)
ret[i] = flags[i]
return ret
}
window.resizable = true
var device = new sdl_gpu.gpu({
shaders_msl:true,
shaders_metallib:true,
@@ -158,6 +178,15 @@ var device = new sdl_gpu.gpu({
device.claim_window(window)
device.set_swapchain(window, 'sdr', 'vsync')
var white_pixel = {
width:1,
height:1,
pixels: new blob(32, true), // 32 bits, all set to 1 for a white blob
pitch:32
}
stone(white_pixel.pixels)
var shader_type = device.shader_format()[0]
shader_type = 'msl'
@@ -398,24 +427,6 @@ function poll_input() {
}
if (shouldInclude) {
// Transform mouse coordinates from window to renderer coordinates
if (event.pos && (event.type == 'mouse_motion' ||
event.type == 'mouse_button_down' ||
event.type == 'mouse_button_up' ||
event.type == 'mouse_wheel')) {
// Convert window coordinates to renderer logical coordinates
// var logicalPos = renderer.coordsFromWindow(event.pos)
// event.pos = logicalPos
}
// Handle drop events which also have position
if (event.pos && (event.type == 'drop_file' ||
event.type == 'drop_text' ||
event.type == 'drop_position')) {
// var logicalPos = renderer.coordsFromWindow(event.pos)
// event.pos = logicalPos
}
// Handle window events
if (event.type == 'window_pixel_size_changed') {
win_size.width = event.width
win_size.height = event.height
@@ -431,7 +442,6 @@ function poll_input() {
if (event.type.startsWith('mouse_') && event.pos && event.pos.y)
event.pos.y = -event.pos.y + win_size.height
// event.pos.y = -event.pos.y + logical.height
filteredEvents.push(event)
}
@@ -537,7 +547,8 @@ function get_img_gpu(surface)
d: 1
}, false);
new_tex.push(gpu)
if (full_mip > 1)
new_tex.push(gpu)
return gpu
}
@@ -670,6 +681,21 @@ cmd_fns.draw_slice9 = function(cmd)
render_geom(mesh, img)
}
cmd_fns.draw_rect = function(cmd)
{
// Create geometry for a rectangle quad
var geom = geometry.make_rect_quad(cmd.rect, null, cmd.material.color || [1,1,1,1])
geom.indices = geometry.make_quad_indices(1)
geom.num_indices = 6
// Use white_pixel as the texture so the color modulation works
if (!white_pixel[GPU]) {
white_pixel[GPU] = get_img_gpu(white_pixel)
}
render_geom(geom, {[GPU]: white_pixel[GPU]})
}
var copy_pass
prosperon.create_batch = function create_batch(draw_cmds, done) {
@@ -806,7 +832,6 @@ function poll_file_changes() {
}
})
// Schedule next poll in 0.5 seconds
$_.delay(poll_file_changes, 0.5)
}

View File

@@ -5,8 +5,7 @@ function tilemap()
this.tiles = [];
this.offset_x = 0;
this.offset_y = 0;
this.size_x = 32;
this.size_y = 32;
this.ppu = 32
this.layer = 0; // Default layer for scene tree sorting
this._geometry_cache = {}; // Cache actual geometry data by texture
this._dirty = true;
@@ -113,13 +112,17 @@ tilemap.prototype =
var textureKey = imageToKey.get(tile);
if (!textureGroups[textureKey]) {
// compute world-unit size of one tile of this texture
var tile_wu = tile.width / this.ppu;
var tile_hu = tile.height / this.ppu;
textureGroups[textureKey] = {
tiles: [],
image: tile, // Store the image object
offset_x: this.offset_x,
offset_y: this.offset_y,
size_x: this.size_x,
size_y: this.size_y
size_x: tile_wu,
size_y: tile_hu
};
}
textureGroups[textureKey].tiles.push({
@@ -142,7 +145,7 @@ tilemap.prototype =
tiles: [],
offset_x: group.offset_x,
offset_y: group.offset_y,
size_x: group.size_x,
size_x: group.size_x, // now in world-units
size_y: group.size_y,
pos_x: pos.x,
pos_y: pos.y

View File

@@ -1428,9 +1428,8 @@ JSC_CCALL(geometry_make_rect_quad,
uv_data[6] = uv.x + uv.w; uv_data[7] = uv.y; // top-right
// Set colors
for (int i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++)
color_data[i] = color;
}
// Create result object
ret = JS_NewObject(js);

View File

@@ -319,10 +319,18 @@ static int event2wota_count_props(const SDL_Event *event)
count += 1;
break;
/* Window events (just group them all together) */
/* Window events that only need 'which' */
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
// which => 1 extra
count += 1;
break;
/* Window events that need data1 and data2 */
case SDL_EVENT_WINDOW_SHOWN:
case SDL_EVENT_WINDOW_HIDDEN:
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_MOVED:
case SDL_EVENT_WINDOW_RESIZED:
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
@@ -332,14 +340,10 @@ static int event2wota_count_props(const SDL_Event *event)
case SDL_EVENT_WINDOW_RESTORED:
case SDL_EVENT_WINDOW_MOUSE_ENTER:
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
case SDL_EVENT_WINDOW_HIT_TEST:
case SDL_EVENT_WINDOW_ICCPROF_CHANGED:
case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
case SDL_EVENT_WINDOW_OCCLUDED:
case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
@@ -349,6 +353,11 @@ static int event2wota_count_props(const SDL_Event *event)
count += 3;
break;
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
// which, x, y, width, height => 5 extra
count += 5;
break;
case SDL_EVENT_JOYSTICK_ADDED:
case SDL_EVENT_JOYSTICK_REMOVED:
case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE:
@@ -557,17 +566,20 @@ static void event2wota_write(WotaBuffer *wb, const SDL_Event *e, int c) {
wota_write_text(wb, "owner");
wota_write_sym(wb, e->clipboard.owner ? WOTA_TRUE : WOTA_FALSE);
break;
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
wota_write_text(wb, "which");
wota_write_number(wb, (double)e->window.windowID);
break;
case SDL_EVENT_WINDOW_SHOWN:
case SDL_EVENT_WINDOW_HIDDEN:
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_MINIMIZED:
case SDL_EVENT_WINDOW_MAXIMIZED:
case SDL_EVENT_WINDOW_RESTORED:
case SDL_EVENT_WINDOW_MOUSE_ENTER:
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
case SDL_EVENT_WINDOW_HIT_TEST:
case SDL_EVENT_WINDOW_ICCPROF_CHANGED:
case SDL_EVENT_WINDOW_OCCLUDED:
@@ -575,7 +587,6 @@ static void event2wota_write(WotaBuffer *wb, const SDL_Event *e, int c) {
case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
case SDL_EVENT_WINDOW_DESTROYED:
case SDL_EVENT_WINDOW_HDR_STATE_CHANGED:
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
wota_write_text(wb, "which");
wota_write_number(wb, (double)e->window.windowID);
wota_write_text(wb, "data1");
@@ -583,6 +594,32 @@ static void event2wota_write(WotaBuffer *wb, const SDL_Event *e, int c) {
wota_write_text(wb, "data2");
wota_write_number(wb, (double)e->window.data2);
break;
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
{
SDL_Window *window = SDL_GetWindowFromID(e->window.windowID);
SDL_Rect safe_area = {0, 0, 0, 0};
if (window && SDL_GetWindowSafeArea(window, &safe_area)) {
wota_write_text(wb, "which");
wota_write_number(wb, (double)e->window.windowID);
wota_write_text(wb, "x");
wota_write_number(wb, (double)safe_area.x);
wota_write_text(wb, "y");
wota_write_number(wb, (double)safe_area.y);
wota_write_text(wb, "width");
wota_write_number(wb, (double)safe_area.w);
wota_write_text(wb, "height");
wota_write_number(wb, (double)safe_area.h);
} else {
// Fallback to original behavior if SDL_GetWindowSafeArea fails
wota_write_text(wb, "which");
wota_write_number(wb, (double)e->window.windowID);
wota_write_text(wb, "data1");
wota_write_number(wb, (double)e->window.data1);
wota_write_text(wb, "data2");
wota_write_number(wb, (double)e->window.data2);
}
}
break;
case SDL_EVENT_WINDOW_MOVED:
wota_write_text(wb, "which");
wota_write_number(wb, (double)e->window.windowID);

View File

@@ -286,9 +286,11 @@ JSValue js_window_theme(JSContext *js, JSValue self)
JSValue js_window_safe_area(JSContext *js, JSValue self)
{
SDL_Window *w = js2SDL_Window(js,self);
rect r;
SDL_Rect r;
SDL_GetWindowSafeArea(w, &r);
return rect2js(js,r);
rect newr;
SDL_RectToFRect(&r, &newr);
return rect2js(js,newr);
}
JSValue js_window_bordered(JSContext *js, JSValue self, int argc, JSValue *argv)
@@ -700,7 +702,36 @@ JSValue js_window_updateSurfaceRects(JSContext *js, JSValue self, int argc, JSVa
JSValue js_window_get_flags(JSContext *js, JSValue self)
{
SDL_Window *w = js2SDL_Window(js,self);
return number2js(js, SDL_GetWindowFlags(w));
SDL_WindowFlags flags = SDL_GetWindowFlags(w);
JSValue ret = JS_NewObject(js);
JS_SetPropertyStr(js, ret, "fullscreen", JS_NewBool(js, flags & SDL_WINDOW_FULLSCREEN));
JS_SetPropertyStr(js, ret, "opengl", JS_NewBool(js, flags & SDL_WINDOW_OPENGL));
JS_SetPropertyStr(js, ret, "occluded", JS_NewBool(js, flags & SDL_WINDOW_OCCLUDED));
JS_SetPropertyStr(js, ret, "hidden", JS_NewBool(js, flags & SDL_WINDOW_HIDDEN));
JS_SetPropertyStr(js, ret, "borderless", JS_NewBool(js, flags & SDL_WINDOW_BORDERLESS));
JS_SetPropertyStr(js, ret, "resizable", JS_NewBool(js, flags & SDL_WINDOW_RESIZABLE));
JS_SetPropertyStr(js, ret, "minimized", JS_NewBool(js, flags & SDL_WINDOW_MINIMIZED));
JS_SetPropertyStr(js, ret, "maximized", JS_NewBool(js, flags & SDL_WINDOW_MAXIMIZED));
JS_SetPropertyStr(js, ret, "mouseGrabbed", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_GRABBED));
JS_SetPropertyStr(js, ret, "inputFocus", JS_NewBool(js, flags & SDL_WINDOW_INPUT_FOCUS));
JS_SetPropertyStr(js, ret, "mouseFocus", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_FOCUS));
JS_SetPropertyStr(js, ret, "external", JS_NewBool(js, flags & SDL_WINDOW_EXTERNAL));
JS_SetPropertyStr(js, ret, "modal", JS_NewBool(js, flags & SDL_WINDOW_MODAL));
JS_SetPropertyStr(js, ret, "highPixelDensity", JS_NewBool(js, flags & SDL_WINDOW_HIGH_PIXEL_DENSITY));
JS_SetPropertyStr(js, ret, "mouseCapture", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_CAPTURE));
JS_SetPropertyStr(js, ret, "mouseRelativeMode", JS_NewBool(js, flags & SDL_WINDOW_MOUSE_RELATIVE_MODE));
JS_SetPropertyStr(js, ret, "alwaysOnTop", JS_NewBool(js, flags & SDL_WINDOW_ALWAYS_ON_TOP));
JS_SetPropertyStr(js, ret, "utility", JS_NewBool(js, flags & SDL_WINDOW_UTILITY));
JS_SetPropertyStr(js, ret, "tooltip", JS_NewBool(js, flags & SDL_WINDOW_TOOLTIP));
JS_SetPropertyStr(js, ret, "popupMenu", JS_NewBool(js, flags & SDL_WINDOW_POPUP_MENU));
JS_SetPropertyStr(js, ret, "keyboardGrabbed", JS_NewBool(js, flags & SDL_WINDOW_KEYBOARD_GRABBED));
JS_SetPropertyStr(js, ret, "vulkan", JS_NewBool(js, flags & SDL_WINDOW_VULKAN));
JS_SetPropertyStr(js, ret, "metal", JS_NewBool(js, flags & SDL_WINDOW_METAL));
JS_SetPropertyStr(js, ret, "transparent", JS_NewBool(js, flags & SDL_WINDOW_TRANSPARENT));
JS_SetPropertyStr(js, ret, "notFocusable", JS_NewBool(js, flags & SDL_WINDOW_NOT_FOCUSABLE));
return ret;
}
JSValue js_window_sync(JSContext *js, JSValue self, int argc, JSValue *argv)