fix mouse pos
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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, it’s 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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 it’s purely embedded, we’ll 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) {
|
||||
|
||||
Reference in New Issue
Block a user