Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local component = require("component")
- local computer = require("computer")
- local event = require("event")
- local gpu = component.gpu
- local math = require("math")
- if gpu.maxDepth() < 8 then
- error("This script requires a Tier 3 GPU.")
- end
- local w, h = gpu.maxResolution()
- gpu.setResolution(w, h)
- local buffer1 = gpu.allocateBuffer(w, h)
- local buffer2 = gpu.allocateBuffer(w, h)
- local currentBuffer = buffer1
- local rotationX, rotationY = 0, 0
- local blob = {
- x = w / 2,
- y = h / 2,
- radius = math.floor(math.min(w, h) / 4),
- baseColor = 0x7F7F7F,
- touchPoint = nil,
- stretchVector = {x = 0, y = 0},
- stretchFactor = 0,
- recoilFactor = 0,
- velocity = {x = 0, y = 0},
- springConstant = 0.1,
- damping = 0.8
- }
- local background = {
- stars = {},
- numStars = 100
- }
- for i = 1, background.numStars do
- table.insert(background.stars, {
- x = math.random(-100, 100),
- y = math.random(-100, 100),
- z = math.random(-100, 0),
- color = math.random(0x444444, 0xFFFFFF)
- })
- end
- local function blendColors(c1, c2, factor)
- local r1, g1, b1 = c1 >> 16, (c1 >> 8) & 0xFF, c1 & 0xFF
- local r2, g2, b2 = c2 >> 16, (c2 >> 8) & 0xFF, c2 & 0xFF
- local r = math.floor((r1 * (1 - factor) + r2 * factor) + 0.5) & 0xFF
- local g = math.floor((g1 * (1 - factor) + g2 * factor) + 0.5) & 0xFF
- local b = math.floor((b1 * (1 - factor) + b2 * factor) + 0.5) & 0xFF
- return (r << 16) | (g << 8) | b
- end
- local function rotate3D(x, y, z, ax, ay)
- local sy, cy = math.sin(ay), math.cos(ay)
- local sx, cx = math.sin(ax), math.cos(ax)
- local nx = x * cy + z * sy
- local ny = y * cx - (x * sy - z * cy) * sx
- local nz = -y * sx + (x * sy - z * cy) * cx
- return nx, ny, nz
- end
- local function updateBlobDeformation(dt)
- local recoilSpeed = 0.2
- local stretchDecay = 0.9
- if blob.touchPoint then
- local dx, dy = blob.touchPoint.x - blob.x, blob.touchPoint.y - blob.y
- local distance = math.sqrt(dx*dx + dy*dy)
- blob.stretchFactor = math.min(distance / (blob.radius * 2), 1) * 0.5
- blob.stretchVector.x, blob.stretchVector.y = dx / distance, dy / distance
- blob.recoilFactor = 0
- else
- -- Spring-like behavior
- local force = {
- x = -blob.springConstant * blob.stretchVector.x * blob.stretchFactor,
- y = -blob.springConstant * blob.stretchVector.y * blob.stretchFactor
- }
- blob.velocity.x = blob.velocity.x + force.x * dt
- blob.velocity.y = blob.velocity.y + force.y * dt
- blob.velocity.x = blob.velocity.x * blob.damping
- blob.velocity.y = blob.velocity.y * blob.damping
- blob.stretchVector.x = blob.stretchVector.x + blob.velocity.x * dt
- blob.stretchVector.y = blob.stretchVector.y + blob.velocity.y * dt
- blob.stretchFactor = math.sqrt(blob.stretchVector.x^2 + blob.stretchVector.y^2)
- if blob.stretchFactor > 0 then
- blob.stretchVector.x = blob.stretchVector.x / blob.stretchFactor
- blob.stretchVector.y = blob.stretchVector.y / blob.stretchFactor
- end
- blob.stretchFactor = blob.stretchFactor * stretchDecay
- if blob.stretchFactor < 0.01 then
- blob.stretchFactor = 0
- blob.stretchVector.x, blob.stretchVector.y = 0, 0
- blob.velocity.x, blob.velocity.y = 0, 0
- end
- end
- end
- local function drawBlob()
- local time = computer.uptime()
- local wobble = math.sin(time * 2) * 1
- local aspectRatio = w / h
- for screenY = 1, h do
- for screenX = 1, w do
- local dx = (screenX - blob.x) / aspectRatio
- local dy = screenY - blob.y
- local distanceSquared = dx*dx + dy*dy
- if distanceSquared <= blob.radius * blob.radius then
- local z = math.sqrt(blob.radius*blob.radius - distanceSquared)
- local nx = dx / blob.radius
- local ny = dy / blob.radius
- local nz = z / blob.radius
- local stretchX = blob.stretchVector.x * blob.stretchFactor * nx
- local stretchY = blob.stretchVector.y * blob.stretchFactor * ny
- local px = nx + stretchX
- local py = ny + stretchY
- local pz = nz * (1 - blob.stretchFactor * 0.5)
- local rx, ry, rz = rotate3D(px, py, pz, rotationX, rotationY)
- -- Lighting
- local lightDir = {x = 0.5, y = -0.5, z = 0.7}
- local lightIntensity = math.max(0, rx * lightDir.x + ry * lightDir.y + rz * lightDir.z)
- -- Reflection
- local viewDir = {x = -rx, y = -ry, z = -rz}
- local reflectDir = {
- x = viewDir.x - 2 * (viewDir.x * rx + viewDir.y * ry + viewDir.z * rz) * rx,
- y = viewDir.y - 2 * (viewDir.x * rx + viewDir.y * ry + viewDir.z * rz) * ry,
- z = viewDir.z - 2 * (viewDir.x * rx + viewDir.y * ry + viewDir.z * rz) * rz
- }
- local reflectionIntensity = math.max(0, reflectDir.x * lightDir.x + reflectDir.y * lightDir.y + reflectDir.z * lightDir.z) ^ 8
- local lightFactor = lightIntensity * 0.7 + 0.3
- local reflectionFactor = reflectionIntensity * 0.3
- local color = blendColors(blob.baseColor, 0xFFFFFF, lightFactor)
- color = blendColors(color, 0xFFFFFF, reflectionFactor)
- local finalY = screenY + wobble * (1 - math.sqrt(distanceSquared) / blob.radius)
- if finalY > 0 and finalY <= h then
- gpu.setBackground(color)
- gpu.set(screenX, math.floor(finalY), " ")
- end
- end
- end
- end
- end
- local function drawBackground()
- for _, star in ipairs(background.stars) do
- local x, y, z = rotate3D(star.x, star.y, star.z, rotationX, rotationY)
- local scale = 200 / (z + 200)
- local screenX, screenY = math.floor(w/2 + x * scale), math.floor(h/2 + y * scale)
- if screenX > 0 and screenX <= w and screenY > 0 and screenY <= h then
- local brightness = math.floor(255 * scale) & 0xFF
- local color = blendColors(0x000000, star.color, brightness / 255)
- gpu.setBackground(color)
- gpu.set(screenX, screenY, " ")
- end
- end
- end
- local function render()
- gpu.setActiveBuffer(currentBuffer)
- gpu.setBackground(0x000000)
- gpu.fill(1, 1, w, h, " ")
- drawBackground()
- drawBlob()
- gpu.setActiveBuffer(0)
- gpu.bitblt(0, 1, 1, w, h, currentBuffer)
- currentBuffer = (currentBuffer == buffer1) and buffer2 or buffer1
- end
- local function handleTouch(_, _, x, y, button)
- local dx, dy = x - blob.x, y - blob.y
- if button == 0 then -- Left mouse button for rotation
- rotationY = rotationY + (x - w/2) * 0.01
- rotationX = rotationX + (y - h/2) * 0.01
- elseif button == 1 and dx*dx + dy*dy <= blob.radius*blob.radius then -- Right mouse button for deformation
- blob.touchPoint = {x = x, y = y}
- blob.velocity.x, blob.velocity.y = 0, 0
- end
- end
- local function handleDrag(_, _, x, y, button)
- if button == 0 then -- Left mouse button for rotation
- rotationY = rotationY + (x - w/2) * 0.01
- rotationX = rotationX + (y - h/2) * 0.01
- elseif button == 1 and blob.touchPoint then -- Right mouse button for deformation
- blob.touchPoint.x, blob.touchPoint.y = x, y
- end
- end
- local function handleRelease(_, _, _, _, button)
- if button == 1 then
- blob.touchPoint = nil
- end
- end
- local running = true
- local lastRender = computer.uptime()
- local targetFPS = 30
- event.listen("touch", handleTouch)
- event.listen("drag", handleDrag)
- event.listen("drop", handleRelease)
- while running do
- local currentTime = computer.uptime()
- local deltaTime = currentTime - lastRender
- if deltaTime >= 1 / targetFPS then
- updateBlobDeformation(deltaTime)
- render()
- lastRender = currentTime
- local e = {event.pull(0)}
- if e[1] == "interrupted" then
- running = false
- end
- else
- os.sleep(0.001)
- end
- end
- event.ignore("touch", handleTouch)
- event.ignore("drag", handleDrag)
- event.ignore("drop", handleRelease)
- gpu.setBackground(0x000000)
- gpu.setForeground(0xFFFFFF)
- gpu.fill(1, 1, w, h, " ")
- gpu.freeBuffer(buffer1)
- gpu.freeBuffer(buffer2)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement