# Soya 3D
# Copyright (C) 2001-2004 Jean-Baptiste LAMY -- jiba@tuxfamily.org
#
# 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

cdef int SHADER_ENABLED
SHADER_ENABLED = 0

class ShaderError(StandardError):
  pass

def init_shader():
  return _init_shader()

cdef int _init_shader():
  global SHADER_ENABLED
  SHADER_ENABLED = 0
  
  if glewGetExtension("GL_ARB_fragment_shader") != GL_TRUE:
    print "* Soya * GL_ARB_fragment_shader extension is not available => disabling shaders"
    return 0
  
  if glewGetExtension("GL_ARB_vertex_shader") != GL_TRUE:
    print "* Soya * GL_ARB_vertex_shader extension is not available => disabling shaders";
    return 0
  
  if glewGetExtension("GL_ARB_shader_objects") != GL_TRUE:
    print "* Soya * GL_ARB_shader_objects extension is not available => disabling shaders"
    return 0
  
  SHADER_ENABLED = 1
  return 1

cdef void _raise_shader_error():
  cdef int     blen
  cdef int     slen
  cdef GLchar* compiler_log
  
  glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &blen)
  if blen > 1:
    compiler_log = <GLchar*> malloc(blen)
    glGetInfoLogARB(shader, blen, &slen, compiler_log)
    log = PyString_FromStringAndSize(<GLchar*> compiler_log, slen)
    free(compiler_log)
    print "ShaderError"
    print log
    print
    raise ShaderError(log)
  

cdef class _Shader:
  cdef GLhandleARB _shader
  
  def __init__(self, code):
    self._compile(code)
    
  def __dealloc__disabled(self):
    glDeleteObjectARB(self._shader)
    
  cdef _compile(self, code):
    if isinstance(code, unicode): code = code.encode("latin")
    
    cdef int length
    length = len(string)
    
    cdef GLubyte* buf
    buf = <GLubyte*> malloc((length + 1) * sizeof(GLubyte))
    memcpy(buf, PyString_AS_STRING(string), length)
    buf[length] = 0
    
    glShaderSourceARB(shader, 1, <GLchar**> &buf, &length)
    glCompileShaderARB(shader)
    free(buf)
    
    cdef int ok
    glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &ok)
    if ok == 0: _raise_shader_error()
    
cdef class _FragmentShader(_Shader):
  def __init__(self, code = ""):
    self._shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB)
    Shader.__init__(self, code)
    
cdef class _VertexShader(_Shader):
  def __init__(self, code = ""):
    self._shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB)
    Shader.__init__(self, code)
    


cdef class _Program:
  cdef GLhandleARB _program
  cdef _shaders
  
  def __init__(self, shaders = None):
    cdef _Shader shader
    
    self._program = glCreateProgramObjectARB()
    self._shaders = tuple(shaders) or ()
    if self._shaders:
      for shader in self._shaders:
        glAttachObjectARB(self._program, shader._shader)
      self._link()

  def __dealloc__(self):
    glDeleteObjectARB(self._program)
    
  property shaders:
    def __get__(self): return self._shaders
    
#   cdef add_shader(self, _Shader shader):
#     if not shader in self._shaders:
#       self._shaders.add(shader)
#       glAttachObjectARB(self._program, shader._shader)
      
#   cdef remove_shader(self, _Shader shader):
#     if shader in self._shaders:
#       self._shaders.remove(shader)
#       glDetachObjectARB(self._program, shader._shader)
      
  cdef _link(self):
    glLinkProgramARB(self._program)
    
    cdef int linked
    glGetObjectParameterivARB(self._program, GL_OBJECT_LINK_STATUS_ARB, &linked)
    if ok == 0: _raise_shader_error()
    


