Fix Atlas gen with simplification
Only track lower and upper bounds in world space, and speak in terms of world space and chunks
This commit is contained in:
parent
dbe944bb4e
commit
8b83672dcc
5 changed files with 240 additions and 121 deletions
|
@ -38,11 +38,11 @@ type Atlas struct {
|
|||
// This is intentionally not a 2D array so it can be expanded in all directions
|
||||
Chunks []Chunk `json:"chunks"`
|
||||
|
||||
// CurrentSize is the current width/height of the atlas in chunks
|
||||
CurrentSize vector.Vector `json:"currentSize"`
|
||||
// LowerBound is the origin of the bottom left corner of the current chunks in world space (current chunks cover >= this value)
|
||||
LowerBound vector.Vector `json:"lowerBound"`
|
||||
|
||||
// WorldOrigin represents the location of the [0,0] world space point in terms of the allotted current chunks
|
||||
WorldOrigin vector.Vector `json:"worldOrigin"`
|
||||
// UpperBound is the top left corner of the current chunks (curent chunks cover < this value)
|
||||
UpperBound vector.Vector `json:"upperBound"`
|
||||
|
||||
// ChunkSize is the x/y dimensions of each square chunk
|
||||
ChunkSize int `json:"chunksize"`
|
||||
|
@ -52,10 +52,10 @@ type Atlas struct {
|
|||
func NewAtlas(chunkSize int) Atlas {
|
||||
// Start up with one chunk
|
||||
a := Atlas{
|
||||
ChunkSize: chunkSize,
|
||||
Chunks: make([]Chunk, 1),
|
||||
CurrentSize: vector.Vector{X: 1, Y: 1},
|
||||
WorldOrigin: vector.Vector{X: 0, Y: 0},
|
||||
ChunkSize: chunkSize,
|
||||
Chunks: make([]Chunk, 1),
|
||||
LowerBound: vector.Vector{X: 0, Y: 0},
|
||||
UpperBound: vector.Vector{X: chunkSize, Y: chunkSize},
|
||||
}
|
||||
// Initialise the first chunk
|
||||
a.Chunks[0].populate(chunkSize)
|
||||
|
@ -162,129 +162,88 @@ func (a *Atlas) worldSpaceToChunkLocal(v vector.Vector) vector.Vector {
|
|||
return vector.Vector{X: maths.Pmod(v.X, a.ChunkSize), Y: maths.Pmod(v.Y, a.ChunkSize)}
|
||||
}
|
||||
|
||||
// worldSpaceToChunk gets the current chunk ID for a position in the world
|
||||
func (a *Atlas) worldSpaceToChunk(v vector.Vector) int {
|
||||
// First convert to chunk space
|
||||
chunkSpace := a.worldSpaceToChunkSpace(v)
|
||||
// worldSpaceToChunkID gets the current chunk ID for a position in the world
|
||||
func (a *Atlas) worldSpaceToChunkIndex(v vector.Vector) int {
|
||||
// Shift the vector by our current min
|
||||
v = v.Added(a.LowerBound.Negated())
|
||||
|
||||
// Then return the ID
|
||||
return a.chunkSpaceToChunk(chunkSpace)
|
||||
// Divide by the current size and floor, to get chunk-scaled vector from the lower bound
|
||||
v = v.DividedFloor(a.ChunkSize)
|
||||
|
||||
// Calculate the width
|
||||
width := a.UpperBound.X - a.LowerBound.X
|
||||
widthInChunks := width / a.ChunkSize
|
||||
|
||||
// Along the corridor and up the stairs
|
||||
return (v.Y * widthInChunks) + v.X
|
||||
}
|
||||
|
||||
// worldSpaceToChunkSpace converts from world space to chunk space
|
||||
func (a *Atlas) worldSpaceToChunkSpace(v vector.Vector) vector.Vector {
|
||||
// Remove the chunk local part
|
||||
chunkOrigin := v.Added(a.worldSpaceToChunkLocal(v).Negated())
|
||||
// Convert to chunk space coordinate
|
||||
chunkSpaceOrigin := chunkOrigin.Divided(a.ChunkSize)
|
||||
// Shift it by our current chunk origin
|
||||
chunkIndexOrigin := chunkSpaceOrigin.Added(a.WorldOrigin)
|
||||
|
||||
return chunkIndexOrigin
|
||||
}
|
||||
|
||||
// chunkSpaceToWorldSpace vonverts from chunk space to world space
|
||||
func (a *Atlas) chunkSpaceToWorldSpace(v vector.Vector) vector.Vector {
|
||||
|
||||
// Shift it by the current chunk origin
|
||||
shifted := v.Added(a.WorldOrigin.Negated())
|
||||
|
||||
// Multiply out by chunk size
|
||||
return shifted.Multiplied(a.ChunkSize)
|
||||
}
|
||||
|
||||
// chunkOriginInChunkSpace Gets the chunk origin in chunk space
|
||||
func (a *Atlas) chunkOriginInChunkSpace(chunk int) vector.Vector {
|
||||
// convert the chunk to chunk space
|
||||
chunkOrigin := a.chunkToChunkSpace(chunk)
|
||||
|
||||
// Shift it by the current chunk origin
|
||||
return chunkOrigin.Added(a.WorldOrigin.Negated())
|
||||
}
|
||||
|
||||
// chunkOriginInWorldSpace gets the chunk origin for a given chunk index
|
||||
// chunkOriginInWorldSpace returns the origin of the chunk in world space
|
||||
func (a *Atlas) chunkOriginInWorldSpace(chunk int) vector.Vector {
|
||||
// convert the chunk to chunk space
|
||||
chunkSpace := a.chunkToChunkSpace(chunk)
|
||||
// Calculate the width
|
||||
width := a.UpperBound.X - a.LowerBound.X
|
||||
widthInChunks := width / a.ChunkSize
|
||||
|
||||
// Convert to world space
|
||||
return a.chunkSpaceToWorldSpace(chunkSpace)
|
||||
}
|
||||
|
||||
// chunkSpaceToChunk converts from chunk space to the chunk
|
||||
func (a *Atlas) chunkSpaceToChunk(v vector.Vector) int {
|
||||
// Along the coridor and up the stair
|
||||
return (v.Y * a.CurrentSize.X) + v.X
|
||||
}
|
||||
|
||||
// chunkToChunkSpace returns the chunk space coord for the chunk
|
||||
func (a *Atlas) chunkToChunkSpace(chunk int) vector.Vector {
|
||||
return vector.Vector{
|
||||
X: maths.Pmod(chunk, a.CurrentSize.Y),
|
||||
Y: (chunk / a.CurrentSize.X),
|
||||
// Reverse the along the corridor and up the stairs
|
||||
v := vector.Vector{
|
||||
X: chunk % widthInChunks,
|
||||
Y: chunk / widthInChunks,
|
||||
}
|
||||
// Multiply up to world scale
|
||||
v = v.Multiplied(a.ChunkSize)
|
||||
// Shift by the lower bound
|
||||
return v.Added(a.LowerBound)
|
||||
}
|
||||
|
||||
func (a *Atlas) getExtents() (min vector.Vector, max vector.Vector) {
|
||||
min = a.WorldOrigin.Negated()
|
||||
max = min.Added(a.CurrentSize)
|
||||
// getNewBounds gets new lower and upper bounds for the world space given a vector
|
||||
func (a *Atlas) getNewBounds(v vector.Vector) (lower vector.Vector, upper vector.Vector) {
|
||||
lower = vector.Min(v, a.LowerBound)
|
||||
upper = vector.Max(v.Added(vector.Vector{X: 1, Y: 1}), a.UpperBound)
|
||||
|
||||
lower = vector.Vector{
|
||||
X: maths.RoundDown(lower.X, a.ChunkSize),
|
||||
Y: maths.RoundDown(lower.Y, a.ChunkSize),
|
||||
}
|
||||
upper = vector.Vector{
|
||||
X: maths.RoundUp(upper.X, a.ChunkSize),
|
||||
Y: maths.RoundUp(upper.Y, a.ChunkSize),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// worldSpaceToTrunkWithGrow will expand the current atlas for a given world space position if needed
|
||||
func (a *Atlas) worldSpaceToChunkWithGrow(v vector.Vector) int {
|
||||
min, max := a.getExtents()
|
||||
|
||||
// Divide by the chunk size to bring into chunk space
|
||||
v = v.Divided(a.ChunkSize)
|
||||
|
||||
// Check we're within the current extents and bail early
|
||||
if v.X >= min.X && v.Y >= min.Y && v.X < max.X && v.Y < max.Y {
|
||||
return a.worldSpaceToChunk(v)
|
||||
// If we're within bounds, just return the current chunk
|
||||
if v.X >= a.LowerBound.X && v.Y >= a.LowerBound.Y && v.X < a.UpperBound.X && v.Y < a.UpperBound.Y {
|
||||
return a.worldSpaceToChunkIndex(v)
|
||||
}
|
||||
|
||||
// Calculate the new origin and the new size
|
||||
origin := min
|
||||
size := a.CurrentSize
|
||||
// Calculate the new bounds
|
||||
lower, upper := a.getNewBounds(v)
|
||||
size := upper.Added(lower.Negated())
|
||||
size = size.Divided(a.ChunkSize)
|
||||
|
||||
// If we need to shift the origin back
|
||||
originDiff := origin.Added(v.Negated())
|
||||
if originDiff.X > 0 {
|
||||
origin.X -= originDiff.X
|
||||
size.X += originDiff.X
|
||||
}
|
||||
if originDiff.Y > 0 {
|
||||
origin.Y -= originDiff.Y
|
||||
size.Y += originDiff.Y
|
||||
}
|
||||
|
||||
// If we need to expand the size
|
||||
maxDiff := v.Added(max.Negated())
|
||||
if maxDiff.X > 0 {
|
||||
size.X += maxDiff.X
|
||||
}
|
||||
if maxDiff.Y > 0 {
|
||||
size.Y += maxDiff.Y
|
||||
}
|
||||
|
||||
// Set up the new size and origin
|
||||
// Create the new empty atlas
|
||||
newAtlas := Atlas{
|
||||
ChunkSize: a.ChunkSize,
|
||||
WorldOrigin: origin.Negated(),
|
||||
CurrentSize: size,
|
||||
Chunks: make([]Chunk, size.X*size.Y),
|
||||
ChunkSize: a.ChunkSize,
|
||||
LowerBound: lower,
|
||||
UpperBound: upper,
|
||||
Chunks: make([]Chunk, size.X*size.Y),
|
||||
}
|
||||
|
||||
// Copy all old chunks into the new atlas
|
||||
for chunk, chunkData := range a.Chunks {
|
||||
// Calculate the new chunk location and copy over the data
|
||||
newChunk := newAtlas.worldSpaceToChunk(a.chunkOriginInWorldSpace(chunk))
|
||||
|
||||
// Calculate the chunk ID in the new atlas
|
||||
origin := a.chunkOriginInWorldSpace(chunk)
|
||||
newChunk := newAtlas.worldSpaceToChunkIndex(origin)
|
||||
|
||||
// Copy over the old chunk to the new atlas
|
||||
newAtlas.Chunks[newChunk] = chunkData
|
||||
}
|
||||
|
||||
// Copy the new atlas data into this one
|
||||
// Overwrite the old atlas with this one
|
||||
*a = newAtlas
|
||||
|
||||
return a.worldSpaceToChunk(v)
|
||||
return a.worldSpaceToChunkIndex(v)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue