# -*- indent-tabs-mode: t -*-

# Soya 3D tutorial
# Copyright (C) 2001-2004 Jean-Baptiste LAMY
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


# modeling-cellshading-1: Modeling : using cell-shading !

# Cell-shading gives a cartoon-like look to your 3D objects by :
#  - adding an outline around this object
#  - shading the object in a non-linear way, according to a 'shader'
#
# The shader is a 1-dimensional gray texture that maps light intensity to the shade level ;
# usually the shader have only a few color levels. See tutorial/data.images/shader.png for
# an example.
#
# In Soya, cell-shading can be activated during world-to-model compilation.
# In this tuto, we'll draw 2 rotating swords, one normal and one with cell-shading.

# To add cell-shading to an animated character, see also tutorial lesson
# character-animation-shadow-cellshading-1.


# Imports and inits Soya (see lesson basic-1.py).

import sys, os, os.path, soya

soya.init()
soya.path.append(os.path.join(os.path.dirname(sys.argv[0]), "data"))

# Creates the scene.

scene = soya.World()

# Set up an atmosphere, so as the background is white (in order to see the black outline
# of the cell-shading).

scene.atmosphere = soya.Atmosphere()
scene.atmosphere.bg_color = (1.0, 1.0, 1.0, 1.0)


# Loads the sword model

sword = soya.World.get("sword")

# Modify the material, for a better effect

material = sword.children[0].material
material.texture = soya.Image.get("epee_turyle-cs.png")
#material.separate_specular = 1
#material.shininess = 15.0
#material.specular = (1.0, 1.0, 1.0, 1.0)

# Compiles the sword model to a normal model

sword_model = sword.to_model()

# Creates the shader. The shader is a normal material with a texture.

shader = soya.Material()
shader.texture = soya.Image.get("shader.png")

# Creates a cell-shading model_builder object. A model_builder is an object that says how a world
# is compiled into a model. When no model_builder is specified, Soya uses the default model_builder
# (an instance of SimpleModelBuilder, that does not include cell-shading effect).

cellshading = soya.CellShadingModelBuilder()

# Sets the model_builder properties. These properties can also be passed to the constructor,
# see docstrings for more info.
# The shader property is (obviously) the shader :-)
# outline_color specifies the color of the outline (default : black)
# outline_width specifies the width of the outline (default 4.0) ; set to 0.0 for no outline
# outline_attenuation specifies how the distance affects the outline_width (default 0.3).

cellshading.shader              = shader
cellshading.outline_color       = (0.0, 0.0, 0.0, 1.0)
cellshading.outline_width       = 7.0
cellshading.outline_attenuation = 1.0

# Assigns the model_builder to the sword.

sword.model_builder = cellshading

# Compiles the sword model to a cell-shaded model. Notice that is you save the sword now,
# the model_builder would be saved with it too, and thus you can use 'soya.Model.get("sword")'
# with cell-shading.

sword_cellshaded_model = sword.to_model()

# Create a rotating body class, and 2 rotating bodys. The left one is normal, the right
# one is cell-shaded.

class RotatingBody(soya.Body):
	def __init__(self, parent = None, model = None, sens = 1.0):
		soya.Body.__init__(self, parent, model)
		self.sens = sens
		
	def advance_time(self, proportion):
		soya.Body.advance_time(self, proportion)
		self.rotate_y(proportion * 2.0 * self.sens)

body1 = RotatingBody(scene, sword_model)
body1.set_xyz(-1.0, 0.0, 0.0)
body1.rotate_x(90.0)

body2 = RotatingBody(scene, sword_cellshaded_model, -1)
body2.set_xyz( 1.0, 0.0, 0.0)
body2.rotate_x(90.0)

# Creates a light.

light = soya.Light(scene)
light.set_xyz(0.0, 1.0, 1.0)

# Creates a camera.

camera = soya.Camera(scene)
camera.set_xyz(0.0, 0.8, 2.5)
soya.set_root_widget(camera)

soya.MainLoop(scene).main_loop()

