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
