func appendBoxExtra(verts []*render.StaticVertex, x, y, z, w, h, d float32, textures [6]render.TextureInfo, extra [6][2]float64) []*render.StaticVertex { for i, face := range faceVertices { tex := textures[i] if tex == nil { continue } for _, v := range face.verts { var rr, gg, bb byte = 255, 255, 255 if direction.Type(i) == direction.West || direction.Type(i) == direction.East { rr = byte(255 * 0.8) gg = byte(255 * 0.8) bb = byte(255 * 0.8) } vert := &render.StaticVertex{ X: float32(v.X)*w + x, Y: float32(v.Y)*h + y, Z: float32(v.Z)*d + z, Texture: tex, TextureX: float64(v.TOffsetX) * extra[i][0], TextureY: float64(v.TOffsetY) * extra[i][1], R: rr, G: gg, B: bb, A: 255, } verts = append(verts, vert) } } return verts }
func genStaticModelFromItem(mdl *model, block Block, mode string) (out []*render.StaticVertex, mat mgl32.Mat4) { mat = mgl32.Rotate3DZ(math.Pi).Mat4(). Mul4(mgl32.Rotate3DY(math.Pi / 2).Mat4()). Mul4(mgl32.Rotate3DZ(-math.Pi / 2).Mat4()) if gui, ok := mdl.display[mode]; ok { if gui.Scale != nil { mat = mat.Mul4(mgl32.Scale3D( float32(gui.Scale[0]), float32(gui.Scale[1]), float32(gui.Scale[2]), )) } if gui.Translation != nil { mat = mat.Mul4(mgl32.Translate3D( float32(gui.Translation[0]/32), float32(gui.Translation[1]/32), float32(gui.Translation[2]/32), )) } if gui.Rotation != nil { mat = mat.Mul4(mgl32.Rotate3DX(math.Pi + float32(gui.Rotation[0]/180)*math.Pi).Mat4()) mat = mat.Mul4(mgl32.Rotate3DZ(math.Pi + float32(gui.Rotation[2]/180)*math.Pi).Mat4()) mat = mat.Mul4(mgl32.Rotate3DY(float32(gui.Rotation[1]/180) * math.Pi).Mat4()) } } mat = mat.Mul4(mgl32.Rotate3DY(math.Pi / 2).Mat4()) mat = mat.Mul4(mgl32.Translate3D(-1/16.0, 0, 0)) tex := render.GetTexture("solid") rect := tex.Rect() tName, plugin := mdl.textureVars["layer0"], "minecraft" if pos := strings.IndexRune(tName, ':'); pos != -1 { plugin = tName[:pos] tName = tName[pos:] } f, err := resource.Open(plugin, "textures/"+tName+".png") if err != nil { return } defer f.Close() img, err := png.Decode(f) if err != nil { panic(err) } w, h := img.Bounds().Dx(), img.Bounds().Dy() sx := 1 / float32(w) sy := 1 / float32(h) isSolid := func(x, y int) bool { col := img.At(x, y) _, _, _, aa := col.RGBA() if aa == 0 { return false } return true } for x := 0; x < w; x++ { for y := 0; y < h; y++ { col := img.At(x, y) rr, gg, bb, aa := col.RGBA() if aa == 0 { continue } for i, f := range faceVertices { facing := direction.Type(i) if facing != direction.North && facing != direction.South { xx, yy, _ := facing.Offset() if isSolid(x+xx, y+yy) { continue } } var cr, cg, cb byte cr = byte(rr >> 8) cg = byte(gg >> 8) cb = byte(bb >> 8) if facing == direction.East || facing == direction.West { cr = byte(float64(cr) * 0.8) cg = byte(float64(cg) * 0.8) cb = byte(float64(cb) * 0.8) } if facing == direction.North || facing == direction.South { cr = byte(float64(cr) * 0.6) cg = byte(float64(cg) * 0.6) cb = byte(float64(cb) * 0.6) } for _, vert := range f.verts { vX, vY, vZ := float32(vert.X), float32(vert.Y), float32(vert.Z) vert := &render.StaticVertex{ Y: vY*sy - 0.5 + sy*float32(y), X: vX*sx - 0.5 + sx*float32(x), Z: (vZ - 0.5) * (1.0 / 16.0), Texture: tex, TextureX: float64(vert.TOffsetX) / float64(16*rect.Width), TextureY: float64(vert.TOffsetY) / float64(16*rect.Height), R: cr, G: cg, B: cb, A: byte(aa >> 8), } out = append(out, vert) } } } } return }
func precomputeModel(bm *model) *processedModel { p := &processedModel{} p.ambientOcclusion = bm.ambientOcclusion p.weight = bm.weight for _, el := range bm.elements { for i, face := range el.faces { faceID := direction.Type(i) if face == nil { continue } pFace := processedFace{} cullFace := face.cullFace if bm.x > 0 { o := int(bm.x) / 90 cullFace = rotateDirection(cullFace, o, faceRotationX, direction.East, direction.West, direction.Invalid) faceID = rotateDirection(faceID, o, faceRotationX, direction.East, direction.West, direction.Invalid) } if bm.y > 0 { o := int(bm.y) / 90 cullFace = rotateDirection(cullFace, o, faceRotation, direction.Up, direction.Down, direction.Invalid) faceID = rotateDirection(faceID, o, faceRotation, direction.Up, direction.Down, direction.Invalid) } pFace.cullFace = cullFace pFace.facing = direction.Type(faceID) pFace.tintIndex = face.tintIndex pFace.shade = el.shade vert := faceVertices[i] tex := bm.lookupTexture(face.texture) rect := tex.Rect() ux1 := int16(face.uv[0] * float64(rect.Width)) ux2 := int16(face.uv[2] * float64(rect.Width)) uy1 := int16(face.uv[1] * float64(rect.Height)) uy2 := int16(face.uv[3] * float64(rect.Height)) tw, th := int16(rect.Width), int16(rect.Height) if face.rotation > 0 { x := ux1 y := uy1 w := ux2 - ux1 h := uy2 - uy1 switch face.rotation { case 90: uy2 = x + w ux1 = tw*16 - (y + h) ux2 = tw*16 - y uy1 = x case 180: uy1 = th*16 - (y + h) uy2 = th*16 - y ux1 = x + w ux2 = x case 270: uy2 = x uy1 = x + w ux2 = y + h ux1 = y } } var minX, minY, minZ = float32(math.Inf(1)), float32(math.Inf(1)), float32(math.Inf(1)) var maxX, maxY, maxZ = float32(math.Inf(-1)), float32(math.Inf(-1)), float32(math.Inf(-1)) for v := range vert.verts { pFace.verticesTexture = append(pFace.verticesTexture, tex) vert.verts[v].TX = uint16(rect.X) vert.verts[v].TY = uint16(rect.Y) vert.verts[v].TW = uint16(rect.Width) vert.verts[v].TH = uint16(rect.Height) vert.verts[v].TAtlas = int16(tex.Atlas()) if vert.verts[v].X == 0 { vert.verts[v].X = float32(el.from[0] / 16.0) } else { vert.verts[v].X = float32(el.to[0] / 16.0) } if vert.verts[v].Y == 0 { vert.verts[v].Y = float32(el.from[1] / 16.0) } else { vert.verts[v].Y = float32(el.to[1] / 16.0) } if vert.verts[v].Z == 0 { vert.verts[v].Z = float32(el.from[2] / 16.0) } else { vert.verts[v].Z = float32(el.to[2] / 16.0) } if el.rotation != nil { r := el.rotation switch r.axis { case "y": rotY := -r.angle * (math.Pi / 180) c := math.Cos(rotY) s := math.Sin(rotY) x := float64(vert.verts[v].X) - (r.origin[0] / 16.0) z := float64(vert.verts[v].Z) - (r.origin[2] / 16.0) vert.verts[v].X = float32(r.origin[0]/16.0 + (x*c - z*s)) vert.verts[v].Z = float32(r.origin[2]/16.0 + (z*c + x*s)) case "x": rotX := r.angle * (math.Pi / 180) c := math.Cos(-rotX) s := math.Sin(-rotX) z := float64(vert.verts[v].Z) - (r.origin[2] / 16.0) y := float64(vert.verts[v].Y) - (r.origin[1] / 16.0) vert.verts[v].Z = float32(r.origin[2]/16.0 + (z*c - y*s)) vert.verts[v].Y = float32(r.origin[1]/16.0 + (y*c + z*s)) case "z": rotZ := -r.angle * (math.Pi / 180) c := math.Cos(-rotZ) s := math.Sin(-rotZ) x := float64(vert.verts[v].X) - (r.origin[0] / 16.0) y := float64(vert.verts[v].Y) - (r.origin[1] / 16.0) vert.verts[v].X = float32(r.origin[0]/16.0 + (x*c - y*s)) vert.verts[v].Y = float32(r.origin[1]/16.0 + (y*c + x*s)) } } if bm.x > 0 { rotX := bm.x * (math.Pi / 180) c := float32(math.Cos(rotX)) s := float32(math.Sin(rotX)) z := vert.verts[v].Z - 0.5 y := vert.verts[v].Y - 0.5 vert.verts[v].Z = 0.5 + (z*c - y*s) vert.verts[v].Y = 0.5 + (y*c + z*s) } if bm.y > 0 { rotY := bm.y * (math.Pi / 180) c := float32(math.Cos(rotY)) s := float32(math.Sin(rotY)) x := vert.verts[v].X - 0.5 z := vert.verts[v].Z - 0.5 vert.verts[v].X = 0.5 + (x*c - z*s) vert.verts[v].Z = 0.5 + (z*c + x*s) } if vert.verts[v].TOffsetX == 0 { vert.verts[v].TOffsetX = int16(ux1) } else { vert.verts[v].TOffsetX = int16(ux2) } if vert.verts[v].TOffsetY == 0 { vert.verts[v].TOffsetY = int16(uy1) } else { vert.verts[v].TOffsetY = int16(uy2) } if face.rotation > 0 { rotY := -float64(face.rotation) * (math.Pi / 180) c := int16(math.Cos(rotY)) s := int16(math.Sin(rotY)) x := vert.verts[v].TOffsetX - 8*tw y := vert.verts[v].TOffsetY - 8*th vert.verts[v].TOffsetX = 8*tw + int16(x*c-y*s) vert.verts[v].TOffsetY = 8*th + int16(y*c+x*s) } if bm.uvLock && bm.y > 0 && (pFace.facing == direction.Up || pFace.facing == direction.Down) { rotY := float64(-bm.y) * (math.Pi / 180) c := int16(math.Cos(rotY)) s := int16(math.Sin(rotY)) x := vert.verts[v].TOffsetX - 8*16 y := vert.verts[v].TOffsetY - 8*16 vert.verts[v].TOffsetX = 8*16 + int16(x*c+y*s) vert.verts[v].TOffsetY = 8*16 + int16(y*c-x*s) } if bm.uvLock && bm.x > 0 && (pFace.facing != direction.Up && pFace.facing != direction.Down) { rotY := float64(bm.x) * (math.Pi / 180) c := int16(math.Cos(rotY)) s := int16(math.Sin(rotY)) x := vert.verts[v].TOffsetX - 8*16 y := vert.verts[v].TOffsetY - 8*16 vert.verts[v].TOffsetX = 8*16 + int16(x*c+y*s) vert.verts[v].TOffsetY = 8*16 + int16(y*c-x*s) } if el.rotation != nil && el.rotation.rescale { if vert.verts[v].X < minX { minX = vert.verts[v].X } else if vert.verts[v].X > maxX { maxX = vert.verts[v].X } if vert.verts[v].Y < minY { minY = vert.verts[v].Y } else if vert.verts[v].Y > maxY { maxY = vert.verts[v].Y } if vert.verts[v].Z < minZ { minZ = vert.verts[v].Z } else if vert.verts[v].Z > maxZ { maxZ = vert.verts[v].Z } } } if el.rotation != nil && el.rotation.rescale { diffX := maxX - minX diffY := maxY - minY diffZ := maxZ - minZ for v := range vert.verts { vert.verts[v].X = (vert.verts[v].X - minX) / diffX vert.verts[v].Y = (vert.verts[v].Y - minY) / diffY vert.verts[v].Z = (vert.verts[v].Z - minZ) / diffZ } } pFace.vertices = vert.verts[:] pFace.indices = vert.indices[:] p.faces = append(p.faces, pFace) } } return p }