Well, mostly. It compiles, but I haven't been able to test it because Pyrex wants to create a separate module, and I think that functions that take land ojects as arguments will probably break because they're expecting the P3 interface, and I've moved the P3 object to the _land attribute.

At one point I actually tried using P3_land as the struct for my Pyrex Land class, but that was a nonstarter because Pyrex wants to define the struct for you. Besides, if we'll be getting rid of the P3 system the way I actually implemented it (with the C struct as an attribute of the Pyrex class) is the correct way.

I've probably broken garbage collection to an extent as well.

Here it is.
# Soya 3D
# Copyright (C) 2001-2002 Jean-Baptiste LAMY -- [EMAIL PROTECTED]
#
# 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

# vim:et:syntax=python

#import soya, soya.soya3d
#import _soya

cdef extern from "stdlib.h":
    cdef void *malloc(int)
    cdef void free(void *)


cdef extern from "Python.h":
    object PyString_FromStringAndSize(char *, int)


cdef extern from "GL/gl.h":
    ctypedef float GLfloat
    ctypedef unsigned int GLuint


cdef extern from "../p3_base.h":
    ctypedef void P3_land_patch
    ctypedef void P3_image
    ctypedef void P3_light
    ctypedef void P3_xmesh

    ctypedef struct P3_chunk:
        void* content
        int nb
        int max

    ctypedef struct P3_land

    ctypedef struct P3_fx:
        GLfloat* color
        GLfloat alpha
        float duration
        void* obj
        GLfloat** vertex_warfogs
        GLfloat** vertex_colors
        char*     vertex_options
        #P3_list* list
        #P3_fx_transition_data* data
        void (*apply)(P3_fx* fx, int vertex_index)
        GLfloat* (*register_color)(P3_land* obj, GLfloat color[4])

    ctypedef struct P3_material:
        P3_image* image
        int option
        GLuint id
        GLfloat shininess
        GLfloat* diffuse
        GLfloat* specular
        GLfloat* emissive
        int nb_packs
        #P3_xpack** packs

    ctypedef struct P3_xpack:
        int option
        P3_material* material
        int data
        P3_xpack* secondpass
        P3_xpack* alpha

    ctypedef struct P3_land_vertex:
        GLfloat texcoord[2]
        GLfloat normal[3]
        GLfloat coord[3]
        P3_xpack* pack

    ctypedef struct P3_land:
        int option # from P3_OBJECT_HEADER
        int nb_materials       # the number of materials used by the heightmap
        P3_material** materials
        P3_land_vertex* vertices
        char* vertex_options
        GLfloat** vertex_colors
        GLfloat** vertex_warfogs
        GLfloat* normals       # full LOD triangles normals
        int nb_colors
        GLfloat* colors        # /* vertices colors */
        int nb_vertex_width    # /* size_width and size_depth must be (2^n) + 1 or I 
don't know what happen (crash?) */
        int nb_vertex_depth
        int patch_size
        int max_level
        GLfloat texture_factor # /* a factor that multiply the texture coordinates */
        GLfloat scale_factor # /* a factor to decide when the triangle must split 
(higher value means more accuracy) */
        GLfloat split_factor
        int nb_patchs
        int nb_patch_width
        int nb_patch_depth
        P3_land_patch* patchs

    cdef enum:
        P3_VERTEX_ALPHA = (1<<1)
        P3_VERTEX_MADE = (1<<3)
        P3_VERTEX_INVISIBLE = (1<<4)
        P3_VERTEX_FX_TRANSITION = (1<<5)

    cdef enum: 
        P3_LAND_VERTEX_HIDDEN =        (1<<0)
        P3_LAND_VERTEX_ALPHA =         P3_VERTEX_ALPHA
        P3_LAND_VERTEX_NON_SOLID =     (1<<2)
        P3_LAND_VERTEX_FORCE_PRESENCE = (1<<3)
        P3_LAND_VERTEX_INVISIBLE =     P3_VERTEX_INVISIBLE
        P3_LAND_VERTEX_FX_TRANSITION = P3_VERTEX_FX_TRANSITION


cdef extern from "../land.h":
    # Creation
    P3_land* P3_land_new(P3_land*, int width, int depth)
    void P3_land_from_image(P3_land*, P3_image*)
    void P3_land_init(object)
    void P3_land_set_material_layer(P3_land*, P3_material*, GLfloat start, GLfloat end)
    void P3_land_set_material_layer_angle(P3_land*, P3_material*, GLfloat start, 
GLfloat end, GLfloat angle_min, GLfloat angle_max)
    void P3_land_dealloc(P3_land*)
    void P3_land_add_material(P3_land*, object)
    void P3_land_set_height(P3_land*, int x, int y, GLfloat value)
    GLfloat P3_land_get_height(P3_land*, int x, int y)
    object P3_land_get_material(P3_land*, int x, int y)
    void P3_land_compute_normals(P3_land*)
    void P3_land_compute_coords(P3_land*)
    void P3_land_create_patchs(P3_land*)
    void P3_land_compute_shadow_color(P3_land*, object, GLfloat*)

    # Rendering
    GLfloat P3_land_get_height_at(P3_land*, GLfloat x, GLfloat z, GLfloat** norm)
    # fx (warfog) 
    void P3_land_check_vertex_options(P3_land*)
    GLfloat* P3_land_check_color(P3_land*, GLfloat*)
    void P3_land_check_warfog(P3_land*)
    GLfloat* P3_land_register_color(P3_land*, GLfloat[4])
    void P3_land_add_vertex_option_all(P3_land*, int flag)
    void P3_land_rem_vertex_option_all(P3_land*, int flag)
    void P3_land_fx_all(P3_land*, P3_fx*)
    void P3_land_fx_in_sphere(P3_land*, P3_fx*, GLfloat sphere[4])
    void P3_land_fx_in_cylinderY(P3_land*, P3_fx*, GLfloat cylinder[3])
                                                                                   
    # loading/saving
    void P3_land_get_data(P3_land*, P3_chunk*)
    void P3_land_set_data(P3_land*, P3_chunk*)
    

cdef extern from "../material.h":
    P3_xpack* P3_xpack_get(int, object)


cdef extern from "../util.h":
    P3_chunk* P3_chunk_new()


cdef extern from *:
    PyP3XMesh_GetMaterials(P3_land*)
    void PyP3XMesh_SetMaterials(P3_land*, object)
    void PyP3Fx_GetFx(P3_fx* fx, object args)


cdef class Land:
    """Land

    A landscape with level of details (LOD).
    """

    cdef P3_land* _land

    def __new__(self, size=0, name=''):
        self._land = P3_land_new(NULL, size, 0)         

    def __init__(self, size = 0, name = ""):
        """Land(size = 0, name = "") -> Land

        Creates a new Land of size SIZE, named NAME. SIZE must be like this: (2^n)+1
        (or can be 0)."""
        self.name = name

    def fade_borders(self, color = (0.0, 0.0, 0.0, 0.0)):
        cdef int x
        cdef int z

        for x from 0 <= x < self._land.nb_vertex_width:
            self.set_vertex_color(x, 0, color)

        for z from 0 <= z < self._land.nb_vertex_depth:
            self.set_vertex_color(0, z, color)

        z = self._land.nb_vertex_depth - 1
        for x from 0 <= x < self._land.nb_vertex_width:
            self.set_vertex_color(x, z, color)

        x = self._land.nb_vertex_width - 1
        for z from 0 <= z < self._land.nb_vertex_depth:
            self.set_vertex_color(x, z, color)
    
    
    def __repr__(self):
        if self.name: return "<Land %s>" % self.name
        return "<Land>"

    def __dealloc__(self):
        # How do we keep track of references to materials in land?
        # We have to make sure we're not leaking them and they don't
        # get deallocated while we're using them
        P3_land_dealloc(self._land)

    def _getstate(self):
        cdef P3_chunk chunk
        
        P3_land_get_data(self._land, &chunk)
        # XXX fixme - need to define PyP3XMesh_GetMaterials, etc
        return PyString_FromStringAndSize(<char*>chunk.content, chunk.nb), 
PyP3XMesh_GetMaterials(self._land)

    def _setstate(self, content, materials):
        cdef P3_chunk* chunk
        
        chunk = P3_chunk_new()

        PyP3XMesh_SetMaterials(self._land, materials)
        chunk.content = <char*>content
        P3_land_set_data(self._land, chunk)
        free(chunk)

    def from_image(self, o):
        cdef P3_image *image
        
        if o is None:
            image = NULL
        else:
            image = <P3_image*>o
        
        P3_land_from_image(self._land, image)

    def get_height(self, int x, int z):
        return P3_land_get_height(self._land, x, z)

    def get_height_at(self, double x, double z):
        return P3_land_get_height_at(self._land, x, z, NULL)

    def get_true_height_and_normal(self, double x, double z):
        cdef GLfloat* n

        height = P3_land_get_height_at(self._land, x, z, &n)
        # XXX how do we get access to the Vector type?
        v = _Vector(None, n[0], n[1], n[2])
        return height, v

    def set_height(self, int x, int z, double height):
        P3_land_set_height(self._land, x, z, height)

    def set_material_layer(self, material, GLfloat fr, GLfloat to): 
        P3_land_set_material_layer(self._land, <P3_material *>material, fr, to)
          
    def set_material_layer_angle(self, material, double height_from, double height_to, 
GLfloat angle_from, GLfloat angle_to):
        P3_land_set_material_layer_angle(self._land, <P3_material *>material, 
height_from, height_to, angle_from, angle_to)

    def multiply_height(self, GLfloat factor):
        cdef int i
        cdef int j

        for j from 0 <= j < self._land.nb_vertex_depth:
            for i from 0 <= i < self._land.nb_vertex_width:
                self._land.vertices[i + j*self._land.nb_vertex_width].coord[1] = 
self._land.vertices[i + j*self._land.nb_vertex_width].coord[1] * factor

    def add_height(self, GLfloat factor):
        cdef int i
        cdef int j

        for j from 0 <= j < self._land.nb_vertex_depth:
            for i from 0 <= i < self._land.nb_vertex_width:
                self._land.vertices[i + j*self._land.nb_vertex_width].coord[1] = 
self._land.vertices[i + j*self._land.nb_vertex_width].coord[1] + factor

    def get_material(self, int x, int z):
        return P3_land_get_material(self._land, x, z)

    def set_material(self, int x, int z, material):
        cdef P3_xpack* pack

        P3_land_add_material(self._land, material)
        pack = P3_xpack_get(P3_FACE_TRIANGLE, material)
        self._land.vertices[x + z*self._land.nb_vertex_width].pack = pack

    def remove_colors(self):
        # XXX need checking here
        free(self._land.colors)
        free(self._land.vertex_colors)
        free(self._land.vertex_warfogs)
        self._land.nb_colors = 0
        self._land.colors = NULL
        self._land.option = self._land.option & ~(P3_LAND_COLORED | PE_LAND_WARFOG)

    def compute_shadow_color(self, light, color):
        cdef GLfloat col[4]
        
        col[0] = color[0]
        col[1] = color[1]
        col[2] = color[2]
        col[3] = color[3]

        P3_land_compute_shadow_color(self._land, light, col)

    def get_vertex_option(self, int x, int z):
        return self.vertex_options[x + z*self._land.nb_vertex_width]

    def set_vertex_option(self, int x, int z, int option):
        P3_land_check_vertex_options(self._land)
        self._land.vertex_options[x, z*self._land.nb_vertex_width] = <char>option
    
    def set_vertex_color(self, int x, int z, col):
        cdef GLfloat color[4]
        cdef GLfloat* color_ptr
        cdef int n

        color[0] = col[0]
        color[1] = col[1]
        color[2] = col[2]
        color[3] = col[3]
        
        n = x + z*self._land.nb_vertex_width
        color_ptr = P3_land_check_color(self._land, color)
        self._land.vertex_colors[n] = color
        if 1.0-color[3] > P3_EPSILON:
            # Turn on alpha for this vertex
            self._land.vertex_options[n] = self._land.vertex_options[n] | 
P3_LAND_VERTEX_ALPHA
        elif self._land.option & P3_LAND_VERTEX_OPTIONS:
            self._land.vertex_options[n] = self._land.vertex_options[n] & 
~P3_LAND_VERTEX_ALPHA
        
        if color[3] < P3_EPSILON:
            self._land.vertex_options[n] = self._land.vertex_options[n] | 
P3_LAND_VERTEX_HIDDEN
        elif self._land.option & PE_LAND_VERTEX_OPTIONS:
            self._land.vertex_options[n] = self._land.vertex_options[n] & 
~P3_LAND_VERTEX_HIDDEN

    def init_fx(self):
        P3_land_check_warfog(self._land)

    def vertex_fx(self, *args):
        cdef P3_fx fx
        cdef GLfloat sphere[4]

        fx.obj = <void*>self._land
        fx.register_color = P3_land_register_color
        fx.vertex_warfogs = self._land.vertex_warfogs
        fx.vertex_colors = self._land.vertex_colors
        fx.vertex_options = self._land.vertex_options
        PyP3Fx_GetFx(&fx, args)
        if args[0] is None:
            P3_land_fx_all(self._land, &fx)
        elif len(args[0]) == 3:
            sphere[0] = select[0]
            sphere[1] = select[1]
            sphere[2] = select[2]
            P3_land_fx_in_cylinderY(self._land, &fx, sphere)
        else:
            sphere[0] = select[0]
            sphere[1] = select[1]
            sphere[2] = select[2]
            sphere[3] = select[3]
            P3_land_fx_in_sphere(self._land, &fx, sphere)

    def reinit(self):
        self._land.option = self._land.option & ~P3_LAND_INITED

    def __getattr__(self, attr):
        if attr == 'width':
            return self._land.nb_vertex_width
        elif attr == 'depth':
            return self._land.nb_vertex_depth
        elif attr == 'has_vertex_options':
            if self._land.option & P3_LAND_VERTEX_OPTIONS:
                return 1
            else:
                return 0
        elif attr == 'split_factor':
            return self._land.split_factor
        elif attr == 'scale_factor':
            return self._land.scale_factor
        elif attr == 'texture_factor':
            return self._land.texture_factor
        elif attr == 'patch_size':
            return self._land.patch_size
        elif attr == 'raypick_with_lod':
            if self._land.option & P3_LAND_REAL_LOD_RAYPICK:
                return 1
            else:
                return 0

    def __setattr__(self, attr, value):
        if attr == 'width':
            raise ValueError, 'Cannot set width'
        elif attr == 'depth':
            raise ValueError, 'Cannot set depth'
        elif attr == 'has_vertex_options':
            free(self._land.vertex_options)
            if value:
                self._land.option = self._land.option | P3_LAND_VERTEX_OPTIONS
                self._land.vertex_options = <char*>malloc(self._land.nb_vertex_width * 
self._land.nb_vertex_depth * sizeof(char))
            else:
                self._land.option = self._land.option & ~P3_LAND_VERTEX_OPTIONS
                self._land.vertex_options = NULL
        elif attr == 'scale_factor':
            self._land.scale_factor = value
            self._land.option = self._land.option & ~P3_LAND_INITED
        elif attr == 'split_factor':
            self._land.split_factor = value
        elif attr == 'texture_factor':
            self._land.texture_factor = value
            P3_land_compute_coords(self._land)
        elif attr == 'patch_size':
            self._land.patch_size = value
            self._land.option = self.option & ~P3_LAND_INITED
        elif attr == 'raypick_with_lod':
            if value:
                self._land.option = self.option | P3_LAND_REAL_LOD_RAYPICK
            else:
                self._land.option = self.option & ~P3_LAND_REAL_LOD_RAYPICK

Reply via email to