PixelLightAPI  .
Mesh.h
Go to the documentation of this file.
00001 /*********************************************************\
00002  *  File: Mesh.h                                         *
00003  *
00004  *  Copyright (C) 2002-2011 The PixelLight Team (http://www.pixellight.org/)
00005  *
00006  *  This file is part of PixelLight.
00007  *
00008  *  PixelLight is free software: you can redistribute it and/or modify
00009  *  it under the terms of the GNU Lesser General Public License as published by
00010  *  the Free Software Foundation, either version 3 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  PixelLight is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  *  GNU Lesser General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU Lesser General Public License
00019  *  along with PixelLight. If not, see <http://www.gnu.org/licenses/>.
00020 \*********************************************************/
00021 
00022 
00023 #ifndef __PLMESH_MESH_H__
00024 #define __PLMESH_MESH_H__
00025 #pragma once
00026 
00027 
00028 //[-------------------------------------------------------]
00029 //[ Includes                                              ]
00030 //[-------------------------------------------------------]
00031 #include <PLCore/Container/Resource.h>
00032 #include <PLMath/Vector3.h>
00033 #include "PLMesh/Weight.h"
00034 #include "PLMesh/AnchorPoint.h"
00035 #include "PLMesh/VertexWeights.h"
00036 #include "PLMesh/MorphTargetAni.h"
00037 
00038 
00039 //[-------------------------------------------------------]
00040 //[ Forward declarations                                  ]
00041 //[-------------------------------------------------------]
00042 namespace PLRenderer {
00043     class Renderer;
00044     class Material;
00045     class MaterialHandler;
00046 }
00047 namespace PLMesh {
00048     class Skeleton;
00049     class MeshManager;
00050     class MeshLODLevel;
00051     class MeshMorphTarget;
00052     class SkeletonHandler;
00053 }
00054 
00055 
00056 //[-------------------------------------------------------]
00057 //[ Namespace                                             ]
00058 //[-------------------------------------------------------]
00059 namespace PLMesh {
00060 
00061 
00062 //[-------------------------------------------------------]
00063 //[ Classes                                               ]
00064 //[-------------------------------------------------------]
00065 /**
00066 *  @brief
00067 *    Mesh triangle
00068 */
00069 class MeshTriangle {
00070     public:
00071     PLCore::uint32 nGeometry;       /**< Index of the geometry this triangle is in */
00072     PLCore::uint32 nVertex[3];      /**< The three vertex indices */
00073     int           nNeighbour[3];    /**< Neighbor triangles */
00074 
00075     PLMESH_API MeshTriangle &operator =(const MeshTriangle &cSource);
00076     PLMESH_API bool operator ==(const MeshTriangle &cMeshTriangle) const;
00077 };
00078 
00079 /**
00080 *  @brief
00081 *    Mesh edge
00082 */
00083 class MeshEdge {
00084     public:
00085     PLCore::uint32 nVertex[2];      /**< The two edge vertex indices */
00086     PLCore::uint32 nTriangle[2];    /**< The two edge triangles */
00087 
00088     PLMESH_API MeshEdge &operator =(const MeshEdge &cSource);
00089     PLMESH_API bool operator ==(const MeshEdge &cMeshEdge) const;
00090 };
00091 
00092 /**
00093 *  @brief
00094 *    Mesh class
00095 *
00096 *  @remarks
00097 *    A mesh defining a 3D mesh consists of several information:\n
00098 *    Animations    (list of predefined animations)\n
00099 *    Anchor points (anchor points are in fact a kind of index to a vertex)\n
00100 *    Morph targets (that contains the vertex data for every frame)\n
00101 *    LOD levels    (each of which can define the geometries and/or index data)\n
00102 *    Skeleton      (that defines a hierarchical structure on the mesh)\n
00103 *    Materials     (list of materials used by the mesh)
00104 */
00105 class Mesh : public PLCore::Resource<Mesh> {
00106 
00107 
00108     //[-------------------------------------------------------]
00109     //[ Friends                                               ]
00110     //[-------------------------------------------------------]
00111     friend class MeshManager;
00112     friend class MeshMorphTarget;
00113 
00114 
00115     //[-------------------------------------------------------]
00116     //[ Public definitions                                    ]
00117     //[-------------------------------------------------------]
00118     public:
00119         /**
00120         *  @brief
00121         *    Mesh draw flags
00122         */
00123         enum EFlags {
00124             DrawVertices = 1<<0,    /**< Draw vertices */
00125             DrawNormals  = 1<<1,    /**< Draw normals */
00126             DrawOctree   = 1<<2     /**< Draw (optional) octree */
00127         };
00128 
00129 
00130     //[-------------------------------------------------------]
00131     //[ Public functions                                      ]
00132     //[-------------------------------------------------------]
00133     public:
00134         //[-------------------------------------------------------]
00135         //[ Main functions                                        ]
00136         //[-------------------------------------------------------]
00137         /**
00138         *  @brief
00139         *    Destructor
00140         */
00141         PLMESH_API virtual ~Mesh();
00142 
00143         /**
00144         *  @brief
00145         *    Returns the owner mesh manager
00146         *
00147         *  @return
00148         *    Pointer to the owner mesh manager, a null pointer on error
00149         */
00150         PLMESH_API MeshManager *GetMeshManager() const;
00151 
00152         /**
00153         *  @brief
00154         *    Returns the used renderer
00155         *
00156         *  @return
00157         *    Pointer to the renderer the mesh uses, can be a null pointer
00158         */
00159         PLMESH_API PLRenderer::Renderer *GetRenderer() const;
00160 
00161         /**
00162         *  @brief
00163         *    Checks all LODs and returns the maximum number of vertices
00164         *
00165         *  @return
00166         *    Maximum number of vertices
00167         */
00168         PLMESH_API PLCore::uint32 GetMaxNumOfVertices() const;
00169 
00170         /**
00171         *  @brief
00172         *    Checks all LODs and returns the maximum number of geometries
00173         *
00174         *  @return
00175         *    Maximum number of geometries
00176         */
00177         PLMESH_API PLCore::uint32 GetMaxNumOfGeometries() const;
00178 
00179         /**
00180         *  @brief
00181         *    Checks all LODs and returns the maximum number of triangles
00182         *
00183         *  @return
00184         *    Maximum number of triangles
00185         */
00186         PLMESH_API PLCore::uint32 GetMaxNumOfTriangles() const;
00187 
00188         /**
00189         *  @brief
00190         *    Draws the mesh
00191         *
00192         *  @param[in] mWorldViewProjection
00193         *    World view projection matrix to use
00194         *  @param[in] bBlend
00195         *    Draw only mesh parts which use a blended material?
00196         *  @param[in] nFlags
00197         *    Draw flags (use EFlags)
00198         *  @param[in] nLODLevel
00199         *    Which LOD level to use
00200         *  @param[in] nMorphTarget
00201         *    Which morph target to use
00202         *  @param[in] bUseMaterials
00203         *    Use the mesh materials? If 'false' no material is bound.
00204         *
00205         *  @note
00206         *    - Use this function only if you know that there's only one special
00207         *      usage of the mesh. (for instance you dynamically change it)
00208         *      Normally you should use a mesh handler to handle the mesh
00209         */
00210         PLMESH_API void Draw(const PLMath::Matrix4x4 &mWorldViewProjection, bool bBlend = false, PLCore::uint32 nFlags = 0, PLCore::uint32 nLODLevel = 0,
00211                              PLCore::uint32 nMorphTarget = 0, bool bUseMaterials = true) const;
00212 
00213         /**
00214         *  @brief
00215         *    Copy operator
00216         *
00217         *  @param[in] cSource
00218         *    Source to copy from
00219         *
00220         *  @return
00221         *    This mesh
00222         */
00223         PLMESH_API Mesh &operator =(const Mesh &cSource);
00224 
00225         //[-------------------------------------------------------]
00226         //[ Mesh data                                             ]
00227         //[-------------------------------------------------------]
00228         /**
00229         *  @brief
00230         *    Returns the anchor point manager
00231         *
00232         *  @return
00233         *    The anchor point manager of the mesh
00234         *
00235         *  @remarks
00236         *    To add an anchor point to the manager you can e.g. do the following:\n
00237         *    AnchorPoint *pAnchorPoint = new AnchorPoint("LeftHand", 0,\n
00238         *      99, &pMyMesh->GetAnchorPointManager());
00239         */
00240         PLMESH_API AnchorPointManager &GetAnchorPointManager();
00241 
00242         //[-------------------------------------------------------]
00243         //[ Morph target functions                                ]
00244         //[-------------------------------------------------------]
00245         /**
00246         *  @brief
00247         *    Clears all morph targets
00248         */
00249         PLMESH_API void ClearMorphTargets();
00250 
00251         /**
00252         *  @brief
00253         *    Returns the number of morph targets
00254         *
00255         *  @return
00256         *    Number of morph targets the mesh contains
00257         */
00258         PLMESH_API PLCore::uint32 GetNumOfMorphTargets() const;
00259 
00260         /**
00261         *  @brief
00262         *    Adds a new morph target
00263         *
00264         *  @return
00265         *    Pointer to the new morph target, a null pointer on error
00266         */
00267         PLMESH_API MeshMorphTarget *AddMorphTarget();
00268 
00269         /**
00270         *  @brief
00271         *    Gets one of the mesh's morph targets by index
00272         *
00273         *  @param[in] nMorphTarget
00274         *    Number of the morph target to get
00275         *
00276         *  @return
00277         *    Pointer to the morph target, or a null pointer
00278         */
00279         PLMESH_API MeshMorphTarget *GetMorphTarget(PLCore::uint32 nMorphTarget = 0) const;
00280 
00281         /**
00282         *  @brief
00283         *    Gets one of the mesh's morph targets by name
00284         *
00285         *  @param[in] sName
00286         *    Name of the morph target to get
00287         *
00288         *  @return
00289         *    Pointer to the morph target, or a null pointer
00290         */
00291         PLMESH_API MeshMorphTarget *GetMorphTarget(const PLCore::String &sName) const;
00292 
00293         /**
00294         *  @brief
00295         *    Returns the index of a given morph target
00296         *
00297         *  @param[in] sName
00298         *    Name of the morph target the index should be returned
00299         *
00300         *  @return
00301         *    The index of the given morph target, < 0 if the morph target wasn't found
00302         */
00303         PLMESH_API int GetMorphTargetIndex(const PLCore::String &sName) const;
00304 
00305         /**
00306         *  @brief
00307         *    Returns the morph target animation manager
00308         *
00309         *  @return
00310         *    The morph target animation manager
00311         *
00312         *  @remarks
00313         *    To add an morph target animation to the manager you can e.g. do the following:\n
00314         *    MorphTargetAni *pAnimation = new MorphTargetAni(&pMyMesh->GetMorphTargetAnimationManager());
00315         */
00316         PLMESH_API MorphTargetAniManager &GetMorphTargetAnimationManager();
00317 
00318         /**
00319         *  @brief
00320         *    Adds a morph target animation
00321         *
00322         *  @param[in] sFilename
00323         *    Morph target animation filename
00324         *
00325         *  @return
00326         *    'true' if all went fine, else 'false'
00327         */
00328         PLMESH_API bool AddMorphTargetAnimation(const PLCore::String &sFilename);
00329 
00330         //[-------------------------------------------------------]
00331         //[ LOD functions                                         ]
00332         //[-------------------------------------------------------]
00333         /**
00334         *  @brief
00335         *    Clears all LOD levels
00336         */
00337         PLMESH_API void ClearLODLevels();
00338 
00339         /**
00340         *  @brief
00341         *    Returns the number of LOD levels
00342         *
00343         *  @return
00344         *    Number of LOD levels the mesh contains
00345         */
00346         PLMESH_API PLCore::uint32 GetNumOfLODLevels() const;
00347 
00348         /**
00349         *  @brief
00350         *    Adds a new LOD level
00351         *
00352         *  @return
00353         *    Pointer to the new LOD level, a null pointer on error
00354         */
00355         PLMESH_API MeshLODLevel *AddLODLevel();
00356 
00357         /**
00358         *  @brief
00359         *    Gets one of the mesh's LOD levels
00360         *
00361         *  @param[in] nLODLevel
00362         *    Number of the LOD level to get
00363         *
00364         *  @return
00365         *    Pointer to the LOD level, or a null pointer
00366         */
00367         PLMESH_API MeshLODLevel *GetLODLevel(PLCore::uint32 nLODLevel = 0) const;
00368 
00369         //[-------------------------------------------------------]
00370         //[ Material functions                                    ]
00371         //[-------------------------------------------------------]
00372         /**
00373         *  @brief
00374         *    Clears all materials
00375         */
00376         PLMESH_API void ClearMaterials();
00377 
00378         /**
00379         *  @brief
00380         *    Returns the number of materials
00381         *
00382         *  @return
00383         *    Number of materials
00384         */
00385         PLMESH_API PLCore::uint32 GetNumOfMaterials() const;
00386 
00387         /**
00388         *  @brief
00389         *    Adds a new material
00390         *
00391         *  @param[in] pMaterial
00392         *    Material to add, if a null pointer, nothing happens
00393         *
00394         *  @return
00395         *    Pointer to the added material, a null pointer on error
00396         */
00397         PLMESH_API PLRenderer::Material *AddMaterial(PLRenderer::Material *pMaterial);
00398 
00399         /**
00400         *  @brief
00401         *    Deletes a material
00402         *
00403         *  @param[in] nMaterial
00404         *    Number of the material to delete
00405         *
00406         *  @return
00407         *    'true' if all went fine else 'false'
00408         *
00409         *  @note
00410         *    - If the deleted material was used by a geometry the geometry
00411         *      material index will be set to 0
00412         *    - The material index of the geometries will automatically corrected
00413         *      if the material index has changed
00414         */
00415         PLMESH_API bool DeleteMaterial(PLCore::uint32 nMaterial);
00416 
00417         /**
00418         *  @brief
00419         *    Returns the number of geometries using this material
00420         *
00421         *  @param[in] nMaterial
00422         *    Number of the material to check
00423         *
00424         *  @return
00425         *    Number of geometries using this material
00426         *
00427         *  @note
00428         *    - Use this function for instance to find unused materials in order to
00429         *      delete them
00430         */
00431         PLMESH_API PLCore::uint32 GetMaterialUsage(PLCore::uint32 nMaterial) const;
00432 
00433         /**
00434         *  @brief
00435         *    Gets one of the mesh's materials
00436         *
00437         *  @param[in] nMaterial
00438         *    Number of the material to get
00439         *
00440         *  @return
00441         *    Pointer to the material, or a null pointer
00442         */
00443         PLMESH_API PLRenderer::Material *GetMaterial(PLCore::uint32 nMaterial = 0) const;
00444 
00445         /**
00446         *  @brief
00447         *    Sets one of the mesh's materials
00448         *
00449         *  @param[in] nMaterial
00450         *    Number of the material to set
00451         *  @param[in] pMaterial
00452         *    Pointer to the material to set, can be a null pointer
00453         *
00454         *  @return
00455         *    'true' if all went fine, else 'false'
00456         */
00457         PLMESH_API bool SetMaterial(PLCore::uint32 nMaterial, PLRenderer::Material *pMaterial);
00458 
00459         //[-------------------------------------------------------]
00460         //[ Skeleton functions                                    ]
00461         //[-------------------------------------------------------]
00462         /**
00463         *  @brief
00464         *    Clears the list of skeleton handlers
00465         *
00466         *  @note
00467         *    - The skeletons are managed by the global skeleton manager, the meshes only
00468         *      can have a list of skeletons 'assigned' to them. This skeletons for instance
00469         *      are saved/loaded directly within the mesh file.
00470         *    - By default the mesh has no skeleton assigned to it
00471         *    - The first skeleton is the base skeleton, all other are for instance
00472         *      additional animations assigned with this mesh
00473         *    - See MeshLODLevel::GetVertexWeights()
00474         */
00475         PLMESH_API void ClearSkeletonHandlers();
00476 
00477         /**
00478         *  @brief
00479         *    Returns the list of skeleton handlers
00480         *  
00481         *  @return
00482         *    The list of skeleton handlers
00483         *
00484         *  @see
00485         *    - ClearSkeletonHandlers()
00486         */
00487         PLMESH_API PLCore::Array<SkeletonHandler*> &GetSkeletonHandlers();
00488 
00489         /**
00490         *  @brief
00491         *    Returns the weights array
00492         *
00493         *  @return
00494         *    Weights array
00495         *
00496         *  @note
00497         *    - The weights are optional, but required for mesh skinning
00498         */
00499         PLMESH_API PLCore::Array<Weight> &GetWeights();
00500 
00501         /**
00502         *  @brief
00503         *    Returns the vertex weights array
00504         *
00505         *  @return
00506         *    Vertex weights array
00507         *
00508         *  @note
00509         *    - The number of vertices in this array should always be the same number
00510         *      as the number of vertices within the vertex buffer of this LOD level!
00511         *     (see MeshMorphTarget::GetVertexBuffer())
00512         *    - The vertex weights are optional, but required for mesh skinning
00513         */
00514         PLMESH_API PLCore::Array<VertexWeights> &GetVertexWeights();
00515 
00516         //[-------------------------------------------------------]
00517         //[ Tool functions                                        ]
00518         //[-------------------------------------------------------]
00519         /**
00520         *  @brief
00521         *    Builds the connectivity information of all LOD levels
00522         *
00523         *  @note
00524         *    - For more information have a look at MeshLODLevel::BuildConnectivity()
00525         */
00526         PLMESH_API void BuildConnectivity();
00527 
00528         /**
00529         *  @brief
00530         *    Builds the current triangle planes of all morph targets
00531         *
00532         *  @note
00533         *    - For more information have a look at MeshMorphTarget::BuildTrianglePlaneList()
00534         */
00535         PLMESH_API void BuildTrianglePlaneList();
00536 
00537         /**
00538         *  @brief
00539         *    Builds the LOD levels automatically
00540         *
00541         *  @param[in] nNumLODLevels
00542         *    Number of LOD levels to create (including the original)
00543         *
00544         *  @return
00545         *    'true' if all went fine, else 'false'
00546         *
00547         *  @note
00548         *    - The first LOD level and morph target must exist already
00549         */
00550         PLMESH_API bool BuildLOD(PLCore::uint32 nNumLODLevels);
00551 
00552         /**
00553         *  @brief
00554         *    Calculate the vertex normals of all morph targets of the mesh
00555         *
00556         *  @return
00557         *    'true' if all went fine, else 'false'
00558         *
00559         *  @note
00560         *    - This function will add normals to the vertex buffer if there are no one
00561         *      allocated yet
00562         */
00563         PLMESH_API bool CalculateNormals();
00564 
00565         /**
00566         *  @brief
00567         *    Calculates all tangent space vectors of all morph targets of the mesh
00568         *
00569         *  @param[in] bTangent
00570         *    Create tangent vectors?
00571         *  @param[in] bBinormal
00572         *    Create binormal vectors?
00573         *
00574         *  @return
00575         *    'true' if all went fine, else 'false'
00576         *
00577         *  @note
00578         *    - This function will add tangents and binormals to the
00579         *      vertex buffer if there are no one allocated yet
00580         *    - If there are no normals available they will be computed (see CalculateNormals())
00581         *    - To save memory one can only hold tangent vectors and compute the binormal for
00582         *      instance within a vertex shader using a cross product of the normal and
00583         *      tangent vector
00584         */
00585         PLMESH_API bool CalculateTangentSpaceVectors(bool bTangent = true, bool bBinormal = true);
00586 
00587         /**
00588         *  @brief
00589         *    Returns the mesh bounding box
00590         *
00591         *  @param[out] vMin
00592         *    Will receive the minimum bounding box position
00593         *  @param[out] vMax
00594         *    Will receive the maximum bounding box position
00595         *
00596         *  @remarks
00597         *    This bounding box should enclose the whole mesh. If it is a 0-bounding box
00598         *    you can use CalculateBoundingBox() to calculate a valid bounding box.
00599         */
00600         PLMESH_API void GetBoundingBox(PLMath::Vector3 &vMin, PLMath::Vector3 &vMax) const;
00601 
00602         /**
00603         *  @brief
00604         *    Set's the mesh bounding box
00605         *
00606         *  @param[in] vMin
00607         *    The minimum bounding box position
00608         *  @param[in] vMax
00609         *    The maximum bounding box position
00610         *
00611         *  @see
00612         *    - SetBoundingBox()
00613         */
00614         PLMESH_API void SetBoundingBox(const PLMath::Vector3 &vMin, const PLMath::Vector3 &vMax);
00615 
00616         /**
00617         *  @brief
00618         *    Calculates the mesh bounding box
00619         *
00620         *  @param[out] vMin
00621         *    Will receive the minimum bounding box position
00622         *  @param[out] vMax
00623         *    Will receive the maximum bounding box position
00624         *
00625         *  @return
00626         *    'true' if all went fine, else 'false'
00627         *
00628         *  @note
00629         *    - This function will take all morph targets into account
00630         *    - The internal mesh bounding box is NOT manipulated!
00631         */
00632         PLMESH_API bool CalculateBoundingBox(PLMath::Vector3 &vMin, PLMath::Vector3 &vMax);
00633 
00634         /**
00635         *  @brief
00636         *    Calculates the mesh bounding sphere
00637         *
00638         *  @param[out] vPos
00639         *    Will receive the bounding sphere position
00640         *  @param[out] fRadius
00641         *    Will receive the bounding sphere radius
00642         *
00643         *  @return
00644         *    'true' if all went fine, else 'false'
00645         *
00646         *  @note
00647         *    - This function will take all morph targets into account
00648         */
00649         PLMESH_API bool CalculateBoundingSphere(PLMath::Vector3 &vPos, float &fRadius);
00650 
00651 
00652     //[-------------------------------------------------------]
00653     //[ Private functions                                     ]
00654     //[-------------------------------------------------------]
00655     private:
00656         /**
00657         *  @brief
00658         *    Constructor
00659         *
00660         *  @param[in] pRenderer
00661         *    Pointer to the renderer to use can be a null pointer
00662         *  @param[in] cManager
00663         *    Mesh manager using this resource
00664         *  @param[in] sName
00665         *    Resource name to set
00666         *  @param[in] bStatic
00667         *    Static mesh? (better performance!)
00668         */
00669         Mesh(PLRenderer::Renderer *pRenderer, PLCore::ResourceManager<Mesh> &cManager, const PLCore::String &sName, bool bStatic = true);
00670 
00671 
00672     //[-------------------------------------------------------]
00673     //[ Private data                                          ]
00674     //[-------------------------------------------------------]
00675     private:
00676         // Data
00677         PLRenderer::Renderer *m_pRenderer;  /**< Renderer the mesh is using, can be a null pointer */
00678         bool                  m_bStatic;    /**< Static mesh? (better performance!) */
00679         PLMath::Vector3       m_vBBMin;     /**< Minimum bounding box position */
00680         PLMath::Vector3       m_vBBMax;     /**< Maximum bounding box position */
00681 
00682         /** Anchor points */
00683         AnchorPointManager m_cAnchorPointManager;
00684 
00685         /** Morph targets */
00686         PLCore::Array<MeshMorphTarget*>                   m_lstMorphTargets;
00687         MorphTargetAniManager                             m_cMorphTargetAnimation;
00688         PLCore::HashMap<PLCore::String, MeshMorphTarget*> m_mapMorphTargets;
00689 
00690         /** LOD data */
00691         PLCore::Array<MeshLODLevel*> m_lstLODLevels;
00692 
00693         /** Materials */
00694         PLCore::Array<PLRenderer::MaterialHandler*> m_lstMaterials;
00695 
00696         /** Skeleton */
00697         PLCore::Array<SkeletonHandler*> m_lstSkeletonHandler;   /**< List of skeleton handlers */
00698         PLCore::Array<Weight>           m_lstWeights;           /**< Optional weights */
00699         PLCore::Array<VertexWeights>    m_lstVertexWeights;     /**< Optional vertex weights per vertex */
00700 
00701 
00702     //[-------------------------------------------------------]
00703     //[ Public virtual PLCore::Loadable functions             ]
00704     //[-------------------------------------------------------]
00705     public:
00706         PLMESH_API virtual bool Unload() override;
00707         PLMESH_API virtual PLCore::String GetLoadableTypeName() const override;
00708 
00709 
00710 };
00711 
00712 
00713 //[-------------------------------------------------------]
00714 //[ Namespace                                             ]
00715 //[-------------------------------------------------------]
00716 } // PLMesh
00717 
00718 
00719 #endif // __PLMESH_MESH_H__


PixelLight PixelLight 0.9.10-R1
Copyright (C) 2002-2011 by The PixelLight Team
Last modified Fri Dec 23 2011 15:50:57
The content of this PixelLight document is published under the
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported