2025-11-13 16:35:40 +08:00
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
-- bins
|
|
|
|
|
-- All geometry ends up in a binding, pipeline, uniforms and draw calls.
|
|
|
|
|
-- So to make this more efficient, geometry buffers (vert, uv, index, normals and others) are
|
|
|
|
|
-- organized in two main bin categories.
|
|
|
|
|
-- Main category: Priority - this is the main ordering of rendering.
|
|
|
|
|
-- The higher the priority id the further down the list of rendering.
|
|
|
|
|
-- Thus bins with priority 1 are highest, and are rendered first.
|
|
|
|
|
-- Secondary category: Shader order id - this is the ordering within a bin.
|
|
|
|
|
-- The higher the shader order id, also the further down the list of rendering within a bin
|
|
|
|
|
-- Thus geometry can be ordered within a priority bin
|
|
|
|
|
-- This is most often happening when the render engine does specifc types of sorting
|
|
|
|
|
--
|
|
|
|
|
-- Notes: Initially the shader order id, will not be managed or used. To be implemented later if
|
|
|
|
|
-- needed (which is expected)
|
|
|
|
|
--
|
|
|
|
|
--
|
|
|
|
|
-- bin default priority ranges.
|
|
|
|
|
-- bins will have ranges for specific types of shaders and geometry.
|
|
|
|
|
-- If a material is tagged with transparent, or opaque then the geometry will be
|
|
|
|
|
-- added to the transparent or opaque bins respectively.
|
|
|
|
|
--
|
|
|
|
|
-- The default bin priority ranges are fixed. And _shall_ _not_ change for the duration of the
|
|
|
|
|
-- development of the rendering engine. READ THIS: THEY ARE FIXED. DO NOT CHANGE!
|
|
|
|
|
--
|
|
|
|
|
-- pass
|
|
|
|
|
-- A pass is a collection of bin ids to render together.
|
|
|
|
|
-- Thus while you might have an ordered set of geom in bins, they can be associated
|
|
|
|
|
-- with a specific pass if needed - even multiple passes eg:
|
|
|
|
|
-- when rendering to texture then rendering the same geometry to the display, or;
|
|
|
|
|
-- rendering one geometry as transparent, and one in the gui.
|
|
|
|
|
--
|
|
|
|
|
-- geometry
|
|
|
|
|
-- The geometry object is specifically:
|
|
|
|
|
-- 1. A set of buffers (vert, index, etc)
|
|
|
|
|
-- 2. An associated material id
|
|
|
|
|
-- 3. Unifrom data - for vs, and fs uniforms when preparing the shaders before draw.
|
|
|
|
|
-- 4. The offset and length of the draw call. This allows for the same buffers to be
|
|
|
|
|
-- used with different materials or uniform data.
|
|
|
|
|
-- When the bin is created, it will do so for the buffers, and assign them an id. If the same
|
|
|
|
|
-- buffers are submitted again, it will lookup these and use them. Minimizing duplication.
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
local sapp = require("sokol_app")
|
2026-07-30 21:27:21 +08:00
|
|
|
sg = require("sokol_gfx")
|
|
|
|
|
sg = require("sokol_nuklear")
|
|
|
|
|
local nk = sg
|
2025-11-13 16:35:40 +08:00
|
|
|
local slib = require("sokol_libs") -- Warn - always after gfx!!
|
|
|
|
|
local hmm = require("hmm")
|
|
|
|
|
local hutils = require("hmm_utils")
|
|
|
|
|
|
|
|
|
|
local utils = require("lua.utils")
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
local cammgr = require("lua.engine.camera_manager")
|
|
|
|
|
|
2025-11-13 16:35:40 +08:00
|
|
|
local ffi = require("ffi")
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
local tinsert = table.insert
|
|
|
|
|
local tcount = table.getn
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
local bintype = {
|
|
|
|
|
BTYPE_CUSTOM_BG = 0x1000,
|
|
|
|
|
BTYPE_BACKGROUND = 0x2000,
|
|
|
|
|
BTYPE_TRANSPARENT = 0x4000,
|
|
|
|
|
BTYPE_CUT_OUT = 0x6000,
|
|
|
|
|
BTYPE_OPAQUE = 0x8000,
|
|
|
|
|
BTYPE_GUI = 0xA000,
|
|
|
|
|
BTYPE_CUSTOM_GUI = 0xC000,
|
|
|
|
|
BTYPE_CUSTOM_OVERLAY = 0xD000,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
-- bins can be inserted (use the management methods to do so!!)
|
|
|
|
|
local default_bins = {
|
|
|
|
|
[bintype.BTYPE_CUSTOM_BG] = {},
|
|
|
|
|
[bintype.BTYPE_BACKGROUND] = {},
|
|
|
|
|
[bintype.BTYPE_TRANSPARENT] = {},
|
|
|
|
|
[bintype.BTYPE_CUT_OUT] = {},
|
|
|
|
|
[bintype.BTYPE_OPAQUE] = {},
|
|
|
|
|
[bintype.BTYPE_GUI] = {},
|
|
|
|
|
[bintype.BTYPE_CUSTOM_GUI] = {},
|
|
|
|
|
[bintype.BTYPE_CUSTOM_OVERLAY] = {},
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
local default_bin_order = {
|
|
|
|
|
BTYPE_CUSTOM_BG,
|
|
|
|
|
BTYPE_BACKGROUND,
|
|
|
|
|
BTYPE_TRANSPARENT,
|
|
|
|
|
BTYPE_CUT_OUT,
|
|
|
|
|
BTYPE_OPAQUE,
|
|
|
|
|
BTYPE_GUI,
|
|
|
|
|
BTYPE_CUSTOM_GUI,
|
|
|
|
|
BTYPE_CUSTOM_OVERLAY,
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-13 16:35:40 +08:00
|
|
|
-- --------------------------------------------------------------------------------------
|
|
|
|
|
-- A ultra base bin_state object - this is what is stored in the bins
|
|
|
|
|
--
|
|
|
|
|
-- Note: params may move from here. TBA.
|
|
|
|
|
ffi.cdef[[
|
|
|
|
|
typedef struct bin_state {
|
|
|
|
|
sg_range *vs_params;
|
|
|
|
|
int vs_block_index;
|
|
|
|
|
sg_range *fs_params;
|
|
|
|
|
int fs_block_index;
|
|
|
|
|
|
|
|
|
|
sg_pipeline pip;
|
|
|
|
|
sg_bindings* bind;
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
uint8_t state; // Visibility, and other important flags
|
2025-11-13 16:35:40 +08:00
|
|
|
int offset;
|
|
|
|
|
int count;
|
|
|
|
|
int instances;
|
|
|
|
|
} bin_state;
|
|
|
|
|
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
-- A table (like a class) to handle the main singleton of bins.
|
|
|
|
|
-- Note: This could be extended to have multiple bins if needed.
|
|
|
|
|
local bin_mgr = {}
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bin_mgr.init = function()
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.bins = utils.deepcopy(default_bins)
|
|
|
|
|
bin_mgr.passes = { }
|
|
|
|
|
bin_mgr.cameras = { }
|
2025-11-13 16:35:40 +08:00
|
|
|
|
|
|
|
|
for k,v in pairs(bintype) do
|
|
|
|
|
bin_mgr[k] = v
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
-- TODO: Need to deal with this. Will become a fast lookup for numerous items
|
|
|
|
|
local cache = {}
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.bin_add_geom = function(geom)
|
2025-11-13 16:35:40 +08:00
|
|
|
|
|
|
|
|
local vs_range = nil
|
|
|
|
|
if(geom.vs_params) then
|
|
|
|
|
vs_range = ffi.new("sg_range[1]")
|
|
|
|
|
vs_range[0].ptr = geom.vs_params
|
|
|
|
|
vs_range[0].size = ffi.sizeof(ffi.typeof(geom.vs_params[0]))
|
|
|
|
|
tinsert(cache, vs_range)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local fs_range = nil
|
|
|
|
|
if(geom.fs_params) then
|
|
|
|
|
fs_range = ffi.new("sg_range[1]")
|
|
|
|
|
fs_range[0].ptr = geom.fs_params
|
|
|
|
|
fs_range[0].size = ffi.sizeof(geom.fs_params[0])
|
|
|
|
|
tinsert(cache, fs_range)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local dstate = ffi.new("bin_state[1]",{})
|
|
|
|
|
dstate[0].vs_params = vs_range
|
|
|
|
|
dstate[0].vs_block_index = 0 -- Need to fix
|
|
|
|
|
dstate[0].fs_params = fs_range
|
|
|
|
|
dstate[0].fs_block_index = 0 -- Need to fix
|
|
|
|
|
|
|
|
|
|
dstate[0].pip = geom.pip
|
|
|
|
|
dstate[0].bind = geom.bind
|
2026-07-30 21:27:21 +08:00
|
|
|
dstate[0].state = 0
|
2025-11-13 16:35:40 +08:00
|
|
|
|
|
|
|
|
dstate[0].offset = geom.offset or 0
|
|
|
|
|
-- Assert will prob be temporary. Will capture this upstream.
|
|
|
|
|
assert(geom.count ~= nil or geom.count ~= 0, "[render bin_add] Invalid geometry count for mesh.")
|
2026-07-30 21:27:21 +08:00
|
|
|
dstate[0].count = geom.count or 0
|
2025-11-13 16:35:40 +08:00
|
|
|
dstate[0].instances = geom.instances or 1
|
|
|
|
|
|
|
|
|
|
local bin_slot = bintype.BTYPE_OPAQUE
|
|
|
|
|
if(geom.bintype) then bin_slot = geom.bintype end
|
|
|
|
|
|
|
|
|
|
-- Insert into known bin slot
|
|
|
|
|
local thebin = bin_mgr.bins[bin_slot]
|
|
|
|
|
if(thebin) then
|
2026-07-30 21:27:21 +08:00
|
|
|
tinsert(bin_mgr.bins[bin_slot], dstate )
|
2025-11-13 16:35:40 +08:00
|
|
|
|
|
|
|
|
-- Insert into newly created bin slot
|
|
|
|
|
else
|
|
|
|
|
bin_mgr.bins[bin_slot] = { dstate }
|
|
|
|
|
end
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
return bin_slot, dstate
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bin_mgr.camera_add = function( cameraid, front )
|
|
|
|
|
|
|
|
|
|
if(cammgr.is_active(cameraid)) then
|
|
|
|
|
if(front) then
|
|
|
|
|
tinsert(bin_mgr.cameras, 1, cameraid)
|
|
|
|
|
else
|
|
|
|
|
tinsert(bin_mgr.cameras, cameraid)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2025-11-13 16:35:40 +08:00
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
-- Need a way to order passes on submission
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.pass_add = function(pdata, index, front, attach)
|
2025-11-13 16:35:40 +08:00
|
|
|
|
|
|
|
|
local thispass = ffi.new("sg_pass[1]")
|
|
|
|
|
thispass[0].action.colors[0].load_action = pdata.action
|
2026-07-30 21:27:21 +08:00
|
|
|
if(pdata.clear) then thispass[0].action.colors[0].clear_value = pdata.clear end
|
|
|
|
|
|
|
|
|
|
if(attach) then
|
|
|
|
|
thispass[0].attachments = attach
|
|
|
|
|
else
|
|
|
|
|
thispass[0].swapchain = slib.sglue_swapchain()
|
|
|
|
|
end
|
2025-11-13 16:35:40 +08:00
|
|
|
|
|
|
|
|
local binpass = {
|
|
|
|
|
pass = thispass,
|
2026-07-30 21:27:21 +08:00
|
|
|
binlist = {},
|
|
|
|
|
offscreen = attach ~= nil,
|
2025-11-13 16:35:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(index) then
|
|
|
|
|
binpass.binlist = { index }
|
2026-07-30 21:27:21 +08:00
|
|
|
else
|
|
|
|
|
binpass.binlist = { bins.BTYPE_OPAQUE }
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local passid = 1
|
|
|
|
|
if(not front) then
|
2026-07-30 21:27:21 +08:00
|
|
|
passid = tcount(bin_mgr.passes) + 1
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.passes[passid] = binpass
|
2025-11-13 16:35:40 +08:00
|
|
|
return passid
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.add_offscreen_buffers = function(w, h)
|
|
|
|
|
|
|
|
|
|
local img_desc = ffi.new("sg_image_desc[1]")
|
|
|
|
|
img_desc[0].render_target = true
|
|
|
|
|
img_desc[0].width = w
|
|
|
|
|
img_desc[0].height = h
|
|
|
|
|
img_desc[0].pixel_format = sg.SG_PIXELFORMAT_RGBA8
|
|
|
|
|
img_desc[0].sample_count = 1
|
|
|
|
|
img_desc[0].label = "color-image"
|
|
|
|
|
local color_img = sg.sg_make_image(img_desc)
|
|
|
|
|
|
|
|
|
|
img_desc[0].pixel_format = sg.SG_PIXELFORMAT_DEPTH
|
|
|
|
|
img_desc[0].label = "depth-image";
|
|
|
|
|
local depth_img = sg.sg_make_image(img_desc)
|
|
|
|
|
|
|
|
|
|
local att_desc = ffi.new("sg_attachments_desc[1]")
|
|
|
|
|
att_desc[0].colors[0].image = color_img
|
|
|
|
|
att_desc[0].depth_stencil.image = depth_img
|
|
|
|
|
att_desc[0].label = "offscreen-attachments"
|
|
|
|
|
local attach = sg.sg_make_attachments(att_desc)
|
|
|
|
|
|
|
|
|
|
-- local p_action = ffi.new("sg_pass_action[1]")
|
|
|
|
|
-- p_action[0].colors[0].load_action = sg.SG_LOADACTION_CLEAR,
|
|
|
|
|
-- p_action[0].colors[0].clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }
|
|
|
|
|
|
|
|
|
|
-- // create a sokol-nuklear image object which associates an sg_image with an sg_sampler
|
|
|
|
|
local img_desc = ffi.new("snk_image_desc_t[1]")
|
|
|
|
|
img_desc[0].image = color_img
|
|
|
|
|
local snk_img = nk.snk_make_image(img_desc)
|
|
|
|
|
local nk_hnd = nk.snk_nkhandle(snk_img)
|
|
|
|
|
local nk_img = nk.nk_image_handle(nk_hnd)
|
|
|
|
|
|
|
|
|
|
return attach, nk_img, depth_img
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- --------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bin_mgr.add_offscreen = function(newcam, clear_color, bin_target, front, w, h)
|
|
|
|
|
|
|
|
|
|
bin_target = bin_target or bintype.BTYPE_OPAQUE
|
|
|
|
|
w = w or 1024
|
|
|
|
|
h = h or 1024
|
|
|
|
|
if(newcam) then
|
|
|
|
|
local main_pass = {
|
|
|
|
|
action = sg.SG_LOADACTION_CLEAR,
|
|
|
|
|
clear = clear_color,
|
|
|
|
|
}
|
|
|
|
|
newcam.offscreen = true
|
|
|
|
|
local off_attachments, color_img, depth_img = bin_mgr.add_offscreen_buffers( w, h )
|
|
|
|
|
local passid = bin_mgr.pass_add(main_pass, bin_target, nil, off_attachments)
|
|
|
|
|
newcam.color_image = color_img
|
|
|
|
|
newcam.depth_image = depth_img
|
|
|
|
|
cammgr.add_pass(newcam.name, passid)
|
|
|
|
|
bin_mgr.camera_add(newcam.id, front)
|
|
|
|
|
return off_attachments
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
|
2025-11-13 16:35:40 +08:00
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.add_pass = function( newcam, attachid, bin_target)
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
if(newcam) then
|
|
|
|
|
local main_pass = {
|
|
|
|
|
action = sg.SG_LOADACTION_LOAD,
|
|
|
|
|
}
|
|
|
|
|
local passid = bin_mgr.pass_add(main_pass, bin_target, nil, attachid)
|
|
|
|
|
cammgr.add_pass(newcam.name, passid)
|
|
|
|
|
end
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
2026-07-30 21:27:21 +08:00
|
|
|
-- Need a way to order passes on submission
|
|
|
|
|
bin_mgr.bin_set_func = function(bid, func, index)
|
|
|
|
|
|
|
|
|
|
if(index) then
|
|
|
|
|
bin_mgr.bins[bid][index] = func
|
|
|
|
|
else
|
|
|
|
|
bin_mgr.bins[bid][1] = func
|
|
|
|
|
end
|
|
|
|
|
end
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.bin_remove = function(bid, index)
|
|
|
|
|
local bin = bin_mgr.bins[bid]
|
|
|
|
|
if(bin) then bin[index] = nil end
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.bin_clear = function(bid, index)
|
|
|
|
|
local bin = bin_mgr.bins[bid]
|
|
|
|
|
if(bin) then bin[index][0].state = 0x00 end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
-- Call updates if a bin has an associate function
|
2025-11-13 16:35:40 +08:00
|
|
|
bin_mgr.update = function(dt)
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
bin_mgr.render = function(w, h)
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
-- Not initialized or no geometry?
|
2025-11-13 16:35:40 +08:00
|
|
|
if(bin_mgr.bins == nil) then return end
|
|
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
-- NOTE: Each active camera renders its associated binlists.
|
|
|
|
|
-- Thus multiple cameras can target they same scene objects if needed
|
|
|
|
|
-- Also, it is the camera that determine offscreen rendering or "special" rendering conditions
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
for ci, cameraid in ipairs(bin_mgr.cameras) do
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
-- only active cameras should populate this list anyway, but check
|
|
|
|
|
if(cammgr.is_active(cameraid)) then
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
local cam_name = cammgr.cameras_active[cameraid]
|
|
|
|
|
local camera = cammgr.get(cam_name)
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
-- iterate passes and render bins with pass setup
|
|
|
|
|
for pi, passid in ipairs(camera.passes) do
|
|
|
|
|
local pass = bin_mgr.passes[passid]
|
|
|
|
|
if(pass.binlist) then
|
2025-11-13 16:35:40 +08:00
|
|
|
|
2026-07-30 21:27:21 +08:00
|
|
|
-- Set offscreen rendering
|
|
|
|
|
if(camera.offscreen == true) then
|
|
|
|
|
if(camera.offscreen_prerender) then camera.offscreen_prerender(pass.binlist) end
|
2025-11-13 16:35:40 +08:00
|
|
|
else
|
2026-07-30 21:27:21 +08:00
|
|
|
pass.pass[0].swapchain = slib.sglue_swapchain()
|
|
|
|
|
-- pprint("normal: ", camera.name)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
sg.sg_begin_pass(pass.pass)
|
|
|
|
|
cammgr.apply( cam_name )
|
|
|
|
|
|
|
|
|
|
-- Go through the bins for this pass!
|
|
|
|
|
for bi, binid in ipairs(pass.binlist) do
|
|
|
|
|
|
|
|
|
|
-- Fetch the bin from the pool
|
|
|
|
|
local binlist = bin_mgr.bins[binid]
|
|
|
|
|
|
|
|
|
|
if(binlist) then
|
|
|
|
|
|
|
|
|
|
for bli, bin in pairs(binlist) do
|
|
|
|
|
|
|
|
|
|
if(type(bin) == "function") then
|
|
|
|
|
bin(w, h)
|
|
|
|
|
else
|
|
|
|
|
if(bit.band(bin[0].state, 0x01) == 1) then
|
|
|
|
|
|
|
|
|
|
sg.sg_apply_pipeline(bin[0].pip)
|
|
|
|
|
sg.sg_apply_bindings(bin[0].bind)
|
|
|
|
|
|
|
|
|
|
if(bin[0].vs_params ~= nil) then
|
|
|
|
|
sg.sg_apply_uniforms(sg.SG_SHADERSTAGE_VS, bin[0].vs_params)
|
|
|
|
|
end
|
|
|
|
|
if(bin[0].fs_params ~= nil) then
|
|
|
|
|
sg.sg_apply_uniforms(sg.SG_SHADERSTAGE_FS, bin[0].fs_params)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
sg.sg_draw(bin[0].offset, bin[0].count, bin[0].instances)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
|
|
|
|
end
|
2026-07-30 21:27:21 +08:00
|
|
|
sg.sg_end_pass()
|
2025-11-13 16:35:40 +08:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
sg.sg_commit()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
return bin_mgr
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------------------------------
|