fix mouse pos

This commit is contained in:
2025-07-09 22:55:41 -05:00
parent 525263a8a6
commit a9b59750e3
6 changed files with 164 additions and 104 deletions

View File

@@ -242,21 +242,17 @@ clay.button = function button(str, action, config = {})
config.action = action;
}
function point_add(a,b) {
return {x: a.x+b.x, y: a.y+b.y}
}
var point = use('point')
// mousepos given in hud coordinates
clay.draw_commands = function draw_commands(cmds, pos = {x:0, y:0}, mousepos = {x:0,y:0})
{
cmds.hovered = null
mousepos = Object.create(mousepos)
mousepos.y = -mousepos.y + 360
for (var cmd of cmds) {
var config = cmd.config;
var boundingbox = geometry.rect_move(cmd.boundingbox,point_add(pos,config.offset));
var content = geometry.rect_move(cmd.content,point_add(pos, config.offset));
var boundingbox = geometry.rect_move(cmd.boundingbox,point.add(pos,config.offset));
var content = geometry.rect_move(cmd.content,point.add(pos, config.offset));
if (config.hovered && geometry.rect_point_inside(boundingbox, mousepos)) {
config.hovered.__proto__ = config;

View File

@@ -289,9 +289,6 @@ graphics.texture[cell.DOC] = `
Load or retrieve a cached image, converting it into a GPU texture. If 'path' is already an object, its returned directly.
`
graphics.texture.cache = {}
graphics.texture.time_cache = {}
graphics.texture.total_size = function() {
var size = 0
// Not yet implemented, presumably sum of (texture.width * texture.height * 4) for images in RAM
@@ -311,16 +308,39 @@ graphics.texture.total_vram[cell.DOC] = `
`
graphics.tex_hotreload = function tex_hotreload(file) {
log.console(`hot reloading ${file}`)
if (!(file in graphics.texture.cache)) return
log.console('really doing it')
// Extract just the filename without path and extension
var basename = file.split('/').pop().split('.')[0]
var img = create_image(file)
var oldimg = graphics.texture.cache[file]
log.console(`new image:${json.encode(img)}`)
log.console(`old image: ${json.encode(oldimg)}`)
// Check if this basename exists in our cache
if (!(basename in cache)) return
merge_objects(oldimg, img, ['surface', 'texture', 'loop', 'time'])
// Find the full path for this image
var fullpath = res.find_image(basename)
if (!fullpath) return
var img = create_image(fullpath)
var oldimg = cache[basename]
// Preserve the GPU texture ID if it exists
var oldGPU = oldimg[GPU]
// Update the CPU surface data
oldimg[CPU] = img[CPU]
// Clear GPU texture to force reload
oldimg[GPU] = null
oldimg[LOADING] = false
// Update dimensions
if (img[CPU]) {
oldimg.rect = {x:0, y:0, width:img[CPU].width, height:img[CPU].height}
decorate_rect_px(oldimg)
}
// If the texture was on GPU, trigger reload
if (oldGPU && renderer_actor) {
oldimg.gpu // This getter will trigger the reload
}
}
graphics.tex_hotreload[cell.DOC] = `
:param file: The file path that was changed on disk.

View File

@@ -29,6 +29,11 @@ $_.start(e => {
}, 'prosperon/sdl_video', {})
var geometry = use('geometry')
var dmon = use('dmon')
var res = use('resources')
// Start watching for file changes
dmon.watch('.')
var camera = {}
@@ -245,19 +250,62 @@ function translate_draw_commands(commands) {
break
case "tilemap":
var texid
tilemap.for(cmd.tilemap, (tile,{x,y}) => {
if (!texid) texid = graphics.texture(tile)
return graphics.texture(tile)
})
var geom = geometry.tilemap_to_data(cmd.tilemap)
if (!texid) break
if (texid.gpu)
geom.texture_id = texid.gpu.id
// Group tiles by texture to batch draw calls
var textureGroups = {}
var tilePositions = []
renderer_commands.push({
op: "geometry_raw",
data: geom
// Collect all tiles and their positions
tilemap.for(cmd.tilemap, (tile, {x,y}) => {
if (tile) {
tilePositions.push({tile, x, y})
}
})
// Group tiles by texture
tilePositions.forEach(({tile, x, y}) => {
var img = graphics.texture(tile)
if (img && img.gpu) {
var texId = img.gpu.id
if (!textureGroups[texId]) {
textureGroups[texId] = {
texture: img,
tiles: []
}
}
textureGroups[texId].tiles.push({x, y, img})
}
})
// Generate draw commands for each texture group
Object.keys(textureGroups).forEach(texId => {
var group = textureGroups[texId]
var tiles = group.tiles
// Create a temporary tilemap with only tiles from this texture
var tempMap = {
tiles: [],
offset_x: cmd.tilemap.offset_x,
offset_y: cmd.tilemap.offset_y,
size_x: cmd.tilemap.size_x,
size_y: cmd.tilemap.size_y
}
// Build sparse array for this texture's tiles
tiles.forEach(({x, y, img}) => {
var arrayX = x - cmd.tilemap.offset_x
var arrayY = y - cmd.tilemap.offset_y
if (!tempMap.tiles[arrayX]) tempMap.tiles[arrayX] = []
tempMap.tiles[arrayX][arrayY] = img
})
// Generate geometry for this texture group
var geom = geometry.tilemap_to_data(tempMap)
geom.texture_id = parseInt(texId)
renderer_commands.push({
op: "geometry_raw",
data: geom
})
})
break
}
@@ -308,6 +356,9 @@ function poll_input() {
if (ev.key)
ev.key = input.keyname(ev.key)
}
if (ev.type.startsWith('mouse_'))
ev.pos.y = -ev.pos.y + win_size.height
}
send(gameactor, evs)
@@ -334,9 +385,37 @@ function create_batch(draw_cmds, done) {
send(video, {kind:'renderer', op:'batch', data:batch}, done)
}
// File watching loop
function poll_file_changes() {
dmon.poll(e => {
if (e.action == 'modify' || e.action == 'create') {
// Check if it's an image file
var ext = e.file.split('.').pop().toLowerCase()
var imageExts = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'tga', 'webp', 'qoi', 'ase', 'aseprite']
if (imageExts.includes(ext)) {
// Try to find the full path for this image
var possiblePaths = [
e.file,
e.root + e.file,
res.find_image(e.file.split('/').pop().split('.')[0])
].filter(p => p)
for (var path of possiblePaths) {
graphics.tex_hotreload(path)
}
}
}
})
// Schedule next poll in 0.5 seconds
$_.delay(poll_file_changes, 0.5)
}
// 3) kick off the very first update→draw
function start_pipeline() {
poll_input()
poll_file_changes() // Start file watching loop
send(gameactor, {kind:'update', dt:0}, () => {
send(gameactor, {kind:'draw'}, cmds => {
pending_draw = cmds

View File

@@ -266,7 +266,7 @@ function handle_window(msg) {
ren = win.make_renderer()
// Initialize ImGui with the window and renderer
imgui.init(win, ren);
// imgui.newframe()
imgui.newframe()
return {success:true};
default:
@@ -483,6 +483,10 @@ var renderfuncs = {
tex = ren.load_texture(surf);
if (!tex) throw new Error("Failed to load texture")
// Set pixel mode to nearest for all textures
tex.scaleMode = "nearest"
var tex_id = allocate_id();
resources.texture[tex_id] = tex;
return {
@@ -510,12 +514,8 @@ var renderfuncs = {
},
imgui_render: function(msg) {
// Render ImGui content
imgui.newframe()
imgui.window("TEST WINDOW", _ => {
imgui.button("test", _ => log.console("test"))
})
imgui.endframe(ren);
imgui.newframe()
return {success: true};
}
};
@@ -564,6 +564,9 @@ function handle_texture(msg) {
return {error: "Must provide either surface_id or width/height"};
}
// Set pixel mode to nearest for all textures
tex.scaleMode = "nearest"
var tex_id = allocate_id();
resources.texture[tex_id] = tex;
return {id: tex_id, data: {size: tex.size}};
@@ -860,21 +863,3 @@ function handle_keyboard(msg) {
return {error: "Unknown keyboard operation: " + msg.op};
}
}
// ImGui operations
function handle_imgui(msg) {
switch (msg.op) {
case 'render':
// Render whatever ImGui has in the barrel and start a new frame
imgui.newframe()
imgui.window("TEST WINDOW", _ => {
imgui.button("test", _ => log.console("test"))
})
imgui.endframe(ren);
return {success: true};
default:
return {error: "Unknown imgui operation: " + msg.op};
}
}

View File

@@ -1,27 +0,0 @@
var dmon = this
dmon.watch[cell.DOC] = `Start watching the root directory, recursively.
This function begins monitoring the specified directory and its subdirectories recursively for events such as file creation, deletion, modification, or movement. Events are queued and can be retrieved by calling poll.
:return: None
:throws: An error if dmon is already watching.
`
dmon.unwatch[cell.DOC] = `Stop watching the currently monitored directory.
This function halts filesystem monitoring for the directory previously set by watch. It clears the watch state, allowing a new watch to be started.
:return: None
:throws: An error if no directory is currently being watched.
`
dmon.poll[cell.DOC] = `Retrieve and process queued filesystem events.
This function dequeues all pending filesystem events and invokes the provided callback for each one. The callback receives an event object with properties: 'action' (string: "create", "delete", "modify", or "move"), 'root' (string: watched directory), 'file' (string: affected file path), and 'old' (string: previous file path for move events, empty if not applicable).
:param callback: A function to call for each event, receiving an event object as its argument.
:return: None
`
return dmon

View File

@@ -112,6 +112,7 @@ if (!io.exists('.cell')) {
os.exit(1);
}
var module_alias = {}
var use_cache = {}
var BASEPATH = 'scripts/base' + MOD_EXT
@@ -123,41 +124,47 @@ js.eval(BASEPATH, script)()
var inProgress = {}
var loadingStack = []
function resolve_alias(name) {
while(module_alias[name]) name = module_alias[name]
return name
}
globalThis.use = function use(file, ...args) {
// Check cache first
if (use_cache[file]) {
return use_cache[file]
}
var requested = file
var key = resolve_alias(file)
if (use_cache[key]) return use_cache[key]
// We'll check for circular dependencies after we determine the path
var path = null
var embed_mod = use_embed(requested)
// First check if we're loading from a script and look in its directory
if (loadingStack.length > 0) {
var currentScript = loadingStack[loadingStack.length - 1]
if (currentScript.includes('/')) {
var currentDir = currentScript.substring(0, currentScript.lastIndexOf('/'))
// Try the file name as-is in the current directory
var localPath = currentDir + '/' + file + MOD_EXT
if (io.exists(localPath) && !io.is_directory(localPath)) {
path = localPath
}
if(loadingStack.length > 0) {
var cur = loadingStack[loadingStack.length-1]
if(cur.includes('/')) {
var dir = cur.substring(0,cur.lastIndexOf('/'))
var cand = dir + '/' + requested + MOD_EXT
if(io.exists(cand) && !io.is_directory(cand))
path = cand
}
}
// If not found locally, check the normal path
if (!path && io.exists(file + MOD_EXT) && !io.is_directory(file + MOD_EXT)) {
path = file + MOD_EXT
if(!path) {
var cand = requested + MOD_EXT
if(io.exists(cand) && !io.is_directory(cand))
path = cand
}
// Check if there's an embedded module
var embed_mod = use_embed(file)
// If no script and no embedded module, error
if (!path && !embed_mod) {
if (!path && !embed_mod)
throw new Error(`Module ${file} could not be found`)
}
// — if its purely embedded, well use the requested name as our key —
var canonical = embed_mod
? requested
: io.realdir(path) + '/' + path // or realpath(path)
// If only embedded module exists, return it
if (!path && embed_mod) {