// Copyright 2014, 2015, 2017 by Sascha L. Teichmann // Use of this source code is governed by the MIT license // that can be found in the LICENSE file. package common import ( "math" ) type area struct { X1, Z1 int16 X2, Z2 int16 } func (a area) contains(x, z int16) bool { return x >= a.X1 && x <= a.X2 && z >= a.Z1 && z <= a.Z2 } func (a area) higher() bool { return a.Z2-a.Z1 > a.X2-a.X1 } func areasContain(areas []area, x, z int16) bool { for _, r := range areas { if r.contains(x, z) { return true } } return false } // recalculate implements a greedy algorithm to figure out // a list of disjunct areas of free regions in the domain // to the (x, z) block plane. // oldAreas are searched and found free areas are appended // to newAreas which ist return. // This is useful to spatial query only blocks from db // that are not below already rendered blocks. func (a area) recalculate(r *Renderer, nareas []area) []area { yM := r.yMin const ex = 1 const ez = 2 nas := len(nareas) for z := a.Z1; z <= a.Z2; z++ { row := z * int16(r.width) for x := a.X1; x <= a.X2; x++ { // Uncovered and not in list of new areas? if yM[row+x] > math.MinInt32 || areasContain(nareas[nas:], x, z) { continue } ar := area{X1: x, Z1: z, X2: x, Z2: z} // Try to extend the area in x and/or z till no further extension is possible. ext: for extend := ex | ez; extend != 0; { // If we extending in both directions a the current area // is higher than wide we gain more block if extend // in the x direction first. if (extend == ex|ez && ar.higher()) || extend&ex == ex { // check x nx := ar.X2 + 1 if nx > a.X2 { // reached border of area extend &= ^ex continue } // Check column right of the current area if its fully free. for nz := ar.Z1; nz <= ar.Z2; nz++ { if yM[nz*int16(r.width)+nx] > math.MinInt32 || areasContain(nareas[nas:], nx, nz) { extend &= ^ex continue ext } } // free -> extend ar.X2 = nx } else if extend&ez == ez { // check z nz := ar.Z2 + 1 if nz > a.Z2 { extend &= ^ez continue } // Check line right below the current area if its free. row2 := nz * int16(r.width) for nx := ar.X1; nx <= ar.X2; nx++ { if yM[row2+nx] > math.MinInt32 || areasContain(nareas[nas:], nx, nz) { extend &= ^ez continue ext } } // free -> extend ar.Z2 = nz } } // At this point the area is extended to max. nareas = append(nareas, ar) } } return nareas }