Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --@name Scanner
- --@author Cheezus
- --@shared
- -------------------------------------------------------------------------------------------------------------
- if SERVER then -----------------------------------SERVER STUFF-----------------------------------------------
- -------------------------------------------------------------------------------------------------------------
- if not chip():isWeldedTo() then return end --If the screen entity doesn't exist, shut 'er down, the chip shouldn't run
- chip():isWeldedTo():linkComponent(chip()) --Automatically link the entity the chip is welded to - the screen
- local screen = chip():isWeldedTo() --Store it in a variable named 'screen'
- --Dunno why I have to send the screen entity to the client a bunch of times but just sending it once
- --means the client doesn't receive it fast enough(?) so I'm sending it 66 times with a 0-second timer
- --Because fuck efficiency.
- timer.create("interval",0,66,function()
- net.start("screenEnt")
- net.writeEntity(screen)
- net.send()
- end)
- -------------------------------------------------------------------------------------------------------------
- else ---------------------------------------------CLIENT STUFF-----------------------------------------------
- -------------------------------------------------------------------------------------------------------------
- render.createRenderTarget("scanner") --Render targets are like a 'custom material' that you can draw to.
- --Here we're creating one named 'scanner'
- --Render targets are useful if you want previously drawn objects/pixels to 'persist' aka not
- --delete themselves when you stop calling the draw function for that specific object/pixel
- -------------------------------------------------------------------------------------------------------------
- --------------------------------------------------SETUP------------------------------------------------------
- -------------------------------------------------------------------------------------------------------------
- local fov = 75 --Field of view
- local maxDist = 10000 --After this distance (in source units) the fog is 100%
- local quotaLimit = 0.9 --Percentage of the client's CPU to use. 0.9-0.95 is usually fine
- local skyColor = Vector(165, 206, 235) --Color of the sky/fog
- local res = 512 --Resolution - keep this 1024 or under
- local useTextelColors = true --Use the world's textel colors for world color information. Slightly buggy, can look odd in some situations
- local shadows = true --Setting this to true enables shadowing, which increases render time but can look nice
- local shadowReduction = 0.5 --Percentage of light shadowed objects should receive, where 0 is flat black and 1 is no shadow
- local sunDirection = Vector(-0.85,0.5,0.5) --Direction the sun is in
- -------------------------------------------------------------------------------------------------------------
- ----------------------------END OF SETUP - DON'T MESS WITH STUFF PAST HERE-----------------------------------
- -------------------------------------------------------------------------------------------------------------
- local x = 0 --Starting pixel, X coordinate. Don't change this.
- local y = 0 --Starting pixel, Y coordinate. Don't change this.
- local startTime = timer.realtime() --Time the scan was started
- --Create a function we'll use to make drawing pixels to the screen easier
- --It takes an X coordinate, a Y coordinate, and a color as inputs
- --local function draw(x, y, col, mat)
- local function draw(x, y, col)
- render.setRGBA(col.x, col.y, col.z, 255) --Sets the color of the next drawn object, based on the color input to this function
- render.drawRect(x * (1024/res), y * (1024/res), 1 + (1024/res), 1 + (1024/res))
- --Draws a rectangle at the specified x and y coordinates (basically a pixel), the size of the pixel being determined by the resolution
- end
- --This function returns 1 if the SF is under the CPU quota, if not, returns 0
- local function canRun(quota)
- if quotaAverage() > quotaMax() * quota or quotaUsed() > quotaMax() * quota then --Checks whether the CPU quota is less than
- --what the user set in the settings
- return 0
- else
- return 1
- end
- end
- --Function which mixes two input vectors together, the bias towards the first or second vector being decided by the ratio
- --Mixing essentially lets you 'slide' between the first and second input smoothly.
- --If your input 1 is Vector(0,0,0), and your input 2 is Vector(5,10,50), mixing with a ratio of 0.5 (half)
- --would return Vector(2.5,5,25), because Vector(2.5,5,25) is exactly half way between the two inputs.
- local function mix(vec1, vec2, ratio)
- return Vector(vec1.x * ratio + vec2.x * (1-ratio), vec1.y * ratio + vec2.y * (1-ratio), vec1.z * ratio + vec2.z * (1-ratio))
- --Mix equation: input1 * ratio + input2 * (1 - ratio)
- end
- --Receive the screen entity which was previously sent from the server
- hook.add("net", "Net", function(name)
- screen = net.readEntity()
- end)
- -------------------------------------------------------------------------------------------------------------
- --------------------------------------------------RENDERING--------------------------------------------------
- -------------------------------------------------------------------------------------------------------------
- hook.add("render", "Render", function()
- render.selectRenderTarget("scanner") --Select the render target we created earlier
- --While loop to speed things up. Runs on the following conditions:
- --The CPU quota is below the limit
- --The current Y coordinate is less than the resolution
- --The screen entity is actually a valid entity (is linked to the chip)
- while canRun(quotaLimit) == 1 and y < res+1 and screen:isValid() do
- --When the scan is first started (both coordinates at 0), clear the screen
- if y == 0 and x == 0 then
- render.clear(Color(0,0,0,0))
- end
- --Run a trace, based on the screen's position and some math to get the direction it should be facing using the X and Y coordinates
- local trace1 = trace.trace(screen:getPos() - screen:getUp()*10, screen:localToWorld( Vector((-res*fov/2 + y*fov) * (1024/res), (-res*fov/2 + x*fov) * (1024/res), -50000)), find.allPlayers())
- local hitPos = trace1.HitPos --The trace's hit position
- local dist = (hitPos - screen:getPos()):getLength() --The distance of the trace's hit position from the screen
- local sky = Vector(skyColor.x/255 - (y/res)/2, skyColor.y/255 - (y/res)/2, skyColor.z/255 - (y/res)/2)*255 --Sky gradient effect
- if shadows == true then
- trace2 = trace.trace(hitPos, hitPos + sunDirection * 100000)
- if trace2.HitSky then
- shadowReductionVal = 1
- else
- shadowReductionVal = shadowReduction
- end
- else
- shadowReductionVal = 1
- end
- if trace1.Entity:isValid() then --If the trace hit an entity, get its color
- --local mat = trace1.Entity:getMaterials()[1]
- color = Vector(trace1.Entity:getColor().r, trace1.Entity:getColor().g, trace1.Entity:getColor().b) * shadowReductionVal
- elseif trace1.HitSky then --If the trace hits the sky, just set the color as the sky color
- color = sky
- else --If the trace hits anything else (probably the world)
- if useTextelColors then
- color = render.traceSurfaceColor(screen:getPos() - screen:getUp()*10, screen:localToWorld( Vector((-res*fov/2 + y*fov) * (1024/res), (-res*fov/2 + x*fov) * (1024/res), -50000))) * 255 * shadowReductionVal
- else
- --This is temporary, color getting shit goes here soon(tm)
- color = Vector(200, 200, 200) * shadowReductionVal
- end
- end
- draw(x, y, mix(color, sky, math.clamp(1-(dist/maxDist), 0, 1))) --Draw the pixel based on current X/Y pos and current color
- --Position advancement
- if x <= res then
- x = x + 1
- else
- x = 0
- y = y + 1
- end
- end --End of the while loop
- render.selectRenderTarget() --Select a blank render target, which returns the chip to drawing to the actual screen instead of the RT texture
- if y < res then --If the scan hasn't finished yet, draw this stuff to the screen
- render.setColor(Color(255,255,255,255)) --Set the draw color to solid white
- render.drawSimpleText(0, 0, "Rendering " .. res .. "x" .. res .. " image", 0, 0) --Display image size
- render.drawSimpleText(0, 12, math.floor((y/res) * 100) .. "%", 0, 0) --Display progress
- render.drawSimpleText(0, 24, math.floor(timer.realtime()-startTime) .. " seconds elasped", 0, 0) --Display time elapsed
- render.drawSimpleText(0, 36, "CPU Usage: " .. math.round( ( quotaAverage() / quotaMax() ) * 100 ) .. "%", 0, 0)
- else --If the scan is finished
- render.setRenderTargetTexture("scanner") --Sets the draw texture to the name of the render target we were drawing to during the scan
- render.drawTexturedRect(0,0,512,512) --Finally, draw a screen-size textured rectangle, using the RT texture we just set
- end
- end)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement