From: Randy McShandy Date: Tue, 17 Feb 2026 03:54:36 +0000 (-0600) Subject: Stenciled viewport rendering and camera management X-Git-Url: http://git.mcshandy.xyz/gitweb.cgi?a=commitdiff_plain;h=cf55265943663c4ae0a5c958b4bae24ebee96b6b;p=sumeriangame Stenciled viewport rendering and camera management --- diff --git a/main/handlers.lua b/main/handlers.lua index d929d9d..899ddd4 100644 --- a/main/handlers.lua +++ b/main/handlers.lua @@ -18,6 +18,9 @@ function love.handlers.map_changed(new_map_name) function love.handlers.movement_control(key, value) player:movement_control(key, value) + render.map.topleft = render.map.active_camera(player) + render.viewport = render.update_viewport() + local n = math.random(1, assets.walk_sfx.size) love.audio.play(assets.walk_sfx[n]) end diff --git a/main/main.lua b/main/main.lua index b0ab403..53edad8 100644 --- a/main/main.lua +++ b/main/main.lua @@ -15,6 +15,7 @@ local render = require('render') player = player_module.player function love.load() + love.setDeprecationOutput(false) love.graphics.setFont(assets.get_font('Cuneiform36')) love.audio.play(assets.get_source('intro')) @@ -36,6 +37,17 @@ function love.keyreleased(key) end function love.draw() + love.graphics.stencil( + function() + love.graphics.rectangle('fill', + render.viewport.ox, + render.viewport.oy, + render.viewport.ex, + render.viewport.ey) + end, + 'replace', 1) + love.graphics.setStencilTest('greater', 0) + render.map.active_map:draw(render.map.topleft.x, render.map.topleft.y, render.map.scale) last_color = { love.graphics.getColor() } diff --git a/main/render.lua b/main/render.lua index e457878..fd03337 100644 --- a/main/render.lua +++ b/main/render.lua @@ -1,6 +1,7 @@ -- render.lua -- assets = require('assets') +conf = require('conf') utils = require('utils') local render = {} @@ -32,6 +33,18 @@ render.map.topleft = { x = 0, y = 0 } render.map.scale = 2.0 render.map.active_map = nil +-- A bounding box to mask rendering for the main scene. +-- e.g., anything outside this (or in?) should not be rendered. +-- I don't know if Love supports this but I can always just draw black boxes lol. +-- Look into love.graphics.stencil +render.viewport = +{ + ox = 0, + oy = 0, + ex = conf.window.width, + ey = conf.window.height, +} + render.activate_map = function(new_map_name) local success = false @@ -47,13 +60,74 @@ render.activate_map = function(new_map_name) local object_in_map = render.map.active_map[key] if object_in_map then object.vec = object_in_map.vec + if key == 'Player' then + render.map.topleft = render.map.active_camera(object) + end end end + render.viewport = render.update_viewport() + love.event.push('map_changed', new_map_name) end return success end +--[[ +Calculate a bounding box (rectangle lol) that ensures each +side of the window has a particular margin such that the portion of the map rendered +is in whole increments of tile dimensions. +]]-- +function render.update_viewport() + local tile = { + w = render.map.active_map.tilewidth * render.map.scale, + h = render.map.active_map.tileheight * render.map.scale, + } + local new_viewport = {} + local backwidth = (conf.window.width % tile.w) + local backheight = (conf.window.height % tile.h) + backwidth = (backwidth == 0) and tile.w or backwidth + backheight = (backheight == 0) and tile.h or backheight + + new_viewport.ox = tile.w + new_viewport.oy = tile.h + new_viewport.ex = (conf.window.width) - (tile.w) - (backwidth) + new_viewport.ey = (conf.window.height) - (tile.h) - (backheight) + + return new_viewport +end + +render.CameraClass = { + -- Constantly place the player in the dead center of the window + PlayerInMiddle = 1, + -- Player free roam, transitioning the entire map screen at boundaries, + -- akin to some retro styles + NESFreeRoam = 2, +} + +render.map.cameras = {} +render.map.cameras[render.CameraClass.PlayerInMiddle] = +function(focus, bounds) + local offsets = {} + local new_txty = + { + x = (((conf.window.width / 2) / render.map.scale) - (focus.vec.x)), + y = (((conf.window.height / 2) / render.map.scale) - (focus.vec.y)), + } + offsets.x = math.fmod(new_txty.x, (render.map.active_map.tilewidth)) + offsets.y = math.fmod(new_txty.y, (render.map.active_map.tileheight)) + new_txty.x = new_txty.x - offsets.x + new_txty.y = new_txty.y - offsets.y + return new_txty +end + +render.map.cameras[render.CameraClass.NESFreeRoam] = +function(focus) + -- temp code + return focus.vec or { x = 0, y = 0 } +end + +render.map.active_camera = render.map.cameras[render.CameraClass.PlayerInMiddle] + return render