diff --git a/.gitignore b/.gitignore index 312c732..be1ac7a 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ dkms.conf # python stuff **/__pycache__/ **/*.bin + +dist/* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..39059e0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2021 Tom Marks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Makefile b/Makefile index b7fd655..24de624 100644 --- a/Makefile +++ b/Makefile @@ -4,19 +4,23 @@ BIN=dist/test.elf PS2HOST?=192.168.20.99 DOCKER_IMG=ps2build -DOCKERFLAGS=--user "$(shell id -u):$(shell id -g)" -DOCKER?=sudo docker +DOCKERFLAGS=--user "$(1000):$(1000)" +DOCKER?=docker + +LUA_BRANCH=ee-v5.4.4 include .lintvars dist: $(BIN) assets .PHONY: assets -assets: +assets: scripts if ! [ -d dist ]; then mkdir dist; fi $(MAKE) -C asset cp asset/*.bin dist/ + cp asset/*.tga dist/ cp distfiles/* dist/ + cp LICENSE dist/ $(BIN): src/test.elf if ! [ -d dist ]; then mkdir dist; fi @@ -24,32 +28,37 @@ $(BIN): src/test.elf .PHONY: src/test.elf src/test.elf: - $(MAKE) PLATFORM=ps2 -C src test.elf + $(MAKE) platform=PS2 -C src test.elf + +.PHONY: scripts +scripts: + if ! [ -d dist/script ]; then mkdir -p dist/script; fi + cp script/* dist/script -# TODO(phy1um): update ISO building to include everything in dist/ +# TODO(Tom Marks): update ISO building to include everything in dist/ $(ISO_TGT): $(EE_BIN) mkisofs -l -o $(ISO_TGT) $(BIN) dist/SYSTEM.CNF .PHONY: docker-elf docker-elf: - $(DOCKER) run -v $(shell pwd):/src $(DOCKER_IMG) make $(BIN) + $(DOCKER) run $(DOCKERFLAGS) -v $(shell pwd):/src $(DOCKER_IMG) make $(BIN) .PHONY: clean -clean: +clean: $(MAKE) -C src clean $(MAKE) -C asset clean rm -rf dist/ .PHONY: run -run: - PCSX2 --elf=$(PWD)/$(BIN) +run: scripts + PCSX2 --elf=$(PWD)/$(BIN) -# TODO(phy1um): this could be improved, hard-coded ELF name is bad +# TODO(Tom Marks): this could be improved, hard-coded ELF name is bad .PHONY: runps2 -runps2: - cp dist && ps2client -h $(PS2HOST) -t 10 execee host:test.elf +runps2: scripts + ps2client -h $(PS2HOST) -t 10 execee host:test.elf .PHONY: resetps2 resetps2: @@ -59,8 +68,20 @@ resetps2: lint: cpplint --filter=$(CPPLINT_FILTERS) --counting=total --linelength=$(CPPLINT_LINE_LENGTH) --extensions=c,h --recursive . +.PHONY: lualint +lualint: + luac5.1 -p script/*.lua + .PHONY: format format: $(DOCKER) run $(DOCKERFLAGS) -v $(shell pwd):/workdir unibeautify/clang-format -i -sort-includes **/*.c **/*.h +deps: + git clone https://github.com/ps2dev/lua --depth 1 --branch $(LUA_BRANCH) --single-branch src/lua + +lua-samples: + $(DOCKER) run $(DOCKERFLAGS) -v $(shell pwd):/src $(DOCKER_IMG) make -C src/lua/sample + +docker-image: + $(DOCKER) build -t $(DOCKER_IMG) . diff --git a/asset/bigfont.tga b/asset/bigfont.tga new file mode 100644 index 0000000..3b99e29 Binary files /dev/null and b/asset/bigfont.tga differ diff --git a/asset/font.txt b/asset/font.txt new file mode 100644 index 0000000..ce2037b --- /dev/null +++ b/asset/font.txt @@ -0,0 +1,2 @@ +SPLEEN +https://github.com/fcambus/spleen diff --git a/asset/test.tga b/asset/test.tga new file mode 100644 index 0000000..f46ba4b Binary files /dev/null and b/asset/test.tga differ diff --git a/distfiles/spleen.font.LICENSE b/distfiles/spleen.font.LICENSE new file mode 100644 index 0000000..2e1411a --- /dev/null +++ b/distfiles/spleen.font.LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2018-2021, Frederic Cambus +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/indirect.py b/indirect.py new file mode 100644 index 0000000..2c20bc8 --- /dev/null +++ b/indirect.py @@ -0,0 +1,31 @@ + +import socket +import subprocess +import sys + +SERVER_IP = "0.0.0.0" +SERVER_PORT = int(sys.argv[1]) +is_running = True + +def run_command(msg): + parts = list(map(lambda x: x.decode("utf-8").strip(), msg.split(b" "))) + print("got cmd " + parts[0]) + if parts[0] == "make": + subprocess.run(parts, stdout=cl, stderr=cl) + else: + print("no matching action for cmd") + +server = socket.socket (socket.AF_INET, socket.SOCK_STREAM) +server.bind((SERVER_IP, SERVER_PORT)) +server.listen(5) + +try: + while is_running == True: + cl, addr = server.accept() + print("got connection from client") + msg = cl.recv(1024) + print("running message") + output = run_command(msg) + cl.close() +finally: + server.close() diff --git a/script/draw2d.lua b/script/draw2d.lua new file mode 100644 index 0000000..41fc7bf --- /dev/null +++ b/script/draw2d.lua @@ -0,0 +1,113 @@ +local GIF = require("gif") +local P = require("ps2const") + +local DRAW_NONE = 0 +local DRAW_GEOM = 1 +local DRAW_SPRITE = 2 + +local DRAW_FMT_GEOM = {1,5,5,5} +local DRAW_FMT_SPRITE = {2,1,5,2,1,5} +local DB_SIZE = 5000 + +local draw = { + col = {r=255, g=255, b=255, a=0x80}, + state = DRAW_NONE, + loopCount = 0, + tagLoopPtr = 0, + currentTexPtr = 0, + buf = nil, + kc = 0, + rawtri = 0, + +} + +function draw:newBuffer() + self.state = DRAW_NONE + self.loopCount = 0 + self.tagLoopPtr = 0 + self.buf = RM.getDrawBuffer(DB_SIZE) + end + +function draw:getBuffer() + return self.buf +end + +function draw:setColour(r,g,b,a) + self.col.r = r + self.col.g = g + self.col.b = b + self.col.a = a +end + +function draw:rect(x, y, w, h) + draw:triangle(x, y, x+w, y, x, y+h) + draw:triangle(x, y+h, x+w, y+h, x+w, y) +end + +function draw:sprite(tex, x, y, w, h, u1, v1, u2, v2) + if self.loopCount > 10000 then self:kick() end + if self.buf.size - self.buf.head < 80 then self:kick() end + if self.state ~= DRAW_SPRITE or self.currentTexPtr ~= tex.basePtr then + if self.state ~= DRAW_NONE then self:kick() end + local pb = math.floor(tex.basePtr/64) + local pw = math.floor(tex.width/64) + GIF.tag(self.buf, GIF.PACKED, 4, false, {0xe}) + GIF.texA(self.buf, 0x80, 0x80) + GIF.tex1(self.buf, true, 0, true, 0, 0) + self.buf:settex(0, pb, pw, tex.format, math.floor(log2(tex.width)), math.floor(log2(tex.height)), 0, 1, 0, 0, 0) + -- GIF.mipTbp1(self.buf, 0, pb, pw, pb, pw, pb, pw) + -- GIF.mipTbp2(self.buf, 0, pb, pw, pb, pw, pb, pw) + GIF.primAd(self.buf, P.PRIM.SPRITE, false, true, false) + --GIF.packedRGBAQ(self.buf, self.col.r, self.col.g, self.col.b, self.col.a) + self.tagLoopPtr = GIF.tag(self.buf, 0, 1, false, DRAW_FMT_SPRITE) + self.loopCount = 0 + self.state = DRAW_SPRITE + end + local ix = math.floor(x) + local iy = math.floor(y) + local ix2 = math.floor(x+w) + local iy2 = math.floor(y+h) + GIF.packedST(self.buf, u1, v1) + GIF.packedRGBAQ(self.buf, self.col.r, self.col.g, self.col.b, self.col.a) + GIF.packedXYZ2(self.buf, 0x8000 + (ix*16), 0x8000 + (iy*16), 0) + GIF.packedST(self.buf, u2, v2) + GIF.packedRGBAQ(self.buf, self.col.r, self.col.g, self.col.b, self.col.a) + GIF.packedXYZ2(self.buf, 0x8000 + (ix2*16), 0x8000 + (iy2*16), 0) + self.loopCount = self.loopCount + 1 +end + +function draw:triangle(x1, y1, x2, y2, x3, y3) + if self.loopCount > 10000 then self:kick() end + if self.buf.size - self.buf.head < 80 then self:kick() end + if self.state ~= DRAW_GEOM then + if self.state ~= DRAW_NONE then self:kick() end + GIF.tag(self.buf, 0, 1, false, {0xe}) + GIF.primAd(self.buf, P.PRIM.TRI, false, false, false) + self.tagLoopPtr = GIF.tag(self.buf, 0, 1, false, DRAW_FMT_GEOM) + self.loopCount = 0 + self.state = DRAW_GEOM + end + GIF.packedRGBAQ(self.buf, self.col.r, self.col.g, self.col.b, self.col.a) + GIF.packedXYZ2(self.buf, 0x8000 + (x1*16), 0x8000 + (y1*16), 0) + GIF.packedXYZ2(self.buf, 0x8000 + (x2*16), 0x8000 + (y2*16), 0) + GIF.packedXYZ2(self.buf, 0x8000 + (x3*16), 0x8000 + (y3*16), 0) + self.loopCount = self.loopCount + 1 + self.rawtri = self.rawtri + 1 +end + +function draw:kick() + local nloop = self.buf:read(self.tagLoopPtr) + if nloop - 0x8000 > 0 then + print("kick EOP") + self.buf:write(self.tagLoopPtr, 0x8000 + self.loopCount) + else + self.buf:write(self.tagLoopPtr, self.loopCount) + end + DMA.send(self.buf, DMA.GIF) + self:newBuffer() + self.kc = self.kc + 1 +end + +return draw + + diff --git a/script/gif.lua b/script/gif.lua new file mode 100644 index 0000000..39e6fb0 --- /dev/null +++ b/script/gif.lua @@ -0,0 +1,146 @@ +local P = require("ps2const") + +local gif = { + PACKED = 0x0, + REGLIST = 0x01 * 2^26, + IMAGE = math.floor(2^27), + BLOCKSIZE = 0x7FF, +} + +function gif.tag(b, flg, nloop, eop, regs) + local lpp = b.head + if #regs == 0 then return end + -- print("GIFTAG: pushing " .. string.format("0x%x", nloop)) + if eop then + b:pushint(nloop + 0x8000) + else + b:pushint(nloop) + end + local nreg = #regs + if nreg > 16 then error("invalid gif tag: nreg = " .. #regs) end + if nreg == 16 then nreg = 0 end + local w2 = (math.floor(nreg * 2^28) + flg) + --print("GIFTAG: pushing " .. string.format("0x%x", w2) .. " :: " .. w2) + --print("GIFTAG: flag = " .. flg) + b:pushint(w2) + local reg = 0 + local regc = 0 + local max = 1 + + -- write the registers + for i=1,#regs,1 do + reg = reg + regs[i] * 2^(4*regc) + regc = regc + 1 + if regc >=8 then + b:pushint(reg) + -- print("GIFTAG: pushing regword " .. string.format("0x%x", reg)) + regc = 0 + max = max - 1 + end + end + + -- pad out the rest + for i=max,0,-1 do + b:pushint(reg) + -- print("GIFTAG: pushing regword " .. string.format("0x%x", reg)) + reg = 0 + end + + return lpp +end + +function gif.setAd(b, reg, v1, v2) + b:pushint(v1) + b:pushint(v2) + b:pushint(reg) + b:pushint(0) +end + +function gif.bitBltBuf(b, dba, dbw, psm) + gif.setAd(b, P.REG.BITBLTBUF, 0, dba + (dbw*2^16) + (psm*2^24)) +end + +function gif.trxPos(b, sx, sy, dx, dy, dir) + gif.setAd(b, P.REG.TRXPOS, sx + (sy*2^16), dx + (dy*2^16) + (dir*2^27)) +end + +function gif.trxReg(b, w, h) + gif.setAd(b, P.REG.TRXREG, w, h) +end + +function gif.trxDir(b, dir) + gif.setAd(b, P.REG.TRXDIR, dir, 0) +end + +function gif.tex1(b, lcm, mxl, mtba, l, k) + local v1 = mxl * 4 + if lcm then v1 = v1 + 1 end + if mtba then v1 = v1 + 2^8 end + v1 = v1 + math.floor(l * (2^18)) + gif.setAd(b, P.REG.TEX1, v1, k) +end + +function gif.texA(b, a0, a1) + gif.setAd(b, P.REG.TEXA, a0, a1) +end + +function gif.tex2(b, v) + gif.setAd(b, P.REG.TEX2, v, 0) +end + +function gif.mipTbp1(b, ctx, p1, w1, p2, w2, p3, w3) + b:setMipTbp(p1, w1, p2, w2, p3, w3) + b:pushint(P.REG.MIPTBP1 + ctx) + b:pushint(0) +end + +function gif.mipTbp2(b, ctx, p1, w1, p2, w2, p3, w3) + b:setMipTbp(p1, w1, p2, w2, p3, w3) + b:pushint(P.REG.MIPTBP2 + ctx) + b:pushint(0) +end + +function gif.primAd(b, primType, shaded, textured, aa) + local bits = primType + if shaded then bits = bits + 0x8 end + if textured then bits = bits + 0x10 end + if aa then bits = bits + 0x80 end + gif.setAd(b, P.REG.PRIM, bits, 0) +end + +function gif.packedRGBAQ(bu, r, g, b, a) + bu:pushint(r) + bu:pushint(g) + bu:pushint(b) + bu:pushint(a) +end + +function gif.packedXYZ2(b, x, y, z) + b:pushint(x) + b:pushint(y) + b:pushint(z) + b:pushint(0) +end + +function gif.packedUV(b, u, v) + local vv = u + math.floor(v * 2^16) + print("u,v -> " .. vv) + b:pushint(vv) + b:pushint(0) + b:pushint(0) + b:pushint(0) +end + +function gif.packedST(b, s, t) + b:pushfloat(s) + b:pushfloat(t) + b:pushfloat(1.0) + b:pushint(0) +end + +function gif.texflush(b) + gif.tag(b, gif.PACKED, 1, true, {0xe}) + gif.setAd(b, P.REG.TEXFLUSH, 0, 0) +end + +return gif diff --git a/script/main.lua b/script/main.lua new file mode 100644 index 0000000..7d348e0 --- /dev/null +++ b/script/main.lua @@ -0,0 +1,2 @@ + +dofile("host:script/texture.lua") diff --git a/script/min.lua b/script/min.lua new file mode 100644 index 0000000..d99de0f --- /dev/null +++ b/script/min.lua @@ -0,0 +1,30 @@ +local gif = dofile("host:script/gif.lua") + +local gs = nil + +function writeToBuffer(b, ints) + print("writing " .. #ints .. " ints") + for i=1,#ints,1 do + b:pushint(ints[i]) + end +end + +function PS2PROG.start() + DMA.init(DMA.GIF) + gs = GS.newState(640, 448, GS.INTERLACED, GS.NTSC) + local fb = gs:alloc(640, 448, GS.PSM24) + local zb = gs:alloc(640, 448, GS.PSMZ24) + gs:setBuffers(fb, zb) + gs:clearColour(0, 255, 0) +end + +function PS2PROG.frame() + local db = RM.getDrawBuffer(5000) + db:frameStart(gs) + -- writeToBuffer(db, {0x8001, 0x10000000, 0xe, 0x0, 0x1, 0x0, 0x61, 0x0}) + db:frameEnd(gs) + DMA.send(db, DMA.GIF) + db:free() +end + + diff --git a/script/pre.lua b/script/pre.lua new file mode 100644 index 0000000..b311323 --- /dev/null +++ b/script/pre.lua @@ -0,0 +1,9 @@ + +function writeToBuffer(b, ints) + for i=1,#ints,1 do + b:pushint(ints[i]) + end +end + + + diff --git a/script/ps2const.lua b/script/ps2const.lua new file mode 100644 index 0000000..b6aa291 --- /dev/null +++ b/script/ps2const.lua @@ -0,0 +1,27 @@ + +return { + PRIM = { + POINT=0x0, + LINE=0x1, + LINE_STRIP=0x2, + TRI=0x3, + TRI_FAN=0x4, + TRI_STRIP=0x5, + SPRITE=0x6, + }, + REG = { + PRIM=0x0, + BITBLTBUF=0x50, + TRXPOS=0x51, + TRXREG=0x52, + TRXDIR=0x53, + TEXFLUSH=0x3F, + TEX0 = 0x06, + TEX1 = 0x14, + TEXA = 0x3B, + MIPTBP1 = 0x34, + MIPTBP2 = 0x36, + }, + ENABLE=0x1, + DISABLE=0x0, +} diff --git a/script/ps2init.lua b/script/ps2init.lua new file mode 100644 index 0000000..b03c5ef --- /dev/null +++ b/script/ps2init.lua @@ -0,0 +1,16 @@ + +local libs = {} +local SEARCH_PATH = "host:script/" + +function require(name) + local l = libs[name] + if l ~= nil then + return l + else + l = dofile(SEARCH_PATH .. name .. ".lua") + libs[name] = l + return l + end +end + +return function() end diff --git a/script/rect.lua b/script/rect.lua new file mode 100644 index 0000000..48a621d --- /dev/null +++ b/script/rect.lua @@ -0,0 +1,32 @@ + +local GIF = require("gif") +local P = require("ps2const") +local D2D = require("draw2d") + +local gs = nil + +function PS2PROG.start() + DMA.init(DMA.GIF) + gs = GS.newState(640, 448, GS.INTERLACED, GS.NTSC) + local fb = gs:alloc(640, 448, GS.PSM24) + local zb = gs:alloc(640, 448, GS.PSMZ24) + gs:setBuffers(fb, zb) + gs:clearColour(0x2b, 0x2b, 0x2b) +end + +function PS2PROG.frame() + D2D:newBuffer() + local db = D2D:getBuffer() + db:frameStart(gs) + D2D:setColour(255,0,0,0x80) + D2D:rect(-200, -200, 200, 200) + db = D2D:getBuffer() + db:frameEnd(gs) + D2D:kick() + print("tris/frame = " .. D2D.rawtri .. ", KC=" .. D2D.kc) + D2D.rawtri = 0 + D2D.kc = 0 + --db:free() +end + + diff --git a/script/stress.lua b/script/stress.lua new file mode 100644 index 0000000..49bae36 --- /dev/null +++ b/script/stress.lua @@ -0,0 +1,59 @@ +--local GIF = dofile("host:script/gif.lua") +local GIF = require("gif") +local P = require("ps2const") +local D2D = require("draw2d") + + +local gs = nil + +local emt = { + x=0,y=0,w=1,h=1, +} +function emt:draw() + --D2D:rect(self.x, self.y, self.w, self.h) + D2D:triangle(self.x, self.y, self.x+self.w, self.y, self.x, self.y+self.h) +end + +function emt.new(x,y,w,h) + return setmetatable({x=x,y=y,w=w,h=h}, {__index = emt}) +end + +local scene = {} + +function PS2PROG.start() + DMA.init(DMA.GIF) + gs = GS.newState(640, 448, GS.INTERLACED, GS.NTSC) + local fb = gs:alloc(640, 448, GS.PSM24) + local zb = gs:alloc(640, 448, GS.PSMZ24) + gs:setBuffers(fb, zb) + gs:clearColour(0x2b, 0x2b, 0x2b) + + local dd = 100 + local dx = math.floor(640/dd) + local dy = math.floor(448/dd) + for x=-320,320,dx do + for y=-224,224,dy do + tt = emt.new(x,y,dx,dy) + table.insert(scene, tt) + end + end +end + +function PS2PROG.frame() + D2D:newBuffer() + local db = D2D:getBuffer() + db:frameStart(gs) + D2D:setColour(255,0,0,0x80) + for i,s in ipairs(scene) do + s:draw() + end + db = D2D:getBuffer() + db:frameEnd(gs) + D2D:kick() + print("tris/frame = " .. D2D.rawtri .. ", KC=" .. D2D.kc) + D2D.rawtri = 0 + D2D.kc = 0 + --db:free() +end + + diff --git a/script/texture.lua b/script/texture.lua new file mode 100644 index 0000000..17d7f6d --- /dev/null +++ b/script/texture.lua @@ -0,0 +1,121 @@ + +local GIF = require("gif") +local P = require("ps2const") +local D2D = require("draw2d") +local VRAM = require("vram") + +function makeTex(w, h, fill) + local t = {} + for x=0,w,1 do + for y=0,h,1 do + t[y*w + x] = fill + end + end + return t +end + + +local gs = nil +--local tex = makeTex(64, 64, 0x800000ff) +local testTex = {} +local fnt = nil + + +-- CURRENT TEXTURE LOADER CANNOT BE USED MID-FRAME!!!!! +function loadTexture(fname, w, h) + print("LOAD TEX: " .. fname .. " @ PSM32") + local tt = { + basePtr = 0, + width = w, + height = h, + data = nil, + format = GS.PSM32 + } + + tt.data = TGA.load(fname, w, h) + + -- only works for power of 2 textures @ psm32!!!!! + local texVramSize = w*h*4 + tt.basePtr = VRAM.alloc(texVramSize, 256) + print("LOAD TEX: got texture VRAM addr = " .. tt.basePtr) + + -- ib = RM.tmpBuffer(1000) + ib = RM.getDrawBuffer(5000) + + GIF.tag(ib, GIF.PACKED, 4, false, {0xe}) + GIF.bitBltBuf(ib, math.floor(tt.basePtr/64), math.floor(tt.width/64), tt.format) + GIF.trxPos(ib,0,0,0,0,0) + GIF.trxReg(ib,tt.width,tt.height) + GIF.trxDir(ib, 0) + + -- ASSUMPTION about format! + local eeSize = tt.width*tt.height*4 + local qwc = math.floor(eeSize / 16) + if qwc % 16 ~= 0 then qwc = qwc + 1 end + local blocksize = math.floor(4496/16) + local packets = math.floor(qwc / blocksize) + local remain = qwc % blocksize + print("LOAD TEX: transmitting in " .. packets .. " packets with " .. remain .. " left") + + local tb = 0 + while packets > 0 do + GIF.tag(ib, GIF.IMAGE, blocksize, false, {0}) + print("LOAD TEX: copy from TT " .. tb*blocksize*16 .. " to IB " .. ib.head .. " -- " .. blocksize*16) + tt.data:copy(ib, ib.head, tb*blocksize*16, blocksize*16) + ib.head = ib.head + blocksize*16 + DMA.send(ib, DMA.GIF) + ib = RM.getDrawBuffer(5000) + packets = packets - 1 + tb = tb + 1 + end + + if remain > 0 then + local base = tb*blocksize*16 + GIF.tag(ib, GIF.IMAGE, remain, false, {1}) + print("copy from TT " .. base .. " to IB " .. ib.head .. " -- " .. remain*16) + tt.data:copy(ib, ib.head, base, remain*16) + ib.head = ib.head + remain*16 + end + + GIF.texflush(ib) + DMA.send(ib, DMA.GIF) + print("LOAD TEX: DMA send") + + return tt +end + +function PS2PROG.start() + testTex = loadTexture("host:test.tga", 64, 64) + fnt = loadTexture("host:bigfont.tga", 256, 64) + DMA.init(DMA.GIF) + gs = GS.newState(640, 448, GS.INTERLACED, GS.NTSC) + local fb = VRAM.buffer(640, 440, GS.PSM24, 256) + local zb = VRAM.buffer(640, 440, GS.PSMZ24, 256) + print("setting new buffers") + gs:setBuffers(fb, zb) + gs:clearColour(0x2b, 0x2b, 0x2b) + +end + +xx = -200 +local dt = 1/60 +function PS2PROG.frame() + D2D:newBuffer() + local db = D2D:getBuffer() + db:frameStart(gs) + D2D:setColour(0x80,0x80,0x80,0x80) + D2D:sprite(testTex, xx, -200, 200, 200, 0, 0, 1, 1) + D2D:sprite(fnt, 50, 100, 256, 64, 0, 0, 1, 1) + db = D2D:getBuffer() + db:frameEnd(gs) + D2D:kick() + print("tris/frame = " .. D2D.rawtri .. ", KC=" .. D2D.kc) + D2D.rawtri = 0 + D2D.kc = 0 + + if PAD.held(PAD.LEFT) then xx = xx - 50*dt end + if PAD.held(PAD.RIGHT) then xx = xx + 50*dt end + --db:free() +end + + diff --git a/script/vram.lua b/script/vram.lua new file mode 100644 index 0000000..8594d0a --- /dev/null +++ b/script/vram.lua @@ -0,0 +1,45 @@ + +local vram = {} +local basePtr = 0 + +function vpa(v, a) + return v + a - (v%a) +end + +function vram.alloc(b, align) + local out = basePtr + out = out + align - (out%align) + basePtr = out + b + print("vram alloc: " .. out .. " base -> " .. basePtr) + return out +end + +function vram.size(w, h, psm, align) + if w%align ~= 0 then + w = vpa(w, 64) + end + local size = w*h*4 + if psm == GS.PSM16 or psm == GS.PSM16S or psm == GS.PSMZ16 or psm == GS.PSMZ16S then + math.floor(width*height*0.5) + elseif psm == GS.PSM8 then size = math.floor(width*height*2^-2) + elseif psm == GS.PSM4 then size = math.floor(width*height*2^-3) + end + + return vpa(size, align) +end + +function vram.buffer(w, h, psm, align) + local sz = vram.size(w, h, psm, align) + return { + address = vram.alloc(sz, align), + width = w, + height = h, + format = psm, + } +end + +function vram.textureSize(w,h,psm) + error("not implemented") +end + +return vram diff --git a/src/Makefile b/src/Makefile index 0aab0d6..2d82dda 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,12 +1,15 @@ PS2SDK=/usr/local/ps2dev/ps2sdk EE_BIN=test.elf -EE_OBJS=main.o gs.o mesh.o draw.o math.o pad.o -EE_LIBS=-ldma -lgraph -ldraw -lkernel -ldebug -lmath3d -lm -lpad -EE_CFLAGS += -Wall --std=c99 -EE_LDFLAGS = -L$(PSDSDK)/ee/common/lib -L$(PS2SDK)/ee/lib +#EE_OBJS=main.o gs.o mesh.o draw.o math.o pad.o drawstate.o script.o luadrawstate.o +EE_OBJS=main.o gslua.o dmalua.o bufferlua.o tga.o padlua.o +EE_LIBS=-ldma -lgraph -ldraw -lkernel -ldebug -lmath3d -lm -lpad -llua +EE_CFLAGS+=-Wall --std=c99 -Wno-sign-compare -fno-strict-aliasing -fno-exceptions -DLUA_USE_PS2 -ifeq ($(PLATFORM), ps2) +EE_INCS+=-I$(PS2SDK)/ports/include +EE_LDFLAGS=-L$(PSDSDK)/ee/common/lib -L$(PS2SDK)/ee/lib -L$(PS2SDK)/ports/lib + +ifeq ($(platform), PS2) include $(PS2SDK)/samples/Makefile.eeglobal include $(PS2SDK)/samples/Makefile.pref endif @@ -16,3 +19,4 @@ clean: rm -rf $(EE_BIN) $(EE_OBJS) + diff --git a/src/bufferlua.c b/src/bufferlua.c new file mode 100644 index 0000000..60f8ab5 --- /dev/null +++ b/src/bufferlua.c @@ -0,0 +1,331 @@ +#include +#include + +#include +#include + +#include +#include + +#include "log.h" +#include "script.h" + +static int drawlua_new_drawbuffer(lua_State *l); + +static const unsigned int DRAW_BUFFER_MAX_SIZE = 5 * 1024; +char *static_draw_buffer; + +static int buffer_pushint(lua_State *l) { + int value = lua_tointeger(l, 2); + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + int *ptr = (int *)lua_touserdata(l, -1); + lua_pushstring(l, "head"); + lua_gettable(l, 1); + int head = lua_tointeger(l, -1); + // TODO(Tom Marks): check size + // ASSUME 4byte int + if (head % 4 != 0) { + // TODO(Tom Marks): manually bitmask etc + logerr("cannot write int to buffer, head%%4 != 0 (%d|%d)", head, head % 4); + return 0; + } + // info("db write int %d @ %d", value, head); + ptr[head / 4] = value; + // info("db head -> %d", head+4); + lua_pushinteger(l, head + 4); + lua_setfield(l, 1, "head"); + return 0; +} + +static int buffer_pushfloat(lua_State *l) { + float value = (float)lua_tonumber(l, 2); + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + float *ptr = (float *)lua_touserdata(l, -1); + lua_pushstring(l, "head"); + lua_gettable(l, 1); + int head = lua_tointeger(l, -1); + // TODO(Tom Marks): check size + // ASSUME 4byte int + if (head % 4 != 0) { + // TODO(Tom Marks): manually bitmask etc + logerr("cannot write int to buffer, head%%4 != 0 (%d|%d)", head, head % 4); + return 0; + } + // info("db write int %d @ %d", value, head); + ptr[head / 4] = value; + // info("db head -> %d", head+4); + lua_pushinteger(l, head + 4); + lua_setfield(l, 1, "head"); + return 0; +} + +static int buffer_settex(lua_State *l) { + int reg = lua_tointeger(l, 2); + int tbp = lua_tointeger(l, 3); + int tbw = lua_tointeger(l, 4); + int psm = lua_tointeger(l, 5); + int tw = lua_tointeger(l, 6); + int th = lua_tointeger(l, 7); + int tcc = lua_tointeger(l, 8); + int tfx = lua_tointeger(l, 9); + + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + int *ptr = (int *)lua_touserdata(l, -1); + lua_pushstring(l, "head"); + lua_gettable(l, 1); + int head = lua_tointeger(l, -1); + // TODO(Tom Marks): check size + // ASSUME 4byte int + if (head % 4 != 0) { + // TODO(Tom Marks): manually bitmask etc + logerr("cannot write int to buffer, head%%4 != 0 (%d|%d)", head, head % 4); + return 0; + } + + int *base = ptr + (head / 4); + + int v1 = tbp | (tbw << 14) | (psm << 20) | (tw << 26) | ((th & 0x3) << 30); + // TODO(Tom Marks): 0x5??? i must mean 0x4 + int v2 = ((th & 0x5) >> 2) | (tcc << 1) | (tfx << 2); + int v3 = 0x6 + reg; + int v4 = 0; + *(base) = v1; + *(base + 1) = v2; + *(base + 2) = v3; + *(base + 3) = v4; + + // info("write tex0 :: %08x %08x %08x %08x", v1, v2, v3, v4); + // info("head -> %d", head+16); + + lua_pushinteger(l, head + 16); + lua_setfield(l, 1, "head"); + + // info("backtrack tex0 :: %08x %08x %08x %08x", base[0], base[1], base[2], + // base[3]); + return 0; +} + +static int buffer_pushmiptbp(lua_State *l) { + int p1 = lua_tointeger(l, 2); + int w1 = lua_tointeger(l, 3); + int p2 = lua_tointeger(l, 4); + int w2 = lua_tointeger(l, 5); + int p3 = lua_tointeger(l, 6); + int w3 = lua_tointeger(l, 7); + + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + int *ptr = (int *)lua_touserdata(l, -1); + lua_pushstring(l, "head"); + lua_gettable(l, 1); + int head = lua_tointeger(l, -1); + + if (head % 4 != 0) { + logerr("buffer head must be =0%%4, got %d", head % 4); + lua_pushstring(l, "buffer write failed"); + lua_error(l); + return 1; + } + + int v1 = p1 | (w1 << 14) | (p2 << 20); + int overflow = (p2 & 0x1000) >> 12; + int v2 = overflow | (w2 << 2) | (p3 << 8) | (w3 << 22); + + (ptr + head)[0] = v1; + (ptr + head)[1] = v2; + + lua_pushinteger(l, head + 8); + lua_setfield(l, 1, "head"); + return 0; +} + +static int buffer_copy(lua_State *l) { + // arg 1 = buffer from + // arg 2 = buffer TO + // arg 3 = buffer TO offset + // arg 4 = buffer FROM offset + // arg 5 = n bytes + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + char *ptr_from = lua_touserdata(l, -1); + lua_pushstring(l, "ptr"); + lua_gettable(l, 2); + char *ptr_to = lua_touserdata(l, -1); + + int to_offset = lua_tointeger(l, 3); + int from_offset = lua_tointeger(l, 4); + int n = lua_tointeger(l, 5); + + memcpy(ptr_to + to_offset, ptr_from + from_offset, n); + + return 0; +} + +static int buffer_read(lua_State *l) { + int index = lua_tointeger(l, 2); + if (index % 4 != 0) { + lua_pushstring(l, "invalid read index, not ==0 %%4"); + lua_error(l); + return 1; + } + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + int *ptr = (int *)lua_touserdata(l, -1); + int res = ptr[index / 4]; + lua_pushinteger(l, res); + return 1; +} + +static int buffer_write(lua_State *l) { + int index = lua_tointeger(l, 2); + if (index % 4 != 0) { + lua_pushstring(l, "invalid read index, not ==0 %%4"); + lua_error(l); + return 1; + } + int value = lua_tointeger(l, 3); + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + int *ptr = (int *)lua_touserdata(l, -1); + ptr[index / 4] = value; + return 0; +} + +int drawlua_init(lua_State *l) { + luaL_newmetatable(l, "ps2.buffer"); + lua_createtable(l, 0, 5); + + lua_pushcfunction(l, buffer_pushint); + lua_setfield(l, -2, "pushint"); + + lua_pushcfunction(l, buffer_pushfloat); + lua_setfield(l, -2, "pushfloat"); + + lua_pushcfunction(l, buffer_settex); + lua_setfield(l, -2, "settex"); + + lua_pushcfunction(l, buffer_pushmiptbp); + lua_setfield(l, -2, "setMipTbp"); + + lua_pushcfunction(l, buffer_copy); + lua_setfield(l, -2, "copy"); + + lua_pushcfunction(l, buffer_read); + lua_setfield(l, -2, "read"); + lua_pushcfunction(l, buffer_write); + lua_setfield(l, -2, "write"); + lua_setfield(l, -2, "__index"); + lua_pop(l, 1); + + lua_createtable(l, 0, 8); + lua_pushcfunction(l, drawlua_new_drawbuffer); + lua_setfield(l, -2, "getDrawBuffer"); + lua_setglobal(l, "RM"); + + info("allocating static draw buffer"); + static_draw_buffer = malloc(DRAW_BUFFER_MAX_SIZE); + + return 0; +} + +static int drawlua_start_frame(lua_State *l) { + // drawbuffer is arg #1 + lua_pushstring(l, "head"); + lua_gettable(l, 1); + int head = lua_tointeger(l, -1); + /* + lua_pushstring(l, "size"); + lua_gettable(l, 1); + int size = lua_tointeger(l, -1); + */ + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + char *ptr = (char *)lua_touserdata(l, -1); + + // gs is arg #2 + lua_pushstring(l, "state"); + lua_gettable(l, 2); + struct gs_state *st = (struct gs_state *)lua_touserdata(l, -1); + lua_pushstring(l, "width"); + lua_gettable(l, 2); + int width = lua_tointeger(l, -1); + lua_pushstring(l, "height"); + lua_gettable(l, 2); + int height = lua_tointeger(l, -1); + + float halfw = st->fb.width / 2.f; + float halfh = st->fb.height / 2.f; + + // info("clear screen :: (%d, %d, %d)", st->clear_r, st->clear_g, + // st->clear_b); + + qword_t *q = (qword_t *)(ptr + head); + q = draw_disable_tests(q, 0, &st->zb); + q = draw_clear(q, 0, 2048.0f - halfw, 2048.0f - halfh, width, height, + st->clear_r, st->clear_g, st->clear_b); + // q = draw_enable_tests(q, 0, &st->zb); + + head = (char *)q - ptr; + // info("db head -> %d", head); + lua_pushinteger(l, head); + lua_setfield(l, 1, "head"); + return 0; +} + +static int drawlua_end_frame(lua_State *l) { + // drawbuffer is arg #1 + lua_pushstring(l, "head"); + lua_gettable(l, 1); + int head = lua_tointeger(l, -1); + /* + lua_pushstring("size"); + lua_gettable(l, 1); + int size = lua_tointeger(l, -1); + */ + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + char *ptr = (char *)lua_touserdata(l, -1); + + qword_t *q = (qword_t *)(ptr + head); + q = draw_finish(q); + + head = (char *)q - ptr; + // info("db head -> %d", head); + lua_pushinteger(l, head); + lua_setfield(l, 1, "head"); + return 0; +} + +static int drawbuffer_free(lua_State *l) { return 0; } + +// TODO(Tom Marks): document this can only be called ONCE +static int drawlua_new_drawbuffer(lua_State *l) { + int size = lua_tointeger(l, 1); + if (size >= DRAW_BUFFER_MAX_SIZE) { + logerr("invalid drawbuffer size: %d must be smaller than %d", size, + DRAW_BUFFER_MAX_SIZE); + lua_pushstring(l, "drawbuffer size is too big"); + lua_error(l); + return 0; + } + lua_createtable(l, 0, 5); + lua_pushinteger(l, size); + lua_setfield(l, -2, "size"); + lua_pushinteger(l, 0); + lua_setfield(l, -2, "head"); + char *buf = static_draw_buffer; + lua_pushlightuserdata(l, buf); + lua_setfield(l, -2, "ptr"); + lua_pushcfunction(l, drawlua_start_frame); + lua_setfield(l, -2, "frameStart"); + lua_pushcfunction(l, drawlua_end_frame); + lua_setfield(l, -2, "frameEnd"); + lua_pushcfunction(l, drawbuffer_free); + lua_setfield(l, -2, "free"); + luaL_getmetatable(l, "ps2.buffer"); + lua_setmetatable(l, -2); + return 1; +} diff --git a/src/dmalua.c b/src/dmalua.c new file mode 100644 index 0000000..0d216d6 --- /dev/null +++ b/src/dmalua.c @@ -0,0 +1,71 @@ +#include + +#include +#include +#include + +#include "log.h" + +static int dma_init(lua_State *l) { + int channel = lua_tointeger(l, 1); + info("doing dma init, channel = %d", channel); + dma_channel_initialize(channel, 0, 0); + dma_channel_fast_waits(channel); + return 0; +} + +int print_buffer(qword_t *b, int len) { + info("-- buffer\n"); + for (int i = 0; i < len; i++) { + printf("%016llx %016llx\n", b->dw[0], b->dw[1]); + b++; + } + info("-- /buffer\n"); + return 0; +} + +static int dma_send_buffer(lua_State *l) { + // buffer is arg 1 + lua_pushstring(l, "ptr"); + lua_gettable(l, 1); + void *ptr = lua_touserdata(l, -1); + lua_pushstring(l, "head"); + lua_gettable(l, 1); + int head = lua_tointeger(l, -1); + + // channel is arg 2 + int channel = lua_tointeger(l, 2); + + // print buffer for debugging + print_buffer(ptr, head / 16); + + // info("DMA send :: sending %d qwords on channel %d", head/16, channel); + dma_channel_send_normal(channel, ptr, head / 16, 0, 0); + return 0; +} + +static int dma_wait(lua_State *l) { + dma_wait_fast(); + + return 0; +} + +int dma_lua_init(lua_State *l) { + lua_createtable(l, 0, 5); + lua_pushcfunction(l, dma_wait); + lua_setfield(l, -2, "waitFast"); + lua_pushcfunction(l, dma_send_buffer); + lua_setfield(l, -2, "send"); + lua_pushcfunction(l, dma_init); + lua_setfield(l, -2, "init"); + + lua_pushinteger(l, DMA_CHANNEL_GIF); + lua_setfield(l, -2, "GIF"); + lua_pushinteger(l, DMA_CHANNEL_VIF0); + lua_setfield(l, -2, "VIF0"); + lua_pushinteger(l, DMA_CHANNEL_VIF1); + lua_setfield(l, -2, "VIF1"); + + lua_setglobal(l, "DMA"); + return 0; +} diff --git a/src/draw.c b/src/draw.c deleted file mode 100644 index 01c18c6..0000000 --- a/src/draw.c +++ /dev/null @@ -1,131 +0,0 @@ - -#include -#include - -#include - -#include "log.h" -#include "mesh.h" -#include "ps2draw.h" -#include "ps2math.h" - -#define ZMAX (1024 * 1024) - -static int cc = 0; - -void log_matrix(MATRIX m) { - printf("Matrix = \n"); - printf("%.2f %.2f %.2f %.2f\n", m[0], m[4], m[8], m[12]); - printf("%.2f %.2f %.2f %.2f\n", m[1], m[5], m[9], m[13]); - printf("%.2f %.2f %.2f %.2f\n", m[2], m[6], m[10], m[14]); - printf("%.2f %.2f %.2f %.2f\n", m[3], m[7], m[11], m[15]); -} - -int mesh_is_visible(struct model_instance *inst, struct render_state *d) { - VECTOR v; - vector_sub(v, d->camera_pos, inst->translate); - float dot = v[0] * d->fwd[0] + v[1] * d->fwd[1] + v[2] * d->fwd[2]; - return (dot > 0); -} - -void mesh_transform(char *b, struct model_instance *inst, - struct render_state *d) { - MATRIX tmp; - MATRIX model; - matrix_unit(model); - create_model_matrix(model, inst->translate, inst->scale, inst->rotate); - matrix_unit(tmp); - - matrix_multiply(tmp, tmp, model); - matrix_multiply(tmp, tmp, d->v); - matrix_multiply(tmp, tmp, d->p); - - if (cc == 0) { - info("PROJECTION == "); - log_matrix(d->p); - } - - if (cc % 200 == 0) { - info("###### Matrix info ######"); - info("rotate=%f", d->camera_rotate_y); - info(" view="); - log_matrix(d->v); - info(" mvp="); - log_matrix(tmp); - } - int stride = inst->m->vertex_size * 16; - float d_avg = 0; - for (int i = 0; i < inst->m->vertex_count; i++) { - // get address of current vertex data - float *pos = - (float *)(b + (stride * i) + (inst->m->vertex_position_offset * 16)); - float *v = pos; - pos[3] = 1.f; - - vector_apply(v, v, tmp); - pos[0] = pos[0] / pos[3]; - pos[1] = pos[1] / pos[3]; - pos[2] = pos[2]; - d_avg += pos[2]; - - pos[0] = (pos[0] * 200); - pos[1] = (pos[1] * 200); - - *((uint32_t *)pos) = ftoi4(pos[0] + d->offset_x); - *((uint32_t *)(pos + 1)) = ftoi4(pos[1] + d->offset_y); - uint32_t zv = (uint32_t)(ZMAX * (pos[2] / 100.f)); - *((uint32_t *)(pos + 2)) = zv; - - uint32_t *col = - (uint32_t *)(b + (stride * i) + (inst->m->vertex_colour_offset * 16)); - col[1] = 0x0f; - col[2] = 0x0f; - col[0] = (int)(((zv) / (ZMAX * 1.0f)) * 255.0f); - col[3] = 0x80; - /* - *((uint32_t*)pos) = (short)((pos[0]+1.0f)*d->offset_x); - *((uint32_t*)(pos+1)) = (short)((pos[1]+1.0f)*d->offset_y); - *((uint32_t*)(pos+2)) = (unsigned int)((pos[2]+1.0f)*20); - */ - - pos[3] = 0; - } - if (cc % 100 == 0) { - info("avg depth = %f", d_avg / (1.0f * inst->m->vertex_count)); - } - cc++; -} - -void create_model_matrix(MATRIX tgt, VECTOR translate, VECTOR scale, - VECTOR rotate) { - matrix_unit(tgt); - matrix_rotate(tgt, tgt, rotate); - matrix_scale(tgt, tgt, scale); - matrix_translate(tgt, tgt, translate); -} - -void update_draw_matrix(struct render_state *d) { - d->up[0] = 0; - d->up[1] = 1.0f; - d->up[2] = 0; - d->up[3] = 0; - - d->fwd[0] = 0; - d->fwd[1] = 0; - d->fwd[2] = -1.f; - d->fwd[3] = 1.f; - vector_rotate_y(d->fwd, d->camera_rotate_y); - - d->camera_tgt[0] = d->camera_pos[0] + d->fwd[0]; - d->camera_tgt[1] = d->camera_pos[1] + d->fwd[1]; - d->camera_tgt[2] = d->camera_pos[2] + d->fwd[2]; - /* - d->camera_tgt[0] = 0; - d->camera_tgt[1] = 0; - d->camera_tgt[2] = 0; - */ - d->camera_tgt[3] = 1; - - matrix_proj(d->p, 1.2f, 0.7f, .1f, 100.f); - matrix_lookat(d->v, d->camera_pos, d->camera_tgt, d->up); -} diff --git a/src/gs.c b/src/gs.c deleted file mode 100644 index 454a5b2..0000000 --- a/src/gs.c +++ /dev/null @@ -1,57 +0,0 @@ - -#include "gs.h" - -#include - -#include -#include - -#include -#include - -#include -#include - -#define GS_OFFSET_X 2048 -#define GS_OFFSET_Y 2048 - -#define GS_CMD_BUFFER_LEN (40 * 16) -static qword_t *gs_cmd_buffer; - -int gs_init(struct draw_state *ds, int psm, int psmz) { - if (!gs_cmd_buffer) { - gs_cmd_buffer = malloc(GS_CMD_BUFFER_LEN); - } - - ds->fb.address = - graph_vram_allocate(ds->width, ds->height, psm, GRAPH_ALIGN_PAGE); - ds->fb.width = ds->width; - ds->fb.height = ds->height; - ds->fb.psm = psm; - ds->fb.mask = 0; - - ds->zb.address = - graph_vram_allocate(ds->width, ds->height, psmz, GRAPH_ALIGN_PAGE); - ds->zb.enable = 1; - ds->zb.method = ZTEST_METHOD_GREATER; - ds->zb.zsm = psmz; - ds->zb.mask = 0; - - graph_set_mode(ds->gmode, ds->vmode, GRAPH_MODE_FIELD, GRAPH_DISABLE); - graph_set_screen(0, 0, ds->width, ds->height); - graph_set_bgcolor(0, 0, 0); - graph_set_framebuffer_filtered(ds->fb.address, ds->width, psm, 0, 0); - graph_enable_output(); - - qword_t *q = gs_cmd_buffer; - memset(gs_cmd_buffer, 0, GS_CMD_BUFFER_LEN); - q = draw_setup_environment(q, 0, &ds->fb, &ds->zb); - q = draw_primitive_xyoffset(q, 0, GS_OFFSET_X - (ds->width / 2), - GS_OFFSET_Y - (ds->height / 2)); - q = draw_finish(q); - dma_channel_send_normal(DMA_CHANNEL_GIF, gs_cmd_buffer, q - gs_cmd_buffer, 0, - 0); - draw_wait_finish(); - - return 0; -} diff --git a/src/gs.h b/src/gs.h deleted file mode 100644 index 26afd2e..0000000 --- a/src/gs.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef GS_H -#define GS_H - -#include -#include - -struct draw_state { - int width; - int height; - int vmode; - int gmode; - framebuffer_t fb; - zbuffer_t zb; -}; - -int gs_init(struct draw_state *ds, int psm, int psmz); - -#endif diff --git a/src/gslua.c b/src/gslua.c new file mode 100644 index 0000000..2026b67 --- /dev/null +++ b/src/gslua.c @@ -0,0 +1,183 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "log.h" +#include "script.h" + +static int gslua_clear_col(lua_State *l) { + lua_pushstring(l, "state"); + lua_gettable(l, 1); + struct gs_state *st = (struct gs_state *)lua_touserdata(l, -1); + lua_pop(l, 1); + if (!st) { + logerr("GS state was NULL"); + return 0; + } + int r = lua_tointeger(l, 2); + int g = lua_tointeger(l, 3); + int b = lua_tointeger(l, 4); + st->clear_r = r; + st->clear_g = g; + st->clear_b = b; + return 0; +} + +static int gslua_vram_alloc(lua_State *l) { + int width = lua_tointeger(l, 2); + int height = lua_tointeger(l, 3); + int format = lua_tointeger(l, 4); + int addr = graph_vram_allocate(width, height, format, GRAPH_ALIGN_PAGE); + lua_createtable(l, 0, 4); + lua_pushinteger(l, addr); + lua_setfield(l, -2, "address"); + lua_pushinteger(l, width); + lua_setfield(l, -2, "width"); + lua_pushinteger(l, height); + lua_setfield(l, -2, "height"); + lua_pushinteger(l, format); + lua_setfield(l, -2, "format"); + return 1; +} + +static int gslua_set_buffers(lua_State *l) { + // get fields from SELF argument (#1) + lua_pushstring(l, "state"); + lua_gettable(l, 1); + struct gs_state *st = (struct gs_state *)lua_touserdata(l, -1); + lua_pop(l, 1); + // get fields from FB argument (#2) + lua_pushstring(l, "width"); + lua_gettable(l, 2); + int fb_width = lua_tointeger(l, -1); + lua_pop(l, 1); + lua_pushstring(l, "height"); + lua_gettable(l, 2); + int fb_height = lua_tointeger(l, -1); + lua_pop(l, 1); + lua_pushstring(l, "address"); + lua_gettable(l, 2); + int fb_addr = lua_tointeger(l, -1); + lua_pop(l, 1); + lua_pushstring(l, "format"); + lua_gettable(l, 2); + int fb_fmt = lua_tointeger(l, -1); + lua_pop(l, 1); + // get fields from ZB argument (#3) + lua_pushstring(l, "address"); + lua_gettable(l, 3); + int zb_addr = lua_tointeger(l, -1); + lua_pushstring(l, "format"); + lua_gettable(l, 3); + int zb_fmt = lua_tointeger(l, -1); + lua_pop(l, 1); + + if (!st) { + // TODO(Tom Marks): error + } + + st->fb.address = fb_addr; + st->fb.width = fb_width; + st->fb.height = fb_height; + st->fb.psm = fb_fmt; + st->fb.mask = 0; + st->zb.address = zb_addr; + st->zb.zsm = zb_fmt; + // st->zb.method = ZTEST_METHOD_GREATER_EQUAL; + st->zb.method = ZTEST_METHOD_ALLPASS; + st->zb.mask = 0; + graph_set_framebuffer_filtered(st->fb.address, fb_width, fb_fmt, 0, 0); + graph_enable_output(); + + // init draw state + qword_t *head = malloc(20 * 16); + memset(head, 0, 20 * 16); + qword_t *q = head; + q = draw_setup_environment(q, 0, &st->fb, &st->zb); + q = draw_primitive_xyoffset(q, 0, 2048 - (st->fb.width / 2), + 2048 - (st->fb.height / 2)); + q = draw_finish(q); + dma_channel_send_normal(DMA_CHANNEL_GIF, head, q - head, 0, 0); + draw_wait_finish(); + free(head); + + return 0; +} + +static int gslua_new_state(lua_State *l) { + int width = lua_tointeger(l, 1); + int height = lua_tointeger(l, 2); + int interlace = lua_tointeger(l, 3); + int mode = lua_tointeger(l, 4); + // create table with GS state + lua_createtable(l, 0, 5); + lua_newuserdata(l, sizeof(struct gs_state)); + lua_setfield(l, -2, "state"); + lua_pushinteger(l, width); + lua_setfield(l, -2, "width"); + lua_pushinteger(l, height); + lua_setfield(l, -2, "height"); + lua_pushinteger(l, interlace); + lua_setfield(l, -2, "interlace"); + lua_pushinteger(l, mode); + lua_setfield(l, -2, "mode"); + + lua_pushcfunction(l, gslua_vram_alloc); + lua_setfield(l, -2, "alloc"); + lua_pushcfunction(l, gslua_set_buffers); + lua_setfield(l, -2, "setBuffers"); + lua_pushcfunction(l, gslua_clear_col); + lua_setfield(l, -2, "clearColour"); + // initialize GS with no output + graph_disable_output(); + graph_set_mode(interlace, mode, GRAPH_MODE_FIELD, GRAPH_DISABLE); + graph_set_screen(0, 0, width, height); + graph_set_bgcolor(0, 0, 0); + return 1; +} + +#define bind(n, b) \ + lua_pushinteger(l, b); \ + lua_setfield(l, -2, n) +int gs_lua_init(lua_State *l) { + lua_createtable(l, 0, 16); + lua_pushcfunction(l, gslua_new_state); + lua_setfield(l, -2, "newState"); + + bind("PSM4", GS_PSM_4); + bind("PSM4HL", GS_PSM_4HL); + bind("PSM4HH", GS_PSM_4HH); + bind("PSM8", GS_PSM_8); + bind("PSM8H", GS_PSM_8H); + bind("PSM16", GS_PSM_16); + bind("PSM16S", GS_PSM_16S); + bind("PSM24", GS_PSM_24); + bind("PSMPS24", GS_PSM_PS24); + bind("PSM32", GS_PSM_32); + + bind("PSMZ16", GS_PSMZ_16); + bind("PSMZ16S", GS_PSMZ_16S); + bind("PSMZ24", GS_PSMZ_24); + bind("PSMZ32", GS_PSMZ_32); + + bind("NONINTERLACED", 1); + bind("INTERLACED", 1); + + bind("AUTO", GRAPH_MODE_AUTO); + bind("NTSC", GRAPH_MODE_NTSC); + bind("PAL", GRAPH_MODE_PAL); + bind("HDTV_480P", GRAPH_MODE_HDTV_480P); + bind("HDTV_576P", GRAPH_MODE_HDTV_576P); + bind("HDTV_720P", GRAPH_MODE_HDTV_720P); + + // bind this table to global name GS, nothing left on stack + lua_setglobal(l, "GS"); + return 0; +} diff --git a/src/main.c b/src/main.c index 880f8df..d0c8435 100644 --- a/src/main.c +++ b/src/main.c @@ -1,171 +1,154 @@ -#include -#include -#include -#include -#include +#include +#include +#include #include -#include #include #include -#include -#include - -#include +#include -#include "gs.h" #include "log.h" -#include "mesh.h" + #include "pad.h" -#include "ps2draw.h" +#include "script.h" -#define OFFSET_X 2048 -#define OFFSET_Y 2048 +#define INIT_SCRIPT "host:script/ps2init.lua" -#define VID_W 640 -#define VID_H 448 +int lua_tga_init(lua_State *l); -#define TGT_FILE "host:cube.bin" +static int ps2luaprog_start_nil(lua_State *l) { + info("default start..."); + return 0; +} -#define fatalerror(st, msg, ...) \ - printf("FATAL: " msg "\n", ##__VA_ARGS__); \ - error_forever(st); \ - ((void)0) -void error_forever(struct draw_state *st); +static int ps2luaprog_frame_nil(lua_State *l) { return 0; } -int print_buffer(qword_t *b, int len) { - printf("-- buffer\n"); - for (int i = 0; i < len; i++) { - printf("%016llx %016llx\n", b->dw[0], b->dw[1]); - b++; - } - printf("-- /buffer\n"); +static int ps2lua_log2(lua_State *l) { + int n = lua_tointeger(l, 1); + float res = log2f(n); + lua_pushnumber(l, res); + return 1; +} + +int ps2luaprog_init(lua_State *l) { + lua_createtable(l, 0, 2); + lua_pushcfunction(l, ps2luaprog_start_nil); + lua_setfield(l, -2, "start"); + lua_pushcfunction(l, ps2luaprog_frame_nil); + lua_setfield(l, -2, "frame"); + lua_setglobal(l, "PS2PROG"); + lua_pushcfunction(l, ps2lua_log2); + lua_setglobal(l, "log2"); return 0; } -int main() { - printf("Hello\n"); - qword_t *buf = malloc(20000 * 16); - char *file_load_buffer = malloc(310 * 1024); - int file_load_buffer_len = 310 * 1024; +int ps2luaprog_onstart(lua_State *l) { + lua_getglobal(l, "PS2PROG"); + lua_pushstring(l, "start"); + lua_gettable(l, -2); + int type = lua_type(l, -1); + // info("start fn has type :: %s (%d)", lua_typename(l, type), type); + int rc = lua_pcall(l, 0, 0, 0); + if (rc) { + const char *err = lua_tostring(l, -1); + logerr("lua execution error (start event) -- %s", err); + } - struct draw_state st = {0}; - st.width = VID_W, st.height = VID_H, st.vmode = graph_get_region(), - st.gmode = GRAPH_MODE_INTERLACED, + return 0; +} - // init DMAC - dma_channel_initialize(DMA_CHANNEL_GIF, 0, 0); - dma_channel_fast_waits(DMA_CHANNEL_GIF); +int ps2luaprog_onframe(lua_State *l) { + lua_getglobal(l, "PS2PROG"); + lua_pushstring(l, "frame"); + lua_gettable(l, -2); + int type = lua_type(l, -1); + // info("frame fn has type :: %s (%d)", lua_typename(l, type), type); + // + int rc = lua_pcall(l, 0, 0, 0); + + if (rc) { + const char *err = lua_tostring(l, -1); + logerr("lua execution error (frame event) -- %s", err); + } - // initialize graphics mode - gs_init(&st, GS_PSM_32, GS_PSMZ_24); + return 0; +} - struct model m = {0}; - m.r = 0xff; - int bytes_read = load_file(TGT_FILE, file_load_buffer, file_load_buffer_len); - if (bytes_read <= 0) { - fatalerror(&st, "failed to load file %s", TGT_FILE); - } - if (bytes_read % 16 != 0) { - fatalerror(&st, "lengt of model file %s was not 0 %% 16", TGT_FILE); +int ps2luaprog_is_running(lua_State *l) { return 1; } + +static int runfile(lua_State *l, const char *fname) { + info("running lua file %s", fname); + int rc = luaL_loadfile(l, fname); + if (rc == LUA_ERRSYNTAX) { + logerr("failed to load %s: syntax error", fname); + const char *err = lua_tostring(l, -1); + logerr("err: %s", err); + return -1; + } else if (rc == LUA_ERRMEM) { + logerr("faild to allocate memory for %s", fname); + return -1; + } else if (rc == LUA_ERRFILE) { + logerr("could not open/read file %s", fname); + return -1; + } else if (rc) { + logerr("unknown error loading %s", fname); + return -1; } - if (!model_load(&m, file_load_buffer, bytes_read)) { - fatalerror(&st, "failed to process model"); + rc = lua_pcall(l, 0, 0, 0); + if (rc) { + const char *err = lua_tostring(l, -1); + logerr("lua execution error -- %s", err); + return -1; } - struct render_state r = {0}; + return 0; +} + +int main(int argc, char *argv[]) { + info("startup - argc = %d", argc); + for (int i = 0; i < argc; i++) { + info("arg %d) %s", i, argv[i]); + } + char *startup = "host:script/main.lua"; + if (argc > 1) { + info("setting entrypoint to %s", argv[1]); + startup = argv[1]; + } - r.camera_pos[0] = 0.0f; - r.camera_pos[2] = 1.0f; - r.camera_pos[3] = 1.0f; + struct lua_State *L; + L = luaL_newstate(); + if (!L) { + logerr("failed to start lua state"); + return -1; + } + luaL_openlibs(L); - r.clear_col[0] = 0xb1; - r.clear_col[1] = 0xce; - r.clear_col[2] = 0xcb; + ps2luaprog_init(L); + dma_lua_init(L); + gs_lua_init(L); + lua_tga_init(L); + pad_lua_init(L); - r.offset_x = OFFSET_X; - r.offset_y = OFFSET_Y; + // TODO(Tom Marks): better abstraction for drawlua_* + drawlua_init(L); - struct model_instance inst = {0}; - inst.m = &m; - inst.scale[0] = 1.f; - inst.scale[1] = 1.f; - inst.scale[2] = 1.f; - inst.scale[3] = 1.0f; - inst.translate[2] = 10.f; + info("finished lua state setup"); - pad_init(); + runfile(L, INIT_SCRIPT); + runfile(L, startup); - graph_wait_vsync(); - while (1) { + ps2luaprog_onstart(L); + while (ps2luaprog_is_running(L)) { pad_frame_start(); pad_poll(); - update_draw_matrix(&r); dma_wait_fast(); - qword_t *q = buf; - memset(buf, 0, 20000 * 16); - q = draw_disable_tests(q, 0, &st.zb); - q = draw_clear(q, 0, 2048.0f - 320, 2048.0f - 244, VID_W, VID_H, - r.clear_col[0], r.clear_col[1], r.clear_col[2]); - q = draw_enable_tests(q, 0, &st.zb); - if (mesh_is_visible(&inst, &r)) { - qword_t *model_verts_start = q; - memcpy(q, m.buffer, m.buffer_len); - // info("copied mesh buffer with len=%d", m.buffer_len); - mesh_transform((char *)(model_verts_start + MESH_HEADER_SIZE), &inst, &r); - q += (m.buffer_len / 16); - } - q = draw_finish(q); - dma_channel_send_normal(DMA_CHANNEL_GIF, buf, q - buf, 0, 0); - // print_buffer(buf, q-buf); - // info("draw from buffer with length %d", q-buf); - + info("ON FRAME"); + ps2luaprog_onframe(L); + info("WAIT DRAW"); draw_wait_finish(); + info("WAIT VSYNC"); graph_wait_vsync(); - -#if 0 - unsigned char joyx = joy_axis_value(AXIS_LEFT_X); - float dx = (joy_axis_value(AXIS_LEFT_X) - 128) / 128.0f; - if ( fabs(dx) < 0.2f ) { dx = 0; } - float dz = (joy_axis_value(AXIS_LEFT_Y) - 128) / 128.0f; - if ( fabs(dz) < 0.2f ) { dz = 0; } - int dy = button_held(DPAD_DOWN) - button_held(DPAD_UP); - - info("joy %f,%f", dx, dz); -#else - int dx = button_held(DPAD_RIGHT) - button_held(DPAD_LEFT); - int dz = button_held(DPAD_DOWN) - button_held(DPAD_UP); - int dy = button_held(BUTTON_L1) - button_held(BUTTON_L2); -#endif - - r.camera_pos[0] += 0.2f * dx; - r.camera_pos[2] += 0.2f * dz; - // r.camera_pos[1] += 0.1f * dy; - r.camera_rotate_y += 0.01f * dy; } + info("main loop ended"); } - -void error_forever(struct draw_state *st) { - qword_t *buf = malloc(1200); - while (1) { - dma_wait_fast(); - qword_t *q = buf; - memset(buf, 0, 1200); - q = draw_disable_tests(q, 0, &st->zb); - q = draw_clear(q, 0, 2048.0f - 320, 2048.0f - 244, VID_W, VID_H, 0xff, 0, - 0); - q = draw_finish(q); - dma_channel_send_normal(DMA_CHANNEL_GIF, buf, q - buf, 0, 0); - draw_wait_finish(); - graph_wait_vsync(); - sleep(2); - } -} - -/* - * - * xxxx xxxx xxxx . yyyy - * 0100 0000 0000 . 0000 - * -2 */ diff --git a/src/math.c b/src/math.c deleted file mode 100644 index 80d1920..0000000 --- a/src/math.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include - -#define SWAP(i, j) \ - do { \ - t = a[i]; \ - a[i] = a[j]; \ - a[j] = t; \ - } while (0) -void matrix_tsp(MATRIX a) { - float t; - SWAP(1, 4); - SWAP(2, 8); - SWAP(3, 12); - SWAP(6, 9); - SWAP(7, 13); - SWAP(11, 14); -} - -void vector_cross(VECTOR out, VECTOR a, VECTOR b) { - out[0] = a[1] * b[2] - a[2] * b[1]; - out[1] = a[2] * b[0] - a[0] * b[2]; - out[2] = a[0] * b[1] - a[1] * b[0]; -} - -void vector_sub(VECTOR out, VECTOR a, VECTOR b) { - out[0] = a[0] - b[0]; - out[1] = a[1] - b[1]; - out[2] = a[2] - b[2]; - // out[3] = a[3] - b[3]; -} - -void matrix_lookat(MATRIX out, VECTOR eye, VECTOR c, VECTOR up) { - VECTOR z, x, y, nd; - vector_sub(z, c, eye); - vector_normalize(z, z); - - vector_cross(x, up, z); - vector_normalize(x, x); - - vector_cross(y, z, x); - vector_normalize(y, y); - - matrix_unit(out); - - nd[0] = -1 * (x[0] * eye[0] + x[1] * eye[1] + x[2] * eye[2]); - nd[1] = -1 * (y[0] * eye[0] + y[1] * eye[1] + y[2] * eye[2]); - nd[2] = -1 * (z[0] * eye[0] + z[1] * eye[1] + z[2] * eye[2]); - - for (int i = 0; i < 3; i++) { - out[4 * i] = x[i]; - out[4 * i + 1] = y[i]; - out[4 * i + 2] = z[i]; - out[4 * i + 3] = nd[i]; - } - - matrix_tsp(out); -} - -void matrix_zero(MATRIX out) { - for (int i = 0; i < 16; i++) { - out[i] = 0; - } -} - -void matrix_proj(MATRIX out, float fov, float ar, float near, float far) { - matrix_zero(out); - float angle = 1.f / (tanf(fov * 0.5f)); - float fn = 1.f / (near - far); - out[0] = angle / ar; - out[5] = angle; - out[10] = -1 * far * fn; - out[14] = near * far * fn; - out[11] = 1.0f; -} - -void matrix_viewport(MATRIX out, float w, float h) { - matrix_unit(out); - out[0] = 320; - out[5] = 224; - out[3] = 320; - out[7] = 224; - matrix_tsp(out); -} - -void vector_rotate_y(VECTOR out, float r) { - out[0] = (out[0] * cos(r)) + (out[2] * sin(r)); - out[2] = (-1.f * out[0] * sin(r)) + (out[2] * cos(r)); -} diff --git a/src/mesh.c b/src/mesh.c deleted file mode 100644 index 33c2c29..0000000 --- a/src/mesh.c +++ /dev/null @@ -1,58 +0,0 @@ - -#include -#include -#include -#include -#include - -#include "log.h" -#include "mesh.h" - -#define myftoi4(x) ((x) << 4) - -int load_file(const char *fname, char *b, int b_len) { - FILE *f = fopen(fname, "rb"); - fseek(f, 0, SEEK_END); - int len = ftell(f); - fseek(f, 0, SEEK_SET); - if (len >= b_len) { - return 0; - } - int byte_read = fread(b, 1, len, f); - fclose(f); - return byte_read; -} - -#define MODEL_BUFFER_PRE (4 * 16) - -// b_len MUST be a multiple of 16 -int model_load(struct model *m, char *b, int b_len) { - if (!m || !b || b_len <= 0) { - return 0; - } - m->buffer = malloc(b_len + MODEL_BUFFER_PRE); - m->buffer_len = b_len + MODEL_BUFFER_PRE; - qword_t *q = m->buffer; - m->vertex_size = 2; - m->vertex_count = b_len / (16 * m->vertex_size); - m->vertex_position_offset = 1; - m->vertex_colour_offset = 0; - m->face_count = m->vertex_count / 3; - info("initializing model: verts=%d, faces=%d, bytes in buf=%d", - m->vertex_count, m->face_count, m->buffer_len); - - // Create giftag, set regs via A+D - q->dw[0] = 0x1000000000000001; - q->dw[1] = 0x000000000000000e; - q++; - // set PRIM = triangle - q->dw[0] = GS_SET_PRIM(GS_PRIM_TRIANGLE, 1, 0, 0, 0, 0, 0, 0, 0); - q->dw[1] = GS_REG_PRIM; - q++; - // start vertex data GIFTAG - q->dw[0] = 0x6000000000000000 | (m->face_count & 0x3fff); - q->dw[1] = 0x0000000000515151; - q++; - memcpy(q, b, b_len); - return 1; -} diff --git a/src/mesh.h b/src/mesh.h deleted file mode 100644 index d6fa7a6..0000000 --- a/src/mesh.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef MESH_H -#define MESH_H - -#include - -struct model { - qword_t *buffer; - char r; - char g; - char b; - int face_count; - int vertex_count; - int vertex_size; - int vertex_position_offset; - int vertex_colour_offset; - int buffer_len; -}; - -int load_file(const char *fname, char *b, int b_len); - -int model_load(struct model *m, char *b, int b_len); - -#endif diff --git a/src/pad.c b/src/pad.c deleted file mode 100644 index 8c280c3..0000000 --- a/src/pad.c +++ /dev/null @@ -1,95 +0,0 @@ - -#include -#include -#include - -#include "log.h" -#include "pad.h" - -#define pad_test(b, v) \ - do { \ - if ((c & b)) { \ - btn_held[v] = 1; \ - } \ - } while (0) - -static char pad_buffer[256]; -static struct padButtonStatus pad_read_space = {0}; - -static int btn_held[BTN_MAX]; - -static unsigned char joysticks[JOY_AXIS_COUNT]; - -static int prev_inputs; - -int button_held(int b) { return btn_held[b]; } - -unsigned char joy_axis_value(int a) { return joysticks[a]; } - -int pad_init() { - info("loading SIF modules for PAD"); - int rc = SifLoadModule(R_SIO2MAN, 0, 0); - if (!rc) { - logerr("failed to load SIF %s", R_SIO2MAN); - return 0; - } - rc = SifLoadModule(R_PADMAN, 0, 0); - if (!rc) { - logerr("failed to load SIF %s", R_PADMAN); - return 0; - } - padInit(0); - padPortOpen(0, 0, &pad_buffer); - // TODO(phy1um): check for dualshock controller - padSetMainMode(0, 0, 1, 3); - return 1; -} - -static int pad_wait(int port, int slot, int tries) { - int now; - int prev = -1; - now = padGetState(port, slot); - if (now == PAD_STATE_DISCONN) { - return -1; - } - while ((now != PAD_STATE_STABLE) && (now != PAD_STATE_FINDCTP1)) { - prev = now; - now = padGetState(port, slot); - tries--; - if (tries == 0) { - break; - } - } - return 0; -} - -void pad_poll() { - if (pad_wait(0, 0, 10) < 0) { - return; - } - - if (padRead(0, 0, &pad_read_space) != 0) { - int pad = 0xffff ^ pad_read_space.btns; - int c = pad ^ prev_inputs; - pad_test(PAD_LEFT, DPAD_LEFT); - pad_test(PAD_RIGHT, DPAD_RIGHT); - pad_test(PAD_UP, DPAD_UP); - pad_test(PAD_DOWN, DPAD_DOWN); - pad_test(PAD_CROSS, BUTTON_1); - pad_test(PAD_SQUARE, BUTTON_2); - pad_test(PAD_L1, BUTTON_L1); - pad_test(PAD_L2, BUTTON_L2); - pad_test(PAD_R1, BUTTON_R1); - pad_test(PAD_R2, BUTTON_R2); - joysticks[AXIS_LEFT_X] = pad_read_space.ljoy_h; - joysticks[AXIS_LEFT_Y] = pad_read_space.ljoy_v; - joysticks[AXIS_RIGHT_X] = pad_read_space.rjoy_h; - joysticks[AXIS_RIGHT_Y] = pad_read_space.rjoy_v; - } -} - -void pad_frame_start() { - for (int i = 0; i < BTN_MAX; i++) { - btn_held[i] = 0; - } -} diff --git a/src/pad.h b/src/pad.h index b9d3ab6..c1683d2 100644 --- a/src/pad.h +++ b/src/pad.h @@ -2,17 +2,21 @@ #ifndef PAD_H #define PAD_H -#define BUTTON_1 0 -#define BUTTON_2 1 -#define BUTTON_L1 2 -#define BUTTON_R1 3 -#define BUTTON_L2 4 -#define BUTTON_R2 5 -#define DPAD_DOWN 6 -#define DPAD_LEFT 7 -#define DPAD_RIGHT 8 -#define DPAD_UP 9 -#define BTN_MAX 10 +#include + +#define BUTTON_X 0 +#define BUTTON_SQUARE 1 +#define BUTTON_TRIANGLE 2 +#define BUTTON_CIRCLE 3 +#define BUTTON_L1 4 +#define BUTTON_R1 5 +#define BUTTON_L2 6 +#define BUTTON_R2 7 +#define DPAD_DOWN 8 +#define DPAD_LEFT 9 +#define DPAD_RIGHT 10 +#define DPAD_UP 11 +#define BTN_MAX 12 #define AXIS_LEFT_X 0 #define AXIS_LEFT_Y 1 @@ -32,4 +36,6 @@ int pad_init(); void pad_poll(); void pad_frame_start(); +int pad_lua_init(lua_State *l); + #endif diff --git a/src/padlua.c b/src/padlua.c new file mode 100644 index 0000000..ead16a1 --- /dev/null +++ b/src/padlua.c @@ -0,0 +1,142 @@ +#include + +#include +#include +#include + +#include + +#include "log.h" +#include "pad.h" + +#define pad_test(b, v) \ + do { \ + if ((c & b)) { \ + info("set button %d", v); \ + btn_held[v] = 1; \ + } \ + } while (0) + +char *pad_buffer; +struct padButtonStatus *pad_read_space; + +int *btn_held; + +unsigned char joysticks[JOY_AXIS_COUNT]; + +int prev_inputs; + +int button_held(int b) { return btn_held[b]; } + +unsigned char joy_axis_value(int a) { return joysticks[a]; } + +int pad_init() { + btn_held = memalign(128, 12 * sizeof(int)); + pad_buffer = memalign(256, 256); + if ((u32)pad_buffer & 0xf) { + info("pad buffer was not 16byte aligned: %x", (int)pad_buffer); + return -1; + } + pad_read_space = memalign(128, sizeof(struct padButtonStatus)); + + info("loading SIF modules for PAD"); + int rc = SifLoadModule(R_SIO2MAN, 0, 0); + if (!rc) { + logerr("failed to load SIF %s", R_SIO2MAN); + return 0; + } + rc = SifLoadModule(R_PADMAN, 0, 0); + if (!rc) { + logerr("failed to load SIF %s", R_PADMAN); + return 0; + } + padInit(0); + padPortOpen(0, 0, pad_buffer); + // TODO(phy1um): check for dualshock controller + padSetMainMode(0, 0, 1, 3); + return 1; +} + +static int pad_wait(int port, int slot, int tries) { + int now; + now = padGetState(port, slot); + if (now == PAD_STATE_DISCONN) { + return -1; + } + while ((now != PAD_STATE_STABLE) && (now != PAD_STATE_FINDCTP1)) { + now = padGetState(port, slot); + tries--; + if (tries == 0) { + break; + } + } + return 0; +} + +void pad_poll() { + if (pad_wait(0, 0, 10) < 0) { + return; + } + + if (padRead(0, 0, pad_read_space) != 0) { + int pad = 0xffff ^ pad_read_space->btns; + int c = pad ^ prev_inputs; + pad_test(PAD_LEFT, DPAD_LEFT); + pad_test(PAD_RIGHT, DPAD_RIGHT); + pad_test(PAD_UP, DPAD_UP); + pad_test(PAD_DOWN, DPAD_DOWN); + pad_test(PAD_CROSS, BUTTON_X); + pad_test(PAD_SQUARE, BUTTON_SQUARE); + pad_test(PAD_TRIANGLE, BUTTON_TRIANGLE); + pad_test(PAD_CIRCLE, BUTTON_CIRCLE); + pad_test(PAD_L1, BUTTON_L1); + pad_test(PAD_L2, BUTTON_L2); + pad_test(PAD_R1, BUTTON_R1); + pad_test(PAD_R2, BUTTON_R2); + /* + joysticks[AXIS_LEFT_X] = pad_read_space->ljoy_h; + joysticks[AXIS_LEFT_Y] = pad_read_space->ljoy_v; + joysticks[AXIS_RIGHT_X] = pad_read_space->rjoy_h; + joysticks[AXIS_RIGHT_Y] = pad_read_space->rjoy_v; + */ + } +} + +void pad_frame_start() { + for (int i = 0; i < BTN_MAX; i++) { + btn_held[i] = 0; + } +} + +static int pad_lua_button_held(lua_State *l) { + int button_id = lua_tointeger(l, 1); + // TODO(Tom Marks): bounds check + int v = btn_held[button_id]; + info("TEST BTN %d = %d", button_id, v); + lua_pushboolean(l, v); + return 1; +} + +#define bind_int(v, name) \ + lua_pushinteger(l, v); \ + lua_setfield(l, -2, name) +int pad_lua_init(lua_State *l) { + if (pad_init() == -1) { + lua_pushstring(l, "failed to init pad"); + lua_error(l); + return 1; + } + lua_createtable(l, 0, 5); + lua_pushcfunction(l, pad_lua_button_held); + lua_setfield(l, -2, "held"); + bind_int(BUTTON_X, "X"); + bind_int(BUTTON_SQUARE, "TRIANGLE"); + bind_int(BUTTON_TRIANGLE, "SQUARE"); + bind_int(BUTTON_CIRCLE, "CIRCLE"); + bind_int(DPAD_LEFT, "LEFT"); + bind_int(DPAD_RIGHT, "RIGHT"); + bind_int(DPAD_UP, "UP"); + bind_int(DPAD_DOWN, "DOWN"); + lua_setglobal(l, "PAD"); + return 0; +} diff --git a/src/ps2draw.h b/src/ps2draw.h index c4ee26d..a26b299 100644 --- a/src/ps2draw.h +++ b/src/ps2draw.h @@ -5,6 +5,8 @@ #define MESH_HEADER_SIZE 3 #define myftoi4(x) (((uint64_t)(x)) << 4) +#include + struct render_state { float offset_x; float offset_y; diff --git a/src/ps2math.h b/src/ps2math.h deleted file mode 100644 index bac9911..0000000 --- a/src/ps2math.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef PS2_MATH_H -#define PS2_MATH_H - -#include - -void matrix_lookat(MATRIX out, VECTOR eye, VECTOR c, VECTOR up); - -void matrix_viewport(MATRIX out, int w, int h); -void matrix_proj(MATRIX out, float fov, float ar, float near, float far); - -void matrix_tsp(MATRIX t); - -void vector_rotate_y(VECTOR out, float r); -void vector_sub(VECTOR out, VECTOR a, VECTOR b); - -#endif diff --git a/src/script.h b/src/script.h new file mode 100644 index 0000000..03f5f8a --- /dev/null +++ b/src/script.h @@ -0,0 +1,19 @@ + +#ifndef SRC_LUA_H +#define SRC_LUA_H + +#include + +struct gs_state { + framebuffer_t fb; + zbuffer_t zb; + unsigned char clear_r; + unsigned char clear_g; + unsigned char clear_b; +}; + +int gs_lua_init(lua_State *l); +int dma_lua_init(lua_State *l); +int drawlua_init(lua_State *l); + +#endif diff --git a/src/tga.c b/src/tga.c new file mode 100644 index 0000000..8db88fa --- /dev/null +++ b/src/tga.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#include +#include +#include + +#include "log.h" + +struct __attribute__((__packed__)) tga_header { + uint8_t idlen; + uint8_t colMapType; + uint8_t imgType; + + uint16_t firstColEntryIndex; + uint16_t colMapLength; + uint8_t colMapBps; + + uint16_t xorigin; + uint16_t yorigin; + uint16_t width; + uint16_t height; + uint8_t bps; + uint8_t descriptor; +}; + +char tmp_buffer[256 * 256 * 4]; +int load_tga_to_raw(const char *fname, void *buffer) { + info("loading TGA %s", fname); + FILE *f = fopen(fname, "rb"); + struct tga_header header = {0}; + size_t rc = fread(&header, 1, 18, f); + + info("reading ID data - %d bytes", header.idlen); + char idData[255]; + rc = fread(idData, 1, header.idlen, f); + + // bytes per pixel from bits per pixel + int bpp = header.bps / 8; + info("reading image data - %d bytes", header.width * header.height * bpp); + rc = fread(tmp_buffer, bpp, header.width * header.height * bpp, f); + char *to = (char *)buffer; + for (int i = 0; i < header.width; i++) { + for (int j = 0; j < header.height; j++) { + to[(j * header.width + i) * 4 + 3] = + tmp_buffer[(j * header.width + i) * 4 + 3]; + to[(j * header.width + i) * 4 + 2] = + tmp_buffer[(j * header.width + i) * 4 + 0]; + to[(j * header.width + i) * 4 + 1] = + tmp_buffer[(j * header.width + i) * 4 + 1]; + to[(j * header.width + i) * 4 + 0] = + tmp_buffer[(j * header.width + i) * 4 + 2]; + } + } + fclose(f); + return 1; +} + +int load_tga_lua(lua_State *l) { + const char *fname = lua_tostring(l, 1); + int width = lua_tointeger(l, 2); + int height = lua_tointeger(l, 3); + uint32_t *b = malloc(width * height * 4); + load_tga_to_raw(fname, b); + + lua_createtable(l, 0, 5); + lua_pushinteger(l, 0); + lua_setfield(l, -2, "head"); + lua_pushinteger(l, width * height * 4); + lua_setfield(l, -2, "size"); + lua_pushlightuserdata(l, b); + lua_setfield(l, -2, "ptr"); + + luaL_getmetatable(l, "ps2.buffer"); + lua_setmetatable(l, -2); + + // return new buffer + return 1; +} + +int lua_tga_init(lua_State *l) { + lua_createtable(l, 0, 1); + lua_pushcfunction(l, load_tga_lua); + lua_setfield(l, -2, "load"); + lua_setglobal(l, "TGA"); + return 0; +}