Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local term = term
- local baseWidth, baseHeight = term.getSize()
- local width = baseWidth * 2
- local height = baseHeight * 3
- local centerX, centerY = width / 2, height / 2 - 12
- local scale = math.min(width, height) * 0.38
- local modFilename = "music.mod"
- if not fs.exists(modFilename) then
- term.clear()
- term.setCursorPos(1,1)
- print("Downloading track via wget...")
- shell.run("wget", "https://files.catbox.moe/n2aqgx.mod", modFilename)
- if not fs.exists(modFilename) then
- error("Download failed! Please check internet settings.")
- end
- end
- local speaker = peripheral.find("speaker")
- if not speaker then error("No speaker attached to the computer!") end
- local AMIGA_CLOCK = 3579545
- local INTERNAL_MIX_RATE = 44100
- local SPEAKER_RATE = 48000
- local CHANNELS = 4
- local proPeriods = {
- 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
- 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
- 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113
- }
- local samples, songOrder, patterns = {}, {}, {}
- local songLength, restartPos = 0, 0
- local curOrder, curRow = 1, 1
- local speed, bpm = 6, 125
- local jumpToRow, jumpToOrder = -1, -1
- local rawBuffer = {}
- local outputBuffer = {}
- local tracks = {}
- local currentTick = 0
- local sampleAccumulator = 0
- local math_floor = math.floor
- local math_min = math.min
- local math_max = math.max
- local math_abs = math.abs
- local math_sin = math.sin
- local math_sqrt = math.sqrt
- local bit32_rshift = bit32.rshift
- local bit32_band = bit32.band
- local bit32_lshift = bit32.lshift -- FIXED TYPO HERE
- local bit32_bor = bit32.bor
- local pixelBuffer = {}
- local colorToHex = {
- [1] = "0", [2] = "1", [4] = "2", [8] = "3",
- [16] = "4", [32] = "5", [64] = "6", [128] = "7",
- [256] = "8", [512] = "9", [1024] = "a", [2048] = "b",
- [4096] = "c", [8192] = "d", [16384] = "e", [32768] = "f"
- }
- local plasmaColors = {
- colors.black, colors.blue, colors.purple, colors.magenta, colors.cyan, colors.white
- }
- local bayer2x2 = {
- { 0.25, 0.75 },
- { 1.00, 0.50 }
- }
- local font = {
- ["A"]={ 6, 9,15, 9, 9}, ["B"]={14, 9,14, 9,14}, ["C"]={ 6, 9, 8, 9, 6}, ["D"]={14, 9, 9, 9,14},
- ["E"]={15, 8,14, 8,15}, ["F"]={15, 8,14, 8, 8}, ["G"]={ 6, 9,11, 9, 6}, ["H"]={ 9, 9,15, 9, 9},
- ["I"]={14, 4, 4, 4,14}, ["J"]={ 2, 2, 2,10, 4}, ["K"]={ 9,10,12,10, 9}, ["L"]={ 8, 8, 8, 8,15},
- ["M"]={ 9,15,15, 9, 9}, ["N"]={ 9,13,11, 9, 9}, ["O"]={ 6, 9, 9, 9, 6}, ["P"]={14, 9,14, 8, 8},
- ["Q"]={ 6, 9, 9,11, 5}, ["R"]={14, 9,14,10, 9}, ["S"]={ 7, 8, 6, 1,14}, ["T"]={15, 4, 4, 4, 4},
- ["U"]={ 9, 9, 9, 9, 6}, ["V"]={ 9, 9, 9, 6, 2}, ["W"]={ 9, 9,15,15, 9}, ["X"]={ 9, 9, 6, 9, 9},
- ["Y"]={ 9, 9, 6, 2, 2}, ["Z"]={15, 2, 4, 8,15},
- ["0"]={ 6, 9, 9, 9, 6}, ["1"]={ 4,12, 4, 4,14}, ["2"]={14, 1, 6, 8,15}, ["3"]={14, 1, 6, 1,14},
- ["4"]={ 9, 9,15, 1, 1}, ["5"]={15, 8,14, 1,14}, ["6"]={ 6, 8,14, 9, 6}, ["7"]={15, 1, 2, 4, 4},
- ["8"]={ 6, 9, 6, 9, 6}, ["9"]={ 6, 9, 7, 1, 6},
- [" "]={ 0, 0, 0, 0, 0}, ["."]={ 0, 0, 0, 0, 4}, [","]={ 0, 0, 0, 4, 8}, ["!"]={ 4, 4, 4, 0, 4},
- ["?"]={14, 1, 2, 0, 4}, ["'"]={ 4, 4, 0, 0, 0}, ["-"]={ 0, 0,15, 0, 0}
- }
- local rawText = "Wow?? Fast 3D With Good Music on ComputerCraft? How is that even possible??? It's thanks to my new LUA Written engine called 'nono3D', It Supports Protracker MOD files, 3D, Plasmas and Much More! It's Still In Development but i hope i would finish it! "
- local scrollText = string.upper(rawText)
- local scrollPixelX = width
- local scrollerHeightSubPixels = 7
- local scrollerStartRow = height - scrollerHeightSubPixels - 1
- local function updateStep(t)
- local s = samples[t.sampleIdx]
- if not s or t.period <= 0 then
- t.step = 0
- return
- end
- local prd = math_max(113, math_min(856, t.period))
- local frequency = AMIGA_CLOCK / prd
- if s.fine ~= 0 then
- frequency = frequency * (2 ^ (s.fine / 96))
- end
- t.step = frequency / INTERNAL_MIX_RATE
- t.volumeScale = t.volume / 64
- end
- local function getArpeggioPeriod(basePeriod, noteOffset)
- local bestIdx, minDiff = 1, 1e9
- for i = 1, 36 do
- local diff = math_abs(proPeriods[i] - basePeriod)
- if diff < minDiff then minDiff = diff bestIdx = i end
- end
- local targetIdx = math_max(1, math_min(36, bestIdx + noteOffset))
- return proPeriods[targetIdx]
- end
- local function processEffects(tick)
- for i = 1, CHANNELS do
- local t = tracks[i]
- local cmd, data = t.effect, t.eData
- if tick == 0 then
- if cmd == 0xC then
- t.volume = math_min(data, 64)
- t.volumeScale = t.volume / 64
- elseif cmd == 0xF then
- if data > 0 and data < 32 then speed = data
- elseif data >= 32 then bpm = math_max(32, math_min(255, data)) end
- elseif cmd == 0xD then
- local newRow = math_floor(data / 16) * 10 + (data % 16)
- if newRow < 64 then jumpToRow = newRow + 1 jumpToOrder = curOrder + 1 end
- elseif cmd == 0xB then
- if data < 128 then jumpToOrder = data + 1 jumpToRow = 1 end
- elseif cmd == 0x3 or cmd == 0x5 then
- if data > 0 then t.portamentoSpeed = data end
- elseif cmd == 0x4 or cmd == 0x6 then
- if data > 0 then
- local s, d = bit32_rshift(data, 4), bit32_band(data, 0x0F)
- if s > 0 then t.vibratoSpeed = s end
- if d > 0 then t.vibratoDepth = d end
- end
- elseif cmd == 0xE then
- local subCmd, subData = bit32_rshift(data, 4), bit32_band(data, 0x0F)
- if subCmd == 0x1 then t.period = math_max(113, t.period - subData) updateStep(t)
- elseif subCmd == 0x2 then t.period = math_min(856, t.period + subData) updateStep(t)
- elseif subCmd == 0xA then t.volume = math_min(64, t.volume + subData) t.volumeScale = t.volume / 64
- elseif subCmd == 0xB then t.volume = math_max(0, t.volume - subData) t.volumeScale = t.volume / 64
- elseif subCmd == 0xC then t.active = false end
- end
- else
- if cmd == 0x0 and data > 0 then
- local phase = tick % 3
- if phase == 1 then t.period = getArpeggioPeriod(t.targetPeriod, bit32_rshift(data, 4))
- elseif phase == 2 then t.period = getArpeggioPeriod(t.targetPeriod, bit32_band(data, 0x0F))
- else t.period = t.targetPeriod end
- updateStep(t)
- elseif cmd == 0x1 then t.period = math_max(113, t.period - data) updateStep(t)
- elseif cmd == 0x2 then t.period = math_min(856, t.period + data) updateStep(t)
- elseif cmd == 0x3 or cmd == 0x5 then
- if t.period < t.targetPeriod then t.period = math_min(t.targetPeriod, t.period + t.portamentoSpeed)
- elseif t.period > t.targetPeriod then t.period = math_max(t.targetPeriod, t.period - t.portamentoSpeed) end
- updateStep(t)
- if cmd == 0x5 and data > 0 then
- local u, d = bit32_rshift(data, 4), bit32_band(data, 0x0F)
- t.volume = math_max(0, math_min(64, t.volume + u - d))
- t.volumeScale = t.volume / 64
- end
- elseif cmd == 0x4 or cmd == 0x6 then
- local vib = math_sin(t.vibratoPos * 0.09817477) * t.vibratoDepth * 2
- t.period = math_max(113, math_min(856, t.targetPeriod + vib))
- t.vibratoPos = (t.vibratoPos + t.vibratoSpeed) % 64
- updateStep(t)
- if cmd == 0x6 and data > 0 then
- local u, d = bit32_rshift(data, 4), bit32_band(data, 0x0F)
- t.volume = math_max(0, math_min(64, t.volume + u - d))
- t.volumeScale = t.volume / 64
- end
- elseif cmd == 0xA then
- local u, d = bit32_rshift(data, 4), bit32_band(data, 0x0F)
- t.volume = math_max(0, math_min(64, t.volume + u - d))
- t.volumeScale = t.volume / 64
- elseif cmd == 0xE then
- local subCmd, subData = bit32_rshift(data, 4), bit32_band(data, 0x0F)
- if subCmd == 0x9 and subData > 0 and tick % subData == 0 then t.cursor = 0 end
- end
- end
- end
- end
- local mixCache = {}
- for i = 1, 32 do
- mixCache[i] = { track = {}, data = {}, len = 0, loopStart = 0, loopLen = 0, hasLoop = false, loopEnd = 0 }
- end
- local function mixSamples(count)
- local normalizationFactor = math_sqrt(CHANNELS) * 1.1
- local activeCount = 0
- for c = 1, CHANNELS do
- local t = tracks[c]
- if t and t.active then
- local s = samples[t.sampleIdx]
- if s and s.len > 0 then
- activeCount = activeCount + 1
- local mc = mixCache[activeCount]
- mc.track = t; mc.data = s.data; mc.len = s.len
- mc.loopStart = s.loopStart; mc.loopLen = s.loopLen
- mc.hasLoop = s.loopLen > 2; mc.loopEnd = s.loopStart + s.loopLen
- end
- end
- end
- for i = 1, count do
- local out = 0
- for c = 1, activeCount do
- local at = mixCache[c]
- local t = at.track
- if t.active then
- if at.hasLoop then
- if t.cursor >= at.loopEnd then
- t.cursor = at.loopStart + ((t.cursor - at.loopEnd) % at.loopLen)
- end
- elseif t.cursor >= at.len then t.active = false end
- if t.active then
- local idx = math_floor(t.cursor) + 1
- local val = at.data[idx]
- if val then
- out = out + (val * t.volumeScale)
- t.cursor = t.cursor + t.step
- else t.active = false end
- end
- end
- end
- rawBuffer[i] = out / normalizationFactor
- end
- local ratio = SPEAKER_RATE / INTERNAL_MIX_RATE
- local outSize = math_floor(count * ratio + 0.5)
- local invRatio = 1 / ratio
- local src_acc = 1
- for i = 1, outSize do
- local idx = math_floor(src_acc)
- local s1 = rawBuffer[idx] or 0
- local s2 = rawBuffer[idx + 1] or s1
- outputBuffer[i] = math_max(-128, math_min(127, math_floor(s1 + (s2 - s1) * (src_acc - idx))))
- src_acc = src_acc + invRatio
- end
- return outputBuffer, outSize
- end
- local function loadMOD(filename)
- local f = fs.open(filename, "rb")
- if not f then error("File not found: " .. filename) end
- local success, err = pcall(function()
- f.read(20)
- for i = 1, 31 do
- f.read(22)
- local len = (f.read() * 256 + f.read()) * 2
- local fine = f.read()
- if fine > 7 then fine = fine - 16 end
- local vol = f.read()
- local lStart = (f.read() * 256 + f.read()) * 2
- local lLen = (f.read() * 256 + f.read()) * 2
- if len > 0 and vol > 0 then
- samples[i] = { len = len, vol = math_min(64, vol), loopStart = lStart, loopLen = lLen, fine = fine, data = {} }
- else
- samples[i] = { len = 0, data = {} }
- end
- end
- songLength = f.read()
- restartPos = f.read()
- local maxPattern = 0
- for i = 1, 128 do
- songOrder[i] = f.read() or 0
- if songOrder[i] > maxPattern then maxPattern = songOrder[i] end
- end
- local m1, m2, m3, m4 = f.read(), f.read(), f.read(), f.read()
- local tag = string.char(m1 or 0, m2 or 0, m3 or 0, m4 or 0)
- CHANNELS = 4
- if tag == "M.K." or tag == "M!K!" or tag == "FLT4" or tag == "4CHN" then CHANNELS = 4
- elseif tag == "6CHN" or tag == "6CNM" then CHANNELS = 6
- elseif tag == "8CHN" or tag == "8CNM" or tag == "CD81" or tag == "OKTA" then CHANNELS = 8
- elseif tag:match("^%d+CH") or tag:match("^%d+CN") then
- local digits = tag:match("^(%d+)CH") or tag:match("^(%d+)CN")
- if digits then CHANNELS = tonumber(digits) end
- end
- for i = 1, CHANNELS do
- tracks[i] = {
- sampleIdx = 0, cursor = 0, period = 0, step = 0, targetPeriod = 0, volume = 64, active = false,
- effect = 0, eData = 0, portamentoSpeed = 0, vibratoSpeed = 0, vibratoDepth = 0, vibratoPos = 0, volumeScale = 1
- }
- end
- for p = 0, maxPattern do
- patterns[p] = {}
- for row = 1, 64 do
- patterns[p][row] = {}
- for chan = 1, CHANNELS do
- local b1, b2, b3, b4 = f.read(), f.read(), f.read(), f.read()
- if b1 and b2 and b3 and b4 then
- local sIdx = bit32_bor(bit32_band(b1, 0xF0), bit32_rshift(b3, 4))
- local prd = bit32_bor(bit32_lshift(bit32_band(b1, 0x0F), 8), b2)
- patterns[p][row][chan] = { samp = sIdx, period = prd, effect = bit32_band(b3, 0x0F), eData = b4 }
- else
- patterns[p][row][chan] = { samp = 0, period = 0, effect = 0, eData = 0 }
- end
- end
- end
- end
- for i = 1, 31 do
- if samples[i] and samples[i].len > 0 then
- local data = samples[i].data
- for j = 1, samples[i].len do
- local b = f.read()
- data[j] = b and ((b > 127) and (b - 256) or b) or 0
- end
- end
- end
- end)
- f.close()
- if not success then error("Failed to load MOD: " .. tostring(err)) end
- end
- local function getPlasmaColor(x, y, time)
- local v1 = math.sin(x / 12 + time)
- local v2 = math.sin(y / 12 + time * 1.2)
- local v3 = math.sin((x + y) / 18 + time)
- local cx = x - width / 2
- local cy = y - height / 2
- local v4 = math.sin(math.sqrt(cx*cx + cy*cy) / 10 - time)
- local total = (v1 + v2 + v3 + v4) / 4
- local factor = (total + 1) / 2
- local rawIdx = factor * (#plasmaColors - 1) + 1
- local baseIdx = math.floor(rawIdx)
- local fraction = rawIdx - baseIdx
- local mX = (x % 2) + 1
- local mY = (y % 2) + 1
- local threshold = bayer2x2[mY][mX]
- local finalIdx = baseIdx
- if fraction > threshold and baseIdx < #plasmaColors then finalIdx = baseIdx + 1 end
- if finalIdx < 1 then finalIdx = 1 elseif finalIdx > #plasmaColors then finalIdx = #plasmaColors end
- return plasmaColors[finalIdx]
- end
- local function clearBuffers(time)
- for y = 1, height do
- local rowOffset = (y - 1) * width
- if y >= scrollerStartRow then
- for x = 1, width do pixelBuffer[rowOffset + x] = colors.black end
- else
- for x = 1, width do pixelBuffer[rowOffset + x] = getPlasmaColor(x, y, time) end
- end
- end
- end
- local function drawChar(char, startX, startY, textColor)
- local glyph = font[char] or font["?"]
- for row = 1, 5 do
- local bitmask = glyph[row]
- local currentY = startY + row - 1
- if currentY >= 1 and currentY <= height then
- local rowOffset = (currentY - 1) * width
- for col = 1, 4 do
- local currentX = startX + col - 1
- if currentX >= 1 and currentX <= width then
- local bit = math.floor(bitmask / (2 ^ (4 - col))) % 2
- if bit == 1 then pixelBuffer[rowOffset + currentX] = textColor end
- end
- end
- end
- end
- end
- local function drawScroller()
- local currentX = math.floor(scrollPixelX)
- local charSpacing = 5
- local textOffsetY = scrollerStartRow + 1
- for i = 1, #scrollText do
- local char = scrollText:sub(i, i)
- if currentX >= -4 and currentX <= width then
- local colorCycle = math_floor((currentX / 12) % 3)
- local txtColor = colors.white
- if colorCycle == 1 then txtColor = colors.cyan
- elseif colorCycle == 2 then txtColor = colors.purple end
- drawChar(char, currentX, textOffsetY, txtColor)
- end
- currentX = currentX + charSpacing
- end
- end
- local function edgeFunction(ax, ay, bx, by, cx, cy)
- return (cx - ax) * (by - ay) - (cy - ay) * (bx - ax)
- end
- local function drawTriangle(p1, p2, p3, color)
- local minX = math.max(1, math.floor(math.min(p1.x, p2.x, p3.x)))
- local maxX = math.min(width, math.floor(math.max(p1.x, p2.x, p3.x)))
- local minY = math.max(1, math.floor(math.min(p1.y, p2.y, p3.y)))
- local maxY = math.min(height, math.floor(math.max(p1.y, p2.y, p3.y)))
- maxY = math.min(maxY, scrollerStartRow - 1)
- for y = minY, maxY do
- local rowOffset = (y - 1) * width
- for x = minX, maxX do
- local w0 = edgeFunction(p2.x, p2.y, p3.x, p3.y, x, y)
- local w1 = edgeFunction(p3.x, p3.y, p1.x, p1.y, x, y)
- local w2 = edgeFunction(p1.x, p1.y, p2.x, p2.y, x, y)
- if (w0 >= 0 and w1 >= 0 and w2 >= 0) or (w0 <= 0 and w1 <= 0 and w2 <= 0) then
- pixelBuffer[rowOffset + x] = color
- end
- end
- end
- end
- local function drawQuad(p1, p2, p3, p4, color)
- drawTriangle(p1, p2, p3, color)
- drawTriangle(p1, p3, p4, color)
- end
- local function renderScreen()
- for y = 1, baseHeight do
- local charRow, textColRow, bgColRow = {}, {}, {}
- for x = 1, baseWidth do
- local hX = (x - 1) * 2
- local hY = (y - 1) * 3
- local c1 = pixelBuffer[(hY * width) + hX + 1] or colors.black
- local c2 = pixelBuffer[(hY * width) + hX + 2] or colors.black
- local c3 = pixelBuffer[((hY + 1) * width) + hX + 1] or colors.black
- local c4 = pixelBuffer[((hY + 1) * width) + hX + 2] or colors.black
- local c5 = pixelBuffer[((hY + 2) * width) + hX + 1] or colors.black
- local c6 = pixelBuffer[((hY + 2) * width) + hX + 2] or colors.black
- local primaryColor, secondaryColor = c1, c1
- local counts, maxCount = {}, 0
- if (hY + 1) >= scrollerStartRow then
- for _, c in ipairs({c1, c2, c3, c4, c5, c6}) do
- counts[c] = (counts[c] or 0) + ((c == colors.white or c == colors.cyan or c == colors.purple) and 20 or 1)
- if counts[c] > maxCount then maxCount = counts[c]; primaryColor = c end
- end
- secondaryColor = colors.black
- else
- for _, c in ipairs({c1, c2, c3, c4, c5, c6}) do
- counts[c] = (counts[c] or 0) + 1
- if counts[c] > maxCount then maxCount = counts[c]; primaryColor = c end
- end
- for _, c in ipairs({c1, c2, c3, c4, c5, c6}) do
- if c ~= primaryColor then secondaryColor = c break end
- end
- end
- local p1 = (c1 == primaryColor) and 1 or 0
- local p2 = (c2 == primaryColor) and 1 or 0
- local p3 = (c3 == primaryColor) and 1 or 0
- local p4 = (c4 == primaryColor) and 1 or 0
- local p5 = (c5 == primaryColor) and 1 or 0
- local p6 = (c6 == primaryColor)
- local textHex = colorToHex[primaryColor] or "f"
- local bgHex = colorToHex[secondaryColor] or "f"
- if p6 then
- p1, p2, p3, p4, p5 = 1 - p1, 1 - p2, 1 - p3, 1 - p4, 1 - p5
- textHex, bgHex = bgHex, textHex
- end
- table.insert(charRow, string.char(128 + p1 + p2 * 2 + p3 * 4 + p4 * 8 + p5 * 16))
- table.insert(textColRow, textHex)
- table.insert(bgColRow, bgHex)
- end
- term.setCursorPos(1, y)
- term.blit(table.concat(charRow), table.concat(textColRow), table.concat(bgColRow))
- end
- end
- local vertices = {
- { -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 },
- { -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 }
- }
- local faces = {
- { vertices = {1, 4, 3, 2}, color = colors.red },
- { vertices = {5, 6, 7, 8}, color = colors.orange },
- { vertices = {1, 2, 6, 5}, color = colors.yellow }, -- FIXED PROPERTY PREFIX HERE
- { vertices = {4, 8, 7, 3}, color = colors.green },
- { vertices = {1, 5, 8, 4}, color = colors.blue },
- { vertices = {2, 3, 7, 6}, color = colors.magenta }
- }
- loadMOD(modFilename)
- local angleX, angleY = 0, 0
- local time = 0
- local function pumpAudioTick()
- if curOrder > songLength then return false end
- local pIdx = songOrder[curOrder]
- if not pIdx or not patterns[pIdx] then
- curOrder = curOrder + 1; curRow = 1; return true
- end
- local rowData = patterns[pIdx][curRow]
- if not rowData then curRow = curRow + 1; return true end
- if currentTick == 0 then
- for c = 1, CHANNELS do
- local cell = rowData[c]
- if cell then
- if cell.samp > 0 then
- local s = samples[cell.samp]
- if s and s.len > 0 then
- tracks[c].sampleIdx = cell.samp
- if s.vol > 0 then tracks[c].volume = s.vol; tracks[c].volumeScale = s.vol / 64 end
- end
- end
- if cell.period > 0 then
- if cell.effect == 0x3 or cell.effect == 0x5 then tracks[c].targetPeriod = cell.period
- else
- tracks[c].period = cell.period; tracks[c].targetPeriod = cell.period
- tracks[c].cursor = 0; tracks[c].vibratoPos = 0
- updateStep(tracks[c]); tracks[c].active = true
- end
- elseif cell.period == 0 and cell.samp > 0 then
- if tracks[c].targetPeriod > 0 then
- tracks[c].cursor = 0; tracks[c].active = true; updateStep(tracks[c])
- end
- end
- tracks[c].effect = cell.effect; tracks[c].eData = cell.eData
- end
- end
- end
- processEffects(currentTick)
- speed = math_max(1, speed)
- bpm = math_max(32, math_min(255, bpm))
- local rowTime = (speed * 2.5) / bpm
- local totalSamplesNeeded = math_floor(INTERNAL_MIX_RATE * rowTime + 0.5)
- local samplesPerTickBase = totalSamplesNeeded / speed
- sampleAccumulator = sampleAccumulator + samplesPerTickBase
- local tickSamples = math_floor(sampleAccumulator)
- sampleAccumulator = sampleAccumulator - tickSamples
- local accepted = true
- if tickSamples > 0 then
- local audio, n = mixSamples(tickSamples)
- accepted = speaker.playAudio(audio)
- end
- if accepted then
- currentTick = currentTick + 1
- if currentTick >= speed then
- currentTick = 0
- if jumpToOrder ~= -1 then
- curOrder = jumpToOrder; curRow = jumpToRow; jumpToOrder = -1; jumpToRow = -1
- else
- curRow = curRow + 1
- if curRow > 64 then
- curRow = 1; curOrder = curOrder + 1
- if curOrder > songLength then curOrder = restartPos + 1; if curOrder < 1 then curOrder = 1 end; curRow = 1 end
- end
- end
- end
- end
- return accepted
- end
- local function audioWorker()
- while true do
- local event, side = os.pullEvent()
- if event == "speaker_audio_empty" then
- local accepted = true
- while accepted do
- accepted = pumpAudioTick()
- end
- end
- end
- end
- local function graphicsWorker()
- while true do
- clearBuffers(time)
- local rotated, projected = {}, {}
- local radX, radY = math.rad(angleX), math.rad(angleY)
- local cosX, sinX = math.cos(radX), math.sin(radX)
- local cosY, sinY = math.cos(radY), math.sin(radY)
- for i, v in ipairs(vertices) do
- local y1 = v[2] * cosX - v[3] * sinX
- local z1 = v[2] * sinX + v[3] * cosX
- local x2 = v[1] * cosY + z1 * sinY
- local z2 = -v[1] * sinY + z1 * cosY
- rotated[i] = { x = x2, y = y1, z = z2 }
- local distance = 3.2
- local rz = 1 / (distance - z2)
- projected[i] = { x = centerX + (x2 * scale * rz) * 1.15, y = centerY + (y1 * scale * rz) }
- end
- for _, face in ipairs(faces) do
- local r1, r2, r3 = rotated[face.vertices[1]], rotated[face.vertices[2]], rotated[face.vertices[3]]
- local v1x, v1y, v1z = r2.x - r1.x, r2.y - r1.y, r2.z - r1.z
- local v2x, v2y, v2z = r3.x - r1.x, r3.y - r1.y, r3.z - r1.z
- local nx = v1y * v2z - v1z * v2y
- local ny = v1z * v2x - v1x * v2z
- local nz = v1x * v2y - v1y * v2x
- if (nx * r1.x + ny * r1.y + nz * (r1.z - 3.2)) < 0 then
- drawQuad(projected[face.vertices[1]], projected[face.vertices[2]], projected[face.vertices[3]], projected[face.vertices[4]], face.color)
- end
- end
- drawScroller()
- renderScreen()
- angleX = (angleX + 3) % 360
- angleY = (angleY + 2) % 360
- time = time + 0.04
- scrollPixelX = scrollPixelX - 1.4
- if scrollPixelX < -(#scrollText * 5) then scrollPixelX = width end
- sleep(0.05)
- end
- end
- term.clear()
- local prefill = true
- while prefill do
- prefill = pumpAudioTick()
- end
- parallel.waitForAny(audioWorker, graphicsWorker)
Add Comment
Please, Sign In to add comment