]> git.mcshandy.xyz Git - sumeriangame/commitdiff
Stenciled viewport rendering and camera management
authorRandy McShandy <randy@mcshandy.xyz>
Tue, 17 Feb 2026 03:54:36 +0000 (21:54 -0600)
committerRandy McShandy <randy@mcshandy.xyz>
Tue, 17 Feb 2026 03:54:36 +0000 (21:54 -0600)
main/handlers.lua
main/main.lua
main/render.lua

index d929d9dd6ad83b7fa8c4460ec496f5a555238bcf..899ddd447227f1e4eaae6fc9b3fcfb8a297c374f 100644 (file)
@@ -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
index b0ab40375b99cac1e67d65fd39f09e3bff47042a..53edad8ac8a38b82870266c4f1d3a47f1252ef11 100644 (file)
@@ -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() }
index e45787836a58951ee232e0dcceb0871454f06390..fd03337ca0e566e5750b93e7a123cdf7b6d4a421 100644 (file)
@@ -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