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

# Soya 3D tutorial
# Copyright (C) 2004      Jean-Baptiste 'Jiba'  LAMY
# Copyright (C) 2001-2002 Bertrand 'blam!' 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


# terrain-1: Terrain : bitmap-based terrain

# This lesson shows how to make a terrain (also known as heightmap or terrain), using
# a bitmap to describe the terrain. The bitmap acts like a popographic map ; the brighter
# a pixel is, the higher it is. You can make such bitmaps in software like the Gimp.


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

import sys, os, os.path, soya, soya.sdlconst

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

# Creates the scene.

scene = soya.World()

# Creates a new terrain in the scene.

terrain = soya.Terrain(scene)

# Gets the image "map1.png" from the tutorial data dir, and create the terrain
# from this image. The image dimension must be power of 2 plus 1 : (2 ** n) + 1.

terrain.from_image(soya.Image.get("map1.png"))

# By default, the terrain height ranges from 0.0 (black pixels) to 1.0 (white pixels).
# Here, we multiply the height by 8.0 so it ranges from 0.0 to 8.0.

terrain.multiply_height(8.0)

# Now that we have the terrain, we are going to texture it
# (see lesson modeling-material-2 about texturing). First, we creates two textured
# materials.

material1 = soya.Material.get("block2")
material2 = soya.Material.get("metal1")

# asigns MATERIAL1 to any point whose height is in the range 0.0-6.0, and material2 to
# any point whose height is in the range 6.0-8.0 (remember, height ranges from 0.0 to 8.0).

terrain.set_material_layer(material1, 0.0, 6.0)
terrain.set_material_layer(material2, 6.0, 8.0)

# Assigns material1 to any point whose height is in the range 0.0-8.0 and if the angle
# between the surface normal and the vertical vector is in the range 0.0-20.0.

terrain.set_material_layer_angle(material1, 0.0, 8.0, 0.0, 20.0)

# Now we set some Terrain attributes:
#  - texture_factor specifies how much the textures are zoomed (higher values mean
#    smaller texture)

#  - scale_factor specifies how the terrain is scaled in the 2 horizontal dimensions.

#  - the 2 last attributes influence the behaviour of the level of detail (LOD) algorithm
#    (LOD means that parts of the terrain are rendered with more detail / more triangle
#    if they are close to the camera). They are a trading between speed and quality.
#    
#    The higher split_factor is, the better precision you have (it means more triangles
#    to draw the Terrain even far from Camera).
#    
#    patch_size represents the size of patches. A patch is a square part of the Terrain that
#    computes its visibility and precision.

# the values below are the default ones.
 
terrain.texture_factor = 1.0
terrain.scale_factor   = 1.0
terrain.patch_size     = 8
terrain.split_factor   = 2.0
terrain.texture_factor = 0.25

# Moves the terrain.

terrain.y = -2.5

# Adds a light.

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

# Adds a keyboard-controlled camera and a rendering loop

class MovableCamera(soya.Camera):
	def __init__(self, parent):
		soya.Camera.__init__(self, parent)
		
		self.speed = soya.Vector(self)
		self.rotation_y_speed = 0.0
		self.rotation_x_speed = 0.0
		
	def begin_round(self):
		soya.Camera.begin_round(self)
		
		for event in soya.process_event():
			if event[0] == soya.sdlconst.KEYDOWN:
				if   event[1] == soya.sdlconst.K_UP:     self.speed.z = -1.0
				elif event[1] == soya.sdlconst.K_DOWN:   self.speed.z =  1.0
				elif event[1] == soya.sdlconst.K_LEFT:   self.rotation_y_speed =  10.0
				elif event[1] == soya.sdlconst.K_RIGHT:  self.rotation_y_speed = -10.0
				elif event[1] == soya.sdlconst.K_q:      soya.MAIN_LOOP.stop()
				elif event[1] == soya.sdlconst.K_ESCAPE: soya.MAIN_LOOP.stop()
			if event[0] == soya.sdlconst.KEYUP:
				if   event[1] == soya.sdlconst.K_UP:     self.speed.z = 0.0
				elif event[1] == soya.sdlconst.K_DOWN:   self.speed.z = 0.0
				elif event[1] == soya.sdlconst.K_LEFT:   self.rotation_y_speed = 0.0
				elif event[1] == soya.sdlconst.K_RIGHT:  self.rotation_y_speed = 0.0
			
	def advance_time(self, proportion):
		self.add_mul_vector(proportion, self.speed)
		self.turn_y(self.rotation_y_speed * proportion)
		self.turn_x(self.rotation_x_speed * proportion)
		

camera = MovableCamera(scene)
camera.set_xyz(16.0, 6.0, 0.0)
camera.look_at(soya.Point(scene, 16.0, 6.0, 10.0))
soya.set_root_widget(camera)


#camera.set_xyz(16.0, 8.0, 0.0)
#camera.look_at(soya.Point(scene, 16.0, 6.0, 10.0))


scene.x = 100.0


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

#soya.MainLoop(scene).main_loop()
i = soya.MainLoop(scene)
#i.min_frame_duration = 0.0
i.main_loop()
print i.fps
