#!/usr/local/bin/python
###########################################################################
# cgkit - Python Computer Graphics Kit
# Copyright (C) 2004 Matthias Baas (baas@ira.uka.de)
#
# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# cgkit homepage: http://cgkit.sourceforge.net
###########################################################################
# $Id: render.py,v 1.6 2005/08/15 15:47:56 mbaas Exp $

"""Render tool."""

import sys, os, optparse, glob, time
from cgkit.ri import *
from cgkit.riutil import *

from math import *
from cgkit.all import *
from cgkit.Interfaces import *
from cgkit.cmds import *
from cgkit.tool import Tool


renderers = { "aqsis"    : ("aqsis", "aqsl", "teqser"),
              "3delight" : ("renderdl", "shaderdl", "tdlmake"),
              "pixie"    : ("rndr", "sdrc", "texmake"),
              "bmrt"     : ("rendrib", "slc", "mkmip"),
              "prman"    : ("prman", "shader", "txmake"),
              "rdc"      : ("renderdc", "shaderdc", "texdc"),
              "air"      : ("air", "shaded", "mktex") }


class RenderException(Exception):
    pass

# Render
class Render(Tool):
    """Render tool."""
    
    def __init__(self):
        Tool.__init__(self, defaultoptionvar="RENDER_DEFAULT_OPTIONS")

    def setOptions(self, optparser):
        """Add options specific to this tool."""
        
        Tool.setOptions(self, optparser)
        optparser.add_option("-r", "--renderer", type="string",
                             default="aqsis",
                             help="Renderer to use")
        optparser.add_option("-I", "--include", action="append", default=[],
                             help="Add include path for shader compilation")
        optparser.add_option("-B", "--bake", action="store_true", default=False,
                             help="Bake a texture map")

    def init(self):
        if self.options.renderer not in renderers:
            raise RenderException("Unknown renderer: %s"%self.options.renderer)

    # setOptionsFromGlobals
    def setOptionsFromGlobals(self):
        Tool.setOptionsFromGlobals(self)

        scene = getScene()
        self.options.bake = scene.getGlobal("bake", self.options.bake)

    def action(self):

        scene = getScene()
        timer = scene.timer()

        renderer, slcompiler, textool = renderers[self.options.renderer]
        ribname = "main.rib"
        output = scene.getGlobal("output", "out.tif")

        while 1:
            print 'Exporting %s...'%ribname
            t1 = time.time()
            framenr = int(round(timer.frame))

            # Determine output name
            if self.time_end==None:
                outname = output
            else:
                name, ext = os.path.splitext(output)
                outname = "%s%04d%s"%(name, framenr, ext)

            # Determine the model to bake...
            bakemodel = scene.getGlobal("bakemodel", None)
            bakestvar = scene.getGlobal("bakestvar", "st")
            if self.options.bake:
                if bakemodel==None:
                    # Get a list of all trimeshes/polyhedrons
                    meshes = filter(lambda obj: isinstance(obj.geom, TriMeshGeom) or isinstance(obj.geom, PolyhedronGeom), list(scene.walkWorld()))
                    if len(meshes)==1:
                        bakemodel = meshes[0]
                    else:
                        print "Please specify a bake model using the 'bakemodel' global"
                        sys.exit(1)
            
            # Create RIB & shaders
            save(ribname,
                 camera = self.cam,
                 output = outname,
                 output_framebuffer = (self.time_end==None),
                 bake = self.options.bake,
                 bakemodel = bakemodel,
                 bakestvar = bakestvar
                 )

            # Compile shaders
            if os.path.exists("shaders"):
                print "Compiling shaders..."
                oldpath = os.getcwd()
                os.chdir("shaders")
                self.compileSL(slcompiler)
                os.chdir(oldpath)

            t2 = time.time()
            print "Preprocessing time:",self.time2str(t2-t1)

            # Render
            print 'Rendering "%s" (frame %d)...'%(outname, framenr)
            os.system("%s %s"%(renderer, ribname))

            t3 = time.time()
            print "Rendering time:",self.time2str(t3-t2)

            # Increase time
            if self.time_end==None:
                break
            timer.step()
            if timer.time>self.time_end:
                break

    # compileSL
    def compileSL(self, slcompiler):
        """Compiles all shader in the current directory."""

        opts = ""
        for p in self.options.include:
            opts+="-I%s"%p
            
        shaders = glob.glob("*.sl")
        for shader in shaders:
            cmd = "%s %s %s"%(slcompiler, opts, shader)
#            print cmd
            os.system(cmd)

    def time2str(self, t):
        if t<60:
            return "%1.0fs"%t
        else:
            min = int(t/60)
            sec = int(t%60)
            if min<60:
                return "%dmin %ds"%(min,sec)
            else:
                h = int(min/60)
                min = int(min%60)
                return "%dh %dmin %ds"%(h,min,sec)
            
        

######################################################################

render = Render()
try:
    render.run()
except RenderException, e:
    print e
