--[[
Template to Easily Make Fancy Voxelized Models
Copyright (C) 2020 Noodlemire

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
--]]

--[[
Some important notes about how to use Voxelmodel:

Using the model itself means giving nodes the "mesh" drawtype, and setting their mesh to "voxelmodel.obj"

It should be provided a texture with an aspect ratio of 3:17.

Voxelmodel textures use an even grid of squares within the texture. The default square size is 16px.
See the included voxelmodel_guide.png for more details. It shows which column corresponds to which axis,
which end of each column is positive or negative, and has color-coded borders to show how axis are aligned.

Due to the nature of how it works, disable backface_culling for all nodes and entities that use voxelmodel.
Nodes have it disabled by default, but entities need it specified in their initial_properties table.

Please provide some kind of inventory and wield image. The default wield model will be partially culled.
--]]

--If default is enabled and bookshelf overriding is enabled...
if default and minetest.settings:get_bool("voxelmodel_override_bookshelf") then
	--Override the default bookshelf to look like the voxelmodel bookshelf
	minetest.override_item("default:bookshelf", {
		drawtype = "mesh",
		mesh = "voxelmodel.obj",
		tiles = {"voxelmodel_bookshelf.png"},
		inventory_image = "voxelmodel_bookshelf_inv.png",
		wield_image = "voxelmodel_bookshelf_inv.png",
	})
else
	--The voxelmodel bookshelf is designed to look like the default bookshelf, 
	--but with added depth so you can see the covers of the books and the inside of the shelf.
	minetest.register_node("voxelmodel:bookshelf", {
		description = "Voxelmodel Bookshelf",

		groups = {oddly_breakable_by_hand = 1},

		paramtype = "light",
		paramtype2 = "facedir",

		drawtype = "mesh",
		mesh = "voxelmodel.obj",
		tiles = {"voxelmodel_bookshelf.png"},
		inventory_image = "voxelmodel_bookshelf_inv.png",
		wield_image = "voxelmodel_bookshelf_inv.png",
	})
end

--The cat is a very basic entity meant to demonstrate some of the possibilities of voxelmodel-based animation,
--As well as an example of how entities can use voxelmodel in general.
--Its behavior is limited to alternating between wandering and standing still in 3 second intervals
--And sometimes blinking.
minetest.register_entity("voxelmodel:cat", {
	initial_properties = {
		physical = true,
		visual = "mesh",
		mesh = "voxelmodel.obj",
		textures = {"voxelmodel_cat_idle.png"},
		visual_size = {x = 10, y = 10},
		automatic_face_movement_dir = 90,
		backface_culling = false,
		static_save = false,
	},

	--Every cat is spawned with the following:
	on_activate = function(self)
		--A walk timer that counts up with dtime. When it reaches 3, the cat either starts walking, or stops walking.
		self.walk_timer = 0
		self.walking = false

		--A frame animation timer that counts up with dtime. When it reaches 0.1, the cat switches to the next frame.
		--This is necessary because animating a mesh's texture automatically doesn't seem possible.
		self.frame_timer = 0
		self.frame = 1

		--A blink timer that counts down with dtime. The cooldown between blinks is a random number in the range [4, 7] seconds.
		--When it reaches 0, the cat starts blinking. While blinking, the timer is reset to 0.4 seconds.
		--When it reaches 0 again, the cat opens its eyes again, and the cooldown begins again.
		self.blink_timer = math.random(4, 7)
		self.blinking = false

		--Enable gravity by giving the cat a downwards acceleration of -9.81
		self.object:set_acceleration({x = 0, y = -9.81, z = 0})
	end,

	--On each globalstep...
	on_step = function(self, dtime, moveresult)
		--First check the blink timer.
		self.blink_timer = self.blink_timer - dtime

		if self.blink_timer <= 0 then
			--Invert the blinking boolean.
			self.blinking = not self.blinking

			if self.blinking then
				--If it should blink now, do so by setting its texture mod to an overlay.
				self.object:set_texture_mod("^voxelmodel_cat_blink.png")
				self.blink_timer = 0.4
			else
				--Otherwise, clear the texture mod.
				self.object:set_texture_mod("")
				self.blink_timer = math.random(4, 7)
			end
		end

		--If it is currently meant to be walking...
		if self.walking then
			--Check its animation frame timer (as it isn't animated when idle)
			self.frame_timer = self.frame_timer + dtime

			if self.frame_timer >= 0.1 then
				self.frame_timer = self.frame_timer - 0.1

				--Increment the frame, but reset it to 1 if it goes too high
				self.frame = self.frame + 1
				if self.frame > 5 then
					self.frame = 1
				end

				--Replace the base texture repeatedly to make it animate.
				self.object:set_properties({textures = {"voxelmodel_cat_walk_"..self.frame..".png"}})
			end
		end

		--Check the walk timer...
		self.walk_timer = self.walk_timer + dtime

		if self.walk_timer >= 3 then
			self.walk_timer = self.walk_timer - 3

			--Invert the walking variable.
			self.walking = not self.walking

			if self.walking then
				--If it should start walking now...

				--First, get a random decimal between 0 and 2.
				local vx = math.random() * 2
				--Set the z velocity to be the inverse of the x velocity, so overall velocity is always 2.
				local vz = 2 - vx

				--The velocities of either axis have independent 50% chances to move in the opposite direction.
				--This overall has an evenly random chance to move in any possible horizontal direction.
				if math.random(2) == 1 then vx = -vx end
				if math.random(2) == 1 then vz = -vz end

				--Get the previous velocity in order to preserve vertical velocity.
				local vel = self.object:get_velocity()
				--Then, change the velocity to the newfound values.
				self.object:set_velocity({x = vx, y = vel.y, z = vz})
			else
				--Otherwise, give it the idle texture and halt its horizontal velocity.
				self.object:set_properties({textures = {"voxelmodel_cat_idle.png"}})

				local vel = self.object:get_velocity()
				self.object:set_velocity({x = 0, y = vel.y, z = 0})
			end
		end
	end,

	--Make the cat instantly die if you dare to hit it, you monster.
	on_punch = function(self)
		self.object:remove()
	end,
})

--This craftitem is used to spawn cats.
minetest.register_craftitem("voxelmodel:cat", {
	description = "Voxelmodel Cat",

	inventory_image = "voxelmodel_cat_inv.png",
	wield_image = "voxelmodel_cat_inv.png",

	on_place = function(itemstack, placer, pointed_thing)
		pointed_thing.above.y = pointed_thing.above.y + 0.1
		minetest.add_entity(pointed_thing.above, "voxelmodel:cat")

		if not minetest.is_creative_enabled(placer:get_player_name()) then
			itemstack:take_item()
		end

		return itemstack
	end
})

--A very basic voxelnode with a very easily "readable" texture. If you study this first, it shouldn't be too hard to picture how its texture works.
minetest.register_node("voxelmodel:table", {
	description = "Voxelmodel Table",

	groups = {oddly_breakable_by_hand = 1},

	paramtype = "light",
	sunlight_propogates = true,

	drawtype = "mesh",
	mesh = "voxelmodel.obj",
	tiles = {"voxelmodel_table.png"},
	inventory_image = "voxelmodel_table_inv.png",
	wield_image = "voxelmodel_table_inv.png",
})

--An example of an animated node. The flame on the torch's tip will visibly wave around.
--There would be an option to override default torches, but I didn't feel like making wall or ceiling models.
minetest.register_node("voxelmodel:torch", {
	description = "Voxelmodel Torch",

	groups = {oddly_breakable_by_hand = 1},

	paramtype = "light",
	sunlight_propogates = true,
	light_source = 12,

	drawtype = "mesh",
	mesh = "voxelmodel.obj",
	tiles = {{name = "voxelmodel_torch.png", animation = {type = "sheet_2d", frames_w = 5, frames_h = 1, frame_length = 0.333}}},
	inventory_image = "voxelmodel_torch_inv.png",
	wield_image = "voxelmodel_torch_inv.png",

	walkable = false,
})
