<commit_before>// Copyright 2015 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package steven

import (
	"image"
	"math"

	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/render/builder"
	"github.com/thinkofdeath/steven/type/direction"
)

type processedModel struct {
	faces            []processedFace
	ambientOcclusion bool
}

type processedFace struct {
	cullFace  direction.Type
	facing    direction.Type
	vertices  []chunkVertex
	shade     bool
	tintIndex int
}

var faceRotation = []direction.Type{
	direction.North,
	direction.East,
	direction.South,
	direction.West,
}

var faceRotationX = []direction.Type{
	direction.North,
	direction.Down,
	direction.South,
	direction.Up,
}

func rotateDirection(val direction.Type, offset int, rots []direction.Type, invalid ...direction.Type) direction.Type {
	for _, d := range invalid {
		if d == val {
			return val
		}
	}
	var pos int
	for di, d := range rots {
		if d == val {
			pos = di
			break
		}
	}
	return rots[(pos+offset)%len(rots)]
}

func precomputeModel(bm *blockModel) *processedModel {
	p := &processedModel{}
	p.ambientOcclusion = bm.ambientOcclusion
	for ei := range bm.elements {
		// Render the last element first so that
		// grass's overlay works correctly.
		el := bm.elements[len(bm.elements)-1-ei]
		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)

			ux1 := int16(face.uv[0] * float64(tex.Width))
			ux2 := int16(face.uv[2] * float64(tex.Width))
			uy1 := int16(face.uv[1] * float64(tex.Height))
			uy2 := int16(face.uv[3] * float64(tex.Height))

			tw, th := int16(tex.Width), int16(tex.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 int16 = math.MaxInt16, math.MaxInt16, math.MaxInt16
			var maxX, maxY, maxZ int16 = math.MinInt16, math.MinInt16, math.MinInt16

			for v := range vert {
				vert[v].TX = uint16(tex.X)
				vert[v].TY = uint16(tex.Y + tex.Atlas*render.AtlasSize)
				vert[v].TW = uint16(tex.Width)
				vert[v].TH = uint16(tex.Height)

				if vert[v].X == 0 {
					vert[v].X = int16(el.from[0] * 16)
				} else {
					vert[v].X = int16(el.to[0] * 16)
				}
				if vert[v].Y == 0 {
					vert[v].Y = int16(el.from[1] * 16)
				} else {
					vert[v].Y = int16(el.to[1] * 16)
				}
				if vert[v].Z == 0 {
					vert[v].Z = int16(el.from[2] * 16)
				} else {
					vert[v].Z = int16(el.to[2] * 16)
				}

				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[v].X) - r.origin[0]*16
						z := float64(vert[v].Z) - r.origin[2]*16
						vert[v].X = int16(r.origin[0]*16 + (x*c - z*s))
						vert[v].Z = int16(r.origin[2]*16 + (z*c + x*s))
					case "x":
						rotX := r.angle * (math.Pi / 180)
						c := math.Cos(-rotX)
						s := math.Sin(-rotX)
						z := float64(vert[v].Z) - r.origin[2]*16
						y := float64(vert[v].Y) - r.origin[1]*16
						vert[v].Z = int16(r.origin[2]*16 + (z*c - y*s))
						vert[v].Y = int16(r.origin[1]*16 + (y*c + z*s))
					case "z":
						rotZ := r.angle * (math.Pi / 180)
						c := math.Cos(-rotZ)
						s := math.Sin(-rotZ)
						x := float64(vert[v].X) - r.origin[0]*16
						y := float64(vert[v].Y) - r.origin[1]*16
						vert[v].X = int16(r.origin[0]*16 + (x*c - y*s))
						vert[v].Y = int16(r.origin[1]*16 + (y*c + x*s))
					}
				}

				if bm.x > 0 {
					rotX := bm.x * (math.Pi / 180)
					c := int16(math.Cos(rotX))
					s := int16(math.Sin(rotX))
					z := vert[v].Z - 8*16
					y := vert[v].Y - 8*16
					vert[v].Z = 8*16 + int16(z*c-y*s)<commit_msg>steven: fix more issues with model rotation<commit_after>// Copyright 2015 <NAME>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package steven

import (
	"image"
	"math"

	"github.com/thinkofdeath/steven/render"
	"github.com/thinkofdeath/steven/render/builder"
	"github.com/thinkofdeath/steven/type/direction"
)

type processedModel struct {
	faces            []processedFace
	ambientOcclusion bool
}

type processedFace struct {
	cullFace  direction.Type
	facing    direction.Type
	vertices  []chunkVertex
	shade     bool
	tintIndex int
}

var faceRotation = []direction.Type{
	direction.North,
	direction.East,
	direction.South,
	direction.West,
}

var faceRotationX = []direction.Type{
	direction.North,
	direction.Down,
	direction.South,
	direction.Up,
}

func rotateDirection(val direction.Type, offset int, rots []direction.Type, invalid ...direction.Type) direction.Type {
	for _, d := range invalid {
		if d == val {
			return val
		}
	}
	var pos int
	for di, d := range rots {
		if d == val {
			pos = di
			break
		}
	}
	return rots[(pos+offset)%len(rots)]
}

func precomputeModel(bm *blockModel) *processedModel {
	p := &processedModel{}
	p.ambientOcclusion = bm.ambientOcclusion
	for ei := range bm.elements {
		// Render the last element first so that
		// grass's overlay works correctly.
		el := bm.elements[len(bm.elements)-1-ei]
		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)

			ux1 := int16(face.uv[0] * float64(tex.Width))
			ux2 := int16(face.uv[2] * float64(tex.Width))
			uy1 := int16(face.uv[1] * float64(tex.Height))
			uy2 := int16(face.uv[3] * float64(tex.Height))

			tw, th := int16(tex.Width), int16(tex.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 int16 = math.MaxInt16, math.MaxInt16, math.MaxInt16
			var maxX, maxY, maxZ int16 = math.MinInt16, math.MinInt16, math.MinInt16

			for v := range vert {
				vert[v].TX = uint16(tex.X)
				vert[v].TY = uint16(tex.Y + tex.Atlas*render.AtlasSize)
				vert[v].TW = uint16(tex.Width)
				vert[v].TH = uint16(tex.Height)

				if vert[v].X == 0 {
					vert[v].X = int16(el.from[0] * 16)
				} else {
					vert[v].X = int16(el.to[0] * 16)
				}
				if vert[v].Y == 0 {
					vert[v].Y = int16(el.from[1] * 16)
				} else {
					vert[v].Y = int16(el.to[1] * 16)
				}
				if vert[v].Z == 0 {
					vert[v].Z = int16(el.from[2] * 16)
				} else {
					vert[v].Z = int16(el.to[2] * 16)
				}

				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[v].X) - r.origin[0]*16
						z := float64(vert[v].Z) - r.origin[2]*16
						vert[v].X = int16(r.origin[0]*16 + (x*c - z*s))
						vert[v].Z = int16(r.origin[2]*16 + (z*c + x*s))
					case "x":
						rotX := -r.angle * (math.Pi / 180)
						c := math.Cos(-rotX)
						s := math.Sin(-rotX)
						z := float64(vert[v].Z) - r.origin[2]*16
						y := float64(vert[v].Y) - r.origin[1]*16
						vert[v].Z = int16(r.origin[2]*16 + (z*c - y*s))
						vert[v].Y = int16(r.origin[1]*16 + (y*c + z*s))
					case "z":
						rotZ := -r.angle * (math.Pi / 180)
						c := math.Cos(-rotZ)
						s := math.Sin(-rotZ)
						x := float64(vert[v].X) - r.origin[0]*16
						y := float64(vert[v].Y) - r.origin[1]*16
						vert[v].X = int16(r.origin[0]*16 + (x*c - y*s))
						vert[v].Y = int16(r.origin[1]*16 + (y*c + x*s))
					}
				}

				if bm.x > 0 {
					rotX := bm.x * (math.Pi / 180)
					c := int16(math.Cos(rotX))
					s := int16(math.Sin(rotX))
					z := vert[v].Z - 8*16
					y := vert[v].Y - 8*16
					vert[v].Z = 8*16 + int16(z*c-y*s)
{'fraction_non_alphanumeric': 0.15942165942165942, 'fraction_numerical': 0.042147042147042145, 'mean_word_length': 2.5194546059195213, 'pattern_counts': {'":': 6, '<': 5, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4358705', 'n_tokens_mistral': 5139, 'n_tokens_neox': 4063, 'n_words': 965}