Skip to content

Commit

Permalink
Chunk generation vaguely near working
Browse files Browse the repository at this point in the history
  • Loading branch information
Middlerun committed Jun 28, 2011
1 parent a76474a commit f7e8469
Show file tree
Hide file tree
Showing 4 changed files with 244 additions and 33 deletions.
159 changes: 158 additions & 1 deletion chunk.lua
@@ -1,12 +1,19 @@

air = 0
stone = 1
dirt = 3

Chunk = {}

function Chunk:new()
o = {}
setmetatable(o, self)
self.__index = self

o.generated = 0
o.generated = false
o.value = {}
o.value = {}
o.perlin = {}
for r = 1, 32 do
o.value[r] = {}
o.perlin[r] = {}
Expand All @@ -19,10 +26,160 @@ function Chunk:new()
return o
end

function Chunk:generate(seed, chunkR, chunkC)
self.perlin = self:generatePerlin(seed, chunkR, chunkC)

local absR
local absC

self.value = {}
for r = 1, 32 do
absR = chunkR * 32 + r
self.value[r] = {}
dirtMargin = (256-absR) * 0.01
for c = 1, 32 do
absC = chunkC * 32 + c
value = self.perlin[r][c]
if r < 128 then
value = value + (128 - r) * 0.02
end
if value > 0.5 then self.value[r][c] = air
elseif value > 1.4 - dirtMargin or value < -0.6 then self.value[r][c] = dirt
else self.value[r][c] = stone
end
end
end
self.generated = true
end

function Chunk:generatePerlin(seed, chunkR, chunkC)
local persistence = 0.55
local N = 6
local amplitude = 1
local compInterp
local compAmplitude
local comp
local data = {}
for r = 1, 32 do
data[r] = {}
for c = 1, 32 do
data[r][c] = 0
end
end
for i = N, 1, -1 do
compInterp = 2^(i-1)
compAmplitude = amplitude * persistence^(N-i)
comp = self:perlinComponent2D(seed+i*1000, chunkR, chunkC, compInterp, compAmplitude)
for r = 1, 32 do
for c = 1, 32 do
data[r][c] = data[r][c] + comp[r][c]
end
end
end
return data
end

function Chunk:perlinComponent2D(seed, chunkR, chunkC, N, amplitude)

local topEdge1 = chunkR * 32 + 1
local bottomEdge1 = (chunkR + 1) * 32 + 1
local leftEdge1 = chunkC * 32 + 1
local rightEdge1 = (chunkC + 1) * 32 + 1

local topEdge2 = math.floor((topEdge1 - 1) / N) - 1
local bottomEdge2 = math.ceil ((bottomEdge1 - 1) / N) + 1
local leftEdge2 = math.floor((leftEdge1 - 1) / N) - 1
local rightEdge2 = math.ceil ((rightEdge1 - 1) / N) + 1

local rawData = {}
local finalData = {}
for r = leftEdge2, rightEdge2 do
rawData[r - leftEdge2 + 1] = {}
for c = topEdge2, bottomEdge2 do
rawData[r - leftEdge2 + 1][c - topEdge2 + 1] = amplitude * rand:get(seed + 1000*N + r, c)
end
end

local interpData = self:interpolate2D(rawData, chunkR, chunkC, N)
for r = 1, 32 do
finalData[r] = {}
for c = 1, 32 do
finalData[r][c] = interpData[r][c]
end
end
return finalData
end

function Chunk:interpolate2D(values, chunkR, chunkC, N)

local topEdge1 = chunkR * 32 + 1
local bottomEdge1 = (chunkR + 1) * 32 + 1
local leftEdge1 = chunkC * 32 + 1
local rightEdge1 = (chunkC + 1) * 32 + 1

local topEdge2 = math.floor((topEdge1 - 1) / N) - 1
local bottomEdge2 = math.ceil ((bottomEdge1 - 1) / N) + 1
local leftEdge2 = math.floor((leftEdge1 - 1) / N) - 1
local rightEdge2 = math.ceil ((rightEdge1 - 1) / N) + 1

