-- Global state win = require("window") hc = require("party.hc.init") ecs = require("ecs") settings = require("settings") color = require("color") shim = require("shader_shim") log = require("log") MAX_LAMPS = 8 print("hc:", hc) --Use a collider to decide what to render x = { world_e: ecs.Entity(1) -- local offsets from the world world_x: 0 world_y: 0 -- Have we selected an input type yet? controller: { text_size: 4 } -- Level information level: { graphics:{} entities:{} graphic_world: hc.new(5) physics_world: hc.new(1) lamps: {} lamps_rev: {} } sync_time: () -> am.current_time! } x.level.collider = x.level.graphic_world\rectangle(-1,-1,2,2) x.level.add_lamp = (lamp) -> --vector4, vec3 position, strength shape = x.level.graphic_world\circle(lamp.x, lamp.y, lamp.w * 2) x.level.lamps[#x.level.lamps+1] = {lamp, shape} x.level.lamps_rev[shape] = #x.level.lamps #x.level.lamps x.level.move_lamp = (id,newx, newy) -> oldlamp = x.level.lamps[id][1] x.level.lamps[id][2]\moveTo(newx, newy) x.level.lamps[id][1] = vec4(newx, newy, oldlamp.z, oldlamp.w) x.level.remove_lap = (id) -> lamp = table.remove(x.level.lamps,id) x.level.lamps_rev[lamp[2]] = nil x.level.graphic_world\remove(lamp[2]) x.level.lamps_on_screen = () -> lamps = {} i = 0 -- collider world is not alligned to the graphic world x.level.collider\moveTo(x.world_x + 3, x.world_y + 3) for shape,_ in pairs(x.level.graphic_world\collisions(x.level.collider)) index = x.level.lamps_rev[shape] lamp = x.level.lamps[index] table.insert(lamps, lamp[1]) i += i if i > MAX_LAMPS return lamps lamps x.fromscreen = (pos) -> print("fromscreen pos is", pos) -- convert creen pixel coords to world xy coords localx = (pos.x * (win.width / win.height) * 4) / (win.width + 1) localy = (pos.y * 1 * 4) / win.height globalx = x.world_x + localx globaly = x.world_y + localy vec2(globalx, globaly) x.level.on_land = (pos) -> not (pos.x > 10 or pos.x < -10 or pos.y > 10 or pos.y < -10) x.level.in_sea = (pos) -> pos.x > 15 or pos.x < -15 or pos.y > 15 or pos.y < -15 -- Each pixel is 4 bytes, 1 byte per channel x.level.bubble_buffer = am.buffer(1024 * 4 * 4, "dynamic") bubble_view = x.level.bubble_buffer\view("vec4") -- xy location, w time? bubble_texture = am.texture2d(am.image_buffer(x.level.bubble_buffer, 1024 * 4, 1)) class Bubble @wrap = 1 new: (pos) => bubble_view[@@wrap] = vec4(pos.x, pos.y, -1, am.current_time!) print("Bubble created") class PhysicsComponent extends ecs.Component new: (name, properties, shape, args) => log.info("Created a physics component " .. shape .. " with " .. tostring(args), {"phys"}) assert(args, "Physcs Component must be passed args") assert(type(shape) == "string" , "Shape must be a string, was " .. tostring(shape)) @node = am.group! super(name, properties) hc = x.level.physics_world table.insert(args,1,hc) print("Creating a physics component with", args) @shape = hc[shape](unpack(args)) @shape.component = @ join: (entity) => super(entity) @ent = entity leave: () => super! x.level.physics_world\remove(@shape) collisions: () => x.level.physics_world\collisions(@shape) class GraphicsComponent extends ecs.Component new: (name, properties) => print("Got name", name, "and properties", properties) @node = am.group! --assert(properties and properties.node , "Failed to find node for graphics component") super(name, properties) --x.node\append(properties.node) join: (entity) => buf_size = @buf_size! print("Creating entity " .. entity.id .. " with graphic component with " .. buf_size .. " vertexes") @geom_buffer = am.buffer(buf_size * 3 * 4)\view("vec3") -- 3 floats per vertex, 4 bytes per float @norm_buffer = am.buffer(buf_size * 2 * 4)\view("vec2") -- 2 floats per uv, 4 bytes per float @populate_buf(@geom_buffer, @norm_buffer) aspect = win.width / win.height s_mv = mat4( 1, 0, 0, 0, 0, aspect, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3.5 ) binds = { MV: s_mv P: mat4(1) land: @geom_buffer landnormal: @norm_buffer time: am.current_time! atlas: require("world.sprites").rocks_normal.texture streamer: 1 world_x: x.world_x world_y: x.world_y rot: 0 water: 0 --bubbles: bubble_texture } for color, value in pairs(color.am_color) binds[color] = value for i = 1,8 do binds["lamp" .. tostring(i)] = vec4(0) @node\append( shim.land\append( am.depth_test("less")\append( am.cull_face("front")\append( am.bind(binds)\append( am.draw("triangles") ))))) print("graphic node created for",@,@node) component = @ @node\action(() => bind = component.node("bind") if component.action component\action(bind) bind.world_x = x.world_x bind.world_y = x.world_y --find the lamps in screen to render lamps = x.level.lamps_on_screen! --print("Found lamps:", lamps, "at",x.world_x, x.world_y) for i = 1,8 do if i <= #lamps --print("Setting lamp",i,"to",lamps[i]) bind["lamp" .. tostring(i)] = lamps[i] else bind["lamp" .. tostring(i)] = vec4(0) --bind.lamps = am.vec4_array(lamps) --bind.nlamps = #lamps --print(world.world_x, world.world_y) --bind.lamp1 = vec4(math.sin(am.current_time!), 0, 0, math.cos(am.current_time! * 3) + math.pi) -- magic numbers to center the player :/ bind.time = am.current_time! % 1000 -- loop back around so noise doesn't look wonky after a while bind.streamer = settings.streamer ) if @setup @setup(@node) print("Appending ", @node, " to the scene") x.node\append(@node) leave: () => x.node\remove(@node) static: () => @@static buf_size: () => error("Subclasses of GraphicsComponent must implement buffer size") populate_buf: (geom_view, normal_view, offset) => error("Subclasses of GraphicsComponent must implement buffer populate method") x.GraphicsComponent = GraphicsComponent x.PhysicsComponent = PhysicsComponent x.Bubble = Bubble x