local newData1 = {}
local min
local max
for r = 1, #values do
newData1[r] = {}
for c = 1, #values[r] - 3 do
P = (values[r][c+3] - values[r][c+2]) - (values[r][c] - values[r][c+1])
Q = (values[r][c] - values[r][c+1]) - P
R = (values[r][c+2] - values[r][c])
S = values[r][c+1]
min = math.max(leftEdge1 - 1, (leftEdge2 + c) * N) % N + 1
max = math.min(rightEdge1 - 1, (leftEdge2 + c + 1) * N) % N + N + 1
for j = min, max-1 do
x = j/N
table.insert(newData1[r], P*x^3 + Q*x^2 + R*x + S)
end
end
end
assert(#newData1[1] == 32, "wrong length. chunkR="..chunkR.." chunkC="..chunkC.." N="..N)

local newData2 = {}
for r = 1, 32 do
newData2[r] = {}
end
for c = 1, 32 do
rowCount = 0
for r = 1, #newData1 - 3 do
P = (newData1[r+3][c] - newData1[r+2][c]) - (newData1[r][c] - newData1[r+1][c])
Q = (newData1[r][c] - newData1[r+1][c]) - P
R = (newData1[r+2][c] - newData1[r][c])
S = newData1[r+1][c]
min = math.max(topEdge1 - 1, (topEdge2 + r) * N) % N + 1
max = math.min(bottomEdge1 - 1, (bottomEdge2 + r + 1) * N) % N + N + 1
for j = min, max-1 do
x = j/N
rowCount = rowCount + 1
newData2[rowCount][c] = P*x^3 + Q*x^2 + R*x + S
end
end
end

for r = 1, 32 do
for c = 1, 32 do
assert(newData2[r][c] ~= nil, "nil value, r="..r.." c="..c.." N="..N)
end
end

return newData2
end

function Chunk:getValue(r, c)
return self.value[r][c]
end

function Chunk:setValue(r, c, value)
self.value[r][c] = value
end

function Chunk:isGenerated()
return self.generated
end
95 changes: 66 additions & 29 deletions main.lua
@@ -1,4 +1,6 @@
love.filesystem.load("perlin.lua")()
love.filesystem.load("chunk.lua")()
love.filesystem.load("terrain.lua")()
love.filesystem.setIdentity("lovecraft")

air = 0
Expand All @@ -7,29 +9,41 @@ dirt = 3
rand = {mySeed = 1, lastN = -1}

function love.load()
showPerlin = 0
showPerlin = false

terrain = makeTerrain()
terrain = Terrain:new(1)
chunk1 = Chunk:new()
chunk1:generate(1, 0, 0)
terrain:addChunk(chunk1, 0, 0)
chunk2 = Chunk:new()
chunk2:generate(1, 0, 1)
terrain:addChunk(chunk2, 0, 1)
chunk3 = Chunk:new()
chunk3:generate(1, 1, 0)
terrain:addChunk(chunk3, 1, 0)
chunk4 = Chunk:new()
chunk4:generate(1, 1, 1)
terrain:addChunk(chunk4, 1, 1)

end

function love.update(dt)
end

function love.draw()
if showPerlin == 1 then plot2D(terrain.perlin)
if showPerlin then drawTerrainPerlin(terrain, 4, 0, 0)
else
love.graphics.setColor(161, 235, 255, 255)
love.graphics.rectangle("fill", -1, -1, love.graphics.getWidth()+2, love.graphics.getHeight()+2)
drawTerrain(terrain)
drawTerrain(terrain, 4, 0, 0)
end
end

function love.keypressed(k, u)
if k == "r" then
terrain = makeTerrain()
elseif k == "p" then
showPerlin = 1 - showPerlin
showPerlin = not showPerlin
elseif k == "escape" then
love.event.push("q")
end
Expand All @@ -40,11 +54,14 @@ function love.keyreleased(k)
end

function rand:get(seed, n)
if n <= 0 then return nil end
if n <= 0 then n = -2 * n
else n = 2 * n - 1
end

if seed ~= self.mySeed or self.lastN < 0 or n <= self.lastN then
self.mySeed = seed
math.randomseed(seed)
self.lastN = 0
self.lastN = -1
end
while self.lastN < n do
num = math.random()
Expand All @@ -53,47 +70,30 @@ function rand:get(seed, n)
return num - 0.5
end

function plot1D(values)
love.graphics.line(0, love.graphics.getHeight()/2 - 200, love.graphics.getWidth(), love.graphics.getHeight()/2 - 200)
love.graphics.line(0, love.graphics.getHeight()/2 + 200, love.graphics.getWidth(), love.graphics.getHeight()/2 + 200)
for i = 1, #values - 1 do
love.graphics.line((i-1)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i] * 400, (i)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i+1] * 400)
end
end

function plot2D(values)
for r = 1, #values do
for c = 1, #(values[1]) do
love.graphics.setColor(128 + 40 * values[r][c], 128 + 40 * values[r][c], 128 + 40 * values[r][c], 255)
love.graphics.rectangle("fill", (c-1)/(#(values[1]))*love.graphics.getWidth(), (r-1)/(#values)*love.graphics.getHeight(), love.graphics.getWidth()/#(values[1]), love.graphics.getHeight()/#values)
end
end
end

function makeTerrain(seed)
terrain = {}
if seed == nil then seed = os.time() end
terrain.seed = seed
terrain.perlin = perlin2D(seed, 341, 256, 0.9, 20, 1)
terrain.perlin = perlin2D(seed, 341, 256, 0.55, 6, 1)
terrain.value = {}
for r = 1, #terrain.perlin do
terrain.value[r] = {}
dirtMargin = (256-r) * 0.01
for c = 1, #(terrain.perlin[r]) do
value = terrain.perlin[r][c]
if r < 128 then
value = value + (128 - r) * 0.05
value = value + (128 - r) * 0.02
end
if value > 0.9 then terrain.value[r][c] = air
elseif value > 1.6 - dirtMargin or value < -1.4 then terrain.value[r][c] = dirt
if value > 0.5 then terrain.value[r][c] = air
elseif value > 1.4 - dirtMargin or value < -0.6 then terrain.value[r][c] = dirt
else terrain.value[r][c] = stone
end
end
end
return terrain
end

function drawTerrain(terrain)
function drawTerrainOld(terrain)
for r = 1, #terrain.value do
for c = 1, #(terrain.value[1]) do
if terrain.value[r][c] ~= air then
Expand All @@ -105,5 +105,42 @@ function drawTerrain(terrain)
end
end

function drawTerrain(terrain, zoom, x, y)
for r = 0, 1 do
for c = 0, 1 do
drawChunk(terrain:getChunk(r, c), zoom, x-32*c, y-32*r)
end
end
end

function drawChunk(chunk, zoom, x, y)
for r = 1, 32 do
for c = 1, 32 do
if chunk.value[r][c] ~= air then
if chunk.value[r][c] == stone then love.graphics.setColor(163, 163, 163, 255) end
if chunk.value[r][c] == dirt then love.graphics.setColor(130, 97, 21, 255) end
love.graphics.rectangle("fill", (c-1-x)*zoom + love.graphics.getWidth()/2, (r-1-y)*zoom+love.graphics.getHeight()/2, zoom, zoom)
end
end
end
end

function drawTerrainPerlin(terrain, zoom, x, y)
for r = 0, 1 do
for c = 0, 1 do
drawChunkPerlin(terrain:getChunk(r, c), zoom, x-32*c, y-32*r)
end
end
end

function drawChunkPerlin(chunk, zoom, x, y)
for r = 1, 32 do
for c = 1, 32 do
love.graphics.setColor(128 + 80 * chunk.perlin[r][c], 128 + 80 * chunk.perlin[r][c], 128 + 80 * chunk.perlin[r][c], 255)
love.graphics.rectangle("fill", (c-1-x)*zoom + love.graphics.getWidth()/2, (r-1-y)*zoom+love.graphics.getHeight()/2, zoom, zoom)
end
end
end



19 changes: 18 additions & 1 deletion perlin.lua
Expand Up @@ -111,7 +111,7 @@ function perlin2D(seed, width, height, persistence, N, amplitude)
for i = N, 1, -1 do
compInterp = 2^(i-1)
compAmplitude = amplitude * persistence^(N-i)
comp = perlinComponent2D(seed+i*1000, width, height, i, compAmplitude)
comp = perlinComponent2D(seed+i*1000, width, height, compInterp, compAmplitude)
for r = 1, height do
for c = 1, width do
data[r][c] = data[r][c] + comp[r][c]
Expand All @@ -121,3 +121,20 @@ function perlin2D(seed, width, height, persistence, N, amplitude)
return data
end

function plot1D(values)
love.graphics.line(0, love.graphics.getHeight()/2 - 200, love.graphics.getWidth(), love.graphics.getHeight()/2 - 200)
love.graphics.line(0, love.graphics.getHeight()/2 + 200, love.graphics.getWidth(), love.graphics.getHeight()/2 + 200)
for i = 1, #values - 1 do
love.graphics.line((i-1)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i] * 400, (i)/(#values-1)*love.graphics.getWidth(), love.graphics.getHeight()/2 - values[i+1] * 400)
end
end

function plot2D(values)
for r = 1, #values do
for c = 1, #(values[1]) do
love.graphics.setColor(128 + 80 * values[r][c], 128 + 80 * values[r][c], 128 + 80 * values[r][c], 255)
love.graphics.rectangle("fill", (c-1)/(#(values[1]))*love.graphics.getWidth(), (r-1)/(#values)*love.graphics.getHeight(), love.graphics.getWidth()/#(values[1]), love.graphics.getHeight()/#values)
end
end
end

4 changes: 2 additions & 2 deletions terrain.lua
Expand Up @@ -12,8 +12,8 @@ function Terrain:new(seed)
return o
end

function Terrain:addChunk(r, c, chunk)
if self.chunk[r] == nil do self.chunk[r] = {}
function Terrain:addChunk(chunk, r, c)
if self.chunk[r] == nil then self.chunk[r] = {} end
self.chunk[r][c] = chunk
end

Expand Down

0 comments on commit f7e8469

Please sign in to comment.