From: TTimo Date: Sun, 4 Nov 2007 03:34:51 +0000 (+0000) Subject: set eol-style X-Git-Tag: xonotic-v0.7.0~16^2~12^2~112^2~64 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=commitdiff_plain;h=99980506540d9546dad31223a6eadf126ba68121 set eol-style git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/ZeroRadiant@183 8a3a26a2-13c4-0310-b231-cf6edde360e5 --- diff --git a/Doxygen_files/doxy_mainpage.h b/Doxygen_files/doxy_mainpage.h index 34e4bc50..34b43d9d 100644 --- a/Doxygen_files/doxy_mainpage.h +++ b/Doxygen_files/doxy_mainpage.h @@ -1,45 +1,45 @@ -/* -** Doxygen index.html generation file -** -*/ - -/*! \mainpage +project+ Doxygen Index - - \section intro Introduction - - This documentation was generated from GtkRadiant source code using Doxygen.
- Generated from source in: +target+ - - \section links Links - General Links
- Doxygen Homepage
- GtkRadiant Homepage
- Zerowing - GtkRadiant Development
- - Local Links
- Doxygen Quick Reference (Local)
- -

- GtkRadiant FAQ Links
- GtkRadiant FAQ
- GtkRadiant FAQ: Open Tasks
- GtkRadiant FAQ: Compiling instructions
- GtkRadiant FAQ: Creating/Submitting patches
- GtkRadiant FAQ: Coding Conventions & Guidelines
-

- - Misc Links
- idsoftware.com
- -

- - * Note: The content on this page was generated from this file. - It is moved into the path when the doxygen documentation is generated, and removed immediately - afterwards. - -

- - This page generated: by +user+ on +machine+
- On +date+ -
-*/ +/* +** Doxygen index.html generation file +** +*/ + +/*! \mainpage +project+ Doxygen Index + + \section intro Introduction + + This documentation was generated from GtkRadiant source code using Doxygen.
+ Generated from source in: +target+ + + \section links Links + General Links
+ Doxygen Homepage
+ GtkRadiant Homepage
+ Zerowing - GtkRadiant Development
+ + Local Links
+ Doxygen Quick Reference (Local)
+ +

+ GtkRadiant FAQ Links
+ GtkRadiant FAQ
+ GtkRadiant FAQ: Open Tasks
+ GtkRadiant FAQ: Compiling instructions
+ GtkRadiant FAQ: Creating/Submitting patches
+ GtkRadiant FAQ: Coding Conventions & Guidelines
+

+ + Misc Links
+ idsoftware.com
+ +

+ + * Note: The content on this page was generated from this file. + It is moved into the path when the doxygen documentation is generated, and removed immediately + afterwards. + +

+ + This page generated: by +user+ on +machine+
+ On +date+ +
+*/ diff --git a/contrib/bkgrnd2d/bkgrnd2d.h b/contrib/bkgrnd2d/bkgrnd2d.h index bee6e811..bf4771bb 100644 --- a/contrib/bkgrnd2d/bkgrnd2d.h +++ b/contrib/bkgrnd2d/bkgrnd2d.h @@ -1,83 +1,83 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// bkgrnd2d Plugin -// -// Code by reyalP aka Reed Mideke -// -// Based on spritemodel source code by hydra -// - -#include "plugin.h" - -class CBackgroundImage { -private: - qtexture_t *m_tex; - VIEWTYPE m_vt; - -// which components of a vec3_t correspond to x and y in the image - unsigned m_ix,m_iy; - -public: - CBackgroundImage(VIEWTYPE vt); -// ~CBackgroundImage(); - - float m_alpha; // vertex alpha - bool m_bActive; - -// x and y axis are in relation to the screen, not world, making rendering -// the same for each view type. Whoever sets them is responsible for -// shuffling. -// units are world units. -// TODO should be private - float m_xmin,m_ymin,m_xmax,m_ymax; - -// load file, create new tex, cleanup old tex, set new tex - bool Load(const char *filename); - void Cleanup(); // free texture, free tex, set make tex NULL - bool SetExtentsMM(); // set extents by ET mapcoordsmaxs/mapcoordsmins - bool SetExtentsSel(); // set extents by selection - void Render(); - bool Valid() { return (m_tex && (m_xmin != m_xmax) && (m_ymin != m_ymax)); } -}; - -class CBackgroundRender : public IGL2DWindow { -public: - - CBackgroundRender(); - virtual ~CBackgroundRender(); - -protected: - int refCount; - -public: - - // IGL2DWindow IGL3DWindow interface - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - void Draw2D( VIEWTYPE vt ); - void Register(); -}; - -extern CBackgroundImage backgroundXY,backgroundXZ,backgroundYZ; -extern CBackgroundRender render; - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on spritemodel source code by hydra +// + +#include "plugin.h" + +class CBackgroundImage { +private: + qtexture_t *m_tex; + VIEWTYPE m_vt; + +// which components of a vec3_t correspond to x and y in the image + unsigned m_ix,m_iy; + +public: + CBackgroundImage(VIEWTYPE vt); +// ~CBackgroundImage(); + + float m_alpha; // vertex alpha + bool m_bActive; + +// x and y axis are in relation to the screen, not world, making rendering +// the same for each view type. Whoever sets them is responsible for +// shuffling. +// units are world units. +// TODO should be private + float m_xmin,m_ymin,m_xmax,m_ymax; + +// load file, create new tex, cleanup old tex, set new tex + bool Load(const char *filename); + void Cleanup(); // free texture, free tex, set make tex NULL + bool SetExtentsMM(); // set extents by ET mapcoordsmaxs/mapcoordsmins + bool SetExtentsSel(); // set extents by selection + void Render(); + bool Valid() { return (m_tex && (m_xmin != m_xmax) && (m_ymin != m_ymax)); } +}; + +class CBackgroundRender : public IGL2DWindow { +public: + + CBackgroundRender(); + virtual ~CBackgroundRender(); + +protected: + int refCount; + +public: + + // IGL2DWindow IGL3DWindow interface + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); + void Register(); +}; + +extern CBackgroundImage backgroundXY,backgroundXZ,backgroundYZ; +extern CBackgroundRender render; + diff --git a/contrib/bkgrnd2d/dialog.h b/contrib/bkgrnd2d/dialog.h index 7a82cdd6..b6d80430 100644 --- a/contrib/bkgrnd2d/dialog.h +++ b/contrib/bkgrnd2d/dialog.h @@ -1,36 +1,36 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// bkgrnd2d Plugin dialog box -// -// Code by reyalP aka Reed Mideke -// -// - -#ifndef _BKGRND2D_DIALOG_H_ -#define _BKGRND2D_DIALOG_H_ - -void InitBackgroundDialog(); -void ShowBackgroundDialog(); -void ShowBackgroundDialogPG(int page); - -#endif // _BKGRND2D_DIALOG_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin dialog box +// +// Code by reyalP aka Reed Mideke +// +// + +#ifndef _BKGRND2D_DIALOG_H_ +#define _BKGRND2D_DIALOG_H_ + +void InitBackgroundDialog(); +void ShowBackgroundDialog(); +void ShowBackgroundDialogPG(int page); + +#endif // _BKGRND2D_DIALOG_H_ diff --git a/contrib/bkgrnd2d/plugin.h b/contrib/bkgrnd2d/plugin.h index 84933ae0..15fe7d62 100644 --- a/contrib/bkgrnd2d/plugin.h +++ b/contrib/bkgrnd2d/plugin.h @@ -1,80 +1,80 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// bkgrnd2d Plugin -// -// Code by reyalP aka Reed Mideke -// -// Based on spritemodel source code by hydra -// - -#ifndef _PLUGIN_H_ -#define _PLUGIN_H_ - -/*! -\todo need general notice about lib purpose etc. -and the external dependencies (such as GLib, STL, mathlib etc.) -*/ - -#include -// for CPtrArray for idata.h -#include "missing.h" - -#include "synapse.h" -#include "iplugin.h" -#include "itoolbar.h" -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#include "igl.h" -#include "ifilesystem.h" -#include "ientity.h" -#include "idata.h" - -// verbose messages -#define BKGRND2D_DEBUG - -extern _QERFuncTable_1 g_FuncTable; -extern _QERQglTable g_QglTable; -extern _QERFileSystemTable g_FileSystemTable; -extern _QEREntityTable g_EntityTable; -extern _QERAppDataTable g_DataTable; -extern void *g_pMainWidget; - -extern CSynapseServer* g_pSynapseServer; - -class CSynapseClientBkgrnd2d : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - const char* GetName(); - - CSynapseClientBkgrnd2d() { } - virtual ~CSynapseClientBkgrnd2d() { } -}; -#define MSG_PREFIX "bkgrnd2d: " -#define MSG_WARN "bkgrnd2d WARNING: " -#define BKGRND2D_MINOR "bkgrnd2d" -#define FILETYPE_KEY "bkgrnd2d" - -#endif // _PLUGIN_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on spritemodel source code by hydra +// + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +/*! +\todo need general notice about lib purpose etc. +and the external dependencies (such as GLib, STL, mathlib etc.) +*/ + +#include +// for CPtrArray for idata.h +#include "missing.h" + +#include "synapse.h" +#include "iplugin.h" +#include "itoolbar.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "igl.h" +#include "ifilesystem.h" +#include "ientity.h" +#include "idata.h" + +// verbose messages +#define BKGRND2D_DEBUG + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERFileSystemTable g_FileSystemTable; +extern _QEREntityTable g_EntityTable; +extern _QERAppDataTable g_DataTable; +extern void *g_pMainWidget; + +extern CSynapseServer* g_pSynapseServer; + +class CSynapseClientBkgrnd2d : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + CSynapseClientBkgrnd2d() { } + virtual ~CSynapseClientBkgrnd2d() { } +}; +#define MSG_PREFIX "bkgrnd2d: " +#define MSG_WARN "bkgrnd2d WARNING: " +#define BKGRND2D_MINOR "bkgrnd2d" +#define FILETYPE_KEY "bkgrnd2d" + +#endif // _PLUGIN_H_ diff --git a/contrib/bobtoolz/CPortals.h b/contrib/bobtoolz/CPortals.h index bc9d16ac..60506be8 100644 --- a/contrib/bobtoolz/CPortals.h +++ b/contrib/bobtoolz/CPortals.h @@ -1,63 +1,63 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#include "StdAfx.h" // Added by ClassView - -class CBspPoint { -public: - float p[3]; -}; - -class CBspPortal { -public: - CBspPortal(); - ~CBspPortal(); - - unsigned point_count; - CBspPoint *point; - bool Build(char *def, unsigned int pointCnt, bool bInverse); -}; - - -class CBspNode { -public: - CBspPortal *portal; - unsigned int portal_count; - - bool AddPortal(char* def, unsigned int pointCnt, bool bInverse); - unsigned int portal_next; - CBspNode(); - ~CBspNode(); -}; - - -class CPortals { -public: - - CPortals(); - ~CPortals(); - - void Load(); // use filename in fn - void Purge(); - - char fn[PATH_MAX]; - CBspNode *node; - - unsigned int node_count; -}; +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#include "StdAfx.h" // Added by ClassView + +class CBspPoint { +public: + float p[3]; +}; + +class CBspPortal { +public: + CBspPortal(); + ~CBspPortal(); + + unsigned point_count; + CBspPoint *point; + bool Build(char *def, unsigned int pointCnt, bool bInverse); +}; + + +class CBspNode { +public: + CBspPortal *portal; + unsigned int portal_count; + + bool AddPortal(char* def, unsigned int pointCnt, bool bInverse); + unsigned int portal_next; + CBspNode(); + ~CBspNode(); +}; + + +class CPortals { +public: + + CPortals(); + ~CPortals(); + + void Load(); // use filename in fn + void Purge(); + + char fn[PATH_MAX]; + CBspNode *node; + + unsigned int node_count; +}; diff --git a/contrib/bobtoolz/DBobView.h b/contrib/bobtoolz/DBobView.h index 4259c97a..94902607 100644 --- a/contrib/bobtoolz/DBobView.h +++ b/contrib/bobtoolz/DBobView.h @@ -1,72 +1,72 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DBobView.h: interface for the DBobView class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ - -class DListener; - -#define BOUNDS_ALL 0 -#define BOUNDS_APEX 1 - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DBobView : - public IGL2DWindow, - public IGL3DWindow -{ -public: - DBobView(); - virtual ~DBobView(); - -protected: - vec3_t* path; - int refCount; -public: - bool m_bShowExtra; - int boundingShow; - DListener* eyes; - float fVarGravity; - - bool UpdatePath(); - char entTarget[256]; - char entTrigger[256]; - void Begin(const char*, const char*, float, int, float, bool, bool); - bool CalculateTrajectory(vec3_t, vec3_t, float, int, float); - - void SetPath(vec3_t* pPath); - void UnRegister(); - void Register(); - void Draw3D(); - void Draw2D(VIEWTYPE vt); - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - - float fMultiplier; - bool m_bHooked; - int nPathCount; -}; - -#endif // !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DBobView.h: interface for the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +class DListener; + +#define BOUNDS_ALL 0 +#define BOUNDS_APEX 1 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DBobView : + public IGL2DWindow, + public IGL3DWindow +{ +public: + DBobView(); + virtual ~DBobView(); + +protected: + vec3_t* path; + int refCount; +public: + bool m_bShowExtra; + int boundingShow; + DListener* eyes; + float fVarGravity; + + bool UpdatePath(); + char entTarget[256]; + char entTrigger[256]; + void Begin(const char*, const char*, float, int, float, bool, bool); + bool CalculateTrajectory(vec3_t, vec3_t, float, int, float); + + void SetPath(vec3_t* pPath); + void UnRegister(); + void Register(); + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + float fMultiplier; + bool m_bHooked; + int nPathCount; +}; + +#endif // !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DBrush.h b/contrib/bobtoolz/DBrush.h index 7f2485cd..65013dcc 100644 --- a/contrib/bobtoolz/DBrush.h +++ b/contrib/bobtoolz/DBrush.h @@ -1,101 +1,101 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DBrush.h: interface for the DBrush class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_ - -#include "DPlane.h" - -#define POINT_IN_BRUSH 0 -#define POINT_ON_BRUSH 1 -#define POINT_OUT_BRUSH 2 - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DBrush -{ -public: - DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); - void SaveToFile(FILE* pFile); - - void Rotate(vec3_t vOrigin, vec3_t vRotation); - void RotateAboutCentre(vec3_t vRotation); - - DPlane* HasPlaneInverted(DPlane* chkPlane); - DPlane* HasPlane(DPlane* chkPlane); - DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); - - bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); - bool IsDetail(); - bool HasTexture(const char* textureName); - bool IntersectsWith(DBrush *chkBrush); - bool IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v); - bool IsCutByPlane(DPlane* cuttingPlane); - bool GetBounds(vec3_t min, vec3_t max); - bool HasPoint(vec3_t pnt); - bool BBoxCollision(DBrush* chkBrush); - bool BBoxTouch(DBrush* chkBrush); - - int BuildPoints(); - void BuildBounds(); - void BuildFromWinding(DWinding* w); - brush_t* BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity = NULL); - - void ResetChecks(list* exclusionList); - - void ClearFaces(); - void ClearPoints(); - - int RemoveRedundantPlanes( void ); - void RemovePlane( DPlane* plane ); - int PointPosition(vec3_t pnt); - void RemoveFromRadiant( void ); - - - void CutByPlane(DPlane* cutPlane, DBrush** newBrush1, DBrush** newBrush2); - - void LoadFromBrush_t(brush_t* brush, bool textured); - void AddPoint(vec3_t pnt); - - DPlane* FindPlaneWithClosestNormal( vec_t* normal ); - int FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ); - - DBrush(int ID = -1); - virtual ~DBrush(); - - bool operator== (DBrush* other); - -// members - brush_t* QER_brush; - list faceList; - list pointList; - int m_nBrushID; - vec3_t bbox_min, bbox_max; - bool bBoundsBuilt; -}; - -//typedef CList DBrushList; - -#endif // !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DBrush.h: interface for the DBrush class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DPlane.h" + +#define POINT_IN_BRUSH 0 +#define POINT_ON_BRUSH 1 +#define POINT_OUT_BRUSH 2 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DBrush +{ +public: + DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); + void SaveToFile(FILE* pFile); + + void Rotate(vec3_t vOrigin, vec3_t vRotation); + void RotateAboutCentre(vec3_t vRotation); + + DPlane* HasPlaneInverted(DPlane* chkPlane); + DPlane* HasPlane(DPlane* chkPlane); + DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); + + bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); + bool IsDetail(); + bool HasTexture(const char* textureName); + bool IntersectsWith(DBrush *chkBrush); + bool IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v); + bool IsCutByPlane(DPlane* cuttingPlane); + bool GetBounds(vec3_t min, vec3_t max); + bool HasPoint(vec3_t pnt); + bool BBoxCollision(DBrush* chkBrush); + bool BBoxTouch(DBrush* chkBrush); + + int BuildPoints(); + void BuildBounds(); + void BuildFromWinding(DWinding* w); + brush_t* BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity = NULL); + + void ResetChecks(list* exclusionList); + + void ClearFaces(); + void ClearPoints(); + + int RemoveRedundantPlanes( void ); + void RemovePlane( DPlane* plane ); + int PointPosition(vec3_t pnt); + void RemoveFromRadiant( void ); + + + void CutByPlane(DPlane* cutPlane, DBrush** newBrush1, DBrush** newBrush2); + + void LoadFromBrush_t(brush_t* brush, bool textured); + void AddPoint(vec3_t pnt); + + DPlane* FindPlaneWithClosestNormal( vec_t* normal ); + int FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ); + + DBrush(int ID = -1); + virtual ~DBrush(); + + bool operator== (DBrush* other); + +// members + brush_t* QER_brush; + list faceList; + list pointList; + int m_nBrushID; + vec3_t bbox_min, bbox_max; + bool bBoundsBuilt; +}; + +//typedef CList DBrushList; + +#endif // !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEPair.h b/contrib/bobtoolz/DEPair.h index e5438af4..11f79045 100644 --- a/contrib/bobtoolz/DEPair.h +++ b/contrib/bobtoolz/DEPair.h @@ -1,45 +1,45 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DEPair.h: interface for the DEPair class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DEPair -{ -public: - DEPair(); - virtual ~DEPair(); - - void Build(char* pKey, char* pValue); - - Str key; - Str value; -}; - -//typedef CList DEPairList; - -#endif // !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DEPair.h: interface for the DEPair class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DEPair +{ +public: + DEPair(); + virtual ~DEPair(); + + void Build(char* pKey, char* pValue); + + Str key; + Str value; +}; + +//typedef CList DEPairList; + +#endif // !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEntity.h b/contrib/bobtoolz/DEntity.h index 382e8a0f..63837c84 100644 --- a/contrib/bobtoolz/DEntity.h +++ b/contrib/bobtoolz/DEntity.h @@ -1,115 +1,115 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DEntity.h: interface for the DEntity class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_ - -#include "DBrush.h" -#include "DEPair.h" -#include "DPatch.h" -#include "StdAfx.h" // Added by ClassView - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DEntity -{ -public: - void RemoveFromRadiant(); - entity_t* QER_Entity; - int m_nID; - -// Constrcution/Destruction - DEntity(char* classname = "worldspawn", int ID = -1); // sets classname - virtual ~DEntity(); -// --------------------------------------------- - -// epair functions........ - void LoadEPairList(epair_t* epl); - void AddEPair(char* key, char* value); - void ClearEPairs(); - DEPair* FindEPairByKey(const char* keyname); -// --------------------------------------------- - -// random functions........ - bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild); - void SaveToFile(FILE* pFile); - void SetClassname(char* classname); - int GetIDMax(); - - void BuildInRadiant(bool allowDestruction); - void ResetChecks(list* exclusionList); - void RemoveNonCheckBrushes(list* exclusionList, bool useDetail); - - DPlane* AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID); // slow, try not to use much - int GetBrushCount( void ); - DBrush* FindBrushByPointer( brush_t* brush ); -// --------------------------------------------- - - -// bool list functions - void SelectBrushes(bool* selectList); - bool* BuildDuplicateList(); - bool* BuildIntersectList(); -// --------------------------------------------- - - -// brush operations - void ClearBrushes(); // clears brush list and frees memory for brushes - - DBrush* GetBrushForID(int ID); - DBrush* NewBrush(int ID = -1); -// --------------------------------------------- - -// patch operations - void ClearPatches(); - - DPatch* NewPatch(); -// --------------------------------------------- - -// vars - list epairList; - list brushList; - // new patches, wahey!!! - list patchList; - Str m_Classname; -// --------------------------------------------- - - - int FixBrushes(bool rebuild); - - bool LoadFromEntity(int id, bool bLoadPatches = FALSE); - bool LoadFromEntity(entity_t* ent, bool bLoadPatches = FALSE); - void LoadSelectedBrushes(); - void LoadSelectedPatches(); - - bool LoadFromPrt(char* filename); -// --------------------------------------------- - void SpawnString(const char* key, const char* defaultstring, const char** out); - void SpawnInt(const char* key, const char* defaultstring, int* out); - void SpawnFloat(const char* key, const char* defaultstring, float* out); - void SpawnVector(const char* key, const char* defaultstring, vec_t* out); -}; - -#endif // !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DEntity.h: interface for the DEntity class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DBrush.h" +#include "DEPair.h" +#include "DPatch.h" +#include "StdAfx.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DEntity +{ +public: + void RemoveFromRadiant(); + entity_t* QER_Entity; + int m_nID; + +// Constrcution/Destruction + DEntity(char* classname = "worldspawn", int ID = -1); // sets classname + virtual ~DEntity(); +// --------------------------------------------- + +// epair functions........ + void LoadEPairList(epair_t* epl); + void AddEPair(char* key, char* value); + void ClearEPairs(); + DEPair* FindEPairByKey(const char* keyname); +// --------------------------------------------- + +// random functions........ + bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild); + void SaveToFile(FILE* pFile); + void SetClassname(char* classname); + int GetIDMax(); + + void BuildInRadiant(bool allowDestruction); + void ResetChecks(list* exclusionList); + void RemoveNonCheckBrushes(list* exclusionList, bool useDetail); + + DPlane* AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID); // slow, try not to use much + int GetBrushCount( void ); + DBrush* FindBrushByPointer( brush_t* brush ); +// --------------------------------------------- + + +// bool list functions + void SelectBrushes(bool* selectList); + bool* BuildDuplicateList(); + bool* BuildIntersectList(); +// --------------------------------------------- + + +// brush operations + void ClearBrushes(); // clears brush list and frees memory for brushes + + DBrush* GetBrushForID(int ID); + DBrush* NewBrush(int ID = -1); +// --------------------------------------------- + +// patch operations + void ClearPatches(); + + DPatch* NewPatch(); +// --------------------------------------------- + +// vars + list epairList; + list brushList; + // new patches, wahey!!! + list patchList; + Str m_Classname; +// --------------------------------------------- + + + int FixBrushes(bool rebuild); + + bool LoadFromEntity(int id, bool bLoadPatches = FALSE); + bool LoadFromEntity(entity_t* ent, bool bLoadPatches = FALSE); + void LoadSelectedBrushes(); + void LoadSelectedPatches(); + + bool LoadFromPrt(char* filename); +// --------------------------------------------- + void SpawnString(const char* key, const char* defaultstring, const char** out); + void SpawnInt(const char* key, const char* defaultstring, int* out); + void SpawnFloat(const char* key, const char* defaultstring, float* out); + void SpawnVector(const char* key, const char* defaultstring, vec_t* out); +}; + +#endif // !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DListener.h b/contrib/bobtoolz/DListener.h index 0ef20577..d2166993 100644 --- a/contrib/bobtoolz/DListener.h +++ b/contrib/bobtoolz/DListener.h @@ -1,62 +1,62 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DListener.h: interface for the DListener class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#include "DBobView.h" - -class DListener : public IWindowListener -{ -public: - DBobView* parent; - - bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); - bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); - bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); - bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); - bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); - bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); - bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); - bool OnKeyPressed(char *s) { return false; } - bool Paint() { return true; } - void Close() { } - - void UnRegister(); - void Register(); - DListener(); - virtual ~DListener(); - - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - -private: - bool m_bHooked; - int refCount; -}; - -#endif // !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DListener.h: interface for the DListener class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "DBobView.h" + +class DListener : public IWindowListener +{ +public: + DBobView* parent; + + bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnKeyPressed(char *s) { return false; } + bool Paint() { return true; } + void Close() { } + + void UnRegister(); + void Register(); + DListener(); + virtual ~DListener(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + +private: + bool m_bHooked; + int refCount; +}; + +#endif // !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DMap.h b/contrib/bobtoolz/DMap.h index 1f814c23..2d572114 100644 --- a/contrib/bobtoolz/DMap.h +++ b/contrib/bobtoolz/DMap.h @@ -1,56 +1,56 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DMap.h: interface for the DMap class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) -#define AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_ - -#include "DEntity.h" - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DMap -{ -public: - static void RebuildEntity(DEntity* ent); - - void ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); - void LoadAll(bool bLoadPatches = FALSE); - void BuildInRadiant(bool bAllowDestruction); - int m_nNextEntity; - DEntity* GetWorldSpawn(); - void ClearEntities(); - - DEntity* DMap::GetEntityForID(int ID); - DEntity* AddEntity(char* classname = "worldspawn", int ID = -1); - - list entityList; - - DMap(); - virtual ~DMap(); - - int FixBrushes(bool rebuild); -}; - -#endif // !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DMap.h: interface for the DMap class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) +#define AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_ + +#include "DEntity.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DMap +{ +public: + static void RebuildEntity(DEntity* ent); + + void ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); + void LoadAll(bool bLoadPatches = FALSE); + void BuildInRadiant(bool bAllowDestruction); + int m_nNextEntity; + DEntity* GetWorldSpawn(); + void ClearEntities(); + + DEntity* DMap::GetEntityForID(int ID); + DEntity* AddEntity(char* classname = "worldspawn", int ID = -1); + + list entityList; + + DMap(); + virtual ~DMap(); + + int FixBrushes(bool rebuild); +}; + +#endif // !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) diff --git a/contrib/bobtoolz/DPatch.h b/contrib/bobtoolz/DPatch.h index d04121ea..6bdf8e60 100644 --- a/contrib/bobtoolz/DPatch.h +++ b/contrib/bobtoolz/DPatch.h @@ -1,62 +1,62 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DPatch.h: interface for the DPatch class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) -#define AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_ - -#include "StdAfx.h" // Added by ClassView -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -typedef struct -{ - bool mergable; - int pos1; - int pos2; -} patch_merge_t; - -class DPatch -{ -public: - list Split(bool rows, bool cols); - void Transpose(); - void Invert(); - DPatch* MergePatches(patch_merge_t merge_info, DPatch* p1, DPatch* p2); - patch_merge_t IsMergable(DPatch* other); - bool ResetTextures(const char *oldTextureName, const char *newTextureName); - void RemoveFromRadiant(void); - brush_t* QER_brush; - void LoadFromBrush_t(brush_t* brush); - patchMesh_t* QER_patch; - void BuildInRadiant(void* entity = NULL); - void SetTexture(const char* textureName); - char texture[256]; - int width, height; - drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; - DPatch(); - virtual ~DPatch(); - -}; - -#endif // !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DPatch.h: interface for the DPatch class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) +#define AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_ + +#include "StdAfx.h" // Added by ClassView +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct +{ + bool mergable; + int pos1; + int pos2; +} patch_merge_t; + +class DPatch +{ +public: + list Split(bool rows, bool cols); + void Transpose(); + void Invert(); + DPatch* MergePatches(patch_merge_t merge_info, DPatch* p1, DPatch* p2); + patch_merge_t IsMergable(DPatch* other); + bool ResetTextures(const char *oldTextureName, const char *newTextureName); + void RemoveFromRadiant(void); + brush_t* QER_brush; + void LoadFromBrush_t(brush_t* brush); + patchMesh_t* QER_patch; + void BuildInRadiant(void* entity = NULL); + void SetTexture(const char* textureName); + char texture[256]; + int width, height; + drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + DPatch(); + virtual ~DPatch(); + +}; + +#endif // !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) diff --git a/contrib/bobtoolz/DPlane.h b/contrib/bobtoolz/DPlane.h index 4399b841..f1a84319 100644 --- a/contrib/bobtoolz/DPlane.h +++ b/contrib/bobtoolz/DPlane.h @@ -1,67 +1,67 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DPlane.h: interface for the DPlane class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_ - -#include "DPoint.h" - -#define FACE_DETAIL 0x8000000 - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DWinding; - -class DPlane -{ -public: - DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); - void ScaleTexture(); - DWinding* BaseWindingForPlane(); - - void Rebuild(); - - bool AddToBrush_t(brush_t *brush); - bool operator != (DPlane& other); - bool operator == (DPlane& other); - - bool IsRedundant(list& pointList); - bool PlaneIntersection(DPlane* pl1, DPlane* pl2, vec3_t out);; - - vec_t DistanceToPoint(vec3_t pnt); - - DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); - DPlane() { } - virtual ~DPlane(); - - bool m_bChkOk; - _QERFaceData texInfo; - vec3_t points[3]; // djbob:do we really need these any more? - vec3_t normal; - float _d; -}; - -//typedef CList DPlaneList; -#endif // !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DPlane.h: interface for the DPlane class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DPoint.h" + +#define FACE_DETAIL 0x8000000 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DWinding; + +class DPlane +{ +public: + DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); + void ScaleTexture(); + DWinding* BaseWindingForPlane(); + + void Rebuild(); + + bool AddToBrush_t(brush_t *brush); + bool operator != (DPlane& other); + bool operator == (DPlane& other); + + bool IsRedundant(list& pointList); + bool PlaneIntersection(DPlane* pl1, DPlane* pl2, vec3_t out);; + + vec_t DistanceToPoint(vec3_t pnt); + + DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); + DPlane() { } + virtual ~DPlane(); + + bool m_bChkOk; + _QERFaceData texInfo; + vec3_t points[3]; // djbob:do we really need these any more? + vec3_t normal; + float _d; +}; + +//typedef CList DPlaneList; +#endif // !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DPoint.h b/contrib/bobtoolz/DPoint.h index 22ae70bc..394352cf 100644 --- a/contrib/bobtoolz/DPoint.h +++ b/contrib/bobtoolz/DPoint.h @@ -1,45 +1,45 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DPoint.h: interface for the DPoint class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DPoint -{ -public: - DPoint(); - virtual ~DPoint(); - - bool operator ==(vec3_t other); - - vec3_t _pnt; - unsigned char m_uData; -}; - -//typedef CList DPointList; - -#endif // !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DPoint.h: interface for the DPoint class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DPoint +{ +public: + DPoint(); + virtual ~DPoint(); + + bool operator ==(vec3_t other); + + vec3_t _pnt; + unsigned char m_uData; +}; + +//typedef CList DPointList; + +#endif // !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DShape.h b/contrib/bobtoolz/DShape.h index 9564943d..4bc4baa8 100644 --- a/contrib/bobtoolz/DShape.h +++ b/contrib/bobtoolz/DShape.h @@ -1,60 +1,60 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DShape.h: interface for the DShape class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) -#define AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_ - -#include "DMap.h" // Added by ClassView -#include "StdAfx.h" // Added by ClassView - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -// defines for polygon stuff -#define MAX_POLYGON_FACES 128 - -extern bool bFacesAll[]; - -class DShape -{ -public: - bool BuildPit(vec3_t min, vec3_t max); - void BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop); - void BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); - void BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); - - int m_nNextBrush; - static DBrush* GetBoundingCube_Ext(vec3_t min, vec3_t max, const char* textureName, bool* bUseFaces = bFacesAll, bool detail = false); - - DShape(); - virtual ~DShape(); - - void Commit(); -private: - DBrush* GetBoundingCube(vec3_t min, vec3_t max, const char* textureName, DEntity* ent = NULL, bool* bUseFaces = bFacesAll); - - DMap m_Container; -}; - -#endif // !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DShape.h: interface for the DShape class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) +#define AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_ + +#include "DMap.h" // Added by ClassView +#include "StdAfx.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// defines for polygon stuff +#define MAX_POLYGON_FACES 128 + +extern bool bFacesAll[]; + +class DShape +{ +public: + bool BuildPit(vec3_t min, vec3_t max); + void BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop); + void BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); + void BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); + + int m_nNextBrush; + static DBrush* GetBoundingCube_Ext(vec3_t min, vec3_t max, const char* textureName, bool* bUseFaces = bFacesAll, bool detail = false); + + DShape(); + virtual ~DShape(); + + void Commit(); +private: + DBrush* GetBoundingCube(vec3_t min, vec3_t max, const char* textureName, DEntity* ent = NULL, bool* bUseFaces = bFacesAll); + + DMap m_Container; +}; + +#endif // !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) diff --git a/contrib/bobtoolz/DTrainDrawer.h b/contrib/bobtoolz/DTrainDrawer.h index 5f424068..3c7ac779 100644 --- a/contrib/bobtoolz/DTrainDrawer.h +++ b/contrib/bobtoolz/DTrainDrawer.h @@ -1,82 +1,82 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DTrainDrawer.h: interface for the DTrainDrawer class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ - -#include "DEntity.h" - -#if _MSC_VER > 1000 - -#pragma once -#endif // _MSC_VER > 1000 - -typedef struct { - char strName[64]; - - vec3_t vOrigin; -} controlPoint_t; - -typedef struct { - controlPoint_t point; - - char strControl[64]; - char strTarget[64]; - - list m_pointList; - list m_vertexList; - - controlPoint_t* pTarget; -} splinePoint_t; - -class DTrainDrawer : - public IGL2DWindow, - public IGL3DWindow -{ -private: - list m_splineList; - list m_pointList; - int refCount; - - bool m_bHooked; - bool m_bDisplay; -public: - void UnRegister(); - void Register(); - - DTrainDrawer(); - virtual ~DTrainDrawer(void); - - void Draw3D(); - void Draw2D(VIEWTYPE vt); - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - void ClearSplines(); - void ClearPoints(); - void BuildPaths(); - void AddControlPoint(const char* name, vec_t* origin); - splinePoint_t* AddSplinePoint(const char* name, const char* target, vec_t* origin); - controlPoint_t* FindControlPoint(const char* name); -}; - -#endif // !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DTrainDrawer.h: interface for the DTrainDrawer class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DEntity.h" + +#if _MSC_VER > 1000 + +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct { + char strName[64]; + + vec3_t vOrigin; +} controlPoint_t; + +typedef struct { + controlPoint_t point; + + char strControl[64]; + char strTarget[64]; + + list m_pointList; + list m_vertexList; + + controlPoint_t* pTarget; +} splinePoint_t; + +class DTrainDrawer : + public IGL2DWindow, + public IGL3DWindow +{ +private: + list m_splineList; + list m_pointList; + int refCount; + + bool m_bHooked; + bool m_bDisplay; +public: + void UnRegister(); + void Register(); + + DTrainDrawer(); + virtual ~DTrainDrawer(void); + + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void ClearSplines(); + void ClearPoints(); + void BuildPaths(); + void AddControlPoint(const char* name, vec_t* origin); + splinePoint_t* AddSplinePoint(const char* name, const char* target, vec_t* origin); + controlPoint_t* FindControlPoint(const char* name); +}; + +#endif // !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DTreePlanter.h b/contrib/bobtoolz/DTreePlanter.h index ab80abff..9048e60b 100644 --- a/contrib/bobtoolz/DTreePlanter.h +++ b/contrib/bobtoolz/DTreePlanter.h @@ -1,223 +1,223 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#ifndef __DTREE_H__ -#define __DTREE_H__ - -#include "../include/igl.h" -#include "DEntity.h" -#include "misc.h" -#include "ScriptParser.h" - -#define MAX_QPATH 64 - -typedef struct treeModel_s { - char name[MAX_QPATH]; -} treeModel_t; - -#define MAX_TP_MODELS 256 - -class DTreePlanter : public IWindowListener { -public: - virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); - virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); - virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); - virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); - virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); - virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); - virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); - virtual bool OnKeyPressed(char *s) { return false; } - virtual bool Paint() { return true; } - virtual void Close() { } - - DTreePlanter() { - m_refCount = 1; - m_hooked = false; - m_XYWrapper = NULL; - m_numModels = 0; - m_offset = 0; - m_maxPitch = 0; - m_minPitch = 0; - m_maxYaw = 0; - m_minYaw = 0; - m_setAngles = false; - m_useScale = false; - m_autoLink = false; - m_linkNum = 0; - - Register(); - - m_world.LoadSelectedBrushes(); - - char buffer[256]; - GetFilename( buffer, "bt/tp_ent.txt" ); - - FILE* file = fopen( buffer, "rb" ); - if(file) { - fseek( file, 0, SEEK_END ); - int len = ftell( file ); - fseek( file, 0, SEEK_SET ); - - if(len) { - char* buf = new char[len+1]; - buf[len] = '\0'; - // parser will do the cleanup, dont delete. - - fread( buf, len, 1, file ); - - CScriptParser parser; - parser.SetScript( buf ); - - ReadConfig( &parser ); - } - - fclose( file ); - } - } - -#define MT(t) !stricmp( pToken, t ) -#define GT pToken = pScriptParser->GetToken( true ) -#define CT if(!*pToken) { return; } - - void ReadConfig( CScriptParser* pScriptParser ) { - const char* GT; - CT; - - do { - GT; - if(*pToken == '}') { - break; - } - - if(MT("model")) { - if(m_numModels >= MAX_TP_MODELS) { - return; - } - - GT; CT; - - strncpy( m_trees[m_numModels++].name, pToken, MAX_QPATH ); - } else if(MT("link")) { - GT; CT; - - strncpy( m_linkName, pToken, MAX_QPATH ); - - m_autoLink = true; - } else if(MT("entity")) { - GT; CT; - - strncpy( m_entType, pToken, MAX_QPATH ); - } else if(MT("offset")) { - GT; CT; - - m_offset = atoi(pToken); - } else if(MT("pitch")) { - GT; CT; - - m_minPitch = atoi(pToken); - - GT; CT; - - m_maxPitch = atoi(pToken); - - m_setAngles = true; - } else if(MT("yaw")) { - GT; CT; - - m_minYaw = atoi(pToken); - - GT; CT; - - m_maxYaw = atoi(pToken); - - m_setAngles = true; - } else if(MT("scale")) { - GT; CT; - - m_minScale = static_cast< float >( atof( pToken ) ); - - GT; CT; - - m_maxScale = static_cast< float >( atof( pToken ) ); - - m_useScale = true; - } else if(MT("numlinks")) { - GT; CT; - - m_linkNum = atoi( pToken ); - } - } while( true ); - } - - virtual ~DTreePlanter() { - UnRegister(); - } - - virtual void IncRef() { m_refCount++; } - virtual void DecRef() { m_refCount--; if (m_refCount <= 0) delete this; } - - void Register() { - if(!m_hooked) { - g_MessageTable.m_pfnHookWindow( this ); - m_XYWrapper = g_MessageTable.m_pfnGetXYWndWrapper(); - m_hooked = true; - } - } - - void UnRegister() { - if(m_hooked) { - g_MessageTable.m_pfnUnHookWindow( this ); - m_XYWrapper = NULL; - m_hooked = false; - } - } - - bool FindDropPoint(vec3_t in, vec3_t out); - void DropEntsToGround( void ); - void MakeChain( void ); - void SelectChain( void ); - -private: - IXYWndWrapper* m_XYWrapper; - DEntity m_world; - - treeModel_t m_trees[MAX_TP_MODELS]; - - int m_refCount; - int m_numModels; - int m_offset; - int m_maxPitch; - int m_minPitch; - int m_maxYaw; - int m_minYaw; - - char m_entType[MAX_QPATH]; - char m_linkName[MAX_QPATH]; - int m_linkNum; - - float m_minScale; - float m_maxScale; - - bool m_hooked; - bool m_useScale; - bool m_setAngles; - bool m_autoLink; -}; - -#endif +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#ifndef __DTREE_H__ +#define __DTREE_H__ + +#include "../include/igl.h" +#include "DEntity.h" +#include "misc.h" +#include "ScriptParser.h" + +#define MAX_QPATH 64 + +typedef struct treeModel_s { + char name[MAX_QPATH]; +} treeModel_t; + +#define MAX_TP_MODELS 256 + +class DTreePlanter : public IWindowListener { +public: + virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnKeyPressed(char *s) { return false; } + virtual bool Paint() { return true; } + virtual void Close() { } + + DTreePlanter() { + m_refCount = 1; + m_hooked = false; + m_XYWrapper = NULL; + m_numModels = 0; + m_offset = 0; + m_maxPitch = 0; + m_minPitch = 0; + m_maxYaw = 0; + m_minYaw = 0; + m_setAngles = false; + m_useScale = false; + m_autoLink = false; + m_linkNum = 0; + + Register(); + + m_world.LoadSelectedBrushes(); + + char buffer[256]; + GetFilename( buffer, "bt/tp_ent.txt" ); + + FILE* file = fopen( buffer, "rb" ); + if(file) { + fseek( file, 0, SEEK_END ); + int len = ftell( file ); + fseek( file, 0, SEEK_SET ); + + if(len) { + char* buf = new char[len+1]; + buf[len] = '\0'; + // parser will do the cleanup, dont delete. + + fread( buf, len, 1, file ); + + CScriptParser parser; + parser.SetScript( buf ); + + ReadConfig( &parser ); + } + + fclose( file ); + } + } + +#define MT(t) !stricmp( pToken, t ) +#define GT pToken = pScriptParser->GetToken( true ) +#define CT if(!*pToken) { return; } + + void ReadConfig( CScriptParser* pScriptParser ) { + const char* GT; + CT; + + do { + GT; + if(*pToken == '}') { + break; + } + + if(MT("model")) { + if(m_numModels >= MAX_TP_MODELS) { + return; + } + + GT; CT; + + strncpy( m_trees[m_numModels++].name, pToken, MAX_QPATH ); + } else if(MT("link")) { + GT; CT; + + strncpy( m_linkName, pToken, MAX_QPATH ); + + m_autoLink = true; + } else if(MT("entity")) { + GT; CT; + + strncpy( m_entType, pToken, MAX_QPATH ); + } else if(MT("offset")) { + GT; CT; + + m_offset = atoi(pToken); + } else if(MT("pitch")) { + GT; CT; + + m_minPitch = atoi(pToken); + + GT; CT; + + m_maxPitch = atoi(pToken); + + m_setAngles = true; + } else if(MT("yaw")) { + GT; CT; + + m_minYaw = atoi(pToken); + + GT; CT; + + m_maxYaw = atoi(pToken); + + m_setAngles = true; + } else if(MT("scale")) { + GT; CT; + + m_minScale = static_cast< float >( atof( pToken ) ); + + GT; CT; + + m_maxScale = static_cast< float >( atof( pToken ) ); + + m_useScale = true; + } else if(MT("numlinks")) { + GT; CT; + + m_linkNum = atoi( pToken ); + } + } while( true ); + } + + virtual ~DTreePlanter() { + UnRegister(); + } + + virtual void IncRef() { m_refCount++; } + virtual void DecRef() { m_refCount--; if (m_refCount <= 0) delete this; } + + void Register() { + if(!m_hooked) { + g_MessageTable.m_pfnHookWindow( this ); + m_XYWrapper = g_MessageTable.m_pfnGetXYWndWrapper(); + m_hooked = true; + } + } + + void UnRegister() { + if(m_hooked) { + g_MessageTable.m_pfnUnHookWindow( this ); + m_XYWrapper = NULL; + m_hooked = false; + } + } + + bool FindDropPoint(vec3_t in, vec3_t out); + void DropEntsToGround( void ); + void MakeChain( void ); + void SelectChain( void ); + +private: + IXYWndWrapper* m_XYWrapper; + DEntity m_world; + + treeModel_t m_trees[MAX_TP_MODELS]; + + int m_refCount; + int m_numModels; + int m_offset; + int m_maxPitch; + int m_minPitch; + int m_maxYaw; + int m_minYaw; + + char m_entType[MAX_QPATH]; + char m_linkName[MAX_QPATH]; + int m_linkNum; + + float m_minScale; + float m_maxScale; + + bool m_hooked; + bool m_useScale; + bool m_setAngles; + bool m_autoLink; +}; + +#endif diff --git a/contrib/bobtoolz/DVisDrawer.h b/contrib/bobtoolz/DVisDrawer.h index c0ba1aa9..2f9ac315 100644 --- a/contrib/bobtoolz/DVisDrawer.h +++ b/contrib/bobtoolz/DVisDrawer.h @@ -1,58 +1,58 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DBobView.h: interface for the DBobView class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ - -#include "DWinding.h" - -#if _MSC_VER > 1000 - -#pragma once -#endif // _MSC_VER > 1000 - -class DVisDrawer : - public IGL2DWindow, - public IGL3DWindow -{ -public: - DVisDrawer(); - virtual ~DVisDrawer(); - -protected: - list* m_list; - int refCount; -public: - void ClearPoints(); - void SetList(list* pointList); - void UnRegister(); - void Register(); - void Draw3D(); - void Draw2D(VIEWTYPE vt); - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - - bool m_bHooked; -}; - -#endif // !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DBobView.h: interface for the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DWinding.h" + +#if _MSC_VER > 1000 + +#pragma once +#endif // _MSC_VER > 1000 + +class DVisDrawer : + public IGL2DWindow, + public IGL3DWindow +{ +public: + DVisDrawer(); + virtual ~DVisDrawer(); + +protected: + list* m_list; + int refCount; +public: + void ClearPoints(); + void SetList(list* pointList); + void UnRegister(); + void Register(); + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + bool m_bHooked; +}; + +#endif // !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DWinding.h b/contrib/bobtoolz/DWinding.h index d173fbf6..6d58e06e 100644 --- a/contrib/bobtoolz/DWinding.h +++ b/contrib/bobtoolz/DWinding.h @@ -1,68 +1,68 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// DWinding.h: interface for the DWinding class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -class DPlane; - -class DWinding -{ -public: - DWinding(); - virtual ~DWinding(); - - void AllocWinding(int points); - - bool ChopWinding(DPlane* chopPlane); - bool ChopWindingInPlace(DPlane* chopPlane, vec_t ON_EPSILON); - void ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding** front, DWinding** back); - - void CheckWinding(); - void WindingCentre(vec3_t centre); - void WindingBounds(vec3_t mins, vec3_t maxs); - void RemoveColinearPoints(); - - DWinding* ReverseWinding(); - DWinding* CopyWinding(); - DPlane* WindingPlane(); - - int WindingOnPlaneSide(vec3_t normal, vec_t dist); - - vec_t WindingArea(); - -// members - int numpoints; - vec3_t* p; - vec3_t clr; -}; - -#define MAX_POINTS_ON_WINDING 64 - -#define ON_EPSILON 0.01 - -#endif // !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// DWinding.h: interface for the DWinding class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DPlane; + +class DWinding +{ +public: + DWinding(); + virtual ~DWinding(); + + void AllocWinding(int points); + + bool ChopWinding(DPlane* chopPlane); + bool ChopWindingInPlace(DPlane* chopPlane, vec_t ON_EPSILON); + void ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding** front, DWinding** back); + + void CheckWinding(); + void WindingCentre(vec3_t centre); + void WindingBounds(vec3_t mins, vec3_t maxs); + void RemoveColinearPoints(); + + DWinding* ReverseWinding(); + DWinding* CopyWinding(); + DPlane* WindingPlane(); + + int WindingOnPlaneSide(vec3_t normal, vec_t dist); + + vec_t WindingArea(); + +// members + int numpoints; + vec3_t* p; + vec3_t clr; +}; + +#define MAX_POINTS_ON_WINDING 64 + +#define ON_EPSILON 0.01 + +#endif // !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/ScriptParser.h b/contrib/bobtoolz/ScriptParser.h index 60c92f51..5537401f 100644 --- a/contrib/bobtoolz/ScriptParser.h +++ b/contrib/bobtoolz/ScriptParser.h @@ -1,41 +1,41 @@ - -#ifndef _SCRIPTPARSER_H_ -#define _SCRIPTPARSER_H_ - -#include "interfaces/IScriptParser.h" - -#define SP_MAX_BREAKCHARS 16 - -class CScriptParser: public IScriptParser { -public: - CScriptParser(void); - ~CScriptParser(void); -private: - char m_breakChars[SP_MAX_BREAKCHARS]; - char* m_pScript; - char* m_pScriptSection; - char* m_pLastScriptSection; - char* m_pToken; - - void SkipWhitespace(bool* pbNewLines); - void ClearBuffer(void); - const char* MakeToken(const char* pToken); - bool IsBreakChar(char c); -public: - const char* GetToken(bool bAllowLinebreaks); - void SkipBracedSection(void); - void SkipRestOfLine(void); - void UndoGetToken(void); - void ResetParseSession(void); - - char* GetBufferCopy(void); - int GetTokenOffset(void); - - void LoadScript(const char* pScript); - void SetScript(char* pScript); - - void AddBreakChar(char c); -private: -}; - -#endif + +#ifndef _SCRIPTPARSER_H_ +#define _SCRIPTPARSER_H_ + +#include "interfaces/IScriptParser.h" + +#define SP_MAX_BREAKCHARS 16 + +class CScriptParser: public IScriptParser { +public: + CScriptParser(void); + ~CScriptParser(void); +private: + char m_breakChars[SP_MAX_BREAKCHARS]; + char* m_pScript; + char* m_pScriptSection; + char* m_pLastScriptSection; + char* m_pToken; + + void SkipWhitespace(bool* pbNewLines); + void ClearBuffer(void); + const char* MakeToken(const char* pToken); + bool IsBreakChar(char c); +public: + const char* GetToken(bool bAllowLinebreaks); + void SkipBracedSection(void); + void SkipRestOfLine(void); + void UndoGetToken(void); + void ResetParseSession(void); + + char* GetBufferCopy(void); + int GetTokenOffset(void); + + void LoadScript(const char* pScript); + void SetScript(char* pScript); + + void AddBreakChar(char c); +private: +}; + +#endif diff --git a/contrib/bobtoolz/StdAfx.h b/contrib/bobtoolz/StdAfx.h index 88183232..195e3d85 100644 --- a/contrib/bobtoolz/StdAfx.h +++ b/contrib/bobtoolz/StdAfx.h @@ -1,154 +1,154 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#ifndef __STDAFX_BOBTOOLZ__ -#define __STDAFX_BOBTOOLZ__ - -#define VC_EXTRALEAN - -#ifdef _WIN32 -#pragma warning(disable : 4786) -#endif - -#define BOBTOOLZ_MINOR "bobtoolz" - -#include -#include -#include -#include - -#include "time.h" - -#if defined (__linux__) || defined (__APPLE__) - -// Necessary for proper boolean type declaration -#include "qertypes.h" - -#include - -typedef void* HMODULE; -typedef void* LPVOID; -typedef char* LPCSTR; -//typedef int bool; - -#define MB_OK 0x00000000L -#define MB_OKCANCEL 0x00000001L -#define MB_ABORTRETRYIGNORE 0x00000002L -#define MB_YESNOCANCEL 0x00000003L -#define MB_YESNO 0x00000004L -#define MB_RETRYCANCEL 0x00000005L - - -#define MB_ICONHAND 0x00000010L -#define MB_ICONQUESTION 0x00000020L -#define MB_ICONEXCLAMATION 0x00000030L -#define MB_ICONASTERISK 0x00000040L - -#define MB_USERICON 0x00000080L -#define MB_ICONWARNING MB_ICONEXCLAMATION -#define MB_ICONERROR MB_ICONHAND -#define MB_ICONINFORMATION MB_ICONASTERISK -#define MB_ICONSTOP MB_ICONHAND - -#define MB_TYPEMASK 0x0000000FL -#define MB_ICONMASK 0x000000F0L -#define MB_DEFMASK 0x00000F00L -#define MB_MODEMASK 0x00003000L -#define MB_MISCMASK 0x0000C000L - -#define IDOK 1 -#define IDCANCEL 2 -#define IDABORT 3 -#define IDRETRY 4 -#define IDIGNORE 5 -#define IDYES 6 -#define IDNO 7 - -#define WINAPI -#define APIENTRY - -#ifndef GUID_DEFINED -#define GUID_DEFINED -typedef struct _GUID -{ - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8]; -} GUID; - -#define stricmp strcasecmp - -#endif - -#if defined(__cplusplus) -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#define REFGUID const GUID & -#endif // !_REFGUID_DEFINED -#endif - -typedef struct tagRECT -{ - long left; - long top; - long right; - long bottom; -} RECT, *PRECT, *LPRECT; - -typedef uint UINT; - -#endif // __linux__ - -#include "synapse.h" -#include "iplugin.h" -#define USE_QERTABLE_DEFINE - -#include "missing.h" // temporary stuff, needs to be removed - -#include "str.h" -#include "qertypes.h" -#include "qerplugin.h" -#include "idata.h" -#include "ibrush.h" -#include "iselectedface.h" -#include "ishaders.h" -#include "ibspfrontend.h" -#include "iui.h" -#include "igl.h" -#include "itoolbar.h" -#include "ientity.h" - -#include "mathlib.h" - -extern _QERFuncTable_1 g_FuncTable; -extern _QERAppDataTable g_AppDataTable; -extern _QERBrushTable g_BrushTable; -extern _QERSelectedFaceTable g_SelectedFaceTable; -extern _QERShadersTable g_ShadersTable; -extern _QERQglTable g_QglTable; -extern _QERUITable g_MessageTable; -extern _QEREntityTable g_EntityTable; - - -#define MAX_ROUND_ERROR 0.05 - -#include "gtkr_list.h" - -#endif +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#ifndef __STDAFX_BOBTOOLZ__ +#define __STDAFX_BOBTOOLZ__ + +#define VC_EXTRALEAN + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#define BOBTOOLZ_MINOR "bobtoolz" + +#include +#include +#include +#include + +#include "time.h" + +#if defined (__linux__) || defined (__APPLE__) + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +#include + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; +//typedef int bool; + +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L + + +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L + +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND + +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 + +#define WINAPI +#define APIENTRY + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; + +#define stricmp strcasecmp + +#endif + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#endif + +typedef struct tagRECT +{ + long left; + long top; + long right; + long bottom; +} RECT, *PRECT, *LPRECT; + +typedef uint UINT; + +#endif // __linux__ + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE + +#include "missing.h" // temporary stuff, needs to be removed + +#include "str.h" +#include "qertypes.h" +#include "qerplugin.h" +#include "idata.h" +#include "ibrush.h" +#include "iselectedface.h" +#include "ishaders.h" +#include "ibspfrontend.h" +#include "iui.h" +#include "igl.h" +#include "itoolbar.h" +#include "ientity.h" + +#include "mathlib.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERAppDataTable g_AppDataTable; +extern _QERBrushTable g_BrushTable; +extern _QERSelectedFaceTable g_SelectedFaceTable; +extern _QERShadersTable g_ShadersTable; +extern _QERQglTable g_QglTable; +extern _QERUITable g_MessageTable; +extern _QEREntityTable g_EntityTable; + + +#define MAX_ROUND_ERROR 0.05 + +#include "gtkr_list.h" + +#endif diff --git a/contrib/bobtoolz/bobToolz.h b/contrib/bobtoolz/bobToolz.h index d4290099..6101e877 100644 --- a/contrib/bobtoolz/bobToolz.h +++ b/contrib/bobtoolz/bobToolz.h @@ -1,64 +1,64 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// plugin.h : main header file for the PLUGIN DLL -// - -#if !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) -#define AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 - -#ifndef __AFXWIN_H__ - #error include 'StdAfx.h' before including this file for PCH -#endif - -#include "resource.h" // main symbols - -///////////////////////////////////////////////////////////////////////////// -// CPluginApp -// See plugin.cpp for the implementation of this class -// - -class CPluginApp : public CWinApp -{ -public: - CPluginApp(); - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CPluginApp) - //}}AFX_VIRTUAL - - //{{AFX_MSG(CPluginApp) - // NOTE - the ClassWizard will add and remove member functions here. - // DO NOT EDIT what you see in these blocks of generated code ! - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - - -///////////////////////////////////////////////////////////////////////////// - -//{{AFX_INSERT_LOCATION}} -// Microsoft Developer Studio will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// plugin.h : main header file for the PLUGIN DLL +// + +#if !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +#define AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef __AFXWIN_H__ + #error include 'StdAfx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CPluginApp +// See plugin.cpp for the implementation of this class +// + +class CPluginApp : public CWinApp +{ +public: + CPluginApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPluginApp) + //}}AFX_VIRTUAL + + //{{AFX_MSG(CPluginApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) diff --git a/contrib/bobtoolz/bsploader.h b/contrib/bobtoolz/bsploader.h index 96f7c851..3b98fc27 100644 --- a/contrib/bobtoolz/bsploader.h +++ b/contrib/bobtoolz/bsploader.h @@ -1,134 +1,134 @@ -#define LUMP_ENTITIES 0 -#define LUMP_SHADERS 1 -#define LUMP_PLANES 2 -#define LUMP_NODES 3 -#define LUMP_LEAFS 4 -#define LUMP_LEAFSURFACES 5 -#define LUMP_LEAFBRUSHES 6 -#define LUMP_MODELS 7 -#define LUMP_BRUSHES 8 -#define LUMP_BRUSHSIDES 9 -#define LUMP_DRAWVERTS 10 -#define LUMP_DRAWINDEXES 11 -#define LUMP_FOGS 12 -#define LUMP_SURFACES 13 -#define LUMP_LIGHTMAPS 14 -#define LUMP_LIGHTGRID 15 -#define LUMP_VISIBILITY 16 -#define HEADER_LUMPS 17 - -typedef struct { - int fileofs, filelen; -} lump_t; - -typedef struct { - int ident; - int version; - - lump_t lumps[HEADER_LUMPS]; -} dheader_t; - -typedef struct { - float normal[3]; - float dist; -} dplane_t; - -typedef struct { - int planeNum; - int children[2]; // negative numbers are -(leafs+1), not nodes - int mins[3]; // for frustom culling - int maxs[3]; -} dnode_t; - -typedef struct { - int cluster; // -1 = opaque cluster (do I still store these?) - int area; - - int mins[3]; // for frustum culling - int maxs[3]; - - int firstLeafSurface; - int numLeafSurfaces; - - int firstLeafBrush; - int numLeafBrushes; -} dleaf_t; - -typedef struct { - vec3_t xyz; - float st[2]; - float lightmap[2]; - vec3_t normal; - byte color[4]; -} qdrawVert_t; - -typedef struct { - int shaderNum; - int fogNum; - int surfaceType; - - int firstVert; - int numVerts; - - int firstIndex; - int numIndexes; - - int lightmapNum; - int lightmapX, lightmapY; - int lightmapWidth, lightmapHeight; - - vec3_t lightmapOrigin; - vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds - - int patchWidth; - int patchHeight; -} dsurface_t; - -typedef struct { - int planeNum; // positive plane side faces out of the leaf - int shaderNum; -} dbrushside_t; - -typedef struct { - int firstSide; - int numSides; - int shaderNum; // the shader that determines the contents flags -} dbrush_t; - -typedef enum { - MST_BAD, - MST_PLANAR, - MST_PATCH, - MST_TRIANGLE_SOUP, - MST_FLARE -} mapSurfaceType_t; - -#define MAX_MAP_VISIBILITY 0x200000 -#define MAX_MAP_NODES 0x20000 -#define MAX_MAP_PLANES 0x20000 -#define MAX_MAP_LEAFS 0x20000 - -extern int numVisBytes; -extern int numleafs; -extern int numplanes; -extern int numnodes; -extern int numDrawVerts; -extern int numDrawSurfaces; -extern int numleafsurfaces; -extern int numbrushes; -extern int numbrushsides; -extern int numleafbrushes; - -extern dnode_t *dnodes; -extern dplane_t *dplanes; -extern dleaf_t *dleafs; -extern byte *visBytes; -extern qdrawVert_t *drawVerts; -extern dsurface_t *drawSurfaces; -extern int *dleafsurfaces; -extern dbrush_t *dbrushes; -extern dbrushside_t *dbrushsides; -extern int *dleafbrushes; - -qboolean LoadBSPFile( const char *filename ); -void FreeBSPData(); +#define LUMP_ENTITIES 0 +#define LUMP_SHADERS 1 +#define LUMP_PLANES 2 +#define LUMP_NODES 3 +#define LUMP_LEAFS 4 +#define LUMP_LEAFSURFACES 5 +#define LUMP_LEAFBRUSHES 6 +#define LUMP_MODELS 7 +#define LUMP_BRUSHES 8 +#define LUMP_BRUSHSIDES 9 +#define LUMP_DRAWVERTS 10 +#define LUMP_DRAWINDEXES 11 +#define LUMP_FOGS 12 +#define LUMP_SURFACES 13 +#define LUMP_LIGHTMAPS 14 +#define LUMP_LIGHTGRID 15 +#define LUMP_VISIBILITY 16 +#define HEADER_LUMPS 17 + +typedef struct { + int fileofs, filelen; +} lump_t; + +typedef struct { + int ident; + int version; + + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct { + float normal[3]; + float dist; +} dplane_t; + +typedef struct { + int planeNum; + int children[2]; // negative numbers are -(leafs+1), not nodes + int mins[3]; // for frustom culling + int maxs[3]; +} dnode_t; + +typedef struct { + int cluster; // -1 = opaque cluster (do I still store these?) + int area; + + int mins[3]; // for frustum culling + int maxs[3]; + + int firstLeafSurface; + int numLeafSurfaces; + + int firstLeafBrush; + int numLeafBrushes; +} dleaf_t; + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; + byte color[4]; +} qdrawVert_t; + +typedef struct { + int shaderNum; + int fogNum; + int surfaceType; + + int firstVert; + int numVerts; + + int firstIndex; + int numIndexes; + + int lightmapNum; + int lightmapX, lightmapY; + int lightmapWidth, lightmapHeight; + + vec3_t lightmapOrigin; + vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds + + int patchWidth; + int patchHeight; +} dsurface_t; + +typedef struct { + int planeNum; // positive plane side faces out of the leaf + int shaderNum; +} dbrushside_t; + +typedef struct { + int firstSide; + int numSides; + int shaderNum; // the shader that determines the contents flags +} dbrush_t; + +typedef enum { + MST_BAD, + MST_PLANAR, + MST_PATCH, + MST_TRIANGLE_SOUP, + MST_FLARE +} mapSurfaceType_t; + +#define MAX_MAP_VISIBILITY 0x200000 +#define MAX_MAP_NODES 0x20000 +#define MAX_MAP_PLANES 0x20000 +#define MAX_MAP_LEAFS 0x20000 + +extern int numVisBytes; +extern int numleafs; +extern int numplanes; +extern int numnodes; +extern int numDrawVerts; +extern int numDrawSurfaces; +extern int numleafsurfaces; +extern int numbrushes; +extern int numbrushsides; +extern int numleafbrushes; + +extern dnode_t *dnodes; +extern dplane_t *dplanes; +extern dleaf_t *dleafs; +extern byte *visBytes; +extern qdrawVert_t *drawVerts; +extern dsurface_t *drawSurfaces; +extern int *dleafsurfaces; +extern dbrush_t *dbrushes; +extern dbrushside_t *dbrushsides; +extern int *dleafbrushes; + +qboolean LoadBSPFile( const char *filename ); +void FreeBSPData(); diff --git a/contrib/bobtoolz/ctfresource_gtk.h b/contrib/bobtoolz/ctfresource_gtk.h index e0d51870..3f706a04 100644 --- a/contrib/bobtoolz/ctfresource_gtk.h +++ b/contrib/bobtoolz/ctfresource_gtk.h @@ -1,34 +1,34 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by ctfresource_gtk.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ctfresource_gtk.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/dialogs/AboutDialog.h b/contrib/bobtoolz/dialogs/AboutDialog.h index 6467b4a6..54cfd017 100644 --- a/contrib/bobtoolz/dialogs/AboutDialog.h +++ b/contrib/bobtoolz/dialogs/AboutDialog.h @@ -1,64 +1,64 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) -#define AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 -// AboutDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CAboutDialog dialog - -class CAboutDialog : public CDialog -{ -// Construction -public: - CAboutDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CAboutDialog) - enum { IDD = IDD_ABOUT }; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CAboutDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CAboutDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Developer Studio will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +#define AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// AboutDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +class CAboutDialog : public CDialog +{ +// Construction +public: + CAboutDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAboutDialog) + enum { IDD = IDD_ABOUT }; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAboutDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/AutoCaulkDialog.h b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h index 313a547b..a8740275 100644 --- a/contrib/bobtoolz/dialogs/AutoCaulkDialog.h +++ b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h @@ -1,66 +1,66 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) -#define AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// AutoCaulkDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CAutoCaulkDialog dialog - -class CAutoCaulkDialog : public CDialog -{ -// Construction -public: - CAutoCaulkDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CAutoCaulkDialog) - enum { IDD = IDD_AUTOCAULK_DIALOG }; - CProgressCtrl m_prog2; - CProgressCtrl m_prog1; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CAutoCaulkDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CAutoCaulkDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AutoCaulkDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog dialog + +class CAutoCaulkDialog : public CDialog +{ +// Construction +public: + CAutoCaulkDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAutoCaulkDialog) + enum { IDD = IDD_AUTOCAULK_DIALOG }; + CProgressCtrl m_prog2; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAutoCaulkDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAutoCaulkDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h index 753b068c..9311c51c 100644 --- a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h +++ b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h @@ -1,71 +1,71 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// AutoCaulkStartDialog.h : header file -// - -#define MODE_AC_NORMAL 0 -#define MODE_AC_BUILD_MINI_PRT 1 -#define MODE_AC_SUPER 2 - -///////////////////////////////////////////////////////////////////////////// -// CAutoCaulkStartDialog dialog - -class CAutoCaulkStartDialog : public CDialog -{ -// Construction -public: - CAutoCaulkStartDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CAutoCaulkStartDialog) - enum { IDD = IDD_AUTOCAULKSTART_DIALOG }; - BOOL m_bAllowDestruction; - CString m_Warning1; - int m_nMode; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CAutoCaulkStartDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CAutoCaulkStartDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AutoCaulkStartDialog.h : header file +// + +#define MODE_AC_NORMAL 0 +#define MODE_AC_BUILD_MINI_PRT 1 +#define MODE_AC_SUPER 2 + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog dialog + +class CAutoCaulkStartDialog : public CDialog +{ +// Construction +public: + CAutoCaulkStartDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAutoCaulkStartDialog) + enum { IDD = IDD_AUTOCAULKSTART_DIALOG }; + BOOL m_bAllowDestruction; + CString m_Warning1; + int m_nMode; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAutoCaulkStartDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAutoCaulkStartDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/BrushCheckDialog.h b/contrib/bobtoolz/dialogs/BrushCheckDialog.h index 776c6137..2ccf8e8f 100644 --- a/contrib/bobtoolz/dialogs/BrushCheckDialog.h +++ b/contrib/bobtoolz/dialogs/BrushCheckDialog.h @@ -1,65 +1,65 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) -#define AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// BrushCheckDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CBrushCheckDialog dialog - -class CBrushCheckDialog : public CDialog -{ -// Construction -public: - CBrushCheckDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CBrushCheckDialog) - enum { IDD = IDD_BRUSHCHECKER_DIALOG }; - CProgressCtrl m_prog1; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CBrushCheckDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CBrushCheckDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// BrushCheckDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog dialog + +class CBrushCheckDialog : public CDialog +{ +// Construction +public: + CBrushCheckDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CBrushCheckDialog) + enum { IDD = IDD_BRUSHCHECKER_DIALOG }; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CBrushCheckDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CBrushCheckDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/DoorDialog.h b/contrib/bobtoolz/dialogs/DoorDialog.h index a40fd5b6..4d312cb9 100644 --- a/contrib/bobtoolz/dialogs/DoorDialog.h +++ b/contrib/bobtoolz/dialogs/DoorDialog.h @@ -1,74 +1,74 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) -#define AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// DoorDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CDoorDialog dialog - -class CDoorDialog : public CDialog -{ -// Construction -public: - CDoorDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CDoorDialog) - enum { IDD = IDD_DOOR_DIALOG }; - CString m_fbTextureName; - BOOL m_bSclMainHor; - BOOL m_bSclMainVert; - BOOL m_bSclTrimHor; - BOOL m_bSclTrimVert; - CString m_trimTextureName; - CString m_trimTexSetBox; - CString m_mainTexSetBox; - int m_doorDirection; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CDoorDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CDoorDialog) - afx_msg void OnSetMaintexBtn(); - afx_msg void OnSetTrimtexBtn(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) +#define AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// DoorDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog dialog + +class CDoorDialog : public CDialog +{ +// Construction +public: + CDoorDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CDoorDialog) + enum { IDD = IDD_DOOR_DIALOG }; + CString m_fbTextureName; + BOOL m_bSclMainHor; + BOOL m_bSclMainVert; + BOOL m_bSclTrimHor; + BOOL m_bSclTrimVert; + CString m_trimTextureName; + CString m_trimTexSetBox; + CString m_mainTexSetBox; + int m_doorDirection; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CDoorDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CDoorDialog) + afx_msg void OnSetMaintexBtn(); + afx_msg void OnSetTrimtexBtn(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/IntersectDialog.h b/contrib/bobtoolz/dialogs/IntersectDialog.h index 79a6e3cb..d1190a6f 100644 --- a/contrib/bobtoolz/dialogs/IntersectDialog.h +++ b/contrib/bobtoolz/dialogs/IntersectDialog.h @@ -1,70 +1,70 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) -#define AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// IntersectDialog.h : header file -// - -#define BRUSH_OPT_WHOLE_MAP 0 -#define BRUSH_OPT_SELECTED 1 - -///////////////////////////////////////////////////////////////////////////// -// CIntersectDialog dialog - -class CIntersectDialog : public CDialog -{ -// Construction -public: - CIntersectDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CIntersectDialog) - enum { IDD = IDD_INTERSECT_DIALOG }; - int m_nBrushOptions; - BOOL m_bUseDetail; - BOOL m_bDuplicateOnly; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CIntersectDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CIntersectDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) +#define AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IntersectDialog.h : header file +// + +#define BRUSH_OPT_WHOLE_MAP 0 +#define BRUSH_OPT_SELECTED 1 + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog dialog + +class CIntersectDialog : public CDialog +{ +// Construction +public: + CIntersectDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CIntersectDialog) + enum { IDD = IDD_INTERSECT_DIALOG }; + int m_nBrushOptions; + BOOL m_bUseDetail; + BOOL m_bDuplicateOnly; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CIntersectDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CIntersectDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/IntersectInfoDialog.h b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h index 72709ab3..51a4bf75 100644 --- a/contrib/bobtoolz/dialogs/IntersectInfoDialog.h +++ b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h @@ -1,65 +1,65 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) -#define AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// IntersectInfoDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CIntersectInfoDialog dialog - -class CIntersectInfoDialog : public CDialog -{ -// Construction -public: - CIntersectInfoDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CIntersectInfoDialog) - enum { IDD = IDD_INTERSECT_INFO_DIALOG }; - CProgressCtrl m_prog1; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CIntersectInfoDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CIntersectInfoDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IntersectInfoDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog dialog + +class CIntersectInfoDialog : public CDialog +{ +// Construction +public: + CIntersectInfoDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CIntersectInfoDialog) + enum { IDD = IDD_INTERSECT_INFO_DIALOG }; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CIntersectInfoDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CIntersectInfoDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/PolygonDialog.h b/contrib/bobtoolz/dialogs/PolygonDialog.h index d556f500..afe5cb87 100644 --- a/contrib/bobtoolz/dialogs/PolygonDialog.h +++ b/contrib/bobtoolz/dialogs/PolygonDialog.h @@ -1,74 +1,74 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) -#define AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// PolygonDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CPolygonDialog dialog - -class CPolygonDialog : public CDialog -{ -// Construction -public: - BOOL GetChkBool(int nID); - void EnableBorderEdit(BOOL bEnable); - void EnableBordered(BOOL bEnable); - CPolygonDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CPolygonDialog) - enum { IDD = IDD_POLYGON_DIALOG }; - UINT m_nSideCount; - BOOL m_bInverse; - BOOL m_bBorder; - UINT m_nBorderSize; - BOOL m_bAlignTop; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CPolygonDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CPolygonDialog) - virtual BOOL OnInitDialog(); - afx_msg void OnBorderChkClicked(); - afx_msg void OnInverseChkClickrd(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) +#define AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PolygonDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog dialog + +class CPolygonDialog : public CDialog +{ +// Construction +public: + BOOL GetChkBool(int nID); + void EnableBorderEdit(BOOL bEnable); + void EnableBordered(BOOL bEnable); + CPolygonDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPolygonDialog) + enum { IDD = IDD_POLYGON_DIALOG }; + UINT m_nSideCount; + BOOL m_bInverse; + BOOL m_bBorder; + UINT m_nBorderSize; + BOOL m_bAlignTop; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPolygonDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPolygonDialog) + virtual BOOL OnInitDialog(); + afx_msg void OnBorderChkClicked(); + afx_msg void OnInverseChkClickrd(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/StairDialog.h b/contrib/bobtoolz/dialogs/StairDialog.h index c42959af..0bcdc0ec 100644 --- a/contrib/bobtoolz/dialogs/StairDialog.h +++ b/contrib/bobtoolz/dialogs/StairDialog.h @@ -1,74 +1,74 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) -#define AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// StairDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CStairDialog dialog - -class CStairDialog : public CDialog -{ -// Construction -public: - CStairDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CStairDialog) - enum { IDD = IDD_STAIR_DIALOG }; - UINT m_nStairHeight; - int m_StairDir; - int m_StairStyle; - CString m_riserTexture; - BOOL m_bDetail; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CStairDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CStairDialog) - afx_msg void OnStyleBobClicked(); - afx_msg void OnStyleOrigClicked(); - virtual BOOL OnInitDialog(); - afx_msg void OnStyleCornerClicked(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -private: - void EnableDetail(BOOL bEnable); -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) +#define AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// StairDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog dialog + +class CStairDialog : public CDialog +{ +// Construction +public: + CStairDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CStairDialog) + enum { IDD = IDD_STAIR_DIALOG }; + UINT m_nStairHeight; + int m_StairDir; + int m_StairStyle; + CString m_riserTexture; + BOOL m_bDetail; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CStairDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CStairDialog) + afx_msg void OnStyleBobClicked(); + afx_msg void OnStyleOrigClicked(); + virtual BOOL OnInitDialog(); + afx_msg void OnStyleCornerClicked(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + void EnableDetail(BOOL bEnable); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/TextureResetDialog.h b/contrib/bobtoolz/dialogs/TextureResetDialog.h index e0843505..6f041611 100644 --- a/contrib/bobtoolz/dialogs/TextureResetDialog.h +++ b/contrib/bobtoolz/dialogs/TextureResetDialog.h @@ -1,73 +1,73 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// TextureResetDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CTextureResetDialog dialog - -class CTextureResetDialog : public CDialog -{ -// Construction -public: - CTextureResetDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CTextureResetDialog) - enum { IDD = IDD_TEXTURE_RESET_DIALOG }; - BOOL m_bAllTextures; - CString m_TextureName; - int m_nRotation; - float m_fScaleHorizontal; - float m_fScaleVertical; - int m_nShiftHorizontal; - int m_nShiftVertical; - BOOL m_bOnlyTexture; - CString m_NewTextureName; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CTextureResetDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CTextureResetDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TextureResetDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog dialog + +class CTextureResetDialog : public CDialog +{ +// Construction +public: + CTextureResetDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CTextureResetDialog) + enum { IDD = IDD_TEXTURE_RESET_DIALOG }; + BOOL m_bAllTextures; + CString m_TextureName; + int m_nRotation; + float m_fScaleHorizontal; + float m_fScaleVertical; + int m_nShiftHorizontal; + int m_nShiftVertical; + BOOL m_bOnlyTexture; + CString m_NewTextureName; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTextureResetDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CTextureResetDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/dialogs-gtk.h b/contrib/bobtoolz/dialogs/dialogs-gtk.h index 589b994e..987f7216 100644 --- a/contrib/bobtoolz/dialogs/dialogs-gtk.h +++ b/contrib/bobtoolz/dialogs/dialogs-gtk.h @@ -1,98 +1,98 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -struct BuildStairsRS{ - char mainTexture[256]; - char riserTexture[256]; - int direction; - int style; - int stairHeight; - qboolean bUseDetail; -}; - -struct ResetTextureRS { - int bResetTextureName; - char textureName[256]; - char newTextureName[256]; - - int bResetScale[2]; - float fScale[2]; - - int bResetShift[2]; - float fShift[2]; - - int bResetRotation; - int rotation; -}; - -struct TrainThingRS { - float fRadiusX, fRadiusY; - float fStartAngle, fEndAngle; - int iNumPoints; - float fStartHeight, fEndHeight; -}; - -struct IntersectRS{ - int nBrushOptions; - qboolean bUseDetail; - qboolean bDuplicateOnly; -}; - -struct PolygonRS{ - qboolean bUseBorder; - qboolean bInverse; - qboolean bAlignTop; - int nSides; - int nBorderWidth; -}; - -struct DoorRS{ - char mainTexture[256]; - char trimTexture[256]; - qboolean bScaleMainH; - qboolean bScaleMainV; - qboolean bScaleTrimH; - qboolean bScaleTrimV; - int nOrientation; -}; - -struct PathPlotterRS{ - int nPoints; - float fMultiplier; - float fGravity; - qboolean bNoUpdate; - qboolean bShowExtra; -}; - -struct TwinWidget{ - GtkWidget* one; - GtkWidget* two; -}; - -int DoMessageBox(const char* lpText, const char* lpCaption, guint32 uType); -int DoIntersectBox(IntersectRS* rs); -int DoPolygonBox(PolygonRS* rs); -int DoResetTextureBox (ResetTextureRS* rs); -int DoBuildStairsBox(BuildStairsRS* rs); -int DoDoorsBox(DoorRS* rs); -int DoPathPlotterBox(PathPlotterRS* rs); -int DoCTFColourChangeBox(); -int DoTrainThingBox (TrainThingRS* rs); - -//GtkWidget* GetProgressWindow(char* title, GtkProgressBar* feedback); +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +struct BuildStairsRS{ + char mainTexture[256]; + char riserTexture[256]; + int direction; + int style; + int stairHeight; + qboolean bUseDetail; +}; + +struct ResetTextureRS { + int bResetTextureName; + char textureName[256]; + char newTextureName[256]; + + int bResetScale[2]; + float fScale[2]; + + int bResetShift[2]; + float fShift[2]; + + int bResetRotation; + int rotation; +}; + +struct TrainThingRS { + float fRadiusX, fRadiusY; + float fStartAngle, fEndAngle; + int iNumPoints; + float fStartHeight, fEndHeight; +}; + +struct IntersectRS{ + int nBrushOptions; + qboolean bUseDetail; + qboolean bDuplicateOnly; +}; + +struct PolygonRS{ + qboolean bUseBorder; + qboolean bInverse; + qboolean bAlignTop; + int nSides; + int nBorderWidth; +}; + +struct DoorRS{ + char mainTexture[256]; + char trimTexture[256]; + qboolean bScaleMainH; + qboolean bScaleMainV; + qboolean bScaleTrimH; + qboolean bScaleTrimV; + int nOrientation; +}; + +struct PathPlotterRS{ + int nPoints; + float fMultiplier; + float fGravity; + qboolean bNoUpdate; + qboolean bShowExtra; +}; + +struct TwinWidget{ + GtkWidget* one; + GtkWidget* two; +}; + +int DoMessageBox(const char* lpText, const char* lpCaption, guint32 uType); +int DoIntersectBox(IntersectRS* rs); +int DoPolygonBox(PolygonRS* rs); +int DoResetTextureBox (ResetTextureRS* rs); +int DoBuildStairsBox(BuildStairsRS* rs); +int DoDoorsBox(DoorRS* rs); +int DoPathPlotterBox(PathPlotterRS* rs); +int DoCTFColourChangeBox(); +int DoTrainThingBox (TrainThingRS* rs); + +//GtkWidget* GetProgressWindow(char* title, GtkProgressBar* feedback); diff --git a/contrib/bobtoolz/dialogs/pathplotterdialog.h b/contrib/bobtoolz/dialogs/pathplotterdialog.h index 749e4da3..6edd8987 100644 --- a/contrib/bobtoolz/dialogs/pathplotterdialog.h +++ b/contrib/bobtoolz/dialogs/pathplotterdialog.h @@ -1,70 +1,70 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#if !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) -#define AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 -// PathPlotterDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CPathPlotterDialog dialog - -class CPathPlotterDialog : public CDialog -{ -// Construction -public: - CPathPlotterDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CPathPlotterDialog) - enum { IDD = IDD_PATHPLOTTER_DIALOG }; - float m_fGravity; - float m_fMultiplier; - BOOL m_bNoUpdate; - int m_nPoints; - BOOL m_bShowExtra; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CPathPlotterDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CPathPlotterDialog) - afx_msg void OnYes(); - afx_msg void OnNo(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#if !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PathPlotterDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog dialog + +class CPathPlotterDialog : public CDialog +{ +// Construction +public: + CPathPlotterDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPathPlotterDialog) + enum { IDD = IDD_PATHPLOTTER_DIALOG }; + float m_fGravity; + float m_fMultiplier; + BOOL m_bNoUpdate; + int m_nPoints; + BOOL m_bShowExtra; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPathPlotterDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPathPlotterDialog) + afx_msg void OnYes(); + afx_msg void OnNo(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/funchandlers.h b/contrib/bobtoolz/funchandlers.h index d8c1e33c..1e3696cb 100644 --- a/contrib/bobtoolz/funchandlers.h +++ b/contrib/bobtoolz/funchandlers.h @@ -1,72 +1,72 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -#include "DBobView.h" -#include "DVisDrawer.h" -#include "DTrainDrawer.h" -#include "DTreePlanter.h" - -extern DBobView* g_PathView; -extern DVisDrawer* g_VisView; -extern DTrainDrawer* g_TrainView; -extern DTreePlanter* g_TreePlanter; - -// intersect stuff -#define BRUSH_OPT_WHOLE_MAP 0 -#define BRUSH_OPT_SELECTED 1 - -// defines for stairs -#define MOVE_NORTH 0 -#define MOVE_SOUTH 1 -#define MOVE_EAST 2 -#define MOVE_WEST 3 - -#define STYLE_ORIGINAL 0 -#define STYLE_BOB 1 -#define STYLE_CORNER 2 - -// defines for doors -#define DIRECTION_NS 0 -#define DIRECTION_EW 1 - -// help -void LoadLists(); - - -// djbob -void DoIntersect( void ); -void DoPolygonsTB( void ); -void DoPolygons(vec3_t vMin, vec3_t vMax); -void DoFixBrushes( void ); -void DoResetTextures( void ); -void DoBuildStairs(vec3_t vMin, vec3_t vMax); -void DoBuildDoors(vec3_t vMin, vec3_t vMax); -void DoPathPlotter( void ); -void DoPitBuilder(vec3_t vMin, vec3_t vMax); -void DoCTFColourChanger( void ); -void DoMergePatches( void ); -void DoSplitPatch( void ); -void DoVisAnalyse( void ); -void DoTrainThing( void ); -void DoTrainPathPlot( void ); -void DoCaulkSelection( void ); -void DoTreePlanter( void ); -void DoDropEnts( void ); -void DoMakeChain( void ); -void DoFlipTerrain( void ); +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +#include "DBobView.h" +#include "DVisDrawer.h" +#include "DTrainDrawer.h" +#include "DTreePlanter.h" + +extern DBobView* g_PathView; +extern DVisDrawer* g_VisView; +extern DTrainDrawer* g_TrainView; +extern DTreePlanter* g_TreePlanter; + +// intersect stuff +#define BRUSH_OPT_WHOLE_MAP 0 +#define BRUSH_OPT_SELECTED 1 + +// defines for stairs +#define MOVE_NORTH 0 +#define MOVE_SOUTH 1 +#define MOVE_EAST 2 +#define MOVE_WEST 3 + +#define STYLE_ORIGINAL 0 +#define STYLE_BOB 1 +#define STYLE_CORNER 2 + +// defines for doors +#define DIRECTION_NS 0 +#define DIRECTION_EW 1 + +// help +void LoadLists(); + + +// djbob +void DoIntersect( void ); +void DoPolygonsTB( void ); +void DoPolygons(vec3_t vMin, vec3_t vMax); +void DoFixBrushes( void ); +void DoResetTextures( void ); +void DoBuildStairs(vec3_t vMin, vec3_t vMax); +void DoBuildDoors(vec3_t vMin, vec3_t vMax); +void DoPathPlotter( void ); +void DoPitBuilder(vec3_t vMin, vec3_t vMax); +void DoCTFColourChanger( void ); +void DoMergePatches( void ); +void DoSplitPatch( void ); +void DoVisAnalyse( void ); +void DoTrainThing( void ); +void DoTrainPathPlot( void ); +void DoCaulkSelection( void ); +void DoTreePlanter( void ); +void DoDropEnts( void ); +void DoMakeChain( void ); +void DoFlipTerrain( void ); diff --git a/contrib/bobtoolz/interfaces/IScriptParser.h b/contrib/bobtoolz/interfaces/IScriptParser.h index 934a9671..5d0ee5ba 100644 --- a/contrib/bobtoolz/interfaces/IScriptParser.h +++ b/contrib/bobtoolz/interfaces/IScriptParser.h @@ -1,23 +1,23 @@ -#ifndef _ISCRIPTPARSER_H_ -#define _ISCRIPTPARSER_H_ - -class IScriptParser { -public: - virtual ~IScriptParser() {}; - - virtual const char* GetToken ( bool ) = 0; - virtual char* GetBufferCopy ( void ) = 0; - virtual int GetTokenOffset ( void ) = 0; - - virtual void SkipBracedSection ( void ) = 0; - virtual void SkipRestOfLine ( void ) = 0; - virtual void UndoGetToken ( void ) = 0; - virtual void ResetParseSession ( void ) = 0; - - virtual void LoadScript ( const char* ) = 0; - virtual void SetScript ( char* ) = 0; - - virtual void AddBreakChar( char ) = 0; -}; - -#endif +#ifndef _ISCRIPTPARSER_H_ +#define _ISCRIPTPARSER_H_ + +class IScriptParser { +public: + virtual ~IScriptParser() {}; + + virtual const char* GetToken ( bool ) = 0; + virtual char* GetBufferCopy ( void ) = 0; + virtual int GetTokenOffset ( void ) = 0; + + virtual void SkipBracedSection ( void ) = 0; + virtual void SkipRestOfLine ( void ) = 0; + virtual void UndoGetToken ( void ) = 0; + virtual void ResetParseSession ( void ) = 0; + + virtual void LoadScript ( const char* ) = 0; + virtual void SetScript ( char* ) = 0; + + virtual void AddBreakChar( char ) = 0; +}; + +#endif diff --git a/contrib/bobtoolz/lists.h b/contrib/bobtoolz/lists.h index d71e7594..6f9774f6 100644 --- a/contrib/bobtoolz/lists.h +++ b/contrib/bobtoolz/lists.h @@ -1,21 +1,21 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -bool LoadExclusionList(char* filename, list* exclusionList); -bool LoadGList(char* filename, GList** loadlist); +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +bool LoadExclusionList(char* filename, list* exclusionList); +bool LoadGList(char* filename, GList** loadlist); diff --git a/contrib/bobtoolz/misc.h b/contrib/bobtoolz/misc.h index c02a99e9..81b48879 100644 --- a/contrib/bobtoolz/misc.h +++ b/contrib/bobtoolz/misc.h @@ -1,48 +1,48 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -vec_t Min(vec_t a, vec_t b); - -epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value); - -// reads current texture into global, returns pointer to it -const char* GetCurrentTexture(); - -void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture); - -void Sys_ERROR (char* text, ...); - -void BuildMiniPrt(list* exclusionList); - -void MoveBlock(int dir, vec3_t min, vec3_t max, float dist); -void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width); - -entity_s* FindEntityFromTargetname(const char* targetname, int* entNum); - -char* UnixToDosPath(char* path); - -char* GetFilename(char* buffer, const char* filename); -char* GetGameFilename(char* buffer, const char* filename); - -float Determinant3x3(float a1, float a2, float a3, - float b1, float b2, float b3, - float c1, float c2, float c3); - -bool GetEntityCentre(const char* entity, vec3_t centre); -void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ); +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +vec_t Min(vec_t a, vec_t b); + +epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value); + +// reads current texture into global, returns pointer to it +const char* GetCurrentTexture(); + +void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture); + +void Sys_ERROR (char* text, ...); + +void BuildMiniPrt(list* exclusionList); + +void MoveBlock(int dir, vec3_t min, vec3_t max, float dist); +void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width); + +entity_s* FindEntityFromTargetname(const char* targetname, int* entNum); + +char* UnixToDosPath(char* path); + +char* GetFilename(char* buffer, const char* filename); +char* GetGameFilename(char* buffer, const char* filename); + +float Determinant3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3); + +bool GetEntityCentre(const char* entity, vec3_t centre); +void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ); diff --git a/contrib/bobtoolz/resource-gtk.h b/contrib/bobtoolz/resource-gtk.h index e4522dff..9297877f 100644 --- a/contrib/bobtoolz/resource-gtk.h +++ b/contrib/bobtoolz/resource-gtk.h @@ -1,15 +1,15 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by bobtoolz-gtk.rc -// - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by bobtoolz-gtk.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/resource.h b/contrib/bobtoolz/resource.h index 999d639b..2c7f97ed 100644 --- a/contrib/bobtoolz/resource.h +++ b/contrib/bobtoolz/resource.h @@ -1,115 +1,115 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by bobToolz.rc -// -#define IDD_PATHPLOTTER_DIALOG 101 -#define IDD_ABOUT 129 -#define IDD_STAIR_DIALOG 130 -#define IDD_POLYGON_DIALOG 131 -#define IDB_BT_BITMAP 137 -#define IDI_ICON1 139 -#define IDD_POLYGON_BRD_DIALOG 141 -#define IDD_DOOR_DIALOG 141 -#define IDD_INTERSECT_DIALOG 143 -#define IDD_INTERSECT_INFO_DIALOG 144 -#define IDD_BRUSHCHECKER_DIALOG 146 -#define IDD_AUTOCAULK_DIALOG 147 -#define IDD_AUTOCAULKSTART_DIALOG 148 -#define IDD_TEXTURE_RESET_DIALOG 149 -#define IDC_EDIT1 1000 -#define IDC_DIR_N_RADIO 1001 -#define IDC_TRIMTEXTURE_EDIT 1001 -#define IDC_SCL_VERT_EDIT 1001 -#define IDC_DIR_S_RADIO 1002 -#define IDC_SCL_HOR_EDIT 1002 -#define IDC_POINTCOUNT_EDIT 1002 -#define IDC_DIR_E_RADIO 1003 -#define IDC_ROTATION_EDIT 1003 -#define IDC_MULTIPLIER_EDIT 1003 -#define IDC_DIR_W_RADIO 1004 -#define IDC_SHFT_VER_EDIT 1004 -#define IDC_GRAVITY_EDIT 1004 -#define IDC_STYLE_ORIG_RADIO 1005 -#define IDC_SHFT_HOR_EDIT 1005 -#define IDC_NOUPDATE_CHECK 1005 -#define IDC_STYLE_BOB_RADIO 1006 -#define IDC_SHOWEXTRA_CHECK 1006 -#define IDC_STYLE_CORNER_RADIO 1007 -#define IDC_RISER_EDIT 1011 -#define IDC_FLAT_EDIT 1012 -#define IDC_MAX_WALL_WIDTH 1013 -#define IDC_MIN_WALL_WIDTH 1014 -#define IDC_DETAIL_CHK 1014 -#define IDC_MAX_CLIFF_HEIGHT 1015 -#define IDC_INVERSE_CHK 1015 -#define IDC_MIN_CLIFF_HEIGHT 1016 -#define IDC_BORDER_CHK 1016 -#define IDC_ALIGN_CHK 1017 -#define IDC_BORDER_EDIT 1018 -#define IDC_MAX_CNR_SIZE 1019 -#define IDC_MIN_CNR_SIZE 1020 -#define IDC_FBTEXTURE_EDIT 1020 -#define IDC_GRID_SNAP 1021 -#define IDC_TEXSCALE1_CHECK 1021 -#define IDC_MAX_WALL_BREADTH 1022 -#define IDC_TEXSCALE2_CHECK 1022 -#define IDC_MIN_WALL_BREADTH 1023 -#define IDC_MAINTEX_COMBO 1023 -#define IDC_TEXSCALE3_CHECK 1024 -#define IDC_TEXSCALE4_CHECK 1025 -#define IDC_TRIMTEX_COMBO 1026 -#define IDC_SET_MAINTEX_BTN 1027 -#define IDC_SET_TRIMTEX_BTN 1028 -#define IDC_WHOLEMAP_CHECK 1030 -#define IDC_DETAIL_INCLUDE_CHECK 1031 -#define IDC_SKIPBOUNDS_CHECK 1032 -#define IDC_SKIPSIMPLE_CHECK 1033 -#define IDC_SKIPACCURATE_CHECK 1034 -#define IDC_PROGRESS1 1035 -#define IDC_INTR_PROG1 1035 -#define IDC_DIR_NS_RADIO 1036 -#define IDC_PROGRESS2 1036 -#define IDC_DIR_EW_RADIO 1037 -#define IDC_DIR_GROUP 1038 -#define IDC_WHOLEMAP_RADIO 1040 -#define IDC_SELECTED_RADIO 1041 -#define IDC_KILLBRUSHES_CHECK 1041 -#define IDC_WARNING1_STATIC 1042 -#define IDC_AC_NORMAL_RADIO 1043 -#define IDC_AC_BUILD_MINI_PRT_RADIO 1044 -#define IDC_AC_SUPER_RADIO 1045 -#define IDC_RESET_TEXTURE_EDIT 1046 -#define IDC_RESET_NEW_TEXTURE_EDIT 1047 -#define IDC_ONLYTEXTURE_CHECK 1048 -#define IDC_ALLTEXTURES_CHECK 1049 -#define IDC_DUPLICATEONLY_CHECK 1050 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1007 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by bobToolz.rc +// +#define IDD_PATHPLOTTER_DIALOG 101 +#define IDD_ABOUT 129 +#define IDD_STAIR_DIALOG 130 +#define IDD_POLYGON_DIALOG 131 +#define IDB_BT_BITMAP 137 +#define IDI_ICON1 139 +#define IDD_POLYGON_BRD_DIALOG 141 +#define IDD_DOOR_DIALOG 141 +#define IDD_INTERSECT_DIALOG 143 +#define IDD_INTERSECT_INFO_DIALOG 144 +#define IDD_BRUSHCHECKER_DIALOG 146 +#define IDD_AUTOCAULK_DIALOG 147 +#define IDD_AUTOCAULKSTART_DIALOG 148 +#define IDD_TEXTURE_RESET_DIALOG 149 +#define IDC_EDIT1 1000 +#define IDC_DIR_N_RADIO 1001 +#define IDC_TRIMTEXTURE_EDIT 1001 +#define IDC_SCL_VERT_EDIT 1001 +#define IDC_DIR_S_RADIO 1002 +#define IDC_SCL_HOR_EDIT 1002 +#define IDC_POINTCOUNT_EDIT 1002 +#define IDC_DIR_E_RADIO 1003 +#define IDC_ROTATION_EDIT 1003 +#define IDC_MULTIPLIER_EDIT 1003 +#define IDC_DIR_W_RADIO 1004 +#define IDC_SHFT_VER_EDIT 1004 +#define IDC_GRAVITY_EDIT 1004 +#define IDC_STYLE_ORIG_RADIO 1005 +#define IDC_SHFT_HOR_EDIT 1005 +#define IDC_NOUPDATE_CHECK 1005 +#define IDC_STYLE_BOB_RADIO 1006 +#define IDC_SHOWEXTRA_CHECK 1006 +#define IDC_STYLE_CORNER_RADIO 1007 +#define IDC_RISER_EDIT 1011 +#define IDC_FLAT_EDIT 1012 +#define IDC_MAX_WALL_WIDTH 1013 +#define IDC_MIN_WALL_WIDTH 1014 +#define IDC_DETAIL_CHK 1014 +#define IDC_MAX_CLIFF_HEIGHT 1015 +#define IDC_INVERSE_CHK 1015 +#define IDC_MIN_CLIFF_HEIGHT 1016 +#define IDC_BORDER_CHK 1016 +#define IDC_ALIGN_CHK 1017 +#define IDC_BORDER_EDIT 1018 +#define IDC_MAX_CNR_SIZE 1019 +#define IDC_MIN_CNR_SIZE 1020 +#define IDC_FBTEXTURE_EDIT 1020 +#define IDC_GRID_SNAP 1021 +#define IDC_TEXSCALE1_CHECK 1021 +#define IDC_MAX_WALL_BREADTH 1022 +#define IDC_TEXSCALE2_CHECK 1022 +#define IDC_MIN_WALL_BREADTH 1023 +#define IDC_MAINTEX_COMBO 1023 +#define IDC_TEXSCALE3_CHECK 1024 +#define IDC_TEXSCALE4_CHECK 1025 +#define IDC_TRIMTEX_COMBO 1026 +#define IDC_SET_MAINTEX_BTN 1027 +#define IDC_SET_TRIMTEX_BTN 1028 +#define IDC_WHOLEMAP_CHECK 1030 +#define IDC_DETAIL_INCLUDE_CHECK 1031 +#define IDC_SKIPBOUNDS_CHECK 1032 +#define IDC_SKIPSIMPLE_CHECK 1033 +#define IDC_SKIPACCURATE_CHECK 1034 +#define IDC_PROGRESS1 1035 +#define IDC_INTR_PROG1 1035 +#define IDC_DIR_NS_RADIO 1036 +#define IDC_PROGRESS2 1036 +#define IDC_DIR_EW_RADIO 1037 +#define IDC_DIR_GROUP 1038 +#define IDC_WHOLEMAP_RADIO 1040 +#define IDC_SELECTED_RADIO 1041 +#define IDC_KILLBRUSHES_CHECK 1041 +#define IDC_WARNING1_STATIC 1042 +#define IDC_AC_NORMAL_RADIO 1043 +#define IDC_AC_BUILD_MINI_PRT_RADIO 1044 +#define IDC_AC_SUPER_RADIO 1045 +#define IDC_RESET_TEXTURE_EDIT 1046 +#define IDC_RESET_NEW_TEXTURE_EDIT 1047 +#define IDC_ONLYTEXTURE_CHECK 1048 +#define IDC_ALLTEXTURES_CHECK 1049 +#define IDC_DUPLICATEONLY_CHECK 1050 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/shapes.h b/contrib/bobtoolz/shapes.h index e5fccd9c..46eae37a 100644 --- a/contrib/bobtoolz/shapes.h +++ b/contrib/bobtoolz/shapes.h @@ -1,49 +1,49 @@ -/* -BobToolz plugin for GtkRadiant -Copyright (C) 2001 Gordon Biggans - -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 -*/ - -// TODO: implement all this stuff via DBrush class. started with DShape -// TODO: Auto Face Scaling, no need to pass parms, calculated via brush. - -// Q3MAP stuff -#define FACE_DETAIL 0x8000000 - -// defines for polygon stuff -#define MAX_POLYGON_FACES 128 - -// generic (detail added 12/01/01, for AC+) -void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail); - -// ------------- -// ---caulked--- -// ------------- -void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp); - -// -------------- -// ---textured--- -// -------------- -void BuildDoorsX2(vec3_t min, vec3_t max, bool bSclMainHor, bool bSclMainVert, bool bSclTrimHor, bool bSclTrimVert, const char* mainTexture, const char* trimTexture, int direction); -void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction); -void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail); -void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex); -// stairs stuff. - -//void Build_Prism_Border(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop = FALSE); //moved to DShape -//void Build_Prism_Ordinary(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape -//void Build_Prism_Efficient(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape -// polygon stuff. +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +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 +*/ + +// TODO: implement all this stuff via DBrush class. started with DShape +// TODO: Auto Face Scaling, no need to pass parms, calculated via brush. + +// Q3MAP stuff +#define FACE_DETAIL 0x8000000 + +// defines for polygon stuff +#define MAX_POLYGON_FACES 128 + +// generic (detail added 12/01/01, for AC+) +void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail); + +// ------------- +// ---caulked--- +// ------------- +void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp); + +// -------------- +// ---textured--- +// -------------- +void BuildDoorsX2(vec3_t min, vec3_t max, bool bSclMainHor, bool bSclMainVert, bool bSclTrimHor, bool bSclTrimVert, const char* mainTexture, const char* trimTexture, int direction); +void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction); +void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail); +void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex); +// stairs stuff. + +//void Build_Prism_Border(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop = FALSE); //moved to DShape +//void Build_Prism_Ordinary(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape +//void Build_Prism_Efficient(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape +// polygon stuff. diff --git a/contrib/bobtoolz/visfind.h b/contrib/bobtoolz/visfind.h index 732f3b6c..0a4b601e 100644 --- a/contrib/bobtoolz/visfind.h +++ b/contrib/bobtoolz/visfind.h @@ -1 +1 @@ -list *BuildTrace(char* filename, vec3_t v_origin); +list *BuildTrace(char* filename, vec3_t v_origin); diff --git a/contrib/camera/camera.h b/contrib/camera/camera.h index d60783a9..cf1387c2 100644 --- a/contrib/camera/camera.h +++ b/contrib/camera/camera.h @@ -1,162 +1,162 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#ifndef _CAMERA_H_ -#define _CAMERA_H_ - -#ifdef _WIN32 - #pragma warning(disable : 4267) -#else - typedef unsigned char byte; -#endif - -class CCamera; - -#include - -#include "str.h" - -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" - -#include "igl.h" -#include "iui.h" -#include "icamera.h" - -#include "misc.h" -#include "dialogs.h" -#include "funchandlers.h" -#include "renderer.h" -#include "listener.h" - -extern _QERFuncTable_1 g_FuncTable; -extern _QERQglTable g_QglTable; -extern _QERUITable g_UITable; -extern _QERCameraTable g_CameraTable; - -extern CRenderer *Renderer; -extern CListener *Listener; - -// splinelib -#define CAMERA_PLUGIN -#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) - -extern void ( APIENTRY * qglBegin )(GLenum mode); -extern void ( APIENTRY * qglEnd )(void); -extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v); - -extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ); - -#include "splines/splines.h" - -// this needs to match splines.cpp -#define MAX_CAMERAS 64 -extern idCameraDef camera[MAX_CAMERAS]; - -extern "C" qboolean loadCamera(int camNum, const char *name); - -// -// CCamera -// - -class CCamera { -public: - CCamera( int i ) { - cam = &camera[i]; - camnum = i; - Init(); - } - ~CCamera(); - - void Init() { - next = prev = NULL; - fileName[0] = '\0'; - hasbeensaved = 0; - } - - idCameraDef *GetCam() { - return( cam ); - } - int GetCamNum() { - return( camnum ); - } - - char *GetFileName() { - return( fileName ); - } - void SetFileName( const char *name, bool save ) { - strcpy( fileName, name ); - if( save ) - hasbeensaved = 1; - } - - CCamera *GetNext() { - return( next ); - } - - CCamera *GetPrev() { - return( prev ); - } - - void SetNext( CCamera *camera ) { - next = camera; - } - void SetPrev( CCamera *camera ) { - prev = camera; - } - - int HasBeenSaved() { - return( hasbeensaved ); - } - void HasBeenModified() { - if( hasbeensaved ) - hasbeensaved = 2; - } - -protected: - idCameraDef *cam; - int camnum; - CCamera *next, *prev; - char fileName[PATH_MAX]; - int hasbeensaved; // 0:never saved 1:saved 2:saved, but modified -}; - -CCamera *AllocCam(); -void FreeCam( CCamera *cam ); -void SetCurrentCam( CCamera *cam ); -CCamera *GetCurrentCam(); - -// globals -extern GtkWidget *g_pRadiantWnd; -extern GtkWidget *g_pCameraInspectorWnd; -extern CCamera *firstCam; -extern bool g_bEditOn; -extern int g_iEditMode; -extern int g_iActiveTarget; -extern int g_iPreviewRunning; -extern CCamera *g_pCurrentEditCam; - -#endif // _CAMERA_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + +#ifdef _WIN32 + #pragma warning(disable : 4267) +#else + typedef unsigned char byte; +#endif + +class CCamera; + +#include + +#include "str.h" + +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" + +#include "igl.h" +#include "iui.h" +#include "icamera.h" + +#include "misc.h" +#include "dialogs.h" +#include "funchandlers.h" +#include "renderer.h" +#include "listener.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERUITable g_UITable; +extern _QERCameraTable g_CameraTable; + +extern CRenderer *Renderer; +extern CListener *Listener; + +// splinelib +#define CAMERA_PLUGIN +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) + +extern void ( APIENTRY * qglBegin )(GLenum mode); +extern void ( APIENTRY * qglEnd )(void); +extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v); + +extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ); + +#include "splines/splines.h" + +// this needs to match splines.cpp +#define MAX_CAMERAS 64 +extern idCameraDef camera[MAX_CAMERAS]; + +extern "C" qboolean loadCamera(int camNum, const char *name); + +// +// CCamera +// + +class CCamera { +public: + CCamera( int i ) { + cam = &camera[i]; + camnum = i; + Init(); + } + ~CCamera(); + + void Init() { + next = prev = NULL; + fileName[0] = '\0'; + hasbeensaved = 0; + } + + idCameraDef *GetCam() { + return( cam ); + } + int GetCamNum() { + return( camnum ); + } + + char *GetFileName() { + return( fileName ); + } + void SetFileName( const char *name, bool save ) { + strcpy( fileName, name ); + if( save ) + hasbeensaved = 1; + } + + CCamera *GetNext() { + return( next ); + } + + CCamera *GetPrev() { + return( prev ); + } + + void SetNext( CCamera *camera ) { + next = camera; + } + void SetPrev( CCamera *camera ) { + prev = camera; + } + + int HasBeenSaved() { + return( hasbeensaved ); + } + void HasBeenModified() { + if( hasbeensaved ) + hasbeensaved = 2; + } + +protected: + idCameraDef *cam; + int camnum; + CCamera *next, *prev; + char fileName[PATH_MAX]; + int hasbeensaved; // 0:never saved 1:saved 2:saved, but modified +}; + +CCamera *AllocCam(); +void FreeCam( CCamera *cam ); +void SetCurrentCam( CCamera *cam ); +CCamera *GetCurrentCam(); + +// globals +extern GtkWidget *g_pRadiantWnd; +extern GtkWidget *g_pCameraInspectorWnd; +extern CCamera *firstCam; +extern bool g_bEditOn; +extern int g_iEditMode; +extern int g_iActiveTarget; +extern int g_iPreviewRunning; +extern CCamera *g_pCurrentEditCam; + +#endif // _CAMERA_H_ diff --git a/contrib/camera/dialogs.h b/contrib/camera/dialogs.h index 5ba86c5a..93dbce1d 100644 --- a/contrib/camera/dialogs.h +++ b/contrib/camera/dialogs.h @@ -1,37 +1,37 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -struct TwinWidget { - GtkWidget* one; - GtkWidget* two; -}; - -void dialog_button_callback (GtkWidget *widget, gpointer data); -gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data); -//void dialog_button_callback_settex (GtkWidget *widget, gpointer data); - -void RefreshCamListCombo( void ); -GtkWidget *CreateCameraInspectorDialog( void ); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +struct TwinWidget { + GtkWidget* one; + GtkWidget* two; +}; + +void dialog_button_callback (GtkWidget *widget, gpointer data); +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data); +//void dialog_button_callback_settex (GtkWidget *widget, gpointer data); + +void RefreshCamListCombo( void ); +GtkWidget *CreateCameraInspectorDialog( void ); diff --git a/contrib/camera/funchandlers.h b/contrib/camera/funchandlers.h index a9419062..ee3b9274 100644 --- a/contrib/camera/funchandlers.h +++ b/contrib/camera/funchandlers.h @@ -1,37 +1,37 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -void DoNewFixedCamera(); -void DoNewInterpolatedCamera(); -void DoNewSplineCamera(); -void DoCameraInspector(); -void DoPreviewCamera(); -void DoLoadCamera(); -void DoSaveCamera(); -void DoUnloadCamera(); -void DoStartEdit( CCamera *cam ); -void DoStopEdit( void ); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +void DoNewFixedCamera(); +void DoNewInterpolatedCamera(); +void DoNewSplineCamera(); +void DoCameraInspector(); +void DoPreviewCamera(); +void DoLoadCamera(); +void DoSaveCamera(); +void DoUnloadCamera(); +void DoStartEdit( CCamera *cam ); +void DoStopEdit( void ); + diff --git a/contrib/camera/listener.h b/contrib/camera/listener.h index 13e14b71..6519508f 100644 --- a/contrib/camera/listener.h +++ b/contrib/camera/listener.h @@ -1,64 +1,64 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -class CListener : public IWindowListener -{ -public: - bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); - bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); - bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); - bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); - bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); - bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); - bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); - bool OnKeyPressed(char *s) { return false; } - bool Paint() { return true; } - void Close() { } - - void UnRegister(); - void Register(); - CListener(); - virtual ~CListener(); - - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - - void SetViewType( VIEWTYPE vt ) { if( m_vt != vt ) oldValid = false; m_vt = vt; } - -private: - IXYWndWrapper *g_pXYWndWrapper; - - bool m_bHooked; - int refCount; - VIEWTYPE m_vt; - - // mouse button status - bool m_bLeftMBPressed, m_bRightMBPressed, m_bMiddleMBPressed; - - // old mouse coordinates - bool oldValid; - gdouble old_x, old_y; -}; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +class CListener : public IWindowListener +{ +public: + bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnKeyPressed(char *s) { return false; } + bool Paint() { return true; } + void Close() { } + + void UnRegister(); + void Register(); + CListener(); + virtual ~CListener(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + void SetViewType( VIEWTYPE vt ) { if( m_vt != vt ) oldValid = false; m_vt = vt; } + +private: + IXYWndWrapper *g_pXYWndWrapper; + + bool m_bHooked; + int refCount; + VIEWTYPE m_vt; + + // mouse button status + bool m_bLeftMBPressed, m_bRightMBPressed, m_bMiddleMBPressed; + + // old mouse coordinates + bool oldValid; + gdouble old_x, old_y; +}; diff --git a/contrib/camera/misc.h b/contrib/camera/misc.h index 6c56dc73..52062c88 100644 --- a/contrib/camera/misc.h +++ b/contrib/camera/misc.h @@ -1,91 +1,91 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -void Sys_ERROR( char* text, ... ); -char* UnixToDosPath( char* path ); -void ExtractFilePath( const char *path, char *dest ); -const char* ExtractFilename( const char* path ); -bool FileExists (const char *filename); -int Q_stricmp (const char *s1, const char *s2); - -typedef int fileHandle_t; - -#define qfalse false -#define qtrue true - -extern "C" { -// command buffer -void Cbuf_AddText( const char *text ); -void Cbuf_Execute (void); - -// common -#ifndef CDECL -#ifdef _WIN32 - #define CDECL __cdecl -#else - #define CDECL -#endif -#endif - -void CDECL Com_Error( int level, const char *error, ... ); -void CDECL Com_Printf( const char *msg, ... ); -void CDECL Com_DPrintf( const char *msg, ... ); -void *Com_Allocate( int bytes ); -void Com_Dealloc( void *ptr ); - -// filesystem -int FS_Read( void *buffer, int len, fileHandle_t f ); -int FS_Write( const void *buffer, int len, fileHandle_t h ); -int FS_ReadFile( const char *qpath, void **buffer ); -void FS_FreeFile( void *buffer ); -int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ); -fileHandle_t FS_FOpenFileWrite( const char *filename ); -void FS_FCloseFile( fileHandle_t f ); -} - -// vectors -#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) -#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) -#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) -#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) - -#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) -#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) -#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) - -#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3]) -#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) -#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) -#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) -#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s)) -#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s)) - -#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) -#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) -#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) -#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) - -#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +void Sys_ERROR( char* text, ... ); +char* UnixToDosPath( char* path ); +void ExtractFilePath( const char *path, char *dest ); +const char* ExtractFilename( const char* path ); +bool FileExists (const char *filename); +int Q_stricmp (const char *s1, const char *s2); + +typedef int fileHandle_t; + +#define qfalse false +#define qtrue true + +extern "C" { +// command buffer +void Cbuf_AddText( const char *text ); +void Cbuf_Execute (void); + +// common +#ifndef CDECL +#ifdef _WIN32 + #define CDECL __cdecl +#else + #define CDECL +#endif +#endif + +void CDECL Com_Error( int level, const char *error, ... ); +void CDECL Com_Printf( const char *msg, ... ); +void CDECL Com_DPrintf( const char *msg, ... ); +void *Com_Allocate( int bytes ); +void Com_Dealloc( void *ptr ); + +// filesystem +int FS_Read( void *buffer, int len, fileHandle_t f ); +int FS_Write( const void *buffer, int len, fileHandle_t h ); +int FS_ReadFile( const char *qpath, void **buffer ); +void FS_FreeFile( void *buffer ); +int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ); +fileHandle_t FS_FOpenFileWrite( const char *filename ); +void FS_FCloseFile( fileHandle_t f ); +} + +// vectors +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) + +#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) +#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) +#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) + +#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3]) +#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) +#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) +#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) +#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s)) +#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s)) + +#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) +#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) +#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) + +#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];} diff --git a/contrib/camera/renderer.h b/contrib/camera/renderer.h index c2ca93bd..989567a1 100644 --- a/contrib/camera/renderer.h +++ b/contrib/camera/renderer.h @@ -1,46 +1,46 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -Camera plugin for GtkRadiant -Copyright (C) 2002 Splash Damage Ltd. -*/ - -class CRenderer : public IGL2DWindow, public IGL3DWindow { -public: - CRenderer(); - virtual ~CRenderer(); - -protected: - int refCount; - -public: - void Register(); - void UnRegister(); - void Initialize(); - void Draw2D( VIEWTYPE vt ); - void Draw3D(); - - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - - bool m_bHooked; -}; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +class CRenderer : public IGL2DWindow, public IGL3DWindow { +public: + CRenderer(); + virtual ~CRenderer(); + +protected: + int refCount; + +public: + void Register(); + void UnRegister(); + void Initialize(); + void Draw2D( VIEWTYPE vt ); + void Draw3D(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + bool m_bHooked; +}; diff --git a/contrib/gtkgensurf/gendlgs.h b/contrib/gtkgensurf/gendlgs.h index c6df4866..dd954678 100644 --- a/contrib/gtkgensurf/gendlgs.h +++ b/contrib/gtkgensurf/gendlgs.h @@ -1,151 +1,151 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#define DLG_PLANE_XY0 100 -#define DLG_PLANE_XY1 101 -#define DLG_PLANE_YZ0 102 -#define DLG_PLANE_XZ0 103 -#define DLG_PLANE_YZ1 104 -#define DLG_PLANE_XZ1 105 -#define DLG_WAVE_01 106 -#define DLG_WAVE_02 107 -#define DLG_WAVE_03 108 -#define DLG_WAVE_04 109 -#define DLG_WAVE_05 110 -#define DLG_WAVE_06 111 -#define DLG_LAMBDA 112 -#define DLG_LAMBDA_TEXT 113 -#define DLG_AMP 114 -#define DLG_AMP_TEXT 115 -#define DLG_ROUGH 116 -#define DLG_ROUGH_TEXT 117 -#define DLG_LINEARBORDER 118 -#define DLG_FILE 119 -#define DLG_FILE_BROWSE 120 -#define DLG_PREVIEW 121 -#define DLG_GO 122 -#define DLG_ABOUT 123 -#define DLG_NH_TEXT 124 -#define DLG_NH 125 -#define DLG_NH_SPIN 126 -#define DLG_NV_TEXT 127 -#define DLG_NV 128 -#define DLG_NV_SPIN 129 -#define DLG_HMIN_TEXT 130 -#define DLG_HMIN 131 -#define DLG_HMAX_TEXT 132 -#define DLG_HMAX 133 -#define DLG_VMIN_TEXT 134 -#define DLG_VMIN 135 -#define DLG_VMAX_TEXT 136 -#define DLG_VMAX 137 -#define DLG_Z00_TEXT 138 -#define DLG_Z00 139 -#define DLG_Z01_TEXT 140 -#define DLG_Z01 141 -#define DLG_Z10_TEXT 142 -#define DLG_Z10 143 -#define DLG_Z11_TEXT 144 -#define DLG_Z11 145 -#define DLG_TEXTURE 146 -#define DLG_SKYBOX 147 -#define DLG_AUTOOVERWRITE 148 -#define DLG_DETAIL 149 -#define DLG_ARGHRAD2 150 -#define DLG_ARGHRAD2_SPIN 151 -#define DLG_APPEND 152 -#define DLG_REFRESH 153 -#define DLG_TEXOFFSETX 154 -#define DLG_TEXOFFSETY 155 -#define DLG_TEXSCALEX 156 -#define DLG_TEXSCALEY 157 -#define DLG_FIXPOINTS 158 -#define DLG_TEXTURE_BROWSE 159 -#define DLG_AZIMUTH 162 -#define DLG_AZIMUTH_SPIN 163 -#define DLG_ELEVATION 164 -#define DLG_ELEVATION_SPIN 165 -#define DLG_RANDOMSEED 166 -#define DLG_RANDOMSEED_SPIN 167 -#define DLG_BITMAP 168 -#define DLG_SAVE 169 -#define DLG_OPEN 170 -#define DLG_TAB 171 -#define DLG_TEXTURE2 172 -#define DLG_TEXTURE2_BROWSE 173 -#define DLG_LADDER 174 -#define DLG_ARGHRAD2_TEXT 175 -#define DLG_FILE_TEXT 176 -#define DLG_DECIMATE 177 -#define DLG_DECIMATE_TEXT 178 -#define DLG_HIDEBACKFACES 179 -#define DLG_DEFAULTS 180 -#define DLG_ABOUT_APP 200 -#define DLG_ABOUT_ICON 201 -#define DLG_BMP_FILE 202 -#define DLG_BMP_FILE_BROWSE 203 -#define DLG_BMP_BLACK 204 -#define DLG_BMP_WHITE 205 -#define DLG_BMP_TEXT1 206 -#define DLG_BMP_TEXT2 207 -#define DLG_BMP_TEXT3 208 -#define DLG_BMP_NOTE 209 -#define DLG_BMP_RELOAD 210 -#define DLG_ABOUT_URL 211 -#define DLG_ABOUT_BOARD 212 -#define DLG_FIX_FREE 300 -#define DLG_FIX_FREEALL 301 -#define DLG_FIX_VALUE_TEXT 302 -#define DLG_FIX_VALUE 303 -#define DLG_FIX_VALUE_SPIN 304 -#define DLG_FIX_DONE 305 -#define DLG_FIX_RANGE_TEXT 306 -#define DLG_FIX_RANGE 307 -#define DLG_FIX_NOTE 308 -#define DLG_FIX_RATE_TEXT 309 -#define DLG_FIX_RATE 310 -#define DLG_USE_PATCHES 311 -#define DLG_DECIMATE_LABEL 312 -#define DLG_HINT 350 -#define DLG_GAME_00 400 -#define DLG_GAME_01 401 -#define DLG_GAME_02 402 -#define DLG_GAME_03 403 -#define DLG_GAME_04 404 -#define DLG_GAME_05 405 -#define DLG_GAME_06 406 -#define DLG_GAME_07 407 -#define DLG_GAME_08 408 -#define DLG_GAME_09 409 -#define DLG_TEX_USEPAK 420 -#define DLG_TEX_PAK_TEXT 421 -#define DLG_TEX_PAKFILE 422 -#define DLG_TEX_PAK_BROWSE 423 -#define DLG_TEX_LIST1 424 -#define DLG_TEX_LIST2 425 -#define DLG_TEX_LIST3 426 -#define DLG_TEXTURE3 427 -#define DLG_TEXTURE3_BROWSE 428 -#define DLG_TEX_SLANT_TEXT 429 -#define DLG_TEX_SLANT 430 -#define DLG_TEX_SLANT_SPIN 431 -#define DLG_EXCEL_FUNC 500 -#define DLG_EXCEL_FUNC_TEXT 501 -#define DLG_PREVIEW_ANTIALIASING 502 // ^Fishman - Antializing for the preview window. -#define DLG_SNAP_TO_GRID 503 // Hydra : snap to grid +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#define DLG_PLANE_XY0 100 +#define DLG_PLANE_XY1 101 +#define DLG_PLANE_YZ0 102 +#define DLG_PLANE_XZ0 103 +#define DLG_PLANE_YZ1 104 +#define DLG_PLANE_XZ1 105 +#define DLG_WAVE_01 106 +#define DLG_WAVE_02 107 +#define DLG_WAVE_03 108 +#define DLG_WAVE_04 109 +#define DLG_WAVE_05 110 +#define DLG_WAVE_06 111 +#define DLG_LAMBDA 112 +#define DLG_LAMBDA_TEXT 113 +#define DLG_AMP 114 +#define DLG_AMP_TEXT 115 +#define DLG_ROUGH 116 +#define DLG_ROUGH_TEXT 117 +#define DLG_LINEARBORDER 118 +#define DLG_FILE 119 +#define DLG_FILE_BROWSE 120 +#define DLG_PREVIEW 121 +#define DLG_GO 122 +#define DLG_ABOUT 123 +#define DLG_NH_TEXT 124 +#define DLG_NH 125 +#define DLG_NH_SPIN 126 +#define DLG_NV_TEXT 127 +#define DLG_NV 128 +#define DLG_NV_SPIN 129 +#define DLG_HMIN_TEXT 130 +#define DLG_HMIN 131 +#define DLG_HMAX_TEXT 132 +#define DLG_HMAX 133 +#define DLG_VMIN_TEXT 134 +#define DLG_VMIN 135 +#define DLG_VMAX_TEXT 136 +#define DLG_VMAX 137 +#define DLG_Z00_TEXT 138 +#define DLG_Z00 139 +#define DLG_Z01_TEXT 140 +#define DLG_Z01 141 +#define DLG_Z10_TEXT 142 +#define DLG_Z10 143 +#define DLG_Z11_TEXT 144 +#define DLG_Z11 145 +#define DLG_TEXTURE 146 +#define DLG_SKYBOX 147 +#define DLG_AUTOOVERWRITE 148 +#define DLG_DETAIL 149 +#define DLG_ARGHRAD2 150 +#define DLG_ARGHRAD2_SPIN 151 +#define DLG_APPEND 152 +#define DLG_REFRESH 153 +#define DLG_TEXOFFSETX 154 +#define DLG_TEXOFFSETY 155 +#define DLG_TEXSCALEX 156 +#define DLG_TEXSCALEY 157 +#define DLG_FIXPOINTS 158 +#define DLG_TEXTURE_BROWSE 159 +#define DLG_AZIMUTH 162 +#define DLG_AZIMUTH_SPIN 163 +#define DLG_ELEVATION 164 +#define DLG_ELEVATION_SPIN 165 +#define DLG_RANDOMSEED 166 +#define DLG_RANDOMSEED_SPIN 167 +#define DLG_BITMAP 168 +#define DLG_SAVE 169 +#define DLG_OPEN 170 +#define DLG_TAB 171 +#define DLG_TEXTURE2 172 +#define DLG_TEXTURE2_BROWSE 173 +#define DLG_LADDER 174 +#define DLG_ARGHRAD2_TEXT 175 +#define DLG_FILE_TEXT 176 +#define DLG_DECIMATE 177 +#define DLG_DECIMATE_TEXT 178 +#define DLG_HIDEBACKFACES 179 +#define DLG_DEFAULTS 180 +#define DLG_ABOUT_APP 200 +#define DLG_ABOUT_ICON 201 +#define DLG_BMP_FILE 202 +#define DLG_BMP_FILE_BROWSE 203 +#define DLG_BMP_BLACK 204 +#define DLG_BMP_WHITE 205 +#define DLG_BMP_TEXT1 206 +#define DLG_BMP_TEXT2 207 +#define DLG_BMP_TEXT3 208 +#define DLG_BMP_NOTE 209 +#define DLG_BMP_RELOAD 210 +#define DLG_ABOUT_URL 211 +#define DLG_ABOUT_BOARD 212 +#define DLG_FIX_FREE 300 +#define DLG_FIX_FREEALL 301 +#define DLG_FIX_VALUE_TEXT 302 +#define DLG_FIX_VALUE 303 +#define DLG_FIX_VALUE_SPIN 304 +#define DLG_FIX_DONE 305 +#define DLG_FIX_RANGE_TEXT 306 +#define DLG_FIX_RANGE 307 +#define DLG_FIX_NOTE 308 +#define DLG_FIX_RATE_TEXT 309 +#define DLG_FIX_RATE 310 +#define DLG_USE_PATCHES 311 +#define DLG_DECIMATE_LABEL 312 +#define DLG_HINT 350 +#define DLG_GAME_00 400 +#define DLG_GAME_01 401 +#define DLG_GAME_02 402 +#define DLG_GAME_03 403 +#define DLG_GAME_04 404 +#define DLG_GAME_05 405 +#define DLG_GAME_06 406 +#define DLG_GAME_07 407 +#define DLG_GAME_08 408 +#define DLG_GAME_09 409 +#define DLG_TEX_USEPAK 420 +#define DLG_TEX_PAK_TEXT 421 +#define DLG_TEX_PAKFILE 422 +#define DLG_TEX_PAK_BROWSE 423 +#define DLG_TEX_LIST1 424 +#define DLG_TEX_LIST2 425 +#define DLG_TEX_LIST3 426 +#define DLG_TEXTURE3 427 +#define DLG_TEXTURE3_BROWSE 428 +#define DLG_TEX_SLANT_TEXT 429 +#define DLG_TEX_SLANT 430 +#define DLG_TEX_SLANT_SPIN 431 +#define DLG_EXCEL_FUNC 500 +#define DLG_EXCEL_FUNC_TEXT 501 +#define DLG_PREVIEW_ANTIALIASING 502 // ^Fishman - Antializing for the preview window. +#define DLG_SNAP_TO_GRID 503 // Hydra : snap to grid diff --git a/contrib/gtkgensurf/gensurf.h b/contrib/gtkgensurf/gensurf.h index 2c516d4e..8e42ac0d 100644 --- a/contrib/gtkgensurf/gensurf.h +++ b/contrib/gtkgensurf/gensurf.h @@ -1,395 +1,395 @@ -/* -GenSurf plugin for GtkRadiant -Copyright (C) 2001 David Hyde, Loki software and qeradiant.com - -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 -*/ - -#ifndef _GENSURF_H_ -#define _GENSURF_H_ - -#include - -#include "qerplugin.h" -//#include "qertypes.h" - -#include "igl.h" -#include "iui_gtk.h" -#include "ientity.h" - -#include "gendlgs.h" - -#define PLUGIN -#define Q3RADIANT - -#if defined(__linux__) || defined(__APPLE__) -template -inline T min (T x, T y) { return (x < y) ? x : y; } -template -inline T max (T x, T y) { return (x > y) ? x : y; } - -typedef struct { long x, y; } POINT; -typedef struct { long left, top, right, bottom; } RECT; -#endif -inline bool PtInRect (RECT *rc, POINT pt) -{ - if (pt.x < rc->left) return false; - if (pt.x > rc->right) return false; - if (pt.y < rc->bottom) return false; - if (pt.y > rc->top) return false; - return true; -} - -#define NUMGAMES 7 - -#define CONTENTS_SOLID 0x00000001 -#define CONTENTS_DETAIL 0x08000000 // brushes to be added after vis leafs -#define CONTENTS_LADDER 0x20000000 -#define SURF_HINT 0x100 // make a primary bsp splitter -#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes -#define HINT_OFFSET 96 - -#define PI 3.14159265358979224 -#define RadiansToDegrees(a) (floor(a*57.2957795 - 0.5)+1.) -#define DegreesToRadians(a) (a/57.2957795) - -#define BOGUS_RANGE 65536 -#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) -#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} -#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} -#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} -#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} -#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} -#define XYZVectorSubtract(a,b,c) {c[0]=(float)a[0]-(float)b[0];c[1]=(float)a[1]-(float)b[1];c[2]=(float)a[2]-(float)b[2];} -#define side(u1,v1,u2,v2,u3,v3) (v3-v1)*(u2-u1) - (u3-u1)*(v2-v1) - -#define QUAKE2 0 -#define HALFLIFE 1 -#define SIN 2 -#define HERETIC2 3 -#define KINGPIN 4 -#define GENESIS3D 5 -#define QUAKE3 6 - -#define MAX_FACES_PER_BRUSH 6 -#define SLIVER_ANGLE DegreesToRadians(20) -#define MAX_NODES (MAX_ROWS+1)*(MAX_ROWS+1) -#define MAX_TRIS (MAX_ROWS)*(MAX_ROWS) - -typedef float vec; -typedef vec vec3[3]; -typedef vec vec2[2]; - -typedef struct -{ - vec3 v[3]; - char texture[64]; - float Shift[2]; - float Rotate; - float Scale[2]; - int Contents; - int Surface; - int Value; -} FACE; - -typedef struct -{ - vec3 normal; - vec dist; -} PLANE; - -typedef struct -{ - int numpoints; - vec3 p[4]; // variable sized -} MY_WINDING; - -typedef struct -{ - int Number; - int NumFaces; - FACE face[MAX_FACES_PER_BRUSH]; -} BRUSH; - -typedef struct tagXYZ -{ - int fixed; - int done; - double p[3]; - double pp[3]; // these used only for general 3D projection (not isometric) - double fixed_value; - double range; - double rate; -} XYZ; - -// Q2 PAK file structures -typedef struct -{ - char id[4]; // Should be 'PACK' - int dstart; // Offest in the file to the directory - int dsize; // Size in bytes of the directory, same as num_items*64 -} pak_header_t; - -typedef struct -{ - char name[56]; // The name of the item, normal C string - int start; // Offset in .pak file to start of item - int size; // Size of item in bytes -} pak_item_t; - -// SiN .SIN structures -#define SINPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'S') -#define MAX_PAK_FILENAME_LENGTH 120 - -typedef struct -{ - char name[MAX_PAK_FILENAME_LENGTH]; - int filepos, filelen; -} dpackfile_t; - -typedef struct -{ - int ident; // == IDPAKHEADER - int dirofs; - int dirlen; -} dpackheader_t; - -// Half-Life WAD file structures -typedef struct -{ - char identification[4]; // should be WAD2 or 2DAW - int numlumps; - int infotableofs; -} wadinfo_t; - -typedef struct -{ - int filepos; - int disksize; - int size; // uncompressed - char type; - char compression; - char pad1, pad2; - char name[16]; // must be null terminated -} lumpinfo_t; - -typedef struct -{ - int signature; - short version; - short bitflag; - short compression_method; - short modfiletime; - short modfiledate; - int crc; - int compressed_size; - int uncompressed_size; - short filename_size; - short extra_size; -} zipheader_t; - -typedef struct -{ - double x[2]; - double y[2]; - double z[2]; -} bounding_box; - -typedef struct -{ - float p[3]; - int used; - int tri; - float error; - int fixed; -} NODE; - -typedef struct -{ - int v[3]; - int n[3]; // indices of neighboring triangles - PLANE plane; - int flag; - float min[3]; - float max[3]; -} TRI; - -//--------------- bitmap.c ----------------------------- -bool OpenBitmap (); -void GenerateBitmapMapping (); -//--------------- face.c ------------------------------- -void PlaneFromPoints (float *, float *, float *, PLANE *); -void CrossProduct (vec3 v1, vec3 v2, vec3 cross); -vec VectorNormalize (vec3 in, vec3 out); -//--------------- gendlg.c ----------------------------- -GtkWidget* create_main_dialog (); -void About (GtkWidget *parent); -//--------------- genmap.c ----------------------------- -double AtLeast(double,double); -bool CanEdit(int, int); -void CloseFuncGroup(); -bool FixedPoint(int,int); -void GenerateMap(); -void GenerateXYZ(); -double LessThan(double,double); -void MakeBrush(BRUSH *); -double MoreThan(double,double); -double Nearest(double,double); -double NoMoreThan(double,double); -void OpenFuncGroup(); -void PlasmaCloud(); -int PlayerStartZ(double,double); -void SubdividePlasma(int,int,int,int); -bool ValidSurface(); -void XYZtoV(XYZ *, vec3 *); -void MakePatch(patchMesh_t *); -double CalculateSnapValue(double value); - -//---------------- gensurf.c --------------------------- -bool GenSurfInit (); -void ReadIniFile (const char *); -void WriteIniFile (const char *); -void OpenSetup (GtkWidget*,int); -void SaveSetup (GtkWidget*); -//---------------- heretic.c --------------------------- -int GetDefSurfaceProps(char *); -//---------------- view.c ------------------------------ -void CreateViewWindow (); -void DrawGrid(RECT); -void DrawPreview(RECT); -void evaluate(); -void GetScaleFactor(RECT); -void project(XYZ *); -void Scale(RECT,XYZ,POINT *); -void ShowPreview (); -void UpdatePreview (bool); - -//---------------- plugin.c ----------------------------- -void UseFaceBounds(); - -extern _QERFuncTable_1 g_FuncTable; -extern _QERQglTable g_GLTable; -extern _QERUIGtkTable g_UIGtkTable; -extern _QEREntityTable g_EntityTable; -//#define MAX_ROWS 64 -#define MAX_ROWS 128 - -#define PLANE_XY0 0 -#define PLANE_XY1 1 -#define PLANE_YZ0 2 -#define PLANE_XZ0 3 -#define PLANE_YZ1 4 -#define PLANE_XZ1 5 - -#define WAVE_COS_SIN 0 -#define WAVE_HCYLINDER 1 -#define WAVE_VCYLINDER 2 -#define WAVE_BITMAP 3 -#define WAVE_ROUGH_ONLY 4 -#define WAVE_FORMULA 5 -#define WAVE_FIRST WAVE_COS_SIN -#define WAVE_LAST WAVE_FORMULA -#define DLG_WAVE_LAST DLG_WAVE_01+WAVE_LAST-WAVE_FIRST - -#define MSG_VERTEX_SELECTED WM_USER+1 - -typedef struct tagMYBITMAP -{ - char name[NAME_MAX]; - char defpath[NAME_MAX]; - double black_value; - double white_value; - int width, height; - unsigned char* colors; -} MYBITMAP; - -typedef struct tagELEMENT { - int i; - int j; -} ELEMENT; - -extern char gszAppDir[NAME_MAX]; -extern char gszCaption[64]; -extern char gszHelpFile[NAME_MAX]; -extern char gszIni[NAME_MAX]; -extern char gszMapFile[NAME_MAX]; -extern char gszVersion[64]; -extern double Amplitude; -extern double Roughness; -extern double TexOffset[2]; -extern double TexScale[2]; -extern double WaveLength; -extern double Hll, Hur, Vll, Vur; -extern double Z00, Z01, Z10, Z11; -extern double yaw, pitch, roll; -extern ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; -extern int AddHints; -extern int ArghRad2; -extern int AutoOverwrite; -extern int Decimate; -extern int FileAppend; -extern int FixBorders; -extern int HideBackFaces; -extern int NH, NV; -extern int NumVerticesSelected; -extern int Plane; -extern int Preview; -extern int RandomSeed; -extern int Skybox; -extern int UseDetail; -extern int UseLadder; -extern int VertexMode; -extern int vid_x, vid_y; -extern int WaveType; -extern int gNumNodes; -extern int gNumTris; -extern int view_x, view_y; -extern int view_cx, view_cy; -extern int UsePatches; -extern int SlantAngle; -extern int GimpHints; -extern int Antialiasing; // ^Fishman - Antializing for the preview window. -extern int AddTerrainKey; // ^Fishman - Add terrain key to func_group. -extern int SnapToGrid; // Hydra : snap to grid -extern int SP; // ^Fishman - Snap to grid. - -/*extern HCURSOR ghCursorCurrent; -extern HCURSOR ghCursorDefault; -extern HCURSOR ghCursorVertex; -extern HINSTANCE ghInst;*/ -extern GtkWidget *g_pRadiantWnd; -extern GtkWidget *g_pWnd; -/*extern HWND ghwndAngles; -extern HWND ghwndFix; -*/extern GtkWidget *g_pWndPreview; -extern GtkWidget *g_pPreviewWidget; -extern MYBITMAP gbmp; -extern NODE *gNode; -extern TRI *gTri; -extern XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; - -extern int Game; -extern bounding_box PlayerBox[NUMGAMES]; -//extern char gszOutputDir[NUMGAMES][NAME_MAX]; -extern char Texture[NUMGAMES][3][64]; -//extern char gszTextureDir[NUMGAMES][NAME_MAX]; -extern char GameName[NUMGAMES][16]; -//extern char pakfile[NUMGAMES][NAME_MAX]; -//extern char lastpakfile[NUMGAMES][NAME_MAX]; -//extern int UsePak[NUMGAMES]; -//extern char GameDir[NUMGAMES][NAME_MAX]; -//extern char ExcelFunc[1024]; - -#endif // _GENSURF_H_ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +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 +*/ + +#ifndef _GENSURF_H_ +#define _GENSURF_H_ + +#include + +#include "qerplugin.h" +//#include "qertypes.h" + +#include "igl.h" +#include "iui_gtk.h" +#include "ientity.h" + +#include "gendlgs.h" + +#define PLUGIN +#define Q3RADIANT + +#if defined(__linux__) || defined(__APPLE__) +template +inline T min (T x, T y) { return (x < y) ? x : y; } +template +inline T max (T x, T y) { return (x > y) ? x : y; } + +typedef struct { long x, y; } POINT; +typedef struct { long left, top, right, bottom; } RECT; +#endif +inline bool PtInRect (RECT *rc, POINT pt) +{ + if (pt.x < rc->left) return false; + if (pt.x > rc->right) return false; + if (pt.y < rc->bottom) return false; + if (pt.y > rc->top) return false; + return true; +} + +#define NUMGAMES 7 + +#define CONTENTS_SOLID 0x00000001 +#define CONTENTS_DETAIL 0x08000000 // brushes to be added after vis leafs +#define CONTENTS_LADDER 0x20000000 +#define SURF_HINT 0x100 // make a primary bsp splitter +#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes +#define HINT_OFFSET 96 + +#define PI 3.14159265358979224 +#define RadiansToDegrees(a) (floor(a*57.2957795 - 0.5)+1.) +#define DegreesToRadians(a) (a/57.2957795) + +#define BOGUS_RANGE 65536 +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define XYZVectorSubtract(a,b,c) {c[0]=(float)a[0]-(float)b[0];c[1]=(float)a[1]-(float)b[1];c[2]=(float)a[2]-(float)b[2];} +#define side(u1,v1,u2,v2,u3,v3) (v3-v1)*(u2-u1) - (u3-u1)*(v2-v1) + +#define QUAKE2 0 +#define HALFLIFE 1 +#define SIN 2 +#define HERETIC2 3 +#define KINGPIN 4 +#define GENESIS3D 5 +#define QUAKE3 6 + +#define MAX_FACES_PER_BRUSH 6 +#define SLIVER_ANGLE DegreesToRadians(20) +#define MAX_NODES (MAX_ROWS+1)*(MAX_ROWS+1) +#define MAX_TRIS (MAX_ROWS)*(MAX_ROWS) + +typedef float vec; +typedef vec vec3[3]; +typedef vec vec2[2]; + +typedef struct +{ + vec3 v[3]; + char texture[64]; + float Shift[2]; + float Rotate; + float Scale[2]; + int Contents; + int Surface; + int Value; +} FACE; + +typedef struct +{ + vec3 normal; + vec dist; +} PLANE; + +typedef struct +{ + int numpoints; + vec3 p[4]; // variable sized +} MY_WINDING; + +typedef struct +{ + int Number; + int NumFaces; + FACE face[MAX_FACES_PER_BRUSH]; +} BRUSH; + +typedef struct tagXYZ +{ + int fixed; + int done; + double p[3]; + double pp[3]; // these used only for general 3D projection (not isometric) + double fixed_value; + double range; + double rate; +} XYZ; + +// Q2 PAK file structures +typedef struct +{ + char id[4]; // Should be 'PACK' + int dstart; // Offest in the file to the directory + int dsize; // Size in bytes of the directory, same as num_items*64 +} pak_header_t; + +typedef struct +{ + char name[56]; // The name of the item, normal C string + int start; // Offset in .pak file to start of item + int size; // Size of item in bytes +} pak_item_t; + +// SiN .SIN structures +#define SINPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'S') +#define MAX_PAK_FILENAME_LENGTH 120 + +typedef struct +{ + char name[MAX_PAK_FILENAME_LENGTH]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +// Half-Life WAD file structures +typedef struct +{ + char identification[4]; // should be WAD2 or 2DAW + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +typedef struct +{ + int signature; + short version; + short bitflag; + short compression_method; + short modfiletime; + short modfiledate; + int crc; + int compressed_size; + int uncompressed_size; + short filename_size; + short extra_size; +} zipheader_t; + +typedef struct +{ + double x[2]; + double y[2]; + double z[2]; +} bounding_box; + +typedef struct +{ + float p[3]; + int used; + int tri; + float error; + int fixed; +} NODE; + +typedef struct +{ + int v[3]; + int n[3]; // indices of neighboring triangles + PLANE plane; + int flag; + float min[3]; + float max[3]; +} TRI; + +//--------------- bitmap.c ----------------------------- +bool OpenBitmap (); +void GenerateBitmapMapping (); +//--------------- face.c ------------------------------- +void PlaneFromPoints (float *, float *, float *, PLANE *); +void CrossProduct (vec3 v1, vec3 v2, vec3 cross); +vec VectorNormalize (vec3 in, vec3 out); +//--------------- gendlg.c ----------------------------- +GtkWidget* create_main_dialog (); +void About (GtkWidget *parent); +//--------------- genmap.c ----------------------------- +double AtLeast(double,double); +bool CanEdit(int, int); +void CloseFuncGroup(); +bool FixedPoint(int,int); +void GenerateMap(); +void GenerateXYZ(); +double LessThan(double,double); +void MakeBrush(BRUSH *); +double MoreThan(double,double); +double Nearest(double,double); +double NoMoreThan(double,double); +void OpenFuncGroup(); +void PlasmaCloud(); +int PlayerStartZ(double,double); +void SubdividePlasma(int,int,int,int); +bool ValidSurface(); +void XYZtoV(XYZ *, vec3 *); +void MakePatch(patchMesh_t *); +double CalculateSnapValue(double value); + +//---------------- gensurf.c --------------------------- +bool GenSurfInit (); +void ReadIniFile (const char *); +void WriteIniFile (const char *); +void OpenSetup (GtkWidget*,int); +void SaveSetup (GtkWidget*); +//---------------- heretic.c --------------------------- +int GetDefSurfaceProps(char *); +//---------------- view.c ------------------------------ +void CreateViewWindow (); +void DrawGrid(RECT); +void DrawPreview(RECT); +void evaluate(); +void GetScaleFactor(RECT); +void project(XYZ *); +void Scale(RECT,XYZ,POINT *); +void ShowPreview (); +void UpdatePreview (bool); + +//---------------- plugin.c ----------------------------- +void UseFaceBounds(); + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_GLTable; +extern _QERUIGtkTable g_UIGtkTable; +extern _QEREntityTable g_EntityTable; +//#define MAX_ROWS 64 +#define MAX_ROWS 128 + +#define PLANE_XY0 0 +#define PLANE_XY1 1 +#define PLANE_YZ0 2 +#define PLANE_XZ0 3 +#define PLANE_YZ1 4 +#define PLANE_XZ1 5 + +#define WAVE_COS_SIN 0 +#define WAVE_HCYLINDER 1 +#define WAVE_VCYLINDER 2 +#define WAVE_BITMAP 3 +#define WAVE_ROUGH_ONLY 4 +#define WAVE_FORMULA 5 +#define WAVE_FIRST WAVE_COS_SIN +#define WAVE_LAST WAVE_FORMULA +#define DLG_WAVE_LAST DLG_WAVE_01+WAVE_LAST-WAVE_FIRST + +#define MSG_VERTEX_SELECTED WM_USER+1 + +typedef struct tagMYBITMAP +{ + char name[NAME_MAX]; + char defpath[NAME_MAX]; + double black_value; + double white_value; + int width, height; + unsigned char* colors; +} MYBITMAP; + +typedef struct tagELEMENT { + int i; + int j; +} ELEMENT; + +extern char gszAppDir[NAME_MAX]; +extern char gszCaption[64]; +extern char gszHelpFile[NAME_MAX]; +extern char gszIni[NAME_MAX]; +extern char gszMapFile[NAME_MAX]; +extern char gszVersion[64]; +extern double Amplitude; +extern double Roughness; +extern double TexOffset[2]; +extern double TexScale[2]; +extern double WaveLength; +extern double Hll, Hur, Vll, Vur; +extern double Z00, Z01, Z10, Z11; +extern double yaw, pitch, roll; +extern ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; +extern int AddHints; +extern int ArghRad2; +extern int AutoOverwrite; +extern int Decimate; +extern int FileAppend; +extern int FixBorders; +extern int HideBackFaces; +extern int NH, NV; +extern int NumVerticesSelected; +extern int Plane; +extern int Preview; +extern int RandomSeed; +extern int Skybox; +extern int UseDetail; +extern int UseLadder; +extern int VertexMode; +extern int vid_x, vid_y; +extern int WaveType; +extern int gNumNodes; +extern int gNumTris; +extern int view_x, view_y; +extern int view_cx, view_cy; +extern int UsePatches; +extern int SlantAngle; +extern int GimpHints; +extern int Antialiasing; // ^Fishman - Antializing for the preview window. +extern int AddTerrainKey; // ^Fishman - Add terrain key to func_group. +extern int SnapToGrid; // Hydra : snap to grid +extern int SP; // ^Fishman - Snap to grid. + +/*extern HCURSOR ghCursorCurrent; +extern HCURSOR ghCursorDefault; +extern HCURSOR ghCursorVertex; +extern HINSTANCE ghInst;*/ +extern GtkWidget *g_pRadiantWnd; +extern GtkWidget *g_pWnd; +/*extern HWND ghwndAngles; +extern HWND ghwndFix; +*/extern GtkWidget *g_pWndPreview; +extern GtkWidget *g_pPreviewWidget; +extern MYBITMAP gbmp; +extern NODE *gNode; +extern TRI *gTri; +extern XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; + +extern int Game; +extern bounding_box PlayerBox[NUMGAMES]; +//extern char gszOutputDir[NUMGAMES][NAME_MAX]; +extern char Texture[NUMGAMES][3][64]; +//extern char gszTextureDir[NUMGAMES][NAME_MAX]; +extern char GameName[NUMGAMES][16]; +//extern char pakfile[NUMGAMES][NAME_MAX]; +//extern char lastpakfile[NUMGAMES][NAME_MAX]; +//extern int UsePak[NUMGAMES]; +//extern char GameDir[NUMGAMES][NAME_MAX]; +//extern char ExcelFunc[1024]; + +#endif // _GENSURF_H_ diff --git a/contrib/gtkgensurf/triangle.c b/contrib/gtkgensurf/triangle.c index 1462499f..1e155cac 100644 --- a/contrib/gtkgensurf/triangle.c +++ b/contrib/gtkgensurf/triangle.c @@ -1,13236 +1,13236 @@ -#define ANSI_DECLARATORS -/*****************************************************************************/ -/* */ -/* 888888888 ,o, / 888 */ -/* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */ -/* 888 888 888 88b 888 888 888 888 888 d888 88b */ -/* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */ -/* 888 888 888 C888 888 888 888 / 888 q888 */ -/* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */ -/* "8oo8D */ -/* */ -/* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */ -/* (triangle.c) */ -/* */ -/* Version 1.3 */ -/* July 19, 1996 */ -/* */ -/* Copyright 1996 */ -/* Jonathan Richard Shewchuk */ -/* School of Computer Science */ -/* Carnegie Mellon University */ -/* 5000 Forbes Avenue */ -/* Pittsburgh, Pennsylvania 15213-3891 */ -/* jrs@cs.cmu.edu */ -/* */ -/* This program may be freely redistributed under the condition that the */ -/* copyright notices (including this entire header and the copyright */ -/* notice printed when the `-h' switch is selected) are not removed, and */ -/* no compensation is received. Private, research, and institutional */ -/* use is free. You may distribute modified versions of this code UNDER */ -/* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */ -/* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */ -/* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */ -/* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */ -/* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */ -/* WITH THE AUTHOR. (If you are not directly supplying this code to a */ -/* customer, and you are instead telling them how they can obtain it for */ -/* free, then you are not required to make any arrangement with me.) */ -/* */ -/* Hypertext instructions for Triangle are available on the Web at */ -/* */ -/* http://www.cs.cmu.edu/~quake/triangle.html */ -/* */ -/* Some of the references listed below are marked [*]. These are available */ -/* for downloading from the Web page */ -/* */ -/* http://www.cs.cmu.edu/~quake/triangle.research.html */ -/* */ -/* A paper discussing some aspects of Triangle is available. See Jonathan */ -/* Richard Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator */ -/* and Delaunay Triangulator," First Workshop on Applied Computational */ -/* Geometry, ACM, May 1996. [*] */ -/* */ -/* Triangle was created as part of the Archimedes project in the School of */ -/* Computer Science at Carnegie Mellon University. Archimedes is a */ -/* system for compiling parallel finite element solvers. For further */ -/* information, see Anja Feldmann, Omar Ghattas, John R. Gilbert, Gary L. */ -/* Miller, David R. O'Hallaron, Eric J. Schwabe, Jonathan R. Shewchuk, */ -/* and Shang-Hua Teng, "Automated Parallel Solution of Unstructured PDE */ -/* Problems." To appear in Communications of the ACM, we hope. */ -/* */ -/* The quality mesh generation algorithm is due to Jim Ruppert, "A */ -/* Delaunay Refinement Algorithm for Quality 2-Dimensional Mesh */ -/* Generation," Journal of Algorithms 18(3):548-585, May 1995. [*] */ -/* */ -/* My implementation of the divide-and-conquer and incremental Delaunay */ -/* triangulation algorithms follows closely the presentation of Guibas */ -/* and Stolfi, even though I use a triangle-based data structure instead */ -/* of their quad-edge data structure. (In fact, I originally implemented */ -/* Triangle using the quad-edge data structure, but switching to a */ -/* triangle-based data structure sped Triangle by a factor of two.) The */ -/* mesh manipulation primitives and the two aforementioned Delaunay */ -/* triangulation algorithms are described by Leonidas J. Guibas and Jorge */ -/* Stolfi, "Primitives for the Manipulation of General Subdivisions and */ -/* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */ -/* 4(2):74-123, April 1985. */ -/* */ -/* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */ -/* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */ -/* Delaunay Triangulation," International Journal of Computer and */ -/* Information Science 9(3):219-242, 1980. The idea to improve the */ -/* divide-and-conquer algorithm by alternating between vertical and */ -/* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */ -/* Conquer Algorithm for Constructing Delaunay Triangulations," */ -/* Algorithmica 2(2):137-151, 1987. */ -/* */ -/* The incremental insertion algorithm was first proposed by C. L. Lawson, */ -/* "Software for C1 Surface Interpolation," in Mathematical Software III, */ -/* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */ -/* For point location, I use the algorithm of Ernst P. Mucke, Isaac */ -/* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */ -/* Preprocessing in Two- and Three-dimensional Delaunay Triangulations," */ -/* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */ -/* ACM, May 1996. [*] If I were to randomize the order of point */ -/* insertion (I currently don't bother), their result combined with the */ -/* result of Leonidas J. Guibas, Donald E. Knuth, and Micha Sharir, */ -/* "Randomized Incremental Construction of Delaunay and Voronoi */ -/* Diagrams," Algorithmica 7(4):381-413, 1992, would yield an expected */ -/* O(n^{4/3}) bound on running time. */ -/* */ -/* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */ -/* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */ -/* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */ -/* boundary of the triangulation are maintained in a splay tree for the */ -/* purpose of point location. Splay trees are described by Daniel */ -/* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */ -/* Trees," Journal of the ACM 32(3):652-686, July 1985. */ -/* */ -/* The algorithms for exact computation of the signs of determinants are */ -/* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */ -/* Point Arithmetic and Fast Robust Geometric Predicates," Technical */ -/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ -/* University, Pittsburgh, Pennsylvania, May 1996. [*] (Submitted to */ -/* Discrete & Computational Geometry.) An abbreviated version appears as */ -/* Jonathan Richard Shewchuk, "Robust Adaptive Floating-Point Geometric */ -/* Predicates," Proceedings of the Twelfth Annual Symposium on Computa- */ -/* tional Geometry, ACM, May 1996. [*] Many of the ideas for my exact */ -/* arithmetic routines originate with Douglas M. Priest, "Algorithms for */ -/* Arbitrary Precision Floating Point Arithmetic," Tenth Symposium on */ -/* Computer Arithmetic, 132-143, IEEE Computer Society Press, 1991. [*] */ -/* Many of the ideas for the correct evaluation of the signs of */ -/* determinants are taken from Steven Fortune and Christopher J. Van Wyk, */ -/* "Efficient Exact Arithmetic for Computational Geometry," Proceedings */ -/* of the Ninth Annual Symposium on Computational Geometry, ACM, */ -/* pp. 163-172, May 1993, and from Steven Fortune, "Numerical Stability */ -/* of Algorithms for 2D Delaunay Triangulations," International Journal */ -/* of Computational Geometry & Applications 5(1-2):193-213, March-June */ -/* 1995. */ -/* */ -/* For definitions of and results involving Delaunay triangulations, */ -/* constrained and conforming versions thereof, and other aspects of */ -/* triangular mesh generation, see the excellent survey by Marshall Bern */ -/* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */ -/* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */ -/* editors, World Scientific, Singapore, pp. 23-90, 1992. */ -/* */ -/* The time for incrementally adding PSLG (planar straight line graph) */ -/* segments to create a constrained Delaunay triangulation is probably */ -/* O(n^2) per segment in the worst case and O(n) per edge in the common */ -/* case, where n is the number of triangles that intersect the segment */ -/* before it is inserted. This doesn't count point location, which can */ -/* be much more expensive. (This note does not apply to conforming */ -/* Delaunay triangulations, for which a different method is used to */ -/* insert segments.) */ -/* */ -/* The time for adding segments to a conforming Delaunay triangulation is */ -/* not clear, but does not depend upon n alone. In some cases, very */ -/* small features (like a point lying next to a segment) can cause a */ -/* single segment to be split an arbitrary number of times. Of course, */ -/* floating-point precision is a practical barrier to how much this can */ -/* happen. */ -/* */ -/* The time for deleting a point from a Delaunay triangulation is O(n^2) in */ -/* the worst case and O(n) in the common case, where n is the degree of */ -/* the point being deleted. I could improve this to expected O(n) time */ -/* by "inserting" the neighboring vertices in random order, but n is */ -/* usually quite small, so it's not worth the bother. (The O(n) time */ -/* for random insertion follows from L. Paul Chew, "Building Voronoi */ -/* Diagrams for Convex Polygons in Linear Expected Time," Technical */ -/* Report PCS-TR90-147, Department of Mathematics and Computer Science, */ -/* Dartmouth College, 1990. */ -/* */ -/* Ruppert's Delaunay refinement algorithm typically generates triangles */ -/* at a linear rate (constant time per triangle) after the initial */ -/* triangulation is formed. There may be pathological cases where more */ -/* time is required, but these never arise in practice. */ -/* */ -/* The segment intersection formulae are straightforward. If you want to */ -/* see them derived, see Franklin Antonio. "Faster Line Segment */ -/* Intersection." In Graphics Gems III (David Kirk, editor), pp. 199- */ -/* 202. Academic Press, Boston, 1992. */ -/* */ -/* If you make any improvements to this code, please please please let me */ -/* know, so that I may obtain the improvements. Even if you don't change */ -/* the code, I'd still love to hear what it's being used for. */ -/* */ -/* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */ -/* whatsoever. This code is provided "as-is". Use at your own risk. */ -/* */ -/*****************************************************************************/ - -/* For single precision (which will save some memory and reduce paging), */ -/* define the symbol SINGLE by using the -DSINGLE compiler switch or by */ -/* writing "#define SINGLE" below. */ -/* */ -/* For double precision (which will allow you to refine meshes to a smaller */ -/* edge length), leave SINGLE undefined. */ -/* */ -/* Double precision uses more memory, but improves the resolution of the */ -/* meshes you can generate with Triangle. It also reduces the likelihood */ -/* of a floating exception due to overflow. Finally, it is much faster */ -/* than single precision on 64-bit architectures like the DEC Alpha. I */ -/* recommend double precision unless you want to generate a mesh for which */ -/* you do not have enough memory. */ - -#define SINGLE - -#ifdef SINGLE -#define REAL float -#else /* not SINGLE */ -#define REAL double -#endif /* not SINGLE */ - -/* If yours is not a Unix system, define the NO_TIMER compiler switch to */ -/* remove the Unix-specific timing code. */ - -#define NO_TIMER - -/* To insert lots of self-checks for internal errors, define the SELF_CHECK */ -/* symbol. This will slow down the program significantly. It is best to */ -/* define the symbol using the -DSELF_CHECK compiler switch, but you could */ -/* write "#define SELF_CHECK" below. If you are modifying this code, I */ -/* recommend you turn self-checks on. */ - -/* #define SELF_CHECK */ - -/* To compile Triangle as a callable object library (triangle.o), define the */ -/* TRILIBRARY symbol. Read the file triangle.h for details on how to call */ -/* the procedure triangulate() that results. */ - -#define TRILIBRARY - -/* It is possible to generate a smaller version of Triangle using one or */ -/* both of the following symbols. Define the REDUCED symbol to eliminate */ -/* all features that are primarily of research interest; specifically, the */ -/* -i, -F, -s, and -C switches. Define the CDT_ONLY symbol to eliminate */ -/* all meshing algorithms above and beyond constrained Delaunay */ -/* triangulation; specifically, the -r, -q, -a, -S, and -s switches. */ -/* These reductions are most likely to be useful when generating an object */ -/* library (triangle.o) by defining the TRILIBRARY symbol. */ - -#define REDUCED -#define CDT_ONLY - -/* On some machines, the exact arithmetic routines might be defeated by the */ -/* use of internal extended precision floating-point registers. Sometimes */ -/* this problem can be fixed by defining certain values to be volatile, */ -/* thus forcing them to be stored to memory and rounded off. This isn't */ -/* a great solution, though, as it slows Triangle down. */ -/* */ -/* To try this out, write "#define INEXACT volatile" below. Normally, */ -/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ - -#define INEXACT /* Nothing */ -/* #define INEXACT volatile */ - -/* Maximum number of characters in a file name (including the null). */ - -#define FILENAMESIZE 512 - -/* Maximum number of characters in a line read from a file (including the */ -/* null). */ - -#define INPUTLINESIZE 512 - -/* For efficiency, a variety of data structures are allocated in bulk. The */ -/* following constants determine how many of each structure is allocated */ -/* at once. */ - -#define TRIPERBLOCK 4092 /* Number of triangles allocated at once. */ -#define SHELLEPERBLOCK 508 /* Number of shell edges allocated at once. */ -#define POINTPERBLOCK 4092 /* Number of points allocated at once. */ -#define VIRUSPERBLOCK 1020 /* Number of virus triangles allocated at once. */ -/* Number of encroached segments allocated at once. */ -#define BADSEGMENTPERBLOCK 252 -/* Number of skinny triangles allocated at once. */ -#define BADTRIPERBLOCK 4092 -/* Number of splay tree nodes allocated at once. */ -#define SPLAYNODEPERBLOCK 508 - -/* The point marker DEADPOINT is an arbitrary number chosen large enough to */ -/* (hopefully) not conflict with user boundary markers. Make sure that it */ -/* is small enough to fit into your machine's integer size. */ - -#define DEADPOINT -1073741824 - -/* The next line is used to outsmart some very stupid compilers. If your */ -/* compiler is smarter, feel free to replace the "int" with "void". */ -/* Not that it matters. */ - -#define VOID int - -/* Two constants for algorithms based on random sampling. Both constants */ -/* have been chosen empirically to optimize their respective algorithms. */ - -/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide */ -/* how large a random sample of triangles to inspect. */ -#define SAMPLEFACTOR 11 -/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */ -/* of boundary edges should be maintained in the splay tree for point */ -/* location on the front. */ -#define SAMPLERATE 10 - -/* A number that speaks for itself, every kissable digit. */ - -#define PI 3.141592653589793238462643383279502884197169399375105820974944592308 - -/* Another fave. */ - -#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732 - -/* And here's one for those of you who are intimidated by math. */ - -#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333 - -#include -#include -#include -#ifndef NO_TIMER -#include -#endif /* NO_TIMER */ -#ifdef TRILIBRARY -#include "triangle.h" -#endif /* TRILIBRARY */ - -/* The following obscenity seems to be necessary to ensure that this program */ -/* will port to Dec Alphas running OSF/1, because their stdio.h file commits */ -/* the unpardonable sin of including stdlib.h. Hence, malloc(), free(), and */ -/* exit() may or may not already be defined at this point. I declare these */ -/* functions explicitly because some non-ANSI C compilers lack stdlib.h. */ - -#ifndef _STDLIB_H_ -extern void *malloc(); -extern void free(); -extern void exit(); -extern double strtod(); -extern long strtol(); -#endif /* _STDLIB_H_ */ - -/* A few forward declarations. */ - -void poolrestart(); -#ifndef TRILIBRARY -char *readline(); -char *findfield(); -#endif /* not TRILIBRARY */ - -/* Labels that signify whether a record consists primarily of pointers or of */ -/* floating-point words. Used to make decisions about data alignment. */ - -enum wordtype {POINTER, FLOATINGPOINT}; - -/* Labels that signify the result of point location. The result of a */ -/* search indicates that the point falls in the interior of a triangle, on */ -/* an edge, on a vertex, or outside the mesh. */ - -enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE}; - -/* Labels that signify the result of site insertion. The result indicates */ -/* that the point was inserted with complete success, was inserted but */ -/* encroaches on a segment, was not inserted because it lies on a segment, */ -/* or was not inserted because another point occupies the same location. */ - -enum insertsiteresult {SUCCESSFULPOINT, ENCROACHINGPOINT, VIOLATINGPOINT, - DUPLICATEPOINT}; - -/* Labels that signify the result of direction finding. The result */ -/* indicates that a segment connecting the two query points falls within */ -/* the direction triangle, along the left edge of the direction triangle, */ -/* or along the right edge of the direction triangle. */ - -enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR}; - -/* Labels that signify the result of the circumcenter computation routine. */ -/* The return value indicates which edge of the triangle is shortest. */ - -enum circumcenterresult {OPPOSITEORG, OPPOSITEDEST, OPPOSITEAPEX}; - -/*****************************************************************************/ -/* */ -/* The basic mesh data structures */ -/* */ -/* There are three: points, triangles, and shell edges (abbreviated */ -/* `shelle'). These three data structures, linked by pointers, comprise */ -/* the mesh. A point simply represents a point in space and its properties.*/ -/* A triangle is a triangle. A shell edge is a special data structure used */ -/* to represent impenetrable segments in the mesh (including the outer */ -/* boundary, boundaries of holes, and internal boundaries separating two */ -/* triangulated regions). Shell edges represent boundaries defined by the */ -/* user that triangles may not lie across. */ -/* */ -/* A triangle consists of a list of three vertices, a list of three */ -/* adjoining triangles, a list of three adjoining shell edges (when shell */ -/* edges are used), an arbitrary number of optional user-defined floating- */ -/* point attributes, and an optional area constraint. The latter is an */ -/* upper bound on the permissible area of each triangle in a region, used */ -/* for mesh refinement. */ -/* */ -/* For a triangle on a boundary of the mesh, some or all of the neighboring */ -/* triangles may not be present. For a triangle in the interior of the */ -/* mesh, often no neighboring shell edges are present. Such absent */ -/* triangles and shell edges are never represented by NULL pointers; they */ -/* are represented by two special records: `dummytri', the triangle that */ -/* fills "outer space", and `dummysh', the omnipresent shell edge. */ -/* `dummytri' and `dummysh' are used for several reasons; for instance, */ -/* they can be dereferenced and their contents examined without causing the */ -/* memory protection exception that would occur if NULL were dereferenced. */ -/* */ -/* However, it is important to understand that a triangle includes other */ -/* information as well. The pointers to adjoining vertices, triangles, and */ -/* shell edges are ordered in a way that indicates their geometric relation */ -/* to each other. Furthermore, each of these pointers contains orientation */ -/* information. Each pointer to an adjoining triangle indicates which face */ -/* of that triangle is contacted. Similarly, each pointer to an adjoining */ -/* shell edge indicates which side of that shell edge is contacted, and how */ -/* the shell edge is oriented relative to the triangle. */ -/* */ -/* Shell edges are found abutting edges of triangles; either sandwiched */ -/* between two triangles, or resting against one triangle on an exterior */ -/* boundary or hole boundary. */ -/* */ -/* A shell edge consists of a list of two vertices, a list of two */ -/* adjoining shell edges, and a list of two adjoining triangles. One of */ -/* the two adjoining triangles may not be present (though there should */ -/* always be one), and neighboring shell edges might not be present. */ -/* Shell edges also store a user-defined integer "boundary marker". */ -/* Typically, this integer is used to indicate what sort of boundary */ -/* conditions are to be applied at that location in a finite element */ -/* simulation. */ -/* */ -/* Like triangles, shell edges maintain information about the relative */ -/* orientation of neighboring objects. */ -/* */ -/* Points are relatively simple. A point is a list of floating point */ -/* numbers, starting with the x, and y coordinates, followed by an */ -/* arbitrary number of optional user-defined floating-point attributes, */ -/* followed by an integer boundary marker. During the segment insertion */ -/* phase, there is also a pointer from each point to a triangle that may */ -/* contain it. Each pointer is not always correct, but when one is, it */ -/* speeds up segment insertion. These pointers are assigned values once */ -/* at the beginning of the segment insertion phase, and are not used or */ -/* updated at any other time. Edge swapping during segment insertion will */ -/* render some of them incorrect. Hence, don't rely upon them for */ -/* anything. For the most part, points do not have any information about */ -/* what triangles or shell edges they are linked to. */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* */ -/* Handles */ -/* */ -/* The oriented triangle (`triedge') and oriented shell edge (`edge') data */ -/* structures defined below do not themselves store any part of the mesh. */ -/* The mesh itself is made of `triangle's, `shelle's, and `point's. */ -/* */ -/* Oriented triangles and oriented shell edges will usually be referred to */ -/* as "handles". A handle is essentially a pointer into the mesh; it */ -/* allows you to "hold" one particular part of the mesh. Handles are used */ -/* to specify the regions in which one is traversing and modifying the mesh.*/ -/* A single `triangle' may be held by many handles, or none at all. (The */ -/* latter case is not a memory leak, because the triangle is still */ -/* connected to other triangles in the mesh.) */ -/* */ -/* A `triedge' is a handle that holds a triangle. It holds a specific side */ -/* of the triangle. An `edge' is a handle that holds a shell edge. It */ -/* holds either the left or right side of the edge. */ -/* */ -/* Navigation about the mesh is accomplished through a set of mesh */ -/* manipulation primitives, further below. Many of these primitives take */ -/* a handle and produce a new handle that holds the mesh near the first */ -/* handle. Other primitives take two handles and glue the corresponding */ -/* parts of the mesh together. The exact position of the handles is */ -/* important. For instance, when two triangles are glued together by the */ -/* bond() primitive, they are glued by the sides on which the handles lie. */ -/* */ -/* Because points have no information about which triangles they are */ -/* attached to, I commonly represent a point by use of a handle whose */ -/* origin is the point. A single handle can simultaneously represent a */ -/* triangle, an edge, and a point. */ -/* */ -/*****************************************************************************/ - -/* The triangle data structure. Each triangle contains three pointers to */ -/* adjoining triangles, plus three pointers to vertex points, plus three */ -/* pointers to shell edges (defined below; these pointers are usually */ -/* `dummysh'). It may or may not also contain user-defined attributes */ -/* and/or a floating-point "area constraint". It may also contain extra */ -/* pointers for nodes, when the user asks for high-order elements. */ -/* Because the size and structure of a `triangle' is not decided until */ -/* runtime, I haven't simply defined the type `triangle' to be a struct. */ - -typedef REAL **triangle; /* Really: typedef triangle *triangle */ - -/* An oriented triangle: includes a pointer to a triangle and orientation. */ -/* The orientation denotes an edge of the triangle. Hence, there are */ -/* three possible orientations. By convention, each edge is always */ -/* directed to point counterclockwise about the corresponding triangle. */ - -struct triedge { - triangle *tri; - int orient; /* Ranges from 0 to 2. */ -}; - -/* The shell data structure. Each shell edge contains two pointers to */ -/* adjoining shell edges, plus two pointers to vertex points, plus two */ -/* pointers to adjoining triangles, plus one shell marker. */ - -typedef REAL **shelle; /* Really: typedef shelle *shelle */ - -/* An oriented shell edge: includes a pointer to a shell edge and an */ -/* orientation. The orientation denotes a side of the edge. Hence, there */ -/* are two possible orientations. By convention, the edge is always */ -/* directed so that the "side" denoted is the right side of the edge. */ - -struct edge { - shelle *sh; - int shorient; /* Ranges from 0 to 1. */ -}; - -/* The point data structure. Each point is actually an array of REALs. */ -/* The number of REALs is unknown until runtime. An integer boundary */ -/* marker, and sometimes a pointer to a triangle, is appended after the */ -/* REALs. */ - -typedef REAL *point; - -/* A queue used to store encroached segments. Each segment's vertices are */ -/* stored so that one can check whether a segment is still the same. */ - -struct badsegment { - struct edge encsegment; /* An encroached segment. */ - point segorg, segdest; /* The two vertices. */ - struct badsegment *nextsegment; /* Pointer to next encroached segment. */ -}; - -/* A queue used to store bad triangles. The key is the square of the cosine */ -/* of the smallest angle of the triangle. Each triangle's vertices are */ -/* stored so that one can check whether a triangle is still the same. */ - -struct badface { - struct triedge badfacetri; /* A bad triangle. */ - REAL key; /* cos^2 of smallest (apical) angle. */ - point faceorg, facedest, faceapex; /* The three vertices. */ - struct badface *nextface; /* Pointer to next bad triangle. */ -}; - -/* A node in a heap used to store events for the sweepline Delaunay */ -/* algorithm. Nodes do not point directly to their parents or children in */ -/* the heap. Instead, each node knows its position in the heap, and can */ -/* look up its parent and children in a separate array. The `eventptr' */ -/* points either to a `point' or to a triangle (in encoded format, so that */ -/* an orientation is included). In the latter case, the origin of the */ -/* oriented triangle is the apex of a "circle event" of the sweepline */ -/* algorithm. To distinguish site events from circle events, all circle */ -/* events are given an invalid (smaller than `xmin') x-coordinate `xkey'. */ - -struct event { - REAL xkey, ykey; /* Coordinates of the event. */ - VOID *eventptr; /* Can be a point or the location of a circle event. */ - int heapposition; /* Marks this event's position in the heap. */ -}; - -/* A node in the splay tree. Each node holds an oriented ghost triangle */ -/* that represents a boundary edge of the growing triangulation. When a */ -/* circle event covers two boundary edges with a triangle, so that they */ -/* are no longer boundary edges, those edges are not immediately deleted */ -/* from the tree; rather, they are lazily deleted when they are next */ -/* encountered. (Since only a random sample of boundary edges are kept */ -/* in the tree, lazy deletion is faster.) `keydest' is used to verify */ -/* that a triangle is still the same as when it entered the splay tree; if */ -/* it has been rotated (due to a circle event), it no longer represents a */ -/* boundary edge and should be deleted. */ - -struct splaynode { - struct triedge keyedge; /* Lprev of an edge on the front. */ - point keydest; /* Used to verify that splay node is still live. */ - struct splaynode *lchild, *rchild; /* Children in splay tree. */ -}; - -/* A type used to allocate memory. firstblock is the first block of items. */ -/* nowblock is the block from which items are currently being allocated. */ -/* nextitem points to the next slab of free memory for an item. */ -/* deaditemstack is the head of a linked list (stack) of deallocated items */ -/* that can be recycled. unallocateditems is the number of items that */ -/* remain to be allocated from nowblock. */ -/* */ -/* Traversal is the process of walking through the entire list of items, and */ -/* is separate from allocation. Note that a traversal will visit items on */ -/* the "deaditemstack" stack as well as live items. pathblock points to */ -/* the block currently being traversed. pathitem points to the next item */ -/* to be traversed. pathitemsleft is the number of items that remain to */ -/* be traversed in pathblock. */ -/* */ -/* itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest */ -/* what sort of word the record is primarily made up of. alignbytes */ -/* determines how new records should be aligned in memory. itembytes and */ -/* itemwords are the length of a record in bytes (after rounding up) and */ -/* words. itemsperblock is the number of items allocated at once in a */ -/* single block. items is the number of currently allocated items. */ -/* maxitems is the maximum number of items that have been allocated at */ -/* once; it is the current number of items plus the number of records kept */ -/* on deaditemstack. */ - -struct memorypool { - VOID **firstblock, **nowblock; - VOID *nextitem; - VOID *deaditemstack; - VOID **pathblock; - VOID *pathitem; - enum wordtype itemwordtype; - int alignbytes; - int itembytes, itemwords; - int itemsperblock; - long items, maxitems; - int unallocateditems; - int pathitemsleft; -}; - -/* Variables used to allocate memory for triangles, shell edges, points, */ -/* viri (triangles being eaten), bad (encroached) segments, bad (skinny */ -/* or too large) triangles, and splay tree nodes. */ - -static struct memorypool triangles; -static struct memorypool shelles; -static struct memorypool points; -static struct memorypool viri; -static struct memorypool badsegments; -static struct memorypool badtriangles; -static struct memorypool splaynodes; - -/* Variables that maintain the bad triangle queues. The tails are pointers */ -/* to the pointers that have to be filled in to enqueue an item. */ - -static struct badface *queuefront[64]; -static struct badface **queuetail[64]; - -static REAL xmin, xmax, ymin, ymax; /* x and y bounds. */ -static REAL xminextreme; /* Nonexistent x value used as a flag in sweepline. */ -static int inpoints; /* Number of input points. */ -static int inelements; /* Number of input triangles. */ -static int insegments; /* Number of input segments. */ -static int holes; /* Number of input holes. */ -static int regions; /* Number of input regions. */ -static long edges; /* Number of output edges. */ -static int mesh_dim; /* Dimension (ought to be 2). */ -static int nextras; /* Number of attributes per point. */ -static int eextras; /* Number of attributes per triangle. */ -static long hullsize; /* Number of edges of convex hull. */ -static int triwords; /* Total words per triangle. */ -static int shwords; /* Total words per shell edge. */ -static int pointmarkindex; /* Index to find boundary marker of a point. */ -static int point2triindex; /* Index to find a triangle adjacent to a point. */ -static int highorderindex; /* Index to find extra nodes for high-order elements. */ -static int elemattribindex; /* Index to find attributes of a triangle. */ -static int areaboundindex; /* Index to find area bound of a triangle. */ -static int checksegments; /* Are there segments in the triangulation yet? */ -static int readnodefile; /* Has a .node file been read? */ -static long samples; /* Number of random samples for point location. */ -static unsigned long randomseed; /* Current random number seed. */ - -static REAL splitter; /* Used to split REAL factors for exact multiplication. */ -static REAL epsilon; /* Floating-point machine epsilon. */ -static REAL resulterrbound; -static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; -static REAL iccerrboundA, iccerrboundB, iccerrboundC; - -static long incirclecount; /* Number of incircle tests performed. */ -static long counterclockcount; /* Number of counterclockwise tests performed. */ -static long hyperbolacount; /* Number of right-of-hyperbola tests performed. */ -static long circumcentercount; /* Number of circumcenter calculations performed. */ -static long circletopcount; /* Number of circle top calculations performed. */ - -/* Switches for the triangulator. */ -/* poly: -p switch. refine: -r switch. */ -/* quality: -q switch. */ -/* minangle: minimum angle bound, specified after -q switch. */ -/* goodangle: cosine squared of minangle. */ -/* vararea: -a switch without number. */ -/* fixedarea: -a switch with number. */ -/* maxarea: maximum area bound, specified after -a switch. */ -/* regionattrib: -A switch. convex: -c switch. */ -/* firstnumber: inverse of -z switch. All items are numbered starting */ -/* from firstnumber. */ -/* edgesout: -e switch. voronoi: -v switch. */ -/* neighbors: -n switch. geomview: -g switch. */ -/* nobound: -B switch. nopolywritten: -P switch. */ -/* nonodewritten: -N switch. noelewritten: -E switch. */ -/* noiterationnum: -I switch. noholes: -O switch. */ -/* noexact: -X switch. */ -/* order: element order, specified after -o switch. */ -/* nobisect: count of how often -Y switch is selected. */ -/* steiner: maximum number of Steiner points, specified after -S switch. */ -/* steinerleft: number of Steiner points not yet used. */ -/* incremental: -i switch. sweepline: -F switch. */ -/* dwyer: inverse of -l switch. */ -/* splitseg: -s switch. */ -/* docheck: -C switch. */ -/* quiet: -Q switch. verbose: count of how often -V switch is selected. */ -/* useshelles: -p, -r, -q, or -c switch; determines whether shell edges */ -/* are used at all. */ -/* */ -/* Read the instructions to find out the meaning of these switches. */ - -static int poly, refine, quality, vararea, fixedarea, regionattrib, convex; -static int firstnumber; -static int edgesout, voronoi, neighbors, geomview; -static int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum; -static int noholes, noexact; -static int incremental, sweepline, dwyer; -static int splitseg; -static int docheck; -static int quiet, verbose; -static int useshelles; -static int order; -static int nobisect; -static int steiner, steinerleft; -static REAL minangle, goodangle; -static REAL maxarea; - -/* Variables for file names. */ - -#ifndef TRILIBRARY -char innodefilename[FILENAMESIZE]; -char inelefilename[FILENAMESIZE]; -char inpolyfilename[FILENAMESIZE]; -char areafilename[FILENAMESIZE]; -char outnodefilename[FILENAMESIZE]; -char outelefilename[FILENAMESIZE]; -char outpolyfilename[FILENAMESIZE]; -char edgefilename[FILENAMESIZE]; -char vnodefilename[FILENAMESIZE]; -char vedgefilename[FILENAMESIZE]; -char neighborfilename[FILENAMESIZE]; -char offfilename[FILENAMESIZE]; -#endif /* not TRILIBRARY */ - -/* Triangular bounding box points. */ - -static point infpoint1, infpoint2, infpoint3; - -/* Pointer to the `triangle' that occupies all of "outer space". */ - -static triangle *dummytri; -static triangle *dummytribase; /* Keep base address so we can free() it later. */ - -/* Pointer to the omnipresent shell edge. Referenced by any triangle or */ -/* shell edge that isn't really connected to a shell edge at that */ -/* location. */ - -static shelle *dummysh; -static shelle *dummyshbase; /* Keep base address so we can free() it later. */ - -/* Pointer to a recently visited triangle. Improves point location if */ -/* proximate points are inserted sequentially. */ - -static struct triedge recenttri; - -/*****************************************************************************/ -/* */ -/* Mesh manipulation primitives. Each triangle contains three pointers to */ -/* other triangles, with orientations. Each pointer points not to the */ -/* first byte of a triangle, but to one of the first three bytes of a */ -/* triangle. It is necessary to extract both the triangle itself and the */ -/* orientation. To save memory, I keep both pieces of information in one */ -/* pointer. To make this possible, I assume that all triangles are aligned */ -/* to four-byte boundaries. The `decode' routine below decodes a pointer, */ -/* extracting an orientation (in the range 0 to 2) and a pointer to the */ -/* beginning of a triangle. The `encode' routine compresses a pointer to a */ -/* triangle and an orientation into a single pointer. My assumptions that */ -/* triangles are four-byte-aligned and that the `unsigned long' type is */ -/* long enough to hold a pointer are two of the few kludges in this program.*/ -/* */ -/* Shell edges are manipulated similarly. A pointer to a shell edge */ -/* carries both an address and an orientation in the range 0 to 1. */ -/* */ -/* The other primitives take an oriented triangle or oriented shell edge, */ -/* and return an oriented triangle or oriented shell edge or point; or they */ -/* change the connections in the data structure. */ -/* */ -/*****************************************************************************/ - -/********* Mesh manipulation primitives begin here *********/ -/** **/ -/** **/ - -/* Fast lookup arrays to speed some of the mesh manipulation primitives. */ - -int plus1mod3[3] = {1, 2, 0}; -int minus1mod3[3] = {2, 0, 1}; - -/********* Primitives for triangles *********/ -/* */ -/* */ - -/* decode() converts a pointer to an oriented triangle. The orientation is */ -/* extracted from the two least significant bits of the pointer. */ - -#define decode(ptr, triedge) \ - (triedge).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l); \ - (triedge).tri = (triangle *) \ - ((unsigned long) (ptr) ^ (unsigned long) (triedge).orient) - -/* encode() compresses an oriented triangle into a single pointer. It */ -/* relies on the assumption that all triangles are aligned to four-byte */ -/* boundaries, so the two least significant bits of (triedge).tri are zero.*/ - -#define encode(triedge) \ - (triangle) ((unsigned long) (triedge).tri | (unsigned long) (triedge).orient) - -/* The following edge manipulation primitives are all described by Guibas */ -/* and Stolfi. However, they use an edge-based data structure, whereas I */ -/* am using a triangle-based data structure. */ - -/* sym() finds the abutting triangle, on the same edge. Note that the */ -/* edge direction is necessarily reversed, because triangle/edge handles */ -/* are always directed counterclockwise around the triangle. */ - -#define sym(triedge1, triedge2) \ - ptr = (triedge1).tri[(triedge1).orient]; \ - decode(ptr, triedge2); - -#define symself(triedge) \ - ptr = (triedge).tri[(triedge).orient]; \ - decode(ptr, triedge); - -/* lnext() finds the next edge (counterclockwise) of a triangle. */ - -#define lnext(triedge1, triedge2) \ - (triedge2).tri = (triedge1).tri; \ - (triedge2).orient = plus1mod3[(triedge1).orient] - -#define lnextself(triedge) \ - (triedge).orient = plus1mod3[(triedge).orient] - -/* lprev() finds the previous edge (clockwise) of a triangle. */ - -#define lprev(triedge1, triedge2) \ - (triedge2).tri = (triedge1).tri; \ - (triedge2).orient = minus1mod3[(triedge1).orient] - -#define lprevself(triedge) \ - (triedge).orient = minus1mod3[(triedge).orient] - -/* onext() spins counterclockwise around a point; that is, it finds the next */ -/* edge with the same origin in the counterclockwise direction. This edge */ -/* will be part of a different triangle. */ - -#define onext(triedge1, triedge2) \ - lprev(triedge1, triedge2); \ - symself(triedge2); - -#define onextself(triedge) \ - lprevself(triedge); \ - symself(triedge); - -/* oprev() spins clockwise around a point; that is, it finds the next edge */ -/* with the same origin in the clockwise direction. This edge will be */ -/* part of a different triangle. */ - -#define oprev(triedge1, triedge2) \ - sym(triedge1, triedge2); \ - lnextself(triedge2); - -#define oprevself(triedge) \ - symself(triedge); \ - lnextself(triedge); - -/* dnext() spins counterclockwise around a point; that is, it finds the next */ -/* edge with the same destination in the counterclockwise direction. This */ -/* edge will be part of a different triangle. */ - -#define dnext(triedge1, triedge2) \ - sym(triedge1, triedge2); \ - lprevself(triedge2); - -#define dnextself(triedge) \ - symself(triedge); \ - lprevself(triedge); - -/* dprev() spins clockwise around a point; that is, it finds the next edge */ -/* with the same destination in the clockwise direction. This edge will */ -/* be part of a different triangle. */ - -#define dprev(triedge1, triedge2) \ - lnext(triedge1, triedge2); \ - symself(triedge2); - -#define dprevself(triedge) \ - lnextself(triedge); \ - symself(triedge); - -/* rnext() moves one edge counterclockwise about the adjacent triangle. */ -/* (It's best understood by reading Guibas and Stolfi. It involves */ -/* changing triangles twice.) */ - -#define rnext(triedge1, triedge2) \ - sym(triedge1, triedge2); \ - lnextself(triedge2); \ - symself(triedge2); - -#define rnextself(triedge) \ - symself(triedge); \ - lnextself(triedge); \ - symself(triedge); - -/* rnext() moves one edge clockwise about the adjacent triangle. */ -/* (It's best understood by reading Guibas and Stolfi. It involves */ -/* changing triangles twice.) */ - -#define rprev(triedge1, triedge2) \ - sym(triedge1, triedge2); \ - lprevself(triedge2); \ - symself(triedge2); - -#define rprevself(triedge) \ - symself(triedge); \ - lprevself(triedge); \ - symself(triedge); - -/* These primitives determine or set the origin, destination, or apex of a */ -/* triangle. */ - -#define org(triedge, pointptr) \ - pointptr = (point) (triedge).tri[plus1mod3[(triedge).orient] + 3] - -#define dest(triedge, pointptr) \ - pointptr = (point) (triedge).tri[minus1mod3[(triedge).orient] + 3] - -#define apex(triedge, pointptr) \ - pointptr = (point) (triedge).tri[(triedge).orient + 3] - -#define setorg(triedge, pointptr) \ - (triedge).tri[plus1mod3[(triedge).orient] + 3] = (triangle) pointptr - -#define setdest(triedge, pointptr) \ - (triedge).tri[minus1mod3[(triedge).orient] + 3] = (triangle) pointptr - -#define setapex(triedge, pointptr) \ - (triedge).tri[(triedge).orient + 3] = (triangle) pointptr - -#define setvertices2null(triedge) \ - (triedge).tri[3] = (triangle) NULL; \ - (triedge).tri[4] = (triangle) NULL; \ - (triedge).tri[5] = (triangle) NULL; - -/* Bond two triangles together. */ - -#define bond(triedge1, triedge2) \ - (triedge1).tri[(triedge1).orient] = encode(triedge2); \ - (triedge2).tri[(triedge2).orient] = encode(triedge1) - -/* Dissolve a bond (from one side). Note that the other triangle will still */ -/* think it's connected to this triangle. Usually, however, the other */ -/* triangle is being deleted entirely, or bonded to another triangle, so */ -/* it doesn't matter. */ - -#define dissolve(triedge) \ - (triedge).tri[(triedge).orient] = (triangle) dummytri - -/* Copy a triangle/edge handle. */ - -#define triedgecopy(triedge1, triedge2) \ - (triedge2).tri = (triedge1).tri; \ - (triedge2).orient = (triedge1).orient - -/* Test for equality of triangle/edge handles. */ - -#define triedgeequal(triedge1, triedge2) \ - (((triedge1).tri == (triedge2).tri) && \ - ((triedge1).orient == (triedge2).orient)) - -/* Primitives to infect or cure a triangle with the virus. These rely on */ -/* the assumption that all shell edges are aligned to four-byte boundaries.*/ - -#define infect(triedge) \ - (triedge).tri[6] = (triangle) \ - ((unsigned long) (triedge).tri[6] | (unsigned long) 2l) - -#define uninfect(triedge) \ - (triedge).tri[6] = (triangle) \ - ((unsigned long) (triedge).tri[6] & ~ (unsigned long) 2l) - -/* Test a triangle for viral infection. */ - -#define infected(triedge) \ - (((unsigned long) (triedge).tri[6] & (unsigned long) 2l) != 0) - -/* Check or set a triangle's attributes. */ - -#define elemattribute(triedge, attnum) \ - ((REAL *) (triedge).tri)[elemattribindex + (attnum)] - -#define setelemattribute(triedge, attnum, value) \ - ((REAL *) (triedge).tri)[elemattribindex + (attnum)] = (REAL)value - -/* Check or set a triangle's maximum area bound. */ - -#define areabound(triedge) ((REAL *) (triedge).tri)[areaboundindex] - -#define setareabound(triedge, value) \ - ((REAL *) (triedge).tri)[areaboundindex] = (REAL)value - -/********* Primitives for shell edges *********/ -/* */ -/* */ - -/* sdecode() converts a pointer to an oriented shell edge. The orientation */ -/* is extracted from the least significant bit of the pointer. The two */ -/* least significant bits (one for orientation, one for viral infection) */ -/* are masked out to produce the real pointer. */ - -#define sdecode(sptr, edge) \ - (edge).shorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l); \ - (edge).sh = (shelle *) \ - ((unsigned long) (sptr) & ~ (unsigned long) 3l) - -/* sencode() compresses an oriented shell edge into a single pointer. It */ -/* relies on the assumption that all shell edges are aligned to two-byte */ -/* boundaries, so the least significant bit of (edge).sh is zero. */ - -#define sencode(edge) \ - (shelle) ((unsigned long) (edge).sh | (unsigned long) (edge).shorient) - -/* ssym() toggles the orientation of a shell edge. */ - -#define ssym(edge1, edge2) \ - (edge2).sh = (edge1).sh; \ - (edge2).shorient = 1 - (edge1).shorient - -#define ssymself(edge) \ - (edge).shorient = 1 - (edge).shorient - -/* spivot() finds the other shell edge (from the same segment) that shares */ -/* the same origin. */ - -#define spivot(edge1, edge2) \ - sptr = (edge1).sh[(edge1).shorient]; \ - sdecode(sptr, edge2) - -#define spivotself(edge) \ - sptr = (edge).sh[(edge).shorient]; \ - sdecode(sptr, edge) - -/* snext() finds the next shell edge (from the same segment) in sequence; */ -/* one whose origin is the input shell edge's destination. */ - -#define snext(edge1, edge2) \ - sptr = (edge1).sh[1 - (edge1).shorient]; \ - sdecode(sptr, edge2) - -#define snextself(edge) \ - sptr = (edge).sh[1 - (edge).shorient]; \ - sdecode(sptr, edge) - -/* These primitives determine or set the origin or destination of a shell */ -/* edge. */ - -#define sorg(edge, pointptr) \ - pointptr = (point) (edge).sh[2 + (edge).shorient] - -#define sdest(edge, pointptr) \ - pointptr = (point) (edge).sh[3 - (edge).shorient] - -#define setsorg(edge, pointptr) \ - (edge).sh[2 + (edge).shorient] = (shelle) pointptr - -#define setsdest(edge, pointptr) \ - (edge).sh[3 - (edge).shorient] = (shelle) pointptr - -/* These primitives read or set a shell marker. Shell markers are used to */ -/* hold user boundary information. */ - -#define mark(edge) (* (int *) ((edge).sh + 6)) - -#define setmark(edge, value) \ - * (int *) ((edge).sh + 6) = value - -/* Bond two shell edges together. */ - -#define sbond(edge1, edge2) \ - (edge1).sh[(edge1).shorient] = sencode(edge2); \ - (edge2).sh[(edge2).shorient] = sencode(edge1) - -/* Dissolve a shell edge bond (from one side). Note that the other shell */ -/* edge will still think it's connected to this shell edge. */ - -#define sdissolve(edge) \ - (edge).sh[(edge).shorient] = (shelle) dummysh - -/* Copy a shell edge. */ - -#define shellecopy(edge1, edge2) \ - (edge2).sh = (edge1).sh; \ - (edge2).shorient = (edge1).shorient - -/* Test for equality of shell edges. */ - -#define shelleequal(edge1, edge2) \ - (((edge1).sh == (edge2).sh) && \ - ((edge1).shorient == (edge2).shorient)) - -/********* Primitives for interacting triangles and shell edges *********/ -/* */ -/* */ - -/* tspivot() finds a shell edge abutting a triangle. */ - -#define tspivot(triedge, edge) \ - sptr = (shelle) (triedge).tri[6 + (triedge).orient]; \ - sdecode(sptr, edge) - -/* stpivot() finds a triangle abutting a shell edge. It requires that the */ -/* variable `ptr' of type `triangle' be defined. */ - -#define stpivot(edge, triedge) \ - ptr = (triangle) (edge).sh[4 + (edge).shorient]; \ - decode(ptr, triedge) - -/* Bond a triangle to a shell edge. */ - -#define tsbond(triedge, edge) \ - (triedge).tri[6 + (triedge).orient] = (triangle) sencode(edge); \ - (edge).sh[4 + (edge).shorient] = (shelle) encode(triedge) - -/* Dissolve a bond (from the triangle side). */ - -#define tsdissolve(triedge) \ - (triedge).tri[6 + (triedge).orient] = (triangle) dummysh - -/* Dissolve a bond (from the shell edge side). */ - -#define stdissolve(edge) \ - (edge).sh[4 + (edge).shorient] = (shelle) dummytri - -/********* Primitives for points *********/ -/* */ -/* */ - -#define pointmark(pt) ((int *) (pt))[pointmarkindex] - -#define setpointmark(pt, value) \ - ((int *) (pt))[pointmarkindex] = value - -#define point2tri(pt) ((triangle *) (pt))[point2triindex] - -#define setpoint2tri(pt, value) \ - ((triangle *) (pt))[point2triindex] = value - -/** **/ -/** **/ -/********* Mesh manipulation primitives end here *********/ - -/********* User interaction routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* syntax() Print list of command line switches. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -void syntax() -{ -#ifdef CDT_ONLY -#ifdef REDUCED - printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n"); -#else /* not REDUCED */ - printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n"); -#endif /* not REDUCED */ -#else /* not CDT_ONLY */ -#ifdef REDUCED - printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n"); -#else /* not REDUCED */ - printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n"); -#endif /* not REDUCED */ -#endif /* not CDT_ONLY */ - - printf(" -p Triangulates a Planar Straight Line Graph (.poly file).\n"); -#ifndef CDT_ONLY - printf(" -r Refines a previously generated mesh.\n"); - printf( - " -q Quality mesh generation. A minimum angle may be specified.\n"); - printf(" -a Applies a maximum triangle area constraint.\n"); -#endif /* not CDT_ONLY */ - printf( - " -A Applies attributes to identify elements in certain regions.\n"); - printf(" -c Encloses the convex hull with segments.\n"); - printf(" -e Generates an edge list.\n"); - printf(" -v Generates a Voronoi diagram.\n"); - printf(" -n Generates a list of triangle neighbors.\n"); - printf(" -g Generates an .off file for Geomview.\n"); - printf(" -B Suppresses output of boundary information.\n"); - printf(" -P Suppresses output of .poly file.\n"); - printf(" -N Suppresses output of .node file.\n"); - printf(" -E Suppresses output of .ele file.\n"); - printf(" -I Suppresses mesh iteration numbers.\n"); - printf(" -O Ignores holes in .poly file.\n"); - printf(" -X Suppresses use of exact arithmetic.\n"); - printf(" -z Numbers all items starting from zero (rather than one).\n"); - printf(" -o2 Generates second-order subparametric elements.\n"); -#ifndef CDT_ONLY - printf(" -Y Suppresses boundary segment splitting.\n"); - printf(" -S Specifies maximum number of added Steiner points.\n"); -#endif /* not CDT_ONLY */ -#ifndef REDUCED - printf(" -i Uses incremental method, rather than divide-and-conquer.\n"); - printf(" -F Uses Fortune's sweepline algorithm, rather than d-and-c.\n"); -#endif /* not REDUCED */ - printf(" -l Uses vertical cuts only, rather than alternating cuts.\n"); -#ifndef REDUCED -#ifndef CDT_ONLY - printf( - " -s Force segments into mesh by splitting (instead of using CDT).\n"); -#endif /* not CDT_ONLY */ - printf(" -C Check consistency of final mesh.\n"); -#endif /* not REDUCED */ - printf(" -Q Quiet: No terminal output except errors.\n"); - printf(" -V Verbose: Detailed information on what I'm doing.\n"); - printf(" -h Help: Detailed instructions for Triangle.\n"); - exit(0); -} - -#endif /* not TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* info() Print out complete instructions. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -void info() -{ - printf("Triangle\n"); - printf( -"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n"); - printf("Version 1.3\n\n"); - printf( -"Copyright 1996 Jonathan Richard Shewchuk (bugs/comments to jrs@cs.cmu.edu)\n" -); - printf("School of Computer Science / Carnegie Mellon University\n"); - printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania 15213-3891\n"); - printf( -"Created as part of the Archimedes project (tools for parallel FEM).\n"); - printf( -"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n"); - printf("There is no warranty whatsoever. Use at your own risk.\n"); -#ifdef SINGLE - printf("This executable is compiled for single precision arithmetic.\n\n\n"); -#else /* not SINGLE */ - printf("This executable is compiled for double precision arithmetic.\n\n\n"); -#endif /* not SINGLE */ - printf( -"Triangle generates exact Delaunay triangulations, constrained Delaunay\n"); - printf( -"triangulations, and quality conforming Delaunay triangulations. The latter\n" -); - printf( -"can be generated with no small angles, and are thus suitable for finite\n"); - printf( -"element analysis. If no command line switches are specified, your .node\n"); - printf( -"input file will be read, and the Delaunay triangulation will be returned in\n" -); - printf(".node and .ele output files. The command syntax is:\n\n"); -#ifdef CDT_ONLY -#ifdef REDUCED - printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n\n"); -#else /* not REDUCED */ - printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n\n"); -#endif /* not REDUCED */ -#else /* not CDT_ONLY */ -#ifdef REDUCED - printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n\n"); -#else /* not REDUCED */ - printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n\n"); -#endif /* not REDUCED */ -#endif /* not CDT_ONLY */ - printf( -"Underscores indicate that numbers may optionally follow certain switches;\n"); - printf( -"do not leave any space between a switch and its numeric parameter.\n"); - printf( -"input_file must be a file with extension .node, or extension .poly if the\n"); - printf( -"-p switch is used. If -r is used, you must supply .node and .ele files,\n"); - printf( -"and possibly a .poly file and .area file as well. The formats of these\n"); - printf("files are described below.\n\n"); - printf("Command Line Switches:\n\n"); - printf( -" -p Reads a Planar Straight Line Graph (.poly file), which can specify\n" -); - printf( -" points, segments, holes, and regional attributes and area\n"); - printf( -" constraints. Will generate a constrained Delaunay triangulation\n"); - printf( -" fitting the input; or, if -s, -q, or -a is used, a conforming\n"); - printf( -" Delaunay triangulation. If -p is not used, Triangle reads a .node\n" -); - printf(" file by default.\n"); - printf( -" -r Refines a previously generated mesh. The mesh is read from a .node\n" -); - printf( -" file and an .ele file. If -p is also used, a .poly file is read\n"); - printf( -" and used to constrain edges in the mesh. Further details on\n"); - printf(" refinement are given below.\n"); - printf( -" -q Quality mesh generation by Jim Ruppert's Delaunay refinement\n"); - printf( -" algorithm. Adds points to the mesh to ensure that no angles\n"); - printf( -" smaller than 20 degrees occur. An alternative minimum angle may be\n" -); - printf( -" specified after the `q'. If the minimum angle is 20.7 degrees or\n"); - printf( -" smaller, the triangulation algorithm is theoretically guaranteed to\n" -); - printf( -" terminate (assuming infinite precision arithmetic - Triangle may\n"); - printf( -" fail to terminate if you run out of precision). In practice, the\n"); - printf( -" algorithm often succeeds for minimum angles up to 33.8 degrees.\n"); - printf( -" For highly refined meshes, however, it may be necessary to reduce\n"); - printf( -" the minimum angle to well below 20 to avoid problems associated\n"); - printf( -" with insufficient floating-point precision. The specified angle\n"); - printf(" may include a decimal point.\n"); - printf( -" -a Imposes a maximum triangle area. If a number follows the `a', no\n"); - printf( -" triangle will be generated whose area is larger than that number.\n"); - printf( -" If no number is specified, an .area file (if -r is used) or .poly\n"); - printf( -" file (if -r is not used) specifies a number of maximum area\n"); - printf( -" constraints. An .area file contains a separate area constraint for\n" -); - printf( -" each triangle, and is useful for refining a finite element mesh\n"); - printf( -" based on a posteriori error estimates. A .poly file can optionally\n" -); - printf( -" contain an area constraint for each segment-bounded region, thereby\n" -); - printf( -" enforcing triangle densities in a first triangulation. You can\n"); - printf( -" impose both a fixed area constraint and a varying area constraint\n"); - printf( -" by invoking the -a switch twice, once with and once without a\n"); - printf( -" number following. Each area specified may include a decimal point.\n" -); - printf( -" -A Assigns an additional attribute to each triangle that identifies\n"); - printf( -" what segment-bounded region each triangle belongs to. Attributes\n"); - printf( -" are assigned to regions by the .poly file. If a region is not\n"); - printf( -" explicitly marked by the .poly file, triangles in that region are\n"); - printf( -" assigned an attribute of zero. The -A switch has an effect only\n"); - printf(" when the -p switch is used and the -r switch is not.\n"); - printf( -" -c Creates segments on the convex hull of the triangulation. If you\n"); - printf( -" are triangulating a point set, this switch causes a .poly file to\n"); - printf( -" be written, containing all edges in the convex hull. (By default,\n" -); - printf( -" a .poly file is written only if a .poly file is read.) If you are\n" -); - printf( -" triangulating a PSLG, this switch specifies that the interior of\n"); - printf( -" the convex hull of the PSLG should be triangulated. If you do not\n" -); - printf( -" use this switch when triangulating a PSLG, it is assumed that you\n"); - printf( -" have identified the region to be triangulated by surrounding it\n"); - printf( -" with segments of the input PSLG. Beware: if you are not careful,\n" -); - printf( -" this switch can cause the introduction of an extremely thin angle\n"); - printf( -" between a PSLG segment and a convex hull segment, which can cause\n"); - printf( -" overrefinement or failure if Triangle runs out of precision. If\n"); - printf( -" you are refining a mesh, the -c switch works differently; it\n"); - printf( -" generates the set of boundary edges of the mesh, rather than the\n"); - printf(" convex hull.\n"); - printf( -" -e Outputs (to an .edge file) a list of edges of the triangulation.\n"); - printf( -" -v Outputs the Voronoi diagram associated with the triangulation.\n"); - printf(" Does not attempt to detect degeneracies.\n"); - printf( -" -n Outputs (to a .neigh file) a list of triangles neighboring each\n"); - printf(" triangle.\n"); - printf( -" -g Outputs the mesh to an Object File Format (.off) file, suitable for\n" -); - printf(" viewing with the Geometry Center's Geomview package.\n"); - printf( -" -B No boundary markers in the output .node, .poly, and .edge output\n"); - printf( -" files. See the detailed discussion of boundary markers below.\n"); - printf( -" -P No output .poly file. Saves disk space, but you lose the ability\n"); - printf( -" to impose segment constraints on later refinements of the mesh.\n"); - printf(" -N No output .node file.\n"); - printf(" -E No output .ele file.\n"); - printf( -" -I No iteration numbers. Suppresses the output of .node and .poly\n"); - printf( -" files, so your input files won't be overwritten. (If your input is\n" -); - printf( -" a .poly file only, a .node file will be written.) Cannot be used\n"); - printf( -" with the -r switch, because that would overwrite your input .ele\n"); - printf( -" file. Shouldn't be used with the -s, -q, or -a switch if you are\n"); - printf( -" using a .node file for input, because no .node file will be\n"); - printf(" written, so there will be no record of any added points.\n"); - printf(" -O No holes. Ignores the holes in the .poly file.\n"); - printf( -" -X No exact arithmetic. Normally, Triangle uses exact floating-point\n" -); - printf( -" arithmetic for certain tests if it thinks the inexact tests are not\n" -); - printf( -" accurate enough. Exact arithmetic ensures the robustness of the\n"); - printf( -" triangulation algorithms, despite floating-point roundoff error.\n"); - printf( -" Disabling exact arithmetic with the -X switch will cause a small\n"); - printf( -" improvement in speed and create the possibility (albeit small) that\n" -); - printf( -" Triangle will fail to produce a valid mesh. Not recommended.\n"); - printf( -" -z Numbers all items starting from zero (rather than one). Note that\n" -); - printf( -" this switch is normally overrided by the value used to number the\n"); - printf( -" first point of the input .node or .poly file. However, this switch\n" -); - printf(" is useful when calling Triangle from another program.\n"); - printf( -" -o2 Generates second-order subparametric elements with six nodes each.\n" -); - printf( -" -Y No new points on the boundary. This switch is useful when the mesh\n" -); - printf( -" boundary must be preserved so that it conforms to some adjacent\n"); - printf( -" mesh. Be forewarned that you will probably sacrifice some of the\n"); - printf( -" quality of the mesh; Triangle will try, but the resulting mesh may\n" -); - printf( -" contain triangles of poor aspect ratio. Works well if all the\n"); - printf( -" boundary points are closely spaced. Specify this switch twice\n"); - printf( -" (`-YY') to prevent all segment splitting, including internal\n"); - printf(" boundaries.\n"); - printf( -" -S Specifies the maximum number of Steiner points (points that are not\n" -); - printf( -" in the input, but are added to meet the constraints of minimum\n"); - printf( -" angle and maximum area). The default is to allow an unlimited\n"); - printf( -" number. If you specify this switch with no number after it,\n"); - printf( -" the limit is set to zero. Triangle always adds points at segment\n"); - printf( -" intersections, even if it needs to use more points than the limit\n"); - printf( -" you set. When Triangle inserts segments by splitting (-s), it\n"); - printf( -" always adds enough points to ensure that all the segments appear in\n" -); - printf( -" the triangulation, again ignoring the limit. Be forewarned that\n"); - printf( -" the -S switch may result in a conforming triangulation that is not\n" -); - printf( -" truly Delaunay, because Triangle may be forced to stop adding\n"); - printf( -" points when the mesh is in a state where a segment is non-Delaunay\n" -); - printf( -" and needs to be split. If so, Triangle will print a warning.\n"); - printf( -" -i Uses an incremental rather than divide-and-conquer algorithm to\n"); - printf( -" form a Delaunay triangulation. Try it if the divide-and-conquer\n"); - printf(" algorithm fails.\n"); - printf( -" -F Uses Steven Fortune's sweepline algorithm to form a Delaunay\n"); - printf( -" triangulation. Warning: does not use exact arithmetic for all\n"); - printf(" calculations. An exact result is not guaranteed.\n"); - printf( -" -l Uses only vertical cuts in the divide-and-conquer algorithm. By\n"); - printf( -" default, Triangle uses alternating vertical and horizontal cuts,\n"); - printf( -" which usually improve the speed except with point sets that are\n"); - printf( -" small or short and wide. This switch is primarily of theoretical\n"); - printf(" interest.\n"); - printf( -" -s Specifies that segments should be forced into the triangulation by\n" -); - printf( -" recursively splitting them at their midpoints, rather than by\n"); - printf( -" generating a constrained Delaunay triangulation. Segment splitting\n" -); - printf( -" is true to Ruppert's original algorithm, but can create needlessly\n" -); - printf(" small triangles near external small features.\n"); - printf( -" -C Check the consistency of the final mesh. Uses exact arithmetic for\n" -); - printf( -" checking, even if the -X switch is used. Useful if you suspect\n"); - printf(" Triangle is buggy.\n"); - printf( -" -Q Quiet: Suppresses all explanation of what Triangle is doing, unless\n" -); - printf(" an error occurs.\n"); - printf( -" -V Verbose: Gives detailed information about what Triangle is doing.\n"); - printf( -" Add more `V's for increasing amount of detail. `-V' gives\n"); - printf( -" information on algorithmic progress and more detailed statistics.\n"); - printf( -" `-VV' gives point-by-point details, and will print so much that\n"); - printf( -" Triangle will run much more slowly. `-VVV' gives information only\n" -); - printf(" a debugger could love.\n"); - printf(" -h Help: Displays these instructions.\n"); - printf("\n"); - printf("Definitions:\n"); - printf("\n"); - printf( -" A Delaunay triangulation of a point set is a triangulation whose vertices\n" -); - printf( -" are the point set, having the property that no point in the point set\n"); - printf( -" falls in the interior of the circumcircle (circle that passes through all\n" -); - printf(" three vertices) of any triangle in the triangulation.\n\n"); - printf( -" A Voronoi diagram of a point set is a subdivision of the plane into\n"); - printf( -" polygonal regions (some of which may be infinite), where each region is\n"); - printf( -" the set of points in the plane that are closer to some input point than\n"); - printf( -" to any other input point. (The Voronoi diagram is the geometric dual of\n" -); - printf(" the Delaunay triangulation.)\n\n"); - printf( -" A Planar Straight Line Graph (PSLG) is a collection of points and\n"); - printf( -" segments. Segments are simply edges, whose endpoints are points in the\n"); - printf( -" PSLG. The file format for PSLGs (.poly files) is described below.\n"); - printf("\n"); - printf( -" A constrained Delaunay triangulation of a PSLG is similar to a Delaunay\n"); - printf( -" triangulation, but each PSLG segment is present as a single edge in the\n"); - printf( -" triangulation. (A constrained Delaunay triangulation is not truly a\n"); - printf(" Delaunay triangulation.)\n\n"); - printf( -" A conforming Delaunay triangulation of a PSLG is a true Delaunay\n"); - printf( -" triangulation in which each PSLG segment may have been subdivided into\n"); - printf( -" several edges by the insertion of additional points. These inserted\n"); - printf( -" points are necessary to allow the segments to exist in the mesh while\n"); - printf(" maintaining the Delaunay property.\n\n"); - printf("File Formats:\n\n"); - printf( -" All files may contain comments prefixed by the character '#'. Points,\n"); - printf( -" triangles, edges, holes, and maximum area constraints must be numbered\n"); - printf( -" consecutively, starting from either 1 or 0. Whichever you choose, all\n"); - printf( -" input files must be consistent; if the nodes are numbered from 1, so must\n" -); - printf( -" be all other objects. Triangle automatically detects your choice while\n"); - printf( -" reading the .node (or .poly) file. (When calling Triangle from another\n"); - printf( -" program, use the -z switch if you wish to number objects from zero.)\n"); - printf(" Examples of these file formats are given below.\n\n"); - printf(" .node files:\n"); - printf( -" First line: <# of points> <# of attributes>\n"); - printf( -" <# of boundary markers (0 or 1)>\n" -); - printf( -" Remaining lines: [attributes] [boundary marker]\n"); - printf("\n"); - printf( -" The attributes, which are typically floating-point values of physical\n"); - printf( -" quantities (such as mass or conductivity) associated with the nodes of\n" -); - printf( -" a finite element mesh, are copied unchanged to the output mesh. If -s,\n" -); - printf( -" -q, or -a is selected, each new Steiner point added to the mesh will\n"); - printf(" have attributes assigned to it by linear interpolation.\n\n"); - printf( -" If the fourth entry of the first line is `1', the last column of the\n"); - printf( -" remainder of the file is assumed to contain boundary markers. Boundary\n" -); - printf( -" markers are used to identify boundary points and points resting on PSLG\n" -); - printf( -" segments; a complete description appears in a section below. The .node\n" -); - printf( -" file produced by Triangle will contain boundary markers in the last\n"); - printf(" column unless they are suppressed by the -B switch.\n\n"); - printf(" .ele files:\n"); - printf( -" First line: <# of triangles> <# of attributes>\n"); - printf( -" Remaining lines: ... [attributes]\n" -); - printf("\n"); - printf( -" Points are indices into the corresponding .node file. The first three\n" -); - printf( -" points are the corners, and are listed in counterclockwise order around\n" -); - printf( -" each triangle. (The remaining points, if any, depend on the type of\n"); - printf( -" finite element used.) The attributes are just like those of .node\n"); - printf( -" files. Because there is no simple mapping from input to output\n"); - printf( -" triangles, an attempt is made to interpolate attributes, which may\n"); - printf( -" result in a good deal of diffusion of attributes among nearby triangles\n" -); - printf( -" as the triangulation is refined. Diffusion does not occur across\n"); - printf( -" segments, so attributes used to identify segment-bounded regions remain\n" -); - printf( -" intact. In output .ele files, all triangles have three points each\n"); - printf( -" unless the -o2 switch is used, in which case they have six, and the\n"); - printf( -" fourth, fifth, and sixth points lie on the midpoints of the edges\n"); - printf(" opposite the first, second, and third corners.\n\n"); - printf(" .poly files:\n"); - printf( -" First line: <# of points> <# of attributes>\n"); - printf( -" <# of boundary markers (0 or 1)>\n" -); - printf( -" Following lines: [attributes] [boundary marker]\n"); - printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); - printf( -" Following lines: [boundary marker]\n"); - printf(" One line: <# of holes>\n"); - printf(" Following lines: \n"); - printf( -" Optional line: <# of regional attributes and/or area constraints>\n"); - printf( -" Optional following lines: \n"); - printf("\n"); - printf( -" A .poly file represents a PSLG, as well as some additional information.\n" -); - printf( -" The first section lists all the points, and is identical to the format\n" -); - printf( -" of .node files. <# of points> may be set to zero to indicate that the\n" -); - printf( -" points are listed in a separate .node file; .poly files produced by\n"); - printf( -" Triangle always have this format. This has the advantage that a point\n" -); - printf( -" set may easily be triangulated with or without segments. (The same\n"); - printf( -" effect can be achieved, albeit using more disk space, by making a copy\n" -); - printf( -" of the .poly file with the extension .node; all sections of the file\n"); - printf(" but the first are ignored.)\n\n"); - printf( -" The second section lists the segments. Segments are edges whose\n"); - printf( -" presence in the triangulation is enforced. Each segment is specified\n"); - printf( -" by listing the indices of its two endpoints. This means that you must\n" -); - printf( -" include its endpoints in the point list. If -s, -q, and -a are not\n"); - printf( -" selected, Triangle will produce a constrained Delaunay triangulation,\n"); - printf( -" in which each segment appears as a single edge in the triangulation.\n"); - printf( -" If -q or -a is selected, Triangle will produce a conforming Delaunay\n"); - printf( -" triangulation, in which segments may be subdivided into smaller edges.\n" -); - printf(" Each segment, like each point, may have a boundary marker.\n\n"); - printf( -" The third section lists holes (and concavities, if -c is selected) in\n"); - printf( -" the triangulation. Holes are specified by identifying a point inside\n"); - printf( -" each hole. After the triangulation is formed, Triangle creates holes\n"); - printf( -" by eating triangles, spreading out from each hole point until its\n"); - printf( -" progress is blocked by PSLG segments; you must be careful to enclose\n"); - printf( -" each hole in segments, or your whole triangulation may be eaten away.\n"); - printf( -" If the two triangles abutting a segment are eaten, the segment itself\n"); - printf( -" is also eaten. Do not place a hole directly on a segment; if you do,\n"); - printf(" Triangle will choose one side of the segment arbitrarily.\n\n"); - printf( -" The optional fourth section lists regional attributes (to be assigned\n"); - printf( -" to all triangles in a region) and regional constraints on the maximum\n"); - printf( -" triangle area. Triangle will read this section only if the -A switch\n"); - printf( -" is used or the -a switch is used without a number following it, and the\n" -); - printf( -" -r switch is not used. Regional attributes and area constraints are\n"); - printf( -" propagated in the same manner as holes; you specify a point for each\n"); - printf( -" attribute and/or constraint, and the attribute and/or constraint will\n"); - printf( -" affect the whole region (bounded by segments) containing the point. If\n" -); - printf( -" two values are written on a line after the x and y coordinate, the\n"); - printf( -" former is assumed to be a regional attribute (but will only be applied\n" -); - printf( -" if the -A switch is selected), and the latter is assumed to be a\n"); - printf( -" regional area constraint (but will only be applied if the -a switch is\n" -); - printf( -" selected). You may also specify just one value after the coordinates,\n" -); - printf( -" which can serve as both an attribute and an area constraint, depending\n" -); - printf( -" on the choice of switches. If you are using the -A and -a switches\n"); - printf( -" simultaneously and wish to assign an attribute to some region without\n"); - printf(" imposing an area constraint, use a negative maximum area.\n\n"); - printf( -" When a triangulation is created from a .poly file, you must either\n"); - printf( -" enclose the entire region to be triangulated in PSLG segments, or\n"); - printf( -" use the -c switch, which encloses the convex hull of the input point\n"); - printf( -" set. If you do not use the -c switch, Triangle will eat all triangles\n" -); - printf( -" on the outer boundary that are not protected by segments; if you are\n"); - printf( -" not careful, your whole triangulation may be eaten away. If you do\n"); - printf( -" use the -c switch, you can still produce concavities by appropriate\n"); - printf(" placement of holes just inside the convex hull.\n\n"); - printf( -" An ideal PSLG has no intersecting segments, nor any points that lie\n"); - printf( -" upon segments (except, of course, the endpoints of each segment.) You\n" -); - printf( -" aren't required to make your .poly files ideal, but you should be aware\n" -); - printf( -" of what can go wrong. Segment intersections are relatively safe -\n"); - printf( -" Triangle will calculate the intersection points for you and add them to\n" -); - printf( -" the triangulation - as long as your machine's floating-point precision\n" -); - printf( -" doesn't become a problem. You are tempting the fates if you have three\n" -); - printf( -" segments that cross at the same location, and expect Triangle to figure\n" -); - printf( -" out where the intersection point is. Thanks to floating-point roundoff\n" -); - printf( -" error, Triangle will probably decide that the three segments intersect\n" -); - printf( -" at three different points, and you will find a minuscule triangle in\n"); - printf( -" your output - unless Triangle tries to refine the tiny triangle, uses\n"); - printf( -" up the last bit of machine precision, and fails to terminate at all.\n"); - printf( -" You're better off putting the intersection point in the input files,\n"); - printf( -" and manually breaking up each segment into two. Similarly, if you\n"); - printf( -" place a point at the middle of a segment, and hope that Triangle will\n"); - printf( -" break up the segment at that point, you might get lucky. On the other\n" -); - printf( -" hand, Triangle might decide that the point doesn't lie precisely on the\n" -); - printf( -" line, and you'll have a needle-sharp triangle in your output - or a lot\n" -); - printf(" of tiny triangles if you're generating a quality mesh.\n\n"); - printf( -" When Triangle reads a .poly file, it also writes a .poly file, which\n"); - printf( -" includes all edges that are part of input segments. If the -c switch\n"); - printf( -" is used, the output .poly file will also include all of the edges on\n"); - printf( -" the convex hull. Hence, the output .poly file is useful for finding\n"); - printf( -" edges associated with input segments and setting boundary conditions in\n" -); - printf( -" finite element simulations. More importantly, you will need it if you\n" -); - printf( -" plan to refine the output mesh, and don't want segments to be missing\n"); - printf(" in later triangulations.\n\n"); - printf(" .area files:\n"); - printf(" First line: <# of triangles>\n"); - printf(" Following lines: \n\n"); - printf( -" An .area file associates with each triangle a maximum area that is used\n" -); - printf( -" for mesh refinement. As with other file formats, every triangle must\n"); - printf( -" be represented, and they must be numbered consecutively. A triangle\n"); - printf( -" may be left unconstrained by assigning it a negative maximum area.\n"); - printf("\n"); - printf(" .edge files:\n"); - printf(" First line: <# of edges> <# of boundary markers (0 or 1)>\n"); - printf( -" Following lines: [boundary marker]\n"); - printf("\n"); - printf( -" Endpoints are indices into the corresponding .node file. Triangle can\n" -); - printf( -" produce .edge files (use the -e switch), but cannot read them. The\n"); - printf( -" optional column of boundary markers is suppressed by the -B switch.\n"); - printf("\n"); - printf( -" In Voronoi diagrams, one also finds a special kind of edge that is an\n"); - printf( -" infinite ray with only one endpoint. For these edges, a different\n"); - printf(" format is used:\n\n"); - printf(" -1 \n\n"); - printf( -" The `direction' is a floating-point vector that indicates the direction\n" -); - printf(" of the infinite ray.\n\n"); - printf(" .neigh files:\n"); - printf( -" First line: <# of triangles> <# of neighbors per triangle (always 3)>\n" -); - printf( -" Following lines: \n"); - printf("\n"); - printf( -" Neighbors are indices into the corresponding .ele file. An index of -1\n" -); - printf( -" indicates a mesh boundary, and therefore no neighbor. Triangle can\n"); - printf( -" produce .neigh files (use the -n switch), but cannot read them.\n"); - printf("\n"); - printf( -" The first neighbor of triangle i is opposite the first corner of\n"); - printf(" triangle i, and so on.\n\n"); - printf("Boundary Markers:\n\n"); - printf( -" Boundary markers are tags used mainly to identify which output points and\n" -); - printf( -" edges are associated with which PSLG segment, and to identify which\n"); - printf( -" points and edges occur on a boundary of the triangulation. A common use\n" -); - printf( -" is to determine where boundary conditions should be applied to a finite\n"); - printf( -" element mesh. You can prevent boundary markers from being written into\n"); - printf(" files produced by Triangle by using the -B switch.\n\n"); - printf( -" The boundary marker associated with each segment in an output .poly file\n" -); - printf(" or edge in an output .edge file is chosen as follows:\n"); - printf( -" - If an output edge is part or all of a PSLG segment with a nonzero\n"); - printf( -" boundary marker, then the edge is assigned the same marker.\n"); - printf( -" - Otherwise, if the edge occurs on a boundary of the triangulation\n"); - printf( -" (including boundaries of holes), then the edge is assigned the marker\n" -); - printf(" one (1).\n"); - printf(" - Otherwise, the edge is assigned the marker zero (0).\n"); - printf( -" The boundary marker associated with each point in an output .node file is\n" -); - printf(" chosen as follows:\n"); - printf( -" - If a point is assigned a nonzero boundary marker in the input file,\n"); - printf( -" then it is assigned the same marker in the output .node file.\n"); - printf( -" - Otherwise, if the point lies on a PSLG segment (including the\n"); - printf( -" segment's endpoints) with a nonzero boundary marker, then the point\n"); - printf( -" is assigned the same marker. If the point lies on several such\n"); - printf(" segments, one of the markers is chosen arbitrarily.\n"); - printf( -" - Otherwise, if the point occurs on a boundary of the triangulation,\n"); - printf(" then the point is assigned the marker one (1).\n"); - printf(" - Otherwise, the point is assigned the marker zero (0).\n"); - printf("\n"); - printf( -" If you want Triangle to determine for you which points and edges are on\n"); - printf( -" the boundary, assign them the boundary marker zero (or use no markers at\n" -); - printf( -" all) in your input files. Alternatively, you can mark some of them and\n"); - printf(" leave others marked zero, allowing Triangle to label them.\n\n"); - printf("Triangulation Iteration Numbers:\n\n"); - printf( -" Because Triangle can read and refine its own triangulations, input\n"); - printf( -" and output files have iteration numbers. For instance, Triangle might\n"); - printf( -" read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the\n"); - printf( -" triangulation, and output the files mesh.4.node, mesh.4.ele, and\n"); - printf(" mesh.4.poly. Files with no iteration number are treated as if\n"); - printf( -" their iteration number is zero; hence, Triangle might read the file\n"); - printf( -" points.node, triangulate it, and produce the files points.1.node and\n"); - printf(" points.1.ele.\n\n"); - printf( -" Iteration numbers allow you to create a sequence of successively finer\n"); - printf( -" meshes suitable for multigrid methods. They also allow you to produce a\n" -); - printf( -" sequence of meshes using error estimate-driven mesh refinement.\n"); - printf("\n"); - printf( -" If you're not using refinement or quality meshing, and you don't like\n"); - printf( -" iteration numbers, use the -I switch to disable them. This switch will\n"); - printf( -" also disable output of .node and .poly files to prevent your input files\n" -); - printf( -" from being overwritten. (If the input is a .poly file that contains its\n" -); - printf(" own points, a .node file will be written.)\n\n"); - printf("Examples of How to Use Triangle:\n\n"); - printf( -" `triangle dots' will read points from dots.node, and write their Delaunay\n" -); - printf( -" triangulation to dots.1.node and dots.1.ele. (dots.1.node will be\n"); - printf( -" identical to dots.node.) `triangle -I dots' writes the triangulation to\n" -); - printf( -" dots.ele instead. (No additional .node file is needed, so none is\n"); - printf(" written.)\n\n"); - printf( -" `triangle -pe object.1' will read a PSLG from object.1.poly (and possibly\n" -); - printf( -" object.1.node, if the points are omitted from object.1.poly) and write\n"); - printf(" their constrained Delaunay triangulation to object.2.node and\n"); - printf( -" object.2.ele. The segments will be copied to object.2.poly, and all\n"); - printf(" edges will be written to object.2.edge.\n\n"); - printf( -" `triangle -pq31.5a.1 object' will read a PSLG from object.poly (and\n"); - printf( -" possibly object.node), generate a mesh whose angles are all greater than\n" -); - printf( -" 31.5 degrees and whose triangles all have area smaller than 0.1, and\n"); - printf( -" write the mesh to object.1.node and object.1.ele. Each segment may have\n" -); - printf( -" been broken up into multiple edges; the resulting constrained edges are\n"); - printf(" written to object.1.poly.\n\n"); - printf( -" Here is a sample file `box.poly' describing a square with a square hole:\n" -); - printf("\n"); - printf( -" # A box with eight points in 2D, no attributes, one boundary marker.\n"); - printf(" 8 2 0 1\n"); - printf(" # Outer box has these vertices:\n"); - printf(" 1 0 0 0\n"); - printf(" 2 0 3 0\n"); - printf(" 3 3 0 0\n"); - printf(" 4 3 3 33 # A special marker for this point.\n"); - printf(" # Inner square has these vertices:\n"); - printf(" 5 1 1 0\n"); - printf(" 6 1 2 0\n"); - printf(" 7 2 1 0\n"); - printf(" 8 2 2 0\n"); - printf(" # Five segments with boundary markers.\n"); - printf(" 5 1\n"); - printf(" 1 1 2 5 # Left side of outer box.\n"); - printf(" 2 5 7 0 # Segments 2 through 5 enclose the hole.\n"); - printf(" 3 7 8 0\n"); - printf(" 4 8 6 10\n"); - printf(" 5 6 5 0\n"); - printf(" # One hole in the middle of the inner square.\n"); - printf(" 1\n"); - printf(" 1 1.5 1.5\n\n"); - printf( -" Note that some segments are missing from the outer square, so one must\n"); - printf( -" use the `-c' switch. After `triangle -pqc box.poly', here is the output\n" -); - printf( -" file `box.1.node', with twelve points. The last four points were added\n"); - printf( -" to meet the angle constraint. Points 1, 2, and 9 have markers from\n"); - printf( -" segment 1. Points 6 and 8 have markers from segment 4. All the other\n"); - printf( -" points but 4 have been marked to indicate that they lie on a boundary.\n"); - printf("\n"); - printf(" 12 2 0 1\n"); - printf(" 1 0 0 5\n"); - printf(" 2 0 3 5\n"); - printf(" 3 3 0 1\n"); - printf(" 4 3 3 33\n"); - printf(" 5 1 1 1\n"); - printf(" 6 1 2 10\n"); - printf(" 7 2 1 1\n"); - printf(" 8 2 2 10\n"); - printf(" 9 0 1.5 5\n"); - printf(" 10 1.5 0 1\n"); - printf(" 11 3 1.5 1\n"); - printf(" 12 1.5 3 1\n"); - printf(" # Generated by triangle -pqc box.poly\n\n"); - printf(" Here is the output file `box.1.ele', with twelve triangles.\n\n"); - printf(" 12 3 0\n"); - printf(" 1 5 6 9\n"); - printf(" 2 10 3 7\n"); - printf(" 3 6 8 12\n"); - printf(" 4 9 1 5\n"); - printf(" 5 6 2 9\n"); - printf(" 6 7 3 11\n"); - printf(" 7 11 4 8\n"); - printf(" 8 7 5 10\n"); - printf(" 9 12 2 6\n"); - printf(" 10 8 7 11\n"); - printf(" 11 5 1 10\n"); - printf(" 12 8 4 12\n"); - printf(" # Generated by triangle -pqc box.poly\n\n"); - printf( -" Here is the output file `box.1.poly'. Note that segments have been added\n" -); - printf( -" to represent the convex hull, and some segments have been split by newly\n" -); - printf( -" added points. Note also that <# of points> is set to zero to indicate\n"); - printf(" that the points should be read from the .node file.\n\n"); - printf(" 0 2 0 1\n"); - printf(" 12 1\n"); - printf(" 1 1 9 5\n"); - printf(" 2 5 7 1\n"); - printf(" 3 8 7 1\n"); - printf(" 4 6 8 10\n"); - printf(" 5 5 6 1\n"); - printf(" 6 3 10 1\n"); - printf(" 7 4 11 1\n"); - printf(" 8 2 12 1\n"); - printf(" 9 9 2 5\n"); - printf(" 10 10 1 1\n"); - printf(" 11 11 3 1\n"); - printf(" 12 12 4 1\n"); - printf(" 1\n"); - printf(" 1 1.5 1.5\n"); - printf(" # Generated by triangle -pqc box.poly\n\n"); - printf("Refinement and Area Constraints:\n\n"); - printf( -" The -r switch causes a mesh (.node and .ele files) to be read and\n"); - printf( -" refined. If the -p switch is also used, a .poly file is read and used to\n" -); - printf( -" specify edges that are constrained and cannot be eliminated (although\n"); - printf( -" they can be divided into smaller edges) by the refinement process.\n"); - printf("\n"); - printf( -" When you refine a mesh, you generally want to impose tighter quality\n"); - printf( -" constraints. One way to accomplish this is to use -q with a larger\n"); - printf( -" angle, or -a followed by a smaller area than you used to generate the\n"); - printf( -" mesh you are refining. Another way to do this is to create an .area\n"); - printf( -" file, which specifies a maximum area for each triangle, and use the -a\n"); - printf( -" switch (without a number following). Each triangle's area constraint is\n" -); - printf( -" applied to that triangle. Area constraints tend to diffuse as the mesh\n"); - printf( -" is refined, so if there are large variations in area constraint between\n"); - printf(" adjacent triangles, you may not get the results you want.\n\n"); - printf( -" If you are refining a mesh composed of linear (three-node) elements, the\n" -); - printf( -" output mesh will contain all the nodes present in the input mesh, in the\n" -); - printf( -" same order, with new nodes added at the end of the .node file. However,\n" -); - printf( -" there is no guarantee that each output element is contained in a single\n"); - printf( -" input element. Often, output elements will overlap two input elements,\n"); - printf( -" and input edges are not present in the output mesh. Hence, a sequence of\n" -); - printf( -" refined meshes will form a hierarchy of nodes, but not a hierarchy of\n"); - printf( -" elements. If you a refining a mesh of higher-order elements, the\n"); - printf( -" hierarchical property applies only to the nodes at the corners of an\n"); - printf(" element; other nodes may not be present in the refined mesh.\n\n"); - printf( -" It is important to understand that maximum area constraints in .poly\n"); - printf( -" files are handled differently from those in .area files. A maximum area\n" -); - printf( -" in a .poly file applies to the whole (segment-bounded) region in which a\n" -); - printf( -" point falls, whereas a maximum area in an .area file applies to only one\n" -); - printf( -" triangle. Area constraints in .poly files are used only when a mesh is\n"); - printf( -" first generated, whereas area constraints in .area files are used only to\n" -); - printf( -" refine an existing mesh, and are typically based on a posteriori error\n"); - printf( -" estimates resulting from a finite element simulation on that mesh.\n"); - printf("\n"); - printf( -" `triangle -rq25 object.1' will read object.1.node and object.1.ele, then\n" -); - printf( -" refine the triangulation to enforce a 25 degree minimum angle, and then\n"); - printf( -" write the refined triangulation to object.2.node and object.2.ele.\n"); - printf("\n"); - printf( -" `triangle -rpaa6.2 z.3' will read z.3.node, z.3.ele, z.3.poly, and\n"); - printf( -" z.3.area. After reconstructing the mesh and its segments, Triangle will\n" -); - printf( -" refine the mesh so that no triangle has area greater than 6.2, and\n"); - printf( -" furthermore the triangles satisfy the maximum area constraints in\n"); - printf( -" z.3.area. The output is written to z.4.node, z.4.ele, and z.4.poly.\n"); - printf("\n"); - printf( -" The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1\n"); - printf( -" x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,\n"); - printf(" suitable for multigrid.\n\n"); - printf("Convex Hulls and Mesh Boundaries:\n\n"); - printf( -" If the input is a point set (rather than a PSLG), Triangle produces its\n"); - printf( -" convex hull as a by-product in the output .poly file if you use the -c\n"); - printf( -" switch. There are faster algorithms for finding a two-dimensional convex\n" -); - printf( -" hull than triangulation, of course, but this one comes for free. If the\n" -); - printf( -" input is an unconstrained mesh (you are using the -r switch but not the\n"); - printf( -" -p switch), Triangle produces a list of its boundary edges (including\n"); - printf(" hole boundaries) as a by-product if you use the -c switch.\n\n"); - printf("Voronoi Diagrams:\n\n"); - printf( -" The -v switch produces a Voronoi diagram, in files suffixed .v.node and\n"); - printf( -" .v.edge. For example, `triangle -v points' will read points.node,\n"); - printf( -" produce its Delaunay triangulation in points.1.node and points.1.ele,\n"); - printf( -" and produce its Voronoi diagram in points.1.v.node and points.1.v.edge.\n"); - printf( -" The .v.node file contains a list of all Voronoi vertices, and the .v.edge\n" -); - printf( -" file contains a list of all Voronoi edges, some of which may be infinite\n" -); - printf( -" rays. (The choice of filenames makes it easy to run the set of Voronoi\n"); - printf(" vertices through Triangle, if so desired.)\n\n"); - printf( -" This implementation does not use exact arithmetic to compute the Voronoi\n" -); - printf( -" vertices, and does not check whether neighboring vertices are identical.\n" -); - printf( -" Be forewarned that if the Delaunay triangulation is degenerate or\n"); - printf( -" near-degenerate, the Voronoi diagram may have duplicate points, crossing\n" -); - printf( -" edges, or infinite rays whose direction vector is zero. Also, if you\n"); - printf( -" generate a constrained (as opposed to conforming) Delaunay triangulation,\n" -); - printf( -" or if the triangulation has holes, the corresponding Voronoi diagram is\n"); - printf(" likely to have crossing edges and unlikely to make sense.\n\n"); - printf("Mesh Topology:\n\n"); - printf( -" You may wish to know which triangles are adjacent to a certain Delaunay\n"); - printf( -" edge in an .edge file, which Voronoi regions are adjacent to a certain\n"); - printf( -" Voronoi edge in a .v.edge file, or which Voronoi regions are adjacent to\n" -); - printf( -" each other. All of this information can be found by cross-referencing\n"); - printf( -" output files with the recollection that the Delaunay triangulation and\n"); - printf(" the Voronoi diagrams are planar duals.\n\n"); - printf( -" Specifically, edge i of an .edge file is the dual of Voronoi edge i of\n"); - printf( -" the corresponding .v.edge file, and is rotated 90 degrees counterclock-\n"); - printf( -" wise from the Voronoi edge. Triangle j of an .ele file is the dual of\n"); - printf( -" vertex j of the corresponding .v.node file; and Voronoi region k is the\n"); - printf(" dual of point k of the corresponding .node file.\n\n"); - printf( -" Hence, to find the triangles adjacent to a Delaunay edge, look at the\n"); - printf( -" vertices of the corresponding Voronoi edge; their dual triangles are on\n"); - printf( -" the left and right of the Delaunay edge, respectively. To find the\n"); - printf( -" Voronoi regions adjacent to a Voronoi edge, look at the endpoints of the\n" -); - printf( -" corresponding Delaunay edge; their dual regions are on the right and left\n" -); - printf( -" of the Voronoi edge, respectively. To find which Voronoi regions are\n"); - printf(" adjacent to each other, just read the list of Delaunay edges.\n"); - printf("\n"); - printf("Statistics:\n"); - printf("\n"); - printf( -" After generating a mesh, Triangle prints a count of the number of points,\n" -); - printf( -" triangles, edges, boundary edges, and segments in the output mesh. If\n"); - printf( -" you've forgotten the statistics for an existing mesh, the -rNEP switches\n" -); - printf( -" (or -rpNEP if you've got a .poly file for the existing mesh) will\n"); - printf(" regenerate these statistics without writing any output.\n\n"); - printf( -" The -V switch produces extended statistics, including a rough estimate\n"); - printf( -" of memory use and a histogram of triangle aspect ratios and angles in the\n" -); - printf(" mesh.\n\n"); - printf("Exact Arithmetic:\n\n"); - printf( -" Triangle uses adaptive exact arithmetic to perform what computational\n"); - printf( -" geometers call the `orientation' and `incircle' tests. If the floating-\n" -); - printf( -" point arithmetic of your machine conforms to the IEEE 754 standard (as\n"); - printf( -" most workstations do), and does not use extended precision internal\n"); - printf( -" registers, then your output is guaranteed to be an absolutely true\n"); - printf(" Delaunay or conforming Delaunay triangulation, roundoff error\n"); - printf( -" notwithstanding. The word `adaptive' implies that these arithmetic\n"); - printf( -" routines compute the result only to the precision necessary to guarantee\n" -); - printf( -" correctness, so they are usually nearly as fast as their approximate\n"); - printf( -" counterparts. The exact tests can be disabled with the -X switch. On\n"); - printf( -" most inputs, this switch will reduce the computation time by about eight\n" -); - printf( -" percent - it's not worth the risk. There are rare difficult inputs\n"); - printf( -" (having many collinear and cocircular points), however, for which the\n"); - printf( -" difference could be a factor of two. These are precisely the inputs most\n" -); - printf(" likely to cause errors if you use the -X switch.\n\n"); - printf( -" Unfortunately, these routines don't solve every numerical problem. Exact\n" -); - printf( -" arithmetic is not used to compute the positions of points, because the\n"); - printf( -" bit complexity of point coordinates would grow without bound. Hence,\n"); - printf( -" segment intersections aren't computed exactly; in very unusual cases,\n"); - printf( -" roundoff error in computing an intersection point might actually lead to\n" -); - printf( -" an inverted triangle and an invalid triangulation. (This is one reason\n"); - printf( -" to compute your own intersection points in your .poly files.) Similarly,\n" -); - printf( -" exact arithmetic is not used to compute the vertices of the Voronoi\n"); - printf(" diagram.\n\n"); - printf( -" Underflow and overflow can also cause difficulties; the exact arithmetic\n" -); - printf( -" routines do not ameliorate out-of-bounds exponents, which can arise\n"); - printf( -" during the orientation and incircle tests. As a rule of thumb, you\n"); - printf( -" should ensure that your input values are within a range such that their\n"); - printf( -" third powers can be taken without underflow or overflow. Underflow can\n"); - printf( -" silently prevent the tests from being performed exactly, while overflow\n"); - printf(" will typically cause a floating exception.\n\n"); - printf("Calling Triangle from Another Program:\n\n"); - printf(" Read the file triangle.h for details.\n\n"); - printf("Troubleshooting:\n\n"); - printf(" Please read this section before mailing me bugs.\n\n"); - printf(" `My output mesh has no triangles!'\n\n"); - printf( -" If you're using a PSLG, you've probably failed to specify a proper set\n" -); - printf( -" of bounding segments, or forgotten to use the -c switch. Or you may\n"); - printf( -" have placed a hole badly. To test these possibilities, try again with\n" -); - printf( -" the -c and -O switches. Alternatively, all your input points may be\n"); - printf( -" collinear, in which case you can hardly expect to triangulate them.\n"); - printf("\n"); - printf(" `Triangle doesn't terminate, or just crashes.'\n"); - printf("\n"); - printf( -" Bad things can happen when triangles get so small that the distance\n"); - printf( -" between their vertices isn't much larger than the precision of your\n"); - printf( -" machine's arithmetic. If you've compiled Triangle for single-precision\n" -); - printf( -" arithmetic, you might do better by recompiling it for double-precision.\n" -); - printf( -" Then again, you might just have to settle for more lenient constraints\n" -); - printf( -" on the minimum angle and the maximum area than you had planned.\n"); - printf("\n"); - printf( -" You can minimize precision problems by ensuring that the origin lies\n"); - printf( -" inside your point set, or even inside the densest part of your\n"); - printf( -" mesh. On the other hand, if you're triangulating an object whose x\n"); - printf( -" coordinates all fall between 6247133 and 6247134, you're not leaving\n"); - printf(" much floating-point precision for Triangle to work with.\n\n"); - printf( -" Precision problems can occur covertly if the input PSLG contains two\n"); - printf( -" segments that meet (or intersect) at a very small angle, or if such an\n" -); - printf( -" angle is introduced by the -c switch, which may occur if a point lies\n"); - printf( -" ever-so-slightly inside the convex hull, and is connected by a PSLG\n"); - printf( -" segment to a point on the convex hull. If you don't realize that a\n"); - printf( -" small angle is being formed, you might never discover why Triangle is\n"); - printf( -" crashing. To check for this possibility, use the -S switch (with an\n"); - printf( -" appropriate limit on the number of Steiner points, found by trial-and-\n" -); - printf( -" error) to stop Triangle early, and view the output .poly file with\n"); - printf( -" Show Me (described below). Look carefully for small angles between\n"); - printf( -" segments; zoom in closely, as such segments might look like a single\n"); - printf(" segment from a distance.\n\n"); - printf( -" If some of the input values are too large, Triangle may suffer a\n"); - printf( -" floating exception due to overflow when attempting to perform an\n"); - printf( -" orientation or incircle test. (Read the section on exact arithmetic\n"); - printf( -" above.) Again, I recommend compiling Triangle for double (rather\n"); - printf(" than single) precision arithmetic.\n\n"); - printf( -" `The numbering of the output points doesn't match the input points.'\n"); - printf("\n"); - printf( -" You may have eaten some of your input points with a hole, or by placing\n" -); - printf(" them outside the area enclosed by segments.\n\n"); - printf( -" `Triangle executes without incident, but when I look at the resulting\n"); - printf( -" mesh, it has overlapping triangles or other geometric inconsistencies.'\n"); - printf("\n"); - printf( -" If you select the -X switch, Triangle's divide-and-conquer Delaunay\n"); - printf( -" triangulation algorithm occasionally makes mistakes due to floating-\n"); - printf( -" point roundoff error. Although these errors are rare, don't use the -X\n" -); - printf(" switch. If you still have problems, please report the bug.\n"); - printf("\n"); - printf( -" Strange things can happen if you've taken liberties with your PSLG. Do\n"); - printf( -" you have a point lying in the middle of a segment? Triangle sometimes\n"); - printf( -" copes poorly with that sort of thing. Do you want to lay out a collinear\n" -); - printf( -" row of evenly spaced, segment-connected points? Have you simply defined\n" -); - printf( -" one long segment connecting the leftmost point to the rightmost point,\n"); - printf( -" and a bunch of points lying along it? This method occasionally works,\n"); - printf( -" especially with horizontal and vertical lines, but often it doesn't, and\n" -); - printf( -" you'll have to connect each adjacent pair of points with a separate\n"); - printf(" segment. If you don't like it, tough.\n\n"); - printf( -" Furthermore, if you have segments that intersect other than at their\n"); - printf( -" endpoints, try not to let the intersections fall extremely close to PSLG\n" -); - printf(" points or each other.\n\n"); - printf( -" If you have problems refining a triangulation not produced by Triangle:\n"); - printf( -" Are you sure the triangulation is geometrically valid? Is it formatted\n"); - printf( -" correctly for Triangle? Are the triangles all listed so the first three\n" -); - printf(" points are their corners in counterclockwise order?\n\n"); - printf("Show Me:\n\n"); - printf( -" Triangle comes with a separate program named `Show Me', whose primary\n"); - printf( -" purpose is to draw meshes on your screen or in PostScript. Its secondary\n" -); - printf( -" purpose is to check the validity of your input files, and do so more\n"); - printf( -" thoroughly than Triangle does. Show Me requires that you have the X\n"); - printf( -" Windows system. If you didn't receive Show Me with Triangle, complain to\n" -); - printf(" whomever you obtained Triangle from, then send me mail.\n\n"); - printf("Triangle on the Web:\n\n"); - printf( -" To see an illustrated, updated version of these instructions, check out\n"); - printf("\n"); - printf(" http://www.cs.cmu.edu/~quake/triangle.html\n"); - printf("\n"); - printf("A Brief Plea:\n"); - printf("\n"); - printf( -" If you use Triangle, and especially if you use it to accomplish real\n"); - printf( -" work, I would like very much to hear from you. A short letter or email\n"); - printf( -" (to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to\n"); - printf( -" me. The more people I know are using this program, the more easily I can\n" -); - printf( -" justify spending time on improvements and on the three-dimensional\n"); - printf( -" successor to Triangle, which in turn will benefit you. Also, I can put\n"); - printf( -" you on a list to receive email whenever a new version of Triangle is\n"); - printf(" available.\n\n"); - printf( -" If you use a mesh generated by Triangle in a publication, please include\n" -); - printf(" an acknowledgment as well.\n\n"); - printf("Research credit:\n\n"); - printf( -" Of course, I can take credit for only a fraction of the ideas that made\n"); - printf( -" this mesh generator possible. Triangle owes its existence to the efforts\n" -); - printf( -" of many fine computational geometers and other researchers, including\n"); - printf( -" Marshall Bern, L. Paul Chew, Boris Delaunay, Rex A. Dwyer, David\n"); - printf( -" Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E. Knuth, C. L.\n"); - printf( -" Lawson, Der-Tsai Lee, Ernst P. Mucke, Douglas M. Priest, Jim Ruppert,\n"); - printf( -" Isaac Saias, Bruce J. Schachter, Micha Sharir, Jorge Stolfi, Christopher\n" -); - printf( -" J. Van Wyk, David F. Watson, and Binhai Zhu. See the comments at the\n"); - printf(" beginning of the source code for references.\n\n"); - exit(0); -} - -#endif /* not TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* internalerror() Ask the user to send me the defective product. Exit. */ -/* */ -/*****************************************************************************/ - -void internalerror() -{ - printf(" Please report this bug to jrs@cs.cmu.edu\n"); - printf(" Include the message above, your input data set, and the exact\n"); - printf(" command line you used to run Triangle.\n"); - exit(1); -} - -/*****************************************************************************/ -/* */ -/* parsecommandline() Read the command line, identify switches, and set */ -/* up options and file names. */ -/* */ -/* The effects of this routine are felt entirely through global variables. */ -/* */ -/*****************************************************************************/ - -void parsecommandline(argc, argv) -int argc; -char **argv; -{ -#ifdef TRILIBRARY -#define STARTINDEX 0 -#else /* not TRILIBRARY */ -#define STARTINDEX 1 - int increment; - int meshnumber; -#endif /* not TRILIBRARY */ - int i, j; -#ifndef CDT_ONLY - int k; - char workstring[FILENAMESIZE]; -#endif - - poly = refine = quality = vararea = fixedarea = regionattrib = convex = 0; - firstnumber = 1; - edgesout = voronoi = neighbors = geomview = 0; - nobound = nopolywritten = nonodewritten = noelewritten = noiterationnum = 0; - noholes = noexact = 0; - incremental = sweepline = 0; - dwyer = 1; - splitseg = 0; - docheck = 0; - nobisect = 0; - steiner = -1; - order = 1; - minangle = 0.0; - maxarea = -1.0; - quiet = verbose = 0; -#ifndef TRILIBRARY - innodefilename[0] = '\0'; -#endif /* not TRILIBRARY */ - - for (i = STARTINDEX; i < argc; i++) { -#ifndef TRILIBRARY - if (argv[i][0] == '-') { -#endif /* not TRILIBRARY */ - for (j = STARTINDEX; argv[i][j] != '\0'; j++) { - if (argv[i][j] == 'p') { - poly = 1; - } -#ifndef CDT_ONLY - if (argv[i][j] == 'r') { - refine = 1; - } - if (argv[i][j] == 'q') { - quality = 1; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - minangle = (REAL) strtod(workstring, (char **) NULL); - } else { - minangle = 20.0; - } - } - if (argv[i][j] == 'a') { - quality = 1; - if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - fixedarea = 1; - k = 0; - while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || - (argv[i][j + 1] == '.')) { - j++; - workstring[k] = argv[i][j]; - k++; - } - workstring[k] = '\0'; - maxarea = (REAL) strtod(workstring, (char **) NULL); - if (maxarea <= 0.0) { - printf("Error: Maximum area must be greater than zero.\n"); - exit(1); - } - } else { - vararea = 1; - } - } -#endif /* not CDT_ONLY */ - if (argv[i][j] == 'A') { - regionattrib = 1; - } - if (argv[i][j] == 'c') { - convex = 1; - } - if (argv[i][j] == 'z') { - firstnumber = 0; - } - if (argv[i][j] == 'e') { - edgesout = 1; - } - if (argv[i][j] == 'v') { - voronoi = 1; - } - if (argv[i][j] == 'n') { - neighbors = 1; - } - if (argv[i][j] == 'g') { - geomview = 1; - } - if (argv[i][j] == 'B') { - nobound = 1; - } - if (argv[i][j] == 'P') { - nopolywritten = 1; - } - if (argv[i][j] == 'N') { - nonodewritten = 1; - } - if (argv[i][j] == 'E') { - noelewritten = 1; - } -#ifndef TRILIBRARY - if (argv[i][j] == 'I') { - noiterationnum = 1; - } -#endif /* not TRILIBRARY */ - if (argv[i][j] == 'O') { - noholes = 1; - } - if (argv[i][j] == 'X') { - noexact = 1; - } - if (argv[i][j] == 'o') { - if (argv[i][j + 1] == '2') { - j++; - order = 2; - } - } -#ifndef CDT_ONLY - if (argv[i][j] == 'Y') { - nobisect++; - } - if (argv[i][j] == 'S') { - steiner = 0; - while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { - j++; - steiner = steiner * 10 + (int) (argv[i][j] - '0'); - } - } -#endif /* not CDT_ONLY */ -#ifndef REDUCED - if (argv[i][j] == 'i') { - incremental = 1; - } - if (argv[i][j] == 'F') { - sweepline = 1; - } -#endif /* not REDUCED */ - if (argv[i][j] == 'l') { - dwyer = 0; - } -#ifndef REDUCED -#ifndef CDT_ONLY - if (argv[i][j] == 's') { - splitseg = 1; - } -#endif /* not CDT_ONLY */ - if (argv[i][j] == 'C') { - docheck = 1; - } -#endif /* not REDUCED */ - if (argv[i][j] == 'Q') { - quiet = 1; - } - if (argv[i][j] == 'V') { - verbose++; - } -#ifndef TRILIBRARY - if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || - (argv[i][j] == '?')) { - info(); - } -#endif /* not TRILIBRARY */ - } -#ifndef TRILIBRARY - } else { - strncpy(innodefilename, argv[i], FILENAMESIZE - 1); - innodefilename[FILENAMESIZE - 1] = '\0'; - } -#endif /* not TRILIBRARY */ - } -#ifndef TRILIBRARY - if (innodefilename[0] == '\0') { - syntax(); - } - if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".node")) { - innodefilename[strlen(innodefilename) - 5] = '\0'; - } - if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".poly")) { - innodefilename[strlen(innodefilename) - 5] = '\0'; - poly = 1; - } -#ifndef CDT_ONLY - if (!strcmp(&innodefilename[strlen(innodefilename) - 4], ".ele")) { - innodefilename[strlen(innodefilename) - 4] = '\0'; - refine = 1; - } - if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".area")) { - innodefilename[strlen(innodefilename) - 5] = '\0'; - refine = 1; - quality = 1; - vararea = 1; - } -#endif /* not CDT_ONLY */ -#endif /* not TRILIBRARY */ - steinerleft = steiner; - useshelles = poly || refine || quality || convex; - goodangle = (REAL)cos(minangle * PI / 180.0); - goodangle *= goodangle; - if (refine && noiterationnum) { - printf( - "Error: You cannot use the -I switch when refining a triangulation.\n"); - exit(1); - } - /* Be careful not to allocate space for element area constraints that */ - /* will never be assigned any value (other than the default -1.0). */ - if (!refine && !poly) { - vararea = 0; - } - /* Be careful not to add an extra attribute to each element unless the */ - /* input supports it (PSLG in, but not refining a preexisting mesh). */ - if (refine || !poly) { - regionattrib = 0; - } - -#ifndef TRILIBRARY - strcpy(inpolyfilename, innodefilename); - strcpy(inelefilename, innodefilename); - strcpy(areafilename, innodefilename); - increment = 0; - strcpy(workstring, innodefilename); - j = 1; - while (workstring[j] != '\0') { - if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { - increment = j + 1; - } - j++; - } - meshnumber = 0; - if (increment > 0) { - j = increment; - do { - if ((workstring[j] >= '0') && (workstring[j] <= '9')) { - meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); - } else { - increment = 0; - } - j++; - } while (workstring[j] != '\0'); - } - if (noiterationnum) { - strcpy(outnodefilename, innodefilename); - strcpy(outelefilename, innodefilename); - strcpy(edgefilename, innodefilename); - strcpy(vnodefilename, innodefilename); - strcpy(vedgefilename, innodefilename); - strcpy(neighborfilename, innodefilename); - strcpy(offfilename, innodefilename); - strcat(outnodefilename, ".node"); - strcat(outelefilename, ".ele"); - strcat(edgefilename, ".edge"); - strcat(vnodefilename, ".v.node"); - strcat(vedgefilename, ".v.edge"); - strcat(neighborfilename, ".neigh"); - strcat(offfilename, ".off"); - } else if (increment == 0) { - strcpy(outnodefilename, innodefilename); - strcpy(outpolyfilename, innodefilename); - strcpy(outelefilename, innodefilename); - strcpy(edgefilename, innodefilename); - strcpy(vnodefilename, innodefilename); - strcpy(vedgefilename, innodefilename); - strcpy(neighborfilename, innodefilename); - strcpy(offfilename, innodefilename); - strcat(outnodefilename, ".1.node"); - strcat(outpolyfilename, ".1.poly"); - strcat(outelefilename, ".1.ele"); - strcat(edgefilename, ".1.edge"); - strcat(vnodefilename, ".1.v.node"); - strcat(vedgefilename, ".1.v.edge"); - strcat(neighborfilename, ".1.neigh"); - strcat(offfilename, ".1.off"); - } else { - workstring[increment] = '%'; - workstring[increment + 1] = 'd'; - workstring[increment + 2] = '\0'; - sprintf(outnodefilename, workstring, meshnumber + 1); - strcpy(outpolyfilename, outnodefilename); - strcpy(outelefilename, outnodefilename); - strcpy(edgefilename, outnodefilename); - strcpy(vnodefilename, outnodefilename); - strcpy(vedgefilename, outnodefilename); - strcpy(neighborfilename, outnodefilename); - strcpy(offfilename, outnodefilename); - strcat(outnodefilename, ".node"); - strcat(outpolyfilename, ".poly"); - strcat(outelefilename, ".ele"); - strcat(edgefilename, ".edge"); - strcat(vnodefilename, ".v.node"); - strcat(vedgefilename, ".v.edge"); - strcat(neighborfilename, ".neigh"); - strcat(offfilename, ".off"); - } - strcat(innodefilename, ".node"); - strcat(inpolyfilename, ".poly"); - strcat(inelefilename, ".ele"); - strcat(areafilename, ".area"); -#endif /* not TRILIBRARY */ -} - -/** **/ -/** **/ -/********* User interaction routines begin here *********/ - -/********* Debugging routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* printtriangle() Print out the details of a triangle/edge handle. */ -/* */ -/* I originally wrote this procedure to simplify debugging; it can be */ -/* called directly from the debugger, and presents information about a */ -/* triangle/edge handle in digestible form. It's also used when the */ -/* highest level of verbosity (`-VVV') is specified. */ -/* */ -/*****************************************************************************/ - -void printtriangle(t) -struct triedge *t; -{ - struct triedge printtri; - struct edge printsh; - point printpoint; - - printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, - t->orient); - decode(t->tri[0], printtri); - if (printtri.tri == dummytri) { - printf(" [0] = Outer space\n"); - } else { - printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, - printtri.orient); - } - decode(t->tri[1], printtri); - if (printtri.tri == dummytri) { - printf(" [1] = Outer space\n"); - } else { - printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, - printtri.orient); - } - decode(t->tri[2], printtri); - if (printtri.tri == dummytri) { - printf(" [2] = Outer space\n"); - } else { - printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, - printtri.orient); - } - org(*t, printpoint); - if (printpoint == (point) NULL) - printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3); - else - printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", - (t->orient + 1) % 3 + 3, (unsigned long) printpoint, - printpoint[0], printpoint[1]); - dest(*t, printpoint); - if (printpoint == (point) NULL) - printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3); - else - printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", - (t->orient + 2) % 3 + 3, (unsigned long) printpoint, - printpoint[0], printpoint[1]); - apex(*t, printpoint); - if (printpoint == (point) NULL) - printf(" Apex [%d] = NULL\n", t->orient + 3); - else - printf(" Apex [%d] = x%lx (%.12g, %.12g)\n", - t->orient + 3, (unsigned long) printpoint, - printpoint[0], printpoint[1]); - if (useshelles) { - sdecode(t->tri[6], printsh); - if (printsh.sh != dummysh) { - printf(" [6] = x%lx %d\n", (unsigned long) printsh.sh, - printsh.shorient); - } - sdecode(t->tri[7], printsh); - if (printsh.sh != dummysh) { - printf(" [7] = x%lx %d\n", (unsigned long) printsh.sh, - printsh.shorient); - } - sdecode(t->tri[8], printsh); - if (printsh.sh != dummysh) { - printf(" [8] = x%lx %d\n", (unsigned long) printsh.sh, - printsh.shorient); - } - } - if (vararea) { - printf(" Area constraint: %.4g\n", areabound(*t)); - } -} - -/*****************************************************************************/ -/* */ -/* printshelle() Print out the details of a shell edge handle. */ -/* */ -/* I originally wrote this procedure to simplify debugging; it can be */ -/* called directly from the debugger, and presents information about a */ -/* shell edge handle in digestible form. It's also used when the highest */ -/* level of verbosity (`-VVV') is specified. */ -/* */ -/*****************************************************************************/ - -void printshelle(s) -struct edge *s; -{ - struct edge printsh; - struct triedge printtri; - point printpoint; - - printf("shell edge x%lx with orientation %d and mark %d:\n", - (unsigned long) s->sh, s->shorient, mark(*s)); - sdecode(s->sh[0], printsh); - if (printsh.sh == dummysh) { - printf(" [0] = No shell\n"); - } else { - printf(" [0] = x%lx %d\n", (unsigned long) printsh.sh, - printsh.shorient); - } - sdecode(s->sh[1], printsh); - if (printsh.sh == dummysh) { - printf(" [1] = No shell\n"); - } else { - printf(" [1] = x%lx %d\n", (unsigned long) printsh.sh, - printsh.shorient); - } - sorg(*s, printpoint); - if (printpoint == (point) NULL) - printf(" Origin[%d] = NULL\n", 2 + s->shorient); - else - printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", - 2 + s->shorient, (unsigned long) printpoint, - printpoint[0], printpoint[1]); - sdest(*s, printpoint); - if (printpoint == (point) NULL) - printf(" Dest [%d] = NULL\n", 3 - s->shorient); - else - printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", - 3 - s->shorient, (unsigned long) printpoint, - printpoint[0], printpoint[1]); - decode(s->sh[4], printtri); - if (printtri.tri == dummytri) { - printf(" [4] = Outer space\n"); - } else { - printf(" [4] = x%lx %d\n", (unsigned long) printtri.tri, - printtri.orient); - } - decode(s->sh[5], printtri); - if (printtri.tri == dummytri) { - printf(" [5] = Outer space\n"); - } else { - printf(" [5] = x%lx %d\n", (unsigned long) printtri.tri, - printtri.orient); - } -} - -/** **/ -/** **/ -/********* Debugging routines end here *********/ - -/********* Memory management routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* poolinit() Initialize a pool of memory for allocation of items. */ -/* */ -/* This routine initializes the machinery for allocating items. A `pool' */ -/* is created whose records have size at least `bytecount'. Items will be */ -/* allocated in `itemcount'-item blocks. Each item is assumed to be a */ -/* collection of words, and either pointers or floating-point values are */ -/* assumed to be the "primary" word type. (The "primary" word type is used */ -/* to determine alignment of items.) If `alignment' isn't zero, all items */ -/* will be `alignment'-byte aligned in memory. `alignment' must be either */ -/* a multiple or a factor of the primary word size; powers of two are safe. */ -/* `alignment' is normally used to create a few unused bits at the bottom */ -/* of each item's pointer, in which information may be stored. */ -/* */ -/* Don't change this routine unless you understand it. */ -/* */ -/*****************************************************************************/ - -void poolinit(pool, bytecount, itemcount, wtype, alignment) -struct memorypool *pool; -int bytecount; -int itemcount; -enum wordtype wtype; -int alignment; -{ - int wordsize; - - /* Initialize values in the pool. */ - pool->itemwordtype = wtype; - wordsize = (pool->itemwordtype == POINTER) ? sizeof(VOID *) : sizeof(REAL); - /* Find the proper alignment, which must be at least as large as: */ - /* - The parameter `alignment'. */ - /* - The primary word type, to avoid unaligned accesses. */ - /* - sizeof(VOID *), so the stack of dead items can be maintained */ - /* without unaligned accesses. */ - if (alignment > wordsize) { - pool->alignbytes = alignment; - } else { - pool->alignbytes = wordsize; - } - if (sizeof(VOID *) > pool->alignbytes) { - pool->alignbytes = sizeof(VOID *); - } - pool->itemwords = ((bytecount + pool->alignbytes - 1) / pool->alignbytes) - * (pool->alignbytes / wordsize); - pool->itembytes = pool->itemwords * wordsize; - pool->itemsperblock = itemcount; - - /* Allocate a block of items. Space for `itemsperblock' items and one */ - /* pointer (to point to the next block) are allocated, as well as space */ - /* to ensure alignment of the items. */ - pool->firstblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes - + sizeof(VOID *) + pool->alignbytes); - if (pool->firstblock == (VOID **) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - /* Set the next block pointer to NULL. */ - *(pool->firstblock) = (VOID *) NULL; - poolrestart(pool); -} - -/*****************************************************************************/ -/* */ -/* poolrestart() Deallocate all items in a pool. */ -/* */ -/* The pool is returned to its starting state, except that no memory is */ -/* freed to the operating system. Rather, the previously allocated blocks */ -/* are ready to be reused. */ -/* */ -/*****************************************************************************/ - -void poolrestart(pool) -struct memorypool *pool; -{ - unsigned long alignptr; - - pool->items = 0; - pool->maxitems = 0; - - /* Set the currently active block. */ - pool->nowblock = pool->firstblock; - /* Find the first item in the pool. Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->nowblock + 1); - /* Align the item on an `alignbytes'-byte boundary. */ - pool->nextitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); - /* There are lots of unallocated items left in this block. */ - pool->unallocateditems = pool->itemsperblock; - /* The stack of deallocated items is empty. */ - pool->deaditemstack = (VOID *) NULL; -} - -/*****************************************************************************/ -/* */ -/* pooldeinit() Free to the operating system all memory taken by a pool. */ -/* */ -/*****************************************************************************/ - -void pooldeinit(pool) -struct memorypool *pool; -{ - while (pool->firstblock != (VOID **) NULL) { - pool->nowblock = (VOID **) *(pool->firstblock); - free(pool->firstblock); - pool->firstblock = pool->nowblock; - } -} - -/*****************************************************************************/ -/* */ -/* poolalloc() Allocate space for an item. */ -/* */ -/*****************************************************************************/ - -VOID *poolalloc(pool) -struct memorypool *pool; -{ - VOID *newitem; - VOID **newblock; - unsigned long alignptr; - - /* First check the linked list of dead items. If the list is not */ - /* empty, allocate an item from the list rather than a fresh one. */ - if (pool->deaditemstack != (VOID *) NULL) { - newitem = pool->deaditemstack; /* Take first item in list. */ - pool->deaditemstack = * (VOID **) pool->deaditemstack; - } else { - /* Check if there are any free items left in the current block. */ - if (pool->unallocateditems == 0) { - /* Check if another block must be allocated. */ - if (*(pool->nowblock) == (VOID *) NULL) { - /* Allocate a new block of items, pointed to by the previous block. */ - newblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes - + sizeof(VOID *) + pool->alignbytes); - if (newblock == (VOID **) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - *(pool->nowblock) = (VOID *) newblock; - /* The next block pointer is NULL. */ - *newblock = (VOID *) NULL; - } - /* Move to the new block. */ - pool->nowblock = (VOID **) *(pool->nowblock); - /* Find the first item in the block. */ - /* Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->nowblock + 1); - /* Align the item on an `alignbytes'-byte boundary. */ - pool->nextitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); - /* There are lots of unallocated items left in this block. */ - pool->unallocateditems = pool->itemsperblock; - } - /* Allocate a new item. */ - newitem = pool->nextitem; - /* Advance `nextitem' pointer to next free item in block. */ - if (pool->itemwordtype == POINTER) { - pool->nextitem = (VOID *) ((VOID **) pool->nextitem + pool->itemwords); - } else { - pool->nextitem = (VOID *) ((REAL *) pool->nextitem + pool->itemwords); - } - pool->unallocateditems--; - pool->maxitems++; - } - pool->items++; - return newitem; -} - -/*****************************************************************************/ -/* */ -/* pooldealloc() Deallocate space for an item. */ -/* */ -/* The deallocated space is stored in a queue for later reuse. */ -/* */ -/*****************************************************************************/ - -void pooldealloc(pool, dyingitem) -struct memorypool *pool; -VOID *dyingitem; -{ - /* Push freshly killed item onto stack. */ - *((VOID **) dyingitem) = pool->deaditemstack; - pool->deaditemstack = dyingitem; - pool->items--; -} - -/*****************************************************************************/ -/* */ -/* traversalinit() Prepare to traverse the entire list of items. */ -/* */ -/* This routine is used in conjunction with traverse(). */ -/* */ -/*****************************************************************************/ - -void traversalinit(pool) -struct memorypool *pool; -{ - unsigned long alignptr; - - /* Begin the traversal in the first block. */ - pool->pathblock = pool->firstblock; - /* Find the first item in the block. Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->pathblock + 1); - /* Align with item on an `alignbytes'-byte boundary. */ - pool->pathitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); - /* Set the number of items left in the current block. */ - pool->pathitemsleft = pool->itemsperblock; -} - -/*****************************************************************************/ -/* */ -/* traverse() Find the next item in the list. */ -/* */ -/* This routine is used in conjunction with traversalinit(). Be forewarned */ -/* that this routine successively returns all items in the list, including */ -/* deallocated ones on the deaditemqueue. It's up to you to figure out */ -/* which ones are actually dead. Why? I don't want to allocate extra */ -/* space just to demarcate dead items. It can usually be done more */ -/* space-efficiently by a routine that knows something about the structure */ -/* of the item. */ -/* */ -/*****************************************************************************/ - -VOID *traverse(pool) -struct memorypool *pool; -{ - VOID *newitem; - unsigned long alignptr; - - /* Stop upon exhausting the list of items. */ - if (pool->pathitem == pool->nextitem) { - return (VOID *) NULL; - } - /* Check whether any untraversed items remain in the current block. */ - if (pool->pathitemsleft == 0) { - /* Find the next block. */ - pool->pathblock = (VOID **) *(pool->pathblock); - /* Find the first item in the block. Increment by the size of (VOID *). */ - alignptr = (unsigned long) (pool->pathblock + 1); - /* Align with item on an `alignbytes'-byte boundary. */ - pool->pathitem = (VOID *) - (alignptr + (unsigned long) pool->alignbytes - - (alignptr % (unsigned long) pool->alignbytes)); - /* Set the number of items left in the current block. */ - pool->pathitemsleft = pool->itemsperblock; - } - newitem = pool->pathitem; - /* Find the next item in the block. */ - if (pool->itemwordtype == POINTER) { - pool->pathitem = (VOID *) ((VOID **) pool->pathitem + pool->itemwords); - } else { - pool->pathitem = (VOID *) ((REAL *) pool->pathitem + pool->itemwords); - } - pool->pathitemsleft--; - return newitem; -} - -/*****************************************************************************/ -/* */ -/* dummyinit() Initialize the triangle that fills "outer space" and the */ -/* omnipresent shell edge. */ -/* */ -/* The triangle that fills "outer space", called `dummytri', is pointed to */ -/* by every triangle and shell edge on a boundary (be it outer or inner) of */ -/* the triangulation. Also, `dummytri' points to one of the triangles on */ -/* the convex hull (until the holes and concavities are carved), making it */ -/* possible to find a starting triangle for point location. */ -/* */ -/* The omnipresent shell edge, `dummysh', is pointed to by every triangle */ -/* or shell edge that doesn't have a full complement of real shell edges */ -/* to point to. */ -/* */ -/*****************************************************************************/ - -void dummyinit(trianglewords, shellewords) -int trianglewords; -int shellewords; -{ - unsigned long alignptr; - - /* `triwords' and `shwords' are used by the mesh manipulation primitives */ - /* to extract orientations of triangles and shell edges from pointers. */ - triwords = trianglewords; /* Initialize `triwords' once and for all. */ - shwords = shellewords; /* Initialize `shwords' once and for all. */ - - /* Set up `dummytri', the `triangle' that occupies "outer space". */ - dummytribase = (triangle *) malloc(triwords * sizeof(triangle) - + triangles.alignbytes); - if (dummytribase == (triangle *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */ - alignptr = (unsigned long) dummytribase; - dummytri = (triangle *) - (alignptr + (unsigned long) triangles.alignbytes - - (alignptr % (unsigned long) triangles.alignbytes)); - /* Initialize the three adjoining triangles to be "outer space". These */ - /* will eventually be changed by various bonding operations, but their */ - /* values don't really matter, as long as they can legally be */ - /* dereferenced. */ - dummytri[0] = (triangle) dummytri; - dummytri[1] = (triangle) dummytri; - dummytri[2] = (triangle) dummytri; - /* Three NULL vertex points. */ - dummytri[3] = (triangle) NULL; - dummytri[4] = (triangle) NULL; - dummytri[5] = (triangle) NULL; - - if (useshelles) { - /* Set up `dummysh', the omnipresent "shell edge" pointed to by any */ - /* triangle side or shell edge end that isn't attached to a real shell */ - /* edge. */ - dummyshbase = (shelle *) malloc(shwords * sizeof(shelle) - + shelles.alignbytes); - if (dummyshbase == (shelle *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - /* Align `dummysh' on a `shelles.alignbytes'-byte boundary. */ - alignptr = (unsigned long) dummyshbase; - dummysh = (shelle *) - (alignptr + (unsigned long) shelles.alignbytes - - (alignptr % (unsigned long) shelles.alignbytes)); - /* Initialize the two adjoining shell edges to be the omnipresent shell */ - /* edge. These will eventually be changed by various bonding */ - /* operations, but their values don't really matter, as long as they */ - /* can legally be dereferenced. */ - dummysh[0] = (shelle) dummysh; - dummysh[1] = (shelle) dummysh; - /* Two NULL vertex points. */ - dummysh[2] = (shelle) NULL; - dummysh[3] = (shelle) NULL; - /* Initialize the two adjoining triangles to be "outer space". */ - dummysh[4] = (shelle) dummytri; - dummysh[5] = (shelle) dummytri; - /* Set the boundary marker to zero. */ - * (int *) (dummysh + 6) = 0; - - /* Initialize the three adjoining shell edges of `dummytri' to be */ - /* the omnipresent shell edge. */ - dummytri[6] = (triangle) dummysh; - dummytri[7] = (triangle) dummysh; - dummytri[8] = (triangle) dummysh; - } -} - -/*****************************************************************************/ -/* */ -/* initializepointpool() Calculate the size of the point data structure */ -/* and initialize its memory pool. */ -/* */ -/* This routine also computes the `pointmarkindex' and `point2triindex' */ -/* indices used to find values within each point. */ -/* */ -/*****************************************************************************/ - -void initializepointpool() -{ - int pointsize; - - /* The index within each point at which the boundary marker is found. */ - /* Ensure the point marker is aligned to a sizeof(int)-byte address. */ - pointmarkindex = ((mesh_dim + nextras) * sizeof(REAL) + sizeof(int) - 1) - / sizeof(int); - pointsize = (pointmarkindex + 1) * sizeof(int); - if (poly) { - /* The index within each point at which a triangle pointer is found. */ - /* Ensure the pointer is aligned to a sizeof(triangle)-byte address. */ - point2triindex = (pointsize + sizeof(triangle) - 1) / sizeof(triangle); - pointsize = (point2triindex + 1) * sizeof(triangle); - } - /* Initialize the pool of points. */ - poolinit(&points, pointsize, POINTPERBLOCK, - (sizeof(REAL) >= sizeof(triangle)) ? FLOATINGPOINT : POINTER, 0); -} - -/*****************************************************************************/ -/* */ -/* initializetrisegpools() Calculate the sizes of the triangle and shell */ -/* edge data structures and initialize their */ -/* memory pools. */ -/* */ -/* This routine also computes the `highorderindex', `elemattribindex', and */ -/* `areaboundindex' indices used to find values within each triangle. */ -/* */ -/*****************************************************************************/ - -void initializetrisegpools() -{ - int trisize; - - /* The index within each triangle at which the extra nodes (above three) */ - /* associated with high order elements are found. There are three */ - /* pointers to other triangles, three pointers to corners, and possibly */ - /* three pointers to shell edges before the extra nodes. */ - highorderindex = 6 + (useshelles * 3); - /* The number of bytes occupied by a triangle. */ - trisize = ((order + 1) * (order + 2) / 2 + (highorderindex - 3)) * - sizeof(triangle); - /* The index within each triangle at which its attributes are found, */ - /* where the index is measured in REALs. */ - elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL); - /* The index within each triangle at which the maximum area constraint */ - /* is found, where the index is measured in REALs. Note that if the */ - /* `regionattrib' flag is set, an additional attribute will be added. */ - areaboundindex = elemattribindex + eextras + regionattrib; - /* If triangle attributes or an area bound are needed, increase the number */ - /* of bytes occupied by a triangle. */ - if (vararea) { - trisize = (areaboundindex + 1) * sizeof(REAL); - } else if (eextras + regionattrib > 0) { - trisize = areaboundindex * sizeof(REAL); - } - /* If a Voronoi diagram or triangle neighbor graph is requested, make */ - /* sure there's room to store an integer index in each triangle. This */ - /* integer index can occupy the same space as the shell edges or */ - /* attributes or area constraint or extra nodes. */ - if ((voronoi || neighbors) && - (trisize < 6 * sizeof(triangle) + sizeof(int))) { - trisize = 6 * sizeof(triangle) + sizeof(int); - } - /* Having determined the memory size of a triangle, initialize the pool. */ - poolinit(&triangles, trisize, TRIPERBLOCK, POINTER, 4); - - if (useshelles) { - /* Initialize the pool of shell edges. */ - poolinit(&shelles, 6 * sizeof(triangle) + sizeof(int), SHELLEPERBLOCK, - POINTER, 4); - - /* Initialize the "outer space" triangle and omnipresent shell edge. */ - dummyinit(triangles.itemwords, shelles.itemwords); - } else { - /* Initialize the "outer space" triangle. */ - dummyinit(triangles.itemwords, 0); - } -} - -/*****************************************************************************/ -/* */ -/* triangledealloc() Deallocate space for a triangle, marking it dead. */ -/* */ -/*****************************************************************************/ - -void triangledealloc(dyingtriangle) -triangle *dyingtriangle; -{ - /* Set triangle's vertices to NULL. This makes it possible to */ - /* detect dead triangles when traversing the list of all triangles. */ - dyingtriangle[3] = (triangle) NULL; - dyingtriangle[4] = (triangle) NULL; - dyingtriangle[5] = (triangle) NULL; - pooldealloc(&triangles, (VOID *) dyingtriangle); -} - -/*****************************************************************************/ -/* */ -/* triangletraverse() Traverse the triangles, skipping dead ones. */ -/* */ -/*****************************************************************************/ - -triangle *triangletraverse() -{ - triangle *newtriangle; - - do { - newtriangle = (triangle *) traverse(&triangles); - if (newtriangle == (triangle *) NULL) { - return (triangle *) NULL; - } - } while (newtriangle[3] == (triangle) NULL); /* Skip dead ones. */ - return newtriangle; -} - -/*****************************************************************************/ -/* */ -/* shelledealloc() Deallocate space for a shell edge, marking it dead. */ -/* */ -/*****************************************************************************/ - -void shelledealloc(dyingshelle) -shelle *dyingshelle; -{ - /* Set shell edge's vertices to NULL. This makes it possible to */ - /* detect dead shells when traversing the list of all shells. */ - dyingshelle[2] = (shelle) NULL; - dyingshelle[3] = (shelle) NULL; - pooldealloc(&shelles, (VOID *) dyingshelle); -} - -/*****************************************************************************/ -/* */ -/* shelletraverse() Traverse the shell edges, skipping dead ones. */ -/* */ -/*****************************************************************************/ - -shelle *shelletraverse() -{ - shelle *newshelle; - - do { - newshelle = (shelle *) traverse(&shelles); - if (newshelle == (shelle *) NULL) { - return (shelle *) NULL; - } - } while (newshelle[2] == (shelle) NULL); /* Skip dead ones. */ - return newshelle; -} - -/*****************************************************************************/ -/* */ -/* pointdealloc() Deallocate space for a point, marking it dead. */ -/* */ -/*****************************************************************************/ - -void pointdealloc(dyingpoint) -point dyingpoint; -{ - /* Mark the point as dead. This makes it possible to detect dead points */ - /* when traversing the list of all points. */ - setpointmark(dyingpoint, DEADPOINT); - pooldealloc(&points, (VOID *) dyingpoint); -} - -/*****************************************************************************/ -/* */ -/* pointtraverse() Traverse the points, skipping dead ones. */ -/* */ -/*****************************************************************************/ - -point pointtraverse() -{ - point newpoint; - - do { - newpoint = (point) traverse(&points); - if (newpoint == (point) NULL) { - return (point) NULL; - } - } while (pointmark(newpoint) == DEADPOINT); /* Skip dead ones. */ - return newpoint; -} - -/*****************************************************************************/ -/* */ -/* badsegmentdealloc() Deallocate space for a bad segment, marking it */ -/* dead. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void badsegmentdealloc(dyingseg) -struct edge *dyingseg; -{ - /* Set segment's orientation to -1. This makes it possible to */ - /* detect dead segments when traversing the list of all segments. */ - dyingseg->shorient = -1; - pooldealloc(&badsegments, (VOID *) dyingseg); -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* badsegmenttraverse() Traverse the bad segments, skipping dead ones. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -struct edge *badsegmenttraverse() -{ - struct edge *newseg; - - do { - newseg = (struct edge *) traverse(&badsegments); - if (newseg == (struct edge *) NULL) { - return (struct edge *) NULL; - } - } while (newseg->shorient == -1); /* Skip dead ones. */ - return newseg; -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* getpoint() Get a specific point, by number, from the list. */ -/* */ -/* The first point is number 'firstnumber'. */ -/* */ -/* Note that this takes O(n) time (with a small constant, if POINTPERBLOCK */ -/* is large). I don't care to take the trouble to make it work in constant */ -/* time. */ -/* */ -/*****************************************************************************/ - -point getpoint(number) -int number; -{ - VOID **getblock; - point foundpoint; - unsigned long alignptr; - int current; - - getblock = points.firstblock; - current = firstnumber; - /* Find the right block. */ - while (current + points.itemsperblock <= number) { - getblock = (VOID **) *getblock; - current += points.itemsperblock; - } - /* Now find the right point. */ - alignptr = (unsigned long) (getblock + 1); - foundpoint = (point) (alignptr + (unsigned long) points.alignbytes - - (alignptr % (unsigned long) points.alignbytes)); - while (current < number) { - foundpoint += points.itemwords; - current++; - } - return foundpoint; -} - -/*****************************************************************************/ -/* */ -/* triangledeinit() Free all remaining allocated memory. */ -/* */ -/*****************************************************************************/ - -void triangledeinit() -{ - pooldeinit(&triangles); - free(dummytribase); - if (useshelles) { - pooldeinit(&shelles); - free(dummyshbase); - } - pooldeinit(&points); -#ifndef CDT_ONLY - if (quality) { - pooldeinit(&badsegments); - if ((minangle > 0.0) || vararea || fixedarea) { - pooldeinit(&badtriangles); - } - } -#endif /* not CDT_ONLY */ -} - -/** **/ -/** **/ -/********* Memory management routines end here *********/ - -/********* Constructors begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* maketriangle() Create a new triangle with orientation zero. */ -/* */ -/*****************************************************************************/ - -void maketriangle(newtriedge) -struct triedge *newtriedge; -{ - int i; - - newtriedge->tri = (triangle *) poolalloc(&triangles); - /* Initialize the three adjoining triangles to be "outer space". */ - newtriedge->tri[0] = (triangle) dummytri; - newtriedge->tri[1] = (triangle) dummytri; - newtriedge->tri[2] = (triangle) dummytri; - /* Three NULL vertex points. */ - newtriedge->tri[3] = (triangle) NULL; - newtriedge->tri[4] = (triangle) NULL; - newtriedge->tri[5] = (triangle) NULL; - /* Initialize the three adjoining shell edges to be the omnipresent */ - /* shell edge. */ - if (useshelles) { - newtriedge->tri[6] = (triangle) dummysh; - newtriedge->tri[7] = (triangle) dummysh; - newtriedge->tri[8] = (triangle) dummysh; - } - for (i = 0; i < eextras; i++) { - setelemattribute(*newtriedge, i, 0.0); - } - if (vararea) { - setareabound(*newtriedge, -1.0); - } - - newtriedge->orient = 0; -} - -/*****************************************************************************/ -/* */ -/* makeshelle() Create a new shell edge with orientation zero. */ -/* */ -/*****************************************************************************/ - -void makeshelle(newedge) -struct edge *newedge; -{ - newedge->sh = (shelle *) poolalloc(&shelles); - /* Initialize the two adjoining shell edges to be the omnipresent */ - /* shell edge. */ - newedge->sh[0] = (shelle) dummysh; - newedge->sh[1] = (shelle) dummysh; - /* Two NULL vertex points. */ - newedge->sh[2] = (shelle) NULL; - newedge->sh[3] = (shelle) NULL; - /* Initialize the two adjoining triangles to be "outer space". */ - newedge->sh[4] = (shelle) dummytri; - newedge->sh[5] = (shelle) dummytri; - /* Set the boundary marker to zero. */ - setmark(*newedge, 0); - - newedge->shorient = 0; -} - -/** **/ -/** **/ -/********* Constructors end here *********/ - -/********* Determinant evaluation routines begin here *********/ -/** **/ -/** **/ - -/* The adaptive exact arithmetic geometric predicates implemented herein are */ -/* described in detail in my Technical Report CMU-CS-96-140. The complete */ -/* reference is given in the header. */ - -/* Which of the following two methods of finding the absolute values is */ -/* fastest is compiler-dependent. A few compilers can inline and optimize */ -/* the fabs() call; but most will incur the overhead of a function call, */ -/* which is disastrously slow. A faster way on IEEE machines might be to */ -/* mask the appropriate bit, but that's difficult to do in C. */ - -#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) -/* #define Absolute(a) fabs(a) */ - -/* Many of the operations are broken up into two pieces, a main part that */ -/* performs an approximate operation, and a "tail" that computes the */ -/* roundoff error of that operation. */ -/* */ -/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ -/* Split(), and Two_Product() are all implemented as described in the */ -/* reference. Each of these macros requires certain variables to be */ -/* defined in the calling routine. The variables `bvirt', `c', `abig', */ -/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ -/* they store the result of an operation that may incur roundoff error. */ -/* The input parameter `x' (or the highest numbered `x_' parameter) must */ -/* also be declared `INEXACT'. */ - -#define Fast_Two_Sum_Tail(a, b, x, y) \ - bvirt = x - a; \ - y = b - bvirt - -#define Fast_Two_Sum(a, b, x, y) \ - x = (REAL) (a + b); \ - Fast_Two_Sum_Tail(a, b, x, y) - -#define Two_Sum_Tail(a, b, x, y) \ - bvirt = (REAL) (x - a); \ - avirt = x - bvirt; \ - bround = b - bvirt; \ - around = a - avirt; \ - y = around + bround - -#define Two_Sum(a, b, x, y) \ - x = (REAL) (a + b); \ - Two_Sum_Tail(a, b, x, y) - -#define Two_Diff_Tail(a, b, x, y) \ - bvirt = (REAL) (a - x); \ - avirt = x + bvirt; \ - bround = bvirt - b; \ - around = a - avirt; \ - y = around + bround - -#define Two_Diff(a, b, x, y) \ - x = (REAL) (a - b); \ - Two_Diff_Tail(a, b, x, y) - -#define Split(a, ahi, alo) \ - c = (REAL) (splitter * a); \ - abig = (REAL) (c - a); \ - ahi = (REAL)(c - abig); \ - alo = (REAL)(a - ahi) - -#define Two_Product_Tail(a, b, x, y) \ - Split(a, ahi, alo); \ - Split(b, bhi, blo); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -#define Two_Product(a, b, x, y) \ - x = (REAL) (a * b); \ - Two_Product_Tail(a, b, x, y) - -/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ -/* already been split. Avoids redundant splitting. */ - -#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ - x = (REAL) (a * b); \ - Split(a, ahi, alo); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -/* Square() can be done more quickly than Two_Product(). */ - -#define Square_Tail(a, x, y) \ - Split(a, ahi, alo); \ - err1 = x - (ahi * ahi); \ - err3 = err1 - ((ahi + ahi) * alo); \ - y = (alo * alo) - err3 - -#define Square(a, x, y) \ - x = (REAL) (a * a); \ - Square_Tail(a, x, y) - -/* Macros for summing expansions of various fixed lengths. These are all */ -/* unrolled versions of Expansion_Sum(). */ - -#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ - Two_Sum(a0, b , _i, x0); \ - Two_Sum(a1, _i, x2, x1) - -#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ - Two_Diff(a0, b , _i, x0); \ - Two_Sum( a1, _i, x2, x1) - -#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ - Two_One_Sum(a1, a0, b0, _j, _0, x0); \ - Two_One_Sum(_j, _0, b1, x3, x2, x1) - -#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ - Two_One_Diff(a1, a0, b0, _j, _0, x0); \ - Two_One_Diff(_j, _0, b1, x3, x2, x1) - -/*****************************************************************************/ -/* */ -/* exactinit() Initialize the variables used for exact arithmetic. */ -/* */ -/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ -/* floating-point arithmetic. `epsilon' bounds the relative roundoff */ -/* error. It is used for floating-point error analysis. */ -/* */ -/* `splitter' is used to split floating-point numbers into two half- */ -/* length significands for exact multiplication. */ -/* */ -/* I imagine that a highly optimizing compiler might be too smart for its */ -/* own good, and somehow cause this routine to fail, if it pretends that */ -/* floating-point arithmetic is too much like real arithmetic. */ -/* */ -/* Don't change this routine unless you fully understand it. */ -/* */ -/*****************************************************************************/ - -void exactinit() -{ - REAL half; - REAL check, lastcheck; - int every_other; - - every_other = 1; - half = 0.5; - epsilon = 1.0; - splitter = 1.0; - check = 1.0; - /* Repeatedly divide `epsilon' by two until it is too small to add to */ - /* one without causing roundoff. (Also check if the sum is equal to */ - /* the previous sum, for machines that round up instead of using exact */ - /* rounding. Not that these routines will work on such machines anyway. */ - do { - lastcheck = check; - epsilon *= half; - if (every_other) { - splitter *= 2.0; - } - every_other = !every_other; - check = (REAL)(1.0 + epsilon); - } while ((check != 1.0) && (check != lastcheck)); - splitter += 1.0; - if (verbose > 1) { - printf("Floating point roundoff is of magnitude %.17g\n", epsilon); - printf("Floating point splitter is %.17g\n", splitter); - } - /* Error bounds for orientation and incircle tests. */ - resulterrbound = (REAL)((3.0 + 8.0 * epsilon) * epsilon); - ccwerrboundA = (REAL)((3.0 + 16.0 * epsilon) * epsilon); - ccwerrboundB = (REAL)((2.0 + 12.0 * epsilon) * epsilon); - ccwerrboundC = (REAL)((9.0 + 64.0 * epsilon) * epsilon * epsilon); - iccerrboundA = (REAL)((10.0 + 96.0 * epsilon) * epsilon); - iccerrboundB = (REAL)((4.0 + 48.0 * epsilon) * epsilon); - iccerrboundC = (REAL)((44.0 + 576.0 * epsilon) * epsilon * epsilon); -} - -/*****************************************************************************/ -/* */ -/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ -/* components from the output expansion. */ -/* */ -/* Sets h = e + f. See my Robust Predicates paper for details. */ -/* */ -/* If round-to-even is used (as with IEEE 754), maintains the strongly */ -/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ -/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ -/* properties. */ -/* */ -/*****************************************************************************/ - -int fast_expansion_sum_zeroelim(elen, e, flen, f, h) /* h cannot be e or f. */ -int elen; -REAL *e; -int flen; -REAL *f; -REAL *h; -{ - REAL Q; - INEXACT REAL Qnew; - INEXACT REAL hh; - INEXACT REAL bvirt; - REAL avirt, bround, around; - int eindex, findex, hindex; - REAL enow, fnow; - - enow = e[0]; - fnow = f[0]; - eindex = findex = 0; - if ((fnow > enow) == (fnow > -enow)) { - Q = enow; - enow = e[++eindex]; - } else { - Q = fnow; - fnow = f[++findex]; - } - hindex = 0; - if ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Fast_Two_Sum(enow, Q, Qnew, hh); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, Q, Qnew, hh); - fnow = f[++findex]; - } - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - while ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Two_Sum(Q, enow, Qnew, hh); - enow = e[++eindex]; - } else { - Two_Sum(Q, fnow, Qnew, hh); - fnow = f[++findex]; - } - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - } - while (eindex < elen) { - Two_Sum(Q, enow, Qnew, hh); - enow = e[++eindex]; - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - while (findex < flen) { - Two_Sum(Q, fnow, Qnew, hh); - fnow = f[++findex]; - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ -/* eliminating zero components from the */ -/* output expansion. */ -/* */ -/* Sets h = be. See my Robust Predicates paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -int scale_expansion_zeroelim(elen, e, b, h) /* e and h cannot be the same. */ -int elen; -REAL *e; -REAL b; -REAL *h; -{ - INEXACT REAL Q, sum; - REAL hh; - INEXACT REAL product1; - REAL product0; - int eindex, hindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - - Split(b, bhi, blo); - Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); - hindex = 0; - if (hh != 0) { - h[hindex++] = hh; - } - for (eindex = 1; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Product_Presplit(enow, b, bhi, blo, product1, product0); - Two_Sum(Q, product0, sum, hh); - if (hh != 0) { - h[hindex++] = hh; - } - Fast_Two_Sum(product1, sum, Q, hh); - if (hh != 0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* estimate() Produce a one-word estimate of an expansion's value. */ -/* */ -/* See my Robust Predicates paper for details. */ -/* */ -/*****************************************************************************/ - -REAL estimate(elen, e) -int elen; -REAL *e; -{ - REAL Q; - int eindex; - - Q = e[0]; - for (eindex = 1; eindex < elen; eindex++) { - Q += e[eindex]; - } - return Q; -} - -/*****************************************************************************/ -/* */ -/* counterclockwise() Return a positive value if the points pa, pb, and */ -/* pc occur in counterclockwise order; a negative */ -/* value if they occur in clockwise order; and zero */ -/* if they are collinear. The result is also a rough */ -/* approximation of twice the signed area of the */ -/* triangle defined by the three points. */ -/* */ -/* Uses exact arithmetic if necessary to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. This determinant is */ -/* computed adaptively, in the sense that exact arithmetic is used only to */ -/* the degree it is needed to ensure that the returned value has the */ -/* correct sign. Hence, this function is usually quite fast, but will run */ -/* more slowly when the input points are collinear or nearly so. */ -/* */ -/* See my Robust Predicates paper for details. */ -/* */ -/*****************************************************************************/ - -REAL counterclockwiseadapt(pa, pb, pc, detsum) -point pa; -point pb; -point pc; -REAL detsum; -{ - INEXACT REAL acx, acy, bcx, bcy; - REAL acxtail, acytail, bcxtail, bcytail; - INEXACT REAL detleft, detright; - REAL detlefttail, detrighttail; - REAL det, errbound; - REAL B[4], C1[8], C2[12], D[16]; - INEXACT REAL B3; - int C1length, C2length, Dlength; - REAL u[4]; - INEXACT REAL u3; - INEXACT REAL s1, t1; - REAL s0, t0; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - acx = (REAL) (pa[0] - pc[0]); - bcx = (REAL) (pb[0] - pc[0]); - acy = (REAL) (pa[1] - pc[1]); - bcy = (REAL) (pb[1] - pc[1]); - - Two_Product(acx, bcy, detleft, detlefttail); - Two_Product(acy, bcx, detright, detrighttail); - - Two_Two_Diff(detleft, detlefttail, detright, detrighttail, - B3, B[2], B[1], B[0]); - B[3] = B3; - - det = estimate(4, B); - errbound = (REAL)(ccwerrboundB * detsum); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pc[0], acx, acxtail); - Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); - Two_Diff_Tail(pa[1], pc[1], acy, acytail); - Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); - - if ((acxtail == 0.0) && (acytail == 0.0) - && (bcxtail == 0.0) && (bcytail == 0.0)) { - return det; - } - - errbound = (REAL)(ccwerrboundC * detsum + resulterrbound * Absolute(det)); - det += (acx * bcytail + bcy * acxtail) - - (acy * bcxtail + bcx * acytail); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Product(acxtail, bcy, s1, s0); - Two_Product(acytail, bcx, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); - - Two_Product(acx, bcytail, s1, s0); - Two_Product(acy, bcxtail, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); - - Two_Product(acxtail, bcytail, s1, s0); - Two_Product(acytail, bcxtail, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); - - return(D[Dlength - 1]); -} - -REAL counterclockwise(pa, pb, pc) -point pa; -point pb; -point pc; -{ - REAL detleft, detright, det; - REAL detsum, errbound; - - counterclockcount++; - - detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); - detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); - det = detleft - detright; - - if (noexact) { - return det; - } - - if (detleft > 0.0) { - if (detright <= 0.0) { - return det; - } else { - detsum = detleft + detright; - } - } else if (detleft < 0.0) { - if (detright >= 0.0) { - return det; - } else { - detsum = -detleft - detright; - } - } else { - return det; - } - - errbound = ccwerrboundA * detsum; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - return counterclockwiseadapt(pa, pb, pc, detsum); -} - -/*****************************************************************************/ -/* */ -/* incircle() Return a positive value if the point pd lies inside the */ -/* circle passing through pa, pb, and pc; a negative value if */ -/* it lies outside; and zero if the four points are cocircular.*/ -/* The points pa, pb, and pc must be in counterclockwise */ -/* order, or the sign of the result will be reversed. */ -/* */ -/* Uses exact arithmetic if necessary to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. This determinant is */ -/* computed adaptively, in the sense that exact arithmetic is used only to */ -/* the degree it is needed to ensure that the returned value has the */ -/* correct sign. Hence, this function is usually quite fast, but will run */ -/* more slowly when the input points are cocircular or nearly so. */ -/* */ -/* See my Robust Predicates paper for details. */ -/* */ -/*****************************************************************************/ - -REAL incircleadapt(pa, pb, pc, pd, permanent) -point pa; -point pb; -point pc; -point pd; -REAL permanent; -{ - INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; - REAL det, errbound; - - INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; - REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; - REAL bc[4], ca[4], ab[4]; - INEXACT REAL bc3, ca3, ab3; - REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; - int axbclen, axxbclen, aybclen, ayybclen, alen; - REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; - int bxcalen, bxxcalen, bycalen, byycalen, blen; - REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; - int cxablen, cxxablen, cyablen, cyyablen, clen; - REAL abdet[64]; - int ablen; - REAL fin1[1152], fin2[1152]; - REAL *finnow, *finother, *finswap; - int finlength; - - REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; - INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; - REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; - REAL aa[4], bb[4], cc[4]; - INEXACT REAL aa3, bb3, cc3; - INEXACT REAL ti1, tj1; - REAL ti0, tj0; - REAL u[4], v[4]; - INEXACT REAL u3, v3; - REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; - REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; - int temp8len, temp16alen, temp16blen, temp16clen; - int temp32alen, temp32blen, temp48len, temp64len; - REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; - int axtbblen, axtcclen, aytbblen, aytcclen; - REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; - int bxtaalen, bxtcclen, bytaalen, bytcclen; - REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; - int cxtaalen, cxtbblen, cytaalen, cytbblen; - REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; - int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; - REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; - int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; - REAL axtbctt[8], aytbctt[8], bxtcatt[8]; - REAL bytcatt[8], cxtabtt[8], cytabtt[8]; - int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; - REAL abt[8], bct[8], cat[8]; - int abtlen, bctlen, catlen; - REAL abtt[4], bctt[4], catt[4]; - int abttlen, bcttlen, cattlen; - INEXACT REAL abtt3, bctt3, catt3; - REAL negate; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - adx = (REAL) (pa[0] - pd[0]); - bdx = (REAL) (pb[0] - pd[0]); - cdx = (REAL) (pc[0] - pd[0]); - ady = (REAL) (pa[1] - pd[1]); - bdy = (REAL) (pb[1] - pd[1]); - cdy = (REAL) (pc[1] - pd[1]); - - Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); - Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); - Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); - bc[3] = bc3; - axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); - axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); - aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); - ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); - alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); - - Two_Product(cdx, ady, cdxady1, cdxady0); - Two_Product(adx, cdy, adxcdy1, adxcdy0); - Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); - ca[3] = ca3; - bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); - bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); - bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); - byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); - blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); - - Two_Product(adx, bdy, adxbdy1, adxbdy0); - Two_Product(bdx, ady, bdxady1, bdxady0); - Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); - ab[3] = ab3; - cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); - cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); - cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); - cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); - clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); - - det = estimate(finlength, fin1); - errbound = (REAL)(iccerrboundB * permanent); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pd[0], adx, adxtail); - Two_Diff_Tail(pa[1], pd[1], ady, adytail); - Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); - Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); - Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); - Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); - if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) - && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { - return det; - } - - errbound = (REAL)(iccerrboundC * permanent + resulterrbound * Absolute(det)); - det += (REAL)(((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) - - (bdy * cdxtail + cdx * bdytail)) - + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) - + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) - - (cdy * adxtail + adx * cdytail)) - + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) - + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) - - (ady * bdxtail + bdx * adytail)) - + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx))); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - finnow = fin1; - finother = fin2; - - if ((bdxtail != 0.0) || (bdytail != 0.0) - || (cdxtail != 0.0) || (cdytail != 0.0)) { - Square(adx, adxadx1, adxadx0); - Square(ady, adyady1, adyady0); - Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); - aa[3] = aa3; - } - if ((cdxtail != 0.0) || (cdytail != 0.0) - || (adxtail != 0.0) || (adytail != 0.0)) { - Square(bdx, bdxbdx1, bdxbdx0); - Square(bdy, bdybdy1, bdybdy0); - Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); - bb[3] = bb3; - } - if ((adxtail != 0.0) || (adytail != 0.0) - || (bdxtail != 0.0) || (bdytail != 0.0)) { - Square(cdx, cdxcdx1, cdxcdx0); - Square(cdy, cdycdy1, cdycdy0); - Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); - cc[3] = cc3; - } - - if (adxtail != 0.0) { - axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); - temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, - temp16a); - - axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); - temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); - - axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); - temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); - temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, - temp16a); - - aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); - temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); - - aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); - temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdxtail != 0.0) { - bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); - temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, - temp16a); - - bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); - temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); - - bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); - temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); - temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, - temp16a); - - bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); - temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); - - bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); - temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdxtail != 0.0) { - cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); - temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, - temp16a); - - cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); - temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); - - cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); - temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); - temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, - temp16a); - - cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); - temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); - - cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); - temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - if ((adxtail != 0.0) || (adytail != 0.0)) { - if ((bdxtail != 0.0) || (bdytail != 0.0) - || (cdxtail != 0.0) || (cdytail != 0.0)) { - Two_Product(bdxtail, cdy, ti1, ti0); - Two_Product(bdx, cdytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -bdy; - Two_Product(cdxtail, negate, ti1, ti0); - negate = -bdytail; - Two_Product(cdx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); - - Two_Product(bdxtail, cdytail, ti1, ti0); - Two_Product(cdxtail, bdytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); - bctt[3] = bctt3; - bcttlen = 4; - } else { - bct[0] = 0.0; - bctlen = 1; - bctt[0] = 0.0; - bcttlen = 1; - } - - if (adxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); - axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); - temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (bdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, - temp32a); - axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); - temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, - temp16a); - temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); - aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); - temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, - temp32a); - aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); - temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, - temp16a); - temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if ((bdxtail != 0.0) || (bdytail != 0.0)) { - if ((cdxtail != 0.0) || (cdytail != 0.0) - || (adxtail != 0.0) || (adytail != 0.0)) { - Two_Product(cdxtail, ady, ti1, ti0); - Two_Product(cdx, adytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -cdy; - Two_Product(adxtail, negate, ti1, ti0); - negate = -cdytail; - Two_Product(adx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); - - Two_Product(cdxtail, adytail, ti1, ti0); - Two_Product(adxtail, cdytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); - catt[3] = catt3; - cattlen = 4; - } else { - cat[0] = 0.0; - catlen = 1; - catt[0] = 0.0; - cattlen = 1; - } - - if (bdxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); - bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); - temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (cdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, - temp32a); - bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); - temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, - temp16a); - temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); - bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); - temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, - temp32a); - bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); - temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, - temp16a); - temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if ((cdxtail != 0.0) || (cdytail != 0.0)) { - if ((adxtail != 0.0) || (adytail != 0.0) - || (bdxtail != 0.0) || (bdytail != 0.0)) { - Two_Product(adxtail, bdy, ti1, ti0); - Two_Product(adx, bdytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -ady; - Two_Product(bdxtail, negate, ti1, ti0); - negate = -adytail; - Two_Product(bdx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); - - Two_Product(adxtail, bdytail, ti1, ti0); - Two_Product(bdxtail, adytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); - abtt[3] = abtt3; - abttlen = 4; - } else { - abt[0] = 0.0; - abtlen = 1; - abtt[0] = 0.0; - abttlen = 1; - } - - if (cdxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); - cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); - temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (adytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, - temp32a); - cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); - temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, - temp16a); - temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); - cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); - temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, - temp32a); - cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); - temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, - temp16a); - temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - - return finnow[finlength - 1]; -} - -REAL incircle(pa, pb, pc, pd) -point pa; -point pb; -point pc; -point pd; -{ - REAL adx, bdx, cdx, ady, bdy, cdy; - REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; - REAL alift, blift, clift; - REAL det; - REAL permanent, errbound; - - incirclecount++; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - - bdxcdy = bdx * cdy; - cdxbdy = cdx * bdy; - alift = adx * adx + ady * ady; - - cdxady = cdx * ady; - adxcdy = adx * cdy; - blift = bdx * bdx + bdy * bdy; - - adxbdy = adx * bdy; - bdxady = bdx * ady; - clift = cdx * cdx + cdy * cdy; - - det = alift * (bdxcdy - cdxbdy) - + blift * (cdxady - adxcdy) - + clift * (adxbdy - bdxady); - - if (noexact) { - return det; - } - - permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift - + (Absolute(cdxady) + Absolute(adxcdy)) * blift - + (Absolute(adxbdy) + Absolute(bdxady)) * clift; - errbound = iccerrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - return det; - } - - return incircleadapt(pa, pb, pc, pd, permanent); -} - -/** **/ -/** **/ -/********* Determinant evaluation routines end here *********/ - -/*****************************************************************************/ -/* */ -/* triangleinit() Initialize some variables. */ -/* */ -/*****************************************************************************/ - -void triangleinit() -{ - points.maxitems = triangles.maxitems = shelles.maxitems = viri.maxitems = - badsegments.maxitems = badtriangles.maxitems = splaynodes.maxitems = 0l; - points.itembytes = triangles.itembytes = shelles.itembytes = viri.itembytes = - badsegments.itembytes = badtriangles.itembytes = splaynodes.itembytes = 0; - recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */ - samples = 1; /* Point location should take at least one sample. */ - checksegments = 0; /* There are no segments in the triangulation yet. */ - incirclecount = counterclockcount = hyperbolacount = 0; - circumcentercount = circletopcount = 0; - randomseed = 1; - - exactinit(); /* Initialize exact arithmetic constants. */ -} - -/*****************************************************************************/ -/* */ -/* randomnation() Generate a random number between 0 and `choices' - 1. */ -/* */ -/* This is a simple linear congruential random number generator. Hence, it */ -/* is a bad random number generator, but good enough for most randomized */ -/* geometric algorithms. */ -/* */ -/*****************************************************************************/ - -unsigned long randomnation(choices) -unsigned int choices; -{ - randomseed = (randomseed * 1366l + 150889l) % 714025l; - return randomseed / (714025l / choices + 1); -} - -/********* Mesh quality testing routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* checkmesh() Test the mesh for topological consistency. */ -/* */ -/*****************************************************************************/ - -#ifndef REDUCED - -void checkmesh() -{ - struct triedge triangleloop; - struct triedge oppotri, oppooppotri; - point triorg, tridest, triapex; - point oppoorg, oppodest; - int horrors; - int saveexact; - triangle ptr; /* Temporary variable used by sym(). */ - - /* Temporarily turn on exact arithmetic if it's off. */ - saveexact = noexact; - noexact = 0; - if (!quiet) { - printf(" Checking consistency of mesh...\n"); - } - horrors = 0; - /* Run through the list of triangles, checking each one. */ - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - while (triangleloop.tri != (triangle *) NULL) { - /* Check all three edges of the triangle. */ - for (triangleloop.orient = 0; triangleloop.orient < 3; - triangleloop.orient++) { - org(triangleloop, triorg); - dest(triangleloop, tridest); - if (triangleloop.orient == 0) { /* Only test for inversion once. */ - /* Test if the triangle is flat or inverted. */ - apex(triangleloop, triapex); - if (counterclockwise(triorg, tridest, triapex) <= 0.0) { - printf(" !! !! Inverted "); - printtriangle(&triangleloop); - horrors++; - } - } - /* Find the neighboring triangle on this edge. */ - sym(triangleloop, oppotri); - if (oppotri.tri != dummytri) { - /* Check that the triangle's neighbor knows it's a neighbor. */ - sym(oppotri, oppooppotri); - if ((triangleloop.tri != oppooppotri.tri) - || (triangleloop.orient != oppooppotri.orient)) { - printf(" !! !! Asymmetric triangle-triangle bond:\n"); - if (triangleloop.tri == oppooppotri.tri) { - printf(" (Right triangle, wrong orientation)\n"); - } - printf(" First "); - printtriangle(&triangleloop); - printf(" Second (nonreciprocating) "); - printtriangle(&oppotri); - horrors++; - } - /* Check that both triangles agree on the identities */ - /* of their shared vertices. */ - org(oppotri, oppoorg); - dest(oppotri, oppodest); - if ((triorg != oppodest) || (tridest != oppoorg)) { - printf(" !! !! Mismatched edge coordinates between two triangles:\n" - ); - printf(" First mismatched "); - printtriangle(&triangleloop); - printf(" Second mismatched "); - printtriangle(&oppotri); - horrors++; - } - } - } - triangleloop.tri = triangletraverse(); - } - if (horrors == 0) { - if (!quiet) { - printf(" In my studied opinion, the mesh appears to be consistent.\n"); - } - } else if (horrors == 1) { - printf(" !! !! !! !! Precisely one festering wound discovered.\n"); - } else { - printf(" !! !! !! !! %d abominations witnessed.\n", horrors); - } - /* Restore the status of exact arithmetic. */ - noexact = saveexact; -} - -#endif /* not REDUCED */ - -/*****************************************************************************/ -/* */ -/* checkdelaunay() Ensure that the mesh is (constrained) Delaunay. */ -/* */ -/*****************************************************************************/ - -#ifndef REDUCED - -void checkdelaunay() -{ - struct triedge triangleloop; - struct triedge oppotri; - struct edge opposhelle; - point triorg, tridest, triapex; - point oppoapex; - int shouldbedelaunay; - int horrors; - int saveexact; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - /* Temporarily turn on exact arithmetic if it's off. */ - saveexact = noexact; - noexact = 0; - if (!quiet) { - printf(" Checking Delaunay property of mesh...\n"); - } - horrors = 0; - /* Run through the list of triangles, checking each one. */ - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - while (triangleloop.tri != (triangle *) NULL) { - /* Check all three edges of the triangle. */ - for (triangleloop.orient = 0; triangleloop.orient < 3; - triangleloop.orient++) { - org(triangleloop, triorg); - dest(triangleloop, tridest); - apex(triangleloop, triapex); - sym(triangleloop, oppotri); - apex(oppotri, oppoapex); - /* Only test that the edge is locally Delaunay if there is an */ - /* adjoining triangle whose pointer is larger (to ensure that */ - /* each pair isn't tested twice). */ - shouldbedelaunay = (oppotri.tri != dummytri) - && (triapex != (point) NULL) && (oppoapex != (point) NULL) - && (triangleloop.tri < oppotri.tri); - if (checksegments && shouldbedelaunay) { - /* If a shell edge separates the triangles, then the edge is */ - /* constrained, so no local Delaunay test should be done. */ - tspivot(triangleloop, opposhelle); - if (opposhelle.sh != dummysh){ - shouldbedelaunay = 0; - } - } - if (shouldbedelaunay) { - if (incircle(triorg, tridest, triapex, oppoapex) > 0.0) { - printf(" !! !! Non-Delaunay pair of triangles:\n"); - printf(" First non-Delaunay "); - printtriangle(&triangleloop); - printf(" Second non-Delaunay "); - printtriangle(&oppotri); - horrors++; - } - } - } - triangleloop.tri = triangletraverse(); - } - if (horrors == 0) { - if (!quiet) { - printf( - " By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n"); - } - } else if (horrors == 1) { - printf( - " !! !! !! !! Precisely one terrifying transgression identified.\n"); - } else { - printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); - } - /* Restore the status of exact arithmetic. */ - noexact = saveexact; -} - -#endif /* not REDUCED */ - -/*****************************************************************************/ -/* */ -/* enqueuebadtri() Add a bad triangle to the end of a queue. */ -/* */ -/* The queue is actually a set of 64 queues. I use multiple queues to give */ -/* priority to smaller angles. I originally implemented a heap, but the */ -/* queues are (to my surprise) much faster. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void enqueuebadtri(instri, angle, insapex, insorg, insdest) -struct triedge *instri; -REAL angle; -point insapex; -point insorg; -point insdest; -{ - struct badface *newface; - int queuenumber; - - if (verbose > 2) { - printf(" Queueing bad triangle:\n"); - printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", insorg[0], - insorg[1], insdest[0], insdest[1], insapex[0], insapex[1]); - } - /* Allocate space for the bad triangle. */ - newface = (struct badface *) poolalloc(&badtriangles); - triedgecopy(*instri, newface->badfacetri); - newface->key = angle; - newface->faceapex = insapex; - newface->faceorg = insorg; - newface->facedest = insdest; - newface->nextface = (struct badface *) NULL; - /* Determine the appropriate queue to put the bad triangle into. */ - if (angle > 0.6) { - queuenumber = (int) (160.0 * (angle - 0.6)); - if (queuenumber > 63) { - queuenumber = 63; - } - } else { - /* It's not a bad angle; put the triangle in the lowest-priority queue. */ - queuenumber = 0; - } - /* Add the triangle to the end of a queue. */ - *queuetail[queuenumber] = newface; - /* Maintain a pointer to the NULL pointer at the end of the queue. */ - queuetail[queuenumber] = &newface->nextface; -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* dequeuebadtri() Remove a triangle from the front of the queue. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -struct badface *dequeuebadtri() -{ - struct badface *result; - int queuenumber; - - /* Look for a nonempty queue. */ - for (queuenumber = 63; queuenumber >= 0; queuenumber--) { - result = queuefront[queuenumber]; - if (result != (struct badface *) NULL) { - /* Remove the triangle from the queue. */ - queuefront[queuenumber] = result->nextface; - /* Maintain a pointer to the NULL pointer at the end of the queue. */ - if (queuefront[queuenumber] == (struct badface *) NULL) { - queuetail[queuenumber] = &queuefront[queuenumber]; - } - return result; - } - } - return (struct badface *) NULL; -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* checkedge4encroach() Check a segment to see if it is encroached; add */ -/* it to the list if it is. */ -/* */ -/* An encroached segment is an unflippable edge that has a point in its */ -/* diametral circle (that is, it faces an angle greater than 90 degrees). */ -/* This definition is due to Ruppert. */ -/* */ -/* Returns a nonzero value if the edge is encroached. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -int checkedge4encroach(testedge) -struct edge *testedge; -{ - struct triedge neighbortri; - struct edge testsym; - struct edge *badedge; - int addtolist; - int sides; - point eorg, edest, eapex; - triangle ptr; /* Temporary variable used by stpivot(). */ - - addtolist = 0; - sides = 0; - - sorg(*testedge, eorg); - sdest(*testedge, edest); - /* Check one neighbor of the shell edge. */ - stpivot(*testedge, neighbortri); - /* Does the neighbor exist, or is this a boundary edge? */ - if (neighbortri.tri != dummytri) { - sides++; - /* Find a vertex opposite this edge. */ - apex(neighbortri, eapex); - /* Check whether the vertex is inside the diametral circle of the */ - /* shell edge. Pythagoras' Theorem is used to check whether the */ - /* angle at the vertex is greater than 90 degrees. */ - if (eapex[0] * (eorg[0] + edest[0]) + eapex[1] * (eorg[1] + edest[1]) > - eapex[0] * eapex[0] + eorg[0] * edest[0] + - eapex[1] * eapex[1] + eorg[1] * edest[1]) { - addtolist = 1; - } - } - /* Check the other neighbor of the shell edge. */ - ssym(*testedge, testsym); - stpivot(testsym, neighbortri); - /* Does the neighbor exist, or is this a boundary edge? */ - if (neighbortri.tri != dummytri) { - sides++; - /* Find the other vertex opposite this edge. */ - apex(neighbortri, eapex); - /* Check whether the vertex is inside the diametral circle of the */ - /* shell edge. Pythagoras' Theorem is used to check whether the */ - /* angle at the vertex is greater than 90 degrees. */ - if (eapex[0] * (eorg[0] + edest[0]) + - eapex[1] * (eorg[1] + edest[1]) > - eapex[0] * eapex[0] + eorg[0] * edest[0] + - eapex[1] * eapex[1] + eorg[1] * edest[1]) { - addtolist += 2; - } - } - - if (addtolist && (!nobisect || ((nobisect == 1) && (sides == 2)))) { - if (verbose > 2) { - printf(" Queueing encroached segment (%.12g, %.12g) (%.12g, %.12g).\n", - eorg[0], eorg[1], edest[0], edest[1]); - } - /* Add the shell edge to the list of encroached segments. */ - /* Be sure to get the orientation right. */ - badedge = (struct edge *) poolalloc(&badsegments); - if (addtolist == 1) { - shellecopy(*testedge, *badedge); - } else { - shellecopy(testsym, *badedge); - } - } - return addtolist; -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* testtriangle() Test a face for quality measures. */ -/* */ -/* Tests a triangle to see if it satisfies the minimum angle condition and */ -/* the maximum area condition. Triangles that aren't up to spec are added */ -/* to the bad triangle queue. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void testtriangle(testtri) -struct triedge *testtri; -{ - struct triedge sametesttri; - struct edge edge1, edge2; - point torg, tdest, tapex; - point anglevertex; - REAL dxod, dyod, dxda, dyda, dxao, dyao; - REAL dxod2, dyod2, dxda2, dyda2, dxao2, dyao2; - REAL apexlen, orglen, destlen; - REAL angle; - REAL area; - shelle sptr; /* Temporary variable used by tspivot(). */ - - org(*testtri, torg); - dest(*testtri, tdest); - apex(*testtri, tapex); - dxod = torg[0] - tdest[0]; - dyod = torg[1] - tdest[1]; - dxda = tdest[0] - tapex[0]; - dyda = tdest[1] - tapex[1]; - dxao = tapex[0] - torg[0]; - dyao = tapex[1] - torg[1]; - dxod2 = dxod * dxod; - dyod2 = dyod * dyod; - dxda2 = dxda * dxda; - dyda2 = dyda * dyda; - dxao2 = dxao * dxao; - dyao2 = dyao * dyao; - /* Find the lengths of the triangle's three edges. */ - apexlen = dxod2 + dyod2; - orglen = dxda2 + dyda2; - destlen = dxao2 + dyao2; - if ((apexlen < orglen) && (apexlen < destlen)) { - /* The edge opposite the apex is shortest. */ - /* Find the square of the cosine of the angle at the apex. */ - angle = dxda * dxao + dyda * dyao; - angle = angle * angle / (orglen * destlen); - anglevertex = tapex; - lnext(*testtri, sametesttri); - tspivot(sametesttri, edge1); - lnextself(sametesttri); - tspivot(sametesttri, edge2); - } else if (orglen < destlen) { - /* The edge opposite the origin is shortest. */ - /* Find the square of the cosine of the angle at the origin. */ - angle = dxod * dxao + dyod * dyao; - angle = angle * angle / (apexlen * destlen); - anglevertex = torg; - tspivot(*testtri, edge1); - lprev(*testtri, sametesttri); - tspivot(sametesttri, edge2); - } else { - /* The edge opposite the destination is shortest. */ - /* Find the square of the cosine of the angle at the destination. */ - angle = dxod * dxda + dyod * dyda; - angle = angle * angle / (apexlen * orglen); - anglevertex = tdest; - tspivot(*testtri, edge1); - lnext(*testtri, sametesttri); - tspivot(sametesttri, edge2); - } - /* Check if both edges that form the angle are segments. */ - if ((edge1.sh != dummysh) && (edge2.sh != dummysh)) { - /* The angle is a segment intersection. */ - if ((angle > 0.9924) && !quiet) { /* Roughly 5 degrees. */ - if (angle > 1.0) { - /* Beware of a floating exception in acos(). */ - angle = 1.0; - } - /* Find the actual angle in degrees, for printing. */ - angle = acos(sqrt(angle)) * (180.0 / PI); - printf( - "Warning: Small angle (%.4g degrees) between segments at point\n", - angle); - printf(" (%.12g, %.12g)\n", anglevertex[0], anglevertex[1]); - } - /* Don't add this bad triangle to the list; there's nothing that */ - /* can be done about a small angle between two segments. */ - angle = 0.0; - } - /* Check whether the angle is smaller than permitted. */ - if (angle > goodangle) { - /* Add this triangle to the list of bad triangles. */ - enqueuebadtri(testtri, angle, tapex, torg, tdest); - return; - } - if (vararea || fixedarea) { - /* Check whether the area is larger than permitted. */ - area = 0.5 * (dxod * dyda - dyod * dxda); - if (fixedarea && (area > maxarea)) { - /* Add this triangle to the list of bad triangles. */ - enqueuebadtri(testtri, angle, tapex, torg, tdest); - } else if (vararea) { - /* Nonpositive area constraints are treated as unconstrained. */ - if ((area > areabound(*testtri)) && (areabound(*testtri) > 0.0)) { - /* Add this triangle to the list of bad triangles. */ - enqueuebadtri(testtri, angle, tapex, torg, tdest); - } - } - } -} - -#endif /* not CDT_ONLY */ - -/** **/ -/** **/ -/********* Mesh quality testing routines end here *********/ - -/********* Point location routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* makepointmap() Construct a mapping from points to triangles to improve */ -/* the speed of point location for segment insertion. */ -/* */ -/* Traverses all the triangles, and provides each corner of each triangle */ -/* with a pointer to that triangle. Of course, pointers will be */ -/* overwritten by other pointers because (almost) each point is a corner */ -/* of several triangles, but in the end every point will point to some */ -/* triangle that contains it. */ -/* */ -/*****************************************************************************/ - -void makepointmap() -{ - struct triedge triangleloop; - point triorg; - - if (verbose) { - printf(" Constructing mapping from points to triangles.\n"); - } - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - while (triangleloop.tri != (triangle *) NULL) { - /* Check all three points of the triangle. */ - for (triangleloop.orient = 0; triangleloop.orient < 3; - triangleloop.orient++) { - org(triangleloop, triorg); - setpoint2tri(triorg, encode(triangleloop)); - } - triangleloop.tri = triangletraverse(); - } -} - -/*****************************************************************************/ -/* */ -/* preciselocate() Find a triangle or edge containing a given point. */ -/* */ -/* Begins its search from `searchtri'. It is important that `searchtri' */ -/* be a handle with the property that `searchpoint' is strictly to the left */ -/* of the edge denoted by `searchtri', or is collinear with that edge and */ -/* does not intersect that edge. (In particular, `searchpoint' should not */ -/* be the origin or destination of that edge.) */ -/* */ -/* These conditions are imposed because preciselocate() is normally used in */ -/* one of two situations: */ -/* */ -/* (1) To try to find the location to insert a new point. Normally, we */ -/* know an edge that the point is strictly to the left of. In the */ -/* incremental Delaunay algorithm, that edge is a bounding box edge. */ -/* In Ruppert's Delaunay refinement algorithm for quality meshing, */ -/* that edge is the shortest edge of the triangle whose circumcenter */ -/* is being inserted. */ -/* */ -/* (2) To try to find an existing point. In this case, any edge on the */ -/* convex hull is a good starting edge. The possibility that the */ -/* vertex one seeks is an endpoint of the starting edge must be */ -/* screened out before preciselocate() is called. */ -/* */ -/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ -/* */ -/* This implementation differs from that given by Guibas and Stolfi. It */ -/* walks from triangle to triangle, crossing an edge only if `searchpoint' */ -/* is on the other side of the line containing that edge. After entering */ -/* a triangle, there are two edges by which one can leave that triangle. */ -/* If both edges are valid (`searchpoint' is on the other side of both */ -/* edges), one of the two is chosen by drawing a line perpendicular to */ -/* the entry edge (whose endpoints are `forg' and `fdest') passing through */ -/* `fapex'. Depending on which side of this perpendicular `searchpoint' */ -/* falls on, an exit edge is chosen. */ -/* */ -/* This implementation is empirically faster than the Guibas and Stolfi */ -/* point location routine (which I originally used), which tends to spiral */ -/* in toward its target. */ -/* */ -/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ -/* is a handle whose origin is the existing vertex. */ -/* */ -/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ -/* handle whose primary edge is the edge on which the point lies. */ -/* */ -/* Returns INTRIANGLE if the point lies strictly within a triangle. */ -/* `searchtri' is a handle on the triangle that contains the point. */ -/* */ -/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ -/* handle whose primary edge the point is to the right of. This might */ -/* occur when the circumcenter of a triangle falls just slightly outside */ -/* the mesh due to floating-point roundoff error. It also occurs when */ -/* seeking a hole or region point that a foolish user has placed outside */ -/* the mesh. */ -/* */ -/* WARNING: This routine is designed for convex triangulations, and will */ -/* not generally work after the holes and concavities have been carved. */ -/* However, it can still be used to find the circumcenter of a triangle, as */ -/* long as the search is begun from the triangle in question. */ -/* */ -/*****************************************************************************/ - -enum locateresult preciselocate(searchpoint, searchtri) -point searchpoint; -struct triedge *searchtri; -{ - struct triedge backtracktri; - point forg, fdest, fapex; - point swappoint; - REAL orgorient, destorient; - int moveleft; - triangle ptr; /* Temporary variable used by sym(). */ - - if (verbose > 2) { - printf(" Searching for point (%.12g, %.12g).\n", - searchpoint[0], searchpoint[1]); - } - /* Where are we? */ - org(*searchtri, forg); - dest(*searchtri, fdest); - apex(*searchtri, fapex); - while (1) { - if (verbose > 2) { - printf(" At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", - forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]); - } - /* Check whether the apex is the point we seek. */ - if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) { - lprevself(*searchtri); - return ONVERTEX; - } - /* Does the point lie on the other side of the line defined by the */ - /* triangle edge opposite the triangle's destination? */ - destorient = counterclockwise(forg, fapex, searchpoint); - /* Does the point lie on the other side of the line defined by the */ - /* triangle edge opposite the triangle's origin? */ - orgorient = counterclockwise(fapex, fdest, searchpoint); - if (destorient > 0.0) { - if (orgorient > 0.0) { - /* Move left if the inner product of (fapex - searchpoint) and */ - /* (fdest - forg) is positive. This is equivalent to drawing */ - /* a line perpendicular to the line (forg, fdest) passing */ - /* through `fapex', and determining which side of this line */ - /* `searchpoint' falls on. */ - moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) + - (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0; - } else { - moveleft = 1; - } - } else { - if (orgorient > 0.0) { - moveleft = 0; - } else { - /* The point we seek must be on the boundary of or inside this */ - /* triangle. */ - if (destorient == 0.0) { - lprevself(*searchtri); - return ONEDGE; - } - if (orgorient == 0.0) { - lnextself(*searchtri); - return ONEDGE; - } - return INTRIANGLE; - } - } - - /* Move to another triangle. Leave a trace `backtracktri' in case */ - /* floating-point roundoff or some such bogey causes us to walk */ - /* off a boundary of the triangulation. We can just bounce off */ - /* the boundary as if it were an elastic band. */ - if (moveleft) { - lprev(*searchtri, backtracktri); - fdest = fapex; - } else { - lnext(*searchtri, backtracktri); - forg = fapex; - } - sym(backtracktri, *searchtri); - - /* Check for walking off the edge. */ - if (searchtri->tri == dummytri) { - /* Turn around. */ - triedgecopy(backtracktri, *searchtri); - swappoint = forg; - forg = fdest; - fdest = swappoint; - apex(*searchtri, fapex); - /* Check if the point really is beyond the triangulation boundary. */ - destorient = counterclockwise(forg, fapex, searchpoint); - orgorient = counterclockwise(fapex, fdest, searchpoint); - if ((orgorient < 0.0) && (destorient < 0.0)) { - return OUTSIDE; - } - } else { - apex(*searchtri, fapex); - } - } -} - -/*****************************************************************************/ -/* */ -/* locate() Find a triangle or edge containing a given point. */ -/* */ -/* Searching begins from one of: the input `searchtri', a recently */ -/* encountered triangle `recenttri', or from a triangle chosen from a */ -/* random sample. The choice is made by determining which triangle's */ -/* origin is closest to the point we are searcing for. Normally, */ -/* `searchtri' should be a handle on the convex hull of the triangulation. */ -/* */ -/* Details on the random sampling method can be found in the Mucke, Saias, */ -/* and Zhu paper cited in the header of this code. */ -/* */ -/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ -/* */ -/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ -/* is a handle whose origin is the existing vertex. */ -/* */ -/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ -/* handle whose primary edge is the edge on which the point lies. */ -/* */ -/* Returns INTRIANGLE if the point lies strictly within a triangle. */ -/* `searchtri' is a handle on the triangle that contains the point. */ -/* */ -/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ -/* handle whose primary edge the point is to the right of. This might */ -/* occur when the circumcenter of a triangle falls just slightly outside */ -/* the mesh due to floating-point roundoff error. It also occurs when */ -/* seeking a hole or region point that a foolish user has placed outside */ -/* the mesh. */ -/* */ -/* WARNING: This routine is designed for convex triangulations, and will */ -/* not generally work after the holes and concavities have been carved. */ -/* */ -/*****************************************************************************/ - -enum locateresult locate(searchpoint, searchtri) -point searchpoint; -struct triedge *searchtri; -{ - VOID **sampleblock; - triangle *firsttri; - struct triedge sampletri; - point torg, tdest; - unsigned long alignptr; - REAL searchdist, dist; - REAL ahead; - long sampleblocks, samplesperblock, samplenum; - long triblocks; - long i, j; - triangle ptr; /* Temporary variable used by sym(). */ - - if (verbose > 2) { - printf(" Randomly sampling for a triangle near point (%.12g, %.12g).\n", - searchpoint[0], searchpoint[1]); - } - /* Record the distance from the suggested starting triangle to the */ - /* point we seek. */ - org(*searchtri, torg); - searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) - + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); - if (verbose > 2) { - printf(" Boundary triangle has origin (%.12g, %.12g).\n", - torg[0], torg[1]); - } - - /* If a recently encountered triangle has been recorded and has not been */ - /* deallocated, test it as a good starting point. */ - if (recenttri.tri != (triangle *) NULL) { - if (recenttri.tri[3] != (triangle) NULL) { - org(recenttri, torg); - if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { - triedgecopy(recenttri, *searchtri); - return ONVERTEX; - } - dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) - + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); - if (dist < searchdist) { - triedgecopy(recenttri, *searchtri); - searchdist = dist; - if (verbose > 2) { - printf(" Choosing recent triangle with origin (%.12g, %.12g).\n", - torg[0], torg[1]); - } - } - } - } - - /* The number of random samples taken is proportional to the cube root of */ - /* the number of triangles in the mesh. The next bit of code assumes */ - /* that the number of triangles increases monotonically. */ - while (SAMPLEFACTOR * samples * samples * samples < triangles.items) { - samples++; - } - triblocks = (triangles.maxitems + TRIPERBLOCK - 1) / TRIPERBLOCK; - samplesperblock = 1 + (samples / triblocks); - sampleblocks = samples / samplesperblock; - sampleblock = triangles.firstblock; - sampletri.orient = 0; - for (i = 0; i < sampleblocks; i++) { - alignptr = (unsigned long) (sampleblock + 1); - firsttri = (triangle *) (alignptr + (unsigned long) triangles.alignbytes - - (alignptr % (unsigned long) triangles.alignbytes)); - for (j = 0; j < samplesperblock; j++) { - if (i == triblocks - 1) { - samplenum = randomnation((int) - (triangles.maxitems - (i * TRIPERBLOCK))); - } else { - samplenum = randomnation(TRIPERBLOCK); - } - sampletri.tri = (triangle *) - (firsttri + (samplenum * triangles.itemwords)); - if (sampletri.tri[3] != (triangle) NULL) { - org(sampletri, torg); - dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) - + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); - if (dist < searchdist) { - triedgecopy(sampletri, *searchtri); - searchdist = dist; - if (verbose > 2) { - printf(" Choosing triangle with origin (%.12g, %.12g).\n", - torg[0], torg[1]); - } - } - } - } - sampleblock = (VOID **) *sampleblock; - } - /* Where are we? */ - org(*searchtri, torg); - dest(*searchtri, tdest); - /* Check the starting triangle's vertices. */ - if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { - return ONVERTEX; - } - if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) { - lnextself(*searchtri); - return ONVERTEX; - } - /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */ - ahead = counterclockwise(torg, tdest, searchpoint); - if (ahead < 0.0) { - /* Turn around so that `searchpoint' is to the left of the */ - /* edge specified by `searchtri'. */ - symself(*searchtri); - } else if (ahead == 0.0) { - /* Check if `searchpoint' is between `torg' and `tdest'. */ - if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0])) - && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) { - return ONEDGE; - } - } - return preciselocate(searchpoint, searchtri); -} - -/** **/ -/** **/ -/********* Point location routines end here *********/ - -/********* Mesh transformation routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* insertshelle() Create a new shell edge and insert it between two */ -/* triangles. */ -/* */ -/* The new shell edge is inserted at the edge described by the handle */ -/* `tri'. Its vertices are properly initialized. The marker `shellemark' */ -/* is applied to the shell edge and, if appropriate, its vertices. */ -/* */ -/*****************************************************************************/ - -void insertshelle(tri, shellemark) -struct triedge *tri; /* Edge at which to insert the new shell edge. */ -int shellemark; /* Marker for the new shell edge. */ -{ - struct triedge oppotri; - struct edge newshelle; - point triorg, tridest; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - /* Mark points if possible. */ - org(*tri, triorg); - dest(*tri, tridest); - if (pointmark(triorg) == 0) { - setpointmark(triorg, shellemark); - } - if (pointmark(tridest) == 0) { - setpointmark(tridest, shellemark); - } - /* Check if there's already a shell edge here. */ - tspivot(*tri, newshelle); - if (newshelle.sh == dummysh) { - /* Make new shell edge and initialize its vertices. */ - makeshelle(&newshelle); - setsorg(newshelle, tridest); - setsdest(newshelle, triorg); - /* Bond new shell edge to the two triangles it is sandwiched between. */ - /* Note that the facing triangle `oppotri' might be equal to */ - /* `dummytri' (outer space), but the new shell edge is bonded to it */ - /* all the same. */ - tsbond(*tri, newshelle); - sym(*tri, oppotri); - ssymself(newshelle); - tsbond(oppotri, newshelle); - setmark(newshelle, shellemark); - if (verbose > 2) { - printf(" Inserting new "); - printshelle(&newshelle); - } - } else { - if (mark(newshelle) == 0) { - setmark(newshelle, shellemark); - } - } -} - -/*****************************************************************************/ -/* */ -/* Terminology */ -/* */ -/* A "local transformation" replaces a small set of triangles with another */ -/* set of triangles. This may or may not involve inserting or deleting a */ -/* point. */ -/* */ -/* The term "casing" is used to describe the set of triangles that are */ -/* attached to the triangles being transformed, but are not transformed */ -/* themselves. Think of the casing as a fixed hollow structure inside */ -/* which all the action happens. A "casing" is only defined relative to */ -/* a single transformation; each occurrence of a transformation will */ -/* involve a different casing. */ -/* */ -/* A "shell" is similar to a "casing". The term "shell" describes the set */ -/* of shell edges (if any) that are attached to the triangles being */ -/* transformed. However, I sometimes use "shell" to refer to a single */ -/* shell edge, so don't get confused. */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* */ -/* flip() Transform two triangles to two different triangles by flipping */ -/* an edge within a quadrilateral. */ -/* */ -/* Imagine the original triangles, abc and bad, oriented so that the */ -/* shared edge ab lies in a horizontal plane, with the point b on the left */ -/* and the point a on the right. The point c lies below the edge, and the */ -/* point d lies above the edge. The `flipedge' handle holds the edge ab */ -/* of triangle abc, and is directed left, from vertex a to vertex b. */ -/* */ -/* The triangles abc and bad are deleted and replaced by the triangles cdb */ -/* and dca. The triangles that represent abc and bad are NOT deallocated; */ -/* they are reused for dca and cdb, respectively. Hence, any handles that */ -/* may have held the original triangles are still valid, although not */ -/* directed as they were before. */ -/* */ -/* Upon completion of this routine, the `flipedge' handle holds the edge */ -/* dc of triangle dca, and is directed down, from vertex d to vertex c. */ -/* (Hence, the two triangles have rotated counterclockwise.) */ -/* */ -/* WARNING: This transformation is geometrically valid only if the */ -/* quadrilateral adbc is convex. Furthermore, this transformation is */ -/* valid only if there is not a shell edge between the triangles abc and */ -/* bad. This routine does not check either of these preconditions, and */ -/* it is the responsibility of the calling routine to ensure that they are */ -/* met. If they are not, the streets shall be filled with wailing and */ -/* gnashing of teeth. */ -/* */ -/*****************************************************************************/ - -void flip(flipedge) -struct triedge *flipedge; /* Handle for the triangle abc. */ -{ - struct triedge botleft, botright; - struct triedge topleft, topright; - struct triedge top; - struct triedge botlcasing, botrcasing; - struct triedge toplcasing, toprcasing; - struct edge botlshelle, botrshelle; - struct edge toplshelle, toprshelle; - point leftpoint, rightpoint, botpoint; - point farpoint; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - /* Identify the vertices of the quadrilateral. */ - org(*flipedge, rightpoint); - dest(*flipedge, leftpoint); - apex(*flipedge, botpoint); - sym(*flipedge, top); -#ifdef SELF_CHECK - if (top.tri == dummytri) { - printf("Internal error in flip(): Attempt to flip on boundary.\n"); - lnextself(*flipedge); - return; - } - if (checksegments) { - tspivot(*flipedge, toplshelle); - if (toplshelle.sh != dummysh) { - printf("Internal error in flip(): Attempt to flip a segment.\n"); - lnextself(*flipedge); - return; - } - } -#endif /* SELF_CHECK */ - apex(top, farpoint); - - /* Identify the casing of the quadrilateral. */ - lprev(top, topleft); - sym(topleft, toplcasing); - lnext(top, topright); - sym(topright, toprcasing); - lnext(*flipedge, botleft); - sym(botleft, botlcasing); - lprev(*flipedge, botright); - sym(botright, botrcasing); - /* Rotate the quadrilateral one-quarter turn counterclockwise. */ - bond(topleft, botlcasing); - bond(botleft, botrcasing); - bond(botright, toprcasing); - bond(topright, toplcasing); - - if (checksegments) { - /* Check for shell edges and rebond them to the quadrilateral. */ - tspivot(topleft, toplshelle); - tspivot(botleft, botlshelle); - tspivot(botright, botrshelle); - tspivot(topright, toprshelle); - if (toplshelle.sh == dummysh) { - tsdissolve(topright); - } else { - tsbond(topright, toplshelle); - } - if (botlshelle.sh == dummysh) { - tsdissolve(topleft); - } else { - tsbond(topleft, botlshelle); - } - if (botrshelle.sh == dummysh) { - tsdissolve(botleft); - } else { - tsbond(botleft, botrshelle); - } - if (toprshelle.sh == dummysh) { - tsdissolve(botright); - } else { - tsbond(botright, toprshelle); - } - } - - /* New point assignments for the rotated quadrilateral. */ - setorg(*flipedge, farpoint); - setdest(*flipedge, botpoint); - setapex(*flipedge, rightpoint); - setorg(top, botpoint); - setdest(top, farpoint); - setapex(top, leftpoint); - if (verbose > 2) { - printf(" Edge flip results in left "); - lnextself(topleft); - printtriangle(&topleft); - printf(" and right "); - printtriangle(flipedge); - } -} - -/*****************************************************************************/ -/* */ -/* insertsite() Insert a vertex into a Delaunay triangulation, */ -/* performing flips as necessary to maintain the Delaunay */ -/* property. */ -/* */ -/* The point `insertpoint' is located. If `searchtri.tri' is not NULL, */ -/* the search for the containing triangle begins from `searchtri'. If */ -/* `searchtri.tri' is NULL, a full point location procedure is called. */ -/* If `insertpoint' is found inside a triangle, the triangle is split into */ -/* three; if `insertpoint' lies on an edge, the edge is split in two, */ -/* thereby splitting the two adjacent triangles into four. Edge flips are */ -/* used to restore the Delaunay property. If `insertpoint' lies on an */ -/* existing vertex, no action is taken, and the value DUPLICATEPOINT is */ -/* returned. On return, `searchtri' is set to a handle whose origin is the */ -/* existing vertex. */ -/* */ -/* Normally, the parameter `splitedge' is set to NULL, implying that no */ -/* segment should be split. In this case, if `insertpoint' is found to */ -/* lie on a segment, no action is taken, and the value VIOLATINGPOINT is */ -/* returned. On return, `searchtri' is set to a handle whose primary edge */ -/* is the violated segment. */ -/* */ -/* If the calling routine wishes to split a segment by inserting a point in */ -/* it, the parameter `splitedge' should be that segment. In this case, */ -/* `searchtri' MUST be the triangle handle reached by pivoting from that */ -/* segment; no point location is done. */ -/* */ -/* `segmentflaws' and `triflaws' are flags that indicate whether or not */ -/* there should be checks for the creation of encroached segments or bad */ -/* quality faces. If a newly inserted point encroaches upon segments, */ -/* these segments are added to the list of segments to be split if */ -/* `segmentflaws' is set. If bad triangles are created, these are added */ -/* to the queue if `triflaws' is set. */ -/* */ -/* If a duplicate point or violated segment does not prevent the point */ -/* from being inserted, the return value will be ENCROACHINGPOINT if the */ -/* point encroaches upon a segment (and checking is enabled), or */ -/* SUCCESSFULPOINT otherwise. In either case, `searchtri' is set to a */ -/* handle whose origin is the newly inserted vertex. */ -/* */ -/* insertsite() does not use flip() for reasons of speed; some */ -/* information can be reused from edge flip to edge flip, like the */ -/* locations of shell edges. */ -/* */ -/*****************************************************************************/ - -enum insertsiteresult insertsite(insertpoint, searchtri, splitedge, - segmentflaws, triflaws) -point insertpoint; -struct triedge *searchtri; -struct edge *splitedge; -int segmentflaws; -int triflaws; -{ - struct triedge horiz; - struct triedge top; - struct triedge botleft, botright; - struct triedge topleft, topright; - struct triedge newbotleft, newbotright; - struct triedge newtopright; - struct triedge botlcasing, botrcasing; - struct triedge toplcasing, toprcasing; - struct triedge testtri; - struct edge botlshelle, botrshelle; - struct edge toplshelle, toprshelle; - struct edge brokenshelle; - struct edge checkshelle; - struct edge rightedge; - struct edge newedge; - struct edge *encroached; - point first; - point leftpoint, rightpoint, botpoint, toppoint, farpoint; - REAL attrib; - REAL area; - enum insertsiteresult success; - enum locateresult intersect; - int doflip; - int mirrorflag; - int i; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by spivot() and tspivot(). */ - - if (verbose > 1) { - printf(" Inserting (%.12g, %.12g).\n", insertpoint[0], insertpoint[1]); - } - if (splitedge == (struct edge *) NULL) { - /* Find the location of the point to be inserted. Check if a good */ - /* starting triangle has already been provided by the caller. */ - if (searchtri->tri == (triangle *) NULL) { - /* Find a boundary triangle. */ - horiz.tri = dummytri; - horiz.orient = 0; - symself(horiz); - /* Search for a triangle containing `insertpoint'. */ - intersect = locate(insertpoint, &horiz); - } else { - /* Start searching from the triangle provided by the caller. */ - triedgecopy(*searchtri, horiz); - intersect = preciselocate(insertpoint, &horiz); - } - } else { - /* The calling routine provides the edge in which the point is inserted. */ - triedgecopy(*searchtri, horiz); - intersect = ONEDGE; - } - if (intersect == ONVERTEX) { - /* There's already a vertex there. Return in `searchtri' a triangle */ - /* whose origin is the existing vertex. */ - triedgecopy(horiz, *searchtri); - triedgecopy(horiz, recenttri); - return DUPLICATEPOINT; - } - if ((intersect == ONEDGE) || (intersect == OUTSIDE)) { - /* The vertex falls on an edge or boundary. */ - if (checksegments && (splitedge == (struct edge *) NULL)) { - /* Check whether the vertex falls on a shell edge. */ - tspivot(horiz, brokenshelle); - if (brokenshelle.sh != dummysh) { - /* The vertex falls on a shell edge. */ - if (segmentflaws) { - if (nobisect == 0) { - /* Add the shell edge to the list of encroached segments. */ - encroached = (struct edge *) poolalloc(&badsegments); - shellecopy(brokenshelle, *encroached); - } else if ((nobisect == 1) && (intersect == ONEDGE)) { - /* This segment may be split only if it is an internal boundary. */ - sym(horiz, testtri); - if (testtri.tri != dummytri) { - /* Add the shell edge to the list of encroached segments. */ - encroached = (struct edge *) poolalloc(&badsegments); - shellecopy(brokenshelle, *encroached); - } - } - } - /* Return a handle whose primary edge contains the point, */ - /* which has not been inserted. */ - triedgecopy(horiz, *searchtri); - triedgecopy(horiz, recenttri); - return VIOLATINGPOINT; - } - } - /* Insert the point on an edge, dividing one triangle into two (if */ - /* the edge lies on a boundary) or two triangles into four. */ - lprev(horiz, botright); - sym(botright, botrcasing); - sym(horiz, topright); - /* Is there a second triangle? (Or does this edge lie on a boundary?) */ - mirrorflag = topright.tri != dummytri; - if (mirrorflag) { - lnextself(topright); - sym(topright, toprcasing); - maketriangle(&newtopright); - } else { - /* Splitting the boundary edge increases the number of boundary edges. */ - hullsize++; - } - maketriangle(&newbotright); - - /* Set the vertices of changed and new triangles. */ - org(horiz, rightpoint); - dest(horiz, leftpoint); - apex(horiz, botpoint); - setorg(newbotright, botpoint); - setdest(newbotright, rightpoint); - setapex(newbotright, insertpoint); - setorg(horiz, insertpoint); - for (i = 0; i < eextras; i++) { - /* Set the element attributes of a new triangle. */ - setelemattribute(newbotright, i, elemattribute(botright, i)); - } - if (vararea) { - /* Set the area constraint of a new triangle. */ - setareabound(newbotright, areabound(botright)); - } - if (mirrorflag) { - dest(topright, toppoint); - setorg(newtopright, rightpoint); - setdest(newtopright, toppoint); - setapex(newtopright, insertpoint); - setorg(topright, insertpoint); - for (i = 0; i < eextras; i++) { - /* Set the element attributes of another new triangle. */ - setelemattribute(newtopright, i, elemattribute(topright, i)); - } - if (vararea) { - /* Set the area constraint of another new triangle. */ - setareabound(newtopright, areabound(topright)); - } - } - - /* There may be shell edges that need to be bonded */ - /* to the new triangle(s). */ - if (checksegments) { - tspivot(botright, botrshelle); - if (botrshelle.sh != dummysh) { - tsdissolve(botright); - tsbond(newbotright, botrshelle); - } - if (mirrorflag) { - tspivot(topright, toprshelle); - if (toprshelle.sh != dummysh) { - tsdissolve(topright); - tsbond(newtopright, toprshelle); - } - } - } - - /* Bond the new triangle(s) to the surrounding triangles. */ - bond(newbotright, botrcasing); - lprevself(newbotright); - bond(newbotright, botright); - lprevself(newbotright); - if (mirrorflag) { - bond(newtopright, toprcasing); - lnextself(newtopright); - bond(newtopright, topright); - lnextself(newtopright); - bond(newtopright, newbotright); - } - - if (splitedge != (struct edge *) NULL) { - /* Split the shell edge into two. */ - setsdest(*splitedge, insertpoint); - ssymself(*splitedge); - spivot(*splitedge, rightedge); - insertshelle(&newbotright, mark(*splitedge)); - tspivot(newbotright, newedge); - sbond(*splitedge, newedge); - ssymself(newedge); - sbond(newedge, rightedge); - ssymself(*splitedge); - } - -#ifdef SELF_CHECK - if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle prior to edge point insertion (bottom).\n"); - } - if (mirrorflag) { - if (counterclockwise(leftpoint, rightpoint, toppoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle prior to edge point insertion (top).\n"); - } - if (counterclockwise(rightpoint, toppoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after edge point insertion (top right).\n" - ); - } - if (counterclockwise(toppoint, leftpoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after edge point insertion (top left).\n" - ); - } - } - if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after edge point insertion (bottom left).\n" - ); - } - if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf( - " Clockwise triangle after edge point insertion (bottom right).\n"); - } -#endif /* SELF_CHECK */ - if (verbose > 2) { - printf(" Updating bottom left "); - printtriangle(&botright); - if (mirrorflag) { - printf(" Updating top left "); - printtriangle(&topright); - printf(" Creating top right "); - printtriangle(&newtopright); - } - printf(" Creating bottom right "); - printtriangle(&newbotright); - } - - /* Position `horiz' on the first edge to check for */ - /* the Delaunay property. */ - lnextself(horiz); - } else { - /* Insert the point in a triangle, splitting it into three. */ - lnext(horiz, botleft); - lprev(horiz, botright); - sym(botleft, botlcasing); - sym(botright, botrcasing); - maketriangle(&newbotleft); - maketriangle(&newbotright); - - /* Set the vertices of changed and new triangles. */ - org(horiz, rightpoint); - dest(horiz, leftpoint); - apex(horiz, botpoint); - setorg(newbotleft, leftpoint); - setdest(newbotleft, botpoint); - setapex(newbotleft, insertpoint); - setorg(newbotright, botpoint); - setdest(newbotright, rightpoint); - setapex(newbotright, insertpoint); - setapex(horiz, insertpoint); - for (i = 0; i < eextras; i++) { - /* Set the element attributes of the new triangles. */ - attrib = elemattribute(horiz, i); - setelemattribute(newbotleft, i, attrib); - setelemattribute(newbotright, i, attrib); - } - if (vararea) { - /* Set the area constraint of the new triangles. */ - area = areabound(horiz); - setareabound(newbotleft, area); - setareabound(newbotright, area); - } - - /* There may be shell edges that need to be bonded */ - /* to the new triangles. */ - if (checksegments) { - tspivot(botleft, botlshelle); - if (botlshelle.sh != dummysh) { - tsdissolve(botleft); - tsbond(newbotleft, botlshelle); - } - tspivot(botright, botrshelle); - if (botrshelle.sh != dummysh) { - tsdissolve(botright); - tsbond(newbotright, botrshelle); - } - } - - /* Bond the new triangles to the surrounding triangles. */ - bond(newbotleft, botlcasing); - bond(newbotright, botrcasing); - lnextself(newbotleft); - lprevself(newbotright); - bond(newbotleft, newbotright); - lnextself(newbotleft); - bond(botleft, newbotleft); - lprevself(newbotright); - bond(botright, newbotright); - -#ifdef SELF_CHECK - if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle prior to point insertion.\n"); - } - if (counterclockwise(rightpoint, leftpoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after point insertion (top).\n"); - } - if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after point insertion (left).\n"); - } - if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after point insertion (right).\n"); - } -#endif /* SELF_CHECK */ - if (verbose > 2) { - printf(" Updating top "); - printtriangle(&horiz); - printf(" Creating left "); - printtriangle(&newbotleft); - printf(" Creating right "); - printtriangle(&newbotright); - } - } - - /* The insertion is successful by default, unless an encroached */ - /* edge is found. */ - success = SUCCESSFULPOINT; - /* Circle around the newly inserted vertex, checking each edge opposite */ - /* it for the Delaunay property. Non-Delaunay edges are flipped. */ - /* `horiz' is always the edge being checked. `first' marks where to */ - /* stop circling. */ - org(horiz, first); - rightpoint = first; - dest(horiz, leftpoint); - /* Circle until finished. */ - while (1) { - /* By default, the edge will be flipped. */ - doflip = 1; - if (checksegments) { - /* Check for a segment, which cannot be flipped. */ - tspivot(horiz, checkshelle); - if (checkshelle.sh != dummysh) { - /* The edge is a segment and cannot be flipped. */ - doflip = 0; -#ifndef CDT_ONLY - if (segmentflaws) { - /* Does the new point encroach upon this segment? */ - if (checkedge4encroach(&checkshelle)) { - success = ENCROACHINGPOINT; - } - } -#endif /* not CDT_ONLY */ - } - } - if (doflip) { - /* Check if the edge is a boundary edge. */ - sym(horiz, top); - if (top.tri == dummytri) { - /* The edge is a boundary edge and cannot be flipped. */ - doflip = 0; - } else { - /* Find the point on the other side of the edge. */ - apex(top, farpoint); - /* In the incremental Delaunay triangulation algorithm, any of */ - /* `leftpoint', `rightpoint', and `farpoint' could be vertices */ - /* of the triangular bounding box. These vertices must be */ - /* treated as if they are infinitely distant, even though their */ - /* "coordinates" are not. */ - if ((leftpoint == infpoint1) || (leftpoint == infpoint2) - || (leftpoint == infpoint3)) { - /* `leftpoint' is infinitely distant. Check the convexity of */ - /* the boundary of the triangulation. 'farpoint' might be */ - /* infinite as well, but trust me, this same condition */ - /* should be applied. */ - doflip = counterclockwise(insertpoint, rightpoint, farpoint) > 0.0; - } else if ((rightpoint == infpoint1) || (rightpoint == infpoint2) - || (rightpoint == infpoint3)) { - /* `rightpoint' is infinitely distant. Check the convexity of */ - /* the boundary of the triangulation. 'farpoint' might be */ - /* infinite as well, but trust me, this same condition */ - /* should be applied. */ - doflip = counterclockwise(farpoint, leftpoint, insertpoint) > 0.0; - } else if ((farpoint == infpoint1) || (farpoint == infpoint2) - || (farpoint == infpoint3)) { - /* `farpoint' is infinitely distant and cannot be inside */ - /* the circumcircle of the triangle `horiz'. */ - doflip = 0; - } else { - /* Test whether the edge is locally Delaunay. */ - doflip = incircle(leftpoint, insertpoint, rightpoint, farpoint) - > 0.0; - } - if (doflip) { - /* We made it! Flip the edge `horiz' by rotating its containing */ - /* quadrilateral (the two triangles adjacent to `horiz'). */ - /* Identify the casing of the quadrilateral. */ - lprev(top, topleft); - sym(topleft, toplcasing); - lnext(top, topright); - sym(topright, toprcasing); - lnext(horiz, botleft); - sym(botleft, botlcasing); - lprev(horiz, botright); - sym(botright, botrcasing); - /* Rotate the quadrilateral one-quarter turn counterclockwise. */ - bond(topleft, botlcasing); - bond(botleft, botrcasing); - bond(botright, toprcasing); - bond(topright, toplcasing); - if (checksegments) { - /* Check for shell edges and rebond them to the quadrilateral. */ - tspivot(topleft, toplshelle); - tspivot(botleft, botlshelle); - tspivot(botright, botrshelle); - tspivot(topright, toprshelle); - if (toplshelle.sh == dummysh) { - tsdissolve(topright); - } else { - tsbond(topright, toplshelle); - } - if (botlshelle.sh == dummysh) { - tsdissolve(topleft); - } else { - tsbond(topleft, botlshelle); - } - if (botrshelle.sh == dummysh) { - tsdissolve(botleft); - } else { - tsbond(botleft, botrshelle); - } - if (toprshelle.sh == dummysh) { - tsdissolve(botright); - } else { - tsbond(botright, toprshelle); - } - } - /* New point assignments for the rotated quadrilateral. */ - setorg(horiz, farpoint); - setdest(horiz, insertpoint); - setapex(horiz, rightpoint); - setorg(top, insertpoint); - setdest(top, farpoint); - setapex(top, leftpoint); - for (i = 0; i < eextras; i++) { - /* Take the average of the two triangles' attributes. */ - attrib = (REAL)(0.5 * (elemattribute(top, i) + elemattribute(horiz, i))); - setelemattribute(top, i, attrib); - setelemattribute(horiz, i, attrib); - } - if (vararea) { - if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) { - area = -1.0; - } else { - /* Take the average of the two triangles' area constraints. */ - /* This prevents small area constraints from migrating a */ - /* long, long way from their original location due to flips. */ - area = (REAL)(0.5 * (areabound(top) + areabound(horiz))); - } - setareabound(top, area); - setareabound(horiz, area); - } -#ifdef SELF_CHECK - if (insertpoint != (point) NULL) { - if (counterclockwise(leftpoint, insertpoint, rightpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle prior to edge flip (bottom).\n"); - } - /* The following test has been removed because constrainededge() */ - /* sometimes generates inverted triangles that insertsite() */ - /* removes. */ -/* - if (counterclockwise(rightpoint, farpoint, leftpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle prior to edge flip (top).\n"); - } -*/ - if (counterclockwise(farpoint, leftpoint, insertpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after edge flip (left).\n"); - } - if (counterclockwise(insertpoint, rightpoint, farpoint) < 0.0) { - printf("Internal error in insertsite():\n"); - printf(" Clockwise triangle after edge flip (right).\n"); - } - } -#endif /* SELF_CHECK */ - if (verbose > 2) { - printf(" Edge flip results in left "); - lnextself(topleft); - printtriangle(&topleft); - printf(" and right "); - printtriangle(&horiz); - } - /* On the next iterations, consider the two edges that were */ - /* exposed (this is, are now visible to the newly inserted */ - /* point) by the edge flip. */ - lprevself(horiz); - leftpoint = farpoint; - } - } - } - if (!doflip) { - /* The handle `horiz' is accepted as locally Delaunay. */ -#ifndef CDT_ONLY - if (triflaws) { - /* Check the triangle `horiz' for quality. */ - testtriangle(&horiz); - } -#endif /* not CDT_ONLY */ - /* Look for the next edge around the newly inserted point. */ - lnextself(horiz); - sym(horiz, testtri); - /* Check for finishing a complete revolution about the new point, or */ - /* falling off the edge of the triangulation. The latter will */ - /* happen when a point is inserted at a boundary. */ - if ((leftpoint == first) || (testtri.tri == dummytri)) { - /* We're done. Return a triangle whose origin is the new point. */ - lnext(horiz, *searchtri); - lnext(horiz, recenttri); - return success; - } - /* Finish finding the next edge around the newly inserted point. */ - lnext(testtri, horiz); - rightpoint = leftpoint; - dest(horiz, leftpoint); - } - } -} - -/*****************************************************************************/ -/* */ -/* triangulatepolygon() Find the Delaunay triangulation of a polygon that */ -/* has a certain "nice" shape. This includes the */ -/* polygons that result from deletion of a point or */ -/* insertion of a segment. */ -/* */ -/* This is a conceptually difficult routine. The starting assumption is */ -/* that we have a polygon with n sides. n - 1 of these sides are currently */ -/* represented as edges in the mesh. One side, called the "base", need not */ -/* be. */ -/* */ -/* Inside the polygon is a structure I call a "fan", consisting of n - 1 */ -/* triangles that share a common origin. For each of these triangles, the */ -/* edge opposite the origin is one of the sides of the polygon. The */ -/* primary edge of each triangle is the edge directed from the origin to */ -/* the destination; note that this is not the same edge that is a side of */ -/* the polygon. `firstedge' is the primary edge of the first triangle. */ -/* From there, the triangles follow in counterclockwise order about the */ -/* polygon, until `lastedge', the primary edge of the last triangle. */ -/* `firstedge' and `lastedge' are probably connected to other triangles */ -/* beyond the extremes of the fan, but their identity is not important, as */ -/* long as the fan remains connected to them. */ -/* */ -/* Imagine the polygon oriented so that its base is at the bottom. This */ -/* puts `firstedge' on the far right, and `lastedge' on the far left. */ -/* The right vertex of the base is the destination of `firstedge', and the */ -/* left vertex of the base is the apex of `lastedge'. */ -/* */ -/* The challenge now is to find the right sequence of edge flips to */ -/* transform the fan into a Delaunay triangulation of the polygon. Each */ -/* edge flip effectively removes one triangle from the fan, committing it */ -/* to the polygon. The resulting polygon has one fewer edge. If `doflip' */ -/* is set, the final flip will be performed, resulting in a fan of one */ -/* (useless?) triangle. If `doflip' is not set, the final flip is not */ -/* performed, resulting in a fan of two triangles, and an unfinished */ -/* triangular polygon that is not yet filled out with a single triangle. */ -/* On completion of the routine, `lastedge' is the last remaining triangle, */ -/* or the leftmost of the last two. */ -/* */ -/* Although the flips are performed in the order described above, the */ -/* decisions about what flips to perform are made in precisely the reverse */ -/* order. The recursive triangulatepolygon() procedure makes a decision, */ -/* uses up to two recursive calls to triangulate the "subproblems" */ -/* (polygons with fewer edges), and then performs an edge flip. */ -/* */ -/* The "decision" it makes is which vertex of the polygon should be */ -/* connected to the base. This decision is made by testing every possible */ -/* vertex. Once the best vertex is found, the two edges that connect this */ -/* vertex to the base become the bases for two smaller polygons. These */ -/* are triangulated recursively. Unfortunately, this approach can take */ -/* O(n^2) time not only in the worst case, but in many common cases. It's */ -/* rarely a big deal for point deletion, where n is rarely larger than ten, */ -/* but it could be a big deal for segment insertion, especially if there's */ -/* a lot of long segments that each cut many triangles. I ought to code */ -/* a faster algorithm some time. */ -/* */ -/* The `edgecount' parameter is the number of sides of the polygon, */ -/* including its base. `triflaws' is a flag that determines whether the */ -/* new triangles should be tested for quality, and enqueued if they are */ -/* bad. */ -/* */ -/*****************************************************************************/ - -void triangulatepolygon(firstedge, lastedge, edgecount, doflip, triflaws) -struct triedge *firstedge; -struct triedge *lastedge; -int edgecount; -int doflip; -int triflaws; -{ - struct triedge testtri; - struct triedge besttri; - struct triedge tempedge; - point leftbasepoint, rightbasepoint; - point testpoint; - point bestpoint; - int bestnumber; - int i; - triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ - - /* Identify the base vertices. */ - apex(*lastedge, leftbasepoint); - dest(*firstedge, rightbasepoint); - if (verbose > 2) { - printf(" Triangulating interior polygon at edge\n"); - printf(" (%.12g, %.12g) (%.12g, %.12g)\n", leftbasepoint[0], - leftbasepoint[1], rightbasepoint[0], rightbasepoint[1]); - } - /* Find the best vertex to connect the base to. */ - onext(*firstedge, besttri); - dest(besttri, bestpoint); - triedgecopy(besttri, testtri); - bestnumber = 1; - for (i = 2; i <= edgecount - 2; i++) { - onextself(testtri); - dest(testtri, testpoint); - /* Is this a better vertex? */ - if (incircle(leftbasepoint, rightbasepoint, bestpoint, testpoint) > 0.0) { - triedgecopy(testtri, besttri); - bestpoint = testpoint; - bestnumber = i; - } - } - if (verbose > 2) { - printf(" Connecting edge to (%.12g, %.12g)\n", bestpoint[0], - bestpoint[1]); - } - if (bestnumber > 1) { - /* Recursively triangulate the smaller polygon on the right. */ - oprev(besttri, tempedge); - triangulatepolygon(firstedge, &tempedge, bestnumber + 1, 1, triflaws); - } - if (bestnumber < edgecount - 2) { - /* Recursively triangulate the smaller polygon on the left. */ - sym(besttri, tempedge); - triangulatepolygon(&besttri, lastedge, edgecount - bestnumber, 1, - triflaws); - /* Find `besttri' again; it may have been lost to edge flips. */ - sym(tempedge, besttri); - } - if (doflip) { - /* Do one final edge flip. */ - flip(&besttri); -#ifndef CDT_ONLY - if (triflaws) { - /* Check the quality of the newly committed triangle. */ - sym(besttri, testtri); - testtriangle(&testtri); - } -#endif /* not CDT_ONLY */ - } - /* Return the base triangle. */ - triedgecopy(besttri, *lastedge); -} - -/*****************************************************************************/ -/* */ -/* deletesite() Delete a vertex from a Delaunay triangulation, ensuring */ -/* that the triangulation remains Delaunay. */ -/* */ -/* The origin of `deltri' is deleted. The union of the triangles adjacent */ -/* to this point is a polygon, for which the Delaunay triangulation is */ -/* found. Two triangles are removed from the mesh. */ -/* */ -/* Only interior points that do not lie on segments (shell edges) or */ -/* boundaries may be deleted. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void deletesite(deltri) -struct triedge *deltri; -{ - struct triedge countingtri; - struct triedge firstedge, lastedge; - struct triedge deltriright; - struct triedge lefttri, righttri; - struct triedge leftcasing, rightcasing; - struct edge leftshelle, rightshelle; - point delpoint; - point neworg; - int edgecount; - triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - org(*deltri, delpoint); - if (verbose > 1) { - printf(" Deleting (%.12g, %.12g).\n", delpoint[0], delpoint[1]); - } - pointdealloc(delpoint); - - /* Count the degree of the point being deleted. */ - onext(*deltri, countingtri); - edgecount = 1; - while (!triedgeequal(*deltri, countingtri)) { -#ifdef SELF_CHECK - if (countingtri.tri == dummytri) { - printf("Internal error in deletesite():\n"); - printf(" Attempt to delete boundary point.\n"); - internalerror(); - } -#endif /* SELF_CHECK */ - edgecount++; - onextself(countingtri); - } - -#ifdef SELF_CHECK - if (edgecount < 3) { - printf("Internal error in deletesite():\n Point has degree %d.\n", - edgecount); - internalerror(); - } -#endif /* SELF_CHECK */ - if (edgecount > 3) { - /* Triangulate the polygon defined by the union of all triangles */ - /* adjacent to the point being deleted. Check the quality of */ - /* the resulting triangles. */ - onext(*deltri, firstedge); - oprev(*deltri, lastedge); - triangulatepolygon(&firstedge, &lastedge, edgecount, 0, !nobisect); - } - /* Splice out two triangles. */ - lprev(*deltri, deltriright); - dnext(*deltri, lefttri); - sym(lefttri, leftcasing); - oprev(deltriright, righttri); - sym(righttri, rightcasing); - bond(*deltri, leftcasing); - bond(deltriright, rightcasing); - tspivot(lefttri, leftshelle); - if (leftshelle.sh != dummysh) { - tsbond(*deltri, leftshelle); - } - tspivot(righttri, rightshelle); - if (rightshelle.sh != dummysh) { - tsbond(deltriright, rightshelle); - } - - /* Set the new origin of `deltri' and check its quality. */ - org(lefttri, neworg); - setorg(*deltri, neworg); - if (!nobisect) { - testtriangle(deltri); - } - - /* Delete the two spliced-out triangles. */ - triangledealloc(lefttri.tri); - triangledealloc(righttri.tri); -} - -#endif /* not CDT_ONLY */ - -/** **/ -/** **/ -/********* Mesh transformation routines end here *********/ - -/********* Divide-and-conquer Delaunay triangulation begins here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* The divide-and-conquer bounding box */ -/* */ -/* I originally implemented the divide-and-conquer and incremental Delaunay */ -/* triangulations using the edge-based data structure presented by Guibas */ -/* and Stolfi. Switching to a triangle-based data structure doubled the */ -/* speed. However, I had to think of a few extra tricks to maintain the */ -/* elegance of the original algorithms. */ -/* */ -/* The "bounding box" used by my variant of the divide-and-conquer */ -/* algorithm uses one triangle for each edge of the convex hull of the */ -/* triangulation. These bounding triangles all share a common apical */ -/* vertex, which is represented by NULL and which represents nothing. */ -/* The bounding triangles are linked in a circular fan about this NULL */ -/* vertex, and the edges on the convex hull of the triangulation appear */ -/* opposite the NULL vertex. You might find it easiest to imagine that */ -/* the NULL vertex is a point in 3D space behind the center of the */ -/* triangulation, and that the bounding triangles form a sort of cone. */ -/* */ -/* This bounding box makes it easy to represent degenerate cases. For */ -/* instance, the triangulation of two vertices is a single edge. This edge */ -/* is represented by two bounding box triangles, one on each "side" of the */ -/* edge. These triangles are also linked together in a fan about the NULL */ -/* vertex. */ -/* */ -/* The bounding box also makes it easy to traverse the convex hull, as the */ -/* divide-and-conquer algorithm needs to do. */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* */ -/* pointsort() Sort an array of points by x-coordinate, using the */ -/* y-coordinate as a secondary key. */ -/* */ -/* Uses quicksort. Randomized O(n log n) time. No, I did not make any of */ -/* the usual quicksort mistakes. */ -/* */ -/*****************************************************************************/ - -void pointsort(sortarray, arraysize) -point *sortarray; -int arraysize; -{ - int left, right; - int pivot; - REAL pivotx, pivoty; - point temp; - - if (arraysize == 2) { - /* Recursive base case. */ - if ((sortarray[0][0] > sortarray[1][0]) || - ((sortarray[0][0] == sortarray[1][0]) && - (sortarray[0][1] > sortarray[1][1]))) { - temp = sortarray[1]; - sortarray[1] = sortarray[0]; - sortarray[0] = temp; - } - return; - } - /* Choose a random pivot to split the array. */ - pivot = (int) randomnation(arraysize); - pivotx = sortarray[pivot][0]; - pivoty = sortarray[pivot][1]; - /* Split the array. */ - left = -1; - right = arraysize; - while (left < right) { - /* Search for a point whose x-coordinate is too large for the left. */ - do { - left++; - } while ((left <= right) && ((sortarray[left][0] < pivotx) || - ((sortarray[left][0] == pivotx) && - (sortarray[left][1] < pivoty)))); - /* Search for a point whose x-coordinate is too small for the right. */ - do { - right--; - } while ((left <= right) && ((sortarray[right][0] > pivotx) || - ((sortarray[right][0] == pivotx) && - (sortarray[right][1] > pivoty)))); - if (left < right) { - /* Swap the left and right points. */ - temp = sortarray[left]; - sortarray[left] = sortarray[right]; - sortarray[right] = temp; - } - } - if (left > 1) { - /* Recursively sort the left subset. */ - pointsort(sortarray, left); - } - if (right < arraysize - 2) { - /* Recursively sort the right subset. */ - pointsort(&sortarray[right + 1], arraysize - right - 1); - } -} - -/*****************************************************************************/ -/* */ -/* pointmedian() An order statistic algorithm, almost. Shuffles an array */ -/* of points so that the first `median' points occur */ -/* lexicographically before the remaining points. */ -/* */ -/* Uses the x-coordinate as the primary key if axis == 0; the y-coordinate */ -/* if axis == 1. Very similar to the pointsort() procedure, but runs in */ -/* randomized linear time. */ -/* */ -/*****************************************************************************/ - -void pointmedian(sortarray, arraysize, median, axis) -point *sortarray; -int arraysize; -int median; -int axis; -{ - int left, right; - int pivot; - REAL pivot1, pivot2; - point temp; - - if (arraysize == 2) { - /* Recursive base case. */ - if ((sortarray[0][axis] > sortarray[1][axis]) || - ((sortarray[0][axis] == sortarray[1][axis]) && - (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) { - temp = sortarray[1]; - sortarray[1] = sortarray[0]; - sortarray[0] = temp; - } - return; - } - /* Choose a random pivot to split the array. */ - pivot = (int) randomnation(arraysize); - pivot1 = sortarray[pivot][axis]; - pivot2 = sortarray[pivot][1 - axis]; - /* Split the array. */ - left = -1; - right = arraysize; - while (left < right) { - /* Search for a point whose x-coordinate is too large for the left. */ - do { - left++; - } while ((left <= right) && ((sortarray[left][axis] < pivot1) || - ((sortarray[left][axis] == pivot1) && - (sortarray[left][1 - axis] < pivot2)))); - /* Search for a point whose x-coordinate is too small for the right. */ - do { - right--; - } while ((left <= right) && ((sortarray[right][axis] > pivot1) || - ((sortarray[right][axis] == pivot1) && - (sortarray[right][1 - axis] > pivot2)))); - if (left < right) { - /* Swap the left and right points. */ - temp = sortarray[left]; - sortarray[left] = sortarray[right]; - sortarray[right] = temp; - } - } - /* Unlike in pointsort(), at most one of the following */ - /* conditionals is true. */ - if (left > median) { - /* Recursively shuffle the left subset. */ - pointmedian(sortarray, left, median, axis); - } - if (right < median - 1) { - /* Recursively shuffle the right subset. */ - pointmedian(&sortarray[right + 1], arraysize - right - 1, - median - right - 1, axis); - } -} - -/*****************************************************************************/ -/* */ -/* alternateaxes() Sorts the points as appropriate for the divide-and- */ -/* conquer algorithm with alternating cuts. */ -/* */ -/* Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1. */ -/* For the base case, subsets containing only two or three points are */ -/* always sorted by x-coordinate. */ -/* */ -/*****************************************************************************/ - -void alternateaxes(sortarray, arraysize, axis) -point *sortarray; -int arraysize; -int axis; -{ - int divider; - - divider = arraysize >> 1; - if (arraysize <= 3) { - /* Recursive base case: subsets of two or three points will be */ - /* handled specially, and should always be sorted by x-coordinate. */ - axis = 0; - } - /* Partition with a horizontal or vertical cut. */ - pointmedian(sortarray, arraysize, divider, axis); - /* Recursively partition the subsets with a cross cut. */ - if (arraysize - divider >= 2) { - if (divider >= 2) { - alternateaxes(sortarray, divider, 1 - axis); - } - alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis); - } -} - -/*****************************************************************************/ -/* */ -/* mergehulls() Merge two adjacent Delaunay triangulations into a */ -/* single Delaunay triangulation. */ -/* */ -/* This is similar to the algorithm given by Guibas and Stolfi, but uses */ -/* a triangle-based, rather than edge-based, data structure. */ -/* */ -/* The algorithm walks up the gap between the two triangulations, knitting */ -/* them together. As they are merged, some of their bounding triangles */ -/* are converted into real triangles of the triangulation. The procedure */ -/* pulls each hull's bounding triangles apart, then knits them together */ -/* like the teeth of two gears. The Delaunay property determines, at each */ -/* step, whether the next "tooth" is a bounding triangle of the left hull */ -/* or the right. When a bounding triangle becomes real, its apex is */ -/* changed from NULL to a real point. */ -/* */ -/* Only two new triangles need to be allocated. These become new bounding */ -/* triangles at the top and bottom of the seam. They are used to connect */ -/* the remaining bounding triangles (those that have not been converted */ -/* into real triangles) into a single fan. */ -/* */ -/* On entry, `farleft' and `innerleft' are bounding triangles of the left */ -/* triangulation. The origin of `farleft' is the leftmost vertex, and */ -/* the destination of `innerleft' is the rightmost vertex of the */ -/* triangulation. Similarly, `innerright' and `farright' are bounding */ -/* triangles of the right triangulation. The origin of `innerright' and */ -/* destination of `farright' are the leftmost and rightmost vertices. */ -/* */ -/* On completion, the origin of `farleft' is the leftmost vertex of the */ -/* merged triangulation, and the destination of `farright' is the rightmost */ -/* vertex. */ -/* */ -/*****************************************************************************/ - -void mergehulls(farleft, innerleft, innerright, farright, axis) -struct triedge *farleft; -struct triedge *innerleft; -struct triedge *innerright; -struct triedge *farright; -int axis; -{ - struct triedge leftcand, rightcand; - struct triedge baseedge; - struct triedge nextedge; - struct triedge sidecasing, topcasing, outercasing; - struct triedge checkedge; - point innerleftdest; - point innerrightorg; - point innerleftapex, innerrightapex; - point farleftpt, farrightpt; - point farleftapex, farrightapex; - point lowerleft, lowerright; - point upperleft, upperright; - point nextapex; - point checkvertex; - int changemade; - int badedge; - int leftfinished, rightfinished; - triangle ptr; /* Temporary variable used by sym(). */ - - dest(*innerleft, innerleftdest); - apex(*innerleft, innerleftapex); - org(*innerright, innerrightorg); - apex(*innerright, innerrightapex); - /* Special treatment for horizontal cuts. */ - if (dwyer && (axis == 1)) { - org(*farleft, farleftpt); - apex(*farleft, farleftapex); - dest(*farright, farrightpt); - apex(*farright, farrightapex); - /* The pointers to the extremal points are shifted to point to the */ - /* topmost and bottommost point of each hull, rather than the */ - /* leftmost and rightmost points. */ - while (farleftapex[1] < farleftpt[1]) { - lnextself(*farleft); - symself(*farleft); - farleftpt = farleftapex; - apex(*farleft, farleftapex); - } - sym(*innerleft, checkedge); - apex(checkedge, checkvertex); - while (checkvertex[1] > innerleftdest[1]) { - lnext(checkedge, *innerleft); - innerleftapex = innerleftdest; - innerleftdest = checkvertex; - sym(*innerleft, checkedge); - apex(checkedge, checkvertex); - } - while (innerrightapex[1] < innerrightorg[1]) { - lnextself(*innerright); - symself(*innerright); - innerrightorg = innerrightapex; - apex(*innerright, innerrightapex); - } - sym(*farright, checkedge); - apex(checkedge, checkvertex); - while (checkvertex[1] > farrightpt[1]) { - lnext(checkedge, *farright); - farrightapex = farrightpt; - farrightpt = checkvertex; - sym(*farright, checkedge); - apex(checkedge, checkvertex); - } - } - /* Find a line tangent to and below both hulls. */ - do { - changemade = 0; - /* Make innerleftdest the "bottommost" point of the left hull. */ - if (counterclockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0) { - lprevself(*innerleft); - symself(*innerleft); - innerleftdest = innerleftapex; - apex(*innerleft, innerleftapex); - changemade = 1; - } - /* Make innerrightorg the "bottommost" point of the right hull. */ - if (counterclockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0) { - lnextself(*innerright); - symself(*innerright); - innerrightorg = innerrightapex; - apex(*innerright, innerrightapex); - changemade = 1; - } - } while (changemade); - /* Find the two candidates to be the next "gear tooth". */ - sym(*innerleft, leftcand); - sym(*innerright, rightcand); - /* Create the bottom new bounding triangle. */ - maketriangle(&baseedge); - /* Connect it to the bounding boxes of the left and right triangulations. */ - bond(baseedge, *innerleft); - lnextself(baseedge); - bond(baseedge, *innerright); - lnextself(baseedge); - setorg(baseedge, innerrightorg); - setdest(baseedge, innerleftdest); - /* Apex is intentionally left NULL. */ - if (verbose > 2) { - printf(" Creating base bounding "); - printtriangle(&baseedge); - } - /* Fix the extreme triangles if necessary. */ - org(*farleft, farleftpt); - if (innerleftdest == farleftpt) { - lnext(baseedge, *farleft); - } - dest(*farright, farrightpt); - if (innerrightorg == farrightpt) { - lprev(baseedge, *farright); - } - /* The vertices of the current knitting edge. */ - lowerleft = innerleftdest; - lowerright = innerrightorg; - /* The candidate vertices for knitting. */ - apex(leftcand, upperleft); - apex(rightcand, upperright); - /* Walk up the gap between the two triangulations, knitting them together. */ - while (1) { - /* Have we reached the top? (This isn't quite the right question, */ - /* because even though the left triangulation might seem finished now, */ - /* moving up on the right triangulation might reveal a new point of */ - /* the left triangulation. And vice-versa.) */ - leftfinished = counterclockwise(upperleft, lowerleft, lowerright) <= 0.0; - rightfinished = counterclockwise(upperright, lowerleft, lowerright) <= 0.0; - if (leftfinished && rightfinished) { - /* Create the top new bounding triangle. */ - maketriangle(&nextedge); - setorg(nextedge, lowerleft); - setdest(nextedge, lowerright); - /* Apex is intentionally left NULL. */ - /* Connect it to the bounding boxes of the two triangulations. */ - bond(nextedge, baseedge); - lnextself(nextedge); - bond(nextedge, rightcand); - lnextself(nextedge); - bond(nextedge, leftcand); - if (verbose > 2) { - printf(" Creating top bounding "); - printtriangle(&baseedge); - } - /* Special treatment for horizontal cuts. */ - if (dwyer && (axis == 1)) { - org(*farleft, farleftpt); - apex(*farleft, farleftapex); - dest(*farright, farrightpt); - apex(*farright, farrightapex); - sym(*farleft, checkedge); - apex(checkedge, checkvertex); - /* The pointers to the extremal points are restored to the leftmost */ - /* and rightmost points (rather than topmost and bottommost). */ - while (checkvertex[0] < farleftpt[0]) { - lprev(checkedge, *farleft); - farleftapex = farleftpt; - farleftpt = checkvertex; - sym(*farleft, checkedge); - apex(checkedge, checkvertex); - } - while (farrightapex[0] > farrightpt[0]) { - lprevself(*farright); - symself(*farright); - farrightpt = farrightapex; - apex(*farright, farrightapex); - } - } - return; - } - /* Consider eliminating edges from the left triangulation. */ - if (!leftfinished) { - /* What vertex would be exposed if an edge were deleted? */ - lprev(leftcand, nextedge); - symself(nextedge); - apex(nextedge, nextapex); - /* If nextapex is NULL, then no vertex would be exposed; the */ - /* triangulation would have been eaten right through. */ - if (nextapex != (point) NULL) { - /* Check whether the edge is Delaunay. */ - badedge = incircle(lowerleft, lowerright, upperleft, nextapex) > 0.0; - while (badedge) { - /* Eliminate the edge with an edge flip. As a result, the */ - /* left triangulation will have one more boundary triangle. */ - lnextself(nextedge); - sym(nextedge, topcasing); - lnextself(nextedge); - sym(nextedge, sidecasing); - bond(nextedge, topcasing); - bond(leftcand, sidecasing); - lnextself(leftcand); - sym(leftcand, outercasing); - lprevself(nextedge); - bond(nextedge, outercasing); - /* Correct the vertices to reflect the edge flip. */ - setorg(leftcand, lowerleft); - setdest(leftcand, NULL); - setapex(leftcand, nextapex); - setorg(nextedge, NULL); - setdest(nextedge, upperleft); - setapex(nextedge, nextapex); - /* Consider the newly exposed vertex. */ - upperleft = nextapex; - /* What vertex would be exposed if another edge were deleted? */ - triedgecopy(sidecasing, nextedge); - apex(nextedge, nextapex); - if (nextapex != (point) NULL) { - /* Check whether the edge is Delaunay. */ - badedge = incircle(lowerleft, lowerright, upperleft, nextapex) - > 0.0; - } else { - /* Avoid eating right through the triangulation. */ - badedge = 0; - } - } - } - } - /* Consider eliminating edges from the right triangulation. */ - if (!rightfinished) { - /* What vertex would be exposed if an edge were deleted? */ - lnext(rightcand, nextedge); - symself(nextedge); - apex(nextedge, nextapex); - /* If nextapex is NULL, then no vertex would be exposed; the */ - /* triangulation would have been eaten right through. */ - if (nextapex != (point) NULL) { - /* Check whether the edge is Delaunay. */ - badedge = incircle(lowerleft, lowerright, upperright, nextapex) > 0.0; - while (badedge) { - /* Eliminate the edge with an edge flip. As a result, the */ - /* right triangulation will have one more boundary triangle. */ - lprevself(nextedge); - sym(nextedge, topcasing); - lprevself(nextedge); - sym(nextedge, sidecasing); - bond(nextedge, topcasing); - bond(rightcand, sidecasing); - lprevself(rightcand); - sym(rightcand, outercasing); - lnextself(nextedge); - bond(nextedge, outercasing); - /* Correct the vertices to reflect the edge flip. */ - setorg(rightcand, NULL); - setdest(rightcand, lowerright); - setapex(rightcand, nextapex); - setorg(nextedge, upperright); - setdest(nextedge, NULL); - setapex(nextedge, nextapex); - /* Consider the newly exposed vertex. */ - upperright = nextapex; - /* What vertex would be exposed if another edge were deleted? */ - triedgecopy(sidecasing, nextedge); - apex(nextedge, nextapex); - if (nextapex != (point) NULL) { - /* Check whether the edge is Delaunay. */ - badedge = incircle(lowerleft, lowerright, upperright, nextapex) - > 0.0; - } else { - /* Avoid eating right through the triangulation. */ - badedge = 0; - } - } - } - } - if (leftfinished || (!rightfinished && - (incircle(upperleft, lowerleft, lowerright, upperright) > 0.0))) { - /* Knit the triangulations, adding an edge from `lowerleft' */ - /* to `upperright'. */ - bond(baseedge, rightcand); - lprev(rightcand, baseedge); - setdest(baseedge, lowerleft); - lowerright = upperright; - sym(baseedge, rightcand); - apex(rightcand, upperright); - } else { - /* Knit the triangulations, adding an edge from `upperleft' */ - /* to `lowerright'. */ - bond(baseedge, leftcand); - lnext(leftcand, baseedge); - setorg(baseedge, lowerright); - lowerleft = upperleft; - sym(baseedge, leftcand); - apex(leftcand, upperleft); - } - if (verbose > 2) { - printf(" Connecting "); - printtriangle(&baseedge); - } - } -} - -/*****************************************************************************/ -/* */ -/* divconqrecurse() Recursively form a Delaunay triangulation by the */ -/* divide-and-conquer method. */ -/* */ -/* Recursively breaks down the problem into smaller pieces, which are */ -/* knitted together by mergehulls(). The base cases (problems of two or */ -/* three points) are handled specially here. */ -/* */ -/* On completion, `farleft' and `farright' are bounding triangles such that */ -/* the origin of `farleft' is the leftmost vertex (breaking ties by */ -/* choosing the highest leftmost vertex), and the destination of */ -/* `farright' is the rightmost vertex (breaking ties by choosing the */ -/* lowest rightmost vertex). */ -/* */ -/*****************************************************************************/ - -void divconqrecurse(sortarray, vertices, axis, farleft, farright) -point *sortarray; -int vertices; -int axis; -struct triedge *farleft; -struct triedge *farright; -{ - struct triedge midtri, tri1, tri2, tri3; - struct triedge innerleft, innerright; - REAL area; - int divider; - - if (verbose > 2) { - printf(" Triangulating %d points.\n", vertices); - } - if (vertices == 2) { - /* The triangulation of two vertices is an edge. An edge is */ - /* represented by two bounding triangles. */ - maketriangle(farleft); - setorg(*farleft, sortarray[0]); - setdest(*farleft, sortarray[1]); - /* The apex is intentionally left NULL. */ - maketriangle(farright); - setorg(*farright, sortarray[1]); - setdest(*farright, sortarray[0]); - /* The apex is intentionally left NULL. */ - bond(*farleft, *farright); - lprevself(*farleft); - lnextself(*farright); - bond(*farleft, *farright); - lprevself(*farleft); - lnextself(*farright); - bond(*farleft, *farright); - if (verbose > 2) { - printf(" Creating "); - printtriangle(farleft); - printf(" Creating "); - printtriangle(farright); - } - /* Ensure that the origin of `farleft' is sortarray[0]. */ - lprev(*farright, *farleft); - return; - } else if (vertices == 3) { - /* The triangulation of three vertices is either a triangle (with */ - /* three bounding triangles) or two edges (with four bounding */ - /* triangles). In either case, four triangles are created. */ - maketriangle(&midtri); - maketriangle(&tri1); - maketriangle(&tri2); - maketriangle(&tri3); - area = counterclockwise(sortarray[0], sortarray[1], sortarray[2]); - if (area == 0.0) { - /* Three collinear points; the triangulation is two edges. */ - setorg(midtri, sortarray[0]); - setdest(midtri, sortarray[1]); - setorg(tri1, sortarray[1]); - setdest(tri1, sortarray[0]); - setorg(tri2, sortarray[2]); - setdest(tri2, sortarray[1]); - setorg(tri3, sortarray[1]); - setdest(tri3, sortarray[2]); - /* All apices are intentionally left NULL. */ - bond(midtri, tri1); - bond(tri2, tri3); - lnextself(midtri); - lprevself(tri1); - lnextself(tri2); - lprevself(tri3); - bond(midtri, tri3); - bond(tri1, tri2); - lnextself(midtri); - lprevself(tri1); - lnextself(tri2); - lprevself(tri3); - bond(midtri, tri1); - bond(tri2, tri3); - /* Ensure that the origin of `farleft' is sortarray[0]. */ - triedgecopy(tri1, *farleft); - /* Ensure that the destination of `farright' is sortarray[2]. */ - triedgecopy(tri2, *farright); - } else { - /* The three points are not collinear; the triangulation is one */ - /* triangle, namely `midtri'. */ - setorg(midtri, sortarray[0]); - setdest(tri1, sortarray[0]); - setorg(tri3, sortarray[0]); - /* Apices of tri1, tri2, and tri3 are left NULL. */ - if (area > 0.0) { - /* The vertices are in counterclockwise order. */ - setdest(midtri, sortarray[1]); - setorg(tri1, sortarray[1]); - setdest(tri2, sortarray[1]); - setapex(midtri, sortarray[2]); - setorg(tri2, sortarray[2]); - setdest(tri3, sortarray[2]); - } else { - /* The vertices are in clockwise order. */ - setdest(midtri, sortarray[2]); - setorg(tri1, sortarray[2]); - setdest(tri2, sortarray[2]); - setapex(midtri, sortarray[1]); - setorg(tri2, sortarray[1]); - setdest(tri3, sortarray[1]); - } - /* The topology does not depend on how the vertices are ordered. */ - bond(midtri, tri1); - lnextself(midtri); - bond(midtri, tri2); - lnextself(midtri); - bond(midtri, tri3); - lprevself(tri1); - lnextself(tri2); - bond(tri1, tri2); - lprevself(tri1); - lprevself(tri3); - bond(tri1, tri3); - lnextself(tri2); - lprevself(tri3); - bond(tri2, tri3); - /* Ensure that the origin of `farleft' is sortarray[0]. */ - triedgecopy(tri1, *farleft); - /* Ensure that the destination of `farright' is sortarray[2]. */ - if (area > 0.0) { - triedgecopy(tri2, *farright); - } else { - lnext(*farleft, *farright); - } - } - if (verbose > 2) { - printf(" Creating "); - printtriangle(&midtri); - printf(" Creating "); - printtriangle(&tri1); - printf(" Creating "); - printtriangle(&tri2); - printf(" Creating "); - printtriangle(&tri3); - } - return; - } else { - /* Split the vertices in half. */ - divider = vertices >> 1; - /* Recursively triangulate each half. */ - divconqrecurse(sortarray, divider, 1 - axis, farleft, &innerleft); - divconqrecurse(&sortarray[divider], vertices - divider, 1 - axis, - &innerright, farright); - if (verbose > 1) { - printf(" Joining triangulations with %d and %d vertices.\n", divider, - vertices - divider); - } - /* Merge the two triangulations into one. */ - mergehulls(farleft, &innerleft, &innerright, farright, axis); - } -} - -long removeghosts(startghost) -struct triedge *startghost; -{ - struct triedge searchedge; - struct triedge dissolveedge; - struct triedge deadtri; - point markorg; - long hullsize; - triangle ptr; /* Temporary variable used by sym(). */ - - if (verbose) { - printf(" Removing ghost triangles.\n"); - } - /* Find an edge on the convex hull to start point location from. */ - lprev(*startghost, searchedge); - symself(searchedge); - dummytri[0] = encode(searchedge); - /* Remove the bounding box and count the convex hull edges. */ - triedgecopy(*startghost, dissolveedge); - hullsize = 0; - do { - hullsize++; - lnext(dissolveedge, deadtri); - lprevself(dissolveedge); - symself(dissolveedge); - /* If no PSLG is involved, set the boundary markers of all the points */ - /* on the convex hull. If a PSLG is used, this step is done later. */ - if (!poly) { - /* Watch out for the case where all the input points are collinear. */ - if (dissolveedge.tri != dummytri) { - org(dissolveedge, markorg); - if (pointmark(markorg) == 0) { - setpointmark(markorg, 1); - } - } - } - /* Remove a bounding triangle from a convex hull triangle. */ - dissolve(dissolveedge); - /* Find the next bounding triangle. */ - sym(deadtri, dissolveedge); - /* Delete the bounding triangle. */ - triangledealloc(deadtri.tri); - } while (!triedgeequal(dissolveedge, *startghost)); - return hullsize; -} - -/*****************************************************************************/ -/* */ -/* divconqdelaunay() Form a Delaunay triangulation by the divide-and- */ -/* conquer method. */ -/* */ -/* Sorts the points, calls a recursive procedure to triangulate them, and */ -/* removes the bounding box, setting boundary markers as appropriate. */ -/* */ -/*****************************************************************************/ - -long divconqdelaunay() -{ - point *sortarray; - struct triedge hullleft, hullright; - int divider; - int i, j; - - /* Allocate an array of pointers to points for sorting. */ - sortarray = (point *) malloc(inpoints * sizeof(point)); - if (sortarray == (point *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - traversalinit(&points); - for (i = 0; i < inpoints; i++) { - sortarray[i] = pointtraverse(); - } - if (verbose) { - printf(" Sorting points.\n"); - } - /* Sort the points. */ - pointsort(sortarray, inpoints); - /* Discard duplicate points, which can really mess up the algorithm. */ - i = 0; - for (j = 1; j < inpoints; j++) { - if ((sortarray[i][0] == sortarray[j][0]) - && (sortarray[i][1] == sortarray[j][1])) { - if (!quiet) { - printf( -"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", - sortarray[j][0], sortarray[j][1]); - } -/* Commented out - would eliminate point from output .node file, but causes - a failure if some segment has this point as an endpoint. - setpointmark(sortarray[j], DEADPOINT); -*/ - } else { - i++; - sortarray[i] = sortarray[j]; - } - } - i++; - if (dwyer) { - /* Re-sort the array of points to accommodate alternating cuts. */ - divider = i >> 1; - if (i - divider >= 2) { - if (divider >= 2) { - alternateaxes(sortarray, divider, 1); - } - alternateaxes(&sortarray[divider], i - divider, 1); - } - } - if (verbose) { - printf(" Forming triangulation.\n"); - } - /* Form the Delaunay triangulation. */ - divconqrecurse(sortarray, i, 0, &hullleft, &hullright); - free(sortarray); - - return removeghosts(&hullleft); -} - -/** **/ -/** **/ -/********* Divide-and-conquer Delaunay triangulation ends here *********/ - -/********* Incremental Delaunay triangulation begins here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* boundingbox() Form an "infinite" bounding triangle to insert points */ -/* into. */ -/* */ -/* The points at "infinity" are assigned finite coordinates, which are used */ -/* by the point location routines, but (mostly) ignored by the Delaunay */ -/* edge flip routines. */ -/* */ -/*****************************************************************************/ - -#ifndef REDUCED - -void boundingbox() -{ - struct triedge inftri; /* Handle for the triangular bounding box. */ - REAL width; - - if (verbose) { - printf(" Creating triangular bounding box.\n"); - } - /* Find the width (or height, whichever is larger) of the triangulation. */ - width = xmax - xmin; - if (ymax - ymin > width) { - width = ymax - ymin; - } - if (width == 0.0) { - width = 1.0; - } - /* Create the vertices of the bounding box. */ - infpoint1 = (point) malloc(points.itembytes); - infpoint2 = (point) malloc(points.itembytes); - infpoint3 = (point) malloc(points.itembytes); - if ((infpoint1 == (point) NULL) || (infpoint2 == (point) NULL) - || (infpoint3 == (point) NULL)) { - printf("Error: Out of memory.\n"); - exit(1); - } - infpoint1[0] = xmin - 50.0 * width; - infpoint1[1] = ymin - 40.0 * width; - infpoint2[0] = xmax + 50.0 * width; - infpoint2[1] = ymin - 40.0 * width; - infpoint3[0] = 0.5 * (xmin + xmax); - infpoint3[1] = ymax + 60.0 * width; - - /* Create the bounding box. */ - maketriangle(&inftri); - setorg(inftri, infpoint1); - setdest(inftri, infpoint2); - setapex(inftri, infpoint3); - /* Link dummytri to the bounding box so we can always find an */ - /* edge to begin searching (point location) from. */ - dummytri[0] = (triangle) inftri.tri; - if (verbose > 2) { - printf(" Creating "); - printtriangle(&inftri); - } -} - -#endif /* not REDUCED */ - -/*****************************************************************************/ -/* */ -/* removebox() Remove the "infinite" bounding triangle, setting boundary */ -/* markers as appropriate. */ -/* */ -/* The triangular bounding box has three boundary triangles (one for each */ -/* side of the bounding box), and a bunch of triangles fanning out from */ -/* the three bounding box vertices (one triangle for each edge of the */ -/* convex hull of the inner mesh). This routine removes these triangles. */ -/* */ -/*****************************************************************************/ - -#ifndef REDUCED - -long removebox() -{ - struct triedge deadtri; - struct triedge searchedge; - struct triedge checkedge; - struct triedge nextedge, finaledge, dissolveedge; - point markorg; - long hullsize; - triangle ptr; /* Temporary variable used by sym(). */ - - if (verbose) { - printf(" Removing triangular bounding box.\n"); - } - /* Find a boundary triangle. */ - nextedge.tri = dummytri; - nextedge.orient = 0; - symself(nextedge); - /* Mark a place to stop. */ - lprev(nextedge, finaledge); - lnextself(nextedge); - symself(nextedge); - /* Find a triangle (on the boundary of the point set) that isn't */ - /* a bounding box triangle. */ - lprev(nextedge, searchedge); - symself(searchedge); - /* Check whether nextedge is another boundary triangle */ - /* adjacent to the first one. */ - lnext(nextedge, checkedge); - symself(checkedge); - if (checkedge.tri == dummytri) { - /* Go on to the next triangle. There are only three boundary */ - /* triangles, and this next triangle cannot be the third one, */ - /* so it's safe to stop here. */ - lprevself(searchedge); - symself(searchedge); - } - /* Find a new boundary edge to search from, as the current search */ - /* edge lies on a bounding box triangle and will be deleted. */ - dummytri[0] = encode(searchedge); - hullsize = -2l; - while (!triedgeequal(nextedge, finaledge)) { - hullsize++; - lprev(nextedge, dissolveedge); - symself(dissolveedge); - /* If not using a PSLG, the vertices should be marked now. */ - /* (If using a PSLG, markhull() will do the job.) */ - if (!poly) { - /* Be careful! One must check for the case where all the input */ - /* points are collinear, and thus all the triangles are part of */ - /* the bounding box. Otherwise, the setpointmark() call below */ - /* will cause a bad pointer reference. */ - if (dissolveedge.tri != dummytri) { - org(dissolveedge, markorg); - if (pointmark(markorg) == 0) { - setpointmark(markorg, 1); - } - } - } - /* Disconnect the bounding box triangle from the mesh triangle. */ - dissolve(dissolveedge); - lnext(nextedge, deadtri); - sym(deadtri, nextedge); - /* Get rid of the bounding box triangle. */ - triangledealloc(deadtri.tri); - /* Do we need to turn the corner? */ - if (nextedge.tri == dummytri) { - /* Turn the corner. */ - triedgecopy(dissolveedge, nextedge); - } - } - triangledealloc(finaledge.tri); - - free(infpoint1); /* Deallocate the bounding box vertices. */ - free(infpoint2); - free(infpoint3); - - return hullsize; -} - -#endif /* not REDUCED */ - -/*****************************************************************************/ -/* */ -/* incrementaldelaunay() Form a Delaunay triangulation by incrementally */ -/* adding vertices. */ -/* */ -/*****************************************************************************/ - -#ifndef REDUCED - -long incrementaldelaunay() -{ - struct triedge starttri; - point pointloop; - int i; - - /* Create a triangular bounding box. */ - boundingbox(); - if (verbose) { - printf(" Incrementally inserting points.\n"); - } - traversalinit(&points); - pointloop = pointtraverse(); - i = 1; - while (pointloop != (point) NULL) { - /* Find a boundary triangle to search from. */ - starttri.tri = (triangle *) NULL; - if (insertsite(pointloop, &starttri, (struct edge *) NULL, 0, 0) == - DUPLICATEPOINT) { - if (!quiet) { - printf( -"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", - pointloop[0], pointloop[1]); - } -/* Commented out - would eliminate point from output .node file. - setpointmark(pointloop, DEADPOINT); -*/ - } - pointloop = pointtraverse(); - i++; - } - /* Remove the bounding box. */ - return removebox(); -} - -#endif /* not REDUCED */ - -/** **/ -/** **/ -/********* Incremental Delaunay triangulation ends here *********/ - -/********* Sweepline Delaunay triangulation begins here *********/ -/** **/ -/** **/ - -#ifndef REDUCED - -void eventheapinsert(heap, heapsize, newevent) -struct event **heap; -int heapsize; -struct event *newevent; -{ - REAL eventx, eventy; - int eventnum; - int parent; - int notdone; - - eventx = newevent->xkey; - eventy = newevent->ykey; - eventnum = heapsize; - notdone = eventnum > 0; - while (notdone) { - parent = (eventnum - 1) >> 1; - if ((heap[parent]->ykey < eventy) || - ((heap[parent]->ykey == eventy) - && (heap[parent]->xkey <= eventx))) { - notdone = 0; - } else { - heap[eventnum] = heap[parent]; - heap[eventnum]->heapposition = eventnum; - - eventnum = parent; - notdone = eventnum > 0; - } - } - heap[eventnum] = newevent; - newevent->heapposition = eventnum; -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -void eventheapify(heap, heapsize, eventnum) -struct event **heap; -int heapsize; -int eventnum; -{ - struct event *thisevent; - REAL eventx, eventy; - int leftchild, rightchild; - int smallest; - int notdone; - - thisevent = heap[eventnum]; - eventx = thisevent->xkey; - eventy = thisevent->ykey; - leftchild = 2 * eventnum + 1; - notdone = leftchild < heapsize; - while (notdone) { - if ((heap[leftchild]->ykey < eventy) || - ((heap[leftchild]->ykey == eventy) - && (heap[leftchild]->xkey < eventx))) { - smallest = leftchild; - } else { - smallest = eventnum; - } - rightchild = leftchild + 1; - if (rightchild < heapsize) { - if ((heap[rightchild]->ykey < heap[smallest]->ykey) || - ((heap[rightchild]->ykey == heap[smallest]->ykey) - && (heap[rightchild]->xkey < heap[smallest]->xkey))) { - smallest = rightchild; - } - } - if (smallest == eventnum) { - notdone = 0; - } else { - heap[eventnum] = heap[smallest]; - heap[eventnum]->heapposition = eventnum; - heap[smallest] = thisevent; - thisevent->heapposition = smallest; - - eventnum = smallest; - leftchild = 2 * eventnum + 1; - notdone = leftchild < heapsize; - } - } -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -void eventheapdelete(heap, heapsize, eventnum) -struct event **heap; -int heapsize; -int eventnum; -{ - struct event *moveevent; - REAL eventx, eventy; - int parent; - int notdone; - - moveevent = heap[heapsize - 1]; - if (eventnum > 0) { - eventx = moveevent->xkey; - eventy = moveevent->ykey; - do { - parent = (eventnum - 1) >> 1; - if ((heap[parent]->ykey < eventy) || - ((heap[parent]->ykey == eventy) - && (heap[parent]->xkey <= eventx))) { - notdone = 0; - } else { - heap[eventnum] = heap[parent]; - heap[eventnum]->heapposition = eventnum; - - eventnum = parent; - notdone = eventnum > 0; - } - } while (notdone); - } - heap[eventnum] = moveevent; - moveevent->heapposition = eventnum; - eventheapify(heap, heapsize - 1, eventnum); -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -void createeventheap(eventheap, events, freeevents) -struct event ***eventheap; -struct event **events; -struct event **freeevents; -{ - point thispoint; - int maxevents; - int i; - - maxevents = (3 * inpoints) / 2; - *eventheap = (struct event **) malloc(maxevents * sizeof(struct event *)); - if (*eventheap == (struct event **) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - *events = (struct event *) malloc(maxevents * sizeof(struct event)); - if (*events == (struct event *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - traversalinit(&points); - for (i = 0; i < inpoints; i++) { - thispoint = pointtraverse(); - (*events)[i].eventptr = (VOID *) thispoint; - (*events)[i].xkey = thispoint[0]; - (*events)[i].ykey = thispoint[1]; - eventheapinsert(*eventheap, i, *events + i); - } - *freeevents = (struct event *) NULL; - for (i = maxevents - 1; i >= inpoints; i--) { - (*events)[i].eventptr = (VOID *) *freeevents; - *freeevents = *events + i; - } -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -int rightofhyperbola(fronttri, newsite) -struct triedge *fronttri; -point newsite; -{ - point leftpoint, rightpoint; - REAL dxa, dya, dxb, dyb; - - hyperbolacount++; - - dest(*fronttri, leftpoint); - apex(*fronttri, rightpoint); - if ((leftpoint[1] < rightpoint[1]) - || ((leftpoint[1] == rightpoint[1]) && (leftpoint[0] < rightpoint[0]))) { - if (newsite[0] >= rightpoint[0]) { - return 1; - } - } else { - if (newsite[0] <= leftpoint[0]) { - return 0; - } - } - dxa = leftpoint[0] - newsite[0]; - dya = leftpoint[1] - newsite[1]; - dxb = rightpoint[0] - newsite[0]; - dyb = rightpoint[1] - newsite[1]; - return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya); -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -REAL circletop(pa, pb, pc, ccwabc) -point pa; -point pb; -point pc; -REAL ccwabc; -{ - REAL xac, yac, xbc, ybc, xab, yab; - REAL aclen2, bclen2, ablen2; - - circletopcount++; - - xac = pa[0] - pc[0]; - yac = pa[1] - pc[1]; - xbc = pb[0] - pc[0]; - ybc = pb[1] - pc[1]; - xab = pa[0] - pb[0]; - yab = pa[1] - pb[1]; - aclen2 = xac * xac + yac * yac; - bclen2 = xbc * xbc + ybc * ybc; - ablen2 = xab * xab + yab * yab; - return pc[1] + (xac * bclen2 - xbc * aclen2 + sqrt(aclen2 * bclen2 * ablen2)) - / (2.0 * ccwabc); -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -void check4deadevent(checktri, freeevents, eventheap, heapsize) -struct triedge *checktri; -struct event **freeevents; -struct event **eventheap; -int *heapsize; -{ - struct event *deadevent; - point eventpoint; - int eventnum; - - org(*checktri, eventpoint); - if (eventpoint != (point) NULL) { - deadevent = (struct event *) eventpoint; - eventnum = deadevent->heapposition; - deadevent->eventptr = (VOID *) *freeevents; - *freeevents = deadevent; - eventheapdelete(eventheap, *heapsize, eventnum); - (*heapsize)--; - setorg(*checktri, NULL); - } -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -struct splaynode *splay(splaytree, searchpoint, searchtri) -struct splaynode *splaytree; -point searchpoint; -struct triedge *searchtri; -{ - struct splaynode *child, *grandchild; - struct splaynode *lefttree, *righttree; - struct splaynode *leftright; - point checkpoint; - int rightofroot, rightofchild; - - if (splaytree == (struct splaynode *) NULL) { - return (struct splaynode *) NULL; - } - dest(splaytree->keyedge, checkpoint); - if (checkpoint == splaytree->keydest) { - rightofroot = rightofhyperbola(&splaytree->keyedge, searchpoint); - if (rightofroot) { - triedgecopy(splaytree->keyedge, *searchtri); - child = splaytree->rchild; - } else { - child = splaytree->lchild; - } - if (child == (struct splaynode *) NULL) { - return splaytree; - } - dest(child->keyedge, checkpoint); - if (checkpoint != child->keydest) { - child = splay(child, searchpoint, searchtri); - if (child == (struct splaynode *) NULL) { - if (rightofroot) { - splaytree->rchild = (struct splaynode *) NULL; - } else { - splaytree->lchild = (struct splaynode *) NULL; - } - return splaytree; - } - } - rightofchild = rightofhyperbola(&child->keyedge, searchpoint); - if (rightofchild) { - triedgecopy(child->keyedge, *searchtri); - grandchild = splay(child->rchild, searchpoint, searchtri); - child->rchild = grandchild; - } else { - grandchild = splay(child->lchild, searchpoint, searchtri); - child->lchild = grandchild; - } - if (grandchild == (struct splaynode *) NULL) { - if (rightofroot) { - splaytree->rchild = child->lchild; - child->lchild = splaytree; - } else { - splaytree->lchild = child->rchild; - child->rchild = splaytree; - } - return child; - } - if (rightofchild) { - if (rightofroot) { - splaytree->rchild = child->lchild; - child->lchild = splaytree; - } else { - splaytree->lchild = grandchild->rchild; - grandchild->rchild = splaytree; - } - child->rchild = grandchild->lchild; - grandchild->lchild = child; - } else { - if (rightofroot) { - splaytree->rchild = grandchild->lchild; - grandchild->lchild = splaytree; - } else { - splaytree->lchild = child->rchild; - child->rchild = splaytree; - } - child->lchild = grandchild->rchild; - grandchild->rchild = child; - } - return grandchild; - } else { - lefttree = splay(splaytree->lchild, searchpoint, searchtri); - righttree = splay(splaytree->rchild, searchpoint, searchtri); - - pooldealloc(&splaynodes, (VOID *) splaytree); - if (lefttree == (struct splaynode *) NULL) { - return righttree; - } else if (righttree == (struct splaynode *) NULL) { - return lefttree; - } else if (lefttree->rchild == (struct splaynode *) NULL) { - lefttree->rchild = righttree->lchild; - righttree->lchild = lefttree; - return righttree; - } else if (righttree->lchild == (struct splaynode *) NULL) { - righttree->lchild = lefttree->rchild; - lefttree->rchild = righttree; - return lefttree; - } else { -/* printf("Holy Toledo!!!\n"); */ - leftright = lefttree->rchild; - while (leftright->rchild != (struct splaynode *) NULL) { - leftright = leftright->rchild; - } - leftright->rchild = righttree; - return lefttree; - } - } -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -struct splaynode *splayinsert(splayroot, newkey, searchpoint) -struct splaynode *splayroot; -struct triedge *newkey; -point searchpoint; -{ - struct splaynode *newsplaynode; - - newsplaynode = (struct splaynode *) poolalloc(&splaynodes); - triedgecopy(*newkey, newsplaynode->keyedge); - dest(*newkey, newsplaynode->keydest); - if (splayroot == (struct splaynode *) NULL) { - newsplaynode->lchild = (struct splaynode *) NULL; - newsplaynode->rchild = (struct splaynode *) NULL; - } else if (rightofhyperbola(&splayroot->keyedge, searchpoint)) { - newsplaynode->lchild = splayroot; - newsplaynode->rchild = splayroot->rchild; - splayroot->rchild = (struct splaynode *) NULL; - } else { - newsplaynode->lchild = splayroot->lchild; - newsplaynode->rchild = splayroot; - splayroot->lchild = (struct splaynode *) NULL; - } - return newsplaynode; -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -struct splaynode *circletopinsert(splayroot, newkey, pa, pb, pc, topy) -struct splaynode *splayroot; -struct triedge *newkey; -point pa; -point pb; -point pc; -REAL topy; -{ - REAL ccwabc; - REAL xac, yac, xbc, ybc; - REAL aclen2, bclen2; - REAL searchpoint[2]; - struct triedge dummytri; - - ccwabc = counterclockwise(pa, pb, pc); - xac = pa[0] - pc[0]; - yac = pa[1] - pc[1]; - xbc = pb[0] - pc[0]; - ybc = pb[1] - pc[1]; - aclen2 = xac * xac + yac * yac; - bclen2 = xbc * xbc + ybc * ybc; - searchpoint[0] = pc[0] - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc); - searchpoint[1] = topy; - return splayinsert(splay(splayroot, (point) searchpoint, &dummytri), newkey, - (point) searchpoint); -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -struct splaynode *frontlocate(splayroot, bottommost, searchpoint, searchtri, - farright) -struct splaynode *splayroot; -struct triedge *bottommost; -point searchpoint; -struct triedge *searchtri; -int *farright; -{ - int farrightflag; - triangle ptr; /* Temporary variable used by onext(). */ - - triedgecopy(*bottommost, *searchtri); - splayroot = splay(splayroot, searchpoint, searchtri); - - farrightflag = 0; - while (!farrightflag && rightofhyperbola(searchtri, searchpoint)) { - onextself(*searchtri); - farrightflag = triedgeequal(*searchtri, *bottommost); - } - *farright = farrightflag; - return splayroot; -} - -#endif /* not REDUCED */ - -#ifndef REDUCED - -long sweeplinedelaunay() -{ - struct event **eventheap; - struct event *events; - struct event *freeevents; - struct event *nextevent; - struct event *newevent; - struct splaynode *splayroot; - struct triedge bottommost; - struct triedge searchtri; - struct triedge fliptri; - struct triedge lefttri, righttri, farlefttri, farrighttri; - struct triedge inserttri; - point firstpoint, secondpoint; - point nextpoint, lastpoint; - point connectpoint; - point leftpoint, midpoint, rightpoint; - REAL lefttest, righttest; - int heapsize; - int check4events, farrightflag; - triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ - - poolinit(&splaynodes, sizeof(struct splaynode), SPLAYNODEPERBLOCK, POINTER, - 0); - splayroot = (struct splaynode *) NULL; - - if (verbose) { - printf(" Placing points in event heap.\n"); - } - createeventheap(&eventheap, &events, &freeevents); - heapsize = inpoints; - - if (verbose) { - printf(" Forming triangulation.\n"); - } - maketriangle(&lefttri); - maketriangle(&righttri); - bond(lefttri, righttri); - lnextself(lefttri); - lprevself(righttri); - bond(lefttri, righttri); - lnextself(lefttri); - lprevself(righttri); - bond(lefttri, righttri); - firstpoint = (point) eventheap[0]->eventptr; - eventheap[0]->eventptr = (VOID *) freeevents; - freeevents = eventheap[0]; - eventheapdelete(eventheap, heapsize, 0); - heapsize--; - do { - if (heapsize == 0) { - printf("Error: Input points are all identical.\n"); - exit(1); - } - secondpoint = (point) eventheap[0]->eventptr; - eventheap[0]->eventptr = (VOID *) freeevents; - freeevents = eventheap[0]; - eventheapdelete(eventheap, heapsize, 0); - heapsize--; - if ((firstpoint[0] == secondpoint[0]) - && (firstpoint[1] == secondpoint[1])) { - printf( -"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", - secondpoint[0], secondpoint[1]); -/* Commented out - would eliminate point from output .node file. - setpointmark(secondpoint, DEADPOINT); -*/ - } - } while ((firstpoint[0] == secondpoint[0]) - && (firstpoint[1] == secondpoint[1])); - setorg(lefttri, firstpoint); - setdest(lefttri, secondpoint); - setorg(righttri, secondpoint); - setdest(righttri, firstpoint); - lprev(lefttri, bottommost); - lastpoint = secondpoint; - while (heapsize > 0) { - nextevent = eventheap[0]; - eventheapdelete(eventheap, heapsize, 0); - heapsize--; - check4events = 1; - if (nextevent->xkey < xmin) { - decode(nextevent->eventptr, fliptri); - oprev(fliptri, farlefttri); - check4deadevent(&farlefttri, &freeevents, eventheap, &heapsize); - onext(fliptri, farrighttri); - check4deadevent(&farrighttri, &freeevents, eventheap, &heapsize); - - if (triedgeequal(farlefttri, bottommost)) { - lprev(fliptri, bottommost); - } - flip(&fliptri); - setapex(fliptri, NULL); - lprev(fliptri, lefttri); - lnext(fliptri, righttri); - sym(lefttri, farlefttri); - - if (randomnation(SAMPLERATE) == 0) { - symself(fliptri); - dest(fliptri, leftpoint); - apex(fliptri, midpoint); - org(fliptri, rightpoint); - splayroot = circletopinsert(splayroot, &lefttri, leftpoint, midpoint, - rightpoint, nextevent->ykey); - } - } else { - nextpoint = (point) nextevent->eventptr; - if ((nextpoint[0] == lastpoint[0]) && (nextpoint[1] == lastpoint[1])) { - printf( -"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", - nextpoint[0], nextpoint[1]); -/* Commented out - would eliminate point from output .node file. - setpointmark(nextpoint, DEADPOINT); -*/ - check4events = 0; - } else { - lastpoint = nextpoint; - - splayroot = frontlocate(splayroot, &bottommost, nextpoint, &searchtri, - &farrightflag); -/* - triedgecopy(bottommost, searchtri); - farrightflag = 0; - while (!farrightflag && rightofhyperbola(&searchtri, nextpoint)) { - onextself(searchtri); - farrightflag = triedgeequal(searchtri, bottommost); - } -*/ - - check4deadevent(&searchtri, &freeevents, eventheap, &heapsize); - - triedgecopy(searchtri, farrighttri); - sym(searchtri, farlefttri); - maketriangle(&lefttri); - maketriangle(&righttri); - dest(farrighttri, connectpoint); - setorg(lefttri, connectpoint); - setdest(lefttri, nextpoint); - setorg(righttri, nextpoint); - setdest(righttri, connectpoint); - bond(lefttri, righttri); - lnextself(lefttri); - lprevself(righttri); - bond(lefttri, righttri); - lnextself(lefttri); - lprevself(righttri); - bond(lefttri, farlefttri); - bond(righttri, farrighttri); - if (!farrightflag && triedgeequal(farrighttri, bottommost)) { - triedgecopy(lefttri, bottommost); - } - - if (randomnation(SAMPLERATE) == 0) { - splayroot = splayinsert(splayroot, &lefttri, nextpoint); - } else if (randomnation(SAMPLERATE) == 0) { - lnext(righttri, inserttri); - splayroot = splayinsert(splayroot, &inserttri, nextpoint); - } - } - } - nextevent->eventptr = (VOID *) freeevents; - freeevents = nextevent; - - if (check4events) { - apex(farlefttri, leftpoint); - dest(lefttri, midpoint); - apex(lefttri, rightpoint); - lefttest = counterclockwise(leftpoint, midpoint, rightpoint); - if (lefttest > 0.0) { - newevent = freeevents; - freeevents = (struct event *) freeevents->eventptr; - newevent->xkey = xminextreme; - newevent->ykey = circletop(leftpoint, midpoint, rightpoint, - lefttest); - newevent->eventptr = (VOID *) encode(lefttri); - eventheapinsert(eventheap, heapsize, newevent); - heapsize++; - setorg(lefttri, newevent); - } - apex(righttri, leftpoint); - org(righttri, midpoint); - apex(farrighttri, rightpoint); - righttest = counterclockwise(leftpoint, midpoint, rightpoint); - if (righttest > 0.0) { - newevent = freeevents; - freeevents = (struct event *) freeevents->eventptr; - newevent->xkey = xminextreme; - newevent->ykey = circletop(leftpoint, midpoint, rightpoint, - righttest); - newevent->eventptr = (VOID *) encode(farrighttri); - eventheapinsert(eventheap, heapsize, newevent); - heapsize++; - setorg(farrighttri, newevent); - } - } - } - - pooldeinit(&splaynodes); - lprevself(bottommost); - return removeghosts(&bottommost); -} - -#endif /* not REDUCED */ - -/** **/ -/** **/ -/********* Sweepline Delaunay triangulation ends here *********/ - -/********* General mesh construction routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* delaunay() Form a Delaunay triangulation. */ -/* */ -/*****************************************************************************/ - -long delaunay() -{ - eextras = 0; - initializetrisegpools(); - -#ifdef REDUCED - if (!quiet) { - printf( - "Constructing Delaunay triangulation by divide-and-conquer method.\n"); - } - return divconqdelaunay(); -#else /* not REDUCED */ - if (!quiet) { - printf("Constructing Delaunay triangulation "); - if (incremental) { - printf("by incremental method.\n"); - } else if (sweepline) { - printf("by sweepline method.\n"); - } else { - printf("by divide-and-conquer method.\n"); - } - } - if (incremental) { - return incrementaldelaunay(); - } else if (sweepline) { - return sweeplinedelaunay(); - } else { - return divconqdelaunay(); - } -#endif /* not REDUCED */ -} - -/*****************************************************************************/ -/* */ -/* reconstruct() Reconstruct a triangulation from its .ele (and possibly */ -/* .poly) file. Used when the -r switch is used. */ -/* */ -/* Reads an .ele file and reconstructs the original mesh. If the -p switch */ -/* is used, this procedure will also read a .poly file and reconstruct the */ -/* shell edges of the original mesh. If the -a switch is used, this */ -/* procedure will also read an .area file and set a maximum area constraint */ -/* on each triangle. */ -/* */ -/* Points that are not corners of triangles, such as nodes on edges of */ -/* subparametric elements, are discarded. */ -/* */ -/* This routine finds the adjacencies between triangles (and shell edges) */ -/* by forming one stack of triangles for each vertex. Each triangle is on */ -/* three different stacks simultaneously. Each triangle's shell edge */ -/* pointers are used to link the items in each stack. This memory-saving */ -/* feature makes the code harder to read. The most important thing to keep */ -/* in mind is that each triangle is removed from a stack precisely when */ -/* the corresponding pointer is adjusted to refer to a shell edge rather */ -/* than the next triangle of the stack. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -#ifdef TRILIBRARY - -int reconstruct(trianglelist, triangleattriblist, trianglearealist, elements, - corners, attribs, segmentlist, segmentmarkerlist, - numberofsegments) -int *trianglelist; -REAL *triangleattriblist; -REAL *trianglearealist; -int elements; -int corners; -int attribs; -int *segmentlist; -int *segmentmarkerlist; -int numberofsegments; - -#else /* not TRILIBRARY */ - -long reconstruct(elefilename, areafilename, polyfilename, polyfile) -char *elefilename; -char *areafilename; -char *polyfilename; -FILE *polyfile; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - int pointindex; - int attribindex; -#else /* not TRILIBRARY */ - FILE *elefile; - FILE *areafile; - char inputline[INPUTLINESIZE]; - char *stringptr; - int areaelements; -#endif /* not TRILIBRARY */ - struct triedge triangleloop; - struct triedge triangleleft; - struct triedge checktri; - struct triedge checkleft; - struct triedge checkneighbor; - struct edge shelleloop; - triangle *vertexarray; - triangle *prevlink; - triangle nexttri; - point tdest, tapex; - point checkdest, checkapex; - point shorg; - point killpoint; - REAL area; - int corner[3]; - int end[2]; - int killpointindex; - int incorners; - int segmentmarkers; - int boundmarker; - int aroundpoint; - long hullsize; - int notfound; - int elementnumber, segmentnumber; - int i, j; - triangle ptr; /* Temporary variable used by sym(). */ - -#ifdef TRILIBRARY - inelements = elements; - incorners = corners; - if (incorners < 3) { - printf("Error: Triangles must have at least 3 points.\n"); - exit(1); - } - eextras = attribs; -#else /* not TRILIBRARY */ - /* Read the triangles from an .ele file. */ - if (!quiet) { - printf("Opening %s.\n", elefilename); - } - elefile = fopen(elefilename, "r"); - if (elefile == (FILE *) NULL) { - printf(" Error: Cannot access file %s.\n", elefilename); - exit(1); - } - /* Read number of triangles, number of points per triangle, and */ - /* number of triangle attributes from .ele file. */ - stringptr = readline(inputline, elefile, elefilename); - inelements = (int) strtol (stringptr, &stringptr, 0); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - incorners = 3; - } else { - incorners = (int) strtol (stringptr, &stringptr, 0); - if (incorners < 3) { - printf("Error: Triangles in %s must have at least 3 points.\n", - elefilename); - exit(1); - } - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - eextras = 0; - } else { - eextras = (int) strtol (stringptr, &stringptr, 0); - } -#endif /* not TRILIBRARY */ - - initializetrisegpools(); - - /* Create the triangles. */ - for (elementnumber = 1; elementnumber <= inelements; elementnumber++) { - maketriangle(&triangleloop); - /* Mark the triangle as living. */ - triangleloop.tri[3] = (triangle) triangleloop.tri; - } - - if (poly) { -#ifdef TRILIBRARY - insegments = numberofsegments; - segmentmarkers = segmentmarkerlist != (int *) NULL; -#else /* not TRILIBRARY */ - /* Read number of segments and number of segment */ - /* boundary markers from .poly file. */ - stringptr = readline(inputline, polyfile, inpolyfilename); - insegments = (int) strtol (stringptr, &stringptr, 0); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - segmentmarkers = 0; - } else { - segmentmarkers = (int) strtol (stringptr, &stringptr, 0); - } -#endif /* not TRILIBRARY */ - - /* Create the shell edges. */ - for (segmentnumber = 1; segmentnumber <= insegments; segmentnumber++) { - makeshelle(&shelleloop); - /* Mark the shell edge as living. */ - shelleloop.sh[2] = (shelle) shelleloop.sh; - } - } - -#ifdef TRILIBRARY - pointindex = 0; - attribindex = 0; -#else /* not TRILIBRARY */ - if (vararea) { - /* Open an .area file, check for consistency with the .ele file. */ - if (!quiet) { - printf("Opening %s.\n", areafilename); - } - areafile = fopen(areafilename, "r"); - if (areafile == (FILE *) NULL) { - printf(" Error: Cannot access file %s.\n", areafilename); - exit(1); - } - stringptr = readline(inputline, areafile, areafilename); - areaelements = (int) strtol (stringptr, &stringptr, 0); - if (areaelements != inelements) { - printf("Error: %s and %s disagree on number of triangles.\n", - elefilename, areafilename); - exit(1); - } - } -#endif /* not TRILIBRARY */ - - if (!quiet) { - printf("Reconstructing mesh.\n"); - } - /* Allocate a temporary array that maps each point to some adjacent */ - /* triangle. I took care to allocate all the permanent memory for */ - /* triangles and shell edges first. */ - vertexarray = (triangle *) malloc(points.items * sizeof(triangle)); - if (vertexarray == (triangle *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - /* Each point is initially unrepresented. */ - for (i = 0; i < points.items; i++) { - vertexarray[i] = (triangle) dummytri; - } - - if (verbose) { - printf(" Assembling triangles.\n"); - } - /* Read the triangles from the .ele file, and link */ - /* together those that share an edge. */ - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - elementnumber = firstnumber; - while (triangleloop.tri != (triangle *) NULL) { -#ifdef TRILIBRARY - /* Copy the triangle's three corners. */ - for (j = 0; j < 3; j++) { - corner[j] = trianglelist[pointindex++]; - if ((corner[j] < firstnumber) || (corner[j] >= firstnumber + inpoints)) { - printf("Error: Triangle %d has an invalid vertex index.\n", - elementnumber); - exit(1); - } - } -#else /* not TRILIBRARY */ - /* Read triangle number and the triangle's three corners. */ - stringptr = readline(inputline, elefile, elefilename); - for (j = 0; j < 3; j++) { - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Triangle %d is missing point %d in %s.\n", - elementnumber, j + 1, elefilename); - exit(1); - } else { - corner[j] = (int) strtol (stringptr, &stringptr, 0); - if ((corner[j] < firstnumber) || - (corner[j] >= firstnumber + inpoints)) { - printf("Error: Triangle %d has an invalid vertex index.\n", - elementnumber); - exit(1); - } - } - } -#endif /* not TRILIBRARY */ - - /* Find out about (and throw away) extra nodes. */ - for (j = 3; j < incorners; j++) { -#ifdef TRILIBRARY - killpointindex = trianglelist[pointindex++]; -#else /* not TRILIBRARY */ - stringptr = findfield(stringptr); - if (*stringptr != '\0') { - killpointindex = (int) strtol (stringptr, &stringptr, 0); -#endif /* not TRILIBRARY */ - if ((killpointindex >= firstnumber) && - (killpointindex < firstnumber + inpoints)) { - /* Delete the non-corner point if it's not already deleted. */ - killpoint = getpoint(killpointindex); - if (pointmark(killpoint) != DEADPOINT) { - pointdealloc(killpoint); - } - } -#ifndef TRILIBRARY - } -#endif /* not TRILIBRARY */ - } - - /* Read the triangle's attributes. */ - for (j = 0; j < eextras; j++) { -#ifdef TRILIBRARY - setelemattribute(triangleloop, j, triangleattriblist[attribindex++]); -#else /* not TRILIBRARY */ - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - setelemattribute(triangleloop, j, 0); - } else { - setelemattribute(triangleloop, j, - (REAL) strtod (stringptr, &stringptr)); - } -#endif /* not TRILIBRARY */ - } - - if (vararea) { -#ifdef TRILIBRARY - area = trianglearealist[elementnumber - firstnumber]; -#else /* not TRILIBRARY */ - /* Read an area constraint from the .area file. */ - stringptr = readline(inputline, areafile, areafilename); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - area = -1.0; /* No constraint on this triangle. */ - } else { - area = (REAL) strtod(stringptr, &stringptr); - } -#endif /* not TRILIBRARY */ - setareabound(triangleloop, area); - } - - /* Set the triangle's vertices. */ - triangleloop.orient = 0; - setorg(triangleloop, getpoint(corner[0])); - setdest(triangleloop, getpoint(corner[1])); - setapex(triangleloop, getpoint(corner[2])); - /* Try linking the triangle to others that share these vertices. */ - for (triangleloop.orient = 0; triangleloop.orient < 3; - triangleloop.orient++) { - /* Take the number for the origin of triangleloop. */ - aroundpoint = corner[triangleloop.orient]; - /* Look for other triangles having this vertex. */ - nexttri = vertexarray[aroundpoint - firstnumber]; - /* Link the current triangle to the next one in the stack. */ - triangleloop.tri[6 + triangleloop.orient] = nexttri; - /* Push the current triangle onto the stack. */ - vertexarray[aroundpoint - firstnumber] = encode(triangleloop); - decode(nexttri, checktri); - if (checktri.tri != dummytri) { - dest(triangleloop, tdest); - apex(triangleloop, tapex); - /* Look for other triangles that share an edge. */ - do { - dest(checktri, checkdest); - apex(checktri, checkapex); - if (tapex == checkdest) { - /* The two triangles share an edge; bond them together. */ - lprev(triangleloop, triangleleft); - bond(triangleleft, checktri); - } - if (tdest == checkapex) { - /* The two triangles share an edge; bond them together. */ - lprev(checktri, checkleft); - bond(triangleloop, checkleft); - } - /* Find the next triangle in the stack. */ - nexttri = checktri.tri[6 + checktri.orient]; - decode(nexttri, checktri); - } while (checktri.tri != dummytri); - } - } - triangleloop.tri = triangletraverse(); - elementnumber++; - } - -#ifdef TRILIBRARY - pointindex = 0; -#else /* not TRILIBRARY */ - fclose(elefile); - if (vararea) { - fclose(areafile); - } -#endif /* not TRILIBRARY */ - - hullsize = 0; /* Prepare to count the boundary edges. */ - if (poly) { - if (verbose) { - printf(" Marking segments in triangulation.\n"); - } - /* Read the segments from the .poly file, and link them */ - /* to their neighboring triangles. */ - boundmarker = 0; - traversalinit(&shelles); - shelleloop.sh = shelletraverse(); - segmentnumber = firstnumber; - while (shelleloop.sh != (shelle *) NULL) { -#ifdef TRILIBRARY - end[0] = segmentlist[pointindex++]; - end[1] = segmentlist[pointindex++]; - if (segmentmarkers) { - boundmarker = segmentmarkerlist[segmentnumber - firstnumber]; - } -#else /* not TRILIBRARY */ - /* Read the endpoints of each segment, and possibly a boundary marker. */ - stringptr = readline(inputline, polyfile, inpolyfilename); - /* Skip the first (segment number) field. */ - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Segment %d has no endpoints in %s.\n", segmentnumber, - polyfilename); - exit(1); - } else { - end[0] = (int) strtol (stringptr, &stringptr, 0); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Segment %d is missing its second endpoint in %s.\n", - segmentnumber, polyfilename); - exit(1); - } else { - end[1] = (int) strtol (stringptr, &stringptr, 0); - } - if (segmentmarkers) { - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - boundmarker = 0; - } else { - boundmarker = (int) strtol (stringptr, &stringptr, 0); - } - } -#endif /* not TRILIBRARY */ - for (j = 0; j < 2; j++) { - if ((end[j] < firstnumber) || (end[j] >= firstnumber + inpoints)) { - printf("Error: Segment %d has an invalid vertex index.\n", - segmentnumber); - exit(1); - } - } - - /* set the shell edge's vertices. */ - shelleloop.shorient = 0; - setsorg(shelleloop, getpoint(end[0])); - setsdest(shelleloop, getpoint(end[1])); - setmark(shelleloop, boundmarker); - /* Try linking the shell edge to triangles that share these vertices. */ - for (shelleloop.shorient = 0; shelleloop.shorient < 2; - shelleloop.shorient++) { - /* Take the number for the destination of shelleloop. */ - aroundpoint = end[1 - shelleloop.shorient]; - /* Look for triangles having this vertex. */ - prevlink = &vertexarray[aroundpoint - firstnumber]; - nexttri = vertexarray[aroundpoint - firstnumber]; - decode(nexttri, checktri); - sorg(shelleloop, shorg); - notfound = 1; - /* Look for triangles having this edge. Note that I'm only */ - /* comparing each triangle's destination with the shell edge; */ - /* each triangle's apex is handled through a different vertex. */ - /* Because each triangle appears on three vertices' lists, each */ - /* occurrence of a triangle on a list can (and does) represent */ - /* an edge. In this way, most edges are represented twice, and */ - /* every triangle-segment bond is represented once. */ - while (notfound && (checktri.tri != dummytri)) { - dest(checktri, checkdest); - if (shorg == checkdest) { - /* We have a match. Remove this triangle from the list. */ - *prevlink = checktri.tri[6 + checktri.orient]; - /* Bond the shell edge to the triangle. */ - tsbond(checktri, shelleloop); - /* Check if this is a boundary edge. */ - sym(checktri, checkneighbor); - if (checkneighbor.tri == dummytri) { - /* The next line doesn't insert a shell edge (because there's */ - /* already one there), but it sets the boundary markers of */ - /* the existing shell edge and its vertices. */ - insertshelle(&checktri, 1); - hullsize++; - } - notfound = 0; - } - /* Find the next triangle in the stack. */ - prevlink = &checktri.tri[6 + checktri.orient]; - nexttri = checktri.tri[6 + checktri.orient]; - decode(nexttri, checktri); - } - } - shelleloop.sh = shelletraverse(); - segmentnumber++; - } - } - - /* Mark the remaining edges as not being attached to any shell edge. */ - /* Also, count the (yet uncounted) boundary edges. */ - for (i = 0; i < points.items; i++) { - /* Search the stack of triangles adjacent to a point. */ - nexttri = vertexarray[i]; - decode(nexttri, checktri); - while (checktri.tri != dummytri) { - /* Find the next triangle in the stack before this */ - /* information gets overwritten. */ - nexttri = checktri.tri[6 + checktri.orient]; - /* No adjacent shell edge. (This overwrites the stack info.) */ - tsdissolve(checktri); - sym(checktri, checkneighbor); - if (checkneighbor.tri == dummytri) { - insertshelle(&checktri, 1); - hullsize++; - } - decode(nexttri, checktri); - } - } - - free(vertexarray); - return hullsize; -} - -#endif /* not CDT_ONLY */ - -/** **/ -/** **/ -/********* General mesh construction routines end here *********/ - -/********* Segment (shell edge) insertion begins here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* finddirection() Find the first triangle on the path from one point */ -/* to another. */ -/* */ -/* Finds the triangle that intersects a line segment drawn from the */ -/* origin of `searchtri' to the point `endpoint', and returns the result */ -/* in `searchtri'. The origin of `searchtri' does not change, even though */ -/* the triangle returned may differ from the one passed in. This routine */ -/* is used to find the direction to move in to get from one point to */ -/* another. */ -/* */ -/* The return value notes whether the destination or apex of the found */ -/* triangle is collinear with the two points in question. */ -/* */ -/*****************************************************************************/ - -enum finddirectionresult finddirection(searchtri, endpoint) -struct triedge *searchtri; -point endpoint; -{ - struct triedge checktri; - point startpoint; - point leftpoint, rightpoint; - REAL leftccw, rightccw; - int leftflag, rightflag; - triangle ptr; /* Temporary variable used by onext() and oprev(). */ - - org(*searchtri, startpoint); - dest(*searchtri, rightpoint); - apex(*searchtri, leftpoint); - /* Is `endpoint' to the left? */ - leftccw = counterclockwise(endpoint, startpoint, leftpoint); - leftflag = leftccw > 0.0; - /* Is `endpoint' to the right? */ - rightccw = counterclockwise(startpoint, endpoint, rightpoint); - rightflag = rightccw > 0.0; - if (leftflag && rightflag) { - /* `searchtri' faces directly away from `endpoint'. We could go */ - /* left or right. Ask whether it's a triangle or a boundary */ - /* on the left. */ - onext(*searchtri, checktri); - if (checktri.tri == dummytri) { - leftflag = 0; - } else { - rightflag = 0; - } - } - while (leftflag) { - /* Turn left until satisfied. */ - onextself(*searchtri); - if (searchtri->tri == dummytri) { - printf("Internal error in finddirection(): Unable to find a\n"); - printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], - startpoint[1]); - printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); - internalerror(); - } - apex(*searchtri, leftpoint); - rightccw = leftccw; - leftccw = counterclockwise(endpoint, startpoint, leftpoint); - leftflag = leftccw > 0.0; - } - while (rightflag) { - /* Turn right until satisfied. */ - oprevself(*searchtri); - if (searchtri->tri == dummytri) { - printf("Internal error in finddirection(): Unable to find a\n"); - printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], - startpoint[1]); - printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); - internalerror(); - } - dest(*searchtri, rightpoint); - leftccw = rightccw; - rightccw = counterclockwise(startpoint, endpoint, rightpoint); - rightflag = rightccw > 0.0; - } - if (leftccw == 0.0) { - return LEFTCOLLINEAR; - } else if (rightccw == 0.0) { - return RIGHTCOLLINEAR; - } else { - return WITHIN; - } -} - -/*****************************************************************************/ -/* */ -/* segmentintersection() Find the intersection of an existing segment */ -/* and a segment that is being inserted. Insert */ -/* a point at the intersection, splitting an */ -/* existing shell edge. */ -/* */ -/* The segment being inserted connects the apex of splittri to endpoint2. */ -/* splitshelle is the shell edge being split, and MUST be opposite */ -/* splittri. Hence, the edge being split connects the origin and */ -/* destination of splittri. */ -/* */ -/* On completion, splittri is a handle having the newly inserted */ -/* intersection point as its origin, and endpoint1 as its destination. */ -/* */ -/*****************************************************************************/ - -void segmentintersection(splittri, splitshelle, endpoint2) -struct triedge *splittri; -struct edge *splitshelle; -point endpoint2; -{ - point endpoint1; - point torg, tdest; - point leftpoint, rightpoint; - point newpoint; - enum insertsiteresult success; - enum finddirectionresult collinear; - REAL ex, ey; - REAL tx, ty; - REAL etx, ety; - REAL split, denom; - int i; - triangle ptr; /* Temporary variable used by onext(). */ - - /* Find the other three segment endpoints. */ - apex(*splittri, endpoint1); - org(*splittri, torg); - dest(*splittri, tdest); - /* Segment intersection formulae; see the Antonio reference. */ - tx = tdest[0] - torg[0]; - ty = tdest[1] - torg[1]; - ex = endpoint2[0] - endpoint1[0]; - ey = endpoint2[1] - endpoint1[1]; - etx = torg[0] - endpoint2[0]; - ety = torg[1] - endpoint2[1]; - denom = ty * ex - tx * ey; - if (denom == 0.0) { - printf("Internal error in segmentintersection():"); - printf(" Attempt to find intersection of parallel segments.\n"); - internalerror(); - } - split = (ey * etx - ex * ety) / denom; - /* Create the new point. */ - newpoint = (point) poolalloc(&points); - /* Interpolate its coordinate and attributes. */ - for (i = 0; i < 2 + nextras; i++) { - newpoint[i] = torg[i] + split * (tdest[i] - torg[i]); - } - setpointmark(newpoint, mark(*splitshelle)); - if (verbose > 1) { - printf( - " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", - torg[0], torg[1], tdest[0], tdest[1], newpoint[0], newpoint[1]); - } - /* Insert the intersection point. This should always succeed. */ - success = insertsite(newpoint, splittri, splitshelle, 0, 0); - if (success != SUCCESSFULPOINT) { - printf("Internal error in segmentintersection():\n"); - printf(" Failure to split a segment.\n"); - internalerror(); - } - if (steinerleft > 0) { - steinerleft--; - } - /* Inserting the point may have caused edge flips. We wish to rediscover */ - /* the edge connecting endpoint1 to the new intersection point. */ - collinear = finddirection(splittri, endpoint1); - dest(*splittri, rightpoint); - apex(*splittri, leftpoint); - if ((leftpoint[0] == endpoint1[0]) && (leftpoint[1] == endpoint1[1])) { - onextself(*splittri); - } else if ((rightpoint[0] != endpoint1[0]) || - (rightpoint[1] != endpoint1[1])) { - printf("Internal error in segmentintersection():\n"); - printf(" Topological inconsistency after splitting a segment.\n"); - internalerror(); - } - /* `splittri' should have destination endpoint1. */ -} - -/*****************************************************************************/ -/* */ -/* scoutsegment() Scout the first triangle on the path from one endpoint */ -/* to another, and check for completion (reaching the */ -/* second endpoint), a collinear point, and the */ -/* intersection of two segments. */ -/* */ -/* Returns one if the entire segment is successfully inserted, and zero if */ -/* the job must be finished by conformingedge() or constrainededge(). */ -/* */ -/* If the first triangle on the path has the second endpoint as its */ -/* destination or apex, a shell edge is inserted and the job is done. */ -/* */ -/* If the first triangle on the path has a destination or apex that lies on */ -/* the segment, a shell edge is inserted connecting the first endpoint to */ -/* the collinear point, and the search is continued from the collinear */ -/* point. */ -/* */ -/* If the first triangle on the path has a shell edge opposite its origin, */ -/* then there is a segment that intersects the segment being inserted. */ -/* Their intersection point is inserted, splitting the shell edge. */ -/* */ -/* Otherwise, return zero. */ -/* */ -/*****************************************************************************/ - -int scoutsegment(searchtri, endpoint2, newmark) -struct triedge *searchtri; -point endpoint2; -int newmark; -{ - struct triedge crosstri; - struct edge crossedge; - point leftpoint, rightpoint; - point endpoint1; - enum finddirectionresult collinear; - shelle sptr; /* Temporary variable used by tspivot(). */ - - collinear = finddirection(searchtri, endpoint2); - dest(*searchtri, rightpoint); - apex(*searchtri, leftpoint); - if (((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) || - ((rightpoint[0] == endpoint2[0]) && (rightpoint[1] == endpoint2[1]))) { - /* The segment is already an edge in the mesh. */ - if ((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) { - lprevself(*searchtri); - } - /* Insert a shell edge, if there isn't already one there. */ - insertshelle(searchtri, newmark); - return 1; - } else if (collinear == LEFTCOLLINEAR) { - /* We've collided with a point between the segment's endpoints. */ - /* Make the collinear point be the triangle's origin. */ - lprevself(*searchtri); - insertshelle(searchtri, newmark); - /* Insert the remainder of the segment. */ - return scoutsegment(searchtri, endpoint2, newmark); - } else if (collinear == RIGHTCOLLINEAR) { - /* We've collided with a point between the segment's endpoints. */ - insertshelle(searchtri, newmark); - /* Make the collinear point be the triangle's origin. */ - lnextself(*searchtri); - /* Insert the remainder of the segment. */ - return scoutsegment(searchtri, endpoint2, newmark); - } else { - lnext(*searchtri, crosstri); - tspivot(crosstri, crossedge); - /* Check for a crossing segment. */ - if (crossedge.sh == dummysh) { - return 0; - } else { - org(*searchtri, endpoint1); - /* Insert a point at the intersection. */ - segmentintersection(&crosstri, &crossedge, endpoint2); - triedgecopy(crosstri, *searchtri); - insertshelle(searchtri, newmark); - /* Insert the remainder of the segment. */ - return scoutsegment(searchtri, endpoint2, newmark); - } - } -} - -/*****************************************************************************/ -/* */ -/* conformingedge() Force a segment into a conforming Delaunay */ -/* triangulation by inserting a point at its midpoint, */ -/* and recursively forcing in the two half-segments if */ -/* necessary. */ -/* */ -/* Generates a sequence of edges connecting `endpoint1' to `endpoint2'. */ -/* `newmark' is the boundary marker of the segment, assigned to each new */ -/* splitting point and shell edge. */ -/* */ -/* Note that conformingedge() does not always maintain the conforming */ -/* Delaunay property. Once inserted, segments are locked into place; */ -/* points inserted later (to force other segments in) may render these */ -/* fixed segments non-Delaunay. The conforming Delaunay property will be */ -/* restored by enforcequality() by splitting encroached segments. */ -/* */ -/*****************************************************************************/ - -#ifndef REDUCED -#ifndef CDT_ONLY - -void conformingedge(endpoint1, endpoint2, newmark) -point endpoint1; -point endpoint2; -int newmark; -{ - struct triedge searchtri1, searchtri2; - struct edge brokenshelle; - point newpoint; - point midpoint1, midpoint2; - enum insertsiteresult success; - int result1, result2; - int i; - shelle sptr; /* Temporary variable used by tspivot(). */ - - if (verbose > 2) { - printf("Forcing segment into triangulation by recursive splitting:\n"); - printf(" (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1], - endpoint2[0], endpoint2[1]); - } - /* Create a new point to insert in the middle of the segment. */ - newpoint = (point) poolalloc(&points); - /* Interpolate coordinates and attributes. */ - for (i = 0; i < 2 + nextras; i++) { - newpoint[i] = 0.5 * (endpoint1[i] + endpoint2[i]); - } - setpointmark(newpoint, newmark); - /* Find a boundary triangle to search from. */ - searchtri1.tri = (triangle *) NULL; - /* Attempt to insert the new point. */ - success = insertsite(newpoint, &searchtri1, (struct edge *) NULL, 0, 0); - if (success == DUPLICATEPOINT) { - if (verbose > 2) { - printf(" Segment intersects existing point (%.12g, %.12g).\n", - newpoint[0], newpoint[1]); - } - /* Use the point that's already there. */ - pointdealloc(newpoint); - org(searchtri1, newpoint); - } else { - if (success == VIOLATINGPOINT) { - if (verbose > 2) { - printf(" Two segments intersect at (%.12g, %.12g).\n", - newpoint[0], newpoint[1]); - } - /* By fluke, we've landed right on another segment. Split it. */ - tspivot(searchtri1, brokenshelle); - success = insertsite(newpoint, &searchtri1, &brokenshelle, 0, 0); - if (success != SUCCESSFULPOINT) { - printf("Internal error in conformingedge():\n"); - printf(" Failure to split a segment.\n"); - internalerror(); - } - } - /* The point has been inserted successfully. */ - if (steinerleft > 0) { - steinerleft--; - } - } - triedgecopy(searchtri1, searchtri2); - result1 = scoutsegment(&searchtri1, endpoint1, newmark); - result2 = scoutsegment(&searchtri2, endpoint2, newmark); - if (!result1) { - /* The origin of searchtri1 may have changed if a collision with an */ - /* intervening vertex on the segment occurred. */ - org(searchtri1, midpoint1); - conformingedge(midpoint1, endpoint1, newmark); - } - if (!result2) { - /* The origin of searchtri2 may have changed if a collision with an */ - /* intervening vertex on the segment occurred. */ - org(searchtri2, midpoint2); - conformingedge(midpoint2, endpoint2, newmark); - } -} - -#endif /* not CDT_ONLY */ -#endif /* not REDUCED */ - -/*****************************************************************************/ -/* */ -/* delaunayfixup() Enforce the Delaunay condition at an edge, fanning out */ -/* recursively from an existing point. Pay special */ -/* attention to stacking inverted triangles. */ -/* */ -/* This is a support routine for inserting segments into a constrained */ -/* Delaunay triangulation. */ -/* */ -/* The origin of fixuptri is treated as if it has just been inserted, and */ -/* the local Delaunay condition needs to be enforced. It is only enforced */ -/* in one sector, however, that being the angular range defined by */ -/* fixuptri. */ -/* */ -/* This routine also needs to make decisions regarding the "stacking" of */ -/* triangles. (Read the description of constrainededge() below before */ -/* reading on here, so you understand the algorithm.) If the position of */ -/* the new point (the origin of fixuptri) indicates that the vertex before */ -/* it on the polygon is a reflex vertex, then "stack" the triangle by */ -/* doing nothing. (fixuptri is an inverted triangle, which is how stacked */ -/* triangles are identified.) */ -/* */ -/* Otherwise, check whether the vertex before that was a reflex vertex. */ -/* If so, perform an edge flip, thereby eliminating an inverted triangle */ -/* (popping it off the stack). The edge flip may result in the creation */ -/* of a new inverted triangle, depending on whether or not the new vertex */ -/* is visible to the vertex three edges behind on the polygon. */ -/* */ -/* If neither of the two vertices behind the new vertex are reflex */ -/* vertices, fixuptri and fartri, the triangle opposite it, are not */ -/* inverted; hence, ensure that the edge between them is locally Delaunay. */ -/* */ -/* `leftside' indicates whether or not fixuptri is to the left of the */ -/* segment being inserted. (Imagine that the segment is pointing up from */ -/* endpoint1 to endpoint2.) */ -/* */ -/*****************************************************************************/ - -void delaunayfixup(fixuptri, leftside) -struct triedge *fixuptri; -int leftside; -{ - struct triedge neartri; - struct triedge fartri; - struct edge faredge; - point nearpoint, leftpoint, rightpoint, farpoint; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - lnext(*fixuptri, neartri); - sym(neartri, fartri); - /* Check if the edge opposite the origin of fixuptri can be flipped. */ - if (fartri.tri == dummytri) { - return; - } - tspivot(neartri, faredge); - if (faredge.sh != dummysh) { - return; - } - /* Find all the relevant vertices. */ - apex(neartri, nearpoint); - org(neartri, leftpoint); - dest(neartri, rightpoint); - apex(fartri, farpoint); - /* Check whether the previous polygon vertex is a reflex vertex. */ - if (leftside) { - if (counterclockwise(nearpoint, leftpoint, farpoint) <= 0.0) { - /* leftpoint is a reflex vertex too. Nothing can */ - /* be done until a convex section is found. */ - return; - } - } else { - if (counterclockwise(farpoint, rightpoint, nearpoint) <= 0.0) { - /* rightpoint is a reflex vertex too. Nothing can */ - /* be done until a convex section is found. */ - return; - } - } - if (counterclockwise(rightpoint, leftpoint, farpoint) > 0.0) { - /* fartri is not an inverted triangle, and farpoint is not a reflex */ - /* vertex. As there are no reflex vertices, fixuptri isn't an */ - /* inverted triangle, either. Hence, test the edge between the */ - /* triangles to ensure it is locally Delaunay. */ - if (incircle(leftpoint, farpoint, rightpoint, nearpoint) <= 0.0) { - return; - } - /* Not locally Delaunay; go on to an edge flip. */ - } /* else fartri is inverted; remove it from the stack by flipping. */ - flip(&neartri); - lprevself(*fixuptri); /* Restore the origin of fixuptri after the flip. */ - /* Recursively process the two triangles that result from the flip. */ - delaunayfixup(fixuptri, leftside); - delaunayfixup(&fartri, leftside); -} - -/*****************************************************************************/ -/* */ -/* constrainededge() Force a segment into a constrained Delaunay */ -/* triangulation by deleting the triangles it */ -/* intersects, and triangulating the polygons that */ -/* form on each side of it. */ -/* */ -/* Generates a single edge connecting `endpoint1' to `endpoint2'. The */ -/* triangle `starttri' has `endpoint1' as its origin. `newmark' is the */ -/* boundary marker of the segment. */ -/* */ -/* To insert a segment, every triangle whose interior intersects the */ -/* segment is deleted. The union of these deleted triangles is a polygon */ -/* (which is not necessarily monotone, but is close enough), which is */ -/* divided into two polygons by the new segment. This routine's task is */ -/* to generate the Delaunay triangulation of these two polygons. */ -/* */ -/* You might think of this routine's behavior as a two-step process. The */ -/* first step is to walk from endpoint1 to endpoint2, flipping each edge */ -/* encountered. This step creates a fan of edges connected to endpoint1, */ -/* including the desired edge to endpoint2. The second step enforces the */ -/* Delaunay condition on each side of the segment in an incremental manner: */ -/* proceeding along the polygon from endpoint1 to endpoint2 (this is done */ -/* independently on each side of the segment), each vertex is "enforced" */ -/* as if it had just been inserted, but affecting only the previous */ -/* vertices. The result is the same as if the vertices had been inserted */ -/* in the order they appear on the polygon, so the result is Delaunay. */ -/* */ -/* In truth, constrainededge() interleaves these two steps. The procedure */ -/* walks from endpoint1 to endpoint2, and each time an edge is encountered */ -/* and flipped, the newly exposed vertex (at the far end of the flipped */ -/* edge) is "enforced" upon the previously flipped edges, usually affecting */ -/* only one side of the polygon (depending upon which side of the segment */ -/* the vertex falls on). */ -/* */ -/* The algorithm is complicated by the need to handle polygons that are not */ -/* convex. Although the polygon is not necessarily monotone, it can be */ -/* triangulated in a manner similar to the stack-based algorithms for */ -/* monotone polygons. For each reflex vertex (local concavity) of the */ -/* polygon, there will be an inverted triangle formed by one of the edge */ -/* flips. (An inverted triangle is one with negative area - that is, its */ -/* vertices are arranged in clockwise order - and is best thought of as a */ -/* wrinkle in the fabric of the mesh.) Each inverted triangle can be */ -/* thought of as a reflex vertex pushed on the stack, waiting to be fixed */ -/* later. */ -/* */ -/* A reflex vertex is popped from the stack when a vertex is inserted that */ -/* is visible to the reflex vertex. (However, if the vertex behind the */ -/* reflex vertex is not visible to the reflex vertex, a new inverted */ -/* triangle will take its place on the stack.) These details are handled */ -/* by the delaunayfixup() routine above. */ -/* */ -/*****************************************************************************/ - -void constrainededge(starttri, endpoint2, newmark) -struct triedge *starttri; -point endpoint2; -int newmark; -{ - struct triedge fixuptri, fixuptri2; - struct edge fixupedge; - point endpoint1; - point farpoint; - REAL area; - int collision; - int done; - triangle ptr; /* Temporary variable used by sym() and oprev(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - org(*starttri, endpoint1); - lnext(*starttri, fixuptri); - flip(&fixuptri); - /* `collision' indicates whether we have found a point directly */ - /* between endpoint1 and endpoint2. */ - collision = 0; - done = 0; - do { - org(fixuptri, farpoint); - /* `farpoint' is the extreme point of the polygon we are "digging" */ - /* to get from endpoint1 to endpoint2. */ - if ((farpoint[0] == endpoint2[0]) && (farpoint[1] == endpoint2[1])) { - oprev(fixuptri, fixuptri2); - /* Enforce the Delaunay condition around endpoint2. */ - delaunayfixup(&fixuptri, 0); - delaunayfixup(&fixuptri2, 1); - done = 1; - } else { - /* Check whether farpoint is to the left or right of the segment */ - /* being inserted, to decide which edge of fixuptri to dig */ - /* through next. */ - area = counterclockwise(endpoint1, endpoint2, farpoint); - if (area == 0.0) { - /* We've collided with a point between endpoint1 and endpoint2. */ - collision = 1; - oprev(fixuptri, fixuptri2); - /* Enforce the Delaunay condition around farpoint. */ - delaunayfixup(&fixuptri, 0); - delaunayfixup(&fixuptri2, 1); - done = 1; - } else { - if (area > 0.0) { /* farpoint is to the left of the segment. */ - oprev(fixuptri, fixuptri2); - /* Enforce the Delaunay condition around farpoint, on the */ - /* left side of the segment only. */ - delaunayfixup(&fixuptri2, 1); - /* Flip the edge that crosses the segment. After the edge is */ - /* flipped, one of its endpoints is the fan vertex, and the */ - /* destination of fixuptri is the fan vertex. */ - lprevself(fixuptri); - } else { /* farpoint is to the right of the segment. */ - delaunayfixup(&fixuptri, 0); - /* Flip the edge that crosses the segment. After the edge is */ - /* flipped, one of its endpoints is the fan vertex, and the */ - /* destination of fixuptri is the fan vertex. */ - oprevself(fixuptri); - } - /* Check for two intersecting segments. */ - tspivot(fixuptri, fixupedge); - if (fixupedge.sh == dummysh) { - flip(&fixuptri); /* May create an inverted triangle on the left. */ - } else { - /* We've collided with a segment between endpoint1 and endpoint2. */ - collision = 1; - /* Insert a point at the intersection. */ - segmentintersection(&fixuptri, &fixupedge, endpoint2); - done = 1; - } - } - } - } while (!done); - /* Insert a shell edge to make the segment permanent. */ - insertshelle(&fixuptri, newmark); - /* If there was a collision with an interceding vertex, install another */ - /* segment connecting that vertex with endpoint2. */ - if (collision) { - /* Insert the remainder of the segment. */ - if (!scoutsegment(&fixuptri, endpoint2, newmark)) { - constrainededge(&fixuptri, endpoint2, newmark); - } - } -} - -/*****************************************************************************/ -/* */ -/* insertsegment() Insert a PSLG segment into a triangulation. */ -/* */ -/*****************************************************************************/ - -void insertsegment(endpoint1, endpoint2, newmark) -point endpoint1; -point endpoint2; -int newmark; -{ - struct triedge searchtri1, searchtri2; - triangle encodedtri; - point checkpoint; - triangle ptr; /* Temporary variable used by sym(). */ - - if (verbose > 1) { - printf(" Connecting (%.12g, %.12g) to (%.12g, %.12g).\n", - endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]); - } - - /* Find a triangle whose origin is the segment's first endpoint. */ - checkpoint = (point) NULL; - encodedtri = point2tri(endpoint1); - if (encodedtri != (triangle) NULL) { - decode(encodedtri, searchtri1); - org(searchtri1, checkpoint); - } - if (checkpoint != endpoint1) { - /* Find a boundary triangle to search from. */ - searchtri1.tri = dummytri; - searchtri1.orient = 0; - symself(searchtri1); - /* Search for the segment's first endpoint by point location. */ - if (locate(endpoint1, &searchtri1) != ONVERTEX) { - printf( - "Internal error in insertsegment(): Unable to locate PSLG point\n"); - printf(" (%.12g, %.12g) in triangulation.\n", - endpoint1[0], endpoint1[1]); - internalerror(); - } - } - /* Remember this triangle to improve subsequent point location. */ - triedgecopy(searchtri1, recenttri); - /* Scout the beginnings of a path from the first endpoint */ - /* toward the second. */ - if (scoutsegment(&searchtri1, endpoint2, newmark)) { - /* The segment was easily inserted. */ - return; - } - /* The first endpoint may have changed if a collision with an intervening */ - /* vertex on the segment occurred. */ - org(searchtri1, endpoint1); - - /* Find a triangle whose origin is the segment's second endpoint. */ - checkpoint = (point) NULL; - encodedtri = point2tri(endpoint2); - if (encodedtri != (triangle) NULL) { - decode(encodedtri, searchtri2); - org(searchtri2, checkpoint); - } - if (checkpoint != endpoint2) { - /* Find a boundary triangle to search from. */ - searchtri2.tri = dummytri; - searchtri2.orient = 0; - symself(searchtri2); - /* Search for the segment's second endpoint by point location. */ - if (locate(endpoint2, &searchtri2) != ONVERTEX) { - printf( - "Internal error in insertsegment(): Unable to locate PSLG point\n"); - printf(" (%.12g, %.12g) in triangulation.\n", - endpoint2[0], endpoint2[1]); - internalerror(); - } - } - /* Remember this triangle to improve subsequent point location. */ - triedgecopy(searchtri2, recenttri); - /* Scout the beginnings of a path from the second endpoint */ - /* toward the first. */ - if (scoutsegment(&searchtri2, endpoint1, newmark)) { - /* The segment was easily inserted. */ - return; - } - /* The second endpoint may have changed if a collision with an intervening */ - /* vertex on the segment occurred. */ - org(searchtri2, endpoint2); - -#ifndef REDUCED -#ifndef CDT_ONLY - if (splitseg) { - /* Insert vertices to force the segment into the triangulation. */ - conformingedge(endpoint1, endpoint2, newmark); - } else { -#endif /* not CDT_ONLY */ -#endif /* not REDUCED */ - /* Insert the segment directly into the triangulation. */ - constrainededge(&searchtri1, endpoint2, newmark); -#ifndef REDUCED -#ifndef CDT_ONLY - } -#endif /* not CDT_ONLY */ -#endif /* not REDUCED */ -} - -/*****************************************************************************/ -/* */ -/* markhull() Cover the convex hull of a triangulation with shell edges. */ -/* */ -/*****************************************************************************/ - -void markhull() -{ - struct triedge hulltri; - struct triedge nexttri; - struct triedge starttri; - triangle ptr; /* Temporary variable used by sym() and oprev(). */ - - /* Find a triangle handle on the hull. */ - hulltri.tri = dummytri; - hulltri.orient = 0; - symself(hulltri); - /* Remember where we started so we know when to stop. */ - triedgecopy(hulltri, starttri); - /* Go once counterclockwise around the convex hull. */ - do { - /* Create a shell edge if there isn't already one here. */ - insertshelle(&hulltri, 1); - /* To find the next hull edge, go clockwise around the next vertex. */ - lnextself(hulltri); - oprev(hulltri, nexttri); - while (nexttri.tri != dummytri) { - triedgecopy(nexttri, hulltri); - oprev(hulltri, nexttri); - } - } while (!triedgeequal(hulltri, starttri)); -} - -/*****************************************************************************/ -/* */ -/* formskeleton() Create the shell edges of a triangulation, including */ -/* PSLG edges and edges on the convex hull. */ -/* */ -/* The PSLG edges are read from a .poly file. The return value is the */ -/* number of segments in the file. */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -int formskeleton(segmentlist, segmentmarkerlist, numberofsegments) -int *segmentlist; -int *segmentmarkerlist; -int numberofsegments; - -#else /* not TRILIBRARY */ - -int formskeleton(polyfile, polyfilename) -FILE *polyfile; -char *polyfilename; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - char polyfilename[6]; - int index; -#else /* not TRILIBRARY */ - char inputline[INPUTLINESIZE]; - char *stringptr; -#endif /* not TRILIBRARY */ - point endpoint1, endpoint2; - int segments; - int segmentmarkers; - int end1, end2; - int boundmarker; - int i; - - if (poly) { - if (!quiet) { - printf("Inserting segments into Delaunay triangulation.\n"); - } -#ifdef TRILIBRARY - strcpy(polyfilename, "input"); - segments = numberofsegments; - segmentmarkers = segmentmarkerlist != (int *) NULL; - index = 0; -#else /* not TRILIBRARY */ - /* Read the segments from a .poly file. */ - /* Read number of segments and number of boundary markers. */ - stringptr = readline(inputline, polyfile, polyfilename); - segments = (int) strtol (stringptr, &stringptr, 0); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - segmentmarkers = 0; - } else { - segmentmarkers = (int) strtol (stringptr, &stringptr, 0); - } -#endif /* not TRILIBRARY */ - /* If segments are to be inserted, compute a mapping */ - /* from points to triangles. */ - if (segments > 0) { - if (verbose) { - printf(" Inserting PSLG segments.\n"); - } - makepointmap(); - } - - boundmarker = 0; - /* Read and insert the segments. */ - for (i = 1; i <= segments; i++) { -#ifdef TRILIBRARY - end1 = segmentlist[index++]; - end2 = segmentlist[index++]; - if (segmentmarkers) { - boundmarker = segmentmarkerlist[i - 1]; - } -#else /* not TRILIBRARY */ - stringptr = readline(inputline, polyfile, inpolyfilename); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Segment %d has no endpoints in %s.\n", i, - polyfilename); - exit(1); - } else { - end1 = (int) strtol (stringptr, &stringptr, 0); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Segment %d is missing its second endpoint in %s.\n", i, - polyfilename); - exit(1); - } else { - end2 = (int) strtol (stringptr, &stringptr, 0); - } - if (segmentmarkers) { - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - boundmarker = 0; - } else { - boundmarker = (int) strtol (stringptr, &stringptr, 0); - } - } -#endif /* not TRILIBRARY */ - if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) { - if (!quiet) { - printf("Warning: Invalid first endpoint of segment %d in %s.\n", i, - polyfilename); - } - } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) { - if (!quiet) { - printf("Warning: Invalid second endpoint of segment %d in %s.\n", i, - polyfilename); - } - } else { - endpoint1 = getpoint(end1); - endpoint2 = getpoint(end2); - if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) { - if (!quiet) { - printf("Warning: Endpoints of segment %d are coincident in %s.\n", - i, polyfilename); - } - } else { - insertsegment(endpoint1, endpoint2, boundmarker); - } - } - } - } else { - segments = 0; - } - if (convex || !poly) { - /* Enclose the convex hull with shell edges. */ - if (verbose) { - printf(" Enclosing convex hull with segments.\n"); - } - markhull(); - } - return segments; -} - -/** **/ -/** **/ -/********* Segment (shell edge) insertion ends here *********/ - -/********* Carving out holes and concavities begins here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* infecthull() Virally infect all of the triangles of the convex hull */ -/* that are not protected by shell edges. Where there are */ -/* shell edges, set boundary markers as appropriate. */ -/* */ -/*****************************************************************************/ - -void infecthull() -{ - struct triedge hulltri; - struct triedge nexttri; - struct triedge starttri; - struct edge hulledge; - triangle **deadtri; - point horg, hdest; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - if (verbose) { - printf(" Marking concavities (external triangles) for elimination.\n"); - } - /* Find a triangle handle on the hull. */ - hulltri.tri = dummytri; - hulltri.orient = 0; - symself(hulltri); - /* Remember where we started so we know when to stop. */ - triedgecopy(hulltri, starttri); - /* Go once counterclockwise around the convex hull. */ - do { - /* Ignore triangles that are already infected. */ - if (!infected(hulltri)) { - /* Is the triangle protected by a shell edge? */ - tspivot(hulltri, hulledge); - if (hulledge.sh == dummysh) { - /* The triangle is not protected; infect it. */ - infect(hulltri); - deadtri = (triangle **) poolalloc(&viri); - *deadtri = hulltri.tri; - } else { - /* The triangle is protected; set boundary markers if appropriate. */ - if (mark(hulledge) == 0) { - setmark(hulledge, 1); - org(hulltri, horg); - dest(hulltri, hdest); - if (pointmark(horg) == 0) { - setpointmark(horg, 1); - } - if (pointmark(hdest) == 0) { - setpointmark(hdest, 1); - } - } - } - } - /* To find the next hull edge, go clockwise around the next vertex. */ - lnextself(hulltri); - oprev(hulltri, nexttri); - while (nexttri.tri != dummytri) { - triedgecopy(nexttri, hulltri); - oprev(hulltri, nexttri); - } - } while (!triedgeequal(hulltri, starttri)); -} - -/*****************************************************************************/ -/* */ -/* plague() Spread the virus from all infected triangles to any neighbors */ -/* not protected by shell edges. Delete all infected triangles. */ -/* */ -/* This is the procedure that actually creates holes and concavities. */ -/* */ -/* This procedure operates in two phases. The first phase identifies all */ -/* the triangles that will die, and marks them as infected. They are */ -/* marked to ensure that each triangle is added to the virus pool only */ -/* once, so the procedure will terminate. */ -/* */ -/* The second phase actually eliminates the infected triangles. It also */ -/* eliminates orphaned points. */ -/* */ -/*****************************************************************************/ - -void plague() -{ - struct triedge testtri; - struct triedge neighbor; - triangle **virusloop; - triangle **deadtri; - struct edge neighborshelle; - point testpoint; - point norg, ndest; - point deadorg, deaddest, deadapex; - int killorg; - triangle ptr; /* Temporary variable used by sym() and onext(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - if (verbose) { - printf(" Marking neighbors of marked triangles.\n"); - } - /* Loop through all the infected triangles, spreading the virus to */ - /* their neighbors, then to their neighbors' neighbors. */ - traversalinit(&viri); - virusloop = (triangle **) traverse(&viri); - while (virusloop != (triangle **) NULL) { - testtri.tri = *virusloop; - /* A triangle is marked as infected by messing with one of its shell */ - /* edges, setting it to an illegal value. Hence, we have to */ - /* temporarily uninfect this triangle so that we can examine its */ - /* adjacent shell edges. */ - uninfect(testtri); - if (verbose > 2) { - /* Assign the triangle an orientation for convenience in */ - /* checking its points. */ - testtri.orient = 0; - org(testtri, deadorg); - dest(testtri, deaddest); - apex(testtri, deadapex); - printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", - deadorg[0], deadorg[1], deaddest[0], deaddest[1], - deadapex[0], deadapex[1]); - } - /* Check each of the triangle's three neighbors. */ - for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { - /* Find the neighbor. */ - sym(testtri, neighbor); - /* Check for a shell between the triangle and its neighbor. */ - tspivot(testtri, neighborshelle); - /* Check if the neighbor is nonexistent or already infected. */ - if ((neighbor.tri == dummytri) || infected(neighbor)) { - if (neighborshelle.sh != dummysh) { - /* There is a shell edge separating the triangle from its */ - /* neighbor, but both triangles are dying, so the shell */ - /* edge dies too. */ - shelledealloc(neighborshelle.sh); - if (neighbor.tri != dummytri) { - /* Make sure the shell edge doesn't get deallocated again */ - /* later when the infected neighbor is visited. */ - uninfect(neighbor); - tsdissolve(neighbor); - infect(neighbor); - } - } - } else { /* The neighbor exists and is not infected. */ - if (neighborshelle.sh == dummysh) { - /* There is no shell edge protecting the neighbor, so */ - /* the neighbor becomes infected. */ - if (verbose > 2) { - org(neighbor, deadorg); - dest(neighbor, deaddest); - apex(neighbor, deadapex); - printf( - " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", - deadorg[0], deadorg[1], deaddest[0], deaddest[1], - deadapex[0], deadapex[1]); - } - infect(neighbor); - /* Ensure that the neighbor's neighbors will be infected. */ - deadtri = (triangle **) poolalloc(&viri); - *deadtri = neighbor.tri; - } else { /* The neighbor is protected by a shell edge. */ - /* Remove this triangle from the shell edge. */ - stdissolve(neighborshelle); - /* The shell edge becomes a boundary. Set markers accordingly. */ - if (mark(neighborshelle) == 0) { - setmark(neighborshelle, 1); - } - org(neighbor, norg); - dest(neighbor, ndest); - if (pointmark(norg) == 0) { - setpointmark(norg, 1); - } - if (pointmark(ndest) == 0) { - setpointmark(ndest, 1); - } - } - } - } - /* Remark the triangle as infected, so it doesn't get added to the */ - /* virus pool again. */ - infect(testtri); - virusloop = (triangle **) traverse(&viri); - } - - if (verbose) { - printf(" Deleting marked triangles.\n"); - } - traversalinit(&viri); - virusloop = (triangle **) traverse(&viri); - while (virusloop != (triangle **) NULL) { - testtri.tri = *virusloop; - - /* Check each of the three corners of the triangle for elimination. */ - /* This is done by walking around each point, checking if it is */ - /* still connected to at least one live triangle. */ - for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { - org(testtri, testpoint); - /* Check if the point has already been tested. */ - if (testpoint != (point) NULL) { - killorg = 1; - /* Mark the corner of the triangle as having been tested. */ - setorg(testtri, NULL); - /* Walk counterclockwise about the point. */ - onext(testtri, neighbor); - /* Stop upon reaching a boundary or the starting triangle. */ - while ((neighbor.tri != dummytri) - && (!triedgeequal(neighbor, testtri))) { - if (infected(neighbor)) { - /* Mark the corner of this triangle as having been tested. */ - setorg(neighbor, NULL); - } else { - /* A live triangle. The point survives. */ - killorg = 0; - } - /* Walk counterclockwise about the point. */ - onextself(neighbor); - } - /* If we reached a boundary, we must walk clockwise as well. */ - if (neighbor.tri == dummytri) { - /* Walk clockwise about the point. */ - oprev(testtri, neighbor); - /* Stop upon reaching a boundary. */ - while (neighbor.tri != dummytri) { - if (infected(neighbor)) { - /* Mark the corner of this triangle as having been tested. */ - setorg(neighbor, NULL); - } else { - /* A live triangle. The point survives. */ - killorg = 0; - } - /* Walk clockwise about the point. */ - oprevself(neighbor); - } - } - if (killorg) { - if (verbose > 1) { - printf(" Deleting point (%.12g, %.12g)\n", - testpoint[0], testpoint[1]); - } - pointdealloc(testpoint); - } - } - } - - /* Record changes in the number of boundary edges, and disconnect */ - /* dead triangles from their neighbors. */ - for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { - sym(testtri, neighbor); - if (neighbor.tri == dummytri) { - /* There is no neighboring triangle on this edge, so this edge */ - /* is a boundary edge. This triangle is being deleted, so this */ - /* boundary edge is deleted. */ - hullsize--; - } else { - /* Disconnect the triangle from its neighbor. */ - dissolve(neighbor); - /* There is a neighboring triangle on this edge, so this edge */ - /* becomes a boundary edge when this triangle is deleted. */ - hullsize++; - } - } - /* Return the dead triangle to the pool of triangles. */ - triangledealloc(testtri.tri); - virusloop = (triangle **) traverse(&viri); - } - /* Empty the virus pool. */ - poolrestart(&viri); -} - -/*****************************************************************************/ -/* */ -/* regionplague() Spread regional attributes and/or area constraints */ -/* (from a .poly file) throughout the mesh. */ -/* */ -/* This procedure operates in two phases. The first phase spreads an */ -/* attribute and/or an area constraint through a (segment-bounded) region. */ -/* The triangles are marked to ensure that each triangle is added to the */ -/* virus pool only once, so the procedure will terminate. */ -/* */ -/* The second phase uninfects all infected triangles, returning them to */ -/* normal. */ -/* */ -/*****************************************************************************/ - -void regionplague(attribute, area) -REAL attribute; -REAL area; -{ - struct triedge testtri; - struct triedge neighbor; - triangle **virusloop; - triangle **regiontri; - struct edge neighborshelle; - point regionorg, regiondest, regionapex; - triangle ptr; /* Temporary variable used by sym() and onext(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - if (verbose > 1) { - printf(" Marking neighbors of marked triangles.\n"); - } - /* Loop through all the infected triangles, spreading the attribute */ - /* and/or area constraint to their neighbors, then to their neighbors' */ - /* neighbors. */ - traversalinit(&viri); - virusloop = (triangle **) traverse(&viri); - while (virusloop != (triangle **) NULL) { - testtri.tri = *virusloop; - /* A triangle is marked as infected by messing with one of its shell */ - /* edges, setting it to an illegal value. Hence, we have to */ - /* temporarily uninfect this triangle so that we can examine its */ - /* adjacent shell edges. */ - uninfect(testtri); - if (regionattrib) { - /* Set an attribute. */ - setelemattribute(testtri, eextras, attribute); - } - if (vararea) { - /* Set an area constraint. */ - setareabound(testtri, area); - } - if (verbose > 2) { - /* Assign the triangle an orientation for convenience in */ - /* checking its points. */ - testtri.orient = 0; - org(testtri, regionorg); - dest(testtri, regiondest); - apex(testtri, regionapex); - printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", - regionorg[0], regionorg[1], regiondest[0], regiondest[1], - regionapex[0], regionapex[1]); - } - /* Check each of the triangle's three neighbors. */ - for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { - /* Find the neighbor. */ - sym(testtri, neighbor); - /* Check for a shell between the triangle and its neighbor. */ - tspivot(testtri, neighborshelle); - /* Make sure the neighbor exists, is not already infected, and */ - /* isn't protected by a shell edge. */ - if ((neighbor.tri != dummytri) && !infected(neighbor) - && (neighborshelle.sh == dummysh)) { - if (verbose > 2) { - org(neighbor, regionorg); - dest(neighbor, regiondest); - apex(neighbor, regionapex); - printf(" Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", - regionorg[0], regionorg[1], regiondest[0], regiondest[1], - regionapex[0], regionapex[1]); - } - /* Infect the neighbor. */ - infect(neighbor); - /* Ensure that the neighbor's neighbors will be infected. */ - regiontri = (triangle **) poolalloc(&viri); - *regiontri = neighbor.tri; - } - } - /* Remark the triangle as infected, so it doesn't get added to the */ - /* virus pool again. */ - infect(testtri); - virusloop = (triangle **) traverse(&viri); - } - - /* Uninfect all triangles. */ - if (verbose > 1) { - printf(" Unmarking marked triangles.\n"); - } - traversalinit(&viri); - virusloop = (triangle **) traverse(&viri); - while (virusloop != (triangle **) NULL) { - testtri.tri = *virusloop; - uninfect(testtri); - virusloop = (triangle **) traverse(&viri); - } - /* Empty the virus pool. */ - poolrestart(&viri); -} - -/*****************************************************************************/ -/* */ -/* carveholes() Find the holes and infect them. Find the area */ -/* constraints and infect them. Infect the convex hull. */ -/* Spread the infection and kill triangles. Spread the */ -/* area constraints. */ -/* */ -/* This routine mainly calls other routines to carry out all these */ -/* functions. */ -/* */ -/*****************************************************************************/ - -void carveholes(holelist, holes, regionlist, regions) -REAL *holelist; -int holes; -REAL *regionlist; -int regions; -{ - struct triedge searchtri; - struct triedge triangleloop; - struct triedge *regiontris; - triangle **holetri; - triangle **regiontri; - point searchorg, searchdest; - enum locateresult intersect; - int i; - triangle ptr; /* Temporary variable used by sym(). */ - - if (!(quiet || (noholes && convex))) { - printf("Removing unwanted triangles.\n"); - if (verbose && (holes > 0)) { - printf(" Marking holes for elimination.\n"); - } - } - - if (regions > 0) { - /* Allocate storage for the triangles in which region points fall. */ - regiontris = (struct triedge *) malloc(regions * sizeof(struct triedge)); - if (regiontris == (struct triedge *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - - if (((holes > 0) && !noholes) || !convex || (regions > 0)) { - /* Initialize a pool of viri to be used for holes, concavities, */ - /* regional attributes, and/or regional area constraints. */ - poolinit(&viri, sizeof(triangle *), VIRUSPERBLOCK, POINTER, 0); - } - - if (!convex) { - /* Mark as infected any unprotected triangles on the boundary. */ - /* This is one way by which concavities are created. */ - infecthull(); - } - - if ((holes > 0) && !noholes) { - /* Infect each triangle in which a hole lies. */ - for (i = 0; i < 2 * holes; i += 2) { - /* Ignore holes that aren't within the bounds of the mesh. */ - if ((holelist[i] >= xmin) && (holelist[i] <= xmax) - && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)) { - /* Start searching from some triangle on the outer boundary. */ - searchtri.tri = dummytri; - searchtri.orient = 0; - symself(searchtri); - /* Ensure that the hole is to the left of this boundary edge; */ - /* otherwise, locate() will falsely report that the hole */ - /* falls within the starting triangle. */ - org(searchtri, searchorg); - dest(searchtri, searchdest); - if (counterclockwise(searchorg, searchdest, &holelist[i]) > 0.0) { - /* Find a triangle that contains the hole. */ - intersect = locate(&holelist[i], &searchtri); - if ((intersect != OUTSIDE) && (!infected(searchtri))) { - /* Infect the triangle. This is done by marking the triangle */ - /* as infect and including the triangle in the virus pool. */ - infect(searchtri); - holetri = (triangle **) poolalloc(&viri); - *holetri = searchtri.tri; - } - } - } - } - } - - /* Now, we have to find all the regions BEFORE we carve the holes, because */ - /* locate() won't work when the triangulation is no longer convex. */ - /* (Incidentally, this is the reason why regional attributes and area */ - /* constraints can't be used when refining a preexisting mesh, which */ - /* might not be convex; they can only be used with a freshly */ - /* triangulated PSLG.) */ - if (regions > 0) { - /* Find the starting triangle for each region. */ - for (i = 0; i < regions; i++) { - regiontris[i].tri = dummytri; - /* Ignore region points that aren't within the bounds of the mesh. */ - if ((regionlist[4 * i] >= xmin) && (regionlist[4 * i] <= xmax) && - (regionlist[4 * i + 1] >= ymin) && (regionlist[4 * i + 1] <= ymax)) { - /* Start searching from some triangle on the outer boundary. */ - searchtri.tri = dummytri; - searchtri.orient = 0; - symself(searchtri); - /* Ensure that the region point is to the left of this boundary */ - /* edge; otherwise, locate() will falsely report that the */ - /* region point falls within the starting triangle. */ - org(searchtri, searchorg); - dest(searchtri, searchdest); - if (counterclockwise(searchorg, searchdest, ®ionlist[4 * i]) > - 0.0) { - /* Find a triangle that contains the region point. */ - intersect = locate(®ionlist[4 * i], &searchtri); - if ((intersect != OUTSIDE) && (!infected(searchtri))) { - /* Record the triangle for processing after the */ - /* holes have been carved. */ - triedgecopy(searchtri, regiontris[i]); - } - } - } - } - } - - if (viri.items > 0) { - /* Carve the holes and concavities. */ - plague(); - } - /* The virus pool should be empty now. */ - - if (regions > 0) { - if (!quiet) { - if (regionattrib) { - if (vararea) { - printf("Spreading regional attributes and area constraints.\n"); - } else { - printf("Spreading regional attributes.\n"); - } - } else { - printf("Spreading regional area constraints.\n"); - } - } - if (regionattrib && !refine) { - /* Assign every triangle a regional attribute of zero. */ - traversalinit(&triangles); - triangleloop.orient = 0; - triangleloop.tri = triangletraverse(); - while (triangleloop.tri != (triangle *) NULL) { - setelemattribute(triangleloop, eextras, 0.0); - triangleloop.tri = triangletraverse(); - } - } - for (i = 0; i < regions; i++) { - if (regiontris[i].tri != dummytri) { - /* Make sure the triangle under consideration still exists. */ - /* It may have been eaten by the virus. */ - if (regiontris[i].tri[3] != (triangle) NULL) { - /* Put one triangle in the virus pool. */ - infect(regiontris[i]); - regiontri = (triangle **) poolalloc(&viri); - *regiontri = regiontris[i].tri; - /* Apply one region's attribute and/or area constraint. */ - regionplague(regionlist[4 * i + 2], regionlist[4 * i + 3]); - /* The virus pool should be empty now. */ - } - } - } - if (regionattrib && !refine) { - /* Note the fact that each triangle has an additional attribute. */ - eextras++; - } - } - - /* Free up memory. */ - if (((holes > 0) && !noholes) || !convex || (regions > 0)) { - pooldeinit(&viri); - } - if (regions > 0) { - free(regiontris); - } -} - -/** **/ -/** **/ -/********* Carving out holes and concavities ends here *********/ - -/********* Mesh quality maintenance begins here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* tallyencs() Traverse the entire list of shell edges, check each edge */ -/* to see if it is encroached. If so, add it to the list. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void tallyencs() -{ - struct edge edgeloop; - int dummy; - - traversalinit(&shelles); - edgeloop.shorient = 0; - edgeloop.sh = shelletraverse(); - while (edgeloop.sh != (shelle *) NULL) { - /* If the segment is encroached, add it to the list. */ - dummy = checkedge4encroach(&edgeloop); - edgeloop.sh = shelletraverse(); - } -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* precisionerror() Print an error message for precision problems. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void precisionerror() -{ - printf("Try increasing the area criterion and/or reducing the minimum\n"); - printf(" allowable angle so that tiny triangles are not created.\n"); -#ifdef SINGLE - printf("Alternatively, try recompiling me with double precision\n"); - printf(" arithmetic (by removing \"#define SINGLE\" from the\n"); - printf(" source file or \"-DSINGLE\" from the makefile).\n"); -#endif /* SINGLE */ -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* repairencs() Find and repair all the encroached segments. */ -/* */ -/* Encroached segments are repaired by splitting them by inserting a point */ -/* at or near their centers. */ -/* */ -/* `flaws' is a flag that specifies whether one should take note of new */ -/* encroached segments and bad triangles that result from inserting points */ -/* to repair existing encroached segments. */ -/* */ -/* When a segment is split, the two resulting subsegments are always */ -/* tested to see if they are encroached upon, regardless of the value */ -/* of `flaws'. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void repairencs(flaws) -int flaws; -{ - struct triedge enctri; - struct triedge testtri; - struct edge *encloop; - struct edge testsh; - point eorg, edest; - point newpoint; - enum insertsiteresult success; - REAL segmentlength, nearestpoweroftwo; - REAL split; - int acuteorg, acutedest; - int dummy; - int i; - triangle ptr; /* Temporary variable used by stpivot(). */ - shelle sptr; /* Temporary variable used by snext(). */ - - while ((badsegments.items > 0) && (steinerleft != 0)) { - traversalinit(&badsegments); - encloop = badsegmenttraverse(); - while ((encloop != (struct edge *) NULL) && (steinerleft != 0)) { - /* To decide where to split a segment, we need to know if the */ - /* segment shares an endpoint with an adjacent segment. */ - /* The concern is that, if we simply split every encroached */ - /* segment in its center, two adjacent segments with a small */ - /* angle between them might lead to an infinite loop; each */ - /* point added to split one segment will encroach upon the */ - /* other segment, which must then be split with a point that */ - /* will encroach upon the first segment, and so on forever. */ - /* To avoid this, imagine a set of concentric circles, whose */ - /* radii are powers of two, about each segment endpoint. */ - /* These concentric circles determine where the segment is */ - /* split. (If both endpoints are shared with adjacent */ - /* segments, split the segment in the middle, and apply the */ - /* concentric shells for later splittings.) */ - - /* Is the origin shared with another segment? */ - stpivot(*encloop, enctri); - lnext(enctri, testtri); - tspivot(testtri, testsh); - acuteorg = testsh.sh != dummysh; - /* Is the destination shared with another segment? */ - lnextself(testtri); - tspivot(testtri, testsh); - acutedest = testsh.sh != dummysh; - /* Now, check the other side of the segment, if there's a triangle */ - /* there. */ - sym(enctri, testtri); - if (testtri.tri != dummytri) { - /* Is the destination shared with another segment? */ - lnextself(testtri); - tspivot(testtri, testsh); - acutedest = acutedest || (testsh.sh != dummysh); - /* Is the origin shared with another segment? */ - lnextself(testtri); - tspivot(testtri, testsh); - acuteorg = acuteorg || (testsh.sh != dummysh); - } - - sorg(*encloop, eorg); - sdest(*encloop, edest); - /* Use the concentric circles if exactly one endpoint is shared */ - /* with another adjacent segment. */ - if (acuteorg ^ acutedest) { - segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0]) - + (edest[1] - eorg[1]) * (edest[1] - eorg[1])); - /* Find the power of two nearest the segment's length. */ - nearestpoweroftwo = 1.0; - while (segmentlength > SQUAREROOTTWO * nearestpoweroftwo) { - nearestpoweroftwo *= 2.0; - } - while (segmentlength < (0.5 * SQUAREROOTTWO) * nearestpoweroftwo) { - nearestpoweroftwo *= 0.5; - } - /* Where do we split the segment? */ - split = 0.5 * nearestpoweroftwo / segmentlength; - if (acutedest) { - split = 1.0 - split; - } - } else { - /* If we're not worried about adjacent segments, split */ - /* this segment in the middle. */ - split = 0.5; - } - - /* Create the new point. */ - newpoint = (point) poolalloc(&points); - /* Interpolate its coordinate and attributes. */ - for (i = 0; i < 2 + nextras; i++) { - newpoint[i] = (1.0 - split) * eorg[i] + split * edest[i]; - } - setpointmark(newpoint, mark(*encloop)); - if (verbose > 1) { - printf( - " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", - eorg[0], eorg[1], edest[0], edest[1], newpoint[0], newpoint[1]); - } - /* Check whether the new point lies on an endpoint. */ - if (((newpoint[0] == eorg[0]) && (newpoint[1] == eorg[1])) - || ((newpoint[0] == edest[0]) && (newpoint[1] == edest[1]))) { - printf("Error: Ran out of precision at (%.12g, %.12g).\n", - newpoint[0], newpoint[1]); - printf("I attempted to split a segment to a smaller size than can\n"); - printf(" be accommodated by the finite precision of floating point\n" - ); - printf(" arithmetic.\n"); - precisionerror(); - exit(1); - } - /* Insert the splitting point. This should always succeed. */ - success = insertsite(newpoint, &enctri, encloop, flaws, flaws); - if ((success != SUCCESSFULPOINT) && (success != ENCROACHINGPOINT)) { - printf("Internal error in repairencs():\n"); - printf(" Failure to split a segment.\n"); - internalerror(); - } - if (steinerleft > 0) { - steinerleft--; - } - /* Check the two new subsegments to see if they're encroached. */ - dummy = checkedge4encroach(encloop); - snextself(*encloop); - dummy = checkedge4encroach(encloop); - - badsegmentdealloc(encloop); - encloop = badsegmenttraverse(); - } - } -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* tallyfaces() Test every triangle in the mesh for quality measures. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void tallyfaces() -{ - struct triedge triangleloop; - - if (verbose) { - printf(" Making a list of bad triangles.\n"); - } - traversalinit(&triangles); - triangleloop.orient = 0; - triangleloop.tri = triangletraverse(); - while (triangleloop.tri != (triangle *) NULL) { - /* If the triangle is bad, enqueue it. */ - testtriangle(&triangleloop); - triangleloop.tri = triangletraverse(); - } -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* findcircumcenter() Find the circumcenter of a triangle. */ -/* */ -/* The result is returned both in terms of x-y coordinates and xi-eta */ -/* coordinates. The xi-eta coordinate system is defined in terms of the */ -/* triangle: the origin of the triangle is the origin of the coordinate */ -/* system; the destination of the triangle is one unit along the xi axis; */ -/* and the apex of the triangle is one unit along the eta axis. */ -/* */ -/* The return value indicates which edge of the triangle is shortest. */ -/* */ -/*****************************************************************************/ - -enum circumcenterresult findcircumcenter(torg, tdest, tapex, circumcenter, - xi, eta) -point torg; -point tdest; -point tapex; -point circumcenter; -REAL *xi; -REAL *eta; -{ - REAL xdo, ydo, xao, yao, xad, yad; - REAL dodist, aodist, addist; - REAL denominator; - REAL dx, dy; - - circumcentercount++; - - /* Compute the circumcenter of the triangle. */ - xdo = tdest[0] - torg[0]; - ydo = tdest[1] - torg[1]; - xao = tapex[0] - torg[0]; - yao = tapex[1] - torg[1]; - dodist = xdo * xdo + ydo * ydo; - aodist = xao * xao + yao * yao; - if (noexact) { - denominator = (REAL)(0.5 / (xdo * yao - xao * ydo)); - } else { - /* Use the counterclockwise() routine to ensure a positive (and */ - /* reasonably accurate) result, avoiding any possibility of */ - /* division by zero. */ - denominator = (REAL)(0.5 / counterclockwise(tdest, tapex, torg)); - /* Don't count the above as an orientation test. */ - counterclockcount--; - } - circumcenter[0] = torg[0] - (ydo * aodist - yao * dodist) * denominator; - circumcenter[1] = torg[1] + (xdo * aodist - xao * dodist) * denominator; - - /* To interpolate point attributes for the new point inserted at */ - /* the circumcenter, define a coordinate system with a xi-axis, */ - /* directed from the triangle's origin to its destination, and */ - /* an eta-axis, directed from its origin to its apex. */ - /* Calculate the xi and eta coordinates of the circumcenter. */ - dx = circumcenter[0] - torg[0]; - dy = circumcenter[1] - torg[1]; - *xi = (REAL)((dx * yao - xao * dy) * (2.0 * denominator)); - *eta = (REAL)((xdo * dy - dx * ydo) * (2.0 * denominator)); - - xad = tapex[0] - tdest[0]; - yad = tapex[1] - tdest[1]; - addist = xad * xad + yad * yad; - if ((addist < dodist) && (addist < aodist)) { - return OPPOSITEORG; - } else if (dodist < aodist) { - return OPPOSITEAPEX; - } else { - return OPPOSITEDEST; - } -} - -/*****************************************************************************/ -/* */ -/* splittriangle() Inserts a point at the circumcenter of a triangle. */ -/* Deletes the newly inserted point if it encroaches upon */ -/* a segment. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void splittriangle(badtri) -struct badface *badtri; -{ - point borg, bdest, bapex; - point newpoint; - REAL xi, eta; - enum insertsiteresult success; - enum circumcenterresult shortedge; - int errorflag; - int i; - - org(badtri->badfacetri, borg); - dest(badtri->badfacetri, bdest); - apex(badtri->badfacetri, bapex); - /* Make sure that this triangle is still the same triangle it was */ - /* when it was tested and determined to be of bad quality. */ - /* Subsequent transformations may have made it a different triangle. */ - if ((borg == badtri->faceorg) && (bdest == badtri->facedest) && - (bapex == badtri->faceapex)) { - if (verbose > 1) { - printf(" Splitting this triangle at its circumcenter:\n"); - printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", borg[0], - borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); - } - errorflag = 0; - /* Create a new point at the triangle's circumcenter. */ - newpoint = (point) poolalloc(&points); - shortedge = findcircumcenter(borg, bdest, bapex, newpoint, &xi, &eta); - /* Check whether the new point lies on a triangle vertex. */ - if (((newpoint[0] == borg[0]) && (newpoint[1] == borg[1])) - || ((newpoint[0] == bdest[0]) && (newpoint[1] == bdest[1])) - || ((newpoint[0] == bapex[0]) && (newpoint[1] == bapex[1]))) { - if (!quiet) { - printf("Warning: New point (%.12g, %.12g) falls on existing vertex.\n" - , newpoint[0], newpoint[1]); - errorflag = 1; - } - pointdealloc(newpoint); - } else { - for (i = 2; i < 2 + nextras; i++) { - /* Interpolate the point attributes at the circumcenter. */ - newpoint[i] = borg[i] + xi * (bdest[i] - borg[i]) - + eta * (bapex[i] - borg[i]); - } - /* The new point must be in the interior, and have a marker of zero. */ - setpointmark(newpoint, 0); - /* Ensure that the handle `badtri->badfacetri' represents the shortest */ - /* edge of the triangle. This ensures that the circumcenter must */ - /* fall to the left of this edge, so point location will work. */ - if (shortedge == OPPOSITEORG) { - lnextself(badtri->badfacetri); - } else if (shortedge == OPPOSITEDEST) { - lprevself(badtri->badfacetri); - } - /* Insert the circumcenter, searching from the edge of the triangle, */ - /* and maintain the Delaunay property of the triangulation. */ - success = insertsite(newpoint, &(badtri->badfacetri), - (struct edge *) NULL, 1, 1); - if (success == SUCCESSFULPOINT) { - if (steinerleft > 0) { - steinerleft--; - } - } else if (success == ENCROACHINGPOINT) { - /* If the newly inserted point encroaches upon a segment, delete it. */ - deletesite(&(badtri->badfacetri)); - } else if (success == VIOLATINGPOINT) { - /* Failed to insert the new point, but some segment was */ - /* marked as being encroached. */ - pointdealloc(newpoint); - } else { /* success == DUPLICATEPOINT */ - /* Failed to insert the new point because a vertex is already there. */ - if (!quiet) { - printf( - "Warning: New point (%.12g, %.12g) falls on existing vertex.\n" - , newpoint[0], newpoint[1]); - errorflag = 1; - } - pointdealloc(newpoint); - } - } - if (errorflag) { - if (verbose) { - printf(" The new point is at the circumcenter of triangle\n"); - printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", - borg[0], borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); - } - printf("This probably means that I am trying to refine triangles\n"); - printf(" to a smaller size than can be accommodated by the finite\n"); - printf(" precision of floating point arithmetic. (You can be\n"); - printf(" sure of this if I fail to terminate.)\n"); - precisionerror(); - } - } - /* Return the bad triangle to the pool. */ - pooldealloc(&badtriangles, (VOID *) badtri); -} - -#endif /* not CDT_ONLY */ - -/*****************************************************************************/ -/* */ -/* enforcequality() Remove all the encroached edges and bad triangles */ -/* from the triangulation. */ -/* */ -/*****************************************************************************/ - -#ifndef CDT_ONLY - -void enforcequality() -{ - int i; - - if (!quiet) { - printf("Adding Steiner points to enforce quality.\n"); - } - /* Initialize the pool of encroached segments. */ - poolinit(&badsegments, sizeof(struct edge), BADSEGMENTPERBLOCK, POINTER, 0); - if (verbose) { - printf(" Looking for encroached segments.\n"); - } - /* Test all segments to see if they're encroached. */ - tallyencs(); - if (verbose && (badsegments.items > 0)) { - printf(" Splitting encroached segments.\n"); - } - /* Note that steinerleft == -1 if an unlimited number */ - /* of Steiner points is allowed. */ - while ((badsegments.items > 0) && (steinerleft != 0)) { - /* Fix the segments without noting newly encroached segments or */ - /* bad triangles. The reason we don't want to note newly */ - /* encroached segments is because some encroached segments are */ - /* likely to be noted multiple times, and would then be blindly */ - /* split multiple times. I should fix that some time. */ - repairencs(0); - /* Now, find all the segments that became encroached while adding */ - /* points to split encroached segments. */ - tallyencs(); - } - /* At this point, if we haven't run out of Steiner points, the */ - /* triangulation should be (conforming) Delaunay. */ - - /* Next, we worry about enforcing triangle quality. */ - if ((minangle > 0.0) || vararea || fixedarea) { - /* Initialize the pool of bad triangles. */ - poolinit(&badtriangles, sizeof(struct badface), BADTRIPERBLOCK, POINTER, - 0); - /* Initialize the queues of bad triangles. */ - for (i = 0; i < 64; i++) { - queuefront[i] = (struct badface *) NULL; - queuetail[i] = &queuefront[i]; - } - /* Test all triangles to see if they're bad. */ - tallyfaces(); - if (verbose) { - printf(" Splitting bad triangles.\n"); - } - while ((badtriangles.items > 0) && (steinerleft != 0)) { - /* Fix one bad triangle by inserting a point at its circumcenter. */ - splittriangle(dequeuebadtri()); - /* Fix any encroached segments that may have resulted. Record */ - /* any new bad triangles or encroached segments that result. */ - if (badsegments.items > 0) { - repairencs(1); - } - } - } - /* At this point, if we haven't run out of Steiner points, the */ - /* triangulation should be (conforming) Delaunay and have no */ - /* low-quality triangles. */ - - /* Might we have run out of Steiner points too soon? */ - if (!quiet && (badsegments.items > 0) && (steinerleft == 0)) { - printf("\nWarning: I ran out of Steiner points, but the mesh has\n"); - if (badsegments.items == 1) { - printf(" an encroached segment, and therefore might not be truly\n"); - } else { - printf(" %ld encroached segments, and therefore might not be truly\n", - badsegments.items); - } - printf(" Delaunay. If the Delaunay property is important to you,\n"); - printf(" try increasing the number of Steiner points (controlled by\n"); - printf(" the -S switch) slightly and try again.\n\n"); - } -} - -#endif /* not CDT_ONLY */ - -/** **/ -/** **/ -/********* Mesh quality maintenance ends here *********/ - -/*****************************************************************************/ -/* */ -/* highorder() Create extra nodes for quadratic subparametric elements. */ -/* */ -/*****************************************************************************/ - -void highorder() -{ - struct triedge triangleloop, trisym; - struct edge checkmark; - point newpoint; - point torg, tdest; - int i; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - - if (!quiet) { - printf("Adding vertices for second-order triangles.\n"); - } - /* The following line ensures that dead items in the pool of nodes */ - /* cannot be allocated for the extra nodes associated with high */ - /* order elements. This ensures that the primary nodes (at the */ - /* corners of elements) will occur earlier in the output files, and */ - /* have lower indices, than the extra nodes. */ - points.deaditemstack = (VOID *) NULL; - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - /* To loop over the set of edges, loop over all triangles, and look at */ - /* the three edges of each triangle. If there isn't another triangle */ - /* adjacent to the edge, operate on the edge. If there is another */ - /* adjacent triangle, operate on the edge only if the current triangle */ - /* has a smaller pointer than its neighbor. This way, each edge is */ - /* considered only once. */ - while (triangleloop.tri != (triangle *) NULL) { - for (triangleloop.orient = 0; triangleloop.orient < 3; - triangleloop.orient++) { - sym(triangleloop, trisym); - if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { - org(triangleloop, torg); - dest(triangleloop, tdest); - /* Create a new node in the middle of the edge. Interpolate */ - /* its attributes. */ - newpoint = (point) poolalloc(&points); - for (i = 0; i < 2 + nextras; i++) { - newpoint[i] = (REAL)(0.5 * (torg[i] + tdest[i])); - } - /* Set the new node's marker to zero or one, depending on */ - /* whether it lies on a boundary. */ - setpointmark(newpoint, trisym.tri == dummytri); - if (useshelles) { - tspivot(triangleloop, checkmark); - /* If this edge is a segment, transfer the marker to the new node. */ - if (checkmark.sh != dummysh) { - setpointmark(newpoint, mark(checkmark)); - } - } - if (verbose > 1) { - printf(" Creating (%.12g, %.12g).\n", newpoint[0], newpoint[1]); - } - /* Record the new node in the (one or two) adjacent elements. */ - triangleloop.tri[highorderindex + triangleloop.orient] = - (triangle) newpoint; - if (trisym.tri != dummytri) { - trisym.tri[highorderindex + trisym.orient] = (triangle) newpoint; - } - } - } - triangleloop.tri = triangletraverse(); - } -} - -/********* File I/O routines begin here *********/ -/** **/ -/** **/ - -/*****************************************************************************/ -/* */ -/* readline() Read a nonempty line from a file. */ -/* */ -/* A line is considered "nonempty" if it contains something that looks like */ -/* a number. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -char *readline(string, infile, infilename) -char *string; -FILE *infile; -char *infilename; -{ - char *result; - - /* Search for something that looks like a number. */ - do { - result = fgets(string, INPUTLINESIZE, infile); - if (result == (char *) NULL) { - printf(" Error: Unexpected end of file in %s.\n", infilename); - exit(1); - } - /* Skip anything that doesn't look like a number, a comment, */ - /* or the end of a line. */ - while ((*result != '\0') && (*result != '#') - && (*result != '.') && (*result != '+') && (*result != '-') - && ((*result < '0') || (*result > '9'))) { - result++; - } - /* If it's a comment or end of line, read another line and try again. */ - } while ((*result == '#') || (*result == '\0')); - return result; -} - -#endif /* not TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* findfield() Find the next field of a string. */ -/* */ -/* Jumps past the current field by searching for whitespace, then jumps */ -/* past the whitespace to find the next field. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -char *findfield(string) -char *string; -{ - char *result; - - result = string; - /* Skip the current field. Stop upon reaching whitespace. */ - while ((*result != '\0') && (*result != '#') - && (*result != ' ') && (*result != '\t')) { - result++; - } - /* Now skip the whitespace and anything else that doesn't look like a */ - /* number, a comment, or the end of a line. */ - while ((*result != '\0') && (*result != '#') - && (*result != '.') && (*result != '+') && (*result != '-') - && ((*result < '0') || (*result > '9'))) { - result++; - } - /* Check for a comment (prefixed with `#'). */ - if (*result == '#') { - *result = '\0'; - } - return result; -} - -#endif /* not TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* readnodes() Read the points from a file, which may be a .node or .poly */ -/* file. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -void readnodes(nodefilename, polyfilename, polyfile) -char *nodefilename; -char *polyfilename; -FILE **polyfile; -{ - FILE *infile; - point pointloop; - char inputline[INPUTLINESIZE]; - char *stringptr; - char *infilename; - REAL x, y; - int firstnode; - int nodemarkers; - int currentmarker; - int i, j; - - if (poly) { - /* Read the points from a .poly file. */ - if (!quiet) { - printf("Opening %s.\n", polyfilename); - } - *polyfile = fopen(polyfilename, "r"); - if (*polyfile == (FILE *) NULL) { - printf(" Error: Cannot access file %s.\n", polyfilename); - exit(1); - } - /* Read number of points, number of dimensions, number of point */ - /* attributes, and number of boundary markers. */ - stringptr = readline(inputline, *polyfile, polyfilename); - inpoints = (int) strtol (stringptr, &stringptr, 0); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - mesh_dim = 2; - } else { - mesh_dim = (int) strtol (stringptr, &stringptr, 0); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - nextras = 0; - } else { - nextras = (int) strtol (stringptr, &stringptr, 0); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - nodemarkers = 0; - } else { - nodemarkers = (int) strtol (stringptr, &stringptr, 0); - } - if (inpoints > 0) { - infile = *polyfile; - infilename = polyfilename; - readnodefile = 0; - } else { - /* If the .poly file claims there are zero points, that means that */ - /* the points should be read from a separate .node file. */ - readnodefile = 1; - infilename = innodefilename; - } - } else { - readnodefile = 1; - infilename = innodefilename; - *polyfile = (FILE *) NULL; - } - - if (readnodefile) { - /* Read the points from a .node file. */ - if (!quiet) { - printf("Opening %s.\n", innodefilename); - } - infile = fopen(innodefilename, "r"); - if (infile == (FILE *) NULL) { - printf(" Error: Cannot access file %s.\n", innodefilename); - exit(1); - } - /* Read number of points, number of dimensions, number of point */ - /* attributes, and number of boundary markers. */ - stringptr = readline(inputline, infile, innodefilename); - inpoints = (int) strtol (stringptr, &stringptr, 0); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - mesh_dim = 2; - } else { - mesh_dim = (int) strtol (stringptr, &stringptr, 0); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - nextras = 0; - } else { - nextras = (int) strtol (stringptr, &stringptr, 0); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - nodemarkers = 0; - } else { - nodemarkers = (int) strtol (stringptr, &stringptr, 0); - } - } - - if (inpoints < 3) { - printf("Error: Input must have at least three input points.\n"); - exit(1); - } - if (mesh_dim != 2) { - printf("Error: Triangle only works with two-dimensional meshes.\n"); - exit(1); - } - - initializepointpool(); - - /* Read the points. */ - for (i = 0; i < inpoints; i++) { - pointloop = (point) poolalloc(&points); - stringptr = readline(inputline, infile, infilename); - if (i == 0) { - firstnode = (int) strtol (stringptr, &stringptr, 0); - if ((firstnode == 0) || (firstnode == 1)) { - firstnumber = firstnode; - } - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Point %d has no x coordinate.\n", firstnumber + i); - exit(1); - } - x = (REAL) strtod(stringptr, &stringptr); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Point %d has no y coordinate.\n", firstnumber + i); - exit(1); - } - y = (REAL) strtod(stringptr, &stringptr); - pointloop[0] = x; - pointloop[1] = y; - /* Read the point attributes. */ - for (j = 2; j < 2 + nextras; j++) { - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - pointloop[j] = 0.0; - } else { - pointloop[j] = (REAL) strtod(stringptr, &stringptr); - } - } - if (nodemarkers) { - /* Read a point marker. */ - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - setpointmark(pointloop, 0); - } else { - currentmarker = (int) strtol (stringptr, &stringptr, 0); - setpointmark(pointloop, currentmarker); - } - } else { - /* If no markers are specified in the file, they default to zero. */ - setpointmark(pointloop, 0); - } - /* Determine the smallest and largest x and y coordinates. */ - if (i == 0) { - xmin = xmax = x; - ymin = ymax = y; - } else { - xmin = (x < xmin) ? x : xmin; - xmax = (x > xmax) ? x : xmax; - ymin = (y < ymin) ? y : ymin; - ymax = (y > ymax) ? y : ymax; - } - } - if (readnodefile) { - fclose(infile); - } - - /* Nonexistent x value used as a flag to mark circle events in sweepline */ - /* Delaunay algorithm. */ - xminextreme = 10 * xmin - 9 * xmax; -} - -#endif /* not TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* transfernodes() Read the points from memory. */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -void transfernodes(pointlist, pointattriblist, pointmarkerlist, numberofpoints, - numberofpointattribs) -REAL *pointlist; -REAL *pointattriblist; -int *pointmarkerlist; -int numberofpoints; -int numberofpointattribs; -{ - point pointloop; - REAL x, y; - int i, j; - int coordindex; - int attribindex; - - inpoints = numberofpoints; - mesh_dim = 2; - nextras = numberofpointattribs; - readnodefile = 0; - if (inpoints < 3) { - printf("Error: Input must have at least three input points.\n"); - exit(1); - } - - initializepointpool(); - - /* Read the points. */ - coordindex = 0; - attribindex = 0; - for (i = 0; i < inpoints; i++) { - pointloop = (point) poolalloc(&points); - /* Read the point coordinates. */ - x = pointloop[0] = pointlist[coordindex++]; - y = pointloop[1] = pointlist[coordindex++]; - /* Read the point attributes. */ - for (j = 0; j < numberofpointattribs; j++) { - pointloop[2 + j] = pointattriblist[attribindex++]; - } - if (pointmarkerlist != (int *) NULL) { - /* Read a point marker. */ - setpointmark(pointloop, pointmarkerlist[i]); - } else { - /* If no markers are specified, they default to zero. */ - setpointmark(pointloop, 0); - } - x = pointloop[0]; - y = pointloop[1]; - /* Determine the smallest and largest x and y coordinates. */ - if (i == 0) { - xmin = xmax = x; - ymin = ymax = y; - } else { - xmin = (x < xmin) ? x : xmin; - xmax = (x > xmax) ? x : xmax; - ymin = (y < ymin) ? y : ymin; - ymax = (y > ymax) ? y : ymax; - } - } - - /* Nonexistent x value used as a flag to mark circle events in sweepline */ - /* Delaunay algorithm. */ - xminextreme = 10 * xmin - 9 * xmax; -} - -#endif /* TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* readholes() Read the holes, and possibly regional attributes and area */ -/* constraints, from a .poly file. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -void readholes(polyfile, polyfilename, hlist, holes, rlist, regions) -FILE *polyfile; -char *polyfilename; -REAL **hlist; -int *holes; -REAL **rlist; -int *regions; -{ - REAL *holelist; - REAL *regionlist; - char inputline[INPUTLINESIZE]; - char *stringptr; - int index; - int i; - - /* Read the holes. */ - stringptr = readline(inputline, polyfile, polyfilename); - *holes = (int) strtol (stringptr, &stringptr, 0); - if (*holes > 0) { - holelist = (REAL *) malloc(2 * *holes * sizeof(REAL)); - *hlist = holelist; - if (holelist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - for (i = 0; i < 2 * *holes; i += 2) { - stringptr = readline(inputline, polyfile, polyfilename); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Hole %d has no x coordinate.\n", - firstnumber + (i >> 1)); - exit(1); - } else { - holelist[i] = (REAL) strtod(stringptr, &stringptr); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Hole %d has no y coordinate.\n", - firstnumber + (i >> 1)); - exit(1); - } else { - holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); - } - } - } else { - *hlist = (REAL *) NULL; - } - -#ifndef CDT_ONLY - if ((regionattrib || vararea) && !refine) { - /* Read the area constraints. */ - stringptr = readline(inputline, polyfile, polyfilename); - *regions = (int) strtol (stringptr, &stringptr, 0); - if (*regions > 0) { - regionlist = (REAL *) malloc(4 * *regions * sizeof(REAL)); - *rlist = regionlist; - if (regionlist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - index = 0; - for (i = 0; i < *regions; i++) { - stringptr = readline(inputline, polyfile, polyfilename); - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Region %d has no x coordinate.\n", - firstnumber + i); - exit(1); - } else { - regionlist[index++] = (REAL) strtod(stringptr, &stringptr); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf("Error: Region %d has no y coordinate.\n", - firstnumber + i); - exit(1); - } else { - regionlist[index++] = (REAL) strtod(stringptr, &stringptr); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - printf( - "Error: Region %d has no region attribute or area constraint.\n", - firstnumber + i); - exit(1); - } else { - regionlist[index++] = (REAL) strtod(stringptr, &stringptr); - } - stringptr = findfield(stringptr); - if (*stringptr == '\0') { - regionlist[index] = regionlist[index - 1]; - } else { - regionlist[index] = (REAL) strtod(stringptr, &stringptr); - } - index++; - } - } - } else { - /* Set `*regions' to zero to avoid an accidental free() later. */ - *regions = 0; - *rlist = (REAL *) NULL; - } -#endif /* not CDT_ONLY */ - - fclose(polyfile); -} - -#endif /* not TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* finishfile() Write the command line to the output file so the user */ -/* can remember how the file was generated. Close the file. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -void finishfile(outfile, argc, argv) -FILE *outfile; -int argc; -char **argv; -{ - int i; - - fprintf(outfile, "# Generated by"); - for (i = 0; i < argc; i++) { - fprintf(outfile, " "); - fputs(argv[i], outfile); - } - fprintf(outfile, "\n"); - fclose(outfile); -} - -#endif /* not TRILIBRARY */ - -/*****************************************************************************/ -/* */ -/* writenodes() Number the points and write them to a .node file. */ -/* */ -/* To save memory, the point numbers are written over the shell markers */ -/* after the points are written to a file. */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -void writenodes(pointlist, pointattriblist, pointmarkerlist) -REAL **pointlist; -REAL **pointattriblist; -int **pointmarkerlist; - -#else /* not TRILIBRARY */ - -void writenodes(nodefilename, argc, argv) -char *nodefilename; -int argc; -char **argv; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - REAL *plist; - REAL *palist; - int *pmlist; - int coordindex; - int attribindex; -#else /* not TRILIBRARY */ - FILE *outfile; -#endif /* not TRILIBRARY */ - point pointloop; - int pointnumber; - int i; - -#ifdef TRILIBRARY - if (!quiet) { - printf("Writing points.\n"); - } - /* Allocate memory for output points if necessary. */ - if (*pointlist == (REAL *) NULL) { - *pointlist = (REAL *) malloc(points.items * 2 * sizeof(REAL)); - if (*pointlist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - /* Allocate memory for output point attributes if necessary. */ - if ((nextras > 0) && (*pointattriblist == (REAL *) NULL)) { - *pointattriblist = (REAL *) malloc(points.items * nextras * sizeof(REAL)); - if (*pointattriblist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - /* Allocate memory for output point markers if necessary. */ - if (!nobound && (*pointmarkerlist == (int *) NULL)) { - *pointmarkerlist = (int *) malloc(points.items * sizeof(int)); - if (*pointmarkerlist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - plist = *pointlist; - palist = *pointattriblist; - pmlist = *pointmarkerlist; - coordindex = 0; - attribindex = 0; -#else /* not TRILIBRARY */ - if (!quiet) { - printf("Writing %s.\n", nodefilename); - } - outfile = fopen(nodefilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", nodefilename); - exit(1); - } - /* Number of points, number of dimensions, number of point attributes, */ - /* and number of boundary markers (zero or one). */ - fprintf(outfile, "%ld %d %d %d\n", points.items, mesh_dim, nextras, - 1 - nobound); -#endif /* not TRILIBRARY */ - - traversalinit(&points); - pointloop = pointtraverse(); - pointnumber = firstnumber; - while (pointloop != (point) NULL) { -#ifdef TRILIBRARY - /* X and y coordinates. */ - plist[coordindex++] = pointloop[0]; - plist[coordindex++] = pointloop[1]; - /* Point attributes. */ - for (i = 0; i < nextras; i++) { - palist[attribindex++] = pointloop[2 + i]; - } - if (!nobound) { - /* Copy the boundary marker. */ - pmlist[pointnumber - firstnumber] = pointmark(pointloop); - } -#else /* not TRILIBRARY */ - /* Point number, x and y coordinates. */ - fprintf(outfile, "%4d %.17g %.17g", pointnumber, pointloop[0], - pointloop[1]); - for (i = 0; i < nextras; i++) { - /* Write an attribute. */ - fprintf(outfile, " %.17g", pointloop[i + 2]); - } - if (nobound) { - fprintf(outfile, "\n"); - } else { - /* Write the boundary marker. */ - fprintf(outfile, " %d\n", pointmark(pointloop)); - } -#endif /* not TRILIBRARY */ - - setpointmark(pointloop, pointnumber); - pointloop = pointtraverse(); - pointnumber++; - } - -#ifndef TRILIBRARY - finishfile(outfile, argc, argv); -#endif /* not TRILIBRARY */ -} - -/*****************************************************************************/ -/* */ -/* numbernodes() Number the points. */ -/* */ -/* Each point is assigned a marker equal to its number. */ -/* */ -/* Used when writenodes() is not called because no .node file is written. */ -/* */ -/*****************************************************************************/ - -void numbernodes() -{ - point pointloop; - int pointnumber; - - traversalinit(&points); - pointloop = pointtraverse(); - pointnumber = firstnumber; - while (pointloop != (point) NULL) { - setpointmark(pointloop, pointnumber); - pointloop = pointtraverse(); - pointnumber++; - } -} - -/*****************************************************************************/ -/* */ -/* writeelements() Write the triangles to an .ele file. */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -void writeelements(trianglelist, triangleattriblist) -int **trianglelist; -REAL **triangleattriblist; - -#else /* not TRILIBRARY */ - -void writeelements(elefilename, argc, argv) -char *elefilename; -int argc; -char **argv; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - int *tlist; - REAL *talist; - int pointindex; - int attribindex; -#else /* not TRILIBRARY */ - FILE *outfile; -#endif /* not TRILIBRARY */ - struct triedge triangleloop; - point p1, p2, p3; - point mid1, mid2, mid3; - int elementnumber; - int i; - -#ifdef TRILIBRARY - if (!quiet) { - printf("Writing triangles.\n"); - } - /* Allocate memory for output triangles if necessary. */ - if (*trianglelist == (int *) NULL) { - *trianglelist = (int *) malloc(triangles.items * - ((order + 1) * (order + 2) / 2) * sizeof(int)); - if (*trianglelist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - /* Allocate memory for output triangle attributes if necessary. */ - if ((eextras > 0) && (*triangleattriblist == (REAL *) NULL)) { - *triangleattriblist = (REAL *) malloc(triangles.items * eextras * - sizeof(REAL)); - if (*triangleattriblist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - tlist = *trianglelist; - talist = *triangleattriblist; - pointindex = 0; - attribindex = 0; -#else /* not TRILIBRARY */ - if (!quiet) { - printf("Writing %s.\n", elefilename); - } - outfile = fopen(elefilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", elefilename); - exit(1); - } - /* Number of triangles, points per triangle, attributes per triangle. */ - fprintf(outfile, "%ld %d %d\n", triangles.items, - (order + 1) * (order + 2) / 2, eextras); -#endif /* not TRILIBRARY */ - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - triangleloop.orient = 0; - elementnumber = firstnumber; - while (triangleloop.tri != (triangle *) NULL) { - org(triangleloop, p1); - dest(triangleloop, p2); - apex(triangleloop, p3); - if (order == 1) { -#ifdef TRILIBRARY - tlist[pointindex++] = pointmark(p1); - tlist[pointindex++] = pointmark(p2); - tlist[pointindex++] = pointmark(p3); -#else /* not TRILIBRARY */ - /* Triangle number, indices for three points. */ - fprintf(outfile, "%4d %4d %4d %4d", elementnumber, - pointmark(p1), pointmark(p2), pointmark(p3)); -#endif /* not TRILIBRARY */ - } else { - mid1 = (point) triangleloop.tri[highorderindex + 1]; - mid2 = (point) triangleloop.tri[highorderindex + 2]; - mid3 = (point) triangleloop.tri[highorderindex]; -#ifdef TRILIBRARY - tlist[pointindex++] = pointmark(p1); - tlist[pointindex++] = pointmark(p2); - tlist[pointindex++] = pointmark(p3); - tlist[pointindex++] = pointmark(mid1); - tlist[pointindex++] = pointmark(mid2); - tlist[pointindex++] = pointmark(mid3); -#else /* not TRILIBRARY */ - /* Triangle number, indices for six points. */ - fprintf(outfile, "%4d %4d %4d %4d %4d %4d %4d", elementnumber, - pointmark(p1), pointmark(p2), pointmark(p3), pointmark(mid1), - pointmark(mid2), pointmark(mid3)); -#endif /* not TRILIBRARY */ - } - -#ifdef TRILIBRARY - for (i = 0; i < eextras; i++) { - talist[attribindex++] = elemattribute(triangleloop, i); - } -#else /* not TRILIBRARY */ - for (i = 0; i < eextras; i++) { - fprintf(outfile, " %.17g", elemattribute(triangleloop, i)); - } - fprintf(outfile, "\n"); -#endif /* not TRILIBRARY */ - - triangleloop.tri = triangletraverse(); - elementnumber++; - } - -#ifndef TRILIBRARY - finishfile(outfile, argc, argv); -#endif /* not TRILIBRARY */ -} - -/*****************************************************************************/ -/* */ -/* writepoly() Write the segments and holes to a .poly file. */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -void writepoly(segmentlist, segmentmarkerlist) -int **segmentlist; -int **segmentmarkerlist; - -#else /* not TRILIBRARY */ - -void writepoly(polyfilename, holelist, holes, regionlist, regions, argc, argv) -char *polyfilename; -REAL *holelist; -int holes; -REAL *regionlist; -int regions; -int argc; -char **argv; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - int *slist; - int *smlist; - int index; -#else /* not TRILIBRARY */ - FILE *outfile; - int i; -#endif /* not TRILIBRARY */ - struct edge shelleloop; - point endpoint1, endpoint2; - int shellenumber; - -#ifdef TRILIBRARY - if (!quiet) { - printf("Writing segments.\n"); - } - /* Allocate memory for output segments if necessary. */ - if (*segmentlist == (int *) NULL) { - *segmentlist = (int *) malloc(shelles.items * 2 * sizeof(int)); - if (*segmentlist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - /* Allocate memory for output segment markers if necessary. */ - if (!nobound && (*segmentmarkerlist == (int *) NULL)) { - *segmentmarkerlist = (int *) malloc(shelles.items * sizeof(int)); - if (*segmentmarkerlist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - slist = *segmentlist; - smlist = *segmentmarkerlist; - index = 0; -#else /* not TRILIBRARY */ - if (!quiet) { - printf("Writing %s.\n", polyfilename); - } - outfile = fopen(polyfilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", polyfilename); - exit(1); - } - /* The zero indicates that the points are in a separate .node file. */ - /* Followed by number of dimensions, number of point attributes, */ - /* and number of boundary markers (zero or one). */ - fprintf(outfile, "%d %d %d %d\n", 0, mesh_dim, nextras, 1 - nobound); - /* Number of segments, number of boundary markers (zero or one). */ - fprintf(outfile, "%ld %d\n", shelles.items, 1 - nobound); -#endif /* not TRILIBRARY */ - - traversalinit(&shelles); - shelleloop.sh = shelletraverse(); - shelleloop.shorient = 0; - shellenumber = firstnumber; - while (shelleloop.sh != (shelle *) NULL) { - sorg(shelleloop, endpoint1); - sdest(shelleloop, endpoint2); -#ifdef TRILIBRARY - /* Copy indices of the segment's two endpoints. */ - slist[index++] = pointmark(endpoint1); - slist[index++] = pointmark(endpoint2); - if (!nobound) { - /* Copy the boundary marker. */ - smlist[shellenumber - firstnumber] = mark(shelleloop); - } -#else /* not TRILIBRARY */ - /* Segment number, indices of its two endpoints, and possibly a marker. */ - if (nobound) { - fprintf(outfile, "%4d %4d %4d\n", shellenumber, - pointmark(endpoint1), pointmark(endpoint2)); - } else { - fprintf(outfile, "%4d %4d %4d %4d\n", shellenumber, - pointmark(endpoint1), pointmark(endpoint2), mark(shelleloop)); - } -#endif /* not TRILIBRARY */ - - shelleloop.sh = shelletraverse(); - shellenumber++; - } - -#ifndef TRILIBRARY -#ifndef CDT_ONLY - fprintf(outfile, "%d\n", holes); - if (holes > 0) { - for (i = 0; i < holes; i++) { - /* Hole number, x and y coordinates. */ - fprintf(outfile, "%4d %.17g %.17g\n", firstnumber + i, - holelist[2 * i], holelist[2 * i + 1]); - } - } - if (regions > 0) { - fprintf(outfile, "%d\n", regions); - for (i = 0; i < regions; i++) { - /* Region number, x and y coordinates, attribute, maximum area. */ - fprintf(outfile, "%4d %.17g %.17g %.17g %.17g\n", firstnumber + i, - regionlist[4 * i], regionlist[4 * i + 1], - regionlist[4 * i + 2], regionlist[4 * i + 3]); - } - } -#endif /* not CDT_ONLY */ - - finishfile(outfile, argc, argv); -#endif /* not TRILIBRARY */ -} - -/*****************************************************************************/ -/* */ -/* writeedges() Write the edges to a .edge file. */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -void writeedges(edgelist, edgemarkerlist) -int **edgelist; -int **edgemarkerlist; - -#else /* not TRILIBRARY */ - -void writeedges(edgefilename, argc, argv) -char *edgefilename; -int argc; -char **argv; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - int *elist; - int *emlist; - int index; -#else /* not TRILIBRARY */ - FILE *outfile; -#endif /* not TRILIBRARY */ - struct triedge triangleloop, trisym; - struct edge checkmark; - point p1, p2; - int edgenumber; - triangle ptr; /* Temporary variable used by sym(). */ - shelle sptr; /* Temporary variable used by tspivot(). */ - -#ifdef TRILIBRARY - if (!quiet) { - printf("Writing edges.\n"); - } - /* Allocate memory for edges if necessary. */ - if (*edgelist == (int *) NULL) { - *edgelist = (int *) malloc(edges * 2 * sizeof(int)); - if (*edgelist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - /* Allocate memory for edge markers if necessary. */ - if (!nobound && (*edgemarkerlist == (int *) NULL)) { - *edgemarkerlist = (int *) malloc(edges * sizeof(int)); - if (*edgemarkerlist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - elist = *edgelist; - emlist = *edgemarkerlist; - index = 0; -#else /* not TRILIBRARY */ - if (!quiet) { - printf("Writing %s.\n", edgefilename); - } - outfile = fopen(edgefilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", edgefilename); - exit(1); - } - /* Number of edges, number of boundary markers (zero or one). */ - fprintf(outfile, "%ld %d\n", edges, 1 - nobound); -#endif /* not TRILIBRARY */ - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - edgenumber = firstnumber; - /* To loop over the set of edges, loop over all triangles, and look at */ - /* the three edges of each triangle. If there isn't another triangle */ - /* adjacent to the edge, operate on the edge. If there is another */ - /* adjacent triangle, operate on the edge only if the current triangle */ - /* has a smaller pointer than its neighbor. This way, each edge is */ - /* considered only once. */ - while (triangleloop.tri != (triangle *) NULL) { - for (triangleloop.orient = 0; triangleloop.orient < 3; - triangleloop.orient++) { - sym(triangleloop, trisym); - if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { - org(triangleloop, p1); - dest(triangleloop, p2); -#ifdef TRILIBRARY - elist[index++] = pointmark(p1); - elist[index++] = pointmark(p2); -#endif /* TRILIBRARY */ - if (nobound) { -#ifndef TRILIBRARY - /* Edge number, indices of two endpoints. */ - fprintf(outfile, "%4d %d %d\n", edgenumber, - pointmark(p1), pointmark(p2)); -#endif /* not TRILIBRARY */ - } else { - /* Edge number, indices of two endpoints, and a boundary marker. */ - /* If there's no shell edge, the boundary marker is zero. */ - if (useshelles) { - tspivot(triangleloop, checkmark); - if (checkmark.sh == dummysh) { -#ifdef TRILIBRARY - emlist[edgenumber - firstnumber] = 0; -#else /* not TRILIBRARY */ - fprintf(outfile, "%4d %d %d %d\n", edgenumber, - pointmark(p1), pointmark(p2), 0); -#endif /* not TRILIBRARY */ - } else { -#ifdef TRILIBRARY - emlist[edgenumber - firstnumber] = mark(checkmark); -#else /* not TRILIBRARY */ - fprintf(outfile, "%4d %d %d %d\n", edgenumber, - pointmark(p1), pointmark(p2), mark(checkmark)); -#endif /* not TRILIBRARY */ - } - } else { -#ifdef TRILIBRARY - emlist[edgenumber - firstnumber] = trisym.tri == dummytri; -#else /* not TRILIBRARY */ - fprintf(outfile, "%4d %d %d %d\n", edgenumber, - pointmark(p1), pointmark(p2), trisym.tri == dummytri); -#endif /* not TRILIBRARY */ - } - } - edgenumber++; - } - } - triangleloop.tri = triangletraverse(); - } - -#ifndef TRILIBRARY - finishfile(outfile, argc, argv); -#endif /* not TRILIBRARY */ -} - -/*****************************************************************************/ -/* */ -/* writevoronoi() Write the Voronoi diagram to a .v.node and .v.edge */ -/* file. */ -/* */ -/* The Voronoi diagram is the geometric dual of the Delaunay triangulation. */ -/* Hence, the Voronoi vertices are listed by traversing the Delaunay */ -/* triangles, and the Voronoi edges are listed by traversing the Delaunay */ -/* edges. */ -/* */ -/* WARNING: In order to assign numbers to the Voronoi vertices, this */ -/* procedure messes up the shell edges or the extra nodes of every */ -/* element. Hence, you should call this procedure last. */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -void writevoronoi(vpointlist, vpointattriblist, vpointmarkerlist, vedgelist, - vedgemarkerlist, vnormlist) -REAL **vpointlist; -REAL **vpointattriblist; -int **vpointmarkerlist; -int **vedgelist; -int **vedgemarkerlist; -REAL **vnormlist; - -#else /* not TRILIBRARY */ - -void writevoronoi(vnodefilename, vedgefilename, argc, argv) -char *vnodefilename; -char *vedgefilename; -int argc; -char **argv; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - REAL *plist; - REAL *palist; - int *elist; - REAL *normlist; - int coordindex; - int attribindex; -#else /* not TRILIBRARY */ - FILE *outfile; -#endif /* not TRILIBRARY */ - struct triedge triangleloop, trisym; - point torg, tdest, tapex; - REAL circumcenter[2]; - REAL xi, eta; - int vnodenumber, vedgenumber; - int p1, p2; - int i; - triangle ptr; /* Temporary variable used by sym(). */ - -#ifdef TRILIBRARY - if (!quiet) { - printf("Writing Voronoi vertices.\n"); - } - /* Allocate memory for Voronoi vertices if necessary. */ - if (*vpointlist == (REAL *) NULL) { - *vpointlist = (REAL *) malloc(triangles.items * 2 * sizeof(REAL)); - if (*vpointlist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - /* Allocate memory for Voronoi vertex attributes if necessary. */ - if (*vpointattriblist == (REAL *) NULL) { - *vpointattriblist = (REAL *) malloc(triangles.items * nextras * - sizeof(REAL)); - if (*vpointattriblist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - *vpointmarkerlist = (int *) NULL; - plist = *vpointlist; - palist = *vpointattriblist; - coordindex = 0; - attribindex = 0; -#else /* not TRILIBRARY */ - if (!quiet) { - printf("Writing %s.\n", vnodefilename); - } - outfile = fopen(vnodefilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", vnodefilename); - exit(1); - } - /* Number of triangles, two dimensions, number of point attributes, */ - /* zero markers. */ - fprintf(outfile, "%ld %d %d %d\n", triangles.items, 2, nextras, 0); -#endif /* not TRILIBRARY */ - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - triangleloop.orient = 0; - vnodenumber = firstnumber; - while (triangleloop.tri != (triangle *) NULL) { - org(triangleloop, torg); - dest(triangleloop, tdest); - apex(triangleloop, tapex); - findcircumcenter(torg, tdest, tapex, circumcenter, &xi, &eta); -#ifdef TRILIBRARY - /* X and y coordinates. */ - plist[coordindex++] = circumcenter[0]; - plist[coordindex++] = circumcenter[1]; - for (i = 2; i < 2 + nextras; i++) { - /* Interpolate the point attributes at the circumcenter. */ - palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i]) - + eta * (tapex[i] - torg[i]); - } -#else /* not TRILIBRARY */ - /* Voronoi vertex number, x and y coordinates. */ - fprintf(outfile, "%4d %.17g %.17g", vnodenumber, circumcenter[0], - circumcenter[1]); - for (i = 2; i < 2 + nextras; i++) { - /* Interpolate the point attributes at the circumcenter. */ - fprintf(outfile, " %.17g", torg[i] + xi * (tdest[i] - torg[i]) - + eta * (tapex[i] - torg[i])); - } - fprintf(outfile, "\n"); -#endif /* not TRILIBRARY */ - - * (int *) (triangleloop.tri + 6) = vnodenumber; - triangleloop.tri = triangletraverse(); - vnodenumber++; - } - -#ifndef TRILIBRARY - finishfile(outfile, argc, argv); -#endif /* not TRILIBRARY */ - -#ifdef TRILIBRARY - if (!quiet) { - printf("Writing Voronoi edges.\n"); - } - /* Allocate memory for output Voronoi edges if necessary. */ - if (*vedgelist == (int *) NULL) { - *vedgelist = (int *) malloc(edges * 2 * sizeof(int)); - if (*vedgelist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - *vedgemarkerlist = (int *) NULL; - /* Allocate memory for output Voronoi norms if necessary. */ - if (*vnormlist == (REAL *) NULL) { - *vnormlist = (REAL *) malloc(edges * 2 * sizeof(REAL)); - if (*vnormlist == (REAL *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - elist = *vedgelist; - normlist = *vnormlist; - coordindex = 0; -#else /* not TRILIBRARY */ - if (!quiet) { - printf("Writing %s.\n", vedgefilename); - } - outfile = fopen(vedgefilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", vedgefilename); - exit(1); - } - /* Number of edges, zero boundary markers. */ - fprintf(outfile, "%ld %d\n", edges, 0); -#endif /* not TRILIBRARY */ - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - vedgenumber = firstnumber; - /* To loop over the set of edges, loop over all triangles, and look at */ - /* the three edges of each triangle. If there isn't another triangle */ - /* adjacent to the edge, operate on the edge. If there is another */ - /* adjacent triangle, operate on the edge only if the current triangle */ - /* has a smaller pointer than its neighbor. This way, each edge is */ - /* considered only once. */ - while (triangleloop.tri != (triangle *) NULL) { - for (triangleloop.orient = 0; triangleloop.orient < 3; - triangleloop.orient++) { - sym(triangleloop, trisym); - if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { - /* Find the number of this triangle (and Voronoi vertex). */ - p1 = * (int *) (triangleloop.tri + 6); - if (trisym.tri == dummytri) { - org(triangleloop, torg); - dest(triangleloop, tdest); -#ifdef TRILIBRARY - /* Copy an infinite ray. Index of one endpoint, and -1. */ - elist[coordindex] = p1; - normlist[coordindex++] = tdest[1] - torg[1]; - elist[coordindex] = -1; - normlist[coordindex++] = torg[0] - tdest[0]; -#else /* not TRILIBRARY */ - /* Write an infinite ray. Edge number, index of one endpoint, -1, */ - /* and x and y coordinates of a vector representing the */ - /* direction of the ray. */ - fprintf(outfile, "%4d %d %d %.17g %.17g\n", vedgenumber, - p1, -1, tdest[1] - torg[1], torg[0] - tdest[0]); -#endif /* not TRILIBRARY */ - } else { - /* Find the number of the adjacent triangle (and Voronoi vertex). */ - p2 = * (int *) (trisym.tri + 6); - /* Finite edge. Write indices of two endpoints. */ -#ifdef TRILIBRARY - elist[coordindex] = p1; - normlist[coordindex++] = 0.0; - elist[coordindex] = p2; - normlist[coordindex++] = 0.0; -#else /* not TRILIBRARY */ - fprintf(outfile, "%4d %d %d\n", vedgenumber, p1, p2); -#endif /* not TRILIBRARY */ - } - vedgenumber++; - } - } - triangleloop.tri = triangletraverse(); - } - -#ifndef TRILIBRARY - finishfile(outfile, argc, argv); -#endif /* not TRILIBRARY */ -} - -#ifdef TRILIBRARY - -void writeneighbors(neighborlist) -int **neighborlist; - -#else /* not TRILIBRARY */ - -void writeneighbors(neighborfilename, argc, argv) -char *neighborfilename; -int argc; -char **argv; - -#endif /* not TRILIBRARY */ - -{ -#ifdef TRILIBRARY - int *nlist; - int index; -#else /* not TRILIBRARY */ - FILE *outfile; -#endif /* not TRILIBRARY */ - struct triedge triangleloop, trisym; - int elementnumber; - int neighbor1, neighbor2, neighbor3; - triangle ptr; /* Temporary variable used by sym(). */ - -#ifdef TRILIBRARY - if (!quiet) { - printf("Writing neighbors.\n"); - } - /* Allocate memory for neighbors if necessary. */ - if (*neighborlist == (int *) NULL) { - *neighborlist = (int *) malloc(triangles.items * 3 * sizeof(int)); - if (*neighborlist == (int *) NULL) { - printf("Error: Out of memory.\n"); - exit(1); - } - } - nlist = *neighborlist; - index = 0; -#else /* not TRILIBRARY */ - if (!quiet) { - printf("Writing %s.\n", neighborfilename); - } - outfile = fopen(neighborfilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", neighborfilename); - exit(1); - } - /* Number of triangles, three edges per triangle. */ - fprintf(outfile, "%ld %d\n", triangles.items, 3); -#endif /* not TRILIBRARY */ - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - triangleloop.orient = 0; - elementnumber = firstnumber; - while (triangleloop.tri != (triangle *) NULL) { - * (int *) (triangleloop.tri + 6) = elementnumber; - triangleloop.tri = triangletraverse(); - elementnumber++; - } - * (int *) (dummytri + 6) = -1; - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - elementnumber = firstnumber; - while (triangleloop.tri != (triangle *) NULL) { - triangleloop.orient = 1; - sym(triangleloop, trisym); - neighbor1 = * (int *) (trisym.tri + 6); - triangleloop.orient = 2; - sym(triangleloop, trisym); - neighbor2 = * (int *) (trisym.tri + 6); - triangleloop.orient = 0; - sym(triangleloop, trisym); - neighbor3 = * (int *) (trisym.tri + 6); -#ifdef TRILIBRARY - nlist[index++] = neighbor1; - nlist[index++] = neighbor2; - nlist[index++] = neighbor3; -#else /* not TRILIBRARY */ - /* Triangle number, neighboring triangle numbers. */ - fprintf(outfile, "%4d %d %d %d\n", elementnumber, - neighbor1, neighbor2, neighbor3); -#endif /* not TRILIBRARY */ - - triangleloop.tri = triangletraverse(); - elementnumber++; - } - -#ifndef TRILIBRARY - finishfile(outfile, argc, argv); -#endif /* TRILIBRARY */ -} - -/*****************************************************************************/ -/* */ -/* writeoff() Write the triangulation to an .off file. */ -/* */ -/* OFF stands for the Object File Format, a format used by the Geometry */ -/* Center's Geomview package. */ -/* */ -/*****************************************************************************/ - -#ifndef TRILIBRARY - -void writeoff(offfilename, argc, argv) -char *offfilename; -int argc; -char **argv; -{ - FILE *outfile; - struct triedge triangleloop; - point pointloop; - point p1, p2, p3; - - if (!quiet) { - printf("Writing %s.\n", offfilename); - } - outfile = fopen(offfilename, "w"); - if (outfile == (FILE *) NULL) { - printf(" Error: Cannot create file %s.\n", offfilename); - exit(1); - } - /* Number of points, triangles, and edges. */ - fprintf(outfile, "OFF\n%ld %ld %ld\n", points.items, triangles.items, - edges); - - /* Write the points. */ - traversalinit(&points); - pointloop = pointtraverse(); - while (pointloop != (point) NULL) { - /* The "0.0" is here because the OFF format uses 3D coordinates. */ - fprintf(outfile, " %.17g %.17g %.17g\n", pointloop[0], - pointloop[1], 0.0); - pointloop = pointtraverse(); - } - - /* Write the triangles. */ - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - triangleloop.orient = 0; - while (triangleloop.tri != (triangle *) NULL) { - org(triangleloop, p1); - dest(triangleloop, p2); - apex(triangleloop, p3); - /* The "3" means a three-vertex polygon. */ - fprintf(outfile, " 3 %4d %4d %4d\n", pointmark(p1) - 1, - pointmark(p2) - 1, pointmark(p3) - 1); - triangleloop.tri = triangletraverse(); - } - finishfile(outfile, argc, argv); -} - -#endif /* not TRILIBRARY */ - -/** **/ -/** **/ -/********* File I/O routines end here *********/ - -/*****************************************************************************/ -/* */ -/* quality_statistics() Print statistics about the quality of the mesh. */ -/* */ -/*****************************************************************************/ - -void quality_statistics() -{ - struct triedge triangleloop; - point p[3]; - REAL cossquaretable[8]; - REAL ratiotable[16]; - REAL dx[3], dy[3]; - REAL edgelength[3]; - REAL dotproduct; - REAL cossquare; - REAL triarea; - REAL shortest, longest; - REAL trilongest2; - REAL smallestarea, biggestarea; - REAL triminaltitude2; - REAL minaltitude; - REAL triaspect2; - REAL worstaspect; - REAL smallestangle, biggestangle; - REAL radconst, degconst; - int angletable[18]; - int aspecttable[16]; - int aspectindex; - int tendegree; - int acutebiggest; - int i, ii, j, k; - - printf("Mesh quality statistics:\n\n"); - radconst = (REAL)(PI / 18.0); - degconst = (REAL)(180.0 / PI); - for (i = 0; i < 8; i++) { - cossquaretable[i] = (REAL)(cos(radconst * (REAL) (i + 1))); - cossquaretable[i] = cossquaretable[i] * cossquaretable[i]; - } - for (i = 0; i < 18; i++) { - angletable[i] = 0; - } - - ratiotable[0] = 1.5; ratiotable[1] = 2.0; - ratiotable[2] = 2.5; ratiotable[3] = 3.0; - ratiotable[4] = 4.0; ratiotable[5] = 6.0; - ratiotable[6] = 10.0; ratiotable[7] = 15.0; - ratiotable[8] = 25.0; ratiotable[9] = 50.0; - ratiotable[10] = 100.0; ratiotable[11] = 300.0; - ratiotable[12] = 1000.0; ratiotable[13] = 10000.0; - ratiotable[14] = 100000.0; ratiotable[15] = 0.0; - for (i = 0; i < 16; i++) { - aspecttable[i] = 0; - } - - worstaspect = 0.0; - minaltitude = xmax - xmin + ymax - ymin; - minaltitude = minaltitude * minaltitude; - shortest = minaltitude; - longest = 0.0; - smallestarea = minaltitude; - biggestarea = 0.0; - worstaspect = 0.0; - smallestangle = 0.0; - biggestangle = 2.0; - acutebiggest = 1; - - traversalinit(&triangles); - triangleloop.tri = triangletraverse(); - triangleloop.orient = 0; - while (triangleloop.tri != (triangle *) NULL) { - org(triangleloop, p[0]); - dest(triangleloop, p[1]); - apex(triangleloop, p[2]); - trilongest2 = 0.0; - - for (i = 0; i < 3; i++) { - j = plus1mod3[i]; - k = minus1mod3[i]; - dx[i] = p[j][0] - p[k][0]; - dy[i] = p[j][1] - p[k][1]; - edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; - if (edgelength[i] > trilongest2) { - trilongest2 = edgelength[i]; - } - if (edgelength[i] > longest) { - longest = edgelength[i]; - } - if (edgelength[i] < shortest) { - shortest = edgelength[i]; - } - } - - triarea = counterclockwise(p[0], p[1], p[2]); - if (triarea < smallestarea) { - smallestarea = triarea; - } - if (triarea > biggestarea) { - biggestarea = triarea; - } - triminaltitude2 = triarea * triarea / trilongest2; - if (triminaltitude2 < minaltitude) { - minaltitude = triminaltitude2; - } - triaspect2 = trilongest2 / triminaltitude2; - if (triaspect2 > worstaspect) { - worstaspect = triaspect2; - } - aspectindex = 0; - while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) - && (aspectindex < 15)) { - aspectindex++; - } - aspecttable[aspectindex]++; - - for (i = 0; i < 3; i++) { - j = plus1mod3[i]; - k = minus1mod3[i]; - dotproduct = dx[j] * dx[k] + dy[j] * dy[k]; - cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]); - tendegree = 8; - for (ii = 7; ii >= 0; ii--) { - if (cossquare > cossquaretable[ii]) { - tendegree = ii; - } - } - if (dotproduct <= 0.0) { - angletable[tendegree]++; - if (cossquare > smallestangle) { - smallestangle = cossquare; - } - if (acutebiggest && (cossquare < biggestangle)) { - biggestangle = cossquare; - } - } else { - angletable[17 - tendegree]++; - if (acutebiggest || (cossquare > biggestangle)) { - biggestangle = cossquare; - acutebiggest = 0; - } - } - } - triangleloop.tri = triangletraverse(); - } - - shortest = (REAL)sqrt(shortest); - longest = (REAL)sqrt(longest); - minaltitude = (REAL)sqrt(minaltitude); - worstaspect = (REAL)sqrt(worstaspect); - smallestarea *= 2.0; - biggestarea *= 2.0; - if (smallestangle >= 1.0) { - smallestangle = 0.0; - } else { - smallestangle = (REAL)(degconst * acos(sqrt(smallestangle))); - } - if (biggestangle >= 1.0) { - biggestangle = 180.0; - } else { - if (acutebiggest) { - biggestangle = (REAL)(degconst * acos(sqrt(biggestangle))); - } else { - biggestangle = (REAL)(180.0 - degconst * acos(sqrt(biggestangle))); - } - } - - printf(" Smallest area: %16.5g | Largest area: %16.5g\n", - smallestarea, biggestarea); - printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", - shortest, longest); - printf(" Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", - minaltitude, worstaspect); - printf(" Aspect ratio histogram:\n"); - printf(" 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", - ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], - aspecttable[8]); - for (i = 1; i < 7; i++) { - printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", - ratiotable[i - 1], ratiotable[i], aspecttable[i], - ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]); - } - printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", - ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], - aspecttable[15]); - printf( -" (Triangle aspect ratio is longest edge divided by shortest altitude)\n\n"); - printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", - smallestangle, biggestangle); - printf(" Angle histogram:\n"); - for (i = 0; i < 9; i++) { - printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", - i * 10, i * 10 + 10, angletable[i], - i * 10 + 90, i * 10 + 100, angletable[i + 9]); - } - printf("\n"); -} - -/*****************************************************************************/ -/* */ -/* statistics() Print all sorts of cool facts. */ -/* */ -/*****************************************************************************/ - -void statistics() -{ - printf("\nStatistics:\n\n"); - printf(" Input points: %d\n", inpoints); - if (refine) { - printf(" Input triangles: %d\n", inelements); - } - if (poly) { - printf(" Input segments: %d\n", insegments); - if (!refine) { - printf(" Input holes: %d\n", holes); - } - } - - printf("\n Mesh points: %ld\n", points.items); - printf(" Mesh triangles: %ld\n", triangles.items); - printf(" Mesh edges: %ld\n", edges); - if (poly || refine) { - printf(" Mesh boundary edges: %ld\n", hullsize); - printf(" Mesh segments: %ld\n\n", shelles.items); - } else { - printf(" Mesh convex hull edges: %ld\n\n", hullsize); - } - if (verbose) { - quality_statistics(); - printf("Memory allocation statistics:\n\n"); - printf(" Maximum number of points: %ld\n", points.maxitems); - printf(" Maximum number of triangles: %ld\n", triangles.maxitems); - if (shelles.maxitems > 0) { - printf(" Maximum number of segments: %ld\n", shelles.maxitems); - } - if (viri.maxitems > 0) { - printf(" Maximum number of viri: %ld\n", viri.maxitems); - } - if (badsegments.maxitems > 0) { - printf(" Maximum number of encroached segments: %ld\n", - badsegments.maxitems); - } - if (badtriangles.maxitems > 0) { - printf(" Maximum number of bad triangles: %ld\n", - badtriangles.maxitems); - } - if (splaynodes.maxitems > 0) { - printf(" Maximum number of splay tree nodes: %ld\n", - splaynodes.maxitems); - } - printf(" Approximate heap memory use (bytes): %ld\n\n", - points.maxitems * points.itembytes - + triangles.maxitems * triangles.itembytes - + shelles.maxitems * shelles.itembytes - + viri.maxitems * viri.itembytes - + badsegments.maxitems * badsegments.itembytes - + badtriangles.maxitems * badtriangles.itembytes - + splaynodes.maxitems * splaynodes.itembytes); - - printf("Algorithmic statistics:\n\n"); - printf(" Number of incircle tests: %ld\n", incirclecount); - printf(" Number of orientation tests: %ld\n", counterclockcount); - if (hyperbolacount > 0) { - printf(" Number of right-of-hyperbola tests: %ld\n", - hyperbolacount); - } - if (circumcentercount > 0) { - printf(" Number of circumcenter computations: %ld\n", - circumcentercount); - } - if (circletopcount > 0) { - printf(" Number of circle top computations: %ld\n", - circletopcount); - } - printf("\n"); - } -} - -/*****************************************************************************/ -/* */ -/* main() or triangulate() Gosh, do everything. */ -/* */ -/* The sequence is roughly as follows. Many of these steps can be skipped, */ -/* depending on the command line switches. */ -/* */ -/* - Initialize constants and parse the command line. */ -/* - Read the points from a file and either */ -/* - triangulate them (no -r), or */ -/* - read an old mesh from files and reconstruct it (-r). */ -/* - Insert the PSLG segments (-p), and possibly segments on the convex */ -/* hull (-c). */ -/* - Read the holes (-p), regional attributes (-pA), and regional area */ -/* constraints (-pa). Carve the holes and concavities, and spread the */ -/* regional attributes and area constraints. */ -/* - Enforce the constraints on minimum angle (-q) and maximum area (-a). */ -/* Also enforce the conforming Delaunay property (-q and -a). */ -/* - Compute the number of edges in the resulting mesh. */ -/* - Promote the mesh's linear triangles to higher order elements (-o). */ -/* - Write the output files and print the statistics. */ -/* - Check the consistency and Delaunay property of the mesh (-C). */ -/* */ -/*****************************************************************************/ - -#ifdef TRILIBRARY - -void triangulate(triswitches, in, out, vorout) -char *triswitches; -struct triangulateio *in; -struct triangulateio *out; -struct triangulateio *vorout; - -#else /* not TRILIBRARY */ - -int main(argc, argv) -int argc; -char **argv; - -#endif /* not TRILIBRARY */ - -{ - REAL *holearray; /* Array of holes. */ - REAL *regionarray; /* Array of regional attributes and area constraints. */ -#ifndef TRILIBRARY - FILE *polyfile; -#endif /* not TRILIBRARY */ -#ifndef NO_TIMER - /* Variables for timing the performance of Triangle. The types are */ - /* defined in sys/time.h. */ - struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6; - struct timezone tz; -#endif /* NO_TIMER */ - -#ifndef NO_TIMER - gettimeofday(&tv0, &tz); -#endif /* NO_TIMER */ - - triangleinit(); -#ifdef TRILIBRARY - parsecommandline(1, &triswitches); -#else /* not TRILIBRARY */ - parsecommandline(argc, argv); -#endif /* not TRILIBRARY */ - -#ifdef TRILIBRARY - transfernodes(in->pointlist, in->pointattributelist, in->pointmarkerlist, - in->numberofpoints, in->numberofpointattributes); -#else /* not TRILIBRARY */ - readnodes(innodefilename, inpolyfilename, &polyfile); -#endif /* not TRILIBRARY */ - -#ifndef NO_TIMER - if (!quiet) { - gettimeofday(&tv1, &tz); - } -#endif /* NO_TIMER */ - -#ifdef CDT_ONLY - hullsize = delaunay(); /* Triangulate the points. */ -#else /* not CDT_ONLY */ - if (refine) { - /* Read and reconstruct a mesh. */ -#ifdef TRILIBRARY - hullsize = reconstruct(in->trianglelist, in->triangleattributelist, - in->trianglearealist, in->numberoftriangles, - in->numberofcorners, in->numberoftriangleattributes, - in->segmentlist, in->segmentmarkerlist, - in->numberofsegments); -#else /* not TRILIBRARY */ - hullsize = reconstruct(inelefilename, areafilename, inpolyfilename, - polyfile); -#endif /* not TRILIBRARY */ - } else { - hullsize = delaunay(); /* Triangulate the points. */ - } -#endif /* not CDT_ONLY */ - -#ifndef NO_TIMER - if (!quiet) { - gettimeofday(&tv2, &tz); - if (refine) { - printf("Mesh reconstruction"); - } else { - printf("Delaunay"); - } - printf(" milliseconds: %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec) - + (tv2.tv_usec - tv1.tv_usec) / 1000l); - } -#endif /* NO_TIMER */ - - /* Ensure that no point can be mistaken for a triangular bounding */ - /* box point in insertsite(). */ - infpoint1 = (point) NULL; - infpoint2 = (point) NULL; - infpoint3 = (point) NULL; - - if (useshelles) { - checksegments = 1; /* Segments will be introduced next. */ - if (!refine) { - /* Insert PSLG segments and/or convex hull segments. */ -#ifdef TRILIBRARY - insegments = formskeleton(in->segmentlist, in->segmentmarkerlist, - in->numberofsegments); -#else /* not TRILIBRARY */ - insegments = formskeleton(polyfile, inpolyfilename); -#endif /* not TRILIBRARY */ - } - } - -#ifndef NO_TIMER - if (!quiet) { - gettimeofday(&tv3, &tz); - if (useshelles && !refine) { - printf("Segment milliseconds: %ld\n", - 1000l * (tv3.tv_sec - tv2.tv_sec) - + (tv3.tv_usec - tv2.tv_usec) / 1000l); - } - } -#endif /* NO_TIMER */ - - if (poly) { -#ifdef TRILIBRARY - holearray = in->holelist; - holes = in->numberofholes; - regionarray = in->regionlist; - regions = in->numberofregions; -#else /* not TRILIBRARY */ - readholes(polyfile, inpolyfilename, &holearray, &holes, - ®ionarray, ®ions); -#endif /* not TRILIBRARY */ - if (!refine) { - /* Carve out holes and concavities. */ - carveholes(holearray, holes, regionarray, regions); - } - } else { - /* Without a PSLG, there can be no holes or regional attributes */ - /* or area constraints. The following are set to zero to avoid */ - /* an accidental free() later. */ - holes = 0; - regions = 0; - } - -#ifndef NO_TIMER - if (!quiet) { - gettimeofday(&tv4, &tz); - if (poly && !refine) { - printf("Hole milliseconds: %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec) - + (tv4.tv_usec - tv3.tv_usec) / 1000l); - } - } -#endif /* NO_TIMER */ - -#ifndef CDT_ONLY - if (quality) { - enforcequality(); /* Enforce angle and area constraints. */ - } -#endif /* not CDT_ONLY */ - -#ifndef NO_TIMER - if (!quiet) { - gettimeofday(&tv5, &tz); -#ifndef CDT_ONLY - if (quality) { - printf("Quality milliseconds: %ld\n", - 1000l * (tv5.tv_sec - tv4.tv_sec) - + (tv5.tv_usec - tv4.tv_usec) / 1000l); - } -#endif /* not CDT_ONLY */ - } -#endif /* NO_TIMER */ - - /* Compute the number of edges. */ - edges = (3l * triangles.items + hullsize) / 2l; - - if (order > 1) { - highorder(); /* Promote elements to higher polynomial order. */ - } - if (!quiet) { - printf("\n"); - } - -#ifdef TRILIBRARY - out->numberofpoints = points.items; - out->numberofpointattributes = nextras; - out->numberoftriangles = triangles.items; - out->numberofcorners = (order + 1) * (order + 2) / 2; - out->numberoftriangleattributes = eextras; - out->numberofedges = edges; - if (useshelles) { - out->numberofsegments = shelles.items; - } else { - out->numberofsegments = hullsize; - } - if (vorout != (struct triangulateio *) NULL) { - vorout->numberofpoints = triangles.items; - vorout->numberofpointattributes = nextras; - vorout->numberofedges = edges; - } -#endif /* TRILIBRARY */ - /* If not using iteration numbers, don't write a .node file if one was */ - /* read, because the original one would be overwritten! */ - if (nonodewritten || (noiterationnum && readnodefile)) { - if (!quiet) { -#ifdef TRILIBRARY - printf("NOT writing points.\n"); -#else /* not TRILIBRARY */ - printf("NOT writing a .node file.\n"); -#endif /* not TRILIBRARY */ - } - numbernodes(); /* We must remember to number the points. */ - } else { -#ifdef TRILIBRARY - writenodes(&out->pointlist, &out->pointattributelist, - &out->pointmarkerlist); -#else /* not TRILIBRARY */ - writenodes(outnodefilename, argc, argv); /* Numbers the points too. */ -#endif /* TRILIBRARY */ - } - if (noelewritten) { - if (!quiet) { -#ifdef TRILIBRARY - printf("NOT writing triangles.\n"); -#else /* not TRILIBRARY */ - printf("NOT writing an .ele file.\n"); -#endif /* not TRILIBRARY */ - } - } else { -#ifdef TRILIBRARY - writeelements(&out->trianglelist, &out->triangleattributelist); -#else /* not TRILIBRARY */ - writeelements(outelefilename, argc, argv); -#endif /* not TRILIBRARY */ - } - /* The -c switch (convex switch) causes a PSLG to be written */ - /* even if none was read. */ - if (poly || convex) { - /* If not using iteration numbers, don't overwrite the .poly file. */ - if (nopolywritten || noiterationnum) { - if (!quiet) { -#ifdef TRILIBRARY - printf("NOT writing segments.\n"); -#else /* not TRILIBRARY */ - printf("NOT writing a .poly file.\n"); -#endif /* not TRILIBRARY */ - } - } else { -#ifdef TRILIBRARY - writepoly(&out->segmentlist, &out->segmentmarkerlist); - out->numberofholes = holes; - out->numberofregions = regions; - if (poly) { - out->holelist = in->holelist; - out->regionlist = in->regionlist; - } else { - out->holelist = (REAL *) NULL; - out->regionlist = (REAL *) NULL; - } -#else /* not TRILIBRARY */ - writepoly(outpolyfilename, holearray, holes, regionarray, regions, - argc, argv); -#endif /* not TRILIBRARY */ - } - } -#ifndef TRILIBRARY -#ifndef CDT_ONLY - if (regions > 0) { - free(regionarray); - } -#endif /* not CDT_ONLY */ - if (holes > 0) { - free(holearray); - } - if (geomview) { - writeoff(offfilename, argc, argv); - } -#endif /* not TRILIBRARY */ - if (edgesout) { -#ifdef TRILIBRARY - writeedges(&out->edgelist, &out->edgemarkerlist); -#else /* not TRILIBRARY */ - writeedges(edgefilename, argc, argv); -#endif /* not TRILIBRARY */ - } - if (voronoi) { -#ifdef TRILIBRARY - writevoronoi(&vorout->pointlist, &vorout->pointattributelist, - &vorout->pointmarkerlist, &vorout->edgelist, - &vorout->edgemarkerlist, &vorout->normlist); -#else /* not TRILIBRARY */ - writevoronoi(vnodefilename, vedgefilename, argc, argv); -#endif /* not TRILIBRARY */ - } - if (neighbors) { -#ifdef TRILIBRARY - writeneighbors(&out->neighborlist); -#else /* not TRILIBRARY */ - writeneighbors(neighborfilename, argc, argv); -#endif /* not TRILIBRARY */ - } - - if (!quiet) { -#ifndef NO_TIMER - gettimeofday(&tv6, &tz); - printf("\nOutput milliseconds: %ld\n", - 1000l * (tv6.tv_sec - tv5.tv_sec) - + (tv6.tv_usec - tv5.tv_usec) / 1000l); - printf("Total running milliseconds: %ld\n", - 1000l * (tv6.tv_sec - tv0.tv_sec) - + (tv6.tv_usec - tv0.tv_usec) / 1000l); -#endif /* NO_TIMER */ - - statistics(); - } - -#ifndef REDUCED - if (docheck) { - checkmesh(); - checkdelaunay(); - } -#endif /* not REDUCED */ - - triangledeinit(); -#ifndef TRILIBRARY - return 0; -#endif /* not TRILIBRARY */ -} +#define ANSI_DECLARATORS +/*****************************************************************************/ +/* */ +/* 888888888 ,o, / 888 */ +/* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */ +/* 888 888 888 88b 888 888 888 888 888 d888 88b */ +/* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */ +/* 888 888 888 C888 888 888 888 / 888 q888 */ +/* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */ +/* "8oo8D */ +/* */ +/* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */ +/* (triangle.c) */ +/* */ +/* Version 1.3 */ +/* July 19, 1996 */ +/* */ +/* Copyright 1996 */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/* This program may be freely redistributed under the condition that the */ +/* copyright notices (including this entire header and the copyright */ +/* notice printed when the `-h' switch is selected) are not removed, and */ +/* no compensation is received. Private, research, and institutional */ +/* use is free. You may distribute modified versions of this code UNDER */ +/* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */ +/* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */ +/* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */ +/* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */ +/* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */ +/* WITH THE AUTHOR. (If you are not directly supplying this code to a */ +/* customer, and you are instead telling them how they can obtain it for */ +/* free, then you are not required to make any arrangement with me.) */ +/* */ +/* Hypertext instructions for Triangle are available on the Web at */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.html */ +/* */ +/* Some of the references listed below are marked [*]. These are available */ +/* for downloading from the Web page */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.research.html */ +/* */ +/* A paper discussing some aspects of Triangle is available. See Jonathan */ +/* Richard Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator */ +/* and Delaunay Triangulator," First Workshop on Applied Computational */ +/* Geometry, ACM, May 1996. [*] */ +/* */ +/* Triangle was created as part of the Archimedes project in the School of */ +/* Computer Science at Carnegie Mellon University. Archimedes is a */ +/* system for compiling parallel finite element solvers. For further */ +/* information, see Anja Feldmann, Omar Ghattas, John R. Gilbert, Gary L. */ +/* Miller, David R. O'Hallaron, Eric J. Schwabe, Jonathan R. Shewchuk, */ +/* and Shang-Hua Teng, "Automated Parallel Solution of Unstructured PDE */ +/* Problems." To appear in Communications of the ACM, we hope. */ +/* */ +/* The quality mesh generation algorithm is due to Jim Ruppert, "A */ +/* Delaunay Refinement Algorithm for Quality 2-Dimensional Mesh */ +/* Generation," Journal of Algorithms 18(3):548-585, May 1995. [*] */ +/* */ +/* My implementation of the divide-and-conquer and incremental Delaunay */ +/* triangulation algorithms follows closely the presentation of Guibas */ +/* and Stolfi, even though I use a triangle-based data structure instead */ +/* of their quad-edge data structure. (In fact, I originally implemented */ +/* Triangle using the quad-edge data structure, but switching to a */ +/* triangle-based data structure sped Triangle by a factor of two.) The */ +/* mesh manipulation primitives and the two aforementioned Delaunay */ +/* triangulation algorithms are described by Leonidas J. Guibas and Jorge */ +/* Stolfi, "Primitives for the Manipulation of General Subdivisions and */ +/* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */ +/* 4(2):74-123, April 1985. */ +/* */ +/* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */ +/* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */ +/* Delaunay Triangulation," International Journal of Computer and */ +/* Information Science 9(3):219-242, 1980. The idea to improve the */ +/* divide-and-conquer algorithm by alternating between vertical and */ +/* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */ +/* Conquer Algorithm for Constructing Delaunay Triangulations," */ +/* Algorithmica 2(2):137-151, 1987. */ +/* */ +/* The incremental insertion algorithm was first proposed by C. L. Lawson, */ +/* "Software for C1 Surface Interpolation," in Mathematical Software III, */ +/* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */ +/* For point location, I use the algorithm of Ernst P. Mucke, Isaac */ +/* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */ +/* Preprocessing in Two- and Three-dimensional Delaunay Triangulations," */ +/* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */ +/* ACM, May 1996. [*] If I were to randomize the order of point */ +/* insertion (I currently don't bother), their result combined with the */ +/* result of Leonidas J. Guibas, Donald E. Knuth, and Micha Sharir, */ +/* "Randomized Incremental Construction of Delaunay and Voronoi */ +/* Diagrams," Algorithmica 7(4):381-413, 1992, would yield an expected */ +/* O(n^{4/3}) bound on running time. */ +/* */ +/* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */ +/* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */ +/* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */ +/* boundary of the triangulation are maintained in a splay tree for the */ +/* purpose of point location. Splay trees are described by Daniel */ +/* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */ +/* Trees," Journal of the ACM 32(3):652-686, July 1985. */ +/* */ +/* The algorithms for exact computation of the signs of determinants are */ +/* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */ +/* Point Arithmetic and Fast Robust Geometric Predicates," Technical */ +/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ +/* University, Pittsburgh, Pennsylvania, May 1996. [*] (Submitted to */ +/* Discrete & Computational Geometry.) An abbreviated version appears as */ +/* Jonathan Richard Shewchuk, "Robust Adaptive Floating-Point Geometric */ +/* Predicates," Proceedings of the Twelfth Annual Symposium on Computa- */ +/* tional Geometry, ACM, May 1996. [*] Many of the ideas for my exact */ +/* arithmetic routines originate with Douglas M. Priest, "Algorithms for */ +/* Arbitrary Precision Floating Point Arithmetic," Tenth Symposium on */ +/* Computer Arithmetic, 132-143, IEEE Computer Society Press, 1991. [*] */ +/* Many of the ideas for the correct evaluation of the signs of */ +/* determinants are taken from Steven Fortune and Christopher J. Van Wyk, */ +/* "Efficient Exact Arithmetic for Computational Geometry," Proceedings */ +/* of the Ninth Annual Symposium on Computational Geometry, ACM, */ +/* pp. 163-172, May 1993, and from Steven Fortune, "Numerical Stability */ +/* of Algorithms for 2D Delaunay Triangulations," International Journal */ +/* of Computational Geometry & Applications 5(1-2):193-213, March-June */ +/* 1995. */ +/* */ +/* For definitions of and results involving Delaunay triangulations, */ +/* constrained and conforming versions thereof, and other aspects of */ +/* triangular mesh generation, see the excellent survey by Marshall Bern */ +/* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */ +/* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */ +/* editors, World Scientific, Singapore, pp. 23-90, 1992. */ +/* */ +/* The time for incrementally adding PSLG (planar straight line graph) */ +/* segments to create a constrained Delaunay triangulation is probably */ +/* O(n^2) per segment in the worst case and O(n) per edge in the common */ +/* case, where n is the number of triangles that intersect the segment */ +/* before it is inserted. This doesn't count point location, which can */ +/* be much more expensive. (This note does not apply to conforming */ +/* Delaunay triangulations, for which a different method is used to */ +/* insert segments.) */ +/* */ +/* The time for adding segments to a conforming Delaunay triangulation is */ +/* not clear, but does not depend upon n alone. In some cases, very */ +/* small features (like a point lying next to a segment) can cause a */ +/* single segment to be split an arbitrary number of times. Of course, */ +/* floating-point precision is a practical barrier to how much this can */ +/* happen. */ +/* */ +/* The time for deleting a point from a Delaunay triangulation is O(n^2) in */ +/* the worst case and O(n) in the common case, where n is the degree of */ +/* the point being deleted. I could improve this to expected O(n) time */ +/* by "inserting" the neighboring vertices in random order, but n is */ +/* usually quite small, so it's not worth the bother. (The O(n) time */ +/* for random insertion follows from L. Paul Chew, "Building Voronoi */ +/* Diagrams for Convex Polygons in Linear Expected Time," Technical */ +/* Report PCS-TR90-147, Department of Mathematics and Computer Science, */ +/* Dartmouth College, 1990. */ +/* */ +/* Ruppert's Delaunay refinement algorithm typically generates triangles */ +/* at a linear rate (constant time per triangle) after the initial */ +/* triangulation is formed. There may be pathological cases where more */ +/* time is required, but these never arise in practice. */ +/* */ +/* The segment intersection formulae are straightforward. If you want to */ +/* see them derived, see Franklin Antonio. "Faster Line Segment */ +/* Intersection." In Graphics Gems III (David Kirk, editor), pp. 199- */ +/* 202. Academic Press, Boston, 1992. */ +/* */ +/* If you make any improvements to this code, please please please let me */ +/* know, so that I may obtain the improvements. Even if you don't change */ +/* the code, I'd still love to hear what it's being used for. */ +/* */ +/* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */ +/* whatsoever. This code is provided "as-is". Use at your own risk. */ +/* */ +/*****************************************************************************/ + +/* For single precision (which will save some memory and reduce paging), */ +/* define the symbol SINGLE by using the -DSINGLE compiler switch or by */ +/* writing "#define SINGLE" below. */ +/* */ +/* For double precision (which will allow you to refine meshes to a smaller */ +/* edge length), leave SINGLE undefined. */ +/* */ +/* Double precision uses more memory, but improves the resolution of the */ +/* meshes you can generate with Triangle. It also reduces the likelihood */ +/* of a floating exception due to overflow. Finally, it is much faster */ +/* than single precision on 64-bit architectures like the DEC Alpha. I */ +/* recommend double precision unless you want to generate a mesh for which */ +/* you do not have enough memory. */ + +#define SINGLE + +#ifdef SINGLE +#define REAL float +#else /* not SINGLE */ +#define REAL double +#endif /* not SINGLE */ + +/* If yours is not a Unix system, define the NO_TIMER compiler switch to */ +/* remove the Unix-specific timing code. */ + +#define NO_TIMER + +/* To insert lots of self-checks for internal errors, define the SELF_CHECK */ +/* symbol. This will slow down the program significantly. It is best to */ +/* define the symbol using the -DSELF_CHECK compiler switch, but you could */ +/* write "#define SELF_CHECK" below. If you are modifying this code, I */ +/* recommend you turn self-checks on. */ + +/* #define SELF_CHECK */ + +/* To compile Triangle as a callable object library (triangle.o), define the */ +/* TRILIBRARY symbol. Read the file triangle.h for details on how to call */ +/* the procedure triangulate() that results. */ + +#define TRILIBRARY + +/* It is possible to generate a smaller version of Triangle using one or */ +/* both of the following symbols. Define the REDUCED symbol to eliminate */ +/* all features that are primarily of research interest; specifically, the */ +/* -i, -F, -s, and -C switches. Define the CDT_ONLY symbol to eliminate */ +/* all meshing algorithms above and beyond constrained Delaunay */ +/* triangulation; specifically, the -r, -q, -a, -S, and -s switches. */ +/* These reductions are most likely to be useful when generating an object */ +/* library (triangle.o) by defining the TRILIBRARY symbol. */ + +#define REDUCED +#define CDT_ONLY + +/* On some machines, the exact arithmetic routines might be defeated by the */ +/* use of internal extended precision floating-point registers. Sometimes */ +/* this problem can be fixed by defining certain values to be volatile, */ +/* thus forcing them to be stored to memory and rounded off. This isn't */ +/* a great solution, though, as it slows Triangle down. */ +/* */ +/* To try this out, write "#define INEXACT volatile" below. Normally, */ +/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ + +#define INEXACT /* Nothing */ +/* #define INEXACT volatile */ + +/* Maximum number of characters in a file name (including the null). */ + +#define FILENAMESIZE 512 + +/* Maximum number of characters in a line read from a file (including the */ +/* null). */ + +#define INPUTLINESIZE 512 + +/* For efficiency, a variety of data structures are allocated in bulk. The */ +/* following constants determine how many of each structure is allocated */ +/* at once. */ + +#define TRIPERBLOCK 4092 /* Number of triangles allocated at once. */ +#define SHELLEPERBLOCK 508 /* Number of shell edges allocated at once. */ +#define POINTPERBLOCK 4092 /* Number of points allocated at once. */ +#define VIRUSPERBLOCK 1020 /* Number of virus triangles allocated at once. */ +/* Number of encroached segments allocated at once. */ +#define BADSEGMENTPERBLOCK 252 +/* Number of skinny triangles allocated at once. */ +#define BADTRIPERBLOCK 4092 +/* Number of splay tree nodes allocated at once. */ +#define SPLAYNODEPERBLOCK 508 + +/* The point marker DEADPOINT is an arbitrary number chosen large enough to */ +/* (hopefully) not conflict with user boundary markers. Make sure that it */ +/* is small enough to fit into your machine's integer size. */ + +#define DEADPOINT -1073741824 + +/* The next line is used to outsmart some very stupid compilers. If your */ +/* compiler is smarter, feel free to replace the "int" with "void". */ +/* Not that it matters. */ + +#define VOID int + +/* Two constants for algorithms based on random sampling. Both constants */ +/* have been chosen empirically to optimize their respective algorithms. */ + +/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide */ +/* how large a random sample of triangles to inspect. */ +#define SAMPLEFACTOR 11 +/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */ +/* of boundary edges should be maintained in the splay tree for point */ +/* location on the front. */ +#define SAMPLERATE 10 + +/* A number that speaks for itself, every kissable digit. */ + +#define PI 3.141592653589793238462643383279502884197169399375105820974944592308 + +/* Another fave. */ + +#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732 + +/* And here's one for those of you who are intimidated by math. */ + +#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333 + +#include +#include +#include +#ifndef NO_TIMER +#include +#endif /* NO_TIMER */ +#ifdef TRILIBRARY +#include "triangle.h" +#endif /* TRILIBRARY */ + +/* The following obscenity seems to be necessary to ensure that this program */ +/* will port to Dec Alphas running OSF/1, because their stdio.h file commits */ +/* the unpardonable sin of including stdlib.h. Hence, malloc(), free(), and */ +/* exit() may or may not already be defined at this point. I declare these */ +/* functions explicitly because some non-ANSI C compilers lack stdlib.h. */ + +#ifndef _STDLIB_H_ +extern void *malloc(); +extern void free(); +extern void exit(); +extern double strtod(); +extern long strtol(); +#endif /* _STDLIB_H_ */ + +/* A few forward declarations. */ + +void poolrestart(); +#ifndef TRILIBRARY +char *readline(); +char *findfield(); +#endif /* not TRILIBRARY */ + +/* Labels that signify whether a record consists primarily of pointers or of */ +/* floating-point words. Used to make decisions about data alignment. */ + +enum wordtype {POINTER, FLOATINGPOINT}; + +/* Labels that signify the result of point location. The result of a */ +/* search indicates that the point falls in the interior of a triangle, on */ +/* an edge, on a vertex, or outside the mesh. */ + +enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE}; + +/* Labels that signify the result of site insertion. The result indicates */ +/* that the point was inserted with complete success, was inserted but */ +/* encroaches on a segment, was not inserted because it lies on a segment, */ +/* or was not inserted because another point occupies the same location. */ + +enum insertsiteresult {SUCCESSFULPOINT, ENCROACHINGPOINT, VIOLATINGPOINT, + DUPLICATEPOINT}; + +/* Labels that signify the result of direction finding. The result */ +/* indicates that a segment connecting the two query points falls within */ +/* the direction triangle, along the left edge of the direction triangle, */ +/* or along the right edge of the direction triangle. */ + +enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR}; + +/* Labels that signify the result of the circumcenter computation routine. */ +/* The return value indicates which edge of the triangle is shortest. */ + +enum circumcenterresult {OPPOSITEORG, OPPOSITEDEST, OPPOSITEAPEX}; + +/*****************************************************************************/ +/* */ +/* The basic mesh data structures */ +/* */ +/* There are three: points, triangles, and shell edges (abbreviated */ +/* `shelle'). These three data structures, linked by pointers, comprise */ +/* the mesh. A point simply represents a point in space and its properties.*/ +/* A triangle is a triangle. A shell edge is a special data structure used */ +/* to represent impenetrable segments in the mesh (including the outer */ +/* boundary, boundaries of holes, and internal boundaries separating two */ +/* triangulated regions). Shell edges represent boundaries defined by the */ +/* user that triangles may not lie across. */ +/* */ +/* A triangle consists of a list of three vertices, a list of three */ +/* adjoining triangles, a list of three adjoining shell edges (when shell */ +/* edges are used), an arbitrary number of optional user-defined floating- */ +/* point attributes, and an optional area constraint. The latter is an */ +/* upper bound on the permissible area of each triangle in a region, used */ +/* for mesh refinement. */ +/* */ +/* For a triangle on a boundary of the mesh, some or all of the neighboring */ +/* triangles may not be present. For a triangle in the interior of the */ +/* mesh, often no neighboring shell edges are present. Such absent */ +/* triangles and shell edges are never represented by NULL pointers; they */ +/* are represented by two special records: `dummytri', the triangle that */ +/* fills "outer space", and `dummysh', the omnipresent shell edge. */ +/* `dummytri' and `dummysh' are used for several reasons; for instance, */ +/* they can be dereferenced and their contents examined without causing the */ +/* memory protection exception that would occur if NULL were dereferenced. */ +/* */ +/* However, it is important to understand that a triangle includes other */ +/* information as well. The pointers to adjoining vertices, triangles, and */ +/* shell edges are ordered in a way that indicates their geometric relation */ +/* to each other. Furthermore, each of these pointers contains orientation */ +/* information. Each pointer to an adjoining triangle indicates which face */ +/* of that triangle is contacted. Similarly, each pointer to an adjoining */ +/* shell edge indicates which side of that shell edge is contacted, and how */ +/* the shell edge is oriented relative to the triangle. */ +/* */ +/* Shell edges are found abutting edges of triangles; either sandwiched */ +/* between two triangles, or resting against one triangle on an exterior */ +/* boundary or hole boundary. */ +/* */ +/* A shell edge consists of a list of two vertices, a list of two */ +/* adjoining shell edges, and a list of two adjoining triangles. One of */ +/* the two adjoining triangles may not be present (though there should */ +/* always be one), and neighboring shell edges might not be present. */ +/* Shell edges also store a user-defined integer "boundary marker". */ +/* Typically, this integer is used to indicate what sort of boundary */ +/* conditions are to be applied at that location in a finite element */ +/* simulation. */ +/* */ +/* Like triangles, shell edges maintain information about the relative */ +/* orientation of neighboring objects. */ +/* */ +/* Points are relatively simple. A point is a list of floating point */ +/* numbers, starting with the x, and y coordinates, followed by an */ +/* arbitrary number of optional user-defined floating-point attributes, */ +/* followed by an integer boundary marker. During the segment insertion */ +/* phase, there is also a pointer from each point to a triangle that may */ +/* contain it. Each pointer is not always correct, but when one is, it */ +/* speeds up segment insertion. These pointers are assigned values once */ +/* at the beginning of the segment insertion phase, and are not used or */ +/* updated at any other time. Edge swapping during segment insertion will */ +/* render some of them incorrect. Hence, don't rely upon them for */ +/* anything. For the most part, points do not have any information about */ +/* what triangles or shell edges they are linked to. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Handles */ +/* */ +/* The oriented triangle (`triedge') and oriented shell edge (`edge') data */ +/* structures defined below do not themselves store any part of the mesh. */ +/* The mesh itself is made of `triangle's, `shelle's, and `point's. */ +/* */ +/* Oriented triangles and oriented shell edges will usually be referred to */ +/* as "handles". A handle is essentially a pointer into the mesh; it */ +/* allows you to "hold" one particular part of the mesh. Handles are used */ +/* to specify the regions in which one is traversing and modifying the mesh.*/ +/* A single `triangle' may be held by many handles, or none at all. (The */ +/* latter case is not a memory leak, because the triangle is still */ +/* connected to other triangles in the mesh.) */ +/* */ +/* A `triedge' is a handle that holds a triangle. It holds a specific side */ +/* of the triangle. An `edge' is a handle that holds a shell edge. It */ +/* holds either the left or right side of the edge. */ +/* */ +/* Navigation about the mesh is accomplished through a set of mesh */ +/* manipulation primitives, further below. Many of these primitives take */ +/* a handle and produce a new handle that holds the mesh near the first */ +/* handle. Other primitives take two handles and glue the corresponding */ +/* parts of the mesh together. The exact position of the handles is */ +/* important. For instance, when two triangles are glued together by the */ +/* bond() primitive, they are glued by the sides on which the handles lie. */ +/* */ +/* Because points have no information about which triangles they are */ +/* attached to, I commonly represent a point by use of a handle whose */ +/* origin is the point. A single handle can simultaneously represent a */ +/* triangle, an edge, and a point. */ +/* */ +/*****************************************************************************/ + +/* The triangle data structure. Each triangle contains three pointers to */ +/* adjoining triangles, plus three pointers to vertex points, plus three */ +/* pointers to shell edges (defined below; these pointers are usually */ +/* `dummysh'). It may or may not also contain user-defined attributes */ +/* and/or a floating-point "area constraint". It may also contain extra */ +/* pointers for nodes, when the user asks for high-order elements. */ +/* Because the size and structure of a `triangle' is not decided until */ +/* runtime, I haven't simply defined the type `triangle' to be a struct. */ + +typedef REAL **triangle; /* Really: typedef triangle *triangle */ + +/* An oriented triangle: includes a pointer to a triangle and orientation. */ +/* The orientation denotes an edge of the triangle. Hence, there are */ +/* three possible orientations. By convention, each edge is always */ +/* directed to point counterclockwise about the corresponding triangle. */ + +struct triedge { + triangle *tri; + int orient; /* Ranges from 0 to 2. */ +}; + +/* The shell data structure. Each shell edge contains two pointers to */ +/* adjoining shell edges, plus two pointers to vertex points, plus two */ +/* pointers to adjoining triangles, plus one shell marker. */ + +typedef REAL **shelle; /* Really: typedef shelle *shelle */ + +/* An oriented shell edge: includes a pointer to a shell edge and an */ +/* orientation. The orientation denotes a side of the edge. Hence, there */ +/* are two possible orientations. By convention, the edge is always */ +/* directed so that the "side" denoted is the right side of the edge. */ + +struct edge { + shelle *sh; + int shorient; /* Ranges from 0 to 1. */ +}; + +/* The point data structure. Each point is actually an array of REALs. */ +/* The number of REALs is unknown until runtime. An integer boundary */ +/* marker, and sometimes a pointer to a triangle, is appended after the */ +/* REALs. */ + +typedef REAL *point; + +/* A queue used to store encroached segments. Each segment's vertices are */ +/* stored so that one can check whether a segment is still the same. */ + +struct badsegment { + struct edge encsegment; /* An encroached segment. */ + point segorg, segdest; /* The two vertices. */ + struct badsegment *nextsegment; /* Pointer to next encroached segment. */ +}; + +/* A queue used to store bad triangles. The key is the square of the cosine */ +/* of the smallest angle of the triangle. Each triangle's vertices are */ +/* stored so that one can check whether a triangle is still the same. */ + +struct badface { + struct triedge badfacetri; /* A bad triangle. */ + REAL key; /* cos^2 of smallest (apical) angle. */ + point faceorg, facedest, faceapex; /* The three vertices. */ + struct badface *nextface; /* Pointer to next bad triangle. */ +}; + +/* A node in a heap used to store events for the sweepline Delaunay */ +/* algorithm. Nodes do not point directly to their parents or children in */ +/* the heap. Instead, each node knows its position in the heap, and can */ +/* look up its parent and children in a separate array. The `eventptr' */ +/* points either to a `point' or to a triangle (in encoded format, so that */ +/* an orientation is included). In the latter case, the origin of the */ +/* oriented triangle is the apex of a "circle event" of the sweepline */ +/* algorithm. To distinguish site events from circle events, all circle */ +/* events are given an invalid (smaller than `xmin') x-coordinate `xkey'. */ + +struct event { + REAL xkey, ykey; /* Coordinates of the event. */ + VOID *eventptr; /* Can be a point or the location of a circle event. */ + int heapposition; /* Marks this event's position in the heap. */ +}; + +/* A node in the splay tree. Each node holds an oriented ghost triangle */ +/* that represents a boundary edge of the growing triangulation. When a */ +/* circle event covers two boundary edges with a triangle, so that they */ +/* are no longer boundary edges, those edges are not immediately deleted */ +/* from the tree; rather, they are lazily deleted when they are next */ +/* encountered. (Since only a random sample of boundary edges are kept */ +/* in the tree, lazy deletion is faster.) `keydest' is used to verify */ +/* that a triangle is still the same as when it entered the splay tree; if */ +/* it has been rotated (due to a circle event), it no longer represents a */ +/* boundary edge and should be deleted. */ + +struct splaynode { + struct triedge keyedge; /* Lprev of an edge on the front. */ + point keydest; /* Used to verify that splay node is still live. */ + struct splaynode *lchild, *rchild; /* Children in splay tree. */ +}; + +/* A type used to allocate memory. firstblock is the first block of items. */ +/* nowblock is the block from which items are currently being allocated. */ +/* nextitem points to the next slab of free memory for an item. */ +/* deaditemstack is the head of a linked list (stack) of deallocated items */ +/* that can be recycled. unallocateditems is the number of items that */ +/* remain to be allocated from nowblock. */ +/* */ +/* Traversal is the process of walking through the entire list of items, and */ +/* is separate from allocation. Note that a traversal will visit items on */ +/* the "deaditemstack" stack as well as live items. pathblock points to */ +/* the block currently being traversed. pathitem points to the next item */ +/* to be traversed. pathitemsleft is the number of items that remain to */ +/* be traversed in pathblock. */ +/* */ +/* itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest */ +/* what sort of word the record is primarily made up of. alignbytes */ +/* determines how new records should be aligned in memory. itembytes and */ +/* itemwords are the length of a record in bytes (after rounding up) and */ +/* words. itemsperblock is the number of items allocated at once in a */ +/* single block. items is the number of currently allocated items. */ +/* maxitems is the maximum number of items that have been allocated at */ +/* once; it is the current number of items plus the number of records kept */ +/* on deaditemstack. */ + +struct memorypool { + VOID **firstblock, **nowblock; + VOID *nextitem; + VOID *deaditemstack; + VOID **pathblock; + VOID *pathitem; + enum wordtype itemwordtype; + int alignbytes; + int itembytes, itemwords; + int itemsperblock; + long items, maxitems; + int unallocateditems; + int pathitemsleft; +}; + +/* Variables used to allocate memory for triangles, shell edges, points, */ +/* viri (triangles being eaten), bad (encroached) segments, bad (skinny */ +/* or too large) triangles, and splay tree nodes. */ + +static struct memorypool triangles; +static struct memorypool shelles; +static struct memorypool points; +static struct memorypool viri; +static struct memorypool badsegments; +static struct memorypool badtriangles; +static struct memorypool splaynodes; + +/* Variables that maintain the bad triangle queues. The tails are pointers */ +/* to the pointers that have to be filled in to enqueue an item. */ + +static struct badface *queuefront[64]; +static struct badface **queuetail[64]; + +static REAL xmin, xmax, ymin, ymax; /* x and y bounds. */ +static REAL xminextreme; /* Nonexistent x value used as a flag in sweepline. */ +static int inpoints; /* Number of input points. */ +static int inelements; /* Number of input triangles. */ +static int insegments; /* Number of input segments. */ +static int holes; /* Number of input holes. */ +static int regions; /* Number of input regions. */ +static long edges; /* Number of output edges. */ +static int mesh_dim; /* Dimension (ought to be 2). */ +static int nextras; /* Number of attributes per point. */ +static int eextras; /* Number of attributes per triangle. */ +static long hullsize; /* Number of edges of convex hull. */ +static int triwords; /* Total words per triangle. */ +static int shwords; /* Total words per shell edge. */ +static int pointmarkindex; /* Index to find boundary marker of a point. */ +static int point2triindex; /* Index to find a triangle adjacent to a point. */ +static int highorderindex; /* Index to find extra nodes for high-order elements. */ +static int elemattribindex; /* Index to find attributes of a triangle. */ +static int areaboundindex; /* Index to find area bound of a triangle. */ +static int checksegments; /* Are there segments in the triangulation yet? */ +static int readnodefile; /* Has a .node file been read? */ +static long samples; /* Number of random samples for point location. */ +static unsigned long randomseed; /* Current random number seed. */ + +static REAL splitter; /* Used to split REAL factors for exact multiplication. */ +static REAL epsilon; /* Floating-point machine epsilon. */ +static REAL resulterrbound; +static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; +static REAL iccerrboundA, iccerrboundB, iccerrboundC; + +static long incirclecount; /* Number of incircle tests performed. */ +static long counterclockcount; /* Number of counterclockwise tests performed. */ +static long hyperbolacount; /* Number of right-of-hyperbola tests performed. */ +static long circumcentercount; /* Number of circumcenter calculations performed. */ +static long circletopcount; /* Number of circle top calculations performed. */ + +/* Switches for the triangulator. */ +/* poly: -p switch. refine: -r switch. */ +/* quality: -q switch. */ +/* minangle: minimum angle bound, specified after -q switch. */ +/* goodangle: cosine squared of minangle. */ +/* vararea: -a switch without number. */ +/* fixedarea: -a switch with number. */ +/* maxarea: maximum area bound, specified after -a switch. */ +/* regionattrib: -A switch. convex: -c switch. */ +/* firstnumber: inverse of -z switch. All items are numbered starting */ +/* from firstnumber. */ +/* edgesout: -e switch. voronoi: -v switch. */ +/* neighbors: -n switch. geomview: -g switch. */ +/* nobound: -B switch. nopolywritten: -P switch. */ +/* nonodewritten: -N switch. noelewritten: -E switch. */ +/* noiterationnum: -I switch. noholes: -O switch. */ +/* noexact: -X switch. */ +/* order: element order, specified after -o switch. */ +/* nobisect: count of how often -Y switch is selected. */ +/* steiner: maximum number of Steiner points, specified after -S switch. */ +/* steinerleft: number of Steiner points not yet used. */ +/* incremental: -i switch. sweepline: -F switch. */ +/* dwyer: inverse of -l switch. */ +/* splitseg: -s switch. */ +/* docheck: -C switch. */ +/* quiet: -Q switch. verbose: count of how often -V switch is selected. */ +/* useshelles: -p, -r, -q, or -c switch; determines whether shell edges */ +/* are used at all. */ +/* */ +/* Read the instructions to find out the meaning of these switches. */ + +static int poly, refine, quality, vararea, fixedarea, regionattrib, convex; +static int firstnumber; +static int edgesout, voronoi, neighbors, geomview; +static int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum; +static int noholes, noexact; +static int incremental, sweepline, dwyer; +static int splitseg; +static int docheck; +static int quiet, verbose; +static int useshelles; +static int order; +static int nobisect; +static int steiner, steinerleft; +static REAL minangle, goodangle; +static REAL maxarea; + +/* Variables for file names. */ + +#ifndef TRILIBRARY +char innodefilename[FILENAMESIZE]; +char inelefilename[FILENAMESIZE]; +char inpolyfilename[FILENAMESIZE]; +char areafilename[FILENAMESIZE]; +char outnodefilename[FILENAMESIZE]; +char outelefilename[FILENAMESIZE]; +char outpolyfilename[FILENAMESIZE]; +char edgefilename[FILENAMESIZE]; +char vnodefilename[FILENAMESIZE]; +char vedgefilename[FILENAMESIZE]; +char neighborfilename[FILENAMESIZE]; +char offfilename[FILENAMESIZE]; +#endif /* not TRILIBRARY */ + +/* Triangular bounding box points. */ + +static point infpoint1, infpoint2, infpoint3; + +/* Pointer to the `triangle' that occupies all of "outer space". */ + +static triangle *dummytri; +static triangle *dummytribase; /* Keep base address so we can free() it later. */ + +/* Pointer to the omnipresent shell edge. Referenced by any triangle or */ +/* shell edge that isn't really connected to a shell edge at that */ +/* location. */ + +static shelle *dummysh; +static shelle *dummyshbase; /* Keep base address so we can free() it later. */ + +/* Pointer to a recently visited triangle. Improves point location if */ +/* proximate points are inserted sequentially. */ + +static struct triedge recenttri; + +/*****************************************************************************/ +/* */ +/* Mesh manipulation primitives. Each triangle contains three pointers to */ +/* other triangles, with orientations. Each pointer points not to the */ +/* first byte of a triangle, but to one of the first three bytes of a */ +/* triangle. It is necessary to extract both the triangle itself and the */ +/* orientation. To save memory, I keep both pieces of information in one */ +/* pointer. To make this possible, I assume that all triangles are aligned */ +/* to four-byte boundaries. The `decode' routine below decodes a pointer, */ +/* extracting an orientation (in the range 0 to 2) and a pointer to the */ +/* beginning of a triangle. The `encode' routine compresses a pointer to a */ +/* triangle and an orientation into a single pointer. My assumptions that */ +/* triangles are four-byte-aligned and that the `unsigned long' type is */ +/* long enough to hold a pointer are two of the few kludges in this program.*/ +/* */ +/* Shell edges are manipulated similarly. A pointer to a shell edge */ +/* carries both an address and an orientation in the range 0 to 1. */ +/* */ +/* The other primitives take an oriented triangle or oriented shell edge, */ +/* and return an oriented triangle or oriented shell edge or point; or they */ +/* change the connections in the data structure. */ +/* */ +/*****************************************************************************/ + +/********* Mesh manipulation primitives begin here *********/ +/** **/ +/** **/ + +/* Fast lookup arrays to speed some of the mesh manipulation primitives. */ + +int plus1mod3[3] = {1, 2, 0}; +int minus1mod3[3] = {2, 0, 1}; + +/********* Primitives for triangles *********/ +/* */ +/* */ + +/* decode() converts a pointer to an oriented triangle. The orientation is */ +/* extracted from the two least significant bits of the pointer. */ + +#define decode(ptr, triedge) \ + (triedge).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l); \ + (triedge).tri = (triangle *) \ + ((unsigned long) (ptr) ^ (unsigned long) (triedge).orient) + +/* encode() compresses an oriented triangle into a single pointer. It */ +/* relies on the assumption that all triangles are aligned to four-byte */ +/* boundaries, so the two least significant bits of (triedge).tri are zero.*/ + +#define encode(triedge) \ + (triangle) ((unsigned long) (triedge).tri | (unsigned long) (triedge).orient) + +/* The following edge manipulation primitives are all described by Guibas */ +/* and Stolfi. However, they use an edge-based data structure, whereas I */ +/* am using a triangle-based data structure. */ + +/* sym() finds the abutting triangle, on the same edge. Note that the */ +/* edge direction is necessarily reversed, because triangle/edge handles */ +/* are always directed counterclockwise around the triangle. */ + +#define sym(triedge1, triedge2) \ + ptr = (triedge1).tri[(triedge1).orient]; \ + decode(ptr, triedge2); + +#define symself(triedge) \ + ptr = (triedge).tri[(triedge).orient]; \ + decode(ptr, triedge); + +/* lnext() finds the next edge (counterclockwise) of a triangle. */ + +#define lnext(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = plus1mod3[(triedge1).orient] + +#define lnextself(triedge) \ + (triedge).orient = plus1mod3[(triedge).orient] + +/* lprev() finds the previous edge (clockwise) of a triangle. */ + +#define lprev(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = minus1mod3[(triedge1).orient] + +#define lprevself(triedge) \ + (triedge).orient = minus1mod3[(triedge).orient] + +/* onext() spins counterclockwise around a point; that is, it finds the next */ +/* edge with the same origin in the counterclockwise direction. This edge */ +/* will be part of a different triangle. */ + +#define onext(triedge1, triedge2) \ + lprev(triedge1, triedge2); \ + symself(triedge2); + +#define onextself(triedge) \ + lprevself(triedge); \ + symself(triedge); + +/* oprev() spins clockwise around a point; that is, it finds the next edge */ +/* with the same origin in the clockwise direction. This edge will be */ +/* part of a different triangle. */ + +#define oprev(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lnextself(triedge2); + +#define oprevself(triedge) \ + symself(triedge); \ + lnextself(triedge); + +/* dnext() spins counterclockwise around a point; that is, it finds the next */ +/* edge with the same destination in the counterclockwise direction. This */ +/* edge will be part of a different triangle. */ + +#define dnext(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lprevself(triedge2); + +#define dnextself(triedge) \ + symself(triedge); \ + lprevself(triedge); + +/* dprev() spins clockwise around a point; that is, it finds the next edge */ +/* with the same destination in the clockwise direction. This edge will */ +/* be part of a different triangle. */ + +#define dprev(triedge1, triedge2) \ + lnext(triedge1, triedge2); \ + symself(triedge2); + +#define dprevself(triedge) \ + lnextself(triedge); \ + symself(triedge); + +/* rnext() moves one edge counterclockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rnext(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lnextself(triedge2); \ + symself(triedge2); + +#define rnextself(triedge) \ + symself(triedge); \ + lnextself(triedge); \ + symself(triedge); + +/* rnext() moves one edge clockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rprev(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lprevself(triedge2); \ + symself(triedge2); + +#define rprevself(triedge) \ + symself(triedge); \ + lprevself(triedge); \ + symself(triedge); + +/* These primitives determine or set the origin, destination, or apex of a */ +/* triangle. */ + +#define org(triedge, pointptr) \ + pointptr = (point) (triedge).tri[plus1mod3[(triedge).orient] + 3] + +#define dest(triedge, pointptr) \ + pointptr = (point) (triedge).tri[minus1mod3[(triedge).orient] + 3] + +#define apex(triedge, pointptr) \ + pointptr = (point) (triedge).tri[(triedge).orient + 3] + +#define setorg(triedge, pointptr) \ + (triedge).tri[plus1mod3[(triedge).orient] + 3] = (triangle) pointptr + +#define setdest(triedge, pointptr) \ + (triedge).tri[minus1mod3[(triedge).orient] + 3] = (triangle) pointptr + +#define setapex(triedge, pointptr) \ + (triedge).tri[(triedge).orient + 3] = (triangle) pointptr + +#define setvertices2null(triedge) \ + (triedge).tri[3] = (triangle) NULL; \ + (triedge).tri[4] = (triangle) NULL; \ + (triedge).tri[5] = (triangle) NULL; + +/* Bond two triangles together. */ + +#define bond(triedge1, triedge2) \ + (triedge1).tri[(triedge1).orient] = encode(triedge2); \ + (triedge2).tri[(triedge2).orient] = encode(triedge1) + +/* Dissolve a bond (from one side). Note that the other triangle will still */ +/* think it's connected to this triangle. Usually, however, the other */ +/* triangle is being deleted entirely, or bonded to another triangle, so */ +/* it doesn't matter. */ + +#define dissolve(triedge) \ + (triedge).tri[(triedge).orient] = (triangle) dummytri + +/* Copy a triangle/edge handle. */ + +#define triedgecopy(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = (triedge1).orient + +/* Test for equality of triangle/edge handles. */ + +#define triedgeequal(triedge1, triedge2) \ + (((triedge1).tri == (triedge2).tri) && \ + ((triedge1).orient == (triedge2).orient)) + +/* Primitives to infect or cure a triangle with the virus. These rely on */ +/* the assumption that all shell edges are aligned to four-byte boundaries.*/ + +#define infect(triedge) \ + (triedge).tri[6] = (triangle) \ + ((unsigned long) (triedge).tri[6] | (unsigned long) 2l) + +#define uninfect(triedge) \ + (triedge).tri[6] = (triangle) \ + ((unsigned long) (triedge).tri[6] & ~ (unsigned long) 2l) + +/* Test a triangle for viral infection. */ + +#define infected(triedge) \ + (((unsigned long) (triedge).tri[6] & (unsigned long) 2l) != 0) + +/* Check or set a triangle's attributes. */ + +#define elemattribute(triedge, attnum) \ + ((REAL *) (triedge).tri)[elemattribindex + (attnum)] + +#define setelemattribute(triedge, attnum, value) \ + ((REAL *) (triedge).tri)[elemattribindex + (attnum)] = (REAL)value + +/* Check or set a triangle's maximum area bound. */ + +#define areabound(triedge) ((REAL *) (triedge).tri)[areaboundindex] + +#define setareabound(triedge, value) \ + ((REAL *) (triedge).tri)[areaboundindex] = (REAL)value + +/********* Primitives for shell edges *********/ +/* */ +/* */ + +/* sdecode() converts a pointer to an oriented shell edge. The orientation */ +/* is extracted from the least significant bit of the pointer. The two */ +/* least significant bits (one for orientation, one for viral infection) */ +/* are masked out to produce the real pointer. */ + +#define sdecode(sptr, edge) \ + (edge).shorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l); \ + (edge).sh = (shelle *) \ + ((unsigned long) (sptr) & ~ (unsigned long) 3l) + +/* sencode() compresses an oriented shell edge into a single pointer. It */ +/* relies on the assumption that all shell edges are aligned to two-byte */ +/* boundaries, so the least significant bit of (edge).sh is zero. */ + +#define sencode(edge) \ + (shelle) ((unsigned long) (edge).sh | (unsigned long) (edge).shorient) + +/* ssym() toggles the orientation of a shell edge. */ + +#define ssym(edge1, edge2) \ + (edge2).sh = (edge1).sh; \ + (edge2).shorient = 1 - (edge1).shorient + +#define ssymself(edge) \ + (edge).shorient = 1 - (edge).shorient + +/* spivot() finds the other shell edge (from the same segment) that shares */ +/* the same origin. */ + +#define spivot(edge1, edge2) \ + sptr = (edge1).sh[(edge1).shorient]; \ + sdecode(sptr, edge2) + +#define spivotself(edge) \ + sptr = (edge).sh[(edge).shorient]; \ + sdecode(sptr, edge) + +/* snext() finds the next shell edge (from the same segment) in sequence; */ +/* one whose origin is the input shell edge's destination. */ + +#define snext(edge1, edge2) \ + sptr = (edge1).sh[1 - (edge1).shorient]; \ + sdecode(sptr, edge2) + +#define snextself(edge) \ + sptr = (edge).sh[1 - (edge).shorient]; \ + sdecode(sptr, edge) + +/* These primitives determine or set the origin or destination of a shell */ +/* edge. */ + +#define sorg(edge, pointptr) \ + pointptr = (point) (edge).sh[2 + (edge).shorient] + +#define sdest(edge, pointptr) \ + pointptr = (point) (edge).sh[3 - (edge).shorient] + +#define setsorg(edge, pointptr) \ + (edge).sh[2 + (edge).shorient] = (shelle) pointptr + +#define setsdest(edge, pointptr) \ + (edge).sh[3 - (edge).shorient] = (shelle) pointptr + +/* These primitives read or set a shell marker. Shell markers are used to */ +/* hold user boundary information. */ + +#define mark(edge) (* (int *) ((edge).sh + 6)) + +#define setmark(edge, value) \ + * (int *) ((edge).sh + 6) = value + +/* Bond two shell edges together. */ + +#define sbond(edge1, edge2) \ + (edge1).sh[(edge1).shorient] = sencode(edge2); \ + (edge2).sh[(edge2).shorient] = sencode(edge1) + +/* Dissolve a shell edge bond (from one side). Note that the other shell */ +/* edge will still think it's connected to this shell edge. */ + +#define sdissolve(edge) \ + (edge).sh[(edge).shorient] = (shelle) dummysh + +/* Copy a shell edge. */ + +#define shellecopy(edge1, edge2) \ + (edge2).sh = (edge1).sh; \ + (edge2).shorient = (edge1).shorient + +/* Test for equality of shell edges. */ + +#define shelleequal(edge1, edge2) \ + (((edge1).sh == (edge2).sh) && \ + ((edge1).shorient == (edge2).shorient)) + +/********* Primitives for interacting triangles and shell edges *********/ +/* */ +/* */ + +/* tspivot() finds a shell edge abutting a triangle. */ + +#define tspivot(triedge, edge) \ + sptr = (shelle) (triedge).tri[6 + (triedge).orient]; \ + sdecode(sptr, edge) + +/* stpivot() finds a triangle abutting a shell edge. It requires that the */ +/* variable `ptr' of type `triangle' be defined. */ + +#define stpivot(edge, triedge) \ + ptr = (triangle) (edge).sh[4 + (edge).shorient]; \ + decode(ptr, triedge) + +/* Bond a triangle to a shell edge. */ + +#define tsbond(triedge, edge) \ + (triedge).tri[6 + (triedge).orient] = (triangle) sencode(edge); \ + (edge).sh[4 + (edge).shorient] = (shelle) encode(triedge) + +/* Dissolve a bond (from the triangle side). */ + +#define tsdissolve(triedge) \ + (triedge).tri[6 + (triedge).orient] = (triangle) dummysh + +/* Dissolve a bond (from the shell edge side). */ + +#define stdissolve(edge) \ + (edge).sh[4 + (edge).shorient] = (shelle) dummytri + +/********* Primitives for points *********/ +/* */ +/* */ + +#define pointmark(pt) ((int *) (pt))[pointmarkindex] + +#define setpointmark(pt, value) \ + ((int *) (pt))[pointmarkindex] = value + +#define point2tri(pt) ((triangle *) (pt))[point2triindex] + +#define setpoint2tri(pt, value) \ + ((triangle *) (pt))[point2triindex] = value + +/** **/ +/** **/ +/********* Mesh manipulation primitives end here *********/ + +/********* User interaction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* syntax() Print list of command line switches. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void syntax() +{ +#ifdef CDT_ONLY +#ifdef REDUCED + printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n"); +#endif /* not REDUCED */ +#else /* not CDT_ONLY */ +#ifdef REDUCED + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n"); +#endif /* not REDUCED */ +#endif /* not CDT_ONLY */ + + printf(" -p Triangulates a Planar Straight Line Graph (.poly file).\n"); +#ifndef CDT_ONLY + printf(" -r Refines a previously generated mesh.\n"); + printf( + " -q Quality mesh generation. A minimum angle may be specified.\n"); + printf(" -a Applies a maximum triangle area constraint.\n"); +#endif /* not CDT_ONLY */ + printf( + " -A Applies attributes to identify elements in certain regions.\n"); + printf(" -c Encloses the convex hull with segments.\n"); + printf(" -e Generates an edge list.\n"); + printf(" -v Generates a Voronoi diagram.\n"); + printf(" -n Generates a list of triangle neighbors.\n"); + printf(" -g Generates an .off file for Geomview.\n"); + printf(" -B Suppresses output of boundary information.\n"); + printf(" -P Suppresses output of .poly file.\n"); + printf(" -N Suppresses output of .node file.\n"); + printf(" -E Suppresses output of .ele file.\n"); + printf(" -I Suppresses mesh iteration numbers.\n"); + printf(" -O Ignores holes in .poly file.\n"); + printf(" -X Suppresses use of exact arithmetic.\n"); + printf(" -z Numbers all items starting from zero (rather than one).\n"); + printf(" -o2 Generates second-order subparametric elements.\n"); +#ifndef CDT_ONLY + printf(" -Y Suppresses boundary segment splitting.\n"); + printf(" -S Specifies maximum number of added Steiner points.\n"); +#endif /* not CDT_ONLY */ +#ifndef REDUCED + printf(" -i Uses incremental method, rather than divide-and-conquer.\n"); + printf(" -F Uses Fortune's sweepline algorithm, rather than d-and-c.\n"); +#endif /* not REDUCED */ + printf(" -l Uses vertical cuts only, rather than alternating cuts.\n"); +#ifndef REDUCED +#ifndef CDT_ONLY + printf( + " -s Force segments into mesh by splitting (instead of using CDT).\n"); +#endif /* not CDT_ONLY */ + printf(" -C Check consistency of final mesh.\n"); +#endif /* not REDUCED */ + printf(" -Q Quiet: No terminal output except errors.\n"); + printf(" -V Verbose: Detailed information on what I'm doing.\n"); + printf(" -h Help: Detailed instructions for Triangle.\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* info() Print out complete instructions. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void info() +{ + printf("Triangle\n"); + printf( +"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n"); + printf("Version 1.3\n\n"); + printf( +"Copyright 1996 Jonathan Richard Shewchuk (bugs/comments to jrs@cs.cmu.edu)\n" +); + printf("School of Computer Science / Carnegie Mellon University\n"); + printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania 15213-3891\n"); + printf( +"Created as part of the Archimedes project (tools for parallel FEM).\n"); + printf( +"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n"); + printf("There is no warranty whatsoever. Use at your own risk.\n"); +#ifdef SINGLE + printf("This executable is compiled for single precision arithmetic.\n\n\n"); +#else /* not SINGLE */ + printf("This executable is compiled for double precision arithmetic.\n\n\n"); +#endif /* not SINGLE */ + printf( +"Triangle generates exact Delaunay triangulations, constrained Delaunay\n"); + printf( +"triangulations, and quality conforming Delaunay triangulations. The latter\n" +); + printf( +"can be generated with no small angles, and are thus suitable for finite\n"); + printf( +"element analysis. If no command line switches are specified, your .node\n"); + printf( +"input file will be read, and the Delaunay triangulation will be returned in\n" +); + printf(".node and .ele output files. The command syntax is:\n\n"); +#ifdef CDT_ONLY +#ifdef REDUCED + printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n\n"); +#else /* not REDUCED */ + printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n\n"); +#endif /* not REDUCED */ +#else /* not CDT_ONLY */ +#ifdef REDUCED + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n\n"); +#else /* not REDUCED */ + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n\n"); +#endif /* not REDUCED */ +#endif /* not CDT_ONLY */ + printf( +"Underscores indicate that numbers may optionally follow certain switches;\n"); + printf( +"do not leave any space between a switch and its numeric parameter.\n"); + printf( +"input_file must be a file with extension .node, or extension .poly if the\n"); + printf( +"-p switch is used. If -r is used, you must supply .node and .ele files,\n"); + printf( +"and possibly a .poly file and .area file as well. The formats of these\n"); + printf("files are described below.\n\n"); + printf("Command Line Switches:\n\n"); + printf( +" -p Reads a Planar Straight Line Graph (.poly file), which can specify\n" +); + printf( +" points, segments, holes, and regional attributes and area\n"); + printf( +" constraints. Will generate a constrained Delaunay triangulation\n"); + printf( +" fitting the input; or, if -s, -q, or -a is used, a conforming\n"); + printf( +" Delaunay triangulation. If -p is not used, Triangle reads a .node\n" +); + printf(" file by default.\n"); + printf( +" -r Refines a previously generated mesh. The mesh is read from a .node\n" +); + printf( +" file and an .ele file. If -p is also used, a .poly file is read\n"); + printf( +" and used to constrain edges in the mesh. Further details on\n"); + printf(" refinement are given below.\n"); + printf( +" -q Quality mesh generation by Jim Ruppert's Delaunay refinement\n"); + printf( +" algorithm. Adds points to the mesh to ensure that no angles\n"); + printf( +" smaller than 20 degrees occur. An alternative minimum angle may be\n" +); + printf( +" specified after the `q'. If the minimum angle is 20.7 degrees or\n"); + printf( +" smaller, the triangulation algorithm is theoretically guaranteed to\n" +); + printf( +" terminate (assuming infinite precision arithmetic - Triangle may\n"); + printf( +" fail to terminate if you run out of precision). In practice, the\n"); + printf( +" algorithm often succeeds for minimum angles up to 33.8 degrees.\n"); + printf( +" For highly refined meshes, however, it may be necessary to reduce\n"); + printf( +" the minimum angle to well below 20 to avoid problems associated\n"); + printf( +" with insufficient floating-point precision. The specified angle\n"); + printf(" may include a decimal point.\n"); + printf( +" -a Imposes a maximum triangle area. If a number follows the `a', no\n"); + printf( +" triangle will be generated whose area is larger than that number.\n"); + printf( +" If no number is specified, an .area file (if -r is used) or .poly\n"); + printf( +" file (if -r is not used) specifies a number of maximum area\n"); + printf( +" constraints. An .area file contains a separate area constraint for\n" +); + printf( +" each triangle, and is useful for refining a finite element mesh\n"); + printf( +" based on a posteriori error estimates. A .poly file can optionally\n" +); + printf( +" contain an area constraint for each segment-bounded region, thereby\n" +); + printf( +" enforcing triangle densities in a first triangulation. You can\n"); + printf( +" impose both a fixed area constraint and a varying area constraint\n"); + printf( +" by invoking the -a switch twice, once with and once without a\n"); + printf( +" number following. Each area specified may include a decimal point.\n" +); + printf( +" -A Assigns an additional attribute to each triangle that identifies\n"); + printf( +" what segment-bounded region each triangle belongs to. Attributes\n"); + printf( +" are assigned to regions by the .poly file. If a region is not\n"); + printf( +" explicitly marked by the .poly file, triangles in that region are\n"); + printf( +" assigned an attribute of zero. The -A switch has an effect only\n"); + printf(" when the -p switch is used and the -r switch is not.\n"); + printf( +" -c Creates segments on the convex hull of the triangulation. If you\n"); + printf( +" are triangulating a point set, this switch causes a .poly file to\n"); + printf( +" be written, containing all edges in the convex hull. (By default,\n" +); + printf( +" a .poly file is written only if a .poly file is read.) If you are\n" +); + printf( +" triangulating a PSLG, this switch specifies that the interior of\n"); + printf( +" the convex hull of the PSLG should be triangulated. If you do not\n" +); + printf( +" use this switch when triangulating a PSLG, it is assumed that you\n"); + printf( +" have identified the region to be triangulated by surrounding it\n"); + printf( +" with segments of the input PSLG. Beware: if you are not careful,\n" +); + printf( +" this switch can cause the introduction of an extremely thin angle\n"); + printf( +" between a PSLG segment and a convex hull segment, which can cause\n"); + printf( +" overrefinement or failure if Triangle runs out of precision. If\n"); + printf( +" you are refining a mesh, the -c switch works differently; it\n"); + printf( +" generates the set of boundary edges of the mesh, rather than the\n"); + printf(" convex hull.\n"); + printf( +" -e Outputs (to an .edge file) a list of edges of the triangulation.\n"); + printf( +" -v Outputs the Voronoi diagram associated with the triangulation.\n"); + printf(" Does not attempt to detect degeneracies.\n"); + printf( +" -n Outputs (to a .neigh file) a list of triangles neighboring each\n"); + printf(" triangle.\n"); + printf( +" -g Outputs the mesh to an Object File Format (.off) file, suitable for\n" +); + printf(" viewing with the Geometry Center's Geomview package.\n"); + printf( +" -B No boundary markers in the output .node, .poly, and .edge output\n"); + printf( +" files. See the detailed discussion of boundary markers below.\n"); + printf( +" -P No output .poly file. Saves disk space, but you lose the ability\n"); + printf( +" to impose segment constraints on later refinements of the mesh.\n"); + printf(" -N No output .node file.\n"); + printf(" -E No output .ele file.\n"); + printf( +" -I No iteration numbers. Suppresses the output of .node and .poly\n"); + printf( +" files, so your input files won't be overwritten. (If your input is\n" +); + printf( +" a .poly file only, a .node file will be written.) Cannot be used\n"); + printf( +" with the -r switch, because that would overwrite your input .ele\n"); + printf( +" file. Shouldn't be used with the -s, -q, or -a switch if you are\n"); + printf( +" using a .node file for input, because no .node file will be\n"); + printf(" written, so there will be no record of any added points.\n"); + printf(" -O No holes. Ignores the holes in the .poly file.\n"); + printf( +" -X No exact arithmetic. Normally, Triangle uses exact floating-point\n" +); + printf( +" arithmetic for certain tests if it thinks the inexact tests are not\n" +); + printf( +" accurate enough. Exact arithmetic ensures the robustness of the\n"); + printf( +" triangulation algorithms, despite floating-point roundoff error.\n"); + printf( +" Disabling exact arithmetic with the -X switch will cause a small\n"); + printf( +" improvement in speed and create the possibility (albeit small) that\n" +); + printf( +" Triangle will fail to produce a valid mesh. Not recommended.\n"); + printf( +" -z Numbers all items starting from zero (rather than one). Note that\n" +); + printf( +" this switch is normally overrided by the value used to number the\n"); + printf( +" first point of the input .node or .poly file. However, this switch\n" +); + printf(" is useful when calling Triangle from another program.\n"); + printf( +" -o2 Generates second-order subparametric elements with six nodes each.\n" +); + printf( +" -Y No new points on the boundary. This switch is useful when the mesh\n" +); + printf( +" boundary must be preserved so that it conforms to some adjacent\n"); + printf( +" mesh. Be forewarned that you will probably sacrifice some of the\n"); + printf( +" quality of the mesh; Triangle will try, but the resulting mesh may\n" +); + printf( +" contain triangles of poor aspect ratio. Works well if all the\n"); + printf( +" boundary points are closely spaced. Specify this switch twice\n"); + printf( +" (`-YY') to prevent all segment splitting, including internal\n"); + printf(" boundaries.\n"); + printf( +" -S Specifies the maximum number of Steiner points (points that are not\n" +); + printf( +" in the input, but are added to meet the constraints of minimum\n"); + printf( +" angle and maximum area). The default is to allow an unlimited\n"); + printf( +" number. If you specify this switch with no number after it,\n"); + printf( +" the limit is set to zero. Triangle always adds points at segment\n"); + printf( +" intersections, even if it needs to use more points than the limit\n"); + printf( +" you set. When Triangle inserts segments by splitting (-s), it\n"); + printf( +" always adds enough points to ensure that all the segments appear in\n" +); + printf( +" the triangulation, again ignoring the limit. Be forewarned that\n"); + printf( +" the -S switch may result in a conforming triangulation that is not\n" +); + printf( +" truly Delaunay, because Triangle may be forced to stop adding\n"); + printf( +" points when the mesh is in a state where a segment is non-Delaunay\n" +); + printf( +" and needs to be split. If so, Triangle will print a warning.\n"); + printf( +" -i Uses an incremental rather than divide-and-conquer algorithm to\n"); + printf( +" form a Delaunay triangulation. Try it if the divide-and-conquer\n"); + printf(" algorithm fails.\n"); + printf( +" -F Uses Steven Fortune's sweepline algorithm to form a Delaunay\n"); + printf( +" triangulation. Warning: does not use exact arithmetic for all\n"); + printf(" calculations. An exact result is not guaranteed.\n"); + printf( +" -l Uses only vertical cuts in the divide-and-conquer algorithm. By\n"); + printf( +" default, Triangle uses alternating vertical and horizontal cuts,\n"); + printf( +" which usually improve the speed except with point sets that are\n"); + printf( +" small or short and wide. This switch is primarily of theoretical\n"); + printf(" interest.\n"); + printf( +" -s Specifies that segments should be forced into the triangulation by\n" +); + printf( +" recursively splitting them at their midpoints, rather than by\n"); + printf( +" generating a constrained Delaunay triangulation. Segment splitting\n" +); + printf( +" is true to Ruppert's original algorithm, but can create needlessly\n" +); + printf(" small triangles near external small features.\n"); + printf( +" -C Check the consistency of the final mesh. Uses exact arithmetic for\n" +); + printf( +" checking, even if the -X switch is used. Useful if you suspect\n"); + printf(" Triangle is buggy.\n"); + printf( +" -Q Quiet: Suppresses all explanation of what Triangle is doing, unless\n" +); + printf(" an error occurs.\n"); + printf( +" -V Verbose: Gives detailed information about what Triangle is doing.\n"); + printf( +" Add more `V's for increasing amount of detail. `-V' gives\n"); + printf( +" information on algorithmic progress and more detailed statistics.\n"); + printf( +" `-VV' gives point-by-point details, and will print so much that\n"); + printf( +" Triangle will run much more slowly. `-VVV' gives information only\n" +); + printf(" a debugger could love.\n"); + printf(" -h Help: Displays these instructions.\n"); + printf("\n"); + printf("Definitions:\n"); + printf("\n"); + printf( +" A Delaunay triangulation of a point set is a triangulation whose vertices\n" +); + printf( +" are the point set, having the property that no point in the point set\n"); + printf( +" falls in the interior of the circumcircle (circle that passes through all\n" +); + printf(" three vertices) of any triangle in the triangulation.\n\n"); + printf( +" A Voronoi diagram of a point set is a subdivision of the plane into\n"); + printf( +" polygonal regions (some of which may be infinite), where each region is\n"); + printf( +" the set of points in the plane that are closer to some input point than\n"); + printf( +" to any other input point. (The Voronoi diagram is the geometric dual of\n" +); + printf(" the Delaunay triangulation.)\n\n"); + printf( +" A Planar Straight Line Graph (PSLG) is a collection of points and\n"); + printf( +" segments. Segments are simply edges, whose endpoints are points in the\n"); + printf( +" PSLG. The file format for PSLGs (.poly files) is described below.\n"); + printf("\n"); + printf( +" A constrained Delaunay triangulation of a PSLG is similar to a Delaunay\n"); + printf( +" triangulation, but each PSLG segment is present as a single edge in the\n"); + printf( +" triangulation. (A constrained Delaunay triangulation is not truly a\n"); + printf(" Delaunay triangulation.)\n\n"); + printf( +" A conforming Delaunay triangulation of a PSLG is a true Delaunay\n"); + printf( +" triangulation in which each PSLG segment may have been subdivided into\n"); + printf( +" several edges by the insertion of additional points. These inserted\n"); + printf( +" points are necessary to allow the segments to exist in the mesh while\n"); + printf(" maintaining the Delaunay property.\n\n"); + printf("File Formats:\n\n"); + printf( +" All files may contain comments prefixed by the character '#'. Points,\n"); + printf( +" triangles, edges, holes, and maximum area constraints must be numbered\n"); + printf( +" consecutively, starting from either 1 or 0. Whichever you choose, all\n"); + printf( +" input files must be consistent; if the nodes are numbered from 1, so must\n" +); + printf( +" be all other objects. Triangle automatically detects your choice while\n"); + printf( +" reading the .node (or .poly) file. (When calling Triangle from another\n"); + printf( +" program, use the -z switch if you wish to number objects from zero.)\n"); + printf(" Examples of these file formats are given below.\n\n"); + printf(" .node files:\n"); + printf( +" First line: <# of points> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Remaining lines: [attributes] [boundary marker]\n"); + printf("\n"); + printf( +" The attributes, which are typically floating-point values of physical\n"); + printf( +" quantities (such as mass or conductivity) associated with the nodes of\n" +); + printf( +" a finite element mesh, are copied unchanged to the output mesh. If -s,\n" +); + printf( +" -q, or -a is selected, each new Steiner point added to the mesh will\n"); + printf(" have attributes assigned to it by linear interpolation.\n\n"); + printf( +" If the fourth entry of the first line is `1', the last column of the\n"); + printf( +" remainder of the file is assumed to contain boundary markers. Boundary\n" +); + printf( +" markers are used to identify boundary points and points resting on PSLG\n" +); + printf( +" segments; a complete description appears in a section below. The .node\n" +); + printf( +" file produced by Triangle will contain boundary markers in the last\n"); + printf(" column unless they are suppressed by the -B switch.\n\n"); + printf(" .ele files:\n"); + printf( +" First line: <# of triangles> <# of attributes>\n"); + printf( +" Remaining lines: ... [attributes]\n" +); + printf("\n"); + printf( +" Points are indices into the corresponding .node file. The first three\n" +); + printf( +" points are the corners, and are listed in counterclockwise order around\n" +); + printf( +" each triangle. (The remaining points, if any, depend on the type of\n"); + printf( +" finite element used.) The attributes are just like those of .node\n"); + printf( +" files. Because there is no simple mapping from input to output\n"); + printf( +" triangles, an attempt is made to interpolate attributes, which may\n"); + printf( +" result in a good deal of diffusion of attributes among nearby triangles\n" +); + printf( +" as the triangulation is refined. Diffusion does not occur across\n"); + printf( +" segments, so attributes used to identify segment-bounded regions remain\n" +); + printf( +" intact. In output .ele files, all triangles have three points each\n"); + printf( +" unless the -o2 switch is used, in which case they have six, and the\n"); + printf( +" fourth, fifth, and sixth points lie on the midpoints of the edges\n"); + printf(" opposite the first, second, and third corners.\n\n"); + printf(" .poly files:\n"); + printf( +" First line: <# of points> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Following lines: [attributes] [boundary marker]\n"); + printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: [boundary marker]\n"); + printf(" One line: <# of holes>\n"); + printf(" Following lines: \n"); + printf( +" Optional line: <# of regional attributes and/or area constraints>\n"); + printf( +" Optional following lines: \n"); + printf("\n"); + printf( +" A .poly file represents a PSLG, as well as some additional information.\n" +); + printf( +" The first section lists all the points, and is identical to the format\n" +); + printf( +" of .node files. <# of points> may be set to zero to indicate that the\n" +); + printf( +" points are listed in a separate .node file; .poly files produced by\n"); + printf( +" Triangle always have this format. This has the advantage that a point\n" +); + printf( +" set may easily be triangulated with or without segments. (The same\n"); + printf( +" effect can be achieved, albeit using more disk space, by making a copy\n" +); + printf( +" of the .poly file with the extension .node; all sections of the file\n"); + printf(" but the first are ignored.)\n\n"); + printf( +" The second section lists the segments. Segments are edges whose\n"); + printf( +" presence in the triangulation is enforced. Each segment is specified\n"); + printf( +" by listing the indices of its two endpoints. This means that you must\n" +); + printf( +" include its endpoints in the point list. If -s, -q, and -a are not\n"); + printf( +" selected, Triangle will produce a constrained Delaunay triangulation,\n"); + printf( +" in which each segment appears as a single edge in the triangulation.\n"); + printf( +" If -q or -a is selected, Triangle will produce a conforming Delaunay\n"); + printf( +" triangulation, in which segments may be subdivided into smaller edges.\n" +); + printf(" Each segment, like each point, may have a boundary marker.\n\n"); + printf( +" The third section lists holes (and concavities, if -c is selected) in\n"); + printf( +" the triangulation. Holes are specified by identifying a point inside\n"); + printf( +" each hole. After the triangulation is formed, Triangle creates holes\n"); + printf( +" by eating triangles, spreading out from each hole point until its\n"); + printf( +" progress is blocked by PSLG segments; you must be careful to enclose\n"); + printf( +" each hole in segments, or your whole triangulation may be eaten away.\n"); + printf( +" If the two triangles abutting a segment are eaten, the segment itself\n"); + printf( +" is also eaten. Do not place a hole directly on a segment; if you do,\n"); + printf(" Triangle will choose one side of the segment arbitrarily.\n\n"); + printf( +" The optional fourth section lists regional attributes (to be assigned\n"); + printf( +" to all triangles in a region) and regional constraints on the maximum\n"); + printf( +" triangle area. Triangle will read this section only if the -A switch\n"); + printf( +" is used or the -a switch is used without a number following it, and the\n" +); + printf( +" -r switch is not used. Regional attributes and area constraints are\n"); + printf( +" propagated in the same manner as holes; you specify a point for each\n"); + printf( +" attribute and/or constraint, and the attribute and/or constraint will\n"); + printf( +" affect the whole region (bounded by segments) containing the point. If\n" +); + printf( +" two values are written on a line after the x and y coordinate, the\n"); + printf( +" former is assumed to be a regional attribute (but will only be applied\n" +); + printf( +" if the -A switch is selected), and the latter is assumed to be a\n"); + printf( +" regional area constraint (but will only be applied if the -a switch is\n" +); + printf( +" selected). You may also specify just one value after the coordinates,\n" +); + printf( +" which can serve as both an attribute and an area constraint, depending\n" +); + printf( +" on the choice of switches. If you are using the -A and -a switches\n"); + printf( +" simultaneously and wish to assign an attribute to some region without\n"); + printf(" imposing an area constraint, use a negative maximum area.\n\n"); + printf( +" When a triangulation is created from a .poly file, you must either\n"); + printf( +" enclose the entire region to be triangulated in PSLG segments, or\n"); + printf( +" use the -c switch, which encloses the convex hull of the input point\n"); + printf( +" set. If you do not use the -c switch, Triangle will eat all triangles\n" +); + printf( +" on the outer boundary that are not protected by segments; if you are\n"); + printf( +" not careful, your whole triangulation may be eaten away. If you do\n"); + printf( +" use the -c switch, you can still produce concavities by appropriate\n"); + printf(" placement of holes just inside the convex hull.\n\n"); + printf( +" An ideal PSLG has no intersecting segments, nor any points that lie\n"); + printf( +" upon segments (except, of course, the endpoints of each segment.) You\n" +); + printf( +" aren't required to make your .poly files ideal, but you should be aware\n" +); + printf( +" of what can go wrong. Segment intersections are relatively safe -\n"); + printf( +" Triangle will calculate the intersection points for you and add them to\n" +); + printf( +" the triangulation - as long as your machine's floating-point precision\n" +); + printf( +" doesn't become a problem. You are tempting the fates if you have three\n" +); + printf( +" segments that cross at the same location, and expect Triangle to figure\n" +); + printf( +" out where the intersection point is. Thanks to floating-point roundoff\n" +); + printf( +" error, Triangle will probably decide that the three segments intersect\n" +); + printf( +" at three different points, and you will find a minuscule triangle in\n"); + printf( +" your output - unless Triangle tries to refine the tiny triangle, uses\n"); + printf( +" up the last bit of machine precision, and fails to terminate at all.\n"); + printf( +" You're better off putting the intersection point in the input files,\n"); + printf( +" and manually breaking up each segment into two. Similarly, if you\n"); + printf( +" place a point at the middle of a segment, and hope that Triangle will\n"); + printf( +" break up the segment at that point, you might get lucky. On the other\n" +); + printf( +" hand, Triangle might decide that the point doesn't lie precisely on the\n" +); + printf( +" line, and you'll have a needle-sharp triangle in your output - or a lot\n" +); + printf(" of tiny triangles if you're generating a quality mesh.\n\n"); + printf( +" When Triangle reads a .poly file, it also writes a .poly file, which\n"); + printf( +" includes all edges that are part of input segments. If the -c switch\n"); + printf( +" is used, the output .poly file will also include all of the edges on\n"); + printf( +" the convex hull. Hence, the output .poly file is useful for finding\n"); + printf( +" edges associated with input segments and setting boundary conditions in\n" +); + printf( +" finite element simulations. More importantly, you will need it if you\n" +); + printf( +" plan to refine the output mesh, and don't want segments to be missing\n"); + printf(" in later triangulations.\n\n"); + printf(" .area files:\n"); + printf(" First line: <# of triangles>\n"); + printf(" Following lines: \n\n"); + printf( +" An .area file associates with each triangle a maximum area that is used\n" +); + printf( +" for mesh refinement. As with other file formats, every triangle must\n"); + printf( +" be represented, and they must be numbered consecutively. A triangle\n"); + printf( +" may be left unconstrained by assigning it a negative maximum area.\n"); + printf("\n"); + printf(" .edge files:\n"); + printf(" First line: <# of edges> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: [boundary marker]\n"); + printf("\n"); + printf( +" Endpoints are indices into the corresponding .node file. Triangle can\n" +); + printf( +" produce .edge files (use the -e switch), but cannot read them. The\n"); + printf( +" optional column of boundary markers is suppressed by the -B switch.\n"); + printf("\n"); + printf( +" In Voronoi diagrams, one also finds a special kind of edge that is an\n"); + printf( +" infinite ray with only one endpoint. For these edges, a different\n"); + printf(" format is used:\n\n"); + printf(" -1 \n\n"); + printf( +" The `direction' is a floating-point vector that indicates the direction\n" +); + printf(" of the infinite ray.\n\n"); + printf(" .neigh files:\n"); + printf( +" First line: <# of triangles> <# of neighbors per triangle (always 3)>\n" +); + printf( +" Following lines: \n"); + printf("\n"); + printf( +" Neighbors are indices into the corresponding .ele file. An index of -1\n" +); + printf( +" indicates a mesh boundary, and therefore no neighbor. Triangle can\n"); + printf( +" produce .neigh files (use the -n switch), but cannot read them.\n"); + printf("\n"); + printf( +" The first neighbor of triangle i is opposite the first corner of\n"); + printf(" triangle i, and so on.\n\n"); + printf("Boundary Markers:\n\n"); + printf( +" Boundary markers are tags used mainly to identify which output points and\n" +); + printf( +" edges are associated with which PSLG segment, and to identify which\n"); + printf( +" points and edges occur on a boundary of the triangulation. A common use\n" +); + printf( +" is to determine where boundary conditions should be applied to a finite\n"); + printf( +" element mesh. You can prevent boundary markers from being written into\n"); + printf(" files produced by Triangle by using the -B switch.\n\n"); + printf( +" The boundary marker associated with each segment in an output .poly file\n" +); + printf(" or edge in an output .edge file is chosen as follows:\n"); + printf( +" - If an output edge is part or all of a PSLG segment with a nonzero\n"); + printf( +" boundary marker, then the edge is assigned the same marker.\n"); + printf( +" - Otherwise, if the edge occurs on a boundary of the triangulation\n"); + printf( +" (including boundaries of holes), then the edge is assigned the marker\n" +); + printf(" one (1).\n"); + printf(" - Otherwise, the edge is assigned the marker zero (0).\n"); + printf( +" The boundary marker associated with each point in an output .node file is\n" +); + printf(" chosen as follows:\n"); + printf( +" - If a point is assigned a nonzero boundary marker in the input file,\n"); + printf( +" then it is assigned the same marker in the output .node file.\n"); + printf( +" - Otherwise, if the point lies on a PSLG segment (including the\n"); + printf( +" segment's endpoints) with a nonzero boundary marker, then the point\n"); + printf( +" is assigned the same marker. If the point lies on several such\n"); + printf(" segments, one of the markers is chosen arbitrarily.\n"); + printf( +" - Otherwise, if the point occurs on a boundary of the triangulation,\n"); + printf(" then the point is assigned the marker one (1).\n"); + printf(" - Otherwise, the point is assigned the marker zero (0).\n"); + printf("\n"); + printf( +" If you want Triangle to determine for you which points and edges are on\n"); + printf( +" the boundary, assign them the boundary marker zero (or use no markers at\n" +); + printf( +" all) in your input files. Alternatively, you can mark some of them and\n"); + printf(" leave others marked zero, allowing Triangle to label them.\n\n"); + printf("Triangulation Iteration Numbers:\n\n"); + printf( +" Because Triangle can read and refine its own triangulations, input\n"); + printf( +" and output files have iteration numbers. For instance, Triangle might\n"); + printf( +" read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the\n"); + printf( +" triangulation, and output the files mesh.4.node, mesh.4.ele, and\n"); + printf(" mesh.4.poly. Files with no iteration number are treated as if\n"); + printf( +" their iteration number is zero; hence, Triangle might read the file\n"); + printf( +" points.node, triangulate it, and produce the files points.1.node and\n"); + printf(" points.1.ele.\n\n"); + printf( +" Iteration numbers allow you to create a sequence of successively finer\n"); + printf( +" meshes suitable for multigrid methods. They also allow you to produce a\n" +); + printf( +" sequence of meshes using error estimate-driven mesh refinement.\n"); + printf("\n"); + printf( +" If you're not using refinement or quality meshing, and you don't like\n"); + printf( +" iteration numbers, use the -I switch to disable them. This switch will\n"); + printf( +" also disable output of .node and .poly files to prevent your input files\n" +); + printf( +" from being overwritten. (If the input is a .poly file that contains its\n" +); + printf(" own points, a .node file will be written.)\n\n"); + printf("Examples of How to Use Triangle:\n\n"); + printf( +" `triangle dots' will read points from dots.node, and write their Delaunay\n" +); + printf( +" triangulation to dots.1.node and dots.1.ele. (dots.1.node will be\n"); + printf( +" identical to dots.node.) `triangle -I dots' writes the triangulation to\n" +); + printf( +" dots.ele instead. (No additional .node file is needed, so none is\n"); + printf(" written.)\n\n"); + printf( +" `triangle -pe object.1' will read a PSLG from object.1.poly (and possibly\n" +); + printf( +" object.1.node, if the points are omitted from object.1.poly) and write\n"); + printf(" their constrained Delaunay triangulation to object.2.node and\n"); + printf( +" object.2.ele. The segments will be copied to object.2.poly, and all\n"); + printf(" edges will be written to object.2.edge.\n\n"); + printf( +" `triangle -pq31.5a.1 object' will read a PSLG from object.poly (and\n"); + printf( +" possibly object.node), generate a mesh whose angles are all greater than\n" +); + printf( +" 31.5 degrees and whose triangles all have area smaller than 0.1, and\n"); + printf( +" write the mesh to object.1.node and object.1.ele. Each segment may have\n" +); + printf( +" been broken up into multiple edges; the resulting constrained edges are\n"); + printf(" written to object.1.poly.\n\n"); + printf( +" Here is a sample file `box.poly' describing a square with a square hole:\n" +); + printf("\n"); + printf( +" # A box with eight points in 2D, no attributes, one boundary marker.\n"); + printf(" 8 2 0 1\n"); + printf(" # Outer box has these vertices:\n"); + printf(" 1 0 0 0\n"); + printf(" 2 0 3 0\n"); + printf(" 3 3 0 0\n"); + printf(" 4 3 3 33 # A special marker for this point.\n"); + printf(" # Inner square has these vertices:\n"); + printf(" 5 1 1 0\n"); + printf(" 6 1 2 0\n"); + printf(" 7 2 1 0\n"); + printf(" 8 2 2 0\n"); + printf(" # Five segments with boundary markers.\n"); + printf(" 5 1\n"); + printf(" 1 1 2 5 # Left side of outer box.\n"); + printf(" 2 5 7 0 # Segments 2 through 5 enclose the hole.\n"); + printf(" 3 7 8 0\n"); + printf(" 4 8 6 10\n"); + printf(" 5 6 5 0\n"); + printf(" # One hole in the middle of the inner square.\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n\n"); + printf( +" Note that some segments are missing from the outer square, so one must\n"); + printf( +" use the `-c' switch. After `triangle -pqc box.poly', here is the output\n" +); + printf( +" file `box.1.node', with twelve points. The last four points were added\n"); + printf( +" to meet the angle constraint. Points 1, 2, and 9 have markers from\n"); + printf( +" segment 1. Points 6 and 8 have markers from segment 4. All the other\n"); + printf( +" points but 4 have been marked to indicate that they lie on a boundary.\n"); + printf("\n"); + printf(" 12 2 0 1\n"); + printf(" 1 0 0 5\n"); + printf(" 2 0 3 5\n"); + printf(" 3 3 0 1\n"); + printf(" 4 3 3 33\n"); + printf(" 5 1 1 1\n"); + printf(" 6 1 2 10\n"); + printf(" 7 2 1 1\n"); + printf(" 8 2 2 10\n"); + printf(" 9 0 1.5 5\n"); + printf(" 10 1.5 0 1\n"); + printf(" 11 3 1.5 1\n"); + printf(" 12 1.5 3 1\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf(" Here is the output file `box.1.ele', with twelve triangles.\n\n"); + printf(" 12 3 0\n"); + printf(" 1 5 6 9\n"); + printf(" 2 10 3 7\n"); + printf(" 3 6 8 12\n"); + printf(" 4 9 1 5\n"); + printf(" 5 6 2 9\n"); + printf(" 6 7 3 11\n"); + printf(" 7 11 4 8\n"); + printf(" 8 7 5 10\n"); + printf(" 9 12 2 6\n"); + printf(" 10 8 7 11\n"); + printf(" 11 5 1 10\n"); + printf(" 12 8 4 12\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf( +" Here is the output file `box.1.poly'. Note that segments have been added\n" +); + printf( +" to represent the convex hull, and some segments have been split by newly\n" +); + printf( +" added points. Note also that <# of points> is set to zero to indicate\n"); + printf(" that the points should be read from the .node file.\n\n"); + printf(" 0 2 0 1\n"); + printf(" 12 1\n"); + printf(" 1 1 9 5\n"); + printf(" 2 5 7 1\n"); + printf(" 3 8 7 1\n"); + printf(" 4 6 8 10\n"); + printf(" 5 5 6 1\n"); + printf(" 6 3 10 1\n"); + printf(" 7 4 11 1\n"); + printf(" 8 2 12 1\n"); + printf(" 9 9 2 5\n"); + printf(" 10 10 1 1\n"); + printf(" 11 11 3 1\n"); + printf(" 12 12 4 1\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf("Refinement and Area Constraints:\n\n"); + printf( +" The -r switch causes a mesh (.node and .ele files) to be read and\n"); + printf( +" refined. If the -p switch is also used, a .poly file is read and used to\n" +); + printf( +" specify edges that are constrained and cannot be eliminated (although\n"); + printf( +" they can be divided into smaller edges) by the refinement process.\n"); + printf("\n"); + printf( +" When you refine a mesh, you generally want to impose tighter quality\n"); + printf( +" constraints. One way to accomplish this is to use -q with a larger\n"); + printf( +" angle, or -a followed by a smaller area than you used to generate the\n"); + printf( +" mesh you are refining. Another way to do this is to create an .area\n"); + printf( +" file, which specifies a maximum area for each triangle, and use the -a\n"); + printf( +" switch (without a number following). Each triangle's area constraint is\n" +); + printf( +" applied to that triangle. Area constraints tend to diffuse as the mesh\n"); + printf( +" is refined, so if there are large variations in area constraint between\n"); + printf(" adjacent triangles, you may not get the results you want.\n\n"); + printf( +" If you are refining a mesh composed of linear (three-node) elements, the\n" +); + printf( +" output mesh will contain all the nodes present in the input mesh, in the\n" +); + printf( +" same order, with new nodes added at the end of the .node file. However,\n" +); + printf( +" there is no guarantee that each output element is contained in a single\n"); + printf( +" input element. Often, output elements will overlap two input elements,\n"); + printf( +" and input edges are not present in the output mesh. Hence, a sequence of\n" +); + printf( +" refined meshes will form a hierarchy of nodes, but not a hierarchy of\n"); + printf( +" elements. If you a refining a mesh of higher-order elements, the\n"); + printf( +" hierarchical property applies only to the nodes at the corners of an\n"); + printf(" element; other nodes may not be present in the refined mesh.\n\n"); + printf( +" It is important to understand that maximum area constraints in .poly\n"); + printf( +" files are handled differently from those in .area files. A maximum area\n" +); + printf( +" in a .poly file applies to the whole (segment-bounded) region in which a\n" +); + printf( +" point falls, whereas a maximum area in an .area file applies to only one\n" +); + printf( +" triangle. Area constraints in .poly files are used only when a mesh is\n"); + printf( +" first generated, whereas area constraints in .area files are used only to\n" +); + printf( +" refine an existing mesh, and are typically based on a posteriori error\n"); + printf( +" estimates resulting from a finite element simulation on that mesh.\n"); + printf("\n"); + printf( +" `triangle -rq25 object.1' will read object.1.node and object.1.ele, then\n" +); + printf( +" refine the triangulation to enforce a 25 degree minimum angle, and then\n"); + printf( +" write the refined triangulation to object.2.node and object.2.ele.\n"); + printf("\n"); + printf( +" `triangle -rpaa6.2 z.3' will read z.3.node, z.3.ele, z.3.poly, and\n"); + printf( +" z.3.area. After reconstructing the mesh and its segments, Triangle will\n" +); + printf( +" refine the mesh so that no triangle has area greater than 6.2, and\n"); + printf( +" furthermore the triangles satisfy the maximum area constraints in\n"); + printf( +" z.3.area. The output is written to z.4.node, z.4.ele, and z.4.poly.\n"); + printf("\n"); + printf( +" The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1\n"); + printf( +" x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,\n"); + printf(" suitable for multigrid.\n\n"); + printf("Convex Hulls and Mesh Boundaries:\n\n"); + printf( +" If the input is a point set (rather than a PSLG), Triangle produces its\n"); + printf( +" convex hull as a by-product in the output .poly file if you use the -c\n"); + printf( +" switch. There are faster algorithms for finding a two-dimensional convex\n" +); + printf( +" hull than triangulation, of course, but this one comes for free. If the\n" +); + printf( +" input is an unconstrained mesh (you are using the -r switch but not the\n"); + printf( +" -p switch), Triangle produces a list of its boundary edges (including\n"); + printf(" hole boundaries) as a by-product if you use the -c switch.\n\n"); + printf("Voronoi Diagrams:\n\n"); + printf( +" The -v switch produces a Voronoi diagram, in files suffixed .v.node and\n"); + printf( +" .v.edge. For example, `triangle -v points' will read points.node,\n"); + printf( +" produce its Delaunay triangulation in points.1.node and points.1.ele,\n"); + printf( +" and produce its Voronoi diagram in points.1.v.node and points.1.v.edge.\n"); + printf( +" The .v.node file contains a list of all Voronoi vertices, and the .v.edge\n" +); + printf( +" file contains a list of all Voronoi edges, some of which may be infinite\n" +); + printf( +" rays. (The choice of filenames makes it easy to run the set of Voronoi\n"); + printf(" vertices through Triangle, if so desired.)\n\n"); + printf( +" This implementation does not use exact arithmetic to compute the Voronoi\n" +); + printf( +" vertices, and does not check whether neighboring vertices are identical.\n" +); + printf( +" Be forewarned that if the Delaunay triangulation is degenerate or\n"); + printf( +" near-degenerate, the Voronoi diagram may have duplicate points, crossing\n" +); + printf( +" edges, or infinite rays whose direction vector is zero. Also, if you\n"); + printf( +" generate a constrained (as opposed to conforming) Delaunay triangulation,\n" +); + printf( +" or if the triangulation has holes, the corresponding Voronoi diagram is\n"); + printf(" likely to have crossing edges and unlikely to make sense.\n\n"); + printf("Mesh Topology:\n\n"); + printf( +" You may wish to know which triangles are adjacent to a certain Delaunay\n"); + printf( +" edge in an .edge file, which Voronoi regions are adjacent to a certain\n"); + printf( +" Voronoi edge in a .v.edge file, or which Voronoi regions are adjacent to\n" +); + printf( +" each other. All of this information can be found by cross-referencing\n"); + printf( +" output files with the recollection that the Delaunay triangulation and\n"); + printf(" the Voronoi diagrams are planar duals.\n\n"); + printf( +" Specifically, edge i of an .edge file is the dual of Voronoi edge i of\n"); + printf( +" the corresponding .v.edge file, and is rotated 90 degrees counterclock-\n"); + printf( +" wise from the Voronoi edge. Triangle j of an .ele file is the dual of\n"); + printf( +" vertex j of the corresponding .v.node file; and Voronoi region k is the\n"); + printf(" dual of point k of the corresponding .node file.\n\n"); + printf( +" Hence, to find the triangles adjacent to a Delaunay edge, look at the\n"); + printf( +" vertices of the corresponding Voronoi edge; their dual triangles are on\n"); + printf( +" the left and right of the Delaunay edge, respectively. To find the\n"); + printf( +" Voronoi regions adjacent to a Voronoi edge, look at the endpoints of the\n" +); + printf( +" corresponding Delaunay edge; their dual regions are on the right and left\n" +); + printf( +" of the Voronoi edge, respectively. To find which Voronoi regions are\n"); + printf(" adjacent to each other, just read the list of Delaunay edges.\n"); + printf("\n"); + printf("Statistics:\n"); + printf("\n"); + printf( +" After generating a mesh, Triangle prints a count of the number of points,\n" +); + printf( +" triangles, edges, boundary edges, and segments in the output mesh. If\n"); + printf( +" you've forgotten the statistics for an existing mesh, the -rNEP switches\n" +); + printf( +" (or -rpNEP if you've got a .poly file for the existing mesh) will\n"); + printf(" regenerate these statistics without writing any output.\n\n"); + printf( +" The -V switch produces extended statistics, including a rough estimate\n"); + printf( +" of memory use and a histogram of triangle aspect ratios and angles in the\n" +); + printf(" mesh.\n\n"); + printf("Exact Arithmetic:\n\n"); + printf( +" Triangle uses adaptive exact arithmetic to perform what computational\n"); + printf( +" geometers call the `orientation' and `incircle' tests. If the floating-\n" +); + printf( +" point arithmetic of your machine conforms to the IEEE 754 standard (as\n"); + printf( +" most workstations do), and does not use extended precision internal\n"); + printf( +" registers, then your output is guaranteed to be an absolutely true\n"); + printf(" Delaunay or conforming Delaunay triangulation, roundoff error\n"); + printf( +" notwithstanding. The word `adaptive' implies that these arithmetic\n"); + printf( +" routines compute the result only to the precision necessary to guarantee\n" +); + printf( +" correctness, so they are usually nearly as fast as their approximate\n"); + printf( +" counterparts. The exact tests can be disabled with the -X switch. On\n"); + printf( +" most inputs, this switch will reduce the computation time by about eight\n" +); + printf( +" percent - it's not worth the risk. There are rare difficult inputs\n"); + printf( +" (having many collinear and cocircular points), however, for which the\n"); + printf( +" difference could be a factor of two. These are precisely the inputs most\n" +); + printf(" likely to cause errors if you use the -X switch.\n\n"); + printf( +" Unfortunately, these routines don't solve every numerical problem. Exact\n" +); + printf( +" arithmetic is not used to compute the positions of points, because the\n"); + printf( +" bit complexity of point coordinates would grow without bound. Hence,\n"); + printf( +" segment intersections aren't computed exactly; in very unusual cases,\n"); + printf( +" roundoff error in computing an intersection point might actually lead to\n" +); + printf( +" an inverted triangle and an invalid triangulation. (This is one reason\n"); + printf( +" to compute your own intersection points in your .poly files.) Similarly,\n" +); + printf( +" exact arithmetic is not used to compute the vertices of the Voronoi\n"); + printf(" diagram.\n\n"); + printf( +" Underflow and overflow can also cause difficulties; the exact arithmetic\n" +); + printf( +" routines do not ameliorate out-of-bounds exponents, which can arise\n"); + printf( +" during the orientation and incircle tests. As a rule of thumb, you\n"); + printf( +" should ensure that your input values are within a range such that their\n"); + printf( +" third powers can be taken without underflow or overflow. Underflow can\n"); + printf( +" silently prevent the tests from being performed exactly, while overflow\n"); + printf(" will typically cause a floating exception.\n\n"); + printf("Calling Triangle from Another Program:\n\n"); + printf(" Read the file triangle.h for details.\n\n"); + printf("Troubleshooting:\n\n"); + printf(" Please read this section before mailing me bugs.\n\n"); + printf(" `My output mesh has no triangles!'\n\n"); + printf( +" If you're using a PSLG, you've probably failed to specify a proper set\n" +); + printf( +" of bounding segments, or forgotten to use the -c switch. Or you may\n"); + printf( +" have placed a hole badly. To test these possibilities, try again with\n" +); + printf( +" the -c and -O switches. Alternatively, all your input points may be\n"); + printf( +" collinear, in which case you can hardly expect to triangulate them.\n"); + printf("\n"); + printf(" `Triangle doesn't terminate, or just crashes.'\n"); + printf("\n"); + printf( +" Bad things can happen when triangles get so small that the distance\n"); + printf( +" between their vertices isn't much larger than the precision of your\n"); + printf( +" machine's arithmetic. If you've compiled Triangle for single-precision\n" +); + printf( +" arithmetic, you might do better by recompiling it for double-precision.\n" +); + printf( +" Then again, you might just have to settle for more lenient constraints\n" +); + printf( +" on the minimum angle and the maximum area than you had planned.\n"); + printf("\n"); + printf( +" You can minimize precision problems by ensuring that the origin lies\n"); + printf( +" inside your point set, or even inside the densest part of your\n"); + printf( +" mesh. On the other hand, if you're triangulating an object whose x\n"); + printf( +" coordinates all fall between 6247133 and 6247134, you're not leaving\n"); + printf(" much floating-point precision for Triangle to work with.\n\n"); + printf( +" Precision problems can occur covertly if the input PSLG contains two\n"); + printf( +" segments that meet (or intersect) at a very small angle, or if such an\n" +); + printf( +" angle is introduced by the -c switch, which may occur if a point lies\n"); + printf( +" ever-so-slightly inside the convex hull, and is connected by a PSLG\n"); + printf( +" segment to a point on the convex hull. If you don't realize that a\n"); + printf( +" small angle is being formed, you might never discover why Triangle is\n"); + printf( +" crashing. To check for this possibility, use the -S switch (with an\n"); + printf( +" appropriate limit on the number of Steiner points, found by trial-and-\n" +); + printf( +" error) to stop Triangle early, and view the output .poly file with\n"); + printf( +" Show Me (described below). Look carefully for small angles between\n"); + printf( +" segments; zoom in closely, as such segments might look like a single\n"); + printf(" segment from a distance.\n\n"); + printf( +" If some of the input values are too large, Triangle may suffer a\n"); + printf( +" floating exception due to overflow when attempting to perform an\n"); + printf( +" orientation or incircle test. (Read the section on exact arithmetic\n"); + printf( +" above.) Again, I recommend compiling Triangle for double (rather\n"); + printf(" than single) precision arithmetic.\n\n"); + printf( +" `The numbering of the output points doesn't match the input points.'\n"); + printf("\n"); + printf( +" You may have eaten some of your input points with a hole, or by placing\n" +); + printf(" them outside the area enclosed by segments.\n\n"); + printf( +" `Triangle executes without incident, but when I look at the resulting\n"); + printf( +" mesh, it has overlapping triangles or other geometric inconsistencies.'\n"); + printf("\n"); + printf( +" If you select the -X switch, Triangle's divide-and-conquer Delaunay\n"); + printf( +" triangulation algorithm occasionally makes mistakes due to floating-\n"); + printf( +" point roundoff error. Although these errors are rare, don't use the -X\n" +); + printf(" switch. If you still have problems, please report the bug.\n"); + printf("\n"); + printf( +" Strange things can happen if you've taken liberties with your PSLG. Do\n"); + printf( +" you have a point lying in the middle of a segment? Triangle sometimes\n"); + printf( +" copes poorly with that sort of thing. Do you want to lay out a collinear\n" +); + printf( +" row of evenly spaced, segment-connected points? Have you simply defined\n" +); + printf( +" one long segment connecting the leftmost point to the rightmost point,\n"); + printf( +" and a bunch of points lying along it? This method occasionally works,\n"); + printf( +" especially with horizontal and vertical lines, but often it doesn't, and\n" +); + printf( +" you'll have to connect each adjacent pair of points with a separate\n"); + printf(" segment. If you don't like it, tough.\n\n"); + printf( +" Furthermore, if you have segments that intersect other than at their\n"); + printf( +" endpoints, try not to let the intersections fall extremely close to PSLG\n" +); + printf(" points or each other.\n\n"); + printf( +" If you have problems refining a triangulation not produced by Triangle:\n"); + printf( +" Are you sure the triangulation is geometrically valid? Is it formatted\n"); + printf( +" correctly for Triangle? Are the triangles all listed so the first three\n" +); + printf(" points are their corners in counterclockwise order?\n\n"); + printf("Show Me:\n\n"); + printf( +" Triangle comes with a separate program named `Show Me', whose primary\n"); + printf( +" purpose is to draw meshes on your screen or in PostScript. Its secondary\n" +); + printf( +" purpose is to check the validity of your input files, and do so more\n"); + printf( +" thoroughly than Triangle does. Show Me requires that you have the X\n"); + printf( +" Windows system. If you didn't receive Show Me with Triangle, complain to\n" +); + printf(" whomever you obtained Triangle from, then send me mail.\n\n"); + printf("Triangle on the Web:\n\n"); + printf( +" To see an illustrated, updated version of these instructions, check out\n"); + printf("\n"); + printf(" http://www.cs.cmu.edu/~quake/triangle.html\n"); + printf("\n"); + printf("A Brief Plea:\n"); + printf("\n"); + printf( +" If you use Triangle, and especially if you use it to accomplish real\n"); + printf( +" work, I would like very much to hear from you. A short letter or email\n"); + printf( +" (to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to\n"); + printf( +" me. The more people I know are using this program, the more easily I can\n" +); + printf( +" justify spending time on improvements and on the three-dimensional\n"); + printf( +" successor to Triangle, which in turn will benefit you. Also, I can put\n"); + printf( +" you on a list to receive email whenever a new version of Triangle is\n"); + printf(" available.\n\n"); + printf( +" If you use a mesh generated by Triangle in a publication, please include\n" +); + printf(" an acknowledgment as well.\n\n"); + printf("Research credit:\n\n"); + printf( +" Of course, I can take credit for only a fraction of the ideas that made\n"); + printf( +" this mesh generator possible. Triangle owes its existence to the efforts\n" +); + printf( +" of many fine computational geometers and other researchers, including\n"); + printf( +" Marshall Bern, L. Paul Chew, Boris Delaunay, Rex A. Dwyer, David\n"); + printf( +" Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E. Knuth, C. L.\n"); + printf( +" Lawson, Der-Tsai Lee, Ernst P. Mucke, Douglas M. Priest, Jim Ruppert,\n"); + printf( +" Isaac Saias, Bruce J. Schachter, Micha Sharir, Jorge Stolfi, Christopher\n" +); + printf( +" J. Van Wyk, David F. Watson, and Binhai Zhu. See the comments at the\n"); + printf(" beginning of the source code for references.\n\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* internalerror() Ask the user to send me the defective product. Exit. */ +/* */ +/*****************************************************************************/ + +void internalerror() +{ + printf(" Please report this bug to jrs@cs.cmu.edu\n"); + printf(" Include the message above, your input data set, and the exact\n"); + printf(" command line you used to run Triangle.\n"); + exit(1); +} + +/*****************************************************************************/ +/* */ +/* parsecommandline() Read the command line, identify switches, and set */ +/* up options and file names. */ +/* */ +/* The effects of this routine are felt entirely through global variables. */ +/* */ +/*****************************************************************************/ + +void parsecommandline(argc, argv) +int argc; +char **argv; +{ +#ifdef TRILIBRARY +#define STARTINDEX 0 +#else /* not TRILIBRARY */ +#define STARTINDEX 1 + int increment; + int meshnumber; +#endif /* not TRILIBRARY */ + int i, j; +#ifndef CDT_ONLY + int k; + char workstring[FILENAMESIZE]; +#endif + + poly = refine = quality = vararea = fixedarea = regionattrib = convex = 0; + firstnumber = 1; + edgesout = voronoi = neighbors = geomview = 0; + nobound = nopolywritten = nonodewritten = noelewritten = noiterationnum = 0; + noholes = noexact = 0; + incremental = sweepline = 0; + dwyer = 1; + splitseg = 0; + docheck = 0; + nobisect = 0; + steiner = -1; + order = 1; + minangle = 0.0; + maxarea = -1.0; + quiet = verbose = 0; +#ifndef TRILIBRARY + innodefilename[0] = '\0'; +#endif /* not TRILIBRARY */ + + for (i = STARTINDEX; i < argc; i++) { +#ifndef TRILIBRARY + if (argv[i][0] == '-') { +#endif /* not TRILIBRARY */ + for (j = STARTINDEX; argv[i][j] != '\0'; j++) { + if (argv[i][j] == 'p') { + poly = 1; + } +#ifndef CDT_ONLY + if (argv[i][j] == 'r') { + refine = 1; + } + if (argv[i][j] == 'q') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + minangle = (REAL) strtod(workstring, (char **) NULL); + } else { + minangle = 20.0; + } + } + if (argv[i][j] == 'a') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + fixedarea = 1; + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + maxarea = (REAL) strtod(workstring, (char **) NULL); + if (maxarea <= 0.0) { + printf("Error: Maximum area must be greater than zero.\n"); + exit(1); + } + } else { + vararea = 1; + } + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'A') { + regionattrib = 1; + } + if (argv[i][j] == 'c') { + convex = 1; + } + if (argv[i][j] == 'z') { + firstnumber = 0; + } + if (argv[i][j] == 'e') { + edgesout = 1; + } + if (argv[i][j] == 'v') { + voronoi = 1; + } + if (argv[i][j] == 'n') { + neighbors = 1; + } + if (argv[i][j] == 'g') { + geomview = 1; + } + if (argv[i][j] == 'B') { + nobound = 1; + } + if (argv[i][j] == 'P') { + nopolywritten = 1; + } + if (argv[i][j] == 'N') { + nonodewritten = 1; + } + if (argv[i][j] == 'E') { + noelewritten = 1; + } +#ifndef TRILIBRARY + if (argv[i][j] == 'I') { + noiterationnum = 1; + } +#endif /* not TRILIBRARY */ + if (argv[i][j] == 'O') { + noholes = 1; + } + if (argv[i][j] == 'X') { + noexact = 1; + } + if (argv[i][j] == 'o') { + if (argv[i][j + 1] == '2') { + j++; + order = 2; + } + } +#ifndef CDT_ONLY + if (argv[i][j] == 'Y') { + nobisect++; + } + if (argv[i][j] == 'S') { + steiner = 0; + while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + j++; + steiner = steiner * 10 + (int) (argv[i][j] - '0'); + } + } +#endif /* not CDT_ONLY */ +#ifndef REDUCED + if (argv[i][j] == 'i') { + incremental = 1; + } + if (argv[i][j] == 'F') { + sweepline = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'l') { + dwyer = 0; + } +#ifndef REDUCED +#ifndef CDT_ONLY + if (argv[i][j] == 's') { + splitseg = 1; + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'C') { + docheck = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'Q') { + quiet = 1; + } + if (argv[i][j] == 'V') { + verbose++; + } +#ifndef TRILIBRARY + if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || + (argv[i][j] == '?')) { + info(); + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + } else { + strncpy(innodefilename, argv[i], FILENAMESIZE - 1); + innodefilename[FILENAMESIZE - 1] = '\0'; + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + if (innodefilename[0] == '\0') { + syntax(); + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".node")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".poly")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + poly = 1; + } +#ifndef CDT_ONLY + if (!strcmp(&innodefilename[strlen(innodefilename) - 4], ".ele")) { + innodefilename[strlen(innodefilename) - 4] = '\0'; + refine = 1; + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".area")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + refine = 1; + quality = 1; + vararea = 1; + } +#endif /* not CDT_ONLY */ +#endif /* not TRILIBRARY */ + steinerleft = steiner; + useshelles = poly || refine || quality || convex; + goodangle = (REAL)cos(minangle * PI / 180.0); + goodangle *= goodangle; + if (refine && noiterationnum) { + printf( + "Error: You cannot use the -I switch when refining a triangulation.\n"); + exit(1); + } + /* Be careful not to allocate space for element area constraints that */ + /* will never be assigned any value (other than the default -1.0). */ + if (!refine && !poly) { + vararea = 0; + } + /* Be careful not to add an extra attribute to each element unless the */ + /* input supports it (PSLG in, but not refining a preexisting mesh). */ + if (refine || !poly) { + regionattrib = 0; + } + +#ifndef TRILIBRARY + strcpy(inpolyfilename, innodefilename); + strcpy(inelefilename, innodefilename); + strcpy(areafilename, innodefilename); + increment = 0; + strcpy(workstring, innodefilename); + j = 1; + while (workstring[j] != '\0') { + if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { + increment = j + 1; + } + j++; + } + meshnumber = 0; + if (increment > 0) { + j = increment; + do { + if ((workstring[j] >= '0') && (workstring[j] <= '9')) { + meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); + } else { + increment = 0; + } + j++; + } while (workstring[j] != '\0'); + } + if (noiterationnum) { + strcpy(outnodefilename, innodefilename); + strcpy(outelefilename, innodefilename); + strcpy(edgefilename, innodefilename); + strcpy(vnodefilename, innodefilename); + strcpy(vedgefilename, innodefilename); + strcpy(neighborfilename, innodefilename); + strcpy(offfilename, innodefilename); + strcat(outnodefilename, ".node"); + strcat(outelefilename, ".ele"); + strcat(edgefilename, ".edge"); + strcat(vnodefilename, ".v.node"); + strcat(vedgefilename, ".v.edge"); + strcat(neighborfilename, ".neigh"); + strcat(offfilename, ".off"); + } else if (increment == 0) { + strcpy(outnodefilename, innodefilename); + strcpy(outpolyfilename, innodefilename); + strcpy(outelefilename, innodefilename); + strcpy(edgefilename, innodefilename); + strcpy(vnodefilename, innodefilename); + strcpy(vedgefilename, innodefilename); + strcpy(neighborfilename, innodefilename); + strcpy(offfilename, innodefilename); + strcat(outnodefilename, ".1.node"); + strcat(outpolyfilename, ".1.poly"); + strcat(outelefilename, ".1.ele"); + strcat(edgefilename, ".1.edge"); + strcat(vnodefilename, ".1.v.node"); + strcat(vedgefilename, ".1.v.edge"); + strcat(neighborfilename, ".1.neigh"); + strcat(offfilename, ".1.off"); + } else { + workstring[increment] = '%'; + workstring[increment + 1] = 'd'; + workstring[increment + 2] = '\0'; + sprintf(outnodefilename, workstring, meshnumber + 1); + strcpy(outpolyfilename, outnodefilename); + strcpy(outelefilename, outnodefilename); + strcpy(edgefilename, outnodefilename); + strcpy(vnodefilename, outnodefilename); + strcpy(vedgefilename, outnodefilename); + strcpy(neighborfilename, outnodefilename); + strcpy(offfilename, outnodefilename); + strcat(outnodefilename, ".node"); + strcat(outpolyfilename, ".poly"); + strcat(outelefilename, ".ele"); + strcat(edgefilename, ".edge"); + strcat(vnodefilename, ".v.node"); + strcat(vedgefilename, ".v.edge"); + strcat(neighborfilename, ".neigh"); + strcat(offfilename, ".off"); + } + strcat(innodefilename, ".node"); + strcat(inpolyfilename, ".poly"); + strcat(inelefilename, ".ele"); + strcat(areafilename, ".area"); +#endif /* not TRILIBRARY */ +} + +/** **/ +/** **/ +/********* User interaction routines begin here *********/ + +/********* Debugging routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* printtriangle() Print out the details of a triangle/edge handle. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about a */ +/* triangle/edge handle in digestible form. It's also used when the */ +/* highest level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +void printtriangle(t) +struct triedge *t; +{ + struct triedge printtri; + struct edge printsh; + point printpoint; + + printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, + t->orient); + decode(t->tri[0], printtri); + if (printtri.tri == dummytri) { + printf(" [0] = Outer space\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[1], printtri); + if (printtri.tri == dummytri) { + printf(" [1] = Outer space\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[2], printtri); + if (printtri.tri == dummytri) { + printf(" [2] = Outer space\n"); + } else { + printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + org(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 1) % 3 + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + dest(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 2) % 3 + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + apex(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Apex [%d] = NULL\n", t->orient + 3); + else + printf(" Apex [%d] = x%lx (%.12g, %.12g)\n", + t->orient + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + if (useshelles) { + sdecode(t->tri[6], printsh); + if (printsh.sh != dummysh) { + printf(" [6] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(t->tri[7], printsh); + if (printsh.sh != dummysh) { + printf(" [7] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(t->tri[8], printsh); + if (printsh.sh != dummysh) { + printf(" [8] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + } + if (vararea) { + printf(" Area constraint: %.4g\n", areabound(*t)); + } +} + +/*****************************************************************************/ +/* */ +/* printshelle() Print out the details of a shell edge handle. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about a */ +/* shell edge handle in digestible form. It's also used when the highest */ +/* level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +void printshelle(s) +struct edge *s; +{ + struct edge printsh; + struct triedge printtri; + point printpoint; + + printf("shell edge x%lx with orientation %d and mark %d:\n", + (unsigned long) s->sh, s->shorient, mark(*s)); + sdecode(s->sh[0], printsh); + if (printsh.sh == dummysh) { + printf(" [0] = No shell\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(s->sh[1], printsh); + if (printsh.sh == dummysh) { + printf(" [1] = No shell\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sorg(*s, printpoint); + if (printpoint == (point) NULL) + printf(" Origin[%d] = NULL\n", 2 + s->shorient); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + 2 + s->shorient, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + sdest(*s, printpoint); + if (printpoint == (point) NULL) + printf(" Dest [%d] = NULL\n", 3 - s->shorient); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + 3 - s->shorient, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + decode(s->sh[4], printtri); + if (printtri.tri == dummytri) { + printf(" [4] = Outer space\n"); + } else { + printf(" [4] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(s->sh[5], printtri); + if (printtri.tri == dummytri) { + printf(" [5] = Outer space\n"); + } else { + printf(" [5] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } +} + +/** **/ +/** **/ +/********* Debugging routines end here *********/ + +/********* Memory management routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* poolinit() Initialize a pool of memory for allocation of items. */ +/* */ +/* This routine initializes the machinery for allocating items. A `pool' */ +/* is created whose records have size at least `bytecount'. Items will be */ +/* allocated in `itemcount'-item blocks. Each item is assumed to be a */ +/* collection of words, and either pointers or floating-point values are */ +/* assumed to be the "primary" word type. (The "primary" word type is used */ +/* to determine alignment of items.) If `alignment' isn't zero, all items */ +/* will be `alignment'-byte aligned in memory. `alignment' must be either */ +/* a multiple or a factor of the primary word size; powers of two are safe. */ +/* `alignment' is normally used to create a few unused bits at the bottom */ +/* of each item's pointer, in which information may be stored. */ +/* */ +/* Don't change this routine unless you understand it. */ +/* */ +/*****************************************************************************/ + +void poolinit(pool, bytecount, itemcount, wtype, alignment) +struct memorypool *pool; +int bytecount; +int itemcount; +enum wordtype wtype; +int alignment; +{ + int wordsize; + + /* Initialize values in the pool. */ + pool->itemwordtype = wtype; + wordsize = (pool->itemwordtype == POINTER) ? sizeof(VOID *) : sizeof(REAL); + /* Find the proper alignment, which must be at least as large as: */ + /* - The parameter `alignment'. */ + /* - The primary word type, to avoid unaligned accesses. */ + /* - sizeof(VOID *), so the stack of dead items can be maintained */ + /* without unaligned accesses. */ + if (alignment > wordsize) { + pool->alignbytes = alignment; + } else { + pool->alignbytes = wordsize; + } + if (sizeof(VOID *) > pool->alignbytes) { + pool->alignbytes = sizeof(VOID *); + } + pool->itemwords = ((bytecount + pool->alignbytes - 1) / pool->alignbytes) + * (pool->alignbytes / wordsize); + pool->itembytes = pool->itemwords * wordsize; + pool->itemsperblock = itemcount; + + /* Allocate a block of items. Space for `itemsperblock' items and one */ + /* pointer (to point to the next block) are allocated, as well as space */ + /* to ensure alignment of the items. */ + pool->firstblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes + + sizeof(VOID *) + pool->alignbytes); + if (pool->firstblock == (VOID **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Set the next block pointer to NULL. */ + *(pool->firstblock) = (VOID *) NULL; + poolrestart(pool); +} + +/*****************************************************************************/ +/* */ +/* poolrestart() Deallocate all items in a pool. */ +/* */ +/* The pool is returned to its starting state, except that no memory is */ +/* freed to the operating system. Rather, the previously allocated blocks */ +/* are ready to be reused. */ +/* */ +/*****************************************************************************/ + +void poolrestart(pool) +struct memorypool *pool; +{ + unsigned long alignptr; + + pool->items = 0; + pool->maxitems = 0; + + /* Set the currently active block. */ + pool->nowblock = pool->firstblock; + /* Find the first item in the pool. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsperblock; + /* The stack of deallocated items is empty. */ + pool->deaditemstack = (VOID *) NULL; +} + +/*****************************************************************************/ +/* */ +/* pooldeinit() Free to the operating system all memory taken by a pool. */ +/* */ +/*****************************************************************************/ + +void pooldeinit(pool) +struct memorypool *pool; +{ + while (pool->firstblock != (VOID **) NULL) { + pool->nowblock = (VOID **) *(pool->firstblock); + free(pool->firstblock); + pool->firstblock = pool->nowblock; + } +} + +/*****************************************************************************/ +/* */ +/* poolalloc() Allocate space for an item. */ +/* */ +/*****************************************************************************/ + +VOID *poolalloc(pool) +struct memorypool *pool; +{ + VOID *newitem; + VOID **newblock; + unsigned long alignptr; + + /* First check the linked list of dead items. If the list is not */ + /* empty, allocate an item from the list rather than a fresh one. */ + if (pool->deaditemstack != (VOID *) NULL) { + newitem = pool->deaditemstack; /* Take first item in list. */ + pool->deaditemstack = * (VOID **) pool->deaditemstack; + } else { + /* Check if there are any free items left in the current block. */ + if (pool->unallocateditems == 0) { + /* Check if another block must be allocated. */ + if (*(pool->nowblock) == (VOID *) NULL) { + /* Allocate a new block of items, pointed to by the previous block. */ + newblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes + + sizeof(VOID *) + pool->alignbytes); + if (newblock == (VOID **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + *(pool->nowblock) = (VOID *) newblock; + /* The next block pointer is NULL. */ + *newblock = (VOID *) NULL; + } + /* Move to the new block. */ + pool->nowblock = (VOID **) *(pool->nowblock); + /* Find the first item in the block. */ + /* Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsperblock; + } + /* Allocate a new item. */ + newitem = pool->nextitem; + /* Advance `nextitem' pointer to next free item in block. */ + if (pool->itemwordtype == POINTER) { + pool->nextitem = (VOID *) ((VOID **) pool->nextitem + pool->itemwords); + } else { + pool->nextitem = (VOID *) ((REAL *) pool->nextitem + pool->itemwords); + } + pool->unallocateditems--; + pool->maxitems++; + } + pool->items++; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* pooldealloc() Deallocate space for an item. */ +/* */ +/* The deallocated space is stored in a queue for later reuse. */ +/* */ +/*****************************************************************************/ + +void pooldealloc(pool, dyingitem) +struct memorypool *pool; +VOID *dyingitem; +{ + /* Push freshly killed item onto stack. */ + *((VOID **) dyingitem) = pool->deaditemstack; + pool->deaditemstack = dyingitem; + pool->items--; +} + +/*****************************************************************************/ +/* */ +/* traversalinit() Prepare to traverse the entire list of items. */ +/* */ +/* This routine is used in conjunction with traverse(). */ +/* */ +/*****************************************************************************/ + +void traversalinit(pool) +struct memorypool *pool; +{ + unsigned long alignptr; + + /* Begin the traversal in the first block. */ + pool->pathblock = pool->firstblock; + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsperblock; +} + +/*****************************************************************************/ +/* */ +/* traverse() Find the next item in the list. */ +/* */ +/* This routine is used in conjunction with traversalinit(). Be forewarned */ +/* that this routine successively returns all items in the list, including */ +/* deallocated ones on the deaditemqueue. It's up to you to figure out */ +/* which ones are actually dead. Why? I don't want to allocate extra */ +/* space just to demarcate dead items. It can usually be done more */ +/* space-efficiently by a routine that knows something about the structure */ +/* of the item. */ +/* */ +/*****************************************************************************/ + +VOID *traverse(pool) +struct memorypool *pool; +{ + VOID *newitem; + unsigned long alignptr; + + /* Stop upon exhausting the list of items. */ + if (pool->pathitem == pool->nextitem) { + return (VOID *) NULL; + } + /* Check whether any untraversed items remain in the current block. */ + if (pool->pathitemsleft == 0) { + /* Find the next block. */ + pool->pathblock = (VOID **) *(pool->pathblock); + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsperblock; + } + newitem = pool->pathitem; + /* Find the next item in the block. */ + if (pool->itemwordtype == POINTER) { + pool->pathitem = (VOID *) ((VOID **) pool->pathitem + pool->itemwords); + } else { + pool->pathitem = (VOID *) ((REAL *) pool->pathitem + pool->itemwords); + } + pool->pathitemsleft--; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* dummyinit() Initialize the triangle that fills "outer space" and the */ +/* omnipresent shell edge. */ +/* */ +/* The triangle that fills "outer space", called `dummytri', is pointed to */ +/* by every triangle and shell edge on a boundary (be it outer or inner) of */ +/* the triangulation. Also, `dummytri' points to one of the triangles on */ +/* the convex hull (until the holes and concavities are carved), making it */ +/* possible to find a starting triangle for point location. */ +/* */ +/* The omnipresent shell edge, `dummysh', is pointed to by every triangle */ +/* or shell edge that doesn't have a full complement of real shell edges */ +/* to point to. */ +/* */ +/*****************************************************************************/ + +void dummyinit(trianglewords, shellewords) +int trianglewords; +int shellewords; +{ + unsigned long alignptr; + + /* `triwords' and `shwords' are used by the mesh manipulation primitives */ + /* to extract orientations of triangles and shell edges from pointers. */ + triwords = trianglewords; /* Initialize `triwords' once and for all. */ + shwords = shellewords; /* Initialize `shwords' once and for all. */ + + /* Set up `dummytri', the `triangle' that occupies "outer space". */ + dummytribase = (triangle *) malloc(triwords * sizeof(triangle) + + triangles.alignbytes); + if (dummytribase == (triangle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */ + alignptr = (unsigned long) dummytribase; + dummytri = (triangle *) + (alignptr + (unsigned long) triangles.alignbytes + - (alignptr % (unsigned long) triangles.alignbytes)); + /* Initialize the three adjoining triangles to be "outer space". These */ + /* will eventually be changed by various bonding operations, but their */ + /* values don't really matter, as long as they can legally be */ + /* dereferenced. */ + dummytri[0] = (triangle) dummytri; + dummytri[1] = (triangle) dummytri; + dummytri[2] = (triangle) dummytri; + /* Three NULL vertex points. */ + dummytri[3] = (triangle) NULL; + dummytri[4] = (triangle) NULL; + dummytri[5] = (triangle) NULL; + + if (useshelles) { + /* Set up `dummysh', the omnipresent "shell edge" pointed to by any */ + /* triangle side or shell edge end that isn't attached to a real shell */ + /* edge. */ + dummyshbase = (shelle *) malloc(shwords * sizeof(shelle) + + shelles.alignbytes); + if (dummyshbase == (shelle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Align `dummysh' on a `shelles.alignbytes'-byte boundary. */ + alignptr = (unsigned long) dummyshbase; + dummysh = (shelle *) + (alignptr + (unsigned long) shelles.alignbytes + - (alignptr % (unsigned long) shelles.alignbytes)); + /* Initialize the two adjoining shell edges to be the omnipresent shell */ + /* edge. These will eventually be changed by various bonding */ + /* operations, but their values don't really matter, as long as they */ + /* can legally be dereferenced. */ + dummysh[0] = (shelle) dummysh; + dummysh[1] = (shelle) dummysh; + /* Two NULL vertex points. */ + dummysh[2] = (shelle) NULL; + dummysh[3] = (shelle) NULL; + /* Initialize the two adjoining triangles to be "outer space". */ + dummysh[4] = (shelle) dummytri; + dummysh[5] = (shelle) dummytri; + /* Set the boundary marker to zero. */ + * (int *) (dummysh + 6) = 0; + + /* Initialize the three adjoining shell edges of `dummytri' to be */ + /* the omnipresent shell edge. */ + dummytri[6] = (triangle) dummysh; + dummytri[7] = (triangle) dummysh; + dummytri[8] = (triangle) dummysh; + } +} + +/*****************************************************************************/ +/* */ +/* initializepointpool() Calculate the size of the point data structure */ +/* and initialize its memory pool. */ +/* */ +/* This routine also computes the `pointmarkindex' and `point2triindex' */ +/* indices used to find values within each point. */ +/* */ +/*****************************************************************************/ + +void initializepointpool() +{ + int pointsize; + + /* The index within each point at which the boundary marker is found. */ + /* Ensure the point marker is aligned to a sizeof(int)-byte address. */ + pointmarkindex = ((mesh_dim + nextras) * sizeof(REAL) + sizeof(int) - 1) + / sizeof(int); + pointsize = (pointmarkindex + 1) * sizeof(int); + if (poly) { + /* The index within each point at which a triangle pointer is found. */ + /* Ensure the pointer is aligned to a sizeof(triangle)-byte address. */ + point2triindex = (pointsize + sizeof(triangle) - 1) / sizeof(triangle); + pointsize = (point2triindex + 1) * sizeof(triangle); + } + /* Initialize the pool of points. */ + poolinit(&points, pointsize, POINTPERBLOCK, + (sizeof(REAL) >= sizeof(triangle)) ? FLOATINGPOINT : POINTER, 0); +} + +/*****************************************************************************/ +/* */ +/* initializetrisegpools() Calculate the sizes of the triangle and shell */ +/* edge data structures and initialize their */ +/* memory pools. */ +/* */ +/* This routine also computes the `highorderindex', `elemattribindex', and */ +/* `areaboundindex' indices used to find values within each triangle. */ +/* */ +/*****************************************************************************/ + +void initializetrisegpools() +{ + int trisize; + + /* The index within each triangle at which the extra nodes (above three) */ + /* associated with high order elements are found. There are three */ + /* pointers to other triangles, three pointers to corners, and possibly */ + /* three pointers to shell edges before the extra nodes. */ + highorderindex = 6 + (useshelles * 3); + /* The number of bytes occupied by a triangle. */ + trisize = ((order + 1) * (order + 2) / 2 + (highorderindex - 3)) * + sizeof(triangle); + /* The index within each triangle at which its attributes are found, */ + /* where the index is measured in REALs. */ + elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL); + /* The index within each triangle at which the maximum area constraint */ + /* is found, where the index is measured in REALs. Note that if the */ + /* `regionattrib' flag is set, an additional attribute will be added. */ + areaboundindex = elemattribindex + eextras + regionattrib; + /* If triangle attributes or an area bound are needed, increase the number */ + /* of bytes occupied by a triangle. */ + if (vararea) { + trisize = (areaboundindex + 1) * sizeof(REAL); + } else if (eextras + regionattrib > 0) { + trisize = areaboundindex * sizeof(REAL); + } + /* If a Voronoi diagram or triangle neighbor graph is requested, make */ + /* sure there's room to store an integer index in each triangle. This */ + /* integer index can occupy the same space as the shell edges or */ + /* attributes or area constraint or extra nodes. */ + if ((voronoi || neighbors) && + (trisize < 6 * sizeof(triangle) + sizeof(int))) { + trisize = 6 * sizeof(triangle) + sizeof(int); + } + /* Having determined the memory size of a triangle, initialize the pool. */ + poolinit(&triangles, trisize, TRIPERBLOCK, POINTER, 4); + + if (useshelles) { + /* Initialize the pool of shell edges. */ + poolinit(&shelles, 6 * sizeof(triangle) + sizeof(int), SHELLEPERBLOCK, + POINTER, 4); + + /* Initialize the "outer space" triangle and omnipresent shell edge. */ + dummyinit(triangles.itemwords, shelles.itemwords); + } else { + /* Initialize the "outer space" triangle. */ + dummyinit(triangles.itemwords, 0); + } +} + +/*****************************************************************************/ +/* */ +/* triangledealloc() Deallocate space for a triangle, marking it dead. */ +/* */ +/*****************************************************************************/ + +void triangledealloc(dyingtriangle) +triangle *dyingtriangle; +{ + /* Set triangle's vertices to NULL. This makes it possible to */ + /* detect dead triangles when traversing the list of all triangles. */ + dyingtriangle[3] = (triangle) NULL; + dyingtriangle[4] = (triangle) NULL; + dyingtriangle[5] = (triangle) NULL; + pooldealloc(&triangles, (VOID *) dyingtriangle); +} + +/*****************************************************************************/ +/* */ +/* triangletraverse() Traverse the triangles, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +triangle *triangletraverse() +{ + triangle *newtriangle; + + do { + newtriangle = (triangle *) traverse(&triangles); + if (newtriangle == (triangle *) NULL) { + return (triangle *) NULL; + } + } while (newtriangle[3] == (triangle) NULL); /* Skip dead ones. */ + return newtriangle; +} + +/*****************************************************************************/ +/* */ +/* shelledealloc() Deallocate space for a shell edge, marking it dead. */ +/* */ +/*****************************************************************************/ + +void shelledealloc(dyingshelle) +shelle *dyingshelle; +{ + /* Set shell edge's vertices to NULL. This makes it possible to */ + /* detect dead shells when traversing the list of all shells. */ + dyingshelle[2] = (shelle) NULL; + dyingshelle[3] = (shelle) NULL; + pooldealloc(&shelles, (VOID *) dyingshelle); +} + +/*****************************************************************************/ +/* */ +/* shelletraverse() Traverse the shell edges, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +shelle *shelletraverse() +{ + shelle *newshelle; + + do { + newshelle = (shelle *) traverse(&shelles); + if (newshelle == (shelle *) NULL) { + return (shelle *) NULL; + } + } while (newshelle[2] == (shelle) NULL); /* Skip dead ones. */ + return newshelle; +} + +/*****************************************************************************/ +/* */ +/* pointdealloc() Deallocate space for a point, marking it dead. */ +/* */ +/*****************************************************************************/ + +void pointdealloc(dyingpoint) +point dyingpoint; +{ + /* Mark the point as dead. This makes it possible to detect dead points */ + /* when traversing the list of all points. */ + setpointmark(dyingpoint, DEADPOINT); + pooldealloc(&points, (VOID *) dyingpoint); +} + +/*****************************************************************************/ +/* */ +/* pointtraverse() Traverse the points, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +point pointtraverse() +{ + point newpoint; + + do { + newpoint = (point) traverse(&points); + if (newpoint == (point) NULL) { + return (point) NULL; + } + } while (pointmark(newpoint) == DEADPOINT); /* Skip dead ones. */ + return newpoint; +} + +/*****************************************************************************/ +/* */ +/* badsegmentdealloc() Deallocate space for a bad segment, marking it */ +/* dead. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void badsegmentdealloc(dyingseg) +struct edge *dyingseg; +{ + /* Set segment's orientation to -1. This makes it possible to */ + /* detect dead segments when traversing the list of all segments. */ + dyingseg->shorient = -1; + pooldealloc(&badsegments, (VOID *) dyingseg); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* badsegmenttraverse() Traverse the bad segments, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +struct edge *badsegmenttraverse() +{ + struct edge *newseg; + + do { + newseg = (struct edge *) traverse(&badsegments); + if (newseg == (struct edge *) NULL) { + return (struct edge *) NULL; + } + } while (newseg->shorient == -1); /* Skip dead ones. */ + return newseg; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* getpoint() Get a specific point, by number, from the list. */ +/* */ +/* The first point is number 'firstnumber'. */ +/* */ +/* Note that this takes O(n) time (with a small constant, if POINTPERBLOCK */ +/* is large). I don't care to take the trouble to make it work in constant */ +/* time. */ +/* */ +/*****************************************************************************/ + +point getpoint(number) +int number; +{ + VOID **getblock; + point foundpoint; + unsigned long alignptr; + int current; + + getblock = points.firstblock; + current = firstnumber; + /* Find the right block. */ + while (current + points.itemsperblock <= number) { + getblock = (VOID **) *getblock; + current += points.itemsperblock; + } + /* Now find the right point. */ + alignptr = (unsigned long) (getblock + 1); + foundpoint = (point) (alignptr + (unsigned long) points.alignbytes + - (alignptr % (unsigned long) points.alignbytes)); + while (current < number) { + foundpoint += points.itemwords; + current++; + } + return foundpoint; +} + +/*****************************************************************************/ +/* */ +/* triangledeinit() Free all remaining allocated memory. */ +/* */ +/*****************************************************************************/ + +void triangledeinit() +{ + pooldeinit(&triangles); + free(dummytribase); + if (useshelles) { + pooldeinit(&shelles); + free(dummyshbase); + } + pooldeinit(&points); +#ifndef CDT_ONLY + if (quality) { + pooldeinit(&badsegments); + if ((minangle > 0.0) || vararea || fixedarea) { + pooldeinit(&badtriangles); + } + } +#endif /* not CDT_ONLY */ +} + +/** **/ +/** **/ +/********* Memory management routines end here *********/ + +/********* Constructors begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* maketriangle() Create a new triangle with orientation zero. */ +/* */ +/*****************************************************************************/ + +void maketriangle(newtriedge) +struct triedge *newtriedge; +{ + int i; + + newtriedge->tri = (triangle *) poolalloc(&triangles); + /* Initialize the three adjoining triangles to be "outer space". */ + newtriedge->tri[0] = (triangle) dummytri; + newtriedge->tri[1] = (triangle) dummytri; + newtriedge->tri[2] = (triangle) dummytri; + /* Three NULL vertex points. */ + newtriedge->tri[3] = (triangle) NULL; + newtriedge->tri[4] = (triangle) NULL; + newtriedge->tri[5] = (triangle) NULL; + /* Initialize the three adjoining shell edges to be the omnipresent */ + /* shell edge. */ + if (useshelles) { + newtriedge->tri[6] = (triangle) dummysh; + newtriedge->tri[7] = (triangle) dummysh; + newtriedge->tri[8] = (triangle) dummysh; + } + for (i = 0; i < eextras; i++) { + setelemattribute(*newtriedge, i, 0.0); + } + if (vararea) { + setareabound(*newtriedge, -1.0); + } + + newtriedge->orient = 0; +} + +/*****************************************************************************/ +/* */ +/* makeshelle() Create a new shell edge with orientation zero. */ +/* */ +/*****************************************************************************/ + +void makeshelle(newedge) +struct edge *newedge; +{ + newedge->sh = (shelle *) poolalloc(&shelles); + /* Initialize the two adjoining shell edges to be the omnipresent */ + /* shell edge. */ + newedge->sh[0] = (shelle) dummysh; + newedge->sh[1] = (shelle) dummysh; + /* Two NULL vertex points. */ + newedge->sh[2] = (shelle) NULL; + newedge->sh[3] = (shelle) NULL; + /* Initialize the two adjoining triangles to be "outer space". */ + newedge->sh[4] = (shelle) dummytri; + newedge->sh[5] = (shelle) dummytri; + /* Set the boundary marker to zero. */ + setmark(*newedge, 0); + + newedge->shorient = 0; +} + +/** **/ +/** **/ +/********* Constructors end here *********/ + +/********* Determinant evaluation routines begin here *********/ +/** **/ +/** **/ + +/* The adaptive exact arithmetic geometric predicates implemented herein are */ +/* described in detail in my Technical Report CMU-CS-96-140. The complete */ +/* reference is given in the header. */ + +/* Which of the following two methods of finding the absolute values is */ +/* fastest is compiler-dependent. A few compilers can inline and optimize */ +/* the fabs() call; but most will incur the overhead of a function call, */ +/* which is disastrously slow. A faster way on IEEE machines might be to */ +/* mask the appropriate bit, but that's difficult to do in C. */ + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +/* #define Absolute(a) fabs(a) */ + +/* Many of the operations are broken up into two pieces, a main part that */ +/* performs an approximate operation, and a "tail" that computes the */ +/* roundoff error of that operation. */ +/* */ +/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ +/* Split(), and Two_Product() are all implemented as described in the */ +/* reference. Each of these macros requires certain variables to be */ +/* defined in the calling routine. The variables `bvirt', `c', `abig', */ +/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ +/* they store the result of an operation that may incur roundoff error. */ +/* The input parameter `x' (or the highest numbered `x_' parameter) must */ +/* also be declared `INEXACT'. */ + +#define Fast_Two_Sum_Tail(a, b, x, y) \ + bvirt = x - a; \ + y = b - bvirt + +#define Fast_Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Fast_Two_Sum_Tail(a, b, x, y) + +#define Two_Sum_Tail(a, b, x, y) \ + bvirt = (REAL) (x - a); \ + avirt = x - bvirt; \ + bround = b - bvirt; \ + around = a - avirt; \ + y = around + bround + +#define Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Two_Sum_Tail(a, b, x, y) + +#define Two_Diff_Tail(a, b, x, y) \ + bvirt = (REAL) (a - x); \ + avirt = x + bvirt; \ + bround = bvirt - b; \ + around = a - avirt; \ + y = around + bround + +#define Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Two_Diff_Tail(a, b, x, y) + +#define Split(a, ahi, alo) \ + c = (REAL) (splitter * a); \ + abig = (REAL) (c - a); \ + ahi = (REAL)(c - abig); \ + alo = (REAL)(a - ahi) + +#define Two_Product_Tail(a, b, x, y) \ + Split(a, ahi, alo); \ + Split(b, bhi, blo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Two_Product(a, b, x, y) \ + x = (REAL) (a * b); \ + Two_Product_Tail(a, b, x, y) + +/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + Split(a, ahi, alo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Square() can be done more quickly than Two_Product(). */ + +#define Square_Tail(a, x, y) \ + Split(a, ahi, alo); \ + err1 = x - (ahi * ahi); \ + err3 = err1 - ((ahi + ahi) * alo); \ + y = (alo * alo) - err3 + +#define Square(a, x, y) \ + x = (REAL) (a * a); \ + Square_Tail(a, x, y) + +/* Macros for summing expansions of various fixed lengths. These are all */ +/* unrolled versions of Expansion_Sum(). */ + +#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ + Two_Sum(a0, b , _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ + Two_Diff(a0, b , _i, x0); \ + Two_Sum( a1, _i, x2, x1) + +#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b0, _j, _0, x0); \ + Two_One_Sum(_j, _0, b1, x3, x2, x1) + +#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Diff(a1, a0, b0, _j, _0, x0); \ + Two_One_Diff(_j, _0, b1, x3, x2, x1) + +/*****************************************************************************/ +/* */ +/* exactinit() Initialize the variables used for exact arithmetic. */ +/* */ +/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ +/* floating-point arithmetic. `epsilon' bounds the relative roundoff */ +/* error. It is used for floating-point error analysis. */ +/* */ +/* `splitter' is used to split floating-point numbers into two half- */ +/* length significands for exact multiplication. */ +/* */ +/* I imagine that a highly optimizing compiler might be too smart for its */ +/* own good, and somehow cause this routine to fail, if it pretends that */ +/* floating-point arithmetic is too much like real arithmetic. */ +/* */ +/* Don't change this routine unless you fully understand it. */ +/* */ +/*****************************************************************************/ + +void exactinit() +{ + REAL half; + REAL check, lastcheck; + int every_other; + + every_other = 1; + half = 0.5; + epsilon = 1.0; + splitter = 1.0; + check = 1.0; + /* Repeatedly divide `epsilon' by two until it is too small to add to */ + /* one without causing roundoff. (Also check if the sum is equal to */ + /* the previous sum, for machines that round up instead of using exact */ + /* rounding. Not that these routines will work on such machines anyway. */ + do { + lastcheck = check; + epsilon *= half; + if (every_other) { + splitter *= 2.0; + } + every_other = !every_other; + check = (REAL)(1.0 + epsilon); + } while ((check != 1.0) && (check != lastcheck)); + splitter += 1.0; + if (verbose > 1) { + printf("Floating point roundoff is of magnitude %.17g\n", epsilon); + printf("Floating point splitter is %.17g\n", splitter); + } + /* Error bounds for orientation and incircle tests. */ + resulterrbound = (REAL)((3.0 + 8.0 * epsilon) * epsilon); + ccwerrboundA = (REAL)((3.0 + 16.0 * epsilon) * epsilon); + ccwerrboundB = (REAL)((2.0 + 12.0 * epsilon) * epsilon); + ccwerrboundC = (REAL)((9.0 + 64.0 * epsilon) * epsilon * epsilon); + iccerrboundA = (REAL)((10.0 + 96.0 * epsilon) * epsilon); + iccerrboundB = (REAL)((4.0 + 48.0 * epsilon) * epsilon); + iccerrboundC = (REAL)((44.0 + 576.0 * epsilon) * epsilon * epsilon); +} + +/*****************************************************************************/ +/* */ +/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See my Robust Predicates paper for details. */ +/* */ +/* If round-to-even is used (as with IEEE 754), maintains the strongly */ +/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ +/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ +/* properties. */ +/* */ +/*****************************************************************************/ + +int fast_expansion_sum_zeroelim(elen, e, flen, f, h) /* h cannot be e or f. */ +int elen; +REAL *e; +int flen; +REAL *f; +REAL *h; +{ + REAL Q; + INEXACT REAL Qnew; + INEXACT REAL hh; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, hh); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, Q, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + } else { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ +/* eliminating zero components from the */ +/* output expansion. */ +/* */ +/* Sets h = be. See my Robust Predicates paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +int scale_expansion_zeroelim(elen, e, b, h) /* e and h cannot be the same. */ +int elen; +REAL *e; +REAL b; +REAL *h; +{ + INEXACT REAL Q, sum; + REAL hh; + INEXACT REAL product1; + REAL product0; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); + hindex = 0; + if (hh != 0) { + h[hindex++] = hh; + } + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, hh); + if (hh != 0) { + h[hindex++] = hh; + } + Fast_Two_Sum(product1, sum, Q, hh); + if (hh != 0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* estimate() Produce a one-word estimate of an expansion's value. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL estimate(elen, e) +int elen; +REAL *e; +{ + REAL Q; + int eindex; + + Q = e[0]; + for (eindex = 1; eindex < elen; eindex++) { + Q += e[eindex]; + } + return Q; +} + +/*****************************************************************************/ +/* */ +/* counterclockwise() Return a positive value if the points pa, pb, and */ +/* pc occur in counterclockwise order; a negative */ +/* value if they occur in clockwise order; and zero */ +/* if they are collinear. The result is also a rough */ +/* approximation of twice the signed area of the */ +/* triangle defined by the three points. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are collinear or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL counterclockwiseadapt(pa, pb, pc, detsum) +point pa; +point pb; +point pc; +REAL detsum; +{ + INEXACT REAL acx, acy, bcx, bcy; + REAL acxtail, acytail, bcxtail, bcytail; + INEXACT REAL detleft, detright; + REAL detlefttail, detrighttail; + REAL det, errbound; + REAL B[4], C1[8], C2[12], D[16]; + INEXACT REAL B3; + int C1length, C2length, Dlength; + REAL u[4]; + INEXACT REAL u3; + INEXACT REAL s1, t1; + REAL s0, t0; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + acx = (REAL) (pa[0] - pc[0]); + bcx = (REAL) (pb[0] - pc[0]); + acy = (REAL) (pa[1] - pc[1]); + bcy = (REAL) (pb[1] - pc[1]); + + Two_Product(acx, bcy, detleft, detlefttail); + Two_Product(acy, bcx, detright, detrighttail); + + Two_Two_Diff(detleft, detlefttail, detright, detrighttail, + B3, B[2], B[1], B[0]); + B[3] = B3; + + det = estimate(4, B); + errbound = (REAL)(ccwerrboundB * detsum); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pc[0], acx, acxtail); + Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); + Two_Diff_Tail(pa[1], pc[1], acy, acytail); + Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); + + if ((acxtail == 0.0) && (acytail == 0.0) + && (bcxtail == 0.0) && (bcytail == 0.0)) { + return det; + } + + errbound = (REAL)(ccwerrboundC * detsum + resulterrbound * Absolute(det)); + det += (acx * bcytail + bcy * acxtail) + - (acy * bcxtail + bcx * acytail); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Product(acxtail, bcy, s1, s0); + Two_Product(acytail, bcx, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); + + Two_Product(acx, bcytail, s1, s0); + Two_Product(acy, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); + + Two_Product(acxtail, bcytail, s1, s0); + Two_Product(acytail, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); + + return(D[Dlength - 1]); +} + +REAL counterclockwise(pa, pb, pc) +point pa; +point pb; +point pc; +{ + REAL detleft, detright, det; + REAL detsum, errbound; + + counterclockcount++; + + detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); + detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); + det = detleft - detright; + + if (noexact) { + return det; + } + + if (detleft > 0.0) { + if (detright <= 0.0) { + return det; + } else { + detsum = detleft + detright; + } + } else if (detleft < 0.0) { + if (detright >= 0.0) { + return det; + } else { + detsum = -detleft - detright; + } + } else { + return det; + } + + errbound = ccwerrboundA * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return counterclockwiseadapt(pa, pb, pc, detsum); +} + +/*****************************************************************************/ +/* */ +/* incircle() Return a positive value if the point pd lies inside the */ +/* circle passing through pa, pb, and pc; a negative value if */ +/* it lies outside; and zero if the four points are cocircular.*/ +/* The points pa, pb, and pc must be in counterclockwise */ +/* order, or the sign of the result will be reversed. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are cocircular or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL incircleadapt(pa, pb, pc, pd, permanent) +point pa; +point pb; +point pc; +point pd; +REAL permanent; +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; + int axbclen, axxbclen, aybclen, ayybclen, alen; + REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; + int bxcalen, bxxcalen, bycalen, byycalen, blen; + REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; + int cxablen, cxxablen, cyablen, cyyablen, clen; + REAL abdet[64]; + int ablen; + REAL fin1[1152], fin2[1152]; + REAL *finnow, *finother, *finswap; + int finlength; + + REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; + INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; + REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; + REAL aa[4], bb[4], cc[4]; + INEXACT REAL aa3, bb3, cc3; + INEXACT REAL ti1, tj1; + REAL ti0, tj0; + REAL u[4], v[4]; + INEXACT REAL u3, v3; + REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; + REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; + int temp8len, temp16alen, temp16blen, temp16clen; + int temp32alen, temp32blen, temp48len, temp64len; + REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; + int axtbblen, axtcclen, aytbblen, aytcclen; + REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; + int bxtaalen, bxtcclen, bytaalen, bytcclen; + REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; + int cxtaalen, cxtbblen, cytaalen, cytbblen; + REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; + int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; + REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; + int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; + REAL axtbctt[8], aytbctt[8], bxtcatt[8]; + REAL bytcatt[8], cxtabtt[8], cytabtt[8]; + int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; + REAL abt[8], bct[8], cat[8]; + int abtlen, bctlen, catlen; + REAL abtt[4], bctt[4], catt[4]; + int abttlen, bcttlen, cattlen; + INEXACT REAL abtt3, bctt3, catt3; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); + axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); + aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); + ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); + alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); + bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); + bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); + byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); + blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); + cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); + cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); + cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); + clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = (REAL)(iccerrboundB * permanent); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { + return det; + } + + errbound = (REAL)(iccerrboundC * permanent + resulterrbound * Absolute(det)); + det += (REAL)(((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx))); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Square(adx, adxadx1, adxadx0); + Square(ady, adyady1, adyady0); + Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); + aa[3] = aa3; + } + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Square(bdx, bdxbdx1, bdxbdx0); + Square(bdy, bdybdy1, bdybdy0); + Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); + bb[3] = bb3; + } + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Square(cdx, cdxcdx1, cdxcdx0); + Square(cdy, cdycdy1, cdycdy0); + Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); + cc[3] = cc3; + } + + if (adxtail != 0.0) { + axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, + temp16a); + + axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); + temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); + + axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); + temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, + temp16a); + + aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); + temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); + + aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); + temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdxtail != 0.0) { + bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, + temp16a); + + bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); + temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); + + bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); + temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, + temp16a); + + bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); + temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); + + bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); + temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdxtail != 0.0) { + cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, + temp16a); + + cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); + temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); + + cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); + temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); + temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, + temp16a); + + cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); + temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); + + cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); + temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if ((adxtail != 0.0) || (adytail != 0.0)) { + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Two_Product(bdxtail, cdy, ti1, ti0); + Two_Product(bdx, cdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -bdy; + Two_Product(cdxtail, negate, ti1, ti0); + negate = -bdytail; + Two_Product(cdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); + + Two_Product(bdxtail, cdytail, ti1, ti0); + Two_Product(cdxtail, bdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); + bctt[3] = bctt3; + bcttlen = 4; + } else { + bct[0] = 0.0; + bctlen = 1; + bctt[0] = 0.0; + bcttlen = 1; + } + + if (adxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); + axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, + temp32a); + axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); + temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, + temp16a); + temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); + aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, + temp32a); + aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); + temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, + temp16a); + temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((bdxtail != 0.0) || (bdytail != 0.0)) { + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Two_Product(cdxtail, ady, ti1, ti0); + Two_Product(cdx, adytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -cdy; + Two_Product(adxtail, negate, ti1, ti0); + negate = -cdytail; + Two_Product(adx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); + + Two_Product(cdxtail, adytail, ti1, ti0); + Two_Product(adxtail, cdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); + catt[3] = catt3; + cattlen = 4; + } else { + cat[0] = 0.0; + catlen = 1; + catt[0] = 0.0; + cattlen = 1; + } + + if (bdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); + bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, + temp32a); + bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); + temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, + temp16a); + temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); + bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, + temp32a); + bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); + temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, + temp16a); + temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((cdxtail != 0.0) || (cdytail != 0.0)) { + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Two_Product(adxtail, bdy, ti1, ti0); + Two_Product(adx, bdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -ady; + Two_Product(bdxtail, negate, ti1, ti0); + negate = -adytail; + Two_Product(bdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); + + Two_Product(adxtail, bdytail, ti1, ti0); + Two_Product(bdxtail, adytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); + abtt[3] = abtt3; + abttlen = 4; + } else { + abt[0] = 0.0; + abtlen = 1; + abtt[0] = 0.0; + abttlen = 1; + } + + if (cdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); + cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, + temp32a); + cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); + temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, + temp16a); + temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); + cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, + temp32a); + cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); + temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, + temp16a); + temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + + return finnow[finlength - 1]; +} + +REAL incircle(pa, pb, pc, pd) +point pa; +point pb; +point pc; +point pd; +{ + REAL adx, bdx, cdx, ady, bdy, cdy; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL alift, blift, clift; + REAL det; + REAL permanent, errbound; + + incirclecount++; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + alift = adx * adx + ady * ady; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + blift = bdx * bdx + bdy * bdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + + blift * (cdxady - adxcdy) + + clift * (adxbdy - bdxady); + + if (noexact) { + return det; + } + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + + (Absolute(cdxady) + Absolute(adxcdy)) * blift + + (Absolute(adxbdy) + Absolute(bdxady)) * clift; + errbound = iccerrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return incircleadapt(pa, pb, pc, pd, permanent); +} + +/** **/ +/** **/ +/********* Determinant evaluation routines end here *********/ + +/*****************************************************************************/ +/* */ +/* triangleinit() Initialize some variables. */ +/* */ +/*****************************************************************************/ + +void triangleinit() +{ + points.maxitems = triangles.maxitems = shelles.maxitems = viri.maxitems = + badsegments.maxitems = badtriangles.maxitems = splaynodes.maxitems = 0l; + points.itembytes = triangles.itembytes = shelles.itembytes = viri.itembytes = + badsegments.itembytes = badtriangles.itembytes = splaynodes.itembytes = 0; + recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */ + samples = 1; /* Point location should take at least one sample. */ + checksegments = 0; /* There are no segments in the triangulation yet. */ + incirclecount = counterclockcount = hyperbolacount = 0; + circumcentercount = circletopcount = 0; + randomseed = 1; + + exactinit(); /* Initialize exact arithmetic constants. */ +} + +/*****************************************************************************/ +/* */ +/* randomnation() Generate a random number between 0 and `choices' - 1. */ +/* */ +/* This is a simple linear congruential random number generator. Hence, it */ +/* is a bad random number generator, but good enough for most randomized */ +/* geometric algorithms. */ +/* */ +/*****************************************************************************/ + +unsigned long randomnation(choices) +unsigned int choices; +{ + randomseed = (randomseed * 1366l + 150889l) % 714025l; + return randomseed / (714025l / choices + 1); +} + +/********* Mesh quality testing routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* checkmesh() Test the mesh for topological consistency. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void checkmesh() +{ + struct triedge triangleloop; + struct triedge oppotri, oppooppotri; + point triorg, tridest, triapex; + point oppoorg, oppodest; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = noexact; + noexact = 0; + if (!quiet) { + printf(" Checking consistency of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + if (triangleloop.orient == 0) { /* Only test for inversion once. */ + /* Test if the triangle is flat or inverted. */ + apex(triangleloop, triapex); + if (counterclockwise(triorg, tridest, triapex) <= 0.0) { + printf(" !! !! Inverted "); + printtriangle(&triangleloop); + horrors++; + } + } + /* Find the neighboring triangle on this edge. */ + sym(triangleloop, oppotri); + if (oppotri.tri != dummytri) { + /* Check that the triangle's neighbor knows it's a neighbor. */ + sym(oppotri, oppooppotri); + if ((triangleloop.tri != oppooppotri.tri) + || (triangleloop.orient != oppooppotri.orient)) { + printf(" !! !! Asymmetric triangle-triangle bond:\n"); + if (triangleloop.tri == oppooppotri.tri) { + printf(" (Right triangle, wrong orientation)\n"); + } + printf(" First "); + printtriangle(&triangleloop); + printf(" Second (nonreciprocating) "); + printtriangle(&oppotri); + horrors++; + } + /* Check that both triangles agree on the identities */ + /* of their shared vertices. */ + org(oppotri, oppoorg); + dest(oppotri, oppodest); + if ((triorg != oppodest) || (tridest != oppoorg)) { + printf(" !! !! Mismatched edge coordinates between two triangles:\n" + ); + printf(" First mismatched "); + printtriangle(&triangleloop); + printf(" Second mismatched "); + printtriangle(&oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(); + } + if (horrors == 0) { + if (!quiet) { + printf(" In my studied opinion, the mesh appears to be consistent.\n"); + } + } else if (horrors == 1) { + printf(" !! !! !! !! Precisely one festering wound discovered.\n"); + } else { + printf(" !! !! !! !! %d abominations witnessed.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* checkdelaunay() Ensure that the mesh is (constrained) Delaunay. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void checkdelaunay() +{ + struct triedge triangleloop; + struct triedge oppotri; + struct edge opposhelle; + point triorg, tridest, triapex; + point oppoapex; + int shouldbedelaunay; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = noexact; + noexact = 0; + if (!quiet) { + printf(" Checking Delaunay property of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + apex(triangleloop, triapex); + sym(triangleloop, oppotri); + apex(oppotri, oppoapex); + /* Only test that the edge is locally Delaunay if there is an */ + /* adjoining triangle whose pointer is larger (to ensure that */ + /* each pair isn't tested twice). */ + shouldbedelaunay = (oppotri.tri != dummytri) + && (triapex != (point) NULL) && (oppoapex != (point) NULL) + && (triangleloop.tri < oppotri.tri); + if (checksegments && shouldbedelaunay) { + /* If a shell edge separates the triangles, then the edge is */ + /* constrained, so no local Delaunay test should be done. */ + tspivot(triangleloop, opposhelle); + if (opposhelle.sh != dummysh){ + shouldbedelaunay = 0; + } + } + if (shouldbedelaunay) { + if (incircle(triorg, tridest, triapex, oppoapex) > 0.0) { + printf(" !! !! Non-Delaunay pair of triangles:\n"); + printf(" First non-Delaunay "); + printtriangle(&triangleloop); + printf(" Second non-Delaunay "); + printtriangle(&oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(); + } + if (horrors == 0) { + if (!quiet) { + printf( + " By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n"); + } + } else if (horrors == 1) { + printf( + " !! !! !! !! Precisely one terrifying transgression identified.\n"); + } else { + printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* enqueuebadtri() Add a bad triangle to the end of a queue. */ +/* */ +/* The queue is actually a set of 64 queues. I use multiple queues to give */ +/* priority to smaller angles. I originally implemented a heap, but the */ +/* queues are (to my surprise) much faster. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void enqueuebadtri(instri, angle, insapex, insorg, insdest) +struct triedge *instri; +REAL angle; +point insapex; +point insorg; +point insdest; +{ + struct badface *newface; + int queuenumber; + + if (verbose > 2) { + printf(" Queueing bad triangle:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", insorg[0], + insorg[1], insdest[0], insdest[1], insapex[0], insapex[1]); + } + /* Allocate space for the bad triangle. */ + newface = (struct badface *) poolalloc(&badtriangles); + triedgecopy(*instri, newface->badfacetri); + newface->key = angle; + newface->faceapex = insapex; + newface->faceorg = insorg; + newface->facedest = insdest; + newface->nextface = (struct badface *) NULL; + /* Determine the appropriate queue to put the bad triangle into. */ + if (angle > 0.6) { + queuenumber = (int) (160.0 * (angle - 0.6)); + if (queuenumber > 63) { + queuenumber = 63; + } + } else { + /* It's not a bad angle; put the triangle in the lowest-priority queue. */ + queuenumber = 0; + } + /* Add the triangle to the end of a queue. */ + *queuetail[queuenumber] = newface; + /* Maintain a pointer to the NULL pointer at the end of the queue. */ + queuetail[queuenumber] = &newface->nextface; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* dequeuebadtri() Remove a triangle from the front of the queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +struct badface *dequeuebadtri() +{ + struct badface *result; + int queuenumber; + + /* Look for a nonempty queue. */ + for (queuenumber = 63; queuenumber >= 0; queuenumber--) { + result = queuefront[queuenumber]; + if (result != (struct badface *) NULL) { + /* Remove the triangle from the queue. */ + queuefront[queuenumber] = result->nextface; + /* Maintain a pointer to the NULL pointer at the end of the queue. */ + if (queuefront[queuenumber] == (struct badface *) NULL) { + queuetail[queuenumber] = &queuefront[queuenumber]; + } + return result; + } + } + return (struct badface *) NULL; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* checkedge4encroach() Check a segment to see if it is encroached; add */ +/* it to the list if it is. */ +/* */ +/* An encroached segment is an unflippable edge that has a point in its */ +/* diametral circle (that is, it faces an angle greater than 90 degrees). */ +/* This definition is due to Ruppert. */ +/* */ +/* Returns a nonzero value if the edge is encroached. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +int checkedge4encroach(testedge) +struct edge *testedge; +{ + struct triedge neighbortri; + struct edge testsym; + struct edge *badedge; + int addtolist; + int sides; + point eorg, edest, eapex; + triangle ptr; /* Temporary variable used by stpivot(). */ + + addtolist = 0; + sides = 0; + + sorg(*testedge, eorg); + sdest(*testedge, edest); + /* Check one neighbor of the shell edge. */ + stpivot(*testedge, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != dummytri) { + sides++; + /* Find a vertex opposite this edge. */ + apex(neighbortri, eapex); + /* Check whether the vertex is inside the diametral circle of the */ + /* shell edge. Pythagoras' Theorem is used to check whether the */ + /* angle at the vertex is greater than 90 degrees. */ + if (eapex[0] * (eorg[0] + edest[0]) + eapex[1] * (eorg[1] + edest[1]) > + eapex[0] * eapex[0] + eorg[0] * edest[0] + + eapex[1] * eapex[1] + eorg[1] * edest[1]) { + addtolist = 1; + } + } + /* Check the other neighbor of the shell edge. */ + ssym(*testedge, testsym); + stpivot(testsym, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != dummytri) { + sides++; + /* Find the other vertex opposite this edge. */ + apex(neighbortri, eapex); + /* Check whether the vertex is inside the diametral circle of the */ + /* shell edge. Pythagoras' Theorem is used to check whether the */ + /* angle at the vertex is greater than 90 degrees. */ + if (eapex[0] * (eorg[0] + edest[0]) + + eapex[1] * (eorg[1] + edest[1]) > + eapex[0] * eapex[0] + eorg[0] * edest[0] + + eapex[1] * eapex[1] + eorg[1] * edest[1]) { + addtolist += 2; + } + } + + if (addtolist && (!nobisect || ((nobisect == 1) && (sides == 2)))) { + if (verbose > 2) { + printf(" Queueing encroached segment (%.12g, %.12g) (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1]); + } + /* Add the shell edge to the list of encroached segments. */ + /* Be sure to get the orientation right. */ + badedge = (struct edge *) poolalloc(&badsegments); + if (addtolist == 1) { + shellecopy(*testedge, *badedge); + } else { + shellecopy(testsym, *badedge); + } + } + return addtolist; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* testtriangle() Test a face for quality measures. */ +/* */ +/* Tests a triangle to see if it satisfies the minimum angle condition and */ +/* the maximum area condition. Triangles that aren't up to spec are added */ +/* to the bad triangle queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void testtriangle(testtri) +struct triedge *testtri; +{ + struct triedge sametesttri; + struct edge edge1, edge2; + point torg, tdest, tapex; + point anglevertex; + REAL dxod, dyod, dxda, dyda, dxao, dyao; + REAL dxod2, dyod2, dxda2, dyda2, dxao2, dyao2; + REAL apexlen, orglen, destlen; + REAL angle; + REAL area; + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*testtri, torg); + dest(*testtri, tdest); + apex(*testtri, tapex); + dxod = torg[0] - tdest[0]; + dyod = torg[1] - tdest[1]; + dxda = tdest[0] - tapex[0]; + dyda = tdest[1] - tapex[1]; + dxao = tapex[0] - torg[0]; + dyao = tapex[1] - torg[1]; + dxod2 = dxod * dxod; + dyod2 = dyod * dyod; + dxda2 = dxda * dxda; + dyda2 = dyda * dyda; + dxao2 = dxao * dxao; + dyao2 = dyao * dyao; + /* Find the lengths of the triangle's three edges. */ + apexlen = dxod2 + dyod2; + orglen = dxda2 + dyda2; + destlen = dxao2 + dyao2; + if ((apexlen < orglen) && (apexlen < destlen)) { + /* The edge opposite the apex is shortest. */ + /* Find the square of the cosine of the angle at the apex. */ + angle = dxda * dxao + dyda * dyao; + angle = angle * angle / (orglen * destlen); + anglevertex = tapex; + lnext(*testtri, sametesttri); + tspivot(sametesttri, edge1); + lnextself(sametesttri); + tspivot(sametesttri, edge2); + } else if (orglen < destlen) { + /* The edge opposite the origin is shortest. */ + /* Find the square of the cosine of the angle at the origin. */ + angle = dxod * dxao + dyod * dyao; + angle = angle * angle / (apexlen * destlen); + anglevertex = torg; + tspivot(*testtri, edge1); + lprev(*testtri, sametesttri); + tspivot(sametesttri, edge2); + } else { + /* The edge opposite the destination is shortest. */ + /* Find the square of the cosine of the angle at the destination. */ + angle = dxod * dxda + dyod * dyda; + angle = angle * angle / (apexlen * orglen); + anglevertex = tdest; + tspivot(*testtri, edge1); + lnext(*testtri, sametesttri); + tspivot(sametesttri, edge2); + } + /* Check if both edges that form the angle are segments. */ + if ((edge1.sh != dummysh) && (edge2.sh != dummysh)) { + /* The angle is a segment intersection. */ + if ((angle > 0.9924) && !quiet) { /* Roughly 5 degrees. */ + if (angle > 1.0) { + /* Beware of a floating exception in acos(). */ + angle = 1.0; + } + /* Find the actual angle in degrees, for printing. */ + angle = acos(sqrt(angle)) * (180.0 / PI); + printf( + "Warning: Small angle (%.4g degrees) between segments at point\n", + angle); + printf(" (%.12g, %.12g)\n", anglevertex[0], anglevertex[1]); + } + /* Don't add this bad triangle to the list; there's nothing that */ + /* can be done about a small angle between two segments. */ + angle = 0.0; + } + /* Check whether the angle is smaller than permitted. */ + if (angle > goodangle) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + return; + } + if (vararea || fixedarea) { + /* Check whether the area is larger than permitted. */ + area = 0.5 * (dxod * dyda - dyod * dxda); + if (fixedarea && (area > maxarea)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + } else if (vararea) { + /* Nonpositive area constraints are treated as unconstrained. */ + if ((area > areabound(*testtri)) && (areabound(*testtri) > 0.0)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + } + } + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality testing routines end here *********/ + +/********* Point location routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* makepointmap() Construct a mapping from points to triangles to improve */ +/* the speed of point location for segment insertion. */ +/* */ +/* Traverses all the triangles, and provides each corner of each triangle */ +/* with a pointer to that triangle. Of course, pointers will be */ +/* overwritten by other pointers because (almost) each point is a corner */ +/* of several triangles, but in the end every point will point to some */ +/* triangle that contains it. */ +/* */ +/*****************************************************************************/ + +void makepointmap() +{ + struct triedge triangleloop; + point triorg; + + if (verbose) { + printf(" Constructing mapping from points to triangles.\n"); + } + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three points of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + setpoint2tri(triorg, encode(triangleloop)); + } + triangleloop.tri = triangletraverse(); + } +} + +/*****************************************************************************/ +/* */ +/* preciselocate() Find a triangle or edge containing a given point. */ +/* */ +/* Begins its search from `searchtri'. It is important that `searchtri' */ +/* be a handle with the property that `searchpoint' is strictly to the left */ +/* of the edge denoted by `searchtri', or is collinear with that edge and */ +/* does not intersect that edge. (In particular, `searchpoint' should not */ +/* be the origin or destination of that edge.) */ +/* */ +/* These conditions are imposed because preciselocate() is normally used in */ +/* one of two situations: */ +/* */ +/* (1) To try to find the location to insert a new point. Normally, we */ +/* know an edge that the point is strictly to the left of. In the */ +/* incremental Delaunay algorithm, that edge is a bounding box edge. */ +/* In Ruppert's Delaunay refinement algorithm for quality meshing, */ +/* that edge is the shortest edge of the triangle whose circumcenter */ +/* is being inserted. */ +/* */ +/* (2) To try to find an existing point. In this case, any edge on the */ +/* convex hull is a good starting edge. The possibility that the */ +/* vertex one seeks is an endpoint of the starting edge must be */ +/* screened out before preciselocate() is called. */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* This implementation differs from that given by Guibas and Stolfi. It */ +/* walks from triangle to triangle, crossing an edge only if `searchpoint' */ +/* is on the other side of the line containing that edge. After entering */ +/* a triangle, there are two edges by which one can leave that triangle. */ +/* If both edges are valid (`searchpoint' is on the other side of both */ +/* edges), one of the two is chosen by drawing a line perpendicular to */ +/* the entry edge (whose endpoints are `forg' and `fdest') passing through */ +/* `fapex'. Depending on which side of this perpendicular `searchpoint' */ +/* falls on, an exit edge is chosen. */ +/* */ +/* This implementation is empirically faster than the Guibas and Stolfi */ +/* point location routine (which I originally used), which tends to spiral */ +/* in toward its target. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* However, it can still be used to find the circumcenter of a triangle, as */ +/* long as the search is begun from the triangle in question. */ +/* */ +/*****************************************************************************/ + +enum locateresult preciselocate(searchpoint, searchtri) +point searchpoint; +struct triedge *searchtri; +{ + struct triedge backtracktri; + point forg, fdest, fapex; + point swappoint; + REAL orgorient, destorient; + int moveleft; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 2) { + printf(" Searching for point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Where are we? */ + org(*searchtri, forg); + dest(*searchtri, fdest); + apex(*searchtri, fapex); + while (1) { + if (verbose > 2) { + printf(" At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]); + } + /* Check whether the apex is the point we seek. */ + if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) { + lprevself(*searchtri); + return ONVERTEX; + } + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's destination? */ + destorient = counterclockwise(forg, fapex, searchpoint); + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's origin? */ + orgorient = counterclockwise(fapex, fdest, searchpoint); + if (destorient > 0.0) { + if (orgorient > 0.0) { + /* Move left if the inner product of (fapex - searchpoint) and */ + /* (fdest - forg) is positive. This is equivalent to drawing */ + /* a line perpendicular to the line (forg, fdest) passing */ + /* through `fapex', and determining which side of this line */ + /* `searchpoint' falls on. */ + moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) + + (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0; + } else { + moveleft = 1; + } + } else { + if (orgorient > 0.0) { + moveleft = 0; + } else { + /* The point we seek must be on the boundary of or inside this */ + /* triangle. */ + if (destorient == 0.0) { + lprevself(*searchtri); + return ONEDGE; + } + if (orgorient == 0.0) { + lnextself(*searchtri); + return ONEDGE; + } + return INTRIANGLE; + } + } + + /* Move to another triangle. Leave a trace `backtracktri' in case */ + /* floating-point roundoff or some such bogey causes us to walk */ + /* off a boundary of the triangulation. We can just bounce off */ + /* the boundary as if it were an elastic band. */ + if (moveleft) { + lprev(*searchtri, backtracktri); + fdest = fapex; + } else { + lnext(*searchtri, backtracktri); + forg = fapex; + } + sym(backtracktri, *searchtri); + + /* Check for walking off the edge. */ + if (searchtri->tri == dummytri) { + /* Turn around. */ + triedgecopy(backtracktri, *searchtri); + swappoint = forg; + forg = fdest; + fdest = swappoint; + apex(*searchtri, fapex); + /* Check if the point really is beyond the triangulation boundary. */ + destorient = counterclockwise(forg, fapex, searchpoint); + orgorient = counterclockwise(fapex, fdest, searchpoint); + if ((orgorient < 0.0) && (destorient < 0.0)) { + return OUTSIDE; + } + } else { + apex(*searchtri, fapex); + } + } +} + +/*****************************************************************************/ +/* */ +/* locate() Find a triangle or edge containing a given point. */ +/* */ +/* Searching begins from one of: the input `searchtri', a recently */ +/* encountered triangle `recenttri', or from a triangle chosen from a */ +/* random sample. The choice is made by determining which triangle's */ +/* origin is closest to the point we are searcing for. Normally, */ +/* `searchtri' should be a handle on the convex hull of the triangulation. */ +/* */ +/* Details on the random sampling method can be found in the Mucke, Saias, */ +/* and Zhu paper cited in the header of this code. */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* */ +/*****************************************************************************/ + +enum locateresult locate(searchpoint, searchtri) +point searchpoint; +struct triedge *searchtri; +{ + VOID **sampleblock; + triangle *firsttri; + struct triedge sampletri; + point torg, tdest; + unsigned long alignptr; + REAL searchdist, dist; + REAL ahead; + long sampleblocks, samplesperblock, samplenum; + long triblocks; + long i, j; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 2) { + printf(" Randomly sampling for a triangle near point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Record the distance from the suggested starting triangle to the */ + /* point we seek. */ + org(*searchtri, torg); + searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (verbose > 2) { + printf(" Boundary triangle has origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + + /* If a recently encountered triangle has been recorded and has not been */ + /* deallocated, test it as a good starting point. */ + if (recenttri.tri != (triangle *) NULL) { + if (recenttri.tri[3] != (triangle) NULL) { + org(recenttri, torg); + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + triedgecopy(recenttri, *searchtri); + return ONVERTEX; + } + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + triedgecopy(recenttri, *searchtri); + searchdist = dist; + if (verbose > 2) { + printf(" Choosing recent triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + + /* The number of random samples taken is proportional to the cube root of */ + /* the number of triangles in the mesh. The next bit of code assumes */ + /* that the number of triangles increases monotonically. */ + while (SAMPLEFACTOR * samples * samples * samples < triangles.items) { + samples++; + } + triblocks = (triangles.maxitems + TRIPERBLOCK - 1) / TRIPERBLOCK; + samplesperblock = 1 + (samples / triblocks); + sampleblocks = samples / samplesperblock; + sampleblock = triangles.firstblock; + sampletri.orient = 0; + for (i = 0; i < sampleblocks; i++) { + alignptr = (unsigned long) (sampleblock + 1); + firsttri = (triangle *) (alignptr + (unsigned long) triangles.alignbytes + - (alignptr % (unsigned long) triangles.alignbytes)); + for (j = 0; j < samplesperblock; j++) { + if (i == triblocks - 1) { + samplenum = randomnation((int) + (triangles.maxitems - (i * TRIPERBLOCK))); + } else { + samplenum = randomnation(TRIPERBLOCK); + } + sampletri.tri = (triangle *) + (firsttri + (samplenum * triangles.itemwords)); + if (sampletri.tri[3] != (triangle) NULL) { + org(sampletri, torg); + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + triedgecopy(sampletri, *searchtri); + searchdist = dist; + if (verbose > 2) { + printf(" Choosing triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + sampleblock = (VOID **) *sampleblock; + } + /* Where are we? */ + org(*searchtri, torg); + dest(*searchtri, tdest); + /* Check the starting triangle's vertices. */ + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + return ONVERTEX; + } + if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) { + lnextself(*searchtri); + return ONVERTEX; + } + /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */ + ahead = counterclockwise(torg, tdest, searchpoint); + if (ahead < 0.0) { + /* Turn around so that `searchpoint' is to the left of the */ + /* edge specified by `searchtri'. */ + symself(*searchtri); + } else if (ahead == 0.0) { + /* Check if `searchpoint' is between `torg' and `tdest'. */ + if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0])) + && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) { + return ONEDGE; + } + } + return preciselocate(searchpoint, searchtri); +} + +/** **/ +/** **/ +/********* Point location routines end here *********/ + +/********* Mesh transformation routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* insertshelle() Create a new shell edge and insert it between two */ +/* triangles. */ +/* */ +/* The new shell edge is inserted at the edge described by the handle */ +/* `tri'. Its vertices are properly initialized. The marker `shellemark' */ +/* is applied to the shell edge and, if appropriate, its vertices. */ +/* */ +/*****************************************************************************/ + +void insertshelle(tri, shellemark) +struct triedge *tri; /* Edge at which to insert the new shell edge. */ +int shellemark; /* Marker for the new shell edge. */ +{ + struct triedge oppotri; + struct edge newshelle; + point triorg, tridest; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Mark points if possible. */ + org(*tri, triorg); + dest(*tri, tridest); + if (pointmark(triorg) == 0) { + setpointmark(triorg, shellemark); + } + if (pointmark(tridest) == 0) { + setpointmark(tridest, shellemark); + } + /* Check if there's already a shell edge here. */ + tspivot(*tri, newshelle); + if (newshelle.sh == dummysh) { + /* Make new shell edge and initialize its vertices. */ + makeshelle(&newshelle); + setsorg(newshelle, tridest); + setsdest(newshelle, triorg); + /* Bond new shell edge to the two triangles it is sandwiched between. */ + /* Note that the facing triangle `oppotri' might be equal to */ + /* `dummytri' (outer space), but the new shell edge is bonded to it */ + /* all the same. */ + tsbond(*tri, newshelle); + sym(*tri, oppotri); + ssymself(newshelle); + tsbond(oppotri, newshelle); + setmark(newshelle, shellemark); + if (verbose > 2) { + printf(" Inserting new "); + printshelle(&newshelle); + } + } else { + if (mark(newshelle) == 0) { + setmark(newshelle, shellemark); + } + } +} + +/*****************************************************************************/ +/* */ +/* Terminology */ +/* */ +/* A "local transformation" replaces a small set of triangles with another */ +/* set of triangles. This may or may not involve inserting or deleting a */ +/* point. */ +/* */ +/* The term "casing" is used to describe the set of triangles that are */ +/* attached to the triangles being transformed, but are not transformed */ +/* themselves. Think of the casing as a fixed hollow structure inside */ +/* which all the action happens. A "casing" is only defined relative to */ +/* a single transformation; each occurrence of a transformation will */ +/* involve a different casing. */ +/* */ +/* A "shell" is similar to a "casing". The term "shell" describes the set */ +/* of shell edges (if any) that are attached to the triangles being */ +/* transformed. However, I sometimes use "shell" to refer to a single */ +/* shell edge, so don't get confused. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* flip() Transform two triangles to two different triangles by flipping */ +/* an edge within a quadrilateral. */ +/* */ +/* Imagine the original triangles, abc and bad, oriented so that the */ +/* shared edge ab lies in a horizontal plane, with the point b on the left */ +/* and the point a on the right. The point c lies below the edge, and the */ +/* point d lies above the edge. The `flipedge' handle holds the edge ab */ +/* of triangle abc, and is directed left, from vertex a to vertex b. */ +/* */ +/* The triangles abc and bad are deleted and replaced by the triangles cdb */ +/* and dca. The triangles that represent abc and bad are NOT deallocated; */ +/* they are reused for dca and cdb, respectively. Hence, any handles that */ +/* may have held the original triangles are still valid, although not */ +/* directed as they were before. */ +/* */ +/* Upon completion of this routine, the `flipedge' handle holds the edge */ +/* dc of triangle dca, and is directed down, from vertex d to vertex c. */ +/* (Hence, the two triangles have rotated counterclockwise.) */ +/* */ +/* WARNING: This transformation is geometrically valid only if the */ +/* quadrilateral adbc is convex. Furthermore, this transformation is */ +/* valid only if there is not a shell edge between the triangles abc and */ +/* bad. This routine does not check either of these preconditions, and */ +/* it is the responsibility of the calling routine to ensure that they are */ +/* met. If they are not, the streets shall be filled with wailing and */ +/* gnashing of teeth. */ +/* */ +/*****************************************************************************/ + +void flip(flipedge) +struct triedge *flipedge; /* Handle for the triangle abc. */ +{ + struct triedge botleft, botright; + struct triedge topleft, topright; + struct triedge top; + struct triedge botlcasing, botrcasing; + struct triedge toplcasing, toprcasing; + struct edge botlshelle, botrshelle; + struct edge toplshelle, toprshelle; + point leftpoint, rightpoint, botpoint; + point farpoint; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Identify the vertices of the quadrilateral. */ + org(*flipedge, rightpoint); + dest(*flipedge, leftpoint); + apex(*flipedge, botpoint); + sym(*flipedge, top); +#ifdef SELF_CHECK + if (top.tri == dummytri) { + printf("Internal error in flip(): Attempt to flip on boundary.\n"); + lnextself(*flipedge); + return; + } + if (checksegments) { + tspivot(*flipedge, toplshelle); + if (toplshelle.sh != dummysh) { + printf("Internal error in flip(): Attempt to flip a segment.\n"); + lnextself(*flipedge); + return; + } + } +#endif /* SELF_CHECK */ + apex(top, farpoint); + + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(*flipedge, botleft); + sym(botleft, botlcasing); + lprev(*flipedge, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + + if (checksegments) { + /* Check for shell edges and rebond them to the quadrilateral. */ + tspivot(topleft, toplshelle); + tspivot(botleft, botlshelle); + tspivot(botright, botrshelle); + tspivot(topright, toprshelle); + if (toplshelle.sh == dummysh) { + tsdissolve(topright); + } else { + tsbond(topright, toplshelle); + } + if (botlshelle.sh == dummysh) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlshelle); + } + if (botrshelle.sh == dummysh) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrshelle); + } + if (toprshelle.sh == dummysh) { + tsdissolve(botright); + } else { + tsbond(botright, toprshelle); + } + } + + /* New point assignments for the rotated quadrilateral. */ + setorg(*flipedge, farpoint); + setdest(*flipedge, botpoint); + setapex(*flipedge, rightpoint); + setorg(top, botpoint); + setdest(top, farpoint); + setapex(top, leftpoint); + if (verbose > 2) { + printf(" Edge flip results in left "); + lnextself(topleft); + printtriangle(&topleft); + printf(" and right "); + printtriangle(flipedge); + } +} + +/*****************************************************************************/ +/* */ +/* insertsite() Insert a vertex into a Delaunay triangulation, */ +/* performing flips as necessary to maintain the Delaunay */ +/* property. */ +/* */ +/* The point `insertpoint' is located. If `searchtri.tri' is not NULL, */ +/* the search for the containing triangle begins from `searchtri'. If */ +/* `searchtri.tri' is NULL, a full point location procedure is called. */ +/* If `insertpoint' is found inside a triangle, the triangle is split into */ +/* three; if `insertpoint' lies on an edge, the edge is split in two, */ +/* thereby splitting the two adjacent triangles into four. Edge flips are */ +/* used to restore the Delaunay property. If `insertpoint' lies on an */ +/* existing vertex, no action is taken, and the value DUPLICATEPOINT is */ +/* returned. On return, `searchtri' is set to a handle whose origin is the */ +/* existing vertex. */ +/* */ +/* Normally, the parameter `splitedge' is set to NULL, implying that no */ +/* segment should be split. In this case, if `insertpoint' is found to */ +/* lie on a segment, no action is taken, and the value VIOLATINGPOINT is */ +/* returned. On return, `searchtri' is set to a handle whose primary edge */ +/* is the violated segment. */ +/* */ +/* If the calling routine wishes to split a segment by inserting a point in */ +/* it, the parameter `splitedge' should be that segment. In this case, */ +/* `searchtri' MUST be the triangle handle reached by pivoting from that */ +/* segment; no point location is done. */ +/* */ +/* `segmentflaws' and `triflaws' are flags that indicate whether or not */ +/* there should be checks for the creation of encroached segments or bad */ +/* quality faces. If a newly inserted point encroaches upon segments, */ +/* these segments are added to the list of segments to be split if */ +/* `segmentflaws' is set. If bad triangles are created, these are added */ +/* to the queue if `triflaws' is set. */ +/* */ +/* If a duplicate point or violated segment does not prevent the point */ +/* from being inserted, the return value will be ENCROACHINGPOINT if the */ +/* point encroaches upon a segment (and checking is enabled), or */ +/* SUCCESSFULPOINT otherwise. In either case, `searchtri' is set to a */ +/* handle whose origin is the newly inserted vertex. */ +/* */ +/* insertsite() does not use flip() for reasons of speed; some */ +/* information can be reused from edge flip to edge flip, like the */ +/* locations of shell edges. */ +/* */ +/*****************************************************************************/ + +enum insertsiteresult insertsite(insertpoint, searchtri, splitedge, + segmentflaws, triflaws) +point insertpoint; +struct triedge *searchtri; +struct edge *splitedge; +int segmentflaws; +int triflaws; +{ + struct triedge horiz; + struct triedge top; + struct triedge botleft, botright; + struct triedge topleft, topright; + struct triedge newbotleft, newbotright; + struct triedge newtopright; + struct triedge botlcasing, botrcasing; + struct triedge toplcasing, toprcasing; + struct triedge testtri; + struct edge botlshelle, botrshelle; + struct edge toplshelle, toprshelle; + struct edge brokenshelle; + struct edge checkshelle; + struct edge rightedge; + struct edge newedge; + struct edge *encroached; + point first; + point leftpoint, rightpoint, botpoint, toppoint, farpoint; + REAL attrib; + REAL area; + enum insertsiteresult success; + enum locateresult intersect; + int doflip; + int mirrorflag; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by spivot() and tspivot(). */ + + if (verbose > 1) { + printf(" Inserting (%.12g, %.12g).\n", insertpoint[0], insertpoint[1]); + } + if (splitedge == (struct edge *) NULL) { + /* Find the location of the point to be inserted. Check if a good */ + /* starting triangle has already been provided by the caller. */ + if (searchtri->tri == (triangle *) NULL) { + /* Find a boundary triangle. */ + horiz.tri = dummytri; + horiz.orient = 0; + symself(horiz); + /* Search for a triangle containing `insertpoint'. */ + intersect = locate(insertpoint, &horiz); + } else { + /* Start searching from the triangle provided by the caller. */ + triedgecopy(*searchtri, horiz); + intersect = preciselocate(insertpoint, &horiz); + } + } else { + /* The calling routine provides the edge in which the point is inserted. */ + triedgecopy(*searchtri, horiz); + intersect = ONEDGE; + } + if (intersect == ONVERTEX) { + /* There's already a vertex there. Return in `searchtri' a triangle */ + /* whose origin is the existing vertex. */ + triedgecopy(horiz, *searchtri); + triedgecopy(horiz, recenttri); + return DUPLICATEPOINT; + } + if ((intersect == ONEDGE) || (intersect == OUTSIDE)) { + /* The vertex falls on an edge or boundary. */ + if (checksegments && (splitedge == (struct edge *) NULL)) { + /* Check whether the vertex falls on a shell edge. */ + tspivot(horiz, brokenshelle); + if (brokenshelle.sh != dummysh) { + /* The vertex falls on a shell edge. */ + if (segmentflaws) { + if (nobisect == 0) { + /* Add the shell edge to the list of encroached segments. */ + encroached = (struct edge *) poolalloc(&badsegments); + shellecopy(brokenshelle, *encroached); + } else if ((nobisect == 1) && (intersect == ONEDGE)) { + /* This segment may be split only if it is an internal boundary. */ + sym(horiz, testtri); + if (testtri.tri != dummytri) { + /* Add the shell edge to the list of encroached segments. */ + encroached = (struct edge *) poolalloc(&badsegments); + shellecopy(brokenshelle, *encroached); + } + } + } + /* Return a handle whose primary edge contains the point, */ + /* which has not been inserted. */ + triedgecopy(horiz, *searchtri); + triedgecopy(horiz, recenttri); + return VIOLATINGPOINT; + } + } + /* Insert the point on an edge, dividing one triangle into two (if */ + /* the edge lies on a boundary) or two triangles into four. */ + lprev(horiz, botright); + sym(botright, botrcasing); + sym(horiz, topright); + /* Is there a second triangle? (Or does this edge lie on a boundary?) */ + mirrorflag = topright.tri != dummytri; + if (mirrorflag) { + lnextself(topright); + sym(topright, toprcasing); + maketriangle(&newtopright); + } else { + /* Splitting the boundary edge increases the number of boundary edges. */ + hullsize++; + } + maketriangle(&newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightpoint); + dest(horiz, leftpoint); + apex(horiz, botpoint); + setorg(newbotright, botpoint); + setdest(newbotright, rightpoint); + setapex(newbotright, insertpoint); + setorg(horiz, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of a new triangle. */ + setelemattribute(newbotright, i, elemattribute(botright, i)); + } + if (vararea) { + /* Set the area constraint of a new triangle. */ + setareabound(newbotright, areabound(botright)); + } + if (mirrorflag) { + dest(topright, toppoint); + setorg(newtopright, rightpoint); + setdest(newtopright, toppoint); + setapex(newtopright, insertpoint); + setorg(topright, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of another new triangle. */ + setelemattribute(newtopright, i, elemattribute(topright, i)); + } + if (vararea) { + /* Set the area constraint of another new triangle. */ + setareabound(newtopright, areabound(topright)); + } + } + + /* There may be shell edges that need to be bonded */ + /* to the new triangle(s). */ + if (checksegments) { + tspivot(botright, botrshelle); + if (botrshelle.sh != dummysh) { + tsdissolve(botright); + tsbond(newbotright, botrshelle); + } + if (mirrorflag) { + tspivot(topright, toprshelle); + if (toprshelle.sh != dummysh) { + tsdissolve(topright); + tsbond(newtopright, toprshelle); + } + } + } + + /* Bond the new triangle(s) to the surrounding triangles. */ + bond(newbotright, botrcasing); + lprevself(newbotright); + bond(newbotright, botright); + lprevself(newbotright); + if (mirrorflag) { + bond(newtopright, toprcasing); + lnextself(newtopright); + bond(newtopright, topright); + lnextself(newtopright); + bond(newtopright, newbotright); + } + + if (splitedge != (struct edge *) NULL) { + /* Split the shell edge into two. */ + setsdest(*splitedge, insertpoint); + ssymself(*splitedge); + spivot(*splitedge, rightedge); + insertshelle(&newbotright, mark(*splitedge)); + tspivot(newbotright, newedge); + sbond(*splitedge, newedge); + ssymself(newedge); + sbond(newedge, rightedge); + ssymself(*splitedge); + } + +#ifdef SELF_CHECK + if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge point insertion (bottom).\n"); + } + if (mirrorflag) { + if (counterclockwise(leftpoint, rightpoint, toppoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge point insertion (top).\n"); + } + if (counterclockwise(rightpoint, toppoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (top right).\n" + ); + } + if (counterclockwise(toppoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (top left).\n" + ); + } + } + if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (bottom left).\n" + ); + } + if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf( + " Clockwise triangle after edge point insertion (bottom right).\n"); + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Updating bottom left "); + printtriangle(&botright); + if (mirrorflag) { + printf(" Updating top left "); + printtriangle(&topright); + printf(" Creating top right "); + printtriangle(&newtopright); + } + printf(" Creating bottom right "); + printtriangle(&newbotright); + } + + /* Position `horiz' on the first edge to check for */ + /* the Delaunay property. */ + lnextself(horiz); + } else { + /* Insert the point in a triangle, splitting it into three. */ + lnext(horiz, botleft); + lprev(horiz, botright); + sym(botleft, botlcasing); + sym(botright, botrcasing); + maketriangle(&newbotleft); + maketriangle(&newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightpoint); + dest(horiz, leftpoint); + apex(horiz, botpoint); + setorg(newbotleft, leftpoint); + setdest(newbotleft, botpoint); + setapex(newbotleft, insertpoint); + setorg(newbotright, botpoint); + setdest(newbotright, rightpoint); + setapex(newbotright, insertpoint); + setapex(horiz, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of the new triangles. */ + attrib = elemattribute(horiz, i); + setelemattribute(newbotleft, i, attrib); + setelemattribute(newbotright, i, attrib); + } + if (vararea) { + /* Set the area constraint of the new triangles. */ + area = areabound(horiz); + setareabound(newbotleft, area); + setareabound(newbotright, area); + } + + /* There may be shell edges that need to be bonded */ + /* to the new triangles. */ + if (checksegments) { + tspivot(botleft, botlshelle); + if (botlshelle.sh != dummysh) { + tsdissolve(botleft); + tsbond(newbotleft, botlshelle); + } + tspivot(botright, botrshelle); + if (botrshelle.sh != dummysh) { + tsdissolve(botright); + tsbond(newbotright, botrshelle); + } + } + + /* Bond the new triangles to the surrounding triangles. */ + bond(newbotleft, botlcasing); + bond(newbotright, botrcasing); + lnextself(newbotleft); + lprevself(newbotright); + bond(newbotleft, newbotright); + lnextself(newbotleft); + bond(botleft, newbotleft); + lprevself(newbotright); + bond(botright, newbotright); + +#ifdef SELF_CHECK + if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to point insertion.\n"); + } + if (counterclockwise(rightpoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (top).\n"); + } + if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (left).\n"); + } + if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (right).\n"); + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Updating top "); + printtriangle(&horiz); + printf(" Creating left "); + printtriangle(&newbotleft); + printf(" Creating right "); + printtriangle(&newbotright); + } + } + + /* The insertion is successful by default, unless an encroached */ + /* edge is found. */ + success = SUCCESSFULPOINT; + /* Circle around the newly inserted vertex, checking each edge opposite */ + /* it for the Delaunay property. Non-Delaunay edges are flipped. */ + /* `horiz' is always the edge being checked. `first' marks where to */ + /* stop circling. */ + org(horiz, first); + rightpoint = first; + dest(horiz, leftpoint); + /* Circle until finished. */ + while (1) { + /* By default, the edge will be flipped. */ + doflip = 1; + if (checksegments) { + /* Check for a segment, which cannot be flipped. */ + tspivot(horiz, checkshelle); + if (checkshelle.sh != dummysh) { + /* The edge is a segment and cannot be flipped. */ + doflip = 0; +#ifndef CDT_ONLY + if (segmentflaws) { + /* Does the new point encroach upon this segment? */ + if (checkedge4encroach(&checkshelle)) { + success = ENCROACHINGPOINT; + } + } +#endif /* not CDT_ONLY */ + } + } + if (doflip) { + /* Check if the edge is a boundary edge. */ + sym(horiz, top); + if (top.tri == dummytri) { + /* The edge is a boundary edge and cannot be flipped. */ + doflip = 0; + } else { + /* Find the point on the other side of the edge. */ + apex(top, farpoint); + /* In the incremental Delaunay triangulation algorithm, any of */ + /* `leftpoint', `rightpoint', and `farpoint' could be vertices */ + /* of the triangular bounding box. These vertices must be */ + /* treated as if they are infinitely distant, even though their */ + /* "coordinates" are not. */ + if ((leftpoint == infpoint1) || (leftpoint == infpoint2) + || (leftpoint == infpoint3)) { + /* `leftpoint' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farpoint' might be */ + /* infinite as well, but trust me, this same condition */ + /* should be applied. */ + doflip = counterclockwise(insertpoint, rightpoint, farpoint) > 0.0; + } else if ((rightpoint == infpoint1) || (rightpoint == infpoint2) + || (rightpoint == infpoint3)) { + /* `rightpoint' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farpoint' might be */ + /* infinite as well, but trust me, this same condition */ + /* should be applied. */ + doflip = counterclockwise(farpoint, leftpoint, insertpoint) > 0.0; + } else if ((farpoint == infpoint1) || (farpoint == infpoint2) + || (farpoint == infpoint3)) { + /* `farpoint' is infinitely distant and cannot be inside */ + /* the circumcircle of the triangle `horiz'. */ + doflip = 0; + } else { + /* Test whether the edge is locally Delaunay. */ + doflip = incircle(leftpoint, insertpoint, rightpoint, farpoint) + > 0.0; + } + if (doflip) { + /* We made it! Flip the edge `horiz' by rotating its containing */ + /* quadrilateral (the two triangles adjacent to `horiz'). */ + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(horiz, botleft); + sym(botleft, botlcasing); + lprev(horiz, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + if (checksegments) { + /* Check for shell edges and rebond them to the quadrilateral. */ + tspivot(topleft, toplshelle); + tspivot(botleft, botlshelle); + tspivot(botright, botrshelle); + tspivot(topright, toprshelle); + if (toplshelle.sh == dummysh) { + tsdissolve(topright); + } else { + tsbond(topright, toplshelle); + } + if (botlshelle.sh == dummysh) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlshelle); + } + if (botrshelle.sh == dummysh) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrshelle); + } + if (toprshelle.sh == dummysh) { + tsdissolve(botright); + } else { + tsbond(botright, toprshelle); + } + } + /* New point assignments for the rotated quadrilateral. */ + setorg(horiz, farpoint); + setdest(horiz, insertpoint); + setapex(horiz, rightpoint); + setorg(top, insertpoint); + setdest(top, farpoint); + setapex(top, leftpoint); + for (i = 0; i < eextras; i++) { + /* Take the average of the two triangles' attributes. */ + attrib = (REAL)(0.5 * (elemattribute(top, i) + elemattribute(horiz, i))); + setelemattribute(top, i, attrib); + setelemattribute(horiz, i, attrib); + } + if (vararea) { + if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) { + area = -1.0; + } else { + /* Take the average of the two triangles' area constraints. */ + /* This prevents small area constraints from migrating a */ + /* long, long way from their original location due to flips. */ + area = (REAL)(0.5 * (areabound(top) + areabound(horiz))); + } + setareabound(top, area); + setareabound(horiz, area); + } +#ifdef SELF_CHECK + if (insertpoint != (point) NULL) { + if (counterclockwise(leftpoint, insertpoint, rightpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge flip (bottom).\n"); + } + /* The following test has been removed because constrainededge() */ + /* sometimes generates inverted triangles that insertsite() */ + /* removes. */ +/* + if (counterclockwise(rightpoint, farpoint, leftpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge flip (top).\n"); + } +*/ + if (counterclockwise(farpoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge flip (left).\n"); + } + if (counterclockwise(insertpoint, rightpoint, farpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge flip (right).\n"); + } + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Edge flip results in left "); + lnextself(topleft); + printtriangle(&topleft); + printf(" and right "); + printtriangle(&horiz); + } + /* On the next iterations, consider the two edges that were */ + /* exposed (this is, are now visible to the newly inserted */ + /* point) by the edge flip. */ + lprevself(horiz); + leftpoint = farpoint; + } + } + } + if (!doflip) { + /* The handle `horiz' is accepted as locally Delaunay. */ +#ifndef CDT_ONLY + if (triflaws) { + /* Check the triangle `horiz' for quality. */ + testtriangle(&horiz); + } +#endif /* not CDT_ONLY */ + /* Look for the next edge around the newly inserted point. */ + lnextself(horiz); + sym(horiz, testtri); + /* Check for finishing a complete revolution about the new point, or */ + /* falling off the edge of the triangulation. The latter will */ + /* happen when a point is inserted at a boundary. */ + if ((leftpoint == first) || (testtri.tri == dummytri)) { + /* We're done. Return a triangle whose origin is the new point. */ + lnext(horiz, *searchtri); + lnext(horiz, recenttri); + return success; + } + /* Finish finding the next edge around the newly inserted point. */ + lnext(testtri, horiz); + rightpoint = leftpoint; + dest(horiz, leftpoint); + } + } +} + +/*****************************************************************************/ +/* */ +/* triangulatepolygon() Find the Delaunay triangulation of a polygon that */ +/* has a certain "nice" shape. This includes the */ +/* polygons that result from deletion of a point or */ +/* insertion of a segment. */ +/* */ +/* This is a conceptually difficult routine. The starting assumption is */ +/* that we have a polygon with n sides. n - 1 of these sides are currently */ +/* represented as edges in the mesh. One side, called the "base", need not */ +/* be. */ +/* */ +/* Inside the polygon is a structure I call a "fan", consisting of n - 1 */ +/* triangles that share a common origin. For each of these triangles, the */ +/* edge opposite the origin is one of the sides of the polygon. The */ +/* primary edge of each triangle is the edge directed from the origin to */ +/* the destination; note that this is not the same edge that is a side of */ +/* the polygon. `firstedge' is the primary edge of the first triangle. */ +/* From there, the triangles follow in counterclockwise order about the */ +/* polygon, until `lastedge', the primary edge of the last triangle. */ +/* `firstedge' and `lastedge' are probably connected to other triangles */ +/* beyond the extremes of the fan, but their identity is not important, as */ +/* long as the fan remains connected to them. */ +/* */ +/* Imagine the polygon oriented so that its base is at the bottom. This */ +/* puts `firstedge' on the far right, and `lastedge' on the far left. */ +/* The right vertex of the base is the destination of `firstedge', and the */ +/* left vertex of the base is the apex of `lastedge'. */ +/* */ +/* The challenge now is to find the right sequence of edge flips to */ +/* transform the fan into a Delaunay triangulation of the polygon. Each */ +/* edge flip effectively removes one triangle from the fan, committing it */ +/* to the polygon. The resulting polygon has one fewer edge. If `doflip' */ +/* is set, the final flip will be performed, resulting in a fan of one */ +/* (useless?) triangle. If `doflip' is not set, the final flip is not */ +/* performed, resulting in a fan of two triangles, and an unfinished */ +/* triangular polygon that is not yet filled out with a single triangle. */ +/* On completion of the routine, `lastedge' is the last remaining triangle, */ +/* or the leftmost of the last two. */ +/* */ +/* Although the flips are performed in the order described above, the */ +/* decisions about what flips to perform are made in precisely the reverse */ +/* order. The recursive triangulatepolygon() procedure makes a decision, */ +/* uses up to two recursive calls to triangulate the "subproblems" */ +/* (polygons with fewer edges), and then performs an edge flip. */ +/* */ +/* The "decision" it makes is which vertex of the polygon should be */ +/* connected to the base. This decision is made by testing every possible */ +/* vertex. Once the best vertex is found, the two edges that connect this */ +/* vertex to the base become the bases for two smaller polygons. These */ +/* are triangulated recursively. Unfortunately, this approach can take */ +/* O(n^2) time not only in the worst case, but in many common cases. It's */ +/* rarely a big deal for point deletion, where n is rarely larger than ten, */ +/* but it could be a big deal for segment insertion, especially if there's */ +/* a lot of long segments that each cut many triangles. I ought to code */ +/* a faster algorithm some time. */ +/* */ +/* The `edgecount' parameter is the number of sides of the polygon, */ +/* including its base. `triflaws' is a flag that determines whether the */ +/* new triangles should be tested for quality, and enqueued if they are */ +/* bad. */ +/* */ +/*****************************************************************************/ + +void triangulatepolygon(firstedge, lastedge, edgecount, doflip, triflaws) +struct triedge *firstedge; +struct triedge *lastedge; +int edgecount; +int doflip; +int triflaws; +{ + struct triedge testtri; + struct triedge besttri; + struct triedge tempedge; + point leftbasepoint, rightbasepoint; + point testpoint; + point bestpoint; + int bestnumber; + int i; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + /* Identify the base vertices. */ + apex(*lastedge, leftbasepoint); + dest(*firstedge, rightbasepoint); + if (verbose > 2) { + printf(" Triangulating interior polygon at edge\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", leftbasepoint[0], + leftbasepoint[1], rightbasepoint[0], rightbasepoint[1]); + } + /* Find the best vertex to connect the base to. */ + onext(*firstedge, besttri); + dest(besttri, bestpoint); + triedgecopy(besttri, testtri); + bestnumber = 1; + for (i = 2; i <= edgecount - 2; i++) { + onextself(testtri); + dest(testtri, testpoint); + /* Is this a better vertex? */ + if (incircle(leftbasepoint, rightbasepoint, bestpoint, testpoint) > 0.0) { + triedgecopy(testtri, besttri); + bestpoint = testpoint; + bestnumber = i; + } + } + if (verbose > 2) { + printf(" Connecting edge to (%.12g, %.12g)\n", bestpoint[0], + bestpoint[1]); + } + if (bestnumber > 1) { + /* Recursively triangulate the smaller polygon on the right. */ + oprev(besttri, tempedge); + triangulatepolygon(firstedge, &tempedge, bestnumber + 1, 1, triflaws); + } + if (bestnumber < edgecount - 2) { + /* Recursively triangulate the smaller polygon on the left. */ + sym(besttri, tempedge); + triangulatepolygon(&besttri, lastedge, edgecount - bestnumber, 1, + triflaws); + /* Find `besttri' again; it may have been lost to edge flips. */ + sym(tempedge, besttri); + } + if (doflip) { + /* Do one final edge flip. */ + flip(&besttri); +#ifndef CDT_ONLY + if (triflaws) { + /* Check the quality of the newly committed triangle. */ + sym(besttri, testtri); + testtriangle(&testtri); + } +#endif /* not CDT_ONLY */ + } + /* Return the base triangle. */ + triedgecopy(besttri, *lastedge); +} + +/*****************************************************************************/ +/* */ +/* deletesite() Delete a vertex from a Delaunay triangulation, ensuring */ +/* that the triangulation remains Delaunay. */ +/* */ +/* The origin of `deltri' is deleted. The union of the triangles adjacent */ +/* to this point is a polygon, for which the Delaunay triangulation is */ +/* found. Two triangles are removed from the mesh. */ +/* */ +/* Only interior points that do not lie on segments (shell edges) or */ +/* boundaries may be deleted. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void deletesite(deltri) +struct triedge *deltri; +{ + struct triedge countingtri; + struct triedge firstedge, lastedge; + struct triedge deltriright; + struct triedge lefttri, righttri; + struct triedge leftcasing, rightcasing; + struct edge leftshelle, rightshelle; + point delpoint; + point neworg; + int edgecount; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*deltri, delpoint); + if (verbose > 1) { + printf(" Deleting (%.12g, %.12g).\n", delpoint[0], delpoint[1]); + } + pointdealloc(delpoint); + + /* Count the degree of the point being deleted. */ + onext(*deltri, countingtri); + edgecount = 1; + while (!triedgeequal(*deltri, countingtri)) { +#ifdef SELF_CHECK + if (countingtri.tri == dummytri) { + printf("Internal error in deletesite():\n"); + printf(" Attempt to delete boundary point.\n"); + internalerror(); + } +#endif /* SELF_CHECK */ + edgecount++; + onextself(countingtri); + } + +#ifdef SELF_CHECK + if (edgecount < 3) { + printf("Internal error in deletesite():\n Point has degree %d.\n", + edgecount); + internalerror(); + } +#endif /* SELF_CHECK */ + if (edgecount > 3) { + /* Triangulate the polygon defined by the union of all triangles */ + /* adjacent to the point being deleted. Check the quality of */ + /* the resulting triangles. */ + onext(*deltri, firstedge); + oprev(*deltri, lastedge); + triangulatepolygon(&firstedge, &lastedge, edgecount, 0, !nobisect); + } + /* Splice out two triangles. */ + lprev(*deltri, deltriright); + dnext(*deltri, lefttri); + sym(lefttri, leftcasing); + oprev(deltriright, righttri); + sym(righttri, rightcasing); + bond(*deltri, leftcasing); + bond(deltriright, rightcasing); + tspivot(lefttri, leftshelle); + if (leftshelle.sh != dummysh) { + tsbond(*deltri, leftshelle); + } + tspivot(righttri, rightshelle); + if (rightshelle.sh != dummysh) { + tsbond(deltriright, rightshelle); + } + + /* Set the new origin of `deltri' and check its quality. */ + org(lefttri, neworg); + setorg(*deltri, neworg); + if (!nobisect) { + testtriangle(deltri); + } + + /* Delete the two spliced-out triangles. */ + triangledealloc(lefttri.tri); + triangledealloc(righttri.tri); +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh transformation routines end here *********/ + +/********* Divide-and-conquer Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* The divide-and-conquer bounding box */ +/* */ +/* I originally implemented the divide-and-conquer and incremental Delaunay */ +/* triangulations using the edge-based data structure presented by Guibas */ +/* and Stolfi. Switching to a triangle-based data structure doubled the */ +/* speed. However, I had to think of a few extra tricks to maintain the */ +/* elegance of the original algorithms. */ +/* */ +/* The "bounding box" used by my variant of the divide-and-conquer */ +/* algorithm uses one triangle for each edge of the convex hull of the */ +/* triangulation. These bounding triangles all share a common apical */ +/* vertex, which is represented by NULL and which represents nothing. */ +/* The bounding triangles are linked in a circular fan about this NULL */ +/* vertex, and the edges on the convex hull of the triangulation appear */ +/* opposite the NULL vertex. You might find it easiest to imagine that */ +/* the NULL vertex is a point in 3D space behind the center of the */ +/* triangulation, and that the bounding triangles form a sort of cone. */ +/* */ +/* This bounding box makes it easy to represent degenerate cases. For */ +/* instance, the triangulation of two vertices is a single edge. This edge */ +/* is represented by two bounding box triangles, one on each "side" of the */ +/* edge. These triangles are also linked together in a fan about the NULL */ +/* vertex. */ +/* */ +/* The bounding box also makes it easy to traverse the convex hull, as the */ +/* divide-and-conquer algorithm needs to do. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* pointsort() Sort an array of points by x-coordinate, using the */ +/* y-coordinate as a secondary key. */ +/* */ +/* Uses quicksort. Randomized O(n log n) time. No, I did not make any of */ +/* the usual quicksort mistakes. */ +/* */ +/*****************************************************************************/ + +void pointsort(sortarray, arraysize) +point *sortarray; +int arraysize; +{ + int left, right; + int pivot; + REAL pivotx, pivoty; + point temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][0] > sortarray[1][0]) || + ((sortarray[0][0] == sortarray[1][0]) && + (sortarray[0][1] > sortarray[1][1]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation(arraysize); + pivotx = sortarray[pivot][0]; + pivoty = sortarray[pivot][1]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a point whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][0] < pivotx) || + ((sortarray[left][0] == pivotx) && + (sortarray[left][1] < pivoty)))); + /* Search for a point whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][0] > pivotx) || + ((sortarray[right][0] == pivotx) && + (sortarray[right][1] > pivoty)))); + if (left < right) { + /* Swap the left and right points. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + if (left > 1) { + /* Recursively sort the left subset. */ + pointsort(sortarray, left); + } + if (right < arraysize - 2) { + /* Recursively sort the right subset. */ + pointsort(&sortarray[right + 1], arraysize - right - 1); + } +} + +/*****************************************************************************/ +/* */ +/* pointmedian() An order statistic algorithm, almost. Shuffles an array */ +/* of points so that the first `median' points occur */ +/* lexicographically before the remaining points. */ +/* */ +/* Uses the x-coordinate as the primary key if axis == 0; the y-coordinate */ +/* if axis == 1. Very similar to the pointsort() procedure, but runs in */ +/* randomized linear time. */ +/* */ +/*****************************************************************************/ + +void pointmedian(sortarray, arraysize, median, axis) +point *sortarray; +int arraysize; +int median; +int axis; +{ + int left, right; + int pivot; + REAL pivot1, pivot2; + point temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][axis] > sortarray[1][axis]) || + ((sortarray[0][axis] == sortarray[1][axis]) && + (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation(arraysize); + pivot1 = sortarray[pivot][axis]; + pivot2 = sortarray[pivot][1 - axis]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a point whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][axis] < pivot1) || + ((sortarray[left][axis] == pivot1) && + (sortarray[left][1 - axis] < pivot2)))); + /* Search for a point whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][axis] > pivot1) || + ((sortarray[right][axis] == pivot1) && + (sortarray[right][1 - axis] > pivot2)))); + if (left < right) { + /* Swap the left and right points. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + /* Unlike in pointsort(), at most one of the following */ + /* conditionals is true. */ + if (left > median) { + /* Recursively shuffle the left subset. */ + pointmedian(sortarray, left, median, axis); + } + if (right < median - 1) { + /* Recursively shuffle the right subset. */ + pointmedian(&sortarray[right + 1], arraysize - right - 1, + median - right - 1, axis); + } +} + +/*****************************************************************************/ +/* */ +/* alternateaxes() Sorts the points as appropriate for the divide-and- */ +/* conquer algorithm with alternating cuts. */ +/* */ +/* Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1. */ +/* For the base case, subsets containing only two or three points are */ +/* always sorted by x-coordinate. */ +/* */ +/*****************************************************************************/ + +void alternateaxes(sortarray, arraysize, axis) +point *sortarray; +int arraysize; +int axis; +{ + int divider; + + divider = arraysize >> 1; + if (arraysize <= 3) { + /* Recursive base case: subsets of two or three points will be */ + /* handled specially, and should always be sorted by x-coordinate. */ + axis = 0; + } + /* Partition with a horizontal or vertical cut. */ + pointmedian(sortarray, arraysize, divider, axis); + /* Recursively partition the subsets with a cross cut. */ + if (arraysize - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1 - axis); + } + alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis); + } +} + +/*****************************************************************************/ +/* */ +/* mergehulls() Merge two adjacent Delaunay triangulations into a */ +/* single Delaunay triangulation. */ +/* */ +/* This is similar to the algorithm given by Guibas and Stolfi, but uses */ +/* a triangle-based, rather than edge-based, data structure. */ +/* */ +/* The algorithm walks up the gap between the two triangulations, knitting */ +/* them together. As they are merged, some of their bounding triangles */ +/* are converted into real triangles of the triangulation. The procedure */ +/* pulls each hull's bounding triangles apart, then knits them together */ +/* like the teeth of two gears. The Delaunay property determines, at each */ +/* step, whether the next "tooth" is a bounding triangle of the left hull */ +/* or the right. When a bounding triangle becomes real, its apex is */ +/* changed from NULL to a real point. */ +/* */ +/* Only two new triangles need to be allocated. These become new bounding */ +/* triangles at the top and bottom of the seam. They are used to connect */ +/* the remaining bounding triangles (those that have not been converted */ +/* into real triangles) into a single fan. */ +/* */ +/* On entry, `farleft' and `innerleft' are bounding triangles of the left */ +/* triangulation. The origin of `farleft' is the leftmost vertex, and */ +/* the destination of `innerleft' is the rightmost vertex of the */ +/* triangulation. Similarly, `innerright' and `farright' are bounding */ +/* triangles of the right triangulation. The origin of `innerright' and */ +/* destination of `farright' are the leftmost and rightmost vertices. */ +/* */ +/* On completion, the origin of `farleft' is the leftmost vertex of the */ +/* merged triangulation, and the destination of `farright' is the rightmost */ +/* vertex. */ +/* */ +/*****************************************************************************/ + +void mergehulls(farleft, innerleft, innerright, farright, axis) +struct triedge *farleft; +struct triedge *innerleft; +struct triedge *innerright; +struct triedge *farright; +int axis; +{ + struct triedge leftcand, rightcand; + struct triedge baseedge; + struct triedge nextedge; + struct triedge sidecasing, topcasing, outercasing; + struct triedge checkedge; + point innerleftdest; + point innerrightorg; + point innerleftapex, innerrightapex; + point farleftpt, farrightpt; + point farleftapex, farrightapex; + point lowerleft, lowerright; + point upperleft, upperright; + point nextapex; + point checkvertex; + int changemade; + int badedge; + int leftfinished, rightfinished; + triangle ptr; /* Temporary variable used by sym(). */ + + dest(*innerleft, innerleftdest); + apex(*innerleft, innerleftapex); + org(*innerright, innerrightorg); + apex(*innerright, innerrightapex); + /* Special treatment for horizontal cuts. */ + if (dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + /* The pointers to the extremal points are shifted to point to the */ + /* topmost and bottommost point of each hull, rather than the */ + /* leftmost and rightmost points. */ + while (farleftapex[1] < farleftpt[1]) { + lnextself(*farleft); + symself(*farleft); + farleftpt = farleftapex; + apex(*farleft, farleftapex); + } + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > innerleftdest[1]) { + lnext(checkedge, *innerleft); + innerleftapex = innerleftdest; + innerleftdest = checkvertex; + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + } + while (innerrightapex[1] < innerrightorg[1]) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + } + sym(*farright, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > farrightpt[1]) { + lnext(checkedge, *farright); + farrightapex = farrightpt; + farrightpt = checkvertex; + sym(*farright, checkedge); + apex(checkedge, checkvertex); + } + } + /* Find a line tangent to and below both hulls. */ + do { + changemade = 0; + /* Make innerleftdest the "bottommost" point of the left hull. */ + if (counterclockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0) { + lprevself(*innerleft); + symself(*innerleft); + innerleftdest = innerleftapex; + apex(*innerleft, innerleftapex); + changemade = 1; + } + /* Make innerrightorg the "bottommost" point of the right hull. */ + if (counterclockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + changemade = 1; + } + } while (changemade); + /* Find the two candidates to be the next "gear tooth". */ + sym(*innerleft, leftcand); + sym(*innerright, rightcand); + /* Create the bottom new bounding triangle. */ + maketriangle(&baseedge); + /* Connect it to the bounding boxes of the left and right triangulations. */ + bond(baseedge, *innerleft); + lnextself(baseedge); + bond(baseedge, *innerright); + lnextself(baseedge); + setorg(baseedge, innerrightorg); + setdest(baseedge, innerleftdest); + /* Apex is intentionally left NULL. */ + if (verbose > 2) { + printf(" Creating base bounding "); + printtriangle(&baseedge); + } + /* Fix the extreme triangles if necessary. */ + org(*farleft, farleftpt); + if (innerleftdest == farleftpt) { + lnext(baseedge, *farleft); + } + dest(*farright, farrightpt); + if (innerrightorg == farrightpt) { + lprev(baseedge, *farright); + } + /* The vertices of the current knitting edge. */ + lowerleft = innerleftdest; + lowerright = innerrightorg; + /* The candidate vertices for knitting. */ + apex(leftcand, upperleft); + apex(rightcand, upperright); + /* Walk up the gap between the two triangulations, knitting them together. */ + while (1) { + /* Have we reached the top? (This isn't quite the right question, */ + /* because even though the left triangulation might seem finished now, */ + /* moving up on the right triangulation might reveal a new point of */ + /* the left triangulation. And vice-versa.) */ + leftfinished = counterclockwise(upperleft, lowerleft, lowerright) <= 0.0; + rightfinished = counterclockwise(upperright, lowerleft, lowerright) <= 0.0; + if (leftfinished && rightfinished) { + /* Create the top new bounding triangle. */ + maketriangle(&nextedge); + setorg(nextedge, lowerleft); + setdest(nextedge, lowerright); + /* Apex is intentionally left NULL. */ + /* Connect it to the bounding boxes of the two triangulations. */ + bond(nextedge, baseedge); + lnextself(nextedge); + bond(nextedge, rightcand); + lnextself(nextedge); + bond(nextedge, leftcand); + if (verbose > 2) { + printf(" Creating top bounding "); + printtriangle(&baseedge); + } + /* Special treatment for horizontal cuts. */ + if (dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + /* The pointers to the extremal points are restored to the leftmost */ + /* and rightmost points (rather than topmost and bottommost). */ + while (checkvertex[0] < farleftpt[0]) { + lprev(checkedge, *farleft); + farleftapex = farleftpt; + farleftpt = checkvertex; + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + } + while (farrightapex[0] > farrightpt[0]) { + lprevself(*farright); + symself(*farright); + farrightpt = farrightapex; + apex(*farright, farrightapex); + } + } + return; + } + /* Consider eliminating edges from the left triangulation. */ + if (!leftfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lprev(leftcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperleft, nextapex) > 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* left triangulation will have one more boundary triangle. */ + lnextself(nextedge); + sym(nextedge, topcasing); + lnextself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(leftcand, sidecasing); + lnextself(leftcand); + sym(leftcand, outercasing); + lprevself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(leftcand, lowerleft); + setdest(leftcand, NULL); + setapex(leftcand, nextapex); + setorg(nextedge, NULL); + setdest(nextedge, upperleft); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperleft = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + triedgecopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperleft, nextapex) + > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + /* Consider eliminating edges from the right triangulation. */ + if (!rightfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lnext(rightcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperright, nextapex) > 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* right triangulation will have one more boundary triangle. */ + lprevself(nextedge); + sym(nextedge, topcasing); + lprevself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(rightcand, sidecasing); + lprevself(rightcand); + sym(rightcand, outercasing); + lnextself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(rightcand, NULL); + setdest(rightcand, lowerright); + setapex(rightcand, nextapex); + setorg(nextedge, upperright); + setdest(nextedge, NULL); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperright = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + triedgecopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperright, nextapex) + > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + if (leftfinished || (!rightfinished && + (incircle(upperleft, lowerleft, lowerright, upperright) > 0.0))) { + /* Knit the triangulations, adding an edge from `lowerleft' */ + /* to `upperright'. */ + bond(baseedge, rightcand); + lprev(rightcand, baseedge); + setdest(baseedge, lowerleft); + lowerright = upperright; + sym(baseedge, rightcand); + apex(rightcand, upperright); + } else { + /* Knit the triangulations, adding an edge from `upperleft' */ + /* to `lowerright'. */ + bond(baseedge, leftcand); + lnext(leftcand, baseedge); + setorg(baseedge, lowerright); + lowerleft = upperleft; + sym(baseedge, leftcand); + apex(leftcand, upperleft); + } + if (verbose > 2) { + printf(" Connecting "); + printtriangle(&baseedge); + } + } +} + +/*****************************************************************************/ +/* */ +/* divconqrecurse() Recursively form a Delaunay triangulation by the */ +/* divide-and-conquer method. */ +/* */ +/* Recursively breaks down the problem into smaller pieces, which are */ +/* knitted together by mergehulls(). The base cases (problems of two or */ +/* three points) are handled specially here. */ +/* */ +/* On completion, `farleft' and `farright' are bounding triangles such that */ +/* the origin of `farleft' is the leftmost vertex (breaking ties by */ +/* choosing the highest leftmost vertex), and the destination of */ +/* `farright' is the rightmost vertex (breaking ties by choosing the */ +/* lowest rightmost vertex). */ +/* */ +/*****************************************************************************/ + +void divconqrecurse(sortarray, vertices, axis, farleft, farright) +point *sortarray; +int vertices; +int axis; +struct triedge *farleft; +struct triedge *farright; +{ + struct triedge midtri, tri1, tri2, tri3; + struct triedge innerleft, innerright; + REAL area; + int divider; + + if (verbose > 2) { + printf(" Triangulating %d points.\n", vertices); + } + if (vertices == 2) { + /* The triangulation of two vertices is an edge. An edge is */ + /* represented by two bounding triangles. */ + maketriangle(farleft); + setorg(*farleft, sortarray[0]); + setdest(*farleft, sortarray[1]); + /* The apex is intentionally left NULL. */ + maketriangle(farright); + setorg(*farright, sortarray[1]); + setdest(*farright, sortarray[0]); + /* The apex is intentionally left NULL. */ + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + if (verbose > 2) { + printf(" Creating "); + printtriangle(farleft); + printf(" Creating "); + printtriangle(farright); + } + /* Ensure that the origin of `farleft' is sortarray[0]. */ + lprev(*farright, *farleft); + return; + } else if (vertices == 3) { + /* The triangulation of three vertices is either a triangle (with */ + /* three bounding triangles) or two edges (with four bounding */ + /* triangles). In either case, four triangles are created. */ + maketriangle(&midtri); + maketriangle(&tri1); + maketriangle(&tri2); + maketriangle(&tri3); + area = counterclockwise(sortarray[0], sortarray[1], sortarray[2]); + if (area == 0.0) { + /* Three collinear points; the triangulation is two edges. */ + setorg(midtri, sortarray[0]); + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri1, sortarray[0]); + setorg(tri2, sortarray[2]); + setdest(tri2, sortarray[1]); + setorg(tri3, sortarray[1]); + setdest(tri3, sortarray[2]); + /* All apices are intentionally left NULL. */ + bond(midtri, tri1); + bond(tri2, tri3); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri3); + bond(tri1, tri2); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri1); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + triedgecopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + triedgecopy(tri2, *farright); + } else { + /* The three points are not collinear; the triangulation is one */ + /* triangle, namely `midtri'. */ + setorg(midtri, sortarray[0]); + setdest(tri1, sortarray[0]); + setorg(tri3, sortarray[0]); + /* Apices of tri1, tri2, and tri3 are left NULL. */ + if (area > 0.0) { + /* The vertices are in counterclockwise order. */ + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri2, sortarray[1]); + setapex(midtri, sortarray[2]); + setorg(tri2, sortarray[2]); + setdest(tri3, sortarray[2]); + } else { + /* The vertices are in clockwise order. */ + setdest(midtri, sortarray[2]); + setorg(tri1, sortarray[2]); + setdest(tri2, sortarray[2]); + setapex(midtri, sortarray[1]); + setorg(tri2, sortarray[1]); + setdest(tri3, sortarray[1]); + } + /* The topology does not depend on how the vertices are ordered. */ + bond(midtri, tri1); + lnextself(midtri); + bond(midtri, tri2); + lnextself(midtri); + bond(midtri, tri3); + lprevself(tri1); + lnextself(tri2); + bond(tri1, tri2); + lprevself(tri1); + lprevself(tri3); + bond(tri1, tri3); + lnextself(tri2); + lprevself(tri3); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + triedgecopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + if (area > 0.0) { + triedgecopy(tri2, *farright); + } else { + lnext(*farleft, *farright); + } + } + if (verbose > 2) { + printf(" Creating "); + printtriangle(&midtri); + printf(" Creating "); + printtriangle(&tri1); + printf(" Creating "); + printtriangle(&tri2); + printf(" Creating "); + printtriangle(&tri3); + } + return; + } else { + /* Split the vertices in half. */ + divider = vertices >> 1; + /* Recursively triangulate each half. */ + divconqrecurse(sortarray, divider, 1 - axis, farleft, &innerleft); + divconqrecurse(&sortarray[divider], vertices - divider, 1 - axis, + &innerright, farright); + if (verbose > 1) { + printf(" Joining triangulations with %d and %d vertices.\n", divider, + vertices - divider); + } + /* Merge the two triangulations into one. */ + mergehulls(farleft, &innerleft, &innerright, farright, axis); + } +} + +long removeghosts(startghost) +struct triedge *startghost; +{ + struct triedge searchedge; + struct triedge dissolveedge; + struct triedge deadtri; + point markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose) { + printf(" Removing ghost triangles.\n"); + } + /* Find an edge on the convex hull to start point location from. */ + lprev(*startghost, searchedge); + symself(searchedge); + dummytri[0] = encode(searchedge); + /* Remove the bounding box and count the convex hull edges. */ + triedgecopy(*startghost, dissolveedge); + hullsize = 0; + do { + hullsize++; + lnext(dissolveedge, deadtri); + lprevself(dissolveedge); + symself(dissolveedge); + /* If no PSLG is involved, set the boundary markers of all the points */ + /* on the convex hull. If a PSLG is used, this step is done later. */ + if (!poly) { + /* Watch out for the case where all the input points are collinear. */ + if (dissolveedge.tri != dummytri) { + org(dissolveedge, markorg); + if (pointmark(markorg) == 0) { + setpointmark(markorg, 1); + } + } + } + /* Remove a bounding triangle from a convex hull triangle. */ + dissolve(dissolveedge); + /* Find the next bounding triangle. */ + sym(deadtri, dissolveedge); + /* Delete the bounding triangle. */ + triangledealloc(deadtri.tri); + } while (!triedgeequal(dissolveedge, *startghost)); + return hullsize; +} + +/*****************************************************************************/ +/* */ +/* divconqdelaunay() Form a Delaunay triangulation by the divide-and- */ +/* conquer method. */ +/* */ +/* Sorts the points, calls a recursive procedure to triangulate them, and */ +/* removes the bounding box, setting boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +long divconqdelaunay() +{ + point *sortarray; + struct triedge hullleft, hullright; + int divider; + int i, j; + + /* Allocate an array of pointers to points for sorting. */ + sortarray = (point *) malloc(inpoints * sizeof(point)); + if (sortarray == (point *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + traversalinit(&points); + for (i = 0; i < inpoints; i++) { + sortarray[i] = pointtraverse(); + } + if (verbose) { + printf(" Sorting points.\n"); + } + /* Sort the points. */ + pointsort(sortarray, inpoints); + /* Discard duplicate points, which can really mess up the algorithm. */ + i = 0; + for (j = 1; j < inpoints; j++) { + if ((sortarray[i][0] == sortarray[j][0]) + && (sortarray[i][1] == sortarray[j][1])) { + if (!quiet) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + sortarray[j][0], sortarray[j][1]); + } +/* Commented out - would eliminate point from output .node file, but causes + a failure if some segment has this point as an endpoint. + setpointmark(sortarray[j], DEADPOINT); +*/ + } else { + i++; + sortarray[i] = sortarray[j]; + } + } + i++; + if (dwyer) { + /* Re-sort the array of points to accommodate alternating cuts. */ + divider = i >> 1; + if (i - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1); + } + alternateaxes(&sortarray[divider], i - divider, 1); + } + } + if (verbose) { + printf(" Forming triangulation.\n"); + } + /* Form the Delaunay triangulation. */ + divconqrecurse(sortarray, i, 0, &hullleft, &hullright); + free(sortarray); + + return removeghosts(&hullleft); +} + +/** **/ +/** **/ +/********* Divide-and-conquer Delaunay triangulation ends here *********/ + +/********* Incremental Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* boundingbox() Form an "infinite" bounding triangle to insert points */ +/* into. */ +/* */ +/* The points at "infinity" are assigned finite coordinates, which are used */ +/* by the point location routines, but (mostly) ignored by the Delaunay */ +/* edge flip routines. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void boundingbox() +{ + struct triedge inftri; /* Handle for the triangular bounding box. */ + REAL width; + + if (verbose) { + printf(" Creating triangular bounding box.\n"); + } + /* Find the width (or height, whichever is larger) of the triangulation. */ + width = xmax - xmin; + if (ymax - ymin > width) { + width = ymax - ymin; + } + if (width == 0.0) { + width = 1.0; + } + /* Create the vertices of the bounding box. */ + infpoint1 = (point) malloc(points.itembytes); + infpoint2 = (point) malloc(points.itembytes); + infpoint3 = (point) malloc(points.itembytes); + if ((infpoint1 == (point) NULL) || (infpoint2 == (point) NULL) + || (infpoint3 == (point) NULL)) { + printf("Error: Out of memory.\n"); + exit(1); + } + infpoint1[0] = xmin - 50.0 * width; + infpoint1[1] = ymin - 40.0 * width; + infpoint2[0] = xmax + 50.0 * width; + infpoint2[1] = ymin - 40.0 * width; + infpoint3[0] = 0.5 * (xmin + xmax); + infpoint3[1] = ymax + 60.0 * width; + + /* Create the bounding box. */ + maketriangle(&inftri); + setorg(inftri, infpoint1); + setdest(inftri, infpoint2); + setapex(inftri, infpoint3); + /* Link dummytri to the bounding box so we can always find an */ + /* edge to begin searching (point location) from. */ + dummytri[0] = (triangle) inftri.tri; + if (verbose > 2) { + printf(" Creating "); + printtriangle(&inftri); + } +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* removebox() Remove the "infinite" bounding triangle, setting boundary */ +/* markers as appropriate. */ +/* */ +/* The triangular bounding box has three boundary triangles (one for each */ +/* side of the bounding box), and a bunch of triangles fanning out from */ +/* the three bounding box vertices (one triangle for each edge of the */ +/* convex hull of the inner mesh). This routine removes these triangles. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +long removebox() +{ + struct triedge deadtri; + struct triedge searchedge; + struct triedge checkedge; + struct triedge nextedge, finaledge, dissolveedge; + point markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose) { + printf(" Removing triangular bounding box.\n"); + } + /* Find a boundary triangle. */ + nextedge.tri = dummytri; + nextedge.orient = 0; + symself(nextedge); + /* Mark a place to stop. */ + lprev(nextedge, finaledge); + lnextself(nextedge); + symself(nextedge); + /* Find a triangle (on the boundary of the point set) that isn't */ + /* a bounding box triangle. */ + lprev(nextedge, searchedge); + symself(searchedge); + /* Check whether nextedge is another boundary triangle */ + /* adjacent to the first one. */ + lnext(nextedge, checkedge); + symself(checkedge); + if (checkedge.tri == dummytri) { + /* Go on to the next triangle. There are only three boundary */ + /* triangles, and this next triangle cannot be the third one, */ + /* so it's safe to stop here. */ + lprevself(searchedge); + symself(searchedge); + } + /* Find a new boundary edge to search from, as the current search */ + /* edge lies on a bounding box triangle and will be deleted. */ + dummytri[0] = encode(searchedge); + hullsize = -2l; + while (!triedgeequal(nextedge, finaledge)) { + hullsize++; + lprev(nextedge, dissolveedge); + symself(dissolveedge); + /* If not using a PSLG, the vertices should be marked now. */ + /* (If using a PSLG, markhull() will do the job.) */ + if (!poly) { + /* Be careful! One must check for the case where all the input */ + /* points are collinear, and thus all the triangles are part of */ + /* the bounding box. Otherwise, the setpointmark() call below */ + /* will cause a bad pointer reference. */ + if (dissolveedge.tri != dummytri) { + org(dissolveedge, markorg); + if (pointmark(markorg) == 0) { + setpointmark(markorg, 1); + } + } + } + /* Disconnect the bounding box triangle from the mesh triangle. */ + dissolve(dissolveedge); + lnext(nextedge, deadtri); + sym(deadtri, nextedge); + /* Get rid of the bounding box triangle. */ + triangledealloc(deadtri.tri); + /* Do we need to turn the corner? */ + if (nextedge.tri == dummytri) { + /* Turn the corner. */ + triedgecopy(dissolveedge, nextedge); + } + } + triangledealloc(finaledge.tri); + + free(infpoint1); /* Deallocate the bounding box vertices. */ + free(infpoint2); + free(infpoint3); + + return hullsize; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* incrementaldelaunay() Form a Delaunay triangulation by incrementally */ +/* adding vertices. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +long incrementaldelaunay() +{ + struct triedge starttri; + point pointloop; + int i; + + /* Create a triangular bounding box. */ + boundingbox(); + if (verbose) { + printf(" Incrementally inserting points.\n"); + } + traversalinit(&points); + pointloop = pointtraverse(); + i = 1; + while (pointloop != (point) NULL) { + /* Find a boundary triangle to search from. */ + starttri.tri = (triangle *) NULL; + if (insertsite(pointloop, &starttri, (struct edge *) NULL, 0, 0) == + DUPLICATEPOINT) { + if (!quiet) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + pointloop[0], pointloop[1]); + } +/* Commented out - would eliminate point from output .node file. + setpointmark(pointloop, DEADPOINT); +*/ + } + pointloop = pointtraverse(); + i++; + } + /* Remove the bounding box. */ + return removebox(); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Incremental Delaunay triangulation ends here *********/ + +/********* Sweepline Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +#ifndef REDUCED + +void eventheapinsert(heap, heapsize, newevent) +struct event **heap; +int heapsize; +struct event *newevent; +{ + REAL eventx, eventy; + int eventnum; + int parent; + int notdone; + + eventx = newevent->xkey; + eventy = newevent->ykey; + eventnum = heapsize; + notdone = eventnum > 0; + while (notdone) { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } + heap[eventnum] = newevent; + newevent->heapposition = eventnum; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void eventheapify(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +{ + struct event *thisevent; + REAL eventx, eventy; + int leftchild, rightchild; + int smallest; + int notdone; + + thisevent = heap[eventnum]; + eventx = thisevent->xkey; + eventy = thisevent->ykey; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + while (notdone) { + if ((heap[leftchild]->ykey < eventy) || + ((heap[leftchild]->ykey == eventy) + && (heap[leftchild]->xkey < eventx))) { + smallest = leftchild; + } else { + smallest = eventnum; + } + rightchild = leftchild + 1; + if (rightchild < heapsize) { + if ((heap[rightchild]->ykey < heap[smallest]->ykey) || + ((heap[rightchild]->ykey == heap[smallest]->ykey) + && (heap[rightchild]->xkey < heap[smallest]->xkey))) { + smallest = rightchild; + } + } + if (smallest == eventnum) { + notdone = 0; + } else { + heap[eventnum] = heap[smallest]; + heap[eventnum]->heapposition = eventnum; + heap[smallest] = thisevent; + thisevent->heapposition = smallest; + + eventnum = smallest; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void eventheapdelete(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +{ + struct event *moveevent; + REAL eventx, eventy; + int parent; + int notdone; + + moveevent = heap[heapsize - 1]; + if (eventnum > 0) { + eventx = moveevent->xkey; + eventy = moveevent->ykey; + do { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } while (notdone); + } + heap[eventnum] = moveevent; + moveevent->heapposition = eventnum; + eventheapify(heap, heapsize - 1, eventnum); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void createeventheap(eventheap, events, freeevents) +struct event ***eventheap; +struct event **events; +struct event **freeevents; +{ + point thispoint; + int maxevents; + int i; + + maxevents = (3 * inpoints) / 2; + *eventheap = (struct event **) malloc(maxevents * sizeof(struct event *)); + if (*eventheap == (struct event **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + *events = (struct event *) malloc(maxevents * sizeof(struct event)); + if (*events == (struct event *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + traversalinit(&points); + for (i = 0; i < inpoints; i++) { + thispoint = pointtraverse(); + (*events)[i].eventptr = (VOID *) thispoint; + (*events)[i].xkey = thispoint[0]; + (*events)[i].ykey = thispoint[1]; + eventheapinsert(*eventheap, i, *events + i); + } + *freeevents = (struct event *) NULL; + for (i = maxevents - 1; i >= inpoints; i--) { + (*events)[i].eventptr = (VOID *) *freeevents; + *freeevents = *events + i; + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +int rightofhyperbola(fronttri, newsite) +struct triedge *fronttri; +point newsite; +{ + point leftpoint, rightpoint; + REAL dxa, dya, dxb, dyb; + + hyperbolacount++; + + dest(*fronttri, leftpoint); + apex(*fronttri, rightpoint); + if ((leftpoint[1] < rightpoint[1]) + || ((leftpoint[1] == rightpoint[1]) && (leftpoint[0] < rightpoint[0]))) { + if (newsite[0] >= rightpoint[0]) { + return 1; + } + } else { + if (newsite[0] <= leftpoint[0]) { + return 0; + } + } + dxa = leftpoint[0] - newsite[0]; + dya = leftpoint[1] - newsite[1]; + dxb = rightpoint[0] - newsite[0]; + dyb = rightpoint[1] - newsite[1]; + return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +REAL circletop(pa, pb, pc, ccwabc) +point pa; +point pb; +point pc; +REAL ccwabc; +{ + REAL xac, yac, xbc, ybc, xab, yab; + REAL aclen2, bclen2, ablen2; + + circletopcount++; + + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + xab = pa[0] - pb[0]; + yab = pa[1] - pb[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + ablen2 = xab * xab + yab * yab; + return pc[1] + (xac * bclen2 - xbc * aclen2 + sqrt(aclen2 * bclen2 * ablen2)) + / (2.0 * ccwabc); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void check4deadevent(checktri, freeevents, eventheap, heapsize) +struct triedge *checktri; +struct event **freeevents; +struct event **eventheap; +int *heapsize; +{ + struct event *deadevent; + point eventpoint; + int eventnum; + + org(*checktri, eventpoint); + if (eventpoint != (point) NULL) { + deadevent = (struct event *) eventpoint; + eventnum = deadevent->heapposition; + deadevent->eventptr = (VOID *) *freeevents; + *freeevents = deadevent; + eventheapdelete(eventheap, *heapsize, eventnum); + (*heapsize)--; + setorg(*checktri, NULL); + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *splay(splaytree, searchpoint, searchtri) +struct splaynode *splaytree; +point searchpoint; +struct triedge *searchtri; +{ + struct splaynode *child, *grandchild; + struct splaynode *lefttree, *righttree; + struct splaynode *leftright; + point checkpoint; + int rightofroot, rightofchild; + + if (splaytree == (struct splaynode *) NULL) { + return (struct splaynode *) NULL; + } + dest(splaytree->keyedge, checkpoint); + if (checkpoint == splaytree->keydest) { + rightofroot = rightofhyperbola(&splaytree->keyedge, searchpoint); + if (rightofroot) { + triedgecopy(splaytree->keyedge, *searchtri); + child = splaytree->rchild; + } else { + child = splaytree->lchild; + } + if (child == (struct splaynode *) NULL) { + return splaytree; + } + dest(child->keyedge, checkpoint); + if (checkpoint != child->keydest) { + child = splay(child, searchpoint, searchtri); + if (child == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = (struct splaynode *) NULL; + } else { + splaytree->lchild = (struct splaynode *) NULL; + } + return splaytree; + } + } + rightofchild = rightofhyperbola(&child->keyedge, searchpoint); + if (rightofchild) { + triedgecopy(child->keyedge, *searchtri); + grandchild = splay(child->rchild, searchpoint, searchtri); + child->rchild = grandchild; + } else { + grandchild = splay(child->lchild, searchpoint, searchtri); + child->lchild = grandchild; + } + if (grandchild == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + return child; + } + if (rightofchild) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = grandchild->rchild; + grandchild->rchild = splaytree; + } + child->rchild = grandchild->lchild; + grandchild->lchild = child; + } else { + if (rightofroot) { + splaytree->rchild = grandchild->lchild; + grandchild->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + child->lchild = grandchild->rchild; + grandchild->rchild = child; + } + return grandchild; + } else { + lefttree = splay(splaytree->lchild, searchpoint, searchtri); + righttree = splay(splaytree->rchild, searchpoint, searchtri); + + pooldealloc(&splaynodes, (VOID *) splaytree); + if (lefttree == (struct splaynode *) NULL) { + return righttree; + } else if (righttree == (struct splaynode *) NULL) { + return lefttree; + } else if (lefttree->rchild == (struct splaynode *) NULL) { + lefttree->rchild = righttree->lchild; + righttree->lchild = lefttree; + return righttree; + } else if (righttree->lchild == (struct splaynode *) NULL) { + righttree->lchild = lefttree->rchild; + lefttree->rchild = righttree; + return lefttree; + } else { +/* printf("Holy Toledo!!!\n"); */ + leftright = lefttree->rchild; + while (leftright->rchild != (struct splaynode *) NULL) { + leftright = leftright->rchild; + } + leftright->rchild = righttree; + return lefttree; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *splayinsert(splayroot, newkey, searchpoint) +struct splaynode *splayroot; +struct triedge *newkey; +point searchpoint; +{ + struct splaynode *newsplaynode; + + newsplaynode = (struct splaynode *) poolalloc(&splaynodes); + triedgecopy(*newkey, newsplaynode->keyedge); + dest(*newkey, newsplaynode->keydest); + if (splayroot == (struct splaynode *) NULL) { + newsplaynode->lchild = (struct splaynode *) NULL; + newsplaynode->rchild = (struct splaynode *) NULL; + } else if (rightofhyperbola(&splayroot->keyedge, searchpoint)) { + newsplaynode->lchild = splayroot; + newsplaynode->rchild = splayroot->rchild; + splayroot->rchild = (struct splaynode *) NULL; + } else { + newsplaynode->lchild = splayroot->lchild; + newsplaynode->rchild = splayroot; + splayroot->lchild = (struct splaynode *) NULL; + } + return newsplaynode; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *circletopinsert(splayroot, newkey, pa, pb, pc, topy) +struct splaynode *splayroot; +struct triedge *newkey; +point pa; +point pb; +point pc; +REAL topy; +{ + REAL ccwabc; + REAL xac, yac, xbc, ybc; + REAL aclen2, bclen2; + REAL searchpoint[2]; + struct triedge dummytri; + + ccwabc = counterclockwise(pa, pb, pc); + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + searchpoint[0] = pc[0] - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc); + searchpoint[1] = topy; + return splayinsert(splay(splayroot, (point) searchpoint, &dummytri), newkey, + (point) searchpoint); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *frontlocate(splayroot, bottommost, searchpoint, searchtri, + farright) +struct splaynode *splayroot; +struct triedge *bottommost; +point searchpoint; +struct triedge *searchtri; +int *farright; +{ + int farrightflag; + triangle ptr; /* Temporary variable used by onext(). */ + + triedgecopy(*bottommost, *searchtri); + splayroot = splay(splayroot, searchpoint, searchtri); + + farrightflag = 0; + while (!farrightflag && rightofhyperbola(searchtri, searchpoint)) { + onextself(*searchtri); + farrightflag = triedgeequal(*searchtri, *bottommost); + } + *farright = farrightflag; + return splayroot; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +long sweeplinedelaunay() +{ + struct event **eventheap; + struct event *events; + struct event *freeevents; + struct event *nextevent; + struct event *newevent; + struct splaynode *splayroot; + struct triedge bottommost; + struct triedge searchtri; + struct triedge fliptri; + struct triedge lefttri, righttri, farlefttri, farrighttri; + struct triedge inserttri; + point firstpoint, secondpoint; + point nextpoint, lastpoint; + point connectpoint; + point leftpoint, midpoint, rightpoint; + REAL lefttest, righttest; + int heapsize; + int check4events, farrightflag; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + poolinit(&splaynodes, sizeof(struct splaynode), SPLAYNODEPERBLOCK, POINTER, + 0); + splayroot = (struct splaynode *) NULL; + + if (verbose) { + printf(" Placing points in event heap.\n"); + } + createeventheap(&eventheap, &events, &freeevents); + heapsize = inpoints; + + if (verbose) { + printf(" Forming triangulation.\n"); + } + maketriangle(&lefttri); + maketriangle(&righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + firstpoint = (point) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + do { + if (heapsize == 0) { + printf("Error: Input points are all identical.\n"); + exit(1); + } + secondpoint = (point) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + if ((firstpoint[0] == secondpoint[0]) + && (firstpoint[1] == secondpoint[1])) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + secondpoint[0], secondpoint[1]); +/* Commented out - would eliminate point from output .node file. + setpointmark(secondpoint, DEADPOINT); +*/ + } + } while ((firstpoint[0] == secondpoint[0]) + && (firstpoint[1] == secondpoint[1])); + setorg(lefttri, firstpoint); + setdest(lefttri, secondpoint); + setorg(righttri, secondpoint); + setdest(righttri, firstpoint); + lprev(lefttri, bottommost); + lastpoint = secondpoint; + while (heapsize > 0) { + nextevent = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + check4events = 1; + if (nextevent->xkey < xmin) { + decode(nextevent->eventptr, fliptri); + oprev(fliptri, farlefttri); + check4deadevent(&farlefttri, &freeevents, eventheap, &heapsize); + onext(fliptri, farrighttri); + check4deadevent(&farrighttri, &freeevents, eventheap, &heapsize); + + if (triedgeequal(farlefttri, bottommost)) { + lprev(fliptri, bottommost); + } + flip(&fliptri); + setapex(fliptri, NULL); + lprev(fliptri, lefttri); + lnext(fliptri, righttri); + sym(lefttri, farlefttri); + + if (randomnation(SAMPLERATE) == 0) { + symself(fliptri); + dest(fliptri, leftpoint); + apex(fliptri, midpoint); + org(fliptri, rightpoint); + splayroot = circletopinsert(splayroot, &lefttri, leftpoint, midpoint, + rightpoint, nextevent->ykey); + } + } else { + nextpoint = (point) nextevent->eventptr; + if ((nextpoint[0] == lastpoint[0]) && (nextpoint[1] == lastpoint[1])) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + nextpoint[0], nextpoint[1]); +/* Commented out - would eliminate point from output .node file. + setpointmark(nextpoint, DEADPOINT); +*/ + check4events = 0; + } else { + lastpoint = nextpoint; + + splayroot = frontlocate(splayroot, &bottommost, nextpoint, &searchtri, + &farrightflag); +/* + triedgecopy(bottommost, searchtri); + farrightflag = 0; + while (!farrightflag && rightofhyperbola(&searchtri, nextpoint)) { + onextself(searchtri); + farrightflag = triedgeequal(searchtri, bottommost); + } +*/ + + check4deadevent(&searchtri, &freeevents, eventheap, &heapsize); + + triedgecopy(searchtri, farrighttri); + sym(searchtri, farlefttri); + maketriangle(&lefttri); + maketriangle(&righttri); + dest(farrighttri, connectpoint); + setorg(lefttri, connectpoint); + setdest(lefttri, nextpoint); + setorg(righttri, nextpoint); + setdest(righttri, connectpoint); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, farlefttri); + bond(righttri, farrighttri); + if (!farrightflag && triedgeequal(farrighttri, bottommost)) { + triedgecopy(lefttri, bottommost); + } + + if (randomnation(SAMPLERATE) == 0) { + splayroot = splayinsert(splayroot, &lefttri, nextpoint); + } else if (randomnation(SAMPLERATE) == 0) { + lnext(righttri, inserttri); + splayroot = splayinsert(splayroot, &inserttri, nextpoint); + } + } + } + nextevent->eventptr = (VOID *) freeevents; + freeevents = nextevent; + + if (check4events) { + apex(farlefttri, leftpoint); + dest(lefttri, midpoint); + apex(lefttri, rightpoint); + lefttest = counterclockwise(leftpoint, midpoint, rightpoint); + if (lefttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = xminextreme; + newevent->ykey = circletop(leftpoint, midpoint, rightpoint, + lefttest); + newevent->eventptr = (VOID *) encode(lefttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(lefttri, newevent); + } + apex(righttri, leftpoint); + org(righttri, midpoint); + apex(farrighttri, rightpoint); + righttest = counterclockwise(leftpoint, midpoint, rightpoint); + if (righttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = xminextreme; + newevent->ykey = circletop(leftpoint, midpoint, rightpoint, + righttest); + newevent->eventptr = (VOID *) encode(farrighttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(farrighttri, newevent); + } + } + } + + pooldeinit(&splaynodes); + lprevself(bottommost); + return removeghosts(&bottommost); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Sweepline Delaunay triangulation ends here *********/ + +/********* General mesh construction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* delaunay() Form a Delaunay triangulation. */ +/* */ +/*****************************************************************************/ + +long delaunay() +{ + eextras = 0; + initializetrisegpools(); + +#ifdef REDUCED + if (!quiet) { + printf( + "Constructing Delaunay triangulation by divide-and-conquer method.\n"); + } + return divconqdelaunay(); +#else /* not REDUCED */ + if (!quiet) { + printf("Constructing Delaunay triangulation "); + if (incremental) { + printf("by incremental method.\n"); + } else if (sweepline) { + printf("by sweepline method.\n"); + } else { + printf("by divide-and-conquer method.\n"); + } + } + if (incremental) { + return incrementaldelaunay(); + } else if (sweepline) { + return sweeplinedelaunay(); + } else { + return divconqdelaunay(); + } +#endif /* not REDUCED */ +} + +/*****************************************************************************/ +/* */ +/* reconstruct() Reconstruct a triangulation from its .ele (and possibly */ +/* .poly) file. Used when the -r switch is used. */ +/* */ +/* Reads an .ele file and reconstructs the original mesh. If the -p switch */ +/* is used, this procedure will also read a .poly file and reconstruct the */ +/* shell edges of the original mesh. If the -a switch is used, this */ +/* procedure will also read an .area file and set a maximum area constraint */ +/* on each triangle. */ +/* */ +/* Points that are not corners of triangles, such as nodes on edges of */ +/* subparametric elements, are discarded. */ +/* */ +/* This routine finds the adjacencies between triangles (and shell edges) */ +/* by forming one stack of triangles for each vertex. Each triangle is on */ +/* three different stacks simultaneously. Each triangle's shell edge */ +/* pointers are used to link the items in each stack. This memory-saving */ +/* feature makes the code harder to read. The most important thing to keep */ +/* in mind is that each triangle is removed from a stack precisely when */ +/* the corresponding pointer is adjusted to refer to a shell edge rather */ +/* than the next triangle of the stack. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef TRILIBRARY + +int reconstruct(trianglelist, triangleattriblist, trianglearealist, elements, + corners, attribs, segmentlist, segmentmarkerlist, + numberofsegments) +int *trianglelist; +REAL *triangleattriblist; +REAL *trianglearealist; +int elements; +int corners; +int attribs; +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; + +#else /* not TRILIBRARY */ + +long reconstruct(elefilename, areafilename, polyfilename, polyfile) +char *elefilename; +char *areafilename; +char *polyfilename; +FILE *polyfile; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int pointindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *elefile; + FILE *areafile; + char inputline[INPUTLINESIZE]; + char *stringptr; + int areaelements; +#endif /* not TRILIBRARY */ + struct triedge triangleloop; + struct triedge triangleleft; + struct triedge checktri; + struct triedge checkleft; + struct triedge checkneighbor; + struct edge shelleloop; + triangle *vertexarray; + triangle *prevlink; + triangle nexttri; + point tdest, tapex; + point checkdest, checkapex; + point shorg; + point killpoint; + REAL area; + int corner[3]; + int end[2]; + int killpointindex; + int incorners; + int segmentmarkers; + int boundmarker; + int aroundpoint; + long hullsize; + int notfound; + int elementnumber, segmentnumber; + int i, j; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + inelements = elements; + incorners = corners; + if (incorners < 3) { + printf("Error: Triangles must have at least 3 points.\n"); + exit(1); + } + eextras = attribs; +#else /* not TRILIBRARY */ + /* Read the triangles from an .ele file. */ + if (!quiet) { + printf("Opening %s.\n", elefilename); + } + elefile = fopen(elefilename, "r"); + if (elefile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", elefilename); + exit(1); + } + /* Read number of triangles, number of points per triangle, and */ + /* number of triangle attributes from .ele file. */ + stringptr = readline(inputline, elefile, elefilename); + inelements = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + incorners = 3; + } else { + incorners = (int) strtol (stringptr, &stringptr, 0); + if (incorners < 3) { + printf("Error: Triangles in %s must have at least 3 points.\n", + elefilename); + exit(1); + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + eextras = 0; + } else { + eextras = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + initializetrisegpools(); + + /* Create the triangles. */ + for (elementnumber = 1; elementnumber <= inelements; elementnumber++) { + maketriangle(&triangleloop); + /* Mark the triangle as living. */ + triangleloop.tri[3] = (triangle) triangleloop.tri; + } + + if (poly) { +#ifdef TRILIBRARY + insegments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; +#else /* not TRILIBRARY */ + /* Read number of segments and number of segment */ + /* boundary markers from .poly file. */ + stringptr = readline(inputline, polyfile, inpolyfilename); + insegments = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + /* Create the shell edges. */ + for (segmentnumber = 1; segmentnumber <= insegments; segmentnumber++) { + makeshelle(&shelleloop); + /* Mark the shell edge as living. */ + shelleloop.sh[2] = (shelle) shelleloop.sh; + } + } + +#ifdef TRILIBRARY + pointindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (vararea) { + /* Open an .area file, check for consistency with the .ele file. */ + if (!quiet) { + printf("Opening %s.\n", areafilename); + } + areafile = fopen(areafilename, "r"); + if (areafile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", areafilename); + exit(1); + } + stringptr = readline(inputline, areafile, areafilename); + areaelements = (int) strtol (stringptr, &stringptr, 0); + if (areaelements != inelements) { + printf("Error: %s and %s disagree on number of triangles.\n", + elefilename, areafilename); + exit(1); + } + } +#endif /* not TRILIBRARY */ + + if (!quiet) { + printf("Reconstructing mesh.\n"); + } + /* Allocate a temporary array that maps each point to some adjacent */ + /* triangle. I took care to allocate all the permanent memory for */ + /* triangles and shell edges first. */ + vertexarray = (triangle *) malloc(points.items * sizeof(triangle)); + if (vertexarray == (triangle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Each point is initially unrepresented. */ + for (i = 0; i < points.items; i++) { + vertexarray[i] = (triangle) dummytri; + } + + if (verbose) { + printf(" Assembling triangles.\n"); + } + /* Read the triangles from the .ele file, and link */ + /* together those that share an edge. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { +#ifdef TRILIBRARY + /* Copy the triangle's three corners. */ + for (j = 0; j < 3; j++) { + corner[j] = trianglelist[pointindex++]; + if ((corner[j] < firstnumber) || (corner[j] >= firstnumber + inpoints)) { + printf("Error: Triangle %d has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } +#else /* not TRILIBRARY */ + /* Read triangle number and the triangle's three corners. */ + stringptr = readline(inputline, elefile, elefilename); + for (j = 0; j < 3; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Triangle %d is missing point %d in %s.\n", + elementnumber, j + 1, elefilename); + exit(1); + } else { + corner[j] = (int) strtol (stringptr, &stringptr, 0); + if ((corner[j] < firstnumber) || + (corner[j] >= firstnumber + inpoints)) { + printf("Error: Triangle %d has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } + } +#endif /* not TRILIBRARY */ + + /* Find out about (and throw away) extra nodes. */ + for (j = 3; j < incorners; j++) { +#ifdef TRILIBRARY + killpointindex = trianglelist[pointindex++]; +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr != '\0') { + killpointindex = (int) strtol (stringptr, &stringptr, 0); +#endif /* not TRILIBRARY */ + if ((killpointindex >= firstnumber) && + (killpointindex < firstnumber + inpoints)) { + /* Delete the non-corner point if it's not already deleted. */ + killpoint = getpoint(killpointindex); + if (pointmark(killpoint) != DEADPOINT) { + pointdealloc(killpoint); + } + } +#ifndef TRILIBRARY + } +#endif /* not TRILIBRARY */ + } + + /* Read the triangle's attributes. */ + for (j = 0; j < eextras; j++) { +#ifdef TRILIBRARY + setelemattribute(triangleloop, j, triangleattriblist[attribindex++]); +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setelemattribute(triangleloop, j, 0); + } else { + setelemattribute(triangleloop, j, + (REAL) strtod (stringptr, &stringptr)); + } +#endif /* not TRILIBRARY */ + } + + if (vararea) { +#ifdef TRILIBRARY + area = trianglearealist[elementnumber - firstnumber]; +#else /* not TRILIBRARY */ + /* Read an area constraint from the .area file. */ + stringptr = readline(inputline, areafile, areafilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + area = -1.0; /* No constraint on this triangle. */ + } else { + area = (REAL) strtod(stringptr, &stringptr); + } +#endif /* not TRILIBRARY */ + setareabound(triangleloop, area); + } + + /* Set the triangle's vertices. */ + triangleloop.orient = 0; + setorg(triangleloop, getpoint(corner[0])); + setdest(triangleloop, getpoint(corner[1])); + setapex(triangleloop, getpoint(corner[2])); + /* Try linking the triangle to others that share these vertices. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + /* Take the number for the origin of triangleloop. */ + aroundpoint = corner[triangleloop.orient]; + /* Look for other triangles having this vertex. */ + nexttri = vertexarray[aroundpoint - firstnumber]; + /* Link the current triangle to the next one in the stack. */ + triangleloop.tri[6 + triangleloop.orient] = nexttri; + /* Push the current triangle onto the stack. */ + vertexarray[aroundpoint - firstnumber] = encode(triangleloop); + decode(nexttri, checktri); + if (checktri.tri != dummytri) { + dest(triangleloop, tdest); + apex(triangleloop, tapex); + /* Look for other triangles that share an edge. */ + do { + dest(checktri, checkdest); + apex(checktri, checkapex); + if (tapex == checkdest) { + /* The two triangles share an edge; bond them together. */ + lprev(triangleloop, triangleleft); + bond(triangleleft, checktri); + } + if (tdest == checkapex) { + /* The two triangles share an edge; bond them together. */ + lprev(checktri, checkleft); + bond(triangleloop, checkleft); + } + /* Find the next triangle in the stack. */ + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } while (checktri.tri != dummytri); + } + } + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifdef TRILIBRARY + pointindex = 0; +#else /* not TRILIBRARY */ + fclose(elefile); + if (vararea) { + fclose(areafile); + } +#endif /* not TRILIBRARY */ + + hullsize = 0; /* Prepare to count the boundary edges. */ + if (poly) { + if (verbose) { + printf(" Marking segments in triangulation.\n"); + } + /* Read the segments from the .poly file, and link them */ + /* to their neighboring triangles. */ + boundmarker = 0; + traversalinit(&shelles); + shelleloop.sh = shelletraverse(); + segmentnumber = firstnumber; + while (shelleloop.sh != (shelle *) NULL) { +#ifdef TRILIBRARY + end[0] = segmentlist[pointindex++]; + end[1] = segmentlist[pointindex++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[segmentnumber - firstnumber]; + } +#else /* not TRILIBRARY */ + /* Read the endpoints of each segment, and possibly a boundary marker. */ + stringptr = readline(inputline, polyfile, inpolyfilename); + /* Skip the first (segment number) field. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d has no endpoints in %s.\n", segmentnumber, + polyfilename); + exit(1); + } else { + end[0] = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d is missing its second endpoint in %s.\n", + segmentnumber, polyfilename); + exit(1); + } else { + end[1] = (int) strtol (stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol (stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + for (j = 0; j < 2; j++) { + if ((end[j] < firstnumber) || (end[j] >= firstnumber + inpoints)) { + printf("Error: Segment %d has an invalid vertex index.\n", + segmentnumber); + exit(1); + } + } + + /* set the shell edge's vertices. */ + shelleloop.shorient = 0; + setsorg(shelleloop, getpoint(end[0])); + setsdest(shelleloop, getpoint(end[1])); + setmark(shelleloop, boundmarker); + /* Try linking the shell edge to triangles that share these vertices. */ + for (shelleloop.shorient = 0; shelleloop.shorient < 2; + shelleloop.shorient++) { + /* Take the number for the destination of shelleloop. */ + aroundpoint = end[1 - shelleloop.shorient]; + /* Look for triangles having this vertex. */ + prevlink = &vertexarray[aroundpoint - firstnumber]; + nexttri = vertexarray[aroundpoint - firstnumber]; + decode(nexttri, checktri); + sorg(shelleloop, shorg); + notfound = 1; + /* Look for triangles having this edge. Note that I'm only */ + /* comparing each triangle's destination with the shell edge; */ + /* each triangle's apex is handled through a different vertex. */ + /* Because each triangle appears on three vertices' lists, each */ + /* occurrence of a triangle on a list can (and does) represent */ + /* an edge. In this way, most edges are represented twice, and */ + /* every triangle-segment bond is represented once. */ + while (notfound && (checktri.tri != dummytri)) { + dest(checktri, checkdest); + if (shorg == checkdest) { + /* We have a match. Remove this triangle from the list. */ + *prevlink = checktri.tri[6 + checktri.orient]; + /* Bond the shell edge to the triangle. */ + tsbond(checktri, shelleloop); + /* Check if this is a boundary edge. */ + sym(checktri, checkneighbor); + if (checkneighbor.tri == dummytri) { + /* The next line doesn't insert a shell edge (because there's */ + /* already one there), but it sets the boundary markers of */ + /* the existing shell edge and its vertices. */ + insertshelle(&checktri, 1); + hullsize++; + } + notfound = 0; + } + /* Find the next triangle in the stack. */ + prevlink = &checktri.tri[6 + checktri.orient]; + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } + } + shelleloop.sh = shelletraverse(); + segmentnumber++; + } + } + + /* Mark the remaining edges as not being attached to any shell edge. */ + /* Also, count the (yet uncounted) boundary edges. */ + for (i = 0; i < points.items; i++) { + /* Search the stack of triangles adjacent to a point. */ + nexttri = vertexarray[i]; + decode(nexttri, checktri); + while (checktri.tri != dummytri) { + /* Find the next triangle in the stack before this */ + /* information gets overwritten. */ + nexttri = checktri.tri[6 + checktri.orient]; + /* No adjacent shell edge. (This overwrites the stack info.) */ + tsdissolve(checktri); + sym(checktri, checkneighbor); + if (checkneighbor.tri == dummytri) { + insertshelle(&checktri, 1); + hullsize++; + } + decode(nexttri, checktri); + } + } + + free(vertexarray); + return hullsize; +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* General mesh construction routines end here *********/ + +/********* Segment (shell edge) insertion begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* finddirection() Find the first triangle on the path from one point */ +/* to another. */ +/* */ +/* Finds the triangle that intersects a line segment drawn from the */ +/* origin of `searchtri' to the point `endpoint', and returns the result */ +/* in `searchtri'. The origin of `searchtri' does not change, even though */ +/* the triangle returned may differ from the one passed in. This routine */ +/* is used to find the direction to move in to get from one point to */ +/* another. */ +/* */ +/* The return value notes whether the destination or apex of the found */ +/* triangle is collinear with the two points in question. */ +/* */ +/*****************************************************************************/ + +enum finddirectionresult finddirection(searchtri, endpoint) +struct triedge *searchtri; +point endpoint; +{ + struct triedge checktri; + point startpoint; + point leftpoint, rightpoint; + REAL leftccw, rightccw; + int leftflag, rightflag; + triangle ptr; /* Temporary variable used by onext() and oprev(). */ + + org(*searchtri, startpoint); + dest(*searchtri, rightpoint); + apex(*searchtri, leftpoint); + /* Is `endpoint' to the left? */ + leftccw = counterclockwise(endpoint, startpoint, leftpoint); + leftflag = leftccw > 0.0; + /* Is `endpoint' to the right? */ + rightccw = counterclockwise(startpoint, endpoint, rightpoint); + rightflag = rightccw > 0.0; + if (leftflag && rightflag) { + /* `searchtri' faces directly away from `endpoint'. We could go */ + /* left or right. Ask whether it's a triangle or a boundary */ + /* on the left. */ + onext(*searchtri, checktri); + if (checktri.tri == dummytri) { + leftflag = 0; + } else { + rightflag = 0; + } + } + while (leftflag) { + /* Turn left until satisfied. */ + onextself(*searchtri); + if (searchtri->tri == dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], + startpoint[1]); + printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); + internalerror(); + } + apex(*searchtri, leftpoint); + rightccw = leftccw; + leftccw = counterclockwise(endpoint, startpoint, leftpoint); + leftflag = leftccw > 0.0; + } + while (rightflag) { + /* Turn right until satisfied. */ + oprevself(*searchtri); + if (searchtri->tri == dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], + startpoint[1]); + printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); + internalerror(); + } + dest(*searchtri, rightpoint); + leftccw = rightccw; + rightccw = counterclockwise(startpoint, endpoint, rightpoint); + rightflag = rightccw > 0.0; + } + if (leftccw == 0.0) { + return LEFTCOLLINEAR; + } else if (rightccw == 0.0) { + return RIGHTCOLLINEAR; + } else { + return WITHIN; + } +} + +/*****************************************************************************/ +/* */ +/* segmentintersection() Find the intersection of an existing segment */ +/* and a segment that is being inserted. Insert */ +/* a point at the intersection, splitting an */ +/* existing shell edge. */ +/* */ +/* The segment being inserted connects the apex of splittri to endpoint2. */ +/* splitshelle is the shell edge being split, and MUST be opposite */ +/* splittri. Hence, the edge being split connects the origin and */ +/* destination of splittri. */ +/* */ +/* On completion, splittri is a handle having the newly inserted */ +/* intersection point as its origin, and endpoint1 as its destination. */ +/* */ +/*****************************************************************************/ + +void segmentintersection(splittri, splitshelle, endpoint2) +struct triedge *splittri; +struct edge *splitshelle; +point endpoint2; +{ + point endpoint1; + point torg, tdest; + point leftpoint, rightpoint; + point newpoint; + enum insertsiteresult success; + enum finddirectionresult collinear; + REAL ex, ey; + REAL tx, ty; + REAL etx, ety; + REAL split, denom; + int i; + triangle ptr; /* Temporary variable used by onext(). */ + + /* Find the other three segment endpoints. */ + apex(*splittri, endpoint1); + org(*splittri, torg); + dest(*splittri, tdest); + /* Segment intersection formulae; see the Antonio reference. */ + tx = tdest[0] - torg[0]; + ty = tdest[1] - torg[1]; + ex = endpoint2[0] - endpoint1[0]; + ey = endpoint2[1] - endpoint1[1]; + etx = torg[0] - endpoint2[0]; + ety = torg[1] - endpoint2[1]; + denom = ty * ex - tx * ey; + if (denom == 0.0) { + printf("Internal error in segmentintersection():"); + printf(" Attempt to find intersection of parallel segments.\n"); + internalerror(); + } + split = (ey * etx - ex * ety) / denom; + /* Create the new point. */ + newpoint = (point) poolalloc(&points); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = torg[i] + split * (tdest[i] - torg[i]); + } + setpointmark(newpoint, mark(*splitshelle)); + if (verbose > 1) { + printf( + " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + torg[0], torg[1], tdest[0], tdest[1], newpoint[0], newpoint[1]); + } + /* Insert the intersection point. This should always succeed. */ + success = insertsite(newpoint, splittri, splitshelle, 0, 0); + if (success != SUCCESSFULPOINT) { + printf("Internal error in segmentintersection():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (steinerleft > 0) { + steinerleft--; + } + /* Inserting the point may have caused edge flips. We wish to rediscover */ + /* the edge connecting endpoint1 to the new intersection point. */ + collinear = finddirection(splittri, endpoint1); + dest(*splittri, rightpoint); + apex(*splittri, leftpoint); + if ((leftpoint[0] == endpoint1[0]) && (leftpoint[1] == endpoint1[1])) { + onextself(*splittri); + } else if ((rightpoint[0] != endpoint1[0]) || + (rightpoint[1] != endpoint1[1])) { + printf("Internal error in segmentintersection():\n"); + printf(" Topological inconsistency after splitting a segment.\n"); + internalerror(); + } + /* `splittri' should have destination endpoint1. */ +} + +/*****************************************************************************/ +/* */ +/* scoutsegment() Scout the first triangle on the path from one endpoint */ +/* to another, and check for completion (reaching the */ +/* second endpoint), a collinear point, and the */ +/* intersection of two segments. */ +/* */ +/* Returns one if the entire segment is successfully inserted, and zero if */ +/* the job must be finished by conformingedge() or constrainededge(). */ +/* */ +/* If the first triangle on the path has the second endpoint as its */ +/* destination or apex, a shell edge is inserted and the job is done. */ +/* */ +/* If the first triangle on the path has a destination or apex that lies on */ +/* the segment, a shell edge is inserted connecting the first endpoint to */ +/* the collinear point, and the search is continued from the collinear */ +/* point. */ +/* */ +/* If the first triangle on the path has a shell edge opposite its origin, */ +/* then there is a segment that intersects the segment being inserted. */ +/* Their intersection point is inserted, splitting the shell edge. */ +/* */ +/* Otherwise, return zero. */ +/* */ +/*****************************************************************************/ + +int scoutsegment(searchtri, endpoint2, newmark) +struct triedge *searchtri; +point endpoint2; +int newmark; +{ + struct triedge crosstri; + struct edge crossedge; + point leftpoint, rightpoint; + point endpoint1; + enum finddirectionresult collinear; + shelle sptr; /* Temporary variable used by tspivot(). */ + + collinear = finddirection(searchtri, endpoint2); + dest(*searchtri, rightpoint); + apex(*searchtri, leftpoint); + if (((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) || + ((rightpoint[0] == endpoint2[0]) && (rightpoint[1] == endpoint2[1]))) { + /* The segment is already an edge in the mesh. */ + if ((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) { + lprevself(*searchtri); + } + /* Insert a shell edge, if there isn't already one there. */ + insertshelle(searchtri, newmark); + return 1; + } else if (collinear == LEFTCOLLINEAR) { + /* We've collided with a point between the segment's endpoints. */ + /* Make the collinear point be the triangle's origin. */ + lprevself(*searchtri); + insertshelle(searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } else if (collinear == RIGHTCOLLINEAR) { + /* We've collided with a point between the segment's endpoints. */ + insertshelle(searchtri, newmark); + /* Make the collinear point be the triangle's origin. */ + lnextself(*searchtri); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } else { + lnext(*searchtri, crosstri); + tspivot(crosstri, crossedge); + /* Check for a crossing segment. */ + if (crossedge.sh == dummysh) { + return 0; + } else { + org(*searchtri, endpoint1); + /* Insert a point at the intersection. */ + segmentintersection(&crosstri, &crossedge, endpoint2); + triedgecopy(crosstri, *searchtri); + insertshelle(searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* conformingedge() Force a segment into a conforming Delaunay */ +/* triangulation by inserting a point at its midpoint, */ +/* and recursively forcing in the two half-segments if */ +/* necessary. */ +/* */ +/* Generates a sequence of edges connecting `endpoint1' to `endpoint2'. */ +/* `newmark' is the boundary marker of the segment, assigned to each new */ +/* splitting point and shell edge. */ +/* */ +/* Note that conformingedge() does not always maintain the conforming */ +/* Delaunay property. Once inserted, segments are locked into place; */ +/* points inserted later (to force other segments in) may render these */ +/* fixed segments non-Delaunay. The conforming Delaunay property will be */ +/* restored by enforcequality() by splitting encroached segments. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED +#ifndef CDT_ONLY + +void conformingedge(endpoint1, endpoint2, newmark) +point endpoint1; +point endpoint2; +int newmark; +{ + struct triedge searchtri1, searchtri2; + struct edge brokenshelle; + point newpoint; + point midpoint1, midpoint2; + enum insertsiteresult success; + int result1, result2; + int i; + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose > 2) { + printf("Forcing segment into triangulation by recursive splitting:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1], + endpoint2[0], endpoint2[1]); + } + /* Create a new point to insert in the middle of the segment. */ + newpoint = (point) poolalloc(&points); + /* Interpolate coordinates and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = 0.5 * (endpoint1[i] + endpoint2[i]); + } + setpointmark(newpoint, newmark); + /* Find a boundary triangle to search from. */ + searchtri1.tri = (triangle *) NULL; + /* Attempt to insert the new point. */ + success = insertsite(newpoint, &searchtri1, (struct edge *) NULL, 0, 0); + if (success == DUPLICATEPOINT) { + if (verbose > 2) { + printf(" Segment intersects existing point (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + } + /* Use the point that's already there. */ + pointdealloc(newpoint); + org(searchtri1, newpoint); + } else { + if (success == VIOLATINGPOINT) { + if (verbose > 2) { + printf(" Two segments intersect at (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + } + /* By fluke, we've landed right on another segment. Split it. */ + tspivot(searchtri1, brokenshelle); + success = insertsite(newpoint, &searchtri1, &brokenshelle, 0, 0); + if (success != SUCCESSFULPOINT) { + printf("Internal error in conformingedge():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + } + /* The point has been inserted successfully. */ + if (steinerleft > 0) { + steinerleft--; + } + } + triedgecopy(searchtri1, searchtri2); + result1 = scoutsegment(&searchtri1, endpoint1, newmark); + result2 = scoutsegment(&searchtri2, endpoint2, newmark); + if (!result1) { + /* The origin of searchtri1 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri1, midpoint1); + conformingedge(midpoint1, endpoint1, newmark); + } + if (!result2) { + /* The origin of searchtri2 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri2, midpoint2); + conformingedge(midpoint2, endpoint2, newmark); + } +} + +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* delaunayfixup() Enforce the Delaunay condition at an edge, fanning out */ +/* recursively from an existing point. Pay special */ +/* attention to stacking inverted triangles. */ +/* */ +/* This is a support routine for inserting segments into a constrained */ +/* Delaunay triangulation. */ +/* */ +/* The origin of fixuptri is treated as if it has just been inserted, and */ +/* the local Delaunay condition needs to be enforced. It is only enforced */ +/* in one sector, however, that being the angular range defined by */ +/* fixuptri. */ +/* */ +/* This routine also needs to make decisions regarding the "stacking" of */ +/* triangles. (Read the description of constrainededge() below before */ +/* reading on here, so you understand the algorithm.) If the position of */ +/* the new point (the origin of fixuptri) indicates that the vertex before */ +/* it on the polygon is a reflex vertex, then "stack" the triangle by */ +/* doing nothing. (fixuptri is an inverted triangle, which is how stacked */ +/* triangles are identified.) */ +/* */ +/* Otherwise, check whether the vertex before that was a reflex vertex. */ +/* If so, perform an edge flip, thereby eliminating an inverted triangle */ +/* (popping it off the stack). The edge flip may result in the creation */ +/* of a new inverted triangle, depending on whether or not the new vertex */ +/* is visible to the vertex three edges behind on the polygon. */ +/* */ +/* If neither of the two vertices behind the new vertex are reflex */ +/* vertices, fixuptri and fartri, the triangle opposite it, are not */ +/* inverted; hence, ensure that the edge between them is locally Delaunay. */ +/* */ +/* `leftside' indicates whether or not fixuptri is to the left of the */ +/* segment being inserted. (Imagine that the segment is pointing up from */ +/* endpoint1 to endpoint2.) */ +/* */ +/*****************************************************************************/ + +void delaunayfixup(fixuptri, leftside) +struct triedge *fixuptri; +int leftside; +{ + struct triedge neartri; + struct triedge fartri; + struct edge faredge; + point nearpoint, leftpoint, rightpoint, farpoint; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + lnext(*fixuptri, neartri); + sym(neartri, fartri); + /* Check if the edge opposite the origin of fixuptri can be flipped. */ + if (fartri.tri == dummytri) { + return; + } + tspivot(neartri, faredge); + if (faredge.sh != dummysh) { + return; + } + /* Find all the relevant vertices. */ + apex(neartri, nearpoint); + org(neartri, leftpoint); + dest(neartri, rightpoint); + apex(fartri, farpoint); + /* Check whether the previous polygon vertex is a reflex vertex. */ + if (leftside) { + if (counterclockwise(nearpoint, leftpoint, farpoint) <= 0.0) { + /* leftpoint is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } else { + if (counterclockwise(farpoint, rightpoint, nearpoint) <= 0.0) { + /* rightpoint is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } + if (counterclockwise(rightpoint, leftpoint, farpoint) > 0.0) { + /* fartri is not an inverted triangle, and farpoint is not a reflex */ + /* vertex. As there are no reflex vertices, fixuptri isn't an */ + /* inverted triangle, either. Hence, test the edge between the */ + /* triangles to ensure it is locally Delaunay. */ + if (incircle(leftpoint, farpoint, rightpoint, nearpoint) <= 0.0) { + return; + } + /* Not locally Delaunay; go on to an edge flip. */ + } /* else fartri is inverted; remove it from the stack by flipping. */ + flip(&neartri); + lprevself(*fixuptri); /* Restore the origin of fixuptri after the flip. */ + /* Recursively process the two triangles that result from the flip. */ + delaunayfixup(fixuptri, leftside); + delaunayfixup(&fartri, leftside); +} + +/*****************************************************************************/ +/* */ +/* constrainededge() Force a segment into a constrained Delaunay */ +/* triangulation by deleting the triangles it */ +/* intersects, and triangulating the polygons that */ +/* form on each side of it. */ +/* */ +/* Generates a single edge connecting `endpoint1' to `endpoint2'. The */ +/* triangle `starttri' has `endpoint1' as its origin. `newmark' is the */ +/* boundary marker of the segment. */ +/* */ +/* To insert a segment, every triangle whose interior intersects the */ +/* segment is deleted. The union of these deleted triangles is a polygon */ +/* (which is not necessarily monotone, but is close enough), which is */ +/* divided into two polygons by the new segment. This routine's task is */ +/* to generate the Delaunay triangulation of these two polygons. */ +/* */ +/* You might think of this routine's behavior as a two-step process. The */ +/* first step is to walk from endpoint1 to endpoint2, flipping each edge */ +/* encountered. This step creates a fan of edges connected to endpoint1, */ +/* including the desired edge to endpoint2. The second step enforces the */ +/* Delaunay condition on each side of the segment in an incremental manner: */ +/* proceeding along the polygon from endpoint1 to endpoint2 (this is done */ +/* independently on each side of the segment), each vertex is "enforced" */ +/* as if it had just been inserted, but affecting only the previous */ +/* vertices. The result is the same as if the vertices had been inserted */ +/* in the order they appear on the polygon, so the result is Delaunay. */ +/* */ +/* In truth, constrainededge() interleaves these two steps. The procedure */ +/* walks from endpoint1 to endpoint2, and each time an edge is encountered */ +/* and flipped, the newly exposed vertex (at the far end of the flipped */ +/* edge) is "enforced" upon the previously flipped edges, usually affecting */ +/* only one side of the polygon (depending upon which side of the segment */ +/* the vertex falls on). */ +/* */ +/* The algorithm is complicated by the need to handle polygons that are not */ +/* convex. Although the polygon is not necessarily monotone, it can be */ +/* triangulated in a manner similar to the stack-based algorithms for */ +/* monotone polygons. For each reflex vertex (local concavity) of the */ +/* polygon, there will be an inverted triangle formed by one of the edge */ +/* flips. (An inverted triangle is one with negative area - that is, its */ +/* vertices are arranged in clockwise order - and is best thought of as a */ +/* wrinkle in the fabric of the mesh.) Each inverted triangle can be */ +/* thought of as a reflex vertex pushed on the stack, waiting to be fixed */ +/* later. */ +/* */ +/* A reflex vertex is popped from the stack when a vertex is inserted that */ +/* is visible to the reflex vertex. (However, if the vertex behind the */ +/* reflex vertex is not visible to the reflex vertex, a new inverted */ +/* triangle will take its place on the stack.) These details are handled */ +/* by the delaunayfixup() routine above. */ +/* */ +/*****************************************************************************/ + +void constrainededge(starttri, endpoint2, newmark) +struct triedge *starttri; +point endpoint2; +int newmark; +{ + struct triedge fixuptri, fixuptri2; + struct edge fixupedge; + point endpoint1; + point farpoint; + REAL area; + int collision; + int done; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*starttri, endpoint1); + lnext(*starttri, fixuptri); + flip(&fixuptri); + /* `collision' indicates whether we have found a point directly */ + /* between endpoint1 and endpoint2. */ + collision = 0; + done = 0; + do { + org(fixuptri, farpoint); + /* `farpoint' is the extreme point of the polygon we are "digging" */ + /* to get from endpoint1 to endpoint2. */ + if ((farpoint[0] == endpoint2[0]) && (farpoint[1] == endpoint2[1])) { + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around endpoint2. */ + delaunayfixup(&fixuptri, 0); + delaunayfixup(&fixuptri2, 1); + done = 1; + } else { + /* Check whether farpoint is to the left or right of the segment */ + /* being inserted, to decide which edge of fixuptri to dig */ + /* through next. */ + area = counterclockwise(endpoint1, endpoint2, farpoint); + if (area == 0.0) { + /* We've collided with a point between endpoint1 and endpoint2. */ + collision = 1; + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farpoint. */ + delaunayfixup(&fixuptri, 0); + delaunayfixup(&fixuptri2, 1); + done = 1; + } else { + if (area > 0.0) { /* farpoint is to the left of the segment. */ + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farpoint, on the */ + /* left side of the segment only. */ + delaunayfixup(&fixuptri2, 1); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + lprevself(fixuptri); + } else { /* farpoint is to the right of the segment. */ + delaunayfixup(&fixuptri, 0); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + oprevself(fixuptri); + } + /* Check for two intersecting segments. */ + tspivot(fixuptri, fixupedge); + if (fixupedge.sh == dummysh) { + flip(&fixuptri); /* May create an inverted triangle on the left. */ + } else { + /* We've collided with a segment between endpoint1 and endpoint2. */ + collision = 1; + /* Insert a point at the intersection. */ + segmentintersection(&fixuptri, &fixupedge, endpoint2); + done = 1; + } + } + } + } while (!done); + /* Insert a shell edge to make the segment permanent. */ + insertshelle(&fixuptri, newmark); + /* If there was a collision with an interceding vertex, install another */ + /* segment connecting that vertex with endpoint2. */ + if (collision) { + /* Insert the remainder of the segment. */ + if (!scoutsegment(&fixuptri, endpoint2, newmark)) { + constrainededge(&fixuptri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* insertsegment() Insert a PSLG segment into a triangulation. */ +/* */ +/*****************************************************************************/ + +void insertsegment(endpoint1, endpoint2, newmark) +point endpoint1; +point endpoint2; +int newmark; +{ + struct triedge searchtri1, searchtri2; + triangle encodedtri; + point checkpoint; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 1) { + printf(" Connecting (%.12g, %.12g) to (%.12g, %.12g).\n", + endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]); + } + + /* Find a triangle whose origin is the segment's first endpoint. */ + checkpoint = (point) NULL; + encodedtri = point2tri(endpoint1); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri1); + org(searchtri1, checkpoint); + } + if (checkpoint != endpoint1) { + /* Find a boundary triangle to search from. */ + searchtri1.tri = dummytri; + searchtri1.orient = 0; + symself(searchtri1); + /* Search for the segment's first endpoint by point location. */ + if (locate(endpoint1, &searchtri1) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG point\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint1[0], endpoint1[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + triedgecopy(searchtri1, recenttri); + /* Scout the beginnings of a path from the first endpoint */ + /* toward the second. */ + if (scoutsegment(&searchtri1, endpoint2, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The first endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri1, endpoint1); + + /* Find a triangle whose origin is the segment's second endpoint. */ + checkpoint = (point) NULL; + encodedtri = point2tri(endpoint2); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri2); + org(searchtri2, checkpoint); + } + if (checkpoint != endpoint2) { + /* Find a boundary triangle to search from. */ + searchtri2.tri = dummytri; + searchtri2.orient = 0; + symself(searchtri2); + /* Search for the segment's second endpoint by point location. */ + if (locate(endpoint2, &searchtri2) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG point\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint2[0], endpoint2[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + triedgecopy(searchtri2, recenttri); + /* Scout the beginnings of a path from the second endpoint */ + /* toward the first. */ + if (scoutsegment(&searchtri2, endpoint1, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The second endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri2, endpoint2); + +#ifndef REDUCED +#ifndef CDT_ONLY + if (splitseg) { + /* Insert vertices to force the segment into the triangulation. */ + conformingedge(endpoint1, endpoint2, newmark); + } else { +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + /* Insert the segment directly into the triangulation. */ + constrainededge(&searchtri1, endpoint2, newmark); +#ifndef REDUCED +#ifndef CDT_ONLY + } +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ +} + +/*****************************************************************************/ +/* */ +/* markhull() Cover the convex hull of a triangulation with shell edges. */ +/* */ +/*****************************************************************************/ + +void markhull() +{ + struct triedge hulltri; + struct triedge nexttri; + struct triedge starttri; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + + /* Find a triangle handle on the hull. */ + hulltri.tri = dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + triedgecopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Create a shell edge if there isn't already one here. */ + insertshelle(&hulltri, 1); + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != dummytri) { + triedgecopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!triedgeequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* formskeleton() Create the shell edges of a triangulation, including */ +/* PSLG edges and edges on the convex hull. */ +/* */ +/* The PSLG edges are read from a .poly file. The return value is the */ +/* number of segments in the file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +int formskeleton(segmentlist, segmentmarkerlist, numberofsegments) +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; + +#else /* not TRILIBRARY */ + +int formskeleton(polyfile, polyfilename) +FILE *polyfile; +char *polyfilename; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + char polyfilename[6]; + int index; +#else /* not TRILIBRARY */ + char inputline[INPUTLINESIZE]; + char *stringptr; +#endif /* not TRILIBRARY */ + point endpoint1, endpoint2; + int segments; + int segmentmarkers; + int end1, end2; + int boundmarker; + int i; + + if (poly) { + if (!quiet) { + printf("Inserting segments into Delaunay triangulation.\n"); + } +#ifdef TRILIBRARY + strcpy(polyfilename, "input"); + segments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; + index = 0; +#else /* not TRILIBRARY */ + /* Read the segments from a .poly file. */ + /* Read number of segments and number of boundary markers. */ + stringptr = readline(inputline, polyfile, polyfilename); + segments = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + /* If segments are to be inserted, compute a mapping */ + /* from points to triangles. */ + if (segments > 0) { + if (verbose) { + printf(" Inserting PSLG segments.\n"); + } + makepointmap(); + } + + boundmarker = 0; + /* Read and insert the segments. */ + for (i = 1; i <= segments; i++) { +#ifdef TRILIBRARY + end1 = segmentlist[index++]; + end2 = segmentlist[index++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[i - 1]; + } +#else /* not TRILIBRARY */ + stringptr = readline(inputline, polyfile, inpolyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d has no endpoints in %s.\n", i, + polyfilename); + exit(1); + } else { + end1 = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d is missing its second endpoint in %s.\n", i, + polyfilename); + exit(1); + } else { + end2 = (int) strtol (stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol (stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) { + if (!quiet) { + printf("Warning: Invalid first endpoint of segment %d in %s.\n", i, + polyfilename); + } + } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) { + if (!quiet) { + printf("Warning: Invalid second endpoint of segment %d in %s.\n", i, + polyfilename); + } + } else { + endpoint1 = getpoint(end1); + endpoint2 = getpoint(end2); + if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) { + if (!quiet) { + printf("Warning: Endpoints of segment %d are coincident in %s.\n", + i, polyfilename); + } + } else { + insertsegment(endpoint1, endpoint2, boundmarker); + } + } + } + } else { + segments = 0; + } + if (convex || !poly) { + /* Enclose the convex hull with shell edges. */ + if (verbose) { + printf(" Enclosing convex hull with segments.\n"); + } + markhull(); + } + return segments; +} + +/** **/ +/** **/ +/********* Segment (shell edge) insertion ends here *********/ + +/********* Carving out holes and concavities begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* infecthull() Virally infect all of the triangles of the convex hull */ +/* that are not protected by shell edges. Where there are */ +/* shell edges, set boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +void infecthull() +{ + struct triedge hulltri; + struct triedge nexttri; + struct triedge starttri; + struct edge hulledge; + triangle **deadtri; + point horg, hdest; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose) { + printf(" Marking concavities (external triangles) for elimination.\n"); + } + /* Find a triangle handle on the hull. */ + hulltri.tri = dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + triedgecopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Ignore triangles that are already infected. */ + if (!infected(hulltri)) { + /* Is the triangle protected by a shell edge? */ + tspivot(hulltri, hulledge); + if (hulledge.sh == dummysh) { + /* The triangle is not protected; infect it. */ + infect(hulltri); + deadtri = (triangle **) poolalloc(&viri); + *deadtri = hulltri.tri; + } else { + /* The triangle is protected; set boundary markers if appropriate. */ + if (mark(hulledge) == 0) { + setmark(hulledge, 1); + org(hulltri, horg); + dest(hulltri, hdest); + if (pointmark(horg) == 0) { + setpointmark(horg, 1); + } + if (pointmark(hdest) == 0) { + setpointmark(hdest, 1); + } + } + } + } + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != dummytri) { + triedgecopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!triedgeequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* plague() Spread the virus from all infected triangles to any neighbors */ +/* not protected by shell edges. Delete all infected triangles. */ +/* */ +/* This is the procedure that actually creates holes and concavities. */ +/* */ +/* This procedure operates in two phases. The first phase identifies all */ +/* the triangles that will die, and marks them as infected. They are */ +/* marked to ensure that each triangle is added to the virus pool only */ +/* once, so the procedure will terminate. */ +/* */ +/* The second phase actually eliminates the infected triangles. It also */ +/* eliminates orphaned points. */ +/* */ +/*****************************************************************************/ + +void plague() +{ + struct triedge testtri; + struct triedge neighbor; + triangle **virusloop; + triangle **deadtri; + struct edge neighborshelle; + point testpoint; + point norg, ndest; + point deadorg, deaddest, deadapex; + int killorg; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the virus to */ + /* their neighbors, then to their neighbors' neighbors. */ + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its shell */ + /* edges, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent shell edges. */ + uninfect(testtri); + if (verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its points. */ + testtri.orient = 0; + org(testtri, deadorg); + dest(testtri, deaddest); + apex(testtri, deadapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a shell between the triangle and its neighbor. */ + tspivot(testtri, neighborshelle); + /* Check if the neighbor is nonexistent or already infected. */ + if ((neighbor.tri == dummytri) || infected(neighbor)) { + if (neighborshelle.sh != dummysh) { + /* There is a shell edge separating the triangle from its */ + /* neighbor, but both triangles are dying, so the shell */ + /* edge dies too. */ + shelledealloc(neighborshelle.sh); + if (neighbor.tri != dummytri) { + /* Make sure the shell edge doesn't get deallocated again */ + /* later when the infected neighbor is visited. */ + uninfect(neighbor); + tsdissolve(neighbor); + infect(neighbor); + } + } + } else { /* The neighbor exists and is not infected. */ + if (neighborshelle.sh == dummysh) { + /* There is no shell edge protecting the neighbor, so */ + /* the neighbor becomes infected. */ + if (verbose > 2) { + org(neighbor, deadorg); + dest(neighbor, deaddest); + apex(neighbor, deadapex); + printf( + " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + deadtri = (triangle **) poolalloc(&viri); + *deadtri = neighbor.tri; + } else { /* The neighbor is protected by a shell edge. */ + /* Remove this triangle from the shell edge. */ + stdissolve(neighborshelle); + /* The shell edge becomes a boundary. Set markers accordingly. */ + if (mark(neighborshelle) == 0) { + setmark(neighborshelle, 1); + } + org(neighbor, norg); + dest(neighbor, ndest); + if (pointmark(norg) == 0) { + setpointmark(norg, 1); + } + if (pointmark(ndest) == 0) { + setpointmark(ndest, 1); + } + } + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&viri); + } + + if (verbose) { + printf(" Deleting marked triangles.\n"); + } + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + + /* Check each of the three corners of the triangle for elimination. */ + /* This is done by walking around each point, checking if it is */ + /* still connected to at least one live triangle. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + org(testtri, testpoint); + /* Check if the point has already been tested. */ + if (testpoint != (point) NULL) { + killorg = 1; + /* Mark the corner of the triangle as having been tested. */ + setorg(testtri, NULL); + /* Walk counterclockwise about the point. */ + onext(testtri, neighbor); + /* Stop upon reaching a boundary or the starting triangle. */ + while ((neighbor.tri != dummytri) + && (!triedgeequal(neighbor, testtri))) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The point survives. */ + killorg = 0; + } + /* Walk counterclockwise about the point. */ + onextself(neighbor); + } + /* If we reached a boundary, we must walk clockwise as well. */ + if (neighbor.tri == dummytri) { + /* Walk clockwise about the point. */ + oprev(testtri, neighbor); + /* Stop upon reaching a boundary. */ + while (neighbor.tri != dummytri) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The point survives. */ + killorg = 0; + } + /* Walk clockwise about the point. */ + oprevself(neighbor); + } + } + if (killorg) { + if (verbose > 1) { + printf(" Deleting point (%.12g, %.12g)\n", + testpoint[0], testpoint[1]); + } + pointdealloc(testpoint); + } + } + } + + /* Record changes in the number of boundary edges, and disconnect */ + /* dead triangles from their neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + sym(testtri, neighbor); + if (neighbor.tri == dummytri) { + /* There is no neighboring triangle on this edge, so this edge */ + /* is a boundary edge. This triangle is being deleted, so this */ + /* boundary edge is deleted. */ + hullsize--; + } else { + /* Disconnect the triangle from its neighbor. */ + dissolve(neighbor); + /* There is a neighboring triangle on this edge, so this edge */ + /* becomes a boundary edge when this triangle is deleted. */ + hullsize++; + } + } + /* Return the dead triangle to the pool of triangles. */ + triangledealloc(testtri.tri); + virusloop = (triangle **) traverse(&viri); + } + /* Empty the virus pool. */ + poolrestart(&viri); +} + +/*****************************************************************************/ +/* */ +/* regionplague() Spread regional attributes and/or area constraints */ +/* (from a .poly file) throughout the mesh. */ +/* */ +/* This procedure operates in two phases. The first phase spreads an */ +/* attribute and/or an area constraint through a (segment-bounded) region. */ +/* The triangles are marked to ensure that each triangle is added to the */ +/* virus pool only once, so the procedure will terminate. */ +/* */ +/* The second phase uninfects all infected triangles, returning them to */ +/* normal. */ +/* */ +/*****************************************************************************/ + +void regionplague(attribute, area) +REAL attribute; +REAL area; +{ + struct triedge testtri; + struct triedge neighbor; + triangle **virusloop; + triangle **regiontri; + struct edge neighborshelle; + point regionorg, regiondest, regionapex; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose > 1) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the attribute */ + /* and/or area constraint to their neighbors, then to their neighbors' */ + /* neighbors. */ + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its shell */ + /* edges, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent shell edges. */ + uninfect(testtri); + if (regionattrib) { + /* Set an attribute. */ + setelemattribute(testtri, eextras, attribute); + } + if (vararea) { + /* Set an area constraint. */ + setareabound(testtri, area); + } + if (verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its points. */ + testtri.orient = 0; + org(testtri, regionorg); + dest(testtri, regiondest); + apex(testtri, regionapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a shell between the triangle and its neighbor. */ + tspivot(testtri, neighborshelle); + /* Make sure the neighbor exists, is not already infected, and */ + /* isn't protected by a shell edge. */ + if ((neighbor.tri != dummytri) && !infected(neighbor) + && (neighborshelle.sh == dummysh)) { + if (verbose > 2) { + org(neighbor, regionorg); + dest(neighbor, regiondest); + apex(neighbor, regionapex); + printf(" Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Infect the neighbor. */ + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + regiontri = (triangle **) poolalloc(&viri); + *regiontri = neighbor.tri; + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&viri); + } + + /* Uninfect all triangles. */ + if (verbose > 1) { + printf(" Unmarking marked triangles.\n"); + } + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + uninfect(testtri); + virusloop = (triangle **) traverse(&viri); + } + /* Empty the virus pool. */ + poolrestart(&viri); +} + +/*****************************************************************************/ +/* */ +/* carveholes() Find the holes and infect them. Find the area */ +/* constraints and infect them. Infect the convex hull. */ +/* Spread the infection and kill triangles. Spread the */ +/* area constraints. */ +/* */ +/* This routine mainly calls other routines to carry out all these */ +/* functions. */ +/* */ +/*****************************************************************************/ + +void carveholes(holelist, holes, regionlist, regions) +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +{ + struct triedge searchtri; + struct triedge triangleloop; + struct triedge *regiontris; + triangle **holetri; + triangle **regiontri; + point searchorg, searchdest; + enum locateresult intersect; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + + if (!(quiet || (noholes && convex))) { + printf("Removing unwanted triangles.\n"); + if (verbose && (holes > 0)) { + printf(" Marking holes for elimination.\n"); + } + } + + if (regions > 0) { + /* Allocate storage for the triangles in which region points fall. */ + regiontris = (struct triedge *) malloc(regions * sizeof(struct triedge)); + if (regiontris == (struct triedge *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + + if (((holes > 0) && !noholes) || !convex || (regions > 0)) { + /* Initialize a pool of viri to be used for holes, concavities, */ + /* regional attributes, and/or regional area constraints. */ + poolinit(&viri, sizeof(triangle *), VIRUSPERBLOCK, POINTER, 0); + } + + if (!convex) { + /* Mark as infected any unprotected triangles on the boundary. */ + /* This is one way by which concavities are created. */ + infecthull(); + } + + if ((holes > 0) && !noholes) { + /* Infect each triangle in which a hole lies. */ + for (i = 0; i < 2 * holes; i += 2) { + /* Ignore holes that aren't within the bounds of the mesh. */ + if ((holelist[i] >= xmin) && (holelist[i] <= xmax) + && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the hole is to the left of this boundary edge; */ + /* otherwise, locate() will falsely report that the hole */ + /* falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(searchorg, searchdest, &holelist[i]) > 0.0) { + /* Find a triangle that contains the hole. */ + intersect = locate(&holelist[i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Infect the triangle. This is done by marking the triangle */ + /* as infect and including the triangle in the virus pool. */ + infect(searchtri); + holetri = (triangle **) poolalloc(&viri); + *holetri = searchtri.tri; + } + } + } + } + } + + /* Now, we have to find all the regions BEFORE we carve the holes, because */ + /* locate() won't work when the triangulation is no longer convex. */ + /* (Incidentally, this is the reason why regional attributes and area */ + /* constraints can't be used when refining a preexisting mesh, which */ + /* might not be convex; they can only be used with a freshly */ + /* triangulated PSLG.) */ + if (regions > 0) { + /* Find the starting triangle for each region. */ + for (i = 0; i < regions; i++) { + regiontris[i].tri = dummytri; + /* Ignore region points that aren't within the bounds of the mesh. */ + if ((regionlist[4 * i] >= xmin) && (regionlist[4 * i] <= xmax) && + (regionlist[4 * i + 1] >= ymin) && (regionlist[4 * i + 1] <= ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the region point is to the left of this boundary */ + /* edge; otherwise, locate() will falsely report that the */ + /* region point falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(searchorg, searchdest, ®ionlist[4 * i]) > + 0.0) { + /* Find a triangle that contains the region point. */ + intersect = locate(®ionlist[4 * i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Record the triangle for processing after the */ + /* holes have been carved. */ + triedgecopy(searchtri, regiontris[i]); + } + } + } + } + } + + if (viri.items > 0) { + /* Carve the holes and concavities. */ + plague(); + } + /* The virus pool should be empty now. */ + + if (regions > 0) { + if (!quiet) { + if (regionattrib) { + if (vararea) { + printf("Spreading regional attributes and area constraints.\n"); + } else { + printf("Spreading regional attributes.\n"); + } + } else { + printf("Spreading regional area constraints.\n"); + } + } + if (regionattrib && !refine) { + /* Assign every triangle a regional attribute of zero. */ + traversalinit(&triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + setelemattribute(triangleloop, eextras, 0.0); + triangleloop.tri = triangletraverse(); + } + } + for (i = 0; i < regions; i++) { + if (regiontris[i].tri != dummytri) { + /* Make sure the triangle under consideration still exists. */ + /* It may have been eaten by the virus. */ + if (regiontris[i].tri[3] != (triangle) NULL) { + /* Put one triangle in the virus pool. */ + infect(regiontris[i]); + regiontri = (triangle **) poolalloc(&viri); + *regiontri = regiontris[i].tri; + /* Apply one region's attribute and/or area constraint. */ + regionplague(regionlist[4 * i + 2], regionlist[4 * i + 3]); + /* The virus pool should be empty now. */ + } + } + } + if (regionattrib && !refine) { + /* Note the fact that each triangle has an additional attribute. */ + eextras++; + } + } + + /* Free up memory. */ + if (((holes > 0) && !noholes) || !convex || (regions > 0)) { + pooldeinit(&viri); + } + if (regions > 0) { + free(regiontris); + } +} + +/** **/ +/** **/ +/********* Carving out holes and concavities ends here *********/ + +/********* Mesh quality maintenance begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* tallyencs() Traverse the entire list of shell edges, check each edge */ +/* to see if it is encroached. If so, add it to the list. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void tallyencs() +{ + struct edge edgeloop; + int dummy; + + traversalinit(&shelles); + edgeloop.shorient = 0; + edgeloop.sh = shelletraverse(); + while (edgeloop.sh != (shelle *) NULL) { + /* If the segment is encroached, add it to the list. */ + dummy = checkedge4encroach(&edgeloop); + edgeloop.sh = shelletraverse(); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* precisionerror() Print an error message for precision problems. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void precisionerror() +{ + printf("Try increasing the area criterion and/or reducing the minimum\n"); + printf(" allowable angle so that tiny triangles are not created.\n"); +#ifdef SINGLE + printf("Alternatively, try recompiling me with double precision\n"); + printf(" arithmetic (by removing \"#define SINGLE\" from the\n"); + printf(" source file or \"-DSINGLE\" from the makefile).\n"); +#endif /* SINGLE */ +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* repairencs() Find and repair all the encroached segments. */ +/* */ +/* Encroached segments are repaired by splitting them by inserting a point */ +/* at or near their centers. */ +/* */ +/* `flaws' is a flag that specifies whether one should take note of new */ +/* encroached segments and bad triangles that result from inserting points */ +/* to repair existing encroached segments. */ +/* */ +/* When a segment is split, the two resulting subsegments are always */ +/* tested to see if they are encroached upon, regardless of the value */ +/* of `flaws'. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void repairencs(flaws) +int flaws; +{ + struct triedge enctri; + struct triedge testtri; + struct edge *encloop; + struct edge testsh; + point eorg, edest; + point newpoint; + enum insertsiteresult success; + REAL segmentlength, nearestpoweroftwo; + REAL split; + int acuteorg, acutedest; + int dummy; + int i; + triangle ptr; /* Temporary variable used by stpivot(). */ + shelle sptr; /* Temporary variable used by snext(). */ + + while ((badsegments.items > 0) && (steinerleft != 0)) { + traversalinit(&badsegments); + encloop = badsegmenttraverse(); + while ((encloop != (struct edge *) NULL) && (steinerleft != 0)) { + /* To decide where to split a segment, we need to know if the */ + /* segment shares an endpoint with an adjacent segment. */ + /* The concern is that, if we simply split every encroached */ + /* segment in its center, two adjacent segments with a small */ + /* angle between them might lead to an infinite loop; each */ + /* point added to split one segment will encroach upon the */ + /* other segment, which must then be split with a point that */ + /* will encroach upon the first segment, and so on forever. */ + /* To avoid this, imagine a set of concentric circles, whose */ + /* radii are powers of two, about each segment endpoint. */ + /* These concentric circles determine where the segment is */ + /* split. (If both endpoints are shared with adjacent */ + /* segments, split the segment in the middle, and apply the */ + /* concentric shells for later splittings.) */ + + /* Is the origin shared with another segment? */ + stpivot(*encloop, enctri); + lnext(enctri, testtri); + tspivot(testtri, testsh); + acuteorg = testsh.sh != dummysh; + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest = testsh.sh != dummysh; + /* Now, check the other side of the segment, if there's a triangle */ + /* there. */ + sym(enctri, testtri); + if (testtri.tri != dummytri) { + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest = acutedest || (testsh.sh != dummysh); + /* Is the origin shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acuteorg = acuteorg || (testsh.sh != dummysh); + } + + sorg(*encloop, eorg); + sdest(*encloop, edest); + /* Use the concentric circles if exactly one endpoint is shared */ + /* with another adjacent segment. */ + if (acuteorg ^ acutedest) { + segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0]) + + (edest[1] - eorg[1]) * (edest[1] - eorg[1])); + /* Find the power of two nearest the segment's length. */ + nearestpoweroftwo = 1.0; + while (segmentlength > SQUAREROOTTWO * nearestpoweroftwo) { + nearestpoweroftwo *= 2.0; + } + while (segmentlength < (0.5 * SQUAREROOTTWO) * nearestpoweroftwo) { + nearestpoweroftwo *= 0.5; + } + /* Where do we split the segment? */ + split = 0.5 * nearestpoweroftwo / segmentlength; + if (acutedest) { + split = 1.0 - split; + } + } else { + /* If we're not worried about adjacent segments, split */ + /* this segment in the middle. */ + split = 0.5; + } + + /* Create the new point. */ + newpoint = (point) poolalloc(&points); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = (1.0 - split) * eorg[i] + split * edest[i]; + } + setpointmark(newpoint, mark(*encloop)); + if (verbose > 1) { + printf( + " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1], newpoint[0], newpoint[1]); + } + /* Check whether the new point lies on an endpoint. */ + if (((newpoint[0] == eorg[0]) && (newpoint[1] == eorg[1])) + || ((newpoint[0] == edest[0]) && (newpoint[1] == edest[1]))) { + printf("Error: Ran out of precision at (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + printf("I attempted to split a segment to a smaller size than can\n"); + printf(" be accommodated by the finite precision of floating point\n" + ); + printf(" arithmetic.\n"); + precisionerror(); + exit(1); + } + /* Insert the splitting point. This should always succeed. */ + success = insertsite(newpoint, &enctri, encloop, flaws, flaws); + if ((success != SUCCESSFULPOINT) && (success != ENCROACHINGPOINT)) { + printf("Internal error in repairencs():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (steinerleft > 0) { + steinerleft--; + } + /* Check the two new subsegments to see if they're encroached. */ + dummy = checkedge4encroach(encloop); + snextself(*encloop); + dummy = checkedge4encroach(encloop); + + badsegmentdealloc(encloop); + encloop = badsegmenttraverse(); + } + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* tallyfaces() Test every triangle in the mesh for quality measures. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void tallyfaces() +{ + struct triedge triangleloop; + + if (verbose) { + printf(" Making a list of bad triangles.\n"); + } + traversalinit(&triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* If the triangle is bad, enqueue it. */ + testtriangle(&triangleloop); + triangleloop.tri = triangletraverse(); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* findcircumcenter() Find the circumcenter of a triangle. */ +/* */ +/* The result is returned both in terms of x-y coordinates and xi-eta */ +/* coordinates. The xi-eta coordinate system is defined in terms of the */ +/* triangle: the origin of the triangle is the origin of the coordinate */ +/* system; the destination of the triangle is one unit along the xi axis; */ +/* and the apex of the triangle is one unit along the eta axis. */ +/* */ +/* The return value indicates which edge of the triangle is shortest. */ +/* */ +/*****************************************************************************/ + +enum circumcenterresult findcircumcenter(torg, tdest, tapex, circumcenter, + xi, eta) +point torg; +point tdest; +point tapex; +point circumcenter; +REAL *xi; +REAL *eta; +{ + REAL xdo, ydo, xao, yao, xad, yad; + REAL dodist, aodist, addist; + REAL denominator; + REAL dx, dy; + + circumcentercount++; + + /* Compute the circumcenter of the triangle. */ + xdo = tdest[0] - torg[0]; + ydo = tdest[1] - torg[1]; + xao = tapex[0] - torg[0]; + yao = tapex[1] - torg[1]; + dodist = xdo * xdo + ydo * ydo; + aodist = xao * xao + yao * yao; + if (noexact) { + denominator = (REAL)(0.5 / (xdo * yao - xao * ydo)); + } else { + /* Use the counterclockwise() routine to ensure a positive (and */ + /* reasonably accurate) result, avoiding any possibility of */ + /* division by zero. */ + denominator = (REAL)(0.5 / counterclockwise(tdest, tapex, torg)); + /* Don't count the above as an orientation test. */ + counterclockcount--; + } + circumcenter[0] = torg[0] - (ydo * aodist - yao * dodist) * denominator; + circumcenter[1] = torg[1] + (xdo * aodist - xao * dodist) * denominator; + + /* To interpolate point attributes for the new point inserted at */ + /* the circumcenter, define a coordinate system with a xi-axis, */ + /* directed from the triangle's origin to its destination, and */ + /* an eta-axis, directed from its origin to its apex. */ + /* Calculate the xi and eta coordinates of the circumcenter. */ + dx = circumcenter[0] - torg[0]; + dy = circumcenter[1] - torg[1]; + *xi = (REAL)((dx * yao - xao * dy) * (2.0 * denominator)); + *eta = (REAL)((xdo * dy - dx * ydo) * (2.0 * denominator)); + + xad = tapex[0] - tdest[0]; + yad = tapex[1] - tdest[1]; + addist = xad * xad + yad * yad; + if ((addist < dodist) && (addist < aodist)) { + return OPPOSITEORG; + } else if (dodist < aodist) { + return OPPOSITEAPEX; + } else { + return OPPOSITEDEST; + } +} + +/*****************************************************************************/ +/* */ +/* splittriangle() Inserts a point at the circumcenter of a triangle. */ +/* Deletes the newly inserted point if it encroaches upon */ +/* a segment. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void splittriangle(badtri) +struct badface *badtri; +{ + point borg, bdest, bapex; + point newpoint; + REAL xi, eta; + enum insertsiteresult success; + enum circumcenterresult shortedge; + int errorflag; + int i; + + org(badtri->badfacetri, borg); + dest(badtri->badfacetri, bdest); + apex(badtri->badfacetri, bapex); + /* Make sure that this triangle is still the same triangle it was */ + /* when it was tested and determined to be of bad quality. */ + /* Subsequent transformations may have made it a different triangle. */ + if ((borg == badtri->faceorg) && (bdest == badtri->facedest) && + (bapex == badtri->faceapex)) { + if (verbose > 1) { + printf(" Splitting this triangle at its circumcenter:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", borg[0], + borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + errorflag = 0; + /* Create a new point at the triangle's circumcenter. */ + newpoint = (point) poolalloc(&points); + shortedge = findcircumcenter(borg, bdest, bapex, newpoint, &xi, &eta); + /* Check whether the new point lies on a triangle vertex. */ + if (((newpoint[0] == borg[0]) && (newpoint[1] == borg[1])) + || ((newpoint[0] == bdest[0]) && (newpoint[1] == bdest[1])) + || ((newpoint[0] == bapex[0]) && (newpoint[1] == bapex[1]))) { + if (!quiet) { + printf("Warning: New point (%.12g, %.12g) falls on existing vertex.\n" + , newpoint[0], newpoint[1]); + errorflag = 1; + } + pointdealloc(newpoint); + } else { + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + newpoint[i] = borg[i] + xi * (bdest[i] - borg[i]) + + eta * (bapex[i] - borg[i]); + } + /* The new point must be in the interior, and have a marker of zero. */ + setpointmark(newpoint, 0); + /* Ensure that the handle `badtri->badfacetri' represents the shortest */ + /* edge of the triangle. This ensures that the circumcenter must */ + /* fall to the left of this edge, so point location will work. */ + if (shortedge == OPPOSITEORG) { + lnextself(badtri->badfacetri); + } else if (shortedge == OPPOSITEDEST) { + lprevself(badtri->badfacetri); + } + /* Insert the circumcenter, searching from the edge of the triangle, */ + /* and maintain the Delaunay property of the triangulation. */ + success = insertsite(newpoint, &(badtri->badfacetri), + (struct edge *) NULL, 1, 1); + if (success == SUCCESSFULPOINT) { + if (steinerleft > 0) { + steinerleft--; + } + } else if (success == ENCROACHINGPOINT) { + /* If the newly inserted point encroaches upon a segment, delete it. */ + deletesite(&(badtri->badfacetri)); + } else if (success == VIOLATINGPOINT) { + /* Failed to insert the new point, but some segment was */ + /* marked as being encroached. */ + pointdealloc(newpoint); + } else { /* success == DUPLICATEPOINT */ + /* Failed to insert the new point because a vertex is already there. */ + if (!quiet) { + printf( + "Warning: New point (%.12g, %.12g) falls on existing vertex.\n" + , newpoint[0], newpoint[1]); + errorflag = 1; + } + pointdealloc(newpoint); + } + } + if (errorflag) { + if (verbose) { + printf(" The new point is at the circumcenter of triangle\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + borg[0], borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + printf("This probably means that I am trying to refine triangles\n"); + printf(" to a smaller size than can be accommodated by the finite\n"); + printf(" precision of floating point arithmetic. (You can be\n"); + printf(" sure of this if I fail to terminate.)\n"); + precisionerror(); + } + } + /* Return the bad triangle to the pool. */ + pooldealloc(&badtriangles, (VOID *) badtri); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* enforcequality() Remove all the encroached edges and bad triangles */ +/* from the triangulation. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void enforcequality() +{ + int i; + + if (!quiet) { + printf("Adding Steiner points to enforce quality.\n"); + } + /* Initialize the pool of encroached segments. */ + poolinit(&badsegments, sizeof(struct edge), BADSEGMENTPERBLOCK, POINTER, 0); + if (verbose) { + printf(" Looking for encroached segments.\n"); + } + /* Test all segments to see if they're encroached. */ + tallyencs(); + if (verbose && (badsegments.items > 0)) { + printf(" Splitting encroached segments.\n"); + } + /* Note that steinerleft == -1 if an unlimited number */ + /* of Steiner points is allowed. */ + while ((badsegments.items > 0) && (steinerleft != 0)) { + /* Fix the segments without noting newly encroached segments or */ + /* bad triangles. The reason we don't want to note newly */ + /* encroached segments is because some encroached segments are */ + /* likely to be noted multiple times, and would then be blindly */ + /* split multiple times. I should fix that some time. */ + repairencs(0); + /* Now, find all the segments that became encroached while adding */ + /* points to split encroached segments. */ + tallyencs(); + } + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay. */ + + /* Next, we worry about enforcing triangle quality. */ + if ((minangle > 0.0) || vararea || fixedarea) { + /* Initialize the pool of bad triangles. */ + poolinit(&badtriangles, sizeof(struct badface), BADTRIPERBLOCK, POINTER, + 0); + /* Initialize the queues of bad triangles. */ + for (i = 0; i < 64; i++) { + queuefront[i] = (struct badface *) NULL; + queuetail[i] = &queuefront[i]; + } + /* Test all triangles to see if they're bad. */ + tallyfaces(); + if (verbose) { + printf(" Splitting bad triangles.\n"); + } + while ((badtriangles.items > 0) && (steinerleft != 0)) { + /* Fix one bad triangle by inserting a point at its circumcenter. */ + splittriangle(dequeuebadtri()); + /* Fix any encroached segments that may have resulted. Record */ + /* any new bad triangles or encroached segments that result. */ + if (badsegments.items > 0) { + repairencs(1); + } + } + } + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay and have no */ + /* low-quality triangles. */ + + /* Might we have run out of Steiner points too soon? */ + if (!quiet && (badsegments.items > 0) && (steinerleft == 0)) { + printf("\nWarning: I ran out of Steiner points, but the mesh has\n"); + if (badsegments.items == 1) { + printf(" an encroached segment, and therefore might not be truly\n"); + } else { + printf(" %ld encroached segments, and therefore might not be truly\n", + badsegments.items); + } + printf(" Delaunay. If the Delaunay property is important to you,\n"); + printf(" try increasing the number of Steiner points (controlled by\n"); + printf(" the -S switch) slightly and try again.\n\n"); + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality maintenance ends here *********/ + +/*****************************************************************************/ +/* */ +/* highorder() Create extra nodes for quadratic subparametric elements. */ +/* */ +/*****************************************************************************/ + +void highorder() +{ + struct triedge triangleloop, trisym; + struct edge checkmark; + point newpoint; + point torg, tdest; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (!quiet) { + printf("Adding vertices for second-order triangles.\n"); + } + /* The following line ensures that dead items in the pool of nodes */ + /* cannot be allocated for the extra nodes associated with high */ + /* order elements. This ensures that the primary nodes (at the */ + /* corners of elements) will occur earlier in the output files, and */ + /* have lower indices, than the extra nodes. */ + points.deaditemstack = (VOID *) NULL; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + org(triangleloop, torg); + dest(triangleloop, tdest); + /* Create a new node in the middle of the edge. Interpolate */ + /* its attributes. */ + newpoint = (point) poolalloc(&points); + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = (REAL)(0.5 * (torg[i] + tdest[i])); + } + /* Set the new node's marker to zero or one, depending on */ + /* whether it lies on a boundary. */ + setpointmark(newpoint, trisym.tri == dummytri); + if (useshelles) { + tspivot(triangleloop, checkmark); + /* If this edge is a segment, transfer the marker to the new node. */ + if (checkmark.sh != dummysh) { + setpointmark(newpoint, mark(checkmark)); + } + } + if (verbose > 1) { + printf(" Creating (%.12g, %.12g).\n", newpoint[0], newpoint[1]); + } + /* Record the new node in the (one or two) adjacent elements. */ + triangleloop.tri[highorderindex + triangleloop.orient] = + (triangle) newpoint; + if (trisym.tri != dummytri) { + trisym.tri[highorderindex + trisym.orient] = (triangle) newpoint; + } + } + } + triangleloop.tri = triangletraverse(); + } +} + +/********* File I/O routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* readline() Read a nonempty line from a file. */ +/* */ +/* A line is considered "nonempty" if it contains something that looks like */ +/* a number. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +char *readline(string, infile, infilename) +char *string; +FILE *infile; +char *infilename; +{ + char *result; + + /* Search for something that looks like a number. */ + do { + result = fgets(string, INPUTLINESIZE, infile); + if (result == (char *) NULL) { + printf(" Error: Unexpected end of file in %s.\n", infilename); + exit(1); + } + /* Skip anything that doesn't look like a number, a comment, */ + /* or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* If it's a comment or end of line, read another line and try again. */ + } while ((*result == '#') || (*result == '\0')); + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* findfield() Find the next field of a string. */ +/* */ +/* Jumps past the current field by searching for whitespace, then jumps */ +/* past the whitespace to find the next field. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +char *findfield(string) +char *string; +{ + char *result; + + result = string; + /* Skip the current field. Stop upon reaching whitespace. */ + while ((*result != '\0') && (*result != '#') + && (*result != ' ') && (*result != '\t')) { + result++; + } + /* Now skip the whitespace and anything else that doesn't look like a */ + /* number, a comment, or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* Check for a comment (prefixed with `#'). */ + if (*result == '#') { + *result = '\0'; + } + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readnodes() Read the points from a file, which may be a .node or .poly */ +/* file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void readnodes(nodefilename, polyfilename, polyfile) +char *nodefilename; +char *polyfilename; +FILE **polyfile; +{ + FILE *infile; + point pointloop; + char inputline[INPUTLINESIZE]; + char *stringptr; + char *infilename; + REAL x, y; + int firstnode; + int nodemarkers; + int currentmarker; + int i, j; + + if (poly) { + /* Read the points from a .poly file. */ + if (!quiet) { + printf("Opening %s.\n", polyfilename); + } + *polyfile = fopen(polyfilename, "r"); + if (*polyfile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", polyfilename); + exit(1); + } + /* Read number of points, number of dimensions, number of point */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, *polyfile, polyfilename); + inpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + mesh_dim = 2; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nextras = 0; + } else { + nextras = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol (stringptr, &stringptr, 0); + } + if (inpoints > 0) { + infile = *polyfile; + infilename = polyfilename; + readnodefile = 0; + } else { + /* If the .poly file claims there are zero points, that means that */ + /* the points should be read from a separate .node file. */ + readnodefile = 1; + infilename = innodefilename; + } + } else { + readnodefile = 1; + infilename = innodefilename; + *polyfile = (FILE *) NULL; + } + + if (readnodefile) { + /* Read the points from a .node file. */ + if (!quiet) { + printf("Opening %s.\n", innodefilename); + } + infile = fopen(innodefilename, "r"); + if (infile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", innodefilename); + exit(1); + } + /* Read number of points, number of dimensions, number of point */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, infile, innodefilename); + inpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + mesh_dim = 2; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nextras = 0; + } else { + nextras = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol (stringptr, &stringptr, 0); + } + } + + if (inpoints < 3) { + printf("Error: Input must have at least three input points.\n"); + exit(1); + } + if (mesh_dim != 2) { + printf("Error: Triangle only works with two-dimensional meshes.\n"); + exit(1); + } + + initializepointpool(); + + /* Read the points. */ + for (i = 0; i < inpoints; i++) { + pointloop = (point) poolalloc(&points); + stringptr = readline(inputline, infile, infilename); + if (i == 0) { + firstnode = (int) strtol (stringptr, &stringptr, 0); + if ((firstnode == 0) || (firstnode == 1)) { + firstnumber = firstnode; + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no x coordinate.\n", firstnumber + i); + exit(1); + } + x = (REAL) strtod(stringptr, &stringptr); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no y coordinate.\n", firstnumber + i); + exit(1); + } + y = (REAL) strtod(stringptr, &stringptr); + pointloop[0] = x; + pointloop[1] = y; + /* Read the point attributes. */ + for (j = 2; j < 2 + nextras; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + pointloop[j] = 0.0; + } else { + pointloop[j] = (REAL) strtod(stringptr, &stringptr); + } + } + if (nodemarkers) { + /* Read a point marker. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setpointmark(pointloop, 0); + } else { + currentmarker = (int) strtol (stringptr, &stringptr, 0); + setpointmark(pointloop, currentmarker); + } + } else { + /* If no markers are specified in the file, they default to zero. */ + setpointmark(pointloop, 0); + } + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + xmin = xmax = x; + ymin = ymax = y; + } else { + xmin = (x < xmin) ? x : xmin; + xmax = (x > xmax) ? x : xmax; + ymin = (y < ymin) ? y : ymin; + ymax = (y > ymax) ? y : ymax; + } + } + if (readnodefile) { + fclose(infile); + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + xminextreme = 10 * xmin - 9 * xmax; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* transfernodes() Read the points from memory. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void transfernodes(pointlist, pointattriblist, pointmarkerlist, numberofpoints, + numberofpointattribs) +REAL *pointlist; +REAL *pointattriblist; +int *pointmarkerlist; +int numberofpoints; +int numberofpointattribs; +{ + point pointloop; + REAL x, y; + int i, j; + int coordindex; + int attribindex; + + inpoints = numberofpoints; + mesh_dim = 2; + nextras = numberofpointattribs; + readnodefile = 0; + if (inpoints < 3) { + printf("Error: Input must have at least three input points.\n"); + exit(1); + } + + initializepointpool(); + + /* Read the points. */ + coordindex = 0; + attribindex = 0; + for (i = 0; i < inpoints; i++) { + pointloop = (point) poolalloc(&points); + /* Read the point coordinates. */ + x = pointloop[0] = pointlist[coordindex++]; + y = pointloop[1] = pointlist[coordindex++]; + /* Read the point attributes. */ + for (j = 0; j < numberofpointattribs; j++) { + pointloop[2 + j] = pointattriblist[attribindex++]; + } + if (pointmarkerlist != (int *) NULL) { + /* Read a point marker. */ + setpointmark(pointloop, pointmarkerlist[i]); + } else { + /* If no markers are specified, they default to zero. */ + setpointmark(pointloop, 0); + } + x = pointloop[0]; + y = pointloop[1]; + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + xmin = xmax = x; + ymin = ymax = y; + } else { + xmin = (x < xmin) ? x : xmin; + xmax = (x > xmax) ? x : xmax; + ymin = (y < ymin) ? y : ymin; + ymax = (y > ymax) ? y : ymax; + } + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + xminextreme = 10 * xmin - 9 * xmax; +} + +#endif /* TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readholes() Read the holes, and possibly regional attributes and area */ +/* constraints, from a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void readholes(polyfile, polyfilename, hlist, holes, rlist, regions) +FILE *polyfile; +char *polyfilename; +REAL **hlist; +int *holes; +REAL **rlist; +int *regions; +{ + REAL *holelist; + REAL *regionlist; + char inputline[INPUTLINESIZE]; + char *stringptr; + int index; + int i; + + /* Read the holes. */ + stringptr = readline(inputline, polyfile, polyfilename); + *holes = (int) strtol (stringptr, &stringptr, 0); + if (*holes > 0) { + holelist = (REAL *) malloc(2 * *holes * sizeof(REAL)); + *hlist = holelist; + if (holelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + for (i = 0; i < 2 * *holes; i += 2) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no x coordinate.\n", + firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no y coordinate.\n", + firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); + } + } + } else { + *hlist = (REAL *) NULL; + } + +#ifndef CDT_ONLY + if ((regionattrib || vararea) && !refine) { + /* Read the area constraints. */ + stringptr = readline(inputline, polyfile, polyfilename); + *regions = (int) strtol (stringptr, &stringptr, 0); + if (*regions > 0) { + regionlist = (REAL *) malloc(4 * *regions * sizeof(REAL)); + *rlist = regionlist; + if (regionlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + index = 0; + for (i = 0; i < *regions; i++) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no x coordinate.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no y coordinate.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf( + "Error: Region %d has no region attribute or area constraint.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + regionlist[index] = regionlist[index - 1]; + } else { + regionlist[index] = (REAL) strtod(stringptr, &stringptr); + } + index++; + } + } + } else { + /* Set `*regions' to zero to avoid an accidental free() later. */ + *regions = 0; + *rlist = (REAL *) NULL; + } +#endif /* not CDT_ONLY */ + + fclose(polyfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* finishfile() Write the command line to the output file so the user */ +/* can remember how the file was generated. Close the file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void finishfile(outfile, argc, argv) +FILE *outfile; +int argc; +char **argv; +{ + int i; + + fprintf(outfile, "# Generated by"); + for (i = 0; i < argc; i++) { + fprintf(outfile, " "); + fputs(argv[i], outfile); + } + fprintf(outfile, "\n"); + fclose(outfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* writenodes() Number the points and write them to a .node file. */ +/* */ +/* To save memory, the point numbers are written over the shell markers */ +/* after the points are written to a file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writenodes(pointlist, pointattriblist, pointmarkerlist) +REAL **pointlist; +REAL **pointattriblist; +int **pointmarkerlist; + +#else /* not TRILIBRARY */ + +void writenodes(nodefilename, argc, argv) +char *nodefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *pmlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + point pointloop; + int pointnumber; + int i; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing points.\n"); + } + /* Allocate memory for output points if necessary. */ + if (*pointlist == (REAL *) NULL) { + *pointlist = (REAL *) malloc(points.items * 2 * sizeof(REAL)); + if (*pointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output point attributes if necessary. */ + if ((nextras > 0) && (*pointattriblist == (REAL *) NULL)) { + *pointattriblist = (REAL *) malloc(points.items * nextras * sizeof(REAL)); + if (*pointattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output point markers if necessary. */ + if (!nobound && (*pointmarkerlist == (int *) NULL)) { + *pointmarkerlist = (int *) malloc(points.items * sizeof(int)); + if (*pointmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + plist = *pointlist; + palist = *pointattriblist; + pmlist = *pointmarkerlist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", nodefilename); + } + outfile = fopen(nodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", nodefilename); + exit(1); + } + /* Number of points, number of dimensions, number of point attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d %d %d\n", points.items, mesh_dim, nextras, + 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&points); + pointloop = pointtraverse(); + pointnumber = firstnumber; + while (pointloop != (point) NULL) { +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = pointloop[0]; + plist[coordindex++] = pointloop[1]; + /* Point attributes. */ + for (i = 0; i < nextras; i++) { + palist[attribindex++] = pointloop[2 + i]; + } + if (!nobound) { + /* Copy the boundary marker. */ + pmlist[pointnumber - firstnumber] = pointmark(pointloop); + } +#else /* not TRILIBRARY */ + /* Point number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g", pointnumber, pointloop[0], + pointloop[1]); + for (i = 0; i < nextras; i++) { + /* Write an attribute. */ + fprintf(outfile, " %.17g", pointloop[i + 2]); + } + if (nobound) { + fprintf(outfile, "\n"); + } else { + /* Write the boundary marker. */ + fprintf(outfile, " %d\n", pointmark(pointloop)); + } +#endif /* not TRILIBRARY */ + + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* numbernodes() Number the points. */ +/* */ +/* Each point is assigned a marker equal to its number. */ +/* */ +/* Used when writenodes() is not called because no .node file is written. */ +/* */ +/*****************************************************************************/ + +void numbernodes() +{ + point pointloop; + int pointnumber; + + traversalinit(&points); + pointloop = pointtraverse(); + pointnumber = firstnumber; + while (pointloop != (point) NULL) { + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } +} + +/*****************************************************************************/ +/* */ +/* writeelements() Write the triangles to an .ele file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writeelements(trianglelist, triangleattriblist) +int **trianglelist; +REAL **triangleattriblist; + +#else /* not TRILIBRARY */ + +void writeelements(elefilename, argc, argv) +char *elefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *tlist; + REAL *talist; + int pointindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop; + point p1, p2, p3; + point mid1, mid2, mid3; + int elementnumber; + int i; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing triangles.\n"); + } + /* Allocate memory for output triangles if necessary. */ + if (*trianglelist == (int *) NULL) { + *trianglelist = (int *) malloc(triangles.items * + ((order + 1) * (order + 2) / 2) * sizeof(int)); + if (*trianglelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output triangle attributes if necessary. */ + if ((eextras > 0) && (*triangleattriblist == (REAL *) NULL)) { + *triangleattriblist = (REAL *) malloc(triangles.items * eextras * + sizeof(REAL)); + if (*triangleattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + tlist = *trianglelist; + talist = *triangleattriblist; + pointindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", elefilename); + } + outfile = fopen(elefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", elefilename); + exit(1); + } + /* Number of triangles, points per triangle, attributes per triangle. */ + fprintf(outfile, "%ld %d %d\n", triangles.items, + (order + 1) * (order + 2) / 2, eextras); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + if (order == 1) { +#ifdef TRILIBRARY + tlist[pointindex++] = pointmark(p1); + tlist[pointindex++] = pointmark(p2); + tlist[pointindex++] = pointmark(p3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for three points. */ + fprintf(outfile, "%4d %4d %4d %4d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3)); +#endif /* not TRILIBRARY */ + } else { + mid1 = (point) triangleloop.tri[highorderindex + 1]; + mid2 = (point) triangleloop.tri[highorderindex + 2]; + mid3 = (point) triangleloop.tri[highorderindex]; +#ifdef TRILIBRARY + tlist[pointindex++] = pointmark(p1); + tlist[pointindex++] = pointmark(p2); + tlist[pointindex++] = pointmark(p3); + tlist[pointindex++] = pointmark(mid1); + tlist[pointindex++] = pointmark(mid2); + tlist[pointindex++] = pointmark(mid3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for six points. */ + fprintf(outfile, "%4d %4d %4d %4d %4d %4d %4d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3), pointmark(mid1), + pointmark(mid2), pointmark(mid3)); +#endif /* not TRILIBRARY */ + } + +#ifdef TRILIBRARY + for (i = 0; i < eextras; i++) { + talist[attribindex++] = elemattribute(triangleloop, i); + } +#else /* not TRILIBRARY */ + for (i = 0; i < eextras; i++) { + fprintf(outfile, " %.17g", elemattribute(triangleloop, i)); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writepoly() Write the segments and holes to a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writepoly(segmentlist, segmentmarkerlist) +int **segmentlist; +int **segmentmarkerlist; + +#else /* not TRILIBRARY */ + +void writepoly(polyfilename, holelist, holes, regionlist, regions, argc, argv) +char *polyfilename; +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *slist; + int *smlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; + int i; +#endif /* not TRILIBRARY */ + struct edge shelleloop; + point endpoint1, endpoint2; + int shellenumber; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing segments.\n"); + } + /* Allocate memory for output segments if necessary. */ + if (*segmentlist == (int *) NULL) { + *segmentlist = (int *) malloc(shelles.items * 2 * sizeof(int)); + if (*segmentlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output segment markers if necessary. */ + if (!nobound && (*segmentmarkerlist == (int *) NULL)) { + *segmentmarkerlist = (int *) malloc(shelles.items * sizeof(int)); + if (*segmentmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + slist = *segmentlist; + smlist = *segmentmarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", polyfilename); + } + outfile = fopen(polyfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", polyfilename); + exit(1); + } + /* The zero indicates that the points are in a separate .node file. */ + /* Followed by number of dimensions, number of point attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%d %d %d %d\n", 0, mesh_dim, nextras, 1 - nobound); + /* Number of segments, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", shelles.items, 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&shelles); + shelleloop.sh = shelletraverse(); + shelleloop.shorient = 0; + shellenumber = firstnumber; + while (shelleloop.sh != (shelle *) NULL) { + sorg(shelleloop, endpoint1); + sdest(shelleloop, endpoint2); +#ifdef TRILIBRARY + /* Copy indices of the segment's two endpoints. */ + slist[index++] = pointmark(endpoint1); + slist[index++] = pointmark(endpoint2); + if (!nobound) { + /* Copy the boundary marker. */ + smlist[shellenumber - firstnumber] = mark(shelleloop); + } +#else /* not TRILIBRARY */ + /* Segment number, indices of its two endpoints, and possibly a marker. */ + if (nobound) { + fprintf(outfile, "%4d %4d %4d\n", shellenumber, + pointmark(endpoint1), pointmark(endpoint2)); + } else { + fprintf(outfile, "%4d %4d %4d %4d\n", shellenumber, + pointmark(endpoint1), pointmark(endpoint2), mark(shelleloop)); + } +#endif /* not TRILIBRARY */ + + shelleloop.sh = shelletraverse(); + shellenumber++; + } + +#ifndef TRILIBRARY +#ifndef CDT_ONLY + fprintf(outfile, "%d\n", holes); + if (holes > 0) { + for (i = 0; i < holes; i++) { + /* Hole number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g\n", firstnumber + i, + holelist[2 * i], holelist[2 * i + 1]); + } + } + if (regions > 0) { + fprintf(outfile, "%d\n", regions); + for (i = 0; i < regions; i++) { + /* Region number, x and y coordinates, attribute, maximum area. */ + fprintf(outfile, "%4d %.17g %.17g %.17g %.17g\n", firstnumber + i, + regionlist[4 * i], regionlist[4 * i + 1], + regionlist[4 * i + 2], regionlist[4 * i + 3]); + } + } +#endif /* not CDT_ONLY */ + + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeedges() Write the edges to a .edge file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writeedges(edgelist, edgemarkerlist) +int **edgelist; +int **edgemarkerlist; + +#else /* not TRILIBRARY */ + +void writeedges(edgefilename, argc, argv) +char *edgefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *elist; + int *emlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + struct edge checkmark; + point p1, p2; + int edgenumber; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing edges.\n"); + } + /* Allocate memory for edges if necessary. */ + if (*edgelist == (int *) NULL) { + *edgelist = (int *) malloc(edges * 2 * sizeof(int)); + if (*edgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for edge markers if necessary. */ + if (!nobound && (*edgemarkerlist == (int *) NULL)) { + *edgemarkerlist = (int *) malloc(edges * sizeof(int)); + if (*edgemarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + elist = *edgelist; + emlist = *edgemarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", edgefilename); + } + outfile = fopen(edgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", edgefilename); + exit(1); + } + /* Number of edges, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", edges, 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + edgenumber = firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + org(triangleloop, p1); + dest(triangleloop, p2); +#ifdef TRILIBRARY + elist[index++] = pointmark(p1); + elist[index++] = pointmark(p2); +#endif /* TRILIBRARY */ + if (nobound) { +#ifndef TRILIBRARY + /* Edge number, indices of two endpoints. */ + fprintf(outfile, "%4d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2)); +#endif /* not TRILIBRARY */ + } else { + /* Edge number, indices of two endpoints, and a boundary marker. */ + /* If there's no shell edge, the boundary marker is zero. */ + if (useshelles) { + tspivot(triangleloop, checkmark); + if (checkmark.sh == dummysh) { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = 0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), 0); +#endif /* not TRILIBRARY */ + } else { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = mark(checkmark); +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), mark(checkmark)); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = trisym.tri == dummytri; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), trisym.tri == dummytri); +#endif /* not TRILIBRARY */ + } + } + edgenumber++; + } + } + triangleloop.tri = triangletraverse(); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writevoronoi() Write the Voronoi diagram to a .v.node and .v.edge */ +/* file. */ +/* */ +/* The Voronoi diagram is the geometric dual of the Delaunay triangulation. */ +/* Hence, the Voronoi vertices are listed by traversing the Delaunay */ +/* triangles, and the Voronoi edges are listed by traversing the Delaunay */ +/* edges. */ +/* */ +/* WARNING: In order to assign numbers to the Voronoi vertices, this */ +/* procedure messes up the shell edges or the extra nodes of every */ +/* element. Hence, you should call this procedure last. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writevoronoi(vpointlist, vpointattriblist, vpointmarkerlist, vedgelist, + vedgemarkerlist, vnormlist) +REAL **vpointlist; +REAL **vpointattriblist; +int **vpointmarkerlist; +int **vedgelist; +int **vedgemarkerlist; +REAL **vnormlist; + +#else /* not TRILIBRARY */ + +void writevoronoi(vnodefilename, vedgefilename, argc, argv) +char *vnodefilename; +char *vedgefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *elist; + REAL *normlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + point torg, tdest, tapex; + REAL circumcenter[2]; + REAL xi, eta; + int vnodenumber, vedgenumber; + int p1, p2; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing Voronoi vertices.\n"); + } + /* Allocate memory for Voronoi vertices if necessary. */ + if (*vpointlist == (REAL *) NULL) { + *vpointlist = (REAL *) malloc(triangles.items * 2 * sizeof(REAL)); + if (*vpointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for Voronoi vertex attributes if necessary. */ + if (*vpointattriblist == (REAL *) NULL) { + *vpointattriblist = (REAL *) malloc(triangles.items * nextras * + sizeof(REAL)); + if (*vpointattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + *vpointmarkerlist = (int *) NULL; + plist = *vpointlist; + palist = *vpointattriblist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", vnodefilename); + } + outfile = fopen(vnodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vnodefilename); + exit(1); + } + /* Number of triangles, two dimensions, number of point attributes, */ + /* zero markers. */ + fprintf(outfile, "%ld %d %d %d\n", triangles.items, 2, nextras, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + vnodenumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, torg); + dest(triangleloop, tdest); + apex(triangleloop, tapex); + findcircumcenter(torg, tdest, tapex, circumcenter, &xi, &eta); +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = circumcenter[0]; + plist[coordindex++] = circumcenter[1]; + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i]); + } +#else /* not TRILIBRARY */ + /* Voronoi vertex number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g", vnodenumber, circumcenter[0], + circumcenter[1]); + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + fprintf(outfile, " %.17g", torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i])); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + * (int *) (triangleloop.tri + 6) = vnodenumber; + triangleloop.tri = triangletraverse(); + vnodenumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing Voronoi edges.\n"); + } + /* Allocate memory for output Voronoi edges if necessary. */ + if (*vedgelist == (int *) NULL) { + *vedgelist = (int *) malloc(edges * 2 * sizeof(int)); + if (*vedgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + *vedgemarkerlist = (int *) NULL; + /* Allocate memory for output Voronoi norms if necessary. */ + if (*vnormlist == (REAL *) NULL) { + *vnormlist = (REAL *) malloc(edges * 2 * sizeof(REAL)); + if (*vnormlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + elist = *vedgelist; + normlist = *vnormlist; + coordindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", vedgefilename); + } + outfile = fopen(vedgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vedgefilename); + exit(1); + } + /* Number of edges, zero boundary markers. */ + fprintf(outfile, "%ld %d\n", edges, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + vedgenumber = firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + /* Find the number of this triangle (and Voronoi vertex). */ + p1 = * (int *) (triangleloop.tri + 6); + if (trisym.tri == dummytri) { + org(triangleloop, torg); + dest(triangleloop, tdest); +#ifdef TRILIBRARY + /* Copy an infinite ray. Index of one endpoint, and -1. */ + elist[coordindex] = p1; + normlist[coordindex++] = tdest[1] - torg[1]; + elist[coordindex] = -1; + normlist[coordindex++] = torg[0] - tdest[0]; +#else /* not TRILIBRARY */ + /* Write an infinite ray. Edge number, index of one endpoint, -1, */ + /* and x and y coordinates of a vector representing the */ + /* direction of the ray. */ + fprintf(outfile, "%4d %d %d %.17g %.17g\n", vedgenumber, + p1, -1, tdest[1] - torg[1], torg[0] - tdest[0]); +#endif /* not TRILIBRARY */ + } else { + /* Find the number of the adjacent triangle (and Voronoi vertex). */ + p2 = * (int *) (trisym.tri + 6); + /* Finite edge. Write indices of two endpoints. */ +#ifdef TRILIBRARY + elist[coordindex] = p1; + normlist[coordindex++] = 0.0; + elist[coordindex] = p2; + normlist[coordindex++] = 0.0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d\n", vedgenumber, p1, p2); +#endif /* not TRILIBRARY */ + } + vedgenumber++; + } + } + triangleloop.tri = triangletraverse(); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +#ifdef TRILIBRARY + +void writeneighbors(neighborlist) +int **neighborlist; + +#else /* not TRILIBRARY */ + +void writeneighbors(neighborfilename, argc, argv) +char *neighborfilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *nlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + int elementnumber; + int neighbor1, neighbor2, neighbor3; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing neighbors.\n"); + } + /* Allocate memory for neighbors if necessary. */ + if (*neighborlist == (int *) NULL) { + *neighborlist = (int *) malloc(triangles.items * 3 * sizeof(int)); + if (*neighborlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + nlist = *neighborlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", neighborfilename); + } + outfile = fopen(neighborfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", neighborfilename); + exit(1); + } + /* Number of triangles, three edges per triangle. */ + fprintf(outfile, "%ld %d\n", triangles.items, 3); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + * (int *) (triangleloop.tri + 6) = elementnumber; + triangleloop.tri = triangletraverse(); + elementnumber++; + } + * (int *) (dummytri + 6) = -1; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + triangleloop.orient = 1; + sym(triangleloop, trisym); + neighbor1 = * (int *) (trisym.tri + 6); + triangleloop.orient = 2; + sym(triangleloop, trisym); + neighbor2 = * (int *) (trisym.tri + 6); + triangleloop.orient = 0; + sym(triangleloop, trisym); + neighbor3 = * (int *) (trisym.tri + 6); +#ifdef TRILIBRARY + nlist[index++] = neighbor1; + nlist[index++] = neighbor2; + nlist[index++] = neighbor3; +#else /* not TRILIBRARY */ + /* Triangle number, neighboring triangle numbers. */ + fprintf(outfile, "%4d %d %d %d\n", elementnumber, + neighbor1, neighbor2, neighbor3); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeoff() Write the triangulation to an .off file. */ +/* */ +/* OFF stands for the Object File Format, a format used by the Geometry */ +/* Center's Geomview package. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void writeoff(offfilename, argc, argv) +char *offfilename; +int argc; +char **argv; +{ + FILE *outfile; + struct triedge triangleloop; + point pointloop; + point p1, p2, p3; + + if (!quiet) { + printf("Writing %s.\n", offfilename); + } + outfile = fopen(offfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", offfilename); + exit(1); + } + /* Number of points, triangles, and edges. */ + fprintf(outfile, "OFF\n%ld %ld %ld\n", points.items, triangles.items, + edges); + + /* Write the points. */ + traversalinit(&points); + pointloop = pointtraverse(); + while (pointloop != (point) NULL) { + /* The "0.0" is here because the OFF format uses 3D coordinates. */ + fprintf(outfile, " %.17g %.17g %.17g\n", pointloop[0], + pointloop[1], 0.0); + pointloop = pointtraverse(); + } + + /* Write the triangles. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + /* The "3" means a three-vertex polygon. */ + fprintf(outfile, " 3 %4d %4d %4d\n", pointmark(p1) - 1, + pointmark(p2) - 1, pointmark(p3) - 1); + triangleloop.tri = triangletraverse(); + } + finishfile(outfile, argc, argv); +} + +#endif /* not TRILIBRARY */ + +/** **/ +/** **/ +/********* File I/O routines end here *********/ + +/*****************************************************************************/ +/* */ +/* quality_statistics() Print statistics about the quality of the mesh. */ +/* */ +/*****************************************************************************/ + +void quality_statistics() +{ + struct triedge triangleloop; + point p[3]; + REAL cossquaretable[8]; + REAL ratiotable[16]; + REAL dx[3], dy[3]; + REAL edgelength[3]; + REAL dotproduct; + REAL cossquare; + REAL triarea; + REAL shortest, longest; + REAL trilongest2; + REAL smallestarea, biggestarea; + REAL triminaltitude2; + REAL minaltitude; + REAL triaspect2; + REAL worstaspect; + REAL smallestangle, biggestangle; + REAL radconst, degconst; + int angletable[18]; + int aspecttable[16]; + int aspectindex; + int tendegree; + int acutebiggest; + int i, ii, j, k; + + printf("Mesh quality statistics:\n\n"); + radconst = (REAL)(PI / 18.0); + degconst = (REAL)(180.0 / PI); + for (i = 0; i < 8; i++) { + cossquaretable[i] = (REAL)(cos(radconst * (REAL) (i + 1))); + cossquaretable[i] = cossquaretable[i] * cossquaretable[i]; + } + for (i = 0; i < 18; i++) { + angletable[i] = 0; + } + + ratiotable[0] = 1.5; ratiotable[1] = 2.0; + ratiotable[2] = 2.5; ratiotable[3] = 3.0; + ratiotable[4] = 4.0; ratiotable[5] = 6.0; + ratiotable[6] = 10.0; ratiotable[7] = 15.0; + ratiotable[8] = 25.0; ratiotable[9] = 50.0; + ratiotable[10] = 100.0; ratiotable[11] = 300.0; + ratiotable[12] = 1000.0; ratiotable[13] = 10000.0; + ratiotable[14] = 100000.0; ratiotable[15] = 0.0; + for (i = 0; i < 16; i++) { + aspecttable[i] = 0; + } + + worstaspect = 0.0; + minaltitude = xmax - xmin + ymax - ymin; + minaltitude = minaltitude * minaltitude; + shortest = minaltitude; + longest = 0.0; + smallestarea = minaltitude; + biggestarea = 0.0; + worstaspect = 0.0; + smallestangle = 0.0; + biggestangle = 2.0; + acutebiggest = 1; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p[0]); + dest(triangleloop, p[1]); + apex(triangleloop, p[2]); + trilongest2 = 0.0; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dx[i] = p[j][0] - p[k][0]; + dy[i] = p[j][1] - p[k][1]; + edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; + if (edgelength[i] > trilongest2) { + trilongest2 = edgelength[i]; + } + if (edgelength[i] > longest) { + longest = edgelength[i]; + } + if (edgelength[i] < shortest) { + shortest = edgelength[i]; + } + } + + triarea = counterclockwise(p[0], p[1], p[2]); + if (triarea < smallestarea) { + smallestarea = triarea; + } + if (triarea > biggestarea) { + biggestarea = triarea; + } + triminaltitude2 = triarea * triarea / trilongest2; + if (triminaltitude2 < minaltitude) { + minaltitude = triminaltitude2; + } + triaspect2 = trilongest2 / triminaltitude2; + if (triaspect2 > worstaspect) { + worstaspect = triaspect2; + } + aspectindex = 0; + while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) + && (aspectindex < 15)) { + aspectindex++; + } + aspecttable[aspectindex]++; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dotproduct = dx[j] * dx[k] + dy[j] * dy[k]; + cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]); + tendegree = 8; + for (ii = 7; ii >= 0; ii--) { + if (cossquare > cossquaretable[ii]) { + tendegree = ii; + } + } + if (dotproduct <= 0.0) { + angletable[tendegree]++; + if (cossquare > smallestangle) { + smallestangle = cossquare; + } + if (acutebiggest && (cossquare < biggestangle)) { + biggestangle = cossquare; + } + } else { + angletable[17 - tendegree]++; + if (acutebiggest || (cossquare > biggestangle)) { + biggestangle = cossquare; + acutebiggest = 0; + } + } + } + triangleloop.tri = triangletraverse(); + } + + shortest = (REAL)sqrt(shortest); + longest = (REAL)sqrt(longest); + minaltitude = (REAL)sqrt(minaltitude); + worstaspect = (REAL)sqrt(worstaspect); + smallestarea *= 2.0; + biggestarea *= 2.0; + if (smallestangle >= 1.0) { + smallestangle = 0.0; + } else { + smallestangle = (REAL)(degconst * acos(sqrt(smallestangle))); + } + if (biggestangle >= 1.0) { + biggestangle = 180.0; + } else { + if (acutebiggest) { + biggestangle = (REAL)(degconst * acos(sqrt(biggestangle))); + } else { + biggestangle = (REAL)(180.0 - degconst * acos(sqrt(biggestangle))); + } + } + + printf(" Smallest area: %16.5g | Largest area: %16.5g\n", + smallestarea, biggestarea); + printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", + shortest, longest); + printf(" Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", + minaltitude, worstaspect); + printf(" Aspect ratio histogram:\n"); + printf(" 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], + aspecttable[8]); + for (i = 1; i < 7; i++) { + printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[i - 1], ratiotable[i], aspecttable[i], + ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]); + } + printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", + ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], + aspecttable[15]); + printf( +" (Triangle aspect ratio is longest edge divided by shortest altitude)\n\n"); + printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", + smallestangle, biggestangle); + printf(" Angle histogram:\n"); + for (i = 0; i < 9; i++) { + printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", + i * 10, i * 10 + 10, angletable[i], + i * 10 + 90, i * 10 + 100, angletable[i + 9]); + } + printf("\n"); +} + +/*****************************************************************************/ +/* */ +/* statistics() Print all sorts of cool facts. */ +/* */ +/*****************************************************************************/ + +void statistics() +{ + printf("\nStatistics:\n\n"); + printf(" Input points: %d\n", inpoints); + if (refine) { + printf(" Input triangles: %d\n", inelements); + } + if (poly) { + printf(" Input segments: %d\n", insegments); + if (!refine) { + printf(" Input holes: %d\n", holes); + } + } + + printf("\n Mesh points: %ld\n", points.items); + printf(" Mesh triangles: %ld\n", triangles.items); + printf(" Mesh edges: %ld\n", edges); + if (poly || refine) { + printf(" Mesh boundary edges: %ld\n", hullsize); + printf(" Mesh segments: %ld\n\n", shelles.items); + } else { + printf(" Mesh convex hull edges: %ld\n\n", hullsize); + } + if (verbose) { + quality_statistics(); + printf("Memory allocation statistics:\n\n"); + printf(" Maximum number of points: %ld\n", points.maxitems); + printf(" Maximum number of triangles: %ld\n", triangles.maxitems); + if (shelles.maxitems > 0) { + printf(" Maximum number of segments: %ld\n", shelles.maxitems); + } + if (viri.maxitems > 0) { + printf(" Maximum number of viri: %ld\n", viri.maxitems); + } + if (badsegments.maxitems > 0) { + printf(" Maximum number of encroached segments: %ld\n", + badsegments.maxitems); + } + if (badtriangles.maxitems > 0) { + printf(" Maximum number of bad triangles: %ld\n", + badtriangles.maxitems); + } + if (splaynodes.maxitems > 0) { + printf(" Maximum number of splay tree nodes: %ld\n", + splaynodes.maxitems); + } + printf(" Approximate heap memory use (bytes): %ld\n\n", + points.maxitems * points.itembytes + + triangles.maxitems * triangles.itembytes + + shelles.maxitems * shelles.itembytes + + viri.maxitems * viri.itembytes + + badsegments.maxitems * badsegments.itembytes + + badtriangles.maxitems * badtriangles.itembytes + + splaynodes.maxitems * splaynodes.itembytes); + + printf("Algorithmic statistics:\n\n"); + printf(" Number of incircle tests: %ld\n", incirclecount); + printf(" Number of orientation tests: %ld\n", counterclockcount); + if (hyperbolacount > 0) { + printf(" Number of right-of-hyperbola tests: %ld\n", + hyperbolacount); + } + if (circumcentercount > 0) { + printf(" Number of circumcenter computations: %ld\n", + circumcentercount); + } + if (circletopcount > 0) { + printf(" Number of circle top computations: %ld\n", + circletopcount); + } + printf("\n"); + } +} + +/*****************************************************************************/ +/* */ +/* main() or triangulate() Gosh, do everything. */ +/* */ +/* The sequence is roughly as follows. Many of these steps can be skipped, */ +/* depending on the command line switches. */ +/* */ +/* - Initialize constants and parse the command line. */ +/* - Read the points from a file and either */ +/* - triangulate them (no -r), or */ +/* - read an old mesh from files and reconstruct it (-r). */ +/* - Insert the PSLG segments (-p), and possibly segments on the convex */ +/* hull (-c). */ +/* - Read the holes (-p), regional attributes (-pA), and regional area */ +/* constraints (-pa). Carve the holes and concavities, and spread the */ +/* regional attributes and area constraints. */ +/* - Enforce the constraints on minimum angle (-q) and maximum area (-a). */ +/* Also enforce the conforming Delaunay property (-q and -a). */ +/* - Compute the number of edges in the resulting mesh. */ +/* - Promote the mesh's linear triangles to higher order elements (-o). */ +/* - Write the output files and print the statistics. */ +/* - Check the consistency and Delaunay property of the mesh (-C). */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void triangulate(triswitches, in, out, vorout) +char *triswitches; +struct triangulateio *in; +struct triangulateio *out; +struct triangulateio *vorout; + +#else /* not TRILIBRARY */ + +int main(argc, argv) +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ + REAL *holearray; /* Array of holes. */ + REAL *regionarray; /* Array of regional attributes and area constraints. */ +#ifndef TRILIBRARY + FILE *polyfile; +#endif /* not TRILIBRARY */ +#ifndef NO_TIMER + /* Variables for timing the performance of Triangle. The types are */ + /* defined in sys/time.h. */ + struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6; + struct timezone tz; +#endif /* NO_TIMER */ + +#ifndef NO_TIMER + gettimeofday(&tv0, &tz); +#endif /* NO_TIMER */ + + triangleinit(); +#ifdef TRILIBRARY + parsecommandline(1, &triswitches); +#else /* not TRILIBRARY */ + parsecommandline(argc, argv); +#endif /* not TRILIBRARY */ + +#ifdef TRILIBRARY + transfernodes(in->pointlist, in->pointattributelist, in->pointmarkerlist, + in->numberofpoints, in->numberofpointattributes); +#else /* not TRILIBRARY */ + readnodes(innodefilename, inpolyfilename, &polyfile); +#endif /* not TRILIBRARY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv1, &tz); + } +#endif /* NO_TIMER */ + +#ifdef CDT_ONLY + hullsize = delaunay(); /* Triangulate the points. */ +#else /* not CDT_ONLY */ + if (refine) { + /* Read and reconstruct a mesh. */ +#ifdef TRILIBRARY + hullsize = reconstruct(in->trianglelist, in->triangleattributelist, + in->trianglearealist, in->numberoftriangles, + in->numberofcorners, in->numberoftriangleattributes, + in->segmentlist, in->segmentmarkerlist, + in->numberofsegments); +#else /* not TRILIBRARY */ + hullsize = reconstruct(inelefilename, areafilename, inpolyfilename, + polyfile); +#endif /* not TRILIBRARY */ + } else { + hullsize = delaunay(); /* Triangulate the points. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv2, &tz); + if (refine) { + printf("Mesh reconstruction"); + } else { + printf("Delaunay"); + } + printf(" milliseconds: %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec) + + (tv2.tv_usec - tv1.tv_usec) / 1000l); + } +#endif /* NO_TIMER */ + + /* Ensure that no point can be mistaken for a triangular bounding */ + /* box point in insertsite(). */ + infpoint1 = (point) NULL; + infpoint2 = (point) NULL; + infpoint3 = (point) NULL; + + if (useshelles) { + checksegments = 1; /* Segments will be introduced next. */ + if (!refine) { + /* Insert PSLG segments and/or convex hull segments. */ +#ifdef TRILIBRARY + insegments = formskeleton(in->segmentlist, in->segmentmarkerlist, + in->numberofsegments); +#else /* not TRILIBRARY */ + insegments = formskeleton(polyfile, inpolyfilename); +#endif /* not TRILIBRARY */ + } + } + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv3, &tz); + if (useshelles && !refine) { + printf("Segment milliseconds: %ld\n", + 1000l * (tv3.tv_sec - tv2.tv_sec) + + (tv3.tv_usec - tv2.tv_usec) / 1000l); + } + } +#endif /* NO_TIMER */ + + if (poly) { +#ifdef TRILIBRARY + holearray = in->holelist; + holes = in->numberofholes; + regionarray = in->regionlist; + regions = in->numberofregions; +#else /* not TRILIBRARY */ + readholes(polyfile, inpolyfilename, &holearray, &holes, + ®ionarray, ®ions); +#endif /* not TRILIBRARY */ + if (!refine) { + /* Carve out holes and concavities. */ + carveholes(holearray, holes, regionarray, regions); + } + } else { + /* Without a PSLG, there can be no holes or regional attributes */ + /* or area constraints. The following are set to zero to avoid */ + /* an accidental free() later. */ + holes = 0; + regions = 0; + } + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv4, &tz); + if (poly && !refine) { + printf("Hole milliseconds: %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec) + + (tv4.tv_usec - tv3.tv_usec) / 1000l); + } + } +#endif /* NO_TIMER */ + +#ifndef CDT_ONLY + if (quality) { + enforcequality(); /* Enforce angle and area constraints. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv5, &tz); +#ifndef CDT_ONLY + if (quality) { + printf("Quality milliseconds: %ld\n", + 1000l * (tv5.tv_sec - tv4.tv_sec) + + (tv5.tv_usec - tv4.tv_usec) / 1000l); + } +#endif /* not CDT_ONLY */ + } +#endif /* NO_TIMER */ + + /* Compute the number of edges. */ + edges = (3l * triangles.items + hullsize) / 2l; + + if (order > 1) { + highorder(); /* Promote elements to higher polynomial order. */ + } + if (!quiet) { + printf("\n"); + } + +#ifdef TRILIBRARY + out->numberofpoints = points.items; + out->numberofpointattributes = nextras; + out->numberoftriangles = triangles.items; + out->numberofcorners = (order + 1) * (order + 2) / 2; + out->numberoftriangleattributes = eextras; + out->numberofedges = edges; + if (useshelles) { + out->numberofsegments = shelles.items; + } else { + out->numberofsegments = hullsize; + } + if (vorout != (struct triangulateio *) NULL) { + vorout->numberofpoints = triangles.items; + vorout->numberofpointattributes = nextras; + vorout->numberofedges = edges; + } +#endif /* TRILIBRARY */ + /* If not using iteration numbers, don't write a .node file if one was */ + /* read, because the original one would be overwritten! */ + if (nonodewritten || (noiterationnum && readnodefile)) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing points.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .node file.\n"); +#endif /* not TRILIBRARY */ + } + numbernodes(); /* We must remember to number the points. */ + } else { +#ifdef TRILIBRARY + writenodes(&out->pointlist, &out->pointattributelist, + &out->pointmarkerlist); +#else /* not TRILIBRARY */ + writenodes(outnodefilename, argc, argv); /* Numbers the points too. */ +#endif /* TRILIBRARY */ + } + if (noelewritten) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing triangles.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing an .ele file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writeelements(&out->trianglelist, &out->triangleattributelist); +#else /* not TRILIBRARY */ + writeelements(outelefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + /* The -c switch (convex switch) causes a PSLG to be written */ + /* even if none was read. */ + if (poly || convex) { + /* If not using iteration numbers, don't overwrite the .poly file. */ + if (nopolywritten || noiterationnum) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing segments.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .poly file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writepoly(&out->segmentlist, &out->segmentmarkerlist); + out->numberofholes = holes; + out->numberofregions = regions; + if (poly) { + out->holelist = in->holelist; + out->regionlist = in->regionlist; + } else { + out->holelist = (REAL *) NULL; + out->regionlist = (REAL *) NULL; + } +#else /* not TRILIBRARY */ + writepoly(outpolyfilename, holearray, holes, regionarray, regions, + argc, argv); +#endif /* not TRILIBRARY */ + } + } +#ifndef TRILIBRARY +#ifndef CDT_ONLY + if (regions > 0) { + free(regionarray); + } +#endif /* not CDT_ONLY */ + if (holes > 0) { + free(holearray); + } + if (geomview) { + writeoff(offfilename, argc, argv); + } +#endif /* not TRILIBRARY */ + if (edgesout) { +#ifdef TRILIBRARY + writeedges(&out->edgelist, &out->edgemarkerlist); +#else /* not TRILIBRARY */ + writeedges(edgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (voronoi) { +#ifdef TRILIBRARY + writevoronoi(&vorout->pointlist, &vorout->pointattributelist, + &vorout->pointmarkerlist, &vorout->edgelist, + &vorout->edgemarkerlist, &vorout->normlist); +#else /* not TRILIBRARY */ + writevoronoi(vnodefilename, vedgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (neighbors) { +#ifdef TRILIBRARY + writeneighbors(&out->neighborlist); +#else /* not TRILIBRARY */ + writeneighbors(neighborfilename, argc, argv); +#endif /* not TRILIBRARY */ + } + + if (!quiet) { +#ifndef NO_TIMER + gettimeofday(&tv6, &tz); + printf("\nOutput milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv5.tv_sec) + + (tv6.tv_usec - tv5.tv_usec) / 1000l); + printf("Total running milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv0.tv_sec) + + (tv6.tv_usec - tv0.tv_usec) / 1000l); +#endif /* NO_TIMER */ + + statistics(); + } + +#ifndef REDUCED + if (docheck) { + checkmesh(); + checkdelaunay(); + } +#endif /* not REDUCED */ + + triangledeinit(); +#ifndef TRILIBRARY + return 0; +#endif /* not TRILIBRARY */ +} diff --git a/contrib/gtkgensurf/triangle.h b/contrib/gtkgensurf/triangle.h index 70cd6596..e7d87d01 100644 --- a/contrib/gtkgensurf/triangle.h +++ b/contrib/gtkgensurf/triangle.h @@ -1,288 +1,288 @@ -/*****************************************************************************/ -/* */ -/* (triangle.h) */ -/* */ -/* Include file for programs that call Triangle. */ -/* */ -/* Accompanies Triangle Version 1.3 */ -/* July 19, 1996 */ -/* */ -/* Copyright 1996 */ -/* Jonathan Richard Shewchuk */ -/* School of Computer Science */ -/* Carnegie Mellon University */ -/* 5000 Forbes Avenue */ -/* Pittsburgh, Pennsylvania 15213-3891 */ -/* jrs@cs.cmu.edu */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* */ -/* How to call Triangle from another program */ -/* */ -/* */ -/* If you haven't read Triangle's instructions (run "triangle -h" to read */ -/* them), you won't understand what follows. */ -/* */ -/* Triangle must be compiled into an object file (triangle.o) with the */ -/* TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */ -/* switch). The makefile included with Triangle will do this for you if */ -/* you run "make trilibrary". The resulting object file can be called via */ -/* the procedure triangulate(). */ -/* */ -/* If the size of the object file is important to you, you may wish to */ -/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */ -/* of all features that are primarily of research interest. Specifically, */ -/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */ -/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */ -/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */ -/* eliminates Triangle's -r, -q, -a, -S, and -s switches. */ -/* */ -/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */ -/* made in the makefile or in triangle.c itself. Putting these definitions */ -/* in this file will not create the desired effect. */ -/* */ -/* */ -/* The calling convention for triangulate() follows. */ -/* */ -/* void triangulate(triswitches, in, out, vorout) */ -/* char *triswitches; */ -/* struct triangulateio *in; */ -/* struct triangulateio *out; */ -/* struct triangulateio *vorout; */ -/* */ -/* `triswitches' is a string containing the command line switches you wish */ -/* to invoke. No initial dash is required. Some suggestions: */ -/* */ -/* - You'll probably find it convenient to use the `z' switch so that */ -/* points (and other items) are numbered from zero. This simplifies */ -/* indexing, because the first item of any type always starts at index */ -/* [0] of the corresponding array, whether that item's number is zero or */ -/* one. */ -/* - You'll probably want to use the `Q' (quiet) switch in your final code, */ -/* but you can take advantage of Triangle's printed output (including the */ -/* `V' switch) while debugging. */ -/* - If you are not using the `q' or `a' switches, then the output points */ -/* will be identical to the input points, except possibly for the */ -/* boundary markers. If you don't need the boundary markers, you should */ -/* use the `N' (no nodes output) switch to save memory. (If you do need */ -/* boundary markers, but need to save memory, a good nasty trick is to */ -/* set out->pointlist equal to in->pointlist before calling triangulate(),*/ -/* so that Triangle overwrites the input points with identical copies.) */ -/* - The `I' (no iteration numbers) and `g' (.off file output) switches */ -/* have no effect when Triangle is compiled with TRILIBRARY defined. */ -/* */ -/* `in', `out', and `vorout' are descriptions of the input, the output, */ -/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */ -/* `vorout' may be NULL. `in' and `out' may never be NULL. */ -/* */ -/* Certain fields of the input and output structures must be initialized, */ -/* as described below. */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* */ -/* The `triangulateio' structure. */ -/* */ -/* Used to pass data into and out of the triangulate() procedure. */ -/* */ -/* */ -/* Arrays are used to store points, triangles, markers, and so forth. In */ -/* all cases, the first item in any array is stored starting at index [0]. */ -/* However, that item is item number `1' unless the `z' switch is used, in */ -/* which case it is item number `0'. Hence, you may find it easier to */ -/* index points (and triangles in the neighbor list) if you use the `z' */ -/* switch. Unless, of course, you're calling Triangle from a Fortran */ -/* program. */ -/* */ -/* Description of fields (except the `numberof' fields, which are obvious): */ -/* */ -/* `pointlist': An array of point coordinates. The first point's x */ -/* coordinate is at index [0] and its y coordinate at index [1], followed */ -/* by the coordinates of the remaining points. Each point occupies two */ -/* REALs. */ -/* `pointattributelist': An array of point attributes. Each point's */ -/* attributes occupy `numberofpointattributes' REALs. */ -/* `pointmarkerlist': An array of point markers; one int per point. */ -/* */ -/* `trianglelist': An array of triangle corners. The first triangle's */ -/* first corner is at index [0], followed by its other two corners in */ -/* counterclockwise order, followed by any other nodes if the triangle */ -/* represents a nonlinear element. Each triangle occupies */ -/* `numberofcorners' ints. */ -/* `triangleattributelist': An array of triangle attributes. Each */ -/* triangle's attributes occupy `numberoftriangleattributes' REALs. */ -/* `trianglearealist': An array of triangle area constraints; one REAL per */ -/* triangle. Input only. */ -/* `neighborlist': An array of triangle neighbors; three ints per */ -/* triangle. Output only. */ -/* */ -/* `segmentlist': An array of segment endpoints. The first segment's */ -/* endpoints are at indices [0] and [1], followed by the remaining */ -/* segments. Two ints per segment. */ -/* `segmentmarkerlist': An array of segment markers; one int per segment. */ -/* */ -/* `holelist': An array of holes. The first hole's x and y coordinates */ -/* are at indices [0] and [1], followed by the remaining holes. Two */ -/* REALs per hole. Input only, although the pointer is copied to the */ -/* output structure for your convenience. */ -/* */ -/* `regionlist': An array of regional attributes and area constraints. */ -/* The first constraint's x and y coordinates are at indices [0] and [1], */ -/* followed by the regional attribute and index [2], followed by the */ -/* maximum area at index [3], followed by the remaining area constraints. */ -/* Four REALs per area constraint. Note that each regional attribute is */ -/* used only if you select the `A' switch, and each area constraint is */ -/* used only if you select the `a' switch (with no number following), but */ -/* omitting one of these switches does not change the memory layout. */ -/* Input only, although the pointer is copied to the output structure for */ -/* your convenience. */ -/* */ -/* `edgelist': An array of edge endpoints. The first edge's endpoints are */ -/* at indices [0] and [1], followed by the remaining edges. Two ints per */ -/* edge. Output only. */ -/* `edgemarkerlist': An array of edge markers; one int per edge. Output */ -/* only. */ -/* `normlist': An array of normal vectors, used for infinite rays in */ -/* Voronoi diagrams. The first normal vector's x and y magnitudes are */ -/* at indices [0] and [1], followed by the remaining vectors. For each */ -/* finite edge in a Voronoi diagram, the normal vector written is the */ -/* zero vector. Two REALs per edge. Output only. */ -/* */ -/* */ -/* Any input fields that Triangle will examine must be initialized. */ -/* Furthermore, for each output array that Triangle will write to, you */ -/* must either provide space by setting the appropriate pointer to point */ -/* to the space you want the data written to, or you must initialize the */ -/* pointer to NULL, which tells Triangle to allocate space for the results. */ -/* The latter option is preferable, because Triangle always knows exactly */ -/* how much space to allocate. The former option is provided mainly for */ -/* people who need to call Triangle from Fortran code, though it also makes */ -/* possible some nasty space-saving tricks, like writing the output to the */ -/* same arrays as the input. */ -/* */ -/* Triangle will not free() any input or output arrays, including those it */ -/* allocates itself; that's up to you. */ -/* */ -/* Here's a guide to help you decide which fields you must initialize */ -/* before you call triangulate(). */ -/* */ -/* `in': */ -/* */ -/* - `pointlist' must always point to a list of points; `numberofpoints' */ -/* and `numberofpointattributes' must be properly set. */ -/* `pointmarkerlist' must either be set to NULL (in which case all */ -/* markers default to zero), or must point to a list of markers. If */ -/* `numberofpointattributes' is not zero, `pointattributelist' must */ -/* point to a list of point attributes. */ -/* - If the `r' switch is used, `trianglelist' must point to a list of */ -/* triangles, and `numberoftriangles', `numberofcorners', and */ -/* `numberoftriangleattributes' must be properly set. If */ -/* `numberoftriangleattributes' is not zero, `triangleattributelist' */ -/* must point to a list of triangle attributes. If the `a' switch is */ -/* used (with no number following), `trianglearealist' must point to a */ -/* list of triangle area constraints. `neighborlist' may be ignored. */ -/* - If the `p' switch is used, `segmentlist' must point to a list of */ -/* segments, `numberofsegments' must be properly set, and */ -/* `segmentmarkerlist' must either be set to NULL (in which case all */ -/* markers default to zero), or must point to a list of markers. */ -/* - If the `p' switch is used without the `r' switch, then */ -/* `numberofholes' and `numberofregions' must be properly set. If */ -/* `numberofholes' is not zero, `holelist' must point to a list of */ -/* holes. If `numberofregions' is not zero, `regionlist' must point to */ -/* a list of region constraints. */ -/* - If the `p' switch is used, `holelist', `numberofholes', */ -/* `regionlist', and `numberofregions' is copied to `out'. (You can */ -/* nonetheless get away with not initializing them if the `r' switch is */ -/* used.) */ -/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */ -/* ignored. */ -/* */ -/* `out': */ -/* */ -/* - `pointlist' must be initialized (NULL or pointing to memory) unless */ -/* the `N' switch is used. `pointmarkerlist' must be initialized */ -/* unless the `N' or `B' switch is used. If `N' is not used and */ -/* `in->numberofpointattributes' is not zero, `pointattributelist' must */ -/* be initialized. */ -/* - `trianglelist' must be initialized unless the `E' switch is used. */ -/* `neighborlist' must be initialized if the `n' switch is used. If */ -/* the `E' switch is not used and (`in->numberofelementattributes' is */ -/* not zero or the `A' switch is used), `elementattributelist' must be */ -/* initialized. `trianglearealist' may be ignored. */ -/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */ -/* and the `P' switch is not used. `segmentmarkerlist' must also be */ -/* initialized under these circumstances unless the `B' switch is used. */ -/* - `edgelist' must be initialized if the `e' switch is used. */ -/* `edgemarkerlist' must be initialized if the `e' switch is used and */ -/* the `B' switch is not. */ -/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/ -/* */ -/* `vorout' (only needed if `v' switch is used): */ -/* */ -/* - `pointlist' must be initialized. If `in->numberofpointattributes' */ -/* is not zero, `pointattributelist' must be initialized. */ -/* `pointmarkerlist' may be ignored. */ -/* - `edgelist' and `normlist' must both be initialized. */ -/* `edgemarkerlist' may be ignored. */ -/* - Everything else may be ignored. */ -/* */ -/* After a call to triangulate(), the valid fields of `out' and `vorout' */ -/* will depend, in an obvious way, on the choice of switches used. Note */ -/* that when the `p' switch is used, the pointers `holelist' and */ -/* `regionlist' are copied from `in' to `out', but no new space is */ -/* allocated; be careful that you don't free() the same array twice. On */ -/* the other hand, Triangle will never copy the `pointlist' pointer (or any */ -/* others); new space is allocated for `out->pointlist', or if the `N' */ -/* switch is used, `out->pointlist' remains uninitialized. */ -/* */ -/* All of the meaningful `numberof' fields will be properly set; for */ -/* instance, `numberofedges' will represent the number of edges in the */ -/* triangulation whether or not the edges were written. If segments are */ -/* not used, `numberofsegments' will indicate the number of boundary edges. */ -/* */ -/*****************************************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -struct triangulateio { - REAL *pointlist; /* In / out */ - REAL *pointattributelist; /* In / out */ - int *pointmarkerlist; /* In / out */ - int numberofpoints; /* In / out */ - int numberofpointattributes; /* In / out */ - - int *trianglelist; /* In / out */ - REAL *triangleattributelist; /* In / out */ - REAL *trianglearealist; /* In only */ - int *neighborlist; /* Out only */ - int numberoftriangles; /* In / out */ - int numberofcorners; /* In / out */ - int numberoftriangleattributes; /* In / out */ - - int *segmentlist; /* In / out */ - int *segmentmarkerlist; /* In / out */ - int numberofsegments; /* In / out */ - - REAL *holelist; /* In / pointer to array copied out */ - int numberofholes; /* In / copied out */ - - REAL *regionlist; /* In / pointer to array copied out */ - int numberofregions; /* In / copied out */ - - int *edgelist; /* Out only */ - int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ - REAL *normlist; /* Used only with Voronoi diagram; out only */ - int numberofedges; /* Out only */ -}; - -void triangulate(char *, struct triangulateio *, struct triangulateio *, - struct triangulateio *); - -#ifdef __cplusplus -} -#endif +/*****************************************************************************/ +/* */ +/* (triangle.h) */ +/* */ +/* Include file for programs that call Triangle. */ +/* */ +/* Accompanies Triangle Version 1.3 */ +/* July 19, 1996 */ +/* */ +/* Copyright 1996 */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* How to call Triangle from another program */ +/* */ +/* */ +/* If you haven't read Triangle's instructions (run "triangle -h" to read */ +/* them), you won't understand what follows. */ +/* */ +/* Triangle must be compiled into an object file (triangle.o) with the */ +/* TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */ +/* switch). The makefile included with Triangle will do this for you if */ +/* you run "make trilibrary". The resulting object file can be called via */ +/* the procedure triangulate(). */ +/* */ +/* If the size of the object file is important to you, you may wish to */ +/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */ +/* of all features that are primarily of research interest. Specifically, */ +/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */ +/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */ +/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */ +/* eliminates Triangle's -r, -q, -a, -S, and -s switches. */ +/* */ +/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */ +/* made in the makefile or in triangle.c itself. Putting these definitions */ +/* in this file will not create the desired effect. */ +/* */ +/* */ +/* The calling convention for triangulate() follows. */ +/* */ +/* void triangulate(triswitches, in, out, vorout) */ +/* char *triswitches; */ +/* struct triangulateio *in; */ +/* struct triangulateio *out; */ +/* struct triangulateio *vorout; */ +/* */ +/* `triswitches' is a string containing the command line switches you wish */ +/* to invoke. No initial dash is required. Some suggestions: */ +/* */ +/* - You'll probably find it convenient to use the `z' switch so that */ +/* points (and other items) are numbered from zero. This simplifies */ +/* indexing, because the first item of any type always starts at index */ +/* [0] of the corresponding array, whether that item's number is zero or */ +/* one. */ +/* - You'll probably want to use the `Q' (quiet) switch in your final code, */ +/* but you can take advantage of Triangle's printed output (including the */ +/* `V' switch) while debugging. */ +/* - If you are not using the `q' or `a' switches, then the output points */ +/* will be identical to the input points, except possibly for the */ +/* boundary markers. If you don't need the boundary markers, you should */ +/* use the `N' (no nodes output) switch to save memory. (If you do need */ +/* boundary markers, but need to save memory, a good nasty trick is to */ +/* set out->pointlist equal to in->pointlist before calling triangulate(),*/ +/* so that Triangle overwrites the input points with identical copies.) */ +/* - The `I' (no iteration numbers) and `g' (.off file output) switches */ +/* have no effect when Triangle is compiled with TRILIBRARY defined. */ +/* */ +/* `in', `out', and `vorout' are descriptions of the input, the output, */ +/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */ +/* `vorout' may be NULL. `in' and `out' may never be NULL. */ +/* */ +/* Certain fields of the input and output structures must be initialized, */ +/* as described below. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* The `triangulateio' structure. */ +/* */ +/* Used to pass data into and out of the triangulate() procedure. */ +/* */ +/* */ +/* Arrays are used to store points, triangles, markers, and so forth. In */ +/* all cases, the first item in any array is stored starting at index [0]. */ +/* However, that item is item number `1' unless the `z' switch is used, in */ +/* which case it is item number `0'. Hence, you may find it easier to */ +/* index points (and triangles in the neighbor list) if you use the `z' */ +/* switch. Unless, of course, you're calling Triangle from a Fortran */ +/* program. */ +/* */ +/* Description of fields (except the `numberof' fields, which are obvious): */ +/* */ +/* `pointlist': An array of point coordinates. The first point's x */ +/* coordinate is at index [0] and its y coordinate at index [1], followed */ +/* by the coordinates of the remaining points. Each point occupies two */ +/* REALs. */ +/* `pointattributelist': An array of point attributes. Each point's */ +/* attributes occupy `numberofpointattributes' REALs. */ +/* `pointmarkerlist': An array of point markers; one int per point. */ +/* */ +/* `trianglelist': An array of triangle corners. The first triangle's */ +/* first corner is at index [0], followed by its other two corners in */ +/* counterclockwise order, followed by any other nodes if the triangle */ +/* represents a nonlinear element. Each triangle occupies */ +/* `numberofcorners' ints. */ +/* `triangleattributelist': An array of triangle attributes. Each */ +/* triangle's attributes occupy `numberoftriangleattributes' REALs. */ +/* `trianglearealist': An array of triangle area constraints; one REAL per */ +/* triangle. Input only. */ +/* `neighborlist': An array of triangle neighbors; three ints per */ +/* triangle. Output only. */ +/* */ +/* `segmentlist': An array of segment endpoints. The first segment's */ +/* endpoints are at indices [0] and [1], followed by the remaining */ +/* segments. Two ints per segment. */ +/* `segmentmarkerlist': An array of segment markers; one int per segment. */ +/* */ +/* `holelist': An array of holes. The first hole's x and y coordinates */ +/* are at indices [0] and [1], followed by the remaining holes. Two */ +/* REALs per hole. Input only, although the pointer is copied to the */ +/* output structure for your convenience. */ +/* */ +/* `regionlist': An array of regional attributes and area constraints. */ +/* The first constraint's x and y coordinates are at indices [0] and [1], */ +/* followed by the regional attribute and index [2], followed by the */ +/* maximum area at index [3], followed by the remaining area constraints. */ +/* Four REALs per area constraint. Note that each regional attribute is */ +/* used only if you select the `A' switch, and each area constraint is */ +/* used only if you select the `a' switch (with no number following), but */ +/* omitting one of these switches does not change the memory layout. */ +/* Input only, although the pointer is copied to the output structure for */ +/* your convenience. */ +/* */ +/* `edgelist': An array of edge endpoints. The first edge's endpoints are */ +/* at indices [0] and [1], followed by the remaining edges. Two ints per */ +/* edge. Output only. */ +/* `edgemarkerlist': An array of edge markers; one int per edge. Output */ +/* only. */ +/* `normlist': An array of normal vectors, used for infinite rays in */ +/* Voronoi diagrams. The first normal vector's x and y magnitudes are */ +/* at indices [0] and [1], followed by the remaining vectors. For each */ +/* finite edge in a Voronoi diagram, the normal vector written is the */ +/* zero vector. Two REALs per edge. Output only. */ +/* */ +/* */ +/* Any input fields that Triangle will examine must be initialized. */ +/* Furthermore, for each output array that Triangle will write to, you */ +/* must either provide space by setting the appropriate pointer to point */ +/* to the space you want the data written to, or you must initialize the */ +/* pointer to NULL, which tells Triangle to allocate space for the results. */ +/* The latter option is preferable, because Triangle always knows exactly */ +/* how much space to allocate. The former option is provided mainly for */ +/* people who need to call Triangle from Fortran code, though it also makes */ +/* possible some nasty space-saving tricks, like writing the output to the */ +/* same arrays as the input. */ +/* */ +/* Triangle will not free() any input or output arrays, including those it */ +/* allocates itself; that's up to you. */ +/* */ +/* Here's a guide to help you decide which fields you must initialize */ +/* before you call triangulate(). */ +/* */ +/* `in': */ +/* */ +/* - `pointlist' must always point to a list of points; `numberofpoints' */ +/* and `numberofpointattributes' must be properly set. */ +/* `pointmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. If */ +/* `numberofpointattributes' is not zero, `pointattributelist' must */ +/* point to a list of point attributes. */ +/* - If the `r' switch is used, `trianglelist' must point to a list of */ +/* triangles, and `numberoftriangles', `numberofcorners', and */ +/* `numberoftriangleattributes' must be properly set. If */ +/* `numberoftriangleattributes' is not zero, `triangleattributelist' */ +/* must point to a list of triangle attributes. If the `a' switch is */ +/* used (with no number following), `trianglearealist' must point to a */ +/* list of triangle area constraints. `neighborlist' may be ignored. */ +/* - If the `p' switch is used, `segmentlist' must point to a list of */ +/* segments, `numberofsegments' must be properly set, and */ +/* `segmentmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. */ +/* - If the `p' switch is used without the `r' switch, then */ +/* `numberofholes' and `numberofregions' must be properly set. If */ +/* `numberofholes' is not zero, `holelist' must point to a list of */ +/* holes. If `numberofregions' is not zero, `regionlist' must point to */ +/* a list of region constraints. */ +/* - If the `p' switch is used, `holelist', `numberofholes', */ +/* `regionlist', and `numberofregions' is copied to `out'. (You can */ +/* nonetheless get away with not initializing them if the `r' switch is */ +/* used.) */ +/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */ +/* ignored. */ +/* */ +/* `out': */ +/* */ +/* - `pointlist' must be initialized (NULL or pointing to memory) unless */ +/* the `N' switch is used. `pointmarkerlist' must be initialized */ +/* unless the `N' or `B' switch is used. If `N' is not used and */ +/* `in->numberofpointattributes' is not zero, `pointattributelist' must */ +/* be initialized. */ +/* - `trianglelist' must be initialized unless the `E' switch is used. */ +/* `neighborlist' must be initialized if the `n' switch is used. If */ +/* the `E' switch is not used and (`in->numberofelementattributes' is */ +/* not zero or the `A' switch is used), `elementattributelist' must be */ +/* initialized. `trianglearealist' may be ignored. */ +/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */ +/* and the `P' switch is not used. `segmentmarkerlist' must also be */ +/* initialized under these circumstances unless the `B' switch is used. */ +/* - `edgelist' must be initialized if the `e' switch is used. */ +/* `edgemarkerlist' must be initialized if the `e' switch is used and */ +/* the `B' switch is not. */ +/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/ +/* */ +/* `vorout' (only needed if `v' switch is used): */ +/* */ +/* - `pointlist' must be initialized. If `in->numberofpointattributes' */ +/* is not zero, `pointattributelist' must be initialized. */ +/* `pointmarkerlist' may be ignored. */ +/* - `edgelist' and `normlist' must both be initialized. */ +/* `edgemarkerlist' may be ignored. */ +/* - Everything else may be ignored. */ +/* */ +/* After a call to triangulate(), the valid fields of `out' and `vorout' */ +/* will depend, in an obvious way, on the choice of switches used. Note */ +/* that when the `p' switch is used, the pointers `holelist' and */ +/* `regionlist' are copied from `in' to `out', but no new space is */ +/* allocated; be careful that you don't free() the same array twice. On */ +/* the other hand, Triangle will never copy the `pointlist' pointer (or any */ +/* others); new space is allocated for `out->pointlist', or if the `N' */ +/* switch is used, `out->pointlist' remains uninitialized. */ +/* */ +/* All of the meaningful `numberof' fields will be properly set; for */ +/* instance, `numberofedges' will represent the number of edges in the */ +/* triangulation whether or not the edges were written. If segments are */ +/* not used, `numberofsegments' will indicate the number of boundary edges. */ +/* */ +/*****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct triangulateio { + REAL *pointlist; /* In / out */ + REAL *pointattributelist; /* In / out */ + int *pointmarkerlist; /* In / out */ + int numberofpoints; /* In / out */ + int numberofpointattributes; /* In / out */ + + int *trianglelist; /* In / out */ + REAL *triangleattributelist; /* In / out */ + REAL *trianglearealist; /* In only */ + int *neighborlist; /* Out only */ + int numberoftriangles; /* In / out */ + int numberofcorners; /* In / out */ + int numberoftriangleattributes; /* In / out */ + + int *segmentlist; /* In / out */ + int *segmentmarkerlist; /* In / out */ + int numberofsegments; /* In / out */ + + REAL *holelist; /* In / pointer to array copied out */ + int numberofholes; /* In / copied out */ + + REAL *regionlist; /* In / pointer to array copied out */ + int numberofregions; /* In / copied out */ + + int *edgelist; /* Out only */ + int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ + REAL *normlist; /* Used only with Voronoi diagram; out only */ + int numberofedges; /* Out only */ +}; + +void triangulate(char *, struct triangulateio *, struct triangulateio *, + struct triangulateio *); + +#ifdef __cplusplus +} +#endif diff --git a/contrib/hydratoolz/plugin.h b/contrib/hydratoolz/plugin.h index 493fa839..42b3c20c 100644 --- a/contrib/hydratoolz/plugin.h +++ b/contrib/hydratoolz/plugin.h @@ -1,51 +1,51 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _PLUGIN_H_ -#define _PLUGIN_H_ - -//#include -//#include -#include -#include - -#include "synapse.h" -#include "iplugin.h" -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#include "ishaders.h" -#define USE_VFSTABLE_DEFINE -#include "ifilesystem.h" -#define USE_ENTITYTABLE_DEFINE -#include "ientity.h" - -class CSynapseClientHydraToolz : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - CSynapseClientHydraToolz() { } - virtual ~CSynapseClientHydraToolz() { } -}; - -#endif // _PLUGIN_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +//#include +//#include +#include +#include + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "ishaders.h" +#define USE_VFSTABLE_DEFINE +#include "ifilesystem.h" +#define USE_ENTITYTABLE_DEFINE +#include "ientity.h" + +class CSynapseClientHydraToolz : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientHydraToolz() { } + virtual ~CSynapseClientHydraToolz() { } +}; + +#endif // _PLUGIN_H_ diff --git a/contrib/prtview/AboutDialog.h b/contrib/prtview/AboutDialog.h index 73dbad78..66d8c0d0 100644 --- a/contrib/prtview/AboutDialog.h +++ b/contrib/prtview/AboutDialog.h @@ -1,72 +1,72 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -#if !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) -#define AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 -// AboutDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CAboutDialog dialog - -#ifdef GTK_PLUGIN -void DoAboutDlg (); - -#else // GTK_PLUGIN - -class CAboutDialog : public CDialog -{ -// Construction -public: - CAboutDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CAboutDialog) - enum { IDD = IDD_ABOUT }; - // NOTE: the ClassWizard will add data members here - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CAboutDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CAboutDialog) - // NOTE: the ClassWizard will add member functions here - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -#endif // GTK_PLUGIN - -//{{AFX_INSERT_LOCATION}} -// Microsoft Developer Studio will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +#if !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) +#define AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// AboutDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +#ifdef GTK_PLUGIN +void DoAboutDlg (); + +#else // GTK_PLUGIN + +class CAboutDialog : public CDialog +{ +// Construction +public: + CAboutDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAboutDialog) + enum { IDD = IDD_ABOUT }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAboutDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/ConfigDialog.h b/contrib/prtview/ConfigDialog.h index 7ca84920..11690fdc 100644 --- a/contrib/prtview/ConfigDialog.h +++ b/contrib/prtview/ConfigDialog.h @@ -1,107 +1,107 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -#if !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) -#define AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 -// ConfigDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CConfigDialog dialog - -#ifdef GTK_PLUGIN - -void DoConfigDialog (); - -#else - -class CConfigDialog : public CDialog -{ -// Construction -public: - CConfigDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CConfigDialog) - enum { IDD = IDD_CONFIG }; - CButton m_clip_ctrl; - CStatic m_cubic_ctrl; - CScrollBar m_scroll_cubic_ctrl; - CButton m_line_ctrl; - CScrollBar m_scroll_3d_trans_ctrl; - CStatic m_3d_trans_ctrl; - CButton m_poly_ctrl; - CButton m_fog_ctrl; - CComboBox m_z_ctrl; - CScrollBar m_scroll_3d_width_ctrl; - CButton m_aa_3d_ctrl; - CStatic m_3d_width_ctrl; - CButton m_aa_2d_ctrl; - CScrollBar m_scroll_2d_width_ctrl; - CStatic m_2d_width_ctrl; - CButton m_3d_ctrl; - CButton m_2d_ctrl; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CConfigDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - void Set2DText(); - void Set3DText(); - void Set3DTransText(); - void SetClipText(); - - // Generated message map functions - //{{AFX_MSG(CConfigDialog) - virtual qboolean OnInitDialog(); - afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); - afx_msg void OnAntiAlias2d(); - afx_msg void OnConfig2d(); - afx_msg void OnConfig3d(); - afx_msg void OnColor2d(); - afx_msg void OnAntiAlias3d(); - afx_msg void OnColor3d(); - afx_msg void OnColorFog(); - afx_msg void OnFog(); - afx_msg void OnSelchangeZbuffer(); - afx_msg void OnPoly(); - afx_msg void OnLines(); - afx_msg void OnClip(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -#endif // GTK_PLUGIN - -//{{AFX_INSERT_LOCATION}} -// Microsoft Developer Studio will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +#if !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) +#define AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// ConfigDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog dialog + +#ifdef GTK_PLUGIN + +void DoConfigDialog (); + +#else + +class CConfigDialog : public CDialog +{ +// Construction +public: + CConfigDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CConfigDialog) + enum { IDD = IDD_CONFIG }; + CButton m_clip_ctrl; + CStatic m_cubic_ctrl; + CScrollBar m_scroll_cubic_ctrl; + CButton m_line_ctrl; + CScrollBar m_scroll_3d_trans_ctrl; + CStatic m_3d_trans_ctrl; + CButton m_poly_ctrl; + CButton m_fog_ctrl; + CComboBox m_z_ctrl; + CScrollBar m_scroll_3d_width_ctrl; + CButton m_aa_3d_ctrl; + CStatic m_3d_width_ctrl; + CButton m_aa_2d_ctrl; + CScrollBar m_scroll_2d_width_ctrl; + CStatic m_2d_width_ctrl; + CButton m_3d_ctrl; + CButton m_2d_ctrl; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CConfigDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + void Set2DText(); + void Set3DText(); + void Set3DTransText(); + void SetClipText(); + + // Generated message map functions + //{{AFX_MSG(CConfigDialog) + virtual qboolean OnInitDialog(); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnAntiAlias2d(); + afx_msg void OnConfig2d(); + afx_msg void OnConfig3d(); + afx_msg void OnColor2d(); + afx_msg void OnAntiAlias3d(); + afx_msg void OnColor3d(); + afx_msg void OnColorFog(); + afx_msg void OnFog(); + afx_msg void OnSelchangeZbuffer(); + afx_msg void OnPoly(); + afx_msg void OnLines(); + afx_msg void OnClip(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/LoadPortalFileDialog.h b/contrib/prtview/LoadPortalFileDialog.h index c11c01ea..4540c104 100644 --- a/contrib/prtview/LoadPortalFileDialog.h +++ b/contrib/prtview/LoadPortalFileDialog.h @@ -1,77 +1,77 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -#if !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) -#define AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_ - -#if _MSC_VER >= 1000 -#pragma once -#endif // _MSC_VER >= 1000 -// LoadPortalFileDialog.h : header file -// - -///////////////////////////////////////////////////////////////////////////// -// CLoadPortalFileDialog dialog - -#ifdef GTK_PLUGIN - -int DoLoadPortalFileDialog (); - -#else - -class CLoadPortalFileDialog : public CDialog -{ -// Construction -public: - CLoadPortalFileDialog(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - //{{AFX_DATA(CLoadPortalFileDialog) - enum { IDD = IDD_LOAD }; - CButton m_3d_ctrl; - CButton m_2d_ctrl; - CStatic m_fn_ctrl; - //}}AFX_DATA - - -// Overrides - // ClassWizard generated virtual function overrides - //{{AFX_VIRTUAL(CLoadPortalFileDialog) - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - //}}AFX_VIRTUAL - -// Implementation -protected: - - // Generated message map functions - //{{AFX_MSG(CLoadPortalFileDialog) - virtual qboolean OnInitDialog(); - virtual void OnOK(); - afx_msg void OnLoadOther(); - //}}AFX_MSG - DECLARE_MESSAGE_MAP() -}; - -#endif // GTK_PLUGIN - -//{{AFX_INSERT_LOCATION}} -// Microsoft Developer Studio will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +#if !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) +#define AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// LoadPortalFileDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog dialog + +#ifdef GTK_PLUGIN + +int DoLoadPortalFileDialog (); + +#else + +class CLoadPortalFileDialog : public CDialog +{ +// Construction +public: + CLoadPortalFileDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLoadPortalFileDialog) + enum { IDD = IDD_LOAD }; + CButton m_3d_ctrl; + CButton m_2d_ctrl; + CStatic m_fn_ctrl; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoadPortalFileDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoadPortalFileDialog) + virtual qboolean OnInitDialog(); + virtual void OnOK(); + afx_msg void OnLoadOther(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/gtkdlgs.h b/contrib/prtview/gtkdlgs.h index afa3ea74..37ca5031 100644 --- a/contrib/prtview/gtkdlgs.h +++ b/contrib/prtview/gtkdlgs.h @@ -1,27 +1,27 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -#ifndef _GTKDLGS_H_ -#define _GTKDLGS_H_ - -int DoLoadPortalFileDialog (); -void DoAboutDlg (); -void DoConfigDialog (); - -#endif // _GTKDLGS_H_ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +#ifndef _GTKDLGS_H_ +#define _GTKDLGS_H_ + +int DoLoadPortalFileDialog (); +void DoAboutDlg (); +void DoConfigDialog (); + +#endif // _GTKDLGS_H_ diff --git a/contrib/prtview/portals.h b/contrib/prtview/portals.h index 33bac1ec..13c7b89f 100644 --- a/contrib/prtview/portals.h +++ b/contrib/prtview/portals.h @@ -1,125 +1,125 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -#ifndef _PORTALS_H_ -#define _PORTALS_H_ - -class CBspPoint { -public: - float p[3]; -}; - -class CBspPortal { -public: - CBspPortal(); - ~CBspPortal(); - -protected: - -public: - CBspPoint center; - unsigned point_count; - CBspPoint *point; - CBspPoint *inner_point; - float fp_color_random[4]; - float min[3]; - float max[3]; - float dist; - qboolean hint; - - qboolean Build(char *def); -}; - -class CPortals { -public: - - CPortals(); - ~CPortals(); - -protected: - - -public: - - void Load(); // use filename in fn - void Purge(); - - void FixColors(); - - char fn[_MAX_PATH]; - - int zbuffer; - int polygons; - int lines; - qboolean show_3d; - qboolean aa_3d; - qboolean fog; - COLORREF color_3d; - float width_3d; // in 8'ths - float fp_color_3d[4]; - COLORREF color_fog; - float fp_color_fog[4]; - float trans_3d; - float clip_range; - qboolean clip; - - qboolean show_2d; - qboolean aa_2d; - COLORREF color_2d; - float width_2d; // in 8'ths - float fp_color_2d[4]; - - CBspPortal *portal; - int *portal_sort; - qboolean hint_flags; -// CBspNode *node; - - unsigned int node_count; - unsigned int portal_count; -}; - -class CPortalsRender : public IGL2DWindow, public IGL3DWindow { -public: - - CPortalsRender(); - virtual ~CPortalsRender(); - -protected: - - int refCount; -#ifdef _WIN32 - CRITICAL_SECTION protect; -#endif - -public: - - // IGL2DWindow IGL3DWindow interface - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } - void Draw2D( VIEWTYPE vt ); - void Draw3D(); - void Register(); -}; - -// void Sys_Printf (char *text, ...); - -extern CPortals portals; -extern CPortalsRender render; - -#endif // _PORTALS_H_ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +#ifndef _PORTALS_H_ +#define _PORTALS_H_ + +class CBspPoint { +public: + float p[3]; +}; + +class CBspPortal { +public: + CBspPortal(); + ~CBspPortal(); + +protected: + +public: + CBspPoint center; + unsigned point_count; + CBspPoint *point; + CBspPoint *inner_point; + float fp_color_random[4]; + float min[3]; + float max[3]; + float dist; + qboolean hint; + + qboolean Build(char *def); +}; + +class CPortals { +public: + + CPortals(); + ~CPortals(); + +protected: + + +public: + + void Load(); // use filename in fn + void Purge(); + + void FixColors(); + + char fn[_MAX_PATH]; + + int zbuffer; + int polygons; + int lines; + qboolean show_3d; + qboolean aa_3d; + qboolean fog; + COLORREF color_3d; + float width_3d; // in 8'ths + float fp_color_3d[4]; + COLORREF color_fog; + float fp_color_fog[4]; + float trans_3d; + float clip_range; + qboolean clip; + + qboolean show_2d; + qboolean aa_2d; + COLORREF color_2d; + float width_2d; // in 8'ths + float fp_color_2d[4]; + + CBspPortal *portal; + int *portal_sort; + qboolean hint_flags; +// CBspNode *node; + + unsigned int node_count; + unsigned int portal_count; +}; + +class CPortalsRender : public IGL2DWindow, public IGL3DWindow { +public: + + CPortalsRender(); + virtual ~CPortalsRender(); + +protected: + + int refCount; +#ifdef _WIN32 + CRITICAL_SECTION protect; +#endif + +public: + + // IGL2DWindow IGL3DWindow interface + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); + void Draw3D(); + void Register(); +}; + +// void Sys_Printf (char *text, ...); + +extern CPortals portals; +extern CPortalsRender render; + +#endif // _PORTALS_H_ diff --git a/contrib/prtview/prtview.h b/contrib/prtview/prtview.h index e478f7d9..468df3fc 100644 --- a/contrib/prtview/prtview.h +++ b/contrib/prtview/prtview.h @@ -1,29 +1,29 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -// PrtView.h : main header file for the PRTVIEW DLL -// - -#if !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) -#define AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_ - -void InitInstance (); -void SaveConfig (); - -#endif // !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +// PrtView.h : main header file for the PRTVIEW DLL +// + +#if !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) +#define AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_ + +void InitInstance (); +void SaveConfig (); + +#endif // !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/resource.h b/contrib/prtview/resource.h index afa9db6e..5fdce405 100644 --- a/contrib/prtview/resource.h +++ b/contrib/prtview/resource.h @@ -1,42 +1,42 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by PrtView.rc -// -#define IDD_ABOUT 129 -#define IDD_LOAD 130 -#define IDD_CONFIG 131 -#define IDC_LOAD_2D 1000 -#define IDC_LOAD_3D 1001 -#define IDC_LOAD_FILE_NAME 1002 -#define IDC_LOAD_OTHER 1003 -#define IDC_CONFIG_3D 1004 -#define IDC_CONFIG_2D 1005 -#define IDC_SCROLL_2D_WIDTH 1006 -#define IDC_2D_WIDTH 1007 -#define IDC_ANTI_ALIAS_2D 1008 -#define IDC_COLOR_2D 1009 -#define IDC_ZBUFFER 1010 -#define IDC_SCROLL_3D_WIDTH 1011 -#define IDC_3D_WIDTH 1012 -#define IDC_ANTI_ALIAS_3D 1013 -#define IDC_COLOR_3D 1014 -#define IDC_COLOR_FOG 1015 -#define IDC_FOG 1016 -#define IDC_SCROLL_3D_TRANS 1017 -#define IDC_POLY 1018 -#define IDC_3D_TRANS 1019 -#define IDC_LINES 1020 -#define IDC_SCROLL_CUBIC 1021 -#define IDC_CUBIC 1022 -#define IDC_CLIP 1023 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 133 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1011 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by PrtView.rc +// +#define IDD_ABOUT 129 +#define IDD_LOAD 130 +#define IDD_CONFIG 131 +#define IDC_LOAD_2D 1000 +#define IDC_LOAD_3D 1001 +#define IDC_LOAD_FILE_NAME 1002 +#define IDC_LOAD_OTHER 1003 +#define IDC_CONFIG_3D 1004 +#define IDC_CONFIG_2D 1005 +#define IDC_SCROLL_2D_WIDTH 1006 +#define IDC_2D_WIDTH 1007 +#define IDC_ANTI_ALIAS_2D 1008 +#define IDC_COLOR_2D 1009 +#define IDC_ZBUFFER 1010 +#define IDC_SCROLL_3D_WIDTH 1011 +#define IDC_3D_WIDTH 1012 +#define IDC_ANTI_ALIAS_3D 1013 +#define IDC_COLOR_3D 1014 +#define IDC_COLOR_FOG 1015 +#define IDC_FOG 1016 +#define IDC_SCROLL_3D_TRANS 1017 +#define IDC_POLY 1018 +#define IDC_3D_TRANS 1019 +#define IDC_LINES 1020 +#define IDC_SCROLL_CUBIC 1021 +#define IDC_CUBIC 1022 +#define IDC_CLIP 1023 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/prtview/stdafx.h b/contrib/prtview/stdafx.h index b4afbc8e..e251fa79 100644 --- a/contrib/prtview/stdafx.h +++ b/contrib/prtview/stdafx.h @@ -1,79 +1,79 @@ -/* -PrtView plugin for GtkRadiant -Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com - -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 -*/ - -#ifndef __PRTVIEW_AFX_H__ -#define __PRTVIEW_AFX_H__ - -#include - -#if defined(__linux__) || defined(__APPLE__) -#include - -// Necessary for proper boolean type declaration -#include "qertypes.h" - -typedef guint32 COLORREF; -typedef void* LPVOID; -typedef char* LPCSTR; -typedef void* HMODULE; -typedef int BOOL; - -#define RGB(r, g, b) ((guint32)(((guint8) (r) | ((guint16) (g) << 8))|(((guint32) (guint8) (b)) << 16))) -#define GetRValue(rgb) ((guint8)(rgb)) -#define GetGValue(rgb) ((guint8)(((guint16)(rgb)) >> 8)) -#define GetBValue(rgb) ((guint8)((rgb)>>16)) - -#define _MAX_PATH PATH_MAX - -#define IDOK 1 -#define IDCANCEL 2 - -#endif // __linux__ - -#include "synapse.h" - -// plugin -#include "iplugin.h" -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#include "ibspfrontend.h" -#include "igl.h" -#include "version.h" - -// PrtView -#include "gtkdlgs.h" -#include "prtview.h" -#include "portals.h" - -#define MSG_PREFIX "Portal Viewer plugin: " -#define PRTVIEW_MINOR "prtview" - -#define UPDATE_2D (W_XY | W_XZ | W_YZ) -#define UPDATE_3D (W_CAMERA) -#define UPDATE_ALL (UPDATE_2D | UPDATE_3D) - -int INIGetInt(char *key, int def); -void INISetInt(char *key, int val, char *comment = NULL); - -extern bool interfaces_started; - -extern _QERFuncTable_1 g_FuncTable; -extern _QERQglTable g_QglTable; - -#endif +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +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 +*/ + +#ifndef __PRTVIEW_AFX_H__ +#define __PRTVIEW_AFX_H__ + +#include + +#if defined(__linux__) || defined(__APPLE__) +#include + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +typedef guint32 COLORREF; +typedef void* LPVOID; +typedef char* LPCSTR; +typedef void* HMODULE; +typedef int BOOL; + +#define RGB(r, g, b) ((guint32)(((guint8) (r) | ((guint16) (g) << 8))|(((guint32) (guint8) (b)) << 16))) +#define GetRValue(rgb) ((guint8)(rgb)) +#define GetGValue(rgb) ((guint8)(((guint16)(rgb)) >> 8)) +#define GetBValue(rgb) ((guint8)((rgb)>>16)) + +#define _MAX_PATH PATH_MAX + +#define IDOK 1 +#define IDCANCEL 2 + +#endif // __linux__ + +#include "synapse.h" + +// plugin +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "ibspfrontend.h" +#include "igl.h" +#include "version.h" + +// PrtView +#include "gtkdlgs.h" +#include "prtview.h" +#include "portals.h" + +#define MSG_PREFIX "Portal Viewer plugin: " +#define PRTVIEW_MINOR "prtview" + +#define UPDATE_2D (W_XY | W_XZ | W_YZ) +#define UPDATE_3D (W_CAMERA) +#define UPDATE_ALL (UPDATE_2D | UPDATE_3D) + +int INIGetInt(char *key, int def); +void INISetInt(char *key, int val, char *comment = NULL); + +extern bool interfaces_started; + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; + +#endif diff --git a/docs/developer/XMLPush/StdAfx.h b/docs/developer/XMLPush/StdAfx.h index fbb8d5e2..628f0aba 100644 --- a/docs/developer/XMLPush/StdAfx.h +++ b/docs/developer/XMLPush/StdAfx.h @@ -1,22 +1,22 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#if !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) -#define AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_ - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - - -// TODO: reference additional headers your program requires here - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#endif // !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) - -#include "libxml/parser.h" -#include "libxml/tree.h" +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) +#define AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) + +#include "libxml/parser.h" +#include "libxml/tree.h" diff --git a/docs/manual/quake3/Compile_Manual/cfgq3.c b/docs/manual/quake3/Compile_Manual/cfgq3.c index b3694bef..47e43c80 100644 --- a/docs/manual/quake3/Compile_Manual/cfgq3.c +++ b/docs/manual/quake3/Compile_Manual/cfgq3.c @@ -1,78 +1,78 @@ -//=========================================================================== -// BSPC configuration file -// Quake3 -//=========================================================================== - -#define PRESENCE_NONE 1 -#define PRESENCE_NORMAL 2 -#define PRESENCE_CROUCH 4 - -// more bounding boxes can be added if required -// always minimize the number of bounding boxes listed here to reduce AAS file size -// for instance if players cannot crouch then it's good to remove the bbox definition for it - -//bounding box when running/walking -bbox //30x30x56 -{ - presencetype PRESENCE_NORMAL - flags 0x0000 - mins {-15, -15, -24} - maxs {15, 15, 32} -} - -// bounding box when crouched -bbox //30x30x40 -{ - presencetype PRESENCE_CROUCH - flags 0x0001 - mins {-15, -15, -24} - maxs {15, 15, 16} -} - -// do not forget settings as they might not be defaulted correctly when this cfg is used -settings -{ - // physics settings - phys_gravitydirection {0, 0, -1} // direction of gravity - phys_friction 6 // friction - phys_stopspeed 100 // stop speed - phys_gravity 800 // gravity - phys_waterfriction 1 // friction in water - phys_watergravity 400 // gravity in water - phys_maxvelocity 320 // maximum run speed - phys_maxwalkvelocity 320 // maximum walk speed (set for running) - phys_maxcrouchvelocity 100 // maximum crouch speed - phys_maxswimvelocity 150 // maximum swim speed - phys_walkaccelerate 100 // acceleration for walking - phys_airaccelerate 0 // acceleration flying through the air - phys_swimaccelerate 0 // acceleration for swimming - phys_maxstep 18 // maximum step height - phys_maxsteepness 0.7 // maximum floor steepness a player can walk on - phys_maxwaterjump 19 // maximum height for an out of water jump - phys_maxbarrier 33 // maximum barrier a player can jump onto - phys_jumpvel 270 // jump velocity - phys_falldelta5 40 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) - phys_falldelta10 60 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) - // reachability settings - // the following are all additional travel times added - // for certain reachabilities in 1/100th of a second - rs_waterjump 400 - rs_teleport 50 - rs_barrierjump 100 - rs_startcrouch 300 - rs_startgrapple 500 - rs_startwalkoffledge 70 - rs_startjump 300 - rs_rocketjump 500 - rs_bfgjump 500 - rs_jumppad 250 - rs_aircontrolledjumppad 300 - rs_funcbob 300 - rs_startelevator 50 - rs_falldamage5 300 // avoid getting 5 damage - rs_falldamage10 500 // avoid getting 10 damage - // if != 0 then this is the maximum fall height a reachability can be created for - rs_maxfallheight 0 - // maximum height a bot may fall down when jumping to some location - rs_maxjumpfallheight 450 -} +//=========================================================================== +// BSPC configuration file +// Quake3 +//=========================================================================== + +#define PRESENCE_NONE 1 +#define PRESENCE_NORMAL 2 +#define PRESENCE_CROUCH 4 + +// more bounding boxes can be added if required +// always minimize the number of bounding boxes listed here to reduce AAS file size +// for instance if players cannot crouch then it's good to remove the bbox definition for it + +//bounding box when running/walking +bbox //30x30x56 +{ + presencetype PRESENCE_NORMAL + flags 0x0000 + mins {-15, -15, -24} + maxs {15, 15, 32} +} + +// bounding box when crouched +bbox //30x30x40 +{ + presencetype PRESENCE_CROUCH + flags 0x0001 + mins {-15, -15, -24} + maxs {15, 15, 16} +} + +// do not forget settings as they might not be defaulted correctly when this cfg is used +settings +{ + // physics settings + phys_gravitydirection {0, 0, -1} // direction of gravity + phys_friction 6 // friction + phys_stopspeed 100 // stop speed + phys_gravity 800 // gravity + phys_waterfriction 1 // friction in water + phys_watergravity 400 // gravity in water + phys_maxvelocity 320 // maximum run speed + phys_maxwalkvelocity 320 // maximum walk speed (set for running) + phys_maxcrouchvelocity 100 // maximum crouch speed + phys_maxswimvelocity 150 // maximum swim speed + phys_walkaccelerate 100 // acceleration for walking + phys_airaccelerate 0 // acceleration flying through the air + phys_swimaccelerate 0 // acceleration for swimming + phys_maxstep 18 // maximum step height + phys_maxsteepness 0.7 // maximum floor steepness a player can walk on + phys_maxwaterjump 19 // maximum height for an out of water jump + phys_maxbarrier 33 // maximum barrier a player can jump onto + phys_jumpvel 270 // jump velocity + phys_falldelta5 40 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) + phys_falldelta10 60 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) + // reachability settings + // the following are all additional travel times added + // for certain reachabilities in 1/100th of a second + rs_waterjump 400 + rs_teleport 50 + rs_barrierjump 100 + rs_startcrouch 300 + rs_startgrapple 500 + rs_startwalkoffledge 70 + rs_startjump 300 + rs_rocketjump 500 + rs_bfgjump 500 + rs_jumppad 250 + rs_aircontrolledjumppad 300 + rs_funcbob 300 + rs_startelevator 50 + rs_falldamage5 300 // avoid getting 5 damage + rs_falldamage10 500 // avoid getting 10 damage + // if != 0 then this is the maximum fall height a reachability can be created for + rs_maxfallheight 0 + // maximum height a bot may fall down when jumping to some location + rs_maxjumpfallheight 450 +} diff --git a/include/aboutmsg.h b/include/aboutmsg.h index 213fe347..33748496 100644 --- a/include/aboutmsg.h +++ b/include/aboutmsg.h @@ -1,2 +1,2 @@ -// generated header, see makeversion.py -#define RADIANT_ABOUTMSG "ZeroRadiant build" +// generated header, see makeversion.py +#define RADIANT_ABOUTMSG "ZeroRadiant build" diff --git a/include/gtkr_list.h b/include/gtkr_list.h index 64ac1710..760f09f7 100644 --- a/include/gtkr_list.h +++ b/include/gtkr_list.h @@ -1,23 +1,23 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include "stl_check.h" +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "stl_check.h" diff --git a/include/gtkr_vector.h b/include/gtkr_vector.h index 3964be67..a070cf46 100644 --- a/include/gtkr_vector.h +++ b/include/gtkr_vector.h @@ -1,23 +1,23 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include -#include "stl_check.h" +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "stl_check.h" diff --git a/include/ibrush.h b/include/ibrush.h index 47eb7a81..e191ac26 100644 --- a/include/ibrush.h +++ b/include/ibrush.h @@ -1,73 +1,73 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _IBRUSH_H_ -#define _IBRUSH_H_ - -// -// API for brush stuff -// - -#define BRUSH_MAJOR "brush" -// {c1c3f567-2541-4aa3-9d5b-031fbe2a013b} -static const GUID QERBrushTable_GUID = -{ 0xc1c3f567, 0x2541, 0x4aa3, { 0x9d, 0x5b, 0x03, 0x1f, 0xbe, 0x2a, 0x01, 0x3b } }; - -typedef void (* PFN_BRUSHADDTOLIST) (brush_t *b, brush_t *lst); -typedef void (* PFN_BRUSHBUILD) (brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest); -typedef brush_t* (* PFN_BRUSHCREATE) (vec3_t mins, vec3_t maxs, texdef_t *texdef); -typedef void (* PFN_BRUSHFREE) (brush_t *b, bool bRemoveNode); -typedef void (* PFN_BRUSHROTATE) (brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild); -typedef brush_t* (* PFN_BRUSHALLOC) (); -typedef int (* PFN_BPMESSAGEBOX) (int); -typedef face_t* (* PFN_FACEALLOC) (void); -typedef eclass_t* (* PFN_HASMODEL) (brush_t *b); - -struct _QERBrushTable -{ - int m_nSize; - PFN_BRUSHADDTOLIST m_pfnBrush_AddToList; - PFN_BRUSHBUILD m_pfnBrush_Build; - PFN_BRUSHCREATE m_pfnBrush_Create; - PFN_BRUSHFREE m_pfnBrush_Free; - PFN_BRUSHROTATE m_pfnBrush_Rotate; - PFN_BRUSHALLOC m_pfnBrushAlloc; - PFN_BPMESSAGEBOX m_pfnBP_MessageBox; - PFN_FACEALLOC m_pfnFace_Alloc; - PFN_HASMODEL m_pfnHasModel; -}; - -#ifdef USE_BRUSHTABLE_DEFINE -#ifndef __BRUSHTABLENAME -#define __BRUSHTABLENAME g_BrushTable -#endif -#define Brush_AddToList __BRUSHTABLENAME.m_pfnBrush_AddToList -#define Brush_Build __BRUSHTABLENAME.m_pfnBrush_Build -#define Brush_Create __BRUSHTABLENAME.m_pfnBrush_Create -#define Brush_Free __BRUSHTABLENAME.m_pfnBrush_Free -#define Brush_Rotate __BRUSHTABLENAME.m_pfnBrush_Rotate -#define Brush_Alloc __BRUSHTABLENAME.m_pfnBrushAlloc -#define BP_MessageBox __BRUSHTABLENAME.m_pfnBP_MessageBox -#define Face_Alloc __BRUSHTABLENAME.m_pfnFace_Alloc -#define HasModel __BRUSHTABLENAME.m_pfnHasModel -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IBRUSH_H_ +#define _IBRUSH_H_ + +// +// API for brush stuff +// + +#define BRUSH_MAJOR "brush" +// {c1c3f567-2541-4aa3-9d5b-031fbe2a013b} +static const GUID QERBrushTable_GUID = +{ 0xc1c3f567, 0x2541, 0x4aa3, { 0x9d, 0x5b, 0x03, 0x1f, 0xbe, 0x2a, 0x01, 0x3b } }; + +typedef void (* PFN_BRUSHADDTOLIST) (brush_t *b, brush_t *lst); +typedef void (* PFN_BRUSHBUILD) (brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest); +typedef brush_t* (* PFN_BRUSHCREATE) (vec3_t mins, vec3_t maxs, texdef_t *texdef); +typedef void (* PFN_BRUSHFREE) (brush_t *b, bool bRemoveNode); +typedef void (* PFN_BRUSHROTATE) (brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild); +typedef brush_t* (* PFN_BRUSHALLOC) (); +typedef int (* PFN_BPMESSAGEBOX) (int); +typedef face_t* (* PFN_FACEALLOC) (void); +typedef eclass_t* (* PFN_HASMODEL) (brush_t *b); + +struct _QERBrushTable +{ + int m_nSize; + PFN_BRUSHADDTOLIST m_pfnBrush_AddToList; + PFN_BRUSHBUILD m_pfnBrush_Build; + PFN_BRUSHCREATE m_pfnBrush_Create; + PFN_BRUSHFREE m_pfnBrush_Free; + PFN_BRUSHROTATE m_pfnBrush_Rotate; + PFN_BRUSHALLOC m_pfnBrushAlloc; + PFN_BPMESSAGEBOX m_pfnBP_MessageBox; + PFN_FACEALLOC m_pfnFace_Alloc; + PFN_HASMODEL m_pfnHasModel; +}; + +#ifdef USE_BRUSHTABLE_DEFINE +#ifndef __BRUSHTABLENAME +#define __BRUSHTABLENAME g_BrushTable +#endif +#define Brush_AddToList __BRUSHTABLENAME.m_pfnBrush_AddToList +#define Brush_Build __BRUSHTABLENAME.m_pfnBrush_Build +#define Brush_Create __BRUSHTABLENAME.m_pfnBrush_Create +#define Brush_Free __BRUSHTABLENAME.m_pfnBrush_Free +#define Brush_Rotate __BRUSHTABLENAME.m_pfnBrush_Rotate +#define Brush_Alloc __BRUSHTABLENAME.m_pfnBrushAlloc +#define BP_MessageBox __BRUSHTABLENAME.m_pfnBP_MessageBox +#define Face_Alloc __BRUSHTABLENAME.m_pfnFace_Alloc +#define HasModel __BRUSHTABLENAME.m_pfnHasModel +#endif + +#endif diff --git a/include/ibspfrontend.h b/include/ibspfrontend.h index c00217fb..973f0633 100644 --- a/include/ibspfrontend.h +++ b/include/ibspfrontend.h @@ -1,77 +1,77 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// interface for BSP frontends plugins -// - -// DONE: - change BSP menu to Q3Build menu ? -// DONE: - detect when Q3Build dies ? -// DELAYED: - hotkeys ! -// SUCCESS: - try again getting feedback from Q3Build - -#ifndef __IBSPFRONTEND_H_ -#define __IBSPFRONTEND_H_ - -// define a GUID for this interface so plugins can access and reference it -// {8ED6A480-BA5E-11d3-A3E3-0004AC96D4C3} -static const GUID QERPlugBSPFrontendTable_GUID = -{ 0x8ed6a480, 0xba5e, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - -// ask the plugin about the items to show up in the BSP menu -typedef char * (WINAPI* PFN_GETBSPMENU) (); -// dispatch a BSP menu command -typedef void (WINAPI* PFN_DISPATCHBSPCOMMAND) (char *); -// this one gets called after a monitoring loop ends -// 0: all good -// 1: timed out / Radiant didn't get the connection -// 2: got a connection, compilation ended with an error -typedef void (WINAPI* PFN_ENDLISTEN) (int status); - -struct _QERPlugBSPFrontendTable -{ - int m_nSize; - PFN_GETBSPMENU m_pfnGetBSPMenu; - PFN_DISPATCHBSPCOMMAND m_pfnDispatchBSPCommand; - PFN_ENDLISTEN m_pfnEndListen; -}; - -// interface provided by Radiant to the plugin -// {A2CCF366-BA60-11d3-A3E3-0004AC96D4C3} -static const GUID QERAppBSPFrontendTable_GUID = -{ 0xa2ccf366, 0xba60, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - -typedef char * (WINAPI* PFN_GETMAPNAME) (); -typedef void (WINAPI* PFN_LISTEN) (); -typedef void (WINAPI* PFN_SLEEP) (); - -struct _QERAppBSPFrontendTable -{ - int m_nSize; - PFN_GETMAPNAME m_pfnGetMapName; - PFN_LISTEN m_pfnListen; - PFN_SLEEP m_pfnSleep; - //++timo TODO: needs a hook to reset the debug window (in regular mode it's done at startup of the BSP operation) -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// interface for BSP frontends plugins +// + +// DONE: - change BSP menu to Q3Build menu ? +// DONE: - detect when Q3Build dies ? +// DELAYED: - hotkeys ! +// SUCCESS: - try again getting feedback from Q3Build + +#ifndef __IBSPFRONTEND_H_ +#define __IBSPFRONTEND_H_ + +// define a GUID for this interface so plugins can access and reference it +// {8ED6A480-BA5E-11d3-A3E3-0004AC96D4C3} +static const GUID QERPlugBSPFrontendTable_GUID = +{ 0x8ed6a480, 0xba5e, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +// ask the plugin about the items to show up in the BSP menu +typedef char * (WINAPI* PFN_GETBSPMENU) (); +// dispatch a BSP menu command +typedef void (WINAPI* PFN_DISPATCHBSPCOMMAND) (char *); +// this one gets called after a monitoring loop ends +// 0: all good +// 1: timed out / Radiant didn't get the connection +// 2: got a connection, compilation ended with an error +typedef void (WINAPI* PFN_ENDLISTEN) (int status); + +struct _QERPlugBSPFrontendTable +{ + int m_nSize; + PFN_GETBSPMENU m_pfnGetBSPMenu; + PFN_DISPATCHBSPCOMMAND m_pfnDispatchBSPCommand; + PFN_ENDLISTEN m_pfnEndListen; +}; + +// interface provided by Radiant to the plugin +// {A2CCF366-BA60-11d3-A3E3-0004AC96D4C3} +static const GUID QERAppBSPFrontendTable_GUID = +{ 0xa2ccf366, 0xba60, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +typedef char * (WINAPI* PFN_GETMAPNAME) (); +typedef void (WINAPI* PFN_LISTEN) (); +typedef void (WINAPI* PFN_SLEEP) (); + +struct _QERAppBSPFrontendTable +{ + int m_nSize; + PFN_GETMAPNAME m_pfnGetMapName; + PFN_LISTEN m_pfnListen; + PFN_SLEEP m_pfnSleep; + //++timo TODO: needs a hook to reset the debug window (in regular mode it's done at startup of the BSP operation) +}; + +#endif diff --git a/include/icamera.h b/include/icamera.h index 22faf0fe..07425ec4 100644 --- a/include/icamera.h +++ b/include/icamera.h @@ -1,45 +1,45 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// camera interface -// - -#ifndef __ICAMERA_H_ -#define __ICAMERA_H_ - -#define CAMERA_MAJOR "camera" - -typedef void (* PFN_GETCAMERA) ( vec3_t origin, vec3_t angles ); -typedef void (* PFN_SETCAMERA) ( vec3_t origin, vec3_t angles ); -typedef void (* PFN_GETCAMWINDOWEXTENTS) ( int *x, int *y, int *width, int *height ); - -struct _QERCameraTable -{ - int m_nSize; - PFN_GETCAMERA m_pfnGetCamera; - PFN_SETCAMERA m_pfnSetCamera; - PFN_GETCAMWINDOWEXTENTS m_pfnGetCamWindowExtents; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// camera interface +// + +#ifndef __ICAMERA_H_ +#define __ICAMERA_H_ + +#define CAMERA_MAJOR "camera" + +typedef void (* PFN_GETCAMERA) ( vec3_t origin, vec3_t angles ); +typedef void (* PFN_SETCAMERA) ( vec3_t origin, vec3_t angles ); +typedef void (* PFN_GETCAMWINDOWEXTENTS) ( int *x, int *y, int *width, int *height ); + +struct _QERCameraTable +{ + int m_nSize; + PFN_GETCAMERA m_pfnGetCamera; + PFN_SETCAMERA m_pfnSetCamera; + PFN_GETCAMWINDOWEXTENTS m_pfnGetCamWindowExtents; +}; + +#endif diff --git a/include/idata.h b/include/idata.h index eb39cfa9..fe453366 100644 --- a/include/idata.h +++ b/include/idata.h @@ -1,57 +1,57 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// interface table to access low-level data inside Radiant (brushes, patches and generic editing primitives) - -#ifndef __IDATA_H_ -#define __IDATA_H_ - -// FIXME TTimo this should probably go away and be replaced by a more flat structure -// having to write access functions for every single var is a big annoyance -// see IMapData_t, generalize it? - -#define DATA_MAJOR "data" -// FIXME: remove -// define a GUID for this interface so plugins can access and reference it -// {608A9870-BCE7-11d4-A454-0004AC96D4C3} -static const GUID QERAppDataTable_GUID = -{ 0x608a9870, 0xbce7, 0x11d4, { 0xa4, 0x54, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - - -// pointers to active_brushes, selected_brushes and filtered_brushes -typedef brush_t* (WINAPI* PFN_ACTIVEBRUSHES) (); -typedef brush_t* (WINAPI* PFN_SELECTEDBRUSHES) (); -typedef brush_t* (WINAPI* PFN_FILTEREDBRUSHES) (); -typedef CPtrArray* (WINAPI* PFN_LSTSKINCACHE) (); - -struct _QERAppDataTable -{ - int m_nSize; - PFN_ACTIVEBRUSHES m_pfnActiveBrushes; - PFN_SELECTEDBRUSHES m_pfnSelectedBrushes; - PFN_FILTEREDBRUSHES m_pfnFilteredBrushes; - PFN_LSTSKINCACHE m_pfnLstSkinCache; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// interface table to access low-level data inside Radiant (brushes, patches and generic editing primitives) + +#ifndef __IDATA_H_ +#define __IDATA_H_ + +// FIXME TTimo this should probably go away and be replaced by a more flat structure +// having to write access functions for every single var is a big annoyance +// see IMapData_t, generalize it? + +#define DATA_MAJOR "data" +// FIXME: remove +// define a GUID for this interface so plugins can access and reference it +// {608A9870-BCE7-11d4-A454-0004AC96D4C3} +static const GUID QERAppDataTable_GUID = +{ 0x608a9870, 0xbce7, 0x11d4, { 0xa4, 0x54, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + + +// pointers to active_brushes, selected_brushes and filtered_brushes +typedef brush_t* (WINAPI* PFN_ACTIVEBRUSHES) (); +typedef brush_t* (WINAPI* PFN_SELECTEDBRUSHES) (); +typedef brush_t* (WINAPI* PFN_FILTEREDBRUSHES) (); +typedef CPtrArray* (WINAPI* PFN_LSTSKINCACHE) (); + +struct _QERAppDataTable +{ + int m_nSize; + PFN_ACTIVEBRUSHES m_pfnActiveBrushes; + PFN_SELECTEDBRUSHES m_pfnSelectedBrushes; + PFN_FILTEREDBRUSHES m_pfnFilteredBrushes; + PFN_LSTSKINCACHE m_pfnLstSkinCache; +}; + +#endif diff --git a/include/idatastream.h b/include/idatastream.h index 8f6b0b8c..19534aa4 100644 --- a/include/idatastream.h +++ b/include/idatastream.h @@ -1,71 +1,71 @@ -/* -Copyright (c) 2001, Loki software, inc. -modifications (c) 2001, Id software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _ISTREAM_H_ -#define _ISTREAM_H_ - -/*! -API for data streams - -Based on an initial implementation by Loki software -modified to be abstracted and shared across modules - -NOTE: why IDataStream and not IStream? because IStream is defined in windows IDL headers -*/ - -class IDataStream -{ -public: - IDataStream(); - virtual ~IDataStream(); - - virtual void IncRef () = 0; ///< Increment the number of references to this object - virtual void DecRef () = 0; ///< Decrement the reference count - - virtual unsigned long GetPosition() const = 0; - virtual unsigned long Seek(long lOff, int nFrom) = 0; - virtual void SetLength(unsigned long nNewLen) = 0; - virtual unsigned long GetLength() const = 0; - - virtual char* ReadString(char* pBuf, unsigned long nMax)=0; - virtual unsigned long Read(void* pBuf, unsigned long nCount)=0; - virtual unsigned long Write(const void* pBuf, unsigned long nCount)=0; - virtual int GetChar()=0; - virtual int PutChar(int c)=0; - - virtual void printf(const char*, ...) = 0; ///< completely matches the usual printf behaviour - - virtual void Abort()=0; - virtual void Flush()=0; - virtual void Close()=0; -}; - -#endif // _ISTREAM_H_ +/* +Copyright (c) 2001, Loki software, inc. +modifications (c) 2001, Id software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _ISTREAM_H_ +#define _ISTREAM_H_ + +/*! +API for data streams + +Based on an initial implementation by Loki software +modified to be abstracted and shared across modules + +NOTE: why IDataStream and not IStream? because IStream is defined in windows IDL headers +*/ + +class IDataStream +{ +public: + IDataStream(); + virtual ~IDataStream(); + + virtual void IncRef () = 0; ///< Increment the number of references to this object + virtual void DecRef () = 0; ///< Decrement the reference count + + virtual unsigned long GetPosition() const = 0; + virtual unsigned long Seek(long lOff, int nFrom) = 0; + virtual void SetLength(unsigned long nNewLen) = 0; + virtual unsigned long GetLength() const = 0; + + virtual char* ReadString(char* pBuf, unsigned long nMax)=0; + virtual unsigned long Read(void* pBuf, unsigned long nCount)=0; + virtual unsigned long Write(const void* pBuf, unsigned long nCount)=0; + virtual int GetChar()=0; + virtual int PutChar(int c)=0; + + virtual void printf(const char*, ...) = 0; ///< completely matches the usual printf behaviour + + virtual void Abort()=0; + virtual void Flush()=0; + virtual void Close()=0; +}; + +#endif // _ISTREAM_H_ diff --git a/include/ieclass.h b/include/ieclass.h index bfca1d60..cb32647c 100644 --- a/include/ieclass.h +++ b/include/ieclass.h @@ -1,84 +1,84 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/*! \file ieclass.h - \brief entity files loader API - this describes the APIs involved when loading entity description files - (initially, .def and .fgd) -*/ - -#ifndef _IECLASS_H_ -#define _IECLASS_H_ - -#define ECLASS_MAJOR "eclass" - -typedef void (* PFN_ECLASS_SCANFILE) (char *filename); -typedef const char* (* PFN_ECLASS_GETEXTENSION) (); - -struct _EClassTable -{ - int m_nSize; - PFN_ECLASS_SCANFILE m_pfnScanFile; - PFN_ECLASS_GETEXTENSION m_pfnGetExtension; -}; - -#ifdef USE_ECLASSTABLE_DEFINE -#ifndef __ECLASSTABLENAME -#define __ECLASSTABLENAME g_EClassTable -#endif -#define EClass_ScanFile __ECLASSTABLENAME.m_pfnEClass_ScanFile -#define EClass_GetExtension __ECLASSTABLENAME.m_pfnEClass_GetExtension -#endif - -#define ECLASSMANAGER_MAJOR "eclassmanager" - -typedef void (* PFN_ECLASS_INSERTALPHABETIZED) (eclass_t *e); -typedef eclass_t** (* PFN_GET_ECLASS_E) (); -typedef void (* PFN_SET_ECLASS_FOUND) (qboolean); -typedef qboolean (* PFN_GET_PARSING_SINGLE) (); -typedef eclass_t* (* PFN_ECLASS_CREATE) (const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments); -typedef eclass_t* (* PFN_ECLASS_FORNAME) (const char* name, qboolean has_brushes); - -struct _EClassManagerTable -{ - int m_nSize; - PFN_ECLASS_INSERTALPHABETIZED m_pfnEclass_InsertAlphabetized; - PFN_GET_ECLASS_E m_pfnGet_Eclass_E; - PFN_SET_ECLASS_FOUND m_pfnSet_Eclass_Found; - PFN_GET_PARSING_SINGLE m_pfnGet_Parsing_Single; - PFN_ECLASS_CREATE m_pfnEClass_Create; - PFN_ECLASS_FORNAME m_pfnEclass_ForName; -}; - -#ifdef USE_ECLASSMANAGER_DEFINE -#ifndef __ECLASSMANAGERTABLENAME -#define __ECLASSMANAGERTABLENAME g_EClassManagerTable -#endif -#define Eclass_InsertAlphabetized __ECLASSMANAGERTABLENAME.m_pfnEclass_InsertAlphabetized -#define Get_Eclass_E __ECLASSMANAGERTABLENAME.m_pfnGet_Eclass_E -#define Set_Eclass_Found __ECLASSMANAGERTABLENAME.m_pfnSet_Eclass_Found -#define Get_Parsing_Single __ECLASSMANAGERTABLENAME.m_pfnGet_Parsing_Single -#define EClass_Create __ECLASSMANAGERTABLENAME.m_pfnEClass_Create -#define Eclass_ForName __ECLASSMANAGERTABLENAME.m_pfnEclass_ForName -#endif - -#endif - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/*! \file ieclass.h + \brief entity files loader API + this describes the APIs involved when loading entity description files + (initially, .def and .fgd) +*/ + +#ifndef _IECLASS_H_ +#define _IECLASS_H_ + +#define ECLASS_MAJOR "eclass" + +typedef void (* PFN_ECLASS_SCANFILE) (char *filename); +typedef const char* (* PFN_ECLASS_GETEXTENSION) (); + +struct _EClassTable +{ + int m_nSize; + PFN_ECLASS_SCANFILE m_pfnScanFile; + PFN_ECLASS_GETEXTENSION m_pfnGetExtension; +}; + +#ifdef USE_ECLASSTABLE_DEFINE +#ifndef __ECLASSTABLENAME +#define __ECLASSTABLENAME g_EClassTable +#endif +#define EClass_ScanFile __ECLASSTABLENAME.m_pfnEClass_ScanFile +#define EClass_GetExtension __ECLASSTABLENAME.m_pfnEClass_GetExtension +#endif + +#define ECLASSMANAGER_MAJOR "eclassmanager" + +typedef void (* PFN_ECLASS_INSERTALPHABETIZED) (eclass_t *e); +typedef eclass_t** (* PFN_GET_ECLASS_E) (); +typedef void (* PFN_SET_ECLASS_FOUND) (qboolean); +typedef qboolean (* PFN_GET_PARSING_SINGLE) (); +typedef eclass_t* (* PFN_ECLASS_CREATE) (const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments); +typedef eclass_t* (* PFN_ECLASS_FORNAME) (const char* name, qboolean has_brushes); + +struct _EClassManagerTable +{ + int m_nSize; + PFN_ECLASS_INSERTALPHABETIZED m_pfnEclass_InsertAlphabetized; + PFN_GET_ECLASS_E m_pfnGet_Eclass_E; + PFN_SET_ECLASS_FOUND m_pfnSet_Eclass_Found; + PFN_GET_PARSING_SINGLE m_pfnGet_Parsing_Single; + PFN_ECLASS_CREATE m_pfnEClass_Create; + PFN_ECLASS_FORNAME m_pfnEclass_ForName; +}; + +#ifdef USE_ECLASSMANAGER_DEFINE +#ifndef __ECLASSMANAGERTABLENAME +#define __ECLASSMANAGERTABLENAME g_EClassManagerTable +#endif +#define Eclass_InsertAlphabetized __ECLASSMANAGERTABLENAME.m_pfnEclass_InsertAlphabetized +#define Get_Eclass_E __ECLASSMANAGERTABLENAME.m_pfnGet_Eclass_E +#define Set_Eclass_Found __ECLASSMANAGERTABLENAME.m_pfnSet_Eclass_Found +#define Get_Parsing_Single __ECLASSMANAGERTABLENAME.m_pfnGet_Parsing_Single +#define EClass_Create __ECLASSMANAGERTABLENAME.m_pfnEClass_Create +#define Eclass_ForName __ECLASSMANAGERTABLENAME.m_pfnEclass_ForName +#endif + +#endif + diff --git a/include/ientity.h b/include/ientity.h index 51ca389f..015cf1ec 100644 --- a/include/ientity.h +++ b/include/ientity.h @@ -1,116 +1,116 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _IENTITY_H_ -#define _IENTITY_H_ - -// -// API for entity manip stuff -// - -// FIXME TTimo this prolly needs to merge with iepairs.h? - -/*! -SPoG -generic "entity" module... -at first, there will only be one implementation for all entities, -perhaps later there will be one for each entity type? -it would probably make more sense to have a single implementation, -a generic one that is very flexible and can adapt the visualisation of -itself depending on an xml config specified in the entity definitions file -*/ -#define ENTITY_MAJOR "entity" -// {A1C9F9FD-75D5-4e4d-9D65-235D6D3F254C} -static const GUID QEREntityTable_GUID = -{ 0xa1c9f9fd, 0x75d5, 0x4e4d, { 0x9d, 0x65, 0x23, 0x5d, 0x6d, 0x3f, 0x25, 0x4c } }; - -typedef entity_t* (* PFN_ENTITYALLOC) (); -typedef void (* PFN_ENTITYFREE) (entity_t *e); -typedef entity_t* (* PFN_ENTITYCREATE) (eclass_t *c); -typedef entity_t* (* PFN_ENTITYCLONE) (entity_t *e); -typedef void (* PFN_ENTITYSETKEYVALUE) (entity_t *ent, const char *key, const char *value); -typedef void (* PFN_ENTITYDELETEKEY) (entity_t *ent, const char *key); -typedef const char* (* PFN_ENTITYVALUEFORKEY) (entity_t *ent, const char *key); -typedef float (* PFN_ENTITYFLOATFORKEY) (entity_t *ent, const char *key); -typedef int (* PFN_ENTITYINTFORKEY) (entity_t *ent, const char *key); -typedef void (* PFN_ENTITYVECTORFORKEY) (entity_t *ent, const char *key, vec3_t vec); -typedef void (* PFN_ENTITYADDTOLIST) (entity_t *e, entity_t *lst); -typedef void (* PFN_ENTITYREMOVEFROMLIST) (entity_t *e); -typedef void (* PFN_ENTITYLINKBRUSH) (entity_t *e, brush_t *b); -typedef void (* PFN_ENTITYUNLINKBRUSH) (brush_t *b); -typedef void (* PFN_ENTITYDRAWLIGHT) (entity_t* e, int nGLState, int pref, int nViewType); -typedef int (* PFN_ENTITYMEMORYSIZE) (entity_t *e); -typedef void (* PFN_ENTITYUPDATEMODEL) (entity_t *e); -typedef epair_t* (* PFN_ALLOCATEEPAIR) (const char *key, const char *value); -typedef epair_t** (* PFN_GETENTITYKEYVALLIST) (entity_t *e); -typedef void (* PFN_SETENTITYKEYVALLIST) (entity_t *e, epair_t* ep); - - -struct _QEREntityTable -{ - int m_nSize; - PFN_ENTITYALLOC m_pfnEntity_Alloc; - PFN_ENTITYFREE m_pfnEntity_Free; - PFN_ENTITYCREATE m_pfnEntity_Create; - PFN_ENTITYCLONE m_pfnEntity_Clone; - PFN_ENTITYSETKEYVALUE m_pfnSetKeyValue; - PFN_ENTITYDELETEKEY m_pfnDeleteKey; - PFN_ENTITYVALUEFORKEY m_pfnValueForKey; - PFN_ENTITYFLOATFORKEY m_pfnFloatForKey; - PFN_ENTITYINTFORKEY m_pfnIntForKey; - PFN_ENTITYVECTORFORKEY m_pfnGetVectorForKey; - PFN_ENTITYADDTOLIST m_pfnEntity_AddToList; - PFN_ENTITYREMOVEFROMLIST m_pfnEntity_RemoveFromList; - PFN_ENTITYLINKBRUSH m_pfnEntity_LinkBrush; - PFN_ENTITYUNLINKBRUSH m_pfnEntity_UnlinkBrush; - PFN_ENTITYDRAWLIGHT m_pfnDrawLight; - PFN_ENTITYMEMORYSIZE m_pfnEntity_MemorySize; - PFN_ALLOCATEEPAIR m_pfnAllocateEpair; - PFN_GETENTITYKEYVALLIST m_pfnGetEntityKeyValList; - PFN_SETENTITYKEYVALLIST m_pfnSetEntityKeyValList; -}; - -#ifdef USE_ENTITYTABLE_DEFINE -#ifndef __ENTITYTABLENAME -#define __ENTITYTABLENAME g_EntityTable -#endif -#define Entity_Alloc __ENTITYTABLENAME.m_pfnEntity_Alloc -#define Entity_Free __ENTITYTABLENAME.m_pfnEntity_Free -#define Entity_Clone __ENTITYTABLENAME.m_pfnEntity_Clone -#define SetKeyValue __ENTITYTABLENAME.m_pfnSetKeyValue -#define DeleteKey __ENTITYTABLENAME.m_pfnDeleteKey -#define ValueForKey __ENTITYTABLENAME.m_pfnValueForKey -#define FloatForKey __ENTITYTABLENAME.m_pfnFloatForKey -#define IntForKey __ENTITYTABLENAME.m_pfnIntForKey -#define GetVectorForKey __ENTITYTABLENAME.m_pfnGetVectorForKey -#define Entity_AddToList __ENTITYTABLENAME.m_pfnEntity_AddToList -#define Entity_RemoveFromList __ENTITYTABLENAME.m_pfnEntity_RemoveFromList -#define Entity_LinkBrush __ENTITYTABLENAME.m_pfnEntity_LinkBrush -#define Entity_UnlinkBrush __ENTITYTABLENAME.m_pfnEntity_UnlinkBrush -#define DrawLight __ENTITYTABLENAME.m_pfnDrawLight -#define Entity_MemorySize __ENTITYTABLENAME.m_pfnEntity_MemorySize -#define Entity_AllocateEpair __ENTITYTABLENAME.m_pfnAllocateEpair -#define Entity_GetKeyValList __ENTITYTABLENAME.m_pfnGetEntityKeyValList -#define Entity_SetKeyValList __ENTITYTABLENAME.m_pfnSetEntityKeyValList -#endif - -#endif - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IENTITY_H_ +#define _IENTITY_H_ + +// +// API for entity manip stuff +// + +// FIXME TTimo this prolly needs to merge with iepairs.h? + +/*! +SPoG +generic "entity" module... +at first, there will only be one implementation for all entities, +perhaps later there will be one for each entity type? +it would probably make more sense to have a single implementation, +a generic one that is very flexible and can adapt the visualisation of +itself depending on an xml config specified in the entity definitions file +*/ +#define ENTITY_MAJOR "entity" +// {A1C9F9FD-75D5-4e4d-9D65-235D6D3F254C} +static const GUID QEREntityTable_GUID = +{ 0xa1c9f9fd, 0x75d5, 0x4e4d, { 0x9d, 0x65, 0x23, 0x5d, 0x6d, 0x3f, 0x25, 0x4c } }; + +typedef entity_t* (* PFN_ENTITYALLOC) (); +typedef void (* PFN_ENTITYFREE) (entity_t *e); +typedef entity_t* (* PFN_ENTITYCREATE) (eclass_t *c); +typedef entity_t* (* PFN_ENTITYCLONE) (entity_t *e); +typedef void (* PFN_ENTITYSETKEYVALUE) (entity_t *ent, const char *key, const char *value); +typedef void (* PFN_ENTITYDELETEKEY) (entity_t *ent, const char *key); +typedef const char* (* PFN_ENTITYVALUEFORKEY) (entity_t *ent, const char *key); +typedef float (* PFN_ENTITYFLOATFORKEY) (entity_t *ent, const char *key); +typedef int (* PFN_ENTITYINTFORKEY) (entity_t *ent, const char *key); +typedef void (* PFN_ENTITYVECTORFORKEY) (entity_t *ent, const char *key, vec3_t vec); +typedef void (* PFN_ENTITYADDTOLIST) (entity_t *e, entity_t *lst); +typedef void (* PFN_ENTITYREMOVEFROMLIST) (entity_t *e); +typedef void (* PFN_ENTITYLINKBRUSH) (entity_t *e, brush_t *b); +typedef void (* PFN_ENTITYUNLINKBRUSH) (brush_t *b); +typedef void (* PFN_ENTITYDRAWLIGHT) (entity_t* e, int nGLState, int pref, int nViewType); +typedef int (* PFN_ENTITYMEMORYSIZE) (entity_t *e); +typedef void (* PFN_ENTITYUPDATEMODEL) (entity_t *e); +typedef epair_t* (* PFN_ALLOCATEEPAIR) (const char *key, const char *value); +typedef epair_t** (* PFN_GETENTITYKEYVALLIST) (entity_t *e); +typedef void (* PFN_SETENTITYKEYVALLIST) (entity_t *e, epair_t* ep); + + +struct _QEREntityTable +{ + int m_nSize; + PFN_ENTITYALLOC m_pfnEntity_Alloc; + PFN_ENTITYFREE m_pfnEntity_Free; + PFN_ENTITYCREATE m_pfnEntity_Create; + PFN_ENTITYCLONE m_pfnEntity_Clone; + PFN_ENTITYSETKEYVALUE m_pfnSetKeyValue; + PFN_ENTITYDELETEKEY m_pfnDeleteKey; + PFN_ENTITYVALUEFORKEY m_pfnValueForKey; + PFN_ENTITYFLOATFORKEY m_pfnFloatForKey; + PFN_ENTITYINTFORKEY m_pfnIntForKey; + PFN_ENTITYVECTORFORKEY m_pfnGetVectorForKey; + PFN_ENTITYADDTOLIST m_pfnEntity_AddToList; + PFN_ENTITYREMOVEFROMLIST m_pfnEntity_RemoveFromList; + PFN_ENTITYLINKBRUSH m_pfnEntity_LinkBrush; + PFN_ENTITYUNLINKBRUSH m_pfnEntity_UnlinkBrush; + PFN_ENTITYDRAWLIGHT m_pfnDrawLight; + PFN_ENTITYMEMORYSIZE m_pfnEntity_MemorySize; + PFN_ALLOCATEEPAIR m_pfnAllocateEpair; + PFN_GETENTITYKEYVALLIST m_pfnGetEntityKeyValList; + PFN_SETENTITYKEYVALLIST m_pfnSetEntityKeyValList; +}; + +#ifdef USE_ENTITYTABLE_DEFINE +#ifndef __ENTITYTABLENAME +#define __ENTITYTABLENAME g_EntityTable +#endif +#define Entity_Alloc __ENTITYTABLENAME.m_pfnEntity_Alloc +#define Entity_Free __ENTITYTABLENAME.m_pfnEntity_Free +#define Entity_Clone __ENTITYTABLENAME.m_pfnEntity_Clone +#define SetKeyValue __ENTITYTABLENAME.m_pfnSetKeyValue +#define DeleteKey __ENTITYTABLENAME.m_pfnDeleteKey +#define ValueForKey __ENTITYTABLENAME.m_pfnValueForKey +#define FloatForKey __ENTITYTABLENAME.m_pfnFloatForKey +#define IntForKey __ENTITYTABLENAME.m_pfnIntForKey +#define GetVectorForKey __ENTITYTABLENAME.m_pfnGetVectorForKey +#define Entity_AddToList __ENTITYTABLENAME.m_pfnEntity_AddToList +#define Entity_RemoveFromList __ENTITYTABLENAME.m_pfnEntity_RemoveFromList +#define Entity_LinkBrush __ENTITYTABLENAME.m_pfnEntity_LinkBrush +#define Entity_UnlinkBrush __ENTITYTABLENAME.m_pfnEntity_UnlinkBrush +#define DrawLight __ENTITYTABLENAME.m_pfnDrawLight +#define Entity_MemorySize __ENTITYTABLENAME.m_pfnEntity_MemorySize +#define Entity_AllocateEpair __ENTITYTABLENAME.m_pfnAllocateEpair +#define Entity_GetKeyValList __ENTITYTABLENAME.m_pfnGetEntityKeyValList +#define Entity_SetKeyValList __ENTITYTABLENAME.m_pfnSetEntityKeyValList +#endif + +#endif + diff --git a/include/ifilesystem.h b/include/ifilesystem.h index 8a9a2006..e9c3e725 100644 --- a/include/ifilesystem.h +++ b/include/ifilesystem.h @@ -1,140 +1,140 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _IFILESYSTEM_H_ -#define _IFILESYSTEM_H_ - -// -// Plugin interface for the virtual filesystem used by Radiant -// - -// NOTE: If you want to write a VFS plugin then you must export -// "QERPlug_ListInterfaces" and "QERPlug_RequestInterface" -// (see qerplugin.h for more information) - -#ifdef _WIN32 -#define VFS_NATIVESEPARATOR '\\' -#else -#define VFS_NATIVESEPARATOR '/' -#endif - -#define VFS_MAJOR "VFS" - -// return the file system supported by the plugin, for example: "quake1" or "quake3" -//typedef const char* (WINAPI* PFN_VFSGETFORMAT) (); -// add all files from a directory to the vfs -typedef void (* PFN_VFSINITDIRECTORY) (const char *path); -// free all resources used by the plugin -typedef void (* PFN_VFSSHUTDOWN) (); -// free memory allocated by VFS for this pointer -typedef void (* PFN_VFSFREEFILE) (void *p); -// return a GSList with all the directories under basedir -typedef GSList* (* PFN_VFSGETDIRLIST) (const char *basedir); -// return a GSList with all the files under basedir (extension can be NULL) -typedef GSList* (* PFN_VFSGETFILELIST) (const char *basedir, const char *extension); -// free a dirlist or filelist returned from one of the above functions -typedef void (* PFN_VFSCLEARFILEDIRLIST) (GSList **lst); -#define VFS_SEARCH_PAK 0x1 -#define VFS_SEARCH_DIR 0x2 -/*! -\brief return the number of files with the exact name described in filename -there can be several hits for a given file, or this can be used to check for existence -\param flags is optional and can be used with VFS_SEARCH_* bits, if flag is 0, everything is searched, else only the specified bits -paks are searched first, then search directories -*/ -typedef int (* PFN_VFSGETFILECOUNT) (const char *filename, int flags); -/*! -\brief load file, allocate buffer -\return -1 if fails or the size of the buffer allocated -\param index is used to load the i-th file in the search directories (see vfsGetFileCount) -this will scan in the search directories first, then it will search in the pak files -WARNING: the allocated buffer must be freed with a g_free call -NOTE TTimo: the g_free release is utter horror - see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 -*/ -typedef int (* PFN_VFSLOADFILE) (const char *filename, void **buffer, int index); -// load a file from it's full path into the buffer, returns the file size or -1 -// the allocated buffer must be freed with a g_free call -typedef int (* PFN_VFSLOADFULLPATHFILE) (const char *filename, void **buffer); -// takes an absolute file path, returns a shortened relative file path if the absolute path matches a valid basedir or NULL if an error occured -typedef char* (* PFN_VFSEXTRACTRELATIVEPATH) (const char *in); -/*! -\return the full path (in a static buff) to a file given it's relative path (NULL if not found) -\param index if several files are matching (as returned in a call to vfsGetFileCount), get the index-th file -\param flag 0 or a combination of VFS_SEARCH_PAK or VFS_SEARCH_DIR -HYDRA: - this now searches VFS/PAK files in addition to the filesystem - if FLAG is 0 then ONLY dirs are searched. - PAK's are searched before DIRs to mimic engine behaviour - index is ignored when searching PAK files. - when searching VFS, files are searched case insensitive. - -WARNING: if you use index from vfsGetFileCount, it works only with a vfsGetFileCount for the search directories only (not the pak files) -FIXME TTimo our VFS names are case insensitive. - this function is not able to build the full path from case-insensitive name - ( this is http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ) -*/ -typedef char* (* PFN_VFSGETFULLPATH) (const char *in, int index, int flag); -/*! -these return a static char*, doesn't need to be freed or anything -get the base path to use when raising file dialogs -we manually add "maps/" or "sounds/" or "mapobjects/models/" etc. -FIXME: I'm not sure this is used / relevant anymore -*/ -typedef const char* (* PFN_VFSBASEPROMPTPATH) (); - -// VFS API -struct _QERFileSystemTable -{ - int m_nSize; - PFN_VFSINITDIRECTORY m_pfnInitDirectory; - PFN_VFSSHUTDOWN m_pfnShutdown; - PFN_VFSFREEFILE m_pfnFreeFile; - PFN_VFSGETDIRLIST m_pfnGetDirList; - PFN_VFSGETFILELIST m_pfnGetFileList; - PFN_VFSCLEARFILEDIRLIST m_pfnClearFileDirList; - PFN_VFSGETFILECOUNT m_pfnGetFileCount; - PFN_VFSLOADFILE m_pfnLoadFile; - PFN_VFSLOADFULLPATHFILE m_pfnLoadFullPathFile; - PFN_VFSEXTRACTRELATIVEPATH m_pfnExtractRelativePath; - PFN_VFSGETFULLPATH m_pfnGetFullPath; - PFN_VFSBASEPROMPTPATH m_pfnBasePromptPath; -}; - -#ifdef USE_VFSTABLE_DEFINE -#ifndef __VFSTABLENAME -#define __VFSTABLENAME g_FileSystemTable -#endif -#define vfsInitDirectory __VFSTABLENAME.m_pfnInitDirectory -#define vfsShutdown __VFSTABLENAME.m_pfnShutdown -#define vfsFreeFile __VFSTABLENAME.m_pfnFreeFile -#define vfsGetDirList __VFSTABLENAME.m_pfnGetDirList -#define vfsGetFileList __VFSTABLENAME.m_pfnGetFileList -#define vfsClearFileDirList __VFSTABLENAME.m_pfnClearFileDirList -#define vfsGetFileCount __VFSTABLENAME.m_pfnGetFileCount -#define vfsLoadFile __VFSTABLENAME.m_pfnLoadFile -#define vfsLoadFullPathFile __VFSTABLENAME.m_pfnLoadFullPathFile -#define vfsExtractRelativePath __VFSTABLENAME.m_pfnExtractRelativePath -#define vfsGetFullPath __VFSTABLENAME.m_pfnGetFullPath -#define vfsBasePromptPath __VFSTABLENAME.m_pfnBasePromptPath -#endif - -#endif // _IFILESYSTEM_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IFILESYSTEM_H_ +#define _IFILESYSTEM_H_ + +// +// Plugin interface for the virtual filesystem used by Radiant +// + +// NOTE: If you want to write a VFS plugin then you must export +// "QERPlug_ListInterfaces" and "QERPlug_RequestInterface" +// (see qerplugin.h for more information) + +#ifdef _WIN32 +#define VFS_NATIVESEPARATOR '\\' +#else +#define VFS_NATIVESEPARATOR '/' +#endif + +#define VFS_MAJOR "VFS" + +// return the file system supported by the plugin, for example: "quake1" or "quake3" +//typedef const char* (WINAPI* PFN_VFSGETFORMAT) (); +// add all files from a directory to the vfs +typedef void (* PFN_VFSINITDIRECTORY) (const char *path); +// free all resources used by the plugin +typedef void (* PFN_VFSSHUTDOWN) (); +// free memory allocated by VFS for this pointer +typedef void (* PFN_VFSFREEFILE) (void *p); +// return a GSList with all the directories under basedir +typedef GSList* (* PFN_VFSGETDIRLIST) (const char *basedir); +// return a GSList with all the files under basedir (extension can be NULL) +typedef GSList* (* PFN_VFSGETFILELIST) (const char *basedir, const char *extension); +// free a dirlist or filelist returned from one of the above functions +typedef void (* PFN_VFSCLEARFILEDIRLIST) (GSList **lst); +#define VFS_SEARCH_PAK 0x1 +#define VFS_SEARCH_DIR 0x2 +/*! +\brief return the number of files with the exact name described in filename +there can be several hits for a given file, or this can be used to check for existence +\param flags is optional and can be used with VFS_SEARCH_* bits, if flag is 0, everything is searched, else only the specified bits +paks are searched first, then search directories +*/ +typedef int (* PFN_VFSGETFILECOUNT) (const char *filename, int flags); +/*! +\brief load file, allocate buffer +\return -1 if fails or the size of the buffer allocated +\param index is used to load the i-th file in the search directories (see vfsGetFileCount) +this will scan in the search directories first, then it will search in the pak files +WARNING: the allocated buffer must be freed with a g_free call +NOTE TTimo: the g_free release is utter horror + see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 +*/ +typedef int (* PFN_VFSLOADFILE) (const char *filename, void **buffer, int index); +// load a file from it's full path into the buffer, returns the file size or -1 +// the allocated buffer must be freed with a g_free call +typedef int (* PFN_VFSLOADFULLPATHFILE) (const char *filename, void **buffer); +// takes an absolute file path, returns a shortened relative file path if the absolute path matches a valid basedir or NULL if an error occured +typedef char* (* PFN_VFSEXTRACTRELATIVEPATH) (const char *in); +/*! +\return the full path (in a static buff) to a file given it's relative path (NULL if not found) +\param index if several files are matching (as returned in a call to vfsGetFileCount), get the index-th file +\param flag 0 or a combination of VFS_SEARCH_PAK or VFS_SEARCH_DIR +HYDRA: + this now searches VFS/PAK files in addition to the filesystem + if FLAG is 0 then ONLY dirs are searched. + PAK's are searched before DIRs to mimic engine behaviour + index is ignored when searching PAK files. + when searching VFS, files are searched case insensitive. + +WARNING: if you use index from vfsGetFileCount, it works only with a vfsGetFileCount for the search directories only (not the pak files) +FIXME TTimo our VFS names are case insensitive. + this function is not able to build the full path from case-insensitive name + ( this is http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ) +*/ +typedef char* (* PFN_VFSGETFULLPATH) (const char *in, int index, int flag); +/*! +these return a static char*, doesn't need to be freed or anything +get the base path to use when raising file dialogs +we manually add "maps/" or "sounds/" or "mapobjects/models/" etc. +FIXME: I'm not sure this is used / relevant anymore +*/ +typedef const char* (* PFN_VFSBASEPROMPTPATH) (); + +// VFS API +struct _QERFileSystemTable +{ + int m_nSize; + PFN_VFSINITDIRECTORY m_pfnInitDirectory; + PFN_VFSSHUTDOWN m_pfnShutdown; + PFN_VFSFREEFILE m_pfnFreeFile; + PFN_VFSGETDIRLIST m_pfnGetDirList; + PFN_VFSGETFILELIST m_pfnGetFileList; + PFN_VFSCLEARFILEDIRLIST m_pfnClearFileDirList; + PFN_VFSGETFILECOUNT m_pfnGetFileCount; + PFN_VFSLOADFILE m_pfnLoadFile; + PFN_VFSLOADFULLPATHFILE m_pfnLoadFullPathFile; + PFN_VFSEXTRACTRELATIVEPATH m_pfnExtractRelativePath; + PFN_VFSGETFULLPATH m_pfnGetFullPath; + PFN_VFSBASEPROMPTPATH m_pfnBasePromptPath; +}; + +#ifdef USE_VFSTABLE_DEFINE +#ifndef __VFSTABLENAME +#define __VFSTABLENAME g_FileSystemTable +#endif +#define vfsInitDirectory __VFSTABLENAME.m_pfnInitDirectory +#define vfsShutdown __VFSTABLENAME.m_pfnShutdown +#define vfsFreeFile __VFSTABLENAME.m_pfnFreeFile +#define vfsGetDirList __VFSTABLENAME.m_pfnGetDirList +#define vfsGetFileList __VFSTABLENAME.m_pfnGetFileList +#define vfsClearFileDirList __VFSTABLENAME.m_pfnClearFileDirList +#define vfsGetFileCount __VFSTABLENAME.m_pfnGetFileCount +#define vfsLoadFile __VFSTABLENAME.m_pfnLoadFile +#define vfsLoadFullPathFile __VFSTABLENAME.m_pfnLoadFullPathFile +#define vfsExtractRelativePath __VFSTABLENAME.m_pfnExtractRelativePath +#define vfsGetFullPath __VFSTABLENAME.m_pfnGetFullPath +#define vfsBasePromptPath __VFSTABLENAME.m_pfnBasePromptPath +#endif + +#endif // _IFILESYSTEM_H_ diff --git a/include/igl.h b/include/igl.h index 99e4141f..630d3d34 100644 --- a/include/igl.h +++ b/include/igl.h @@ -1,266 +1,266 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// -// DESCRIPTION: -// all purpose OpenGL interface for Q3Radiant plugins -// - -#ifndef __IGL_H__ -#define __IGL_H__ - -#if defined (__linux__) || defined (__APPLE__) -#include -#endif - -// we use these classes to let plugins draw inside the Radiant windows -// 2D window like YZ XZ XY -class IGL2DWindow -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - virtual void Draw2D( VIEWTYPE vt ) = 0; -}; - -// 3D window -class IGL3DWindow -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - virtual void Draw3D() = 0; -}; - -#define QGL_MAJOR "qgl" - -#include - -typedef void (APIENTRY* PFN_QGLALPHAFUNC) (GLenum func, GLclampf ref); -typedef void (APIENTRY* PFN_QGLBEGIN) (GLenum); -typedef void (APIENTRY* PFN_QGLBINDTEXTURE) (GLenum target, GLuint texture); -typedef void (APIENTRY* PFN_QGLBLENDFUNC) (GLenum sfactor, GLenum dfactor); -typedef void (APIENTRY* PFN_QGLCALLLIST) (GLuint list); -typedef void (APIENTRY* PFN_QGLCALLLISTS) (GLsizei n, GLenum type, const GLvoid *lists); -typedef void (APIENTRY* PFN_QGLCLEAR) (GLbitfield mask); -typedef void (APIENTRY* PFN_QGLCLEARCOLOR) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -typedef void (APIENTRY* PFN_QGLCLEARDEPTH) (GLclampd depth); -typedef void (APIENTRY* PFN_QGLCOLOR3F) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRY* PFN_QGLCOLOR3FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLCOLOR4F) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (APIENTRY* PFN_QGLCOLOR4FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLCOLOR4UBV) (const GLubyte *v); -typedef void (APIENTRY* PFN_QGLCOLORPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLCULLFACE) (GLenum mode); -typedef void (APIENTRY* PFN_QGLDELETELISTS) (GLuint list, GLsizei range); -typedef void (APIENTRY* PFN_QGLDELETETEXTURES) (GLsizei n, const GLuint *textures); -typedef void (APIENTRY* PFN_QGLDEPTHFUNC) (GLenum func); -typedef void (APIENTRY* PFN_QGLDEPTHMASK) (GLboolean flag); -typedef void (APIENTRY* PFN_QGLDISABLE) (GLenum cap); -typedef void (APIENTRY* PFN_QGLDISABLECLIENTSTATE) (GLenum array); -typedef void (APIENTRY* PFN_QGLDRAWELEMENTS) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); -typedef void (APIENTRY* PFN_QGLENABLE) (GLenum cap); -typedef void (APIENTRY* PFN_QGLENABLECLIENTSTATE) (GLenum array); -typedef void (APIENTRY* PFN_QGLEND) (); -typedef void (APIENTRY* PFN_QGLENDLIST) (); -typedef void (APIENTRY* PFN_QGLFOGF) (GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLFOGFV) (GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLFOGFI) (GLenum pname, GLint param); -typedef GLuint (APIENTRY* PFN_QGLGENLISTS) (GLsizei range); -typedef void (APIENTRY *PFN_QGLGENTEXTURES) (GLsizei n, GLuint *textures); -typedef void (APIENTRY* PFN_QGLGETDOUBLEV) (GLenum pname, GLdouble *params); -typedef void (APIENTRY* PFN_QGLHINT) (GLenum target, GLenum mode); -typedef void (APIENTRY* PFN_QGLGETINTEGERV) (GLenum pname, GLint *params); -typedef void (APIENTRY* PFN_QGLLIGHTFV) (GLenum light, GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); -typedef void (APIENTRY* PFN_QGLLINESTIPPLE) (GLint factor, GLushort pattern); -typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); -typedef void (APIENTRY* PFN_QGLLISTBASE) (GLuint base); -typedef void (APIENTRY* PFN_QGLLOADIDENTITY) (); -typedef void (APIENTRY* PFN_QGLMATERIALF) (GLenum face, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLMATERIALFV) (GLenum face, GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLMATRIXMODE) (GLenum mode); -typedef void (APIENTRY* PFN_QGLMULTMATRIXF) (const GLfloat *m); -typedef void (APIENTRY* PFN_QGLNEWLIST) (GLuint list, GLenum mode); -typedef void (APIENTRY* PFN_QGLNORMAL3F) (GLfloat nx, GLfloat ny, GLfloat nz); -typedef void (APIENTRY* PFN_QGLNORMAL3FV) (const GLfloat *n); -typedef void (APIENTRY* PFN_QGLNORMALPOINTER) (GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLORTHO) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRY* PFN_QGLPOINTSIZE) (GLfloat size); -typedef void (APIENTRY* PFN_QGLPOLYGONMODE) (GLenum face, GLenum mode); -typedef void (APIENTRY* PFN_QGLPOPATTRIB) (); -typedef void (APIENTRY* PFN_QGLPOPMATRIX) (); -typedef void (APIENTRY* PFN_QGLPUSHATTRIB) (GLbitfield mask); -typedef void (APIENTRY* PFN_QGLPUSHMATRIX) (); -typedef void (APIENTRY* PFN_QGLRASTERPOS3FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLROTATED) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRY* PFN_QGLROTATEF) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLSCISSOR) (GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLSHADEMODEL) (GLenum mode); -typedef void (APIENTRY* PFN_QGLTEXCOORD2F) (GLfloat s, GLfloat t); -typedef void (APIENTRY* PFN_QGLTEXCOORD2FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLTEXCOORDPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLTEXENVF) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLTEXGENF) (GLenum coord, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLTEXIMAGE1D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTEXIMAGE2D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERF) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERFV) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERI) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERIV) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTRANSLATED) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRY* PFN_QGLTRANSLATEF) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLVERTEX2F) (GLfloat x, GLfloat y); -typedef void (APIENTRY* PFN_QGLVERTEX3F) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLVERTEX3FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLVERTEXPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLVIEWPORT) (GLint x, GLint y, GLsizei width, GLsizei height); - -typedef void (WINAPI* PFN_QE_CHECKOPENGLFORERRORS) (); - -// glu stuff -// TTimo: NOTE: relying on glu might not be such a good idea. On many systems, the GLU lib is outdated, misversioned etc. -typedef void (APIENTRY * PFN_QGLUPERSPECTIVE) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRY * PFN_QGLULOOKAT) (GLdouble eyex, GLdouble eyey, GLdouble eyez, - GLdouble centerx, GLdouble centery, GLdouble centerz, - GLdouble upx, GLdouble upy, GLdouble upz); -//++timo gluErrorString is defined but not exposed in the IGL interface - - -// plugins drawing inside the GL windows -//++timo TODO: add hooking into other windows (Z and .. texture??) -//+timo NOTE: this could be moved to the messaging system instead of having a dedicated interface <- yet I don't know how -typedef void (WINAPI* PFN_QERAPP_HOOKGL2DWINDOW) (IGL2DWindow *); -typedef void (WINAPI* PFN_QERAPP_UNHOOKGL2DWINDOW) (IGL2DWindow *); -typedef void (WINAPI* PFN_QERAPP_HOOKGL3DWINDOW) (IGL3DWindow *); -typedef void (WINAPI* PFN_QERAPP_UNHOOKGL3DWINDOW) (IGL3DWindow *); - -struct _QERQglTable -{ - //++timo do we really wanna play with versions ? - // float m_fVersion; - int m_nSize; - PFN_QGLALPHAFUNC m_pfn_qglAlphaFunc; - PFN_QGLBEGIN m_pfn_qglBegin; - PFN_QGLBINDTEXTURE m_pfn_qglBindTexture; - PFN_QGLBLENDFUNC m_pfn_qglBlendFunc; - PFN_QGLCALLLIST m_pfn_qglCallList; - PFN_QGLCLEAR m_pfn_qglClear; - PFN_QGLCLEARCOLOR m_pfn_qglClearColor; - PFN_QGLCALLLISTS m_pfn_qglCallLists; - PFN_QGLCLEARDEPTH m_pfn_qglClearDepth; - PFN_QGLCOLOR3F m_pfn_qglColor3f; - PFN_QGLCOLOR3FV m_pfn_qglColor3fv; - PFN_QGLCOLOR4F m_pfn_qglColor4f; - PFN_QGLCOLOR4FV m_pfn_qglColor4fv; - PFN_QGLCOLOR4UBV m_pfn_qglColor4ubv; // ydnar - PFN_QGLCOLORPOINTER m_pfn_qglColorPointer; - PFN_QGLCULLFACE m_pfn_qglCullFace; - PFN_QGLDELETELISTS m_pfn_qglDeleteLists; - PFN_QGLDELETETEXTURES m_pfn_qglDeleteTextures; - PFN_QGLDEPTHFUNC m_pfn_qglDepthFunc; - PFN_QGLDEPTHMASK m_pfn_qglDepthMask; - PFN_QGLDISABLE m_pfn_qglDisable; - PFN_QGLDISABLECLIENTSTATE m_pfn_qglDisableClientState; - PFN_QGLDRAWELEMENTS m_pfn_qglDrawElements; - PFN_QGLENABLE m_pfn_qglEnable; - PFN_QGLENABLECLIENTSTATE m_pfn_qglEnableClientState; - PFN_QGLEND m_pfn_qglEnd; - PFN_QGLENDLIST m_pfn_qglEndList; - PFN_QGLFOGF m_pfn_qglFogf; - PFN_QGLFOGFV m_pfn_qglFogfv; - PFN_QGLFOGFI m_pfn_qglFogi; - PFN_QGLGENLISTS m_pfn_qglGenLists; - PFN_QGLGENTEXTURES m_pfn_qglGenTextures; - PFN_QGLGETDOUBLEV m_pfn_qglGetDoublev; - PFN_QGLGETINTEGERV m_pfn_qglGetIntegerv; - PFN_QGLHINT m_pfn_qglHint; - PFN_QGLLIGHTFV m_pfn_qglLightfv; - PFN_QGLLINESTIPPLE m_pfn_qglLineStipple; - PFN_QGLLINEWIDTH m_pfn_qglLineWidth; - PFN_QGLLISTBASE m_pfn_qglListBase; - PFN_QGLLOADIDENTITY m_pfn_qglLoadIdentity; - PFN_QGLMATERIALF m_pfn_qglMaterialf; - PFN_QGLMATERIALFV m_pfn_qglMaterialfv; - PFN_QGLMATRIXMODE m_pfn_qglMatrixMode; - PFN_QGLMULTMATRIXF m_pfn_qglMultMatrixf; - PFN_QGLNEWLIST m_pfn_qglNewList; - PFN_QGLNORMAL3F m_pfn_qglNormal3f; - PFN_QGLNORMAL3FV m_pfn_qglNormal3fv; - PFN_QGLNORMALPOINTER m_pfn_qglNormalPointer; - PFN_QGLORTHO m_pfn_qglOrtho; - PFN_QGLPOINTSIZE m_pfn_qglPointSize; - PFN_QGLPOLYGONMODE m_pfn_qglPolygonMode; - PFN_QGLPOPATTRIB m_pfn_qglPopAttrib; - PFN_QGLPOPMATRIX m_pfn_qglPopMatrix; - PFN_QGLPUSHATTRIB m_pfn_qglPushAttrib; - PFN_QGLPUSHMATRIX m_pfn_qglPushMatrix; - PFN_QGLRASTERPOS3FV m_pfn_qglRasterPos3fv; - PFN_QGLROTATED m_pfn_qglRotated; - PFN_QGLROTATEF m_pfn_qglRotatef; - PFN_QGLSCALEF m_pfn_qglScalef; - PFN_QGLSCISSOR m_pfn_qglScissor; - PFN_QGLSHADEMODEL m_pfn_qglShadeModel; - PFN_QGLTEXCOORD2F m_pfn_qglTexCoord2f; - PFN_QGLTEXCOORD2FV m_pfn_qglTexCoord2fv; - PFN_QGLTEXCOORDPOINTER m_pfn_qglTexCoordPointer; - PFN_QGLTEXENVF m_pfn_qglTexEnvf; - PFN_QGLTEXGENF m_pfn_qglTexGenf; - PFN_QGLTEXIMAGE1D m_pfn_qglTexImage1D; - PFN_QGLTEXIMAGE2D m_pfn_qglTexImage2D; - PFN_QGLTEXPARAMETERF m_pfn_qglTexParameterf; - PFN_QGLTEXPARAMETERFV m_pfn_qglTexParameterfv; - PFN_QGLTEXPARAMETERI m_pfn_qglTexParameteri; - PFN_QGLTEXPARAMETERIV m_pfn_qglTexParameteriv; - PFN_QGLTEXSUBIMAGE1D m_pfn_qglTexSubImage1D; - PFN_QGLTEXSUBIMAGE2D m_pfn_qglTexSubImage2D; - PFN_QGLTRANSLATED m_pfn_qglTranslated; - PFN_QGLTRANSLATEF m_pfn_qglTranslatef; - PFN_QGLVERTEX2F m_pfn_qglVertex2f; - PFN_QGLVERTEX3F m_pfn_qglVertex3f; - PFN_QGLVERTEX3FV m_pfn_qglVertex3fv; - PFN_QGLVERTEXPOINTER m_pfn_qglVertexPointer; - PFN_QGLVIEWPORT m_pfn_qglViewport; - - PFN_QE_CHECKOPENGLFORERRORS m_pfn_QE_CheckOpenGLForErrors; - - // glu stuff - PFN_QGLUPERSPECTIVE m_pfn_qgluPerspective; - PFN_QGLULOOKAT m_pfn_qgluLookAt; - - // plugin entities drawing inside Radiant windows - PFN_QERAPP_HOOKGL2DWINDOW m_pfnHookGL2DWindow; - PFN_QERAPP_UNHOOKGL2DWINDOW m_pfnUnHookGL2DWindow; - PFN_QERAPP_HOOKGL3DWINDOW m_pfnHookGL3DWindow; - PFN_QERAPP_UNHOOKGL3DWINDOW m_pfnUnHookGL3DWindow; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// all purpose OpenGL interface for Q3Radiant plugins +// + +#ifndef __IGL_H__ +#define __IGL_H__ + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +// we use these classes to let plugins draw inside the Radiant windows +// 2D window like YZ XZ XY +class IGL2DWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + virtual void Draw2D( VIEWTYPE vt ) = 0; +}; + +// 3D window +class IGL3DWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + virtual void Draw3D() = 0; +}; + +#define QGL_MAJOR "qgl" + +#include + +typedef void (APIENTRY* PFN_QGLALPHAFUNC) (GLenum func, GLclampf ref); +typedef void (APIENTRY* PFN_QGLBEGIN) (GLenum); +typedef void (APIENTRY* PFN_QGLBINDTEXTURE) (GLenum target, GLuint texture); +typedef void (APIENTRY* PFN_QGLBLENDFUNC) (GLenum sfactor, GLenum dfactor); +typedef void (APIENTRY* PFN_QGLCALLLIST) (GLuint list); +typedef void (APIENTRY* PFN_QGLCALLLISTS) (GLsizei n, GLenum type, const GLvoid *lists); +typedef void (APIENTRY* PFN_QGLCLEAR) (GLbitfield mask); +typedef void (APIENTRY* PFN_QGLCLEARCOLOR) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +typedef void (APIENTRY* PFN_QGLCLEARDEPTH) (GLclampd depth); +typedef void (APIENTRY* PFN_QGLCOLOR3F) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRY* PFN_QGLCOLOR3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLCOLOR4F) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRY* PFN_QGLCOLOR4FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLCOLOR4UBV) (const GLubyte *v); +typedef void (APIENTRY* PFN_QGLCOLORPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLCULLFACE) (GLenum mode); +typedef void (APIENTRY* PFN_QGLDELETELISTS) (GLuint list, GLsizei range); +typedef void (APIENTRY* PFN_QGLDELETETEXTURES) (GLsizei n, const GLuint *textures); +typedef void (APIENTRY* PFN_QGLDEPTHFUNC) (GLenum func); +typedef void (APIENTRY* PFN_QGLDEPTHMASK) (GLboolean flag); +typedef void (APIENTRY* PFN_QGLDISABLE) (GLenum cap); +typedef void (APIENTRY* PFN_QGLDISABLECLIENTSTATE) (GLenum array); +typedef void (APIENTRY* PFN_QGLDRAWELEMENTS) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRY* PFN_QGLENABLE) (GLenum cap); +typedef void (APIENTRY* PFN_QGLENABLECLIENTSTATE) (GLenum array); +typedef void (APIENTRY* PFN_QGLEND) (); +typedef void (APIENTRY* PFN_QGLENDLIST) (); +typedef void (APIENTRY* PFN_QGLFOGF) (GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLFOGFV) (GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLFOGFI) (GLenum pname, GLint param); +typedef GLuint (APIENTRY* PFN_QGLGENLISTS) (GLsizei range); +typedef void (APIENTRY *PFN_QGLGENTEXTURES) (GLsizei n, GLuint *textures); +typedef void (APIENTRY* PFN_QGLGETDOUBLEV) (GLenum pname, GLdouble *params); +typedef void (APIENTRY* PFN_QGLHINT) (GLenum target, GLenum mode); +typedef void (APIENTRY* PFN_QGLGETINTEGERV) (GLenum pname, GLint *params); +typedef void (APIENTRY* PFN_QGLLIGHTFV) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); +typedef void (APIENTRY* PFN_QGLLINESTIPPLE) (GLint factor, GLushort pattern); +typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); +typedef void (APIENTRY* PFN_QGLLISTBASE) (GLuint base); +typedef void (APIENTRY* PFN_QGLLOADIDENTITY) (); +typedef void (APIENTRY* PFN_QGLMATERIALF) (GLenum face, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLMATERIALFV) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLMATRIXMODE) (GLenum mode); +typedef void (APIENTRY* PFN_QGLMULTMATRIXF) (const GLfloat *m); +typedef void (APIENTRY* PFN_QGLNEWLIST) (GLuint list, GLenum mode); +typedef void (APIENTRY* PFN_QGLNORMAL3F) (GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRY* PFN_QGLNORMAL3FV) (const GLfloat *n); +typedef void (APIENTRY* PFN_QGLNORMALPOINTER) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLORTHO) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRY* PFN_QGLPOINTSIZE) (GLfloat size); +typedef void (APIENTRY* PFN_QGLPOLYGONMODE) (GLenum face, GLenum mode); +typedef void (APIENTRY* PFN_QGLPOPATTRIB) (); +typedef void (APIENTRY* PFN_QGLPOPMATRIX) (); +typedef void (APIENTRY* PFN_QGLPUSHATTRIB) (GLbitfield mask); +typedef void (APIENTRY* PFN_QGLPUSHMATRIX) (); +typedef void (APIENTRY* PFN_QGLRASTERPOS3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLROTATED) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRY* PFN_QGLROTATEF) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSCISSOR) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSHADEMODEL) (GLenum mode); +typedef void (APIENTRY* PFN_QGLTEXCOORD2F) (GLfloat s, GLfloat t); +typedef void (APIENTRY* PFN_QGLTEXCOORD2FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLTEXCOORDPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLTEXENVF) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXGENF) (GLenum coord, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXIMAGE1D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXIMAGE2D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERF) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERFV) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERI) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERIV) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTRANSLATED) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRY* PFN_QGLTRANSLATEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLVERTEX2F) (GLfloat x, GLfloat y); +typedef void (APIENTRY* PFN_QGLVERTEX3F) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLVERTEX3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLVERTEXPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLVIEWPORT) (GLint x, GLint y, GLsizei width, GLsizei height); + +typedef void (WINAPI* PFN_QE_CHECKOPENGLFORERRORS) (); + +// glu stuff +// TTimo: NOTE: relying on glu might not be such a good idea. On many systems, the GLU lib is outdated, misversioned etc. +typedef void (APIENTRY * PFN_QGLUPERSPECTIVE) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRY * PFN_QGLULOOKAT) (GLdouble eyex, GLdouble eyey, GLdouble eyez, + GLdouble centerx, GLdouble centery, GLdouble centerz, + GLdouble upx, GLdouble upy, GLdouble upz); +//++timo gluErrorString is defined but not exposed in the IGL interface + + +// plugins drawing inside the GL windows +//++timo TODO: add hooking into other windows (Z and .. texture??) +//+timo NOTE: this could be moved to the messaging system instead of having a dedicated interface <- yet I don't know how +typedef void (WINAPI* PFN_QERAPP_HOOKGL2DWINDOW) (IGL2DWindow *); +typedef void (WINAPI* PFN_QERAPP_UNHOOKGL2DWINDOW) (IGL2DWindow *); +typedef void (WINAPI* PFN_QERAPP_HOOKGL3DWINDOW) (IGL3DWindow *); +typedef void (WINAPI* PFN_QERAPP_UNHOOKGL3DWINDOW) (IGL3DWindow *); + +struct _QERQglTable +{ + //++timo do we really wanna play with versions ? + // float m_fVersion; + int m_nSize; + PFN_QGLALPHAFUNC m_pfn_qglAlphaFunc; + PFN_QGLBEGIN m_pfn_qglBegin; + PFN_QGLBINDTEXTURE m_pfn_qglBindTexture; + PFN_QGLBLENDFUNC m_pfn_qglBlendFunc; + PFN_QGLCALLLIST m_pfn_qglCallList; + PFN_QGLCLEAR m_pfn_qglClear; + PFN_QGLCLEARCOLOR m_pfn_qglClearColor; + PFN_QGLCALLLISTS m_pfn_qglCallLists; + PFN_QGLCLEARDEPTH m_pfn_qglClearDepth; + PFN_QGLCOLOR3F m_pfn_qglColor3f; + PFN_QGLCOLOR3FV m_pfn_qglColor3fv; + PFN_QGLCOLOR4F m_pfn_qglColor4f; + PFN_QGLCOLOR4FV m_pfn_qglColor4fv; + PFN_QGLCOLOR4UBV m_pfn_qglColor4ubv; // ydnar + PFN_QGLCOLORPOINTER m_pfn_qglColorPointer; + PFN_QGLCULLFACE m_pfn_qglCullFace; + PFN_QGLDELETELISTS m_pfn_qglDeleteLists; + PFN_QGLDELETETEXTURES m_pfn_qglDeleteTextures; + PFN_QGLDEPTHFUNC m_pfn_qglDepthFunc; + PFN_QGLDEPTHMASK m_pfn_qglDepthMask; + PFN_QGLDISABLE m_pfn_qglDisable; + PFN_QGLDISABLECLIENTSTATE m_pfn_qglDisableClientState; + PFN_QGLDRAWELEMENTS m_pfn_qglDrawElements; + PFN_QGLENABLE m_pfn_qglEnable; + PFN_QGLENABLECLIENTSTATE m_pfn_qglEnableClientState; + PFN_QGLEND m_pfn_qglEnd; + PFN_QGLENDLIST m_pfn_qglEndList; + PFN_QGLFOGF m_pfn_qglFogf; + PFN_QGLFOGFV m_pfn_qglFogfv; + PFN_QGLFOGFI m_pfn_qglFogi; + PFN_QGLGENLISTS m_pfn_qglGenLists; + PFN_QGLGENTEXTURES m_pfn_qglGenTextures; + PFN_QGLGETDOUBLEV m_pfn_qglGetDoublev; + PFN_QGLGETINTEGERV m_pfn_qglGetIntegerv; + PFN_QGLHINT m_pfn_qglHint; + PFN_QGLLIGHTFV m_pfn_qglLightfv; + PFN_QGLLINESTIPPLE m_pfn_qglLineStipple; + PFN_QGLLINEWIDTH m_pfn_qglLineWidth; + PFN_QGLLISTBASE m_pfn_qglListBase; + PFN_QGLLOADIDENTITY m_pfn_qglLoadIdentity; + PFN_QGLMATERIALF m_pfn_qglMaterialf; + PFN_QGLMATERIALFV m_pfn_qglMaterialfv; + PFN_QGLMATRIXMODE m_pfn_qglMatrixMode; + PFN_QGLMULTMATRIXF m_pfn_qglMultMatrixf; + PFN_QGLNEWLIST m_pfn_qglNewList; + PFN_QGLNORMAL3F m_pfn_qglNormal3f; + PFN_QGLNORMAL3FV m_pfn_qglNormal3fv; + PFN_QGLNORMALPOINTER m_pfn_qglNormalPointer; + PFN_QGLORTHO m_pfn_qglOrtho; + PFN_QGLPOINTSIZE m_pfn_qglPointSize; + PFN_QGLPOLYGONMODE m_pfn_qglPolygonMode; + PFN_QGLPOPATTRIB m_pfn_qglPopAttrib; + PFN_QGLPOPMATRIX m_pfn_qglPopMatrix; + PFN_QGLPUSHATTRIB m_pfn_qglPushAttrib; + PFN_QGLPUSHMATRIX m_pfn_qglPushMatrix; + PFN_QGLRASTERPOS3FV m_pfn_qglRasterPos3fv; + PFN_QGLROTATED m_pfn_qglRotated; + PFN_QGLROTATEF m_pfn_qglRotatef; + PFN_QGLSCALEF m_pfn_qglScalef; + PFN_QGLSCISSOR m_pfn_qglScissor; + PFN_QGLSHADEMODEL m_pfn_qglShadeModel; + PFN_QGLTEXCOORD2F m_pfn_qglTexCoord2f; + PFN_QGLTEXCOORD2FV m_pfn_qglTexCoord2fv; + PFN_QGLTEXCOORDPOINTER m_pfn_qglTexCoordPointer; + PFN_QGLTEXENVF m_pfn_qglTexEnvf; + PFN_QGLTEXGENF m_pfn_qglTexGenf; + PFN_QGLTEXIMAGE1D m_pfn_qglTexImage1D; + PFN_QGLTEXIMAGE2D m_pfn_qglTexImage2D; + PFN_QGLTEXPARAMETERF m_pfn_qglTexParameterf; + PFN_QGLTEXPARAMETERFV m_pfn_qglTexParameterfv; + PFN_QGLTEXPARAMETERI m_pfn_qglTexParameteri; + PFN_QGLTEXPARAMETERIV m_pfn_qglTexParameteriv; + PFN_QGLTEXSUBIMAGE1D m_pfn_qglTexSubImage1D; + PFN_QGLTEXSUBIMAGE2D m_pfn_qglTexSubImage2D; + PFN_QGLTRANSLATED m_pfn_qglTranslated; + PFN_QGLTRANSLATEF m_pfn_qglTranslatef; + PFN_QGLVERTEX2F m_pfn_qglVertex2f; + PFN_QGLVERTEX3F m_pfn_qglVertex3f; + PFN_QGLVERTEX3FV m_pfn_qglVertex3fv; + PFN_QGLVERTEXPOINTER m_pfn_qglVertexPointer; + PFN_QGLVIEWPORT m_pfn_qglViewport; + + PFN_QE_CHECKOPENGLFORERRORS m_pfn_QE_CheckOpenGLForErrors; + + // glu stuff + PFN_QGLUPERSPECTIVE m_pfn_qgluPerspective; + PFN_QGLULOOKAT m_pfn_qgluLookAt; + + // plugin entities drawing inside Radiant windows + PFN_QERAPP_HOOKGL2DWINDOW m_pfnHookGL2DWindow; + PFN_QERAPP_UNHOOKGL2DWINDOW m_pfnUnHookGL2DWindow; + PFN_QERAPP_HOOKGL3DWINDOW m_pfnHookGL3DWindow; + PFN_QERAPP_UNHOOKGL3DWINDOW m_pfnUnHookGL3DWindow; +}; + +#endif diff --git a/include/iimage.h b/include/iimage.h index e473c4fe..6335082b 100644 --- a/include/iimage.h +++ b/include/iimage.h @@ -1,40 +1,40 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// Plugin interface for loading image files -// - -#ifndef _IIMAGE_H_ -#define _IIMAGE_H_ - -#define IMAGE_MAJOR "image" - -// Load an image file -typedef void (* PFN_QERPLUG_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); - -struct _QERPlugImageTable -{ - int m_nSize; - PFN_QERPLUG_LOADIMAGE m_pfnLoadImage; -}; - -#endif // _IIMAGE_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Plugin interface for loading image files +// + +#ifndef _IIMAGE_H_ +#define _IIMAGE_H_ + +#define IMAGE_MAJOR "image" + +// Load an image file +typedef void (* PFN_QERPLUG_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); + +struct _QERPlugImageTable +{ + int m_nSize; + PFN_QERPLUG_LOADIMAGE m_pfnLoadImage; +}; + +#endif // _IIMAGE_H_ diff --git a/include/imap.h b/include/imap.h index 230d5dd1..cddbadf7 100644 --- a/include/imap.h +++ b/include/imap.h @@ -1,82 +1,82 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//---------------------------------------------------------------------------- -// -// DESCRIPTION: -// map format interface (.map and .xmap, Q3 and other games) -// - -#ifndef __IMAP_H__ -#define __IMAP_H__ - -/*! IMap depends on IDataStream, including the header there for now */ -#include "idatastream.h" - -/*! header for CPtrArray */ -#include "missing.h" - -#define MAP_MAJOR "map" -/*! -define a GUID for this interface so everyone can acces and reference it -{75076973-3414-49c9-be5b-2378ec5601af} -*/ -static const GUID QERPlugMapTable_GUID = -{ 0x75076973, 0x3414, 0x49c9, { 0xbe, 0x5b, 0x23, 0x78, 0xec, 0x56, 0x01, 0xaf } }; - -/*! -read from a stream into a list of entities -\param in the input stream. For regular map file parsing it's possible to copy the content in a text buffer -and use the old school parser -\param ents the list of entities read from the stream. They are not linked to the world, and their brushes -are not either. -*/ -typedef void (* PFN_MAP_READ) (IDataStream *in, CPtrArray *ents); ///< read from a stream into a list of entities -typedef void (* PFN_MAP_WRITE) (CPtrArray *ents, IDataStream *out); ///< save a list of entities into a stream - -struct _QERPlugMapTable -{ - int m_nSize; - PFN_MAP_READ m_pfnMap_Read; - PFN_MAP_WRITE m_pfnMap_Write; -}; - -/*! -this set of macros will define the functions to map on a given table - it should be used in the headers (see modules source, plugin.h) -we don't want those defines in the part where WE implement the Map_LoadFile - so we're using a define to disable .. should find a standard define name - (for instance QCOM_CLIENT / QCOM_SERVER ?) - or the name should be specific to any interface .. it's not a client/server thing here anyway -*/ -#ifdef USE_MAPTABLE_DEFINE -#ifndef __MAPTABLENAME -/*! -TTimo NOTE: this is the default table name we map to - if you are using a different table name, just define __MAPTABLENAME before you include the imap.h header -*/ -#define __MAPTABLENAME g_MapTable -#endif -#define Map_Read __MAPTABLENAME.m_pfnMap_Read -#define Map_Write __MAPTABLENAME.m_pfnMap_Write -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//---------------------------------------------------------------------------- +// +// DESCRIPTION: +// map format interface (.map and .xmap, Q3 and other games) +// + +#ifndef __IMAP_H__ +#define __IMAP_H__ + +/*! IMap depends on IDataStream, including the header there for now */ +#include "idatastream.h" + +/*! header for CPtrArray */ +#include "missing.h" + +#define MAP_MAJOR "map" +/*! +define a GUID for this interface so everyone can acces and reference it +{75076973-3414-49c9-be5b-2378ec5601af} +*/ +static const GUID QERPlugMapTable_GUID = +{ 0x75076973, 0x3414, 0x49c9, { 0xbe, 0x5b, 0x23, 0x78, 0xec, 0x56, 0x01, 0xaf } }; + +/*! +read from a stream into a list of entities +\param in the input stream. For regular map file parsing it's possible to copy the content in a text buffer +and use the old school parser +\param ents the list of entities read from the stream. They are not linked to the world, and their brushes +are not either. +*/ +typedef void (* PFN_MAP_READ) (IDataStream *in, CPtrArray *ents); ///< read from a stream into a list of entities +typedef void (* PFN_MAP_WRITE) (CPtrArray *ents, IDataStream *out); ///< save a list of entities into a stream + +struct _QERPlugMapTable +{ + int m_nSize; + PFN_MAP_READ m_pfnMap_Read; + PFN_MAP_WRITE m_pfnMap_Write; +}; + +/*! +this set of macros will define the functions to map on a given table + it should be used in the headers (see modules source, plugin.h) +we don't want those defines in the part where WE implement the Map_LoadFile + so we're using a define to disable .. should find a standard define name + (for instance QCOM_CLIENT / QCOM_SERVER ?) + or the name should be specific to any interface .. it's not a client/server thing here anyway +*/ +#ifdef USE_MAPTABLE_DEFINE +#ifndef __MAPTABLENAME +/*! +TTimo NOTE: this is the default table name we map to + if you are using a different table name, just define __MAPTABLENAME before you include the imap.h header +*/ +#define __MAPTABLENAME g_MapTable +#endif +#define Map_Read __MAPTABLENAME.m_pfnMap_Read +#define Map_Write __MAPTABLENAME.m_pfnMap_Write +#endif + +#endif diff --git a/include/imodel.h b/include/imodel.h index de5964a8..3dead05e 100644 --- a/include/imodel.h +++ b/include/imodel.h @@ -1,106 +1,106 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _IMODEL_H_ -#define _IMODEL_H_ - -#define MODEL_MAJOR "model" - -/*! -loads model from model file name specified, -fills model struct with pointers to model interfaces - -name is a relative path, we'll use VFS to extract a basepath to add to get the absolute path. -*/ -typedef void (* PFN_LOADMODEL) (entity_interfaces_t *model, const char *name); - -struct _QERPlugModelTable -{ - int m_nSize; - PFN_LOADMODEL m_pfnLoadModel; -}; - - -//forward declare entity_t -struct entity_s; -typedef struct entity_s entity_t; - -// any module relying on imodel will need to link against the mathlib -#include "mathlib.h" - -// state flags -#define DRAW_GL_FILL 0x0001 -#define DRAW_GL_LIGHTING 0x0010 -#define DRAW_GL_TEXTURE_2D 0x0100 -#define DRAW_GL_BLEND 0x1000 - -// predefined state combinations -#define DRAW_GL_WIRE 0x0000 -#define DRAW_GL_FLAT 0x0001 -#define DRAW_GL_SOLID 0x0011 -#define DRAW_GL_TEXTURED 0x0111 - -// mode -#define DRAW_WIRE 0 -#define DRAW_SOLID 1 -#define DRAW_TEXTURED 2 - -// render flags -#define DRAW_RF_NONE 0x0000 -#define DRAW_RF_SEL_OUTLINE 0x0001 -#define DRAW_RF_SEL_FILL 0x0010 -#define DRAW_RF_XY 0x0011 -#define DRAW_RF_CAM 0x0100 - -class IRender -{ -public: - virtual ~IRender() { } - virtual void IncRef() = 0; // increments the reference counter for this object - virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero - virtual void Draw(int state, int rflags) const = 0; // render the object - state = the opengl state - virtual const aabb_t *GetAABB() const = 0; -}; - -class ISelect -{ -public: - virtual ~ISelect() { } - virtual void IncRef() = 0; // increments the reference counter for this object - virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero - virtual bool TestRay(const ray_t *ray, vec_t *dist) const = 0; // test ray intersection, return bool true if intersects, and store distance to closest point of intersection - //virtual bool TestBox(const aabb_t *aabb) const = 0; // test aabb intersection, return bool true if touching or intersecting -}; - -class IEdit -{ -public: - virtual ~IEdit() { } - virtual void IncRef() = 0; // increments the reference counter for this object - virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero - virtual void Translate(const vec3_t translation) = 0; - virtual void Rotate(const vec3_t pivot, const vec3_t rotation) = 0; - virtual const vec_t *GetTranslation() const = 0; - virtual const vec_t *GetRotation() const = 0; - virtual void OnKeyValueChanged(entity_t *e, const char *key, const char* value) = 0; -}; - -#endif /* _IMODEL_H_ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IMODEL_H_ +#define _IMODEL_H_ + +#define MODEL_MAJOR "model" + +/*! +loads model from model file name specified, +fills model struct with pointers to model interfaces + +name is a relative path, we'll use VFS to extract a basepath to add to get the absolute path. +*/ +typedef void (* PFN_LOADMODEL) (entity_interfaces_t *model, const char *name); + +struct _QERPlugModelTable +{ + int m_nSize; + PFN_LOADMODEL m_pfnLoadModel; +}; + + +//forward declare entity_t +struct entity_s; +typedef struct entity_s entity_t; + +// any module relying on imodel will need to link against the mathlib +#include "mathlib.h" + +// state flags +#define DRAW_GL_FILL 0x0001 +#define DRAW_GL_LIGHTING 0x0010 +#define DRAW_GL_TEXTURE_2D 0x0100 +#define DRAW_GL_BLEND 0x1000 + +// predefined state combinations +#define DRAW_GL_WIRE 0x0000 +#define DRAW_GL_FLAT 0x0001 +#define DRAW_GL_SOLID 0x0011 +#define DRAW_GL_TEXTURED 0x0111 + +// mode +#define DRAW_WIRE 0 +#define DRAW_SOLID 1 +#define DRAW_TEXTURED 2 + +// render flags +#define DRAW_RF_NONE 0x0000 +#define DRAW_RF_SEL_OUTLINE 0x0001 +#define DRAW_RF_SEL_FILL 0x0010 +#define DRAW_RF_XY 0x0011 +#define DRAW_RF_CAM 0x0100 + +class IRender +{ +public: + virtual ~IRender() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual void Draw(int state, int rflags) const = 0; // render the object - state = the opengl state + virtual const aabb_t *GetAABB() const = 0; +}; + +class ISelect +{ +public: + virtual ~ISelect() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual bool TestRay(const ray_t *ray, vec_t *dist) const = 0; // test ray intersection, return bool true if intersects, and store distance to closest point of intersection + //virtual bool TestBox(const aabb_t *aabb) const = 0; // test aabb intersection, return bool true if touching or intersecting +}; + +class IEdit +{ +public: + virtual ~IEdit() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual void Translate(const vec3_t translation) = 0; + virtual void Rotate(const vec3_t pivot, const vec3_t rotation) = 0; + virtual const vec_t *GetTranslation() const = 0; + virtual const vec_t *GetRotation() const = 0; + virtual void OnKeyValueChanged(entity_t *e, const char *key, const char* value) = 0; +}; + +#endif /* _IMODEL_H_ */ diff --git a/include/ipatch.h b/include/ipatch.h index ccfd39ed..300a0a75 100644 --- a/include/ipatch.h +++ b/include/ipatch.h @@ -1,53 +1,53 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _IPATCH_H_ -#define _IPATCH_H_ - -// -// API for patch stuff -// - -#define PATCH_MAJOR "patch" -// {4715565b-ab3a-49fa-841f-ee965b6d88a5} -static const GUID QERPatchTable_GUID = -{ 0x4715565b, 0xab3a, 0x49fa, { 0x84, 0x1f, 0xee, 0x96, 0x5b, 0x6d, 0x88, 0xa5 } }; - -typedef patchMesh_t* (* PFN_PATCHALLOC) (); -typedef patchMesh_t* (* PFN_MAKENEWPATCH) (); -typedef brush_t* (* PFN_ADDBRUSHFORPATCH) (patchMesh_t *pm, bool bLinkToWorld ); - -struct _QERPatchTable -{ - int m_nSize; - PFN_PATCHALLOC m_pfnPatch_Alloc; - PFN_MAKENEWPATCH m_pfnMakeNewPatch; - PFN_ADDBRUSHFORPATCH m_pfnAddBrushForPatch; -}; - -#ifdef USE_PATCHTABLE_DEFINE -#define __PATCHTABLENAME g_PatchTable -#define Patch_Alloc __PATCHTABLENAME.m_pfnPatch_Alloc -#define MakeNewPatch __PATCHTABLENAME.m_pfnMakeNewPatch -#define AddBrushForPatch __PATCHTABLENAME.m_pfnAddBrushForPatch -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IPATCH_H_ +#define _IPATCH_H_ + +// +// API for patch stuff +// + +#define PATCH_MAJOR "patch" +// {4715565b-ab3a-49fa-841f-ee965b6d88a5} +static const GUID QERPatchTable_GUID = +{ 0x4715565b, 0xab3a, 0x49fa, { 0x84, 0x1f, 0xee, 0x96, 0x5b, 0x6d, 0x88, 0xa5 } }; + +typedef patchMesh_t* (* PFN_PATCHALLOC) (); +typedef patchMesh_t* (* PFN_MAKENEWPATCH) (); +typedef brush_t* (* PFN_ADDBRUSHFORPATCH) (patchMesh_t *pm, bool bLinkToWorld ); + +struct _QERPatchTable +{ + int m_nSize; + PFN_PATCHALLOC m_pfnPatch_Alloc; + PFN_MAKENEWPATCH m_pfnMakeNewPatch; + PFN_ADDBRUSHFORPATCH m_pfnAddBrushForPatch; +}; + +#ifdef USE_PATCHTABLE_DEFINE +#define __PATCHTABLENAME g_PatchTable +#define Patch_Alloc __PATCHTABLENAME.m_pfnPatch_Alloc +#define MakeNewPatch __PATCHTABLENAME.m_pfnMakeNewPatch +#define AddBrushForPatch __PATCHTABLENAME.m_pfnAddBrushForPatch +#endif + +#endif diff --git a/include/iplugin.h b/include/iplugin.h index e2974b9b..3f21bfef 100644 --- a/include/iplugin.h +++ b/include/iplugin.h @@ -1,41 +1,41 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _IPLUGIN_H_ -#define _IPLUGIN_H_ - -#define PLUGIN_MAJOR "plugin" - -typedef const char* (* PFN_QERPLUG_INIT) (void* hApp, void* pMainWidget); -typedef const char* (* PFN_QERPLUG_GETNAME) (); -typedef const char* (* PFN_QERPLUG_GETCOMMANDLIST) (); -typedef void (* PFN_QERPLUG_DISPATCH) (const char* p, float* vMin, float* vMax, bool bSingleBrush); - -struct _QERPluginTable -{ - int m_nSize; - PFN_QERPLUG_INIT m_pfnQERPlug_Init; - PFN_QERPLUG_GETNAME m_pfnQERPlug_GetName; - PFN_QERPLUG_GETCOMMANDLIST m_pfnQERPlug_GetCommandList; - PFN_QERPLUG_DISPATCH m_pfnQERPlug_Dispatch; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IPLUGIN_H_ +#define _IPLUGIN_H_ + +#define PLUGIN_MAJOR "plugin" + +typedef const char* (* PFN_QERPLUG_INIT) (void* hApp, void* pMainWidget); +typedef const char* (* PFN_QERPLUG_GETNAME) (); +typedef const char* (* PFN_QERPLUG_GETCOMMANDLIST) (); +typedef void (* PFN_QERPLUG_DISPATCH) (const char* p, float* vMin, float* vMax, bool bSingleBrush); + +struct _QERPluginTable +{ + int m_nSize; + PFN_QERPLUG_INIT m_pfnQERPlug_Init; + PFN_QERPLUG_GETNAME m_pfnQERPlug_GetName; + PFN_QERPLUG_GETCOMMANDLIST m_pfnQERPlug_GetCommandList; + PFN_QERPLUG_DISPATCH m_pfnQERPlug_Dispatch; +}; + +#endif diff --git a/include/irefcount.h b/include/irefcount.h index 2fc495ad..e49e80d7 100644 --- a/include/irefcount.h +++ b/include/irefcount.h @@ -1,62 +1,62 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef __IREFCOUNT_H__ -#define __IREFCOUNT_H__ - -/*! -\class IRefCounted -\brief reference counted objects - -general hints: how to use ref count properly - we consider ref counting as an extension of new and delete operators - the main issue is 'when to incref' 'when to decref' - in most cases connected to function calls - the general thinking about that: - - if you get a pointer to a refcounted object through a call to a function, assume that this object has been 'reserved' for you - already (i.e. allocated if you think this the new/delete way). so if you keep the object, you don't need to incref it, and if - you don't keep it you need to decref it. - - if you are called in a function and a refcounted object passed as parameter, then you should assume that this is an optional - object given to you FYI, which you don't need to decref if you don't keep / need to incref if you keep - - refcount is initialized to 1 in constructor. that serves for static objects and memory allocator - when you allocate in memory a ref counted object, it's default ref count will be 1, you should never delete it but just call DecRef on it - -define an interface and an implementation macro to make things easier -NOTE: we may have to provide a static library to go with that - in case we would move irecount.h out of here into libs/ - -\todo functionality needed: -mostly enable/disable some features with compile time flags (independently from each other as much as possible) -- log the destructor calls with != 0 ref count -- log all incref/decref (with module info, and maybe even file/line number etc.?) -*/ -class IRefCounted -{ - int refCount; -public: - IRefCounted() { refCount = 1; } - virtual ~IRefCounted() { } - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } -}; - -#endif // __ISYNAPSE_H__ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __IREFCOUNT_H__ +#define __IREFCOUNT_H__ + +/*! +\class IRefCounted +\brief reference counted objects + +general hints: how to use ref count properly + we consider ref counting as an extension of new and delete operators + the main issue is 'when to incref' 'when to decref' + in most cases connected to function calls + the general thinking about that: + - if you get a pointer to a refcounted object through a call to a function, assume that this object has been 'reserved' for you + already (i.e. allocated if you think this the new/delete way). so if you keep the object, you don't need to incref it, and if + you don't keep it you need to decref it. + - if you are called in a function and a refcounted object passed as parameter, then you should assume that this is an optional + object given to you FYI, which you don't need to decref if you don't keep / need to incref if you keep + + refcount is initialized to 1 in constructor. that serves for static objects and memory allocator + when you allocate in memory a ref counted object, it's default ref count will be 1, you should never delete it but just call DecRef on it + +define an interface and an implementation macro to make things easier +NOTE: we may have to provide a static library to go with that + in case we would move irecount.h out of here into libs/ + +\todo functionality needed: +mostly enable/disable some features with compile time flags (independently from each other as much as possible) +- log the destructor calls with != 0 ref count +- log all incref/decref (with module info, and maybe even file/line number etc.?) +*/ +class IRefCounted +{ + int refCount; +public: + IRefCounted() { refCount = 1; } + virtual ~IRefCounted() { } + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } +}; + +#endif // __ISYNAPSE_H__ diff --git a/include/iscriplib.h b/include/iscriplib.h index 00ba6617..30b9bd8a 100644 --- a/include/iscriplib.h +++ b/include/iscriplib.h @@ -1,86 +1,86 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// all purpose scriplib interface for Q3Radiant plugins (cf. parse.h) -// - -#ifndef __ISCRIPLIB_H_ -#define __ISCRIPLIB_H_ - -/*! \file iscriplib.h - \brief function tables for Radiant core's text parsing functions - two token based parsers cohexist in Radiant - the primary one (GetToken UnGetToken etc.) is used on the .map parsing etc. - COM_Parse is another parser, used on .def parse for instance - - NOTE: I hope we can totally get rid of this part when we have XML support -*/ - -#define SCRIPLIB_MAJOR "scriptlib" - -typedef qboolean (* PFN_GETTOKEN) (qboolean crossline); -typedef void (* PFN_UNGETTOKEN) (); -// only used to retrieve &token -typedef char* (* PFN_TOKEN) (); -typedef void (* PFN_STARTTOKENPARSING) (char *); -// script line -typedef int (* PFN_SCRIPTLINE) (); -typedef qboolean (* PFN_TOKENAVAILABLE) (); -// COM_Parse -typedef char* (* PFN_COM_PARSE) (char *data); -typedef char* (* PFN_GET_COM_TOKEN) (); -// Hydra: added support for GetTokenExtra() -typedef qboolean (* PFN_GETTOKENEXTRA) (qboolean crossline,char *delimiters,qboolean keepdelimiter); - -struct _QERScripLibTable -{ - float m_fVersion; - int m_nSize; - PFN_GETTOKEN m_pfnGetToken; - PFN_GETTOKENEXTRA m_pfnGetTokenExtra; // Hydra: added support for GetTokenExtra() - PFN_UNGETTOKEN m_pfnUnGetToken; - PFN_TOKEN m_pfnToken; - PFN_STARTTOKENPARSING m_pfnStartTokenParsing; - PFN_SCRIPTLINE m_pfnScriptLine; - PFN_TOKENAVAILABLE m_pfnTokenAvailable; - PFN_COM_PARSE m_pfnCOM_Parse; - PFN_GET_COM_TOKEN m_pfnGet_COM_Token; -}; - -#ifdef USE_SCRIPLIBTABLE_DEFINE -#ifndef __SCRIPLIBTABLENAME -#define __SCRIPLIBTABLENAME g_ScripLibTable -#endif -#define GetToken __SCRIPLIBTABLENAME.m_pfnGetToken -#define Token __SCRIPLIBTABLENAME.m_pfnToken -#define UnGetToken __SCRIPLIBTABLENAME.m_pfnUnGetToken -#define StartTokenParsing __SCRIPLIBTABLENAME.m_pfnStartTokenParsing -#define ScriptLine __SCRIPLIBTABLENAME.m_pfnScriptLine -#define TokenAvailable __SCRIPLIBTABLENAME.m_pfnTokenAvailable -#define COM_Parse __SCRIPLIBTABLENAME.m_pfnCOM_Parse -#define Get_COM_Token __SCRIPLIBTABLENAME.m_pfnGet_COM_Token -#define GetTokenExtra __SCRIPLIBTABLENAME.m_pfnGetTokenExtra // Hydra: added support for GetTokenExtra() -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// all purpose scriplib interface for Q3Radiant plugins (cf. parse.h) +// + +#ifndef __ISCRIPLIB_H_ +#define __ISCRIPLIB_H_ + +/*! \file iscriplib.h + \brief function tables for Radiant core's text parsing functions + two token based parsers cohexist in Radiant + the primary one (GetToken UnGetToken etc.) is used on the .map parsing etc. + COM_Parse is another parser, used on .def parse for instance + + NOTE: I hope we can totally get rid of this part when we have XML support +*/ + +#define SCRIPLIB_MAJOR "scriptlib" + +typedef qboolean (* PFN_GETTOKEN) (qboolean crossline); +typedef void (* PFN_UNGETTOKEN) (); +// only used to retrieve &token +typedef char* (* PFN_TOKEN) (); +typedef void (* PFN_STARTTOKENPARSING) (char *); +// script line +typedef int (* PFN_SCRIPTLINE) (); +typedef qboolean (* PFN_TOKENAVAILABLE) (); +// COM_Parse +typedef char* (* PFN_COM_PARSE) (char *data); +typedef char* (* PFN_GET_COM_TOKEN) (); +// Hydra: added support for GetTokenExtra() +typedef qboolean (* PFN_GETTOKENEXTRA) (qboolean crossline,char *delimiters,qboolean keepdelimiter); + +struct _QERScripLibTable +{ + float m_fVersion; + int m_nSize; + PFN_GETTOKEN m_pfnGetToken; + PFN_GETTOKENEXTRA m_pfnGetTokenExtra; // Hydra: added support for GetTokenExtra() + PFN_UNGETTOKEN m_pfnUnGetToken; + PFN_TOKEN m_pfnToken; + PFN_STARTTOKENPARSING m_pfnStartTokenParsing; + PFN_SCRIPTLINE m_pfnScriptLine; + PFN_TOKENAVAILABLE m_pfnTokenAvailable; + PFN_COM_PARSE m_pfnCOM_Parse; + PFN_GET_COM_TOKEN m_pfnGet_COM_Token; +}; + +#ifdef USE_SCRIPLIBTABLE_DEFINE +#ifndef __SCRIPLIBTABLENAME +#define __SCRIPLIBTABLENAME g_ScripLibTable +#endif +#define GetToken __SCRIPLIBTABLENAME.m_pfnGetToken +#define Token __SCRIPLIBTABLENAME.m_pfnToken +#define UnGetToken __SCRIPLIBTABLENAME.m_pfnUnGetToken +#define StartTokenParsing __SCRIPLIBTABLENAME.m_pfnStartTokenParsing +#define ScriptLine __SCRIPLIBTABLENAME.m_pfnScriptLine +#define TokenAvailable __SCRIPLIBTABLENAME.m_pfnTokenAvailable +#define COM_Parse __SCRIPLIBTABLENAME.m_pfnCOM_Parse +#define Get_COM_Token __SCRIPLIBTABLENAME.m_pfnGet_COM_Token +#define GetTokenExtra __SCRIPLIBTABLENAME.m_pfnGetTokenExtra // Hydra: added support for GetTokenExtra() +#endif + +#endif diff --git a/include/iselectedface.h b/include/iselectedface.h index a01c5283..61bc70d4 100644 --- a/include/iselectedface.h +++ b/include/iselectedface.h @@ -1,88 +1,88 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// Quick interface hack for selected face interface -// this one really needs more work, but I'm in a hurry with TexTool - -#ifndef __ISELECTEDFACE_H_ -#define __ISELECTEDFACE_H_ - -#define SELECTEDFACE_MAJOR "selectedface" -// v2.0 -// support for multiple faces selection (first use in textool v2) -// using the g_ptrSelectedFaces indexes, get the face_t* with GETFACE -// still relies on the _QERFaceData*, unless you cast the face_t* to do your own stuff -// removed PFN_TEXTUREFORNAME, it's in the IShaders API now - -//++timo TODO: this interface needs some cleanup with the new texture / shaders interface - -// number of selected textures -typedef int (WINAPI* PFN_GETSELECTEDFACECOUNT) (); -// retrieve the corresponding brush_t* (we need it when we need to explicitely rebuild stuff) -typedef brush_t* (WINAPI* PFN_GETFACEBRUSH) (int iface); -// retrieve a given face_t* -typedef face_t* (WINAPI* PFN_GETFACE) (int iface); -// winding_t is assumed to have MAX_POINTS_ON_WINDING allocated and waiting -typedef int (WINAPI* PFN_GETFACEINFO) (int iface, _QERFaceData*, winding_t* ); -// tell editor to update the selected face data -typedef int (WINAPI* PFN_SETFACEINFO) (int iface, _QERFaceData*); -// retrieve the texture number to bind to -typedef int (WINAPI* PFN_GETTEXTURENUMBER) (int iface); -// retrieving some texture information -typedef void (WINAPI* PFN_GETTEXTURESIZE) (int iface, int Size[2] ); -// straight func pointer to Select_SetTexture -// last parameter must be casted to an IPluginTexdef -typedef void (WINAPI* PFN_SELECT_SETTEXTURE) (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef); - -// NOTE: some things in there are not really related to the selected face -// having some stuff moved into a textures-dedicated part ? -struct _QERSelectedFaceTable -{ - int m_nSize; - PFN_GETSELECTEDFACECOUNT m_pfnGetSelectedFaceCount; - PFN_GETFACEBRUSH m_pfnGetFaceBrush; - PFN_GETFACE m_pfnGetFace; - PFN_GETFACEINFO m_pfnGetFaceInfo; - PFN_SETFACEINFO m_pfnSetFaceInfo; - PFN_GETTEXTURENUMBER m_pfnGetTextureNumber; - PFN_GETTEXTURESIZE m_pfnGetTextureSize; - PFN_SELECT_SETTEXTURE m_pfnSelect_SetTexture; -}; - -#ifdef USE_SELECTEDFACETABLE_DEFINE - #ifndef __SELECTEDFACETABLENAME - #define __SELECTEDFACETABLENAME g_SelectedFaceTable - #endif - - #define GetSelectedFaceCount __SELECTEDFACETABLENAME.m_pfnGetSelectedFaceCount - #define GetFaceBrush __SELECTEDFACETABLENAME.m_pfnGetFaceBrush - #define GetFace __SELECTEDFACETABLENAME.m_pfnGetFace - #define GetFaceInfo __SELECTEDFACETABLENAME.m_pfnGetFaceInfo - #define SetFaceInfo __SELECTEDFACETABLENAME.m_pfnSetFaceInfo - #define GetTextureNumber __SELECTEDFACETABLENAME.m_pfnGetTextureNumber - #define GetTextureSize __SELECTEDFACETABLENAME.m_pfnGetTextureSize - #define Select_SetTexture __SELECTEDFACETABLENAME.m_pfnSelect_SetTexture -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// Quick interface hack for selected face interface +// this one really needs more work, but I'm in a hurry with TexTool + +#ifndef __ISELECTEDFACE_H_ +#define __ISELECTEDFACE_H_ + +#define SELECTEDFACE_MAJOR "selectedface" +// v2.0 +// support for multiple faces selection (first use in textool v2) +// using the g_ptrSelectedFaces indexes, get the face_t* with GETFACE +// still relies on the _QERFaceData*, unless you cast the face_t* to do your own stuff +// removed PFN_TEXTUREFORNAME, it's in the IShaders API now + +//++timo TODO: this interface needs some cleanup with the new texture / shaders interface + +// number of selected textures +typedef int (WINAPI* PFN_GETSELECTEDFACECOUNT) (); +// retrieve the corresponding brush_t* (we need it when we need to explicitely rebuild stuff) +typedef brush_t* (WINAPI* PFN_GETFACEBRUSH) (int iface); +// retrieve a given face_t* +typedef face_t* (WINAPI* PFN_GETFACE) (int iface); +// winding_t is assumed to have MAX_POINTS_ON_WINDING allocated and waiting +typedef int (WINAPI* PFN_GETFACEINFO) (int iface, _QERFaceData*, winding_t* ); +// tell editor to update the selected face data +typedef int (WINAPI* PFN_SETFACEINFO) (int iface, _QERFaceData*); +// retrieve the texture number to bind to +typedef int (WINAPI* PFN_GETTEXTURENUMBER) (int iface); +// retrieving some texture information +typedef void (WINAPI* PFN_GETTEXTURESIZE) (int iface, int Size[2] ); +// straight func pointer to Select_SetTexture +// last parameter must be casted to an IPluginTexdef +typedef void (WINAPI* PFN_SELECT_SETTEXTURE) (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef); + +// NOTE: some things in there are not really related to the selected face +// having some stuff moved into a textures-dedicated part ? +struct _QERSelectedFaceTable +{ + int m_nSize; + PFN_GETSELECTEDFACECOUNT m_pfnGetSelectedFaceCount; + PFN_GETFACEBRUSH m_pfnGetFaceBrush; + PFN_GETFACE m_pfnGetFace; + PFN_GETFACEINFO m_pfnGetFaceInfo; + PFN_SETFACEINFO m_pfnSetFaceInfo; + PFN_GETTEXTURENUMBER m_pfnGetTextureNumber; + PFN_GETTEXTURESIZE m_pfnGetTextureSize; + PFN_SELECT_SETTEXTURE m_pfnSelect_SetTexture; +}; + +#ifdef USE_SELECTEDFACETABLE_DEFINE + #ifndef __SELECTEDFACETABLENAME + #define __SELECTEDFACETABLENAME g_SelectedFaceTable + #endif + + #define GetSelectedFaceCount __SELECTEDFACETABLENAME.m_pfnGetSelectedFaceCount + #define GetFaceBrush __SELECTEDFACETABLENAME.m_pfnGetFaceBrush + #define GetFace __SELECTEDFACETABLENAME.m_pfnGetFace + #define GetFaceInfo __SELECTEDFACETABLENAME.m_pfnGetFaceInfo + #define SetFaceInfo __SELECTEDFACETABLENAME.m_pfnSetFaceInfo + #define GetTextureNumber __SELECTEDFACETABLENAME.m_pfnGetTextureNumber + #define GetTextureSize __SELECTEDFACETABLENAME.m_pfnGetTextureSize + #define Select_SetTexture __SELECTEDFACETABLENAME.m_pfnSelect_SetTexture +#endif + +#endif diff --git a/include/ishaders.h b/include/ishaders.h index 17cafc36..e50233ed 100644 --- a/include/ishaders.h +++ b/include/ishaders.h @@ -1,284 +1,284 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// -// DESCRIPTION: -// a set of functions to manipulate textures in Radiant -// - -#ifndef __ISHADERS_H_ -#define __ISHADERS_H_ - -#define SHADERS_MAJOR "shaders" -// define a GUID for this interface so plugins can access and reference it -// {D42F798A-DF57-11d3-A3EE-0004AC96D4C3} -static const GUID QERShadersTable_GUID = -{ 0xd42f798a, 0xdf57, 0x11d3, { 0xa3, 0xee, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - -// NOTES ABOUT SYNTAX: -// if a function starts by 'Try' it means that if the requested thing could not be found / loaded it will return nothing / NULL -// otherwise a default object will be created -// the _QERShadersTable is also used by shader code inside Radiant. but for speed and "keep it simple" consideration you -// can get the static equivalent of the func pointers by adding 'QERApp_' (access to _QERShadersTable is better thought .. -// see the note to move all the shader language out of Radiant below) - -/*! -\todo FIXME TTimo -fix the reference count strategy -- define the policy. It seems the initial policy of doing an inc ref when you create the shader is not good -(it doesn't work, and it's not being used right) -so, when you request an IShader and store it, incref it yourself -as a debugging safe check: push the created increfed objects into a list, and scan them at next idle loop -to make sure they have been decref'ed ? (sounds easy, may not be that much). -*/ - -class IShader -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // get/set the qtexture_t* Radiant uses to represent this shader object - virtual qtexture_t* getTexture() const = 0; - virtual void setTexture(qtexture_t *pTex) = 0; - // get shader name - virtual const char* getName() const = 0; - // is this shader in use? - // NOTE: this flag can mean this shader has been in use at least once since the last rescan of in-use stuff - // (rescan of in-use happens in several cases, user command or during a texture directory load) - // NOTE: this is used to draw the green outline in the texture window - // NOTE: when does Radiant set the InUse flag? Whenever Select_SetTexture is called (well that doesn't necessarily means the texture actually gets in use, but that's close enough) - virtual bool IsInUse() const = 0; - virtual void SetInUse(bool) = 0; - // is this shader displayed in the texture browser? - // NOTE: if IsInUse() == true, the shader will always be displayed in the texture window and this flag ingored - virtual bool IsDisplayed() const = 0; - virtual void SetDisplayed(bool) = 0; - // get the editor flags (QER_NOCARVE QER_TRANS) - virtual int getFlags() = 0; - // get the transparency value - virtual float getTrans() = 0; - // test if it's a true shader, or a default shader created to wrap around a texture - virtual bool IsDefault() = 0; - // test if it's a plain color shader, i.e. a shader we use on plain color stuff (like info_playerstart) - virtual bool IsColor() = 0; - // get the related color then! - virtual void getColor(vec3_t v) = 0; - // get the alphaFunc - virtual void getAlphaFunc(int *func, float *ref) = 0; - // get the cull type - virtual int getCull() = 0; - // get shader file name (ie the file where this one is defined) - virtual const char* getShaderFileName() const = 0; -}; - -// NOTE: how to move all the shader language out of Radiant in a plugin? -// -> change this _QERShadersTable into an IShadersManager -// -> let the plugin create an instance of IShadersManager -// -> make sure Radiant uses this IShadersManager to load / query the shaders - -// NOTE: shader and texture names used must be full path, ie. most often with "textures/" prefix -// (since shaders are defined in .shader files with textures/) - -// free all shaders -// free the shaders, will not free the qtexture_t* -typedef void (WINAPI* PFN_FREESHADERS) (); -// reload all the shaders -// this will free everything (shaders and their textures), then reload all in use stuff -typedef void (WINAPI* PFN_RELOADSHADERS) (); -// load all shaders in a given directory -// this will scan the list of in-memory shaders, and load the related qtexture_t if needed -typedef int (WINAPI* PFN_LOADSHADERSFROMDIR)(const char* path); -// load a shader file (ie a set of shaders) -// after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses to represent them -// if a shader with the same name exists, new one will not be loaded - don't use this to refresh the shaders! -typedef void (WINAPI* PFN_LOADSHADERFILE) (const char* filename); -// tell if a given shader exists in our shader table -// NOTE: this doesn't tell wether it's corresponding qtexture is loaded -typedef int (WINAPI* PFN_HASSHADER) (const char* name); -// return the shader for a given name -// if the qtexture is not already in memory, will try loading it -// if the qtexture could not be found, will use default -// will return NULL on shader not found -typedef IShader* (WINAPI* PFN_TRYSHADERFORNAME) (const char* name); -// return the shader for a given name -// if the qtexture is not already in memory, will try loading it -// will create a default shader if not found (will use a default texture) -typedef IShader* (WINAPI* PFN_SHADERFORNAME) (const char* name); -// query / load a texture -// will not try loading a shader, will look for the actual image file .. -// returns NULL on file not found -// NOTE: strategy for file lookup: -// paths must be relative, ie. textures/me/myfile -// if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first -// if not found or no extension, will try loading after adding .tga and .jpg (in this order) -typedef qtexture_t* (WINAPI* PFN_TRYTEXTUREFORNAME) (const char* filename); -// query / load a texture -// will not try loading a shader, will look for the actual image file .. -// on file not found will use the "texture not found" -typedef qtexture_t* (WINAPI* PFN_TEXTUREFORNAME) (const char* filename); -// get the number of active shaders -// these are the shaders currently loaded, that have an associated qtexture_t* -typedef int (WINAPI* PFN_GETACTIVESHADERCOUNT) (); -// for stuff that needs to be represented by a plain texture -// the shader will get a "color" name, use GetColor to get the actual color -typedef IShader* (WINAPI* PFN_COLORSHADERFORNAME) (const char* name); -// reload a shaderfile - update shaders and their display properties/qtexture_t if needed -// will not reload the texture files -// will switch to "show in use" atfer use -// filename must be reletive path of the shader, ex. scripts/gothic_wall.shader -typedef void (WINAPI* PFN_RELOADSHADERFILE)(const char* filename); -// retrieve a shader if exists, without loading the textures for it etc. -// use this function if you want special info on a shader -typedef IShader* (WINAPI* PFN_SHADERFORNAMENOLOAD) (const char* name); -// force the "in use" flag on all active shaders -typedef void (WINAPI* PFN_ACTIVESHADERSSETINUSE) (bool b); -// sort the shaders in alphabetical order, we use the order in the texture inspector -typedef void (WINAPI* PFN_SORTACTIVESHADERS) (); -// check if there exists an active shader with the given texture name (loaded or not, doesn't matter) -// (used to detect the textures we need to create a default shader for .. while scanning a directory) -typedef IShader* (WINAPI* PFN_ACTIVESHADERFORTEXTURENAME) (char *); -// create a shader to wrap around a texture name, we use this when loading a texture directory and some textures -// are not present as shaders -typedef IShader* (WINAPI* PFN_CREATESHADERFORTEXTURENAME) (const char* name); -// switch the IsDisplayed flag on all the active shaders -typedef void (WINAPI* PFN_ACTIVESHADERSSETDISPLAYED) (bool b); -// retrieve an active shader based on index -typedef IShader* (WINAPI* PFN_ACTIVESHADERFORINDEX) (int i); -// will cleanup a texture name and force it to the right format -// the debug version is painfully slow, but will detect more problems -// the idea being to avoid loading the same file several time because of uppercase/lowercase etc. -typedef const char* (WINAPI* PFN_CLEANTEXTURENAME) (const char* name, bool bAddTexture); - -struct _QERShadersTable -{ - int m_nSize; - PFN_FREESHADERS m_pfnFreeShaders; - PFN_RELOADSHADERS m_pfnReloadShaders; - PFN_LOADSHADERSFROMDIR m_pfnLoadShadersFromDir; - PFN_LOADSHADERFILE m_pfnLoadShaderFile; - PFN_RELOADSHADERFILE m_pfnReloadShaderFile; - PFN_HASSHADER m_pfnHasShader; - PFN_TRYSHADERFORNAME m_pfnTry_Shader_ForName; - PFN_SHADERFORNAME m_pfnShader_ForName; - PFN_TRYTEXTUREFORNAME m_pfnTry_Texture_ForName; - PFN_TEXTUREFORNAME m_pfnTexture_ForName; - PFN_GETACTIVESHADERCOUNT m_pfnGetActiveShaderCount; - PFN_COLORSHADERFORNAME m_pfnColorShader_ForName; - PFN_SHADERFORNAMENOLOAD m_pfnShader_ForName_NoLoad; - PFN_ACTIVESHADERSSETINUSE m_pfnActiveShaders_SetInUse; - PFN_SORTACTIVESHADERS m_pfnSortActiveShaders; - PFN_ACTIVESHADERFORTEXTURENAME m_pfnActiveShader_ForTextureName; - PFN_CREATESHADERFORTEXTURENAME m_pfnCreateShader_ForTextureName; - PFN_ACTIVESHADERSSETDISPLAYED m_pfnActiveShaders_SetDisplayed; - PFN_ACTIVESHADERFORINDEX m_pfnActiveShader_ForIndex; - PFN_CLEANTEXTURENAME m_pfnCleanTextureName; -}; - -/*! -\todo FIXME fix the QERApp_ prototyping on shaders module -make it homogeneous with other modules, should be straight calls -*/ - -#ifdef USE_SHADERSTABLE_DEFINE - #ifndef __SHADERSTABLENAME - #define __SHADERSTABLENAME g_ShadersTable - #endif -#define QERApp_Shader_ForName __SHADERSTABLENAME.m_pfnShader_ForName -#define QERApp_Texture_ForName2 __SHADERSTABLENAME.m_pfnTexture_ForName -#define QERApp_FreeShaders __SHADERSTABLENAME.m_pfnFreeShaders -#define QERApp_ReloadShaders __SHADERSTABLENAME.m_pfnReloadShaders -#define QERApp_SortActiveShaders __SHADERSTABLENAME.m_pfnSortActiveShaders -#define QERApp_ReloadShaderFile __SHADERSTABLENAME.m_pfnReloadShaderFile -#define QERApp_LoadShaderFile __SHADERSTABLENAME.m_pfnLoadShaderFile -#define QERApp_HasShader __SHADERSTABLENAME.m_pfnHasShader -#define QERApp_Try_Shader_ForName __SHADERSTABLENAME.m_pfnTry_Shader_ForName -#define QERApp_Try_Texture_ForName __SHADERSTABLENAME.m_pfnTry_Texture_ForName -#define QERApp_ColorShader_ForName __SHADERSTABLENAME.m_pfnColorShader_ForName -#define QERApp_Shader_ForName_NoLoad __SHADERSTABLENAME.m_pfnShader_ForName_NoLoad -#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir -#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir -#define QERApp_CreateShader_ForTextureName __SHADERSTABLENAME.m_pfnCreateShader_ForTextureName -#define QERApp_GetActiveShaderCount __SHADERSTABLENAME.m_pfnGetActiveShaderCount -#define QERApp_ActiveShaders_SetDisplayed __SHADERSTABLENAME.m_pfnActiveShaders_SetDisplayed -#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex -#define QERApp_ActiveShaders_SetInUse __SHADERSTABLENAME.m_pfnActiveShaders_SetInUse -#define QERApp_ActiveShader_ForTextureName __SHADERSTABLENAME.m_pfnActiveShader_ForTextureName -#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex -#define QERApp_CleanTextureName __SHADERSTABLENAME.m_pfnCleanTextureName -#endif - -#define APPSHADERS_MAJOR "appshaders" -// FIXME: remove -static const GUID QERAppShadersTable_GUID = -{ 0xec3008a8, 0xbd0b, 0x11d4, { 0x82, 0x51, 0x20, 0x4c, 0x4f, 0x4f, 0x50, 0x20 } }; - -// g_qeglobals.d_qtextures is used internally by the editor for actual camera drawing -typedef qtexture_t** (WINAPI* PFN_QTEXTURES)(); -// g_qeglobals.d_qtexmap is a map for fast access -typedef GHashTable* (WINAPI* PFN_QTEXMAP)(); -// d_texturewin -//++timo NOTE: this same function is also in isurface.h table, we would eventually have to merge some stuff -typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN)(); -// Texture_SetTexture -//++timo NOTE: this one may have to be reorganized too .. putting it here is a bit clumsy -// NOTE: the C++ function used internally has a lot of default values -typedef void (WINAPI* PFN_TEXTURESETTEXTURE)(texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef); -// Texture_ShowInuse -typedef void (WINAPI* PFN_TEXTURESHOWINUSE)(); -// BuildShaderList -typedef void (* PFN_BUILDSHADERLIST)(); -// PreloadShaders -typedef void (* PFN_PRELOADSHADERS)(); - -// a table that Radiant makes available to the shader module in return -struct _QERAppShadersTable -{ - int m_nSize; - PFN_QTEXTURES m_pfnQTextures; - PFN_QTEXMAP m_pfnQTexmap; - PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; - PFN_TEXTURESETTEXTURE m_pfnTexture_SetTexture; - PFN_TEXTURESHOWINUSE m_pfnTexture_ShowInuse; - PFN_BUILDSHADERLIST m_pfnBuildShaderList; - PFN_PRELOADSHADERS m_pfnPreloadShaders; -}; - -#ifdef USE_APPSHADERSTABLE_DEFINE - #ifndef __APPSHADERTABLENAME - #define __APPSHADERTABLENAME g_AppShadersTable - #endif -#define Texture_ShowInuse __APPSHADERTABLENAME.m_pfnTexture_ShowInuse -#endif - -/*! -NOTE TTimo: there is an important distinction between SHADER_NOT_FOUND and SHADER_NOTEX: -SHADER_NOT_FOUND means we didn't find the raw texture or the shader for this -SHADER_NOTEX means we recognize this as a shader script, but we are missing the texture to represent it -this was in the initial design of the shader code since early GtkRadiant alpha, and got sort of foxed in 1.2 and put back in -*/ -#define SHADER_NOT_FOUND "textures/radiant/notex" -#define SHADER_NOTEX "textures/radiant/shadernotex" ///< Q3 tech specific - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// a set of functions to manipulate textures in Radiant +// + +#ifndef __ISHADERS_H_ +#define __ISHADERS_H_ + +#define SHADERS_MAJOR "shaders" +// define a GUID for this interface so plugins can access and reference it +// {D42F798A-DF57-11d3-A3EE-0004AC96D4C3} +static const GUID QERShadersTable_GUID = +{ 0xd42f798a, 0xdf57, 0x11d3, { 0xa3, 0xee, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +// NOTES ABOUT SYNTAX: +// if a function starts by 'Try' it means that if the requested thing could not be found / loaded it will return nothing / NULL +// otherwise a default object will be created +// the _QERShadersTable is also used by shader code inside Radiant. but for speed and "keep it simple" consideration you +// can get the static equivalent of the func pointers by adding 'QERApp_' (access to _QERShadersTable is better thought .. +// see the note to move all the shader language out of Radiant below) + +/*! +\todo FIXME TTimo +fix the reference count strategy +- define the policy. It seems the initial policy of doing an inc ref when you create the shader is not good +(it doesn't work, and it's not being used right) +so, when you request an IShader and store it, incref it yourself +as a debugging safe check: push the created increfed objects into a list, and scan them at next idle loop +to make sure they have been decref'ed ? (sounds easy, may not be that much). +*/ + +class IShader +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // get/set the qtexture_t* Radiant uses to represent this shader object + virtual qtexture_t* getTexture() const = 0; + virtual void setTexture(qtexture_t *pTex) = 0; + // get shader name + virtual const char* getName() const = 0; + // is this shader in use? + // NOTE: this flag can mean this shader has been in use at least once since the last rescan of in-use stuff + // (rescan of in-use happens in several cases, user command or during a texture directory load) + // NOTE: this is used to draw the green outline in the texture window + // NOTE: when does Radiant set the InUse flag? Whenever Select_SetTexture is called (well that doesn't necessarily means the texture actually gets in use, but that's close enough) + virtual bool IsInUse() const = 0; + virtual void SetInUse(bool) = 0; + // is this shader displayed in the texture browser? + // NOTE: if IsInUse() == true, the shader will always be displayed in the texture window and this flag ingored + virtual bool IsDisplayed() const = 0; + virtual void SetDisplayed(bool) = 0; + // get the editor flags (QER_NOCARVE QER_TRANS) + virtual int getFlags() = 0; + // get the transparency value + virtual float getTrans() = 0; + // test if it's a true shader, or a default shader created to wrap around a texture + virtual bool IsDefault() = 0; + // test if it's a plain color shader, i.e. a shader we use on plain color stuff (like info_playerstart) + virtual bool IsColor() = 0; + // get the related color then! + virtual void getColor(vec3_t v) = 0; + // get the alphaFunc + virtual void getAlphaFunc(int *func, float *ref) = 0; + // get the cull type + virtual int getCull() = 0; + // get shader file name (ie the file where this one is defined) + virtual const char* getShaderFileName() const = 0; +}; + +// NOTE: how to move all the shader language out of Radiant in a plugin? +// -> change this _QERShadersTable into an IShadersManager +// -> let the plugin create an instance of IShadersManager +// -> make sure Radiant uses this IShadersManager to load / query the shaders + +// NOTE: shader and texture names used must be full path, ie. most often with "textures/" prefix +// (since shaders are defined in .shader files with textures/) + +// free all shaders +// free the shaders, will not free the qtexture_t* +typedef void (WINAPI* PFN_FREESHADERS) (); +// reload all the shaders +// this will free everything (shaders and their textures), then reload all in use stuff +typedef void (WINAPI* PFN_RELOADSHADERS) (); +// load all shaders in a given directory +// this will scan the list of in-memory shaders, and load the related qtexture_t if needed +typedef int (WINAPI* PFN_LOADSHADERSFROMDIR)(const char* path); +// load a shader file (ie a set of shaders) +// after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses to represent them +// if a shader with the same name exists, new one will not be loaded - don't use this to refresh the shaders! +typedef void (WINAPI* PFN_LOADSHADERFILE) (const char* filename); +// tell if a given shader exists in our shader table +// NOTE: this doesn't tell wether it's corresponding qtexture is loaded +typedef int (WINAPI* PFN_HASSHADER) (const char* name); +// return the shader for a given name +// if the qtexture is not already in memory, will try loading it +// if the qtexture could not be found, will use default +// will return NULL on shader not found +typedef IShader* (WINAPI* PFN_TRYSHADERFORNAME) (const char* name); +// return the shader for a given name +// if the qtexture is not already in memory, will try loading it +// will create a default shader if not found (will use a default texture) +typedef IShader* (WINAPI* PFN_SHADERFORNAME) (const char* name); +// query / load a texture +// will not try loading a shader, will look for the actual image file .. +// returns NULL on file not found +// NOTE: strategy for file lookup: +// paths must be relative, ie. textures/me/myfile +// if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first +// if not found or no extension, will try loading after adding .tga and .jpg (in this order) +typedef qtexture_t* (WINAPI* PFN_TRYTEXTUREFORNAME) (const char* filename); +// query / load a texture +// will not try loading a shader, will look for the actual image file .. +// on file not found will use the "texture not found" +typedef qtexture_t* (WINAPI* PFN_TEXTUREFORNAME) (const char* filename); +// get the number of active shaders +// these are the shaders currently loaded, that have an associated qtexture_t* +typedef int (WINAPI* PFN_GETACTIVESHADERCOUNT) (); +// for stuff that needs to be represented by a plain texture +// the shader will get a "color" name, use GetColor to get the actual color +typedef IShader* (WINAPI* PFN_COLORSHADERFORNAME) (const char* name); +// reload a shaderfile - update shaders and their display properties/qtexture_t if needed +// will not reload the texture files +// will switch to "show in use" atfer use +// filename must be reletive path of the shader, ex. scripts/gothic_wall.shader +typedef void (WINAPI* PFN_RELOADSHADERFILE)(const char* filename); +// retrieve a shader if exists, without loading the textures for it etc. +// use this function if you want special info on a shader +typedef IShader* (WINAPI* PFN_SHADERFORNAMENOLOAD) (const char* name); +// force the "in use" flag on all active shaders +typedef void (WINAPI* PFN_ACTIVESHADERSSETINUSE) (bool b); +// sort the shaders in alphabetical order, we use the order in the texture inspector +typedef void (WINAPI* PFN_SORTACTIVESHADERS) (); +// check if there exists an active shader with the given texture name (loaded or not, doesn't matter) +// (used to detect the textures we need to create a default shader for .. while scanning a directory) +typedef IShader* (WINAPI* PFN_ACTIVESHADERFORTEXTURENAME) (char *); +// create a shader to wrap around a texture name, we use this when loading a texture directory and some textures +// are not present as shaders +typedef IShader* (WINAPI* PFN_CREATESHADERFORTEXTURENAME) (const char* name); +// switch the IsDisplayed flag on all the active shaders +typedef void (WINAPI* PFN_ACTIVESHADERSSETDISPLAYED) (bool b); +// retrieve an active shader based on index +typedef IShader* (WINAPI* PFN_ACTIVESHADERFORINDEX) (int i); +// will cleanup a texture name and force it to the right format +// the debug version is painfully slow, but will detect more problems +// the idea being to avoid loading the same file several time because of uppercase/lowercase etc. +typedef const char* (WINAPI* PFN_CLEANTEXTURENAME) (const char* name, bool bAddTexture); + +struct _QERShadersTable +{ + int m_nSize; + PFN_FREESHADERS m_pfnFreeShaders; + PFN_RELOADSHADERS m_pfnReloadShaders; + PFN_LOADSHADERSFROMDIR m_pfnLoadShadersFromDir; + PFN_LOADSHADERFILE m_pfnLoadShaderFile; + PFN_RELOADSHADERFILE m_pfnReloadShaderFile; + PFN_HASSHADER m_pfnHasShader; + PFN_TRYSHADERFORNAME m_pfnTry_Shader_ForName; + PFN_SHADERFORNAME m_pfnShader_ForName; + PFN_TRYTEXTUREFORNAME m_pfnTry_Texture_ForName; + PFN_TEXTUREFORNAME m_pfnTexture_ForName; + PFN_GETACTIVESHADERCOUNT m_pfnGetActiveShaderCount; + PFN_COLORSHADERFORNAME m_pfnColorShader_ForName; + PFN_SHADERFORNAMENOLOAD m_pfnShader_ForName_NoLoad; + PFN_ACTIVESHADERSSETINUSE m_pfnActiveShaders_SetInUse; + PFN_SORTACTIVESHADERS m_pfnSortActiveShaders; + PFN_ACTIVESHADERFORTEXTURENAME m_pfnActiveShader_ForTextureName; + PFN_CREATESHADERFORTEXTURENAME m_pfnCreateShader_ForTextureName; + PFN_ACTIVESHADERSSETDISPLAYED m_pfnActiveShaders_SetDisplayed; + PFN_ACTIVESHADERFORINDEX m_pfnActiveShader_ForIndex; + PFN_CLEANTEXTURENAME m_pfnCleanTextureName; +}; + +/*! +\todo FIXME fix the QERApp_ prototyping on shaders module +make it homogeneous with other modules, should be straight calls +*/ + +#ifdef USE_SHADERSTABLE_DEFINE + #ifndef __SHADERSTABLENAME + #define __SHADERSTABLENAME g_ShadersTable + #endif +#define QERApp_Shader_ForName __SHADERSTABLENAME.m_pfnShader_ForName +#define QERApp_Texture_ForName2 __SHADERSTABLENAME.m_pfnTexture_ForName +#define QERApp_FreeShaders __SHADERSTABLENAME.m_pfnFreeShaders +#define QERApp_ReloadShaders __SHADERSTABLENAME.m_pfnReloadShaders +#define QERApp_SortActiveShaders __SHADERSTABLENAME.m_pfnSortActiveShaders +#define QERApp_ReloadShaderFile __SHADERSTABLENAME.m_pfnReloadShaderFile +#define QERApp_LoadShaderFile __SHADERSTABLENAME.m_pfnLoadShaderFile +#define QERApp_HasShader __SHADERSTABLENAME.m_pfnHasShader +#define QERApp_Try_Shader_ForName __SHADERSTABLENAME.m_pfnTry_Shader_ForName +#define QERApp_Try_Texture_ForName __SHADERSTABLENAME.m_pfnTry_Texture_ForName +#define QERApp_ColorShader_ForName __SHADERSTABLENAME.m_pfnColorShader_ForName +#define QERApp_Shader_ForName_NoLoad __SHADERSTABLENAME.m_pfnShader_ForName_NoLoad +#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir +#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir +#define QERApp_CreateShader_ForTextureName __SHADERSTABLENAME.m_pfnCreateShader_ForTextureName +#define QERApp_GetActiveShaderCount __SHADERSTABLENAME.m_pfnGetActiveShaderCount +#define QERApp_ActiveShaders_SetDisplayed __SHADERSTABLENAME.m_pfnActiveShaders_SetDisplayed +#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex +#define QERApp_ActiveShaders_SetInUse __SHADERSTABLENAME.m_pfnActiveShaders_SetInUse +#define QERApp_ActiveShader_ForTextureName __SHADERSTABLENAME.m_pfnActiveShader_ForTextureName +#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex +#define QERApp_CleanTextureName __SHADERSTABLENAME.m_pfnCleanTextureName +#endif + +#define APPSHADERS_MAJOR "appshaders" +// FIXME: remove +static const GUID QERAppShadersTable_GUID = +{ 0xec3008a8, 0xbd0b, 0x11d4, { 0x82, 0x51, 0x20, 0x4c, 0x4f, 0x4f, 0x50, 0x20 } }; + +// g_qeglobals.d_qtextures is used internally by the editor for actual camera drawing +typedef qtexture_t** (WINAPI* PFN_QTEXTURES)(); +// g_qeglobals.d_qtexmap is a map for fast access +typedef GHashTable* (WINAPI* PFN_QTEXMAP)(); +// d_texturewin +//++timo NOTE: this same function is also in isurface.h table, we would eventually have to merge some stuff +typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN)(); +// Texture_SetTexture +//++timo NOTE: this one may have to be reorganized too .. putting it here is a bit clumsy +// NOTE: the C++ function used internally has a lot of default values +typedef void (WINAPI* PFN_TEXTURESETTEXTURE)(texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef); +// Texture_ShowInuse +typedef void (WINAPI* PFN_TEXTURESHOWINUSE)(); +// BuildShaderList +typedef void (* PFN_BUILDSHADERLIST)(); +// PreloadShaders +typedef void (* PFN_PRELOADSHADERS)(); + +// a table that Radiant makes available to the shader module in return +struct _QERAppShadersTable +{ + int m_nSize; + PFN_QTEXTURES m_pfnQTextures; + PFN_QTEXMAP m_pfnQTexmap; + PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; + PFN_TEXTURESETTEXTURE m_pfnTexture_SetTexture; + PFN_TEXTURESHOWINUSE m_pfnTexture_ShowInuse; + PFN_BUILDSHADERLIST m_pfnBuildShaderList; + PFN_PRELOADSHADERS m_pfnPreloadShaders; +}; + +#ifdef USE_APPSHADERSTABLE_DEFINE + #ifndef __APPSHADERTABLENAME + #define __APPSHADERTABLENAME g_AppShadersTable + #endif +#define Texture_ShowInuse __APPSHADERTABLENAME.m_pfnTexture_ShowInuse +#endif + +/*! +NOTE TTimo: there is an important distinction between SHADER_NOT_FOUND and SHADER_NOTEX: +SHADER_NOT_FOUND means we didn't find the raw texture or the shader for this +SHADER_NOTEX means we recognize this as a shader script, but we are missing the texture to represent it +this was in the initial design of the shader code since early GtkRadiant alpha, and got sort of foxed in 1.2 and put back in +*/ +#define SHADER_NOT_FOUND "textures/radiant/notex" +#define SHADER_NOTEX "textures/radiant/shadernotex" ///< Q3 tech specific + +#endif diff --git a/include/ishadersmanager.h b/include/ishadersmanager.h index a9bf0f03..06ac9d32 100644 --- a/include/ishadersmanager.h +++ b/include/ishadersmanager.h @@ -1,102 +1,102 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _ISHADERSMANAGER_H_ -#define _ISHADERSMANAGER_H_ - -class IShadersManager -{ - public: - IShadersManager (); - virtual ~IShadersManager (); - - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - - // free all shaders - // free the shaders, will not free the qtexture_t* - virtual void FreeShaders () = 0; - - // reload all the shaders - // this will free everything (shaders and their textures), then reload all in use stuff - virtual void ReloadShaders () = 0; - - // load all shaders in a given directory - // this will scan the list of in-memory shaders, and load the related qtexture_t if needed - virtual void LoadShadersFromDir (const char* path) = 0; - - // load a shader file (ie a set of shaders) - // after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses - // to represent them if a shader with the same name exists, new one will not be loaded - // don't use this to refresh the shaders! - virtual void LoadShaderFile (const char* filename) = 0; - - // tell if a given shader exists in our shader table - // NOTE: this doesn't tell wether it's corresponding qtexture is loaded - virtual int HasShader (const char* name) = 0; - - // return the shader for a given name - // if the qtexture is not already in memory, will try loading it - // if the qtexture could not be found, will use default - // will return NULL on shader not found - virtual IShader* Try_Shader_ForName (const char* name) = 0; - - // return the shader for a given name - // if the qtexture is not already in memory, will try loading it - // will create a default shader if not found (will use a default texture) - virtual IShader* Shader_ForName (const char* name) = 0; - - // query / load a texture - // will not try loading a shader, will look for the actual image file .. - // returns NULL on file not found - // NOTE: strategy for file lookup: - // paths must be relative, ie. textures/me/myfile - // if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first - // if not found or no extension, will try loading after adding .tga and .jpg (in this order) - virtual qtexture_t* Try_Texture_ForName (const char* filename) = 0; - - // query / load a texture - // will not try loading a shader, will look for the actual image file .. - // on file not found will use the "texture not found" - virtual qtexture_t* Texture_ForName (const char* filename) = 0; - - // get the number of active shaders - // these are the shaders currently loaded, that have an associated qtexture_t* - virtual int GetActiveShaderCount () = 0; - - // for stuff that needs to be represented by a plain texture - // the shader will get a "color" name, use GetColor to get the actual color - virtual IShader* ColorShader_ForName (const char* name) = 0; - - // reload a shaderfile - update shaders and their display properties/qtexture_t if needed - // will not reload the texture files - // will switch to "show in use" atfer use - // filename must be reletive path of the shader, ex. scripts/gothic_wall.shader - virtual void ReloadShaderFile (const char* filename) = 0; - - // retrieve a shader if exists, without loading the textures for it etc. - // use this function if you want special info on a shader - virtual IShader* Shader_ForName_NoLoad (const char* name) = 0; -}; - -#endif // _ISHADERSMANAGER_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _ISHADERSMANAGER_H_ +#define _ISHADERSMANAGER_H_ + +class IShadersManager +{ + public: + IShadersManager (); + virtual ~IShadersManager (); + + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + + // free all shaders + // free the shaders, will not free the qtexture_t* + virtual void FreeShaders () = 0; + + // reload all the shaders + // this will free everything (shaders and their textures), then reload all in use stuff + virtual void ReloadShaders () = 0; + + // load all shaders in a given directory + // this will scan the list of in-memory shaders, and load the related qtexture_t if needed + virtual void LoadShadersFromDir (const char* path) = 0; + + // load a shader file (ie a set of shaders) + // after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses + // to represent them if a shader with the same name exists, new one will not be loaded + // don't use this to refresh the shaders! + virtual void LoadShaderFile (const char* filename) = 0; + + // tell if a given shader exists in our shader table + // NOTE: this doesn't tell wether it's corresponding qtexture is loaded + virtual int HasShader (const char* name) = 0; + + // return the shader for a given name + // if the qtexture is not already in memory, will try loading it + // if the qtexture could not be found, will use default + // will return NULL on shader not found + virtual IShader* Try_Shader_ForName (const char* name) = 0; + + // return the shader for a given name + // if the qtexture is not already in memory, will try loading it + // will create a default shader if not found (will use a default texture) + virtual IShader* Shader_ForName (const char* name) = 0; + + // query / load a texture + // will not try loading a shader, will look for the actual image file .. + // returns NULL on file not found + // NOTE: strategy for file lookup: + // paths must be relative, ie. textures/me/myfile + // if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first + // if not found or no extension, will try loading after adding .tga and .jpg (in this order) + virtual qtexture_t* Try_Texture_ForName (const char* filename) = 0; + + // query / load a texture + // will not try loading a shader, will look for the actual image file .. + // on file not found will use the "texture not found" + virtual qtexture_t* Texture_ForName (const char* filename) = 0; + + // get the number of active shaders + // these are the shaders currently loaded, that have an associated qtexture_t* + virtual int GetActiveShaderCount () = 0; + + // for stuff that needs to be represented by a plain texture + // the shader will get a "color" name, use GetColor to get the actual color + virtual IShader* ColorShader_ForName (const char* name) = 0; + + // reload a shaderfile - update shaders and their display properties/qtexture_t if needed + // will not reload the texture files + // will switch to "show in use" atfer use + // filename must be reletive path of the shader, ex. scripts/gothic_wall.shader + virtual void ReloadShaderFile (const char* filename) = 0; + + // retrieve a shader if exists, without loading the textures for it etc. + // use this function if you want special info on a shader + virtual IShader* Shader_ForName_NoLoad (const char* name) = 0; +}; + +#endif // _ISHADERSMANAGER_H_ diff --git a/include/isurfaceplugin.h b/include/isurfaceplugin.h index 6783bb2c..d7be03fd 100644 --- a/include/isurfaceplugin.h +++ b/include/isurfaceplugin.h @@ -1,158 +1,158 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// -// - -#ifndef __ISURFACEPLUGIN_H_ -#define __ISURFACEPLUGIN_H_ - -typedef struct _GtkWidget GtkWidget; -typedef struct _GtkWindow GtkWindow; - -#define SURFACEDIALOG_MAJOR "surfdialog" - -// there's a void* in each qtexture_t, must be casted to a IPluginTexdef* -// there's a void* in each face_t, must be casted to a IPluginTexdef* -// NOTE: IPluginTexdef stores a pointer to the qtexture_t or face_t it's stored in -// members of IPluginTexdef often access the qtexture_t or face_t they are connected to - -// Write texdef needs a function pointer, because Radiant either writes into a FILE or a CMemFile -typedef void (* PFN_QERAPP_MAPPRINTF) ( char *text, ... ); - -class IPluginTexdef -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; -}; - - - -// Nurail: For SI module -class texdef_to_face_t -{ -public: - texdef_to_face_t* next; - brush_t *brush; // Brush faces belong to (for Undo) - face_t *face; // Face of Texdef - texdef_t texdef; // Working texdef - texdef_t orig_texdef; // Original, for baselining changes -}; - - -typedef void (* PFN_QERPLUG_DOSURFACE) (); -typedef void (* PFN_QERPLUG_TOGGLESURFACE) (); -typedef void (* PFN_QERPLUG_UPDATESURFACEDIALOG) (); -typedef void (* PFN_QERPLUG_SURFACEDLGFITALL) (); -typedef GtkWidget* (* PFN_GET_SI_MODULE_WIDGET) (); - -struct _QERPlugSurfaceTable -{ - int m_nSize; - PFN_QERPLUG_TOGGLESURFACE m_pfnToggleSurface; - PFN_QERPLUG_DOSURFACE m_pfnDoSurface; - PFN_QERPLUG_UPDATESURFACEDIALOG m_pfnUpdateSurfaceDialog; - PFN_QERPLUG_SURFACEDLGFITALL m_pfnSurfaceDlgFitAll; - PFN_GET_SI_MODULE_WIDGET m_pfnGet_SI_Module_Widget; -}; - -// this one is used by the plugin to access some Radiant stuff - -#define APPSURFACEDIALOG_MAJOR "appsurfdialog" - -// {42BAE4C0-9787-11d3-8EF3-0000E8E8657B} -static const GUID QERAppSurfaceTable_GUID = -{ 0x42bae4c0, 0x9787, 0x11d3, { 0x8e, 0xf3, 0x0, 0x0, 0xe8, 0xe8, 0x65, 0x7b } }; - -typedef bool (* PFN_PATCHESSELECTED) (); -// retrieve g_qeglobals.texturewin_t -//++timo FIXME: this should move in a dedicated table for all g_qeglobals stuff -typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN) (); -// look for the first selected patch mesh -//++timo FIXME: this is a convenient func since there's no way to scan patches ( yet ) -typedef patchMesh_t* (* PFN_GETSELECTEDPATCH) (); -//++timo FIXME: this one in particular is a hack -typedef void (* PFN_GETTWOSELECTEDPATCH) (patchMesh_t **p1, patchMesh_t **p2); - - -// leo FIXME: hacks uglier than the ones above -typedef void (* PFN_TEXMATTOFAKETEXCOORDS) (vec_t texMat[2][3], float shift[2], float *rot, float scale[2]); -typedef void (* PFN_CONVERTTEXMATWITHQTEXTURE) (brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2); -typedef void (* PFN_FAKETEXCOORDSTOTEXMAT) (float shift[2], float rot, float scale[2], vec_t texMat[2][3]); -typedef void (* PFN_PATCH_RESETTEXTURING) (float fx, float fy); -typedef void (* PFN_PATCH_FITTEXTURING) (); -typedef void (* PFN_PATCH_NATURALIZESELECTED) (bool bCap); -typedef const char* (* PFN_PATCH_GETTEXTURENAME) (); -typedef qboolean (* PFN_QE_SINGLEBRUSH) (bool bQuiet); -typedef qboolean (* PFN_ISBRUSHPRIMITMODE) (); -typedef void (* PFN_SELECT_FITTEXTURE)(int nHeight, int nWidth); -typedef void (*PFN_COMPUTEAXISBASE)(vec3_t normal,vec3_t texS,vec3_t texT ); -typedef void (*PFN_BPMATMUL)(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]); -typedef void (*PFN_EMITBRUSHPRIMITTEXCOORDS)(face_t * f, winding_t * w); -typedef texdef_t* (*PFN_QEGLOBALSSAVEDINFO_SIINC) (); -typedef float (* PFN_QEGLOBALSGETGRIDSIZE) (); -typedef void (* PFN_FACELIST_FITTEXTURE) (texdef_to_face_t* texdef_face_list, int nHeight, int nWidth); -typedef GtkWindow* (* PFN_GETMAINWINDOW)(); -typedef void (* PFN_SETWINPOS_FROM_PREFS) (GtkWidget *win); -typedef int (* PFN_GETSELECTEDFACECOUNT_BRUSH) (); -typedef void (* PFN_GETSELFACESTEXDEF) (texdef_to_face_t *); -typedef void (* PFN_SETTEXDEF_FACELIST) (texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale); -typedef void (* PFN_SETACTIVEINRADIANT) (); - - -struct _QERAppSurfaceTable -{ - int m_nSize; - PFN_PATCHESSELECTED m_pfnOnlyPatchesSelected; - PFN_PATCHESSELECTED m_pfnAnyPatchesSelected; - PFN_GETSELECTEDPATCH m_pfnGetSelectedPatch; - PFN_GETTWOSELECTEDPATCH m_pfnGetTwoSelectedPatch; - PFN_TEXMATTOFAKETEXCOORDS m_pfnTexMatToFakeTexCoords; - PFN_CONVERTTEXMATWITHQTEXTURE m_pfnConvertTexMatWithQTexture; - PFN_FAKETEXCOORDSTOTEXMAT m_pfnFakeTexCoordsToTexMat; - PFN_PATCH_RESETTEXTURING m_pfnPatch_ResetTexturing; - PFN_PATCH_FITTEXTURING m_pfnPatch_FitTexturing; - PFN_PATCH_NATURALIZESELECTED m_pfnPatch_NaturalizeSelected; - PFN_PATCH_GETTEXTURENAME m_pfnPatch_GetTextureName; - PFN_QE_SINGLEBRUSH m_pfnQE_SingleBrush; - PFN_ISBRUSHPRIMITMODE m_pfnIsBrushPrimitMode; - PFN_COMPUTEAXISBASE m_pfnComputeAxisBase; - PFN_BPMATMUL m_pfnBPMatMul; - PFN_EMITBRUSHPRIMITTEXCOORDS m_pfnEmitBrushPrimitTextureCoordinates; - PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; - PFN_SELECT_FITTEXTURE m_pfnSelect_FitTexture; - PFN_QEGLOBALSSAVEDINFO_SIINC m_pfnQERApp_QeglobalsSavedinfo_SIInc; - PFN_QEGLOBALSGETGRIDSIZE m_pfnQeglobalsGetGridSize; - PFN_FACELIST_FITTEXTURE m_pfnFaceList_FitTexture; - PFN_GETMAINWINDOW m_pfnGetMainWindow; - PFN_SETWINPOS_FROM_PREFS m_pfnSetWinPos_From_Prefs; - PFN_GETSELECTEDFACECOUNT_BRUSH m_pfnGetSelectedFaceCountfromBrushes; - PFN_GETSELFACESTEXDEF m_pfnGetSelFacesTexdef; - PFN_SETTEXDEF_FACELIST m_pfnSetTexdef_FaceList; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// +// + +#ifndef __ISURFACEPLUGIN_H_ +#define __ISURFACEPLUGIN_H_ + +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWindow GtkWindow; + +#define SURFACEDIALOG_MAJOR "surfdialog" + +// there's a void* in each qtexture_t, must be casted to a IPluginTexdef* +// there's a void* in each face_t, must be casted to a IPluginTexdef* +// NOTE: IPluginTexdef stores a pointer to the qtexture_t or face_t it's stored in +// members of IPluginTexdef often access the qtexture_t or face_t they are connected to + +// Write texdef needs a function pointer, because Radiant either writes into a FILE or a CMemFile +typedef void (* PFN_QERAPP_MAPPRINTF) ( char *text, ... ); + +class IPluginTexdef +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; +}; + + + +// Nurail: For SI module +class texdef_to_face_t +{ +public: + texdef_to_face_t* next; + brush_t *brush; // Brush faces belong to (for Undo) + face_t *face; // Face of Texdef + texdef_t texdef; // Working texdef + texdef_t orig_texdef; // Original, for baselining changes +}; + + +typedef void (* PFN_QERPLUG_DOSURFACE) (); +typedef void (* PFN_QERPLUG_TOGGLESURFACE) (); +typedef void (* PFN_QERPLUG_UPDATESURFACEDIALOG) (); +typedef void (* PFN_QERPLUG_SURFACEDLGFITALL) (); +typedef GtkWidget* (* PFN_GET_SI_MODULE_WIDGET) (); + +struct _QERPlugSurfaceTable +{ + int m_nSize; + PFN_QERPLUG_TOGGLESURFACE m_pfnToggleSurface; + PFN_QERPLUG_DOSURFACE m_pfnDoSurface; + PFN_QERPLUG_UPDATESURFACEDIALOG m_pfnUpdateSurfaceDialog; + PFN_QERPLUG_SURFACEDLGFITALL m_pfnSurfaceDlgFitAll; + PFN_GET_SI_MODULE_WIDGET m_pfnGet_SI_Module_Widget; +}; + +// this one is used by the plugin to access some Radiant stuff + +#define APPSURFACEDIALOG_MAJOR "appsurfdialog" + +// {42BAE4C0-9787-11d3-8EF3-0000E8E8657B} +static const GUID QERAppSurfaceTable_GUID = +{ 0x42bae4c0, 0x9787, 0x11d3, { 0x8e, 0xf3, 0x0, 0x0, 0xe8, 0xe8, 0x65, 0x7b } }; + +typedef bool (* PFN_PATCHESSELECTED) (); +// retrieve g_qeglobals.texturewin_t +//++timo FIXME: this should move in a dedicated table for all g_qeglobals stuff +typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN) (); +// look for the first selected patch mesh +//++timo FIXME: this is a convenient func since there's no way to scan patches ( yet ) +typedef patchMesh_t* (* PFN_GETSELECTEDPATCH) (); +//++timo FIXME: this one in particular is a hack +typedef void (* PFN_GETTWOSELECTEDPATCH) (patchMesh_t **p1, patchMesh_t **p2); + + +// leo FIXME: hacks uglier than the ones above +typedef void (* PFN_TEXMATTOFAKETEXCOORDS) (vec_t texMat[2][3], float shift[2], float *rot, float scale[2]); +typedef void (* PFN_CONVERTTEXMATWITHQTEXTURE) (brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2); +typedef void (* PFN_FAKETEXCOORDSTOTEXMAT) (float shift[2], float rot, float scale[2], vec_t texMat[2][3]); +typedef void (* PFN_PATCH_RESETTEXTURING) (float fx, float fy); +typedef void (* PFN_PATCH_FITTEXTURING) (); +typedef void (* PFN_PATCH_NATURALIZESELECTED) (bool bCap); +typedef const char* (* PFN_PATCH_GETTEXTURENAME) (); +typedef qboolean (* PFN_QE_SINGLEBRUSH) (bool bQuiet); +typedef qboolean (* PFN_ISBRUSHPRIMITMODE) (); +typedef void (* PFN_SELECT_FITTEXTURE)(int nHeight, int nWidth); +typedef void (*PFN_COMPUTEAXISBASE)(vec3_t normal,vec3_t texS,vec3_t texT ); +typedef void (*PFN_BPMATMUL)(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]); +typedef void (*PFN_EMITBRUSHPRIMITTEXCOORDS)(face_t * f, winding_t * w); +typedef texdef_t* (*PFN_QEGLOBALSSAVEDINFO_SIINC) (); +typedef float (* PFN_QEGLOBALSGETGRIDSIZE) (); +typedef void (* PFN_FACELIST_FITTEXTURE) (texdef_to_face_t* texdef_face_list, int nHeight, int nWidth); +typedef GtkWindow* (* PFN_GETMAINWINDOW)(); +typedef void (* PFN_SETWINPOS_FROM_PREFS) (GtkWidget *win); +typedef int (* PFN_GETSELECTEDFACECOUNT_BRUSH) (); +typedef void (* PFN_GETSELFACESTEXDEF) (texdef_to_face_t *); +typedef void (* PFN_SETTEXDEF_FACELIST) (texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale); +typedef void (* PFN_SETACTIVEINRADIANT) (); + + +struct _QERAppSurfaceTable +{ + int m_nSize; + PFN_PATCHESSELECTED m_pfnOnlyPatchesSelected; + PFN_PATCHESSELECTED m_pfnAnyPatchesSelected; + PFN_GETSELECTEDPATCH m_pfnGetSelectedPatch; + PFN_GETTWOSELECTEDPATCH m_pfnGetTwoSelectedPatch; + PFN_TEXMATTOFAKETEXCOORDS m_pfnTexMatToFakeTexCoords; + PFN_CONVERTTEXMATWITHQTEXTURE m_pfnConvertTexMatWithQTexture; + PFN_FAKETEXCOORDSTOTEXMAT m_pfnFakeTexCoordsToTexMat; + PFN_PATCH_RESETTEXTURING m_pfnPatch_ResetTexturing; + PFN_PATCH_FITTEXTURING m_pfnPatch_FitTexturing; + PFN_PATCH_NATURALIZESELECTED m_pfnPatch_NaturalizeSelected; + PFN_PATCH_GETTEXTURENAME m_pfnPatch_GetTextureName; + PFN_QE_SINGLEBRUSH m_pfnQE_SingleBrush; + PFN_ISBRUSHPRIMITMODE m_pfnIsBrushPrimitMode; + PFN_COMPUTEAXISBASE m_pfnComputeAxisBase; + PFN_BPMATMUL m_pfnBPMatMul; + PFN_EMITBRUSHPRIMITTEXCOORDS m_pfnEmitBrushPrimitTextureCoordinates; + PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; + PFN_SELECT_FITTEXTURE m_pfnSelect_FitTexture; + PFN_QEGLOBALSSAVEDINFO_SIINC m_pfnQERApp_QeglobalsSavedinfo_SIInc; + PFN_QEGLOBALSGETGRIDSIZE m_pfnQeglobalsGetGridSize; + PFN_FACELIST_FITTEXTURE m_pfnFaceList_FitTexture; + PFN_GETMAINWINDOW m_pfnGetMainWindow; + PFN_SETWINPOS_FROM_PREFS m_pfnSetWinPos_From_Prefs; + PFN_GETSELECTEDFACECOUNT_BRUSH m_pfnGetSelectedFaceCountfromBrushes; + PFN_GETSELFACESTEXDEF m_pfnGetSelFacesTexdef; + PFN_SETTEXDEF_FACELIST m_pfnSetTexdef_FaceList; +}; + +#endif diff --git a/include/itoolbar.h b/include/itoolbar.h index 05a05559..221938f6 100644 --- a/include/itoolbar.h +++ b/include/itoolbar.h @@ -1,61 +1,61 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef __IPLUGTOOLBAR_H_ -#define __IPLUGTOOLBAR_H_ - -/* -NOTE: this API requires Gtk -it's a good practice to avoid putting #include here -in some cases, the compiler will get confused because of 'list' identifiers between Gtk and STL headers -*/ - -#define TOOLBAR_MAJOR "toolbar" - -class IToolbarButton -{ -public: - enum EType - { - eSpace, - eButton, - eToggleButton, - eRadioButton, - }; - - virtual const char* getImage() const = 0; - virtual const char* getText() const = 0; - virtual const char* getTooltip() const = 0; - virtual EType getType() const = 0; - virtual void activate() const = 0; -}; - -typedef unsigned int (* PFN_TOOLBARBUTTONCOUNT)(); -typedef const IToolbarButton* (* PFN_GETTOOLBARBUTTON)(unsigned int index); - -struct _QERPlugToolbarTable -{ - int m_nSize; - PFN_TOOLBARBUTTONCOUNT m_pfnToolbarButtonCount; - PFN_GETTOOLBARBUTTON m_pfnGetToolbarButton; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __IPLUGTOOLBAR_H_ +#define __IPLUGTOOLBAR_H_ + +/* +NOTE: this API requires Gtk +it's a good practice to avoid putting #include here +in some cases, the compiler will get confused because of 'list' identifiers between Gtk and STL headers +*/ + +#define TOOLBAR_MAJOR "toolbar" + +class IToolbarButton +{ +public: + enum EType + { + eSpace, + eButton, + eToggleButton, + eRadioButton, + }; + + virtual const char* getImage() const = 0; + virtual const char* getText() const = 0; + virtual const char* getTooltip() const = 0; + virtual EType getType() const = 0; + virtual void activate() const = 0; +}; + +typedef unsigned int (* PFN_TOOLBARBUTTONCOUNT)(); +typedef const IToolbarButton* (* PFN_GETTOOLBARBUTTON)(unsigned int index); + +struct _QERPlugToolbarTable +{ + int m_nSize; + PFN_TOOLBARBUTTONCOUNT m_pfnToolbarButtonCount; + PFN_GETTOOLBARBUTTON m_pfnGetToolbarButton; +}; + +#endif diff --git a/include/iui.h b/include/iui.h index 16b7c8cd..d3af6777 100644 --- a/include/iui.h +++ b/include/iui.h @@ -1,158 +1,158 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// interface for all-purpose messaging and UI -// window class for MFC, Gtk or Q3 UI -// each version of Radiant implements the API, using the native code that it needs - -#ifndef __IUI_H_ -#define __IUI_H_ - -// this one can be hooked in the GL window procs for customizing GUI through plugins -// the class is implemented by the plugin module, and given to Radiant who calls into it -class IWindowListener -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // since Radiant is MFC we don't use a WNDPROC, we wrap the MFC handlers - // the handler is called first, if returns false Radiant continues processing - //++timo maybe add more later ? OnKeyUp and OnKeyDown for instance - //++timo TODO: add handlers everywhere - // Gef: Changed 2nd & 3rd params to gdouble's for sub-integer grid sizes - virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnKeyPressed(char *s) = 0; - - // paint message, the caller makes the GL context current, calls Paint, then swaps GL buffers - // return value might be false if something failed and closure is requested .. then the buffer swap will be cancelled - virtual bool Paint() = 0; - // window is closing (nothing you can do, just telling) - virtual void Close() = 0; -}; - -// IWindowListener with additional properties -// NOTE: for now it is both a window and the GL widget -// in the case of Gtk, there are two widgets, the window widget (a container) and the GL widget -class IWindow -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // misc data ------------------------------------------------ - // get pixel size - virtual int getHeight() = 0; - virtual int getWidth() = 0; - // initialisation stuff ------------------------------------- - // set pixel size and other parameters before showing it - virtual void setSizeParm(int width, int height) = 0; - // set the IWindowListener (implemented by the plugin using this window) - virtual void setListener(IWindowListener *) = 0; - // set the window name - virtual void setName(char *) = 0; - // will actually create the GL and the window based on the parameters - virtual bool Show() = 0; - // commands ------------------------------------------------- - // call this to ask for a Redraw - virtual void Redraw() = 0; -}; - -// various Radiant messages -------- -// this one holds the total number of supported messages (this is used to allocate structs) -#define RADIANT_MSGCOUNT 5 -// they start with a 0, can be indexed in an array -// something was selected / deselected -#define RADIANT_SELECTION 0 -// a brush face was selected / deselected -#define RADIANT_SFACE 1 -// current texture / shader changed -#define RADIANT_TEXTURE 2 -// Radiant is going to enter "sleep mode" (all GL contexts will be destroyed) -#define RADIANT_SLEEP 3 -// Radiant has left "sleep mode" (GL contexts are recreated) -#define RADIANT_WAKEUP 4 - - -// this one can be used to listen for Radiant-specific events, not related to a window -class IListener -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // message is one of the RADIANT_* consts - virtual void DispatchRadiantMsg( int Msg ) = 0; -}; - -// this one is provided by Radiant, it's a wrapper for some usefull functions -class IXYWndWrapper -{ -public: - virtual void SnapToGrid( int x1, int y1, vec3_t pt ) = 0; - virtual VIEWTYPE GetViewType( void ) = 0; -}; - -#define UI_MAJOR "ui" - -// create an IWindow with GL context -typedef IWindow* (WINAPI* PFN_QERAPP_CREATEGLWINDOW) (); - -// will hook the given IWindowListener to the XY window and increment the ref count -//++timo TODO: add hooking in the CAM view and Z view -typedef void (WINAPI* PFN_QERAPP_HOOKWINDOW) (IWindowListener *); -// will unhook the given IWindowListener -typedef void (WINAPI* PFN_QERAPP_UNHOOKWINDOW) (IWindowListener *); -// to retrieve the IXYWndWrapper -typedef IXYWndWrapper* (WINAPI* PFN_QERAPP_GETXYWNDWRAPPER) (); - -// will hook a given listener into Radiant listening for the given message and increment ref count -// call several times to listen for several messages -typedef void (WINAPI* PFN_QERAPP_HOOKLISTENER) (IListener *, int Msg); -// will unhook the listener and return the number of messages the given listener was removed from -typedef int (WINAPI* PFN_QERAPP_UNHOOKLISTENER)(IListener *); - -// TODO: create GL widget, destroy it - -struct _QERUITable -{ - int m_nSize; - PFN_QERAPP_CREATEGLWINDOW m_pfnCreateGLWindow; - PFN_QERAPP_HOOKWINDOW m_pfnHookWindow; - PFN_QERAPP_UNHOOKWINDOW m_pfnUnHookWindow; - PFN_QERAPP_GETXYWNDWRAPPER m_pfnGetXYWndWrapper; - PFN_QERAPP_HOOKLISTENER m_pfnHookListener; - PFN_QERAPP_UNHOOKLISTENER m_pfnUnHookListener; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// interface for all-purpose messaging and UI +// window class for MFC, Gtk or Q3 UI +// each version of Radiant implements the API, using the native code that it needs + +#ifndef __IUI_H_ +#define __IUI_H_ + +// this one can be hooked in the GL window procs for customizing GUI through plugins +// the class is implemented by the plugin module, and given to Radiant who calls into it +class IWindowListener +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // since Radiant is MFC we don't use a WNDPROC, we wrap the MFC handlers + // the handler is called first, if returns false Radiant continues processing + //++timo maybe add more later ? OnKeyUp and OnKeyDown for instance + //++timo TODO: add handlers everywhere + // Gef: Changed 2nd & 3rd params to gdouble's for sub-integer grid sizes + virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnKeyPressed(char *s) = 0; + + // paint message, the caller makes the GL context current, calls Paint, then swaps GL buffers + // return value might be false if something failed and closure is requested .. then the buffer swap will be cancelled + virtual bool Paint() = 0; + // window is closing (nothing you can do, just telling) + virtual void Close() = 0; +}; + +// IWindowListener with additional properties +// NOTE: for now it is both a window and the GL widget +// in the case of Gtk, there are two widgets, the window widget (a container) and the GL widget +class IWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // misc data ------------------------------------------------ + // get pixel size + virtual int getHeight() = 0; + virtual int getWidth() = 0; + // initialisation stuff ------------------------------------- + // set pixel size and other parameters before showing it + virtual void setSizeParm(int width, int height) = 0; + // set the IWindowListener (implemented by the plugin using this window) + virtual void setListener(IWindowListener *) = 0; + // set the window name + virtual void setName(char *) = 0; + // will actually create the GL and the window based on the parameters + virtual bool Show() = 0; + // commands ------------------------------------------------- + // call this to ask for a Redraw + virtual void Redraw() = 0; +}; + +// various Radiant messages -------- +// this one holds the total number of supported messages (this is used to allocate structs) +#define RADIANT_MSGCOUNT 5 +// they start with a 0, can be indexed in an array +// something was selected / deselected +#define RADIANT_SELECTION 0 +// a brush face was selected / deselected +#define RADIANT_SFACE 1 +// current texture / shader changed +#define RADIANT_TEXTURE 2 +// Radiant is going to enter "sleep mode" (all GL contexts will be destroyed) +#define RADIANT_SLEEP 3 +// Radiant has left "sleep mode" (GL contexts are recreated) +#define RADIANT_WAKEUP 4 + + +// this one can be used to listen for Radiant-specific events, not related to a window +class IListener +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // message is one of the RADIANT_* consts + virtual void DispatchRadiantMsg( int Msg ) = 0; +}; + +// this one is provided by Radiant, it's a wrapper for some usefull functions +class IXYWndWrapper +{ +public: + virtual void SnapToGrid( int x1, int y1, vec3_t pt ) = 0; + virtual VIEWTYPE GetViewType( void ) = 0; +}; + +#define UI_MAJOR "ui" + +// create an IWindow with GL context +typedef IWindow* (WINAPI* PFN_QERAPP_CREATEGLWINDOW) (); + +// will hook the given IWindowListener to the XY window and increment the ref count +//++timo TODO: add hooking in the CAM view and Z view +typedef void (WINAPI* PFN_QERAPP_HOOKWINDOW) (IWindowListener *); +// will unhook the given IWindowListener +typedef void (WINAPI* PFN_QERAPP_UNHOOKWINDOW) (IWindowListener *); +// to retrieve the IXYWndWrapper +typedef IXYWndWrapper* (WINAPI* PFN_QERAPP_GETXYWNDWRAPPER) (); + +// will hook a given listener into Radiant listening for the given message and increment ref count +// call several times to listen for several messages +typedef void (WINAPI* PFN_QERAPP_HOOKLISTENER) (IListener *, int Msg); +// will unhook the listener and return the number of messages the given listener was removed from +typedef int (WINAPI* PFN_QERAPP_UNHOOKLISTENER)(IListener *); + +// TODO: create GL widget, destroy it + +struct _QERUITable +{ + int m_nSize; + PFN_QERAPP_CREATEGLWINDOW m_pfnCreateGLWindow; + PFN_QERAPP_HOOKWINDOW m_pfnHookWindow; + PFN_QERAPP_UNHOOKWINDOW m_pfnUnHookWindow; + PFN_QERAPP_GETXYWNDWRAPPER m_pfnGetXYWndWrapper; + PFN_QERAPP_HOOKLISTENER m_pfnHookListener; + PFN_QERAPP_UNHOOKLISTENER m_pfnUnHookListener; +}; + +#endif diff --git a/include/iui_gtk.h b/include/iui_gtk.h index 5cd820c4..93973672 100644 --- a/include/iui_gtk.h +++ b/include/iui_gtk.h @@ -1,59 +1,59 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION -// This contains functions specific to the UI toolkit -// it is best to avoid using them, but they are provided for backward compatibility with the older interfaces -// the abstracted UI layer in iUI.h is not sufficient for some tasks .. no other choice than to rely on UI specific code - -#ifndef __IGL_GTK_H__ -#define __IGL_GTK_H__ - -#define UIGTK_MAJOR "uigtk" - -// All OpenGL stuff is handled by GLWidget to ensure portability -typedef GtkWidget* (WINAPI* PFN_QERAPP_GETQEGLOBALSGLWIDGET) (); -typedef GtkWidget* (WINAPI* PFN_GLWIDGET_NEW) (gboolean zbufffer, GtkWidget* share); -typedef void (WINAPI* PFN_GLWIDGET_SWAPBUFFERS) (GtkWidget* widget); -typedef gboolean (WINAPI* PFN_GLWIDGET_MAKECURRENT) (GtkWidget* widget); -typedef void (WINAPI* PFN_GLWIDGET_DESTROYCONTEXT) (GtkWidget* widget); -typedef void (WINAPI* PFN_GLWIDGET_CREATECONTEXT) (GtkWidget* widget); -#if 0 -typedef gpointer (WINAPI* PFN_GLWIDGET_GETCONTEXT) (GtkWidget* widget); -#endif - -struct _QERUIGtkTable -{ - int m_nSize; - PFN_QERAPP_GETQEGLOBALSGLWIDGET m_pfn_GetQeglobalsGLWidget; - PFN_GLWIDGET_NEW m_pfn_glwidget_new; - PFN_GLWIDGET_SWAPBUFFERS m_pfn_glwidget_swap_buffers; - PFN_GLWIDGET_MAKECURRENT m_pfn_glwidget_make_current; - PFN_GLWIDGET_DESTROYCONTEXT m_pfn_glwidget_destroy_context; - PFN_GLWIDGET_CREATECONTEXT m_pfn_glwidget_create_context; -#if 0 - PFN_GLWIDGET_GETCONTEXT m_pfn_glwidget_get_context; -#endif -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION +// This contains functions specific to the UI toolkit +// it is best to avoid using them, but they are provided for backward compatibility with the older interfaces +// the abstracted UI layer in iUI.h is not sufficient for some tasks .. no other choice than to rely on UI specific code + +#ifndef __IGL_GTK_H__ +#define __IGL_GTK_H__ + +#define UIGTK_MAJOR "uigtk" + +// All OpenGL stuff is handled by GLWidget to ensure portability +typedef GtkWidget* (WINAPI* PFN_QERAPP_GETQEGLOBALSGLWIDGET) (); +typedef GtkWidget* (WINAPI* PFN_GLWIDGET_NEW) (gboolean zbufffer, GtkWidget* share); +typedef void (WINAPI* PFN_GLWIDGET_SWAPBUFFERS) (GtkWidget* widget); +typedef gboolean (WINAPI* PFN_GLWIDGET_MAKECURRENT) (GtkWidget* widget); +typedef void (WINAPI* PFN_GLWIDGET_DESTROYCONTEXT) (GtkWidget* widget); +typedef void (WINAPI* PFN_GLWIDGET_CREATECONTEXT) (GtkWidget* widget); +#if 0 +typedef gpointer (WINAPI* PFN_GLWIDGET_GETCONTEXT) (GtkWidget* widget); +#endif + +struct _QERUIGtkTable +{ + int m_nSize; + PFN_QERAPP_GETQEGLOBALSGLWIDGET m_pfn_GetQeglobalsGLWidget; + PFN_GLWIDGET_NEW m_pfn_glwidget_new; + PFN_GLWIDGET_SWAPBUFFERS m_pfn_glwidget_swap_buffers; + PFN_GLWIDGET_MAKECURRENT m_pfn_glwidget_make_current; + PFN_GLWIDGET_DESTROYCONTEXT m_pfn_glwidget_destroy_context; + PFN_GLWIDGET_CREATECONTEXT m_pfn_glwidget_create_context; +#if 0 + PFN_GLWIDGET_GETCONTEXT m_pfn_glwidget_get_context; +#endif +}; + +#endif diff --git a/include/iundo.h b/include/iundo.h index d5194b52..b4fffeec 100644 --- a/include/iundo.h +++ b/include/iundo.h @@ -1,87 +1,87 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _IUNDO_H_ -#define _IUNDO_H_ - -#define UNDO_MAJOR "undo" - -//start operation -typedef void (*PFN_UNDOSTART) (char *operation); -//end operation -typedef void (*PFN_UNDOEND) (void); -//add brush to the undo -typedef void (*PFN_UNDOADDBRUSH) (brush_t *pBrush); -//end a brush after the operation is performed -typedef void (*PFN_UNDOENDBRUSH) (brush_t *pBrush); -//add a list with brushes to the undo -typedef void (*PFN_UNDOADDBRUSHLIST) (brush_t *brushlist); -//end a list with brushes after the operation is performed -typedef void (*PFN_UNDOENDBRUSHLIST) (brush_t *brushlist); -//add entity to undo -typedef void (*PFN_UNDOADDENTITY) (entity_t *entity); -//end an entity after the operation is performed -typedef void (*PFN_UNDOENDENTITY) (entity_t *entity); -//undo last operation (bSilent == true -> will not print the "undone blah blah message") -typedef void (*PFN_UNDO) (unsigned char bSilent); -//redo last undone operation -typedef void (*PFN_REDO) (void); -//get the undo Id of the next undo (0 if none available) -typedef int (*PFN_GETUNDOID) (void); -//returns true if there is something to be undone available -typedef int (*PFN_UNDOAVAILABLE) (void); -//returns true if there is something to redo available -typedef int (*PFN_REDOAVAILABLE) (void); - -struct _QERUndoTable -{ - int m_nSize; - PFN_UNDOSTART m_pfnUndo_Start; - PFN_UNDOEND m_pfnUndo_End; - PFN_UNDOADDBRUSH m_pfnUndo_AddBrush; - PFN_UNDOENDBRUSH m_pfnUndo_EndBrush; - PFN_UNDOADDBRUSHLIST m_pfnUndo_AddBrushList; - PFN_UNDOENDBRUSHLIST m_pfnUndo_EndBrushList; - PFN_UNDOADDENTITY m_pfnUndo_AddEntity; - PFN_UNDOENDENTITY m_pfnUndo_EndEntity; - PFN_UNDO m_pfnUndo_Undo; - PFN_REDO m_pfnUndo_Redo; - PFN_GETUNDOID m_pfnUndo_GetUndoId; - PFN_UNDOAVAILABLE m_pfnUndo_UndoAvailable; - PFN_REDOAVAILABLE m_pfnUndo_RedoAvailable; -}; - -#ifdef USE_UNDOTABLE_DEFINE -#ifndef __UNDOTABLENAME -#define __UNDOTABLENAME g_UndoTable -#endif -#define Undo_Start __UNDOTABLENAME.m_pfnUndo_Start -#define Undo_End __UNDOTABLENAME.m_pfnUndo_End -#define Undo_AddBrush __UNDOTABLENAME.m_pfnUndo_AddBrush -#define Undo_EndBrush __UNDOTABLENAME.m_pfnUndo_EndBrush -#define Undo_AddBrushList __UNDOTABLENAME.m_pfnUndo_AddBrushList -#define Undo_EndBrushList __UNDOTABLENAME.m_pfnUndo_EndBrushList -#define Undo_AddEntity __UNDOTABLENAME.m_pfnUndo_AddEntity -#define Undo_EndEntity __UNDOTABLENAME.m_pfnUndo_EndEntity -#endif - -#endif // _IUNDO_H_ - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IUNDO_H_ +#define _IUNDO_H_ + +#define UNDO_MAJOR "undo" + +//start operation +typedef void (*PFN_UNDOSTART) (char *operation); +//end operation +typedef void (*PFN_UNDOEND) (void); +//add brush to the undo +typedef void (*PFN_UNDOADDBRUSH) (brush_t *pBrush); +//end a brush after the operation is performed +typedef void (*PFN_UNDOENDBRUSH) (brush_t *pBrush); +//add a list with brushes to the undo +typedef void (*PFN_UNDOADDBRUSHLIST) (brush_t *brushlist); +//end a list with brushes after the operation is performed +typedef void (*PFN_UNDOENDBRUSHLIST) (brush_t *brushlist); +//add entity to undo +typedef void (*PFN_UNDOADDENTITY) (entity_t *entity); +//end an entity after the operation is performed +typedef void (*PFN_UNDOENDENTITY) (entity_t *entity); +//undo last operation (bSilent == true -> will not print the "undone blah blah message") +typedef void (*PFN_UNDO) (unsigned char bSilent); +//redo last undone operation +typedef void (*PFN_REDO) (void); +//get the undo Id of the next undo (0 if none available) +typedef int (*PFN_GETUNDOID) (void); +//returns true if there is something to be undone available +typedef int (*PFN_UNDOAVAILABLE) (void); +//returns true if there is something to redo available +typedef int (*PFN_REDOAVAILABLE) (void); + +struct _QERUndoTable +{ + int m_nSize; + PFN_UNDOSTART m_pfnUndo_Start; + PFN_UNDOEND m_pfnUndo_End; + PFN_UNDOADDBRUSH m_pfnUndo_AddBrush; + PFN_UNDOENDBRUSH m_pfnUndo_EndBrush; + PFN_UNDOADDBRUSHLIST m_pfnUndo_AddBrushList; + PFN_UNDOENDBRUSHLIST m_pfnUndo_EndBrushList; + PFN_UNDOADDENTITY m_pfnUndo_AddEntity; + PFN_UNDOENDENTITY m_pfnUndo_EndEntity; + PFN_UNDO m_pfnUndo_Undo; + PFN_REDO m_pfnUndo_Redo; + PFN_GETUNDOID m_pfnUndo_GetUndoId; + PFN_UNDOAVAILABLE m_pfnUndo_UndoAvailable; + PFN_REDOAVAILABLE m_pfnUndo_RedoAvailable; +}; + +#ifdef USE_UNDOTABLE_DEFINE +#ifndef __UNDOTABLENAME +#define __UNDOTABLENAME g_UndoTable +#endif +#define Undo_Start __UNDOTABLENAME.m_pfnUndo_Start +#define Undo_End __UNDOTABLENAME.m_pfnUndo_End +#define Undo_AddBrush __UNDOTABLENAME.m_pfnUndo_AddBrush +#define Undo_EndBrush __UNDOTABLENAME.m_pfnUndo_EndBrush +#define Undo_AddBrushList __UNDOTABLENAME.m_pfnUndo_AddBrushList +#define Undo_EndBrushList __UNDOTABLENAME.m_pfnUndo_EndBrushList +#define Undo_AddEntity __UNDOTABLENAME.m_pfnUndo_AddEntity +#define Undo_EndEntity __UNDOTABLENAME.m_pfnUndo_EndEntity +#endif + +#endif // _IUNDO_H_ + diff --git a/include/misc_def.h b/include/misc_def.h index ea5a600b..c6ab2ebb 100644 --- a/include/misc_def.h +++ b/include/misc_def.h @@ -1,64 +1,64 @@ -#ifndef _WIN32 - -#define WINAPI -#define APIENTRY - -typedef void* HMODULE; -typedef void* LPVOID; -typedef char* LPCSTR; -typedef char* LPSTR; - -#define IsEqualGUID(a,b) (memcmp(&a,&b,sizeof(a)) == 0) - -#ifndef GUID_DEFINED -#define GUID_DEFINED -typedef struct _GUID -{ - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8]; -} GUID; -#endif - -#if defined(__cplusplus) -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#define REFGUID const GUID & -#endif // !_REFGUID_DEFINED -#endif - -// Message box constants -#define MB_OK 0x00000000L -#define MB_OKCANCEL 0x00000001L -#define MB_ABORTRETRYIGNORE 0x00000002L -#define MB_YESNOCANCEL 0x00000003L -#define MB_YESNO 0x00000004L -#define MB_RETRYCANCEL 0x00000005L - -#define MB_ICONHAND 0x00000010L -#define MB_ICONQUESTION 0x00000020L -#define MB_ICONEXCLAMATION 0x00000030L -#define MB_ICONASTERISK 0x00000040L - -#define MB_USERICON 0x00000080L -#define MB_ICONWARNING MB_ICONEXCLAMATION -#define MB_ICONERROR MB_ICONHAND -#define MB_ICONINFORMATION MB_ICONASTERISK -#define MB_ICONSTOP MB_ICONHAND - -#define MB_TYPEMASK 0x0000000FL -#define MB_ICONMASK 0x000000F0L -#define MB_DEFMASK 0x00000F00L -#define MB_MODEMASK 0x00003000L -#define MB_MISCMASK 0x0000C000L - -#define IDOK 1 -#define IDCANCEL 2 -#define IDABORT 3 -#define IDRETRY 4 -#define IDIGNORE 5 -#define IDYES 6 -#define IDNO 7 - -#endif +#ifndef _WIN32 + +#define WINAPI +#define APIENTRY + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; +typedef char* LPSTR; + +#define IsEqualGUID(a,b) (memcmp(&a,&b,sizeof(a)) == 0) + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; +#endif + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#endif + +// Message box constants +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L + +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L + +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND + +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 + +#endif diff --git a/include/qerplugin.h b/include/qerplugin.h index 907a4bee..e6f1a96e 100644 --- a/include/qerplugin.h +++ b/include/qerplugin.h @@ -1,787 +1,787 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// QERadiant PlugIns -// -// - -#ifndef __QERPLUGIN_H__ -#define __QERPLUGIN_H__ - -/*! -\todo this header is intended to be turned into a header for the core editor functionality -some portability related code should be moved to synapse (such as the GUID stuff) -*/ - -#include -#include -// TTimo -// ideally the plugin API would be UI toolkit independent, but removing the dependency with GLib seems tricky right now.. -#include -#include "qertypes.h" - -// FIXME TTimo: -// GUID declaration here should be trashed, it is in synapse.h -#ifdef _WIN32 -#include -#endif - -#define QER_MAX_NAMELEN 1024 - -#ifndef _WIN32 -#include "misc_def.h" -#endif - -// the editor will look for plugins in two places, the plugins path -// under the application path, and the path under the basepath as defined -// in the project (.qe4) file. -// -// you can drop any number of new texture, model format DLL's in the standard plugin path -// but only one plugin that overrides map loading/saving, surface dialog, surface flags, etc.. -// should be used at one time.. if multiples are loaded then the last one loaded will be the -// active one -// -// type of services the plugin supplies, pass any combo of these flags -// it is assumed the plugin will have a matching function as defined below -// to correlate to the implied functionality -// - -#define RADIANT_MAJOR "radiant" - -// basics -#define QERPLUG_INIT "QERPlug_Init" -#define QERPLUG_GETNAME "QERPlug_GetName" -#define QERPLUG_GETCOMMANDLIST "QERPlug_GetCommandList" -#define QERPLUG_DISPATCH "QERPlug_Dispatch" -#define QERPLUG_GETFUNCTABLE "QERPlug_GetFuncTable" - -// game stuff -#define QERPLUG_GETTEXTUREINFO "QERPlug_GetTextureInfo" // gets a texture info structure -#define QERPLUG_LOADTEXTURE "QERPlug_LoadTexture" // loads a texture, will return an RGBA structure - // and any surface flags/contents for it -#define QERPLUG_GETSURFACEFLAGS "QERPlug_GetSurfaceFlags" // gets a list of surface/content flag names from a plugin - -struct _QERTextureInfo -{ - char m_TextureExtension[QER_MAX_NAMELEN]; // the extension these textures have - qboolean m_bHiColor; // if textures are NOT high color, the default - // palette (as described inthe qe4 file will be used for gamma correction) - // if they are high color, gamma and shading are computed on the fly - // based on the rgba data - //--bool m_bIsShader; // will probably do q3 shaders this way when i merge - qboolean m_bWadStyle; // if this is true, the plugin will be presented with the texture path - // defined in the .qe4 file and is expected to preload all the textures - qboolean m_bHalfLife; // causes brushes to be saved/parsed without the surface contents/flags/value -}; - -struct _QERTextureLoad // returned by a plugin -{ - _QERTextureLoad() - { - memset(reinterpret_cast(this), 0, sizeof(_QERTextureLoad)); - }; - - ~_QERTextureLoad() - { - delete []m_pRGBA; - delete []m_pName; - }; - - void makeSpace(int nSize) - { - m_pRGBA = new unsigned char[nSize+1]; - }; - - void setName(const char* p) - { - m_pName = new char[strlen(p)+1]; - strcpy(m_pName, p); - }; - - - unsigned char *m_pRGBA; // rgba data (alpha channel is supported and drawn appropriately) - int m_nWidth; // width - int m_nHeight; // height - int m_nContents; // default contents - int m_nFlags; // "" flags - int m_nValue; // "" value - char *m_pName; // name to be referenced in map, build tools, etc. -}; - -struct _QERModelInfo -{ - char m_ModelExtension[QER_MAX_NAMELEN]; - bool m_bSkinned; - bool m_bMultipart; -}; - -struct _QERModelLoad -{ - // vertex and skin data -}; - - -//========================================= -// plugin functions -#if 0 -// NOTE TTimo: hack to make old plugin tech and new plugin tech live together -#ifndef _IPLUGIN_H_ -// toolkit-independant interface, cast hwndMain to GtkWidget* -typedef const char* (WINAPI *PFN_QERPLUG_INIT)(void* hApp, void* hwndMain); -typedef const char* (WINAPI *PFN_QERPLUG_GETNAME)(); -typedef const char* (WINAPI *PFN_QERPLUG_GETCOMMANDLIST)(); -typedef void (WINAPI *PFN_QERPLUG_DISPATCH)(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush); -#endif -#endif - -typedef char* (WINAPI *PFN_QERPLUG_GETFUNCTABLE)(); - -// v1.5 -// -// Texture loading -// returns a ptr to _QERTextureInfo -typedef void* (WINAPI *PFN_QERPLUG_GETTEXTUREINFO)(); -// -// loads a texture by calling the texture load func in the editor (defined below) -// transparency (for water, fog, lava, etc.. ) can be emulated in the editor -// by passing in appropriate alpha data or by setting the appropriate surface flags -// expected by q2 (which the editor will use.. ) -typedef void (WINAPI *PFN_QERPLUG_LOADTEXTURE)(const char* pFilename); - -// v1.6 -typedef void* (WINAPI *PFN_QERPLUG_GETSURFACEFLAGS)(); - -// v1.7 -// if exists in plugin, gets called between INIT and GETCOMMANDLIST -// the plugin can register the EClasses he wants to handle -//++timo TODO: this has got to move into the table, and be requested by QERPlug_RequestInterface -//++timo FIXME: the LPVOID parameter must be casted to an IEpair interface -#define QERPLUG_REGISTERPLUGINENTITIES "QERPlug_RegisterPluginEntities" -typedef void (WINAPI * PFN_QERPLUG_REGISTERPLUGINENTITIES)( void* ); - -// if exists in plugin, gets called between INIT and GETCOMMANDLIST -// the plugin can Init all it needs for surface properties -#define QERPLUG_INITSURFACEPROPERTIES "QERPlug_InitSurfaceProperties" -typedef void (WINAPI * PFN_QERPLUG_INITSURFACEPROPERTIES)(); - -// if Radiant needs to use a particular set of commands, it can request the plugin to fill a func table -// this is similar to PFN_QERAPP_REQUESTINTERFACE -#define QERPLUG_REQUESTINTERFACE "QERPlug_RequestInterface" -typedef int (WINAPI * PFN_QERPLUG_REQUESTINTERFACE) (REFGUID refGUID, void* pInterface, const char *version_name); - -// Load an image file -typedef void (* PFN_QERAPP_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); - -// TTimo FIXME: the logic for this is in synapse now - -// MODULES specific: -// if it exports this entry point, will be considered as a module -// a module is a plugin that provides some REQUIRED interfaces to Radiant, such as the shader module -// Radiant will call QERPLUG_LISTINTERFACES to get a list of the interfaces a given plugin implements -// then it will call PFN_QERPLUG_REQUESTINTERFACE to actually get them - -// following leo's code .. looks ok to use a string to identify the various versions of a same interface -// obviously it would be handy to have the same string naming for the interfaces. -// best way would be to have the names come in when you list the interfaces -// NOTE: we might have a problem with the order in which the interfaces are filled in -// there's some kind of dependency graph, the shader module expects to find the VFS ready etc. -typedef struct moduleentry_s { - const GUID *interface_GUID; - const char* interface_name; - const char* version_name; -} moduleentry_t; - -#define QERPLUG_LISTINTERFACES "QERPlug_ListInterfaces" -#define MAX_QERPLUG_INTERFACES 10 -typedef int (WINAPI* PFN_QERPLUG_LISTINTERFACES) (moduleentry_t table[MAX_QERPLUG_INTERFACES]); - -// ======================================== -// GTK+ helper functions - -// NOTE: parent can be NULL in all functions but it's best to set them - -// simple Message Box, see above for the 'type' flags -// toolkit-independent, cast parent ot a GtkWidget* -typedef gint (WINAPI* PFN_QERAPP_MESSAGEBOX) (void *parent, const char* text, - const char* caption, guint32 type, const char *URL); - -// file and directory selection functions return NULL if the user hits cancel -// or a gchar* string that must be g_free'd by the user -// - 'title' is the dialog title (can be NULL) -// - 'path' is used to set the initial directory (can be NULL) -// - 'pattern': the first pattern is for the win32 mode, then comes the Gtk pattern list, see Radiant source for samples -// TTimo 04/01/2001 toolkit-independant, cast parent to a GtkWidget* -typedef const gchar* (* PFN_QERAPP_FILEDIALOG) (void *parent, gboolean open, const char* title, - const char* path, const char* pattern); -typedef gchar* (WINAPI* PFN_QERAPP_DIRDIALOG) (void *parent, const char* title, - const char* path); - -// return true if the user closed the dialog with 'Ok' -// 'color' is used to set the initial value and store the selected value -typedef bool (WINAPI* PFN_QERAPP_COLORDIALOG) (void *parent, float *color, - const char* title); - -// load a .bmp file and store the results in 'gdkpixmap' and 'mask' -// returns TRUE on success but even if it fails, it creates an empty pixmap -// NOTE: 'filename' is relative to /plugins/bitmaps/ -// TTimo 04/01/2001 toolkit-independant, cast gkpixmap to GdkPixmap and mask to GdkBitmap -typedef bool (WINAPI* PFN_QERAPP_LOADBITMAP) (const char* filename, void **gdkpixmap, void **mask); - -// ======================================== -// read/write preferences file - -// use this function to get the directory where the preferences file are stored -typedef const char* (WINAPI* PFN_QERAPP_PROFILE_GETDIR) (); - -// 'filename' is the absolute path -typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVEINT) (const char *filename, const char *section, - const char *key, int value); -typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVESTR) (const char *filename, const char *section, - const char *key, const char *value); -typedef int (WINAPI* PFN_QERAPP_PROFILE_LOADINT) (const char *filename, const char *section, - const char *key, int default_value); -typedef char* (WINAPI* PFN_QERAPP_PROFILE_LOADSTR) (const char *filename, const char *section, - const char *key, const char *default_value); - -//========================================= -// editor functions - -// There are 3 potential brush handle lists -// 1. the list that contains brushes a plugin creates using CreateBrushHandle -// 2. the selected brush list (brushes the user has selected) -// 3. the active brush list (brushes in the map that are not selected) -// -// In general, the same things can be done to brush handles (face manip, delete brushhandle, etc.. ) in each -// list. There are a few exceptions. -// 1. You cannot commit a selected or active brush handle to the map. This is because it is already in the map. -// 2. You cannot bind brush handles from the selected or active brush list to an entity. As of v1.0 of the plugins -// the only way for a plugin to create entities is to create a brush handles (or a list of handles) and then bind -// them to an entity. This will commit the brush(s) and/or the entities to the map as well. -// -// To use the active or selected brush lists, you must first allocate them (which returns a count) and then -// release them when you are finish manipulating brushes in one of those lists. - -//++timo NOTE : the #defines here are never used, but can help finding where things are done in the editor -#if 0 -// brush manipulation routines -#define QERAPP_CREATEBRUSH "QERApp_CreateBrush" -#define QERAPP_CREATEBRUSHHANDLE "QERApp_CreateBrushHandle" -#define QERAPP_DELETEBRUSHHANDLE "QERApp_DeleteBrushHandle" -#define QERAPP_COMMITBRUSHHANDLETOMAP "QERApp_CommitBrushHandleToMap" -//++timo not implemented .. remove -// #define QERAPP_BINDHANDLESTOENTITY "QERApp_BindHandlesToEntity" -#define QERAPP_ADDFACE "QERApp_AddFace" -#define QERAPP_ADDFACEDATA "QERApp_AddFaceData" -#define QERAPP_GETFACECOUNT "QERApp_GetFaceCount" -#define QERAPP_GETFACEDATA "QERApp_GetFaceData" -#define QERAPP_SETFACEDATA "QERApp_SetFaceData" -#define QERAPP_DELETEFACE "QERApp_DeleteFace" -#define QERAPP_TEXTUREBRUSH "QERApp_TextureBrush" -#define QERAPP_BUILDBRUSH "QERApp_BuildBrush" // PGM -#define QERAPP_SELECTEDBRUSHCOUNT "QERApp_SelectedBrushCount" -#define QERAPP_ALLOCATESELECTEDBRUSHHANDLES "QERApp_AllocateSelectedBrushHandles" -#define QERAPP_RELEASESELECTEDBRUSHHANDLES "QERApp_ReleaseSelectedBrushHandles" -#define QERAPP_GETSELECTEDBRUSHHANDLE "QERApp_GetSelectedBrushHandle" -#define QERAPP_ACTIVEBRUSHCOUNT "QERApp_ActiveBrushCount" -#define QERAPP_ALLOCATEACTIVEBRUSHHANDLES "QERApp_AllocateActiveBrushHandles" -#define QERAPP_RELEASEACTIVEBRUSHHANDLES "QERApp_ReleaseActiveBrushHandles" -#define QERAPP_GETACTIVEBRUSHHANDLE "QERApp_GetActiveBrushHandle" - -// texture stuff -#define QERAPP_TEXTURECOUNT "QERApp_TextureCount" -#define QERAPP_GETTEXTURE "QERApp_GetTexture" -#define QERAPP_GETCURRENTTEXTURE "QERApp_GetCurrentTexture" -#define QERAPP_SETCURRENTTEXTURE "QERApp_SetCurrentTexture" - -// selection -#define QERAPP_DELETESELECTION "QERApp_DeleteSelection" -#define QERAPP_SELECTBRUSH "QERApp_SelectBrush" // PGM -#define QERAPP_DESELECTBRUSH "QERApp_DeselectBrush" // PGM -#define QERAPP_DESELECTALLBRUSHES "QERApp_DeselectAllBrushes" // PGM - -// data gathering -#define QERAPP_GETPOINTS "QERApp_GetPoints" -#define QERAPP_SELECTBRUSHES "QERApp_GetBrushes" - -// entity class stuff -// the entity handling is very basic for 1.0 -#define QERAPP_GETECLASSCOUNT "QERApp_GetEClassCount" -#define QERAPP_GETECLASS "QERApp_GetEClass" - -// misc -#define QERAPP_SYSMSG "QERApp_SysMsg" -#define QERAPP_INFOMSG "QERApp_InfoMsg" -#define QERAPP_HIDEINFOMSG "QERApp_HideInfoMsg" -#define QERAPP_RESET_PLUGINS "QERApp_ResetPlugins" - -// texture loading -#define QERAPP_LOADTEXTURERGBA "QERApp_LoadTextureRGBA" - -// FIXME: the following are not implemented yet -// hook registrations -#define QERAPP_REGISTER_MAPLOADFUNC "QERApp_Register_MapLoadFunc" -#define QERAPP_REGISTER_MAPSAVEFUNC "QERApp_Register_MapSaveFunc" - -// FIXME: the following are not implemented yet -#define QERAPP_REGISTER_PROJECTLOADFUNC "QERApp_Register_ProjectLoadFunc" -#define QERAPP_REGISTER_MOUSEHANDLER "QERApp_Register_MouseHandler" -#define QERAPP_REGISTER_KEYHANDLER "QERApp_Register_KeyHandler" - -// FIXME: new primtives do not work in v1.00 -// primitives are new types of things in the map -// for instance, the Q3 curves could have been done as -// primitives instead of being built in -// it will be a plugins responsibility to hook the map load and save funcs to load -// and/or save any additional data (like new primitives of some type) -// the editor will call each registered renderer during the rendering process to repaint -// any primitives the plugin owns -// each primitive object has a temporary sibling brush that lives in the map -// FIXME: go backwards on this a bit.. orient it more towards the temp brush mode as it will be cleaner -// basically a plugin will hook the map load and save and will add the primitives to the map.. this will -// produce a temporary 'primitive' brush and the appropriate renderer will be called as well as the -// edit handler (for edge drags, sizes, rotates, etc.. ) and the vertex maker will be called when vertex -// mode is attemped on the brush.. there will need to be a GetPrimitiveBounds callback in the edit handler -// so the brush can resize appropriately as needed.. this might be the plugins responsibility to set the -// sibling brushes size.. it will then be the plugins responsibility to hook map save to save the primitives -// as the editor will discard any temp primitive brushes.. (there probably needs to be some kind of sanity check -// here as far as keeping the brushes and the plugin in sync.. i suppose the edit handler can deal with all of that -// crap but it looks like a nice place for a mess) -#define QERAPP_REGISTER_PRIMITIVE "QERApp_Register_Primitive" -#define QERAPP_REGISTER_RENDERER "QERApp_Register_Renderer" -#define QERAPP_REGISTER_EDITHANDLER "QERApp_Register_EditHandler" -#define QERAPP_REGISTER_VERTEXMAKER "QERApp_Register_VertexMaker" -#define QERAPP_ADDPRIMITIVE "QERApp_AddPrimitive" - -// v1.70 -#define QERAPP_GETENTITYCOUNT "QERApp_GetEntityCount" -#define QERAPP_GETENTITYHANDLE "QERApp_GetEntityHandle" -//++timo not implemented for the moment -// #define QERAPP_GETENTITYINFO "QERApp_GetEntityInfo" -//++timo does the keyval need some more funcs to add/remove ? -// get the pointer and do the changes yourself -#define QERAPP_ALLOCATEEPAIR "QERApp_AllocateEpair" -#define QERAPP_ALLOCATEENTITYBRUSHHANDLES "QERApp_AllocateEntityBrushHandles" -#define QERAPP_RELEASEENTITYBRUSHHANDLES "QERApp_ReleaseEntityBrushHandles" -#define QERAPP_GETENTITYBRUSHHANDLE "QERApp_GetEntityBrushHandle" -#define QERAPP_CREATEENTITYHANDLE "QERApp_CreateEntityHandle" -#define QERAPP_COMMITBRUSHHANDLETOENTITY "QERApp_CommitBrushHandleToEntity" -#define QERAPP_COMMITENTITYHANDLETOMAP "QERApp_CommitEntityHandleToMap" -#define QERAPP_SETSCREENUPDATE "QERApp_SetScreenUpdate" -#define QERAPP_BUILDBRUSH2 "QERApp_BuildBrush2" -#endif - -// v1.80 -#define QERAPP_GETDISPATCHPARAMS "QERApp_GetDispatchParams" - -struct _QERPointData -{ - int m_nCount; - vec3_t *m_pVectors; -}; - -struct _QERFaceData -{ - char m_TextureName[QER_MAX_NAMELEN]; - int m_nContents; - int m_nFlags; - int m_nValue; - float m_fShift[2]; - float m_fRotate; - float m_fScale[2]; - vec3_t m_v1, m_v2, m_v3; - // brush primitive additions - qboolean m_bBPrimit; - brushprimit_texdef_t brushprimit_texdef; -}; - -typedef void (WINAPI * PFN_QERAPP_CREATEBRUSH)(vec3_t vMin, vec3_t vMax); - -typedef void* (WINAPI * PFN_QERAPP_CREATEBRUSHHANDLE)(); -typedef void (WINAPI * PFN_QERAPP_DELETEBRUSHHANDLE)(void* pv); -typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOMAP)(void* pv); -typedef void (WINAPI * PFN_QERAPP_ADDFACE)(void* pv, vec3_t v1, vec3_t v2, vec3_t v3); - -typedef void (WINAPI * PFN_QERAPP_ADDFACEDATA)(void* pv, _QERFaceData *pData); -typedef int (WINAPI * PFN_QERAPP_GETFACECOUNT)(void* pv); -typedef _QERFaceData* (WINAPI * PFN_QERAPP_GETFACEDATA)(void* pv, int nFaceIndex); -typedef void (WINAPI * PFN_QERAPP_SETFACEDATA)(void* pv, int nFaceIndex, _QERFaceData *pData); -typedef void (WINAPI * PFN_QERAPP_DELETEFACE)(void* pv, int nFaceIndex); -typedef void (WINAPI * PFN_QERAPP_TEXTUREBRUSH)(void* pv, char* pName); -typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH)(void* pv); // PGM -typedef void (WINAPI * PFN_QERAPP_SELECTBRUSH)(void* pv); // PGM -typedef void (WINAPI * PFN_QERAPP_DESELECTBRUSH)(void* pv); // PGM -typedef void (WINAPI * PFN_QERAPP_DESELECTALLBRUSHES)(); // PGM - -typedef void (WINAPI * PFN_QERAPP_DELETESELECTION)(); -typedef void (WINAPI * PFN_QERAPP_GETPOINTS)(int nMax, _QERPointData *pData, char* pMsg); - -typedef int (WINAPI * PFN_QERAPP_SELECTEDBRUSHCOUNT)(); -typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES)(); -typedef void (WINAPI * PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES)(); -typedef void* (WINAPI * PFN_QERAPP_GETSELECTEDBRUSHHANDLE)(int nIndex); - -typedef int (WINAPI * PFN_QERAPP_ACTIVEBRUSHCOUNT)(); -typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES)(); -typedef void (WINAPI * PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES)(); -typedef void* (WINAPI * PFN_QERAPP_GETACTIVEBRUSHHANDLE)(int nIndex); - -typedef int (WINAPI * PFN_QERAPP_TEXTURECOUNT)(); -typedef char* (WINAPI * PFN_QERAPP_GETTEXTURE)(int nIndex); -typedef char* (WINAPI * PFN_QERAPP_GETCURRENTTEXTURE)(); -typedef void (WINAPI * PFN_QERAPP_SETCURRENTTEXTURE)(char* pName); - -typedef void (WINAPI * PFN_QERAPP_REGISTERMAPLOAD)(void* vp); -typedef void (WINAPI * PFN_QERAPP_REGISTERMAPSAVE)(void* vp); - -typedef int (WINAPI * PFN_QERAPP_GETECLASSCOUNT)(); -typedef char* (WINAPI * PFN_QERAPP_GETECLASS)(int nIndex); - -typedef void (WINAPI * PFN_QERAPP_RESETPLUGINS)(); -//--typedef int (WINAPI* PFN_QERAPP_GETENTITYCOUNT)(); - -/*! -\fn LoadTextureRGBA -\param pPixels is the raw RGBA pixel data (24bits, 8 bit depth) -\param nWidth image width -\param nHeight image height -this will work from the RGBA data and create a GL texture (accessed through a GL bind number) -it takes care of creating the mipmapping levels too -see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=575 for some related issues -*/ -typedef qtexture_t* (* PFN_QERAPP_LOADTEXTURERGBA)(unsigned char* pPixels, int nWidth, int nHeight); - -//--typedef LPCSTR (WINAPI* PFN_QERAPP_GETENTITY)(int nIndex); - -// v1.70 -typedef int (WINAPI * PFN_QERAPP_GETENTITYCOUNT)(); -typedef void* (WINAPI * PFN_QERAPP_GETENTITYHANDLE)(int nIndex); -// FIXME: those two are fairly outdated, you get the epairs -// but you don't have a clean epair read/write query -// and you rely on the C structs directly, which might go away soon -// ok now, stop using, it's bad for your karma (see iepairs.h instead) -typedef epair_t* (WINAPI * PFN_QERAPP_ALLOCATEEPAIR)( char*, char* ); -typedef int (WINAPI * PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES)(void* vp); -typedef void (WINAPI * PFN_QERAPP_RELEASEENTITYBRUSHHANDLES)(); -typedef void* (WINAPI * PFN_QERAPP_GETENTITYBRUSHHANDLE)(int nIndex); -typedef void* (WINAPI * PFN_QERAPP_CREATEENTITYHANDLE)(); -typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOENTITY)( void* vpBrush, void* vpEntity); -typedef void (WINAPI * PFN_QERAPP_COMMITENTITYHANDLETOMAP)(void* vp); -typedef void (WINAPI * PFN_QERAPP_SETSCREENUPDATE)(int bScreenUpdate); -// this one uses window flags defined in qertypes.h -typedef void (WINAPI * PFN_QERAPP_SYSUPDATEWINDOWS)(int bits); -//++timo remove this one -typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH2)(void* vp, int bConvert); - -// v1.80 -typedef void (WINAPI * PFN_QERAPP_GETDISPATCHPARAMS)(vec3_t vMin, vec3_t vMax, bool *bSingleBrush); - -typedef int (WINAPI * PFN_QERAPP_REQUESTINTERFACE)( REFGUID, void* ); -// use this one for errors, Radiant will stop after the "edit preferences" dialog -typedef void (WINAPI * PFN_QERAPP_ERROR)(char* pMsg, ...); -// use to gain read access to the project epairs -// FIXME: removed, accessed through QERPlug_RegisterPluginEntities with the IEpair interface -// typedef void (WINAPI* PFN_QERAPP_GETPROJECTEPAIR)(epair_t **); -// used to allocate and read a buffer -//++timo NOTE: perhaps this would need moving to some kind of dedicated interface -typedef int (WINAPI * PFN_QERAPP_LOADFILE)(const char *pLocation, void ** buffer); -typedef char* (WINAPI * PFN_QERAPP_EXPANDRELETIVEPATH)(char *); -typedef void (WINAPI * PFN_QERAPP_QECONVERTDOSTOUNIXNAME)( char *dst, const char *src ); -typedef int (WINAPI * PFN_QERAPP_HASSHADER)(const char *); -typedef int (WINAPI * PFN_QERAPP_TEXTURELOADSKIN)(char *pName, int *pnWidth, int *pnHeight); -// retrieves the path to the engine from the preferences dialog box -typedef const char* (WINAPI * PFN_QERAPP_GETGAMEPATH)(); -// retrieves full Radiant path -typedef const char* (WINAPI * PFN_QERAPP_GETQERPATH)(); -// retieves .game name of current active game -typedef const char* (WINAPI * PFN_QERAPP_GETGAMEFILE)(); - -// patches in/out -// NOTE: this is a bit different from the brushes in/out, no LPVOID handles this time -// use int indexes instead -// if you call AllocateActivePatchHandles, you'll be playing with active patches -// AllocateSelectedPatcheHandles for selected stuff -// a call to CreatePatchHandle will move you to a seperate index table -typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES) (); -typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES) (); -typedef void (WINAPI * PFN_QERAPP_RELEASEPATCHHANDLES) (); -typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHDATA) (int); -typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHHANDLE) (int); -typedef void (WINAPI * PFN_QERAPP_DELETEPATCH) (int); -typedef int (WINAPI * PFN_QERAPP_CREATEPATCHHANDLE) (); -// when commiting, only a few patchMesh_t members are relevant: -// int width, height; // in control points, not patches -// int contents, flags, value, type; -// drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; -// once you have commited the index is still available, if the patch handle was allocated by you -// then you can re-use the index to commit other patches .. otherwise you can change existing patches -// NOTE: the handle thing for plugin-allocated patches is a bit silly (nobody's perfect) -// TODO: change current behaviour to an index = 0 to tell Radiant to allocate, other indexes to existing patches -// patch is selected after a commit -// you can add an optional texture / shader name .. if NULL will use the current texture -typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOMAP) (int, patchMesh_t* pMesh, char *texName); -typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOENTITY) (int, patchMesh_t* pMesh, char *texName, void* vpEntity); - -// console output -#define SYS_VRB 0 ///< verbose support (on/off) -#define SYS_STD 1 ///< standard print level - this is the default -#define SYS_WRN 2 ///< warnings -#define SYS_ERR 3 ///< error -#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) -typedef void (WINAPI* PFN_QERAPP_SYSPRINTF) (const char *text, ...); -typedef void (WINAPI* PFN_QERAPP_SYSFPRINTF) (int flag, const char *text, ...); - -typedef void (WINAPI* PFN_QERAPP_SYSBEGINWAIT) (); -typedef void (WINAPI* PFN_QERAPP_SYSENDWAIT) (); - -typedef void (* PFN_QERAPP_SYSBEEP) (); - -typedef void (* PFN_QERAPP_SYSSTATUS) (const char *psz, int part ); - -// core map functionality -typedef void (* PFN_QERAPP_MAPNEW) (); -typedef void (* PFN_QERAPP_MAPFREE) (); -typedef void (* PFN_QERAPP_MAPBUILDBRUSHDATA) (); -typedef qboolean (* PFN_QERAPP_MAPISBRUSHFILTERED) (brush_t *); -typedef void (* PFN_QERAPP_MAPSTARTPOSITION) (); -typedef void (* PFN_QERAPP_MAPREGIONOFF) (); -//typedef void (* PFN_QERAPP_SAVEASDIALOG) (bool bRegion); -typedef void (* PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD) (bool); -typedef void (* PFN_QERAPP_POINTFILECLEAR) (); - -typedef void (* PFN_QERAPP_SYSSETTITLE) (const char *text); - -typedef void (* PFN_QERAPP_CSGMAKEHOLLOW) (); - -typedef void (* PFN_QERAPP_REGIONSPAWNPOINT) (FILE *f); - -/*! -access to a portable GetTickCount -*/ -typedef unsigned long (* PFN_QERAPP_GETTICKCOUNT) (); - -class IModelCache -{ -public: - virtual entity_interfaces_t *GetByID(const char *id, const char* version) = 0; - virtual void DeleteByID(const char *id, const char* version) = 0; - virtual void RefreshAll() = 0; -}; - -typedef IModelCache* (* PFN_GETMODELCACHE)(); - -class IFileTypeList -{ -public: - virtual void addType(filetype_t type) = 0; -}; - -class IFileTypeRegistry -{ -public: - virtual void addType(const char* key, filetype_t type) = 0; - virtual void getTypeList(const char* key, IFileTypeList* typelist) = 0; -private: -}; - -typedef IFileTypeRegistry* (* PFN_GETFILETYPEREGISTRY)(); - -typedef const char* (* PFN_QERAPP_READPROJECTKEY)(const char* key); - -typedef char* (* PFN_GETMAPFILENAME)(); - - // FIXME: -// add map format extensions -// add texture format handlers -// add surface dialog handler -// add model handler/displayer - -// v1 func table -// Plugins need to declare one of these and implement the getfunctable as described above -struct _QERFuncTable_1 -{ - int m_nSize; - PFN_QERAPP_CREATEBRUSH m_pfnCreateBrush; - PFN_QERAPP_CREATEBRUSHHANDLE m_pfnCreateBrushHandle; - PFN_QERAPP_DELETEBRUSHHANDLE m_pfnDeleteBrushHandle; - PFN_QERAPP_COMMITBRUSHHANDLETOMAP m_pfnCommitBrushHandle; - PFN_QERAPP_ADDFACE m_pfnAddFace; - PFN_QERAPP_ADDFACEDATA m_pfnAddFaceData; - PFN_QERAPP_GETFACEDATA m_pfnGetFaceData; - PFN_QERAPP_GETFACECOUNT m_pfnGetFaceCount; - PFN_QERAPP_SETFACEDATA m_pfnSetFaceData; - PFN_QERAPP_DELETEFACE m_pfnDeleteFace; - PFN_QERAPP_TEXTUREBRUSH m_pfnTextureBrush; - PFN_QERAPP_BUILDBRUSH m_pfnBuildBrush; // PGM - PFN_QERAPP_SELECTBRUSH m_pfnSelectBrush; // PGM - PFN_QERAPP_DESELECTBRUSH m_pfnDeselectBrush; // PGM - PFN_QERAPP_DESELECTALLBRUSHES m_pfnDeselectAllBrushes; // PGM - - PFN_QERAPP_DELETESELECTION m_pfnDeleteSelection; - PFN_QERAPP_GETPOINTS m_pfnGetPoints; - - PFN_QERAPP_SELECTEDBRUSHCOUNT m_pfnSelectedBrushCount; - PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES m_pfnAllocateSelectedBrushHandles; - PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES m_pfnReleaseSelectedBrushHandles; - PFN_QERAPP_GETSELECTEDBRUSHHANDLE m_pfnGetSelectedBrushHandle; - - PFN_QERAPP_ACTIVEBRUSHCOUNT m_pfnActiveBrushCount; - PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES m_pfnAllocateActiveBrushHandles; - PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES m_pfnReleaseActiveBrushHandles; - PFN_QERAPP_GETACTIVEBRUSHHANDLE m_pfnGetActiveBrushHandle; - - //++timo this would need to be removed and replaced by the IShaders interface - PFN_QERAPP_TEXTURECOUNT m_pfnTextureCount; - PFN_QERAPP_GETTEXTURE m_pfnGetTexture; - PFN_QERAPP_GETCURRENTTEXTURE m_pfnGetCurrentTexture; - PFN_QERAPP_SETCURRENTTEXTURE m_pfnSetCurrentTexture; - - PFN_QERAPP_GETECLASSCOUNT m_pfnGetEClassCount; - PFN_QERAPP_GETECLASS m_pfnGetEClass; - PFN_QERAPP_RESETPLUGINS m_pfnResetPlugins; - // v1.00 ends here - // v1.50 starts here - PFN_QERAPP_LOADTEXTURERGBA m_pfnLoadTextureRGBA; - // v1.50 ends here - // v1.70 starts here - PFN_QERAPP_GETENTITYCOUNT m_pfnGetEntityCount; - PFN_QERAPP_GETENTITYHANDLE m_pfnGetEntityHandle; - PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES m_pfnAllocateEntityBrushHandles; - PFN_QERAPP_RELEASEENTITYBRUSHHANDLES m_pfnReleaseEntityBrushHandles; - PFN_QERAPP_GETENTITYBRUSHHANDLE m_pfnGetEntityBrushHandle; - PFN_QERAPP_CREATEENTITYHANDLE m_pfnCreateEntityHandle; - PFN_QERAPP_COMMITBRUSHHANDLETOENTITY m_pfnCommitBrushHandleToEntity; - PFN_QERAPP_COMMITENTITYHANDLETOMAP m_pfnCommitEntityHandleToMap; - PFN_QERAPP_ALLOCATEEPAIR m_pfnAllocateEpair; - PFN_QERAPP_SETSCREENUPDATE m_pfnSetScreenUpdate; - PFN_QERAPP_BUILDBRUSH2 m_pfnBuildBrush2; - // v1.70 ends here - // v1.80 starts here - PFN_QERAPP_GETDISPATCHPARAMS m_pfnGetDispatchParams; - - // plugins can request additional interfaces - PFN_QERAPP_REQUESTINTERFACE m_pfnRequestInterface; - PFN_QERAPP_ERROR m_pfnError; - // loading a file into a buffer - PFN_QERAPP_LOADFILE m_pfnLoadFile; - PFN_QERAPP_EXPANDRELETIVEPATH m_pfnExpandReletivePath; - PFN_QERAPP_QECONVERTDOSTOUNIXNAME m_pfnQE_ConvertDOSToUnixName; - PFN_QERAPP_HASSHADER m_pfnHasShader; - PFN_QERAPP_TEXTURELOADSKIN m_pfnTexture_LoadSkin; - PFN_QERAPP_GETGAMEPATH m_pfnGetGamePath; - PFN_QERAPP_GETQERPATH m_pfnGetQERPath; - PFN_QERAPP_GETGAMEFILE m_pfnGetGameFile; - // patches in / out - PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES m_pfnAllocateActivePatchHandles; - PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES m_pfnAllocateSelectedPatchHandles; - PFN_QERAPP_RELEASEPATCHHANDLES m_pfnReleasePatchHandles; - PFN_QERAPP_GETPATCHDATA m_pfnGetPatchData; - PFN_QERAPP_GETPATCHHANDLE m_pfnGetPatchHandle; - PFN_QERAPP_DELETEPATCH m_pfnDeletePatch; - PFN_QERAPP_CREATEPATCHHANDLE m_pfnCreatePatchHandle; - PFN_QERAPP_COMMITPATCHHANDLETOMAP m_pfnCommitPatchHandleToMap; - PFN_QERAPP_COMMITPATCHHANDLETOENTITY m_pfnCommitPatchHandleToEntity; - - PFN_QERAPP_LOADIMAGE m_pfnLoadImage; - - // GTK+ functions - PFN_QERAPP_MESSAGEBOX m_pfnMessageBox; - PFN_QERAPP_FILEDIALOG m_pfnFileDialog; - PFN_QERAPP_DIRDIALOG m_pfnDirDialog; - PFN_QERAPP_COLORDIALOG m_pfnColorDialog; - PFN_QERAPP_LOADBITMAP m_pfnLoadBitmap; - - // Profile functions - PFN_QERAPP_PROFILE_GETDIR m_pfnProfileGetDirectory; - PFN_QERAPP_PROFILE_SAVEINT m_pfnProfileSaveInt; - PFN_QERAPP_PROFILE_SAVESTR m_pfnProfileSaveString; - PFN_QERAPP_PROFILE_LOADINT m_pfnProfileLoadInt; - PFN_QERAPP_PROFILE_LOADSTR m_pfnProfileLoadString; - - // Sys_ functions - PFN_QERAPP_SYSUPDATEWINDOWS m_pfnSysUpdateWindows; - PFN_QERAPP_SYSBEEP m_pfnSysBeep; - PFN_QERAPP_SYSPRINTF m_pfnSysPrintf; - PFN_QERAPP_SYSFPRINTF m_pfnSysFPrintf; - PFN_QERAPP_SYSBEGINWAIT m_pfnSysBeginWait; - PFN_QERAPP_SYSENDWAIT m_pfnSysEndWait; - PFN_QERAPP_SYSSETTITLE m_pfnSys_SetTitle; - PFN_QERAPP_SYSSTATUS m_pfnSys_Status; - - // some core functionality on the map - PFN_QERAPP_MAPNEW m_pfnMapNew; - PFN_QERAPP_MAPFREE m_pfnMapFree; - PFN_QERAPP_MAPBUILDBRUSHDATA m_pfnMapBuildBrushData; - PFN_QERAPP_MAPISBRUSHFILTERED m_pfnMap_IsBrushFiltered; - PFN_QERAPP_MAPSTARTPOSITION m_pfnMapStartPosition; - PFN_QERAPP_MAPREGIONOFF m_pfnMapRegionOff; - PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD m_pfnSetBuildWindingsNoTexBuild; -// PFN_QERAPP_SAVEASDIALOG m_pfnSaveAsDialog; - PFN_QERAPP_POINTFILECLEAR m_pfnPointFileClear; - - // FIXME TTimo prolly want to move that somewhere else - PFN_QERAPP_CSGMAKEHOLLOW m_pfnCSG_MakeHollow; - - PFN_QERAPP_REGIONSPAWNPOINT m_pfnRegionSpawnPoint; - PFN_QERAPP_GETTICKCOUNT m_pfnQGetTickCount; - PFN_GETMODELCACHE m_pfnGetModelCache; - PFN_GETFILETYPEREGISTRY m_pfnGetFileTypeRegistry; - - PFN_QERAPP_READPROJECTKEY m_pfnReadProjectKey; - - // digibob from the old _QERAppBSPFrontendTable table - PFN_GETMAPFILENAME m_pfnGetMapName; -}; - -// macros to access those faster in plugins -#ifdef USE_QERTABLE_DEFINE -#ifndef __QERTABLENAME -#define __QERTABLENAME g_FuncTable -#endif -#define CSG_MakeHollow __QERTABLENAME.m_pfnCSG_MakeHollow -#define Sys_Beep __QERTABLENAME.m_pfnSysBeep -#define Sys_Printf __QERTABLENAME.m_pfnSysPrintf -#define Sys_FPrintf __QERTABLENAME.m_pfnSysFPrintf -#define Sys_BeginWait __QERTABLENAME.m_pfnSysBeginWait -#define Sys_EndWait __QERTABLENAME.m_pfnSysEndWait -#define Sys_UpdateWindows __QERTABLENAME.m_pfnSysUpdateWindows -#define Sys_SetTitle __QERTABLENAME.m_pfnSys_SetTitle -#define Sys_Status __QERTABLENAME.m_pfnSys_Status -#define Select_Deselect __QERTABLENAME.m_pfnDeselectAllBrushes -#define Map_New __QERTABLENAME.m_pfnMapNew -#define Map_Free __QERTABLENAME.m_pfnMapFree -#define Map_IsBrushFiltered __QERTABLENAME.m_pfnMap_IsBrushFiltered -#define Map_BuildBrushData __QERTABLENAME.m_pfnMapBuildBrushData -#define Map_StartPosition __QERTABLENAME.m_pfnMapStartPosition -#define Map_RegionOff __QERTABLENAME.m_pfnMapRegionOff -#define QE_ConvertDOSToUnixName __QERTABLENAME.m_pfnQE_ConvertDOSToUnixName -#define SetBuildWindingsNoTexBuild __QERTABLENAME.m_pfnSetBuildWindingsNoTexBuild -//#define SaveAsDialog __QERTABLENAME.m_pfnSaveAsDialog -#define Pointfile_Clear __QERTABLENAME.m_pfnPointFileClear -#define SetScreenUpdate __QERTABLENAME.m_pfnSetScreenUpdate -#define Region_SpawnPoint __QERTABLENAME.m_pfnRegionSpawnPoint -#define QGetTickCount __QERTABLENAME.m_pfnGetTickCount -#define GetModelCache __QERTABLENAME.m_pfnGetModelCache -#define GetFileTypeRegistry __QERTABLENAME.m_pfnGetFileTypeRegistry -#else -IFileTypeRegistry* GetFileTypeRegistry(); -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// QERadiant PlugIns +// +// + +#ifndef __QERPLUGIN_H__ +#define __QERPLUGIN_H__ + +/*! +\todo this header is intended to be turned into a header for the core editor functionality +some portability related code should be moved to synapse (such as the GUID stuff) +*/ + +#include +#include +// TTimo +// ideally the plugin API would be UI toolkit independent, but removing the dependency with GLib seems tricky right now.. +#include +#include "qertypes.h" + +// FIXME TTimo: +// GUID declaration here should be trashed, it is in synapse.h +#ifdef _WIN32 +#include +#endif + +#define QER_MAX_NAMELEN 1024 + +#ifndef _WIN32 +#include "misc_def.h" +#endif + +// the editor will look for plugins in two places, the plugins path +// under the application path, and the path under the basepath as defined +// in the project (.qe4) file. +// +// you can drop any number of new texture, model format DLL's in the standard plugin path +// but only one plugin that overrides map loading/saving, surface dialog, surface flags, etc.. +// should be used at one time.. if multiples are loaded then the last one loaded will be the +// active one +// +// type of services the plugin supplies, pass any combo of these flags +// it is assumed the plugin will have a matching function as defined below +// to correlate to the implied functionality +// + +#define RADIANT_MAJOR "radiant" + +// basics +#define QERPLUG_INIT "QERPlug_Init" +#define QERPLUG_GETNAME "QERPlug_GetName" +#define QERPLUG_GETCOMMANDLIST "QERPlug_GetCommandList" +#define QERPLUG_DISPATCH "QERPlug_Dispatch" +#define QERPLUG_GETFUNCTABLE "QERPlug_GetFuncTable" + +// game stuff +#define QERPLUG_GETTEXTUREINFO "QERPlug_GetTextureInfo" // gets a texture info structure +#define QERPLUG_LOADTEXTURE "QERPlug_LoadTexture" // loads a texture, will return an RGBA structure + // and any surface flags/contents for it +#define QERPLUG_GETSURFACEFLAGS "QERPlug_GetSurfaceFlags" // gets a list of surface/content flag names from a plugin + +struct _QERTextureInfo +{ + char m_TextureExtension[QER_MAX_NAMELEN]; // the extension these textures have + qboolean m_bHiColor; // if textures are NOT high color, the default + // palette (as described inthe qe4 file will be used for gamma correction) + // if they are high color, gamma and shading are computed on the fly + // based on the rgba data + //--bool m_bIsShader; // will probably do q3 shaders this way when i merge + qboolean m_bWadStyle; // if this is true, the plugin will be presented with the texture path + // defined in the .qe4 file and is expected to preload all the textures + qboolean m_bHalfLife; // causes brushes to be saved/parsed without the surface contents/flags/value +}; + +struct _QERTextureLoad // returned by a plugin +{ + _QERTextureLoad() + { + memset(reinterpret_cast(this), 0, sizeof(_QERTextureLoad)); + }; + + ~_QERTextureLoad() + { + delete []m_pRGBA; + delete []m_pName; + }; + + void makeSpace(int nSize) + { + m_pRGBA = new unsigned char[nSize+1]; + }; + + void setName(const char* p) + { + m_pName = new char[strlen(p)+1]; + strcpy(m_pName, p); + }; + + + unsigned char *m_pRGBA; // rgba data (alpha channel is supported and drawn appropriately) + int m_nWidth; // width + int m_nHeight; // height + int m_nContents; // default contents + int m_nFlags; // "" flags + int m_nValue; // "" value + char *m_pName; // name to be referenced in map, build tools, etc. +}; + +struct _QERModelInfo +{ + char m_ModelExtension[QER_MAX_NAMELEN]; + bool m_bSkinned; + bool m_bMultipart; +}; + +struct _QERModelLoad +{ + // vertex and skin data +}; + + +//========================================= +// plugin functions +#if 0 +// NOTE TTimo: hack to make old plugin tech and new plugin tech live together +#ifndef _IPLUGIN_H_ +// toolkit-independant interface, cast hwndMain to GtkWidget* +typedef const char* (WINAPI *PFN_QERPLUG_INIT)(void* hApp, void* hwndMain); +typedef const char* (WINAPI *PFN_QERPLUG_GETNAME)(); +typedef const char* (WINAPI *PFN_QERPLUG_GETCOMMANDLIST)(); +typedef void (WINAPI *PFN_QERPLUG_DISPATCH)(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush); +#endif +#endif + +typedef char* (WINAPI *PFN_QERPLUG_GETFUNCTABLE)(); + +// v1.5 +// +// Texture loading +// returns a ptr to _QERTextureInfo +typedef void* (WINAPI *PFN_QERPLUG_GETTEXTUREINFO)(); +// +// loads a texture by calling the texture load func in the editor (defined below) +// transparency (for water, fog, lava, etc.. ) can be emulated in the editor +// by passing in appropriate alpha data or by setting the appropriate surface flags +// expected by q2 (which the editor will use.. ) +typedef void (WINAPI *PFN_QERPLUG_LOADTEXTURE)(const char* pFilename); + +// v1.6 +typedef void* (WINAPI *PFN_QERPLUG_GETSURFACEFLAGS)(); + +// v1.7 +// if exists in plugin, gets called between INIT and GETCOMMANDLIST +// the plugin can register the EClasses he wants to handle +//++timo TODO: this has got to move into the table, and be requested by QERPlug_RequestInterface +//++timo FIXME: the LPVOID parameter must be casted to an IEpair interface +#define QERPLUG_REGISTERPLUGINENTITIES "QERPlug_RegisterPluginEntities" +typedef void (WINAPI * PFN_QERPLUG_REGISTERPLUGINENTITIES)( void* ); + +// if exists in plugin, gets called between INIT and GETCOMMANDLIST +// the plugin can Init all it needs for surface properties +#define QERPLUG_INITSURFACEPROPERTIES "QERPlug_InitSurfaceProperties" +typedef void (WINAPI * PFN_QERPLUG_INITSURFACEPROPERTIES)(); + +// if Radiant needs to use a particular set of commands, it can request the plugin to fill a func table +// this is similar to PFN_QERAPP_REQUESTINTERFACE +#define QERPLUG_REQUESTINTERFACE "QERPlug_RequestInterface" +typedef int (WINAPI * PFN_QERPLUG_REQUESTINTERFACE) (REFGUID refGUID, void* pInterface, const char *version_name); + +// Load an image file +typedef void (* PFN_QERAPP_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); + +// TTimo FIXME: the logic for this is in synapse now + +// MODULES specific: +// if it exports this entry point, will be considered as a module +// a module is a plugin that provides some REQUIRED interfaces to Radiant, such as the shader module +// Radiant will call QERPLUG_LISTINTERFACES to get a list of the interfaces a given plugin implements +// then it will call PFN_QERPLUG_REQUESTINTERFACE to actually get them + +// following leo's code .. looks ok to use a string to identify the various versions of a same interface +// obviously it would be handy to have the same string naming for the interfaces. +// best way would be to have the names come in when you list the interfaces +// NOTE: we might have a problem with the order in which the interfaces are filled in +// there's some kind of dependency graph, the shader module expects to find the VFS ready etc. +typedef struct moduleentry_s { + const GUID *interface_GUID; + const char* interface_name; + const char* version_name; +} moduleentry_t; + +#define QERPLUG_LISTINTERFACES "QERPlug_ListInterfaces" +#define MAX_QERPLUG_INTERFACES 10 +typedef int (WINAPI* PFN_QERPLUG_LISTINTERFACES) (moduleentry_t table[MAX_QERPLUG_INTERFACES]); + +// ======================================== +// GTK+ helper functions + +// NOTE: parent can be NULL in all functions but it's best to set them + +// simple Message Box, see above for the 'type' flags +// toolkit-independent, cast parent ot a GtkWidget* +typedef gint (WINAPI* PFN_QERAPP_MESSAGEBOX) (void *parent, const char* text, + const char* caption, guint32 type, const char *URL); + +// file and directory selection functions return NULL if the user hits cancel +// or a gchar* string that must be g_free'd by the user +// - 'title' is the dialog title (can be NULL) +// - 'path' is used to set the initial directory (can be NULL) +// - 'pattern': the first pattern is for the win32 mode, then comes the Gtk pattern list, see Radiant source for samples +// TTimo 04/01/2001 toolkit-independant, cast parent to a GtkWidget* +typedef const gchar* (* PFN_QERAPP_FILEDIALOG) (void *parent, gboolean open, const char* title, + const char* path, const char* pattern); +typedef gchar* (WINAPI* PFN_QERAPP_DIRDIALOG) (void *parent, const char* title, + const char* path); + +// return true if the user closed the dialog with 'Ok' +// 'color' is used to set the initial value and store the selected value +typedef bool (WINAPI* PFN_QERAPP_COLORDIALOG) (void *parent, float *color, + const char* title); + +// load a .bmp file and store the results in 'gdkpixmap' and 'mask' +// returns TRUE on success but even if it fails, it creates an empty pixmap +// NOTE: 'filename' is relative to /plugins/bitmaps/ +// TTimo 04/01/2001 toolkit-independant, cast gkpixmap to GdkPixmap and mask to GdkBitmap +typedef bool (WINAPI* PFN_QERAPP_LOADBITMAP) (const char* filename, void **gdkpixmap, void **mask); + +// ======================================== +// read/write preferences file + +// use this function to get the directory where the preferences file are stored +typedef const char* (WINAPI* PFN_QERAPP_PROFILE_GETDIR) (); + +// 'filename' is the absolute path +typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVEINT) (const char *filename, const char *section, + const char *key, int value); +typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVESTR) (const char *filename, const char *section, + const char *key, const char *value); +typedef int (WINAPI* PFN_QERAPP_PROFILE_LOADINT) (const char *filename, const char *section, + const char *key, int default_value); +typedef char* (WINAPI* PFN_QERAPP_PROFILE_LOADSTR) (const char *filename, const char *section, + const char *key, const char *default_value); + +//========================================= +// editor functions + +// There are 3 potential brush handle lists +// 1. the list that contains brushes a plugin creates using CreateBrushHandle +// 2. the selected brush list (brushes the user has selected) +// 3. the active brush list (brushes in the map that are not selected) +// +// In general, the same things can be done to brush handles (face manip, delete brushhandle, etc.. ) in each +// list. There are a few exceptions. +// 1. You cannot commit a selected or active brush handle to the map. This is because it is already in the map. +// 2. You cannot bind brush handles from the selected or active brush list to an entity. As of v1.0 of the plugins +// the only way for a plugin to create entities is to create a brush handles (or a list of handles) and then bind +// them to an entity. This will commit the brush(s) and/or the entities to the map as well. +// +// To use the active or selected brush lists, you must first allocate them (which returns a count) and then +// release them when you are finish manipulating brushes in one of those lists. + +//++timo NOTE : the #defines here are never used, but can help finding where things are done in the editor +#if 0 +// brush manipulation routines +#define QERAPP_CREATEBRUSH "QERApp_CreateBrush" +#define QERAPP_CREATEBRUSHHANDLE "QERApp_CreateBrushHandle" +#define QERAPP_DELETEBRUSHHANDLE "QERApp_DeleteBrushHandle" +#define QERAPP_COMMITBRUSHHANDLETOMAP "QERApp_CommitBrushHandleToMap" +//++timo not implemented .. remove +// #define QERAPP_BINDHANDLESTOENTITY "QERApp_BindHandlesToEntity" +#define QERAPP_ADDFACE "QERApp_AddFace" +#define QERAPP_ADDFACEDATA "QERApp_AddFaceData" +#define QERAPP_GETFACECOUNT "QERApp_GetFaceCount" +#define QERAPP_GETFACEDATA "QERApp_GetFaceData" +#define QERAPP_SETFACEDATA "QERApp_SetFaceData" +#define QERAPP_DELETEFACE "QERApp_DeleteFace" +#define QERAPP_TEXTUREBRUSH "QERApp_TextureBrush" +#define QERAPP_BUILDBRUSH "QERApp_BuildBrush" // PGM +#define QERAPP_SELECTEDBRUSHCOUNT "QERApp_SelectedBrushCount" +#define QERAPP_ALLOCATESELECTEDBRUSHHANDLES "QERApp_AllocateSelectedBrushHandles" +#define QERAPP_RELEASESELECTEDBRUSHHANDLES "QERApp_ReleaseSelectedBrushHandles" +#define QERAPP_GETSELECTEDBRUSHHANDLE "QERApp_GetSelectedBrushHandle" +#define QERAPP_ACTIVEBRUSHCOUNT "QERApp_ActiveBrushCount" +#define QERAPP_ALLOCATEACTIVEBRUSHHANDLES "QERApp_AllocateActiveBrushHandles" +#define QERAPP_RELEASEACTIVEBRUSHHANDLES "QERApp_ReleaseActiveBrushHandles" +#define QERAPP_GETACTIVEBRUSHHANDLE "QERApp_GetActiveBrushHandle" + +// texture stuff +#define QERAPP_TEXTURECOUNT "QERApp_TextureCount" +#define QERAPP_GETTEXTURE "QERApp_GetTexture" +#define QERAPP_GETCURRENTTEXTURE "QERApp_GetCurrentTexture" +#define QERAPP_SETCURRENTTEXTURE "QERApp_SetCurrentTexture" + +// selection +#define QERAPP_DELETESELECTION "QERApp_DeleteSelection" +#define QERAPP_SELECTBRUSH "QERApp_SelectBrush" // PGM +#define QERAPP_DESELECTBRUSH "QERApp_DeselectBrush" // PGM +#define QERAPP_DESELECTALLBRUSHES "QERApp_DeselectAllBrushes" // PGM + +// data gathering +#define QERAPP_GETPOINTS "QERApp_GetPoints" +#define QERAPP_SELECTBRUSHES "QERApp_GetBrushes" + +// entity class stuff +// the entity handling is very basic for 1.0 +#define QERAPP_GETECLASSCOUNT "QERApp_GetEClassCount" +#define QERAPP_GETECLASS "QERApp_GetEClass" + +// misc +#define QERAPP_SYSMSG "QERApp_SysMsg" +#define QERAPP_INFOMSG "QERApp_InfoMsg" +#define QERAPP_HIDEINFOMSG "QERApp_HideInfoMsg" +#define QERAPP_RESET_PLUGINS "QERApp_ResetPlugins" + +// texture loading +#define QERAPP_LOADTEXTURERGBA "QERApp_LoadTextureRGBA" + +// FIXME: the following are not implemented yet +// hook registrations +#define QERAPP_REGISTER_MAPLOADFUNC "QERApp_Register_MapLoadFunc" +#define QERAPP_REGISTER_MAPSAVEFUNC "QERApp_Register_MapSaveFunc" + +// FIXME: the following are not implemented yet +#define QERAPP_REGISTER_PROJECTLOADFUNC "QERApp_Register_ProjectLoadFunc" +#define QERAPP_REGISTER_MOUSEHANDLER "QERApp_Register_MouseHandler" +#define QERAPP_REGISTER_KEYHANDLER "QERApp_Register_KeyHandler" + +// FIXME: new primtives do not work in v1.00 +// primitives are new types of things in the map +// for instance, the Q3 curves could have been done as +// primitives instead of being built in +// it will be a plugins responsibility to hook the map load and save funcs to load +// and/or save any additional data (like new primitives of some type) +// the editor will call each registered renderer during the rendering process to repaint +// any primitives the plugin owns +// each primitive object has a temporary sibling brush that lives in the map +// FIXME: go backwards on this a bit.. orient it more towards the temp brush mode as it will be cleaner +// basically a plugin will hook the map load and save and will add the primitives to the map.. this will +// produce a temporary 'primitive' brush and the appropriate renderer will be called as well as the +// edit handler (for edge drags, sizes, rotates, etc.. ) and the vertex maker will be called when vertex +// mode is attemped on the brush.. there will need to be a GetPrimitiveBounds callback in the edit handler +// so the brush can resize appropriately as needed.. this might be the plugins responsibility to set the +// sibling brushes size.. it will then be the plugins responsibility to hook map save to save the primitives +// as the editor will discard any temp primitive brushes.. (there probably needs to be some kind of sanity check +// here as far as keeping the brushes and the plugin in sync.. i suppose the edit handler can deal with all of that +// crap but it looks like a nice place for a mess) +#define QERAPP_REGISTER_PRIMITIVE "QERApp_Register_Primitive" +#define QERAPP_REGISTER_RENDERER "QERApp_Register_Renderer" +#define QERAPP_REGISTER_EDITHANDLER "QERApp_Register_EditHandler" +#define QERAPP_REGISTER_VERTEXMAKER "QERApp_Register_VertexMaker" +#define QERAPP_ADDPRIMITIVE "QERApp_AddPrimitive" + +// v1.70 +#define QERAPP_GETENTITYCOUNT "QERApp_GetEntityCount" +#define QERAPP_GETENTITYHANDLE "QERApp_GetEntityHandle" +//++timo not implemented for the moment +// #define QERAPP_GETENTITYINFO "QERApp_GetEntityInfo" +//++timo does the keyval need some more funcs to add/remove ? +// get the pointer and do the changes yourself +#define QERAPP_ALLOCATEEPAIR "QERApp_AllocateEpair" +#define QERAPP_ALLOCATEENTITYBRUSHHANDLES "QERApp_AllocateEntityBrushHandles" +#define QERAPP_RELEASEENTITYBRUSHHANDLES "QERApp_ReleaseEntityBrushHandles" +#define QERAPP_GETENTITYBRUSHHANDLE "QERApp_GetEntityBrushHandle" +#define QERAPP_CREATEENTITYHANDLE "QERApp_CreateEntityHandle" +#define QERAPP_COMMITBRUSHHANDLETOENTITY "QERApp_CommitBrushHandleToEntity" +#define QERAPP_COMMITENTITYHANDLETOMAP "QERApp_CommitEntityHandleToMap" +#define QERAPP_SETSCREENUPDATE "QERApp_SetScreenUpdate" +#define QERAPP_BUILDBRUSH2 "QERApp_BuildBrush2" +#endif + +// v1.80 +#define QERAPP_GETDISPATCHPARAMS "QERApp_GetDispatchParams" + +struct _QERPointData +{ + int m_nCount; + vec3_t *m_pVectors; +}; + +struct _QERFaceData +{ + char m_TextureName[QER_MAX_NAMELEN]; + int m_nContents; + int m_nFlags; + int m_nValue; + float m_fShift[2]; + float m_fRotate; + float m_fScale[2]; + vec3_t m_v1, m_v2, m_v3; + // brush primitive additions + qboolean m_bBPrimit; + brushprimit_texdef_t brushprimit_texdef; +}; + +typedef void (WINAPI * PFN_QERAPP_CREATEBRUSH)(vec3_t vMin, vec3_t vMax); + +typedef void* (WINAPI * PFN_QERAPP_CREATEBRUSHHANDLE)(); +typedef void (WINAPI * PFN_QERAPP_DELETEBRUSHHANDLE)(void* pv); +typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOMAP)(void* pv); +typedef void (WINAPI * PFN_QERAPP_ADDFACE)(void* pv, vec3_t v1, vec3_t v2, vec3_t v3); + +typedef void (WINAPI * PFN_QERAPP_ADDFACEDATA)(void* pv, _QERFaceData *pData); +typedef int (WINAPI * PFN_QERAPP_GETFACECOUNT)(void* pv); +typedef _QERFaceData* (WINAPI * PFN_QERAPP_GETFACEDATA)(void* pv, int nFaceIndex); +typedef void (WINAPI * PFN_QERAPP_SETFACEDATA)(void* pv, int nFaceIndex, _QERFaceData *pData); +typedef void (WINAPI * PFN_QERAPP_DELETEFACE)(void* pv, int nFaceIndex); +typedef void (WINAPI * PFN_QERAPP_TEXTUREBRUSH)(void* pv, char* pName); +typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_SELECTBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_DESELECTBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_DESELECTALLBRUSHES)(); // PGM + +typedef void (WINAPI * PFN_QERAPP_DELETESELECTION)(); +typedef void (WINAPI * PFN_QERAPP_GETPOINTS)(int nMax, _QERPointData *pData, char* pMsg); + +typedef int (WINAPI * PFN_QERAPP_SELECTEDBRUSHCOUNT)(); +typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES)(); +typedef void (WINAPI * PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETSELECTEDBRUSHHANDLE)(int nIndex); + +typedef int (WINAPI * PFN_QERAPP_ACTIVEBRUSHCOUNT)(); +typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES)(); +typedef void (WINAPI * PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETACTIVEBRUSHHANDLE)(int nIndex); + +typedef int (WINAPI * PFN_QERAPP_TEXTURECOUNT)(); +typedef char* (WINAPI * PFN_QERAPP_GETTEXTURE)(int nIndex); +typedef char* (WINAPI * PFN_QERAPP_GETCURRENTTEXTURE)(); +typedef void (WINAPI * PFN_QERAPP_SETCURRENTTEXTURE)(char* pName); + +typedef void (WINAPI * PFN_QERAPP_REGISTERMAPLOAD)(void* vp); +typedef void (WINAPI * PFN_QERAPP_REGISTERMAPSAVE)(void* vp); + +typedef int (WINAPI * PFN_QERAPP_GETECLASSCOUNT)(); +typedef char* (WINAPI * PFN_QERAPP_GETECLASS)(int nIndex); + +typedef void (WINAPI * PFN_QERAPP_RESETPLUGINS)(); +//--typedef int (WINAPI* PFN_QERAPP_GETENTITYCOUNT)(); + +/*! +\fn LoadTextureRGBA +\param pPixels is the raw RGBA pixel data (24bits, 8 bit depth) +\param nWidth image width +\param nHeight image height +this will work from the RGBA data and create a GL texture (accessed through a GL bind number) +it takes care of creating the mipmapping levels too +see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=575 for some related issues +*/ +typedef qtexture_t* (* PFN_QERAPP_LOADTEXTURERGBA)(unsigned char* pPixels, int nWidth, int nHeight); + +//--typedef LPCSTR (WINAPI* PFN_QERAPP_GETENTITY)(int nIndex); + +// v1.70 +typedef int (WINAPI * PFN_QERAPP_GETENTITYCOUNT)(); +typedef void* (WINAPI * PFN_QERAPP_GETENTITYHANDLE)(int nIndex); +// FIXME: those two are fairly outdated, you get the epairs +// but you don't have a clean epair read/write query +// and you rely on the C structs directly, which might go away soon +// ok now, stop using, it's bad for your karma (see iepairs.h instead) +typedef epair_t* (WINAPI * PFN_QERAPP_ALLOCATEEPAIR)( char*, char* ); +typedef int (WINAPI * PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES)(void* vp); +typedef void (WINAPI * PFN_QERAPP_RELEASEENTITYBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETENTITYBRUSHHANDLE)(int nIndex); +typedef void* (WINAPI * PFN_QERAPP_CREATEENTITYHANDLE)(); +typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOENTITY)( void* vpBrush, void* vpEntity); +typedef void (WINAPI * PFN_QERAPP_COMMITENTITYHANDLETOMAP)(void* vp); +typedef void (WINAPI * PFN_QERAPP_SETSCREENUPDATE)(int bScreenUpdate); +// this one uses window flags defined in qertypes.h +typedef void (WINAPI * PFN_QERAPP_SYSUPDATEWINDOWS)(int bits); +//++timo remove this one +typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH2)(void* vp, int bConvert); + +// v1.80 +typedef void (WINAPI * PFN_QERAPP_GETDISPATCHPARAMS)(vec3_t vMin, vec3_t vMax, bool *bSingleBrush); + +typedef int (WINAPI * PFN_QERAPP_REQUESTINTERFACE)( REFGUID, void* ); +// use this one for errors, Radiant will stop after the "edit preferences" dialog +typedef void (WINAPI * PFN_QERAPP_ERROR)(char* pMsg, ...); +// use to gain read access to the project epairs +// FIXME: removed, accessed through QERPlug_RegisterPluginEntities with the IEpair interface +// typedef void (WINAPI* PFN_QERAPP_GETPROJECTEPAIR)(epair_t **); +// used to allocate and read a buffer +//++timo NOTE: perhaps this would need moving to some kind of dedicated interface +typedef int (WINAPI * PFN_QERAPP_LOADFILE)(const char *pLocation, void ** buffer); +typedef char* (WINAPI * PFN_QERAPP_EXPANDRELETIVEPATH)(char *); +typedef void (WINAPI * PFN_QERAPP_QECONVERTDOSTOUNIXNAME)( char *dst, const char *src ); +typedef int (WINAPI * PFN_QERAPP_HASSHADER)(const char *); +typedef int (WINAPI * PFN_QERAPP_TEXTURELOADSKIN)(char *pName, int *pnWidth, int *pnHeight); +// retrieves the path to the engine from the preferences dialog box +typedef const char* (WINAPI * PFN_QERAPP_GETGAMEPATH)(); +// retrieves full Radiant path +typedef const char* (WINAPI * PFN_QERAPP_GETQERPATH)(); +// retieves .game name of current active game +typedef const char* (WINAPI * PFN_QERAPP_GETGAMEFILE)(); + +// patches in/out +// NOTE: this is a bit different from the brushes in/out, no LPVOID handles this time +// use int indexes instead +// if you call AllocateActivePatchHandles, you'll be playing with active patches +// AllocateSelectedPatcheHandles for selected stuff +// a call to CreatePatchHandle will move you to a seperate index table +typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES) (); +typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES) (); +typedef void (WINAPI * PFN_QERAPP_RELEASEPATCHHANDLES) (); +typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHDATA) (int); +typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHHANDLE) (int); +typedef void (WINAPI * PFN_QERAPP_DELETEPATCH) (int); +typedef int (WINAPI * PFN_QERAPP_CREATEPATCHHANDLE) (); +// when commiting, only a few patchMesh_t members are relevant: +// int width, height; // in control points, not patches +// int contents, flags, value, type; +// drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; +// once you have commited the index is still available, if the patch handle was allocated by you +// then you can re-use the index to commit other patches .. otherwise you can change existing patches +// NOTE: the handle thing for plugin-allocated patches is a bit silly (nobody's perfect) +// TODO: change current behaviour to an index = 0 to tell Radiant to allocate, other indexes to existing patches +// patch is selected after a commit +// you can add an optional texture / shader name .. if NULL will use the current texture +typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOMAP) (int, patchMesh_t* pMesh, char *texName); +typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOENTITY) (int, patchMesh_t* pMesh, char *texName, void* vpEntity); + +// console output +#define SYS_VRB 0 ///< verbose support (on/off) +#define SYS_STD 1 ///< standard print level - this is the default +#define SYS_WRN 2 ///< warnings +#define SYS_ERR 3 ///< error +#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) +typedef void (WINAPI* PFN_QERAPP_SYSPRINTF) (const char *text, ...); +typedef void (WINAPI* PFN_QERAPP_SYSFPRINTF) (int flag, const char *text, ...); + +typedef void (WINAPI* PFN_QERAPP_SYSBEGINWAIT) (); +typedef void (WINAPI* PFN_QERAPP_SYSENDWAIT) (); + +typedef void (* PFN_QERAPP_SYSBEEP) (); + +typedef void (* PFN_QERAPP_SYSSTATUS) (const char *psz, int part ); + +// core map functionality +typedef void (* PFN_QERAPP_MAPNEW) (); +typedef void (* PFN_QERAPP_MAPFREE) (); +typedef void (* PFN_QERAPP_MAPBUILDBRUSHDATA) (); +typedef qboolean (* PFN_QERAPP_MAPISBRUSHFILTERED) (brush_t *); +typedef void (* PFN_QERAPP_MAPSTARTPOSITION) (); +typedef void (* PFN_QERAPP_MAPREGIONOFF) (); +//typedef void (* PFN_QERAPP_SAVEASDIALOG) (bool bRegion); +typedef void (* PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD) (bool); +typedef void (* PFN_QERAPP_POINTFILECLEAR) (); + +typedef void (* PFN_QERAPP_SYSSETTITLE) (const char *text); + +typedef void (* PFN_QERAPP_CSGMAKEHOLLOW) (); + +typedef void (* PFN_QERAPP_REGIONSPAWNPOINT) (FILE *f); + +/*! +access to a portable GetTickCount +*/ +typedef unsigned long (* PFN_QERAPP_GETTICKCOUNT) (); + +class IModelCache +{ +public: + virtual entity_interfaces_t *GetByID(const char *id, const char* version) = 0; + virtual void DeleteByID(const char *id, const char* version) = 0; + virtual void RefreshAll() = 0; +}; + +typedef IModelCache* (* PFN_GETMODELCACHE)(); + +class IFileTypeList +{ +public: + virtual void addType(filetype_t type) = 0; +}; + +class IFileTypeRegistry +{ +public: + virtual void addType(const char* key, filetype_t type) = 0; + virtual void getTypeList(const char* key, IFileTypeList* typelist) = 0; +private: +}; + +typedef IFileTypeRegistry* (* PFN_GETFILETYPEREGISTRY)(); + +typedef const char* (* PFN_QERAPP_READPROJECTKEY)(const char* key); + +typedef char* (* PFN_GETMAPFILENAME)(); + + // FIXME: +// add map format extensions +// add texture format handlers +// add surface dialog handler +// add model handler/displayer + +// v1 func table +// Plugins need to declare one of these and implement the getfunctable as described above +struct _QERFuncTable_1 +{ + int m_nSize; + PFN_QERAPP_CREATEBRUSH m_pfnCreateBrush; + PFN_QERAPP_CREATEBRUSHHANDLE m_pfnCreateBrushHandle; + PFN_QERAPP_DELETEBRUSHHANDLE m_pfnDeleteBrushHandle; + PFN_QERAPP_COMMITBRUSHHANDLETOMAP m_pfnCommitBrushHandle; + PFN_QERAPP_ADDFACE m_pfnAddFace; + PFN_QERAPP_ADDFACEDATA m_pfnAddFaceData; + PFN_QERAPP_GETFACEDATA m_pfnGetFaceData; + PFN_QERAPP_GETFACECOUNT m_pfnGetFaceCount; + PFN_QERAPP_SETFACEDATA m_pfnSetFaceData; + PFN_QERAPP_DELETEFACE m_pfnDeleteFace; + PFN_QERAPP_TEXTUREBRUSH m_pfnTextureBrush; + PFN_QERAPP_BUILDBRUSH m_pfnBuildBrush; // PGM + PFN_QERAPP_SELECTBRUSH m_pfnSelectBrush; // PGM + PFN_QERAPP_DESELECTBRUSH m_pfnDeselectBrush; // PGM + PFN_QERAPP_DESELECTALLBRUSHES m_pfnDeselectAllBrushes; // PGM + + PFN_QERAPP_DELETESELECTION m_pfnDeleteSelection; + PFN_QERAPP_GETPOINTS m_pfnGetPoints; + + PFN_QERAPP_SELECTEDBRUSHCOUNT m_pfnSelectedBrushCount; + PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES m_pfnAllocateSelectedBrushHandles; + PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES m_pfnReleaseSelectedBrushHandles; + PFN_QERAPP_GETSELECTEDBRUSHHANDLE m_pfnGetSelectedBrushHandle; + + PFN_QERAPP_ACTIVEBRUSHCOUNT m_pfnActiveBrushCount; + PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES m_pfnAllocateActiveBrushHandles; + PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES m_pfnReleaseActiveBrushHandles; + PFN_QERAPP_GETACTIVEBRUSHHANDLE m_pfnGetActiveBrushHandle; + + //++timo this would need to be removed and replaced by the IShaders interface + PFN_QERAPP_TEXTURECOUNT m_pfnTextureCount; + PFN_QERAPP_GETTEXTURE m_pfnGetTexture; + PFN_QERAPP_GETCURRENTTEXTURE m_pfnGetCurrentTexture; + PFN_QERAPP_SETCURRENTTEXTURE m_pfnSetCurrentTexture; + + PFN_QERAPP_GETECLASSCOUNT m_pfnGetEClassCount; + PFN_QERAPP_GETECLASS m_pfnGetEClass; + PFN_QERAPP_RESETPLUGINS m_pfnResetPlugins; + // v1.00 ends here + // v1.50 starts here + PFN_QERAPP_LOADTEXTURERGBA m_pfnLoadTextureRGBA; + // v1.50 ends here + // v1.70 starts here + PFN_QERAPP_GETENTITYCOUNT m_pfnGetEntityCount; + PFN_QERAPP_GETENTITYHANDLE m_pfnGetEntityHandle; + PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES m_pfnAllocateEntityBrushHandles; + PFN_QERAPP_RELEASEENTITYBRUSHHANDLES m_pfnReleaseEntityBrushHandles; + PFN_QERAPP_GETENTITYBRUSHHANDLE m_pfnGetEntityBrushHandle; + PFN_QERAPP_CREATEENTITYHANDLE m_pfnCreateEntityHandle; + PFN_QERAPP_COMMITBRUSHHANDLETOENTITY m_pfnCommitBrushHandleToEntity; + PFN_QERAPP_COMMITENTITYHANDLETOMAP m_pfnCommitEntityHandleToMap; + PFN_QERAPP_ALLOCATEEPAIR m_pfnAllocateEpair; + PFN_QERAPP_SETSCREENUPDATE m_pfnSetScreenUpdate; + PFN_QERAPP_BUILDBRUSH2 m_pfnBuildBrush2; + // v1.70 ends here + // v1.80 starts here + PFN_QERAPP_GETDISPATCHPARAMS m_pfnGetDispatchParams; + + // plugins can request additional interfaces + PFN_QERAPP_REQUESTINTERFACE m_pfnRequestInterface; + PFN_QERAPP_ERROR m_pfnError; + // loading a file into a buffer + PFN_QERAPP_LOADFILE m_pfnLoadFile; + PFN_QERAPP_EXPANDRELETIVEPATH m_pfnExpandReletivePath; + PFN_QERAPP_QECONVERTDOSTOUNIXNAME m_pfnQE_ConvertDOSToUnixName; + PFN_QERAPP_HASSHADER m_pfnHasShader; + PFN_QERAPP_TEXTURELOADSKIN m_pfnTexture_LoadSkin; + PFN_QERAPP_GETGAMEPATH m_pfnGetGamePath; + PFN_QERAPP_GETQERPATH m_pfnGetQERPath; + PFN_QERAPP_GETGAMEFILE m_pfnGetGameFile; + // patches in / out + PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES m_pfnAllocateActivePatchHandles; + PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES m_pfnAllocateSelectedPatchHandles; + PFN_QERAPP_RELEASEPATCHHANDLES m_pfnReleasePatchHandles; + PFN_QERAPP_GETPATCHDATA m_pfnGetPatchData; + PFN_QERAPP_GETPATCHHANDLE m_pfnGetPatchHandle; + PFN_QERAPP_DELETEPATCH m_pfnDeletePatch; + PFN_QERAPP_CREATEPATCHHANDLE m_pfnCreatePatchHandle; + PFN_QERAPP_COMMITPATCHHANDLETOMAP m_pfnCommitPatchHandleToMap; + PFN_QERAPP_COMMITPATCHHANDLETOENTITY m_pfnCommitPatchHandleToEntity; + + PFN_QERAPP_LOADIMAGE m_pfnLoadImage; + + // GTK+ functions + PFN_QERAPP_MESSAGEBOX m_pfnMessageBox; + PFN_QERAPP_FILEDIALOG m_pfnFileDialog; + PFN_QERAPP_DIRDIALOG m_pfnDirDialog; + PFN_QERAPP_COLORDIALOG m_pfnColorDialog; + PFN_QERAPP_LOADBITMAP m_pfnLoadBitmap; + + // Profile functions + PFN_QERAPP_PROFILE_GETDIR m_pfnProfileGetDirectory; + PFN_QERAPP_PROFILE_SAVEINT m_pfnProfileSaveInt; + PFN_QERAPP_PROFILE_SAVESTR m_pfnProfileSaveString; + PFN_QERAPP_PROFILE_LOADINT m_pfnProfileLoadInt; + PFN_QERAPP_PROFILE_LOADSTR m_pfnProfileLoadString; + + // Sys_ functions + PFN_QERAPP_SYSUPDATEWINDOWS m_pfnSysUpdateWindows; + PFN_QERAPP_SYSBEEP m_pfnSysBeep; + PFN_QERAPP_SYSPRINTF m_pfnSysPrintf; + PFN_QERAPP_SYSFPRINTF m_pfnSysFPrintf; + PFN_QERAPP_SYSBEGINWAIT m_pfnSysBeginWait; + PFN_QERAPP_SYSENDWAIT m_pfnSysEndWait; + PFN_QERAPP_SYSSETTITLE m_pfnSys_SetTitle; + PFN_QERAPP_SYSSTATUS m_pfnSys_Status; + + // some core functionality on the map + PFN_QERAPP_MAPNEW m_pfnMapNew; + PFN_QERAPP_MAPFREE m_pfnMapFree; + PFN_QERAPP_MAPBUILDBRUSHDATA m_pfnMapBuildBrushData; + PFN_QERAPP_MAPISBRUSHFILTERED m_pfnMap_IsBrushFiltered; + PFN_QERAPP_MAPSTARTPOSITION m_pfnMapStartPosition; + PFN_QERAPP_MAPREGIONOFF m_pfnMapRegionOff; + PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD m_pfnSetBuildWindingsNoTexBuild; +// PFN_QERAPP_SAVEASDIALOG m_pfnSaveAsDialog; + PFN_QERAPP_POINTFILECLEAR m_pfnPointFileClear; + + // FIXME TTimo prolly want to move that somewhere else + PFN_QERAPP_CSGMAKEHOLLOW m_pfnCSG_MakeHollow; + + PFN_QERAPP_REGIONSPAWNPOINT m_pfnRegionSpawnPoint; + PFN_QERAPP_GETTICKCOUNT m_pfnQGetTickCount; + PFN_GETMODELCACHE m_pfnGetModelCache; + PFN_GETFILETYPEREGISTRY m_pfnGetFileTypeRegistry; + + PFN_QERAPP_READPROJECTKEY m_pfnReadProjectKey; + + // digibob from the old _QERAppBSPFrontendTable table + PFN_GETMAPFILENAME m_pfnGetMapName; +}; + +// macros to access those faster in plugins +#ifdef USE_QERTABLE_DEFINE +#ifndef __QERTABLENAME +#define __QERTABLENAME g_FuncTable +#endif +#define CSG_MakeHollow __QERTABLENAME.m_pfnCSG_MakeHollow +#define Sys_Beep __QERTABLENAME.m_pfnSysBeep +#define Sys_Printf __QERTABLENAME.m_pfnSysPrintf +#define Sys_FPrintf __QERTABLENAME.m_pfnSysFPrintf +#define Sys_BeginWait __QERTABLENAME.m_pfnSysBeginWait +#define Sys_EndWait __QERTABLENAME.m_pfnSysEndWait +#define Sys_UpdateWindows __QERTABLENAME.m_pfnSysUpdateWindows +#define Sys_SetTitle __QERTABLENAME.m_pfnSys_SetTitle +#define Sys_Status __QERTABLENAME.m_pfnSys_Status +#define Select_Deselect __QERTABLENAME.m_pfnDeselectAllBrushes +#define Map_New __QERTABLENAME.m_pfnMapNew +#define Map_Free __QERTABLENAME.m_pfnMapFree +#define Map_IsBrushFiltered __QERTABLENAME.m_pfnMap_IsBrushFiltered +#define Map_BuildBrushData __QERTABLENAME.m_pfnMapBuildBrushData +#define Map_StartPosition __QERTABLENAME.m_pfnMapStartPosition +#define Map_RegionOff __QERTABLENAME.m_pfnMapRegionOff +#define QE_ConvertDOSToUnixName __QERTABLENAME.m_pfnQE_ConvertDOSToUnixName +#define SetBuildWindingsNoTexBuild __QERTABLENAME.m_pfnSetBuildWindingsNoTexBuild +//#define SaveAsDialog __QERTABLENAME.m_pfnSaveAsDialog +#define Pointfile_Clear __QERTABLENAME.m_pfnPointFileClear +#define SetScreenUpdate __QERTABLENAME.m_pfnSetScreenUpdate +#define Region_SpawnPoint __QERTABLENAME.m_pfnRegionSpawnPoint +#define QGetTickCount __QERTABLENAME.m_pfnGetTickCount +#define GetModelCache __QERTABLENAME.m_pfnGetModelCache +#define GetFileTypeRegistry __QERTABLENAME.m_pfnGetFileTypeRegistry +#else +IFileTypeRegistry* GetFileTypeRegistry(); +#endif + +#endif diff --git a/include/qertypes.h b/include/qertypes.h index 0c6ebbdb..ad785cfe 100644 --- a/include/qertypes.h +++ b/include/qertypes.h @@ -1,911 +1,911 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// qertypes.h -// -// common types -// merged from brush.h, etc. for plugin support -// -#ifndef _QERTYPES_H_ -#define _QERTYPES_H_ - -#ifdef _WIN32 -#include -#endif - -#include - -#include "str.h" - -#ifdef _WIN32 -#define PATH_MAX 260 -#endif - -// HACK glib-2.0 -#define NAME_MAX 255 - -typedef bool qboolean; - -#define MAXPOINTS 16 - -// merged from qedefs.h ------ - -#define MAX_EDGES 512 -#define MAX_POINTS 1024 - -#define COLOR_TEXTUREBACK 0 -#define COLOR_GRIDBACK 1 -#define COLOR_GRIDMINOR 2 -#define COLOR_GRIDMAJOR 3 -#define COLOR_CAMERABACK 4 -#define COLOR_ENTITY 5 -#define COLOR_GRIDBLOCK 6 -#define COLOR_GRIDTEXT 7 -#define COLOR_BRUSHES 8 -#define COLOR_SELBRUSHES 9 -#define COLOR_CLIPPER 10 -#define COLOR_VIEWNAME 11 -#define COLOR_SELBRUSHES3D 12 - -#define COLOR_GRIDMINOR_ALT 13 -#define COLOR_GRIDMAJOR_ALT 14 - -#define COLOR_LAST 15 - -// ---------------------------- - -typedef float vec_t; -typedef vec_t vec3_t[3]; - -// turn this on/off to use a static texdef or a memory one -// THIS MUST BE CONSISTENT throughout a whole build of Radiant / modules / plugins -// DO_TEXDEF_ALLOC is more memory efficient, but I suspect it to be wacky on win32 / C runtime etc. -#define DO_TEXDEF_ALLOC 1 -#if DO_TEXDEF_ALLOC - -class texdef_t -{ -private: - char *name; -public: - texdef_t() - { - name = new char[1]; - name[0] = '\0'; - shift[0] = 0.0f; - shift[1] = 0.0f; - rotate = 0.0f; - scale[0] = 1.0f; - scale[1] = 1.0f; - contents = 0; - flags = 0; - value = 0; - } - texdef_t(const texdef_t& other) - { - name = NULL; - SetName(other.name); - shift[0] = other.shift[0]; - shift[1] = other.shift[1]; - rotate = other.rotate; - scale[0] = other.scale[0]; - scale[1] = other.scale[1]; - contents = other.contents; - flags = other.flags; - value = other.value; - } - ~texdef_t() - { - if (name) - { - delete []name; - name = (char*)NULL; - } - } - - void SetName(const char *p) - { - if (name) - { - delete []name; - name = NULL; - } - if (p) - { - name = strcpy(new char[strlen(p)+1], p); - } - else - { - name = new char[1]; - name[0] = '\0'; - } - } - - const char * GetName() const - { - return name; - } - - // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. - void DropName() - { - name = NULL; - SetName(NULL); - } - - texdef_t& operator =(const texdef_t& rhs) - { - if (&rhs != this) - { - SetName(rhs.name); - shift[0] = rhs.shift[0]; - shift[1] = rhs.shift[1]; - rotate = rhs.rotate; - scale[0] = rhs.scale[0]; - scale[1] = rhs.scale[1]; - contents = rhs.contents; - flags = rhs.flags; - value = rhs.value; - } - return *this; - } - float shift[2]; - float rotate; - float scale[2]; - int contents; - int flags; - int value; -}; - -#else - -// max length of a vfs texture path -#define QPATH 64 -class texdef_t -{ -private: - char name[QPATH]; -public: - texdef_t() { name[0] = '\0'; } - ~texdef_t() { } - - void SetName(const char *p) - { - strncpy(name, p, QPATH); - } - - const char * GetName() const - { - return name; - } - - // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. - void DropName() - { - name[0] = '\0'; - } - - texdef_t& operator =(const texdef_t& rhs) - { - if (&rhs != this) - { - SetName(rhs.name); - shift[0] = rhs.shift[0]; - shift[1] = rhs.shift[1]; - rotate = rhs.rotate; - scale[0] = rhs.scale[0]; - scale[1] = rhs.scale[1]; - contents = rhs.contents; - flags = rhs.flags; - value = rhs.value; - } - return *this; - } - float shift[2]; - float rotate; - float scale[2]; - int contents; - int flags; - int value; -}; - -#endif - -// forward declare -class IShader; - -// Timo -// new brush primitive texdef -typedef struct brushprimit_texdef_s -{ - vec_t coords[2][3]; -} brushprimit_texdef_t; - -// this structure is used in Radiant to reflect the state of the texture window -// it gives information on current shader and various flags -class texturewin_t -{ -public: - texturewin_t() - { - } - ~texturewin_t() - { - } - int width, height; - int originy; - // add brushprimit_texdef_t for brush primitive coordinates storage - brushprimit_texdef_t brushprimit_texdef; - int m_nTotalHeight; - // surface plugin, must be casted to a IPluginTexdef* - void* pTexdef; - texdef_t texdef; - // shader - // NOTE: never NULL, initialized in Texture_Init - // NOTE: the reference name of the shader is texdef.name (see QERApp_ReloadShaders for an example) - IShader *pShader; -}; - -#define QER_TRANS 0x00000001 -#define QER_NOCARVE 0x00000002 -#define QER_NODRAW 0x00000004 -#define QER_NONSOLID 0x00000008 -#define QER_WATER 0x00000010 -#define QER_LAVA 0x00000020 -#define QER_FOG 0x00000040 -#define QER_ALPHAFUNC 0x00000080 -#define QER_CULL 0x00000100 - - -// describes a GL texture that Radiant uses to represent a shader -// NOTE: all qtexture_t are stored in a main list at g_qeglobals.d_qtextures -// shaders have reference couting, but qtexture_t don't (they're way too deep into Radiant) -typedef struct qtexture_s -{ - struct qtexture_s *next; - // name of the texture file (the physical image file we are using) - // NOTE: used for lookup, must be unique .. vfs path of the texture, lowercase, NO FILE EXTENSION - // ex textures/gothic_wall/iron - // NOTE: the "textures/" prefix might seem unnecessary .. but it's better to stick to the vfs name - char name[64]; - int width, height; - GLuint texture_number; // gl bind number (the qtexture_t are usually loaded and binded by the shaders module) - vec3_t color; // for flat shade mode - qboolean inuse; // true = is present on the level (for the texture browser interface) -} qtexture_t; - -// NOTE: don't trust this definition! -// you should read float points[..][5] -// see NewWinding definition -// WARNING: don't touch anything to this struct unless you looked into winding.cpp and WINDING_SIZE(pt) -#define MAX_POINTS_ON_WINDING 64 -typedef struct -{ - int numpoints; - int maxpoints; - float points[8][5]; // variable sized -} winding_t; - -typedef struct -{ - vec3_t normal; - double dist; - int type; -} plane_t; - -// pShader is a shortcut to the shader -// it's only up-to-date after a Brush_Build call -// to initialize the pShader, use QERApp_Shader_ForName(texdef.name) -typedef struct face_s -{ - struct face_s *next; - struct face_s *prev; - struct face_s *original; //used for vertex movement - vec3_t planepts[3]; - texdef_t texdef; - plane_t plane; - - // Nurail: Face Undo - int undoId; - int redoId; - - winding_t *face_winding; - - vec3_t d_color; - vec_t d_shade; - // calls through here have indirections (pure virtual) - // it would be good if the rendering loop would avoid scanning there (for the GL binding number for example) - IShader *pShader; - //++timo FIXME: remove! - qtexture_t *d_texture; - - // Timo new brush primit texdef - brushprimit_texdef_t brushprimit_texdef; - - // cast this one to an IPluginTexdef if you are using it - // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h - // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? - void *pData; -} face_t; - -typedef struct { - vec3_t xyz; - float sideST[2]; - float capST[2]; -} curveVertex_t; - -typedef struct { - curveVertex_t v[2]; -} sideVertex_t; - - -#define MIN_PATCH_WIDTH 3 -#define MIN_PATCH_HEIGHT 3 - -#define MAX_PATCH_WIDTH 16 -#define MAX_PATCH_HEIGHT 16 - -// patch type info -// type in lower 16 bits, flags in upper -// endcaps directly follow this patch in the list - -// types -#define PATCH_GENERIC 0x00000000 // generic flat patch -#define PATCH_CYLINDER 0x00000001 // cylinder -#define PATCH_BEVEL 0x00000002 // bevel -#define PATCH_ENDCAP 0x00000004 // endcap -#define PATCH_HEMISPHERE 0x00000008 // hemisphere -#define PATCH_CONE 0x00000010 // cone -#define PATCH_TRIANGLE 0x00000020 // simple tri, assumes 3x3 patch - -// behaviour styles -#define PATCH_CAP 0x00001000 // flat patch applied as a cap -#define PATCH_SEAM 0x00002000 // flat patch applied as a seam -#define PATCH_THICK 0x00004000 // patch applied as a thick portion - -// styles -#define PATCH_BEZIER 0x00000000 // default bezier -#define PATCH_BSPLINE 0x10000000 // bspline - -#define PATCH_TYPEMASK 0x00000fff // -#define PATCH_BTYPEMASK 0x0000f000 // -#define PATCH_STYLEMASK 0xffff0000 // - -typedef struct { - vec3_t xyz; - float st[2]; - float lightmap[2]; - vec3_t normal; -} drawVert_t; - -// spog - used for patch LOD trees - -struct BTNode_t -{ - BTNode_t *left, *right; - drawVert_t info; - drawVert_t vMid; -}; - -struct BTreeList_t -{ - BTreeList_t *next; - BTNode_t *pBT; - drawVert_t vLeft, vRight; -}; - -struct BTListList_t -{ - BTListList_t *next; - BTreeList_t *list; -}; - -// used in brush primitive AND entities -typedef struct epair_s -{ - struct epair_s *next; - char *key; - char *value; -} epair_t; - -struct brush_s; -typedef struct brush_s brush_t; - -typedef struct { - int width, height; // in control points, not patches - int contents, flags, value, type; - qtexture_t *d_texture; - IShader *pShader; - drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; - brush_t *pSymbiot; - qboolean bSelected; - qboolean bOverlay; - qboolean bDirty; - int nListID; - epair_t *epairs; - // cast this one to an IPluginTexdef if you are using it - // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h - // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? - void *pData; - // spog - curve LOD binary trees and lists - BTNode_t *rowLOD[((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT]; // = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT - BTNode_t *colLOD[((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH]; // = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH - bool rowDirty[((MAX_PATCH_WIDTH-1)-1)/2]; - bool colDirty[((MAX_PATCH_HEIGHT-1)-1)/2]; - bool LODUpdated; - void *drawLists; // pointer to std::list -} patchMesh_t; - -typedef struct brush_s -{ - struct brush_s *prev, *next; // links in active/selected - struct brush_s *oprev, *onext; // links in entity - struct entity_s *owner; - vec3_t mins, maxs; - face_t *brush_faces; - - qboolean bModelFailed; - // - // curve brush extensions - // all are derived from brush_faces - qboolean patchBrush; - qboolean hiddenBrush; - - //int nPatchID; - - patchMesh_t *pPatch; - struct entity_s *pUndoOwner; - - int undoId; //undo ID - int redoId; //redo ID - int ownerId; //entityId of the owner entity for undo - - // TTimo: this is not legal, we are not supposed to put UI toolkit dependant stuff in the interfaces - // NOTE: the grouping stuff never worked, there is embryonary code everywhere though - int numberId; - void* itemOwner; // GtkCTreeNode* ? - - // brush primitive only - epair_t *epairs; - - // brush filtered toggle - bool bFiltered; - bool bCamCulled; - bool bBrushDef; -} brush_t; - -#define MAX_FLAGS 16 - -typedef struct vertmodel_t -{ - float v[3]; - float st[2]; - float normal[3]; -} vertmodel; - -typedef struct triindex_t -{ - int indexes[3]; -} triindex; - -// TTimo: NOTE: we don't have dedicated stuff to copy/allocate/delete this structure like we do for entity_t and brush_t -// could be necessary, I'm adding GString *strSkin that needs to be copied around -// TTimo 04/01/2001 removing the GString* for toolkit-independent interfaces .. cast it .. -typedef struct entitymodel_t -{ - struct entitymodel_t *pNext; - int nTriCount; - //trimodel *pTriList; - //md3Triangle_t *pTriList; - triindex *pTriList; - vertmodel *pVertList; - int numVerts; - int nTextureBind; - void *strSkin; // toolkit-independent .. cast to a GString* - int nSkinWidth; - int nSkinHeight; - int nModelPosition; -} entitymodel; - -// eclass show flags - -#define ECLASS_LIGHT 0x00000001 -#define ECLASS_ANGLE 0x00000002 -#define ECLASS_PATH 0x00000004 -#define ECLASS_MISCMODEL 0x00000008 - -#ifdef USEPLUGINENTITIES -#define ECLASS_PLUGINENTITY 0x00000010 -#endif // USEPLUGINENTITIES - -typedef struct eclass_s -{ - struct eclass_s *next; - char *name; - qboolean fixedsize; - qboolean unknown; // wasn't found in source - vec3_t mins, maxs; - vec3_t color; - texdef_t texdef; - char *comments; - char flagnames[MAX_FLAGS][32]; - - entitymodel *model; - char *modelpath; - //++timo NOTE: I don't know what this is used for exactly. But don't trust it for the real skin paths on models (screws up with long/short path names) - //++hydra NOTE: this, hopefully, will be used to use specific shaders on the bounding boxes of the eclass instead of a color. - char *skinpath; - int nFrame; - unsigned int nShowFlags; - - void* hPlug; -} eclass_t; - -extern eclass_t *eclass; - -/* -** window bits -*/ -#define W_CAMERA 0x0001 -#define W_XY 0x0002 -#define W_XY_OVERLAY 0x0004 -#define W_Z 0x0008 -#define W_TEXTURE 0x0010 -#define W_Z_OVERLAY 0x0020 -#define W_CONSOLE 0x0040 -#define W_ENTITY 0x0080 -#define W_CAMERA_IFON 0x0100 -#define W_XZ 0x0200 //--| only used for patch vertex manip stuff -#define W_YZ 0x0400 //--| -#define W_GROUP 0x0800 -#define W_MEDIA 0x1000 -#define W_ALL 0xFFFFFFFF - -// used in some Drawing routines -enum VIEWTYPE {YZ, XZ, XY}; -const char g_AxisName[3] = { 'X', 'Y', 'Z' }; - -// dynamically allocated string -class string_t -{ -public: - inline string_t() - { - copy(""); - } - inline string_t(const string_t& other) - { - copy(other.m_string); - } - inline string_t(const char* string) - { - copy(string); - } - inline ~string_t() - { - destroy(); - } - inline const string_t& operator=(const string_t& other) - { - destroy(); - copy(other.m_string); - return *this; - } - inline const string_t& operator=(const char* string) - { - destroy(); - copy(string); - return *this; - } - inline bool operator<(const string_t& other) const - { - return compare(other) < 0; - } - inline bool operator>(const string_t& other) const - { - return compare(other) > 0; - } - inline bool operator==(const string_t& other) const - { - return compare(other) == 0; - } - inline bool operator!=(const string_t& other) const - { - return compare(other) != 0; - } - inline const char* c_str() const - { - return m_string; - } -private: - inline void copy(const char* string) - { - m_string = new char[strlen(string)+1]; - strcpy(m_string, string); - } - inline void destroy() - { - delete[] m_string; - } - inline int compare(const string_t& other) const - { - return strcmp(m_string, other.m_string); - } - - char* m_string; -}; - -class filetype_t -{ -public: - filetype_t() - : name(""), pattern("") - {} - filetype_t(const char* _name, const char* _pattern) - : name(_name), pattern(_pattern) - {} - const char* name; - const char* pattern; -}; - - -/* -** Outline bits -*/ -#define OUTLINE_ZBUF 0x01 // zbuffered outline -#define OUTLINE_BSEL 0x02 // selection overlay - -#ifdef USEPLUGINENTITIES -// forward declare this one -class IPluginEntity; -#endif // USEPLUGINENTITIES - -// MODEL - -class IRender; -class ISelect; -class IEdit; - -// NOTE TTimo about ~entity_interfaces_t -// using constructors / destructors on C structs is bad practice -struct entity_interfaces_t -{ - IRender *pRender; - ISelect *pSelect; - IEdit *pEdit; -}; -// MODEL END - -typedef struct entity_s -{ - struct entity_s *prev, *next; - - /*! - \todo can use a brushes list, or the blind data below - for now, blind data should be interpreted as CPtrArray*, only use in the IMAP API - */ - brush_t brushes; // head/tail of list - void *pData; - - int undoId, redoId, entityId; // used for undo/redo - vec3_t origin; - eclass_t *eclass; - epair_t *epairs; - entity_interfaces_t model; -#ifdef USEPLUGINENTITIES - IPluginEntity *pPlugEnt; -#endif // USEPLUGINENTITIES - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=252 - // this is cam code addition? - vec3_t color; - - // Arnout: HACK-ish and change for 1.3 (in 1.3 we have a blind data pointer according to TTimo) - float fLightEnvelope1[3]; - float fLightEnvelope2[2]; -} entity_t; - -typedef struct -{ - int p1, p2; - face_t *f1, *f2; -} pedge_t; - -// window system independent camera view code -// NOTE TTimo taken from xy.h -typedef struct -{ - int width, height; - - qboolean timing; - - vec3_t origin; // at center of window - float scale; - - float topclip, bottomclip; - - qboolean d_dirty; -} xy_t; - -// spog - struct used for nodes in filters list -struct bfilter_t //c++ style -{ - bfilter_t *next; - int attribute; // 1=brush->face->pShader->getName() - // 2=brush->pPatch->pShader->getFlags() - // 3=brush->owner->eclass->name - // 4=brush->owner->eclass->nShowFlags - int mask; - char *string; - bool active; -}; - -// djbob: no longer any need to add only to end, versioning removed, it is no longer saved as binary -// IMPORTANT: whenever you update this struct, you need to add the relevant load/save code -// preferences.cpp LoadPref / SavePref -typedef struct -{ - int iTexMenu; // nearest, linear, etc - float fGamma; // gamma for textures - vec3_t colors[COLOR_LAST]; - int exclude; - int include; - texdef_t m_SIIncrement; // increments for the surface inspector - texdef_t m_PIIncrement; // increments for the patch inspector - vec3_t AxisColors[3]; // colors used for X, Y Z axis - // these are in the View > Show menu with Show coordinates - qboolean show_names; - qboolean show_coordinates; - qboolean show_angles; - qboolean show_outline; - qboolean show_axis; - qboolean bNoSelectedOutlines; - bfilter_t *filters; // FIXME spog - might be better in another location? - int iSelectedOutlinesStyle; -} SavedInfo_t; - -typedef enum -{ - sel_brush, - sel_brush_on, - sel_brush_off, - // sel_sticky_brush, - // sel_face, - sel_vertex, - sel_edge, - sel_singlevertex, - sel_curvepoint, - sel_area, - sel_areatall, - sel_facets_on, - sel_facets_off, -} select_t; - -// most of the QE globals are stored in this structure -typedef struct -{ - qboolean d_showgrid; - float d_gridsize; - qboolean d_bSmallGrid; // we use this flag to hack our way into editing of <1 grids - - int d_num_entities; - - entity_t *d_project_entity; - - // defines the boundaries of the current work area - // is used to guess brushes and drop points third coordinate when creating from 2D view - vec3_t d_work_min,d_work_max; - // not stored in registry, default is off - qboolean d_show_work; - - vec3_t d_points[MAX_POINTS]; - int d_numpoints; - pedge_t d_edges[MAX_EDGES]; - int d_numedges; - - int d_num_move_points; - float *d_move_points[4096]; - - qtexture_t *d_qtextures; - // used to speedup access, specially in QERApp_Try_Texture_ForName - // must always be kept up-to-date with d_qtextures* - //++timo FIXME at some point in the future it would even be better to remove d_qtextures and use this instead - GHashTable *d_qtexmap; - - texturewin_t d_texturewin; - - int d_pointfile_display_list; - - xy_t d_xyOld; - - SavedInfo_t d_savedinfo; - - int d_workcount; - - // connect entities uses the last two brushes selected - int d_select_count; - brush_t *d_select_order[2]; - vec3_t d_select_translate; // for dragging w/o making new display lists - select_t d_select_mode; - - int d_parsed_brushes; - - qboolean show_blocks; - int blockSize; - - // NOTE TTimo - // a lot of this data should be in a property bag and available to the other modules through an API - // this is generated from game configuration and the project settings, and should be still be part of it - - // tells if we are internally using brush primitive (texture coordinates and map format) - // this is a shortcut for IntForKey( g_qeglobals.d_project_entity, "brush_primit" ) - // NOTE: must keep the two ones in sync - bool m_bBrushPrimitMode; - - /*! - win32: engine full path. - unix: user home full path + engine dir. - */ - Str m_strHomeGame; - /*! - cache for m_strHomeGame + mod subdirectory. - */ - Str m_strHomeMaps; - - // used while importing brush data from file or memory buffer - // tells if conversion between map format and internal preferences ( m_bBrushPrimitMode ) is needed - qboolean bNeedConvert; - qboolean bOldBrushes; - qboolean bPrimitBrushes; - - vec3_t d_vAreaTL; - vec3_t d_vAreaBR; - - // tells if we are using .INI files for prefs instead of registry - qboolean use_ini; - // even in .INI mode we use the registry for all void* prefs - char use_ini_registry[64]; - // disabled all INI / registry read write .. used when shutting down after registry cleanup - qboolean disable_ini; - - // tells we are using a BSP frontend plugin - qboolean bBSPFrontendPlugin; - - // handle to the console log file - // we use low level I/O to get rid of buffering and have everything on file if we crash - int hLogFile; - - qboolean bTextureCompressionSupported; // is texture compression supported by hardware? - GLint texture_components; - - // temporary values that should be initialised only once at run-time - // there are too many uneccessary calls to Sys_QGL_ExtensionSupported - // NOTE TTimo: those are unused atm (set right, but not used) - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=623 - bool m_bOpenGLCompressionSupported; - bool m_bS3CompressionSupported; - - // set to true after OpenGL has been initialized and extensions have been tested - bool m_bOpenGLReady; - -} QEGlobals_t; - -#endif // _QERTYPES_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// qertypes.h +// +// common types +// merged from brush.h, etc. for plugin support +// +#ifndef _QERTYPES_H_ +#define _QERTYPES_H_ + +#ifdef _WIN32 +#include +#endif + +#include + +#include "str.h" + +#ifdef _WIN32 +#define PATH_MAX 260 +#endif + +// HACK glib-2.0 +#define NAME_MAX 255 + +typedef bool qboolean; + +#define MAXPOINTS 16 + +// merged from qedefs.h ------ + +#define MAX_EDGES 512 +#define MAX_POINTS 1024 + +#define COLOR_TEXTUREBACK 0 +#define COLOR_GRIDBACK 1 +#define COLOR_GRIDMINOR 2 +#define COLOR_GRIDMAJOR 3 +#define COLOR_CAMERABACK 4 +#define COLOR_ENTITY 5 +#define COLOR_GRIDBLOCK 6 +#define COLOR_GRIDTEXT 7 +#define COLOR_BRUSHES 8 +#define COLOR_SELBRUSHES 9 +#define COLOR_CLIPPER 10 +#define COLOR_VIEWNAME 11 +#define COLOR_SELBRUSHES3D 12 + +#define COLOR_GRIDMINOR_ALT 13 +#define COLOR_GRIDMAJOR_ALT 14 + +#define COLOR_LAST 15 + +// ---------------------------- + +typedef float vec_t; +typedef vec_t vec3_t[3]; + +// turn this on/off to use a static texdef or a memory one +// THIS MUST BE CONSISTENT throughout a whole build of Radiant / modules / plugins +// DO_TEXDEF_ALLOC is more memory efficient, but I suspect it to be wacky on win32 / C runtime etc. +#define DO_TEXDEF_ALLOC 1 +#if DO_TEXDEF_ALLOC + +class texdef_t +{ +private: + char *name; +public: + texdef_t() + { + name = new char[1]; + name[0] = '\0'; + shift[0] = 0.0f; + shift[1] = 0.0f; + rotate = 0.0f; + scale[0] = 1.0f; + scale[1] = 1.0f; + contents = 0; + flags = 0; + value = 0; + } + texdef_t(const texdef_t& other) + { + name = NULL; + SetName(other.name); + shift[0] = other.shift[0]; + shift[1] = other.shift[1]; + rotate = other.rotate; + scale[0] = other.scale[0]; + scale[1] = other.scale[1]; + contents = other.contents; + flags = other.flags; + value = other.value; + } + ~texdef_t() + { + if (name) + { + delete []name; + name = (char*)NULL; + } + } + + void SetName(const char *p) + { + if (name) + { + delete []name; + name = NULL; + } + if (p) + { + name = strcpy(new char[strlen(p)+1], p); + } + else + { + name = new char[1]; + name[0] = '\0'; + } + } + + const char * GetName() const + { + return name; + } + + // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. + void DropName() + { + name = NULL; + SetName(NULL); + } + + texdef_t& operator =(const texdef_t& rhs) + { + if (&rhs != this) + { + SetName(rhs.name); + shift[0] = rhs.shift[0]; + shift[1] = rhs.shift[1]; + rotate = rhs.rotate; + scale[0] = rhs.scale[0]; + scale[1] = rhs.scale[1]; + contents = rhs.contents; + flags = rhs.flags; + value = rhs.value; + } + return *this; + } + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; +}; + +#else + +// max length of a vfs texture path +#define QPATH 64 +class texdef_t +{ +private: + char name[QPATH]; +public: + texdef_t() { name[0] = '\0'; } + ~texdef_t() { } + + void SetName(const char *p) + { + strncpy(name, p, QPATH); + } + + const char * GetName() const + { + return name; + } + + // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. + void DropName() + { + name[0] = '\0'; + } + + texdef_t& operator =(const texdef_t& rhs) + { + if (&rhs != this) + { + SetName(rhs.name); + shift[0] = rhs.shift[0]; + shift[1] = rhs.shift[1]; + rotate = rhs.rotate; + scale[0] = rhs.scale[0]; + scale[1] = rhs.scale[1]; + contents = rhs.contents; + flags = rhs.flags; + value = rhs.value; + } + return *this; + } + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; +}; + +#endif + +// forward declare +class IShader; + +// Timo +// new brush primitive texdef +typedef struct brushprimit_texdef_s +{ + vec_t coords[2][3]; +} brushprimit_texdef_t; + +// this structure is used in Radiant to reflect the state of the texture window +// it gives information on current shader and various flags +class texturewin_t +{ +public: + texturewin_t() + { + } + ~texturewin_t() + { + } + int width, height; + int originy; + // add brushprimit_texdef_t for brush primitive coordinates storage + brushprimit_texdef_t brushprimit_texdef; + int m_nTotalHeight; + // surface plugin, must be casted to a IPluginTexdef* + void* pTexdef; + texdef_t texdef; + // shader + // NOTE: never NULL, initialized in Texture_Init + // NOTE: the reference name of the shader is texdef.name (see QERApp_ReloadShaders for an example) + IShader *pShader; +}; + +#define QER_TRANS 0x00000001 +#define QER_NOCARVE 0x00000002 +#define QER_NODRAW 0x00000004 +#define QER_NONSOLID 0x00000008 +#define QER_WATER 0x00000010 +#define QER_LAVA 0x00000020 +#define QER_FOG 0x00000040 +#define QER_ALPHAFUNC 0x00000080 +#define QER_CULL 0x00000100 + + +// describes a GL texture that Radiant uses to represent a shader +// NOTE: all qtexture_t are stored in a main list at g_qeglobals.d_qtextures +// shaders have reference couting, but qtexture_t don't (they're way too deep into Radiant) +typedef struct qtexture_s +{ + struct qtexture_s *next; + // name of the texture file (the physical image file we are using) + // NOTE: used for lookup, must be unique .. vfs path of the texture, lowercase, NO FILE EXTENSION + // ex textures/gothic_wall/iron + // NOTE: the "textures/" prefix might seem unnecessary .. but it's better to stick to the vfs name + char name[64]; + int width, height; + GLuint texture_number; // gl bind number (the qtexture_t are usually loaded and binded by the shaders module) + vec3_t color; // for flat shade mode + qboolean inuse; // true = is present on the level (for the texture browser interface) +} qtexture_t; + +// NOTE: don't trust this definition! +// you should read float points[..][5] +// see NewWinding definition +// WARNING: don't touch anything to this struct unless you looked into winding.cpp and WINDING_SIZE(pt) +#define MAX_POINTS_ON_WINDING 64 +typedef struct +{ + int numpoints; + int maxpoints; + float points[8][5]; // variable sized +} winding_t; + +typedef struct +{ + vec3_t normal; + double dist; + int type; +} plane_t; + +// pShader is a shortcut to the shader +// it's only up-to-date after a Brush_Build call +// to initialize the pShader, use QERApp_Shader_ForName(texdef.name) +typedef struct face_s +{ + struct face_s *next; + struct face_s *prev; + struct face_s *original; //used for vertex movement + vec3_t planepts[3]; + texdef_t texdef; + plane_t plane; + + // Nurail: Face Undo + int undoId; + int redoId; + + winding_t *face_winding; + + vec3_t d_color; + vec_t d_shade; + // calls through here have indirections (pure virtual) + // it would be good if the rendering loop would avoid scanning there (for the GL binding number for example) + IShader *pShader; + //++timo FIXME: remove! + qtexture_t *d_texture; + + // Timo new brush primit texdef + brushprimit_texdef_t brushprimit_texdef; + + // cast this one to an IPluginTexdef if you are using it + // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h + // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? + void *pData; +} face_t; + +typedef struct { + vec3_t xyz; + float sideST[2]; + float capST[2]; +} curveVertex_t; + +typedef struct { + curveVertex_t v[2]; +} sideVertex_t; + + +#define MIN_PATCH_WIDTH 3 +#define MIN_PATCH_HEIGHT 3 + +#define MAX_PATCH_WIDTH 16 +#define MAX_PATCH_HEIGHT 16 + +// patch type info +// type in lower 16 bits, flags in upper +// endcaps directly follow this patch in the list + +// types +#define PATCH_GENERIC 0x00000000 // generic flat patch +#define PATCH_CYLINDER 0x00000001 // cylinder +#define PATCH_BEVEL 0x00000002 // bevel +#define PATCH_ENDCAP 0x00000004 // endcap +#define PATCH_HEMISPHERE 0x00000008 // hemisphere +#define PATCH_CONE 0x00000010 // cone +#define PATCH_TRIANGLE 0x00000020 // simple tri, assumes 3x3 patch + +// behaviour styles +#define PATCH_CAP 0x00001000 // flat patch applied as a cap +#define PATCH_SEAM 0x00002000 // flat patch applied as a seam +#define PATCH_THICK 0x00004000 // patch applied as a thick portion + +// styles +#define PATCH_BEZIER 0x00000000 // default bezier +#define PATCH_BSPLINE 0x10000000 // bspline + +#define PATCH_TYPEMASK 0x00000fff // +#define PATCH_BTYPEMASK 0x0000f000 // +#define PATCH_STYLEMASK 0xffff0000 // + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; +} drawVert_t; + +// spog - used for patch LOD trees + +struct BTNode_t +{ + BTNode_t *left, *right; + drawVert_t info; + drawVert_t vMid; +}; + +struct BTreeList_t +{ + BTreeList_t *next; + BTNode_t *pBT; + drawVert_t vLeft, vRight; +}; + +struct BTListList_t +{ + BTListList_t *next; + BTreeList_t *list; +}; + +// used in brush primitive AND entities +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +struct brush_s; +typedef struct brush_s brush_t; + +typedef struct { + int width, height; // in control points, not patches + int contents, flags, value, type; + qtexture_t *d_texture; + IShader *pShader; + drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + brush_t *pSymbiot; + qboolean bSelected; + qboolean bOverlay; + qboolean bDirty; + int nListID; + epair_t *epairs; + // cast this one to an IPluginTexdef if you are using it + // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h + // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? + void *pData; + // spog - curve LOD binary trees and lists + BTNode_t *rowLOD[((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT]; // = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT + BTNode_t *colLOD[((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH]; // = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH + bool rowDirty[((MAX_PATCH_WIDTH-1)-1)/2]; + bool colDirty[((MAX_PATCH_HEIGHT-1)-1)/2]; + bool LODUpdated; + void *drawLists; // pointer to std::list +} patchMesh_t; + +typedef struct brush_s +{ + struct brush_s *prev, *next; // links in active/selected + struct brush_s *oprev, *onext; // links in entity + struct entity_s *owner; + vec3_t mins, maxs; + face_t *brush_faces; + + qboolean bModelFailed; + // + // curve brush extensions + // all are derived from brush_faces + qboolean patchBrush; + qboolean hiddenBrush; + + //int nPatchID; + + patchMesh_t *pPatch; + struct entity_s *pUndoOwner; + + int undoId; //undo ID + int redoId; //redo ID + int ownerId; //entityId of the owner entity for undo + + // TTimo: this is not legal, we are not supposed to put UI toolkit dependant stuff in the interfaces + // NOTE: the grouping stuff never worked, there is embryonary code everywhere though + int numberId; + void* itemOwner; // GtkCTreeNode* ? + + // brush primitive only + epair_t *epairs; + + // brush filtered toggle + bool bFiltered; + bool bCamCulled; + bool bBrushDef; +} brush_t; + +#define MAX_FLAGS 16 + +typedef struct vertmodel_t +{ + float v[3]; + float st[2]; + float normal[3]; +} vertmodel; + +typedef struct triindex_t +{ + int indexes[3]; +} triindex; + +// TTimo: NOTE: we don't have dedicated stuff to copy/allocate/delete this structure like we do for entity_t and brush_t +// could be necessary, I'm adding GString *strSkin that needs to be copied around +// TTimo 04/01/2001 removing the GString* for toolkit-independent interfaces .. cast it .. +typedef struct entitymodel_t +{ + struct entitymodel_t *pNext; + int nTriCount; + //trimodel *pTriList; + //md3Triangle_t *pTriList; + triindex *pTriList; + vertmodel *pVertList; + int numVerts; + int nTextureBind; + void *strSkin; // toolkit-independent .. cast to a GString* + int nSkinWidth; + int nSkinHeight; + int nModelPosition; +} entitymodel; + +// eclass show flags + +#define ECLASS_LIGHT 0x00000001 +#define ECLASS_ANGLE 0x00000002 +#define ECLASS_PATH 0x00000004 +#define ECLASS_MISCMODEL 0x00000008 + +#ifdef USEPLUGINENTITIES +#define ECLASS_PLUGINENTITY 0x00000010 +#endif // USEPLUGINENTITIES + +typedef struct eclass_s +{ + struct eclass_s *next; + char *name; + qboolean fixedsize; + qboolean unknown; // wasn't found in source + vec3_t mins, maxs; + vec3_t color; + texdef_t texdef; + char *comments; + char flagnames[MAX_FLAGS][32]; + + entitymodel *model; + char *modelpath; + //++timo NOTE: I don't know what this is used for exactly. But don't trust it for the real skin paths on models (screws up with long/short path names) + //++hydra NOTE: this, hopefully, will be used to use specific shaders on the bounding boxes of the eclass instead of a color. + char *skinpath; + int nFrame; + unsigned int nShowFlags; + + void* hPlug; +} eclass_t; + +extern eclass_t *eclass; + +/* +** window bits +*/ +#define W_CAMERA 0x0001 +#define W_XY 0x0002 +#define W_XY_OVERLAY 0x0004 +#define W_Z 0x0008 +#define W_TEXTURE 0x0010 +#define W_Z_OVERLAY 0x0020 +#define W_CONSOLE 0x0040 +#define W_ENTITY 0x0080 +#define W_CAMERA_IFON 0x0100 +#define W_XZ 0x0200 //--| only used for patch vertex manip stuff +#define W_YZ 0x0400 //--| +#define W_GROUP 0x0800 +#define W_MEDIA 0x1000 +#define W_ALL 0xFFFFFFFF + +// used in some Drawing routines +enum VIEWTYPE {YZ, XZ, XY}; +const char g_AxisName[3] = { 'X', 'Y', 'Z' }; + +// dynamically allocated string +class string_t +{ +public: + inline string_t() + { + copy(""); + } + inline string_t(const string_t& other) + { + copy(other.m_string); + } + inline string_t(const char* string) + { + copy(string); + } + inline ~string_t() + { + destroy(); + } + inline const string_t& operator=(const string_t& other) + { + destroy(); + copy(other.m_string); + return *this; + } + inline const string_t& operator=(const char* string) + { + destroy(); + copy(string); + return *this; + } + inline bool operator<(const string_t& other) const + { + return compare(other) < 0; + } + inline bool operator>(const string_t& other) const + { + return compare(other) > 0; + } + inline bool operator==(const string_t& other) const + { + return compare(other) == 0; + } + inline bool operator!=(const string_t& other) const + { + return compare(other) != 0; + } + inline const char* c_str() const + { + return m_string; + } +private: + inline void copy(const char* string) + { + m_string = new char[strlen(string)+1]; + strcpy(m_string, string); + } + inline void destroy() + { + delete[] m_string; + } + inline int compare(const string_t& other) const + { + return strcmp(m_string, other.m_string); + } + + char* m_string; +}; + +class filetype_t +{ +public: + filetype_t() + : name(""), pattern("") + {} + filetype_t(const char* _name, const char* _pattern) + : name(_name), pattern(_pattern) + {} + const char* name; + const char* pattern; +}; + + +/* +** Outline bits +*/ +#define OUTLINE_ZBUF 0x01 // zbuffered outline +#define OUTLINE_BSEL 0x02 // selection overlay + +#ifdef USEPLUGINENTITIES +// forward declare this one +class IPluginEntity; +#endif // USEPLUGINENTITIES + +// MODEL + +class IRender; +class ISelect; +class IEdit; + +// NOTE TTimo about ~entity_interfaces_t +// using constructors / destructors on C structs is bad practice +struct entity_interfaces_t +{ + IRender *pRender; + ISelect *pSelect; + IEdit *pEdit; +}; +// MODEL END + +typedef struct entity_s +{ + struct entity_s *prev, *next; + + /*! + \todo can use a brushes list, or the blind data below + for now, blind data should be interpreted as CPtrArray*, only use in the IMAP API + */ + brush_t brushes; // head/tail of list + void *pData; + + int undoId, redoId, entityId; // used for undo/redo + vec3_t origin; + eclass_t *eclass; + epair_t *epairs; + entity_interfaces_t model; +#ifdef USEPLUGINENTITIES + IPluginEntity *pPlugEnt; +#endif // USEPLUGINENTITIES + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=252 + // this is cam code addition? + vec3_t color; + + // Arnout: HACK-ish and change for 1.3 (in 1.3 we have a blind data pointer according to TTimo) + float fLightEnvelope1[3]; + float fLightEnvelope2[2]; +} entity_t; + +typedef struct +{ + int p1, p2; + face_t *f1, *f2; +} pedge_t; + +// window system independent camera view code +// NOTE TTimo taken from xy.h +typedef struct +{ + int width, height; + + qboolean timing; + + vec3_t origin; // at center of window + float scale; + + float topclip, bottomclip; + + qboolean d_dirty; +} xy_t; + +// spog - struct used for nodes in filters list +struct bfilter_t //c++ style +{ + bfilter_t *next; + int attribute; // 1=brush->face->pShader->getName() + // 2=brush->pPatch->pShader->getFlags() + // 3=brush->owner->eclass->name + // 4=brush->owner->eclass->nShowFlags + int mask; + char *string; + bool active; +}; + +// djbob: no longer any need to add only to end, versioning removed, it is no longer saved as binary +// IMPORTANT: whenever you update this struct, you need to add the relevant load/save code +// preferences.cpp LoadPref / SavePref +typedef struct +{ + int iTexMenu; // nearest, linear, etc + float fGamma; // gamma for textures + vec3_t colors[COLOR_LAST]; + int exclude; + int include; + texdef_t m_SIIncrement; // increments for the surface inspector + texdef_t m_PIIncrement; // increments for the patch inspector + vec3_t AxisColors[3]; // colors used for X, Y Z axis + // these are in the View > Show menu with Show coordinates + qboolean show_names; + qboolean show_coordinates; + qboolean show_angles; + qboolean show_outline; + qboolean show_axis; + qboolean bNoSelectedOutlines; + bfilter_t *filters; // FIXME spog - might be better in another location? + int iSelectedOutlinesStyle; +} SavedInfo_t; + +typedef enum +{ + sel_brush, + sel_brush_on, + sel_brush_off, + // sel_sticky_brush, + // sel_face, + sel_vertex, + sel_edge, + sel_singlevertex, + sel_curvepoint, + sel_area, + sel_areatall, + sel_facets_on, + sel_facets_off, +} select_t; + +// most of the QE globals are stored in this structure +typedef struct +{ + qboolean d_showgrid; + float d_gridsize; + qboolean d_bSmallGrid; // we use this flag to hack our way into editing of <1 grids + + int d_num_entities; + + entity_t *d_project_entity; + + // defines the boundaries of the current work area + // is used to guess brushes and drop points third coordinate when creating from 2D view + vec3_t d_work_min,d_work_max; + // not stored in registry, default is off + qboolean d_show_work; + + vec3_t d_points[MAX_POINTS]; + int d_numpoints; + pedge_t d_edges[MAX_EDGES]; + int d_numedges; + + int d_num_move_points; + float *d_move_points[4096]; + + qtexture_t *d_qtextures; + // used to speedup access, specially in QERApp_Try_Texture_ForName + // must always be kept up-to-date with d_qtextures* + //++timo FIXME at some point in the future it would even be better to remove d_qtextures and use this instead + GHashTable *d_qtexmap; + + texturewin_t d_texturewin; + + int d_pointfile_display_list; + + xy_t d_xyOld; + + SavedInfo_t d_savedinfo; + + int d_workcount; + + // connect entities uses the last two brushes selected + int d_select_count; + brush_t *d_select_order[2]; + vec3_t d_select_translate; // for dragging w/o making new display lists + select_t d_select_mode; + + int d_parsed_brushes; + + qboolean show_blocks; + int blockSize; + + // NOTE TTimo + // a lot of this data should be in a property bag and available to the other modules through an API + // this is generated from game configuration and the project settings, and should be still be part of it + + // tells if we are internally using brush primitive (texture coordinates and map format) + // this is a shortcut for IntForKey( g_qeglobals.d_project_entity, "brush_primit" ) + // NOTE: must keep the two ones in sync + bool m_bBrushPrimitMode; + + /*! + win32: engine full path. + unix: user home full path + engine dir. + */ + Str m_strHomeGame; + /*! + cache for m_strHomeGame + mod subdirectory. + */ + Str m_strHomeMaps; + + // used while importing brush data from file or memory buffer + // tells if conversion between map format and internal preferences ( m_bBrushPrimitMode ) is needed + qboolean bNeedConvert; + qboolean bOldBrushes; + qboolean bPrimitBrushes; + + vec3_t d_vAreaTL; + vec3_t d_vAreaBR; + + // tells if we are using .INI files for prefs instead of registry + qboolean use_ini; + // even in .INI mode we use the registry for all void* prefs + char use_ini_registry[64]; + // disabled all INI / registry read write .. used when shutting down after registry cleanup + qboolean disable_ini; + + // tells we are using a BSP frontend plugin + qboolean bBSPFrontendPlugin; + + // handle to the console log file + // we use low level I/O to get rid of buffering and have everything on file if we crash + int hLogFile; + + qboolean bTextureCompressionSupported; // is texture compression supported by hardware? + GLint texture_components; + + // temporary values that should be initialised only once at run-time + // there are too many uneccessary calls to Sys_QGL_ExtensionSupported + // NOTE TTimo: those are unused atm (set right, but not used) + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=623 + bool m_bOpenGLCompressionSupported; + bool m_bS3CompressionSupported; + + // set to true after OpenGL has been initialized and extensions have been tested + bool m_bOpenGLReady; + +} QEGlobals_t; + +#endif // _QERTYPES_H_ diff --git a/include/qsysprintf.h b/include/qsysprintf.h index 83622784..a8d2874a 100644 --- a/include/qsysprintf.h +++ b/include/qsysprintf.h @@ -1,67 +1,67 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef __QSYSPRINTF_H__ -#define __QSYSPRINTF_H__ - -/*! -this header is provided in libs/ in an attempt to provide a common API -for all the diagnostic printing / fatal error situations - -this is oriented at synapse server targets ONLY -synapse clients should not include this, as they are supposed to go -through the function tables to report print diagnostics -(or use Syn_Printf for situations where the func table may not be available) - -each server target implements that in it's own way. Radiant logs to -a file and sends to the console, q3map prints to stdout and to the -XML network stream, etc. -*/ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -// NOTE: might want to switch to bits if needed -#define SYS_VRB 0 ///< verbose support (on/off) -#define SYS_STD 1 ///< standard print level - this is the default -#define SYS_WRN 2 ///< warnings -#define SYS_ERR 3 ///< error -#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) - -/*! -those are the real implementation -*/ -void Sys_Printf_VA (const char *text, va_list args); ///< matches PFN_SYN_PRINTF_VA prototype -void Sys_FPrintf_VA (int level, const char *text, va_list args); - -/*! -this is easy to call, wrappers around va_list version -*/ -void Sys_Printf (const char *text, ...); -void Sys_FPrintf (int flag, const char *text, ...); - -#if defined(__cplusplus) -}; -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __QSYSPRINTF_H__ +#define __QSYSPRINTF_H__ + +/*! +this header is provided in libs/ in an attempt to provide a common API +for all the diagnostic printing / fatal error situations + +this is oriented at synapse server targets ONLY +synapse clients should not include this, as they are supposed to go +through the function tables to report print diagnostics +(or use Syn_Printf for situations where the func table may not be available) + +each server target implements that in it's own way. Radiant logs to +a file and sends to the console, q3map prints to stdout and to the +XML network stream, etc. +*/ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +// NOTE: might want to switch to bits if needed +#define SYS_VRB 0 ///< verbose support (on/off) +#define SYS_STD 1 ///< standard print level - this is the default +#define SYS_WRN 2 ///< warnings +#define SYS_ERR 3 ///< error +#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) + +/*! +those are the real implementation +*/ +void Sys_Printf_VA (const char *text, va_list args); ///< matches PFN_SYN_PRINTF_VA prototype +void Sys_FPrintf_VA (int level, const char *text, va_list args); + +/*! +this is easy to call, wrappers around va_list version +*/ +void Sys_Printf (const char *text, ...); +void Sys_FPrintf (int flag, const char *text, ...); + +#if defined(__cplusplus) +}; +#endif + +#endif diff --git a/include/stl_check.h b/include/stl_check.h index b30481df..b6def1db 100644 --- a/include/stl_check.h +++ b/include/stl_check.h @@ -1,60 +1,60 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/*! -This header is used to make sure the STL we are using is what we expect -this allows to catch some weird errors early at compile time -*/ - -#ifdef Q_NO_STLPORT - -// not using STLPort (gcc 3.x build) -using namespace std; - -#else - -#ifndef _STLPORT_VERSION -#error "Can't find _STLPORT_VERSION, check you are compiling against STLPort" -#endif - -#if !defined(_STLP_DONT_USE_EXCEPTIONS) -#error exc -#endif - -#if !defined(_STLP_NO_NAMESPACES) -#error namespace -#endif - -#if !defined(_STLP_NO_IOSTREAMS) -#error io -#endif - -// now check a few more things (paranoid) -// if you use our custom STLPort distribution it should be alright though -#if !defined(_STLP_DONT_USE_EXCEPTIONS) || !defined(_STLP_NO_NAMESPACES) || !defined(_STLP_NO_IOSTREAMS) -#error "There is something broken in your STLPort config" -#endif - -#ifdef _WIN32 -#pragma warning(disable : 4786) -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/*! +This header is used to make sure the STL we are using is what we expect +this allows to catch some weird errors early at compile time +*/ + +#ifdef Q_NO_STLPORT + +// not using STLPort (gcc 3.x build) +using namespace std; + +#else + +#ifndef _STLPORT_VERSION +#error "Can't find _STLPORT_VERSION, check you are compiling against STLPort" +#endif + +#if !defined(_STLP_DONT_USE_EXCEPTIONS) +#error exc +#endif + +#if !defined(_STLP_NO_NAMESPACES) +#error namespace +#endif + +#if !defined(_STLP_NO_IOSTREAMS) +#error io +#endif + +// now check a few more things (paranoid) +// if you use our custom STLPort distribution it should be alright though +#if !defined(_STLP_DONT_USE_EXCEPTIONS) || !defined(_STLP_NO_NAMESPACES) || !defined(_STLP_NO_IOSTREAMS) +#error "There is something broken in your STLPort config" +#endif + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#endif diff --git a/include/stream_version.h b/include/stream_version.h index d9271854..17ce6339 100644 --- a/include/stream_version.h +++ b/include/stream_version.h @@ -1,3 +1,3 @@ -// version defines for q3map stream -#define Q3MAP_STREAM_VERSION "1" - +// version defines for q3map stream +#define Q3MAP_STREAM_VERSION "1" + diff --git a/include/version.h b/include/version.h index f3905933..2ef2606b 100644 --- a/include/version.h +++ b/include/version.h @@ -1,4 +1,4 @@ -// generated header, see makeversion.py -#define RADIANT_VERSION "1.4.0" -#define RADIANT_MINOR_VERSION "0" -#define RADIANT_MAJOR_VERSION "4" +// generated header, see makeversion.py +#define RADIANT_VERSION "1.4.0" +#define RADIANT_MINOR_VERSION "0" +#define RADIANT_MAJOR_VERSION "4" diff --git a/install/games/default_project.proj b/install/games/default_project.proj new file mode 100644 index 00000000..9738c418 --- /dev/null +++ b/install/games/default_project.proj @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/install/games/q3.game b/install/games/q3.game new file mode 100644 index 00000000..fc3e82fa --- /dev/null +++ b/install/games/q3.game @@ -0,0 +1,7 @@ + + diff --git a/install/games/qz.game b/install/games/qz.game deleted file mode 100644 index 5e116a9c..00000000 --- a/install/games/qz.game +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/libs/bytebool.h b/libs/bytebool.h index 9253bd35..e0617893 100644 --- a/libs/bytebool.h +++ b/libs/bytebool.h @@ -1,20 +1,20 @@ -#ifndef __BYTEBOOL__ -#define __BYTEBOOL__ - -// bool is a C++ type -// if we are compiling for C, use an enum - -// this header is not really meant for direct inclusion, -// it is used by mathlib and cmdlib - -#ifdef __cplusplus -typedef bool qboolean; -#define qtrue true -#define qfalse false -#else -typedef enum { qfalse, qtrue } qboolean; -#endif - -typedef unsigned char byte; - -#endif +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ + +// bool is a C++ type +// if we are compiling for C, use an enum + +// this header is not really meant for direct inclusion, +// it is used by mathlib and cmdlib + +#ifdef __cplusplus +typedef bool qboolean; +#define qtrue true +#define qfalse false +#else +typedef enum { qfalse, qtrue } qboolean; +#endif + +typedef unsigned char byte; + +#endif diff --git a/libs/cmdlib.h b/libs/cmdlib.h index 84833fcd..92d985ae 100644 --- a/libs/cmdlib.h +++ b/libs/cmdlib.h @@ -1,111 +1,111 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// start of shared cmdlib stuff -// - -#ifndef __CMDLIB__ -#define __CMDLIB__ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef _WIN32 - #define PATH_MAX 260 -#endif - -// some easy portability crap -#ifdef _WIN32 - #include - #define Q_mkdir(a,b) _mkdir(a) -#else - #include - #define Q_mkdir(a,b) mkdir(a,b) -#endif - -#ifdef __cplusplus - typedef bool qboolean; -#endif - -// NOTE TTimo: is this worth anything? -#ifndef __BYTEBOOL__ -#define __BYTEBOOL__ - -#ifndef __cplusplus - typedef enum {false, true} boolean; -#else - typedef unsigned char boolean; -#endif - -typedef unsigned char byte; - -#endif // __BYTEBOOL__ - -void DefaultExtension( char *path, char *extension ); -void DefaultPath( char *path, char *basepath ); -void StripFilename( char *path ); -void StripExtension( char *path ); -void ExtractFilePath( const char *path, char *dest ); -void ExtractFileName( const char *path, char *dest ); -void ExtractFileBase( const char *path, char *dest ); -void ExtractFileExtension( const char *path, char *dest ); -/*! -\brief create all directories leading to a file path. if you pass a directory, terminate it with a '/' -*/ -void CreateDirectoryPath (const char *path); - -short BigShort (short l); -short LittleShort (short l); -int BigLong (int l); -int LittleLong (int l); -float BigFloat (float l); -float LittleFloat (float l); -void *qmalloc (size_t size); -void* qblockmalloc(size_t nSize); - -void ConvertDOSToUnixName( char *dst, const char *src ); -#ifdef __cplusplus - char* StrDup(char* pStr); -#endif -char* StrDup(const char* pStr); - -// TTimo started adding portability code: -// return true if spawning was successful, false otherwise -// on win32 we have a bCreateConsole flag to create a new console or run inside the current one -//boolean Q_Exec(const char* pCmd, boolean bCreateConsole); -// execute a system command: -// cmd: the command to run -// cmdline: the command line -// NOTE TTimo following are win32 specific: -// execdir: the directory to execute in -// bCreateConsole: spawn a new console or not -// return values; -// if the spawn was fine -// TODO TTimo add functionality to track the process until it dies -bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole); - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// start of shared cmdlib stuff +// + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 + #define PATH_MAX 260 +#endif + +// some easy portability crap +#ifdef _WIN32 + #include + #define Q_mkdir(a,b) _mkdir(a) +#else + #include + #define Q_mkdir(a,b) mkdir(a,b) +#endif + +#ifdef __cplusplus + typedef bool qboolean; +#endif + +// NOTE TTimo: is this worth anything? +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ + +#ifndef __cplusplus + typedef enum {false, true} boolean; +#else + typedef unsigned char boolean; +#endif + +typedef unsigned char byte; + +#endif // __BYTEBOOL__ + +void DefaultExtension( char *path, char *extension ); +void DefaultPath( char *path, char *basepath ); +void StripFilename( char *path ); +void StripExtension( char *path ); +void ExtractFilePath( const char *path, char *dest ); +void ExtractFileName( const char *path, char *dest ); +void ExtractFileBase( const char *path, char *dest ); +void ExtractFileExtension( const char *path, char *dest ); +/*! +\brief create all directories leading to a file path. if you pass a directory, terminate it with a '/' +*/ +void CreateDirectoryPath (const char *path); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); +void *qmalloc (size_t size); +void* qblockmalloc(size_t nSize); + +void ConvertDOSToUnixName( char *dst, const char *src ); +#ifdef __cplusplus + char* StrDup(char* pStr); +#endif +char* StrDup(const char* pStr); + +// TTimo started adding portability code: +// return true if spawning was successful, false otherwise +// on win32 we have a bCreateConsole flag to create a new console or run inside the current one +//boolean Q_Exec(const char* pCmd, boolean bCreateConsole); +// execute a system command: +// cmd: the command to run +// cmdline: the command line +// NOTE TTimo following are win32 specific: +// execdir: the directory to execute in +// bCreateConsole: spawn a new console or not +// return values; +// if the spawn was fine +// TODO TTimo add functionality to track the process until it dies +bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole); + +#endif diff --git a/libs/ddslib.h b/libs/ddslib.h index 246e31be..3f5f124c 100644 --- a/libs/ddslib.h +++ b/libs/ddslib.h @@ -1,250 +1,250 @@ -/* ----------------------------------------------------------------------------- - -DDS Library - -Based on code from Nvidia's DDS example: -http://www.nvidia.com/object/dxtc_decompression_code.html - -Copyright (c) 2003 Randy Reddig -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#ifndef DDSLIB_H -#define DDSLIB_H - - - -/* dependencies */ -#include -#include - - - -/* c++ marker */ -#ifdef __cplusplus -extern "C" -{ -#endif - - - -/* dds definition */ -typedef enum -{ - DDS_PF_ARGB8888, - DDS_PF_DXT1, - DDS_PF_DXT2, - DDS_PF_DXT3, - DDS_PF_DXT4, - DDS_PF_DXT5, - DDS_PF_UNKNOWN -} -ddsPF_t; - - -/* 16bpp stuff */ -#define DDS_LOW_5 0x001F; -#define DDS_MID_6 0x07E0; -#define DDS_HIGH_5 0xF800; -#define DDS_MID_555 0x03E0; -#define DDS_HI_555 0x7C00; - - -/* structures */ -typedef struct ddsColorKey_s -{ - unsigned int colorSpaceLowValue; - unsigned int colorSpaceHighValue; -} -ddsColorKey_t; - - -typedef struct ddsCaps_s -{ - unsigned int caps1; - unsigned int caps2; - unsigned int caps3; - unsigned int caps4; -} -ddsCaps_t; - - -typedef struct ddsMultiSampleCaps_s -{ - unsigned short flipMSTypes; - unsigned short bltMSTypes; -} -ddsMultiSampleCaps_t; - - -typedef struct ddsPixelFormat_s -{ - unsigned int size; - unsigned int flags; - unsigned int fourCC; - union - { - unsigned int rgbBitCount; - unsigned int yuvBitCount; - unsigned int zBufferBitDepth; - unsigned int alphaBitDepth; - unsigned int luminanceBitCount; - unsigned int bumpBitCount; - unsigned int privateFormatBitCount; - }; - union - { - unsigned int rBitMask; - unsigned int yBitMask; - unsigned int stencilBitDepth; - unsigned int luminanceBitMask; - unsigned int bumpDuBitMask; - unsigned int operations; - }; - union - { - unsigned int gBitMask; - unsigned int uBitMask; - unsigned int zBitMask; - unsigned int bumpDvBitMask; - ddsMultiSampleCaps_t multiSampleCaps; - }; - union - { - unsigned int bBitMask; - unsigned int vBitMask; - unsigned int stencilBitMask; - unsigned int bumpLuminanceBitMask; - }; - union - { - unsigned int rgbAlphaBitMask; - unsigned int yuvAlphaBitMask; - unsigned int luminanceAlphaBitMask; - unsigned int rgbZBitMask; - unsigned int yuvZBitMask; - }; -} -ddsPixelFormat_t; - - -typedef struct ddsBuffer_s -{ - /* magic: 'dds ' */ - char magic[ 4 ]; - - /* directdraw surface */ - unsigned int size; - unsigned int flags; - unsigned int height; - unsigned int width; - union - { - int pitch; - unsigned int linearSize; - }; - unsigned int backBufferCount; - union - { - unsigned int mipMapCount; - unsigned int refreshRate; - unsigned int srcVBHandle; - }; - unsigned int alphaBitDepth; - unsigned int reserved; - void *surface; - union - { - ddsColorKey_t ckDestOverlay; - unsigned int emptyFaceColor; - }; - ddsColorKey_t ckDestBlt; - ddsColorKey_t ckSrcOverlay; - ddsColorKey_t ckSrcBlt; - union - { - ddsPixelFormat_t pixelFormat; - unsigned int fvf; - }; - ddsCaps_t ddsCaps; - unsigned int textureStage; - - /* data (Varying size) */ - unsigned char data[ 4 ]; -} -ddsBuffer_t; - - -typedef struct ddsColorBlock_s -{ - unsigned short colors[ 2 ]; - unsigned char row[ 4 ]; -} -ddsColorBlock_t; - - -typedef struct ddsAlphaBlockExplicit_s -{ - unsigned short row[ 4 ]; -} -ddsAlphaBlockExplicit_t; - - -typedef struct ddsAlphaBlock3BitLinear_s -{ - unsigned char alpha0; - unsigned char alpha1; - unsigned char stuff[ 6 ]; -} -ddsAlphaBlock3BitLinear_t; - - -typedef struct ddsColor_s -{ - unsigned char r, g, b, a; -} -ddsColor_t; - - - -/* public functions */ -int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ); -int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ); - - - -/* end marker */ -#ifdef __cplusplus -} -#endif - -#endif +/* ----------------------------------------------------------------------------- + +DDS Library + +Based on code from Nvidia's DDS example: +http://www.nvidia.com/object/dxtc_decompression_code.html + +Copyright (c) 2003 Randy Reddig +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef DDSLIB_H +#define DDSLIB_H + + + +/* dependencies */ +#include +#include + + + +/* c++ marker */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* dds definition */ +typedef enum +{ + DDS_PF_ARGB8888, + DDS_PF_DXT1, + DDS_PF_DXT2, + DDS_PF_DXT3, + DDS_PF_DXT4, + DDS_PF_DXT5, + DDS_PF_UNKNOWN +} +ddsPF_t; + + +/* 16bpp stuff */ +#define DDS_LOW_5 0x001F; +#define DDS_MID_6 0x07E0; +#define DDS_HIGH_5 0xF800; +#define DDS_MID_555 0x03E0; +#define DDS_HI_555 0x7C00; + + +/* structures */ +typedef struct ddsColorKey_s +{ + unsigned int colorSpaceLowValue; + unsigned int colorSpaceHighValue; +} +ddsColorKey_t; + + +typedef struct ddsCaps_s +{ + unsigned int caps1; + unsigned int caps2; + unsigned int caps3; + unsigned int caps4; +} +ddsCaps_t; + + +typedef struct ddsMultiSampleCaps_s +{ + unsigned short flipMSTypes; + unsigned short bltMSTypes; +} +ddsMultiSampleCaps_t; + + +typedef struct ddsPixelFormat_s +{ + unsigned int size; + unsigned int flags; + unsigned int fourCC; + union + { + unsigned int rgbBitCount; + unsigned int yuvBitCount; + unsigned int zBufferBitDepth; + unsigned int alphaBitDepth; + unsigned int luminanceBitCount; + unsigned int bumpBitCount; + unsigned int privateFormatBitCount; + }; + union + { + unsigned int rBitMask; + unsigned int yBitMask; + unsigned int stencilBitDepth; + unsigned int luminanceBitMask; + unsigned int bumpDuBitMask; + unsigned int operations; + }; + union + { + unsigned int gBitMask; + unsigned int uBitMask; + unsigned int zBitMask; + unsigned int bumpDvBitMask; + ddsMultiSampleCaps_t multiSampleCaps; + }; + union + { + unsigned int bBitMask; + unsigned int vBitMask; + unsigned int stencilBitMask; + unsigned int bumpLuminanceBitMask; + }; + union + { + unsigned int rgbAlphaBitMask; + unsigned int yuvAlphaBitMask; + unsigned int luminanceAlphaBitMask; + unsigned int rgbZBitMask; + unsigned int yuvZBitMask; + }; +} +ddsPixelFormat_t; + + +typedef struct ddsBuffer_s +{ + /* magic: 'dds ' */ + char magic[ 4 ]; + + /* directdraw surface */ + unsigned int size; + unsigned int flags; + unsigned int height; + unsigned int width; + union + { + int pitch; + unsigned int linearSize; + }; + unsigned int backBufferCount; + union + { + unsigned int mipMapCount; + unsigned int refreshRate; + unsigned int srcVBHandle; + }; + unsigned int alphaBitDepth; + unsigned int reserved; + void *surface; + union + { + ddsColorKey_t ckDestOverlay; + unsigned int emptyFaceColor; + }; + ddsColorKey_t ckDestBlt; + ddsColorKey_t ckSrcOverlay; + ddsColorKey_t ckSrcBlt; + union + { + ddsPixelFormat_t pixelFormat; + unsigned int fvf; + }; + ddsCaps_t ddsCaps; + unsigned int textureStage; + + /* data (Varying size) */ + unsigned char data[ 4 ]; +} +ddsBuffer_t; + + +typedef struct ddsColorBlock_s +{ + unsigned short colors[ 2 ]; + unsigned char row[ 4 ]; +} +ddsColorBlock_t; + + +typedef struct ddsAlphaBlockExplicit_s +{ + unsigned short row[ 4 ]; +} +ddsAlphaBlockExplicit_t; + + +typedef struct ddsAlphaBlock3BitLinear_s +{ + unsigned char alpha0; + unsigned char alpha1; + unsigned char stuff[ 6 ]; +} +ddsAlphaBlock3BitLinear_t; + + +typedef struct ddsColor_s +{ + unsigned char r, g, b, a; +} +ddsColor_t; + + + +/* public functions */ +int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ); +int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ); + + + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/ddslib/ddslib.c b/libs/ddslib/ddslib.c index e7bfeb2b..bf1a9f15 100644 --- a/libs/ddslib/ddslib.c +++ b/libs/ddslib/ddslib.c @@ -1,781 +1,781 @@ -/* ----------------------------------------------------------------------------- - -DDS Library - -Based on code from Nvidia's DDS example: -http://www.nvidia.com/object/dxtc_decompression_code.html - -Copyright (c) 2003 Randy Reddig -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define DDSLIB_C - - - -/* dependencies */ -#include "ddslib.h" - - - -/* endian tomfoolery */ -typedef union -{ - float f; - char c[ 4 ]; -} -floatSwapUnion; - - -#ifndef __BIG_ENDIAN__ - #ifdef _SGI_SOURCE - #define __BIG_ENDIAN__ - #endif -#endif - - -#ifdef __BIG_ENDIAN__ - - int DDSBigLong( int src ) { return src; } - short DDSBigShort( short src ) { return src; } - float DDSBigFloat( float src ) { return src; } - - int DDSLittleLong( int src ) - { - return ((src & 0xFF000000) >> 24) | - ((src & 0x00FF0000) >> 8) | - ((src & 0x0000FF00) << 8) | - ((src & 0x000000FF) << 24); - } - - short DDSLittleShort( short src ) - { - return ((src & 0xFF00) >> 8) | - ((src & 0x00FF) << 8); - } - - float DDSLittleFloat( float src ) - { - floatSwapUnion in,out; - in.f = src; - out.c[ 0 ] = in.c[ 3 ]; - out.c[ 1 ] = in.c[ 2 ]; - out.c[ 2 ] = in.c[ 1 ]; - out.c[ 3 ] = in.c[ 0 ]; - return out.f; - } - -#else /*__BIG_ENDIAN__*/ - - int DDSLittleLong( int src ) { return src; } - short DDSLittleShort( short src ) { return src; } - float DDSLittleFloat( float src ) { return src; } - - int DDSBigLong( int src ) - { - return ((src & 0xFF000000) >> 24) | - ((src & 0x00FF0000) >> 8) | - ((src & 0x0000FF00) << 8) | - ((src & 0x000000FF) << 24); - } - - short DDSBigShort( short src ) - { - return ((src & 0xFF00) >> 8) | - ((src & 0x00FF) << 8); - } - - float DDSBigFloat( float src ) - { - floatSwapUnion in,out; - in.f = src; - out.c[ 0 ] = in.c[ 3 ]; - out.c[ 1 ] = in.c[ 2 ]; - out.c[ 2 ] = in.c[ 1 ]; - out.c[ 3 ] = in.c[ 0 ]; - return out.f; - } - -#endif /*__BIG_ENDIAN__*/ - - - -/* -DDSDecodePixelFormat() -determines which pixel format the dds texture is in -*/ - -static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf ) -{ - unsigned int fourCC; - - - /* dummy check */ - if( dds == NULL || pf == NULL ) - return; - - /* extract fourCC */ - fourCC = dds->pixelFormat.fourCC; - - /* test it */ - if( fourCC == 0 ) - *pf = DDS_PF_ARGB8888; - else if( fourCC == *((unsigned int*) "DXT1") ) - *pf = DDS_PF_DXT1; - else if( fourCC == *((unsigned int*) "DXT2") ) - *pf = DDS_PF_DXT2; - else if( fourCC == *((unsigned int*) "DXT3") ) - *pf = DDS_PF_DXT3; - else if( fourCC == *((unsigned int*) "DXT4") ) - *pf = DDS_PF_DXT4; - else if( fourCC == *((unsigned int*) "DXT5") ) - *pf = DDS_PF_DXT5; - else - *pf = DDS_PF_UNKNOWN; -} - - - -/* -DDSGetInfo() -extracts relevant info from a dds texture, returns 0 on success -*/ - -int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ) -{ - /* dummy test */ - if( dds == NULL ) - return -1; - - /* test dds header */ - if( *((int*) dds->magic) != *((int*) "DDS ") ) - return -1; - if( DDSLittleLong( dds->size ) != 124 ) - return -1; - - /* extract width and height */ - if( width != NULL ) - *width = DDSLittleLong( dds->width ); - if( height != NULL ) - *height = DDSLittleLong( dds->height ); - - /* get pixel format */ - DDSDecodePixelFormat( dds, pf ); - - /* return ok */ - return 0; -} - - - -/* -DDSGetColorBlockColors() -extracts colors from a dds color block -*/ - -static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] ) -{ - unsigned short word; - - - /* color 0 */ - word = DDSLittleShort( block->colors[ 0 ] ); - colors[ 0 ].a = 0xff; - - /* extract rgb bits */ - colors[ 0 ].b = (unsigned char) word; - colors[ 0 ].b <<= 3; - colors[ 0 ].b |= (colors[ 0 ].b >> 5); - word >>= 5; - colors[ 0 ].g = (unsigned char) word; - colors[ 0 ].g <<= 2; - colors[ 0 ].g |= (colors[ 0 ].g >> 5); - word >>= 6; - colors[ 0 ].r = (unsigned char) word; - colors[ 0 ].r <<= 3; - colors[ 0 ].r |= (colors[ 0 ].r >> 5); - - /* same for color 1 */ - word = DDSLittleShort( block->colors[ 1 ] ); - colors[ 1 ].a = 0xff; - - /* extract rgb bits */ - colors[ 1 ].b = (unsigned char) word; - colors[ 1 ].b <<= 3; - colors[ 1 ].b |= (colors[ 1 ].b >> 5); - word >>= 5; - colors[ 1 ].g = (unsigned char) word; - colors[ 1 ].g <<= 2; - colors[ 1 ].g |= (colors[ 1 ].g >> 5); - word >>= 6; - colors[ 1 ].r = (unsigned char) word; - colors[ 1 ].r <<= 3; - colors[ 1 ].r |= (colors[ 1 ].r >> 5); - - /* use this for all but the super-freak math method */ - if( block->colors[ 0 ] > block->colors[ 1 ] ) - { - /* four-color block: derive the other two colors. - 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 - these two bit codes correspond to the 2-bit fields - stored in the 64-bit block. */ - - word = ((unsigned short) colors[ 0 ].r * 2 + (unsigned short) colors[ 1 ].r ) / 3; - /* no +1 for rounding */ - /* as bits have been shifted to 888 */ - colors[ 2 ].r = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].g * 2 + (unsigned short) colors[ 1 ].g) / 3; - colors[ 2 ].g = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].b * 2 + (unsigned short) colors[ 1 ].b) / 3; - colors[ 2 ].b = (unsigned char) word; - colors[ 2 ].a = 0xff; - - word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r * 2) / 3; - colors[ 3 ].r = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g * 2) / 3; - colors[ 3 ].g = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b * 2) / 3; - colors[ 3 ].b = (unsigned char) word; - colors[ 3 ].a = 0xff; - } - else - { - /* three-color block: derive the other color. - 00 = color 0, 01 = color 1, 10 = color 2, - 11 = transparent. - These two bit codes correspond to the 2-bit fields - stored in the 64-bit block */ - - word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r) / 2; - colors[ 2 ].r = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g) / 2; - colors[ 2 ].g = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b) / 2; - colors[ 2 ].b = (unsigned char) word; - colors[ 2 ].a = 0xff; - - /* random color to indicate alpha */ - colors[ 3 ].r = 0x00; - colors[ 3 ].g = 0xff; - colors[ 3 ].b = 0xff; - colors[ 3 ].a = 0x00; - } -} - - - -/* -DDSDecodeColorBlock() -decodes a dds color block -fixme: make endian-safe -*/ - -static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] ) -{ - int r, n; - unsigned int bits; - unsigned int masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ - int shift[] = { 0, 2, 4, 6 }; - - - /* r steps through lines in y */ - for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as unsigned int ptr inc will * 4 */ - { - /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ - - /* n steps through pixels */ - for( n = 0; n < 4; n++ ) - { - bits = block->row[ r ] & masks[ n ]; - bits >>= shift[ n ]; - - switch( bits ) - { - case 0: - *pixel = colors[ 0 ]; - pixel++; - break; - - case 1: - *pixel = colors[ 1 ]; - pixel++; - break; - - case 2: - *pixel = colors[ 2 ]; - pixel++; - break; - - case 3: - *pixel = colors[ 3 ]; - pixel++; - break; - - default: - /* invalid */ - pixel++; - break; - } - } - } -} - - - -/* -DDSDecodeAlphaExplicit() -decodes a dds explicit alpha block -*/ - -static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero ) -{ - int row, pix; - unsigned short word; - ddsColor_t color; - - - /* clear color */ - color.r = 0; - color.g = 0; - color.b = 0; - - /* walk rows */ - for( row = 0; row < 4; row++, pixel += (width - 4) ) - { - word = DDSLittleShort( alphaBlock->row[ row ] ); - - /* walk pixels */ - for( pix = 0; pix < 4; pix++ ) - { - /* zero the alpha bits of image pixel */ - *pixel &= alphaZero; - color.a = word & 0x000F; - color.a = color.a | (color.a << 4); - *pixel |= *((unsigned int*) &color); - word >>= 4; /* move next bits to lowest 4 */ - pixel++; /* move to next pixel in the row */ - - } - } -} - - - -/* -DDSDecodeAlpha3BitLinear() -decodes interpolated alpha block -*/ - -static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero ) -{ - - int row, pix; - unsigned int stuff; - unsigned char bits[ 4 ][ 4 ]; - unsigned short alphas[ 8 ]; - ddsColor_t aColors[ 4 ][ 4 ]; - - - /* get initial alphas */ - alphas[ 0 ] = alphaBlock->alpha0; - alphas[ 1 ] = alphaBlock->alpha1; - - /* 8-alpha block */ - if( alphas[ 0 ] > alphas[ 1 ] ) - { - /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ - alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ - alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ - alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ - alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ - alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ - alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ - } - - /* 6-alpha block */ - else - { - /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ - alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ - alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ - alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ - alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ - alphas[ 6 ] = 0; /* bit code 110 */ - alphas[ 7 ] = 255; /* bit code 111 */ - } - - /* decode 3-bit fields into array of 16 bytes with same value */ - - /* first two rows of 4 pixels each */ - stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ])); - - bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - - /* last two rows */ - stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ - - bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - - /* decode the codes into alpha values */ - for( row = 0; row < 4; row++ ) - { - for( pix=0; pix < 4; pix++ ) - { - aColors[ row ][ pix ].r = 0; - aColors[ row ][ pix ].g = 0; - aColors[ row ][ pix ].b = 0; - aColors[ row ][ pix ].a = (unsigned char) alphas[ bits[ row ][ pix ] ]; - } - } - - /* write out alpha values to the image bits */ - for( row = 0; row < 4; row++, pixel += width-4 ) - { - for( pix = 0; pix < 4; pix++ ) - { - /* zero the alpha bits of image pixel */ - *pixel &= alphaZero; - - /* or the bits into the prev. nulled alpha */ - *pixel |= *((unsigned int*) &(aColors[ row ][ pix ])); - pixel++; - } - } -} - - - -/* -DDSDecompressDXT1() -decompresses a dxt1 format texture -*/ - -static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y, xBlocks, yBlocks; - unsigned int *pixel; - ddsColorBlock_t *block; - ddsColor_t colors[ 4 ]; - - - /* setup */ - xBlocks = width / 4; - yBlocks = height / 4; - - /* walk y */ - for( y = 0; y < yBlocks; y++ ) - { - /* 8 bytes per block */ - block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8); - - /* walk x */ - for( x = 0; x < xBlocks; x++, block++ ) - { - DDSGetColorBlockColors( block, colors ); - pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); - DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompressDXT3() -decompresses a dxt3 format texture -*/ - -static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y, xBlocks, yBlocks; - unsigned int *pixel, alphaZero; - ddsColorBlock_t *block; - ddsAlphaBlockExplicit_t *alphaBlock; - ddsColor_t colors[ 4 ]; - - - /* setup */ - xBlocks = width / 4; - yBlocks = height / 4; - - /* create zero alpha */ - colors[ 0 ].a = 0; - colors[ 0 ].r = 0xFF; - colors[ 0 ].g = 0xFF; - colors[ 0 ].b = 0xFF; - alphaZero = *((unsigned int*) &colors[ 0 ]); - - /* walk y */ - for( y = 0; y < yBlocks; y++ ) - { - /* 8 bytes per block, 1 block for alpha, 1 block for color */ - block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); - - /* walk x */ - for( x = 0; x < xBlocks; x++, block++ ) - { - /* get alpha block */ - alphaBlock = (ddsAlphaBlockExplicit_t*) block; - - /* get color block */ - block++; - DDSGetColorBlockColors( block, colors ); - - /* decode color block */ - pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); - DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); - - /* overwrite alpha bits with alpha block */ - DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompressDXT5() -decompresses a dxt5 format texture -*/ - -static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y, xBlocks, yBlocks; - unsigned int *pixel, alphaZero; - ddsColorBlock_t *block; - ddsAlphaBlock3BitLinear_t *alphaBlock; - ddsColor_t colors[ 4 ]; - - - /* setup */ - xBlocks = width / 4; - yBlocks = height / 4; - - /* create zero alpha */ - colors[ 0 ].a = 0; - colors[ 0 ].r = 0xFF; - colors[ 0 ].g = 0xFF; - colors[ 0 ].b = 0xFF; - alphaZero = *((unsigned int*) &colors[ 0 ]); - - /* walk y */ - for( y = 0; y < yBlocks; y++ ) - { - /* 8 bytes per block, 1 block for alpha, 1 block for color */ - block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); - - /* walk x */ - for( x = 0; x < xBlocks; x++, block++ ) - { - /* get alpha block */ - alphaBlock = (ddsAlphaBlock3BitLinear_t*) block; - - /* get color block */ - block++; - DDSGetColorBlockColors( block, colors ); - - /* decode color block */ - pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); - DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); - - /* overwrite alpha bits with alpha block */ - DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompressDXT2() -decompresses a dxt2 format texture (fixme: un-premultiply alpha) -*/ - -static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int r; - - - /* decompress dxt3 first */ - r = DDSDecompressDXT3( dds, width, height, pixels ); - - /* return to sender */ - return r; -} - - - -/* -DDSDecompressDXT4() -decompresses a dxt4 format texture (fixme: un-premultiply alpha) -*/ - -static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int r; - - - /* decompress dxt5 first */ - r = DDSDecompressDXT5( dds, width, height, pixels ); - - /* return to sender */ - return r; -} - - - -/* -DDSDecompressARGB8888() -decompresses an argb 8888 format texture -*/ - -static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y; - unsigned char *in, *out; - - - /* setup */ - in = dds->data; - out = pixels; - - /* walk y */ - for( y = 0; y < height; y++ ) - { - /* walk x */ - for( x = 0; x < width; x++ ) - { - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompress() -decompresses a dds texture into an rgba image buffer, returns 0 on success -*/ - -int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ) -{ - int width, height, r; - ddsPF_t pf; - - - /* get dds info */ - r = DDSGetInfo( dds, &width, &height, &pf ); - if( r ) - return r; - - /* decompress */ - switch( pf ) - { - case DDS_PF_ARGB8888: - /* fixme: support other [a]rgb formats */ - r = DDSDecompressARGB8888( dds, width, height, pixels ); - break; - - case DDS_PF_DXT1: - r = DDSDecompressDXT1( dds, width, height, pixels ); - break; - - case DDS_PF_DXT2: - r = DDSDecompressDXT2( dds, width, height, pixels ); - break; - - case DDS_PF_DXT3: - r = DDSDecompressDXT3( dds, width, height, pixels ); - break; - - case DDS_PF_DXT4: - r = DDSDecompressDXT4( dds, width, height, pixels ); - break; - - case DDS_PF_DXT5: - r = DDSDecompressDXT5( dds, width, height, pixels ); - break; - - default: - case DDS_PF_UNKNOWN: - memset( pixels, 0xFF, width * height * 4 ); - r = -1; - break; - } - - /* return to sender */ - return r; -} - +/* ----------------------------------------------------------------------------- + +DDS Library + +Based on code from Nvidia's DDS example: +http://www.nvidia.com/object/dxtc_decompression_code.html + +Copyright (c) 2003 Randy Reddig +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define DDSLIB_C + + + +/* dependencies */ +#include "ddslib.h" + + + +/* endian tomfoolery */ +typedef union +{ + float f; + char c[ 4 ]; +} +floatSwapUnion; + + +#ifndef __BIG_ENDIAN__ + #ifdef _SGI_SOURCE + #define __BIG_ENDIAN__ + #endif +#endif + + +#ifdef __BIG_ENDIAN__ + + int DDSBigLong( int src ) { return src; } + short DDSBigShort( short src ) { return src; } + float DDSBigFloat( float src ) { return src; } + + int DDSLittleLong( int src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + short DDSLittleShort( short src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + float DDSLittleFloat( float src ) + { + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; + } + +#else /*__BIG_ENDIAN__*/ + + int DDSLittleLong( int src ) { return src; } + short DDSLittleShort( short src ) { return src; } + float DDSLittleFloat( float src ) { return src; } + + int DDSBigLong( int src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + short DDSBigShort( short src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + float DDSBigFloat( float src ) + { + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; + } + +#endif /*__BIG_ENDIAN__*/ + + + +/* +DDSDecodePixelFormat() +determines which pixel format the dds texture is in +*/ + +static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf ) +{ + unsigned int fourCC; + + + /* dummy check */ + if( dds == NULL || pf == NULL ) + return; + + /* extract fourCC */ + fourCC = dds->pixelFormat.fourCC; + + /* test it */ + if( fourCC == 0 ) + *pf = DDS_PF_ARGB8888; + else if( fourCC == *((unsigned int*) "DXT1") ) + *pf = DDS_PF_DXT1; + else if( fourCC == *((unsigned int*) "DXT2") ) + *pf = DDS_PF_DXT2; + else if( fourCC == *((unsigned int*) "DXT3") ) + *pf = DDS_PF_DXT3; + else if( fourCC == *((unsigned int*) "DXT4") ) + *pf = DDS_PF_DXT4; + else if( fourCC == *((unsigned int*) "DXT5") ) + *pf = DDS_PF_DXT5; + else + *pf = DDS_PF_UNKNOWN; +} + + + +/* +DDSGetInfo() +extracts relevant info from a dds texture, returns 0 on success +*/ + +int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ) +{ + /* dummy test */ + if( dds == NULL ) + return -1; + + /* test dds header */ + if( *((int*) dds->magic) != *((int*) "DDS ") ) + return -1; + if( DDSLittleLong( dds->size ) != 124 ) + return -1; + + /* extract width and height */ + if( width != NULL ) + *width = DDSLittleLong( dds->width ); + if( height != NULL ) + *height = DDSLittleLong( dds->height ); + + /* get pixel format */ + DDSDecodePixelFormat( dds, pf ); + + /* return ok */ + return 0; +} + + + +/* +DDSGetColorBlockColors() +extracts colors from a dds color block +*/ + +static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] ) +{ + unsigned short word; + + + /* color 0 */ + word = DDSLittleShort( block->colors[ 0 ] ); + colors[ 0 ].a = 0xff; + + /* extract rgb bits */ + colors[ 0 ].b = (unsigned char) word; + colors[ 0 ].b <<= 3; + colors[ 0 ].b |= (colors[ 0 ].b >> 5); + word >>= 5; + colors[ 0 ].g = (unsigned char) word; + colors[ 0 ].g <<= 2; + colors[ 0 ].g |= (colors[ 0 ].g >> 5); + word >>= 6; + colors[ 0 ].r = (unsigned char) word; + colors[ 0 ].r <<= 3; + colors[ 0 ].r |= (colors[ 0 ].r >> 5); + + /* same for color 1 */ + word = DDSLittleShort( block->colors[ 1 ] ); + colors[ 1 ].a = 0xff; + + /* extract rgb bits */ + colors[ 1 ].b = (unsigned char) word; + colors[ 1 ].b <<= 3; + colors[ 1 ].b |= (colors[ 1 ].b >> 5); + word >>= 5; + colors[ 1 ].g = (unsigned char) word; + colors[ 1 ].g <<= 2; + colors[ 1 ].g |= (colors[ 1 ].g >> 5); + word >>= 6; + colors[ 1 ].r = (unsigned char) word; + colors[ 1 ].r <<= 3; + colors[ 1 ].r |= (colors[ 1 ].r >> 5); + + /* use this for all but the super-freak math method */ + if( block->colors[ 0 ] > block->colors[ 1 ] ) + { + /* four-color block: derive the other two colors. + 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 + these two bit codes correspond to the 2-bit fields + stored in the 64-bit block. */ + + word = ((unsigned short) colors[ 0 ].r * 2 + (unsigned short) colors[ 1 ].r ) / 3; + /* no +1 for rounding */ + /* as bits have been shifted to 888 */ + colors[ 2 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g * 2 + (unsigned short) colors[ 1 ].g) / 3; + colors[ 2 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b * 2 + (unsigned short) colors[ 1 ].b) / 3; + colors[ 2 ].b = (unsigned char) word; + colors[ 2 ].a = 0xff; + + word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r * 2) / 3; + colors[ 3 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g * 2) / 3; + colors[ 3 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b * 2) / 3; + colors[ 3 ].b = (unsigned char) word; + colors[ 3 ].a = 0xff; + } + else + { + /* three-color block: derive the other color. + 00 = color 0, 01 = color 1, 10 = color 2, + 11 = transparent. + These two bit codes correspond to the 2-bit fields + stored in the 64-bit block */ + + word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r) / 2; + colors[ 2 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g) / 2; + colors[ 2 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b) / 2; + colors[ 2 ].b = (unsigned char) word; + colors[ 2 ].a = 0xff; + + /* random color to indicate alpha */ + colors[ 3 ].r = 0x00; + colors[ 3 ].g = 0xff; + colors[ 3 ].b = 0xff; + colors[ 3 ].a = 0x00; + } +} + + + +/* +DDSDecodeColorBlock() +decodes a dds color block +fixme: make endian-safe +*/ + +static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] ) +{ + int r, n; + unsigned int bits; + unsigned int masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ + int shift[] = { 0, 2, 4, 6 }; + + + /* r steps through lines in y */ + for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as unsigned int ptr inc will * 4 */ + { + /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ + + /* n steps through pixels */ + for( n = 0; n < 4; n++ ) + { + bits = block->row[ r ] & masks[ n ]; + bits >>= shift[ n ]; + + switch( bits ) + { + case 0: + *pixel = colors[ 0 ]; + pixel++; + break; + + case 1: + *pixel = colors[ 1 ]; + pixel++; + break; + + case 2: + *pixel = colors[ 2 ]; + pixel++; + break; + + case 3: + *pixel = colors[ 3 ]; + pixel++; + break; + + default: + /* invalid */ + pixel++; + break; + } + } + } +} + + + +/* +DDSDecodeAlphaExplicit() +decodes a dds explicit alpha block +*/ + +static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero ) +{ + int row, pix; + unsigned short word; + ddsColor_t color; + + + /* clear color */ + color.r = 0; + color.g = 0; + color.b = 0; + + /* walk rows */ + for( row = 0; row < 4; row++, pixel += (width - 4) ) + { + word = DDSLittleShort( alphaBlock->row[ row ] ); + + /* walk pixels */ + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + color.a = word & 0x000F; + color.a = color.a | (color.a << 4); + *pixel |= *((unsigned int*) &color); + word >>= 4; /* move next bits to lowest 4 */ + pixel++; /* move to next pixel in the row */ + + } + } +} + + + +/* +DDSDecodeAlpha3BitLinear() +decodes interpolated alpha block +*/ + +static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero ) +{ + + int row, pix; + unsigned int stuff; + unsigned char bits[ 4 ][ 4 ]; + unsigned short alphas[ 8 ]; + ddsColor_t aColors[ 4 ][ 4 ]; + + + /* get initial alphas */ + alphas[ 0 ] = alphaBlock->alpha0; + alphas[ 1 ] = alphaBlock->alpha1; + + /* 8-alpha block */ + if( alphas[ 0 ] > alphas[ 1 ] ) + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ + alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ + alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ + alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ + alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ + alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ + } + + /* 6-alpha block */ + else + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ + alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ + alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ + alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ + alphas[ 6 ] = 0; /* bit code 110 */ + alphas[ 7 ] = 255; /* bit code 111 */ + } + + /* decode 3-bit fields into array of 16 bytes with same value */ + + /* first two rows of 4 pixels each */ + stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ])); + + bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + + /* last two rows */ + stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ + + bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + + /* decode the codes into alpha values */ + for( row = 0; row < 4; row++ ) + { + for( pix=0; pix < 4; pix++ ) + { + aColors[ row ][ pix ].r = 0; + aColors[ row ][ pix ].g = 0; + aColors[ row ][ pix ].b = 0; + aColors[ row ][ pix ].a = (unsigned char) alphas[ bits[ row ][ pix ] ]; + } + } + + /* write out alpha values to the image bits */ + for( row = 0; row < 4; row++, pixel += width-4 ) + { + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + + /* or the bits into the prev. nulled alpha */ + *pixel |= *((unsigned int*) &(aColors[ row ][ pix ])); + pixel++; + } + } +} + + + +/* +DDSDecompressDXT1() +decompresses a dxt1 format texture +*/ + +static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel; + ddsColorBlock_t *block; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + DDSGetColorBlockColors( block, colors ); + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT3() +decompresses a dxt3 format texture +*/ + +static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel, alphaZero; + ddsColorBlock_t *block; + ddsAlphaBlockExplicit_t *alphaBlock; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((unsigned int*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlockExplicit_t*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT5() +decompresses a dxt5 format texture +*/ + +static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel, alphaZero; + ddsColorBlock_t *block; + ddsAlphaBlock3BitLinear_t *alphaBlock; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((unsigned int*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlock3BitLinear_t*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT2() +decompresses a dxt2 format texture (fixme: un-premultiply alpha) +*/ + +static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int r; + + + /* decompress dxt3 first */ + r = DDSDecompressDXT3( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + + +/* +DDSDecompressDXT4() +decompresses a dxt4 format texture (fixme: un-premultiply alpha) +*/ + +static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int r; + + + /* decompress dxt5 first */ + r = DDSDecompressDXT5( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + + +/* +DDSDecompressARGB8888() +decompresses an argb 8888 format texture +*/ + +static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y; + unsigned char *in, *out; + + + /* setup */ + in = dds->data; + out = pixels; + + /* walk y */ + for( y = 0; y < height; y++ ) + { + /* walk x */ + for( x = 0; x < width; x++ ) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompress() +decompresses a dds texture into an rgba image buffer, returns 0 on success +*/ + +int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ) +{ + int width, height, r; + ddsPF_t pf; + + + /* get dds info */ + r = DDSGetInfo( dds, &width, &height, &pf ); + if( r ) + return r; + + /* decompress */ + switch( pf ) + { + case DDS_PF_ARGB8888: + /* fixme: support other [a]rgb formats */ + r = DDSDecompressARGB8888( dds, width, height, pixels ); + break; + + case DDS_PF_DXT1: + r = DDSDecompressDXT1( dds, width, height, pixels ); + break; + + case DDS_PF_DXT2: + r = DDSDecompressDXT2( dds, width, height, pixels ); + break; + + case DDS_PF_DXT3: + r = DDSDecompressDXT3( dds, width, height, pixels ); + break; + + case DDS_PF_DXT4: + r = DDSDecompressDXT4( dds, width, height, pixels ); + break; + + case DDS_PF_DXT5: + r = DDSDecompressDXT5( dds, width, height, pixels ); + break; + + default: + case DDS_PF_UNKNOWN: + memset( pixels, 0xFF, width * height * 4 ); + r = -1; + break; + } + + /* return to sender */ + return r; +} + diff --git a/libs/igl_to_qgl.h b/libs/igl_to_qgl.h index a71ecd2e..633cf478 100644 --- a/libs/igl_to_qgl.h +++ b/libs/igl_to_qgl.h @@ -1,806 +1,806 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -IGL tp QGL mapping header -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#ifndef _IGL_TO_QGL_H_ -#define _IGL_TO_QGL_H_ - -#ifdef _WIN32 -#include -#endif - -enum VIEWTYPE {YZ, XZ, XY}; - -#include "igl.h" - -#ifndef APIENTRY - #define APIENTRY -#endif - -void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); -void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); -GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); -void ( APIENTRY * qglArrayElement )(GLint i); -void ( APIENTRY * qglBegin )(GLenum mode); -void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); -void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); -void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); -void ( APIENTRY * qglCallList )(GLuint list); -void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); -void ( APIENTRY * qglClear )(GLbitfield mask); -void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -void ( APIENTRY * qglClearDepth )(GLclampd depth); -void ( APIENTRY * qglClearIndex )(GLfloat c); -void ( APIENTRY * qglClearStencil )(GLint s); -void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); -void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); -void ( APIENTRY * qglColor3bv )(const GLbyte *v); -void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); -void ( APIENTRY * qglColor3dv )(const GLdouble *v); -void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); -void ( APIENTRY * qglColor3fv )(const GLfloat *v); -void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); -void ( APIENTRY * qglColor3iv )(const GLint *v); -void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); -void ( APIENTRY * qglColor3sv )(const GLshort *v); -void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); -void ( APIENTRY * qglColor3ubv )(const GLubyte *v); -void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); -void ( APIENTRY * qglColor3uiv )(const GLuint *v); -void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); -void ( APIENTRY * qglColor3usv )(const GLushort *v); -void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); -void ( APIENTRY * qglColor4bv )(const GLbyte *v); -void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); -void ( APIENTRY * qglColor4dv )(const GLdouble *v); -void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -void ( APIENTRY * qglColor4fv )(const GLfloat *v); -void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); -void ( APIENTRY * qglColor4iv )(const GLint *v); -void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); -void ( APIENTRY * qglColor4sv )(const GLshort *v); -void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); -void ( APIENTRY * qglColor4ubv )(const GLubyte *v); -void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); -void ( APIENTRY * qglColor4uiv )(const GLuint *v); -void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); -void ( APIENTRY * qglColor4usv )(const GLushort *v); -void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); -void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); -void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); -void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); -void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); -void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); -void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); -void ( APIENTRY * qglCullFace )(GLenum mode); -void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); -void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); -void ( APIENTRY * qglDepthFunc )(GLenum func); -void ( APIENTRY * qglDepthMask )(GLboolean flag); -void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); -void ( APIENTRY * qglDisable )(GLenum cap); -void ( APIENTRY * qglDisableClientState )(GLenum array); -void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); -void ( APIENTRY * qglDrawBuffer )(GLenum mode); -void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); -void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -void ( APIENTRY * qglEdgeFlag )(GLboolean flag); -void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); -void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); -void ( APIENTRY * qglEnable )(GLenum cap); -void ( APIENTRY * qglEnableClientState )(GLenum array); -void ( APIENTRY * qglEnd )(void); -void ( APIENTRY * qglEndList )(void); -void ( APIENTRY * qglEvalCoord1d )(GLdouble u); -void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); -void ( APIENTRY * qglEvalCoord1f )(GLfloat u); -void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); -void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); -void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); -void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); -void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); -void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); -void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); -void ( APIENTRY * qglEvalPoint1 )(GLint i); -void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); -void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); -void ( APIENTRY * qglFinish )(void); -void ( APIENTRY * qglFlush )(void); -void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); -void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); -void ( APIENTRY * qglFogi )(GLenum pname, GLint param); -void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); -void ( APIENTRY * qglFrontFace )(GLenum mode); -void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -GLuint ( APIENTRY * qglGenLists )(GLsizei range); -void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); -void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); -void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); -void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); -GLenum ( APIENTRY * qglGetError )(void); -void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); -void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); -void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); -void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); -void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); -void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); -void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); -void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); -void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); -void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); -void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); -void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); -void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); -void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); -const GLubyte * ( APIENTRY * qglGetString )(GLenum name); -void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); -void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); -void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); -void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); -void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); -void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); -void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); -void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); -void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); -void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); -void ( APIENTRY * qglHint )(GLenum target, GLenum mode); -void ( APIENTRY * qglIndexMask )(GLuint mask); -void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); -void ( APIENTRY * qglIndexd )(GLdouble c); -void ( APIENTRY * qglIndexdv )(const GLdouble *c); -void ( APIENTRY * qglIndexf )(GLfloat c); -void ( APIENTRY * qglIndexfv )(const GLfloat *c); -void ( APIENTRY * qglIndexi )(GLint c); -void ( APIENTRY * qglIndexiv )(const GLint *c); -void ( APIENTRY * qglIndexs )(GLshort c); -void ( APIENTRY * qglIndexsv )(const GLshort *c); -void ( APIENTRY * qglIndexub )(GLubyte c); -void ( APIENTRY * qglIndexubv )(const GLubyte *c); -void ( APIENTRY * qglInitNames )(void); -void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); -GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); -GLboolean ( APIENTRY * qglIsList )(GLuint list); -GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); -void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); -void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); -void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); -void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); -void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); -void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); -void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); -void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); -void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); -void ( APIENTRY * qglLineWidth )(GLfloat width); -void ( APIENTRY * qglListBase )(GLuint base); -void ( APIENTRY * qglLoadIdentity )(void); -void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); -void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); -void ( APIENTRY * qglLoadName )(GLuint name); -void ( APIENTRY * qglLogicOp )(GLenum opcode); -void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); -void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); -void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); -void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); -void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); -void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); -void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); -void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); -void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); -void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); -void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); -void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); -void ( APIENTRY * qglMatrixMode )(GLenum mode); -void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); -void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); -void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); -void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); -void ( APIENTRY * qglNormal3bv )(const GLbyte *v); -void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); -void ( APIENTRY * qglNormal3dv )(const GLdouble *v); -void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); -void ( APIENTRY * qglNormal3fv )(const GLfloat *v); -void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); -void ( APIENTRY * qglNormal3iv )(const GLint *v); -void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); -void ( APIENTRY * qglNormal3sv )(const GLshort *v); -void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); -void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -void ( APIENTRY * qglPassThrough )(GLfloat token); -void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); -void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); -void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); -void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); -void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); -void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); -void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); -void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); -void ( APIENTRY * qglPointSize )(GLfloat size); -void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); -void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); -void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); -void ( APIENTRY * qglPopAttrib )(void); -void ( APIENTRY * qglPopClientAttrib )(void); -void ( APIENTRY * qglPopMatrix )(void); -void ( APIENTRY * qglPopName )(void); -void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); -void ( APIENTRY * qglPushAttrib )(GLbitfield mask); -void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); -void ( APIENTRY * qglPushMatrix )(void); -void ( APIENTRY * qglPushName )(GLuint name); -void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); -void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); -void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); -void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); -void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); -void ( APIENTRY * qglRasterPos2iv )(const GLint *v); -void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); -void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); -void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); -void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); -void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); -void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); -void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); -void ( APIENTRY * qglRasterPos3iv )(const GLint *v); -void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); -void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); -void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); -void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); -void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); -void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); -void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); -void ( APIENTRY * qglRasterPos4iv )(const GLint *v); -void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); -void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); -void ( APIENTRY * qglReadBuffer )(GLenum mode); -void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); -void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); -void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); -void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); -void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); -void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); -void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); -void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); -void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); -GLint ( APIENTRY * qglRenderMode )(GLenum mode); -void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); -void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); -void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); -void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); -void ( APIENTRY * qglShadeModel )(GLenum mode); -void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); -void ( APIENTRY * qglStencilMask )(GLuint mask); -void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); -void ( APIENTRY * qglTexCoord1d )(GLdouble s); -void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); -void ( APIENTRY * qglTexCoord1f )(GLfloat s); -void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); -void ( APIENTRY * qglTexCoord1i )(GLint s); -void ( APIENTRY * qglTexCoord1iv )(const GLint *v); -void ( APIENTRY * qglTexCoord1s )(GLshort s); -void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); -void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); -void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); -void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); -void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); -void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); -void ( APIENTRY * qglTexCoord2iv )(const GLint *v); -void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); -void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); -void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); -void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); -void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); -void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); -void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); -void ( APIENTRY * qglTexCoord3iv )(const GLint *v); -void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); -void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); -void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); -void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); -void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); -void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); -void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); -void ( APIENTRY * qglTexCoord4iv )(const GLint *v); -void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); -void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); -void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); -void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); -void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); -void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); -void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); -void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); -void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); -void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); -void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); -void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); -void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); -void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); -void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); -void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); -void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); -void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); -void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); -void ( APIENTRY * qglVertex2dv )(const GLdouble *v); -void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); -void ( APIENTRY * qglVertex2fv )(const GLfloat *v); -void ( APIENTRY * qglVertex2i )(GLint x, GLint y); -void ( APIENTRY * qglVertex2iv )(const GLint *v); -void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); -void ( APIENTRY * qglVertex2sv )(const GLshort *v); -void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); -void ( APIENTRY * qglVertex3dv )(const GLdouble *v); -void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); -void ( APIENTRY * qglVertex3fv )(const GLfloat *v); -void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); -void ( APIENTRY * qglVertex3iv )(const GLint *v); -void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); -void ( APIENTRY * qglVertex3sv )(const GLshort *v); -void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); -void ( APIENTRY * qglVertex4dv )(const GLdouble *v); -void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); -void ( APIENTRY * qglVertex4fv )(const GLfloat *v); -void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); -void ( APIENTRY * qglVertex4iv )(const GLint *v); -void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); -void ( APIENTRY * qglVertex4sv )(const GLshort *v); -void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); - -void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); -void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); -void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); - -void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); -void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); - -void ( APIENTRY * qglActiveTextureARB) (GLenum texture); -void ( APIENTRY * qglClientActiveTextureARB) (GLenum texture); -void ( APIENTRY * qglMultiTexCoord1dARB) (GLenum target, GLdouble s); -void ( APIENTRY * qglMultiTexCoord1dvARB) (GLenum target, const GLdouble *v); -void ( APIENTRY * qglMultiTexCoord1fARB) (GLenum target, GLfloat s); -void ( APIENTRY * qglMultiTexCoord1fvARB) (GLenum target, const GLfloat *v); -void ( APIENTRY * qglMultiTexCoord1iARB) (GLenum target, GLint s); -void ( APIENTRY * qglMultiTexCoord1ivARB) (GLenum target, const GLint *v); -void ( APIENTRY * qglMultiTexCoord1sARB) (GLenum target, GLshort s); -void ( APIENTRY * qglMultiTexCoord1svARB) (GLenum target, const GLshort *v); -void ( APIENTRY * qglMultiTexCoord2dARB) (GLenum target, GLdouble s); -void ( APIENTRY * qglMultiTexCoord2dvARB) (GLenum target, const GLdouble *v); -void ( APIENTRY * qglMultiTexCoord2fARB) (GLenum target, GLfloat s); -void ( APIENTRY * qglMultiTexCoord2fvARB) (GLenum target, const GLfloat *v); -void ( APIENTRY * qglMultiTexCoord2iARB) (GLenum target, GLint s); -void ( APIENTRY * qglMultiTexCoord2ivARB) (GLenum target, const GLint *v); -void ( APIENTRY * qglMultiTexCoord2sARB) (GLenum target, GLshort s); -void ( APIENTRY * qglMultiTexCoord2svARB) (GLenum target, const GLshort *v); -void ( APIENTRY * qglMultiTexCoord3dARB) (GLenum target, GLdouble s); -void ( APIENTRY * qglMultiTexCoord3dvARB) (GLenum target, const GLdouble *v); -void ( APIENTRY * qglMultiTexCoord3fARB) (GLenum target, GLfloat s); -void ( APIENTRY * qglMultiTexCoord3fvARB) (GLenum target, const GLfloat *v); -void ( APIENTRY * qglMultiTexCoord3iARB) (GLenum target, GLint s); -void ( APIENTRY * qglMultiTexCoord3ivARB) (GLenum target, const GLint *v); -void ( APIENTRY * qglMultiTexCoord3sARB) (GLenum target, GLshort s); -void ( APIENTRY * qglMultiTexCoord3svARB) (GLenum target, const GLshort *v); -void ( APIENTRY * qglMultiTexCoord4dARB) (GLenum target, GLdouble s); -void ( APIENTRY * qglMultiTexCoord4dvARB) (GLenum target, const GLdouble *v); -void ( APIENTRY * qglMultiTexCoord4fARB) (GLenum target, GLfloat s); -void ( APIENTRY * qglMultiTexCoord4fvARB) (GLenum target, const GLfloat *v); -void ( APIENTRY * qglMultiTexCoord4iARB) (GLenum target, GLint s); -void ( APIENTRY * qglMultiTexCoord4ivARB) (GLenum target, const GLint *v); -void ( APIENTRY * qglMultiTexCoord4sARB) (GLenum target, GLshort s); -void ( APIENTRY * qglMultiTexCoord4svARB) (GLenum target, const GLshort *v); - -extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ) -{ -/* - // initialze the qgl functions - qglAccum = NULL; - qglAlphaFunc = g_QglTable->m_pfn_qglAlphaFunc; - qglAreTexturesResident = NULL; - qglArrayElement = NULL; - qglBegin = g_QglTable->m_pfn_qglBegin; - qglBindTexture = g_QglTable->m_pfn_qglBindTexture; - qglBitmap = NULL; - qglBlendFunc = g_QglTable->m_pfn_qglBlendFunc; - qglCallList = g_QglTable->m_pfn_qglCallList; - qglCallLists = g_QglTable->m_pfn_qglCallLists; - qglClear = g_QglTable->m_pfn_qglClear; - qglClearAccum = NULL; - qglClearColor = g_QglTable->m_pfn_qglClearColor; - qglClearDepth = g_QglTable->m_pfn_qglClearDepth; - qglClearIndex = NULL; - qglClearStencil = NULL; - qglClipPlane = NULL; - qglColor3b = NULL; - qglColor3bv = NULL; - qglColor3d = NULL; - qglColor3dv = NULL; - qglColor3f = g_QglTable->m_pfn_qglColor3f; - qglColor3fv = g_QglTable->m_pfn_qglColor3fv; - qglColor3i = NULL; - qglColor3iv = NULL; - qglColor3s = NULL; - qglColor3sv = NULL; - qglColor3ub = NULL; - qglColor3ubv = NULL; - qglColor3ui = NULL; - qglColor3uiv = NULL; - qglColor3us = NULL; - qglColor3usv = NULL; - qglColor4b = NULL; - qglColor4bv = NULL; - qglColor4d = NULL; - qglColor4dv = NULL; - qglColor4f = g_QglTable->m_pfn_qglColor4f; - qglColor4fv = g_QglTable->m_pfn_qglColor4fv; - qglColor4i = NULL; - qglColor4iv = NULL; - qglColor4s = NULL; - qglColor4sv = NULL; - qglColor4ub = NULL; - qglColor4ubv = NULL; - qglColor4ui = NULL; - qglColor4uiv = NULL; - qglColor4us = NULL; - qglColor4usv = NULL; - qglColorMask = NULL; - qglColorMaterial = NULL; - qglColorPointer = NULL; - qglCopyPixels = NULL; - qglCopyTexImage1D = NULL; - qglCopyTexImage2D = NULL; - qglCopyTexSubImage1D = NULL; - qglCopyTexSubImage2D = NULL; - qglCullFace = g_QglTable->m_pfn_qglCullFace; - qglDeleteLists = g_QglTable->m_pfn_qglDeleteLists; - qglDeleteTextures = g_QglTable->m_pfn_qglDeleteTextures; - qglDepthFunc = g_QglTable->m_pfn_qglDepthFunc; - qglDepthMask = g_QglTable->m_pfn_qglDepthMask; - qglDepthRange = NULL; - qglDisable = g_QglTable->m_pfn_qglDisable; - qglDisableClientState = NULL; - qglDrawArrays = NULL; - qglDrawBuffer = NULL; - qglDrawElements = NULL; - qglDrawPixels = NULL; - qglEdgeFlag = NULL; - qglEdgeFlagPointer = NULL; - qglEdgeFlagv = NULL; - qglEnable = g_QglTable->m_pfn_qglEnable; - qglEnableClientState = NULL; - qglEnd = g_QglTable->m_pfn_qglEnd; - qglEndList = g_QglTable->m_pfn_qglEndList; - qglEvalCoord1d = NULL; - qglEvalCoord1dv = NULL; - qglEvalCoord1f = NULL; - qglEvalCoord1fv = NULL; - qglEvalCoord2d = NULL; - qglEvalCoord2dv = NULL; - qglEvalCoord2f= NULL; - qglEvalCoord2fv = NULL; - qglEvalMesh1 = NULL; - qglEvalMesh2 = NULL; - qglEvalPoint1 = NULL; - qglEvalPoint2 = NULL; - qglFeedbackBuffer = NULL; - qglFinish = NULL; - qglFlush = NULL; - qglFogf = g_QglTable->m_pfn_qglFogf; - qglFogfv = g_QglTable->m_pfn_qglFogfv; - qglFogi = g_QglTable->m_pfn_qglFogi; - qglFogiv = NULL; - qglFrontFace = NULL; - qglFrustum = NULL; - qglGenLists = g_QglTable->m_pfn_qglGenLists; - qglGenTextures = g_QglTable->m_pfn_qglGenTextures; - qglGetBooleanv = NULL; - qglGetClipPlane = NULL; - qglGetDoublev = NULL; - qglGetError = NULL; - qglGetFloatv = NULL; - qglGetIntegerv = NULL; - qglGetLightfv = NULL; - qglGetLightiv = NULL; - qglGetMapdv = NULL; - qglGetMapfv = NULL; - qglGetMapiv = NULL; - qglGetMaterialfv = NULL; - qglGetMaterialiv = NULL; - qglGetPixelMapfv = NULL; - qglGetPixelMapuiv = NULL; - qglGetPixelMapusv = NULL; - qglGetPointerv = NULL; - qglGetPolygonStipple = NULL; - qglGetString = NULL; - qglGetTexEnvfv = NULL; - qglGetTexEnviv = NULL; - qglGetTexGendv = NULL; - qglGetTexGenfv = NULL; - qglGetTexGeniv = NULL; - qglGetTexImage = NULL; - qglGetTexLevelParameterfv = NULL; - qglGetTexLevelParameteriv = NULL; - qglGetTexParameterfv = NULL; - qglGetTexParameteriv = NULL; - qglHint = g_QglTable->m_pfn_qglHint; - qglIndexMask = NULL; - qglIndexPointer = NULL; - qglIndexd = NULL; - qglIndexdv = NULL; - qglIndexf = NULL; - qglIndexfv = NULL; - qglIndexi = NULL; - qglIndexiv = NULL; - qglIndexs = NULL; - qglIndexsv = NULL; - qglIndexub = NULL; - qglIndexubv = NULL; - qglInitNames = NULL; - qglInterleavedArrays = NULL; - qglIsEnabled = NULL; - qglIsList = NULL; - qglIsTexture = NULL; - qglLightModelf = NULL; - qglLightModelfv = NULL; - qglLightModeli = NULL; - qglLightModeliv = NULL; - qglLightf = NULL; - qglLightfv = g_QglTable->m_pfn_qglLightfv; - qglLighti = NULL; - qglLightiv = NULL; - qglLineStipple = g_QglTable->m_pfn_qglLineStipple; - qglLineWidth = g_QglTable->m_pfn_qglLineWidth; - qglListBase = g_QglTable->m_pfn_qglListBase; - qglLoadIdentity = g_QglTable->m_pfn_qglLoadIdentity; - qglLoadMatrixd = NULL; - qglLoadMatrixf = NULL; - qglLoadName = NULL; - qglLogicOp = NULL; - qglMap1d = NULL; - qglMap1f = NULL; - qglMap2d = NULL; - qglMap2f = NULL; - qglMapGrid1d = NULL; - qglMapGrid1f = NULL; - qglMapGrid2d = NULL; - qglMapGrid2f = NULL; - qglMaterialf = g_QglTable->m_pfn_qglMaterialf; - qglMaterialfv = g_QglTable->m_pfn_qglMaterialfv; - qglMateriali = NULL; - qglMaterialiv = NULL; - qglMatrixMode = g_QglTable->m_pfn_qglMatrixMode; - qglMultMatrixd = NULL; - qglMultMatrixf = g_QglTable->m_pfn_qglMultMatrixf; - qglNewList = g_QglTable->m_pfn_qglNewList; - qglNormal3b = NULL; - qglNormal3bv = NULL; - qglNormal3d = NULL; - qglNormal3dv = NULL; - qglNormal3f = g_QglTable->m_pfn_qglNormal3f; - qglNormal3fv = g_QglTable->m_pfn_qglNormal3fv; - qglNormal3i = NULL; - qglNormal3iv = NULL; - qglNormal3s = NULL; - qglNormal3sv = NULL; - qglNormalPointer = NULL; - qglOrtho = g_QglTable->m_pfn_qglOrtho; - qglPassThrough = NULL; - qglPixelMapfv = NULL; - qglPixelMapuiv = NULL; - qglPixelMapusv = NULL; - qglPixelStoref = NULL; - qglPixelStorei = NULL; - qglPixelTransferf = NULL; - qglPixelTransferi = NULL; - qglPixelZoom = NULL; - qglPointSize = g_QglTable->m_pfn_qglPointSize; - qglPolygonMode = g_QglTable->m_pfn_qglPolygonMode; - qglPolygonOffset = NULL; - qglPolygonStipple = NULL; - qglPopAttrib = g_QglTable->m_pfn_qglPopAttrib; - qglPopClientAttrib = NULL; - qglPopMatrix = g_QglTable->m_pfn_qglPopMatrix; - qglPopName = NULL; - qglPrioritizeTextures = NULL; - qglPushAttrib = g_QglTable->m_pfn_qglPushAttrib; - qglPushClientAttrib = NULL; - qglPushMatrix = g_QglTable->m_pfn_qglPushMatrix; - qglPushName = NULL; - qglRasterPos2d = NULL; - qglRasterPos2dv = NULL; - qglRasterPos2f = NULL; - qglRasterPos2fv = NULL; - qglRasterPos2i = NULL; - qglRasterPos2iv = NULL; - qglRasterPos2s = NULL; - qglRasterPos2sv = NULL; - qglRasterPos3d = NULL; - qglRasterPos3dv = NULL; - qglRasterPos3f = NULL; - qglRasterPos3fv = g_QglTable->m_pfn_qglRasterPos3fv; - qglRasterPos3i = NULL; - qglRasterPos3iv = NULL; - qglRasterPos3s = NULL; - qglRasterPos3sv = NULL; - qglRasterPos4d = NULL; - qglRasterPos4dv = NULL; - qglRasterPos4f = NULL; - qglRasterPos4fv = NULL; - qglRasterPos4i = NULL; - qglRasterPos4iv = NULL; - qglRasterPos4s = NULL; - qglRasterPos4sv = NULL; - qglReadBuffer = NULL; - qglReadPixels = NULL; - qglRectd = NULL; - qglRectdv = NULL; - qglRectf = NULL; - qglRectfv = NULL; - qglRecti = NULL; - qglRectiv = NULL; - qglRects = NULL; - qglRectsv = NULL; - qglRenderMode = NULL; - qglRotated = g_QglTable->m_pfn_qglRotated; - qglRotatef = g_QglTable->m_pfn_qglRotatef; - qglScaled = NULL; - qglScalef = g_QglTable->m_pfn_qglScalef; - qglScissor = g_QglTable->m_pfn_qglScissor; - qglSelectBuffer = NULL; - qglShadeModel = g_QglTable->m_pfn_qglShadeModel; - qglStencilFunc = NULL; - qglStencilMask = NULL; - qglStencilOp = NULL; - qglTexCoord1d = NULL; - qglTexCoord1dv = NULL; - qglTexCoord1f = NULL; - qglTexCoord1fv = NULL; - qglTexCoord1i = NULL; - qglTexCoord1iv = NULL; - qglTexCoord1s = NULL; - qglTexCoord1sv = NULL; - qglTexCoord2d = NULL; - qglTexCoord2dv = NULL; - qglTexCoord2f = g_QglTable->m_pfn_qglTexCoord2f; - qglTexCoord2fv = g_QglTable->m_pfn_qglTexCoord2fv; - qglTexCoord2i = NULL; - qglTexCoord2iv = NULL; - qglTexCoord2s = NULL; - qglTexCoord2sv = NULL; - qglTexCoord3d = NULL; - qglTexCoord3dv = NULL; - qglTexCoord3f = NULL; - qglTexCoord3fv = NULL; - qglTexCoord3i = NULL; - qglTexCoord3iv = NULL; - qglTexCoord3s = NULL; - qglTexCoord3sv = NULL; - qglTexCoord4d = NULL; - qglTexCoord4dv = NULL; - qglTexCoord4f = NULL; - qglTexCoord4fv = NULL; - qglTexCoord4i = NULL; - qglTexCoord4iv = NULL; - qglTexCoord4s = NULL; - qglTexCoord4sv = NULL; - qglTexCoordPointer = NULL; - qglTexEnvf = g_QglTable->m_pfn_qglTexEnvf; - qglTexEnvfv = NULL; - qglTexEnvi = NULL; - qglTexEnviv = NULL; - qglTexGend = NULL; - qglTexGendv = NULL; - qglTexGenf = g_QglTable->m_pfn_qglTexGenf; - qglTexGenfv = NULL; - qglTexGeni = NULL; - qglTexGeniv = NULL; - qglTexImage1D = g_QglTable->m_pfn_qglTexImage1D; - qglTexImage2D = g_QglTable->m_pfn_qglTexImage2D; - qglTexParameterf = g_QglTable->m_pfn_qglTexParameterf; - qglTexParameterfv = g_QglTable->m_pfn_qglTexParameterfv; - qglTexParameteri = g_QglTable->m_pfn_qglTexParameteri; - qglTexParameteriv = g_QglTable->m_pfn_qglTexParameteriv; - qglTexSubImage1D = g_QglTable->m_pfn_qglTexSubImage1D; - qglTexSubImage2D = g_QglTable->m_pfn_qglTexSubImage2D; - qglTranslated = g_QglTable->m_pfn_qglTranslated; - qglTranslatef = g_QglTable->m_pfn_qglTranslatef; - qglVertex2d = NULL; - qglVertex2dv = NULL; - qglVertex2f = g_QglTable->m_pfn_qglVertex2f; - qglVertex2fv = NULL; - qglVertex2i = NULL; - qglVertex2iv = NULL; - qglVertex2s = NULL; - qglVertex2sv = NULL; - qglVertex3d = NULL; - qglVertex3dv = NULL; - qglVertex3f = g_QglTable->m_pfn_qglVertex3f; - qglVertex3fv = g_QglTable->m_pfn_qglVertex3fv; - qglVertex3i = NULL; - qglVertex3iv = NULL; - qglVertex3s = NULL; - qglVertex3sv = NULL; - qglVertex4d = NULL; - qglVertex4dv = NULL; - qglVertex4f = NULL; - qglVertex4fv = NULL; - qglVertex4i = NULL; - qglVertex4iv = NULL; - qglVertex4s = NULL; - qglVertex4sv = NULL; - qglVertexPointer = NULL; - qglViewport = g_QglTable->m_pfn_qglViewport; - - qglPointParameterfEXT = NULL; - qglPointParameterfvEXT = NULL; - qglColorTableEXT = NULL; - - qglMTexCoord2fSGIS = NULL; - qglSelectTextureSGIS = NULL; - - qglActiveTextureARB = NULL; - qglClientActiveTextureARB = NULL; - qglMultiTexCoord1dARB = NULL; - qglMultiTexCoord1dvARB = NULL; - qglMultiTexCoord1fARB = NULL; - qglMultiTexCoord1fvARB = NULL; - qglMultiTexCoord1iARB = NULL; - qglMultiTexCoord1ivARB = NULL; - qglMultiTexCoord1sARB = NULL; - qglMultiTexCoord1svARB = NULL; - qglMultiTexCoord2dARB = NULL; - qglMultiTexCoord2dvARB = NULL; - qglMultiTexCoord2fARB = NULL; - qglMultiTexCoord2fvARB = NULL; - qglMultiTexCoord2iARB = NULL; - qglMultiTexCoord2ivARB = NULL; - qglMultiTexCoord2sARB = NULL; - qglMultiTexCoord2svARB = NULL; - qglMultiTexCoord3dARB = NULL; - qglMultiTexCoord3dvARB = NULL; - qglMultiTexCoord3fARB = NULL; - qglMultiTexCoord3fvARB = NULL; - qglMultiTexCoord3iARB = NULL; - qglMultiTexCoord3ivARB = NULL; - qglMultiTexCoord3sARB = NULL; - qglMultiTexCoord3svARB = NULL; - qglMultiTexCoord4dARB = NULL; - qglMultiTexCoord4dvARB = NULL; - qglMultiTexCoord4fARB = NULL; - qglMultiTexCoord4fvARB = NULL; - qglMultiTexCoord4iARB = NULL; - qglMultiTexCoord4ivARB = NULL; - qglMultiTexCoord4sARB = NULL; - qglMultiTexCoord4svARB = NULL; -*/ -} - -#endif // _IGL_TO_QGL_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +IGL tp QGL mapping header +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#ifndef _IGL_TO_QGL_H_ +#define _IGL_TO_QGL_H_ + +#ifdef _WIN32 +#include +#endif + +enum VIEWTYPE {YZ, XZ, XY}; + +#include "igl.h" + +#ifndef APIENTRY + #define APIENTRY +#endif + +void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +void ( APIENTRY * qglArrayElement )(GLint i); +void ( APIENTRY * qglBegin )(GLenum mode); +void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +void ( APIENTRY * qglCallList )(GLuint list); +void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +void ( APIENTRY * qglClear )(GLbitfield mask); +void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void ( APIENTRY * qglClearDepth )(GLclampd depth); +void ( APIENTRY * qglClearIndex )(GLfloat c); +void ( APIENTRY * qglClearStencil )(GLint s); +void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +void ( APIENTRY * qglColor3bv )(const GLbyte *v); +void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +void ( APIENTRY * qglColor3dv )(const GLdouble *v); +void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +void ( APIENTRY * qglColor3fv )(const GLfloat *v); +void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +void ( APIENTRY * qglColor3iv )(const GLint *v); +void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +void ( APIENTRY * qglColor3sv )(const GLshort *v); +void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +void ( APIENTRY * qglColor3uiv )(const GLuint *v); +void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +void ( APIENTRY * qglColor3usv )(const GLushort *v); +void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +void ( APIENTRY * qglColor4bv )(const GLbyte *v); +void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +void ( APIENTRY * qglColor4dv )(const GLdouble *v); +void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglColor4fv )(const GLfloat *v); +void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +void ( APIENTRY * qglColor4iv )(const GLint *v); +void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +void ( APIENTRY * qglColor4sv )(const GLshort *v); +void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +void ( APIENTRY * qglColor4uiv )(const GLuint *v); +void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +void ( APIENTRY * qglColor4usv )(const GLushort *v); +void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglCullFace )(GLenum mode); +void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +void ( APIENTRY * qglDepthFunc )(GLenum func); +void ( APIENTRY * qglDepthMask )(GLboolean flag); +void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +void ( APIENTRY * qglDisable )(GLenum cap); +void ( APIENTRY * qglDisableClientState )(GLenum array); +void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +void ( APIENTRY * qglDrawBuffer )(GLenum mode); +void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +void ( APIENTRY * qglEnable )(GLenum cap); +void ( APIENTRY * qglEnableClientState )(GLenum array); +void ( APIENTRY * qglEnd )(void); +void ( APIENTRY * qglEndList )(void); +void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +void ( APIENTRY * qglEvalPoint1 )(GLint i); +void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +void ( APIENTRY * qglFinish )(void); +void ( APIENTRY * qglFlush )(void); +void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglFrontFace )(GLenum mode); +void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * qglGenLists )(GLsizei range); +void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * qglGetError )(void); +void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +void ( APIENTRY * qglIndexMask )(GLuint mask); +void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglIndexd )(GLdouble c); +void ( APIENTRY * qglIndexdv )(const GLdouble *c); +void ( APIENTRY * qglIndexf )(GLfloat c); +void ( APIENTRY * qglIndexfv )(const GLfloat *c); +void ( APIENTRY * qglIndexi )(GLint c); +void ( APIENTRY * qglIndexiv )(const GLint *c); +void ( APIENTRY * qglIndexs )(GLshort c); +void ( APIENTRY * qglIndexsv )(const GLshort *c); +void ( APIENTRY * qglIndexub )(GLubyte c); +void ( APIENTRY * qglIndexubv )(const GLubyte *c); +void ( APIENTRY * qglInitNames )(void); +void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * qglIsList )(GLuint list); +GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +void ( APIENTRY * qglLineWidth )(GLfloat width); +void ( APIENTRY * qglListBase )(GLuint base); +void ( APIENTRY * qglLoadIdentity )(void); +void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +void ( APIENTRY * qglLoadName )(GLuint name); +void ( APIENTRY * qglLogicOp )(GLenum opcode); +void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +void ( APIENTRY * qglMatrixMode )(GLenum mode); +void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +void ( APIENTRY * qglNormal3iv )(const GLint *v); +void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +void ( APIENTRY * qglNormal3sv )(const GLshort *v); +void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +void ( APIENTRY * qglPassThrough )(GLfloat token); +void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +void ( APIENTRY * qglPointSize )(GLfloat size); +void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +void ( APIENTRY * qglPopAttrib )(void); +void ( APIENTRY * qglPopClientAttrib )(void); +void ( APIENTRY * qglPopMatrix )(void); +void ( APIENTRY * qglPopName )(void); +void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushMatrix )(void); +void ( APIENTRY * qglPushName )(GLuint name); +void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +void ( APIENTRY * qglReadBuffer )(GLenum mode); +void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * qglRenderMode )(GLenum mode); +void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +void ( APIENTRY * qglShadeModel )(GLenum mode); +void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +void ( APIENTRY * qglStencilMask )(GLuint mask); +void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +void ( APIENTRY * qglTexCoord1d )(GLdouble s); +void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord1f )(GLfloat s); +void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord1i )(GLint s); +void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +void ( APIENTRY * qglTexCoord1s )(GLshort s); +void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +void ( APIENTRY * qglVertex2iv )(const GLint *v); +void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +void ( APIENTRY * qglVertex2sv )(const GLshort *v); +void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglVertex3iv )(const GLint *v); +void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglVertex3sv )(const GLshort *v); +void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglVertex4iv )(const GLint *v); +void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglVertex4sv )(const GLshort *v); +void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); + +void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); + +void ( APIENTRY * qglActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglClientActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglMultiTexCoord1dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord1dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord1fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord1fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord1iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord1ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord1sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord1svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord2dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord2dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord2fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord2fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord2iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord2ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord2sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord2svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord3dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord3dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord3fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord3fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord3iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord3ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord3sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord3svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord4dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord4dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord4fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord4fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord4iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord4ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord4sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord4svARB) (GLenum target, const GLshort *v); + +extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ) +{ +/* + // initialze the qgl functions + qglAccum = NULL; + qglAlphaFunc = g_QglTable->m_pfn_qglAlphaFunc; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = g_QglTable->m_pfn_qglBegin; + qglBindTexture = g_QglTable->m_pfn_qglBindTexture; + qglBitmap = NULL; + qglBlendFunc = g_QglTable->m_pfn_qglBlendFunc; + qglCallList = g_QglTable->m_pfn_qglCallList; + qglCallLists = g_QglTable->m_pfn_qglCallLists; + qglClear = g_QglTable->m_pfn_qglClear; + qglClearAccum = NULL; + qglClearColor = g_QglTable->m_pfn_qglClearColor; + qglClearDepth = g_QglTable->m_pfn_qglClearDepth; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = g_QglTable->m_pfn_qglColor3f; + qglColor3fv = g_QglTable->m_pfn_qglColor3fv; + qglColor3i = NULL; + qglColor3iv = NULL; + qglColor3s = NULL; + qglColor3sv = NULL; + qglColor3ub = NULL; + qglColor3ubv = NULL; + qglColor3ui = NULL; + qglColor3uiv = NULL; + qglColor3us = NULL; + qglColor3usv = NULL; + qglColor4b = NULL; + qglColor4bv = NULL; + qglColor4d = NULL; + qglColor4dv = NULL; + qglColor4f = g_QglTable->m_pfn_qglColor4f; + qglColor4fv = g_QglTable->m_pfn_qglColor4fv; + qglColor4i = NULL; + qglColor4iv = NULL; + qglColor4s = NULL; + qglColor4sv = NULL; + qglColor4ub = NULL; + qglColor4ubv = NULL; + qglColor4ui = NULL; + qglColor4uiv = NULL; + qglColor4us = NULL; + qglColor4usv = NULL; + qglColorMask = NULL; + qglColorMaterial = NULL; + qglColorPointer = NULL; + qglCopyPixels = NULL; + qglCopyTexImage1D = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage1D = NULL; + qglCopyTexSubImage2D = NULL; + qglCullFace = g_QglTable->m_pfn_qglCullFace; + qglDeleteLists = g_QglTable->m_pfn_qglDeleteLists; + qglDeleteTextures = g_QglTable->m_pfn_qglDeleteTextures; + qglDepthFunc = g_QglTable->m_pfn_qglDepthFunc; + qglDepthMask = g_QglTable->m_pfn_qglDepthMask; + qglDepthRange = NULL; + qglDisable = g_QglTable->m_pfn_qglDisable; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = g_QglTable->m_pfn_qglEnable; + qglEnableClientState = NULL; + qglEnd = g_QglTable->m_pfn_qglEnd; + qglEndList = g_QglTable->m_pfn_qglEndList; + qglEvalCoord1d = NULL; + qglEvalCoord1dv = NULL; + qglEvalCoord1f = NULL; + qglEvalCoord1fv = NULL; + qglEvalCoord2d = NULL; + qglEvalCoord2dv = NULL; + qglEvalCoord2f= NULL; + qglEvalCoord2fv = NULL; + qglEvalMesh1 = NULL; + qglEvalMesh2 = NULL; + qglEvalPoint1 = NULL; + qglEvalPoint2 = NULL; + qglFeedbackBuffer = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglFogf = g_QglTable->m_pfn_qglFogf; + qglFogfv = g_QglTable->m_pfn_qglFogfv; + qglFogi = g_QglTable->m_pfn_qglFogi; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = g_QglTable->m_pfn_qglGenLists; + qglGenTextures = g_QglTable->m_pfn_qglGenTextures; + qglGetBooleanv = NULL; + qglGetClipPlane = NULL; + qglGetDoublev = NULL; + qglGetError = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetLightfv = NULL; + qglGetLightiv = NULL; + qglGetMapdv = NULL; + qglGetMapfv = NULL; + qglGetMapiv = NULL; + qglGetMaterialfv = NULL; + qglGetMaterialiv = NULL; + qglGetPixelMapfv = NULL; + qglGetPixelMapuiv = NULL; + qglGetPixelMapusv = NULL; + qglGetPointerv = NULL; + qglGetPolygonStipple = NULL; + qglGetString = NULL; + qglGetTexEnvfv = NULL; + qglGetTexEnviv = NULL; + qglGetTexGendv = NULL; + qglGetTexGenfv = NULL; + qglGetTexGeniv = NULL; + qglGetTexImage = NULL; + qglGetTexLevelParameterfv = NULL; + qglGetTexLevelParameteriv = NULL; + qglGetTexParameterfv = NULL; + qglGetTexParameteriv = NULL; + qglHint = g_QglTable->m_pfn_qglHint; + qglIndexMask = NULL; + qglIndexPointer = NULL; + qglIndexd = NULL; + qglIndexdv = NULL; + qglIndexf = NULL; + qglIndexfv = NULL; + qglIndexi = NULL; + qglIndexiv = NULL; + qglIndexs = NULL; + qglIndexsv = NULL; + qglIndexub = NULL; + qglIndexubv = NULL; + qglInitNames = NULL; + qglInterleavedArrays = NULL; + qglIsEnabled = NULL; + qglIsList = NULL; + qglIsTexture = NULL; + qglLightModelf = NULL; + qglLightModelfv = NULL; + qglLightModeli = NULL; + qglLightModeliv = NULL; + qglLightf = NULL; + qglLightfv = g_QglTable->m_pfn_qglLightfv; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = g_QglTable->m_pfn_qglLineStipple; + qglLineWidth = g_QglTable->m_pfn_qglLineWidth; + qglListBase = g_QglTable->m_pfn_qglListBase; + qglLoadIdentity = g_QglTable->m_pfn_qglLoadIdentity; + qglLoadMatrixd = NULL; + qglLoadMatrixf = NULL; + qglLoadName = NULL; + qglLogicOp = NULL; + qglMap1d = NULL; + qglMap1f = NULL; + qglMap2d = NULL; + qglMap2f = NULL; + qglMapGrid1d = NULL; + qglMapGrid1f = NULL; + qglMapGrid2d = NULL; + qglMapGrid2f = NULL; + qglMaterialf = g_QglTable->m_pfn_qglMaterialf; + qglMaterialfv = g_QglTable->m_pfn_qglMaterialfv; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = g_QglTable->m_pfn_qglMatrixMode; + qglMultMatrixd = NULL; + qglMultMatrixf = g_QglTable->m_pfn_qglMultMatrixf; + qglNewList = g_QglTable->m_pfn_qglNewList; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = g_QglTable->m_pfn_qglNormal3f; + qglNormal3fv = g_QglTable->m_pfn_qglNormal3fv; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = g_QglTable->m_pfn_qglOrtho; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = g_QglTable->m_pfn_qglPointSize; + qglPolygonMode = g_QglTable->m_pfn_qglPolygonMode; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = g_QglTable->m_pfn_qglPopAttrib; + qglPopClientAttrib = NULL; + qglPopMatrix = g_QglTable->m_pfn_qglPopMatrix; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = g_QglTable->m_pfn_qglPushAttrib; + qglPushClientAttrib = NULL; + qglPushMatrix = g_QglTable->m_pfn_qglPushMatrix; + qglPushName = NULL; + qglRasterPos2d = NULL; + qglRasterPos2dv = NULL; + qglRasterPos2f = NULL; + qglRasterPos2fv = NULL; + qglRasterPos2i = NULL; + qglRasterPos2iv = NULL; + qglRasterPos2s = NULL; + qglRasterPos2sv = NULL; + qglRasterPos3d = NULL; + qglRasterPos3dv = NULL; + qglRasterPos3f = NULL; + qglRasterPos3fv = g_QglTable->m_pfn_qglRasterPos3fv; + qglRasterPos3i = NULL; + qglRasterPos3iv = NULL; + qglRasterPos3s = NULL; + qglRasterPos3sv = NULL; + qglRasterPos4d = NULL; + qglRasterPos4dv = NULL; + qglRasterPos4f = NULL; + qglRasterPos4fv = NULL; + qglRasterPos4i = NULL; + qglRasterPos4iv = NULL; + qglRasterPos4s = NULL; + qglRasterPos4sv = NULL; + qglReadBuffer = NULL; + qglReadPixels = NULL; + qglRectd = NULL; + qglRectdv = NULL; + qglRectf = NULL; + qglRectfv = NULL; + qglRecti = NULL; + qglRectiv = NULL; + qglRects = NULL; + qglRectsv = NULL; + qglRenderMode = NULL; + qglRotated = g_QglTable->m_pfn_qglRotated; + qglRotatef = g_QglTable->m_pfn_qglRotatef; + qglScaled = NULL; + qglScalef = g_QglTable->m_pfn_qglScalef; + qglScissor = g_QglTable->m_pfn_qglScissor; + qglSelectBuffer = NULL; + qglShadeModel = g_QglTable->m_pfn_qglShadeModel; + qglStencilFunc = NULL; + qglStencilMask = NULL; + qglStencilOp = NULL; + qglTexCoord1d = NULL; + qglTexCoord1dv = NULL; + qglTexCoord1f = NULL; + qglTexCoord1fv = NULL; + qglTexCoord1i = NULL; + qglTexCoord1iv = NULL; + qglTexCoord1s = NULL; + qglTexCoord1sv = NULL; + qglTexCoord2d = NULL; + qglTexCoord2dv = NULL; + qglTexCoord2f = g_QglTable->m_pfn_qglTexCoord2f; + qglTexCoord2fv = g_QglTable->m_pfn_qglTexCoord2fv; + qglTexCoord2i = NULL; + qglTexCoord2iv = NULL; + qglTexCoord2s = NULL; + qglTexCoord2sv = NULL; + qglTexCoord3d = NULL; + qglTexCoord3dv = NULL; + qglTexCoord3f = NULL; + qglTexCoord3fv = NULL; + qglTexCoord3i = NULL; + qglTexCoord3iv = NULL; + qglTexCoord3s = NULL; + qglTexCoord3sv = NULL; + qglTexCoord4d = NULL; + qglTexCoord4dv = NULL; + qglTexCoord4f = NULL; + qglTexCoord4fv = NULL; + qglTexCoord4i = NULL; + qglTexCoord4iv = NULL; + qglTexCoord4s = NULL; + qglTexCoord4sv = NULL; + qglTexCoordPointer = NULL; + qglTexEnvf = g_QglTable->m_pfn_qglTexEnvf; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = g_QglTable->m_pfn_qglTexGenf; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = g_QglTable->m_pfn_qglTexImage1D; + qglTexImage2D = g_QglTable->m_pfn_qglTexImage2D; + qglTexParameterf = g_QglTable->m_pfn_qglTexParameterf; + qglTexParameterfv = g_QglTable->m_pfn_qglTexParameterfv; + qglTexParameteri = g_QglTable->m_pfn_qglTexParameteri; + qglTexParameteriv = g_QglTable->m_pfn_qglTexParameteriv; + qglTexSubImage1D = g_QglTable->m_pfn_qglTexSubImage1D; + qglTexSubImage2D = g_QglTable->m_pfn_qglTexSubImage2D; + qglTranslated = g_QglTable->m_pfn_qglTranslated; + qglTranslatef = g_QglTable->m_pfn_qglTranslatef; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = g_QglTable->m_pfn_qglVertex2f; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = g_QglTable->m_pfn_qglVertex3f; + qglVertex3fv = g_QglTable->m_pfn_qglVertex3fv; + qglVertex3i = NULL; + qglVertex3iv = NULL; + qglVertex3s = NULL; + qglVertex3sv = NULL; + qglVertex4d = NULL; + qglVertex4dv = NULL; + qglVertex4f = NULL; + qglVertex4fv = NULL; + qglVertex4i = NULL; + qglVertex4iv = NULL; + qglVertex4s = NULL; + qglVertex4sv = NULL; + qglVertexPointer = NULL; + qglViewport = g_QglTable->m_pfn_qglViewport; + + qglPointParameterfEXT = NULL; + qglPointParameterfvEXT = NULL; + qglColorTableEXT = NULL; + + qglMTexCoord2fSGIS = NULL; + qglSelectTextureSGIS = NULL; + + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + qglMultiTexCoord1dARB = NULL; + qglMultiTexCoord1dvARB = NULL; + qglMultiTexCoord1fARB = NULL; + qglMultiTexCoord1fvARB = NULL; + qglMultiTexCoord1iARB = NULL; + qglMultiTexCoord1ivARB = NULL; + qglMultiTexCoord1sARB = NULL; + qglMultiTexCoord1svARB = NULL; + qglMultiTexCoord2dARB = NULL; + qglMultiTexCoord2dvARB = NULL; + qglMultiTexCoord2fARB = NULL; + qglMultiTexCoord2fvARB = NULL; + qglMultiTexCoord2iARB = NULL; + qglMultiTexCoord2ivARB = NULL; + qglMultiTexCoord2sARB = NULL; + qglMultiTexCoord2svARB = NULL; + qglMultiTexCoord3dARB = NULL; + qglMultiTexCoord3dvARB = NULL; + qglMultiTexCoord3fARB = NULL; + qglMultiTexCoord3fvARB = NULL; + qglMultiTexCoord3iARB = NULL; + qglMultiTexCoord3ivARB = NULL; + qglMultiTexCoord3sARB = NULL; + qglMultiTexCoord3svARB = NULL; + qglMultiTexCoord4dARB = NULL; + qglMultiTexCoord4dvARB = NULL; + qglMultiTexCoord4fARB = NULL; + qglMultiTexCoord4fvARB = NULL; + qglMultiTexCoord4iARB = NULL; + qglMultiTexCoord4ivARB = NULL; + qglMultiTexCoord4sARB = NULL; + qglMultiTexCoord4svARB = NULL; +*/ +} + +#endif // _IGL_TO_QGL_H_ diff --git a/libs/l_net/l_net.c b/libs/l_net/l_net.c index fed856b5..9ead6652 100644 --- a/libs/l_net/l_net.c +++ b/libs/l_net/l_net.c @@ -1,627 +1,627 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//==================================================================== -// -// Name: l_net.c -// Function: - -// Programmer: MrElusive -// Last update: - -// Tab size: 3 -// Notes: -//==================================================================== - -#include -#include -#include -#include -#include "l_net.h" -#include "l_net_wins.h" - -#define GetMemory malloc -#define FreeMemory free - -#define qtrue 1 -#define qfalse 0 - -#ifdef _DEBUG -void WinPrint(char *str, ...) -{ - va_list argptr; - char text[4096]; - - va_start (argptr,str); - vsprintf (text, str, argptr); - va_end (argptr); - - printf(text); -} -#else -void WinPrint(char *str, ...) -{ -} -#endif - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Net_SetAddressPort(address_t *address, int port) -{ - sockaddr_t addr; - - WINS_StringToAddr(address->ip, &addr); - WINS_SetSocketPort(&addr, port); - strcpy(address->ip, WINS_AddrToString(&addr)); -} //end of the function Net_SetAddressPort -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Net_AddressCompare(address_t *addr1, address_t *addr2) -{ -#ifdef _WIN32 - return stricmp(addr1->ip, addr2->ip); -#endif -#ifdef __linux__ - return strcasecmp(addr1->ip, addr2->ip); -#endif -} //end of the function Net_AddressCompare -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Net_SocketToAddress(socket_t *sock, address_t *address) -{ - strcpy(address->ip, WINS_AddrToString(&sock->addr)); -} //end of the function Net_SocketToAddress -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Net_Send(socket_t *sock, netmessage_t *msg) -{ - int size; - - size = msg->size; - msg->size = 0; - NMSG_WriteLong(msg, size-4); - msg->size = size; - //WinPrint("Net_Send: message of size %d\n", sendmsg.size); - return WINS_Write(sock->socket, msg->data, msg->size, NULL); -} //end of the function Net_SendSocketReliable -//=========================================================================== -// returns the number of bytes recieved -// -1 on error -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Net_Receive(socket_t *sock, netmessage_t *msg) -{ - int curread; - - if (sock->remaining > 0) - { - curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); - if (curread == -1) - { - WinPrint("Net_Receive: read error\n"); - return -1; - } //end if - sock->remaining -= curread; - sock->msg.size += curread; - if (sock->remaining <= 0) - { - sock->remaining = 0; - memcpy(msg, &sock->msg, sizeof(netmessage_t)); - sock->msg.size = 0; - return msg->size - 4; - } //end if - return 0; - } //end if - sock->msg.size = WINS_Read(sock->socket, sock->msg.data, 4, NULL); - if (sock->msg.size == 0) return 0; - if (sock->msg.size == -1) - { - WinPrint("Net_Receive: size header read error\n"); - return -1; - } //end if - //WinPrint("Net_Receive: message size header %d\n", msg->size); - sock->msg.read = 0; - sock->remaining = NMSG_ReadLong(&sock->msg); - if (sock->remaining == 0) return 0; - if (sock->remaining < 0 || sock->remaining > MAX_NETMESSAGE) - { - WinPrint("Net_Receive: invalid message size %d\n", sock->remaining); - return -1; - } //end if - //try to read the message - curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); - if (curread == -1) - { - WinPrint("Net_Receive: read error\n"); - return -1; - } //end if - sock->remaining -= curread; - sock->msg.size += curread; - if (sock->remaining <= 0) - { - sock->remaining = 0; - memcpy(msg, &sock->msg, sizeof(netmessage_t)); - sock->msg.size = 0; - return msg->size - 4; - } //end if - //the message has not been completely read yet -#ifdef _DEBUG - printf("++timo TODO: debug the Net_Receive on big size messages\n"); -#endif - return 0; -} //end of the function Net_Receive -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -socket_t *Net_AllocSocket(void) -{ - socket_t *sock; - - sock = (socket_t *) GetMemory(sizeof(socket_t)); - memset(sock, 0, sizeof(socket_t)); - return sock; -} //end of the function Net_AllocSocket -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Net_FreeSocket(socket_t *sock) -{ - FreeMemory(sock); -} //end of the function Net_FreeSocket -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -socket_t *Net_Connect(address_t *address, int port) -{ - int newsock; - socket_t *sock; - sockaddr_t sendaddr; - - // see if we can resolve the host name - WINS_StringToAddr(address->ip, &sendaddr); - - newsock = WINS_OpenReliableSocket(port); - if (newsock == -1) return NULL; - - sock = Net_AllocSocket(); - if (sock == NULL) - { - WINS_CloseSocket(newsock); - return NULL; - } //end if - sock->socket = newsock; - - //connect to the host - if (WINS_Connect(newsock, &sendaddr) == -1) - { - Net_FreeSocket(sock); - WINS_CloseSocket(newsock); - WinPrint("Net_Connect: error connecting\n"); - return NULL; - } //end if - - memcpy(&sock->addr, &sendaddr, sizeof(sockaddr_t)); - //now we can send messages - // - return sock; -} //end of the function Net_Connect - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -socket_t *Net_ListenSocket(int port) -{ - int newsock; - socket_t *sock; - - newsock = WINS_OpenReliableSocket(port); - if (newsock == -1) return NULL; - - if (WINS_Listen(newsock) == -1) - { - WINS_CloseSocket(newsock); - return NULL; - } //end if - sock = Net_AllocSocket(); - if (sock == NULL) - { - WINS_CloseSocket(newsock); - return NULL; - } //end if - sock->socket = newsock; - WINS_GetSocketAddr(newsock, &sock->addr); - WinPrint("listen socket opened at %s\n", WINS_AddrToString(&sock->addr)); - // - return sock; -} //end of the function Net_ListenSocket -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -socket_t *Net_Accept(socket_t *sock) -{ - int newsocket; - sockaddr_t sendaddr; - socket_t *newsock; - - newsocket = WINS_Accept(sock->socket, &sendaddr); - if (newsocket == -1) return NULL; - - newsock = Net_AllocSocket(); - if (newsock == NULL) - { - WINS_CloseSocket(newsocket); - return NULL; - } //end if - newsock->socket = newsocket; - memcpy(&newsock->addr, &sendaddr, sizeof(sockaddr_t)); - // - return newsock; -} //end of the function Net_Accept -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Net_Disconnect(socket_t *sock) -{ - WINS_CloseSocket(sock->socket); - Net_FreeSocket(sock); -} //end of the function Net_Disconnect -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Net_StringToAddress(char *string, address_t *address) -{ - strcpy(address->ip, string); -} //end of the function Net_StringToAddress -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Net_MyAddress(address_t *address) -{ - strcpy(address->ip, WINS_MyAddress()); -} //end of the function Net_MyAddress -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int Net_Setup(void) -{ - WINS_Init(); - // - WinPrint("my address is %s\n", WINS_MyAddress()); - // - return qtrue; -} //end of the function Net_Setup -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void Net_Shutdown(void) -{ - WINS_Shutdown(); -} //end of the function Net_Shutdown -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_Clear(netmessage_t *msg) -{ - msg->size = 4; -} //end of the function NMSG_Clear -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_WriteChar (netmessage_t *msg, int c) -{ - if (c < -128 || c > 127) - WinPrint("NMSG_WriteChar: range error\n"); - - if (msg->size >= MAX_NETMESSAGE) - { - WinPrint("NMSG_WriteChar: overflow\n"); - return; - } //end if - msg->data[msg->size] = c; - msg->size++; -} //end of the function NMSG_WriteChar -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_WriteByte(netmessage_t *msg, int c) -{ - if (c < -128 || c > 127) - WinPrint("NMSG_WriteByte: range error\n"); - - if (msg->size + 1 >= MAX_NETMESSAGE) - { - WinPrint("NMSG_WriteByte: overflow\n"); - return; - } //end if - msg->data[msg->size] = c; - msg->size++; -} //end of the function NMSG_WriteByte -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_WriteShort(netmessage_t *msg, int c) -{ - if (c < ((short)0x8000) || c > (short)0x7fff) - WinPrint("NMSG_WriteShort: range error"); - - if (msg->size + 2 >= MAX_NETMESSAGE) - { - WinPrint("NMSG_WriteShort: overflow\n"); - return; - } //end if - msg->data[msg->size] = c&0xff; - msg->data[msg->size+1] = c>>8; - msg->size += 2; -} //end of the function NMSG_WriteShort -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_WriteLong(netmessage_t *msg, int c) -{ - if (msg->size + 4 >= MAX_NETMESSAGE) - { - WinPrint("NMSG_WriteLong: overflow\n"); - return; - } //end if - msg->data[msg->size] = c&0xff; - msg->data[msg->size+1] = (c>>8)&0xff; - msg->data[msg->size+2] = (c>>16)&0xff; - msg->data[msg->size+3] = c>>24; - msg->size += 4; -} //end of the function NMSG_WriteLong -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_WriteFloat(netmessage_t *msg, float c) -{ - if (msg->size + 4 >= MAX_NETMESSAGE) - { - WinPrint("NMSG_WriteLong: overflow\n"); - return; - } //end if - msg->data[msg->size] = *((int *)&c)&0xff; - msg->data[msg->size+1] = (*((int *)&c)>>8)&0xff; - msg->data[msg->size+2] = (*((int *)&c)>>16)&0xff; - msg->data[msg->size+3] = *((int *)&c)>>24; - msg->size += 4; -} //end of the function NMSG_WriteFloat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_WriteString(netmessage_t *msg, char *string) -{ - if (msg->size + strlen(string) + 1 >= MAX_NETMESSAGE) - { - WinPrint("NMSG_WriteString: overflow\n"); - return; - } //end if - strcpy(&msg->data[msg->size], string); - msg->size += strlen(string) + 1; -} //end of the function NMSG_WriteString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void NMSG_ReadStart(netmessage_t *msg) -{ - msg->readoverflow = qfalse; - msg->read = 4; -} //end of the function NMSG_ReadStart -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int NMSG_ReadChar(netmessage_t *msg) -{ - if (msg->size + 1 > msg->size) - { - msg->readoverflow = qtrue; - WinPrint("NMSG_ReadChar: read overflow\n"); - return 0; - } //end if - msg->read++; - return msg->data[msg->read-1]; -} //end of the function NMSG_ReadChar -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int NMSG_ReadByte(netmessage_t *msg) -{ - if (msg->read + 1 > msg->size) - { - msg->readoverflow = qtrue; - WinPrint("NMSG_ReadByte: read overflow\n"); - return 0; - } //end if - msg->read++; - return msg->data[msg->read-1]; -} //end of the function NMSG_ReadByte -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int NMSG_ReadShort(netmessage_t *msg) -{ - int c; - - if (msg->read + 2 > msg->size) - { - msg->readoverflow = qtrue; - WinPrint("NMSG_ReadShort: read overflow\n"); - return 0; - } //end if - c = (short)(msg->data[msg->read] + (msg->data[msg->read+1]<<8)); - msg->read += 2; - return c; -} //end of the function NMSG_ReadShort -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int NMSG_ReadLong(netmessage_t *msg) -{ - int c; - - if (msg->read + 4 > msg->size) - { - msg->readoverflow = qtrue; - WinPrint("NMSG_ReadLong: read overflow\n"); - return 0; - } //end if - c = msg->data[msg->read] - + (msg->data[msg->read+1]<<8) - + (msg->data[msg->read+2]<<16) - + (msg->data[msg->read+3]<<24); - msg->read += 4; - return c; -} //end of the function NMSG_ReadLong -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -float NMSG_ReadFloat(netmessage_t *msg) -{ - int c; - - if (msg->read + 4 > msg->size) - { - msg->readoverflow = qtrue; - WinPrint("NMSG_ReadLong: read overflow\n"); - return 0; - } //end if - c = msg->data[msg->read] - + (msg->data[msg->read+1]<<8) - + (msg->data[msg->read+2]<<16) - + (msg->data[msg->read+3]<<24); - msg->read += 4; - return *(float *)&c; -} //end of the function NMSG_ReadFloat -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *NMSG_ReadString(netmessage_t *msg) -{ - static char string[2048]; - int l, c; - - l = 0; - do - { - if (msg->read + 1 > msg->size) - { - msg->readoverflow = qtrue; - WinPrint("NMSG_ReadString: read overflow\n"); - string[l] = 0; - return string; - } //end if - c = msg->data[msg->read]; - msg->read++; - if (c == 0) break; - string[l] = c; - l++; - } while (l < sizeof(string)-1); - string[l] = 0; - return string; -} //end of the function NMSG_ReadString +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//==================================================================== +// +// Name: l_net.c +// Function: - +// Programmer: MrElusive +// Last update: - +// Tab size: 3 +// Notes: +//==================================================================== + +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" + +#define GetMemory malloc +#define FreeMemory free + +#define qtrue 1 +#define qfalse 0 + +#ifdef _DEBUG +void WinPrint(char *str, ...) +{ + va_list argptr; + char text[4096]; + + va_start (argptr,str); + vsprintf (text, str, argptr); + va_end (argptr); + + printf(text); +} +#else +void WinPrint(char *str, ...) +{ +} +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_SetAddressPort(address_t *address, int port) +{ + sockaddr_t addr; + + WINS_StringToAddr(address->ip, &addr); + WINS_SetSocketPort(&addr, port); + strcpy(address->ip, WINS_AddrToString(&addr)); +} //end of the function Net_SetAddressPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_AddressCompare(address_t *addr1, address_t *addr2) +{ +#ifdef _WIN32 + return stricmp(addr1->ip, addr2->ip); +#endif +#ifdef __linux__ + return strcasecmp(addr1->ip, addr2->ip); +#endif +} //end of the function Net_AddressCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_SocketToAddress(socket_t *sock, address_t *address) +{ + strcpy(address->ip, WINS_AddrToString(&sock->addr)); +} //end of the function Net_SocketToAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Send(socket_t *sock, netmessage_t *msg) +{ + int size; + + size = msg->size; + msg->size = 0; + NMSG_WriteLong(msg, size-4); + msg->size = size; + //WinPrint("Net_Send: message of size %d\n", sendmsg.size); + return WINS_Write(sock->socket, msg->data, msg->size, NULL); +} //end of the function Net_SendSocketReliable +//=========================================================================== +// returns the number of bytes recieved +// -1 on error +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Receive(socket_t *sock, netmessage_t *msg) +{ + int curread; + + if (sock->remaining > 0) + { + curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); + if (curread == -1) + { + WinPrint("Net_Receive: read error\n"); + return -1; + } //end if + sock->remaining -= curread; + sock->msg.size += curread; + if (sock->remaining <= 0) + { + sock->remaining = 0; + memcpy(msg, &sock->msg, sizeof(netmessage_t)); + sock->msg.size = 0; + return msg->size - 4; + } //end if + return 0; + } //end if + sock->msg.size = WINS_Read(sock->socket, sock->msg.data, 4, NULL); + if (sock->msg.size == 0) return 0; + if (sock->msg.size == -1) + { + WinPrint("Net_Receive: size header read error\n"); + return -1; + } //end if + //WinPrint("Net_Receive: message size header %d\n", msg->size); + sock->msg.read = 0; + sock->remaining = NMSG_ReadLong(&sock->msg); + if (sock->remaining == 0) return 0; + if (sock->remaining < 0 || sock->remaining > MAX_NETMESSAGE) + { + WinPrint("Net_Receive: invalid message size %d\n", sock->remaining); + return -1; + } //end if + //try to read the message + curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); + if (curread == -1) + { + WinPrint("Net_Receive: read error\n"); + return -1; + } //end if + sock->remaining -= curread; + sock->msg.size += curread; + if (sock->remaining <= 0) + { + sock->remaining = 0; + memcpy(msg, &sock->msg, sizeof(netmessage_t)); + sock->msg.size = 0; + return msg->size - 4; + } //end if + //the message has not been completely read yet +#ifdef _DEBUG + printf("++timo TODO: debug the Net_Receive on big size messages\n"); +#endif + return 0; +} //end of the function Net_Receive +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_AllocSocket(void) +{ + socket_t *sock; + + sock = (socket_t *) GetMemory(sizeof(socket_t)); + memset(sock, 0, sizeof(socket_t)); + return sock; +} //end of the function Net_AllocSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_FreeSocket(socket_t *sock) +{ + FreeMemory(sock); +} //end of the function Net_FreeSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_Connect(address_t *address, int port) +{ + int newsock; + socket_t *sock; + sockaddr_t sendaddr; + + // see if we can resolve the host name + WINS_StringToAddr(address->ip, &sendaddr); + + newsock = WINS_OpenReliableSocket(port); + if (newsock == -1) return NULL; + + sock = Net_AllocSocket(); + if (sock == NULL) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock->socket = newsock; + + //connect to the host + if (WINS_Connect(newsock, &sendaddr) == -1) + { + Net_FreeSocket(sock); + WINS_CloseSocket(newsock); + WinPrint("Net_Connect: error connecting\n"); + return NULL; + } //end if + + memcpy(&sock->addr, &sendaddr, sizeof(sockaddr_t)); + //now we can send messages + // + return sock; +} //end of the function Net_Connect + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_ListenSocket(int port) +{ + int newsock; + socket_t *sock; + + newsock = WINS_OpenReliableSocket(port); + if (newsock == -1) return NULL; + + if (WINS_Listen(newsock) == -1) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock = Net_AllocSocket(); + if (sock == NULL) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock->socket = newsock; + WINS_GetSocketAddr(newsock, &sock->addr); + WinPrint("listen socket opened at %s\n", WINS_AddrToString(&sock->addr)); + // + return sock; +} //end of the function Net_ListenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_Accept(socket_t *sock) +{ + int newsocket; + sockaddr_t sendaddr; + socket_t *newsock; + + newsocket = WINS_Accept(sock->socket, &sendaddr); + if (newsocket == -1) return NULL; + + newsock = Net_AllocSocket(); + if (newsock == NULL) + { + WINS_CloseSocket(newsocket); + return NULL; + } //end if + newsock->socket = newsocket; + memcpy(&newsock->addr, &sendaddr, sizeof(sockaddr_t)); + // + return newsock; +} //end of the function Net_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_Disconnect(socket_t *sock) +{ + WINS_CloseSocket(sock->socket); + Net_FreeSocket(sock); +} //end of the function Net_Disconnect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_StringToAddress(char *string, address_t *address) +{ + strcpy(address->ip, string); +} //end of the function Net_StringToAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_MyAddress(address_t *address) +{ + strcpy(address->ip, WINS_MyAddress()); +} //end of the function Net_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Setup(void) +{ + WINS_Init(); + // + WinPrint("my address is %s\n", WINS_MyAddress()); + // + return qtrue; +} //end of the function Net_Setup +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_Shutdown(void) +{ + WINS_Shutdown(); +} //end of the function Net_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_Clear(netmessage_t *msg) +{ + msg->size = 4; +} //end of the function NMSG_Clear +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteChar (netmessage_t *msg, int c) +{ + if (c < -128 || c > 127) + WinPrint("NMSG_WriteChar: range error\n"); + + if (msg->size >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteChar: overflow\n"); + return; + } //end if + msg->data[msg->size] = c; + msg->size++; +} //end of the function NMSG_WriteChar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteByte(netmessage_t *msg, int c) +{ + if (c < -128 || c > 127) + WinPrint("NMSG_WriteByte: range error\n"); + + if (msg->size + 1 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteByte: overflow\n"); + return; + } //end if + msg->data[msg->size] = c; + msg->size++; +} //end of the function NMSG_WriteByte +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteShort(netmessage_t *msg, int c) +{ + if (c < ((short)0x8000) || c > (short)0x7fff) + WinPrint("NMSG_WriteShort: range error"); + + if (msg->size + 2 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteShort: overflow\n"); + return; + } //end if + msg->data[msg->size] = c&0xff; + msg->data[msg->size+1] = c>>8; + msg->size += 2; +} //end of the function NMSG_WriteShort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteLong(netmessage_t *msg, int c) +{ + if (msg->size + 4 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteLong: overflow\n"); + return; + } //end if + msg->data[msg->size] = c&0xff; + msg->data[msg->size+1] = (c>>8)&0xff; + msg->data[msg->size+2] = (c>>16)&0xff; + msg->data[msg->size+3] = c>>24; + msg->size += 4; +} //end of the function NMSG_WriteLong +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteFloat(netmessage_t *msg, float c) +{ + if (msg->size + 4 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteLong: overflow\n"); + return; + } //end if + msg->data[msg->size] = *((int *)&c)&0xff; + msg->data[msg->size+1] = (*((int *)&c)>>8)&0xff; + msg->data[msg->size+2] = (*((int *)&c)>>16)&0xff; + msg->data[msg->size+3] = *((int *)&c)>>24; + msg->size += 4; +} //end of the function NMSG_WriteFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteString(netmessage_t *msg, char *string) +{ + if (msg->size + strlen(string) + 1 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteString: overflow\n"); + return; + } //end if + strcpy(&msg->data[msg->size], string); + msg->size += strlen(string) + 1; +} //end of the function NMSG_WriteString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_ReadStart(netmessage_t *msg) +{ + msg->readoverflow = qfalse; + msg->read = 4; +} //end of the function NMSG_ReadStart +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadChar(netmessage_t *msg) +{ + if (msg->size + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadChar: read overflow\n"); + return 0; + } //end if + msg->read++; + return msg->data[msg->read-1]; +} //end of the function NMSG_ReadChar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadByte(netmessage_t *msg) +{ + if (msg->read + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadByte: read overflow\n"); + return 0; + } //end if + msg->read++; + return msg->data[msg->read-1]; +} //end of the function NMSG_ReadByte +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadShort(netmessage_t *msg) +{ + int c; + + if (msg->read + 2 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadShort: read overflow\n"); + return 0; + } //end if + c = (short)(msg->data[msg->read] + (msg->data[msg->read+1]<<8)); + msg->read += 2; + return c; +} //end of the function NMSG_ReadShort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadLong(netmessage_t *msg) +{ + int c; + + if (msg->read + 4 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadLong: read overflow\n"); + return 0; + } //end if + c = msg->data[msg->read] + + (msg->data[msg->read+1]<<8) + + (msg->data[msg->read+2]<<16) + + (msg->data[msg->read+3]<<24); + msg->read += 4; + return c; +} //end of the function NMSG_ReadLong +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float NMSG_ReadFloat(netmessage_t *msg) +{ + int c; + + if (msg->read + 4 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadLong: read overflow\n"); + return 0; + } //end if + c = msg->data[msg->read] + + (msg->data[msg->read+1]<<8) + + (msg->data[msg->read+2]<<16) + + (msg->data[msg->read+3]<<24); + msg->read += 4; + return *(float *)&c; +} //end of the function NMSG_ReadFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *NMSG_ReadString(netmessage_t *msg) +{ + static char string[2048]; + int l, c; + + l = 0; + do + { + if (msg->read + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadString: read overflow\n"); + string[l] = 0; + return string; + } //end if + c = msg->data[msg->read]; + msg->read++; + if (c == 0) break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + string[l] = 0; + return string; +} //end of the function NMSG_ReadString diff --git a/libs/l_net/l_net.h b/libs/l_net/l_net.h index dd27d38b..167a5a36 100644 --- a/libs/l_net/l_net.h +++ b/libs/l_net/l_net.h @@ -1,125 +1,125 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//==================================================================== -// -// Name: l_net.h -// Function: - -// Programmer: MrElusive -// Last update: TTimo: cross-platform version, l_net library -// Tab size: 2 -// Notes: -//==================================================================== - -//++timo FIXME: the l_net code understands that as the max size for the netmessage_s structure -// we have defined unsigned char data[MAX_NETMESSAGE] in netmessage_s but actually it cannot be filled completely -// we need to introduce a new #define and adapt to data[MAX_NETBUFFER] -#define MAX_NETMESSAGE 1024 -#define MAX_NETADDRESS 32 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __BYTEBOOL__ -#define __BYTEBOOL__ -typedef enum { qfalse, qtrue } qboolean; -typedef unsigned char byte; -#endif - -typedef struct address_s -{ - char ip[MAX_NETADDRESS]; -} address_t; - -typedef struct sockaddr_s -{ - short sa_family; - unsigned char sa_data[14]; -} sockaddr_t; - -typedef struct netmessage_s -{ - unsigned char data[MAX_NETMESSAGE]; - int size; - int read; - int readoverflow; -} netmessage_t; - -typedef struct socket_s -{ - int socket; //socket number - sockaddr_t addr; //socket address - netmessage_t msg; //current message being read - int remaining; //remaining bytes to read for the current message - struct socket_s *prev, *next; //prev and next socket in a list -} socket_t; - -//compare addresses -int Net_AddressCompare(address_t *addr1, address_t *addr2); -//gives the address of a socket -void Net_SocketToAddress(socket_t *sock, address_t *address); -//converts a string to an address -void Net_StringToAddress(char *string, address_t *address); -//set the address ip port -void Net_SetAddressPort(address_t *address, int port); -//send a message to the given socket -int Net_Send(socket_t *sock, netmessage_t *msg); -//recieve a message from the given socket -int Net_Receive(socket_t *sock, netmessage_t *msg); -//connect to a host -// NOTE: port is the localhost port, usually 0 -// ex: Net_Connect( "192.168.0.1:39000", 0 ) -socket_t *Net_Connect(address_t *address, int port); -//disconnect from a host -void Net_Disconnect(socket_t *sock); -//returns the local address -void Net_MyAddress(address_t *address); -//listen at the given port -socket_t *Net_ListenSocket(int port); -//accept new connections at the given socket -socket_t *Net_Accept(socket_t *sock); -//setup networking -int Net_Setup(void); -//shutdown networking -void Net_Shutdown(void); -//message handling -void NMSG_Clear(netmessage_t *msg); -void NMSG_WriteChar(netmessage_t *msg, int c); -void NMSG_WriteByte(netmessage_t *msg, int c); -void NMSG_WriteShort(netmessage_t *msg, int c); -void NMSG_WriteLong(netmessage_t *msg, int c); -void NMSG_WriteFloat(netmessage_t *msg, float c); -void NMSG_WriteString(netmessage_t *msg, char *string); -void NMSG_ReadStart(netmessage_t *msg); -int NMSG_ReadChar(netmessage_t *msg); -int NMSG_ReadByte(netmessage_t *msg); -int NMSG_ReadShort(netmessage_t *msg); -int NMSG_ReadLong(netmessage_t *msg); -float NMSG_ReadFloat(netmessage_t *msg); -char *NMSG_ReadString(netmessage_t *msg); - -//++timo FIXME: the WINS_ things are not necessary, they can be made portable arther easily -char *WINS_ErrorMessage(int error); - -#ifdef __cplusplus -} -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//==================================================================== +// +// Name: l_net.h +// Function: - +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab size: 2 +// Notes: +//==================================================================== + +//++timo FIXME: the l_net code understands that as the max size for the netmessage_s structure +// we have defined unsigned char data[MAX_NETMESSAGE] in netmessage_s but actually it cannot be filled completely +// we need to introduce a new #define and adapt to data[MAX_NETBUFFER] +#define MAX_NETMESSAGE 1024 +#define MAX_NETADDRESS 32 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +typedef enum { qfalse, qtrue } qboolean; +typedef unsigned char byte; +#endif + +typedef struct address_s +{ + char ip[MAX_NETADDRESS]; +} address_t; + +typedef struct sockaddr_s +{ + short sa_family; + unsigned char sa_data[14]; +} sockaddr_t; + +typedef struct netmessage_s +{ + unsigned char data[MAX_NETMESSAGE]; + int size; + int read; + int readoverflow; +} netmessage_t; + +typedef struct socket_s +{ + int socket; //socket number + sockaddr_t addr; //socket address + netmessage_t msg; //current message being read + int remaining; //remaining bytes to read for the current message + struct socket_s *prev, *next; //prev and next socket in a list +} socket_t; + +//compare addresses +int Net_AddressCompare(address_t *addr1, address_t *addr2); +//gives the address of a socket +void Net_SocketToAddress(socket_t *sock, address_t *address); +//converts a string to an address +void Net_StringToAddress(char *string, address_t *address); +//set the address ip port +void Net_SetAddressPort(address_t *address, int port); +//send a message to the given socket +int Net_Send(socket_t *sock, netmessage_t *msg); +//recieve a message from the given socket +int Net_Receive(socket_t *sock, netmessage_t *msg); +//connect to a host +// NOTE: port is the localhost port, usually 0 +// ex: Net_Connect( "192.168.0.1:39000", 0 ) +socket_t *Net_Connect(address_t *address, int port); +//disconnect from a host +void Net_Disconnect(socket_t *sock); +//returns the local address +void Net_MyAddress(address_t *address); +//listen at the given port +socket_t *Net_ListenSocket(int port); +//accept new connections at the given socket +socket_t *Net_Accept(socket_t *sock); +//setup networking +int Net_Setup(void); +//shutdown networking +void Net_Shutdown(void); +//message handling +void NMSG_Clear(netmessage_t *msg); +void NMSG_WriteChar(netmessage_t *msg, int c); +void NMSG_WriteByte(netmessage_t *msg, int c); +void NMSG_WriteShort(netmessage_t *msg, int c); +void NMSG_WriteLong(netmessage_t *msg, int c); +void NMSG_WriteFloat(netmessage_t *msg, float c); +void NMSG_WriteString(netmessage_t *msg, char *string); +void NMSG_ReadStart(netmessage_t *msg); +int NMSG_ReadChar(netmessage_t *msg); +int NMSG_ReadByte(netmessage_t *msg); +int NMSG_ReadShort(netmessage_t *msg); +int NMSG_ReadLong(netmessage_t *msg); +float NMSG_ReadFloat(netmessage_t *msg); +char *NMSG_ReadString(netmessage_t *msg); + +//++timo FIXME: the WINS_ things are not necessary, they can be made portable arther easily +char *WINS_ErrorMessage(int error); + +#ifdef __cplusplus +} +#endif diff --git a/libs/l_net/l_net_berkeley.c b/libs/l_net/l_net_berkeley.c index 60912aee..2d4d33bc 100644 --- a/libs/l_net/l_net_berkeley.c +++ b/libs/l_net/l_net_berkeley.c @@ -1,770 +1,770 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//=========================================================================== -// -// Name: l_net_wins.c -// Function: WinSock -// Programmer: MrElusive -// Last update: TTimo: cross-platform version, l_net library -// Tab Size: 2 -// Notes: -//=========================================================================== - -//#include -#include -#include -#include -#include -#include "l_net.h" -#include "l_net_wins.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#define SOCKET_ERROR -1 -#define INVALID_SOCKET -1 - -extern void WinPrint(char *str, ...); - -#define WinError WinPrint - -#define qtrue 1 -#define qfalse 0 - -#define ioctlsocket ioctl -#define closesocket close - -int WSAGetLastError() -{ - return errno; -} - -/* -typedef struct tag_error_struct -{ - int errnum; - LPSTR errstr; -} ERROR_STRUCT; -*/ - -typedef struct tag_error_struct -{ - int errnum; - const char *errstr; -} ERROR_STRUCT; - -#define NET_NAMELEN 64 - -static char my_tcpip_address[NET_NAMELEN]; - -#define DEFAULTnet_hostport 26000 - -#define MAXHOSTNAMELEN 256 - -static int net_acceptsocket = -1; // socket for fielding new connections -static int net_controlsocket; -static int net_hostport; // udp port number for acceptsocket -static int net_broadcastsocket = 0; -//static qboolean ifbcastinit = qfalse; -//static struct sockaddr_s broadcastaddr; -static struct sockaddr_s broadcastaddr; - -static unsigned long myAddr; - -ERROR_STRUCT errlist[] = { - {EACCES,"EACCES - The address is protected, user is not root"}, - {EAGAIN,"EAGAIN - Operation on non-blocking socket that cannot return immediatly"}, - {EBADF, "EBADF - sockfd is not a valid descriptor"}, - {EFAULT, "EFAULT - The parameter is not in a writable part of the user address space"}, - {EINVAL,"EINVAL - The socket is already bound to an address"}, - {ENOBUFS,"ENOBUFS - not enough memory"}, - {ENOMEM, "ENOMEM - not enough memory"}, - {ENOTCONN, "ENOTCONN - not connected"}, - {ENOTSOCK,"ENOTSOCK - Argument is file descriptor not a socket"}, - {EOPNOTSUPP,"ENOTSUPP - The referenced socket is not of type SOCK_STREAM"}, - {EPERM, "EPERM - Firewall rules forbid connection"}, - {-1, NULL} -}; - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *WINS_ErrorMessage(int error) -{ - int search = 0; - - if (!error) return "No error occurred"; - - for (search = 0; errlist[search].errstr; search++) - { - if (error == errlist[search].errnum) - return (char *)errlist[search].errstr; - } //end for - - return "Unknown error"; -} //end of the function WINS_ErrorMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Init(void) -{ - int i; - struct hostent *local; - char buff[MAXHOSTNAMELEN]; - struct sockaddr_s addr; - char *p; - int r; -/* - linux doesn't have anything to initialize for the net - "Windows .. built for the internet .. the internet .. built with unix" - */ -#if 0 - WORD wVersionRequested; - - wVersionRequested = MAKEWORD(2, 2); - - r = WSAStartup (wVersionRequested, &winsockdata); - - if (r) - { - WinPrint("Winsock initialization failed.\n"); - return -1; - } -#endif - /* - i = COM_CheckParm ("-udpport"); - if (i == 0)*/ - net_hostport = DEFAULTnet_hostport; - /* - else if (i < com_argc-1) - net_hostport = Q_atoi (com_argv[i+1]); - else - Sys_Error ("WINS_Init: you must specify a number after -udpport"); - */ - - // determine my name & address - gethostname(buff, MAXHOSTNAMELEN); - local = gethostbyname(buff); - myAddr = *(int *)local->h_addr_list[0]; - - // if the quake hostname isn't set, set it to the machine name -// if (Q_strcmp(hostname.string, "UNNAMED") == 0) - { - // see if it's a text IP address (well, close enough) - for (p = buff; *p; p++) - if ((*p < '0' || *p > '9') && *p != '.') - break; - - // if it is a real name, strip off the domain; we only want the host - if (*p) - { - for (i = 0; i < 15; i++) - if (buff[i] == '.') - break; - buff[i] = 0; - } -// Cvar_Set ("hostname", buff); - } - - //++timo WTF is that net_controlsocket? it's sole purpose is to retrieve the local IP? - if ((net_controlsocket = WINS_OpenSocket (0)) == SOCKET_ERROR) - WinError("WINS_Init: Unable to open control socket\n"); - - ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; - ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; - ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); - - WINS_GetSocketAddr (net_controlsocket, &addr); - strcpy(my_tcpip_address, WINS_AddrToString (&addr)); - p = strrchr (my_tcpip_address, ':'); - if (p) *p = 0; - WinPrint("Winsock Initialized\n"); - - return net_controlsocket; -} //end of the function WINS_Init -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *WINS_MyAddress(void) -{ - return my_tcpip_address; -} //end of the function WINS_MyAddress -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void WINS_Shutdown(void) -{ - //WINS_Listen(0); - WINS_CloseSocket(net_controlsocket); -// WSACleanup(); - // - WinPrint("Winsock Shutdown\n"); -} //end of the function WINS_Shutdown -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -/* -void WINS_Listen(int state) -{ - // enable listening - if (state) - { - if (net_acceptsocket != -1) - return; - if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) - WinError ("WINS_Listen: Unable to open accept socket\n"); - return; - } - - // disable listening - if (net_acceptsocket == -1) - return; - WINS_CloseSocket (net_acceptsocket); - net_acceptsocket = -1; -} //end of the function WINS_Listen*/ -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_OpenSocket(int port) -{ - int newsocket; - struct sockaddr_in address; - u_long _true = 1; - - if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR) - { - WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - - if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR) - { - WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - closesocket(newsocket); - return -1; - } //end if - - memset((char *) &address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons((u_short)port); - if( bind (newsocket, (void *)&address, sizeof(address)) == -1) - { - WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - closesocket(newsocket); - return -1; - } //end if - - return newsocket; -} //end of the function WINS_OpenSocket -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_OpenReliableSocket(int port) -{ - int newsocket; - struct sockaddr_in address; - qboolean _true = 0xFFFFFFFF; - - //IPPROTO_TCP - // - if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) - { - WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - - memset((char *) &address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = htonl(INADDR_ANY); - address.sin_port = htons((u_short)port); - if (bind(newsocket, (void *)&address, sizeof(address)) == -1) - { - WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - closesocket(newsocket); - return -1; - } //end if - - // - if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == -1) - { - WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - WinPrint("setsockopt error\n"); - } //end if - - return newsocket; -} //end of the function WINS_OpenReliableSocket -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Listen(int socket) -{ - u_long _true = 1; - - if (ioctlsocket(socket, FIONBIO, &_true) == -1) - { - WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - if (listen(socket, SOMAXCONN) == SOCKET_ERROR) - { - WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - return 0; -} //end of the function WINS_Listen -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Accept(int socket, struct sockaddr_s *addr) -{ - int addrlen = sizeof (struct sockaddr_s); - int newsocket; - qboolean _true = 1; - - newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); - if (newsocket == INVALID_SOCKET) - { - if (errno == EAGAIN) return -1; - WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - // - if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) - { - WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); - WinPrint("setsockopt error\n"); - } //end if - return newsocket; -} //end of the function WINS_Accept -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_CloseSocket(int socket) -{ - /* - if (socket == net_broadcastsocket) - net_broadcastsocket = 0; - */ -// shutdown(socket, SD_SEND); - - if (closesocket(socket) == SOCKET_ERROR) - { - WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return SOCKET_ERROR; - } //end if - return 0; -} //end of the function WINS_CloseSocket -//=========================================================================== -// this lets you type only as much of the net address as required, using -// the local network components to fill in the rest -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) -{ - char buff[256]; - char *b; - int addr; - int num; - int mask; - - buff[0] = '.'; - b = buff; - strcpy(buff+1, in); - if (buff[1] == '.') b++; - - addr = 0; - mask=-1; - while (*b == '.') - { - num = 0; - if (*++b < '0' || *b > '9') return -1; - while (!( *b < '0' || *b > '9')) - num = num*10 + *(b++) - '0'; - mask<<=8; - addr = (addr<<8) + num; - } - - hostaddr->sa_family = AF_INET; - ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); - ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); - - return 0; -} //end of the function PartialIPAddress -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Connect(int socket, struct sockaddr_s *addr) -{ - int ret; - u_long _true2 = 0xFFFFFFFF; - - ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); - if (ret == SOCKET_ERROR) - { - WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - if (ioctlsocket(socket, FIONBIO, &_true2) == -1) - { - WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - return 0; -} //end of the function WINS_Connect -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_CheckNewConnections(void) -{ - char buf[4]; - - if (net_acceptsocket == -1) - return -1; - - if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) - return net_acceptsocket; - return -1; -} //end of the function WINS_CheckNewConnections -//=========================================================================== -// returns the number of bytes read -// 0 if no bytes available -// -1 on failure -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) -{ - int addrlen = sizeof (struct sockaddr_s); - int ret; - - if (addr) - { - ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); - if (ret == -1) - { -// errno = WSAGetLastError(); - - if (errno == EAGAIN || errno == ENOTCONN) - return 0; - } //end if - } //end if - else - { - ret = recv(socket, buf, len, 0); - // if there's no data on the socket ret == -1 and errno == EAGAIN - // MSDN states that if ret == 0 the socket has been closed - // man recv doesn't say anything - if (ret == 0) - return -1; - if (ret == SOCKET_ERROR) - { -// errno = WSAGetLastError(); - - if (errno == EAGAIN || errno == ENOTCONN) - return 0; - } //end if - } //end else - if (ret == SOCKET_ERROR) - { - WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); - } //end if - return ret; -} //end of the function WINS_Read -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_MakeSocketBroadcastCapable (int socket) -{ - int i = 1; - - // make this socket broadcast capable - if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) - return -1; - net_broadcastsocket = socket; - - return 0; -} //end of the function WINS_MakeSocketBroadcastCapable -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Broadcast (int socket, byte *buf, int len) -{ - int ret; - - if (socket != net_broadcastsocket) - { - if (net_broadcastsocket != 0) - WinError("Attempted to use multiple broadcasts sockets\n"); - ret = WINS_MakeSocketBroadcastCapable (socket); - if (ret == -1) - { - WinPrint("Unable to make socket broadcast capable\n"); - return ret; - } - } - - return WINS_Write (socket, buf, len, &broadcastaddr); -} //end of the function WINS_Broadcast -//=========================================================================== -// returns qtrue on success or qfalse on failure -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) -{ - int ret, written; - - if (addr) - { - written = 0; - while(written < len) - { - ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != EAGAIN) - return qfalse; - //++timo FIXME: what is this used for? -// Sleep(1000); - } //end if - else - { - written += ret; - } - } - } //end if - else - { - written = 0; - while(written < len) - { - ret = send(socket, buf, len, 0); - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != EAGAIN) - return qfalse; - //++timo FIXME: what is this used for? -// Sleep(1000); - } //end if - else - { - written += ret; - } - } - } //end else - if (ret == SOCKET_ERROR) - { - WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); - } //end if - return (ret == len); -} //end of the function WINS_Write -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *WINS_AddrToString (struct sockaddr_s *addr) -{ - static char buffer[22]; - int haddr; - - haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); - sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); - return buffer; -} //end of the function WINS_AddrToString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_StringToAddr(char *string, struct sockaddr_s *addr) -{ - int ha1, ha2, ha3, ha4, hp; - int ipaddr; - - sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); - ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; - - addr->sa_family = AF_INET; - ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); - ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); - return 0; -} //end of the function WINS_StringToAddr -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) -{ - int addrlen = sizeof(struct sockaddr_s); - unsigned int a; - - memset(addr, 0, sizeof(struct sockaddr_s)); - getsockname(socket, (struct sockaddr *)addr, &addrlen); - a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - if (a == 0 || a == inet_addr("127.0.0.1")) - ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; - - return 0; -} //end of the function WINS_GetSocketAddr -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) -{ - struct hostent *hostentry; - - hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); - if (hostentry) - { - strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); - return 0; - } - - strcpy (name, WINS_AddrToString (addr)); - return 0; -} //end of the function WINS_GetNameFromAddr -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) -{ - struct hostent *hostentry; - - if (name[0] >= '0' && name[0] <= '9') - return PartialIPAddress (name, addr); - - hostentry = gethostbyname (name); - if (!hostentry) - return -1; - - addr->sa_family = AF_INET; - ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); - ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; - - return 0; -} //end of the function WINS_GetAddrFromName -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) -{ - if (addr1->sa_family != addr2->sa_family) - return -1; - - if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) - return -1; - - if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) - return 1; - - return 0; -} //end of the function WINS_AddrCompare -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetSocketPort (struct sockaddr_s *addr) -{ - return ntohs(((struct sockaddr_in *)addr)->sin_port); -} //end of the function WINS_GetSocketPort -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_SetSocketPort (struct sockaddr_s *addr, int port) -{ - ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); - return 0; -} //end of the function WINS_SetSocketPort +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.c +// Function: WinSock +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab Size: 2 +// Notes: +//=========================================================================== + +//#include +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 + +extern void WinPrint(char *str, ...); + +#define WinError WinPrint + +#define qtrue 1 +#define qfalse 0 + +#define ioctlsocket ioctl +#define closesocket close + +int WSAGetLastError() +{ + return errno; +} + +/* +typedef struct tag_error_struct +{ + int errnum; + LPSTR errstr; +} ERROR_STRUCT; +*/ + +typedef struct tag_error_struct +{ + int errnum; + const char *errstr; +} ERROR_STRUCT; + +#define NET_NAMELEN 64 + +static char my_tcpip_address[NET_NAMELEN]; + +#define DEFAULTnet_hostport 26000 + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_hostport; // udp port number for acceptsocket +static int net_broadcastsocket = 0; +//static qboolean ifbcastinit = qfalse; +//static struct sockaddr_s broadcastaddr; +static struct sockaddr_s broadcastaddr; + +static unsigned long myAddr; + +ERROR_STRUCT errlist[] = { + {EACCES,"EACCES - The address is protected, user is not root"}, + {EAGAIN,"EAGAIN - Operation on non-blocking socket that cannot return immediatly"}, + {EBADF, "EBADF - sockfd is not a valid descriptor"}, + {EFAULT, "EFAULT - The parameter is not in a writable part of the user address space"}, + {EINVAL,"EINVAL - The socket is already bound to an address"}, + {ENOBUFS,"ENOBUFS - not enough memory"}, + {ENOMEM, "ENOMEM - not enough memory"}, + {ENOTCONN, "ENOTCONN - not connected"}, + {ENOTSOCK,"ENOTSOCK - Argument is file descriptor not a socket"}, + {EOPNOTSUPP,"ENOTSUPP - The referenced socket is not of type SOCK_STREAM"}, + {EPERM, "EPERM - Firewall rules forbid connection"}, + {-1, NULL} +}; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_ErrorMessage(int error) +{ + int search = 0; + + if (!error) return "No error occurred"; + + for (search = 0; errlist[search].errstr; search++) + { + if (error == errlist[search].errnum) + return (char *)errlist[search].errstr; + } //end for + + return "Unknown error"; +} //end of the function WINS_ErrorMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Init(void) +{ + int i; + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct sockaddr_s addr; + char *p; + int r; +/* + linux doesn't have anything to initialize for the net + "Windows .. built for the internet .. the internet .. built with unix" + */ +#if 0 + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(2, 2); + + r = WSAStartup (wVersionRequested, &winsockdata); + + if (r) + { + WinPrint("Winsock initialization failed.\n"); + return -1; + } +#endif + /* + i = COM_CheckParm ("-udpport"); + if (i == 0)*/ + net_hostport = DEFAULTnet_hostport; + /* + else if (i < com_argc-1) + net_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("WINS_Init: you must specify a number after -udpport"); + */ + + // determine my name & address + gethostname(buff, MAXHOSTNAMELEN); + local = gethostbyname(buff); + myAddr = *(int *)local->h_addr_list[0]; + + // if the quake hostname isn't set, set it to the machine name +// if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } +// Cvar_Set ("hostname", buff); + } + + //++timo WTF is that net_controlsocket? it's sole purpose is to retrieve the local IP? + if ((net_controlsocket = WINS_OpenSocket (0)) == SOCKET_ERROR) + WinError("WINS_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); + + WINS_GetSocketAddr (net_controlsocket, &addr); + strcpy(my_tcpip_address, WINS_AddrToString (&addr)); + p = strrchr (my_tcpip_address, ':'); + if (p) *p = 0; + WinPrint("Winsock Initialized\n"); + + return net_controlsocket; +} //end of the function WINS_Init +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_MyAddress(void) +{ + return my_tcpip_address; +} //end of the function WINS_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void WINS_Shutdown(void) +{ + //WINS_Listen(0); + WINS_CloseSocket(net_controlsocket); +// WSACleanup(); + // + WinPrint("Winsock Shutdown\n"); +} //end of the function WINS_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +void WINS_Listen(int state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) + WinError ("WINS_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WINS_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} //end of the function WINS_Listen*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + u_long _true = 1; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons((u_short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + return newsocket; +} //end of the function WINS_OpenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenReliableSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + qboolean _true = 0xFFFFFFFF; + + //IPPROTO_TCP + // + if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_port = htons((u_short)port); + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + + return newsocket; +} //end of the function WINS_OpenReliableSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Listen(int socket) +{ + u_long _true = 1; + + if (ioctlsocket(socket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (listen(socket, SOMAXCONN) == SOCKET_ERROR) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Listen +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Accept(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int newsocket; + qboolean _true = 1; + + newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); + if (newsocket == INVALID_SOCKET) + { + if (errno == EAGAIN) return -1; + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + return newsocket; +} //end of the function WINS_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CloseSocket(int socket) +{ + /* + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + */ +// shutdown(socket, SD_SEND); + + if (closesocket(socket) == SOCKET_ERROR) + { + WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return SOCKET_ERROR; + } //end if + return 0; +} //end of the function WINS_CloseSocket +//=========================================================================== +// this lets you type only as much of the net address as required, using +// the local network components to fill in the rest +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + num = 0; + if (*++b < '0' || *b > '9') return -1; + while (!( *b < '0' || *b > '9')) + num = num*10 + *(b++) - '0'; + mask<<=8; + addr = (addr<<8) + num; + } + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} //end of the function PartialIPAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Connect(int socket, struct sockaddr_s *addr) +{ + int ret; + u_long _true2 = 0xFFFFFFFF; + + ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (ioctlsocket(socket, FIONBIO, &_true2) == -1) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Connect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CheckNewConnections(void) +{ + char buf[4]; + + if (net_acceptsocket == -1) + return -1; + + if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) + return net_acceptsocket; + return -1; +} //end of the function WINS_CheckNewConnections +//=========================================================================== +// returns the number of bytes read +// 0 if no bytes available +// -1 on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int ret; + + if (addr) + { + ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { +// errno = WSAGetLastError(); + + if (errno == EAGAIN || errno == ENOTCONN) + return 0; + } //end if + } //end if + else + { + ret = recv(socket, buf, len, 0); + // if there's no data on the socket ret == -1 and errno == EAGAIN + // MSDN states that if ret == 0 the socket has been closed + // man recv doesn't say anything + if (ret == 0) + return -1; + if (ret == SOCKET_ERROR) + { +// errno = WSAGetLastError(); + + if (errno == EAGAIN || errno == ENOTCONN) + return 0; + } //end if + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return ret; +} //end of the function WINS_Read +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} //end of the function WINS_MakeSocketBroadcastCapable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + WinError("Attempted to use multiple broadcasts sockets\n"); + ret = WINS_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + WinPrint("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return WINS_Write (socket, buf, len, &broadcastaddr); +} //end of the function WINS_Broadcast +//=========================================================================== +// returns qtrue on success or qfalse on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int ret, written; + + if (addr) + { + written = 0; + while(written < len) + { + ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != EAGAIN) + return qfalse; + //++timo FIXME: what is this used for? +// Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end if + else + { + written = 0; + while(written < len) + { + ret = send(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != EAGAIN) + return qfalse; + //++timo FIXME: what is this used for? +// Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return (ret == len); +} //end of the function WINS_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_AddrToString (struct sockaddr_s *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); + return buffer; +} //end of the function WINS_AddrToString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_StringToAddr(char *string, struct sockaddr_s *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); + return 0; +} //end of the function WINS_StringToAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof(struct sockaddr_s); + unsigned int a; + + memset(addr, 0, sizeof(struct sockaddr_s)); + getsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} //end of the function WINS_GetSocketAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + strcpy (name, WINS_AddrToString (addr)); + return 0; +} //end of the function WINS_GetNameFromAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = gethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} //end of the function WINS_GetAddrFromName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} //end of the function WINS_AddrCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketPort (struct sockaddr_s *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} //end of the function WINS_GetSocketPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_SetSocketPort (struct sockaddr_s *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); + return 0; +} //end of the function WINS_SetSocketPort diff --git a/libs/l_net/l_net_wins.c b/libs/l_net/l_net_wins.c index 56ee6789..8a73f996 100644 --- a/libs/l_net/l_net_wins.c +++ b/libs/l_net/l_net_wins.c @@ -1,789 +1,789 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//=========================================================================== -// -// Name: l_net_wins.c -// Function: WinSock -// Programmer: MrElusive -// Last update: - -// Tab Size: 3 -// Notes: -//=========================================================================== - -#include -#include -#include -#include -#include "l_net.h" -#include "l_net_wins.h" -//#include -//#include "mpdosock.h" - -#define WinError WinPrint - -#define qtrue 1 -#define qfalse 0 - -typedef struct tag_error_struct -{ - int errnum; - LPSTR errstr; -} ERROR_STRUCT; - -#define NET_NAMELEN 64 - -char my_tcpip_address[NET_NAMELEN]; - -#define DEFAULTnet_hostport 26000 - -#define MAXHOSTNAMELEN 256 - -static int net_acceptsocket = -1; // socket for fielding new connections -static int net_controlsocket; -static int net_hostport; // udp port number for acceptsocket -static int net_broadcastsocket = 0; -//static qboolean ifbcastinit = qfalse; -static struct sockaddr_s broadcastaddr; - -static unsigned long myAddr; - -WSADATA winsockdata; - -ERROR_STRUCT errlist[] = { - {WSAEINTR, "WSAEINTR - Interrupted"}, - {WSAEBADF, "WSAEBADF - Bad file number"}, - {WSAEFAULT, "WSAEFAULT - Bad address"}, - {WSAEINVAL, "WSAEINVAL - Invalid argument"}, - {WSAEMFILE, "WSAEMFILE - Too many open files"}, - -/* -* Windows Sockets definitions of regular Berkeley error constants -*/ - - {WSAEWOULDBLOCK, "WSAEWOULDBLOCK - Socket marked as non-blocking"}, - {WSAEINPROGRESS, "WSAEINPROGRESS - Blocking call in progress"}, - {WSAEALREADY, "WSAEALREADY - Command already completed"}, - {WSAENOTSOCK, "WSAENOTSOCK - Descriptor is not a socket"}, - {WSAEDESTADDRREQ, "WSAEDESTADDRREQ - Destination address required"}, - {WSAEMSGSIZE, "WSAEMSGSIZE - Data size too large"}, - {WSAEPROTOTYPE, "WSAEPROTOTYPE - Protocol is of wrong type for this socket"}, - {WSAENOPROTOOPT, "WSAENOPROTOOPT - Protocol option not supported for this socket type"}, - {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT - Protocol is not supported"}, - {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT - Socket type not supported by this address family"}, - {WSAEOPNOTSUPP, "WSAEOPNOTSUPP - Option not supported"}, - {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT - "}, - {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT - Address family not supported by this protocol"}, - {WSAEADDRINUSE, "WSAEADDRINUSE - Address is in use"}, - {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL - Address not available from local machine"}, - {WSAENETDOWN, "WSAENETDOWN - Network subsystem is down"}, - {WSAENETUNREACH, "WSAENETUNREACH - Network cannot be reached"}, - {WSAENETRESET, "WSAENETRESET - Connection has been dropped"}, - {WSAECONNABORTED, "WSAECONNABORTED - Connection aborted"}, - {WSAECONNRESET, "WSAECONNRESET - Connection reset"}, - {WSAENOBUFS, "WSAENOBUFS - No buffer space available"}, - {WSAEISCONN, "WSAEISCONN - Socket is already connected"}, - {WSAENOTCONN, "WSAENOTCONN - Socket is not connected"}, - {WSAESHUTDOWN, "WSAESHUTDOWN - Socket has been shut down"}, - {WSAETOOMANYREFS, "WSAETOOMANYREFS - Too many references"}, - {WSAETIMEDOUT, "WSAETIMEDOUT - Command timed out"}, - {WSAECONNREFUSED, "WSAECONNREFUSED - Connection refused"}, - {WSAELOOP, "WSAELOOP - "}, - {WSAENAMETOOLONG, "WSAENAMETOOLONG - "}, - {WSAEHOSTDOWN, "WSAEHOSTDOWN - Host is down"}, - {WSAEHOSTUNREACH, "WSAEHOSTUNREACH - "}, - {WSAENOTEMPTY, "WSAENOTEMPTY - "}, - {WSAEPROCLIM, "WSAEPROCLIM - "}, - {WSAEUSERS, "WSAEUSERS - "}, - {WSAEDQUOT, "WSAEDQUOT - "}, - {WSAESTALE, "WSAESTALE - "}, - {WSAEREMOTE, "WSAEREMOTE - "}, - -/* -* Extended Windows Sockets error constant definitions -*/ - - {WSASYSNOTREADY, "WSASYSNOTREADY - Network subsystem not ready"}, - {WSAVERNOTSUPPORTED, "WSAVERNOTSUPPORTED - Version not supported"}, - {WSANOTINITIALISED, "WSANOTINITIALISED - WSAStartup() has not been successfully called"}, - -/* -* Other error constants. -*/ - - {WSAHOST_NOT_FOUND, "WSAHOST_NOT_FOUND - Host not found"}, - {WSATRY_AGAIN, "WSATRY_AGAIN - Host not found or SERVERFAIL"}, - {WSANO_RECOVERY, "WSANO_RECOVERY - Non-recoverable error"}, - {WSANO_DATA, "WSANO_DATA - (or WSANO_ADDRESS) - No data record of requested type"}, - {-1, NULL} -}; - -#ifdef _DEBUG -void WinPrint(char *str, ...); -#else -void WinPrint(char *str, ...); -#endif - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *WINS_ErrorMessage(int error) -{ - int search = 0; - - if (!error) return "No error occurred"; - - for (search = 0; errlist[search].errstr; search++) - { - if (error == errlist[search].errnum) - return errlist[search].errstr; - } //end for - - return "Unknown error"; -} //end of the function WINS_ErrorMessage -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Init(void) -{ - int i; - struct hostent *local; - char buff[MAXHOSTNAMELEN]; - struct sockaddr_s addr; - char *p; - int r; - WORD wVersionRequested; - - wVersionRequested = MAKEWORD(1, 1); - - r = WSAStartup (wVersionRequested, &winsockdata); - - if (r) - { - WinPrint("Winsock initialization failed.\n"); - return -1; - } - - /* - i = COM_CheckParm ("-udpport"); - if (i == 0)*/ - net_hostport = DEFAULTnet_hostport; - /* - else if (i < com_argc-1) - net_hostport = Q_atoi (com_argv[i+1]); - else - Sys_Error ("WINS_Init: you must specify a number after -udpport"); - */ - - // determine my name & address - gethostname(buff, MAXHOSTNAMELEN); - local = gethostbyname(buff); - myAddr = *(int *)local->h_addr_list[0]; - - // if the quake hostname isn't set, set it to the machine name -// if (Q_strcmp(hostname.string, "UNNAMED") == 0) - { - // see if it's a text IP address (well, close enough) - for (p = buff; *p; p++) - if ((*p < '0' || *p > '9') && *p != '.') - break; - - // if it is a real name, strip off the domain; we only want the host - if (*p) - { - for (i = 0; i < 15; i++) - if (buff[i] == '.') - break; - buff[i] = 0; - } -// Cvar_Set ("hostname", buff); - } - - if ((net_controlsocket = WINS_OpenSocket (0)) == -1) - WinError("WINS_Init: Unable to open control socket\n"); - - ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; - ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; - ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); - - WINS_GetSocketAddr (net_controlsocket, &addr); - strcpy(my_tcpip_address, WINS_AddrToString (&addr)); - p = strrchr (my_tcpip_address, ':'); - if (p) *p = 0; - WinPrint("Winsock Initialized\n"); - - return net_controlsocket; -} //end of the function WINS_Init -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *WINS_MyAddress(void) -{ - return my_tcpip_address; -} //end of the function WINS_MyAddress -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void WINS_Shutdown(void) -{ - //WINS_Listen(0); - WINS_CloseSocket(net_controlsocket); - WSACleanup(); - // - WinPrint("Winsock Shutdown\n"); -} //end of the function WINS_Shutdown -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -/* -void WINS_Listen(int state) -{ - // enable listening - if (state) - { - if (net_acceptsocket != -1) - return; - if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) - WinError ("WINS_Listen: Unable to open accept socket\n"); - return; - } - - // disable listening - if (net_acceptsocket == -1) - return; - WINS_CloseSocket (net_acceptsocket); - net_acceptsocket = -1; -} //end of the function WINS_Listen*/ -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_OpenSocket(int port) -{ - int newsocket; - struct sockaddr_in address; - u_long _true = 1; - - if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) - { - WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - - if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) - { - WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - closesocket(newsocket); - return -1; - } //end if - - memset((char *) &address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons((u_short)port); - if( bind (newsocket, (void *)&address, sizeof(address)) == -1) - { - WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - closesocket(newsocket); - return -1; - } //end if - - return newsocket; -} //end of the function WINS_OpenSocket -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_OpenReliableSocket(int port) -{ - int newsocket; - struct sockaddr_in address; - BOOL _true = 0xFFFFFFFF; - - //IPPROTO_TCP - // - if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) - { - WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - - memset((char *) &address, 0, sizeof(address)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = htonl(INADDR_ANY); - address.sin_port = htons((u_short)port); - if (bind(newsocket, (void *)&address, sizeof(address)) == -1) - { - WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - closesocket(newsocket); - return -1; - } //end if - - // - if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) - { - WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - WinPrint("setsockopt error\n"); - } //end if - - return newsocket; -} //end of the function WINS_OpenReliableSocket -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Listen(int socket) -{ - u_long _true = 1; - - if (ioctlsocket(socket, FIONBIO, &_true) == -1) - { - WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - if (listen(socket, SOMAXCONN) == SOCKET_ERROR) - { - WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - return 0; -} //end of the function WINS_Listen -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Accept(int socket, struct sockaddr_s *addr) -{ - int addrlen = sizeof (struct sockaddr_s); - int newsocket; - BOOL _true = 1; - - newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); - if (newsocket == INVALID_SOCKET) - { - if (WSAGetLastError() == WSAEWOULDBLOCK) return -1; - WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - // - if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) - { - WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); - WinPrint("setsockopt error\n"); - } //end if - return newsocket; -} //end of the function WINS_Accept -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_CloseSocket(int socket) -{ - /* - if (socket == net_broadcastsocket) - net_broadcastsocket = 0; - */ -// shutdown(socket, SD_SEND); - - if (closesocket(socket) == SOCKET_ERROR) - { - WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return SOCKET_ERROR; - } //end if - return 0; -} //end of the function WINS_CloseSocket -//=========================================================================== -// this lets you type only as much of the net address as required, using -// the local network components to fill in the rest -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) -{ - char buff[256]; - char *b; - int addr; - int num; - int mask; - - buff[0] = '.'; - b = buff; - strcpy(buff+1, in); - if (buff[1] == '.') b++; - - addr = 0; - mask=-1; - while (*b == '.') - { - num = 0; - if (*++b < '0' || *b > '9') return -1; - while (!( *b < '0' || *b > '9')) - num = num*10 + *(b++) - '0'; - mask<<=8; - addr = (addr<<8) + num; - } - - hostaddr->sa_family = AF_INET; - ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); - ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); - - return 0; -} //end of the function PartialIPAddress -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Connect(int socket, struct sockaddr_s *addr) -{ - int ret; - u_long _true2 = 0xFFFFFFFF; - - ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); - if (ret == SOCKET_ERROR) - { - WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - if (ioctlsocket(socket, FIONBIO, &_true2) == -1) - { - WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); - return -1; - } //end if - return 0; -} //end of the function WINS_Connect -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_CheckNewConnections(void) -{ - char buf[4]; - - if (net_acceptsocket == -1) - return -1; - - if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) - return net_acceptsocket; - return -1; -} //end of the function WINS_CheckNewConnections -//=========================================================================== -// returns the number of bytes read -// 0 if no bytes available -// -1 on failure -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) -{ - int addrlen = sizeof (struct sockaddr_s); - int ret, errno; - - if (addr) - { - ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); - if (ret == -1) - { - errno = WSAGetLastError(); - - if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) - return 0; - } //end if - } //end if - else - { - ret = recv(socket, buf, len, 0); - if (ret == SOCKET_ERROR) - { - errno = WSAGetLastError(); - - if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) - return 0; - } //end if - } //end else - if (ret == SOCKET_ERROR) - { - WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); - } //end if - return ret; -} //end of the function WINS_Read -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_MakeSocketBroadcastCapable (int socket) -{ - int i = 1; - - // make this socket broadcast capable - if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) - return -1; - net_broadcastsocket = socket; - - return 0; -} //end of the function WINS_MakeSocketBroadcastCapable -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Broadcast (int socket, byte *buf, int len) -{ - int ret; - - if (socket != net_broadcastsocket) - { - if (net_broadcastsocket != 0) - WinError("Attempted to use multiple broadcasts sockets\n"); - ret = WINS_MakeSocketBroadcastCapable (socket); - if (ret == -1) - { - WinPrint("Unable to make socket broadcast capable\n"); - return ret; - } - } - - return WINS_Write (socket, buf, len, &broadcastaddr); -} //end of the function WINS_Broadcast -//=========================================================================== -// returns qtrue on success or qfalse on failure -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) -{ - int ret, written; - - if (addr) - { - written = 0; - while(written < len) - { - ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - return qfalse; - Sleep(1000); - } //end if - else - { - written += ret; - } - } - } //end if - else - { - written = 0; - while(written < len) - { - ret = send(socket, buf, len, 0); - if (ret == SOCKET_ERROR) - { - if (WSAGetLastError() != WSAEWOULDBLOCK) - return qfalse; - Sleep(1000); - } //end if - else - { - written += ret; - } - } - } //end else - if (ret == SOCKET_ERROR) - { - WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); - } //end if - return (ret == len); -} //end of the function WINS_Write -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *WINS_AddrToString (struct sockaddr_s *addr) -{ - static char buffer[22]; - int haddr; - - haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); - sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); - return buffer; -} //end of the function WINS_AddrToString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_StringToAddr(char *string, struct sockaddr_s *addr) -{ - int ha1, ha2, ha3, ha4, hp; - int ipaddr; - - sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); - ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; - - addr->sa_family = AF_INET; - ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); - ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); - return 0; -} //end of the function WINS_StringToAddr -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) -{ - int addrlen = sizeof(struct sockaddr_s); - unsigned int a; - - memset(addr, 0, sizeof(struct sockaddr_s)); - getsockname(socket, (struct sockaddr *)addr, &addrlen); - a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - if (a == 0 || a == inet_addr("127.0.0.1")) - ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; - - return 0; -} //end of the function WINS_GetSocketAddr -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) -{ - struct hostent *hostentry; - - hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); - if (hostentry) - { - strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); - return 0; - } - - strcpy (name, WINS_AddrToString (addr)); - return 0; -} //end of the function WINS_GetNameFromAddr -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) -{ - struct hostent *hostentry; - - if (name[0] >= '0' && name[0] <= '9') - return PartialIPAddress (name, addr); - - hostentry = gethostbyname (name); - if (!hostentry) - return -1; - - addr->sa_family = AF_INET; - ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); - ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; - - return 0; -} //end of the function WINS_GetAddrFromName -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) -{ - if (addr1->sa_family != addr2->sa_family) - return -1; - - if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) - return -1; - - if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) - return 1; - - return 0; -} //end of the function WINS_AddrCompare -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_GetSocketPort (struct sockaddr_s *addr) -{ - return ntohs(((struct sockaddr_in *)addr)->sin_port); -} //end of the function WINS_GetSocketPort -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int WINS_SetSocketPort (struct sockaddr_s *addr, int port) -{ - ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); - return 0; -} //end of the function WINS_SetSocketPort +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.c +// Function: WinSock +// Programmer: MrElusive +// Last update: - +// Tab Size: 3 +// Notes: +//=========================================================================== + +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" +//#include +//#include "mpdosock.h" + +#define WinError WinPrint + +#define qtrue 1 +#define qfalse 0 + +typedef struct tag_error_struct +{ + int errnum; + LPSTR errstr; +} ERROR_STRUCT; + +#define NET_NAMELEN 64 + +char my_tcpip_address[NET_NAMELEN]; + +#define DEFAULTnet_hostport 26000 + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_hostport; // udp port number for acceptsocket +static int net_broadcastsocket = 0; +//static qboolean ifbcastinit = qfalse; +static struct sockaddr_s broadcastaddr; + +static unsigned long myAddr; + +WSADATA winsockdata; + +ERROR_STRUCT errlist[] = { + {WSAEINTR, "WSAEINTR - Interrupted"}, + {WSAEBADF, "WSAEBADF - Bad file number"}, + {WSAEFAULT, "WSAEFAULT - Bad address"}, + {WSAEINVAL, "WSAEINVAL - Invalid argument"}, + {WSAEMFILE, "WSAEMFILE - Too many open files"}, + +/* +* Windows Sockets definitions of regular Berkeley error constants +*/ + + {WSAEWOULDBLOCK, "WSAEWOULDBLOCK - Socket marked as non-blocking"}, + {WSAEINPROGRESS, "WSAEINPROGRESS - Blocking call in progress"}, + {WSAEALREADY, "WSAEALREADY - Command already completed"}, + {WSAENOTSOCK, "WSAENOTSOCK - Descriptor is not a socket"}, + {WSAEDESTADDRREQ, "WSAEDESTADDRREQ - Destination address required"}, + {WSAEMSGSIZE, "WSAEMSGSIZE - Data size too large"}, + {WSAEPROTOTYPE, "WSAEPROTOTYPE - Protocol is of wrong type for this socket"}, + {WSAENOPROTOOPT, "WSAENOPROTOOPT - Protocol option not supported for this socket type"}, + {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT - Protocol is not supported"}, + {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT - Socket type not supported by this address family"}, + {WSAEOPNOTSUPP, "WSAEOPNOTSUPP - Option not supported"}, + {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT - "}, + {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT - Address family not supported by this protocol"}, + {WSAEADDRINUSE, "WSAEADDRINUSE - Address is in use"}, + {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL - Address not available from local machine"}, + {WSAENETDOWN, "WSAENETDOWN - Network subsystem is down"}, + {WSAENETUNREACH, "WSAENETUNREACH - Network cannot be reached"}, + {WSAENETRESET, "WSAENETRESET - Connection has been dropped"}, + {WSAECONNABORTED, "WSAECONNABORTED - Connection aborted"}, + {WSAECONNRESET, "WSAECONNRESET - Connection reset"}, + {WSAENOBUFS, "WSAENOBUFS - No buffer space available"}, + {WSAEISCONN, "WSAEISCONN - Socket is already connected"}, + {WSAENOTCONN, "WSAENOTCONN - Socket is not connected"}, + {WSAESHUTDOWN, "WSAESHUTDOWN - Socket has been shut down"}, + {WSAETOOMANYREFS, "WSAETOOMANYREFS - Too many references"}, + {WSAETIMEDOUT, "WSAETIMEDOUT - Command timed out"}, + {WSAECONNREFUSED, "WSAECONNREFUSED - Connection refused"}, + {WSAELOOP, "WSAELOOP - "}, + {WSAENAMETOOLONG, "WSAENAMETOOLONG - "}, + {WSAEHOSTDOWN, "WSAEHOSTDOWN - Host is down"}, + {WSAEHOSTUNREACH, "WSAEHOSTUNREACH - "}, + {WSAENOTEMPTY, "WSAENOTEMPTY - "}, + {WSAEPROCLIM, "WSAEPROCLIM - "}, + {WSAEUSERS, "WSAEUSERS - "}, + {WSAEDQUOT, "WSAEDQUOT - "}, + {WSAESTALE, "WSAESTALE - "}, + {WSAEREMOTE, "WSAEREMOTE - "}, + +/* +* Extended Windows Sockets error constant definitions +*/ + + {WSASYSNOTREADY, "WSASYSNOTREADY - Network subsystem not ready"}, + {WSAVERNOTSUPPORTED, "WSAVERNOTSUPPORTED - Version not supported"}, + {WSANOTINITIALISED, "WSANOTINITIALISED - WSAStartup() has not been successfully called"}, + +/* +* Other error constants. +*/ + + {WSAHOST_NOT_FOUND, "WSAHOST_NOT_FOUND - Host not found"}, + {WSATRY_AGAIN, "WSATRY_AGAIN - Host not found or SERVERFAIL"}, + {WSANO_RECOVERY, "WSANO_RECOVERY - Non-recoverable error"}, + {WSANO_DATA, "WSANO_DATA - (or WSANO_ADDRESS) - No data record of requested type"}, + {-1, NULL} +}; + +#ifdef _DEBUG +void WinPrint(char *str, ...); +#else +void WinPrint(char *str, ...); +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_ErrorMessage(int error) +{ + int search = 0; + + if (!error) return "No error occurred"; + + for (search = 0; errlist[search].errstr; search++) + { + if (error == errlist[search].errnum) + return errlist[search].errstr; + } //end for + + return "Unknown error"; +} //end of the function WINS_ErrorMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Init(void) +{ + int i; + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct sockaddr_s addr; + char *p; + int r; + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(1, 1); + + r = WSAStartup (wVersionRequested, &winsockdata); + + if (r) + { + WinPrint("Winsock initialization failed.\n"); + return -1; + } + + /* + i = COM_CheckParm ("-udpport"); + if (i == 0)*/ + net_hostport = DEFAULTnet_hostport; + /* + else if (i < com_argc-1) + net_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("WINS_Init: you must specify a number after -udpport"); + */ + + // determine my name & address + gethostname(buff, MAXHOSTNAMELEN); + local = gethostbyname(buff); + myAddr = *(int *)local->h_addr_list[0]; + + // if the quake hostname isn't set, set it to the machine name +// if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } +// Cvar_Set ("hostname", buff); + } + + if ((net_controlsocket = WINS_OpenSocket (0)) == -1) + WinError("WINS_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); + + WINS_GetSocketAddr (net_controlsocket, &addr); + strcpy(my_tcpip_address, WINS_AddrToString (&addr)); + p = strrchr (my_tcpip_address, ':'); + if (p) *p = 0; + WinPrint("Winsock Initialized\n"); + + return net_controlsocket; +} //end of the function WINS_Init +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_MyAddress(void) +{ + return my_tcpip_address; +} //end of the function WINS_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void WINS_Shutdown(void) +{ + //WINS_Listen(0); + WINS_CloseSocket(net_controlsocket); + WSACleanup(); + // + WinPrint("Winsock Shutdown\n"); +} //end of the function WINS_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +void WINS_Listen(int state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) + WinError ("WINS_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WINS_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} //end of the function WINS_Listen*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + u_long _true = 1; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons((u_short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + return newsocket; +} //end of the function WINS_OpenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenReliableSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + BOOL _true = 0xFFFFFFFF; + + //IPPROTO_TCP + // + if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_port = htons((u_short)port); + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + + return newsocket; +} //end of the function WINS_OpenReliableSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Listen(int socket) +{ + u_long _true = 1; + + if (ioctlsocket(socket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (listen(socket, SOMAXCONN) == SOCKET_ERROR) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Listen +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Accept(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int newsocket; + BOOL _true = 1; + + newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); + if (newsocket == INVALID_SOCKET) + { + if (WSAGetLastError() == WSAEWOULDBLOCK) return -1; + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + return newsocket; +} //end of the function WINS_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CloseSocket(int socket) +{ + /* + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + */ +// shutdown(socket, SD_SEND); + + if (closesocket(socket) == SOCKET_ERROR) + { + WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return SOCKET_ERROR; + } //end if + return 0; +} //end of the function WINS_CloseSocket +//=========================================================================== +// this lets you type only as much of the net address as required, using +// the local network components to fill in the rest +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + num = 0; + if (*++b < '0' || *b > '9') return -1; + while (!( *b < '0' || *b > '9')) + num = num*10 + *(b++) - '0'; + mask<<=8; + addr = (addr<<8) + num; + } + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} //end of the function PartialIPAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Connect(int socket, struct sockaddr_s *addr) +{ + int ret; + u_long _true2 = 0xFFFFFFFF; + + ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (ioctlsocket(socket, FIONBIO, &_true2) == -1) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Connect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CheckNewConnections(void) +{ + char buf[4]; + + if (net_acceptsocket == -1) + return -1; + + if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) + return net_acceptsocket; + return -1; +} //end of the function WINS_CheckNewConnections +//=========================================================================== +// returns the number of bytes read +// 0 if no bytes available +// -1 on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int ret, errno; + + if (addr) + { + ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { + errno = WSAGetLastError(); + + if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + return 0; + } //end if + } //end if + else + { + ret = recv(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + errno = WSAGetLastError(); + + if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + return 0; + } //end if + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return ret; +} //end of the function WINS_Read +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} //end of the function WINS_MakeSocketBroadcastCapable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + WinError("Attempted to use multiple broadcasts sockets\n"); + ret = WINS_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + WinPrint("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return WINS_Write (socket, buf, len, &broadcastaddr); +} //end of the function WINS_Broadcast +//=========================================================================== +// returns qtrue on success or qfalse on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int ret, written; + + if (addr) + { + written = 0; + while(written < len) + { + ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return qfalse; + Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end if + else + { + written = 0; + while(written < len) + { + ret = send(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return qfalse; + Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return (ret == len); +} //end of the function WINS_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_AddrToString (struct sockaddr_s *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); + return buffer; +} //end of the function WINS_AddrToString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_StringToAddr(char *string, struct sockaddr_s *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); + return 0; +} //end of the function WINS_StringToAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof(struct sockaddr_s); + unsigned int a; + + memset(addr, 0, sizeof(struct sockaddr_s)); + getsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} //end of the function WINS_GetSocketAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + strcpy (name, WINS_AddrToString (addr)); + return 0; +} //end of the function WINS_GetNameFromAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = gethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} //end of the function WINS_GetAddrFromName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} //end of the function WINS_AddrCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketPort (struct sockaddr_s *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} //end of the function WINS_GetSocketPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_SetSocketPort (struct sockaddr_s *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); + return 0; +} //end of the function WINS_SetSocketPort diff --git a/libs/l_net/l_net_wins.h b/libs/l_net/l_net_wins.h index 0a06ea7a..73598795 100644 --- a/libs/l_net/l_net_wins.h +++ b/libs/l_net/l_net_wins.h @@ -1,52 +1,52 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//=========================================================================== -// -// Name: l_net_wins.h -// Function: WinSock -// Programmer: MrElusive -// Last update: TTimo: cross-platform version, l_net library -// Tab Size: 3 -// Notes: -//=========================================================================== - -int WINS_Init(void); -void WINS_Shutdown(void); -char *WINS_MyAddress(void); -int WINS_Listen(int socket); -int WINS_Accept(int socket, struct sockaddr_s *addr); -int WINS_OpenSocket(int port); -int WINS_OpenReliableSocket(int port); -int WINS_CloseSocket(int socket); -int WINS_Connect (int socket, struct sockaddr_s *addr); -int WINS_CheckNewConnections(void); -int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr); -int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr); -int WINS_Broadcast (int socket, byte *buf, int len); -char *WINS_AddrToString (struct sockaddr_s *addr); -int WINS_StringToAddr (char *string, struct sockaddr_s *addr); -int WINS_GetSocketAddr (int socket, struct sockaddr_s *addr); -int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name); -int WINS_GetAddrFromName (char *name, struct sockaddr_s *addr); -int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2); -int WINS_GetSocketPort (struct sockaddr_s *addr); -int WINS_SetSocketPort (struct sockaddr_s *addr, int port); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.h +// Function: WinSock +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab Size: 3 +// Notes: +//=========================================================================== + +int WINS_Init(void); +void WINS_Shutdown(void); +char *WINS_MyAddress(void); +int WINS_Listen(int socket); +int WINS_Accept(int socket, struct sockaddr_s *addr); +int WINS_OpenSocket(int port); +int WINS_OpenReliableSocket(int port); +int WINS_CloseSocket(int socket); +int WINS_Connect (int socket, struct sockaddr_s *addr); +int WINS_CheckNewConnections(void); +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr); +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr); +int WINS_Broadcast (int socket, byte *buf, int len); +char *WINS_AddrToString (struct sockaddr_s *addr); +int WINS_StringToAddr (char *string, struct sockaddr_s *addr); +int WINS_GetSocketAddr (int socket, struct sockaddr_s *addr); +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name); +int WINS_GetAddrFromName (char *name, struct sockaddr_s *addr); +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2); +int WINS_GetSocketPort (struct sockaddr_s *addr); +int WINS_SetSocketPort (struct sockaddr_s *addr, int port); diff --git a/libs/mathlib.h b/libs/mathlib.h index 97fcf461..44bf01c9 100644 --- a/libs/mathlib.h +++ b/libs/mathlib.h @@ -1,305 +1,305 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef __MATHLIB__ -#define __MATHLIB__ - -// mathlib.h -#include - -#include "bytebool.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef float vec_t; -typedef vec_t vec3_t[3]; -typedef vec_t vec5_t[5]; -typedef vec_t vec4_t[4]; - -#define SIDE_FRONT 0 -#define SIDE_ON 2 -#define SIDE_BACK 1 -#define SIDE_CROSS -2 - -// plane types are used to speed some tests -// 0-2 are axial planes -#define PLANE_X 0 -#define PLANE_Y 1 -#define PLANE_Z 2 -#define PLANE_NON_AXIAL 3 - -#define Q_PI 3.14159265358979323846f - -extern vec3_t vec3_origin; - -#define EQUAL_EPSILON 0.001 - -#ifndef VEC_MAX -#define VEC_MAX 3.402823466e+38F -#endif - -qboolean VectorCompare (vec3_t v1, vec3_t v2); - -#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) -#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) -#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) -#define VectorIncrement(a,b) ((b)[0]+=(a)[0],(b)[1]+=(a)[1],(b)[2]+=(a)[2]) -#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) -#define VectorSet(v, a, b, c) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c)) -#define VectorScale(a,b,c) ((c)[0]=(b)*(a)[0],(c)[1]=(b)*(a)[1],(c)[2]=(b)*(a)[2]) -#define VectorMid(a,b,c) ((c)[0]=((a)[0]+(b)[0])*0.5f,(c)[1]=((a)[1]+(b)[1])*0.5f,(c)[2]=((a)[2]+(b)[2])*0.5f) -#define VectorNegative(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) -#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) -#define VectorClear(x) ((x)[0]=(x)[1]=(x)[2]=0) - -#define Q_rint(in) ((vec_t)floor(in+0.5)) - -vec_t VectorLength(vec3_t v); - -void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ); - -void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); -vec_t VectorNormalize (const vec3_t in, vec3_t out); -vec_t ColorNormalize( const vec3_t in, vec3_t out ); -void VectorInverse (vec3_t v); -void VectorPolar(vec3_t v, float radius, float theta, float phi); - -// default snapping, to 1 -void VectorSnap(vec3_t v); - -// integer snapping -void VectorISnap(vec3_t point, int snap); - -// Gef: added snap to float for sub-integer grid sizes -// TTimo: we still use the int version of VectorSnap when possible -// to avoid potential rounding issues -// TTimo: renaming to VectorFSnap for C implementation -void VectorFSnap(vec3_t point, float snap); - -// NOTE: added these from Ritual's Q3Radiant -void ClearBounds (vec3_t mins, vec3_t maxs); -void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); - -void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); -void VectorToAngles( vec3_t vec, vec3_t angles ); - -#define ZERO_EPSILON 1.0E-6 -#define RAD2DEGMULT 57.29577951308232f -#define DEG2RADMULT 0.01745329251994329f -#define RAD2DEG( a ) ( (a) * RAD2DEGMULT ) -#define DEG2RAD( a ) ( (a) * DEG2RADMULT ) - -void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out); -void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out); - -// some function merged from tools mathlib code - -qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ); -void NormalToLatLong( const vec3_t normal, byte bytes[2] ); -int PlaneTypeForNormal (vec3_t normal); -void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); - -// Spog -// code imported from geomlib - -/*! -\todo -FIXME test calls such as intersect tests should be named test_ -*/ - -typedef vec_t m3x3_t[9]; -/*!NOTE -m4x4 looks like this.. - - x y z -x axis ( 0 1 2) -y axis ( 4 5 6) -z axis ( 8 9 10) -translation (12 13 14) -scale ( 0 5 10) -*/ -typedef vec_t m4x4_t[16]; - -#define M4X4_INDEX(m,row,col) (m[(col<<2)+row]) - -typedef enum { TRANSLATE, SCALE, ROTATE } transformtype; // legacy, used only in pmesh.cpp - -typedef enum { eXYZ, eYZX, eZXY, eXZY, eYXZ, eZYX } eulerOrder_t; - -// constructors -/*! create m4x4 as identity matrix */ -void m4x4_identity(m4x4_t matrix); -/*! create m4x4 as a translation matrix, for a translation vec3 */ -void m4x4_translation_for_vec3(m4x4_t matrix, const vec3_t translation); -/*! create m4x4 as a rotation matrix, for an euler angles (degrees) vec3 */ -void m4x4_rotation_for_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); -/*! create m4x4 as a scaling matrix, for a scale vec3 */ -void m4x4_scale_for_vec3(m4x4_t matrix, const vec3_t scale); -/*! create m4x4 as a rotation matrix, for a quaternion vec4 */ -void m4x4_rotation_for_quat(m4x4_t matrix, const vec4_t rotation); -/*! create m4x4 as a rotation matrix, for an axis vec3 and an angle (radians) */ -void m4x4_rotation_for_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); - -// a valid m4x4 to be modified is always first argument -/*! translate m4x4 by a translation vec3 */ -void m4x4_translate_by_vec3(m4x4_t matrix, const vec3_t translation); -/*! rotate m4x4 by a euler (degrees) vec3 */ -void m4x4_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); -/*! scale m4x4 by a scaling vec3 */ -void m4x4_scale_by_vec3(m4x4_t matrix, const vec3_t scale); -/*! rotate m4x4 by a quaternion vec4 */ -void m4x4_rotate_by_quat(m4x4_t matrix, const vec4_t rotation); -/*! rotate m4x4 by an axis vec3 and an angle (radians) */ -void m4x4_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); -/*! transform m4x4 by translation/euler/scaling vec3 (transform = translation.euler.scale) */ -void m4x4_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale); -/*! rotate m4x4 around a pivot point by euler(degrees) vec3 */ -void m4x4_pivoted_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order, const vec3_t pivotpoint); -/*! scale m4x4 around a pivot point by scaling vec3 */ -void m4x4_pivoted_scale_by_vec3(m4x4_t matrix, const vec3_t scale, const vec3_t pivotpoint); -/*! transform m4x4 around a pivot point by translation/euler/scaling vec3 */ -void m4x4_pivoted_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale, const vec3_t pivotpoint); -/*! rotate m4x4 around a pivot point by quaternion vec4 */ -void m4x4_pivoted_rotate_by_quat(m4x4_t matrix, const vec4_t rotation, const vec3_t pivotpoint); -/*! rotate m4x4 around a pivot point by axis vec3 and angle (radians) */ -void m4x4_pivoted_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle, const vec3_t pivotpoint); -/*! post-multiply m4x4 by another m4x4 */ -void m4x4_multiply_by_m4x4(m4x4_t matrix, const m4x4_t other); -/*! pre-multiply m4x4 by another m4x4 */ -void m4x4_premultiply_by_m4x4(m4x4_t matrix, const m4x4_t other); - -/*! multiply a point (x,y,z,1) by matrix */ -void m4x4_transform_point(const m4x4_t matrix, vec3_t point); -/*! multiply a normal (x,y,z,0) by matrix */ -void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); -/*! multiply a vec4 (x,y,z,w) by matrix */ -void m4x4_transform_vec4(const m4x4_t matrix, vec4_t vector); - -/*! multiply a point (x,y,z,1) by matrix */ -void m4x4_transform_point(const m4x4_t matrix, vec3_t point); -/*! multiply a normal (x,y,z,0) by matrix */ -void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); - -/*! transpose a m4x4 */ -void m4x4_transpose(m4x4_t matrix); -/*! invert an orthogonal 4x3 subset of a 4x4 matrix */ -void m4x4_orthogonal_invert(m4x4_t matrix); -/*! invert any m4x4 using Kramer's rule.. return 1 if matrix is singular, else return 0 */ -int m4x4_invert(m4x4_t matrix); - -/*! -\todo object/ray intersection functions should maybe return a point rather than a distance? -*/ - -/*! -aabb_t - "axis-aligned" bounding box... - origin: centre of bounding box... - extents: +/- extents of box from origin... - radius: cached length of extents vector... -*/ -typedef struct aabb_s -{ - vec3_t origin; - vec3_t extents; - vec_t radius; -} aabb_t; - -/*! -bbox_t - oriented bounding box... - aabb: axis-aligned bounding box... - axes: orientation axes... -*/ -typedef struct bbox_s -{ - aabb_t aabb; - vec3_t axes[3]; -} bbox_t; - -/*! -ray_t - origin point and direction unit-vector -*/ -typedef struct ray_s -{ - vec3_t origin; - vec3_t direction; -} ray_t; - - -/*! Generate AABB from min/max. */ -void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max); -/*! Update bounding-sphere radius. */ -void aabb_update_radius(aabb_t *aabb); -/*! Initialise AABB to negative size. */ -void aabb_clear(aabb_t *aabb); - -/*! Extend AABB to include point. */ -void aabb_extend_by_point(aabb_t *aabb, const vec3_t point); -/*! Extend AABB to include aabb_src. */ -void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src); -/*! Extend AABB by +/- extension vector. */ -void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension); - -/*! Return 2 if point is inside, else 1 if point is on surface, else 0. */ -int aabb_intersect_point(const aabb_t *aabb, const vec3_t point); -/*! Return 2 if aabb_src intersects, else 1 if aabb_src touches exactly, else 0. */ -int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src); -/*! Return 2 if aabb is behind plane, else 1 if aabb intersects plane, else 0. */ -int aabb_intersect_plane(const aabb_t *aabb, const float *plane); -/*! Return 1 if aabb intersects ray, else 0... dist = closest intersection. */ -int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist); -/*! Return 1 if aabb intersects ray, else 0. Faster, but does not provide point of intersection */ -int aabb_test_ray(const aabb_t* aabb, const ray_t* ray); - -/*! Generate AABB from oriented bounding box. */ -void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox); -/*! Generate AABB from 2-dimensions of min/max, specified by axis. */ -void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis); -/*! Generate AABB to contain src * transform. NOTE: transform must be orthogonal */ -void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform); - - -/*! Generate oriented bounding box from AABB and transformation matrix. */ -/*!\todo Remove need to specify euler/scale. */ -void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, - const m4x4_t matrix, const vec3_t euler, const vec3_t scale); -/*! Return 2 is bbox is behind plane, else return 1 if bbox intersects plane, else return 0. */ -int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane); - - -/*! Generate a ray from an origin point and a direction unit-vector */ -void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction); - -/*! Transform a ray */ -void ray_transform(ray_t *ray, const m4x4_t matrix); - -/*! return true if point intersects cone formed by ray, divergence and epsilon */ -vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence); -/*! return true if triangle intersects ray... dist = dist from intersection point to ray-origin */ -vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2); - -#ifdef __cplusplus -} -#endif - -#endif /* __MATHLIB__ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h +#include + +#include "bytebool.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec5_t[5]; +typedef vec_t vec4_t[4]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +// plane types are used to speed some tests +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_NON_AXIAL 3 + +#define Q_PI 3.14159265358979323846f + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +#ifndef VEC_MAX +#define VEC_MAX 3.402823466e+38F +#endif + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorIncrement(a,b) ((b)[0]+=(a)[0],(b)[1]+=(a)[1],(b)[2]+=(a)[2]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) +#define VectorSet(v, a, b, c) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c)) +#define VectorScale(a,b,c) ((c)[0]=(b)*(a)[0],(c)[1]=(b)*(a)[1],(c)[2]=(b)*(a)[2]) +#define VectorMid(a,b,c) ((c)[0]=((a)[0]+(b)[0])*0.5f,(c)[1]=((a)[1]+(b)[1])*0.5f,(c)[2]=((a)[2]+(b)[2])*0.5f) +#define VectorNegative(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) +#define VectorClear(x) ((x)[0]=(x)[1]=(x)[2]=0) + +#define Q_rint(in) ((vec_t)floor(in+0.5)) + +vec_t VectorLength(vec3_t v); + +void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ); + +void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (const vec3_t in, vec3_t out); +vec_t ColorNormalize( const vec3_t in, vec3_t out ); +void VectorInverse (vec3_t v); +void VectorPolar(vec3_t v, float radius, float theta, float phi); + +// default snapping, to 1 +void VectorSnap(vec3_t v); + +// integer snapping +void VectorISnap(vec3_t point, int snap); + +// Gef: added snap to float for sub-integer grid sizes +// TTimo: we still use the int version of VectorSnap when possible +// to avoid potential rounding issues +// TTimo: renaming to VectorFSnap for C implementation +void VectorFSnap(vec3_t point, float snap); + +// NOTE: added these from Ritual's Q3Radiant +void ClearBounds (vec3_t mins, vec3_t maxs); +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void VectorToAngles( vec3_t vec, vec3_t angles ); + +#define ZERO_EPSILON 1.0E-6 +#define RAD2DEGMULT 57.29577951308232f +#define DEG2RADMULT 0.01745329251994329f +#define RAD2DEG( a ) ( (a) * RAD2DEGMULT ) +#define DEG2RAD( a ) ( (a) * DEG2RADMULT ) + +void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out); +void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out); + +// some function merged from tools mathlib code + +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ); +void NormalToLatLong( const vec3_t normal, byte bytes[2] ); +int PlaneTypeForNormal (vec3_t normal); +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); + +// Spog +// code imported from geomlib + +/*! +\todo +FIXME test calls such as intersect tests should be named test_ +*/ + +typedef vec_t m3x3_t[9]; +/*!NOTE +m4x4 looks like this.. + + x y z +x axis ( 0 1 2) +y axis ( 4 5 6) +z axis ( 8 9 10) +translation (12 13 14) +scale ( 0 5 10) +*/ +typedef vec_t m4x4_t[16]; + +#define M4X4_INDEX(m,row,col) (m[(col<<2)+row]) + +typedef enum { TRANSLATE, SCALE, ROTATE } transformtype; // legacy, used only in pmesh.cpp + +typedef enum { eXYZ, eYZX, eZXY, eXZY, eYXZ, eZYX } eulerOrder_t; + +// constructors +/*! create m4x4 as identity matrix */ +void m4x4_identity(m4x4_t matrix); +/*! create m4x4 as a translation matrix, for a translation vec3 */ +void m4x4_translation_for_vec3(m4x4_t matrix, const vec3_t translation); +/*! create m4x4 as a rotation matrix, for an euler angles (degrees) vec3 */ +void m4x4_rotation_for_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); +/*! create m4x4 as a scaling matrix, for a scale vec3 */ +void m4x4_scale_for_vec3(m4x4_t matrix, const vec3_t scale); +/*! create m4x4 as a rotation matrix, for a quaternion vec4 */ +void m4x4_rotation_for_quat(m4x4_t matrix, const vec4_t rotation); +/*! create m4x4 as a rotation matrix, for an axis vec3 and an angle (radians) */ +void m4x4_rotation_for_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); + +// a valid m4x4 to be modified is always first argument +/*! translate m4x4 by a translation vec3 */ +void m4x4_translate_by_vec3(m4x4_t matrix, const vec3_t translation); +/*! rotate m4x4 by a euler (degrees) vec3 */ +void m4x4_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); +/*! scale m4x4 by a scaling vec3 */ +void m4x4_scale_by_vec3(m4x4_t matrix, const vec3_t scale); +/*! rotate m4x4 by a quaternion vec4 */ +void m4x4_rotate_by_quat(m4x4_t matrix, const vec4_t rotation); +/*! rotate m4x4 by an axis vec3 and an angle (radians) */ +void m4x4_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); +/*! transform m4x4 by translation/euler/scaling vec3 (transform = translation.euler.scale) */ +void m4x4_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale); +/*! rotate m4x4 around a pivot point by euler(degrees) vec3 */ +void m4x4_pivoted_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order, const vec3_t pivotpoint); +/*! scale m4x4 around a pivot point by scaling vec3 */ +void m4x4_pivoted_scale_by_vec3(m4x4_t matrix, const vec3_t scale, const vec3_t pivotpoint); +/*! transform m4x4 around a pivot point by translation/euler/scaling vec3 */ +void m4x4_pivoted_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale, const vec3_t pivotpoint); +/*! rotate m4x4 around a pivot point by quaternion vec4 */ +void m4x4_pivoted_rotate_by_quat(m4x4_t matrix, const vec4_t rotation, const vec3_t pivotpoint); +/*! rotate m4x4 around a pivot point by axis vec3 and angle (radians) */ +void m4x4_pivoted_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle, const vec3_t pivotpoint); +/*! post-multiply m4x4 by another m4x4 */ +void m4x4_multiply_by_m4x4(m4x4_t matrix, const m4x4_t other); +/*! pre-multiply m4x4 by another m4x4 */ +void m4x4_premultiply_by_m4x4(m4x4_t matrix, const m4x4_t other); + +/*! multiply a point (x,y,z,1) by matrix */ +void m4x4_transform_point(const m4x4_t matrix, vec3_t point); +/*! multiply a normal (x,y,z,0) by matrix */ +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); +/*! multiply a vec4 (x,y,z,w) by matrix */ +void m4x4_transform_vec4(const m4x4_t matrix, vec4_t vector); + +/*! multiply a point (x,y,z,1) by matrix */ +void m4x4_transform_point(const m4x4_t matrix, vec3_t point); +/*! multiply a normal (x,y,z,0) by matrix */ +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); + +/*! transpose a m4x4 */ +void m4x4_transpose(m4x4_t matrix); +/*! invert an orthogonal 4x3 subset of a 4x4 matrix */ +void m4x4_orthogonal_invert(m4x4_t matrix); +/*! invert any m4x4 using Kramer's rule.. return 1 if matrix is singular, else return 0 */ +int m4x4_invert(m4x4_t matrix); + +/*! +\todo object/ray intersection functions should maybe return a point rather than a distance? +*/ + +/*! +aabb_t - "axis-aligned" bounding box... + origin: centre of bounding box... + extents: +/- extents of box from origin... + radius: cached length of extents vector... +*/ +typedef struct aabb_s +{ + vec3_t origin; + vec3_t extents; + vec_t radius; +} aabb_t; + +/*! +bbox_t - oriented bounding box... + aabb: axis-aligned bounding box... + axes: orientation axes... +*/ +typedef struct bbox_s +{ + aabb_t aabb; + vec3_t axes[3]; +} bbox_t; + +/*! +ray_t - origin point and direction unit-vector +*/ +typedef struct ray_s +{ + vec3_t origin; + vec3_t direction; +} ray_t; + + +/*! Generate AABB from min/max. */ +void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max); +/*! Update bounding-sphere radius. */ +void aabb_update_radius(aabb_t *aabb); +/*! Initialise AABB to negative size. */ +void aabb_clear(aabb_t *aabb); + +/*! Extend AABB to include point. */ +void aabb_extend_by_point(aabb_t *aabb, const vec3_t point); +/*! Extend AABB to include aabb_src. */ +void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src); +/*! Extend AABB by +/- extension vector. */ +void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension); + +/*! Return 2 if point is inside, else 1 if point is on surface, else 0. */ +int aabb_intersect_point(const aabb_t *aabb, const vec3_t point); +/*! Return 2 if aabb_src intersects, else 1 if aabb_src touches exactly, else 0. */ +int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src); +/*! Return 2 if aabb is behind plane, else 1 if aabb intersects plane, else 0. */ +int aabb_intersect_plane(const aabb_t *aabb, const float *plane); +/*! Return 1 if aabb intersects ray, else 0... dist = closest intersection. */ +int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist); +/*! Return 1 if aabb intersects ray, else 0. Faster, but does not provide point of intersection */ +int aabb_test_ray(const aabb_t* aabb, const ray_t* ray); + +/*! Generate AABB from oriented bounding box. */ +void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox); +/*! Generate AABB from 2-dimensions of min/max, specified by axis. */ +void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis); +/*! Generate AABB to contain src * transform. NOTE: transform must be orthogonal */ +void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform); + + +/*! Generate oriented bounding box from AABB and transformation matrix. */ +/*!\todo Remove need to specify euler/scale. */ +void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, + const m4x4_t matrix, const vec3_t euler, const vec3_t scale); +/*! Return 2 is bbox is behind plane, else return 1 if bbox intersects plane, else return 0. */ +int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane); + + +/*! Generate a ray from an origin point and a direction unit-vector */ +void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction); + +/*! Transform a ray */ +void ray_transform(ray_t *ray, const m4x4_t matrix); + +/*! return true if point intersects cone formed by ray, divergence and epsilon */ +vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence); +/*! return true if triangle intersects ray... dist = dist from intersection point to ray-origin */ +vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATHLIB__ */ diff --git a/libs/mathlib/bbox.c b/libs/mathlib/bbox.c index 510c4e7c..f421f917 100644 --- a/libs/mathlib/bbox.c +++ b/libs/mathlib/bbox.c @@ -1,391 +1,391 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -#include "mathlib.h" - -void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max) -{ - VectorMid(min, max, aabb->origin); - VectorSubtract(max, aabb->origin, aabb->extents); -} - -void aabb_update_radius(aabb_t *aabb) -{ - aabb->radius = VectorLength(aabb->extents); -} - -void aabb_clear(aabb_t *aabb) -{ - aabb->origin[0] = aabb->origin[1] = aabb->origin[2] = 0; - aabb->extents[0] = aabb->extents[1] = aabb->extents[2] = -FLT_MAX; -} - -void aabb_extend_by_point(aabb_t *aabb, const vec3_t point) -{ - int i; - vec_t min, max, displacement; - for(i=0; i<3; i++) - { - displacement = point[i] - aabb->origin[i]; - if(fabs(displacement) > aabb->extents[i]) - { - if(aabb->extents[i] < 0) // degenerate - { - min = max = point[i]; - } - else if(displacement > 0) - { - min = aabb->origin[i] - aabb->extents[i]; - max = aabb->origin[i] + displacement; - } - else - { - max = aabb->origin[i] + aabb->extents[i]; - min = aabb->origin[i] + displacement; - } - aabb->origin[i] = (min + max) * 0.5f; - aabb->extents[i] = max - aabb->origin[i]; - } - } -} - -void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src) -{ - int i; - vec_t min, max, displacement, difference; - for(i=0; i<3; i++) - { - displacement = aabb_src->origin[i] - aabb->origin[i]; - difference = aabb_src->extents[i] - aabb->extents[i]; - if(aabb->extents[i] < 0 - || difference >= fabs(displacement)) - { - // 2nd contains 1st - aabb->extents[i] = aabb_src->extents[i]; - aabb->origin[i] = aabb_src->origin[i]; - } - else if(aabb_src->extents[i] < 0 - || -difference >= fabs(displacement)) - { - // 1st contains 2nd - continue; - } - else - { - // not contained - if(displacement > 0) - { - min = aabb->origin[i] - aabb->extents[i]; - max = aabb_src->origin[i] + aabb_src->extents[i]; - } - else - { - min = aabb_src->origin[i] - aabb_src->extents[i]; - max = aabb->origin[i] + aabb->extents[i]; - } - aabb->origin[i] = (min + max) * 0.5f; - aabb->extents[i] = max - aabb->origin[i]; - } - } -} - -void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension) -{ - VectorAdd(aabb->extents, extension, aabb->extents); -} - -int aabb_intersect_point(const aabb_t *aabb, const vec3_t point) -{ - int i; - for(i=0; i<3; i++) - if(fabs(point[i] - aabb->origin[i]) >= aabb->extents[i]) - return 0; - return 1; -} - -int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src) -{ - int i; - for (i=0; i<3; i++) - if ( fabs(aabb_src->origin[i] - aabb->origin[i]) > (fabs(aabb->extents[i]) + fabs(aabb_src->extents[i])) ) - return 0; - return 1; -} - -int aabb_intersect_plane(const aabb_t *aabb, const float *plane) -{ - float fDist, fIntersect; - - // calc distance of origin from plane - fDist = DotProduct(plane, aabb->origin) + plane[3]; - - // trivial accept/reject using bounding sphere - if (fabs(fDist) > aabb->radius) - { - if (fDist < 0) - return 2; // totally inside - else - return 0; // totally outside - } - - // calc extents distance relative to plane normal - fIntersect = (vec_t)(fabs(plane[0] * aabb->extents[0]) + fabs(plane[1] * aabb->extents[1]) + fabs(plane[2] * aabb->extents[2])); - // accept if origin is less than or equal to this distance - if (fabs(fDist) < fIntersect) return 1; // partially inside - else if (fDist < 0) return 2; // totally inside - return 0; // totally outside -} - -/* -Fast Ray-Box Intersection -by Andrew Woo -from "Graphics Gems", Academic Press, 1990 -*/ - -#define NUMDIM 3 -#define RIGHT 0 -#define LEFT 1 -#define MIDDLE 2 - -int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist) -{ - int inside = 1; - char quadrant[NUMDIM]; - register int i; - int whichPlane; - double maxT[NUMDIM]; - double candidatePlane[NUMDIM]; - vec3_t coord, segment; - - const float *origin = ray->origin; - const float *direction = ray->direction; - - /* Find candidate planes; this loop can be avoided if - rays cast all from the eye(assume perpsective view) */ - for (i=0; iorigin[i] - aabb->extents[i])) - { - quadrant[i] = LEFT; - candidatePlane[i] = (aabb->origin[i] - aabb->extents[i]); - inside = 0; - } - else if (origin[i] > (aabb->origin[i] + aabb->extents[i])) - { - quadrant[i] = RIGHT; - candidatePlane[i] = (aabb->origin[i] + aabb->extents[i]); - inside = 0; - } - else - { - quadrant[i] = MIDDLE; - } - } - - /* Ray origin inside bounding box */ - if(inside == 1) - { - *dist = 0.0f; - return 1; - } - - - /* Calculate T distances to candidate planes */ - for (i = 0; i < NUMDIM; i++) - { - if (quadrant[i] != MIDDLE && direction[i] !=0.) - maxT[i] = (candidatePlane[i] - origin[i]) / direction[i]; - else - maxT[i] = -1.; - } - - /* Get largest of the maxT's for final choice of intersection */ - whichPlane = 0; - for (i = 1; i < NUMDIM; i++) - if (maxT[whichPlane] < maxT[i]) - whichPlane = i; - - /* Check final candidate actually inside box */ - if (maxT[whichPlane] < 0.) - return 0; - for (i = 0; i < NUMDIM; i++) - { - if (whichPlane != i) - { - coord[i] = (vec_t)(origin[i] + maxT[whichPlane] * direction[i]); - if (fabs(coord[i] - aabb->origin[i]) > aabb->extents[i]) - return 0; - } - else - { - coord[i] = (vec_t)candidatePlane[i]; - } - } - - VectorSubtract(coord, origin, segment); - *dist = DotProduct(segment, direction); - - return 1; /* ray hits box */ -} - -int aabb_test_ray(const aabb_t* aabb, const ray_t* ray) -{ - vec3_t displacement, ray_absolute; - vec_t f; - - displacement[0] = ray->origin[0] - aabb->origin[0]; - if(fabs(displacement[0]) > aabb->extents[0] && displacement[0] * ray->direction[0] >= 0.0f) - return 0; - - displacement[1] = ray->origin[1] - aabb->origin[1]; - if(fabs(displacement[1]) > aabb->extents[1] && displacement[1] * ray->direction[1] >= 0.0f) - return 0; - - displacement[2] = ray->origin[2] - aabb->origin[2]; - if(fabs(displacement[2]) > aabb->extents[2] && displacement[2] * ray->direction[2] >= 0.0f) - return 0; - - ray_absolute[0] = (float)fabs(ray->direction[0]); - ray_absolute[1] = (float)fabs(ray->direction[1]); - ray_absolute[2] = (float)fabs(ray->direction[2]); - - f = ray->direction[1] * displacement[2] - ray->direction[2] * displacement[1]; - if((float)fabs(f) > aabb->extents[1] * ray_absolute[2] + aabb->extents[2] * ray_absolute[1]) - return 0; - - f = ray->direction[2] * displacement[0] - ray->direction[0] * displacement[2]; - if((float)fabs(f) > aabb->extents[0] * ray_absolute[2] + aabb->extents[2] * ray_absolute[0]) - return 0; - - f = ray->direction[0] * displacement[1] - ray->direction[1] * displacement[0]; - if((float)fabs(f) > aabb->extents[0] * ray_absolute[1] + aabb->extents[1] * ray_absolute[0]) - return 0; - - return 1; -} - -void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox) -{ - int i; - vec3_t temp[3]; - - VectorCopy(bbox->aabb.origin, aabb->origin); - - // calculate the AABB extents in local coord space from the OBB extents and axes - VectorScale(bbox->axes[0], bbox->aabb.extents[0], temp[0]); - VectorScale(bbox->axes[1], bbox->aabb.extents[1], temp[1]); - VectorScale(bbox->axes[2], bbox->aabb.extents[2], temp[2]); - for(i=0;i<3;i++) aabb->extents[i] = (vec_t)(fabs(temp[0][i]) + fabs(temp[1][i]) + fabs(temp[2][i])); -} - -void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis) -{ - aabb_clear(aabb); - aabb->extents[axis] = FLT_MAX; - aabb_extend_by_point(aabb, area_tl); - aabb_extend_by_point(aabb, area_br); -} - -void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform) -{ - VectorCopy(src->origin, dst->origin); - m4x4_transform_point(transform, dst->origin); - - dst->extents[0] = (vec_t)(fabs(transform[0] * src->extents[0]) - + fabs(transform[4] * src->extents[1]) - + fabs(transform[8] * src->extents[2])); - dst->extents[1] = (vec_t)(fabs(transform[1] * src->extents[0]) - + fabs(transform[5] * src->extents[1]) - + fabs(transform[9] * src->extents[2])); - dst->extents[2] = (vec_t)(fabs(transform[2] * src->extents[0]) - + fabs(transform[6] * src->extents[1]) - + fabs(transform[10] * src->extents[2])); -} - - -void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, const m4x4_t matrix, const vec3_t euler, const vec3_t scale) -{ - double rad[3]; - double pi_180 = Q_PI / 180; - double A, B, C, D, E, F, AD, BD; - - VectorCopy(aabb->origin, bbox->aabb.origin); - - m4x4_transform_point(matrix, bbox->aabb.origin); - - bbox->aabb.extents[0] = aabb->extents[0] * scale[0]; - bbox->aabb.extents[1] = aabb->extents[1] * scale[1]; - bbox->aabb.extents[2] = aabb->extents[2] * scale[2]; - - rad[0] = euler[0] * pi_180; - rad[1] = euler[1] * pi_180; - rad[2] = euler[2] * pi_180; - - A = cos(rad[0]); - B = sin(rad[0]); - C = cos(rad[1]); - D = sin(rad[1]); - E = cos(rad[2]); - F = sin(rad[2]); - - AD = A * -D; - BD = B * -D; - - bbox->axes[0][0] = (vec_t)(C*E); - bbox->axes[0][1] = (vec_t)(-BD*E + A*F); - bbox->axes[0][2] = (vec_t)(AD*E + B*F); - bbox->axes[1][0] = (vec_t)(-C*F); - bbox->axes[1][1] = (vec_t)(BD*F + A*E); - bbox->axes[1][2] = (vec_t)(-AD*F + B*E); - bbox->axes[2][0] = (vec_t)D; - bbox->axes[2][1] = (vec_t)(-B*C); - bbox->axes[2][2] = (vec_t)(A*C); - - aabb_update_radius(&bbox->aabb); -} - -int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane) -{ - vec_t fDist, fIntersect; - - // calc distance of origin from plane - fDist = DotProduct(plane, bbox->aabb.origin) + plane[3]; - - // trivial accept/reject using bounding sphere - if (fabs(fDist) > bbox->aabb.radius) - { - if (fDist < 0) - return 2; // totally inside - else - return 0; // totally outside - } - - // calc extents distance relative to plane normal - fIntersect = (vec_t)(fabs(bbox->aabb.extents[0] * DotProduct(plane, bbox->axes[0])) - + fabs(bbox->aabb.extents[1] * DotProduct(plane, bbox->axes[1])) - + fabs(bbox->aabb.extents[2] * DotProduct(plane, bbox->axes[2]))); - // accept if origin is less than this distance - if (fabs(fDist) < fIntersect) return 1; // partially inside - else if (fDist < 0) return 2; // totally inside - return 0; // totally outside -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "mathlib.h" + +void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max) +{ + VectorMid(min, max, aabb->origin); + VectorSubtract(max, aabb->origin, aabb->extents); +} + +void aabb_update_radius(aabb_t *aabb) +{ + aabb->radius = VectorLength(aabb->extents); +} + +void aabb_clear(aabb_t *aabb) +{ + aabb->origin[0] = aabb->origin[1] = aabb->origin[2] = 0; + aabb->extents[0] = aabb->extents[1] = aabb->extents[2] = -FLT_MAX; +} + +void aabb_extend_by_point(aabb_t *aabb, const vec3_t point) +{ + int i; + vec_t min, max, displacement; + for(i=0; i<3; i++) + { + displacement = point[i] - aabb->origin[i]; + if(fabs(displacement) > aabb->extents[i]) + { + if(aabb->extents[i] < 0) // degenerate + { + min = max = point[i]; + } + else if(displacement > 0) + { + min = aabb->origin[i] - aabb->extents[i]; + max = aabb->origin[i] + displacement; + } + else + { + max = aabb->origin[i] + aabb->extents[i]; + min = aabb->origin[i] + displacement; + } + aabb->origin[i] = (min + max) * 0.5f; + aabb->extents[i] = max - aabb->origin[i]; + } + } +} + +void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src) +{ + int i; + vec_t min, max, displacement, difference; + for(i=0; i<3; i++) + { + displacement = aabb_src->origin[i] - aabb->origin[i]; + difference = aabb_src->extents[i] - aabb->extents[i]; + if(aabb->extents[i] < 0 + || difference >= fabs(displacement)) + { + // 2nd contains 1st + aabb->extents[i] = aabb_src->extents[i]; + aabb->origin[i] = aabb_src->origin[i]; + } + else if(aabb_src->extents[i] < 0 + || -difference >= fabs(displacement)) + { + // 1st contains 2nd + continue; + } + else + { + // not contained + if(displacement > 0) + { + min = aabb->origin[i] - aabb->extents[i]; + max = aabb_src->origin[i] + aabb_src->extents[i]; + } + else + { + min = aabb_src->origin[i] - aabb_src->extents[i]; + max = aabb->origin[i] + aabb->extents[i]; + } + aabb->origin[i] = (min + max) * 0.5f; + aabb->extents[i] = max - aabb->origin[i]; + } + } +} + +void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension) +{ + VectorAdd(aabb->extents, extension, aabb->extents); +} + +int aabb_intersect_point(const aabb_t *aabb, const vec3_t point) +{ + int i; + for(i=0; i<3; i++) + if(fabs(point[i] - aabb->origin[i]) >= aabb->extents[i]) + return 0; + return 1; +} + +int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src) +{ + int i; + for (i=0; i<3; i++) + if ( fabs(aabb_src->origin[i] - aabb->origin[i]) > (fabs(aabb->extents[i]) + fabs(aabb_src->extents[i])) ) + return 0; + return 1; +} + +int aabb_intersect_plane(const aabb_t *aabb, const float *plane) +{ + float fDist, fIntersect; + + // calc distance of origin from plane + fDist = DotProduct(plane, aabb->origin) + plane[3]; + + // trivial accept/reject using bounding sphere + if (fabs(fDist) > aabb->radius) + { + if (fDist < 0) + return 2; // totally inside + else + return 0; // totally outside + } + + // calc extents distance relative to plane normal + fIntersect = (vec_t)(fabs(plane[0] * aabb->extents[0]) + fabs(plane[1] * aabb->extents[1]) + fabs(plane[2] * aabb->extents[2])); + // accept if origin is less than or equal to this distance + if (fabs(fDist) < fIntersect) return 1; // partially inside + else if (fDist < 0) return 2; // totally inside + return 0; // totally outside +} + +/* +Fast Ray-Box Intersection +by Andrew Woo +from "Graphics Gems", Academic Press, 1990 +*/ + +#define NUMDIM 3 +#define RIGHT 0 +#define LEFT 1 +#define MIDDLE 2 + +int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist) +{ + int inside = 1; + char quadrant[NUMDIM]; + register int i; + int whichPlane; + double maxT[NUMDIM]; + double candidatePlane[NUMDIM]; + vec3_t coord, segment; + + const float *origin = ray->origin; + const float *direction = ray->direction; + + /* Find candidate planes; this loop can be avoided if + rays cast all from the eye(assume perpsective view) */ + for (i=0; iorigin[i] - aabb->extents[i])) + { + quadrant[i] = LEFT; + candidatePlane[i] = (aabb->origin[i] - aabb->extents[i]); + inside = 0; + } + else if (origin[i] > (aabb->origin[i] + aabb->extents[i])) + { + quadrant[i] = RIGHT; + candidatePlane[i] = (aabb->origin[i] + aabb->extents[i]); + inside = 0; + } + else + { + quadrant[i] = MIDDLE; + } + } + + /* Ray origin inside bounding box */ + if(inside == 1) + { + *dist = 0.0f; + return 1; + } + + + /* Calculate T distances to candidate planes */ + for (i = 0; i < NUMDIM; i++) + { + if (quadrant[i] != MIDDLE && direction[i] !=0.) + maxT[i] = (candidatePlane[i] - origin[i]) / direction[i]; + else + maxT[i] = -1.; + } + + /* Get largest of the maxT's for final choice of intersection */ + whichPlane = 0; + for (i = 1; i < NUMDIM; i++) + if (maxT[whichPlane] < maxT[i]) + whichPlane = i; + + /* Check final candidate actually inside box */ + if (maxT[whichPlane] < 0.) + return 0; + for (i = 0; i < NUMDIM; i++) + { + if (whichPlane != i) + { + coord[i] = (vec_t)(origin[i] + maxT[whichPlane] * direction[i]); + if (fabs(coord[i] - aabb->origin[i]) > aabb->extents[i]) + return 0; + } + else + { + coord[i] = (vec_t)candidatePlane[i]; + } + } + + VectorSubtract(coord, origin, segment); + *dist = DotProduct(segment, direction); + + return 1; /* ray hits box */ +} + +int aabb_test_ray(const aabb_t* aabb, const ray_t* ray) +{ + vec3_t displacement, ray_absolute; + vec_t f; + + displacement[0] = ray->origin[0] - aabb->origin[0]; + if(fabs(displacement[0]) > aabb->extents[0] && displacement[0] * ray->direction[0] >= 0.0f) + return 0; + + displacement[1] = ray->origin[1] - aabb->origin[1]; + if(fabs(displacement[1]) > aabb->extents[1] && displacement[1] * ray->direction[1] >= 0.0f) + return 0; + + displacement[2] = ray->origin[2] - aabb->origin[2]; + if(fabs(displacement[2]) > aabb->extents[2] && displacement[2] * ray->direction[2] >= 0.0f) + return 0; + + ray_absolute[0] = (float)fabs(ray->direction[0]); + ray_absolute[1] = (float)fabs(ray->direction[1]); + ray_absolute[2] = (float)fabs(ray->direction[2]); + + f = ray->direction[1] * displacement[2] - ray->direction[2] * displacement[1]; + if((float)fabs(f) > aabb->extents[1] * ray_absolute[2] + aabb->extents[2] * ray_absolute[1]) + return 0; + + f = ray->direction[2] * displacement[0] - ray->direction[0] * displacement[2]; + if((float)fabs(f) > aabb->extents[0] * ray_absolute[2] + aabb->extents[2] * ray_absolute[0]) + return 0; + + f = ray->direction[0] * displacement[1] - ray->direction[1] * displacement[0]; + if((float)fabs(f) > aabb->extents[0] * ray_absolute[1] + aabb->extents[1] * ray_absolute[0]) + return 0; + + return 1; +} + +void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox) +{ + int i; + vec3_t temp[3]; + + VectorCopy(bbox->aabb.origin, aabb->origin); + + // calculate the AABB extents in local coord space from the OBB extents and axes + VectorScale(bbox->axes[0], bbox->aabb.extents[0], temp[0]); + VectorScale(bbox->axes[1], bbox->aabb.extents[1], temp[1]); + VectorScale(bbox->axes[2], bbox->aabb.extents[2], temp[2]); + for(i=0;i<3;i++) aabb->extents[i] = (vec_t)(fabs(temp[0][i]) + fabs(temp[1][i]) + fabs(temp[2][i])); +} + +void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis) +{ + aabb_clear(aabb); + aabb->extents[axis] = FLT_MAX; + aabb_extend_by_point(aabb, area_tl); + aabb_extend_by_point(aabb, area_br); +} + +void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform) +{ + VectorCopy(src->origin, dst->origin); + m4x4_transform_point(transform, dst->origin); + + dst->extents[0] = (vec_t)(fabs(transform[0] * src->extents[0]) + + fabs(transform[4] * src->extents[1]) + + fabs(transform[8] * src->extents[2])); + dst->extents[1] = (vec_t)(fabs(transform[1] * src->extents[0]) + + fabs(transform[5] * src->extents[1]) + + fabs(transform[9] * src->extents[2])); + dst->extents[2] = (vec_t)(fabs(transform[2] * src->extents[0]) + + fabs(transform[6] * src->extents[1]) + + fabs(transform[10] * src->extents[2])); +} + + +void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, const m4x4_t matrix, const vec3_t euler, const vec3_t scale) +{ + double rad[3]; + double pi_180 = Q_PI / 180; + double A, B, C, D, E, F, AD, BD; + + VectorCopy(aabb->origin, bbox->aabb.origin); + + m4x4_transform_point(matrix, bbox->aabb.origin); + + bbox->aabb.extents[0] = aabb->extents[0] * scale[0]; + bbox->aabb.extents[1] = aabb->extents[1] * scale[1]; + bbox->aabb.extents[2] = aabb->extents[2] * scale[2]; + + rad[0] = euler[0] * pi_180; + rad[1] = euler[1] * pi_180; + rad[2] = euler[2] * pi_180; + + A = cos(rad[0]); + B = sin(rad[0]); + C = cos(rad[1]); + D = sin(rad[1]); + E = cos(rad[2]); + F = sin(rad[2]); + + AD = A * -D; + BD = B * -D; + + bbox->axes[0][0] = (vec_t)(C*E); + bbox->axes[0][1] = (vec_t)(-BD*E + A*F); + bbox->axes[0][2] = (vec_t)(AD*E + B*F); + bbox->axes[1][0] = (vec_t)(-C*F); + bbox->axes[1][1] = (vec_t)(BD*F + A*E); + bbox->axes[1][2] = (vec_t)(-AD*F + B*E); + bbox->axes[2][0] = (vec_t)D; + bbox->axes[2][1] = (vec_t)(-B*C); + bbox->axes[2][2] = (vec_t)(A*C); + + aabb_update_radius(&bbox->aabb); +} + +int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane) +{ + vec_t fDist, fIntersect; + + // calc distance of origin from plane + fDist = DotProduct(plane, bbox->aabb.origin) + plane[3]; + + // trivial accept/reject using bounding sphere + if (fabs(fDist) > bbox->aabb.radius) + { + if (fDist < 0) + return 2; // totally inside + else + return 0; // totally outside + } + + // calc extents distance relative to plane normal + fIntersect = (vec_t)(fabs(bbox->aabb.extents[0] * DotProduct(plane, bbox->axes[0])) + + fabs(bbox->aabb.extents[1] * DotProduct(plane, bbox->axes[1])) + + fabs(bbox->aabb.extents[2] * DotProduct(plane, bbox->axes[2]))); + // accept if origin is less than this distance + if (fabs(fDist) < fIntersect) return 1; // partially inside + else if (fDist < 0) return 2; // totally inside + return 0; // totally outside +} diff --git a/libs/mathlib/linear.c b/libs/mathlib/linear.c index bdef7145..7414c135 100644 --- a/libs/mathlib/linear.c +++ b/libs/mathlib/linear.c @@ -1,100 +1,100 @@ -#ifndef __APPLE__ -#include -#else -#include -#endif -#include -#include - -#include "mathlib.h" - -#define TINY FLT_MIN - -void lubksb(float **a, int n, int *indx, float b[]) -// Solves the set of n linear equations A.X=B. Here a[n][n] is input, not as the matrix -// A but rather as its LU decomposition determined by the routine ludcmp. indx[n] is input -// as the permutation vector returned by ludcmp. b[n] is input as the right-hand side vector -// B, and returns with the solution vector X. a, n and indx are not modified by this routine -// and can be left in place for successive calls with different right-hand sides b. This routine takes -// into account the possibility that b will begin with many zero elements, so it is efficient for use -// in matrix inversion -{ - int i,ii=-1,ip,j; - float sum; - - for (i=0;i=0) - for (j=ii;j=0;i--) { - sum=b[i]; - for (j=i+1;j big) big=temp; - if (big == 0.0) return 1; - vv[i]=1.0f/big; - } - for (j=0;j= big) { - big=dum; - imax=i; - } - } - if (j != imax) { - for (k=0;k +#else +#include +#endif +#include +#include + +#include "mathlib.h" + +#define TINY FLT_MIN + +void lubksb(float **a, int n, int *indx, float b[]) +// Solves the set of n linear equations A.X=B. Here a[n][n] is input, not as the matrix +// A but rather as its LU decomposition determined by the routine ludcmp. indx[n] is input +// as the permutation vector returned by ludcmp. b[n] is input as the right-hand side vector +// B, and returns with the solution vector X. a, n and indx are not modified by this routine +// and can be left in place for successive calls with different right-hand sides b. This routine takes +// into account the possibility that b will begin with many zero elements, so it is efficient for use +// in matrix inversion +{ + int i,ii=-1,ip,j; + float sum; + + for (i=0;i=0) + for (j=ii;j=0;i--) { + sum=b[i]; + for (j=i+1;j big) big=temp; + if (big == 0.0) return 1; + vv[i]=1.0f/big; + } + for (j=0;j= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (k=0;k i ) - idst = ti-1; - - for ( tj = 0; tj < 4; tj++ ) - { - if ( tj < j ) - jdst = tj; - else - if ( tj > j ) - jdst = tj-1; - - if ( ti != i && tj != j ) - mb[idst*3 + jdst] = mr[ti*4 + tj ]; - } - } -} - -float m4_det( m4x4_t mr ) -{ - float det, result = 0, i = 1; - m3x3_t msub3; - int n; - - for ( n = 0; n < 4; n++, i *= -1 ) - { - m4_submat( mr, msub3, 0, n ); - - det = m3_det( msub3 ); - result += mr[n] * det * i; - } - - return result; -} - -int m4x4_invert(m4x4_t matrix) -{ - float mdet = m4_det( matrix ); - m3x3_t mtemp; - int i, j, sign; - m4x4_t m4x4_temp; - - if ( fabs( mdet ) < 0.0000000001 ) //% 0.0005 - return 1; - - memcpy(m4x4_temp, matrix, sizeof(m4x4_t)); - - for ( i = 0; i < 4; i++ ) - for ( j = 0; j < 4; j++ ) - { - sign = 1 - ( (i +j) % 2 ) * 2; - - m4_submat( m4x4_temp, mtemp, i, j ); - - matrix[i+j*4] = ( m3_det( mtemp ) * sign ) / mdet; - } - - return 0; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "mathlib.h" +#include "memory.h" + +void m4x4_identity(m4x4_t matrix) +{ + matrix[1] = matrix[2] = matrix[3] = + matrix[4] = matrix[6] = matrix[7] = + matrix[8] = matrix[9] = matrix[11] = + matrix[12] = matrix[13] = matrix[14] = 0; + + matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1; +} + +void m4x4_translation_for_vec3(m4x4_t matrix, const vec3_t translation) +{ + matrix[1] = matrix[2] = matrix[3] = + matrix[4] = matrix[6] = matrix[7] = + matrix[8] = matrix[9] = matrix[11] = 0; + + matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1; + + matrix[12] = translation[0]; + matrix[13] = translation[1]; + matrix[14] = translation[2]; +} + +void m4x4_rotation_for_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order) +{ + double cx, sx, cy, sy, cz, sz; + + cx = cos(DEG2RAD(euler[0])); + sx = sin(DEG2RAD(euler[0])); + cy = cos(DEG2RAD(euler[1])); + sy = sin(DEG2RAD(euler[1])); + cz = cos(DEG2RAD(euler[2])); + sz = sin(DEG2RAD(euler[2])); + + switch(order) + { + case eXYZ: + +#if 1 + + { + matrix[0] = (vec_t)(cy*cz); + matrix[1] = (vec_t)(cy*sz); + matrix[2] = (vec_t)-sy; + matrix[4] = (vec_t)(sx*sy*cz + cx*-sz); + matrix[5] = (vec_t)(sx*sy*sz + cx*cz); + matrix[6] = (vec_t)(sx*cy); + matrix[8] = (vec_t)(cx*sy*cz + sx*sz); + matrix[9] = (vec_t)(cx*sy*sz + -sx*cz); + matrix[10] = (vec_t)(cx*cy); + } + + matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; + matrix[15] = 1; + +#else + + m4x4_identity(matrix); + matrix[5] =(vec_t) cx; matrix[6] =(vec_t) sx; + matrix[9] =(vec_t)-sx; matrix[10]=(vec_t) cx; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + } +#endif + + break; + + case eYZX: + m4x4_identity(matrix); + matrix[0] =(vec_t) cy; matrix[2] =(vec_t)-sy; + matrix[8] =(vec_t) sy; matrix[10]=(vec_t) cy; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + } + break; + + case eZXY: + m4x4_identity(matrix); + matrix[0] =(vec_t) cz; matrix[1] =(vec_t) sz; + matrix[4] =(vec_t)-sz; matrix[5] =(vec_t) cz; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + } + break; + + case eXZY: + m4x4_identity(matrix); + matrix[5] =(vec_t) cx; matrix[6] =(vec_t) sx; + matrix[9] =(vec_t)-sx; matrix[10]=(vec_t) cx; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + } + break; + + case eYXZ: + +/* transposed +| cy.cz + sx.sy.-sz + -cx.sy.0 0.cz + cx.-sz + sx.0 sy.cz + -sx.cy.-sz + cx.cy.0 | +| cy.sz + sx.sy.cz + -cx.sy.0 0.sz + cx.cz + sx.0 sy.sz + -sx.cy.cz + cx.cy.0 | +| cy.0 + sx.sy.0 + -cx.sy.1 0.0 + cx.0 + sx.1 sy.0 + -sx.cy.0 + cx.cy.1 | +*/ + +#if 1 + + { + matrix[0] = (vec_t)(cy*cz + sx*sy*-sz); + matrix[1] = (vec_t)(cy*sz + sx*sy*cz); + matrix[2] = (vec_t)(-cx*sy); + matrix[4] = (vec_t)(cx*-sz); + matrix[5] = (vec_t)(cx*cz); + matrix[6] = (vec_t)(sx); + matrix[8] = (vec_t)(sy*cz + -sx*cy*-sz); + matrix[9] = (vec_t)(sy*sz + -sx*cy*cz); + matrix[10] = (vec_t)(cx*cy); + } + + matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; + matrix[15] = 1; + +#else + + m4x4_identity(matrix); + matrix[0] =(vec_t) cy; matrix[2] =(vec_t)-sy; + matrix[8] =(vec_t) sy; matrix[10]=(vec_t) cy; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + } +#endif + break; + + case eZYX: +#if 1 + + { + matrix[0] = (vec_t)(cy*cz); + matrix[4] = (vec_t)(cy*-sz); + matrix[8] = (vec_t)sy; + matrix[1] = (vec_t)(sx*sy*cz + cx*sz); + matrix[5] = (vec_t)(sx*sy*-sz + cx*cz); + matrix[9] = (vec_t)(-sx*cy); + matrix[2] = (vec_t)(cx*-sy*cz + sx*sz); + matrix[6] = (vec_t)(cx*-sy*-sz + sx*cz); + matrix[10] = (vec_t)(cx*cy); + } + + matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; + matrix[15] = 1; + +#else + + m4x4_identity(matrix); + matrix[0] =(vec_t) cz; matrix[1] =(vec_t) sz; + matrix[4] =(vec_t)-sz; matrix[5] =(vec_t) cz; + { + m4x4_t temp; + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + } + +#endif + break; + + } + +} + +void m4x4_scale_for_vec3(m4x4_t matrix, const vec3_t scale) +{ + matrix[1] = matrix[2] = matrix[3] = + matrix[4] = matrix[6] = matrix[7] = + matrix[8] = matrix[9] = matrix[11] = + matrix[12] = matrix[13] = matrix[14] = 0; + + matrix[15] = 1; + + matrix[0] = scale[0]; + matrix[5] = scale[1]; + matrix[10] = scale[2]; +} + +void m4x4_rotation_for_quat(m4x4_t matrix, const vec4_t rotation) +{ + float xx,xy,xz,xw,yy,yz,yw,zz,zw; + + xx = rotation[0] * rotation[0]; + xy = rotation[0] * rotation[1]; + xz = rotation[0] * rotation[2]; + xw = rotation[0] * rotation[3]; + + yy = rotation[1] * rotation[1]; + yz = rotation[1] * rotation[2]; + yw = rotation[1] * rotation[3]; + + zz = rotation[2] * rotation[2]; + zw = rotation[2] * rotation[3]; + + matrix[0] = 1 - 2 * ( yy + zz ); + matrix[4] = 2 * ( xy - zw ); + matrix[8] = 2 * ( xz + yw ); + + matrix[1] = 2 * ( xy + zw ); + matrix[5] = 1 - 2 * ( xx + zz ); + matrix[9] = 2 * ( yz - xw ); + + matrix[2] = 2 * ( xz - yw ); + matrix[6] = 2 * ( yz + xw ); + matrix[10] = 1 - 2 * ( xx + yy ); + + matrix[3] = matrix[7] = matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0; + matrix[15] = 1; +} + +void m4x4_rotation_for_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle) +{ + vec4_t rotation; + angle *= 0.5; + + rotation[3] = (float)sin((float)(angle)); + + rotation[0] = axis[0] * rotation[3]; + rotation[1] = axis[1] * rotation[3]; + rotation[2] = axis[2] * rotation[3]; + rotation[3] = (float)cos((float)(angle)); + + m4x4_rotation_for_quat(matrix, rotation); +} + +void m4x4_translate_by_vec3(m4x4_t matrix, const vec3_t translation) +{ + m4x4_t temp; + m4x4_translation_for_vec3(temp, translation); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order) +{ + m4x4_t temp; + m4x4_rotation_for_vec3(temp, euler, order); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_scale_by_vec3(m4x4_t matrix, const vec3_t scale) +{ + m4x4_t temp; + m4x4_scale_for_vec3(temp, scale); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_rotate_by_quat(m4x4_t matrix, const vec4_t rotation) +{ + m4x4_t temp; + m4x4_rotation_for_quat(temp, rotation); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle) +{ + m4x4_t temp; + m4x4_rotation_for_axisangle(temp, axis, angle); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale) +{ + m4x4_translate_by_vec3(matrix, translation); + m4x4_rotate_by_vec3(matrix, euler, order); + m4x4_scale_by_vec3(matrix, scale); +} + +void m4x4_pivoted_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_rotate_by_vec3(matrix, euler, order); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +void m4x4_pivoted_scale_by_vec3(m4x4_t matrix, const vec3_t scale, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_scale_by_vec3(matrix, scale); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +void m4x4_pivoted_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + + VectorAdd(pivotpoint, translation, vec3_temp); + m4x4_translate_by_vec3(matrix, vec3_temp); + m4x4_rotate_by_vec3(matrix, euler, order); + m4x4_scale_by_vec3(matrix, scale); + VectorNegative(pivotpoint, vec3_temp); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +void m4x4_pivoted_rotate_by_quat(m4x4_t matrix, const vec4_t rotation, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_rotate_by_quat(matrix, rotation); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +void m4x4_pivoted_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_rotate_by_axisangle(matrix, axis, angle); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + + +/* +A = A.B + +A0 = B0 * A0 + B1 * A4 + B2 * A8 + B3 * A12 +A4 = B4 * A0 + B5 * A4 + B6 * A8 + B7 * A12 +A8 = B8 * A0 + B9 * A4 + B10* A8 + B11* A12 +A12= B12* A0 + B13* A4 + B14* A8 + B15* A12 + +A1 = B0 * A1 + B1 * A5 + B2 * A9 + B3 * A13 +A5 = B4 * A1 + B5 * A5 + B6 * A9 + B7 * A13 +A9 = B8 * A1 + B9 * A5 + B10* A9 + B11* A13 +A13= B12* A1 + B13* A5 + B14* A9 + B15* A13 + +A2 = B0 * A2 + B1 * A6 + B2 * A10+ B3 * A14 +A6 = B4 * A2 + B5 * A6 + B6 * A10+ B7 * A14 +A10= B8 * A2 + B9 * A6 + B10* A10+ B11* A14 +A14= B12* A2 + B13* A6 + B14* A10+ B15* A14 + +A3 = B0 * A3 + B1 * A7 + B2 * A11+ B3 * A15 +A7 = B4 * A3 + B5 * A7 + B6 * A11+ B7 * A15 +A11= B8 * A3 + B9 * A7 + B10* A11+ B11* A15 +A15= B12* A3 + B13* A7 + B14* A11+ B15* A15 +*/ + +void m4x4_multiply_by_m4x4(m4x4_t dst, const m4x4_t src) +{ + vec_t dst0, dst1, dst2, dst3; + +#if 1 + + dst0 = src[0] * dst[0] + src[1] * dst[4] + src[2] * dst[8] + src[3] * dst[12]; + dst1 = src[4] * dst[0] + src[5] * dst[4] + src[6] * dst[8] + src[7] * dst[12]; + dst2 = src[8] * dst[0] + src[9] * dst[4] + src[10]* dst[8] + src[11]* dst[12]; + dst3 = src[12]* dst[0] + src[13]* dst[4] + src[14]* dst[8] + src[15]* dst[12]; + dst[0] = dst0; dst[4] = dst1; dst[8] = dst2; dst[12]= dst3; + + dst0 = src[0] * dst[1] + src[1] * dst[5] + src[2] * dst[9] + src[3] * dst[13]; + dst1 = src[4] * dst[1] + src[5] * dst[5] + src[6] * dst[9] + src[7] * dst[13]; + dst2 = src[8] * dst[1] + src[9] * dst[5] + src[10]* dst[9] + src[11]* dst[13]; + dst3 = src[12]* dst[1] + src[13]* dst[5] + src[14]* dst[9] + src[15]* dst[13]; + dst[1] = dst0; dst[5] = dst1; dst[9] = dst2; dst[13]= dst3; + + dst0 = src[0] * dst[2] + src[1] * dst[6] + src[2] * dst[10]+ src[3] * dst[14]; + dst1 = src[4] * dst[2] + src[5] * dst[6] + src[6] * dst[10]+ src[7] * dst[14]; + dst2 = src[8] * dst[2] + src[9] * dst[6] + src[10]* dst[10]+ src[11]* dst[14]; + dst3 = src[12]* dst[2] + src[13]* dst[6] + src[14]* dst[10]+ src[15]* dst[14]; + dst[2] = dst0; dst[6] = dst1; dst[10]= dst2; dst[14]= dst3; + + dst0 = src[0] * dst[3] + src[1] * dst[7] + src[2] * dst[11]+ src[3] * dst[15]; + dst1 = src[4] * dst[3] + src[5] * dst[7] + src[6] * dst[11]+ src[7] * dst[15]; + dst2 = src[8] * dst[3] + src[9] * dst[7] + src[10]* dst[11]+ src[11]* dst[15]; + dst3 = src[12]* dst[3] + src[13]* dst[7] + src[14]* dst[11]+ src[15]* dst[15]; + dst[3] = dst0; dst[7] = dst1; dst[11]= dst2; dst[15]= dst3; + +#else + + vec_t * p = dst; + for(int i=0;i<4;i++) + { + dst1 = src[0] * p[0]; + dst1 += src[1] * p[4]; + dst1 += src[2] * p[8]; + dst1 += src[3] * p[12]; + dst2 = src[4] * p[0]; + dst2 += src[5] * p[4]; + dst2 += src[6] * p[8]; + dst2 += src[7] * p[12]; + dst3 = src[8] * p[0]; + dst3 += src[9] * p[4]; + dst3 += src[10] * p[8]; + dst3 += src[11] * p[12]; + dst4 = src[12] * p[0]; + dst4 += src[13] * p[4]; + dst4 += src[14] * p[8]; + dst4 += src[15] * p[12]; + + p[0] = dst1; + p[4] = dst2; + p[8] = dst3; + p[12] = dst4; + p++; + } + +#endif +} + +/* +A = B.A + +A0 = A0 * B0 + A1 * B4 + A2 * B8 + A3 * B12 +A1 = A0 * B1 + A1 * B5 + A2 * B9 + A3 * B13 +A2 = A0 * B2 + A1 * B6 + A2 * B10+ A3 * B14 +A3 = A0 * B3 + A1 * B7 + A2 * B11+ A3 * B15 + +A4 = A4 * B0 + A5 * B4 + A6 * B8 + A7 * B12 +A5 = A4 * B1 + A5 * B5 + A6 * B9 + A7 * B13 +A6 = A4 * B2 + A5 * B6 + A6 * B10+ A7 * B14 +A7 = A4 * B3 + A5 * B7 + A6 * B11+ A7 * B15 + +A8 = A8 * B0 + A9 * B4 + A10* B8 + A11* B12 +A9 = A8 * B1 + A9 * B5 + A10* B9 + A11* B13 +A10= A8 * B2 + A9 * B6 + A10* B10+ A11* B14 +A11= A8 * B3 + A9 * B7 + A10* B11+ A11* B15 + +A12= A12* B0 + A13* B4 + A14* B8 + A15* B12 +A13= A12* B1 + A13* B5 + A14* B9 + A15* B13 +A14= A12* B2 + A13* B6 + A14* B10+ A15* B14 +A15= A12* B3 + A13* B7 + A14* B11+ A15* B15 +*/ + +void m4x4_premultiply_by_m4x4(m4x4_t dst, const m4x4_t src) +{ + vec_t dst0, dst1, dst2, dst3; + +#if 1 + + dst0 = dst[0] * src[0] + dst[1] * src[4] + dst[2] * src[8] + dst[3] * src[12]; + dst1 = dst[0] * src[1] + dst[1] * src[5] + dst[2] * src[9] + dst[3] * src[13]; + dst2 = dst[0] * src[2] + dst[1] * src[6] + dst[2] * src[10]+ dst[3] * src[14]; + dst3 = dst[0] * src[3] + dst[1] * src[7] + dst[2] * src[11]+ dst[3] * src[15]; + dst[0] = dst0; dst[1] = dst1; dst[2] = dst2; dst[3]= dst3; + + dst0 = dst[4] * src[0] + dst[5] * src[4] + dst[6] * src[8] + dst[7] * src[12]; + dst1 = dst[4] * src[1] + dst[5] * src[5] + dst[6] * src[9] + dst[7] * src[13]; + dst2 = dst[4] * src[2] + dst[5] * src[6] + dst[6] * src[10]+ dst[7] * src[14]; + dst3 = dst[4] * src[3] + dst[5] * src[7] + dst[6] * src[11]+ dst[7] * src[15]; + dst[4] = dst0; dst[5] = dst1; dst[6] = dst2; dst[7]= dst3; + + dst0 = dst[8] * src[0] + dst[9] * src[4] + dst[10]* src[8] + dst[11]* src[12]; + dst1 = dst[8] * src[1] + dst[9] * src[5] + dst[10]* src[9] + dst[11]* src[13]; + dst2 = dst[8] * src[2] + dst[9] * src[6] + dst[10]* src[10]+ dst[11]* src[14]; + dst3 = dst[8] * src[3] + dst[9] * src[7] + dst[10]* src[11]+ dst[11]* src[15]; + dst[8] = dst0; dst[9] = dst1; dst[10] = dst2; dst[11]= dst3; + + dst0 = dst[12]* src[0] + dst[13]* src[4] + dst[14]* src[8] + dst[15]* src[12]; + dst1 = dst[12]* src[1] + dst[13]* src[5] + dst[14]* src[9] + dst[15]* src[13]; + dst2 = dst[12]* src[2] + dst[13]* src[6] + dst[14]* src[10]+ dst[15]* src[14]; + dst3 = dst[12]* src[3] + dst[13]* src[7] + dst[14]* src[11]+ dst[15]* src[15]; + dst[12] = dst0; dst[13] = dst1; dst[14] = dst2; dst[15]= dst3; + +#else + + vec_t* p = dst; + for(int i=0;i<4;i++) + { + dst1 = src[0] * p[0]; + dst2 = src[1] * p[0]; + dst3 = src[2] * p[0]; + dst4 = src[3] * p[0]; + dst1 += src[4] * p[1]; + dst2 += src[5] * p[1]; + dst3 += src[6] * p[1]; + dst4 += src[7] * p[1]; + dst1 += src[8] * p[2]; + dst2 += src[9] * p[2]; + dst4 += src[11] * p[2]; + dst3 += src[10] * p[2]; + dst1 += src[12] * p[3]; + dst2 += src[13] * p[3]; + dst3 += src[14] * p[3]; + dst4 += src[15] * p[3]; + + *p++ = dst1; + *p++ = dst2; + *p++ = dst3; + *p++ = dst4; + } + +#endif +} + +void m4x4_transform_point(const m4x4_t matrix, vec3_t point) +{ + float out1, out2, out3; + + out1 = matrix[0] * point[0]; + out2 = matrix[1] * point[0]; + out3 = matrix[2] * point[0]; + out1 += matrix[4] * point[1]; + out2 += matrix[5] * point[1]; + out3 += matrix[6] * point[1]; + out1 += matrix[8] * point[2]; + out2 += matrix[9] * point[2]; + out3 += matrix[10] * point[2]; + out1 += matrix[12]; + out2 += matrix[13]; + out3 += matrix[14]; + + point[0] = out1; + point[1] = out2; + point[2] = out3; +} + +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal) +{ + float out1, out2, out3; + + out1 = matrix[0] * normal[0]; + out2 = matrix[1] * normal[0]; + out3 = matrix[2] * normal[0]; + out1 += matrix[4] * normal[1]; + out2 += matrix[5] * normal[1]; + out3 += matrix[6] * normal[1]; + out1 += matrix[8] * normal[2]; + out2 += matrix[9] * normal[2]; + out3 += matrix[10] * normal[2]; + + normal[0] = out1; + normal[1] = out2; + normal[2] = out3; +} + +void m4x4_transform_vec4(const m4x4_t matrix, vec4_t vector) +{ + float out1, out2, out3, out4; + + out1 = matrix[0] * vector[0]; + out2 = matrix[1] * vector[0]; + out3 = matrix[2] * vector[0]; + out4 = matrix[3] * vector[0]; + out1 += matrix[4] * vector[1]; + out2 += matrix[5] * vector[1]; + out3 += matrix[6] * vector[1]; + out4 += matrix[7] * vector[1]; + out1 += matrix[8] * vector[2]; + out2 += matrix[9] * vector[2]; + out3 += matrix[10] * vector[2]; + out4 += matrix[11] * vector[2]; + out1 += matrix[12] * vector[3]; + out2 += matrix[13] * vector[3]; + out3 += matrix[14] * vector[3]; + out4 += matrix[15] * vector[3]; + + vector[0] = out1; + vector[1] = out2; + vector[2] = out3; + vector[3] = out4; +} + +void m4x4_transpose(m4x4_t matrix) +{ + int i, j; + float temp, *p1, *p2; + + for (i=1; i<4; i++) { + for (j=0; j i ) + idst = ti-1; + + for ( tj = 0; tj < 4; tj++ ) + { + if ( tj < j ) + jdst = tj; + else + if ( tj > j ) + jdst = tj-1; + + if ( ti != i && tj != j ) + mb[idst*3 + jdst] = mr[ti*4 + tj ]; + } + } +} + +float m4_det( m4x4_t mr ) +{ + float det, result = 0, i = 1; + m3x3_t msub3; + int n; + + for ( n = 0; n < 4; n++, i *= -1 ) + { + m4_submat( mr, msub3, 0, n ); + + det = m3_det( msub3 ); + result += mr[n] * det * i; + } + + return result; +} + +int m4x4_invert(m4x4_t matrix) +{ + float mdet = m4_det( matrix ); + m3x3_t mtemp; + int i, j, sign; + m4x4_t m4x4_temp; + + if ( fabs( mdet ) < 0.0000000001 ) //% 0.0005 + return 1; + + memcpy(m4x4_temp, matrix, sizeof(m4x4_t)); + + for ( i = 0; i < 4; i++ ) + for ( j = 0; j < 4; j++ ) + { + sign = 1 - ( (i +j) % 2 ) * 2; + + m4_submat( m4x4_temp, mtemp, i, j ); + + matrix[i+j*4] = ( m3_det( mtemp ) * sign ) / mdet; + } + + return 0; +} diff --git a/libs/mathlib/mathlib.c b/libs/mathlib/mathlib.c index 0c26a963..b9b7b869 100644 --- a/libs/mathlib/mathlib.c +++ b/libs/mathlib/mathlib.c @@ -1,593 +1,593 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// mathlib.c -- math primitives -#include "mathlib.h" -// we use memcpy and memset -#include - -vec3_t vec3_origin = {0.0f,0.0f,0.0f}; - -/* -================ -MakeNormalVectors - -Given a normalized forward vector, create two -other perpendicular vectors -================ -*/ -void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up) -{ - float d; - - // this rotate and negate guarantees a vector - // not colinear with the original - right[1] = -forward[0]; - right[2] = forward[1]; - right[0] = forward[2]; - - d = DotProduct (right, forward); - VectorMA (right, -d, forward, right); - VectorNormalize (right, right); - CrossProduct (right, forward, up); -} - -vec_t VectorLength(vec3_t v) -{ - int i; - float length; - - length = 0.0f; - for (i=0 ; i< 3 ; i++) - length += v[i]*v[i]; - length = (float)sqrt (length); - - return length; -} - -qboolean VectorCompare (vec3_t v1, vec3_t v2) -{ - int i; - - for (i=0 ; i<3 ; i++) - if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) - return qfalse; - - return qtrue; -} - -/* -// FIXME TTimo this implementation has to be particular to radiant -// through another name I'd say -vec_t Q_rint (vec_t in) -{ - if (g_PrefsDlg.m_bNoClamp) - return in; - else - return (float)floor (in + 0.5); -} -*/ - -void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ) -{ - vc[0] = va[0] + scale*vb[0]; - vc[1] = va[1] + scale*vb[1]; - vc[2] = va[2] + scale*vb[2]; -} - -void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) -{ - cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; - cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; - cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; -} - -vec_t _DotProduct (vec3_t v1, vec3_t v2) -{ - return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; -} - -void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) -{ - out[0] = va[0]-vb[0]; - out[1] = va[1]-vb[1]; - out[2] = va[2]-vb[2]; -} - -void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) -{ - out[0] = va[0]+vb[0]; - out[1] = va[1]+vb[1]; - out[2] = va[2]+vb[2]; -} - -void _VectorCopy (vec3_t in, vec3_t out) -{ - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; -} - -vec_t VectorNormalize( const vec3_t in, vec3_t out ) { - vec_t length, ilength; - - length = (vec_t)sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); - if (length == 0) - { - VectorClear (out); - return 0; - } - - ilength = 1.0f/length; - out[0] = in[0]*ilength; - out[1] = in[1]*ilength; - out[2] = in[2]*ilength; - - return length; -} - -vec_t ColorNormalize( const vec3_t in, vec3_t out ) { - float max, scale; - - max = in[0]; - if (in[1] > max) - max = in[1]; - if (in[2] > max) - max = in[2]; - - if (max == 0) { - out[0] = out[1] = out[2] = 1.0; - return 0; - } - - scale = 1.0f / max; - - VectorScale (in, scale, out); - - return max; -} - -void VectorInverse (vec3_t v) -{ - v[0] = -v[0]; - v[1] = -v[1]; - v[2] = -v[2]; -} - -/* -void VectorScale (vec3_t v, vec_t scale, vec3_t out) -{ - out[0] = v[0] * scale; - out[1] = v[1] * scale; - out[2] = v[2] * scale; -} -*/ - -void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out) -{ - vec3_t vWork, va; - int nIndex[3][2]; - int i; - - VectorCopy(vIn, va); - VectorCopy(va, vWork); - nIndex[0][0] = 1; nIndex[0][1] = 2; - nIndex[1][0] = 2; nIndex[1][1] = 0; - nIndex[2][0] = 0; nIndex[2][1] = 1; - - for (i = 0; i < 3; i++) - { - if (vRotation[i] != 0) - { - float dAngle = vRotation[i] * Q_PI / 180.0f; - float c = (vec_t)cos(dAngle); - float s = (vec_t)sin(dAngle); - vWork[nIndex[i][0]] = va[nIndex[i][0]] * c - va[nIndex[i][1]] * s; - vWork[nIndex[i][1]] = va[nIndex[i][0]] * s + va[nIndex[i][1]] * c; - } - VectorCopy(vWork, va); - } - VectorCopy(vWork, out); -} - -void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out) -{ - vec3_t vTemp, vTemp2; - - VectorSubtract(vIn, vOrigin, vTemp); - VectorRotate(vTemp, vRotation, vTemp2); - VectorAdd(vTemp2, vOrigin, out); -} - -void VectorPolar(vec3_t v, float radius, float theta, float phi) -{ - v[0]=(float)(radius * cos(theta) * cos(phi)); - v[1]=(float)(radius * sin(theta) * cos(phi)); - v[2]=(float)(radius * sin(phi)); -} - -void VectorSnap(vec3_t v) -{ - int i; - for (i = 0; i < 3; i++) - { - v[i] = (vec_t)floor (v[i] + 0.5); - } -} - -void VectorISnap(vec3_t point, int snap) -{ - int i; - for (i = 0 ;i < 3 ; i++) - { - point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; - } -} - -void VectorFSnap(vec3_t point, float snap) -{ - int i; - for (i = 0 ;i < 3 ; i++) - { - point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; - } -} - -void _Vector5Add (vec5_t va, vec5_t vb, vec5_t out) -{ - out[0] = va[0]+vb[0]; - out[1] = va[1]+vb[1]; - out[2] = va[2]+vb[2]; - out[3] = va[3]+vb[3]; - out[4] = va[4]+vb[4]; -} - -void _Vector5Scale (vec5_t v, vec_t scale, vec5_t out) -{ - out[0] = v[0] * scale; - out[1] = v[1] * scale; - out[2] = v[2] * scale; - out[3] = v[3] * scale; - out[4] = v[4] * scale; -} - -void _Vector53Copy (vec5_t in, vec3_t out) -{ - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; -} - -// NOTE: added these from Ritual's Q3Radiant -void ClearBounds (vec3_t mins, vec3_t maxs) -{ - mins[0] = mins[1] = mins[2] = 99999; - maxs[0] = maxs[1] = maxs[2] = -99999; -} - -void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) -{ - int i; - vec_t val; - - for (i=0 ; i<3 ; i++) - { - val = v[i]; - if (val < mins[i]) - mins[i] = val; - if (val > maxs[i]) - maxs[i] = val; - } -} - -#define PITCH 0 // up / down -#define YAW 1 // left / right -#define ROLL 2 // fall over -#ifndef M_PI -#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h -#endif - -void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) -{ - float angle; - static float sr, sp, sy, cr, cp, cy; - // static to help MS compiler fp bugs - - angle = angles[YAW] * (M_PI*2.0f / 360.0f); - sy = (vec_t)sin(angle); - cy = (vec_t)cos(angle); - angle = angles[PITCH] * (M_PI*2.0f / 360.0f); - sp = (vec_t)sin(angle); - cp = (vec_t)cos(angle); - angle = angles[ROLL] * (M_PI*2.0f / 360.0f); - sr = (vec_t)sin(angle); - cr = (vec_t)cos(angle); - - if (forward) - { - forward[0] = cp*cy; - forward[1] = cp*sy; - forward[2] = -sp; - } - if (right) - { - right[0] = -sr*sp*cy+cr*sy; - right[1] = -sr*sp*sy-cr*cy; - right[2] = -sr*cp; - } - if (up) - { - up[0] = cr*sp*cy+sr*sy; - up[1] = cr*sp*sy-sr*cy; - up[2] = cr*cp; - } -} - -void VectorToAngles( vec3_t vec, vec3_t angles ) -{ - float forward; - float yaw, pitch; - - if ( ( vec[ 0 ] == 0 ) && ( vec[ 1 ] == 0 ) ) - { - yaw = 0; - if ( vec[ 2 ] > 0 ) - { - pitch = 90; - } - else - { - pitch = 270; - } - } - else - { - yaw = (vec_t)atan2( vec[ 1 ], vec[ 0 ] ) * 180 / M_PI; - if ( yaw < 0 ) - { - yaw += 360; - } - - forward = ( float )sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] ); - pitch = (vec_t)atan2( vec[ 2 ], forward ) * 180 / M_PI; - if ( pitch < 0 ) - { - pitch += 360; - } - } - - angles[ 0 ] = pitch; - angles[ 1 ] = yaw; - angles[ 2 ] = 0; -} - -/* -===================== -PlaneFromPoints - -Returns false if the triangle is degenrate. -The normal will point out of the clock for clockwise ordered points -===================== -*/ -qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) { - vec3_t d1, d2; - - VectorSubtract( b, a, d1 ); - VectorSubtract( c, a, d2 ); - CrossProduct( d2, d1, plane ); - if ( VectorNormalize( plane, plane ) == 0 ) { - return qfalse; - } - - plane[3] = DotProduct( a, plane ); - return qtrue; -} - -/* -** NormalToLatLong -** -** We use two byte encoded normals in some space critical applications. -** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format -** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format -** -*/ -void NormalToLatLong( const vec3_t normal, byte bytes[2] ) { - // check for singularities - if ( normal[0] == 0 && normal[1] == 0 ) { - if ( normal[2] > 0 ) { - bytes[0] = 0; - bytes[1] = 0; // lat = 0, long = 0 - } else { - bytes[0] = 128; - bytes[1] = 0; // lat = 0, long = 128 - } - } else { - int a, b; - - a = (int)( RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f ) ); - a &= 0xff; - - b = (int)( RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f ) ); - b &= 0xff; - - bytes[0] = b; // longitude - bytes[1] = a; // lattitude - } -} - -/* -================= -PlaneTypeForNormal -================= -*/ -int PlaneTypeForNormal (vec3_t normal) { - if (normal[0] == 1.0 || normal[0] == -1.0) - return PLANE_X; - if (normal[1] == 1.0 || normal[1] == -1.0) - return PLANE_Y; - if (normal[2] == 1.0 || normal[2] == -1.0) - return PLANE_Z; - - return PLANE_NON_AXIAL; -} - -/* -================ -MatrixMultiply -================ -*/ -void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) { - out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + - in1[0][2] * in2[2][0]; - out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + - in1[0][2] * in2[2][1]; - out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + - in1[0][2] * in2[2][2]; - out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + - in1[1][2] * in2[2][0]; - out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + - in1[1][2] * in2[2][1]; - out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + - in1[1][2] * in2[2][2]; - out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + - in1[2][2] * in2[2][0]; - out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + - in1[2][2] * in2[2][1]; - out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + - in1[2][2] * in2[2][2]; -} - -void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) -{ - float d; - vec3_t n; - float inv_denom; - - inv_denom = 1.0F / DotProduct( normal, normal ); - - d = DotProduct( normal, p ) * inv_denom; - - n[0] = normal[0] * inv_denom; - n[1] = normal[1] * inv_denom; - n[2] = normal[2] * inv_denom; - - dst[0] = p[0] - d * n[0]; - dst[1] = p[1] - d * n[1]; - dst[2] = p[2] - d * n[2]; -} - -/* -** assumes "src" is normalized -*/ -void PerpendicularVector( vec3_t dst, const vec3_t src ) -{ - int pos; - int i; - vec_t minelem = 1.0F; - vec3_t tempvec; - - /* - ** find the smallest magnitude axially aligned vector - */ - for ( pos = 0, i = 0; i < 3; i++ ) - { - if ( fabs( src[i] ) < minelem ) - { - pos = i; - minelem = (vec_t)fabs( src[i] ); - } - } - tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; - tempvec[pos] = 1.0F; - - /* - ** project the point onto the plane defined by src - */ - ProjectPointOnPlane( dst, tempvec, src ); - - /* - ** normalize the result - */ - VectorNormalize( dst, dst ); -} - -/* -=============== -RotatePointAroundVector - -This is not implemented very well... -=============== -*/ -void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, - float degrees ) { - float m[3][3]; - float im[3][3]; - float zrot[3][3]; - float tmpmat[3][3]; - float rot[3][3]; - int i; - vec3_t vr, vup, vf; - float rad; - - vf[0] = dir[0]; - vf[1] = dir[1]; - vf[2] = dir[2]; - - PerpendicularVector( vr, dir ); - CrossProduct( vr, vf, vup ); - - m[0][0] = vr[0]; - m[1][0] = vr[1]; - m[2][0] = vr[2]; - - m[0][1] = vup[0]; - m[1][1] = vup[1]; - m[2][1] = vup[2]; - - m[0][2] = vf[0]; - m[1][2] = vf[1]; - m[2][2] = vf[2]; - - memcpy( im, m, sizeof( im ) ); - - im[0][1] = m[1][0]; - im[0][2] = m[2][0]; - im[1][0] = m[0][1]; - im[1][2] = m[2][1]; - im[2][0] = m[0][2]; - im[2][1] = m[1][2]; - - memset( zrot, 0, sizeof( zrot ) ); - zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; - - rad = DEG2RAD( degrees ); - zrot[0][0] = (vec_t)cos( rad ); - zrot[0][1] = (vec_t)sin( rad ); - zrot[1][0] = (vec_t)-sin( rad ); - zrot[1][1] = (vec_t)cos( rad ); - - MatrixMultiply( m, zrot, tmpmat ); - MatrixMultiply( tmpmat, im, rot ); - - for ( i = 0; i < 3; i++ ) { - dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// mathlib.c -- math primitives +#include "mathlib.h" +// we use memcpy and memset +#include + +vec3_t vec3_origin = {0.0f,0.0f,0.0f}; + +/* +================ +MakeNormalVectors + +Given a normalized forward vector, create two +other perpendicular vectors +================ +*/ +void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up) +{ + float d; + + // this rotate and negate guarantees a vector + // not colinear with the original + right[1] = -forward[0]; + right[2] = forward[1]; + right[0] = forward[2]; + + d = DotProduct (right, forward); + VectorMA (right, -d, forward, right); + VectorNormalize (right, right); + CrossProduct (right, forward, up); +} + +vec_t VectorLength(vec3_t v) +{ + int i; + float length; + + length = 0.0f; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = (float)sqrt (length); + + return length; +} + +qboolean VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) + return qfalse; + + return qtrue; +} + +/* +// FIXME TTimo this implementation has to be particular to radiant +// through another name I'd say +vec_t Q_rint (vec_t in) +{ + if (g_PrefsDlg.m_bNoClamp) + return in; + else + return (float)floor (in + 0.5); +} +*/ + +void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +vec_t VectorNormalize( const vec3_t in, vec3_t out ) { + vec_t length, ilength; + + length = (vec_t)sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0f/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +vec_t ColorNormalize( const vec3_t in, vec3_t out ) { + float max, scale; + + max = in[0]; + if (in[1] > max) + max = in[1]; + if (in[2] > max) + max = in[2]; + + if (max == 0) { + out[0] = out[1] = out[2] = 1.0; + return 0; + } + + scale = 1.0f / max; + + VectorScale (in, scale, out); + + return max; +} + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +/* +void VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} +*/ + +void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out) +{ + vec3_t vWork, va; + int nIndex[3][2]; + int i; + + VectorCopy(vIn, va); + VectorCopy(va, vWork); + nIndex[0][0] = 1; nIndex[0][1] = 2; + nIndex[1][0] = 2; nIndex[1][1] = 0; + nIndex[2][0] = 0; nIndex[2][1] = 1; + + for (i = 0; i < 3; i++) + { + if (vRotation[i] != 0) + { + float dAngle = vRotation[i] * Q_PI / 180.0f; + float c = (vec_t)cos(dAngle); + float s = (vec_t)sin(dAngle); + vWork[nIndex[i][0]] = va[nIndex[i][0]] * c - va[nIndex[i][1]] * s; + vWork[nIndex[i][1]] = va[nIndex[i][0]] * s + va[nIndex[i][1]] * c; + } + VectorCopy(vWork, va); + } + VectorCopy(vWork, out); +} + +void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out) +{ + vec3_t vTemp, vTemp2; + + VectorSubtract(vIn, vOrigin, vTemp); + VectorRotate(vTemp, vRotation, vTemp2); + VectorAdd(vTemp2, vOrigin, out); +} + +void VectorPolar(vec3_t v, float radius, float theta, float phi) +{ + v[0]=(float)(radius * cos(theta) * cos(phi)); + v[1]=(float)(radius * sin(theta) * cos(phi)); + v[2]=(float)(radius * sin(phi)); +} + +void VectorSnap(vec3_t v) +{ + int i; + for (i = 0; i < 3; i++) + { + v[i] = (vec_t)floor (v[i] + 0.5); + } +} + +void VectorISnap(vec3_t point, int snap) +{ + int i; + for (i = 0 ;i < 3 ; i++) + { + point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; + } +} + +void VectorFSnap(vec3_t point, float snap) +{ + int i; + for (i = 0 ;i < 3 ; i++) + { + point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; + } +} + +void _Vector5Add (vec5_t va, vec5_t vb, vec5_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; + out[3] = va[3]+vb[3]; + out[4] = va[4]+vb[4]; +} + +void _Vector5Scale (vec5_t v, vec_t scale, vec5_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; + out[3] = v[3] * scale; + out[4] = v[4] * scale; +} + +void _Vector53Copy (vec5_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +// NOTE: added these from Ritual's Q3Radiant +void ClearBounds (vec3_t mins, vec3_t maxs) +{ + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) +{ + int i; + vec_t val; + + for (i=0 ; i<3 ; i++) + { + val = v[i]; + if (val < mins[i]) + mins[i] = val; + if (val > maxs[i]) + maxs[i] = val; + } +} + +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over +#ifndef M_PI +#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h +#endif + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + static float sr, sp, sy, cr, cp, cy; + // static to help MS compiler fp bugs + + angle = angles[YAW] * (M_PI*2.0f / 360.0f); + sy = (vec_t)sin(angle); + cy = (vec_t)cos(angle); + angle = angles[PITCH] * (M_PI*2.0f / 360.0f); + sp = (vec_t)sin(angle); + cp = (vec_t)cos(angle); + angle = angles[ROLL] * (M_PI*2.0f / 360.0f); + sr = (vec_t)sin(angle); + cr = (vec_t)cos(angle); + + if (forward) + { + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + } + if (right) + { + right[0] = -sr*sp*cy+cr*sy; + right[1] = -sr*sp*sy-cr*cy; + right[2] = -sr*cp; + } + if (up) + { + up[0] = cr*sp*cy+sr*sy; + up[1] = cr*sp*sy-sr*cy; + up[2] = cr*cp; + } +} + +void VectorToAngles( vec3_t vec, vec3_t angles ) +{ + float forward; + float yaw, pitch; + + if ( ( vec[ 0 ] == 0 ) && ( vec[ 1 ] == 0 ) ) + { + yaw = 0; + if ( vec[ 2 ] > 0 ) + { + pitch = 90; + } + else + { + pitch = 270; + } + } + else + { + yaw = (vec_t)atan2( vec[ 1 ], vec[ 0 ] ) * 180 / M_PI; + if ( yaw < 0 ) + { + yaw += 360; + } + + forward = ( float )sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] ); + pitch = (vec_t)atan2( vec[ 2 ], forward ) * 180 / M_PI; + if ( pitch < 0 ) + { + pitch += 360; + } + } + + angles[ 0 ] = pitch; + angles[ 1 ] = yaw; + angles[ 2 ] = 0; +} + +/* +===================== +PlaneFromPoints + +Returns false if the triangle is degenrate. +The normal will point out of the clock for clockwise ordered points +===================== +*/ +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) { + vec3_t d1, d2; + + VectorSubtract( b, a, d1 ); + VectorSubtract( c, a, d2 ); + CrossProduct( d2, d1, plane ); + if ( VectorNormalize( plane, plane ) == 0 ) { + return qfalse; + } + + plane[3] = DotProduct( a, plane ); + return qtrue; +} + +/* +** NormalToLatLong +** +** We use two byte encoded normals in some space critical applications. +** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format +** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format +** +*/ +void NormalToLatLong( const vec3_t normal, byte bytes[2] ) { + // check for singularities + if ( normal[0] == 0 && normal[1] == 0 ) { + if ( normal[2] > 0 ) { + bytes[0] = 0; + bytes[1] = 0; // lat = 0, long = 0 + } else { + bytes[0] = 128; + bytes[1] = 0; // lat = 0, long = 128 + } + } else { + int a, b; + + a = (int)( RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f ) ); + a &= 0xff; + + b = (int)( RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f ) ); + b &= 0xff; + + bytes[0] = b; // longitude + bytes[1] = a; // lattitude + } +} + +/* +================= +PlaneTypeForNormal +================= +*/ +int PlaneTypeForNormal (vec3_t normal) { + if (normal[0] == 1.0 || normal[0] == -1.0) + return PLANE_X; + if (normal[1] == 1.0 || normal[1] == -1.0) + return PLANE_Y; + if (normal[2] == 1.0 || normal[2] == -1.0) + return PLANE_Z; + + return PLANE_NON_AXIAL; +} + +/* +================ +MatrixMultiply +================ +*/ +void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) { + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} + +void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) +{ + float d; + vec3_t n; + float inv_denom; + + inv_denom = 1.0F / DotProduct( normal, normal ); + + d = DotProduct( normal, p ) * inv_denom; + + n[0] = normal[0] * inv_denom; + n[1] = normal[1] * inv_denom; + n[2] = normal[2] * inv_denom; + + dst[0] = p[0] - d * n[0]; + dst[1] = p[1] - d * n[1]; + dst[2] = p[2] - d * n[2]; +} + +/* +** assumes "src" is normalized +*/ +void PerpendicularVector( vec3_t dst, const vec3_t src ) +{ + int pos; + int i; + vec_t minelem = 1.0F; + vec3_t tempvec; + + /* + ** find the smallest magnitude axially aligned vector + */ + for ( pos = 0, i = 0; i < 3; i++ ) + { + if ( fabs( src[i] ) < minelem ) + { + pos = i; + minelem = (vec_t)fabs( src[i] ); + } + } + tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; + tempvec[pos] = 1.0F; + + /* + ** project the point onto the plane defined by src + */ + ProjectPointOnPlane( dst, tempvec, src ); + + /* + ** normalize the result + */ + VectorNormalize( dst, dst ); +} + +/* +=============== +RotatePointAroundVector + +This is not implemented very well... +=============== +*/ +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, + float degrees ) { + float m[3][3]; + float im[3][3]; + float zrot[3][3]; + float tmpmat[3][3]; + float rot[3][3]; + int i; + vec3_t vr, vup, vf; + float rad; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVector( vr, dir ); + CrossProduct( vr, vf, vup ); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + memcpy( im, m, sizeof( im ) ); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + memset( zrot, 0, sizeof( zrot ) ); + zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; + + rad = DEG2RAD( degrees ); + zrot[0][0] = (vec_t)cos( rad ); + zrot[0][1] = (vec_t)sin( rad ); + zrot[1][0] = (vec_t)-sin( rad ); + zrot[1][1] = (vec_t)cos( rad ); + + MatrixMultiply( m, zrot, tmpmat ); + MatrixMultiply( tmpmat, im, rot ); + + for ( i = 0; i < 3; i++ ) { + dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; + } +} diff --git a/libs/mathlib/ray.c b/libs/mathlib/ray.c index 08cb9f87..cfe4bfd4 100644 --- a/libs/mathlib/ray.c +++ b/libs/mathlib/ray.c @@ -1,135 +1,135 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "mathlib.h" -/*! for memcpy */ -#include - -vec3_t identity = { 0,0,0 }; - -void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction) -{ - VectorCopy(origin, ray->origin); - VectorCopy(direction, ray->direction); -} - -void ray_transform(ray_t *ray, const m4x4_t matrix) -{ - m4x4_transform_point(matrix, ray->origin); - m4x4_transform_normal(matrix, ray->direction); -} - -vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence) -{ - vec3_t displacement; - vec_t depth; - - // calc displacement of test point from ray origin - VectorSubtract(point, ray->origin, displacement); - // calc length of displacement vector along ray direction - depth = DotProduct(displacement, ray->direction); - if(depth < 0.0f) return (vec_t)VEC_MAX; - // calc position of closest point on ray to test point - VectorMA (ray->origin, depth, ray->direction, displacement); - // calc displacement of test point from closest point - VectorSubtract(point, displacement, displacement); - // calc length of displacement, subtract depth-dependant epsilon - if (VectorLength(displacement) - (epsilon + (depth * divergence)) > 0.0f) return (vec_t)VEC_MAX; - return depth; -} - -// Tomas Moller and Ben Trumbore. Fast, minimum storage ray-triangle intersection. Journal of graphics tools, 2(1):21-28, 1997 - -#define EPSILON 0.000001 - -vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2) -{ - float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; - float det,inv_det; - float u, v; - vec_t depth = (vec_t)VEC_MAX; - - /* find vectors for two edges sharing vert0 */ - VectorSubtract(vert1, vert0, edge1); - VectorSubtract(vert2, vert0, edge2); - - /* begin calculating determinant - also used to calculate U parameter */ - CrossProduct(ray->direction, edge2, pvec); - - /* if determinant is near zero, ray lies in plane of triangle */ - det = DotProduct(edge1, pvec); - - if (bCullBack == qtrue) - { - if (det < EPSILON) - return depth; - - // calculate distance from vert0 to ray origin - VectorSubtract(ray->origin, vert0, tvec); - - // calculate U parameter and test bounds - u = DotProduct(tvec, pvec); - if (u < 0.0 || u > det) - return depth; - - // prepare to test V parameter - CrossProduct(tvec, edge1, qvec); - - // calculate V parameter and test bounds - v = DotProduct(ray->direction, qvec); - if (v < 0.0 || u + v > det) - return depth; - - // calculate t, scale parameters, ray intersects triangle - depth = DotProduct(edge2, qvec); - inv_det = 1.0f / det; - depth *= inv_det; - //u *= inv_det; - //v *= inv_det; - } - else - { - /* the non-culling branch */ - if (det > -EPSILON && det < EPSILON) - return depth; - inv_det = 1.0f / det; - - /* calculate distance from vert0 to ray origin */ - VectorSubtract(ray->origin, vert0, tvec); - - /* calculate U parameter and test bounds */ - u = DotProduct(tvec, pvec) * inv_det; - if (u < 0.0 || u > 1.0) - return depth; - - /* prepare to test V parameter */ - CrossProduct(tvec, edge1, qvec); - - /* calculate V parameter and test bounds */ - v = DotProduct(ray->direction, qvec) * inv_det; - if (v < 0.0 || u + v > 1.0) - return depth; - - /* calculate t, ray intersects triangle */ - depth = DotProduct(edge2, qvec) * inv_det; - } - return depth; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "mathlib.h" +/*! for memcpy */ +#include + +vec3_t identity = { 0,0,0 }; + +void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction) +{ + VectorCopy(origin, ray->origin); + VectorCopy(direction, ray->direction); +} + +void ray_transform(ray_t *ray, const m4x4_t matrix) +{ + m4x4_transform_point(matrix, ray->origin); + m4x4_transform_normal(matrix, ray->direction); +} + +vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence) +{ + vec3_t displacement; + vec_t depth; + + // calc displacement of test point from ray origin + VectorSubtract(point, ray->origin, displacement); + // calc length of displacement vector along ray direction + depth = DotProduct(displacement, ray->direction); + if(depth < 0.0f) return (vec_t)VEC_MAX; + // calc position of closest point on ray to test point + VectorMA (ray->origin, depth, ray->direction, displacement); + // calc displacement of test point from closest point + VectorSubtract(point, displacement, displacement); + // calc length of displacement, subtract depth-dependant epsilon + if (VectorLength(displacement) - (epsilon + (depth * divergence)) > 0.0f) return (vec_t)VEC_MAX; + return depth; +} + +// Tomas Moller and Ben Trumbore. Fast, minimum storage ray-triangle intersection. Journal of graphics tools, 2(1):21-28, 1997 + +#define EPSILON 0.000001 + +vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2) +{ + float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + float det,inv_det; + float u, v; + vec_t depth = (vec_t)VEC_MAX; + + /* find vectors for two edges sharing vert0 */ + VectorSubtract(vert1, vert0, edge1); + VectorSubtract(vert2, vert0, edge2); + + /* begin calculating determinant - also used to calculate U parameter */ + CrossProduct(ray->direction, edge2, pvec); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = DotProduct(edge1, pvec); + + if (bCullBack == qtrue) + { + if (det < EPSILON) + return depth; + + // calculate distance from vert0 to ray origin + VectorSubtract(ray->origin, vert0, tvec); + + // calculate U parameter and test bounds + u = DotProduct(tvec, pvec); + if (u < 0.0 || u > det) + return depth; + + // prepare to test V parameter + CrossProduct(tvec, edge1, qvec); + + // calculate V parameter and test bounds + v = DotProduct(ray->direction, qvec); + if (v < 0.0 || u + v > det) + return depth; + + // calculate t, scale parameters, ray intersects triangle + depth = DotProduct(edge2, qvec); + inv_det = 1.0f / det; + depth *= inv_det; + //u *= inv_det; + //v *= inv_det; + } + else + { + /* the non-culling branch */ + if (det > -EPSILON && det < EPSILON) + return depth; + inv_det = 1.0f / det; + + /* calculate distance from vert0 to ray origin */ + VectorSubtract(ray->origin, vert0, tvec); + + /* calculate U parameter and test bounds */ + u = DotProduct(tvec, pvec) * inv_det; + if (u < 0.0 || u > 1.0) + return depth; + + /* prepare to test V parameter */ + CrossProduct(tvec, edge1, qvec); + + /* calculate V parameter and test bounds */ + v = DotProduct(ray->direction, qvec) * inv_det; + if (v < 0.0 || u + v > 1.0) + return depth; + + /* calculate t, ray intersects triangle */ + depth = DotProduct(edge2, qvec) * inv_det; + } + return depth; +} diff --git a/libs/md5lib.h b/libs/md5lib.h index 32963357..d56f0263 100644 --- a/libs/md5lib.h +++ b/libs/md5lib.h @@ -1,91 +1,91 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5lib.h,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5lib.h,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/libs/md5lib/md5lib.c b/libs/md5lib/md5lib.c index 6fb45f13..60b45148 100644 --- a/libs/md5lib/md5lib.c +++ b/libs/md5lib/md5lib.c @@ -1,395 +1,395 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5lib.c,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2003-07-17 ydnar added to gtkradiant project from - http://sourceforge.net/projects/libmd5-rfc/ - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5lib.h" /* ydnar */ -#include - -/* ydnar: gtkradiant endian picking */ -#ifdef _SGI_SOURCE -#define __BIG_ENDIAN__ -#endif - -#ifdef __BIG_ENDIAN__ -#define ARCH_IS_BIG_ENDIAN 1 -#else -#define ARCH_IS_BIG_ENDIAN 0 -#endif -/* ydnar: end */ - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5lib.c,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2003-07-17 ydnar added to gtkradiant project from + http://sourceforge.net/projects/libmd5-rfc/ + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5lib.h" /* ydnar */ +#include + +/* ydnar: gtkradiant endian picking */ +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ +#define ARCH_IS_BIG_ENDIAN 1 +#else +#define ARCH_IS_BIG_ENDIAN 0 +#endif +/* ydnar: end */ + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/libs/missing.h b/libs/missing.h index a9288d5c..f374d1ac 100644 --- a/libs/missing.h +++ b/libs/missing.h @@ -1,212 +1,212 @@ -/* -Copyright (c) 2001, Loki software, inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the name of Loki software nor the names of its contributors may be used -to endorse or promote products derived from this software without specific prior -written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _MISSING_H_ -#define _MISSING_H_ - -// NOTE TTimo -// this goes along with str.h and provides various utility classes -// and portability defines -// the filename is a legecy issue, it would be better to clean that up -// in a central 'portability' lib - -#include -#include - -#ifdef _WIN32 -#include -#include - -#define MyCopyFile(a,b) CopyFile(a,b,FALSE) - -#define S_ISDIR(mode) (mode & _S_IFDIR) -#define R_OK 04 -#define mymkdir(a,b) _mkdir(a) - -#else - -#define MyCopyFile CopyFile -#define mymkdir(a,b) mkdir(a,b) - -#endif - -#ifndef _WIN32 - -// LZ: very ugly hacks -inline int GetLastError () { return 0; }; - -// temp stuff -inline int GetPrivateProfileInt(char* a, char* b, int i, char* c) { return i; }; -#define VERIFY(a) a; -int GetFullPathName(const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart); -bool CopyFile(const char *lpExistingFileName, const char *lpNewFileName); - -#ifndef APIENTRY -#define APIENTRY -#endif - -int MemorySize(void *ptr); -#define _msize MemorySize - -#define MK_LBUTTON 0x0001 -#define MK_RBUTTON 0x0002 -#define MK_SHIFT 0x0004 -#define MK_CONTROL 0x0008 -#define MK_MBUTTON 0x0010 - -#endif - -#define CString Str -#include "str.h" - -class CPtrArray -{ -public: - CPtrArray () - { m_ptrs = g_ptr_array_new (); }; - virtual ~CPtrArray () - { g_ptr_array_free (m_ptrs, TRUE); }; - - void* operator[](int i) const - { return g_ptr_array_index (m_ptrs,i); }; - void* GetAt(int i) const - { return g_ptr_array_index (m_ptrs,i); }; - int GetSize () const - { return m_ptrs->len; }; - void Add (void* ptr) - { g_ptr_array_add (m_ptrs, ptr); }; - void RemoveAll () - { g_ptr_array_set_size (m_ptrs, 0); }; - void RemoveAt(int index, int count = 1) - { - if ((index < 0) || (count < 0) || (count + index > (int)m_ptrs->len)) - return; - for (; count > 0; count--) - g_ptr_array_remove_index (m_ptrs, index); - } - void InsertAt(int nStartIndex, CPtrArray* pNewArray) - { - for (int i = 0; i < pNewArray->GetSize(); i++) - InsertAt(nStartIndex+i, pNewArray->GetAt(i)); - } - void InsertAt(int nIndex, void* newElement, int nCount = 1) - { - if ((guint32)nIndex >= m_ptrs->len) - { - g_ptr_array_set_size (m_ptrs, nIndex + nCount); // grow so nIndex is valid - } - else - { - // inserting in the middle of the array - int nOldSize = m_ptrs->len; - g_ptr_array_set_size (m_ptrs, m_ptrs->len + nCount); - // shift old data up to fill gap - memmove(&m_ptrs->pdata[nIndex+nCount], &m_ptrs->pdata[nIndex], - (nOldSize-nIndex) * sizeof(gpointer)); - - memset(&m_ptrs->pdata[nIndex], 0, nCount * sizeof(gpointer)); - } - - // insert new value in the gap - while (nCount--) - m_ptrs->pdata[nIndex++] = newElement; - } - void Copy(const CPtrArray& src) - { - g_ptr_array_set_size (m_ptrs, src.m_ptrs->len); - memcpy (m_ptrs->pdata, src.m_ptrs->pdata, m_ptrs->len*sizeof(gpointer)); - } - -protected: - GPtrArray* m_ptrs; -}; - -typedef struct stringmap_s -{ - char* key; - char* value; -} stringmap_t; - -class CMapStringToString -{ -public: - CMapStringToString () - { m_map = g_ptr_array_new (); }; - ~CMapStringToString () - { - for (guint32 i = 0; i < m_map->len; i++) - FreeElement ((stringmap_t*)g_ptr_array_index (m_map,i)); - g_ptr_array_set_size (m_map, 0); - g_ptr_array_free (m_map, TRUE); - }; - void SetAt(char* key, char* newValue) - { - for (guint32 i = 0; i < m_map->len; i++) - { - stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); - if (strcmp (entry->key, key) == 0) - { - g_free (entry->value); - entry->value = g_strdup (newValue); - return; - } - } - stringmap_t* entry = (stringmap_t*)g_malloc (sizeof (stringmap_t)); - entry->key = g_strdup (key); - entry->value = g_strdup (newValue); - g_ptr_array_add (m_map, entry); - } - - bool Lookup(const char* key, CString& rValue) const - { - for (guint32 i = 0; i < m_map->len; i++) - { - stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); - if (strcmp (entry->key, key) == 0) - { - rValue = entry->value; - return true; - } - } - return false; - } - -protected: - GPtrArray* m_map; - - void FreeElement(stringmap_t* elem) - { - g_free (elem->key); - g_free (elem->value); - g_free (elem); - }; -}; - -#endif // _MISSING_H_ +/* +Copyright (c) 2001, Loki software, inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the name of Loki software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _MISSING_H_ +#define _MISSING_H_ + +// NOTE TTimo +// this goes along with str.h and provides various utility classes +// and portability defines +// the filename is a legecy issue, it would be better to clean that up +// in a central 'portability' lib + +#include +#include + +#ifdef _WIN32 +#include +#include + +#define MyCopyFile(a,b) CopyFile(a,b,FALSE) + +#define S_ISDIR(mode) (mode & _S_IFDIR) +#define R_OK 04 +#define mymkdir(a,b) _mkdir(a) + +#else + +#define MyCopyFile CopyFile +#define mymkdir(a,b) mkdir(a,b) + +#endif + +#ifndef _WIN32 + +// LZ: very ugly hacks +inline int GetLastError () { return 0; }; + +// temp stuff +inline int GetPrivateProfileInt(char* a, char* b, int i, char* c) { return i; }; +#define VERIFY(a) a; +int GetFullPathName(const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart); +bool CopyFile(const char *lpExistingFileName, const char *lpNewFileName); + +#ifndef APIENTRY +#define APIENTRY +#endif + +int MemorySize(void *ptr); +#define _msize MemorySize + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 + +#endif + +#define CString Str +#include "str.h" + +class CPtrArray +{ +public: + CPtrArray () + { m_ptrs = g_ptr_array_new (); }; + virtual ~CPtrArray () + { g_ptr_array_free (m_ptrs, TRUE); }; + + void* operator[](int i) const + { return g_ptr_array_index (m_ptrs,i); }; + void* GetAt(int i) const + { return g_ptr_array_index (m_ptrs,i); }; + int GetSize () const + { return m_ptrs->len; }; + void Add (void* ptr) + { g_ptr_array_add (m_ptrs, ptr); }; + void RemoveAll () + { g_ptr_array_set_size (m_ptrs, 0); }; + void RemoveAt(int index, int count = 1) + { + if ((index < 0) || (count < 0) || (count + index > (int)m_ptrs->len)) + return; + for (; count > 0; count--) + g_ptr_array_remove_index (m_ptrs, index); + } + void InsertAt(int nStartIndex, CPtrArray* pNewArray) + { + for (int i = 0; i < pNewArray->GetSize(); i++) + InsertAt(nStartIndex+i, pNewArray->GetAt(i)); + } + void InsertAt(int nIndex, void* newElement, int nCount = 1) + { + if ((guint32)nIndex >= m_ptrs->len) + { + g_ptr_array_set_size (m_ptrs, nIndex + nCount); // grow so nIndex is valid + } + else + { + // inserting in the middle of the array + int nOldSize = m_ptrs->len; + g_ptr_array_set_size (m_ptrs, m_ptrs->len + nCount); + // shift old data up to fill gap + memmove(&m_ptrs->pdata[nIndex+nCount], &m_ptrs->pdata[nIndex], + (nOldSize-nIndex) * sizeof(gpointer)); + + memset(&m_ptrs->pdata[nIndex], 0, nCount * sizeof(gpointer)); + } + + // insert new value in the gap + while (nCount--) + m_ptrs->pdata[nIndex++] = newElement; + } + void Copy(const CPtrArray& src) + { + g_ptr_array_set_size (m_ptrs, src.m_ptrs->len); + memcpy (m_ptrs->pdata, src.m_ptrs->pdata, m_ptrs->len*sizeof(gpointer)); + } + +protected: + GPtrArray* m_ptrs; +}; + +typedef struct stringmap_s +{ + char* key; + char* value; +} stringmap_t; + +class CMapStringToString +{ +public: + CMapStringToString () + { m_map = g_ptr_array_new (); }; + ~CMapStringToString () + { + for (guint32 i = 0; i < m_map->len; i++) + FreeElement ((stringmap_t*)g_ptr_array_index (m_map,i)); + g_ptr_array_set_size (m_map, 0); + g_ptr_array_free (m_map, TRUE); + }; + void SetAt(char* key, char* newValue) + { + for (guint32 i = 0; i < m_map->len; i++) + { + stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); + if (strcmp (entry->key, key) == 0) + { + g_free (entry->value); + entry->value = g_strdup (newValue); + return; + } + } + stringmap_t* entry = (stringmap_t*)g_malloc (sizeof (stringmap_t)); + entry->key = g_strdup (key); + entry->value = g_strdup (newValue); + g_ptr_array_add (m_map, entry); + } + + bool Lookup(const char* key, CString& rValue) const + { + for (guint32 i = 0; i < m_map->len; i++) + { + stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); + if (strcmp (entry->key, key) == 0) + { + rValue = entry->value; + return true; + } + } + return false; + } + +protected: + GPtrArray* m_map; + + void FreeElement(stringmap_t* elem) + { + g_free (elem->key); + g_free (elem->value); + g_free (elem); + }; +}; + +#endif // _MISSING_H_ diff --git a/libs/multimon.h b/libs/multimon.h index 9a4e9ad7..638e353a 100644 --- a/libs/multimon.h +++ b/libs/multimon.h @@ -1,381 +1,381 @@ -#ifndef __MULTIMON_H -#define __MULTIMON_H - -#ifdef _WIN32 - -//============================================================================= -// -// MULTIMON -// stub module that "stubs" multiple monitor APIs on pre-Memphis Win32 OSes -// -// By using this header your code will work unchanged on Win95, -// you will get back correct values from GetSystemMetrics() for new metrics -// and the new APIs will act like only one display is present. -// -// exactly one source must include this with COMPILE_MULTIMON_STUBS defined -// -//============================================================================= - -#ifdef __cplusplus -extern "C" { /* Assume C declarations for C++ */ -#endif /* __cplusplus */ - -// -// if we are building on Win95/NT4 headers we need to declare this stuff ourselves -// -#ifndef SM_CMONITORS - -#define SM_XVIRTUALSCREEN 76 -#define SM_YVIRTUALSCREEN 77 -#define SM_CXVIRTUALSCREEN 78 -#define SM_CYVIRTUALSCREEN 79 -#define SM_CMONITORS 80 -#define SM_SAMEDISPLAYFORMAT 81 - -DECLARE_HANDLE(HMONITOR); - -#define MONITOR_DEFAULTTONULL 0x00000000 -#define MONITOR_DEFAULTTOPRIMARY 0x00000001 -#define MONITOR_DEFAULTTONEAREST 0x00000002 - -#define MONITORINFOF_PRIMARY 0x00000001 - -typedef struct tagMONITORINFO -{ - DWORD cbSize; - RECT rcMonitor; - RECT rcWork; - DWORD dwFlags; -} MONITORINFO, *LPMONITORINFO; - -#define CCHDEVICENAME 32 - -#ifdef __cplusplus -typedef struct tagMONITORINFOEX : public tagMONITORINFO -{ - TCHAR szDevice[CCHDEVICENAME]; -} MONITORINFOEX, *LPMONITORINFOEX; -#else -typedef struct -{ - MONITORINFO; - TCHAR szDevice[CCHDEVICENAME]; -} MONITORINFOEX, *LPMONITORINFOEX; -#endif - -typedef BOOL (CALLBACK* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM); - -#endif // SM_CMONITORS - -#ifndef DISPLAY_DEVICE_ATTACHED_TO_DESKTOP - -typedef struct { - DWORD cb; - CHAR DeviceName[32]; - CHAR DeviceString[128]; - DWORD StateFlags; -} DISPLAY_DEVICE; - -#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 -#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 -#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 -#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 - -#endif -#define DISPLAY_DEVICE_VGA 0x00000010 - -#ifndef ENUM_CURRENT_SETTINGS -#define ENUM_CURRENT_SETTINGS ((DWORD)-1) -#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) -#endif - -#undef GetMonitorInfo -#undef GetSystemMetrics -#undef MonitorFromWindow -#undef MonitorFromRect -#undef MonitorFromPoint -#undef EnumDisplayMonitors -#undef EnumDisplayDevices - -// -// define this to compile the stubs -// otherwise you get the declarations -// -#ifdef COMPILE_MULTIMON_STUBS - - //--------------------------------------------------------------------------- - // - // Implement the API stubs. - // - //--------------------------------------------------------------------------- - - int (WINAPI* g_pfnGetSystemMetrics)(int); - HMONITOR (WINAPI* g_pfnMonitorFromWindow)(HWND, BOOL); - HMONITOR (WINAPI* g_pfnMonitorFromRect)(LPCRECT, BOOL); - HMONITOR (WINAPI* g_pfnMonitorFromPoint)(POINT, BOOL); - BOOL (WINAPI* g_pfnGetMonitorInfo)(HMONITOR, LPMONITORINFO); - BOOL (WINAPI* g_pfnEnumDisplayMonitors)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); - BOOL (WINAPI *g_pfnEnumDisplayDevices)(LPVOID, int, DISPLAY_DEVICE *, DWORD); - - BOOL InitMultipleMonitorStubs(void) - { - HMODULE hUser32; - static BOOL fInitDone; - - if (fInitDone) - { - return g_pfnGetMonitorInfo != NULL; - } - - if ((hUser32 = GetModuleHandle(TEXT("USER32"))) && - (*(FARPROC*)&g_pfnGetSystemMetrics = GetProcAddress(hUser32,"GetSystemMetrics")) && - (*(FARPROC*)&g_pfnMonitorFromWindow = GetProcAddress(hUser32,"MonitorFromWindow")) && - (*(FARPROC*)&g_pfnMonitorFromRect = GetProcAddress(hUser32,"MonitorFromRect")) && - (*(FARPROC*)&g_pfnMonitorFromPoint = GetProcAddress(hUser32,"MonitorFromPoint")) && - (*(FARPROC*)&g_pfnEnumDisplayMonitors = GetProcAddress(hUser32,"EnumDisplayMonitors")) && - #ifdef UNICODE - (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoW")) && - (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesW")) && - #else - (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoA")) && - (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesA")) && - #endif - (GetSystemMetrics(SM_CXVIRTUALSCREEN) >= GetSystemMetrics(SM_CXSCREEN)) && - (GetSystemMetrics(SM_CYVIRTUALSCREEN) >= GetSystemMetrics(SM_CYSCREEN)) ) - { - fInitDone = TRUE; - return TRUE; - } - else - { - g_pfnGetSystemMetrics = NULL; - g_pfnMonitorFromWindow = NULL; - g_pfnMonitorFromRect = NULL; - g_pfnMonitorFromPoint = NULL; - g_pfnGetMonitorInfo = NULL; - g_pfnEnumDisplayMonitors = NULL; - g_pfnEnumDisplayDevices = NULL; - - fInitDone = TRUE; - return FALSE; - } - } - - //--------------------------------------------------------------------------- - // - // "stubbed" implementations of Monitor APIs that work with the primary // display - // - //--------------------------------------------------------------------------- - - int WINAPI - xGetSystemMetrics(int nIndex) - { - if (InitMultipleMonitorStubs()) - return g_pfnGetSystemMetrics(nIndex); - - switch (nIndex) - { - case SM_CMONITORS: - case SM_SAMEDISPLAYFORMAT: - return 1; - - case SM_XVIRTUALSCREEN: - case SM_YVIRTUALSCREEN: - return 0; - - case SM_CXVIRTUALSCREEN: - nIndex = SM_CXSCREEN; - break; - - case SM_CYVIRTUALSCREEN: - nIndex = SM_CYSCREEN; - break; - } - - return GetSystemMetrics(nIndex); - } - - #define xPRIMARY_MONITOR ((HMONITOR)0x42) - - HMONITOR WINAPI - xMonitorFromRect(LPCRECT lprcScreenCoords, - UINT uFlags) - { - if (InitMultipleMonitorStubs()) - return g_pfnMonitorFromRect(lprcScreenCoords, uFlags); - - if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || - ((lprcScreenCoords->right > 0) && - (lprcScreenCoords->bottom > 0) && - (lprcScreenCoords->left < GetSystemMetrics(SM_CXSCREEN)) && - (lprcScreenCoords->top < GetSystemMetrics(SM_CYSCREEN)))) - { - return xPRIMARY_MONITOR; - } - - return NULL; - } - - HMONITOR WINAPI - xMonitorFromWindow(HWND hWnd, - UINT uFlags) - { - RECT rc; - - if (InitMultipleMonitorStubs()) - return g_pfnMonitorFromWindow(hWnd, uFlags); - - if (uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) - return xPRIMARY_MONITOR; - - if (GetWindowRect(hWnd, &rc)) - return xMonitorFromRect(&rc, uFlags); - - return NULL; - } - - HMONITOR WINAPI - xMonitorFromPoint(POINT ptScreenCoords, - UINT uFlags) - { - if (InitMultipleMonitorStubs()) - return g_pfnMonitorFromPoint(ptScreenCoords, uFlags); - - if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || - ((ptScreenCoords.x >= 0) && - (ptScreenCoords.x < GetSystemMetrics(SM_CXSCREEN)) && - (ptScreenCoords.y >= 0) && - (ptScreenCoords.y < GetSystemMetrics(SM_CYSCREEN)))) - { - return xPRIMARY_MONITOR; - } - - return NULL; - } - - BOOL WINAPI - xGetMonitorInfo(HMONITOR hMonitor, - LPMONITORINFO lpMonitorInfo) - { - RECT rcWork; - - if (InitMultipleMonitorStubs()) - return g_pfnGetMonitorInfo(hMonitor, lpMonitorInfo); - - if ((hMonitor == xPRIMARY_MONITOR) && lpMonitorInfo && - (lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) && - SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0)) - { - lpMonitorInfo->rcMonitor.left = 0; - lpMonitorInfo->rcMonitor.top = 0; - lpMonitorInfo->rcMonitor.right = GetSystemMetrics(SM_CXSCREEN); - lpMonitorInfo->rcMonitor.bottom = GetSystemMetrics(SM_CYSCREEN); - lpMonitorInfo->rcWork = rcWork; - lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY; - - if (lpMonitorInfo->cbSize >= sizeof(MONITORINFOEX)) - lstrcpy(((MONITORINFOEX*)lpMonitorInfo)->szDevice, - TEXT("DISPLAY")); - - return TRUE; - } - - return FALSE; - } - - BOOL WINAPI - xEnumDisplayMonitors(HDC hdc, - LPCRECT lprcIntersect, - MONITORENUMPROC lpfnEnumProc, - LPARAM lData) - { - RECT rcCallback, rcLimit; - - if (InitMultipleMonitorStubs()) - return g_pfnEnumDisplayMonitors(hdc, lprcIntersect, lpfnEnumProc, lData); - - if (!lpfnEnumProc) - return FALSE; - - rcLimit.left = 0; - rcLimit.top = 0; - rcLimit.right = GetSystemMetrics(SM_CXSCREEN); - rcLimit.bottom = GetSystemMetrics(SM_CYSCREEN); - - if (hdc) - { - RECT rcClip; - HWND hWnd; - - if ((hWnd = WindowFromDC(hdc)) == NULL) - return FALSE; - - switch (GetClipBox(hdc, &rcClip)) - { - default: - MapWindowPoints(NULL, hWnd, (LPPOINT)&rcLimit, 2); - if (IntersectRect(&rcCallback, &rcClip, &rcLimit)) - break; - //fall thru - case NULLREGION: - return TRUE; - case ERROR: - return FALSE; - } - - rcLimit = rcCallback; - } - - if (!lprcIntersect || IntersectRect(&rcCallback, lprcIntersect, &rcLimit)) - { - lpfnEnumProc(xPRIMARY_MONITOR, hdc, &rcCallback, lData); - } - - return TRUE; - } - - BOOL WINAPI - xEnumDisplayDevices(LPVOID lpReserved, - int iDeviceNum, - DISPLAY_DEVICE * pDisplayDevice, - DWORD dwFlags) - { - if (InitMultipleMonitorStubs()) - return g_pfnEnumDisplayDevices(lpReserved, iDeviceNum, pDisplayDevice, dwFlags); - - return FALSE; - } - - #undef xPRIMARY_MONITOR - #undef COMPILE_MULTIMON_STUBS - -#else // COMPILE_MULTIMON_STUBS - - extern int WINAPI xGetSystemMetrics(int); - extern HMONITOR WINAPI xMonitorFromWindow(HWND, UINT); - extern HMONITOR WINAPI xMonitorFromRect(LPCRECT, UINT); - extern HMONITOR WINAPI xMonitorFromPoint(POINT, UINT); - extern BOOL WINAPI xGetMonitorInfo(HMONITOR, LPMONITORINFO); - extern BOOL WINAPI xEnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM); - extern BOOL WINAPI xEnumDisplayDevices(LPVOID, int, DISPLAY_DEVICE *, DWORD); - -#endif // COMPILE_MULTIMON_STUBS - -// -// build defines that replace the regular APIs with our versions -// -#define GetSystemMetrics xGetSystemMetrics -#define MonitorFromWindow xMonitorFromWindow -#define MonitorFromRect xMonitorFromRect -#define MonitorFromPoint xMonitorFromPoint -#define GetMonitorInfo xGetMonitorInfo -#define EnumDisplayMonitors xEnumDisplayMonitors -#define EnumDisplayDevices xEnumDisplayDevices - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // WIN32 - +#ifndef __MULTIMON_H +#define __MULTIMON_H + +#ifdef _WIN32 + +//============================================================================= +// +// MULTIMON +// stub module that "stubs" multiple monitor APIs on pre-Memphis Win32 OSes +// +// By using this header your code will work unchanged on Win95, +// you will get back correct values from GetSystemMetrics() for new metrics +// and the new APIs will act like only one display is present. +// +// exactly one source must include this with COMPILE_MULTIMON_STUBS defined +// +//============================================================================= + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +// +// if we are building on Win95/NT4 headers we need to declare this stuff ourselves +// +#ifndef SM_CMONITORS + +#define SM_XVIRTUALSCREEN 76 +#define SM_YVIRTUALSCREEN 77 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 +#define SM_CMONITORS 80 +#define SM_SAMEDISPLAYFORMAT 81 + +DECLARE_HANDLE(HMONITOR); + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + +#define MONITORINFOF_PRIMARY 0x00000001 + +typedef struct tagMONITORINFO +{ + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} MONITORINFO, *LPMONITORINFO; + +#define CCHDEVICENAME 32 + +#ifdef __cplusplus +typedef struct tagMONITORINFOEX : public tagMONITORINFO +{ + TCHAR szDevice[CCHDEVICENAME]; +} MONITORINFOEX, *LPMONITORINFOEX; +#else +typedef struct +{ + MONITORINFO; + TCHAR szDevice[CCHDEVICENAME]; +} MONITORINFOEX, *LPMONITORINFOEX; +#endif + +typedef BOOL (CALLBACK* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM); + +#endif // SM_CMONITORS + +#ifndef DISPLAY_DEVICE_ATTACHED_TO_DESKTOP + +typedef struct { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD StateFlags; +} DISPLAY_DEVICE; + +#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 +#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 +#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 +#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 + +#endif +#define DISPLAY_DEVICE_VGA 0x00000010 + +#ifndef ENUM_CURRENT_SETTINGS +#define ENUM_CURRENT_SETTINGS ((DWORD)-1) +#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) +#endif + +#undef GetMonitorInfo +#undef GetSystemMetrics +#undef MonitorFromWindow +#undef MonitorFromRect +#undef MonitorFromPoint +#undef EnumDisplayMonitors +#undef EnumDisplayDevices + +// +// define this to compile the stubs +// otherwise you get the declarations +// +#ifdef COMPILE_MULTIMON_STUBS + + //--------------------------------------------------------------------------- + // + // Implement the API stubs. + // + //--------------------------------------------------------------------------- + + int (WINAPI* g_pfnGetSystemMetrics)(int); + HMONITOR (WINAPI* g_pfnMonitorFromWindow)(HWND, BOOL); + HMONITOR (WINAPI* g_pfnMonitorFromRect)(LPCRECT, BOOL); + HMONITOR (WINAPI* g_pfnMonitorFromPoint)(POINT, BOOL); + BOOL (WINAPI* g_pfnGetMonitorInfo)(HMONITOR, LPMONITORINFO); + BOOL (WINAPI* g_pfnEnumDisplayMonitors)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + BOOL (WINAPI *g_pfnEnumDisplayDevices)(LPVOID, int, DISPLAY_DEVICE *, DWORD); + + BOOL InitMultipleMonitorStubs(void) + { + HMODULE hUser32; + static BOOL fInitDone; + + if (fInitDone) + { + return g_pfnGetMonitorInfo != NULL; + } + + if ((hUser32 = GetModuleHandle(TEXT("USER32"))) && + (*(FARPROC*)&g_pfnGetSystemMetrics = GetProcAddress(hUser32,"GetSystemMetrics")) && + (*(FARPROC*)&g_pfnMonitorFromWindow = GetProcAddress(hUser32,"MonitorFromWindow")) && + (*(FARPROC*)&g_pfnMonitorFromRect = GetProcAddress(hUser32,"MonitorFromRect")) && + (*(FARPROC*)&g_pfnMonitorFromPoint = GetProcAddress(hUser32,"MonitorFromPoint")) && + (*(FARPROC*)&g_pfnEnumDisplayMonitors = GetProcAddress(hUser32,"EnumDisplayMonitors")) && + #ifdef UNICODE + (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoW")) && + (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesW")) && + #else + (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoA")) && + (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesA")) && + #endif + (GetSystemMetrics(SM_CXVIRTUALSCREEN) >= GetSystemMetrics(SM_CXSCREEN)) && + (GetSystemMetrics(SM_CYVIRTUALSCREEN) >= GetSystemMetrics(SM_CYSCREEN)) ) + { + fInitDone = TRUE; + return TRUE; + } + else + { + g_pfnGetSystemMetrics = NULL; + g_pfnMonitorFromWindow = NULL; + g_pfnMonitorFromRect = NULL; + g_pfnMonitorFromPoint = NULL; + g_pfnGetMonitorInfo = NULL; + g_pfnEnumDisplayMonitors = NULL; + g_pfnEnumDisplayDevices = NULL; + + fInitDone = TRUE; + return FALSE; + } + } + + //--------------------------------------------------------------------------- + // + // "stubbed" implementations of Monitor APIs that work with the primary // display + // + //--------------------------------------------------------------------------- + + int WINAPI + xGetSystemMetrics(int nIndex) + { + if (InitMultipleMonitorStubs()) + return g_pfnGetSystemMetrics(nIndex); + + switch (nIndex) + { + case SM_CMONITORS: + case SM_SAMEDISPLAYFORMAT: + return 1; + + case SM_XVIRTUALSCREEN: + case SM_YVIRTUALSCREEN: + return 0; + + case SM_CXVIRTUALSCREEN: + nIndex = SM_CXSCREEN; + break; + + case SM_CYVIRTUALSCREEN: + nIndex = SM_CYSCREEN; + break; + } + + return GetSystemMetrics(nIndex); + } + + #define xPRIMARY_MONITOR ((HMONITOR)0x42) + + HMONITOR WINAPI + xMonitorFromRect(LPCRECT lprcScreenCoords, + UINT uFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromRect(lprcScreenCoords, uFlags); + + if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || + ((lprcScreenCoords->right > 0) && + (lprcScreenCoords->bottom > 0) && + (lprcScreenCoords->left < GetSystemMetrics(SM_CXSCREEN)) && + (lprcScreenCoords->top < GetSystemMetrics(SM_CYSCREEN)))) + { + return xPRIMARY_MONITOR; + } + + return NULL; + } + + HMONITOR WINAPI + xMonitorFromWindow(HWND hWnd, + UINT uFlags) + { + RECT rc; + + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromWindow(hWnd, uFlags); + + if (uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) + return xPRIMARY_MONITOR; + + if (GetWindowRect(hWnd, &rc)) + return xMonitorFromRect(&rc, uFlags); + + return NULL; + } + + HMONITOR WINAPI + xMonitorFromPoint(POINT ptScreenCoords, + UINT uFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromPoint(ptScreenCoords, uFlags); + + if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || + ((ptScreenCoords.x >= 0) && + (ptScreenCoords.x < GetSystemMetrics(SM_CXSCREEN)) && + (ptScreenCoords.y >= 0) && + (ptScreenCoords.y < GetSystemMetrics(SM_CYSCREEN)))) + { + return xPRIMARY_MONITOR; + } + + return NULL; + } + + BOOL WINAPI + xGetMonitorInfo(HMONITOR hMonitor, + LPMONITORINFO lpMonitorInfo) + { + RECT rcWork; + + if (InitMultipleMonitorStubs()) + return g_pfnGetMonitorInfo(hMonitor, lpMonitorInfo); + + if ((hMonitor == xPRIMARY_MONITOR) && lpMonitorInfo && + (lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) && + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0)) + { + lpMonitorInfo->rcMonitor.left = 0; + lpMonitorInfo->rcMonitor.top = 0; + lpMonitorInfo->rcMonitor.right = GetSystemMetrics(SM_CXSCREEN); + lpMonitorInfo->rcMonitor.bottom = GetSystemMetrics(SM_CYSCREEN); + lpMonitorInfo->rcWork = rcWork; + lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY; + + if (lpMonitorInfo->cbSize >= sizeof(MONITORINFOEX)) + lstrcpy(((MONITORINFOEX*)lpMonitorInfo)->szDevice, + TEXT("DISPLAY")); + + return TRUE; + } + + return FALSE; + } + + BOOL WINAPI + xEnumDisplayMonitors(HDC hdc, + LPCRECT lprcIntersect, + MONITORENUMPROC lpfnEnumProc, + LPARAM lData) + { + RECT rcCallback, rcLimit; + + if (InitMultipleMonitorStubs()) + return g_pfnEnumDisplayMonitors(hdc, lprcIntersect, lpfnEnumProc, lData); + + if (!lpfnEnumProc) + return FALSE; + + rcLimit.left = 0; + rcLimit.top = 0; + rcLimit.right = GetSystemMetrics(SM_CXSCREEN); + rcLimit.bottom = GetSystemMetrics(SM_CYSCREEN); + + if (hdc) + { + RECT rcClip; + HWND hWnd; + + if ((hWnd = WindowFromDC(hdc)) == NULL) + return FALSE; + + switch (GetClipBox(hdc, &rcClip)) + { + default: + MapWindowPoints(NULL, hWnd, (LPPOINT)&rcLimit, 2); + if (IntersectRect(&rcCallback, &rcClip, &rcLimit)) + break; + //fall thru + case NULLREGION: + return TRUE; + case ERROR: + return FALSE; + } + + rcLimit = rcCallback; + } + + if (!lprcIntersect || IntersectRect(&rcCallback, lprcIntersect, &rcLimit)) + { + lpfnEnumProc(xPRIMARY_MONITOR, hdc, &rcCallback, lData); + } + + return TRUE; + } + + BOOL WINAPI + xEnumDisplayDevices(LPVOID lpReserved, + int iDeviceNum, + DISPLAY_DEVICE * pDisplayDevice, + DWORD dwFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnEnumDisplayDevices(lpReserved, iDeviceNum, pDisplayDevice, dwFlags); + + return FALSE; + } + + #undef xPRIMARY_MONITOR + #undef COMPILE_MULTIMON_STUBS + +#else // COMPILE_MULTIMON_STUBS + + extern int WINAPI xGetSystemMetrics(int); + extern HMONITOR WINAPI xMonitorFromWindow(HWND, UINT); + extern HMONITOR WINAPI xMonitorFromRect(LPCRECT, UINT); + extern HMONITOR WINAPI xMonitorFromPoint(POINT, UINT); + extern BOOL WINAPI xGetMonitorInfo(HMONITOR, LPMONITORINFO); + extern BOOL WINAPI xEnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + extern BOOL WINAPI xEnumDisplayDevices(LPVOID, int, DISPLAY_DEVICE *, DWORD); + +#endif // COMPILE_MULTIMON_STUBS + +// +// build defines that replace the regular APIs with our versions +// +#define GetSystemMetrics xGetSystemMetrics +#define MonitorFromWindow xMonitorFromWindow +#define MonitorFromRect xMonitorFromRect +#define MonitorFromPoint xMonitorFromPoint +#define GetMonitorInfo xGetMonitorInfo +#define EnumDisplayMonitors xEnumDisplayMonitors +#define EnumDisplayDevices xEnumDisplayDevices + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // WIN32 + #endif // __MULTIMON_H \ No newline at end of file diff --git a/libs/pak/unzip.h b/libs/pak/unzip.h index d5c165dc..79a487e3 100644 --- a/libs/pak/unzip.h +++ b/libs/pak/unzip.h @@ -1,300 +1,300 @@ - -#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) -/* like the STRICT of WIN32, we define a pointer that cannot be converted - from (void*) without cast */ -typedef struct TagunzFile__ { int unused; } unzFile__; -typedef unzFile__ *unzFile; -#else -typedef void* unzFile; -#endif - - -/* tm_unz contain date/time info */ -typedef struct tm_unz_s -{ - unsigned int tm_sec; /* seconds after the minute - [0,59] */ - unsigned int tm_min; /* minutes after the hour - [0,59] */ - unsigned int tm_hour; /* hours since midnight - [0,23] */ - unsigned int tm_mday; /* day of the month - [1,31] */ - unsigned int tm_mon; /* months since January - [0,11] */ - unsigned int tm_year; /* years - [1980..2044] */ -} tm_unz; - -/* unz_global_info structure contain global data about the ZIPfile - These data comes from the end of central dir */ -typedef struct unz_global_info_s -{ - unsigned long number_entry; /* total number of entries in the central dir on this disk */ - unsigned long size_comment; /* size of the global comment of the zipfile */ -} unz_global_info; - - -/* unz_file_info contain information about a file in the zipfile */ -typedef struct unz_file_info_s -{ - unsigned long version; /* version made by 2 unsigned chars */ - unsigned long version_needed; /* version needed to extract 2 unsigned chars */ - unsigned long flag; /* general purpose bit flag 2 unsigned chars */ - unsigned long compression_method; /* compression method 2 unsigned chars */ - unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */ - unsigned long crc; /* crc-32 4 unsigned chars */ - unsigned long compressed_size; /* compressed size 4 unsigned chars */ - unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */ - unsigned long size_filename; /* filename length 2 unsigned chars */ - unsigned long size_file_extra; /* extra field length 2 unsigned chars */ - unsigned long size_file_comment; /* file comment length 2 unsigned chars */ - - unsigned long disk_num_start; /* disk number start 2 unsigned chars */ - unsigned long internal_fa; /* internal file attributes 2 unsigned chars */ - unsigned long external_fa; /* external file attributes 4 unsigned chars */ - - tm_unz tmu_date; -} unz_file_info; - -/* unz_file_info_interntal contain internal info about a file in zipfile*/ -typedef struct unz_file_info_internal_s -{ - unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */ -} unz_file_info_internal; - -typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size); -typedef void (*free_func) (void* opaque, void* address); - -struct internal_state; - -typedef struct z_stream_s { - unsigned char *next_in; /* next input unsigned char */ - unsigned int avail_in; /* number of unsigned chars available at next_in */ - unsigned long total_in; /* total nb of input unsigned chars read so */ - - unsigned char *next_out; /* next output unsigned char should be put there */ - unsigned int avail_out; /* remaining free space at next_out */ - unsigned long total_out; /* total nb of unsigned chars output so */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - unsigned char* opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: ascii or binary */ - unsigned long adler; /* adler32 value of the uncompressed data */ - unsigned long reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream *z_streamp; - - -/* file_in_zip_read_info_s contain internal information about a file in zipfile, - when reading and decompress it */ -typedef struct -{ - char *read_buffer; /* internal buffer for compressed data */ - z_stream stream; /* zLib stream structure for inflate */ - - unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/ - unsigned long stream_initialised; /* flag set if stream structure is initialised*/ - - unsigned long offset_local_extrafield;/* offset of the static extra field */ - unsigned int size_local_extrafield;/* size of the static extra field */ - unsigned long pos_local_extrafield; /* position in the static extra field in read*/ - - unsigned long crc32; /* crc32 of all data uncompressed */ - unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ - unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */ - unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/ - FILE* file; /* io structore of the zipfile */ - unsigned long compression_method; /* compression method (0==store) */ - unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ -} file_in_zip_read_info_s; - - -/* unz_s contain internal information about the zipfile -*/ -typedef struct -{ - FILE* file; /* io structore of the zipfile */ - unz_global_info gi; /* public global information */ - unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ - unsigned long num_file; /* number of the current file in the zipfile*/ - unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ - unsigned long current_file_ok; /* flag about the usability of the current file*/ - unsigned long central_pos; /* position of the beginning of the central dir*/ - - unsigned long size_central_dir; /* size of the central directory */ - unsigned long offset_central_dir; /* offset of start of central directory with - respect to the starting disk number */ - - unz_file_info cur_file_info; /* public info about the current file in zip*/ - unz_file_info_internal cur_file_info_internal; /* private info about it*/ - file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current - file if we are decompressing it */ -} unz_s; - -#define UNZ_OK (0) -#define UNZ_END_OF_LIST_OF_FILE (-100) -#define UNZ_ERRNO (Z_ERRNO) -#define UNZ_EOF (0) -#define UNZ_PARAMERROR (-102) -#define UNZ_BADZIPFILE (-103) -#define UNZ_INTERNALERROR (-104) -#define UNZ_CRCERROR (-105) - -#define UNZ_CASESENSITIVE 1 -#define UNZ_NOTCASESENSITIVE 2 -#define UNZ_OSDEFAULTCASE 0 - -extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity); - -/* - Compare two filename (fileName1,fileName2). - If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) - If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi - or strcasecmp) - If iCaseSenisivity = 0, case sensitivity is defaut of your operating system - (like 1 on Unix, 2 on Windows) -*/ - -extern unzFile unzOpen (const char *path); -extern unzFile unzReOpen (const char* path, unzFile file); - -/* - Open a Zip file. path contain the full pathname (by example, - on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer - "zlib/zlib111.zip". - If the zipfile cannot be opened (file don't exist or in not valid), the - return value is NULL. - Else, the return value is a unzFile Handle, usable with other function - of this unzip package. -*/ - -extern int unzClose (unzFile file); - -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ - -extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info); - -/* - Write info about the ZipFile in the *pglobal_info structure. - No preparation of the structure is needed - return UNZ_OK if there is no problem. */ - - -extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf); - -/* - Get the global comment string of the ZipFile, in the szComment buffer. - uSizeBuf is the size of the szComment buffer. - return the number of unsigned char copied or an error code <0 -*/ - - -/***************************************************************************/ -/* Unzip package allow you browse the directory of the zipfile */ - -extern int unzGoToFirstFile (unzFile file); - -/* - Set the current file of the zipfile to the first file. - return UNZ_OK if there is no problem -*/ - -extern int unzGoToNextFile (unzFile file); - -/* - Set the current file of the zipfile to the next file. - return UNZ_OK if there is no problem - return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. -*/ - -extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity); - -/* - Try locate the file szFileName in the zipfile. - For the iCaseSensitivity signification, see unzStringFileNameCompare - - return value : - UNZ_OK if the file is found. It becomes the current file. - UNZ_END_OF_LIST_OF_FILE if the file is not found -*/ - - -extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize); - -/* - Get Info about the current file - if pfile_info!=NULL, the *pfile_info structure will contain somes info about - the current file - if szFileName!=NULL, the filemane string will be copied in szFileName - (fileNameBufferSize is the size of the buffer) - if extraField!=NULL, the extra field information will be copied in extraField - (extraFieldBufferSize is the size of the buffer). - This is the Central-header version of the extra field - if szComment!=NULL, the comment string of the file will be copied in szComment - (commentBufferSize is the size of the buffer) -*/ - -/***************************************************************************/ -/* for reading the content of the current zipfile, you can open it, read data - from it, and close it (you can close it before reading all the file) - */ - -extern int unzOpenCurrentFile (unzFile file); - -/* - Open for reading data the current file in the zipfile. - If there is no error, the return value is UNZ_OK. -*/ - -extern int unzCloseCurrentFile (unzFile file); - -/* - Close the file in zip opened with unzOpenCurrentFile - Return UNZ_CRCERROR if all the file was read but the CRC is not good -*/ - - -extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len); - -/* - Read unsigned chars from the current file (opened by unzOpenCurrentFile) - buf contain buffer where data must be copied - len the size of buf. - - return the number of unsigned char copied if somes unsigned chars are copied - return 0 if the end of file was reached - return <0 with error code if there is an error - (UNZ_ERRNO for IO error, or zLib error for uncompress error) -*/ - -extern long unztell(unzFile file); - -/* - Give the current position in uncompressed data -*/ - -extern int unzeof (unzFile file); - -/* - return 1 if the end of file was reached, 0 elsewhere -*/ - -extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len); - -/* - Read extra field from the current file (opened by unzOpenCurrentFile) - This is the local-header version of the extra field (sometimes, there is - more info in the local-header version than in the central-header) - - if buf==NULL, it return the size of the local extra field - - if buf!=NULL, len is the size of the buffer, the extra header is copied in - buf. - the return value is the number of unsigned chars copied in buf, or (if <0) - the error code -*/ + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef void* unzFile; +#endif + + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + unsigned long number_entry; /* total number of entries in the central dir on this disk */ + unsigned long size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + unsigned long version; /* version made by 2 unsigned chars */ + unsigned long version_needed; /* version needed to extract 2 unsigned chars */ + unsigned long flag; /* general purpose bit flag 2 unsigned chars */ + unsigned long compression_method; /* compression method 2 unsigned chars */ + unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */ + unsigned long crc; /* crc-32 4 unsigned chars */ + unsigned long compressed_size; /* compressed size 4 unsigned chars */ + unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */ + unsigned long size_filename; /* filename length 2 unsigned chars */ + unsigned long size_file_extra; /* extra field length 2 unsigned chars */ + unsigned long size_file_comment; /* file comment length 2 unsigned chars */ + + unsigned long disk_num_start; /* disk number start 2 unsigned chars */ + unsigned long internal_fa; /* internal file attributes 2 unsigned chars */ + unsigned long external_fa; /* external file attributes 4 unsigned chars */ + + tm_unz tmu_date; +} unz_file_info; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */ +} unz_file_info_internal; + +typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void* opaque, void* address); + +struct internal_state; + +typedef struct z_stream_s { + unsigned char *next_in; /* next input unsigned char */ + unsigned int avail_in; /* number of unsigned chars available at next_in */ + unsigned long total_in; /* total nb of input unsigned chars read so */ + + unsigned char *next_out; /* next output unsigned char should be put there */ + unsigned int avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total nb of unsigned chars output so */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + unsigned char* opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + unsigned long adler; /* adler32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream *z_streamp; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/ + unsigned long stream_initialised; /* flag set if stream structure is initialised*/ + + unsigned long offset_local_extrafield;/* offset of the static extra field */ + unsigned int size_local_extrafield;/* size of the static extra field */ + unsigned long pos_local_extrafield; /* position in the static extra field in read*/ + + unsigned long crc32; /* crc32 of all data uncompressed */ + unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ + unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */ + unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + unsigned long compression_method; /* compression method (0==store) */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ + unsigned long num_file; /* number of the current file in the zipfile*/ + unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ + unsigned long current_file_ok; /* flag about the usability of the current file*/ + unsigned long central_pos; /* position of the beginning of the central dir*/ + + unsigned long size_central_dir; /* size of the central directory */ + unsigned long offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +#define UNZ_CASESENSITIVE 1 +#define UNZ_NOTCASESENSITIVE 2 +#define UNZ_OSDEFAULTCASE 0 + +extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity); + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + +extern unzFile unzOpen (const char *path); +extern unzFile unzReOpen (const char* path, unzFile file); + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int unzClose (unzFile file); + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info); + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf); + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of unsigned char copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int unzGoToFirstFile (unzFile file); + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int unzGoToNextFile (unzFile file); + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity); + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize); + +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int unzOpenCurrentFile (unzFile file); + +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int unzCloseCurrentFile (unzFile file); + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len); + +/* + Read unsigned chars from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of unsigned char copied if somes unsigned chars are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern long unztell(unzFile file); + +/* + Give the current position in uncompressed data +*/ + +extern int unzeof (unzFile file); + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len); + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of unsigned chars copied in buf, or (if <0) + the error code +*/ diff --git a/libs/pakstuff.h b/libs/pakstuff.h index 4c709cae..340e8798 100644 --- a/libs/pakstuff.h +++ b/libs/pakstuff.h @@ -1,150 +1,150 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant 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. - -GtkRadiant 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 GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _PAKSTUFF_H_ -#define _PAKSTUFF_H_ - -#ifndef _WIN32 -#define WINAPI -#else -#include -#endif - -#ifndef __cplusplus -typedef int bool; // leo -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef char Int8; -typedef short Int16; -typedef long Int32; -typedef unsigned char UInt8; -typedef unsigned short UInt16; -typedef unsigned long UInt32; -typedef float Float32; -typedef double Float64; -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define RANDOM(x) (random() % (x)) -#define RANDOMIZE() srand((int) time(NULL)) - -#define FTYPE_UNKNOWN 0 -#define FTYPE_IWAD 1 /* .wad "IWAD" */ -#define FTYPE_PWAD 2 /* .wad "PWAD" */ -#define FTYPE_PACK 3 /* .pak "PACK" */ -#define FTYPE_WAD2 4 /* .wad "WAD2" */ -#define FTYPE_BSP 10 /* .bsp (0x17 0x00 0x00 0x00) */ -#define FTYPE_MODEL 11 /* .mdl "IDPO" */ -#define FTYPE_SPRITE 12 /* .spr "IDSP" */ -#define FTYPE_WAV 20 /* .wav "RIFF" */ -#define FTYPE_AU 21 /* .au ".snd" */ -#define FTYPE_VOC 22 /* .voc ? */ -#define FTYPE_PBM_ASC 30 /* .pbm "P1" */ -#define FTYPE_PGM_ASC 31 /* .pgm "P2" */ -#define FTYPE_PPM_ASC 32 /* .ppm "P3" */ -#define FTYPE_PBM_RAW 33 /* .pbm "P4" */ -#define FTYPE_PGM_RAW 34 /* .pgm "P5" */ -#define FTYPE_PPM_RAW 35 /* .ppm "P6" */ -#define FTYPE_BMP 36 /* .bmp "BM" */ -#define FTYPE_GIF 37 /* .gif "GIF8" */ -#define FTYPE_PCX 38 /* .pcx (0x0a 0x05 0x01 0x08) */ -#define FTYPE_ERROR -1 - -#ifdef FAT_ENDIAN -Bool ReadInt16 (FILE *file, UInt16 huge *x); -Bool ReadInt32 (FILE *file, UInt32 huge *x); -Bool ReadFloat32 (FILE *file, Float32 huge *x); -Bool WriteInt16 (FILE *file, UInt16 huge *x); -Bool WriteInt32 (FILE *file, UInt32 huge *x); -Bool WriteFloat32 (FILE *file, Float32 huge *x); -UInt16 SwapInt16 (UInt16 x); -UInt32 SwapInt32 (UInt32 x); -Float32 SwapFloat32 (Float32 x); -#else -#define ReadInt16(f, p) ReadBytes((f), (p), 2L) -#define ReadInt32(f, p) ReadBytes((f), (p), 4L) -#define ReadFloat32(f, p) ReadBytes((f), (p), 4L) -#define WriteInt16(f, p) WriteBytes((f), (p), 2L) -#define WriteInt32(f, p) WriteBytes((f), (p), 4L) -#define WriteFloat32(f, p) WriteBytes((f), (p), 4L) -#define SwapInt16(x) (x) -#define SwapInt32(x) (x) -#define SwapFloat32(x) (x) -#endif /* FAT_ENDIAN */ - -#define FROMDISK -1 -struct PACKDirectory -{ - char name[56]; /* name of file */ - UInt32 offset; /* offset to start of data */ - UInt32 size; /* byte size of data */ -}; -typedef struct PACKDirectory *PACKDirPtr; - -typedef struct DirListStruct -{ - char dirname[1024]; - int from; - struct DirListStruct *next; -} DIRLIST; - -typedef struct FileListStruct -{ - char filename[1024]; - UInt32 offset; - UInt32 size; - struct FileListStruct *next; -} FILELIST; - -typedef struct DirStruct -{ - char name[1024]; - FILELIST *files; - struct DirStruct *next; -} DIRECTORY; - - -extern int m_nPAKIndex; -extern FILE* pakfile[16]; -extern bool pakopen; -extern DIRECTORY *paktextures; - -void ClearFileList (FILELIST **); -void ClearDirList (DIRLIST **); -bool GetPackFileList (FILELIST **, char *); -bool GetPackTextureDirs (DIRLIST **); -bool AddToDirListAlphabetized (DIRLIST **, char *, int); -bool AddToFileListAlphabetized (FILELIST **t, char *, UInt32, UInt32, bool); -bool PakLoadFile (const char *, void **); -void OpenPakFile (const char *); -void ClosePakFile (void); -int PakLoadAnyFile(const char *filename, void **bufferptr); -void WINAPI InitPakFile(const char * pBasePath, const char *pName); - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant 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. + +GtkRadiant 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 GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PAKSTUFF_H_ +#define _PAKSTUFF_H_ + +#ifndef _WIN32 +#define WINAPI +#else +#include +#endif + +#ifndef __cplusplus +typedef int bool; // leo +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef char Int8; +typedef short Int16; +typedef long Int32; +typedef unsigned char UInt8; +typedef unsigned short UInt16; +typedef unsigned long UInt32; +typedef float Float32; +typedef double Float64; +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define RANDOM(x) (random() % (x)) +#define RANDOMIZE() srand((int) time(NULL)) + +#define FTYPE_UNKNOWN 0 +#define FTYPE_IWAD 1 /* .wad "IWAD" */ +#define FTYPE_PWAD 2 /* .wad "PWAD" */ +#define FTYPE_PACK 3 /* .pak "PACK" */ +#define FTYPE_WAD2 4 /* .wad "WAD2" */ +#define FTYPE_BSP 10 /* .bsp (0x17 0x00 0x00 0x00) */ +#define FTYPE_MODEL 11 /* .mdl "IDPO" */ +#define FTYPE_SPRITE 12 /* .spr "IDSP" */ +#define FTYPE_WAV 20 /* .wav "RIFF" */ +#define FTYPE_AU 21 /* .au ".snd" */ +#define FTYPE_VOC 22 /* .voc ? */ +#define FTYPE_PBM_ASC 30 /* .pbm "P1" */ +#define FTYPE_PGM_ASC 31 /* .pgm "P2" */ +#define FTYPE_PPM_ASC 32 /* .ppm "P3" */ +#define FTYPE_PBM_RAW 33 /* .pbm "P4" */ +#define FTYPE_PGM_RAW 34 /* .pgm "P5" */ +#define FTYPE_PPM_RAW 35 /* .ppm "P6" */ +#define FTYPE_BMP 36 /* .bmp "BM" */ +#define FTYPE_GIF 37 /* .gif "GIF8" */ +#define FTYPE_PCX 38 /* .pcx (0x0a 0x05 0x01 0x08) */ +#define FTYPE_ERROR -1 + +#ifdef FAT_ENDIAN +Bool ReadInt16 (FILE *file, UInt16 huge *x); +Bool ReadInt32 (FILE *file, UInt32 huge *x); +Bool ReadFloat32 (FILE *file, Float32 huge *x); +Bool WriteInt16 (FILE *file, UInt16 huge *x); +Bool WriteInt32 (FILE *file, UInt32 huge *x); +Bool WriteFloat32 (FILE *file, Float32 huge *x); +UInt16 SwapInt16 (UInt16 x); +UInt32 SwapInt32 (UInt32 x); +Float32 SwapFloat32 (Float32 x); +#else +#define ReadInt16(f, p) ReadBytes((f), (p), 2L) +#define ReadInt32(f, p) ReadBytes((f), (p), 4L) +#define ReadFloat32(f, p) ReadBytes((f), (p), 4L) +#define WriteInt16(f, p) WriteBytes((f), (p), 2L) +#define WriteInt32(f, p) WriteBytes((f), (p), 4L) +#define WriteFloat32(f, p) WriteBytes((f), (p), 4L) +#define SwapInt16(x) (x) +#define SwapInt32(x) (x) +#define SwapFloat32(x) (x) +#endif /* FAT_ENDIAN */ + +#define FROMDISK -1 +struct PACKDirectory +{ + char name[56]; /* name of file */ + UInt32 offset; /* offset to start of data */ + UInt32 size; /* byte size of data */ +}; +typedef struct PACKDirectory *PACKDirPtr; + +typedef struct DirListStruct +{ + char dirname[1024]; + int from; + struct DirListStruct *next; +} DIRLIST; + +typedef struct FileListStruct +{ + char filename[1024]; + UInt32 offset; + UInt32 size; + struct FileListStruct *next; +} FILELIST; + +typedef struct DirStruct +{ + char name[1024]; + FILELIST *files; + struct DirStruct *next; +} DIRECTORY; + + +extern int m_nPAKIndex; +extern FILE* pakfile[16]; +extern bool pakopen; +extern DIRECTORY *paktextures; + +void ClearFileList (FILELIST **); +void ClearDirList (DIRLIST **); +bool GetPackFileList (FILELIST **, char *); +bool GetPackTextureDirs (DIRLIST **); +bool AddToDirListAlphabetized (DIRLIST **, char *, int); +bool AddToFileListAlphabetized (FILELIST **t, char *, UInt32, UInt32, bool); +bool PakLoadFile (const char *, void **); +void OpenPakFile (const char *); +void ClosePakFile (void); +int PakLoadAnyFile(const char *filename, void **bufferptr); +void WINAPI InitPakFile(const char * pBasePath, const char *pName); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel.h b/libs/picomodel.h index 8642527a..1912b4cb 100644 --- a/libs/picomodel.h +++ b/libs/picomodel.h @@ -1,345 +1,345 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#ifndef PICOMODEL_H -#define PICOMODEL_H - -#ifdef __cplusplus -extern "C" -{ -#endif - - - -/* version */ -#define PICOMODEL_VERSION "0.8.20" - - -/* constants */ -#define PICO_GROW_SHADERS 16 -#define PICO_GROW_SURFACES 16 -#define PICO_GROW_VERTEXES 1024 -#define PICO_GROW_INDEXES 1024 -#define PICO_GROW_ARRAYS 8 -#define PICO_GROW_FACES 256 -#define PICO_MAX_SPECIAL 8 -#define PICO_MAX_DEFAULT_EXTS 4 /* max default extensions per module */ - - -/* types */ -typedef unsigned char picoByte_t; -typedef float picoVec_t; -typedef float picoVec2_t[ 2 ]; -typedef float picoVec3_t[ 3 ]; -typedef float picoVec4_t[ 4 ]; -typedef picoByte_t picoColor_t[ 4 ]; -typedef int picoIndex_t; - -typedef enum -{ - PICO_BAD, - PICO_TRIANGLES, - PICO_PATCH -} -picoSurfaceType_t; - -typedef enum -{ - PICO_NORMAL, - PICO_VERBOSE, - PICO_WARNING, - PICO_ERROR, - PICO_FATAL -} -picoPrintLevel_t; - -typedef struct picoSurface_s picoSurface_t; -typedef struct picoShader_s picoShader_t; -typedef struct picoModel_s picoModel_t; -typedef struct picoModule_s picoModule_t; - -struct picoSurface_s -{ - void *data; - - picoModel_t *model; /* owner model */ - - picoSurfaceType_t type; - char *name; /* sea: surface name */ - picoShader_t *shader; /* ydnar: changed to ptr */ - - int numVertexes, maxVertexes; - picoVec3_t *xyz; - picoVec3_t *normal; - - int numSTArrays, maxSTArrays; - picoVec2_t **st; - - int numColorArrays, maxColorArrays; - picoColor_t **color; - - int numIndexes, maxIndexes; - picoIndex_t *index; - - int numFaceNormals, maxFaceNormals; - picoVec3_t *faceNormal; - - int special[ PICO_MAX_SPECIAL ]; -}; - - -/* seaw0lf */ -struct picoShader_s -{ - picoModel_t *model; /* owner model */ - - char *name; /* shader name */ - char *mapName; /* shader file name (name of diffuse texturemap) */ - picoColor_t ambientColor; /* ambient color of mesh (rgba) */ - picoColor_t diffuseColor; /* diffuse color of mesh (rgba) */ - picoColor_t specularColor; /* specular color of mesh (rgba) */ - float transparency; /* transparency (0..1; 1 = 100% transparent) */ - float shininess; /* shininess (0..128; 128 = 100% shiny) */ -}; - -struct picoModel_s -{ - void *data; - char *name; /* model name */ - char *fileName; /* sea: model file name */ - int frameNum; /* sea: renamed to frameNum */ - int numFrames; /* sea: number of frames */ - picoVec3_t mins; - picoVec3_t maxs; - - int numShaders, maxShaders; - picoShader_t **shader; - - int numSurfaces, maxSurfaces; - picoSurface_t **surface; - - const picoModule_t *module; /* sea */ -}; - - -/* seaw0lf */ -/* return codes used by the validation callbacks; pmv is short */ -/* for 'pico module validation'. everything >PICO_PMV_OK means */ -/* that there was an error. */ -enum -{ - PICO_PMV_OK, /* file valid */ - PICO_PMV_ERROR, /* file not valid */ - PICO_PMV_ERROR_IDENT, /* unknown file magic (aka ident) */ - PICO_PMV_ERROR_VERSION, /* unsupported file version */ - PICO_PMV_ERROR_SIZE, /* file size error */ - PICO_PMV_ERROR_MEMORY, /* out of memory error */ -}; - -/* convenience (makes it easy to add new params to the callbacks) */ -#define PM_PARAMS_CANLOAD \ - char *fileName, const void *buffer, int bufSize - -#define PM_PARAMS_LOAD \ - char *fileName, int frameNum, const void *buffer, int bufSize - -#define PM_PARAMS_CANSAVE \ - void - -#define PM_PARAMS_SAVE \ - char *fileName, picoModel_t *model - -/* pico file format module structure */ -struct picoModule_s -{ - char *version; /* internal module version (e.g. '1.5-b2') */ - - char *displayName; /* string used to display in guis, etc. */ - char *authorName; /* author name (eg. 'My Real Name') */ - char *copyright; /* copyright year and holder (eg. '2002 My Company') */ - - char *defaultExts[ PICO_MAX_DEFAULT_EXTS ]; /* default file extensions used by this file type */ - int (*canload)( PM_PARAMS_CANLOAD ); /* checks whether module can load given file (returns PMVR_*) */ - picoModel_t *(*load)( PM_PARAMS_LOAD ); /* parses model file data */ - int (*cansave)( PM_PARAMS_CANSAVE ); /* checks whether module can save (returns 1 or 0 and might spit out a message) */ - int (*save)( PM_PARAMS_SAVE ); /* saves a pico model in module's native model format */ -}; - - - -/* general functions */ -int PicoInit( void ); -void PicoShutdown( void ); -int PicoError( void ); - -void PicoSetMallocFunc( void *(*func)( size_t ) ); -void PicoSetFreeFunc( void (*func)( void* ) ); -void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ); -void PicoSetFreeFileFunc( void (*func)( void* ) ); -void PicoSetPrintFunc( void (*func)( int, const char* ) ); - -const picoModule_t **PicoModuleList( int *numModules ); - -picoModel_t *PicoLoadModel( char *name, int frameNum ); - - -/* model functions */ -picoModel_t *PicoNewModel( void ); -void PicoFreeModel( picoModel_t *model ); -int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ); - - -/* shader functions */ -picoShader_t *PicoNewShader( picoModel_t *model ); -void PicoFreeShader( picoShader_t *shader ); -picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ); - - -/* surface functions */ -picoSurface_t *PicoNewSurface( picoModel_t *model ); -void PicoFreeSurface( picoSurface_t *surface ); -picoSurface_t *PicoFindSurface( picoModel_t *model, char *name, int caseSensitive ); -int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ); - - -/* setter functions */ -void PicoSetModelName( picoModel_t *model, char *name ); -void PicoSetModelFileName( picoModel_t *model, char *fileName ); -void PicoSetModelFrameNum( picoModel_t *model, int frameNum ); -void PicoSetModelNumFrames( picoModel_t *model, int numFrames ); -void PicoSetModelData( picoModel_t *model, void *data ); - -void PicoSetShaderName( picoShader_t *shader, char *name ); -void PicoSetShaderMapName( picoShader_t *shader, char *mapName ); -void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ); -void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ); -void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ); -void PicoSetShaderTransparency( picoShader_t *shader, float value ); -void PicoSetShaderShininess( picoShader_t *shader, float value ); - -void PicoSetSurfaceData( picoSurface_t *surface, void *data ); -void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ); -void PicoSetSurfaceName( picoSurface_t *surface, char *name ); -void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ); -void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ); -void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); -void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ); -void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ); -void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ); -void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ); -void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); -void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ); - - -/* getter functions */ -char *PicoGetModelName( picoModel_t *model ); -char *PicoGetModelFileName( picoModel_t *model ); -int PicoGetModelFrameNum( picoModel_t *model ); -int PicoGetModelNumFrames( picoModel_t *model ); -void *PicoGetModelData( picoModel_t *model ); -int PicoGetModelNumShaders( picoModel_t *model ); -picoShader_t *PicoGetModelShader( picoModel_t *model, int num ); /* sea */ -int PicoGetModelNumSurfaces( picoModel_t *model ); -picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ); -int PicoGetModelTotalVertexes( picoModel_t *model ); -int PicoGetModelTotalIndexes( picoModel_t *model ); - -char *PicoGetShaderName( picoShader_t *shader ); -char *PicoGetShaderMapName( picoShader_t *shader ); -picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ); -picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ); -picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ); -float PicoGetShaderTransparency( picoShader_t *shader ); -float PicoGetShaderShininess( picoShader_t *shader ); - -void *PicoGetSurfaceData( picoSurface_t *surface ); -char *PicoGetSurfaceName( picoSurface_t *surface ); /* sea */ -picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ); -char *PicoGetSurfaceName( picoSurface_t *surface ); -picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ); /* sea */ - -int PicoGetSurfaceNumVertexes( picoSurface_t *surface ); -picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ); -picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ); -picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ); -picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ); -int PicoGetSurfaceNumIndexes( picoSurface_t *surface ); -picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ); -picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ); -picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ); -int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ); - - -/* hashtable related functions */ -typedef struct picoVertexCombinationData_s -{ - picoVec3_t xyz, normal; - picoVec2_t st; - picoColor_t color; -} picoVertexCombinationData_t; - -typedef struct picoVertexCombinationHash_s -{ - picoVertexCombinationData_t vcd; - picoIndex_t index; - - void *data; - - struct picoVertexCombinationHash_s *next; -} picoVertexCombinationHash_t; - -int PicoGetHashTableSize( void ); -unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ); -picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ); -void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ); -picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ); -picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ); - -/* specialized functions */ -int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ); -void PicoFixSurfaceNormals( picoSurface_t *surface ); -int PicoRemapModel( picoModel_t *model, char *remapFile ); - - -void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, picoShader_t* shader ); - -/* end marker */ -#ifdef __cplusplus -} -#endif - -#endif +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef PICOMODEL_H +#define PICOMODEL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* version */ +#define PICOMODEL_VERSION "0.8.20" + + +/* constants */ +#define PICO_GROW_SHADERS 16 +#define PICO_GROW_SURFACES 16 +#define PICO_GROW_VERTEXES 1024 +#define PICO_GROW_INDEXES 1024 +#define PICO_GROW_ARRAYS 8 +#define PICO_GROW_FACES 256 +#define PICO_MAX_SPECIAL 8 +#define PICO_MAX_DEFAULT_EXTS 4 /* max default extensions per module */ + + +/* types */ +typedef unsigned char picoByte_t; +typedef float picoVec_t; +typedef float picoVec2_t[ 2 ]; +typedef float picoVec3_t[ 3 ]; +typedef float picoVec4_t[ 4 ]; +typedef picoByte_t picoColor_t[ 4 ]; +typedef int picoIndex_t; + +typedef enum +{ + PICO_BAD, + PICO_TRIANGLES, + PICO_PATCH +} +picoSurfaceType_t; + +typedef enum +{ + PICO_NORMAL, + PICO_VERBOSE, + PICO_WARNING, + PICO_ERROR, + PICO_FATAL +} +picoPrintLevel_t; + +typedef struct picoSurface_s picoSurface_t; +typedef struct picoShader_s picoShader_t; +typedef struct picoModel_s picoModel_t; +typedef struct picoModule_s picoModule_t; + +struct picoSurface_s +{ + void *data; + + picoModel_t *model; /* owner model */ + + picoSurfaceType_t type; + char *name; /* sea: surface name */ + picoShader_t *shader; /* ydnar: changed to ptr */ + + int numVertexes, maxVertexes; + picoVec3_t *xyz; + picoVec3_t *normal; + + int numSTArrays, maxSTArrays; + picoVec2_t **st; + + int numColorArrays, maxColorArrays; + picoColor_t **color; + + int numIndexes, maxIndexes; + picoIndex_t *index; + + int numFaceNormals, maxFaceNormals; + picoVec3_t *faceNormal; + + int special[ PICO_MAX_SPECIAL ]; +}; + + +/* seaw0lf */ +struct picoShader_s +{ + picoModel_t *model; /* owner model */ + + char *name; /* shader name */ + char *mapName; /* shader file name (name of diffuse texturemap) */ + picoColor_t ambientColor; /* ambient color of mesh (rgba) */ + picoColor_t diffuseColor; /* diffuse color of mesh (rgba) */ + picoColor_t specularColor; /* specular color of mesh (rgba) */ + float transparency; /* transparency (0..1; 1 = 100% transparent) */ + float shininess; /* shininess (0..128; 128 = 100% shiny) */ +}; + +struct picoModel_s +{ + void *data; + char *name; /* model name */ + char *fileName; /* sea: model file name */ + int frameNum; /* sea: renamed to frameNum */ + int numFrames; /* sea: number of frames */ + picoVec3_t mins; + picoVec3_t maxs; + + int numShaders, maxShaders; + picoShader_t **shader; + + int numSurfaces, maxSurfaces; + picoSurface_t **surface; + + const picoModule_t *module; /* sea */ +}; + + +/* seaw0lf */ +/* return codes used by the validation callbacks; pmv is short */ +/* for 'pico module validation'. everything >PICO_PMV_OK means */ +/* that there was an error. */ +enum +{ + PICO_PMV_OK, /* file valid */ + PICO_PMV_ERROR, /* file not valid */ + PICO_PMV_ERROR_IDENT, /* unknown file magic (aka ident) */ + PICO_PMV_ERROR_VERSION, /* unsupported file version */ + PICO_PMV_ERROR_SIZE, /* file size error */ + PICO_PMV_ERROR_MEMORY, /* out of memory error */ +}; + +/* convenience (makes it easy to add new params to the callbacks) */ +#define PM_PARAMS_CANLOAD \ + char *fileName, const void *buffer, int bufSize + +#define PM_PARAMS_LOAD \ + char *fileName, int frameNum, const void *buffer, int bufSize + +#define PM_PARAMS_CANSAVE \ + void + +#define PM_PARAMS_SAVE \ + char *fileName, picoModel_t *model + +/* pico file format module structure */ +struct picoModule_s +{ + char *version; /* internal module version (e.g. '1.5-b2') */ + + char *displayName; /* string used to display in guis, etc. */ + char *authorName; /* author name (eg. 'My Real Name') */ + char *copyright; /* copyright year and holder (eg. '2002 My Company') */ + + char *defaultExts[ PICO_MAX_DEFAULT_EXTS ]; /* default file extensions used by this file type */ + int (*canload)( PM_PARAMS_CANLOAD ); /* checks whether module can load given file (returns PMVR_*) */ + picoModel_t *(*load)( PM_PARAMS_LOAD ); /* parses model file data */ + int (*cansave)( PM_PARAMS_CANSAVE ); /* checks whether module can save (returns 1 or 0 and might spit out a message) */ + int (*save)( PM_PARAMS_SAVE ); /* saves a pico model in module's native model format */ +}; + + + +/* general functions */ +int PicoInit( void ); +void PicoShutdown( void ); +int PicoError( void ); + +void PicoSetMallocFunc( void *(*func)( size_t ) ); +void PicoSetFreeFunc( void (*func)( void* ) ); +void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ); +void PicoSetFreeFileFunc( void (*func)( void* ) ); +void PicoSetPrintFunc( void (*func)( int, const char* ) ); + +const picoModule_t **PicoModuleList( int *numModules ); + +picoModel_t *PicoLoadModel( char *name, int frameNum ); + + +/* model functions */ +picoModel_t *PicoNewModel( void ); +void PicoFreeModel( picoModel_t *model ); +int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ); + + +/* shader functions */ +picoShader_t *PicoNewShader( picoModel_t *model ); +void PicoFreeShader( picoShader_t *shader ); +picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ); + + +/* surface functions */ +picoSurface_t *PicoNewSurface( picoModel_t *model ); +void PicoFreeSurface( picoSurface_t *surface ); +picoSurface_t *PicoFindSurface( picoModel_t *model, char *name, int caseSensitive ); +int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ); + + +/* setter functions */ +void PicoSetModelName( picoModel_t *model, char *name ); +void PicoSetModelFileName( picoModel_t *model, char *fileName ); +void PicoSetModelFrameNum( picoModel_t *model, int frameNum ); +void PicoSetModelNumFrames( picoModel_t *model, int numFrames ); +void PicoSetModelData( picoModel_t *model, void *data ); + +void PicoSetShaderName( picoShader_t *shader, char *name ); +void PicoSetShaderMapName( picoShader_t *shader, char *mapName ); +void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderTransparency( picoShader_t *shader, float value ); +void PicoSetShaderShininess( picoShader_t *shader, float value ); + +void PicoSetSurfaceData( picoSurface_t *surface, void *data ); +void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ); +void PicoSetSurfaceName( picoSurface_t *surface, char *name ); +void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ); +void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ); +void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); +void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ); +void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ); +void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ); +void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ); +void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); +void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ); + + +/* getter functions */ +char *PicoGetModelName( picoModel_t *model ); +char *PicoGetModelFileName( picoModel_t *model ); +int PicoGetModelFrameNum( picoModel_t *model ); +int PicoGetModelNumFrames( picoModel_t *model ); +void *PicoGetModelData( picoModel_t *model ); +int PicoGetModelNumShaders( picoModel_t *model ); +picoShader_t *PicoGetModelShader( picoModel_t *model, int num ); /* sea */ +int PicoGetModelNumSurfaces( picoModel_t *model ); +picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ); +int PicoGetModelTotalVertexes( picoModel_t *model ); +int PicoGetModelTotalIndexes( picoModel_t *model ); + +char *PicoGetShaderName( picoShader_t *shader ); +char *PicoGetShaderMapName( picoShader_t *shader ); +picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ); +picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ); +picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ); +float PicoGetShaderTransparency( picoShader_t *shader ); +float PicoGetShaderShininess( picoShader_t *shader ); + +void *PicoGetSurfaceData( picoSurface_t *surface ); +char *PicoGetSurfaceName( picoSurface_t *surface ); /* sea */ +picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ); +char *PicoGetSurfaceName( picoSurface_t *surface ); +picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ); /* sea */ + +int PicoGetSurfaceNumVertexes( picoSurface_t *surface ); +picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ); +picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ); +picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ); +picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ); +int PicoGetSurfaceNumIndexes( picoSurface_t *surface ); +picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ); +picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ); +picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ); +int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ); + + +/* hashtable related functions */ +typedef struct picoVertexCombinationData_s +{ + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; +} picoVertexCombinationData_t; + +typedef struct picoVertexCombinationHash_s +{ + picoVertexCombinationData_t vcd; + picoIndex_t index; + + void *data; + + struct picoVertexCombinationHash_s *next; +} picoVertexCombinationHash_t; + +int PicoGetHashTableSize( void ); +unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ); +picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ); +void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ); +picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ); +picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ); + +/* specialized functions */ +int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ); +void PicoFixSurfaceNormals( picoSurface_t *surface ); +int PicoRemapModel( picoModel_t *model, char *remapFile ); + + +void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, picoShader_t* shader ); + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel/lwo/clip.c b/libs/picomodel/lwo/clip.c index 349222a4..8999f409 100644 --- a/libs/picomodel/lwo/clip.c +++ b/libs/picomodel/lwo/clip.c @@ -1,249 +1,249 @@ -/* -====================================================================== -clip.c - -Functions for LWO2 image references. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - - -/* -====================================================================== -lwFreeClip() - -Free memory used by an lwClip. -====================================================================== */ - -void lwFreeClip( lwClip *clip ) -{ - if ( clip ) { - lwListFree( (void*) clip->ifilter, lwFreePlugin ); - lwListFree( (void*) clip->pfilter, lwFreePlugin ); - _pico_free( clip ); - } -} - - -/* -====================================================================== -lwGetClip() - -Read image references from a CLIP chunk in an LWO2 file. -====================================================================== */ - -lwClip *lwGetClip( picoMemStream_t *fp, int cksize ) -{ - lwClip *clip; - lwPlugin *filt; - unsigned int id; - unsigned short sz; - int pos, rlen; - - - /* allocate the Clip structure */ - - clip = _pico_calloc( 1, sizeof( lwClip )); - if ( !clip ) goto Fail; - - clip->contrast.val = 1.0f; - clip->brightness.val = 1.0f; - clip->saturation.val = 1.0f; - clip->gamma.val = 1.0f; - - /* remember where we started */ - - set_flen( 0 ); - pos = _pico_memstream_tell( fp ); - - /* index */ - - clip->index = getI4( fp ); - - /* first subchunk header */ - - clip->type = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) goto Fail; - - sz += sz & 1; - set_flen( 0 ); - - switch ( clip->type ) { - case ID_STIL: - clip->source.still.name = getS0( fp ); - break; - - case ID_ISEQ: - clip->source.seq.digits = getU1( fp ); - clip->source.seq.flags = getU1( fp ); - clip->source.seq.offset = getI2( fp ); - getU2( fp ); /* not sure what this is yet */ - clip->source.seq.start = getI2( fp ); - clip->source.seq.end = getI2( fp ); - clip->source.seq.prefix = getS0( fp ); - clip->source.seq.suffix = getS0( fp ); - break; - - case ID_ANIM: - clip->source.anim.name = getS0( fp ); - clip->source.anim.server = getS0( fp ); - rlen = get_flen(); - clip->source.anim.data = getbytes( fp, sz - rlen ); - break; - - case ID_XREF: - clip->source.xref.index = getI4( fp ); - clip->source.xref.string = getS0( fp ); - break; - - case ID_STCC: - clip->source.cycle.lo = getI2( fp ); - clip->source.cycle.hi = getI2( fp ); - clip->source.cycle.name = getS0( fp ); - break; - - default: - break; - } - - /* error while reading current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) goto Fail; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the CLIP chunk? */ - - rlen = _pico_memstream_tell( fp ) - pos; - if ( cksize < rlen ) goto Fail; - if ( cksize == rlen ) - return clip; - - /* process subchunks as they're encountered */ - - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) goto Fail; - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_TIME: - clip->start_time = getF4( fp ); - clip->duration = getF4( fp ); - clip->frame_rate = getF4( fp ); - break; - - case ID_CONT: - clip->contrast.val = getF4( fp ); - clip->contrast.eindex = getVX( fp ); - break; - - case ID_BRIT: - clip->brightness.val = getF4( fp ); - clip->brightness.eindex = getVX( fp ); - break; - - case ID_SATR: - clip->saturation.val = getF4( fp ); - clip->saturation.eindex = getVX( fp ); - break; - - case ID_HUE: - clip->hue.val = getF4( fp ); - clip->hue.eindex = getVX( fp ); - break; - - case ID_GAMM: - clip->gamma.val = getF4( fp ); - clip->gamma.eindex = getVX( fp ); - break; - - case ID_NEGA: - clip->negative = getU2( fp ); - break; - - case ID_IFLT: - case ID_PFLT: - filt = _pico_calloc( 1, sizeof( lwPlugin )); - if ( !filt ) goto Fail; - - filt->name = getS0( fp ); - filt->flags = getU2( fp ); - rlen = get_flen(); - filt->data = getbytes( fp, sz - rlen ); - - if ( id == ID_IFLT ) { - lwListAdd( &clip->ifilter, filt ); - clip->nifilters++; - } - else { - lwListAdd( &clip->pfilter, filt ); - clip->npfilters++; - } - break; - - default: - break; - } - - /* error while reading current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) goto Fail; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the CLIP chunk? */ - - rlen = _pico_memstream_tell( fp ) - pos; - if ( cksize < rlen ) goto Fail; - if ( cksize == rlen ) break; - - /* get the next chunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) goto Fail; - } - - return clip; - -Fail: - lwFreeClip( clip ); - return NULL; -} - - -/* -====================================================================== -lwFindClip() - -Returns an lwClip pointer, given a clip index. -====================================================================== */ - -lwClip *lwFindClip( lwClip *list, int index ) -{ - lwClip *clip; - - clip = list; - while ( clip ) { - if ( clip->index == index ) break; - clip = clip->next; - } - return clip; -} +/* +====================================================================== +clip.c + +Functions for LWO2 image references. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreeClip() + +Free memory used by an lwClip. +====================================================================== */ + +void lwFreeClip( lwClip *clip ) +{ + if ( clip ) { + lwListFree( (void*) clip->ifilter, lwFreePlugin ); + lwListFree( (void*) clip->pfilter, lwFreePlugin ); + _pico_free( clip ); + } +} + + +/* +====================================================================== +lwGetClip() + +Read image references from a CLIP chunk in an LWO2 file. +====================================================================== */ + +lwClip *lwGetClip( picoMemStream_t *fp, int cksize ) +{ + lwClip *clip; + lwPlugin *filt; + unsigned int id; + unsigned short sz; + int pos, rlen; + + + /* allocate the Clip structure */ + + clip = _pico_calloc( 1, sizeof( lwClip )); + if ( !clip ) goto Fail; + + clip->contrast.val = 1.0f; + clip->brightness.val = 1.0f; + clip->saturation.val = 1.0f; + clip->gamma.val = 1.0f; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* index */ + + clip->index = getI4( fp ); + + /* first subchunk header */ + + clip->type = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + sz += sz & 1; + set_flen( 0 ); + + switch ( clip->type ) { + case ID_STIL: + clip->source.still.name = getS0( fp ); + break; + + case ID_ISEQ: + clip->source.seq.digits = getU1( fp ); + clip->source.seq.flags = getU1( fp ); + clip->source.seq.offset = getI2( fp ); + getU2( fp ); /* not sure what this is yet */ + clip->source.seq.start = getI2( fp ); + clip->source.seq.end = getI2( fp ); + clip->source.seq.prefix = getS0( fp ); + clip->source.seq.suffix = getS0( fp ); + break; + + case ID_ANIM: + clip->source.anim.name = getS0( fp ); + clip->source.anim.server = getS0( fp ); + rlen = get_flen(); + clip->source.anim.data = getbytes( fp, sz - rlen ); + break; + + case ID_XREF: + clip->source.xref.index = getI4( fp ); + clip->source.xref.string = getS0( fp ); + break; + + case ID_STCC: + clip->source.cycle.lo = getI2( fp ); + clip->source.cycle.hi = getI2( fp ); + clip->source.cycle.name = getS0( fp ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the CLIP chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) + return clip; + + /* process subchunks as they're encountered */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TIME: + clip->start_time = getF4( fp ); + clip->duration = getF4( fp ); + clip->frame_rate = getF4( fp ); + break; + + case ID_CONT: + clip->contrast.val = getF4( fp ); + clip->contrast.eindex = getVX( fp ); + break; + + case ID_BRIT: + clip->brightness.val = getF4( fp ); + clip->brightness.eindex = getVX( fp ); + break; + + case ID_SATR: + clip->saturation.val = getF4( fp ); + clip->saturation.eindex = getVX( fp ); + break; + + case ID_HUE: + clip->hue.val = getF4( fp ); + clip->hue.eindex = getVX( fp ); + break; + + case ID_GAMM: + clip->gamma.val = getF4( fp ); + clip->gamma.eindex = getVX( fp ); + break; + + case ID_NEGA: + clip->negative = getU2( fp ); + break; + + case ID_IFLT: + case ID_PFLT: + filt = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !filt ) goto Fail; + + filt->name = getS0( fp ); + filt->flags = getU2( fp ); + rlen = get_flen(); + filt->data = getbytes( fp, sz - rlen ); + + if ( id == ID_IFLT ) { + lwListAdd( &clip->ifilter, filt ); + clip->nifilters++; + } + else { + lwListAdd( &clip->pfilter, filt ); + clip->npfilters++; + } + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the CLIP chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return clip; + +Fail: + lwFreeClip( clip ); + return NULL; +} + + +/* +====================================================================== +lwFindClip() + +Returns an lwClip pointer, given a clip index. +====================================================================== */ + +lwClip *lwFindClip( lwClip *list, int index ) +{ + lwClip *clip; + + clip = list; + while ( clip ) { + if ( clip->index == index ) break; + clip = clip->next; + } + return clip; +} diff --git a/libs/picomodel/lwo/envelope.c b/libs/picomodel/lwo/envelope.c index 4ece5951..e3e281ff 100644 --- a/libs/picomodel/lwo/envelope.c +++ b/libs/picomodel/lwo/envelope.c @@ -1,600 +1,600 @@ -/* -====================================================================== -envelope.c - -Envelope functions for an LWO2 reader. - -Ernie Wright 16 Nov 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - -/* -====================================================================== -lwFreeEnvelope() - -Free the memory used by an lwEnvelope. -====================================================================== */ - -void lwFreeEnvelope( lwEnvelope *env ) -{ - if ( env ) { - if ( env->name ) _pico_free( env->name ); - lwListFree( env->key, _pico_free ); - lwListFree( env->cfilter, lwFreePlugin ); - _pico_free( env ); - } -} - - -static int compare_keys( lwKey *k1, lwKey *k2 ) -{ - return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0; -} - - -/* -====================================================================== -lwGetEnvelope() - -Read an ENVL chunk from an LWO2 file. -====================================================================== */ - -lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ) -{ - lwEnvelope *env; - lwKey *key; - lwPlugin *plug; - unsigned int id; - unsigned short sz; - float f[ 4 ]; - int i, nparams, pos, rlen; - - - /* allocate the Envelope structure */ - - env = _pico_calloc( 1, sizeof( lwEnvelope )); - if ( !env ) goto Fail; - - /* remember where we started */ - - set_flen( 0 ); - pos = _pico_memstream_tell( fp ); - - /* index */ - - env->index = getVX( fp ); - - /* first subchunk header */ - - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) goto Fail; - - /* process subchunks as they're encountered */ - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_TYPE: - env->type = getU2( fp ); - break; - - case ID_NAME: - env->name = getS0( fp ); - break; - - case ID_PRE: - env->behavior[ 0 ] = getU2( fp ); - break; - - case ID_POST: - env->behavior[ 1 ] = getU2( fp ); - break; - - case ID_KEY: - key = _pico_calloc( 1, sizeof( lwKey )); - if ( !key ) goto Fail; - key->time = getF4( fp ); - key->value = getF4( fp ); - lwListInsert( &env->key, key, compare_keys ); - env->nkeys++; - break; - - case ID_SPAN: - if ( !key ) goto Fail; - key->shape = getU4( fp ); - - nparams = ( sz - 4 ) / 4; - if ( nparams > 4 ) nparams = 4; - for ( i = 0; i < nparams; i++ ) - f[ i ] = getF4( fp ); - - switch ( key->shape ) { - case ID_TCB: - key->tension = f[ 0 ]; - key->continuity = f[ 1 ]; - key->bias = f[ 2 ]; - break; - - case ID_BEZI: - case ID_HERM: - case ID_BEZ2: - for ( i = 0; i < nparams; i++ ) - key->param[ i ] = f[ i ]; - break; - } - break; - - case ID_CHAN: - plug = _pico_calloc( 1, sizeof( lwPlugin )); - if ( !plug ) goto Fail; - - plug->name = getS0( fp ); - plug->flags = getU2( fp ); - plug->data = getbytes( fp, sz - get_flen() ); - - lwListAdd( &env->cfilter, plug ); - env->ncfilters++; - break; - - default: - break; - } - - /* error while reading current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) goto Fail; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the ENVL chunk? */ - - rlen = _pico_memstream_tell( fp ) - pos; - if ( cksize < rlen ) goto Fail; - if ( cksize == rlen ) break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) goto Fail; - } - - return env; - -Fail: - lwFreeEnvelope( env ); - return NULL; -} - - -/* -====================================================================== -lwFindEnvelope() - -Returns an lwEnvelope pointer, given an envelope index. -====================================================================== */ - -lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ) -{ - lwEnvelope *env; - - env = list; - while ( env ) { - if ( env->index == index ) break; - env = env->next; - } - return env; -} - - -/* -====================================================================== -range() - -Given the value v of a periodic function, returns the equivalent value -v2 in the principal interval [lo, hi]. If i isn't NULL, it receives -the number of wavelengths between v and v2. - - v2 = v - i * (hi - lo) - -For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1. -====================================================================== */ - -static float range( float v, float lo, float hi, int *i ) -{ - float v2, r = hi - lo; - - if ( r == 0.0 ) { - if ( i ) *i = 0; - return lo; - } - - v2 = lo + v - r * ( float ) floor(( double ) v / r ); - if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 )); - - return v2; -} - - -/* -====================================================================== -hermite() - -Calculate the Hermite coefficients. -====================================================================== */ - -static void hermite( float t, float *h1, float *h2, float *h3, float *h4 ) -{ - float t2, t3; - - t2 = t * t; - t3 = t * t2; - - *h2 = 3.0f * t2 - t3 - t3; - *h1 = 1.0f - *h2; - *h4 = t3 - t2; - *h3 = *h4 - t2 + t; -} - - -/* -====================================================================== -bezier() - -Interpolate the value of a 1D Bezier curve. -====================================================================== */ - -static float bezier( float x0, float x1, float x2, float x3, float t ) -{ - float a, b, c, t2, t3; - - t2 = t * t; - t3 = t2 * t; - - c = 3.0f * ( x1 - x0 ); - b = 3.0f * ( x2 - x1 ) - c; - a = x3 - x0 - c - b; - - return a * t3 + b * t2 + c * t + x0; -} - - -/* -====================================================================== -bez2_time() - -Find the t for which bezier() returns the input time. The handle -endpoints of a BEZ2 curve represent the control points, and these have -(time, value) coordinates, so time is used as both a coordinate and a -parameter for this curve type. -====================================================================== */ - -static float bez2_time( float x0, float x1, float x2, float x3, float time, - float *t0, float *t1 ) -{ - float v, t; - - t = *t0 + ( *t1 - *t0 ) * 0.5f; - v = bezier( x0, x1, x2, x3, t ); - if ( fabs( time - v ) > .0001f ) { - if ( v > time ) - *t1 = t; - else - *t0 = t; - return bez2_time( x0, x1, x2, x3, time, t0, t1 ); - } - else - return t; -} - - -/* -====================================================================== -bez2() - -Interpolate the value of a BEZ2 curve. -====================================================================== */ - -static float bez2( lwKey *key0, lwKey *key1, float time ) -{ - float x, y, t, t0 = 0.0f, t1 = 1.0f; - - if ( key0->shape == ID_BEZ2 ) - x = key0->time + key0->param[ 2 ]; - else - x = key0->time + ( key1->time - key0->time ) / 3.0f; - - t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time, - time, &t0, &t1 ); - - if ( key0->shape == ID_BEZ2 ) - y = key0->value + key0->param[ 3 ]; - else - y = key0->value + key0->param[ 1 ] / 3.0f; - - return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t ); -} - - -/* -====================================================================== -outgoing() - -Return the outgoing tangent to the curve at key0. The value returned -for the BEZ2 case is used when extrapolating a linear pre behavior and -when interpolating a non-BEZ2 span. -====================================================================== */ - -static float outgoing( lwKey *key0, lwKey *key1 ) -{ - float a, b, d, t, out; - - switch ( key0->shape ) - { - case ID_TCB: - a = ( 1.0f - key0->tension ) - * ( 1.0f + key0->continuity ) - * ( 1.0f + key0->bias ); - b = ( 1.0f - key0->tension ) - * ( 1.0f - key0->continuity ) - * ( 1.0f - key0->bias ); - d = key1->value - key0->value; - - if ( key0->prev ) { - t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); - out = t * ( a * ( key0->value - key0->prev->value ) + b * d ); - } - else - out = b * d; - break; - - case ID_LINE: - d = key1->value - key0->value; - if ( key0->prev ) { - t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); - out = t * ( key0->value - key0->prev->value + d ); - } - else - out = d; - break; - - case ID_BEZI: - case ID_HERM: - out = key0->param[ 1 ]; - if ( key0->prev ) - out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); - break; - - case ID_BEZ2: - out = key0->param[ 3 ] * ( key1->time - key0->time ); - if ( fabs( key0->param[ 2 ] ) > 1e-5f ) - out /= key0->param[ 2 ]; - else - out *= 1e5f; - break; - - case ID_STEP: - default: - out = 0.0f; - break; - } - - return out; -} - - -/* -====================================================================== -incoming() - -Return the incoming tangent to the curve at key1. The value returned -for the BEZ2 case is used when extrapolating a linear post behavior. -====================================================================== */ - -static float incoming( lwKey *key0, lwKey *key1 ) -{ - float a, b, d, t, in; - - switch ( key1->shape ) - { - case ID_LINE: - d = key1->value - key0->value; - if ( key1->next ) { - t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); - in = t * ( key1->next->value - key1->value + d ); - } - else - in = d; - break; - - case ID_TCB: - a = ( 1.0f - key1->tension ) - * ( 1.0f - key1->continuity ) - * ( 1.0f + key1->bias ); - b = ( 1.0f - key1->tension ) - * ( 1.0f + key1->continuity ) - * ( 1.0f - key1->bias ); - d = key1->value - key0->value; - - if ( key1->next ) { - t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); - in = t * ( b * ( key1->next->value - key1->value ) + a * d ); - } - else - in = a * d; - break; - - case ID_BEZI: - case ID_HERM: - in = key1->param[ 0 ]; - if ( key1->next ) - in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time ); - break; - return in; - - case ID_BEZ2: - in = key1->param[ 1 ] * ( key1->time - key0->time ); - if ( fabs( key1->param[ 0 ] ) > 1e-5f ) - in /= key1->param[ 0 ]; - else - in *= 1e5f; - break; - - case ID_STEP: - default: - in = 0.0f; - break; - } - - return in; -} - - -/* -====================================================================== -evalEnvelope() - -Given a list of keys and a time, returns the interpolated value of the -envelope at that time. -====================================================================== */ - -float evalEnvelope( lwEnvelope *env, float time ) -{ - lwKey *key0, *key1, *skey, *ekey; - float t, h1, h2, h3, h4, in, out, offset = 0.0f; - int noff; - - - /* if there's no key, the value is 0 */ - - if ( env->nkeys == 0 ) return 0.0f; - - /* if there's only one key, the value is constant */ - - if ( env->nkeys == 1 ) - return env->key->value; - - /* find the first and last keys */ - - skey = ekey = env->key; - while ( ekey->next ) ekey = ekey->next; - - /* use pre-behavior if time is before first key time */ - - if ( time < skey->time ) { - switch ( env->behavior[ 0 ] ) - { - case BEH_RESET: - return 0.0f; - - case BEH_CONSTANT: - return skey->value; - - case BEH_REPEAT: - time = range( time, skey->time, ekey->time, NULL ); - break; - - case BEH_OSCILLATE: - time = range( time, skey->time, ekey->time, &noff ); - if ( noff % 2 ) - time = ekey->time - skey->time - time; - break; - - case BEH_OFFSET: - time = range( time, skey->time, ekey->time, &noff ); - offset = noff * ( ekey->value - skey->value ); - break; - - case BEH_LINEAR: - out = outgoing( skey, skey->next ) - / ( skey->next->time - skey->time ); - return out * ( time - skey->time ) + skey->value; - } - } - - /* use post-behavior if time is after last key time */ - - else if ( time > ekey->time ) { - switch ( env->behavior[ 1 ] ) - { - case BEH_RESET: - return 0.0f; - - case BEH_CONSTANT: - return ekey->value; - - case BEH_REPEAT: - time = range( time, skey->time, ekey->time, NULL ); - break; - - case BEH_OSCILLATE: - time = range( time, skey->time, ekey->time, &noff ); - if ( noff % 2 ) - time = ekey->time - skey->time - time; - break; - - case BEH_OFFSET: - time = range( time, skey->time, ekey->time, &noff ); - offset = noff * ( ekey->value - skey->value ); - break; - - case BEH_LINEAR: - in = incoming( ekey->prev, ekey ) - / ( ekey->time - ekey->prev->time ); - return in * ( time - ekey->time ) + ekey->value; - } - } - - /* get the endpoints of the interval being evaluated */ - - key0 = env->key; - while ( time > key0->next->time ) - key0 = key0->next; - key1 = key0->next; - - /* check for singularities first */ - - if ( time == key0->time ) - return key0->value + offset; - else if ( time == key1->time ) - return key1->value + offset; - - /* get interval length, time in [0, 1] */ - - t = ( time - key0->time ) / ( key1->time - key0->time ); - - /* interpolate */ - - switch ( key1->shape ) - { - case ID_TCB: - case ID_BEZI: - case ID_HERM: - out = outgoing( key0, key1 ); - in = incoming( key0, key1 ); - hermite( t, &h1, &h2, &h3, &h4 ); - return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset; - - case ID_BEZ2: - return bez2( key0, key1, time ) + offset; - - case ID_LINE: - return key0->value + t * ( key1->value - key0->value ) + offset; - - case ID_STEP: - return key0->value + offset; - - default: - return offset; - } -} +/* +====================================================================== +envelope.c + +Envelope functions for an LWO2 reader. + +Ernie Wright 16 Nov 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* +====================================================================== +lwFreeEnvelope() + +Free the memory used by an lwEnvelope. +====================================================================== */ + +void lwFreeEnvelope( lwEnvelope *env ) +{ + if ( env ) { + if ( env->name ) _pico_free( env->name ); + lwListFree( env->key, _pico_free ); + lwListFree( env->cfilter, lwFreePlugin ); + _pico_free( env ); + } +} + + +static int compare_keys( lwKey *k1, lwKey *k2 ) +{ + return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0; +} + + +/* +====================================================================== +lwGetEnvelope() + +Read an ENVL chunk from an LWO2 file. +====================================================================== */ + +lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ) +{ + lwEnvelope *env; + lwKey *key; + lwPlugin *plug; + unsigned int id; + unsigned short sz; + float f[ 4 ]; + int i, nparams, pos, rlen; + + + /* allocate the Envelope structure */ + + env = _pico_calloc( 1, sizeof( lwEnvelope )); + if ( !env ) goto Fail; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* index */ + + env->index = getVX( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TYPE: + env->type = getU2( fp ); + break; + + case ID_NAME: + env->name = getS0( fp ); + break; + + case ID_PRE: + env->behavior[ 0 ] = getU2( fp ); + break; + + case ID_POST: + env->behavior[ 1 ] = getU2( fp ); + break; + + case ID_KEY: + key = _pico_calloc( 1, sizeof( lwKey )); + if ( !key ) goto Fail; + key->time = getF4( fp ); + key->value = getF4( fp ); + lwListInsert( &env->key, key, compare_keys ); + env->nkeys++; + break; + + case ID_SPAN: + if ( !key ) goto Fail; + key->shape = getU4( fp ); + + nparams = ( sz - 4 ) / 4; + if ( nparams > 4 ) nparams = 4; + for ( i = 0; i < nparams; i++ ) + f[ i ] = getF4( fp ); + + switch ( key->shape ) { + case ID_TCB: + key->tension = f[ 0 ]; + key->continuity = f[ 1 ]; + key->bias = f[ 2 ]; + break; + + case ID_BEZI: + case ID_HERM: + case ID_BEZ2: + for ( i = 0; i < nparams; i++ ) + key->param[ i ] = f[ i ]; + break; + } + break; + + case ID_CHAN: + plug = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !plug ) goto Fail; + + plug->name = getS0( fp ); + plug->flags = getU2( fp ); + plug->data = getbytes( fp, sz - get_flen() ); + + lwListAdd( &env->cfilter, plug ); + env->ncfilters++; + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the ENVL chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return env; + +Fail: + lwFreeEnvelope( env ); + return NULL; +} + + +/* +====================================================================== +lwFindEnvelope() + +Returns an lwEnvelope pointer, given an envelope index. +====================================================================== */ + +lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ) +{ + lwEnvelope *env; + + env = list; + while ( env ) { + if ( env->index == index ) break; + env = env->next; + } + return env; +} + + +/* +====================================================================== +range() + +Given the value v of a periodic function, returns the equivalent value +v2 in the principal interval [lo, hi]. If i isn't NULL, it receives +the number of wavelengths between v and v2. + + v2 = v - i * (hi - lo) + +For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1. +====================================================================== */ + +static float range( float v, float lo, float hi, int *i ) +{ + float v2, r = hi - lo; + + if ( r == 0.0 ) { + if ( i ) *i = 0; + return lo; + } + + v2 = lo + v - r * ( float ) floor(( double ) v / r ); + if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 )); + + return v2; +} + + +/* +====================================================================== +hermite() + +Calculate the Hermite coefficients. +====================================================================== */ + +static void hermite( float t, float *h1, float *h2, float *h3, float *h4 ) +{ + float t2, t3; + + t2 = t * t; + t3 = t * t2; + + *h2 = 3.0f * t2 - t3 - t3; + *h1 = 1.0f - *h2; + *h4 = t3 - t2; + *h3 = *h4 - t2 + t; +} + + +/* +====================================================================== +bezier() + +Interpolate the value of a 1D Bezier curve. +====================================================================== */ + +static float bezier( float x0, float x1, float x2, float x3, float t ) +{ + float a, b, c, t2, t3; + + t2 = t * t; + t3 = t2 * t; + + c = 3.0f * ( x1 - x0 ); + b = 3.0f * ( x2 - x1 ) - c; + a = x3 - x0 - c - b; + + return a * t3 + b * t2 + c * t + x0; +} + + +/* +====================================================================== +bez2_time() + +Find the t for which bezier() returns the input time. The handle +endpoints of a BEZ2 curve represent the control points, and these have +(time, value) coordinates, so time is used as both a coordinate and a +parameter for this curve type. +====================================================================== */ + +static float bez2_time( float x0, float x1, float x2, float x3, float time, + float *t0, float *t1 ) +{ + float v, t; + + t = *t0 + ( *t1 - *t0 ) * 0.5f; + v = bezier( x0, x1, x2, x3, t ); + if ( fabs( time - v ) > .0001f ) { + if ( v > time ) + *t1 = t; + else + *t0 = t; + return bez2_time( x0, x1, x2, x3, time, t0, t1 ); + } + else + return t; +} + + +/* +====================================================================== +bez2() + +Interpolate the value of a BEZ2 curve. +====================================================================== */ + +static float bez2( lwKey *key0, lwKey *key1, float time ) +{ + float x, y, t, t0 = 0.0f, t1 = 1.0f; + + if ( key0->shape == ID_BEZ2 ) + x = key0->time + key0->param[ 2 ]; + else + x = key0->time + ( key1->time - key0->time ) / 3.0f; + + t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time, + time, &t0, &t1 ); + + if ( key0->shape == ID_BEZ2 ) + y = key0->value + key0->param[ 3 ]; + else + y = key0->value + key0->param[ 1 ] / 3.0f; + + return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t ); +} + + +/* +====================================================================== +outgoing() + +Return the outgoing tangent to the curve at key0. The value returned +for the BEZ2 case is used when extrapolating a linear pre behavior and +when interpolating a non-BEZ2 span. +====================================================================== */ + +static float outgoing( lwKey *key0, lwKey *key1 ) +{ + float a, b, d, t, out; + + switch ( key0->shape ) + { + case ID_TCB: + a = ( 1.0f - key0->tension ) + * ( 1.0f + key0->continuity ) + * ( 1.0f + key0->bias ); + b = ( 1.0f - key0->tension ) + * ( 1.0f - key0->continuity ) + * ( 1.0f - key0->bias ); + d = key1->value - key0->value; + + if ( key0->prev ) { + t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + out = t * ( a * ( key0->value - key0->prev->value ) + b * d ); + } + else + out = b * d; + break; + + case ID_LINE: + d = key1->value - key0->value; + if ( key0->prev ) { + t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + out = t * ( key0->value - key0->prev->value + d ); + } + else + out = d; + break; + + case ID_BEZI: + case ID_HERM: + out = key0->param[ 1 ]; + if ( key0->prev ) + out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + break; + + case ID_BEZ2: + out = key0->param[ 3 ] * ( key1->time - key0->time ); + if ( fabs( key0->param[ 2 ] ) > 1e-5f ) + out /= key0->param[ 2 ]; + else + out *= 1e5f; + break; + + case ID_STEP: + default: + out = 0.0f; + break; + } + + return out; +} + + +/* +====================================================================== +incoming() + +Return the incoming tangent to the curve at key1. The value returned +for the BEZ2 case is used when extrapolating a linear post behavior. +====================================================================== */ + +static float incoming( lwKey *key0, lwKey *key1 ) +{ + float a, b, d, t, in; + + switch ( key1->shape ) + { + case ID_LINE: + d = key1->value - key0->value; + if ( key1->next ) { + t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + in = t * ( key1->next->value - key1->value + d ); + } + else + in = d; + break; + + case ID_TCB: + a = ( 1.0f - key1->tension ) + * ( 1.0f - key1->continuity ) + * ( 1.0f + key1->bias ); + b = ( 1.0f - key1->tension ) + * ( 1.0f + key1->continuity ) + * ( 1.0f - key1->bias ); + d = key1->value - key0->value; + + if ( key1->next ) { + t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + in = t * ( b * ( key1->next->value - key1->value ) + a * d ); + } + else + in = a * d; + break; + + case ID_BEZI: + case ID_HERM: + in = key1->param[ 0 ]; + if ( key1->next ) + in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + break; + return in; + + case ID_BEZ2: + in = key1->param[ 1 ] * ( key1->time - key0->time ); + if ( fabs( key1->param[ 0 ] ) > 1e-5f ) + in /= key1->param[ 0 ]; + else + in *= 1e5f; + break; + + case ID_STEP: + default: + in = 0.0f; + break; + } + + return in; +} + + +/* +====================================================================== +evalEnvelope() + +Given a list of keys and a time, returns the interpolated value of the +envelope at that time. +====================================================================== */ + +float evalEnvelope( lwEnvelope *env, float time ) +{ + lwKey *key0, *key1, *skey, *ekey; + float t, h1, h2, h3, h4, in, out, offset = 0.0f; + int noff; + + + /* if there's no key, the value is 0 */ + + if ( env->nkeys == 0 ) return 0.0f; + + /* if there's only one key, the value is constant */ + + if ( env->nkeys == 1 ) + return env->key->value; + + /* find the first and last keys */ + + skey = ekey = env->key; + while ( ekey->next ) ekey = ekey->next; + + /* use pre-behavior if time is before first key time */ + + if ( time < skey->time ) { + switch ( env->behavior[ 0 ] ) + { + case BEH_RESET: + return 0.0f; + + case BEH_CONSTANT: + return skey->value; + + case BEH_REPEAT: + time = range( time, skey->time, ekey->time, NULL ); + break; + + case BEH_OSCILLATE: + time = range( time, skey->time, ekey->time, &noff ); + if ( noff % 2 ) + time = ekey->time - skey->time - time; + break; + + case BEH_OFFSET: + time = range( time, skey->time, ekey->time, &noff ); + offset = noff * ( ekey->value - skey->value ); + break; + + case BEH_LINEAR: + out = outgoing( skey, skey->next ) + / ( skey->next->time - skey->time ); + return out * ( time - skey->time ) + skey->value; + } + } + + /* use post-behavior if time is after last key time */ + + else if ( time > ekey->time ) { + switch ( env->behavior[ 1 ] ) + { + case BEH_RESET: + return 0.0f; + + case BEH_CONSTANT: + return ekey->value; + + case BEH_REPEAT: + time = range( time, skey->time, ekey->time, NULL ); + break; + + case BEH_OSCILLATE: + time = range( time, skey->time, ekey->time, &noff ); + if ( noff % 2 ) + time = ekey->time - skey->time - time; + break; + + case BEH_OFFSET: + time = range( time, skey->time, ekey->time, &noff ); + offset = noff * ( ekey->value - skey->value ); + break; + + case BEH_LINEAR: + in = incoming( ekey->prev, ekey ) + / ( ekey->time - ekey->prev->time ); + return in * ( time - ekey->time ) + ekey->value; + } + } + + /* get the endpoints of the interval being evaluated */ + + key0 = env->key; + while ( time > key0->next->time ) + key0 = key0->next; + key1 = key0->next; + + /* check for singularities first */ + + if ( time == key0->time ) + return key0->value + offset; + else if ( time == key1->time ) + return key1->value + offset; + + /* get interval length, time in [0, 1] */ + + t = ( time - key0->time ) / ( key1->time - key0->time ); + + /* interpolate */ + + switch ( key1->shape ) + { + case ID_TCB: + case ID_BEZI: + case ID_HERM: + out = outgoing( key0, key1 ); + in = incoming( key0, key1 ); + hermite( t, &h1, &h2, &h3, &h4 ); + return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset; + + case ID_BEZ2: + return bez2( key0, key1, time ) + offset; + + case ID_LINE: + return key0->value + t * ( key1->value - key0->value ) + offset; + + case ID_STEP: + return key0->value + offset; + + default: + return offset; + } +} diff --git a/libs/picomodel/lwo/list.c b/libs/picomodel/lwo/list.c index d07b0337..d337296c 100644 --- a/libs/picomodel/lwo/list.c +++ b/libs/picomodel/lwo/list.c @@ -1,101 +1,101 @@ -/* -====================================================================== -list.c - -Generic linked list operations. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - - -/* -====================================================================== -lwListFree() - -Free the items in a list. -====================================================================== */ - -void lwListFree( void *list, void ( *freeNode )( void * )) -{ - lwNode *node, *next; - - node = ( lwNode * ) list; - while ( node ) { - next = node->next; - freeNode( node ); - node = next; - } -} - - -/* -====================================================================== -lwListAdd() - -Append a node to a list. -====================================================================== */ - -void lwListAdd( void **list, void *node ) -{ - lwNode *head, *tail; - - head = *(( lwNode ** ) list ); - if ( !head ) { - *list = node; - return; - } - while ( head ) { - tail = head; - head = head->next; - } - tail->next = ( lwNode * ) node; - (( lwNode * ) node )->prev = tail; -} - - -/* -====================================================================== -lwListInsert() - -Insert a node into a list in sorted order. -====================================================================== */ - -void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * )) -{ - lwNode **list, *item, *node, *prev; - - if ( !*vlist ) { - *vlist = vitem; - return; - } - - list = ( lwNode ** ) vlist; - item = ( lwNode * ) vitem; - node = *list; - prev = NULL; - - while ( node ) { - if ( 0 < compare( node, item )) break; - prev = node; - node = node->next; - } - - if ( !prev ) { - *list = item; - node->prev = item; - item->next = node; - } - else if ( !node ) { - prev->next = item; - item->prev = prev; - } - else { - item->next = node; - item->prev = prev; - prev->next = item; - node->prev = item; - } -} +/* +====================================================================== +list.c + +Generic linked list operations. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwListFree() + +Free the items in a list. +====================================================================== */ + +void lwListFree( void *list, void ( *freeNode )( void * )) +{ + lwNode *node, *next; + + node = ( lwNode * ) list; + while ( node ) { + next = node->next; + freeNode( node ); + node = next; + } +} + + +/* +====================================================================== +lwListAdd() + +Append a node to a list. +====================================================================== */ + +void lwListAdd( void **list, void *node ) +{ + lwNode *head, *tail; + + head = *(( lwNode ** ) list ); + if ( !head ) { + *list = node; + return; + } + while ( head ) { + tail = head; + head = head->next; + } + tail->next = ( lwNode * ) node; + (( lwNode * ) node )->prev = tail; +} + + +/* +====================================================================== +lwListInsert() + +Insert a node into a list in sorted order. +====================================================================== */ + +void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * )) +{ + lwNode **list, *item, *node, *prev; + + if ( !*vlist ) { + *vlist = vitem; + return; + } + + list = ( lwNode ** ) vlist; + item = ( lwNode * ) vitem; + node = *list; + prev = NULL; + + while ( node ) { + if ( 0 < compare( node, item )) break; + prev = node; + node = node->next; + } + + if ( !prev ) { + *list = item; + node->prev = item; + item->next = node; + } + else if ( !node ) { + prev->next = item; + item->prev = prev; + } + else { + item->next = node; + item->prev = prev; + prev->next = item; + node->prev = item; + } +} diff --git a/libs/picomodel/lwo/lwio.c b/libs/picomodel/lwo/lwio.c index eea380bf..ec74932f 100644 --- a/libs/picomodel/lwo/lwio.c +++ b/libs/picomodel/lwo/lwio.c @@ -1,442 +1,442 @@ -/* -====================================================================== -lwio.c - -Functions for reading basic LWO2 data types. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - - -/* -====================================================================== -flen - -This accumulates a count of the number of bytes read. Callers can set -it at the beginning of a sequence of reads and then retrieve it to get -the number of bytes actually read. If one of the I/O functions fails, -flen is set to an error code, after which the I/O functions ignore -read requests until flen is reset. -====================================================================== */ - -#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ -#define FLEN_ERROR INT_MIN - -static int flen; - -void set_flen( int i ) { flen = i; } - -int get_flen( void ) { return flen; } - - -#ifdef _WIN32 -/* -===================================================================== -revbytes() - -Reverses byte order in place. - -INPUTS - bp bytes to reverse - elsize size of the underlying data type - elcount number of elements to swap - -RESULTS - Reverses the byte order in each of elcount elements. - -This only needs to be defined on little-endian platforms, most -notably Windows. lwo2.h replaces this with a #define on big-endian -platforms. -===================================================================== */ - -void revbytes( void *bp, int elsize, int elcount ) -{ - register unsigned char *p, *q; - - p = ( unsigned char * ) bp; - - if ( elsize == 2 ) { - q = p + 1; - while ( elcount-- ) { - *p ^= *q; - *q ^= *p; - *p ^= *q; - p += 2; - q += 2; - } - return; - } - - while ( elcount-- ) { - q = p + elsize - 1; - while ( p < q ) { - *p ^= *q; - *q ^= *p; - *p ^= *q; - ++p; - --q; - } - p += elsize >> 1; - } -} -#endif - - -void *getbytes( picoMemStream_t *fp, int size ) -{ - void *data; - - if ( flen == FLEN_ERROR ) return NULL; - if ( size < 0 ) { - flen = FLEN_ERROR; - return NULL; - } - data = _pico_alloc( size ); - if ( !data ) { - flen = FLEN_ERROR; - return NULL; - } - if ( 1 != _pico_memstream_read( fp, data, size )) { - flen = FLEN_ERROR; - _pico_free( data ); - return NULL; - } - - flen += size; - return data; -} - - -void skipbytes( picoMemStream_t *fp, int n ) -{ - if ( flen == FLEN_ERROR ) return; - if ( _pico_memstream_seek( fp, n, PICO_SEEK_CUR )) - flen = FLEN_ERROR; - else - flen += n; -} - - -int getI1( picoMemStream_t *fp ) -{ - int i; - - if ( flen == FLEN_ERROR ) return 0; - i = _pico_memstream_getc( fp ); - if ( i < 0 ) { - flen = FLEN_ERROR; - return 0; - } - if ( i > 127 ) i -= 256; - flen += 1; - return i; -} - - -short getI2( picoMemStream_t *fp ) -{ - short i; - - if ( flen == FLEN_ERROR ) return 0; - if ( 1 != _pico_memstream_read( fp, &i, 2 )) { - flen = FLEN_ERROR; - return 0; - } - revbytes( &i, 2, 1 ); - flen += 2; - return i; -} - - -int getI4( picoMemStream_t *fp ) -{ - int i; - - if ( flen == FLEN_ERROR ) return 0; - if ( 1 != _pico_memstream_read( fp, &i, 4 )) { - flen = FLEN_ERROR; - return 0; - } - revbytes( &i, 4, 1 ); - flen += 4; - return i; -} - - -unsigned char getU1( picoMemStream_t *fp ) -{ - int i; - - if ( flen == FLEN_ERROR ) return 0; - i = _pico_memstream_getc( fp ); - if ( i < 0 ) { - flen = FLEN_ERROR; - return 0; - } - flen += 1; - return i; -} - - -unsigned short getU2( picoMemStream_t *fp ) -{ - unsigned short i; - - if ( flen == FLEN_ERROR ) return 0; - if ( 1 != _pico_memstream_read( fp, &i, 2 )) { - flen = FLEN_ERROR; - return 0; - } - revbytes( &i, 2, 1 ); - flen += 2; - return i; -} - - -unsigned int getU4( picoMemStream_t *fp ) -{ - unsigned int i; - - if ( flen == FLEN_ERROR ) return 0; - if ( 1 != _pico_memstream_read( fp, &i, 4 )) { - flen = FLEN_ERROR; - return 0; - } - revbytes( &i, 4, 1 ); - flen += 4; - return i; -} - - -int getVX( picoMemStream_t *fp ) -{ - int i, c; - - if ( flen == FLEN_ERROR ) return 0; - - c = _pico_memstream_getc( fp ); - if ( c != 0xFF ) { - i = c << 8; - c = _pico_memstream_getc( fp ); - i |= c; - flen += 2; - } - else { - c = _pico_memstream_getc( fp ); - i = c << 16; - c = _pico_memstream_getc( fp ); - i |= c << 8; - c = _pico_memstream_getc( fp ); - i |= c; - flen += 4; - } - - if ( _pico_memstream_error( fp )) { - flen = FLEN_ERROR; - return 0; - } - return i; -} - - -float getF4( picoMemStream_t *fp ) -{ - float f; - - if ( flen == FLEN_ERROR ) return 0.0f; - if ( 1 != _pico_memstream_read( fp, &f, 4 )) { - flen = FLEN_ERROR; - return 0.0f; - } - revbytes( &f, 4, 1 ); - flen += 4; - return f; -} - - -char *getS0( picoMemStream_t *fp ) -{ - char *s; - int i, c, len, pos; - - if ( flen == FLEN_ERROR ) return NULL; - - pos = _pico_memstream_tell( fp ); - for ( i = 1; ; i++ ) { - c = _pico_memstream_getc( fp ); - if ( c <= 0 ) break; - } - if ( c < 0 ) { - flen = FLEN_ERROR; - return NULL; - } - - if ( i == 1 ) { - if ( _pico_memstream_seek( fp, pos + 2, PICO_SEEK_SET )) - flen = FLEN_ERROR; - else - flen += 2; - return NULL; - } - - len = i + ( i & 1 ); - s = _pico_alloc( len ); - if ( !s ) { - flen = FLEN_ERROR; - return NULL; - } - - if ( _pico_memstream_seek( fp, pos, PICO_SEEK_SET )) { - flen = FLEN_ERROR; - return NULL; - } - if ( 1 != _pico_memstream_read( fp, s, len )) { - flen = FLEN_ERROR; - return NULL; - } - - flen += len; - return s; -} - - -int sgetI1( unsigned char **bp ) -{ - int i; - - if ( flen == FLEN_ERROR ) return 0; - i = **bp; - if ( i > 127 ) i -= 256; - flen += 1; - *bp++; - return i; -} - - -short sgetI2( unsigned char **bp ) -{ - short i; - - if ( flen == FLEN_ERROR ) return 0; - memcpy( &i, *bp, 2 ); - revbytes( &i, 2, 1 ); - flen += 2; - *bp += 2; - return i; -} - - -int sgetI4( unsigned char **bp ) -{ - int i; - - if ( flen == FLEN_ERROR ) return 0; - memcpy( &i, *bp, 4 ); - revbytes( &i, 4, 1 ); - flen += 4; - *bp += 4; - return i; -} - - -unsigned char sgetU1( unsigned char **bp ) -{ - unsigned char c; - - if ( flen == FLEN_ERROR ) return 0; - c = **bp; - flen += 1; - *bp++; - return c; -} - - -unsigned short sgetU2( unsigned char **bp ) -{ - unsigned char *buf = *bp; - unsigned short i; - - if ( flen == FLEN_ERROR ) return 0; - i = ( buf[ 0 ] << 8 ) | buf[ 1 ]; - flen += 2; - *bp += 2; - return i; -} - - -unsigned int sgetU4( unsigned char **bp ) -{ - unsigned int i; - - if ( flen == FLEN_ERROR ) return 0; - memcpy( &i, *bp, 4 ); - revbytes( &i, 4, 1 ); - flen += 4; - *bp += 4; - return i; -} - - -int sgetVX( unsigned char **bp ) -{ - unsigned char *buf = *bp; - int i; - - if ( flen == FLEN_ERROR ) return 0; - - if ( buf[ 0 ] != 0xFF ) { - i = buf[ 0 ] << 8 | buf[ 1 ]; - flen += 2; - *bp += 2; - } - else { - i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ]; - flen += 4; - *bp += 4; - } - return i; -} - - -float sgetF4( unsigned char **bp ) -{ - float f; - - if ( flen == FLEN_ERROR ) return 0.0f; - memcpy( &f, *bp, 4 ); - revbytes( &f, 4, 1 ); - flen += 4; - *bp += 4; - return f; -} - - -char *sgetS0( unsigned char **bp ) -{ - char *s; - unsigned char *buf = *bp; - int len; - - if ( flen == FLEN_ERROR ) return NULL; - - len = strlen( buf ) + 1; - if ( len == 1 ) { - flen += 2; - *bp += 2; - return NULL; - } - len += len & 1; - s = _pico_alloc( len ); - if ( !s ) { - flen = FLEN_ERROR; - return NULL; - } - - memcpy( s, buf, len ); - flen += len; - *bp += len; - return s; -} +/* +====================================================================== +lwio.c + +Functions for reading basic LWO2 data types. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +flen + +This accumulates a count of the number of bytes read. Callers can set +it at the beginning of a sequence of reads and then retrieve it to get +the number of bytes actually read. If one of the I/O functions fails, +flen is set to an error code, after which the I/O functions ignore +read requests until flen is reset. +====================================================================== */ + +#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ +#define FLEN_ERROR INT_MIN + +static int flen; + +void set_flen( int i ) { flen = i; } + +int get_flen( void ) { return flen; } + + +#ifdef _WIN32 +/* +===================================================================== +revbytes() + +Reverses byte order in place. + +INPUTS + bp bytes to reverse + elsize size of the underlying data type + elcount number of elements to swap + +RESULTS + Reverses the byte order in each of elcount elements. + +This only needs to be defined on little-endian platforms, most +notably Windows. lwo2.h replaces this with a #define on big-endian +platforms. +===================================================================== */ + +void revbytes( void *bp, int elsize, int elcount ) +{ + register unsigned char *p, *q; + + p = ( unsigned char * ) bp; + + if ( elsize == 2 ) { + q = p + 1; + while ( elcount-- ) { + *p ^= *q; + *q ^= *p; + *p ^= *q; + p += 2; + q += 2; + } + return; + } + + while ( elcount-- ) { + q = p + elsize - 1; + while ( p < q ) { + *p ^= *q; + *q ^= *p; + *p ^= *q; + ++p; + --q; + } + p += elsize >> 1; + } +} +#endif + + +void *getbytes( picoMemStream_t *fp, int size ) +{ + void *data; + + if ( flen == FLEN_ERROR ) return NULL; + if ( size < 0 ) { + flen = FLEN_ERROR; + return NULL; + } + data = _pico_alloc( size ); + if ( !data ) { + flen = FLEN_ERROR; + return NULL; + } + if ( 1 != _pico_memstream_read( fp, data, size )) { + flen = FLEN_ERROR; + _pico_free( data ); + return NULL; + } + + flen += size; + return data; +} + + +void skipbytes( picoMemStream_t *fp, int n ) +{ + if ( flen == FLEN_ERROR ) return; + if ( _pico_memstream_seek( fp, n, PICO_SEEK_CUR )) + flen = FLEN_ERROR; + else + flen += n; +} + + +int getI1( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = _pico_memstream_getc( fp ); + if ( i < 0 ) { + flen = FLEN_ERROR; + return 0; + } + if ( i > 127 ) i -= 256; + flen += 1; + return i; +} + + +short getI2( picoMemStream_t *fp ) +{ + short i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 2 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 2, 1 ); + flen += 2; + return i; +} + + +int getI4( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 4 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 4, 1 ); + flen += 4; + return i; +} + + +unsigned char getU1( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = _pico_memstream_getc( fp ); + if ( i < 0 ) { + flen = FLEN_ERROR; + return 0; + } + flen += 1; + return i; +} + + +unsigned short getU2( picoMemStream_t *fp ) +{ + unsigned short i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 2 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 2, 1 ); + flen += 2; + return i; +} + + +unsigned int getU4( picoMemStream_t *fp ) +{ + unsigned int i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 4 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 4, 1 ); + flen += 4; + return i; +} + + +int getVX( picoMemStream_t *fp ) +{ + int i, c; + + if ( flen == FLEN_ERROR ) return 0; + + c = _pico_memstream_getc( fp ); + if ( c != 0xFF ) { + i = c << 8; + c = _pico_memstream_getc( fp ); + i |= c; + flen += 2; + } + else { + c = _pico_memstream_getc( fp ); + i = c << 16; + c = _pico_memstream_getc( fp ); + i |= c << 8; + c = _pico_memstream_getc( fp ); + i |= c; + flen += 4; + } + + if ( _pico_memstream_error( fp )) { + flen = FLEN_ERROR; + return 0; + } + return i; +} + + +float getF4( picoMemStream_t *fp ) +{ + float f; + + if ( flen == FLEN_ERROR ) return 0.0f; + if ( 1 != _pico_memstream_read( fp, &f, 4 )) { + flen = FLEN_ERROR; + return 0.0f; + } + revbytes( &f, 4, 1 ); + flen += 4; + return f; +} + + +char *getS0( picoMemStream_t *fp ) +{ + char *s; + int i, c, len, pos; + + if ( flen == FLEN_ERROR ) return NULL; + + pos = _pico_memstream_tell( fp ); + for ( i = 1; ; i++ ) { + c = _pico_memstream_getc( fp ); + if ( c <= 0 ) break; + } + if ( c < 0 ) { + flen = FLEN_ERROR; + return NULL; + } + + if ( i == 1 ) { + if ( _pico_memstream_seek( fp, pos + 2, PICO_SEEK_SET )) + flen = FLEN_ERROR; + else + flen += 2; + return NULL; + } + + len = i + ( i & 1 ); + s = _pico_alloc( len ); + if ( !s ) { + flen = FLEN_ERROR; + return NULL; + } + + if ( _pico_memstream_seek( fp, pos, PICO_SEEK_SET )) { + flen = FLEN_ERROR; + return NULL; + } + if ( 1 != _pico_memstream_read( fp, s, len )) { + flen = FLEN_ERROR; + return NULL; + } + + flen += len; + return s; +} + + +int sgetI1( unsigned char **bp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = **bp; + if ( i > 127 ) i -= 256; + flen += 1; + *bp++; + return i; +} + + +short sgetI2( unsigned char **bp ) +{ + short i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 2 ); + revbytes( &i, 2, 1 ); + flen += 2; + *bp += 2; + return i; +} + + +int sgetI4( unsigned char **bp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 4 ); + revbytes( &i, 4, 1 ); + flen += 4; + *bp += 4; + return i; +} + + +unsigned char sgetU1( unsigned char **bp ) +{ + unsigned char c; + + if ( flen == FLEN_ERROR ) return 0; + c = **bp; + flen += 1; + *bp++; + return c; +} + + +unsigned short sgetU2( unsigned char **bp ) +{ + unsigned char *buf = *bp; + unsigned short i; + + if ( flen == FLEN_ERROR ) return 0; + i = ( buf[ 0 ] << 8 ) | buf[ 1 ]; + flen += 2; + *bp += 2; + return i; +} + + +unsigned int sgetU4( unsigned char **bp ) +{ + unsigned int i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 4 ); + revbytes( &i, 4, 1 ); + flen += 4; + *bp += 4; + return i; +} + + +int sgetVX( unsigned char **bp ) +{ + unsigned char *buf = *bp; + int i; + + if ( flen == FLEN_ERROR ) return 0; + + if ( buf[ 0 ] != 0xFF ) { + i = buf[ 0 ] << 8 | buf[ 1 ]; + flen += 2; + *bp += 2; + } + else { + i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ]; + flen += 4; + *bp += 4; + } + return i; +} + + +float sgetF4( unsigned char **bp ) +{ + float f; + + if ( flen == FLEN_ERROR ) return 0.0f; + memcpy( &f, *bp, 4 ); + revbytes( &f, 4, 1 ); + flen += 4; + *bp += 4; + return f; +} + + +char *sgetS0( unsigned char **bp ) +{ + char *s; + unsigned char *buf = *bp; + int len; + + if ( flen == FLEN_ERROR ) return NULL; + + len = strlen( buf ) + 1; + if ( len == 1 ) { + flen += 2; + *bp += 2; + return NULL; + } + len += len & 1; + s = _pico_alloc( len ); + if ( !s ) { + flen = FLEN_ERROR; + return NULL; + } + + memcpy( s, buf, len ); + flen += len; + *bp += len; + return s; +} diff --git a/libs/picomodel/lwo/lwo2.c b/libs/picomodel/lwo/lwo2.c index 1d72af7d..f4c72443 100644 --- a/libs/picomodel/lwo/lwo2.c +++ b/libs/picomodel/lwo/lwo2.c @@ -1,308 +1,308 @@ -/* -====================================================================== -lwo2.c - -The entry point for loading LightWave object files. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - -/* disable warnings */ -#ifdef _WIN32 -#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ -#endif - - -/* -====================================================================== -lwFreeLayer() - -Free memory used by an lwLayer. -====================================================================== */ - -void lwFreeLayer( lwLayer *layer ) -{ - if ( layer ) { - if ( layer->name ) _pico_free( layer->name ); - lwFreePoints( &layer->point ); - lwFreePolygons( &layer->polygon ); - lwListFree( layer->vmap, lwFreeVMap ); - _pico_free( layer ); - } -} - - -/* -====================================================================== -lwFreeObject() - -Free memory used by an lwObject. -====================================================================== */ - -void lwFreeObject( lwObject *object ) -{ - if ( object ) { - lwListFree( object->layer, lwFreeLayer ); - lwListFree( object->env, lwFreeEnvelope ); - lwListFree( object->clip, lwFreeClip ); - lwListFree( object->surf, lwFreeSurface ); - lwFreeTags( &object->taglist ); - _pico_free( object ); - } -} - - -/* -====================================================================== -lwGetObject() - -Returns the contents of a LightWave object, given its filename, or -NULL if the file couldn't be loaded. On failure, failID and failpos -can be used to diagnose the cause. - -1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and - failID will be unchanged. - -2. If an error occurs while reading, failID will contain the most - recently read IFF chunk ID, and failpos will contain the value - returned by _pico_memstream_tell() at the time of the failure. - -3. If the file couldn't be opened, or an error occurs while reading - the first 12 bytes, both failID and failpos will be unchanged. - -If you don't need this information, failID and failpos can be NULL. -====================================================================== */ - -lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) -{ - lwObject *object; - lwLayer *layer; - lwNode *node; - unsigned int id, formsize, type, cksize; - int i, rlen; - - /* open the file */ - - if ( !fp ) return NULL; - - /* read the first 12 bytes */ - - set_flen( 0 ); - id = getU4( fp ); - formsize = getU4( fp ); - type = getU4( fp ); - if ( 12 != get_flen() ) { - return NULL; - } - - /* is this a LW object? */ - - if ( id != ID_FORM ) { - if ( failpos ) *failpos = 12; - return NULL; - } - - if ( type != ID_LWO2 ) { - if ( type == ID_LWOB ) - return lwGetObject5( filename, fp, failID, failpos ); - else { - if ( failpos ) *failpos = 12; - return NULL; - } - } - - /* allocate an object and a default layer */ - - object = _pico_calloc( 1, sizeof( lwObject )); - if ( !object ) goto Fail; - - layer = _pico_calloc( 1, sizeof( lwLayer )); - if ( !layer ) goto Fail; - object->layer = layer; - - /* get the first chunk header */ - - id = getU4( fp ); - cksize = getU4( fp ); - if ( 0 > get_flen() ) goto Fail; - - /* process chunks as they're encountered */ - - while ( 1 ) { - cksize += cksize & 1; - - switch ( id ) - { - case ID_LAYR: - if ( object->nlayers > 0 ) { - layer = _pico_calloc( 1, sizeof( lwLayer )); - if ( !layer ) goto Fail; - lwListAdd( &object->layer, layer ); - } - object->nlayers++; - - set_flen( 0 ); - layer->index = getU2( fp ); - layer->flags = getU2( fp ); - layer->pivot[ 0 ] = getF4( fp ); - layer->pivot[ 1 ] = getF4( fp ); - layer->pivot[ 2 ] = getF4( fp ); - layer->name = getS0( fp ); - - rlen = get_flen(); - if ( rlen < 0 || rlen > cksize ) goto Fail; - if ( rlen <= cksize - 2 ) - layer->parent = getU2( fp ); - rlen = get_flen(); - if ( rlen < cksize ) - _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); - break; - - case ID_PNTS: - if ( !lwGetPoints( fp, cksize, &layer->point )) - goto Fail; - break; - - case ID_POLS: - if ( !lwGetPolygons( fp, cksize, &layer->polygon, - layer->point.offset )) - goto Fail; - break; - - case ID_VMAP: - case ID_VMAD: - node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset, - layer->polygon.offset, id == ID_VMAD ); - if ( !node ) goto Fail; - lwListAdd( &layer->vmap, node ); - layer->nvmaps++; - break; - - case ID_PTAG: - if ( !lwGetPolygonTags( fp, cksize, &object->taglist, - &layer->polygon )) - goto Fail; - break; - - case ID_BBOX: - set_flen( 0 ); - for ( i = 0; i < 6; i++ ) - layer->bbox[ i ] = getF4( fp ); - rlen = get_flen(); - if ( rlen < 0 || rlen > cksize ) goto Fail; - if ( rlen < cksize ) - _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); - break; - - case ID_TAGS: - if ( !lwGetTags( fp, cksize, &object->taglist )) - goto Fail; - break; - - case ID_ENVL: - node = ( lwNode * ) lwGetEnvelope( fp, cksize ); - if ( !node ) goto Fail; - lwListAdd( &object->env, node ); - object->nenvs++; - break; - - case ID_CLIP: - node = ( lwNode * ) lwGetClip( fp, cksize ); - if ( !node ) goto Fail; - lwListAdd( &object->clip, node ); - object->nclips++; - break; - - case ID_SURF: - node = ( lwNode * ) lwGetSurface( fp, cksize ); - if ( !node ) goto Fail; - lwListAdd( &object->surf, node ); - object->nsurfs++; - break; - - case ID_DESC: - case ID_TEXT: - case ID_ICON: - default: - _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); - break; - } - - /* end of the file? */ - - if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; - - /* get the next chunk header */ - - set_flen( 0 ); - id = getU4( fp ); - cksize = getU4( fp ); - if ( 8 != get_flen() ) goto Fail; - } - - if ( object->nlayers == 0 ) - object->nlayers = 1; - - layer = object->layer; - while ( layer ) { - lwGetBoundingBox( &layer->point, layer->bbox ); - lwGetPolyNormals( &layer->point, &layer->polygon ); - if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; - if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, - &object->surf, &object->nsurfs )) goto Fail; - lwGetVertNormals( &layer->point, &layer->polygon ); - if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail; - if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail; - layer = layer->next; - } - - return object; - -Fail: - if ( failID ) *failID = id; - if ( fp ) { - if ( failpos ) *failpos = _pico_memstream_tell( fp ); - } - lwFreeObject( object ); - return NULL; -} - -int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) -{ - unsigned int id, formsize, type; - - /* open the file */ - - if ( !fp ) return PICO_PMV_ERROR_MEMORY; - - /* read the first 12 bytes */ - - set_flen( 0 ); - id = getU4( fp ); - formsize = getU4( fp ); - type = getU4( fp ); - if ( 12 != get_flen() ) { - return PICO_PMV_ERROR_SIZE; - } - - /* is this a LW object? */ - - if ( id != ID_FORM ) { - if ( failpos ) *failpos = 12; - return PICO_PMV_ERROR_SIZE; - } - - if ( type != ID_LWO2 ) { - if ( type == ID_LWOB ) - return lwValidateObject5( filename, fp, failID, failpos ); - else { - if ( failpos ) *failpos = 12; - return PICO_PMV_ERROR_IDENT; - } - } - - return PICO_PMV_OK; -} +/* +====================================================================== +lwo2.c + +The entry point for loading LightWave object files. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ +#endif + + +/* +====================================================================== +lwFreeLayer() + +Free memory used by an lwLayer. +====================================================================== */ + +void lwFreeLayer( lwLayer *layer ) +{ + if ( layer ) { + if ( layer->name ) _pico_free( layer->name ); + lwFreePoints( &layer->point ); + lwFreePolygons( &layer->polygon ); + lwListFree( layer->vmap, lwFreeVMap ); + _pico_free( layer ); + } +} + + +/* +====================================================================== +lwFreeObject() + +Free memory used by an lwObject. +====================================================================== */ + +void lwFreeObject( lwObject *object ) +{ + if ( object ) { + lwListFree( object->layer, lwFreeLayer ); + lwListFree( object->env, lwFreeEnvelope ); + lwListFree( object->clip, lwFreeClip ); + lwListFree( object->surf, lwFreeSurface ); + lwFreeTags( &object->taglist ); + _pico_free( object ); + } +} + + +/* +====================================================================== +lwGetObject() + +Returns the contents of a LightWave object, given its filename, or +NULL if the file couldn't be loaded. On failure, failID and failpos +can be used to diagnose the cause. + +1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and + failID will be unchanged. + +2. If an error occurs while reading, failID will contain the most + recently read IFF chunk ID, and failpos will contain the value + returned by _pico_memstream_tell() at the time of the failure. + +3. If the file couldn't be opened, or an error occurs while reading + the first 12 bytes, both failID and failpos will be unchanged. + +If you don't need this information, failID and failpos can be NULL. +====================================================================== */ + +lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + lwObject *object; + lwLayer *layer; + lwNode *node; + unsigned int id, formsize, type, cksize; + int i, rlen; + + /* open the file */ + + if ( !fp ) return NULL; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return NULL; + } + + /* is this a LW object? */ + + if ( id != ID_FORM ) { + if ( failpos ) *failpos = 12; + return NULL; + } + + if ( type != ID_LWO2 ) { + if ( type == ID_LWOB ) + return lwGetObject5( filename, fp, failID, failpos ); + else { + if ( failpos ) *failpos = 12; + return NULL; + } + } + + /* allocate an object and a default layer */ + + object = _pico_calloc( 1, sizeof( lwObject )); + if ( !object ) goto Fail; + + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + object->layer = layer; + + /* get the first chunk header */ + + id = getU4( fp ); + cksize = getU4( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process chunks as they're encountered */ + + while ( 1 ) { + cksize += cksize & 1; + + switch ( id ) + { + case ID_LAYR: + if ( object->nlayers > 0 ) { + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + lwListAdd( &object->layer, layer ); + } + object->nlayers++; + + set_flen( 0 ); + layer->index = getU2( fp ); + layer->flags = getU2( fp ); + layer->pivot[ 0 ] = getF4( fp ); + layer->pivot[ 1 ] = getF4( fp ); + layer->pivot[ 2 ] = getF4( fp ); + layer->name = getS0( fp ); + + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) goto Fail; + if ( rlen <= cksize - 2 ) + layer->parent = getU2( fp ); + rlen = get_flen(); + if ( rlen < cksize ) + _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); + break; + + case ID_PNTS: + if ( !lwGetPoints( fp, cksize, &layer->point )) + goto Fail; + break; + + case ID_POLS: + if ( !lwGetPolygons( fp, cksize, &layer->polygon, + layer->point.offset )) + goto Fail; + break; + + case ID_VMAP: + case ID_VMAD: + node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset, + layer->polygon.offset, id == ID_VMAD ); + if ( !node ) goto Fail; + lwListAdd( &layer->vmap, node ); + layer->nvmaps++; + break; + + case ID_PTAG: + if ( !lwGetPolygonTags( fp, cksize, &object->taglist, + &layer->polygon )) + goto Fail; + break; + + case ID_BBOX: + set_flen( 0 ); + for ( i = 0; i < 6; i++ ) + layer->bbox[ i ] = getF4( fp ); + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) goto Fail; + if ( rlen < cksize ) + _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); + break; + + case ID_TAGS: + if ( !lwGetTags( fp, cksize, &object->taglist )) + goto Fail; + break; + + case ID_ENVL: + node = ( lwNode * ) lwGetEnvelope( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->env, node ); + object->nenvs++; + break; + + case ID_CLIP: + node = ( lwNode * ) lwGetClip( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->clip, node ); + object->nclips++; + break; + + case ID_SURF: + node = ( lwNode * ) lwGetSurface( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->surf, node ); + object->nsurfs++; + break; + + case ID_DESC: + case ID_TEXT: + case ID_ICON: + default: + _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); + break; + } + + /* end of the file? */ + + if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + cksize = getU4( fp ); + if ( 8 != get_flen() ) goto Fail; + } + + if ( object->nlayers == 0 ) + object->nlayers = 1; + + layer = object->layer; + while ( layer ) { + lwGetBoundingBox( &layer->point, layer->bbox ); + lwGetPolyNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; + if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, + &object->surf, &object->nsurfs )) goto Fail; + lwGetVertNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail; + if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail; + layer = layer->next; + } + + return object; + +Fail: + if ( failID ) *failID = id; + if ( fp ) { + if ( failpos ) *failpos = _pico_memstream_tell( fp ); + } + lwFreeObject( object ); + return NULL; +} + +int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + unsigned int id, formsize, type; + + /* open the file */ + + if ( !fp ) return PICO_PMV_ERROR_MEMORY; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return PICO_PMV_ERROR_SIZE; + } + + /* is this a LW object? */ + + if ( id != ID_FORM ) { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_SIZE; + } + + if ( type != ID_LWO2 ) { + if ( type == ID_LWOB ) + return lwValidateObject5( filename, fp, failID, failpos ); + else { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_IDENT; + } + } + + return PICO_PMV_OK; +} diff --git a/libs/picomodel/lwo/lwo2.h b/libs/picomodel/lwo/lwo2.h index 1fe1dd97..1d55ba46 100644 --- a/libs/picomodel/lwo/lwo2.h +++ b/libs/picomodel/lwo/lwo2.h @@ -1,651 +1,651 @@ -/* -====================================================================== -lwo2.h - -Definitions and typedefs for LWO2 files. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#ifndef LWO2_H -#define LWO2_H - -/* chunk and subchunk IDs */ - -#define LWID_(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d)) - -#define ID_FORM LWID_('F','O','R','M') -#define ID_LWO2 LWID_('L','W','O','2') -#define ID_LWOB LWID_('L','W','O','B') - -/* top-level chunks */ -#define ID_LAYR LWID_('L','A','Y','R') -#define ID_TAGS LWID_('T','A','G','S') -#define ID_PNTS LWID_('P','N','T','S') -#define ID_BBOX LWID_('B','B','O','X') -#define ID_VMAP LWID_('V','M','A','P') -#define ID_VMAD LWID_('V','M','A','D') -#define ID_POLS LWID_('P','O','L','S') -#define ID_PTAG LWID_('P','T','A','G') -#define ID_ENVL LWID_('E','N','V','L') -#define ID_CLIP LWID_('C','L','I','P') -#define ID_SURF LWID_('S','U','R','F') -#define ID_DESC LWID_('D','E','S','C') -#define ID_TEXT LWID_('T','E','X','T') -#define ID_ICON LWID_('I','C','O','N') - -/* polygon types */ -#define ID_FACE LWID_('F','A','C','E') -#define ID_CURV LWID_('C','U','R','V') -#define ID_PTCH LWID_('P','T','C','H') -#define ID_MBAL LWID_('M','B','A','L') -#define ID_BONE LWID_('B','O','N','E') - -/* polygon tags */ -#define ID_SURF LWID_('S','U','R','F') -#define ID_PART LWID_('P','A','R','T') -#define ID_SMGP LWID_('S','M','G','P') - -/* envelopes */ -#define ID_PRE LWID_('P','R','E',' ') -#define ID_POST LWID_('P','O','S','T') -#define ID_KEY LWID_('K','E','Y',' ') -#define ID_SPAN LWID_('S','P','A','N') -#define ID_TCB LWID_('T','C','B',' ') -#define ID_HERM LWID_('H','E','R','M') -#define ID_BEZI LWID_('B','E','Z','I') -#define ID_BEZ2 LWID_('B','E','Z','2') -#define ID_LINE LWID_('L','I','N','E') -#define ID_STEP LWID_('S','T','E','P') - -/* clips */ -#define ID_STIL LWID_('S','T','I','L') -#define ID_ISEQ LWID_('I','S','E','Q') -#define ID_ANIM LWID_('A','N','I','M') -#define ID_XREF LWID_('X','R','E','F') -#define ID_STCC LWID_('S','T','C','C') -#define ID_TIME LWID_('T','I','M','E') -#define ID_CONT LWID_('C','O','N','T') -#define ID_BRIT LWID_('B','R','I','T') -#define ID_SATR LWID_('S','A','T','R') -#define ID_HUE LWID_('H','U','E',' ') -#define ID_GAMM LWID_('G','A','M','M') -#define ID_NEGA LWID_('N','E','G','A') -#define ID_IFLT LWID_('I','F','L','T') -#define ID_PFLT LWID_('P','F','L','T') - -/* surfaces */ -#define ID_COLR LWID_('C','O','L','R') -#define ID_LUMI LWID_('L','U','M','I') -#define ID_DIFF LWID_('D','I','F','F') -#define ID_SPEC LWID_('S','P','E','C') -#define ID_GLOS LWID_('G','L','O','S') -#define ID_REFL LWID_('R','E','F','L') -#define ID_RFOP LWID_('R','F','O','P') -#define ID_RIMG LWID_('R','I','M','G') -#define ID_RSAN LWID_('R','S','A','N') -#define ID_TRAN LWID_('T','R','A','N') -#define ID_TROP LWID_('T','R','O','P') -#define ID_TIMG LWID_('T','I','M','G') -#define ID_RIND LWID_('R','I','N','D') -#define ID_TRNL LWID_('T','R','N','L') -#define ID_BUMP LWID_('B','U','M','P') -#define ID_SMAN LWID_('S','M','A','N') -#define ID_SIDE LWID_('S','I','D','E') -#define ID_CLRH LWID_('C','L','R','H') -#define ID_CLRF LWID_('C','L','R','F') -#define ID_ADTR LWID_('A','D','T','R') -#define ID_SHRP LWID_('S','H','R','P') -#define ID_LINE LWID_('L','I','N','E') -#define ID_LSIZ LWID_('L','S','I','Z') -#define ID_ALPH LWID_('A','L','P','H') -#define ID_AVAL LWID_('A','V','A','L') -#define ID_GVAL LWID_('G','V','A','L') -#define ID_BLOK LWID_('B','L','O','K') - -/* texture layer */ -#define ID_TYPE LWID_('T','Y','P','E') -#define ID_CHAN LWID_('C','H','A','N') -#define ID_NAME LWID_('N','A','M','E') -#define ID_ENAB LWID_('E','N','A','B') -#define ID_OPAC LWID_('O','P','A','C') -#define ID_FLAG LWID_('F','L','A','G') -#define ID_PROJ LWID_('P','R','O','J') -#define ID_STCK LWID_('S','T','C','K') -#define ID_TAMP LWID_('T','A','M','P') - -/* texture coordinates */ -#define ID_TMAP LWID_('T','M','A','P') -#define ID_AXIS LWID_('A','X','I','S') -#define ID_CNTR LWID_('C','N','T','R') -#define ID_SIZE LWID_('S','I','Z','E') -#define ID_ROTA LWID_('R','O','T','A') -#define ID_OREF LWID_('O','R','E','F') -#define ID_FALL LWID_('F','A','L','L') -#define ID_CSYS LWID_('C','S','Y','S') - -/* image map */ -#define ID_IMAP LWID_('I','M','A','P') -#define ID_IMAG LWID_('I','M','A','G') -#define ID_WRAP LWID_('W','R','A','P') -#define ID_WRPW LWID_('W','R','P','W') -#define ID_WRPH LWID_('W','R','P','H') -#define ID_VMAP LWID_('V','M','A','P') -#define ID_AAST LWID_('A','A','S','T') -#define ID_PIXB LWID_('P','I','X','B') - -/* procedural */ -#define ID_PROC LWID_('P','R','O','C') -#define ID_COLR LWID_('C','O','L','R') -#define ID_VALU LWID_('V','A','L','U') -#define ID_FUNC LWID_('F','U','N','C') -#define ID_FTPS LWID_('F','T','P','S') -#define ID_ITPS LWID_('I','T','P','S') -#define ID_ETPS LWID_('E','T','P','S') - -/* gradient */ -#define ID_GRAD LWID_('G','R','A','D') -#define ID_GRST LWID_('G','R','S','T') -#define ID_GREN LWID_('G','R','E','N') -#define ID_PNAM LWID_('P','N','A','M') -#define ID_INAM LWID_('I','N','A','M') -#define ID_GRPT LWID_('G','R','P','T') -#define ID_FKEY LWID_('F','K','E','Y') -#define ID_IKEY LWID_('I','K','E','Y') - -/* shader */ -#define ID_SHDR LWID_('S','H','D','R') -#define ID_DATA LWID_('D','A','T','A') - - -/* generic linked list */ - -typedef struct st_lwNode { - struct st_lwNode *next, *prev; - void *data; -} lwNode; - - -/* plug-in reference */ - -typedef struct st_lwPlugin { - struct st_lwPlugin *next, *prev; - char *ord; - char *name; - int flags; - void *data; -} lwPlugin; - - -/* envelopes */ - -typedef struct st_lwKey { - struct st_lwKey *next, *prev; - float value; - float time; - unsigned int shape; /* ID_TCB, ID_BEZ2, etc. */ - float tension; - float continuity; - float bias; - float param[ 4 ]; -} lwKey; - -typedef struct st_lwEnvelope { - struct st_lwEnvelope *next, *prev; - int index; - int type; - char *name; - lwKey *key; /* linked list of keys */ - int nkeys; - int behavior[ 2 ]; /* pre and post (extrapolation) */ - lwPlugin *cfilter; /* linked list of channel filters */ - int ncfilters; -} lwEnvelope; - -#define BEH_RESET 0 -#define BEH_CONSTANT 1 -#define BEH_REPEAT 2 -#define BEH_OSCILLATE 3 -#define BEH_OFFSET 4 -#define BEH_LINEAR 5 - - -/* values that can be enveloped */ - -typedef struct st_lwEParam { - float val; - int eindex; -} lwEParam; - -typedef struct st_lwVParam { - float val[ 3 ]; - int eindex; -} lwVParam; - - -/* clips */ - -typedef struct st_lwClipStill { - char *name; -} lwClipStill; - -typedef struct st_lwClipSeq { - char *prefix; /* filename before sequence digits */ - char *suffix; /* after digits, e.g. extensions */ - int digits; - int flags; - int offset; - int start; - int end; -} lwClipSeq; - -typedef struct st_lwClipAnim { - char *name; - char *server; /* anim loader plug-in */ - void *data; -} lwClipAnim; - -typedef struct st_lwClipXRef { - char *string; - int index; - struct st_lwClip *clip; -} lwClipXRef; - -typedef struct st_lwClipCycle { - char *name; - int lo; - int hi; -} lwClipCycle; - -typedef struct st_lwClip { - struct st_lwClip *next, *prev; - int index; - unsigned int type; /* ID_STIL, ID_ISEQ, etc. */ - union { - lwClipStill still; - lwClipSeq seq; - lwClipAnim anim; - lwClipXRef xref; - lwClipCycle cycle; - } source; - float start_time; - float duration; - float frame_rate; - lwEParam contrast; - lwEParam brightness; - lwEParam saturation; - lwEParam hue; - lwEParam gamma; - int negative; - lwPlugin *ifilter; /* linked list of image filters */ - int nifilters; - lwPlugin *pfilter; /* linked list of pixel filters */ - int npfilters; -} lwClip; - - -/* textures */ - -typedef struct st_lwTMap { - lwVParam size; - lwVParam center; - lwVParam rotate; - lwVParam falloff; - int fall_type; - char *ref_object; - int coord_sys; -} lwTMap; - -typedef struct st_lwImageMap { - int cindex; - int projection; - char *vmap_name; - int axis; - int wrapw_type; - int wraph_type; - lwEParam wrapw; - lwEParam wraph; - float aa_strength; - int aas_flags; - int pblend; - lwEParam stck; - lwEParam amplitude; -} lwImageMap; - -#define PROJ_PLANAR 0 -#define PROJ_CYLINDRICAL 1 -#define PROJ_SPHERICAL 2 -#define PROJ_CUBIC 3 -#define PROJ_FRONT 4 - -#define WRAP_NONE 0 -#define WRAP_EDGE 1 -#define WRAP_REPEAT 2 -#define WRAP_MIRROR 3 - -typedef struct st_lwProcedural { - int axis; - float value[ 3 ]; - char *name; - void *data; -} lwProcedural; - -typedef struct st_lwGradKey { - struct st_lwGradKey *next, *prev; - float value; - float rgba[ 4 ]; -} lwGradKey; - -typedef struct st_lwGradient { - char *paramname; - char *itemname; - float start; - float end; - int repeat; - lwGradKey *key; /* array of gradient keys */ - short *ikey; /* array of interpolation codes */ -} lwGradient; - -typedef struct st_lwTexture { - struct st_lwTexture *next, *prev; - char *ord; - unsigned int type; - unsigned int chan; - lwEParam opacity; - short opac_type; - short enabled; - short negative; - short axis; - union { - lwImageMap imap; - lwProcedural proc; - lwGradient grad; - } param; - lwTMap tmap; -} lwTexture; - - -/* values that can be textured */ - -typedef struct st_lwTParam { - float val; - int eindex; - lwTexture *tex; /* linked list of texture layers */ -} lwTParam; - -typedef struct st_lwCParam { - float rgb[ 3 ]; - int eindex; - lwTexture *tex; /* linked list of texture layers */ -} lwCParam; - - -/* surfaces */ - -typedef struct st_lwGlow { - short enabled; - short type; - lwEParam intensity; - lwEParam size; -} Glow; - -typedef struct st_lwRMap { - lwTParam val; - int options; - int cindex; - float seam_angle; -} lwRMap; - -typedef struct st_lwLine { - short enabled; - unsigned short flags; - lwEParam size; -} lwLine; - -typedef struct st_lwSurface { - struct st_lwSurface *next, *prev; - char *name; - char *srcname; - lwCParam color; - lwTParam luminosity; - lwTParam diffuse; - lwTParam specularity; - lwTParam glossiness; - lwRMap reflection; - lwRMap transparency; - lwTParam eta; - lwTParam translucency; - lwTParam bump; - float smooth; - int sideflags; - float alpha; - int alpha_mode; - lwEParam color_hilite; - lwEParam color_filter; - lwEParam add_trans; - lwEParam dif_sharp; - lwEParam glow; - lwLine line; - lwPlugin *shader; /* linked list of shaders */ - int nshaders; -} lwSurface; - - -/* vertex maps */ - -typedef struct st_lwVMap { - struct st_lwVMap *next, *prev; - char *name; - unsigned int type; - int dim; - int nverts; - int perpoly; - int *vindex; /* array of point indexes */ - int *pindex; /* array of polygon indexes */ - float **val; -} lwVMap; - -typedef struct st_lwVMapPt { - lwVMap *vmap; - int index; /* vindex or pindex element */ -} lwVMapPt; - - -/* points and polygons */ - -typedef struct st_lwPoint { - float pos[ 3 ]; - int npols; /* number of polygons sharing the point */ - int *pol; /* array of polygon indexes */ - int nvmaps; - lwVMapPt *vm; /* array of vmap references */ -} lwPoint; - -typedef struct st_lwPolVert { - int index; /* index into the point array */ - float norm[ 3 ]; - int nvmaps; - lwVMapPt *vm; /* array of vmap references */ -} lwPolVert; - -typedef struct st_lwPolygon { - lwSurface *surf; - int part; /* part index */ - int smoothgrp; /* smoothing group */ - int flags; - unsigned int type; - float norm[ 3 ]; - int nverts; - lwPolVert *v; /* array of vertex records */ -} lwPolygon; - -typedef struct st_lwPointList { - int count; - int offset; /* only used during reading */ - lwPoint *pt; /* array of points */ -} lwPointList; - -typedef struct st_lwPolygonList { - int count; - int offset; /* only used during reading */ - int vcount; /* total number of vertices */ - int voffset; /* only used during reading */ - lwPolygon *pol; /* array of polygons */ -} lwPolygonList; - - -/* geometry layers */ - -typedef struct st_lwLayer { - struct st_lwLayer *next, *prev; - char *name; - int index; - int parent; - int flags; - float pivot[ 3 ]; - float bbox[ 6 ]; - lwPointList point; - lwPolygonList polygon; - int nvmaps; - lwVMap *vmap; /* linked list of vmaps */ -} lwLayer; - - -/* tag strings */ - -typedef struct st_lwTagList { - int count; - int offset; /* only used during reading */ - char **tag; /* array of strings */ -} lwTagList; - - -/* an object */ - -typedef struct st_lwObject { - lwLayer *layer; /* linked list of layers */ - lwEnvelope *env; /* linked list of envelopes */ - lwClip *clip; /* linked list of clips */ - lwSurface *surf; /* linked list of surfaces */ - lwTagList taglist; - int nlayers; - int nenvs; - int nclips; - int nsurfs; -} lwObject; - - -/* lwo2.c */ - -void lwFreeLayer( lwLayer *layer ); -void lwFreeObject( lwObject *object ); -lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); -int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); - -/* pntspols.c */ - -void lwFreePoints( lwPointList *point ); -void lwFreePolygons( lwPolygonList *plist ); -int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ); -void lwGetBoundingBox( lwPointList *point, float bbox[] ); -int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ); -int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); -void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ); -int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ); -int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, - lwSurface **surf, int *nsurfs ); -void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ); -void lwFreeTags( lwTagList *tlist ); -int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ); -int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, - lwPolygonList *plist ); - -/* vmap.c */ - -void lwFreeVMap( lwVMap *vmap ); -lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, - int perpoly ); -int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ); -int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ); - -/* clip.c */ - -void lwFreeClip( lwClip *clip ); -lwClip *lwGetClip( picoMemStream_t *fp, int cksize ); -lwClip *lwFindClip( lwClip *list, int index ); - -/* envelope.c */ - -void lwFreeEnvelope( lwEnvelope *env ); -lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ); -lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ); -float lwEvalEnvelope( lwEnvelope *env, float time ); - -/* surface.c */ - -void lwFreePlugin( lwPlugin *p ); -void lwFreeTexture( lwTexture *t ); -void lwFreeSurface( lwSurface *surf ); -int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ); -int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ); -int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ); -int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ); -int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ); -lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ); -lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ); -lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ); -lwSurface *lwDefaultSurface( void ); - -/* lwob.c */ - -lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ); -int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); -lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); -int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); - -/* list.c */ - -void lwListFree( void *list, void ( *freeNode )( void * )); -void lwListAdd( void **list, void *node ); -void lwListInsert( void **vlist, void *vitem, - int ( *compare )( void *, void * )); - -/* vecmath.c */ - -float dot( float a[], float b[] ); -void cross( float a[], float b[], float c[] ); -void normalize( float v[] ); -#define vecangle( a, b ) ( float ) acos( dot( a, b )) - -/* lwio.c */ - -void set_flen( int i ); -int get_flen( void ); -void *getbytes( picoMemStream_t *fp, int size ); -void skipbytes( picoMemStream_t *fp, int n ); -int getI1( picoMemStream_t *fp ); -short getI2( picoMemStream_t *fp ); -int getI4( picoMemStream_t *fp ); -unsigned char getU1( picoMemStream_t *fp ); -unsigned short getU2( picoMemStream_t *fp ); -unsigned int getU4( picoMemStream_t *fp ); -int getVX( picoMemStream_t *fp ); -float getF4( picoMemStream_t *fp ); -char *getS0( picoMemStream_t *fp ); -int sgetI1( unsigned char **bp ); -short sgetI2( unsigned char **bp ); -int sgetI4( unsigned char **bp ); -unsigned char sgetU1( unsigned char **bp ); -unsigned short sgetU2( unsigned char **bp ); -unsigned int sgetU4( unsigned char **bp ); -int sgetVX( unsigned char **bp ); -float sgetF4( unsigned char **bp ); -char *sgetS0( unsigned char **bp ); - -#ifdef _WIN32 - void revbytes( void *bp, int elsize, int elcount ); -#else - #define revbytes( b, s, c ) -#endif - -#endif +/* +====================================================================== +lwo2.h + +Definitions and typedefs for LWO2 files. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#ifndef LWO2_H +#define LWO2_H + +/* chunk and subchunk IDs */ + +#define LWID_(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d)) + +#define ID_FORM LWID_('F','O','R','M') +#define ID_LWO2 LWID_('L','W','O','2') +#define ID_LWOB LWID_('L','W','O','B') + +/* top-level chunks */ +#define ID_LAYR LWID_('L','A','Y','R') +#define ID_TAGS LWID_('T','A','G','S') +#define ID_PNTS LWID_('P','N','T','S') +#define ID_BBOX LWID_('B','B','O','X') +#define ID_VMAP LWID_('V','M','A','P') +#define ID_VMAD LWID_('V','M','A','D') +#define ID_POLS LWID_('P','O','L','S') +#define ID_PTAG LWID_('P','T','A','G') +#define ID_ENVL LWID_('E','N','V','L') +#define ID_CLIP LWID_('C','L','I','P') +#define ID_SURF LWID_('S','U','R','F') +#define ID_DESC LWID_('D','E','S','C') +#define ID_TEXT LWID_('T','E','X','T') +#define ID_ICON LWID_('I','C','O','N') + +/* polygon types */ +#define ID_FACE LWID_('F','A','C','E') +#define ID_CURV LWID_('C','U','R','V') +#define ID_PTCH LWID_('P','T','C','H') +#define ID_MBAL LWID_('M','B','A','L') +#define ID_BONE LWID_('B','O','N','E') + +/* polygon tags */ +#define ID_SURF LWID_('S','U','R','F') +#define ID_PART LWID_('P','A','R','T') +#define ID_SMGP LWID_('S','M','G','P') + +/* envelopes */ +#define ID_PRE LWID_('P','R','E',' ') +#define ID_POST LWID_('P','O','S','T') +#define ID_KEY LWID_('K','E','Y',' ') +#define ID_SPAN LWID_('S','P','A','N') +#define ID_TCB LWID_('T','C','B',' ') +#define ID_HERM LWID_('H','E','R','M') +#define ID_BEZI LWID_('B','E','Z','I') +#define ID_BEZ2 LWID_('B','E','Z','2') +#define ID_LINE LWID_('L','I','N','E') +#define ID_STEP LWID_('S','T','E','P') + +/* clips */ +#define ID_STIL LWID_('S','T','I','L') +#define ID_ISEQ LWID_('I','S','E','Q') +#define ID_ANIM LWID_('A','N','I','M') +#define ID_XREF LWID_('X','R','E','F') +#define ID_STCC LWID_('S','T','C','C') +#define ID_TIME LWID_('T','I','M','E') +#define ID_CONT LWID_('C','O','N','T') +#define ID_BRIT LWID_('B','R','I','T') +#define ID_SATR LWID_('S','A','T','R') +#define ID_HUE LWID_('H','U','E',' ') +#define ID_GAMM LWID_('G','A','M','M') +#define ID_NEGA LWID_('N','E','G','A') +#define ID_IFLT LWID_('I','F','L','T') +#define ID_PFLT LWID_('P','F','L','T') + +/* surfaces */ +#define ID_COLR LWID_('C','O','L','R') +#define ID_LUMI LWID_('L','U','M','I') +#define ID_DIFF LWID_('D','I','F','F') +#define ID_SPEC LWID_('S','P','E','C') +#define ID_GLOS LWID_('G','L','O','S') +#define ID_REFL LWID_('R','E','F','L') +#define ID_RFOP LWID_('R','F','O','P') +#define ID_RIMG LWID_('R','I','M','G') +#define ID_RSAN LWID_('R','S','A','N') +#define ID_TRAN LWID_('T','R','A','N') +#define ID_TROP LWID_('T','R','O','P') +#define ID_TIMG LWID_('T','I','M','G') +#define ID_RIND LWID_('R','I','N','D') +#define ID_TRNL LWID_('T','R','N','L') +#define ID_BUMP LWID_('B','U','M','P') +#define ID_SMAN LWID_('S','M','A','N') +#define ID_SIDE LWID_('S','I','D','E') +#define ID_CLRH LWID_('C','L','R','H') +#define ID_CLRF LWID_('C','L','R','F') +#define ID_ADTR LWID_('A','D','T','R') +#define ID_SHRP LWID_('S','H','R','P') +#define ID_LINE LWID_('L','I','N','E') +#define ID_LSIZ LWID_('L','S','I','Z') +#define ID_ALPH LWID_('A','L','P','H') +#define ID_AVAL LWID_('A','V','A','L') +#define ID_GVAL LWID_('G','V','A','L') +#define ID_BLOK LWID_('B','L','O','K') + +/* texture layer */ +#define ID_TYPE LWID_('T','Y','P','E') +#define ID_CHAN LWID_('C','H','A','N') +#define ID_NAME LWID_('N','A','M','E') +#define ID_ENAB LWID_('E','N','A','B') +#define ID_OPAC LWID_('O','P','A','C') +#define ID_FLAG LWID_('F','L','A','G') +#define ID_PROJ LWID_('P','R','O','J') +#define ID_STCK LWID_('S','T','C','K') +#define ID_TAMP LWID_('T','A','M','P') + +/* texture coordinates */ +#define ID_TMAP LWID_('T','M','A','P') +#define ID_AXIS LWID_('A','X','I','S') +#define ID_CNTR LWID_('C','N','T','R') +#define ID_SIZE LWID_('S','I','Z','E') +#define ID_ROTA LWID_('R','O','T','A') +#define ID_OREF LWID_('O','R','E','F') +#define ID_FALL LWID_('F','A','L','L') +#define ID_CSYS LWID_('C','S','Y','S') + +/* image map */ +#define ID_IMAP LWID_('I','M','A','P') +#define ID_IMAG LWID_('I','M','A','G') +#define ID_WRAP LWID_('W','R','A','P') +#define ID_WRPW LWID_('W','R','P','W') +#define ID_WRPH LWID_('W','R','P','H') +#define ID_VMAP LWID_('V','M','A','P') +#define ID_AAST LWID_('A','A','S','T') +#define ID_PIXB LWID_('P','I','X','B') + +/* procedural */ +#define ID_PROC LWID_('P','R','O','C') +#define ID_COLR LWID_('C','O','L','R') +#define ID_VALU LWID_('V','A','L','U') +#define ID_FUNC LWID_('F','U','N','C') +#define ID_FTPS LWID_('F','T','P','S') +#define ID_ITPS LWID_('I','T','P','S') +#define ID_ETPS LWID_('E','T','P','S') + +/* gradient */ +#define ID_GRAD LWID_('G','R','A','D') +#define ID_GRST LWID_('G','R','S','T') +#define ID_GREN LWID_('G','R','E','N') +#define ID_PNAM LWID_('P','N','A','M') +#define ID_INAM LWID_('I','N','A','M') +#define ID_GRPT LWID_('G','R','P','T') +#define ID_FKEY LWID_('F','K','E','Y') +#define ID_IKEY LWID_('I','K','E','Y') + +/* shader */ +#define ID_SHDR LWID_('S','H','D','R') +#define ID_DATA LWID_('D','A','T','A') + + +/* generic linked list */ + +typedef struct st_lwNode { + struct st_lwNode *next, *prev; + void *data; +} lwNode; + + +/* plug-in reference */ + +typedef struct st_lwPlugin { + struct st_lwPlugin *next, *prev; + char *ord; + char *name; + int flags; + void *data; +} lwPlugin; + + +/* envelopes */ + +typedef struct st_lwKey { + struct st_lwKey *next, *prev; + float value; + float time; + unsigned int shape; /* ID_TCB, ID_BEZ2, etc. */ + float tension; + float continuity; + float bias; + float param[ 4 ]; +} lwKey; + +typedef struct st_lwEnvelope { + struct st_lwEnvelope *next, *prev; + int index; + int type; + char *name; + lwKey *key; /* linked list of keys */ + int nkeys; + int behavior[ 2 ]; /* pre and post (extrapolation) */ + lwPlugin *cfilter; /* linked list of channel filters */ + int ncfilters; +} lwEnvelope; + +#define BEH_RESET 0 +#define BEH_CONSTANT 1 +#define BEH_REPEAT 2 +#define BEH_OSCILLATE 3 +#define BEH_OFFSET 4 +#define BEH_LINEAR 5 + + +/* values that can be enveloped */ + +typedef struct st_lwEParam { + float val; + int eindex; +} lwEParam; + +typedef struct st_lwVParam { + float val[ 3 ]; + int eindex; +} lwVParam; + + +/* clips */ + +typedef struct st_lwClipStill { + char *name; +} lwClipStill; + +typedef struct st_lwClipSeq { + char *prefix; /* filename before sequence digits */ + char *suffix; /* after digits, e.g. extensions */ + int digits; + int flags; + int offset; + int start; + int end; +} lwClipSeq; + +typedef struct st_lwClipAnim { + char *name; + char *server; /* anim loader plug-in */ + void *data; +} lwClipAnim; + +typedef struct st_lwClipXRef { + char *string; + int index; + struct st_lwClip *clip; +} lwClipXRef; + +typedef struct st_lwClipCycle { + char *name; + int lo; + int hi; +} lwClipCycle; + +typedef struct st_lwClip { + struct st_lwClip *next, *prev; + int index; + unsigned int type; /* ID_STIL, ID_ISEQ, etc. */ + union { + lwClipStill still; + lwClipSeq seq; + lwClipAnim anim; + lwClipXRef xref; + lwClipCycle cycle; + } source; + float start_time; + float duration; + float frame_rate; + lwEParam contrast; + lwEParam brightness; + lwEParam saturation; + lwEParam hue; + lwEParam gamma; + int negative; + lwPlugin *ifilter; /* linked list of image filters */ + int nifilters; + lwPlugin *pfilter; /* linked list of pixel filters */ + int npfilters; +} lwClip; + + +/* textures */ + +typedef struct st_lwTMap { + lwVParam size; + lwVParam center; + lwVParam rotate; + lwVParam falloff; + int fall_type; + char *ref_object; + int coord_sys; +} lwTMap; + +typedef struct st_lwImageMap { + int cindex; + int projection; + char *vmap_name; + int axis; + int wrapw_type; + int wraph_type; + lwEParam wrapw; + lwEParam wraph; + float aa_strength; + int aas_flags; + int pblend; + lwEParam stck; + lwEParam amplitude; +} lwImageMap; + +#define PROJ_PLANAR 0 +#define PROJ_CYLINDRICAL 1 +#define PROJ_SPHERICAL 2 +#define PROJ_CUBIC 3 +#define PROJ_FRONT 4 + +#define WRAP_NONE 0 +#define WRAP_EDGE 1 +#define WRAP_REPEAT 2 +#define WRAP_MIRROR 3 + +typedef struct st_lwProcedural { + int axis; + float value[ 3 ]; + char *name; + void *data; +} lwProcedural; + +typedef struct st_lwGradKey { + struct st_lwGradKey *next, *prev; + float value; + float rgba[ 4 ]; +} lwGradKey; + +typedef struct st_lwGradient { + char *paramname; + char *itemname; + float start; + float end; + int repeat; + lwGradKey *key; /* array of gradient keys */ + short *ikey; /* array of interpolation codes */ +} lwGradient; + +typedef struct st_lwTexture { + struct st_lwTexture *next, *prev; + char *ord; + unsigned int type; + unsigned int chan; + lwEParam opacity; + short opac_type; + short enabled; + short negative; + short axis; + union { + lwImageMap imap; + lwProcedural proc; + lwGradient grad; + } param; + lwTMap tmap; +} lwTexture; + + +/* values that can be textured */ + +typedef struct st_lwTParam { + float val; + int eindex; + lwTexture *tex; /* linked list of texture layers */ +} lwTParam; + +typedef struct st_lwCParam { + float rgb[ 3 ]; + int eindex; + lwTexture *tex; /* linked list of texture layers */ +} lwCParam; + + +/* surfaces */ + +typedef struct st_lwGlow { + short enabled; + short type; + lwEParam intensity; + lwEParam size; +} Glow; + +typedef struct st_lwRMap { + lwTParam val; + int options; + int cindex; + float seam_angle; +} lwRMap; + +typedef struct st_lwLine { + short enabled; + unsigned short flags; + lwEParam size; +} lwLine; + +typedef struct st_lwSurface { + struct st_lwSurface *next, *prev; + char *name; + char *srcname; + lwCParam color; + lwTParam luminosity; + lwTParam diffuse; + lwTParam specularity; + lwTParam glossiness; + lwRMap reflection; + lwRMap transparency; + lwTParam eta; + lwTParam translucency; + lwTParam bump; + float smooth; + int sideflags; + float alpha; + int alpha_mode; + lwEParam color_hilite; + lwEParam color_filter; + lwEParam add_trans; + lwEParam dif_sharp; + lwEParam glow; + lwLine line; + lwPlugin *shader; /* linked list of shaders */ + int nshaders; +} lwSurface; + + +/* vertex maps */ + +typedef struct st_lwVMap { + struct st_lwVMap *next, *prev; + char *name; + unsigned int type; + int dim; + int nverts; + int perpoly; + int *vindex; /* array of point indexes */ + int *pindex; /* array of polygon indexes */ + float **val; +} lwVMap; + +typedef struct st_lwVMapPt { + lwVMap *vmap; + int index; /* vindex or pindex element */ +} lwVMapPt; + + +/* points and polygons */ + +typedef struct st_lwPoint { + float pos[ 3 ]; + int npols; /* number of polygons sharing the point */ + int *pol; /* array of polygon indexes */ + int nvmaps; + lwVMapPt *vm; /* array of vmap references */ +} lwPoint; + +typedef struct st_lwPolVert { + int index; /* index into the point array */ + float norm[ 3 ]; + int nvmaps; + lwVMapPt *vm; /* array of vmap references */ +} lwPolVert; + +typedef struct st_lwPolygon { + lwSurface *surf; + int part; /* part index */ + int smoothgrp; /* smoothing group */ + int flags; + unsigned int type; + float norm[ 3 ]; + int nverts; + lwPolVert *v; /* array of vertex records */ +} lwPolygon; + +typedef struct st_lwPointList { + int count; + int offset; /* only used during reading */ + lwPoint *pt; /* array of points */ +} lwPointList; + +typedef struct st_lwPolygonList { + int count; + int offset; /* only used during reading */ + int vcount; /* total number of vertices */ + int voffset; /* only used during reading */ + lwPolygon *pol; /* array of polygons */ +} lwPolygonList; + + +/* geometry layers */ + +typedef struct st_lwLayer { + struct st_lwLayer *next, *prev; + char *name; + int index; + int parent; + int flags; + float pivot[ 3 ]; + float bbox[ 6 ]; + lwPointList point; + lwPolygonList polygon; + int nvmaps; + lwVMap *vmap; /* linked list of vmaps */ +} lwLayer; + + +/* tag strings */ + +typedef struct st_lwTagList { + int count; + int offset; /* only used during reading */ + char **tag; /* array of strings */ +} lwTagList; + + +/* an object */ + +typedef struct st_lwObject { + lwLayer *layer; /* linked list of layers */ + lwEnvelope *env; /* linked list of envelopes */ + lwClip *clip; /* linked list of clips */ + lwSurface *surf; /* linked list of surfaces */ + lwTagList taglist; + int nlayers; + int nenvs; + int nclips; + int nsurfs; +} lwObject; + + +/* lwo2.c */ + +void lwFreeLayer( lwLayer *layer ); +void lwFreeObject( lwObject *object ); +lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); +int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); + +/* pntspols.c */ + +void lwFreePoints( lwPointList *point ); +void lwFreePolygons( lwPolygonList *plist ); +int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ); +void lwGetBoundingBox( lwPointList *point, float bbox[] ); +int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ); +int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); +void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ); +int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ); +int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, + lwSurface **surf, int *nsurfs ); +void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ); +void lwFreeTags( lwTagList *tlist ); +int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ); +int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, + lwPolygonList *plist ); + +/* vmap.c */ + +void lwFreeVMap( lwVMap *vmap ); +lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, + int perpoly ); +int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ); +int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ); + +/* clip.c */ + +void lwFreeClip( lwClip *clip ); +lwClip *lwGetClip( picoMemStream_t *fp, int cksize ); +lwClip *lwFindClip( lwClip *list, int index ); + +/* envelope.c */ + +void lwFreeEnvelope( lwEnvelope *env ); +lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ); +lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ); +float lwEvalEnvelope( lwEnvelope *env, float time ); + +/* surface.c */ + +void lwFreePlugin( lwPlugin *p ); +void lwFreeTexture( lwTexture *t ); +void lwFreeSurface( lwSurface *surf ); +int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ); +int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ); +int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ); +int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ); +int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ); +lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ); +lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ); +lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ); +lwSurface *lwDefaultSurface( void ); + +/* lwob.c */ + +lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ); +int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); +lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); +int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); + +/* list.c */ + +void lwListFree( void *list, void ( *freeNode )( void * )); +void lwListAdd( void **list, void *node ); +void lwListInsert( void **vlist, void *vitem, + int ( *compare )( void *, void * )); + +/* vecmath.c */ + +float dot( float a[], float b[] ); +void cross( float a[], float b[], float c[] ); +void normalize( float v[] ); +#define vecangle( a, b ) ( float ) acos( dot( a, b )) + +/* lwio.c */ + +void set_flen( int i ); +int get_flen( void ); +void *getbytes( picoMemStream_t *fp, int size ); +void skipbytes( picoMemStream_t *fp, int n ); +int getI1( picoMemStream_t *fp ); +short getI2( picoMemStream_t *fp ); +int getI4( picoMemStream_t *fp ); +unsigned char getU1( picoMemStream_t *fp ); +unsigned short getU2( picoMemStream_t *fp ); +unsigned int getU4( picoMemStream_t *fp ); +int getVX( picoMemStream_t *fp ); +float getF4( picoMemStream_t *fp ); +char *getS0( picoMemStream_t *fp ); +int sgetI1( unsigned char **bp ); +short sgetI2( unsigned char **bp ); +int sgetI4( unsigned char **bp ); +unsigned char sgetU1( unsigned char **bp ); +unsigned short sgetU2( unsigned char **bp ); +unsigned int sgetU4( unsigned char **bp ); +int sgetVX( unsigned char **bp ); +float sgetF4( unsigned char **bp ); +char *sgetS0( unsigned char **bp ); + +#ifdef _WIN32 + void revbytes( void *bp, int elsize, int elcount ); +#else + #define revbytes( b, s, c ) +#endif + +#endif diff --git a/libs/picomodel/lwo/lwob.c b/libs/picomodel/lwo/lwob.c index 0e386a30..edf42cff 100644 --- a/libs/picomodel/lwo/lwob.c +++ b/libs/picomodel/lwo/lwob.c @@ -1,723 +1,723 @@ -/* -====================================================================== -lwob.c - -Functions for an LWOB reader. LWOB is the LightWave object format -for versions of LW prior to 6.0. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - -/* disable warnings */ -#ifdef _WIN32 -#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ -#endif - - -/* IDs specific to LWOB */ - -#define ID_SRFS LWID_('S','R','F','S') -#define ID_FLAG LWID_('F','L','A','G') -#define ID_VLUM LWID_('V','L','U','M') -#define ID_VDIF LWID_('V','D','I','F') -#define ID_VSPC LWID_('V','S','P','C') -#define ID_RFLT LWID_('R','F','L','T') -#define ID_BTEX LWID_('B','T','E','X') -#define ID_CTEX LWID_('C','T','E','X') -#define ID_DTEX LWID_('D','T','E','X') -#define ID_LTEX LWID_('L','T','E','X') -#define ID_RTEX LWID_('R','T','E','X') -#define ID_STEX LWID_('S','T','E','X') -#define ID_TTEX LWID_('T','T','E','X') -#define ID_TFLG LWID_('T','F','L','G') -#define ID_TSIZ LWID_('T','S','I','Z') -#define ID_TCTR LWID_('T','C','T','R') -#define ID_TFAL LWID_('T','F','A','L') -#define ID_TVEL LWID_('T','V','E','L') -#define ID_TCLR LWID_('T','C','L','R') -#define ID_TVAL LWID_('T','V','A','L') -#define ID_TAMP LWID_('T','A','M','P') -#define ID_TIMG LWID_('T','I','M','G') -#define ID_TAAS LWID_('T','A','A','S') -#define ID_TREF LWID_('T','R','E','F') -#define ID_TOPC LWID_('T','O','P','C') -#define ID_SDAT LWID_('S','D','A','T') -#define ID_TFP0 LWID_('T','F','P','0') -#define ID_TFP1 LWID_('T','F','P','1') - - -/* -====================================================================== -add_clip() - -Add a clip to the clip list. Used to store the contents of an RIMG or -TIMG surface subchunk. -====================================================================== */ - -static int add_clip( char *s, lwClip **clist, int *nclips ) -{ - lwClip *clip; - char *p; - - clip = _pico_calloc( 1, sizeof( lwClip )); - if ( !clip ) return 0; - - clip->contrast.val = 1.0f; - clip->brightness.val = 1.0f; - clip->saturation.val = 1.0f; - clip->gamma.val = 1.0f; - - if ( p = strstr( s, "(sequence)" )) { - p[ -1 ] = 0; - clip->type = ID_ISEQ; - clip->source.seq.prefix = s; - clip->source.seq.digits = 3; - } - else { - clip->type = ID_STIL; - clip->source.still.name = s; - } - - *nclips++; - clip->index = *nclips; - - lwListAdd( clist, clip ); - - return clip->index; -} - - -/* -====================================================================== -add_tvel() - -Add a triple of envelopes to simulate the old texture velocity -parameters. -====================================================================== */ - -static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs ) -{ - lwEnvelope *env; - lwKey *key0, *key1; - int i; - - for ( i = 0; i < 3; i++ ) { - env = _pico_calloc( 1, sizeof( lwEnvelope )); - key0 = _pico_calloc( 1, sizeof( lwKey )); - key1 = _pico_calloc( 1, sizeof( lwKey )); - if ( !env || !key0 || !key1 ) return 0; - - key0->next = key1; - key0->value = pos[ i ]; - key0->time = 0.0f; - key1->prev = key0; - key1->value = pos[ i ] + vel[ i ] * 30.0f; - key1->time = 1.0f; - key0->shape = key1->shape = ID_LINE; - - env->index = *nenvs + i + 1; - env->type = 0x0301 + i; - env->name = _pico_alloc( 11 ); - if ( env->name ) { - strcpy( env->name, "Position.X" ); - env->name[ 9 ] += i; - } - env->key = key0; - env->nkeys = 2; - env->behavior[ 0 ] = BEH_LINEAR; - env->behavior[ 1 ] = BEH_LINEAR; - - lwListAdd( elist, env ); - } - - *nenvs += 3; - return env->index - 2; -} - - -/* -====================================================================== -get_texture() - -Create a new texture for BTEX, CTEX, etc. subchunks. -====================================================================== */ - -static lwTexture *get_texture( char *s ) -{ - lwTexture *tex; - - tex = _pico_calloc( 1, sizeof( lwTexture )); - if ( !tex ) return NULL; - - tex->tmap.size.val[ 0 ] = - tex->tmap.size.val[ 1 ] = - tex->tmap.size.val[ 2 ] = 1.0f; - tex->opacity.val = 1.0f; - tex->enabled = 1; - - if ( strstr( s, "Image Map" )) { - tex->type = ID_IMAP; - if ( strstr( s, "Planar" )) tex->param.imap.projection = 0; - else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1; - else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2; - else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3; - else if ( strstr( s, "Front" )) tex->param.imap.projection = 4; - tex->param.imap.aa_strength = 1.0f; - tex->param.imap.amplitude.val = 1.0f; - _pico_free( s ); - } - else { - tex->type = ID_PROC; - tex->param.proc.name = s; - } - - return tex; -} - - -/* -====================================================================== -lwGetSurface5() - -Read an lwSurface from an LWOB file. -====================================================================== */ - -lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ) -{ - lwSurface *surf; - lwTexture *tex; - lwPlugin *shdr; - char *s; - float v[ 3 ]; - unsigned int id, flags; - unsigned short sz; - int pos, rlen, i; - - - /* allocate the Surface structure */ - - surf = _pico_calloc( 1, sizeof( lwSurface )); - if ( !surf ) goto Fail; - - /* non-zero defaults */ - - surf->color.rgb[ 0 ] = 0.78431f; - surf->color.rgb[ 1 ] = 0.78431f; - surf->color.rgb[ 2 ] = 0.78431f; - surf->diffuse.val = 1.0f; - surf->glossiness.val = 0.4f; - surf->bump.val = 1.0f; - surf->eta.val = 1.0f; - surf->sideflags = 1; - - /* remember where we started */ - - set_flen( 0 ); - pos = _pico_memstream_tell( fp ); - - /* name */ - - surf->name = getS0( fp ); - - /* first subchunk header */ - - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) goto Fail; - - /* process subchunks as they're encountered */ - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_COLR: - surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f; - surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f; - surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f; - break; - - case ID_FLAG: - flags = getU2( fp ); - if ( flags & 4 ) surf->smooth = 1.56207f; - if ( flags & 8 ) surf->color_hilite.val = 1.0f; - if ( flags & 16 ) surf->color_filter.val = 1.0f; - if ( flags & 128 ) surf->dif_sharp.val = 0.5f; - if ( flags & 256 ) surf->sideflags = 3; - if ( flags & 512 ) surf->add_trans.val = 1.0f; - break; - - case ID_LUMI: - surf->luminosity.val = getI2( fp ) / 256.0f; - break; - - case ID_VLUM: - surf->luminosity.val = getF4( fp ); - break; - - case ID_DIFF: - surf->diffuse.val = getI2( fp ) / 256.0f; - break; - - case ID_VDIF: - surf->diffuse.val = getF4( fp ); - break; - - case ID_SPEC: - surf->specularity.val = getI2( fp ) / 256.0f; - break; - - case ID_VSPC: - surf->specularity.val = getF4( fp ); - break; - - case ID_GLOS: - surf->glossiness.val = ( float ) log( getU2( fp )) / 20.7944f; - break; - - case ID_SMAN: - surf->smooth = getF4( fp ); - break; - - case ID_REFL: - surf->reflection.val.val = getI2( fp ) / 256.0f; - break; - - case ID_RFLT: - surf->reflection.options = getU2( fp ); - break; - - case ID_RIMG: - s = getS0( fp ); - surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips ); - surf->reflection.options = 3; - break; - - case ID_RSAN: - surf->reflection.seam_angle = getF4( fp ); - break; - - case ID_TRAN: - surf->transparency.val.val = getI2( fp ) / 256.0f; - break; - - case ID_RIND: - surf->eta.val = getF4( fp ); - break; - - case ID_BTEX: - s = getbytes( fp, sz ); - tex = get_texture( s ); - lwListAdd( &surf->bump.tex, tex ); - break; - - case ID_CTEX: - s = getbytes( fp, sz ); - tex = get_texture( s ); - lwListAdd( &surf->color.tex, tex ); - break; - - case ID_DTEX: - s = getbytes( fp, sz ); - tex = get_texture( s ); - lwListAdd( &surf->diffuse.tex, tex ); - break; - - case ID_LTEX: - s = getbytes( fp, sz ); - tex = get_texture( s ); - lwListAdd( &surf->luminosity.tex, tex ); - break; - - case ID_RTEX: - s = getbytes( fp, sz ); - tex = get_texture( s ); - lwListAdd( &surf->reflection.val.tex, tex ); - break; - - case ID_STEX: - s = getbytes( fp, sz ); - tex = get_texture( s ); - lwListAdd( &surf->specularity.tex, tex ); - break; - - case ID_TTEX: - s = getbytes( fp, sz ); - tex = get_texture( s ); - lwListAdd( &surf->transparency.val.tex, tex ); - break; - - case ID_TFLG: - flags = getU2( fp ); - - if ( flags & 1 ) i = 0; - if ( flags & 2 ) i = 1; - if ( flags & 4 ) i = 2; - tex->axis = i; - if ( tex->type == ID_IMAP ) - tex->param.imap.axis = i; - else - tex->param.proc.axis = i; - - if ( flags & 8 ) tex->tmap.coord_sys = 1; - if ( flags & 16 ) tex->negative = 1; - if ( flags & 32 ) tex->param.imap.pblend = 1; - if ( flags & 64 ) { - tex->param.imap.aa_strength = 1.0f; - tex->param.imap.aas_flags = 1; - } - break; - - case ID_TSIZ: - for ( i = 0; i < 3; i++ ) - tex->tmap.size.val[ i ] = getF4( fp ); - break; - - case ID_TCTR: - for ( i = 0; i < 3; i++ ) - tex->tmap.center.val[ i ] = getF4( fp ); - break; - - case ID_TFAL: - for ( i = 0; i < 3; i++ ) - tex->tmap.falloff.val[ i ] = getF4( fp ); - break; - - case ID_TVEL: - for ( i = 0; i < 3; i++ ) - v[ i ] = getF4( fp ); - tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v, - &obj->env, &obj->nenvs ); - break; - - case ID_TCLR: - if ( tex->type == ID_PROC ) - for ( i = 0; i < 3; i++ ) - tex->param.proc.value[ i ] = getU1( fp ) / 255.0f; - break; - - case ID_TVAL: - tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f; - break; - - case ID_TAMP: - if ( tex->type == ID_IMAP ) - tex->param.imap.amplitude.val = getF4( fp ); - break; - - case ID_TIMG: - s = getS0( fp ); - tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips ); - break; - - case ID_TAAS: - tex->param.imap.aa_strength = getF4( fp ); - tex->param.imap.aas_flags = 1; - break; - - case ID_TREF: - tex->tmap.ref_object = getbytes( fp, sz ); - break; - - case ID_TOPC: - tex->opacity.val = getF4( fp ); - break; - - case ID_TFP0: - if ( tex->type == ID_IMAP ) - tex->param.imap.wrapw.val = getF4( fp ); - break; - - case ID_TFP1: - if ( tex->type == ID_IMAP ) - tex->param.imap.wraph.val = getF4( fp ); - break; - - case ID_SHDR: - shdr = _pico_calloc( 1, sizeof( lwPlugin )); - if ( !shdr ) goto Fail; - shdr->name = getbytes( fp, sz ); - lwListAdd( &surf->shader, shdr ); - surf->nshaders++; - break; - - case ID_SDAT: - shdr->data = getbytes( fp, sz ); - break; - - default: - break; - } - - /* error while reading current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) goto Fail; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the SURF chunk? */ - - if ( cksize <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) goto Fail; - } - - return surf; - -Fail: - if ( surf ) lwFreeSurface( surf ); - return NULL; -} - - -/* -====================================================================== -lwGetPolygons5() - -Read polygon records from a POLS chunk in an LWOB file. The polygons -are added to the array in the lwPolygonList. -====================================================================== */ - -int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) -{ - lwPolygon *pp; - lwPolVert *pv; - unsigned char *buf, *bp; - int i, j, nv, nverts, npols; - - - if ( cksize == 0 ) return 1; - - /* read the whole chunk */ - - set_flen( 0 ); - buf = getbytes( fp, cksize ); - if ( !buf ) goto Fail; - - /* count the polygons and vertices */ - - nverts = 0; - npols = 0; - bp = buf; - - while ( bp < buf + cksize ) { - nv = sgetU2( &bp ); - nverts += nv; - npols++; - bp += 2 * nv; - i = sgetI2( &bp ); - if ( i < 0 ) bp += 2; /* detail polygons */ - } - - if ( !lwAllocPolygons( plist, npols, nverts )) - goto Fail; - - /* fill in the new polygons */ - - bp = buf; - pp = plist->pol + plist->offset; - pv = plist->pol[ 0 ].v + plist->voffset; - - for ( i = 0; i < npols; i++ ) { - nv = sgetU2( &bp ); - - pp->nverts = nv; - pp->type = ID_FACE; - if ( !pp->v ) pp->v = pv; - for ( j = 0; j < nv; j++ ) - pv[ j ].index = sgetU2( &bp ) + ptoffset; - j = sgetI2( &bp ); - if ( j < 0 ) { - j = -j; - bp += 2; - } - j -= 1; - pp->surf = ( lwSurface * ) j; - - pp++; - pv += nv; - } - - _pico_free( buf ); - return 1; - -Fail: - if ( buf ) _pico_free( buf ); - lwFreePolygons( plist ); - return 0; -} - - -/* -====================================================================== -getLWObject5() - -Returns the contents of an LWOB, given its filename, or NULL if the -file couldn't be loaded. On failure, failID and failpos can be used -to diagnose the cause. - -1. If the file isn't an LWOB, failpos will contain 12 and failID will - be unchanged. - -2. If an error occurs while reading an LWOB, failID will contain the - most recently read IFF chunk ID, and failpos will contain the - value returned by _pico_memstream_tell() at the time of the failure. - -3. If the file couldn't be opened, or an error occurs while reading - the first 12 bytes, both failID and failpos will be unchanged. - -If you don't need this information, failID and failpos can be NULL. -====================================================================== */ - -lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) -{ - lwObject *object; - lwLayer *layer; - lwNode *node; - unsigned int id, formsize, type, cksize; - - - /* open the file */ - - if ( !fp ) return NULL; - - /* read the first 12 bytes */ - - set_flen( 0 ); - id = getU4( fp ); - formsize = getU4( fp ); - type = getU4( fp ); - if ( 12 != get_flen() ) { - return NULL; - } - - /* LWOB? */ - - if ( id != ID_FORM || type != ID_LWOB ) { - if ( failpos ) *failpos = 12; - return NULL; - } - - /* allocate an object and a default layer */ - - object = _pico_calloc( 1, sizeof( lwObject )); - if ( !object ) goto Fail; - - layer = _pico_calloc( 1, sizeof( lwLayer )); - if ( !layer ) goto Fail; - object->layer = layer; - object->nlayers = 1; - - /* get the first chunk header */ - - id = getU4( fp ); - cksize = getU4( fp ); - if ( 0 > get_flen() ) goto Fail; - - /* process chunks as they're encountered */ - - while ( 1 ) { - cksize += cksize & 1; - - switch ( id ) - { - case ID_PNTS: - if ( !lwGetPoints( fp, cksize, &layer->point )) - goto Fail; - break; - - case ID_POLS: - if ( !lwGetPolygons5( fp, cksize, &layer->polygon, - layer->point.offset )) - goto Fail; - break; - - case ID_SRFS: - if ( !lwGetTags( fp, cksize, &object->taglist )) - goto Fail; - break; - - case ID_SURF: - node = ( lwNode * ) lwGetSurface5( fp, cksize, object ); - if ( !node ) goto Fail; - lwListAdd( &object->surf, node ); - object->nsurfs++; - break; - - default: - _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); - break; - } - - /* end of the file? */ - - if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; - - /* get the next chunk header */ - - set_flen( 0 ); - id = getU4( fp ); - cksize = getU4( fp ); - if ( 8 != get_flen() ) goto Fail; - } - - lwGetBoundingBox( &layer->point, layer->bbox ); - lwGetPolyNormals( &layer->point, &layer->polygon ); - if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; - if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, - &object->surf, &object->nsurfs )) goto Fail; - lwGetVertNormals( &layer->point, &layer->polygon ); - - return object; - -Fail: - if ( failID ) *failID = id; - if ( fp ) { - if ( failpos ) *failpos = _pico_memstream_tell( fp ); - } - lwFreeObject( object ); - return NULL; -} - -int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) -{ - unsigned int id, formsize, type; - - - /* open the file */ - - if ( !fp ) return PICO_PMV_ERROR_MEMORY; - - /* read the first 12 bytes */ - - set_flen( 0 ); - id = getU4( fp ); - formsize = getU4( fp ); - type = getU4( fp ); - if ( 12 != get_flen() ) { - return PICO_PMV_ERROR_SIZE; - } - - /* LWOB? */ - - if ( id != ID_FORM || type != ID_LWOB ) { - if ( failpos ) *failpos = 12; - return PICO_PMV_ERROR_IDENT; - } - - return PICO_PMV_OK; -} +/* +====================================================================== +lwob.c + +Functions for an LWOB reader. LWOB is the LightWave object format +for versions of LW prior to 6.0. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ +#endif + + +/* IDs specific to LWOB */ + +#define ID_SRFS LWID_('S','R','F','S') +#define ID_FLAG LWID_('F','L','A','G') +#define ID_VLUM LWID_('V','L','U','M') +#define ID_VDIF LWID_('V','D','I','F') +#define ID_VSPC LWID_('V','S','P','C') +#define ID_RFLT LWID_('R','F','L','T') +#define ID_BTEX LWID_('B','T','E','X') +#define ID_CTEX LWID_('C','T','E','X') +#define ID_DTEX LWID_('D','T','E','X') +#define ID_LTEX LWID_('L','T','E','X') +#define ID_RTEX LWID_('R','T','E','X') +#define ID_STEX LWID_('S','T','E','X') +#define ID_TTEX LWID_('T','T','E','X') +#define ID_TFLG LWID_('T','F','L','G') +#define ID_TSIZ LWID_('T','S','I','Z') +#define ID_TCTR LWID_('T','C','T','R') +#define ID_TFAL LWID_('T','F','A','L') +#define ID_TVEL LWID_('T','V','E','L') +#define ID_TCLR LWID_('T','C','L','R') +#define ID_TVAL LWID_('T','V','A','L') +#define ID_TAMP LWID_('T','A','M','P') +#define ID_TIMG LWID_('T','I','M','G') +#define ID_TAAS LWID_('T','A','A','S') +#define ID_TREF LWID_('T','R','E','F') +#define ID_TOPC LWID_('T','O','P','C') +#define ID_SDAT LWID_('S','D','A','T') +#define ID_TFP0 LWID_('T','F','P','0') +#define ID_TFP1 LWID_('T','F','P','1') + + +/* +====================================================================== +add_clip() + +Add a clip to the clip list. Used to store the contents of an RIMG or +TIMG surface subchunk. +====================================================================== */ + +static int add_clip( char *s, lwClip **clist, int *nclips ) +{ + lwClip *clip; + char *p; + + clip = _pico_calloc( 1, sizeof( lwClip )); + if ( !clip ) return 0; + + clip->contrast.val = 1.0f; + clip->brightness.val = 1.0f; + clip->saturation.val = 1.0f; + clip->gamma.val = 1.0f; + + if ( p = strstr( s, "(sequence)" )) { + p[ -1 ] = 0; + clip->type = ID_ISEQ; + clip->source.seq.prefix = s; + clip->source.seq.digits = 3; + } + else { + clip->type = ID_STIL; + clip->source.still.name = s; + } + + *nclips++; + clip->index = *nclips; + + lwListAdd( clist, clip ); + + return clip->index; +} + + +/* +====================================================================== +add_tvel() + +Add a triple of envelopes to simulate the old texture velocity +parameters. +====================================================================== */ + +static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs ) +{ + lwEnvelope *env; + lwKey *key0, *key1; + int i; + + for ( i = 0; i < 3; i++ ) { + env = _pico_calloc( 1, sizeof( lwEnvelope )); + key0 = _pico_calloc( 1, sizeof( lwKey )); + key1 = _pico_calloc( 1, sizeof( lwKey )); + if ( !env || !key0 || !key1 ) return 0; + + key0->next = key1; + key0->value = pos[ i ]; + key0->time = 0.0f; + key1->prev = key0; + key1->value = pos[ i ] + vel[ i ] * 30.0f; + key1->time = 1.0f; + key0->shape = key1->shape = ID_LINE; + + env->index = *nenvs + i + 1; + env->type = 0x0301 + i; + env->name = _pico_alloc( 11 ); + if ( env->name ) { + strcpy( env->name, "Position.X" ); + env->name[ 9 ] += i; + } + env->key = key0; + env->nkeys = 2; + env->behavior[ 0 ] = BEH_LINEAR; + env->behavior[ 1 ] = BEH_LINEAR; + + lwListAdd( elist, env ); + } + + *nenvs += 3; + return env->index - 2; +} + + +/* +====================================================================== +get_texture() + +Create a new texture for BTEX, CTEX, etc. subchunks. +====================================================================== */ + +static lwTexture *get_texture( char *s ) +{ + lwTexture *tex; + + tex = _pico_calloc( 1, sizeof( lwTexture )); + if ( !tex ) return NULL; + + tex->tmap.size.val[ 0 ] = + tex->tmap.size.val[ 1 ] = + tex->tmap.size.val[ 2 ] = 1.0f; + tex->opacity.val = 1.0f; + tex->enabled = 1; + + if ( strstr( s, "Image Map" )) { + tex->type = ID_IMAP; + if ( strstr( s, "Planar" )) tex->param.imap.projection = 0; + else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1; + else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2; + else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3; + else if ( strstr( s, "Front" )) tex->param.imap.projection = 4; + tex->param.imap.aa_strength = 1.0f; + tex->param.imap.amplitude.val = 1.0f; + _pico_free( s ); + } + else { + tex->type = ID_PROC; + tex->param.proc.name = s; + } + + return tex; +} + + +/* +====================================================================== +lwGetSurface5() + +Read an lwSurface from an LWOB file. +====================================================================== */ + +lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ) +{ + lwSurface *surf; + lwTexture *tex; + lwPlugin *shdr; + char *s; + float v[ 3 ]; + unsigned int id, flags; + unsigned short sz; + int pos, rlen, i; + + + /* allocate the Surface structure */ + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) goto Fail; + + /* non-zero defaults */ + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* name */ + + surf->name = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_COLR: + surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f; + surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f; + surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f; + break; + + case ID_FLAG: + flags = getU2( fp ); + if ( flags & 4 ) surf->smooth = 1.56207f; + if ( flags & 8 ) surf->color_hilite.val = 1.0f; + if ( flags & 16 ) surf->color_filter.val = 1.0f; + if ( flags & 128 ) surf->dif_sharp.val = 0.5f; + if ( flags & 256 ) surf->sideflags = 3; + if ( flags & 512 ) surf->add_trans.val = 1.0f; + break; + + case ID_LUMI: + surf->luminosity.val = getI2( fp ) / 256.0f; + break; + + case ID_VLUM: + surf->luminosity.val = getF4( fp ); + break; + + case ID_DIFF: + surf->diffuse.val = getI2( fp ) / 256.0f; + break; + + case ID_VDIF: + surf->diffuse.val = getF4( fp ); + break; + + case ID_SPEC: + surf->specularity.val = getI2( fp ) / 256.0f; + break; + + case ID_VSPC: + surf->specularity.val = getF4( fp ); + break; + + case ID_GLOS: + surf->glossiness.val = ( float ) log( getU2( fp )) / 20.7944f; + break; + + case ID_SMAN: + surf->smooth = getF4( fp ); + break; + + case ID_REFL: + surf->reflection.val.val = getI2( fp ) / 256.0f; + break; + + case ID_RFLT: + surf->reflection.options = getU2( fp ); + break; + + case ID_RIMG: + s = getS0( fp ); + surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips ); + surf->reflection.options = 3; + break; + + case ID_RSAN: + surf->reflection.seam_angle = getF4( fp ); + break; + + case ID_TRAN: + surf->transparency.val.val = getI2( fp ) / 256.0f; + break; + + case ID_RIND: + surf->eta.val = getF4( fp ); + break; + + case ID_BTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->bump.tex, tex ); + break; + + case ID_CTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->color.tex, tex ); + break; + + case ID_DTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->diffuse.tex, tex ); + break; + + case ID_LTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->luminosity.tex, tex ); + break; + + case ID_RTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->reflection.val.tex, tex ); + break; + + case ID_STEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->specularity.tex, tex ); + break; + + case ID_TTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->transparency.val.tex, tex ); + break; + + case ID_TFLG: + flags = getU2( fp ); + + if ( flags & 1 ) i = 0; + if ( flags & 2 ) i = 1; + if ( flags & 4 ) i = 2; + tex->axis = i; + if ( tex->type == ID_IMAP ) + tex->param.imap.axis = i; + else + tex->param.proc.axis = i; + + if ( flags & 8 ) tex->tmap.coord_sys = 1; + if ( flags & 16 ) tex->negative = 1; + if ( flags & 32 ) tex->param.imap.pblend = 1; + if ( flags & 64 ) { + tex->param.imap.aa_strength = 1.0f; + tex->param.imap.aas_flags = 1; + } + break; + + case ID_TSIZ: + for ( i = 0; i < 3; i++ ) + tex->tmap.size.val[ i ] = getF4( fp ); + break; + + case ID_TCTR: + for ( i = 0; i < 3; i++ ) + tex->tmap.center.val[ i ] = getF4( fp ); + break; + + case ID_TFAL: + for ( i = 0; i < 3; i++ ) + tex->tmap.falloff.val[ i ] = getF4( fp ); + break; + + case ID_TVEL: + for ( i = 0; i < 3; i++ ) + v[ i ] = getF4( fp ); + tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v, + &obj->env, &obj->nenvs ); + break; + + case ID_TCLR: + if ( tex->type == ID_PROC ) + for ( i = 0; i < 3; i++ ) + tex->param.proc.value[ i ] = getU1( fp ) / 255.0f; + break; + + case ID_TVAL: + tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f; + break; + + case ID_TAMP: + if ( tex->type == ID_IMAP ) + tex->param.imap.amplitude.val = getF4( fp ); + break; + + case ID_TIMG: + s = getS0( fp ); + tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips ); + break; + + case ID_TAAS: + tex->param.imap.aa_strength = getF4( fp ); + tex->param.imap.aas_flags = 1; + break; + + case ID_TREF: + tex->tmap.ref_object = getbytes( fp, sz ); + break; + + case ID_TOPC: + tex->opacity.val = getF4( fp ); + break; + + case ID_TFP0: + if ( tex->type == ID_IMAP ) + tex->param.imap.wrapw.val = getF4( fp ); + break; + + case ID_TFP1: + if ( tex->type == ID_IMAP ) + tex->param.imap.wraph.val = getF4( fp ); + break; + + case ID_SHDR: + shdr = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !shdr ) goto Fail; + shdr->name = getbytes( fp, sz ); + lwListAdd( &surf->shader, shdr ); + surf->nshaders++; + break; + + case ID_SDAT: + shdr->data = getbytes( fp, sz ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the SURF chunk? */ + + if ( cksize <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return surf; + +Fail: + if ( surf ) lwFreeSurface( surf ); + return NULL; +} + + +/* +====================================================================== +lwGetPolygons5() + +Read polygon records from a POLS chunk in an LWOB file. The polygons +are added to the array in the lwPolygonList. +====================================================================== */ + +int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) +{ + lwPolygon *pp; + lwPolVert *pv; + unsigned char *buf, *bp; + int i, j, nv, nverts, npols; + + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) goto Fail; + + /* count the polygons and vertices */ + + nverts = 0; + npols = 0; + bp = buf; + + while ( bp < buf + cksize ) { + nv = sgetU2( &bp ); + nverts += nv; + npols++; + bp += 2 * nv; + i = sgetI2( &bp ); + if ( i < 0 ) bp += 2; /* detail polygons */ + } + + if ( !lwAllocPolygons( plist, npols, nverts )) + goto Fail; + + /* fill in the new polygons */ + + bp = buf; + pp = plist->pol + plist->offset; + pv = plist->pol[ 0 ].v + plist->voffset; + + for ( i = 0; i < npols; i++ ) { + nv = sgetU2( &bp ); + + pp->nverts = nv; + pp->type = ID_FACE; + if ( !pp->v ) pp->v = pv; + for ( j = 0; j < nv; j++ ) + pv[ j ].index = sgetU2( &bp ) + ptoffset; + j = sgetI2( &bp ); + if ( j < 0 ) { + j = -j; + bp += 2; + } + j -= 1; + pp->surf = ( lwSurface * ) j; + + pp++; + pv += nv; + } + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreePolygons( plist ); + return 0; +} + + +/* +====================================================================== +getLWObject5() + +Returns the contents of an LWOB, given its filename, or NULL if the +file couldn't be loaded. On failure, failID and failpos can be used +to diagnose the cause. + +1. If the file isn't an LWOB, failpos will contain 12 and failID will + be unchanged. + +2. If an error occurs while reading an LWOB, failID will contain the + most recently read IFF chunk ID, and failpos will contain the + value returned by _pico_memstream_tell() at the time of the failure. + +3. If the file couldn't be opened, or an error occurs while reading + the first 12 bytes, both failID and failpos will be unchanged. + +If you don't need this information, failID and failpos can be NULL. +====================================================================== */ + +lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + lwObject *object; + lwLayer *layer; + lwNode *node; + unsigned int id, formsize, type, cksize; + + + /* open the file */ + + if ( !fp ) return NULL; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return NULL; + } + + /* LWOB? */ + + if ( id != ID_FORM || type != ID_LWOB ) { + if ( failpos ) *failpos = 12; + return NULL; + } + + /* allocate an object and a default layer */ + + object = _pico_calloc( 1, sizeof( lwObject )); + if ( !object ) goto Fail; + + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + object->layer = layer; + object->nlayers = 1; + + /* get the first chunk header */ + + id = getU4( fp ); + cksize = getU4( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process chunks as they're encountered */ + + while ( 1 ) { + cksize += cksize & 1; + + switch ( id ) + { + case ID_PNTS: + if ( !lwGetPoints( fp, cksize, &layer->point )) + goto Fail; + break; + + case ID_POLS: + if ( !lwGetPolygons5( fp, cksize, &layer->polygon, + layer->point.offset )) + goto Fail; + break; + + case ID_SRFS: + if ( !lwGetTags( fp, cksize, &object->taglist )) + goto Fail; + break; + + case ID_SURF: + node = ( lwNode * ) lwGetSurface5( fp, cksize, object ); + if ( !node ) goto Fail; + lwListAdd( &object->surf, node ); + object->nsurfs++; + break; + + default: + _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); + break; + } + + /* end of the file? */ + + if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + cksize = getU4( fp ); + if ( 8 != get_flen() ) goto Fail; + } + + lwGetBoundingBox( &layer->point, layer->bbox ); + lwGetPolyNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; + if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, + &object->surf, &object->nsurfs )) goto Fail; + lwGetVertNormals( &layer->point, &layer->polygon ); + + return object; + +Fail: + if ( failID ) *failID = id; + if ( fp ) { + if ( failpos ) *failpos = _pico_memstream_tell( fp ); + } + lwFreeObject( object ); + return NULL; +} + +int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + unsigned int id, formsize, type; + + + /* open the file */ + + if ( !fp ) return PICO_PMV_ERROR_MEMORY; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return PICO_PMV_ERROR_SIZE; + } + + /* LWOB? */ + + if ( id != ID_FORM || type != ID_LWOB ) { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_IDENT; + } + + return PICO_PMV_OK; +} diff --git a/libs/picomodel/lwo/pntspols.c b/libs/picomodel/lwo/pntspols.c index d6c3152d..5cef01e6 100644 --- a/libs/picomodel/lwo/pntspols.c +++ b/libs/picomodel/lwo/pntspols.c @@ -1,537 +1,537 @@ -/* -====================================================================== -pntspols.c - -Point and polygon functions for an LWO2 reader. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - - -/* -====================================================================== -lwFreePoints() - -Free the memory used by an lwPointList. -====================================================================== */ - -void lwFreePoints( lwPointList *point ) -{ - int i; - - if ( point ) { - if ( point->pt ) { - for ( i = 0; i < point->count; i++ ) { - if ( point->pt[ i ].pol ) _pico_free( point->pt[ i ].pol ); - if ( point->pt[ i ].vm ) _pico_free( point->pt[ i ].vm ); - } - _pico_free( point->pt ); - } - memset( point, 0, sizeof( lwPointList )); - } -} - - -/* -====================================================================== -lwFreePolygons() - -Free the memory used by an lwPolygonList. -====================================================================== */ - -void lwFreePolygons( lwPolygonList *plist ) -{ - int i, j; - - if ( plist ) { - if ( plist->pol ) { - for ( i = 0; i < plist->count; i++ ) { - if ( plist->pol[ i ].v ) { - for ( j = 0; j < plist->pol[ i ].nverts; j++ ) - if ( plist->pol[ i ].v[ j ].vm ) - _pico_free( plist->pol[ i ].v[ j ].vm ); - } - } - if ( plist->pol[ 0 ].v ) - _pico_free( plist->pol[ 0 ].v ); - _pico_free( plist->pol ); - } - memset( plist, 0, sizeof( lwPolygonList )); - } -} - - -/* -====================================================================== -lwGetPoints() - -Read point records from a PNTS chunk in an LWO2 file. The points are -added to the array in the lwPointList. -====================================================================== */ - -int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ) -{ - float *f; - int np, i, j; - - if ( cksize == 1 ) return 1; - - /* extend the point array to hold the new points */ - - np = cksize / 12; - point->offset = point->count; - point->count += np; - if ( !_pico_realloc( (void *) &point->pt, (point->count - np) * sizeof( lwPoint ), point->count * sizeof( lwPoint )) ) - return 0; - memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint )); - - /* read the whole chunk */ - - f = ( float * ) getbytes( fp, cksize ); - if ( !f ) return 0; - revbytes( f, 4, np * 3 ); - - /* assign position values */ - - for ( i = 0, j = 0; i < np; i++, j += 3 ) { - point->pt[ i ].pos[ 0 ] = f[ j ]; - point->pt[ i ].pos[ 1 ] = f[ j + 1 ]; - point->pt[ i ].pos[ 2 ] = f[ j + 2 ]; - } - - _pico_free( f ); - return 1; -} - - -/* -====================================================================== -lwGetBoundingBox() - -Calculate the bounding box for a point list, but only if the bounding -box hasn't already been initialized. -====================================================================== */ - -void lwGetBoundingBox( lwPointList *point, float bbox[] ) -{ - int i, j; - - if ( point->count == 0 ) return; - - for ( i = 0; i < 6; i++ ) - if ( bbox[ i ] != 0.0f ) return; - - bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f; - bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f; - for ( i = 0; i < point->count; i++ ) { - for ( j = 0; j < 3; j++ ) { - if ( bbox[ j ] > point->pt[ i ].pos[ j ] ) - bbox[ j ] = point->pt[ i ].pos[ j ]; - if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] ) - bbox[ j + 3 ] = point->pt[ i ].pos[ j ]; - } - } -} - - -/* -====================================================================== -lwAllocPolygons() - -Allocate or extend the polygon arrays to hold new records. -====================================================================== */ - -int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ) -{ - int i; - - plist->offset = plist->count; - plist->count += npols; - if ( !_pico_realloc( (void *) &plist->pol, (plist->count - npols) * sizeof( lwPolygon ), plist->count * sizeof( lwPolygon )) ) - return 0; - memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon )); - - plist->voffset = plist->vcount; - plist->vcount += nverts; - if ( !_pico_realloc( (void *) &plist->pol[ 0 ].v, (plist->vcount - nverts) * sizeof( lwPolVert ), plist->vcount * sizeof( lwPolVert )) ) - return 0; - memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert )); - - /* fix up the old vertex pointers */ - - for ( i = 1; i < plist->offset; i++ ) - plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts; - - return 1; -} - - -/* -====================================================================== -lwGetPolygons() - -Read polygon records from a POLS chunk in an LWO2 file. The polygons -are added to the array in the lwPolygonList. -====================================================================== */ - -int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) -{ - lwPolygon *pp; - lwPolVert *pv; - unsigned char *buf, *bp; - int i, j, flags, nv, nverts, npols; - unsigned int type; - - - if ( cksize == 0 ) return 1; - - /* read the whole chunk */ - - set_flen( 0 ); - type = getU4( fp ); - buf = getbytes( fp, cksize - 4 ); - if ( cksize != get_flen() ) goto Fail; - - /* count the polygons and vertices */ - - nverts = 0; - npols = 0; - bp = buf; - - while ( bp < buf + cksize - 4 ) { - nv = sgetU2( &bp ); - nv &= 0x03FF; - nverts += nv; - npols++; - for ( i = 0; i < nv; i++ ) - j = sgetVX( &bp ); - } - - if ( !lwAllocPolygons( plist, npols, nverts )) - goto Fail; - - /* fill in the new polygons */ - - bp = buf; - pp = plist->pol + plist->offset; - pv = plist->pol[ 0 ].v + plist->voffset; - - for ( i = 0; i < npols; i++ ) { - nv = sgetU2( &bp ); - flags = nv & 0xFC00; - nv &= 0x03FF; - - pp->nverts = nv; - pp->flags = flags; - pp->type = type; - if ( !pp->v ) pp->v = pv; - for ( j = 0; j < nv; j++ ) - pp->v[ j ].index = sgetVX( &bp ) + ptoffset; - - pp++; - pv += nv; - } - - _pico_free( buf ); - return 1; - -Fail: - if ( buf ) _pico_free( buf ); - lwFreePolygons( plist ); - return 0; -} - - -/* -====================================================================== -lwGetPolyNormals() - -Calculate the polygon normals. By convention, LW's polygon normals -are found as the cross product of the first and last edges. It's -undefined for one- and two-point polygons. -====================================================================== */ - -void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ) -{ - int i, j; - float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ]; - - for ( i = 0; i < polygon->count; i++ ) { - if ( polygon->pol[ i ].nverts < 3 ) continue; - for ( j = 0; j < 3; j++ ) { - p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ]; - p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ]; - pn[ j ] = point->pt[ polygon->pol[ i ].v[ - polygon->pol[ i ].nverts - 1 ].index ].pos[ j ]; - } - - for ( j = 0; j < 3; j++ ) { - v1[ j ] = p2[ j ] - p1[ j ]; - v2[ j ] = pn[ j ] - p1[ j ]; - } - - cross( v1, v2, polygon->pol[ i ].norm ); - normalize( polygon->pol[ i ].norm ); - } -} - - -/* -====================================================================== -lwGetPointPolygons() - -For each point, fill in the indexes of the polygons that share the -point. Returns 0 if any of the memory allocations fail, otherwise -returns 1. -====================================================================== */ - -int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ) -{ - int i, j, k; - - /* count the number of polygons per point */ - - for ( i = 0; i < polygon->count; i++ ) - for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) - ++point->pt[ polygon->pol[ i ].v[ j ].index ].npols; - - /* alloc per-point polygon arrays */ - - for ( i = 0; i < point->count; i++ ) { - if ( point->pt[ i ].npols == 0 ) continue; - point->pt[ i ].pol = _pico_calloc( point->pt[ i ].npols, sizeof( int )); - if ( !point->pt[ i ].pol ) return 0; - point->pt[ i ].npols = 0; - } - - /* fill in polygon array for each point */ - - for ( i = 0; i < polygon->count; i++ ) { - for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { - k = polygon->pol[ i ].v[ j ].index; - point->pt[ k ].pol[ point->pt[ k ].npols ] = i; - ++point->pt[ k ].npols; - } - } - - return 1; -} - - -/* -====================================================================== -lwResolvePolySurfaces() - -Convert tag indexes into actual lwSurface pointers. If any polygons -point to tags for which no corresponding surface can be found, a -default surface is created. -====================================================================== */ - -int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, - lwSurface **surf, int *nsurfs ) -{ - lwSurface **s, *st; - int i, index; - - if ( tlist->count == 0 ) return 1; - - s = _pico_calloc( tlist->count, sizeof( lwSurface * )); - if ( !s ) return 0; - - for ( i = 0; i < tlist->count; i++ ) { - st = *surf; - while ( st ) { - if ( !strcmp( st->name, tlist->tag[ i ] )) { - s[ i ] = st; - break; - } - st = st->next; - } - } - - for ( i = 0; i < polygon->count; i++ ) { - index = ( int ) polygon->pol[ i ].surf; - if ( index < 0 || index > tlist->count ) return 0; - if ( !s[ index ] ) { - s[ index ] = lwDefaultSurface(); - if ( !s[ index ] ) return 0; - s[ index ]->name = _pico_alloc( strlen( tlist->tag[ index ] ) + 1 ); - if ( !s[ index ]->name ) return 0; - strcpy( s[ index ]->name, tlist->tag[ index ] ); - lwListAdd( surf, s[ index ] ); - *nsurfs = *nsurfs + 1; - } - polygon->pol[ i ].surf = s[ index ]; - } - - _pico_free( s ); - return 1; -} - - -/* -====================================================================== -lwGetVertNormals() - -Calculate the vertex normals. For each polygon vertex, sum the -normals of the polygons that share the point. If the normals of the -current and adjacent polygons form an angle greater than the max -smoothing angle for the current polygon's surface, the normal of the -adjacent polygon is excluded from the sum. It's also excluded if the -polygons aren't in the same smoothing group. - -Assumes that lwGetPointPolygons(), lwGetPolyNormals() and -lwResolvePolySurfaces() have already been called. -====================================================================== */ - -void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ) -{ - int j, k, n, g, h, p; - float a; - - for ( j = 0; j < polygon->count; j++ ) { - for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) { - for ( k = 0; k < 3; k++ ) - polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ]; - - if ( polygon->pol[ j ].surf->smooth <= 0 ) continue; - - p = polygon->pol[ j ].v[ n ].index; - - for ( g = 0; g < point->pt[ p ].npols; g++ ) { - h = point->pt[ p ].pol[ g ]; - if ( h == j ) continue; - - if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp ) - continue; - a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm ); - if ( a > polygon->pol[ j ].surf->smooth ) continue; - - for ( k = 0; k < 3; k++ ) - polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ]; - } - - normalize( polygon->pol[ j ].v[ n ].norm ); - } - } -} - - -/* -====================================================================== -lwFreeTags() - -Free memory used by an lwTagList. -====================================================================== */ - -void lwFreeTags( lwTagList *tlist ) -{ - int i; - - if ( tlist ) { - if ( tlist->tag ) { - for ( i = 0; i < tlist->count; i++ ) - if ( tlist->tag[ i ] ) _pico_free( tlist->tag[ i ] ); - _pico_free( tlist->tag ); - } - memset( tlist, 0, sizeof( lwTagList )); - } -} - - -/* -====================================================================== -lwGetTags() - -Read tag strings from a TAGS chunk in an LWO2 file. The tags are -added to the lwTagList array. -====================================================================== */ - -int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ) -{ - char *buf, *bp; - int i, len, ntags; - - if ( cksize == 0 ) return 1; - - /* read the whole chunk */ - - set_flen( 0 ); - buf = getbytes( fp, cksize ); - if ( !buf ) return 0; - - /* count the strings */ - - ntags = 0; - bp = buf; - while ( bp < buf + cksize ) { - len = strlen( bp ) + 1; - len += len & 1; - bp += len; - ++ntags; - } - - /* expand the string array to hold the new tags */ - - tlist->offset = tlist->count; - tlist->count += ntags; - if ( !_pico_realloc( (void *) &tlist->tag, (tlist->count - ntags) * sizeof( char * ), tlist->count * sizeof( char * )) ) - goto Fail; - memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * )); - - /* copy the new tags to the tag array */ - - bp = buf; - for ( i = 0; i < ntags; i++ ) - tlist->tag[ i + tlist->offset ] = sgetS0( &bp ); - - _pico_free( buf ); - return 1; - -Fail: - if ( buf ) _pico_free( buf ); - return 0; -} - - -/* -====================================================================== -lwGetPolygonTags() - -Read polygon tags from a PTAG chunk in an LWO2 file. -====================================================================== */ - -int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, - lwPolygonList *plist ) -{ - unsigned int type; - int rlen = 0, i, j; - - set_flen( 0 ); - type = getU4( fp ); - rlen = get_flen(); - if ( rlen < 0 ) return 0; - - if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) { - _pico_memstream_seek( fp, cksize - 4, PICO_SEEK_CUR ); - return 1; - } - - while ( rlen < cksize ) { - i = getVX( fp ) + plist->offset; - j = getVX( fp ) + tlist->offset; - rlen = get_flen(); - if ( rlen < 0 || rlen > cksize ) return 0; - - switch ( type ) { - case ID_SURF: plist->pol[ i ].surf = ( lwSurface * ) j; break; - case ID_PART: plist->pol[ i ].part = j; break; - case ID_SMGP: plist->pol[ i ].smoothgrp = j; break; - } - } - - return 1; -} +/* +====================================================================== +pntspols.c + +Point and polygon functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreePoints() + +Free the memory used by an lwPointList. +====================================================================== */ + +void lwFreePoints( lwPointList *point ) +{ + int i; + + if ( point ) { + if ( point->pt ) { + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].pol ) _pico_free( point->pt[ i ].pol ); + if ( point->pt[ i ].vm ) _pico_free( point->pt[ i ].vm ); + } + _pico_free( point->pt ); + } + memset( point, 0, sizeof( lwPointList )); + } +} + + +/* +====================================================================== +lwFreePolygons() + +Free the memory used by an lwPolygonList. +====================================================================== */ + +void lwFreePolygons( lwPolygonList *plist ) +{ + int i, j; + + if ( plist ) { + if ( plist->pol ) { + for ( i = 0; i < plist->count; i++ ) { + if ( plist->pol[ i ].v ) { + for ( j = 0; j < plist->pol[ i ].nverts; j++ ) + if ( plist->pol[ i ].v[ j ].vm ) + _pico_free( plist->pol[ i ].v[ j ].vm ); + } + } + if ( plist->pol[ 0 ].v ) + _pico_free( plist->pol[ 0 ].v ); + _pico_free( plist->pol ); + } + memset( plist, 0, sizeof( lwPolygonList )); + } +} + + +/* +====================================================================== +lwGetPoints() + +Read point records from a PNTS chunk in an LWO2 file. The points are +added to the array in the lwPointList. +====================================================================== */ + +int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ) +{ + float *f; + int np, i, j; + + if ( cksize == 1 ) return 1; + + /* extend the point array to hold the new points */ + + np = cksize / 12; + point->offset = point->count; + point->count += np; + if ( !_pico_realloc( (void *) &point->pt, (point->count - np) * sizeof( lwPoint ), point->count * sizeof( lwPoint )) ) + return 0; + memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint )); + + /* read the whole chunk */ + + f = ( float * ) getbytes( fp, cksize ); + if ( !f ) return 0; + revbytes( f, 4, np * 3 ); + + /* assign position values */ + + for ( i = 0, j = 0; i < np; i++, j += 3 ) { + point->pt[ i ].pos[ 0 ] = f[ j ]; + point->pt[ i ].pos[ 1 ] = f[ j + 1 ]; + point->pt[ i ].pos[ 2 ] = f[ j + 2 ]; + } + + _pico_free( f ); + return 1; +} + + +/* +====================================================================== +lwGetBoundingBox() + +Calculate the bounding box for a point list, but only if the bounding +box hasn't already been initialized. +====================================================================== */ + +void lwGetBoundingBox( lwPointList *point, float bbox[] ) +{ + int i, j; + + if ( point->count == 0 ) return; + + for ( i = 0; i < 6; i++ ) + if ( bbox[ i ] != 0.0f ) return; + + bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f; + bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f; + for ( i = 0; i < point->count; i++ ) { + for ( j = 0; j < 3; j++ ) { + if ( bbox[ j ] > point->pt[ i ].pos[ j ] ) + bbox[ j ] = point->pt[ i ].pos[ j ]; + if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] ) + bbox[ j + 3 ] = point->pt[ i ].pos[ j ]; + } + } +} + + +/* +====================================================================== +lwAllocPolygons() + +Allocate or extend the polygon arrays to hold new records. +====================================================================== */ + +int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ) +{ + int i; + + plist->offset = plist->count; + plist->count += npols; + if ( !_pico_realloc( (void *) &plist->pol, (plist->count - npols) * sizeof( lwPolygon ), plist->count * sizeof( lwPolygon )) ) + return 0; + memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon )); + + plist->voffset = plist->vcount; + plist->vcount += nverts; + if ( !_pico_realloc( (void *) &plist->pol[ 0 ].v, (plist->vcount - nverts) * sizeof( lwPolVert ), plist->vcount * sizeof( lwPolVert )) ) + return 0; + memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert )); + + /* fix up the old vertex pointers */ + + for ( i = 1; i < plist->offset; i++ ) + plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts; + + return 1; +} + + +/* +====================================================================== +lwGetPolygons() + +Read polygon records from a POLS chunk in an LWO2 file. The polygons +are added to the array in the lwPolygonList. +====================================================================== */ + +int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) +{ + lwPolygon *pp; + lwPolVert *pv; + unsigned char *buf, *bp; + int i, j, flags, nv, nverts, npols; + unsigned int type; + + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + type = getU4( fp ); + buf = getbytes( fp, cksize - 4 ); + if ( cksize != get_flen() ) goto Fail; + + /* count the polygons and vertices */ + + nverts = 0; + npols = 0; + bp = buf; + + while ( bp < buf + cksize - 4 ) { + nv = sgetU2( &bp ); + nv &= 0x03FF; + nverts += nv; + npols++; + for ( i = 0; i < nv; i++ ) + j = sgetVX( &bp ); + } + + if ( !lwAllocPolygons( plist, npols, nverts )) + goto Fail; + + /* fill in the new polygons */ + + bp = buf; + pp = plist->pol + plist->offset; + pv = plist->pol[ 0 ].v + plist->voffset; + + for ( i = 0; i < npols; i++ ) { + nv = sgetU2( &bp ); + flags = nv & 0xFC00; + nv &= 0x03FF; + + pp->nverts = nv; + pp->flags = flags; + pp->type = type; + if ( !pp->v ) pp->v = pv; + for ( j = 0; j < nv; j++ ) + pp->v[ j ].index = sgetVX( &bp ) + ptoffset; + + pp++; + pv += nv; + } + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreePolygons( plist ); + return 0; +} + + +/* +====================================================================== +lwGetPolyNormals() + +Calculate the polygon normals. By convention, LW's polygon normals +are found as the cross product of the first and last edges. It's +undefined for one- and two-point polygons. +====================================================================== */ + +void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ) +{ + int i, j; + float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ]; + + for ( i = 0; i < polygon->count; i++ ) { + if ( polygon->pol[ i ].nverts < 3 ) continue; + for ( j = 0; j < 3; j++ ) { + p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ]; + p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ]; + pn[ j ] = point->pt[ polygon->pol[ i ].v[ + polygon->pol[ i ].nverts - 1 ].index ].pos[ j ]; + } + + for ( j = 0; j < 3; j++ ) { + v1[ j ] = p2[ j ] - p1[ j ]; + v2[ j ] = pn[ j ] - p1[ j ]; + } + + cross( v1, v2, polygon->pol[ i ].norm ); + normalize( polygon->pol[ i ].norm ); + } +} + + +/* +====================================================================== +lwGetPointPolygons() + +For each point, fill in the indexes of the polygons that share the +point. Returns 0 if any of the memory allocations fail, otherwise +returns 1. +====================================================================== */ + +int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ) +{ + int i, j, k; + + /* count the number of polygons per point */ + + for ( i = 0; i < polygon->count; i++ ) + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) + ++point->pt[ polygon->pol[ i ].v[ j ].index ].npols; + + /* alloc per-point polygon arrays */ + + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].npols == 0 ) continue; + point->pt[ i ].pol = _pico_calloc( point->pt[ i ].npols, sizeof( int )); + if ( !point->pt[ i ].pol ) return 0; + point->pt[ i ].npols = 0; + } + + /* fill in polygon array for each point */ + + for ( i = 0; i < polygon->count; i++ ) { + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { + k = polygon->pol[ i ].v[ j ].index; + point->pt[ k ].pol[ point->pt[ k ].npols ] = i; + ++point->pt[ k ].npols; + } + } + + return 1; +} + + +/* +====================================================================== +lwResolvePolySurfaces() + +Convert tag indexes into actual lwSurface pointers. If any polygons +point to tags for which no corresponding surface can be found, a +default surface is created. +====================================================================== */ + +int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, + lwSurface **surf, int *nsurfs ) +{ + lwSurface **s, *st; + int i, index; + + if ( tlist->count == 0 ) return 1; + + s = _pico_calloc( tlist->count, sizeof( lwSurface * )); + if ( !s ) return 0; + + for ( i = 0; i < tlist->count; i++ ) { + st = *surf; + while ( st ) { + if ( !strcmp( st->name, tlist->tag[ i ] )) { + s[ i ] = st; + break; + } + st = st->next; + } + } + + for ( i = 0; i < polygon->count; i++ ) { + index = ( int ) polygon->pol[ i ].surf; + if ( index < 0 || index > tlist->count ) return 0; + if ( !s[ index ] ) { + s[ index ] = lwDefaultSurface(); + if ( !s[ index ] ) return 0; + s[ index ]->name = _pico_alloc( strlen( tlist->tag[ index ] ) + 1 ); + if ( !s[ index ]->name ) return 0; + strcpy( s[ index ]->name, tlist->tag[ index ] ); + lwListAdd( surf, s[ index ] ); + *nsurfs = *nsurfs + 1; + } + polygon->pol[ i ].surf = s[ index ]; + } + + _pico_free( s ); + return 1; +} + + +/* +====================================================================== +lwGetVertNormals() + +Calculate the vertex normals. For each polygon vertex, sum the +normals of the polygons that share the point. If the normals of the +current and adjacent polygons form an angle greater than the max +smoothing angle for the current polygon's surface, the normal of the +adjacent polygon is excluded from the sum. It's also excluded if the +polygons aren't in the same smoothing group. + +Assumes that lwGetPointPolygons(), lwGetPolyNormals() and +lwResolvePolySurfaces() have already been called. +====================================================================== */ + +void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ) +{ + int j, k, n, g, h, p; + float a; + + for ( j = 0; j < polygon->count; j++ ) { + for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) { + for ( k = 0; k < 3; k++ ) + polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ]; + + if ( polygon->pol[ j ].surf->smooth <= 0 ) continue; + + p = polygon->pol[ j ].v[ n ].index; + + for ( g = 0; g < point->pt[ p ].npols; g++ ) { + h = point->pt[ p ].pol[ g ]; + if ( h == j ) continue; + + if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp ) + continue; + a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm ); + if ( a > polygon->pol[ j ].surf->smooth ) continue; + + for ( k = 0; k < 3; k++ ) + polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ]; + } + + normalize( polygon->pol[ j ].v[ n ].norm ); + } + } +} + + +/* +====================================================================== +lwFreeTags() + +Free memory used by an lwTagList. +====================================================================== */ + +void lwFreeTags( lwTagList *tlist ) +{ + int i; + + if ( tlist ) { + if ( tlist->tag ) { + for ( i = 0; i < tlist->count; i++ ) + if ( tlist->tag[ i ] ) _pico_free( tlist->tag[ i ] ); + _pico_free( tlist->tag ); + } + memset( tlist, 0, sizeof( lwTagList )); + } +} + + +/* +====================================================================== +lwGetTags() + +Read tag strings from a TAGS chunk in an LWO2 file. The tags are +added to the lwTagList array. +====================================================================== */ + +int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ) +{ + char *buf, *bp; + int i, len, ntags; + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) return 0; + + /* count the strings */ + + ntags = 0; + bp = buf; + while ( bp < buf + cksize ) { + len = strlen( bp ) + 1; + len += len & 1; + bp += len; + ++ntags; + } + + /* expand the string array to hold the new tags */ + + tlist->offset = tlist->count; + tlist->count += ntags; + if ( !_pico_realloc( (void *) &tlist->tag, (tlist->count - ntags) * sizeof( char * ), tlist->count * sizeof( char * )) ) + goto Fail; + memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * )); + + /* copy the new tags to the tag array */ + + bp = buf; + for ( i = 0; i < ntags; i++ ) + tlist->tag[ i + tlist->offset ] = sgetS0( &bp ); + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + return 0; +} + + +/* +====================================================================== +lwGetPolygonTags() + +Read polygon tags from a PTAG chunk in an LWO2 file. +====================================================================== */ + +int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, + lwPolygonList *plist ) +{ + unsigned int type; + int rlen = 0, i, j; + + set_flen( 0 ); + type = getU4( fp ); + rlen = get_flen(); + if ( rlen < 0 ) return 0; + + if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) { + _pico_memstream_seek( fp, cksize - 4, PICO_SEEK_CUR ); + return 1; + } + + while ( rlen < cksize ) { + i = getVX( fp ) + plist->offset; + j = getVX( fp ) + tlist->offset; + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) return 0; + + switch ( type ) { + case ID_SURF: plist->pol[ i ].surf = ( lwSurface * ) j; break; + case ID_PART: plist->pol[ i ].part = j; break; + case ID_SMGP: plist->pol[ i ].smoothgrp = j; break; + } + } + + return 1; +} diff --git a/libs/picomodel/lwo/surface.c b/libs/picomodel/lwo/surface.c index 6456a957..6c205df2 100644 --- a/libs/picomodel/lwo/surface.c +++ b/libs/picomodel/lwo/surface.c @@ -1,1004 +1,1004 @@ -/* -====================================================================== -surface.c - -Surface functions for an LWO2 reader. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - - -/* -====================================================================== -lwFreePlugin() - -Free the memory used by an lwPlugin. -====================================================================== */ - -void lwFreePlugin( lwPlugin *p ) -{ - if ( p ) { - if ( p->ord ) _pico_free( p->ord ); - if ( p->name ) _pico_free( p->name ); - if ( p->data ) _pico_free( p->data ); - _pico_free( p ); - } -} - - -/* -====================================================================== -lwFreeTexture() - -Free the memory used by an lwTexture. -====================================================================== */ - -void lwFreeTexture( lwTexture *t ) -{ - if ( t ) { - if ( t->ord ) _pico_free( t->ord ); - switch ( t->type ) { - case ID_IMAP: - if ( t->param.imap.vmap_name ) _pico_free( t->param.imap.vmap_name ); - break; - case ID_PROC: - if ( t->param.proc.name ) _pico_free( t->param.proc.name ); - if ( t->param.proc.data ) _pico_free( t->param.proc.data ); - break; - case ID_GRAD: - if ( t->param.grad.key ) _pico_free( t->param.grad.key ); - if ( t->param.grad.ikey ) _pico_free( t->param.grad.ikey ); - break; - } - _pico_free( t ); - } -} - - -/* -====================================================================== -lwFreeSurface() - -Free the memory used by an lwSurface. -====================================================================== */ - -void lwFreeSurface( lwSurface *surf ) -{ - if ( surf ) { - if ( surf->name ) _pico_free( surf->name ); - if ( surf->srcname ) _pico_free( surf->srcname ); - - lwListFree( surf->shader, lwFreePlugin ); - - lwListFree( surf->color.tex, lwFreeTexture ); - lwListFree( surf->luminosity.tex, lwFreeTexture ); - lwListFree( surf->diffuse.tex, lwFreeTexture ); - lwListFree( surf->specularity.tex, lwFreeTexture ); - lwListFree( surf->glossiness.tex, lwFreeTexture ); - lwListFree( surf->reflection.val.tex, lwFreeTexture ); - lwListFree( surf->transparency.val.tex, lwFreeTexture ); - lwListFree( surf->eta.tex, lwFreeTexture ); - lwListFree( surf->translucency.tex, lwFreeTexture ); - lwListFree( surf->bump.tex, lwFreeTexture ); - - _pico_free( surf ); - } -} - - -/* -====================================================================== -lwGetTHeader() - -Read a texture map header from a SURF.BLOK in an LWO2 file. This is -the first subchunk in a BLOK, and its contents are common to all three -texture types. -====================================================================== */ - -int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ) -{ - unsigned int id; - unsigned short sz; - int pos, rlen; - - - /* remember where we started */ - - set_flen( 0 ); - pos = _pico_memstream_tell( fp ); - - /* ordinal string */ - - tex->ord = getS0( fp ); - - /* first subchunk header */ - - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) return 0; - - /* process subchunks as they're encountered */ - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_CHAN: - tex->chan = getU4( fp ); - break; - - case ID_OPAC: - tex->opac_type = getU2( fp ); - tex->opacity.val = getF4( fp ); - tex->opacity.eindex = getVX( fp ); - break; - - case ID_ENAB: - tex->enabled = getU2( fp ); - break; - - case ID_NEGA: - tex->negative = getU2( fp ); - break; - - case ID_AXIS: - tex->axis = getU2( fp ); - break; - - default: - break; - } - - /* error while reading current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) return 0; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the texture header subchunk? */ - - if ( hsz <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) return 0; - } - - set_flen( _pico_memstream_tell( fp ) - pos ); - return 1; -} - - -/* -====================================================================== -lwGetTMap() - -Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP -defines the mapping from texture to world or object coordinates. -====================================================================== */ - -int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ) -{ - unsigned int id; - unsigned short sz; - int rlen, pos, i; - - pos = _pico_memstream_tell( fp ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) return 0; - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_SIZE: - for ( i = 0; i < 3; i++ ) - tmap->size.val[ i ] = getF4( fp ); - tmap->size.eindex = getVX( fp ); - break; - - case ID_CNTR: - for ( i = 0; i < 3; i++ ) - tmap->center.val[ i ] = getF4( fp ); - tmap->center.eindex = getVX( fp ); - break; - - case ID_ROTA: - for ( i = 0; i < 3; i++ ) - tmap->rotate.val[ i ] = getF4( fp ); - tmap->rotate.eindex = getVX( fp ); - break; - - case ID_FALL: - tmap->fall_type = getU2( fp ); - for ( i = 0; i < 3; i++ ) - tmap->falloff.val[ i ] = getF4( fp ); - tmap->falloff.eindex = getVX( fp ); - break; - - case ID_OREF: - tmap->ref_object = getS0( fp ); - break; - - case ID_CSYS: - tmap->coord_sys = getU2( fp ); - break; - - default: - break; - } - - /* error while reading the current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) return 0; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the TMAP subchunk? */ - - if ( tmapsz <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) return 0; - } - - set_flen( _pico_memstream_tell( fp ) - pos ); - return 1; -} - - -/* -====================================================================== -lwGetImageMap() - -Read an lwImageMap from a SURF.BLOK in an LWO2 file. -====================================================================== */ - -int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ) -{ - unsigned int id; - unsigned short sz; - int rlen, pos; - - pos = _pico_memstream_tell( fp ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) return 0; - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_TMAP: - if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; - break; - - case ID_PROJ: - tex->param.imap.projection = getU2( fp ); - break; - - case ID_VMAP: - tex->param.imap.vmap_name = getS0( fp ); - break; - - case ID_AXIS: - tex->param.imap.axis = getU2( fp ); - break; - - case ID_IMAG: - tex->param.imap.cindex = getVX( fp ); - break; - - case ID_WRAP: - tex->param.imap.wrapw_type = getU2( fp ); - tex->param.imap.wraph_type = getU2( fp ); - break; - - case ID_WRPW: - tex->param.imap.wrapw.val = getF4( fp ); - tex->param.imap.wrapw.eindex = getVX( fp ); - break; - - case ID_WRPH: - tex->param.imap.wraph.val = getF4( fp ); - tex->param.imap.wraph.eindex = getVX( fp ); - break; - - case ID_AAST: - tex->param.imap.aas_flags = getU2( fp ); - tex->param.imap.aa_strength = getF4( fp ); - break; - - case ID_PIXB: - tex->param.imap.pblend = getU2( fp ); - break; - - case ID_STCK: - tex->param.imap.stck.val = getF4( fp ); - tex->param.imap.stck.eindex = getVX( fp ); - break; - - case ID_TAMP: - tex->param.imap.amplitude.val = getF4( fp ); - tex->param.imap.amplitude.eindex = getVX( fp ); - break; - - default: - break; - } - - /* error while reading the current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) return 0; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the image map? */ - - if ( rsz <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) return 0; - } - - set_flen( _pico_memstream_tell( fp ) - pos ); - return 1; -} - - -/* -====================================================================== -lwGetProcedural() - -Read an lwProcedural from a SURF.BLOK in an LWO2 file. -====================================================================== */ - -int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ) -{ - unsigned int id; - unsigned short sz; - int rlen, pos; - - pos = _pico_memstream_tell( fp ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) return 0; - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_TMAP: - if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; - break; - - case ID_AXIS: - tex->param.proc.axis = getU2( fp ); - break; - - case ID_VALU: - tex->param.proc.value[ 0 ] = getF4( fp ); - if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp ); - if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp ); - break; - - case ID_FUNC: - tex->param.proc.name = getS0( fp ); - rlen = get_flen(); - tex->param.proc.data = getbytes( fp, sz - rlen ); - break; - - default: - break; - } - - /* error while reading the current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) return 0; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the procedural block? */ - - if ( rsz <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) return 0; - } - - set_flen( _pico_memstream_tell( fp ) - pos ); - return 1; -} - - -/* -====================================================================== -lwGetGradient() - -Read an lwGradient from a SURF.BLOK in an LWO2 file. -====================================================================== */ - -int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ) -{ - unsigned int id; - unsigned short sz; - int rlen, pos, i, j, nkeys; - - pos = _pico_memstream_tell( fp ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) return 0; - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_TMAP: - if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; - break; - - case ID_PNAM: - tex->param.grad.paramname = getS0( fp ); - break; - - case ID_INAM: - tex->param.grad.itemname = getS0( fp ); - break; - - case ID_GRST: - tex->param.grad.start = getF4( fp ); - break; - - case ID_GREN: - tex->param.grad.end = getF4( fp ); - break; - - case ID_GRPT: - tex->param.grad.repeat = getU2( fp ); - break; - - case ID_FKEY: - nkeys = sz / sizeof( lwGradKey ); - tex->param.grad.key = _pico_calloc( nkeys, sizeof( lwGradKey )); - if ( !tex->param.grad.key ) return 0; - for ( i = 0; i < nkeys; i++ ) { - tex->param.grad.key[ i ].value = getF4( fp ); - for ( j = 0; j < 4; j++ ) - tex->param.grad.key[ i ].rgba[ j ] = getF4( fp ); - } - break; - - case ID_IKEY: - nkeys = sz / 2; - tex->param.grad.ikey = _pico_calloc( nkeys, sizeof( short )); - if ( !tex->param.grad.ikey ) return 0; - for ( i = 0; i < nkeys; i++ ) - tex->param.grad.ikey[ i ] = getU2( fp ); - break; - - default: - break; - } - - /* error while reading the current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) return 0; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the gradient? */ - - if ( rsz <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) return 0; - } - - set_flen( _pico_memstream_tell( fp ) - pos ); - return 1; -} - - -/* -====================================================================== -lwGetTexture() - -Read an lwTexture from a SURF.BLOK in an LWO2 file. -====================================================================== */ - -lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ) -{ - lwTexture *tex; - unsigned short sz; - int ok; - - tex = _pico_calloc( 1, sizeof( lwTexture )); - if ( !tex ) return NULL; - - tex->type = type; - tex->tmap.size.val[ 0 ] = - tex->tmap.size.val[ 1 ] = - tex->tmap.size.val[ 2 ] = 1.0f; - tex->opacity.val = 1.0f; - tex->enabled = 1; - - sz = getU2( fp ); - if ( !lwGetTHeader( fp, sz, tex )) { - _pico_free( tex ); - return NULL; - } - - sz = bloksz - sz - 6; - switch ( type ) { - case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break; - case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break; - case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break; - default: - ok = !_pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); - } - - if ( !ok ) { - lwFreeTexture( tex ); - return NULL; - } - - set_flen( bloksz ); - return tex; -} - - -/* -====================================================================== -lwGetShader() - -Read a shader record from a SURF.BLOK in an LWO2 file. -====================================================================== */ - -lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ) -{ - lwPlugin *shdr; - unsigned int id; - unsigned short sz; - int hsz, rlen, pos; - - shdr = _pico_calloc( 1, sizeof( lwPlugin )); - if ( !shdr ) return NULL; - - pos = _pico_memstream_tell( fp ); - set_flen( 0 ); - hsz = getU2( fp ); - shdr->ord = getS0( fp ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) goto Fail; - - while ( hsz > 0 ) { - sz += sz & 1; - hsz -= sz; - if ( id == ID_ENAB ) { - shdr->flags = getU2( fp ); - break; - } - else { - _pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); - id = getU4( fp ); - sz = getU2( fp ); - } - } - - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) goto Fail; - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_FUNC: - shdr->name = getS0( fp ); - rlen = get_flen(); - shdr->data = getbytes( fp, sz - rlen ); - break; - - default: - break; - } - - /* error while reading the current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) goto Fail; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the shader block? */ - - if ( bloksz <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) goto Fail; - } - - set_flen( _pico_memstream_tell( fp ) - pos ); - return shdr; - -Fail: - lwFreePlugin( shdr ); - return NULL; -} - - -/* -====================================================================== -compare_textures() -compare_shaders() - -Callbacks for the lwListInsert() function, which is called to add -textures to surface channels and shaders to surfaces. -====================================================================== */ - -static int compare_textures( lwTexture *a, lwTexture *b ) -{ - return strcmp( a->ord, b->ord ); -} - - -static int compare_shaders( lwPlugin *a, lwPlugin *b ) -{ - return strcmp( a->ord, b->ord ); -} - - -/* -====================================================================== -add_texture() - -Finds the surface channel (lwTParam or lwCParam) to which a texture is -applied, then calls lwListInsert(). -====================================================================== */ - -static int add_texture( lwSurface *surf, lwTexture *tex ) -{ - lwTexture **list; - - switch ( tex->chan ) { - case ID_COLR: list = &surf->color.tex; break; - case ID_LUMI: list = &surf->luminosity.tex; break; - case ID_DIFF: list = &surf->diffuse.tex; break; - case ID_SPEC: list = &surf->specularity.tex; break; - case ID_GLOS: list = &surf->glossiness.tex; break; - case ID_REFL: list = &surf->reflection.val.tex; break; - case ID_TRAN: list = &surf->transparency.val.tex; break; - case ID_RIND: list = &surf->eta.tex; break; - case ID_TRNL: list = &surf->translucency.tex; break; - case ID_BUMP: list = &surf->bump.tex; break; - default: return 0; - } - - lwListInsert( list, tex, compare_textures ); - return 1; -} - - -/* -====================================================================== -lwDefaultSurface() - -Allocate and initialize a surface. -====================================================================== */ - -lwSurface *lwDefaultSurface( void ) -{ - lwSurface *surf; - - surf = _pico_calloc( 1, sizeof( lwSurface )); - if ( !surf ) return NULL; - - surf->color.rgb[ 0 ] = 0.78431f; - surf->color.rgb[ 1 ] = 0.78431f; - surf->color.rgb[ 2 ] = 0.78431f; - surf->diffuse.val = 1.0f; - surf->glossiness.val = 0.4f; - surf->bump.val = 1.0f; - surf->eta.val = 1.0f; - surf->sideflags = 1; - - return surf; -} - - -/* -====================================================================== -lwGetSurface() - -Read an lwSurface from an LWO2 file. -====================================================================== */ - -lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ) -{ - lwSurface *surf; - lwTexture *tex; - lwPlugin *shdr; - unsigned int id, type; - unsigned short sz; - int pos, rlen; - - - /* allocate the Surface structure */ - - surf = _pico_calloc( 1, sizeof( lwSurface )); - if ( !surf ) goto Fail; - - /* non-zero defaults */ - - surf->color.rgb[ 0 ] = 0.78431f; - surf->color.rgb[ 1 ] = 0.78431f; - surf->color.rgb[ 2 ] = 0.78431f; - surf->diffuse.val = 1.0f; - surf->glossiness.val = 0.4f; - surf->bump.val = 1.0f; - surf->eta.val = 1.0f; - surf->sideflags = 1; - - /* remember where we started */ - - set_flen( 0 ); - pos = _pico_memstream_tell( fp ); - - /* names */ - - surf->name = getS0( fp ); - surf->srcname = getS0( fp ); - - /* first subchunk header */ - - id = getU4( fp ); - sz = getU2( fp ); - if ( 0 > get_flen() ) goto Fail; - - /* process subchunks as they're encountered */ - - while ( 1 ) { - sz += sz & 1; - set_flen( 0 ); - - switch ( id ) { - case ID_COLR: - surf->color.rgb[ 0 ] = getF4( fp ); - surf->color.rgb[ 1 ] = getF4( fp ); - surf->color.rgb[ 2 ] = getF4( fp ); - surf->color.eindex = getVX( fp ); - break; - - case ID_LUMI: - surf->luminosity.val = getF4( fp ); - surf->luminosity.eindex = getVX( fp ); - break; - - case ID_DIFF: - surf->diffuse.val = getF4( fp ); - surf->diffuse.eindex = getVX( fp ); - break; - - case ID_SPEC: - surf->specularity.val = getF4( fp ); - surf->specularity.eindex = getVX( fp ); - break; - - case ID_GLOS: - surf->glossiness.val = getF4( fp ); - surf->glossiness.eindex = getVX( fp ); - break; - - case ID_REFL: - surf->reflection.val.val = getF4( fp ); - surf->reflection.val.eindex = getVX( fp ); - break; - - case ID_RFOP: - surf->reflection.options = getU2( fp ); - break; - - case ID_RIMG: - surf->reflection.cindex = getVX( fp ); - break; - - case ID_RSAN: - surf->reflection.seam_angle = getF4( fp ); - break; - - case ID_TRAN: - surf->transparency.val.val = getF4( fp ); - surf->transparency.val.eindex = getVX( fp ); - break; - - case ID_TROP: - surf->transparency.options = getU2( fp ); - break; - - case ID_TIMG: - surf->transparency.cindex = getVX( fp ); - break; - - case ID_RIND: - surf->eta.val = getF4( fp ); - surf->eta.eindex = getVX( fp ); - break; - - case ID_TRNL: - surf->translucency.val = getF4( fp ); - surf->translucency.eindex = getVX( fp ); - break; - - case ID_BUMP: - surf->bump.val = getF4( fp ); - surf->bump.eindex = getVX( fp ); - break; - - case ID_SMAN: - surf->smooth = getF4( fp ); - break; - - case ID_SIDE: - surf->sideflags = getU2( fp ); - break; - - case ID_CLRH: - surf->color_hilite.val = getF4( fp ); - surf->color_hilite.eindex = getVX( fp ); - break; - - case ID_CLRF: - surf->color_filter.val = getF4( fp ); - surf->color_filter.eindex = getVX( fp ); - break; - - case ID_ADTR: - surf->add_trans.val = getF4( fp ); - surf->add_trans.eindex = getVX( fp ); - break; - - case ID_SHRP: - surf->dif_sharp.val = getF4( fp ); - surf->dif_sharp.eindex = getVX( fp ); - break; - - case ID_GVAL: - surf->glow.val = getF4( fp ); - surf->glow.eindex = getVX( fp ); - break; - - case ID_LINE: - surf->line.enabled = 1; - if ( sz >= 2 ) surf->line.flags = getU2( fp ); - if ( sz >= 6 ) surf->line.size.val = getF4( fp ); - if ( sz >= 8 ) surf->line.size.eindex = getVX( fp ); - break; - - case ID_ALPH: - surf->alpha_mode = getU2( fp ); - surf->alpha = getF4( fp ); - break; - - case ID_AVAL: - surf->alpha = getF4( fp ); - break; - - case ID_BLOK: - type = getU4( fp ); - - switch ( type ) { - case ID_IMAP: - case ID_PROC: - case ID_GRAD: - tex = lwGetTexture( fp, sz - 4, type ); - if ( !tex ) goto Fail; - if ( !add_texture( surf, tex )) - lwFreeTexture( tex ); - set_flen( 4 + get_flen() ); - break; - case ID_SHDR: - shdr = lwGetShader( fp, sz - 4 ); - if ( !shdr ) goto Fail; - lwListInsert( &surf->shader, shdr, compare_shaders ); - ++surf->nshaders; - set_flen( 4 + get_flen() ); - break; - } - break; - - default: - break; - } - - /* error while reading current subchunk? */ - - rlen = get_flen(); - if ( rlen < 0 || rlen > sz ) goto Fail; - - /* skip unread parts of the current subchunk */ - - if ( rlen < sz ) - _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); - - /* end of the SURF chunk? */ - - if ( cksize <= _pico_memstream_tell( fp ) - pos ) - break; - - /* get the next subchunk header */ - - set_flen( 0 ); - id = getU4( fp ); - sz = getU2( fp ); - if ( 6 != get_flen() ) goto Fail; - } - - return surf; - -Fail: - if ( surf ) lwFreeSurface( surf ); - return NULL; -} +/* +====================================================================== +surface.c + +Surface functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreePlugin() + +Free the memory used by an lwPlugin. +====================================================================== */ + +void lwFreePlugin( lwPlugin *p ) +{ + if ( p ) { + if ( p->ord ) _pico_free( p->ord ); + if ( p->name ) _pico_free( p->name ); + if ( p->data ) _pico_free( p->data ); + _pico_free( p ); + } +} + + +/* +====================================================================== +lwFreeTexture() + +Free the memory used by an lwTexture. +====================================================================== */ + +void lwFreeTexture( lwTexture *t ) +{ + if ( t ) { + if ( t->ord ) _pico_free( t->ord ); + switch ( t->type ) { + case ID_IMAP: + if ( t->param.imap.vmap_name ) _pico_free( t->param.imap.vmap_name ); + break; + case ID_PROC: + if ( t->param.proc.name ) _pico_free( t->param.proc.name ); + if ( t->param.proc.data ) _pico_free( t->param.proc.data ); + break; + case ID_GRAD: + if ( t->param.grad.key ) _pico_free( t->param.grad.key ); + if ( t->param.grad.ikey ) _pico_free( t->param.grad.ikey ); + break; + } + _pico_free( t ); + } +} + + +/* +====================================================================== +lwFreeSurface() + +Free the memory used by an lwSurface. +====================================================================== */ + +void lwFreeSurface( lwSurface *surf ) +{ + if ( surf ) { + if ( surf->name ) _pico_free( surf->name ); + if ( surf->srcname ) _pico_free( surf->srcname ); + + lwListFree( surf->shader, lwFreePlugin ); + + lwListFree( surf->color.tex, lwFreeTexture ); + lwListFree( surf->luminosity.tex, lwFreeTexture ); + lwListFree( surf->diffuse.tex, lwFreeTexture ); + lwListFree( surf->specularity.tex, lwFreeTexture ); + lwListFree( surf->glossiness.tex, lwFreeTexture ); + lwListFree( surf->reflection.val.tex, lwFreeTexture ); + lwListFree( surf->transparency.val.tex, lwFreeTexture ); + lwListFree( surf->eta.tex, lwFreeTexture ); + lwListFree( surf->translucency.tex, lwFreeTexture ); + lwListFree( surf->bump.tex, lwFreeTexture ); + + _pico_free( surf ); + } +} + + +/* +====================================================================== +lwGetTHeader() + +Read a texture map header from a SURF.BLOK in an LWO2 file. This is +the first subchunk in a BLOK, and its contents are common to all three +texture types. +====================================================================== */ + +int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int pos, rlen; + + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* ordinal string */ + + tex->ord = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_CHAN: + tex->chan = getU4( fp ); + break; + + case ID_OPAC: + tex->opac_type = getU2( fp ); + tex->opacity.val = getF4( fp ); + tex->opacity.eindex = getVX( fp ); + break; + + case ID_ENAB: + tex->enabled = getU2( fp ); + break; + + case ID_NEGA: + tex->negative = getU2( fp ); + break; + + case ID_AXIS: + tex->axis = getU2( fp ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the texture header subchunk? */ + + if ( hsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetTMap() + +Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP +defines the mapping from texture to world or object coordinates. +====================================================================== */ + +int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos, i; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_SIZE: + for ( i = 0; i < 3; i++ ) + tmap->size.val[ i ] = getF4( fp ); + tmap->size.eindex = getVX( fp ); + break; + + case ID_CNTR: + for ( i = 0; i < 3; i++ ) + tmap->center.val[ i ] = getF4( fp ); + tmap->center.eindex = getVX( fp ); + break; + + case ID_ROTA: + for ( i = 0; i < 3; i++ ) + tmap->rotate.val[ i ] = getF4( fp ); + tmap->rotate.eindex = getVX( fp ); + break; + + case ID_FALL: + tmap->fall_type = getU2( fp ); + for ( i = 0; i < 3; i++ ) + tmap->falloff.val[ i ] = getF4( fp ); + tmap->falloff.eindex = getVX( fp ); + break; + + case ID_OREF: + tmap->ref_object = getS0( fp ); + break; + + case ID_CSYS: + tmap->coord_sys = getU2( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the TMAP subchunk? */ + + if ( tmapsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetImageMap() + +Read an lwImageMap from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_PROJ: + tex->param.imap.projection = getU2( fp ); + break; + + case ID_VMAP: + tex->param.imap.vmap_name = getS0( fp ); + break; + + case ID_AXIS: + tex->param.imap.axis = getU2( fp ); + break; + + case ID_IMAG: + tex->param.imap.cindex = getVX( fp ); + break; + + case ID_WRAP: + tex->param.imap.wrapw_type = getU2( fp ); + tex->param.imap.wraph_type = getU2( fp ); + break; + + case ID_WRPW: + tex->param.imap.wrapw.val = getF4( fp ); + tex->param.imap.wrapw.eindex = getVX( fp ); + break; + + case ID_WRPH: + tex->param.imap.wraph.val = getF4( fp ); + tex->param.imap.wraph.eindex = getVX( fp ); + break; + + case ID_AAST: + tex->param.imap.aas_flags = getU2( fp ); + tex->param.imap.aa_strength = getF4( fp ); + break; + + case ID_PIXB: + tex->param.imap.pblend = getU2( fp ); + break; + + case ID_STCK: + tex->param.imap.stck.val = getF4( fp ); + tex->param.imap.stck.eindex = getVX( fp ); + break; + + case ID_TAMP: + tex->param.imap.amplitude.val = getF4( fp ); + tex->param.imap.amplitude.eindex = getVX( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the image map? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetProcedural() + +Read an lwProcedural from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_AXIS: + tex->param.proc.axis = getU2( fp ); + break; + + case ID_VALU: + tex->param.proc.value[ 0 ] = getF4( fp ); + if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp ); + if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp ); + break; + + case ID_FUNC: + tex->param.proc.name = getS0( fp ); + rlen = get_flen(); + tex->param.proc.data = getbytes( fp, sz - rlen ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the procedural block? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetGradient() + +Read an lwGradient from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos, i, j, nkeys; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_PNAM: + tex->param.grad.paramname = getS0( fp ); + break; + + case ID_INAM: + tex->param.grad.itemname = getS0( fp ); + break; + + case ID_GRST: + tex->param.grad.start = getF4( fp ); + break; + + case ID_GREN: + tex->param.grad.end = getF4( fp ); + break; + + case ID_GRPT: + tex->param.grad.repeat = getU2( fp ); + break; + + case ID_FKEY: + nkeys = sz / sizeof( lwGradKey ); + tex->param.grad.key = _pico_calloc( nkeys, sizeof( lwGradKey )); + if ( !tex->param.grad.key ) return 0; + for ( i = 0; i < nkeys; i++ ) { + tex->param.grad.key[ i ].value = getF4( fp ); + for ( j = 0; j < 4; j++ ) + tex->param.grad.key[ i ].rgba[ j ] = getF4( fp ); + } + break; + + case ID_IKEY: + nkeys = sz / 2; + tex->param.grad.ikey = _pico_calloc( nkeys, sizeof( short )); + if ( !tex->param.grad.ikey ) return 0; + for ( i = 0; i < nkeys; i++ ) + tex->param.grad.ikey[ i ] = getU2( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the gradient? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetTexture() + +Read an lwTexture from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ) +{ + lwTexture *tex; + unsigned short sz; + int ok; + + tex = _pico_calloc( 1, sizeof( lwTexture )); + if ( !tex ) return NULL; + + tex->type = type; + tex->tmap.size.val[ 0 ] = + tex->tmap.size.val[ 1 ] = + tex->tmap.size.val[ 2 ] = 1.0f; + tex->opacity.val = 1.0f; + tex->enabled = 1; + + sz = getU2( fp ); + if ( !lwGetTHeader( fp, sz, tex )) { + _pico_free( tex ); + return NULL; + } + + sz = bloksz - sz - 6; + switch ( type ) { + case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break; + case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break; + case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break; + default: + ok = !_pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); + } + + if ( !ok ) { + lwFreeTexture( tex ); + return NULL; + } + + set_flen( bloksz ); + return tex; +} + + +/* +====================================================================== +lwGetShader() + +Read a shader record from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ) +{ + lwPlugin *shdr; + unsigned int id; + unsigned short sz; + int hsz, rlen, pos; + + shdr = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !shdr ) return NULL; + + pos = _pico_memstream_tell( fp ); + set_flen( 0 ); + hsz = getU2( fp ); + shdr->ord = getS0( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( hsz > 0 ) { + sz += sz & 1; + hsz -= sz; + if ( id == ID_ENAB ) { + shdr->flags = getU2( fp ); + break; + } + else { + _pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); + id = getU4( fp ); + sz = getU2( fp ); + } + } + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_FUNC: + shdr->name = getS0( fp ); + rlen = get_flen(); + shdr->data = getbytes( fp, sz - rlen ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the shader block? */ + + if ( bloksz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return shdr; + +Fail: + lwFreePlugin( shdr ); + return NULL; +} + + +/* +====================================================================== +compare_textures() +compare_shaders() + +Callbacks for the lwListInsert() function, which is called to add +textures to surface channels and shaders to surfaces. +====================================================================== */ + +static int compare_textures( lwTexture *a, lwTexture *b ) +{ + return strcmp( a->ord, b->ord ); +} + + +static int compare_shaders( lwPlugin *a, lwPlugin *b ) +{ + return strcmp( a->ord, b->ord ); +} + + +/* +====================================================================== +add_texture() + +Finds the surface channel (lwTParam or lwCParam) to which a texture is +applied, then calls lwListInsert(). +====================================================================== */ + +static int add_texture( lwSurface *surf, lwTexture *tex ) +{ + lwTexture **list; + + switch ( tex->chan ) { + case ID_COLR: list = &surf->color.tex; break; + case ID_LUMI: list = &surf->luminosity.tex; break; + case ID_DIFF: list = &surf->diffuse.tex; break; + case ID_SPEC: list = &surf->specularity.tex; break; + case ID_GLOS: list = &surf->glossiness.tex; break; + case ID_REFL: list = &surf->reflection.val.tex; break; + case ID_TRAN: list = &surf->transparency.val.tex; break; + case ID_RIND: list = &surf->eta.tex; break; + case ID_TRNL: list = &surf->translucency.tex; break; + case ID_BUMP: list = &surf->bump.tex; break; + default: return 0; + } + + lwListInsert( list, tex, compare_textures ); + return 1; +} + + +/* +====================================================================== +lwDefaultSurface() + +Allocate and initialize a surface. +====================================================================== */ + +lwSurface *lwDefaultSurface( void ) +{ + lwSurface *surf; + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) return NULL; + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + return surf; +} + + +/* +====================================================================== +lwGetSurface() + +Read an lwSurface from an LWO2 file. +====================================================================== */ + +lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ) +{ + lwSurface *surf; + lwTexture *tex; + lwPlugin *shdr; + unsigned int id, type; + unsigned short sz; + int pos, rlen; + + + /* allocate the Surface structure */ + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) goto Fail; + + /* non-zero defaults */ + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* names */ + + surf->name = getS0( fp ); + surf->srcname = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_COLR: + surf->color.rgb[ 0 ] = getF4( fp ); + surf->color.rgb[ 1 ] = getF4( fp ); + surf->color.rgb[ 2 ] = getF4( fp ); + surf->color.eindex = getVX( fp ); + break; + + case ID_LUMI: + surf->luminosity.val = getF4( fp ); + surf->luminosity.eindex = getVX( fp ); + break; + + case ID_DIFF: + surf->diffuse.val = getF4( fp ); + surf->diffuse.eindex = getVX( fp ); + break; + + case ID_SPEC: + surf->specularity.val = getF4( fp ); + surf->specularity.eindex = getVX( fp ); + break; + + case ID_GLOS: + surf->glossiness.val = getF4( fp ); + surf->glossiness.eindex = getVX( fp ); + break; + + case ID_REFL: + surf->reflection.val.val = getF4( fp ); + surf->reflection.val.eindex = getVX( fp ); + break; + + case ID_RFOP: + surf->reflection.options = getU2( fp ); + break; + + case ID_RIMG: + surf->reflection.cindex = getVX( fp ); + break; + + case ID_RSAN: + surf->reflection.seam_angle = getF4( fp ); + break; + + case ID_TRAN: + surf->transparency.val.val = getF4( fp ); + surf->transparency.val.eindex = getVX( fp ); + break; + + case ID_TROP: + surf->transparency.options = getU2( fp ); + break; + + case ID_TIMG: + surf->transparency.cindex = getVX( fp ); + break; + + case ID_RIND: + surf->eta.val = getF4( fp ); + surf->eta.eindex = getVX( fp ); + break; + + case ID_TRNL: + surf->translucency.val = getF4( fp ); + surf->translucency.eindex = getVX( fp ); + break; + + case ID_BUMP: + surf->bump.val = getF4( fp ); + surf->bump.eindex = getVX( fp ); + break; + + case ID_SMAN: + surf->smooth = getF4( fp ); + break; + + case ID_SIDE: + surf->sideflags = getU2( fp ); + break; + + case ID_CLRH: + surf->color_hilite.val = getF4( fp ); + surf->color_hilite.eindex = getVX( fp ); + break; + + case ID_CLRF: + surf->color_filter.val = getF4( fp ); + surf->color_filter.eindex = getVX( fp ); + break; + + case ID_ADTR: + surf->add_trans.val = getF4( fp ); + surf->add_trans.eindex = getVX( fp ); + break; + + case ID_SHRP: + surf->dif_sharp.val = getF4( fp ); + surf->dif_sharp.eindex = getVX( fp ); + break; + + case ID_GVAL: + surf->glow.val = getF4( fp ); + surf->glow.eindex = getVX( fp ); + break; + + case ID_LINE: + surf->line.enabled = 1; + if ( sz >= 2 ) surf->line.flags = getU2( fp ); + if ( sz >= 6 ) surf->line.size.val = getF4( fp ); + if ( sz >= 8 ) surf->line.size.eindex = getVX( fp ); + break; + + case ID_ALPH: + surf->alpha_mode = getU2( fp ); + surf->alpha = getF4( fp ); + break; + + case ID_AVAL: + surf->alpha = getF4( fp ); + break; + + case ID_BLOK: + type = getU4( fp ); + + switch ( type ) { + case ID_IMAP: + case ID_PROC: + case ID_GRAD: + tex = lwGetTexture( fp, sz - 4, type ); + if ( !tex ) goto Fail; + if ( !add_texture( surf, tex )) + lwFreeTexture( tex ); + set_flen( 4 + get_flen() ); + break; + case ID_SHDR: + shdr = lwGetShader( fp, sz - 4 ); + if ( !shdr ) goto Fail; + lwListInsert( &surf->shader, shdr, compare_shaders ); + ++surf->nshaders; + set_flen( 4 + get_flen() ); + break; + } + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the SURF chunk? */ + + if ( cksize <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return surf; + +Fail: + if ( surf ) lwFreeSurface( surf ); + return NULL; +} diff --git a/libs/picomodel/lwo/vecmath.c b/libs/picomodel/lwo/vecmath.c index 44d317b0..eaa1e8fc 100644 --- a/libs/picomodel/lwo/vecmath.c +++ b/libs/picomodel/lwo/vecmath.c @@ -1,37 +1,37 @@ -/* -====================================================================== -vecmath.c - -Basic vector and matrix functions. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include - - -float dot( float a[], float b[] ) -{ - return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; -} - - -void cross( float a[], float b[], float c[] ) -{ - c[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ]; - c[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ]; - c[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ]; -} - - -void normalize( float v[] ) -{ - float r; - - r = ( float ) sqrt( dot( v, v )); - if ( r > 0 ) { - v[ 0 ] /= r; - v[ 1 ] /= r; - v[ 2 ] /= r; - } -} +/* +====================================================================== +vecmath.c + +Basic vector and matrix functions. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include + + +float dot( float a[], float b[] ) +{ + return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; +} + + +void cross( float a[], float b[], float c[] ) +{ + c[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ]; + c[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ]; + c[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ]; +} + + +void normalize( float v[] ) +{ + float r; + + r = ( float ) sqrt( dot( v, v )); + if ( r > 0 ) { + v[ 0 ] /= r; + v[ 1 ] /= r; + v[ 2 ] /= r; + } +} diff --git a/libs/picomodel/lwo/vmap.c b/libs/picomodel/lwo/vmap.c index 1a24bee0..69f87cf9 100644 --- a/libs/picomodel/lwo/vmap.c +++ b/libs/picomodel/lwo/vmap.c @@ -1,243 +1,243 @@ -/* -====================================================================== -vmap.c - -Vertex map functions for an LWO2 reader. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include "../picointernal.h" -#include "lwo2.h" - - -/* -====================================================================== -lwFreeVMap() - -Free memory used by an lwVMap. -====================================================================== */ - -void lwFreeVMap( lwVMap *vmap ) -{ - if ( vmap ) { - if ( vmap->name ) _pico_free( vmap->name ); - if ( vmap->vindex ) _pico_free( vmap->vindex ); - if ( vmap->pindex ) _pico_free( vmap->pindex ); - if ( vmap->val ) { - if ( vmap->val[ 0 ] ) _pico_free( vmap->val[ 0 ] ); - _pico_free( vmap->val ); - } - _pico_free( vmap ); - } -} - - -/* -====================================================================== -lwGetVMap() - -Read an lwVMap from a VMAP or VMAD chunk in an LWO2. -====================================================================== */ - -lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, - int perpoly ) -{ - unsigned char *buf, *bp; - lwVMap *vmap; - float *f; - int i, j, npts, rlen; - - - /* read the whole chunk */ - - set_flen( 0 ); - buf = getbytes( fp, cksize ); - if ( !buf ) return NULL; - - vmap = _pico_calloc( 1, sizeof( lwVMap )); - if ( !vmap ) { - _pico_free( buf ); - return NULL; - } - - /* initialize the vmap */ - - vmap->perpoly = perpoly; - - bp = buf; - set_flen( 0 ); - vmap->type = sgetU4( &bp ); - vmap->dim = sgetU2( &bp ); - vmap->name = sgetS0( &bp ); - rlen = get_flen(); - - /* count the vmap records */ - - npts = 0; - while ( bp < buf + cksize ) { - i = sgetVX( &bp ); - if ( perpoly ) - i = sgetVX( &bp ); - bp += vmap->dim * sizeof( float ); - ++npts; - } - - /* allocate the vmap */ - - vmap->nverts = npts; - vmap->vindex = _pico_calloc( npts, sizeof( int )); - if ( !vmap->vindex ) goto Fail; - if ( perpoly ) { - vmap->pindex = _pico_calloc( npts, sizeof( int )); - if ( !vmap->pindex ) goto Fail; - } - - if ( vmap->dim > 0 ) { - vmap->val = _pico_calloc( npts, sizeof( float * )); - if ( !vmap->val ) goto Fail; - f = _pico_alloc( npts * vmap->dim * sizeof( float )); - if ( !f ) goto Fail; - for ( i = 0; i < npts; i++ ) - vmap->val[ i ] = f + i * vmap->dim; - } - - /* fill in the vmap values */ - - bp = buf + rlen; - for ( i = 0; i < npts; i++ ) { - vmap->vindex[ i ] = sgetVX( &bp ); - if ( perpoly ) - vmap->pindex[ i ] = sgetVX( &bp ); - for ( j = 0; j < vmap->dim; j++ ) - vmap->val[ i ][ j ] = sgetF4( &bp ); - } - - _pico_free( buf ); - return vmap; - -Fail: - if ( buf ) _pico_free( buf ); - lwFreeVMap( vmap ); - return NULL; -} - - -/* -====================================================================== -lwGetPointVMaps() - -Fill in the lwVMapPt structure for each point. -====================================================================== */ - -int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ) -{ - lwVMap *vm; - int i, j, n; - - /* count the number of vmap values for each point */ - - vm = vmap; - while ( vm ) { - if ( !vm->perpoly ) - for ( i = 0; i < vm->nverts; i++ ) - ++point->pt[ vm->vindex[ i ]].nvmaps; - vm = vm->next; - } - - /* allocate vmap references for each mapped point */ - - for ( i = 0; i < point->count; i++ ) { - if ( point->pt[ i ].nvmaps ) { - point->pt[ i ].vm = _pico_calloc( point->pt[ i ].nvmaps, sizeof( lwVMapPt )); - if ( !point->pt[ i ].vm ) return 0; - point->pt[ i ].nvmaps = 0; - } - } - - /* fill in vmap references for each mapped point */ - - vm = vmap; - while ( vm ) { - if ( !vm->perpoly ) { - for ( i = 0; i < vm->nverts; i++ ) { - j = vm->vindex[ i ]; - n = point->pt[ j ].nvmaps; - point->pt[ j ].vm[ n ].vmap = vm; - point->pt[ j ].vm[ n ].index = i; - ++point->pt[ j ].nvmaps; - } - } - vm = vm->next; - } - - return 1; -} - - -/* -====================================================================== -lwGetPolyVMaps() - -Fill in the lwVMapPt structure for each polygon vertex. -====================================================================== */ - -int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ) -{ - lwVMap *vm; - lwPolVert *pv; - int i, j; - - /* count the number of vmap values for each polygon vertex */ - - vm = vmap; - while ( vm ) { - if ( vm->perpoly ) { - for ( i = 0; i < vm->nverts; i++ ) { - for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { - pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; - if ( vm->vindex[ i ] == pv->index ) { - ++pv->nvmaps; - break; - } - } - } - } - vm = vm->next; - } - - /* allocate vmap references for each mapped vertex */ - - for ( i = 0; i < polygon->count; i++ ) { - for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { - pv = &polygon->pol[ i ].v[ j ]; - if ( pv->nvmaps ) { - pv->vm = _pico_calloc( pv->nvmaps, sizeof( lwVMapPt )); - if ( !pv->vm ) return 0; - pv->nvmaps = 0; - } - } - } - - /* fill in vmap references for each mapped point */ - - vm = vmap; - while ( vm ) { - if ( vm->perpoly ) { - for ( i = 0; i < vm->nverts; i++ ) { - for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { - pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; - if ( vm->vindex[ i ] == pv->index ) { - pv->vm[ pv->nvmaps ].vmap = vm; - pv->vm[ pv->nvmaps ].index = i; - ++pv->nvmaps; - break; - } - } - } - } - vm = vm->next; - } - - return 1; -} +/* +====================================================================== +vmap.c + +Vertex map functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreeVMap() + +Free memory used by an lwVMap. +====================================================================== */ + +void lwFreeVMap( lwVMap *vmap ) +{ + if ( vmap ) { + if ( vmap->name ) _pico_free( vmap->name ); + if ( vmap->vindex ) _pico_free( vmap->vindex ); + if ( vmap->pindex ) _pico_free( vmap->pindex ); + if ( vmap->val ) { + if ( vmap->val[ 0 ] ) _pico_free( vmap->val[ 0 ] ); + _pico_free( vmap->val ); + } + _pico_free( vmap ); + } +} + + +/* +====================================================================== +lwGetVMap() + +Read an lwVMap from a VMAP or VMAD chunk in an LWO2. +====================================================================== */ + +lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, + int perpoly ) +{ + unsigned char *buf, *bp; + lwVMap *vmap; + float *f; + int i, j, npts, rlen; + + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) return NULL; + + vmap = _pico_calloc( 1, sizeof( lwVMap )); + if ( !vmap ) { + _pico_free( buf ); + return NULL; + } + + /* initialize the vmap */ + + vmap->perpoly = perpoly; + + bp = buf; + set_flen( 0 ); + vmap->type = sgetU4( &bp ); + vmap->dim = sgetU2( &bp ); + vmap->name = sgetS0( &bp ); + rlen = get_flen(); + + /* count the vmap records */ + + npts = 0; + while ( bp < buf + cksize ) { + i = sgetVX( &bp ); + if ( perpoly ) + i = sgetVX( &bp ); + bp += vmap->dim * sizeof( float ); + ++npts; + } + + /* allocate the vmap */ + + vmap->nverts = npts; + vmap->vindex = _pico_calloc( npts, sizeof( int )); + if ( !vmap->vindex ) goto Fail; + if ( perpoly ) { + vmap->pindex = _pico_calloc( npts, sizeof( int )); + if ( !vmap->pindex ) goto Fail; + } + + if ( vmap->dim > 0 ) { + vmap->val = _pico_calloc( npts, sizeof( float * )); + if ( !vmap->val ) goto Fail; + f = _pico_alloc( npts * vmap->dim * sizeof( float )); + if ( !f ) goto Fail; + for ( i = 0; i < npts; i++ ) + vmap->val[ i ] = f + i * vmap->dim; + } + + /* fill in the vmap values */ + + bp = buf + rlen; + for ( i = 0; i < npts; i++ ) { + vmap->vindex[ i ] = sgetVX( &bp ); + if ( perpoly ) + vmap->pindex[ i ] = sgetVX( &bp ); + for ( j = 0; j < vmap->dim; j++ ) + vmap->val[ i ][ j ] = sgetF4( &bp ); + } + + _pico_free( buf ); + return vmap; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreeVMap( vmap ); + return NULL; +} + + +/* +====================================================================== +lwGetPointVMaps() + +Fill in the lwVMapPt structure for each point. +====================================================================== */ + +int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ) +{ + lwVMap *vm; + int i, j, n; + + /* count the number of vmap values for each point */ + + vm = vmap; + while ( vm ) { + if ( !vm->perpoly ) + for ( i = 0; i < vm->nverts; i++ ) + ++point->pt[ vm->vindex[ i ]].nvmaps; + vm = vm->next; + } + + /* allocate vmap references for each mapped point */ + + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].nvmaps ) { + point->pt[ i ].vm = _pico_calloc( point->pt[ i ].nvmaps, sizeof( lwVMapPt )); + if ( !point->pt[ i ].vm ) return 0; + point->pt[ i ].nvmaps = 0; + } + } + + /* fill in vmap references for each mapped point */ + + vm = vmap; + while ( vm ) { + if ( !vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + j = vm->vindex[ i ]; + n = point->pt[ j ].nvmaps; + point->pt[ j ].vm[ n ].vmap = vm; + point->pt[ j ].vm[ n ].index = i; + ++point->pt[ j ].nvmaps; + } + } + vm = vm->next; + } + + return 1; +} + + +/* +====================================================================== +lwGetPolyVMaps() + +Fill in the lwVMapPt structure for each polygon vertex. +====================================================================== */ + +int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ) +{ + lwVMap *vm; + lwPolVert *pv; + int i, j; + + /* count the number of vmap values for each polygon vertex */ + + vm = vmap; + while ( vm ) { + if ( vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { + pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; + if ( vm->vindex[ i ] == pv->index ) { + ++pv->nvmaps; + break; + } + } + } + } + vm = vm->next; + } + + /* allocate vmap references for each mapped vertex */ + + for ( i = 0; i < polygon->count; i++ ) { + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { + pv = &polygon->pol[ i ].v[ j ]; + if ( pv->nvmaps ) { + pv->vm = _pico_calloc( pv->nvmaps, sizeof( lwVMapPt )); + if ( !pv->vm ) return 0; + pv->nvmaps = 0; + } + } + } + + /* fill in vmap references for each mapped point */ + + vm = vmap; + while ( vm ) { + if ( vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { + pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; + if ( vm->vindex[ i ] == pv->index ) { + pv->vm[ pv->nvmaps ].vmap = vm; + pv->vm[ pv->nvmaps ].index = i; + ++pv->nvmaps; + break; + } + } + } + } + vm = vm->next; + } + + return 1; +} diff --git a/libs/picomodel/picointernal.c b/libs/picomodel/picointernal.c index 6afae90a..3e32dd08 100644 --- a/libs/picomodel/picointernal.c +++ b/libs/picomodel/picointernal.c @@ -1,1353 +1,1353 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define PICOINTERNAL_C - - - -/* todo: - * - fix p->curLine for parser routines. increased twice - */ - -/* dependencies */ -#include -#include "picointernal.h" - - - -/* function pointers */ -void *(*_pico_ptr_malloc )( size_t ) = malloc; -void (*_pico_ptr_free )( void* ) = free; -void (*_pico_ptr_load_file )( char*, unsigned char**, int* ) = NULL; -void (*_pico_ptr_free_file )( void* ) = NULL; -void (*_pico_ptr_print )( int, const char* ) = NULL; - -typedef union -{ - float f; - char c[4]; -} -floatSwapUnion; - -/* _pico_alloc: - * kludged memory allocation wrapper - */ -void *_pico_alloc( size_t size ) -{ - void *ptr; - - /* some sanity checks */ - if( size == 0 ) - return NULL; - if (_pico_ptr_malloc == NULL) - return NULL; - - /* allocate memory */ - ptr = _pico_ptr_malloc(size); - if (ptr == NULL) - return NULL; - - /* zero out allocated memory */ - memset(ptr,0,size); - - /* return pointer to allocated memory */ - return ptr; -} - -/* _pico_calloc: - * _pico_calloc wrapper - */ -void *_pico_calloc( size_t num, size_t size ) -{ - void *ptr; - - /* some sanity checks */ - if( num == 0 || size == 0 ) - return NULL; - if (_pico_ptr_malloc == NULL) - return NULL; - - /* allocate memory */ - ptr = _pico_ptr_malloc(num*size); - if (ptr == NULL) - return NULL; - - /* zero out allocated memory */ - memset(ptr,0,num*size); - - /* return pointer to allocated memory */ - return ptr; -} - -/* _pico_realloc: - * memory reallocation wrapper (note: only grows, - * but never shrinks or frees) - */ -void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ) -{ - void *ptr2; - - /* sanity checks */ - if( ptr == NULL ) - return NULL; - if( newSize < oldSize ) - return *ptr; - if (_pico_ptr_malloc == NULL) - return NULL; - - /* allocate new pointer */ - ptr2 = _pico_alloc( newSize ); - if( ptr2 == NULL ) - return NULL; - - /* copy */ - if( *ptr != NULL ) - { - memcpy( ptr2, *ptr, oldSize ); - _pico_free( *ptr ); - } - - /* fix up and return */ - *ptr = ptr2; - return *ptr; -} - -/* _pico_clone_alloc: - * handy function for quick string allocation/copy. it clones - * the given string and returns a pointer to the new allocated - * clone (which must be freed by caller of course) or returns - * NULL on memory alloc or param errors. if 'size' is -1 the - * length of the input string is used, otherwise 'size' is used - * as custom clone size (the string is cropped to fit into mem - * if needed). -sea - */ -char *_pico_clone_alloc( char *str, int size ) -{ - char *cloned; - size_t cloneSize; - - /* sanity check */ - if (str == NULL) return NULL; - - /* set real size of cloned string */ - cloneSize = (size < 0) ? strlen(str) : size; - - /* allocate memory */ - cloned = _pico_alloc( cloneSize+1 ); /* bugfix! */ - if (cloned == NULL) - return NULL; - - /* zero out memory allocated by cloned string */ - memset( cloned,0,cloneSize ); - - /* copy input string to cloned string */ - if (cloneSize < strlen( str )) { - memcpy( cloned,str,cloneSize ); - cloned[ cloneSize ] = '\0'; - } else { - strcpy( cloned,str ); - } - /* return ptr to cloned string */ - return cloned; -} - -/* _pico_free: - * wrapper around the free function pointer - */ -void _pico_free( void *ptr ) -{ - /* sanity checks */ - if( ptr == NULL ) - return; - if (_pico_ptr_free == NULL) - return; - - /* free the allocated memory */ - _pico_ptr_free( ptr ); -} - -/* _pico_load_file: - * wrapper around the loadfile function pointer - */ -void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ) -{ - /* sanity checks */ - if( name == NULL ) - { - *bufSize = -1; - return; - } - if (_pico_ptr_load_file == NULL) - { - *bufSize = -1; - return; - } - /* do the actual call to read in the file; */ - /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */ - _pico_ptr_load_file( name,buffer,bufSize ); -} - -/* _pico_free_file: - * wrapper around the file free function pointer - */ -void _pico_free_file( void *buffer ) -{ - /* sanity checks */ - if( buffer == NULL ) - return; - - /* use default free */ - if( _pico_ptr_free_file == NULL ) - { - free( buffer ); - return; - } - /* free the allocated file */ - _pico_ptr_free_file( buffer ); -} - -/* _pico_printf: - * wrapper around the print function pointer -sea - */ -void _pico_printf( int level, const char *format, ...) -{ - char str[4096]; - va_list argptr; - - /* sanity checks */ - if( format == NULL ) - return; - if (_pico_ptr_print == NULL) - return; - - /* format string */ - va_start( argptr,format ); - vsprintf( str,format,argptr ); - va_end( argptr ); - - /* remove linefeeds */ - if (str[ strlen(str)-1 ] == '\n') - str[ strlen(str)-1 ] = '\0'; - - /* do the actual call */ - _pico_ptr_print( level,str ); -} - -/* _pico_strltrim: - * left trims the given string -sea - */ -char *_pico_strltrim( char *str ) -{ - char *str1 = str, *str2 = str; - - while (isspace(*str2)) str2++; - if( str2 != str ) - while( *str2 != '\0' ) /* fix: ydnar */ - *str1++ = *str2++; - return str; -} - -/* _pico_strrtrim: - * right trims the given string -sea - */ -char *_pico_strrtrim( char *str ) -{ - if (str && *str) - { - char *str1 = str; - int allspace = 1; - - while (*str1) - { - if (allspace && !isspace(*str1)) allspace = 0; - str1++; - } - if (allspace) *str = '\0'; - else { - str1--; - while ((isspace(*str1)) && (str1 >= str)) - *str1-- = '\0'; - } - } - return str; -} - -/* _pico_strlwr: - * pico internal string-to-lower routine. - */ -char *_pico_strlwr( char *str ) -{ - char *cp; - for (cp=str; *cp; ++cp) - { - if ('A' <= *cp && *cp <= 'Z') - { - *cp += ('a' - 'A'); - } - } - return str; -} - -/* _pico_strchcount: - * counts how often the given char appears in str. -sea - */ -int _pico_strchcount( char *str, int ch ) -{ - int count = 0; - while (*str++) if (*str == ch) count++; - return count; -} - -void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ) -{ - int i; - for (i=0; i<3; i++) - { - mins[i] = +999999; - maxs[i] = -999999; - } -} - -void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ) -{ - int i; - for (i=0; i<3; i++) - { - float value = p[i]; - if (value < mins[i]) mins[i] = value; - if (value > maxs[i]) maxs[i] = value; - } -} - -void _pico_zero_vec( picoVec3_t vec ) -{ - vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0; -} - -void _pico_zero_vec2( picoVec2_t vec ) -{ - vec[ 0 ] = vec[ 1 ] = 0; -} - -void _pico_zero_vec4( picoVec4_t vec ) -{ - vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0; -} - -void _pico_set_vec( picoVec3_t v, float a, float b, float c ) -{ - v[ 0 ] = a; - v[ 1 ] = b; - v[ 2 ] = c; -} - -void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ) -{ - v[ 0 ] = a; - v[ 1 ] = b; - v[ 2 ] = c; - v[ 3 ] = d; -} - -void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ) -{ - dest[ 0 ] = src[ 0 ]; - dest[ 1 ] = src[ 1 ]; - dest[ 2 ] = src[ 2 ]; -} - -void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ) -{ - dest[ 0 ] = src[ 0 ]; - dest[ 1 ] = src[ 1 ]; -} - -void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest ) -{ - dest[ 0 ] = src[ 0 ]; - dest[ 1 ] = src[ 1 ]; - dest[ 2 ] = src[ 2 ]; - dest[ 3 ] = src[ 3 ]; -} - -/* ydnar */ -picoVec_t _pico_normalize_vec( picoVec3_t vec ) -{ - double len, ilen; - - len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] ); - if( len == 0.0 ) return 0.0; - ilen = 1.0 / len; - vec[ 0 ] *= (picoVec_t) ilen; - vec[ 1 ] *= (picoVec_t) ilen; - vec[ 2 ] *= (picoVec_t) ilen; - return (picoVec_t) len; -} - -void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) -{ - dest[ 0 ] = a[ 0 ] + b[ 0 ]; - dest[ 1 ] = a[ 1 ] + b[ 1 ]; - dest[ 2 ] = a[ 2 ] + b[ 2 ]; -} - -void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) -{ - dest[ 0 ] = a[ 0 ] - b[ 0 ]; - dest[ 1 ] = a[ 1 ] - b[ 1 ]; - dest[ 2 ] = a[ 2 ] - b[ 2 ]; -} - -void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ) -{ - dest[ 0 ] = v[ 0 ] * scale; - dest[ 1 ] = v[ 1 ] * scale; - dest[ 2 ] = v[ 2 ] * scale; -} - -void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ) -{ - dest[ 0 ] = v[ 0 ] * scale; - dest[ 1 ] = v[ 1 ] * scale; - dest[ 2 ] = v[ 2 ] * scale; - dest[ 3 ] = v[ 3 ] * scale; -} - -picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ) -{ - return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; -} - -void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) -{ - dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ]; - dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ]; - dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ]; -} - -picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ) -{ - picoVec3_t ba, ca; - - _pico_subtract_vec( b, a, ba ); - _pico_subtract_vec( c, a, ca ); - _pico_cross_vec( ca, ba, plane ); - plane[ 3 ] = _pico_dot_vec( a, plane ); - return _pico_normalize_vec( plane ); -} - -/* separate from _pico_set_vec4 */ -void _pico_set_color( picoColor_t c, int r, int g, int b, int a ) -{ - c[ 0 ] = r; - c[ 1 ] = g; - c[ 2 ] = b; - c[ 3 ] = a; -} - -void _pico_copy_color( picoColor_t src, picoColor_t dest ) -{ - dest[ 0 ] = src[ 0 ]; - dest[ 1 ] = src[ 1 ]; - dest[ 2 ] = src[ 2 ]; - dest[ 3 ] = src[ 3 ]; -} - -#ifdef __BIG_ENDIAN__ - -int _pico_big_long ( int src ) { return src; } -short _pico_big_short( short src ) { return src; } -float _pico_big_float( float src ) { return src; } - -int _pico_little_long( int src ) -{ - return ((src & 0xFF000000) >> 24) | - ((src & 0x00FF0000) >> 8) | - ((src & 0x0000FF00) << 8) | - ((src & 0x000000FF) << 24); -} - -short _pico_little_short( short src ) -{ - return ((src & 0xFF00) >> 8) | - ((src & 0x00FF) << 8); -} - -float _pico_little_float( float src ) -{ - floatSwapUnion in,out; - in.f = src; - out.c[ 0 ] = in.c[ 3 ]; - out.c[ 1 ] = in.c[ 2 ]; - out.c[ 2 ] = in.c[ 1 ]; - out.c[ 3 ] = in.c[ 0 ]; - return out.f; -} -#else /*__BIG_ENDIAN__*/ - -int _pico_little_long ( int src ) { return src; } -short _pico_little_short( short src ) { return src; } -float _pico_little_float( float src ) { return src; } - -int _pico_big_long( int src ) -{ - return ((src & 0xFF000000) >> 24) | - ((src & 0x00FF0000) >> 8) | - ((src & 0x0000FF00) << 8) | - ((src & 0x000000FF) << 24); -} - -short _pico_big_short( short src ) -{ - return ((src & 0xFF00) >> 8) | - ((src & 0x00FF) << 8); -} - -float _pico_big_float( float src ) -{ - floatSwapUnion in,out; - in.f = src; - out.c[ 0 ] = in.c[ 3 ]; - out.c[ 1 ] = in.c[ 2 ]; - out.c[ 2 ] = in.c[ 1 ]; - out.c[ 3 ] = in.c[ 0 ]; - return out.f; -} -#endif /*__BIG_ENDIAN__*/ - -/* _pico_stristr: - * case-insensitive strstr. -sea - */ -char *_pico_stristr( char *str, const char *substr ) -{ - const int sublen = strlen(substr); - while (*str) - { - if (!_pico_strnicmp(str,substr,sublen)) break; - str++; - } - if (!(*str)) str = NULL; - return str; -} - -/* -_pico_unixify() -changes dos \ style path separators to / -*/ - -void _pico_unixify( char *path ) -{ - if( path == NULL ) - return; - while( *path ) - { - if( *path == '\\' ) - *path = '/'; - path++; - } -} - -/* _pico_nofname: - * removes file name portion from given file path and converts - * the directory separators to un*x style. returns 1 on success - * or 0 when 'destSize' was exceeded. -sea - */ -int _pico_nofname( const char *path, char *dest, int destSize ) -{ - int left = destSize; - char *temp = dest; - - while ((*dest = *path) != '\0') - { - if (*dest == '/' || *dest == '\\') - { - temp = (dest + 1); - *dest = '/'; - } - dest++; path++; - - if (--left < 1) - { - *temp = '\0'; - return 0; - } - } - *temp = '\0'; - return 1; -} - -/* _pico_nopath: - * returns ptr to filename portion in given path or an empty - * string otherwise. given 'path' is not altered. -sea - */ -char *_pico_nopath( const char *path ) -{ - char *src; - src = (char *)path + (strlen(path) - 1); - - if (path == NULL) return (char *)""; - if (!strchr((char *)path,'/') && !strchr((char *)path,'\\')) - return ((char *)path); - - while ((src--) != path) - { - if (*src == '/' || *src == '\\') - return (++src); - } - return (char *)""; -} - -/* _pico_setfext: - * sets/changes the file extension for the given filename - * or filepath's filename portion. the given 'path' *is* - * altered. leave 'ext' empty to remove extension. -sea - */ -char *_pico_setfext( char *path, const char *ext ) -{ - char *src; - int remfext = 0; - - src = path + (strlen(path) - 1); - - if (ext == NULL) ext = ""; - if (strlen(ext ) < 1) remfext = 1; - if (strlen(path) < 1) - return path; - - while ((src--) != path) - { - if (*src == '/' || *src == '\\') - return path; - - if (*src == '.') - { - if (remfext) - { - *src = '\0'; - return path; - } - *(++src) = '\0'; - break; - } - } - strcat(path,ext); - return path; -} - -/* _pico_getline: - * extracts one line from the given buffer and stores it in dest. - * returns -1 on error or the length of the line on success. i've - * removed string trimming here. this can be done manually by the - * calling func. - */ -int _pico_getline( char *buf, int bufsize, char *dest, int destsize ) -{ - int pos; - - /* check output */ - if (dest == NULL || destsize < 1) return -1; - memset( dest,0,destsize ); - - /* check input */ - if (buf == NULL || bufsize < 1) - return -1; - - /* get next line */ - for (pos=0; poscursor == NULL) - return; - - /* skin white spaces */ - while( 1 ) - { - /* sanity checks */ - if (p->cursor < p->buffer || - p->cursor >= p->max) - { - return; - } - /* break for chars other than white spaces */ - if (*p->cursor > 0x20) break; - if (*p->cursor == 0x00) return; - - /* a bit of linefeed handling */ - if (*p->cursor == '\n') - { - *hasLFs = 1; - p->curLine++; - } - /* go to next character */ - p->cursor++; - } -} - -/* _pico_new_parser: - * allocates a new ascii parser object. - */ -picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ) -{ - picoParser_t *p; - - /* sanity check */ - if( buffer == NULL || bufSize <= 0 ) - return NULL; - - /* allocate reader */ - p = _pico_alloc( sizeof(picoParser_t) ); - if (p == NULL) return NULL; - memset( p,0,sizeof(picoParser_t) ); - - /* allocate token space */ - p->tokenSize = 0; - p->tokenMax = 1024; - p->token = _pico_alloc( p->tokenMax ); - if( p->token == NULL ) - { - _pico_free( p ); - return NULL; - } - /* setup */ - p->buffer = buffer; - p->cursor = buffer; - p->bufSize = bufSize; - p->max = p->buffer + bufSize; - p->curLine = 1; /* sea: new */ - - /* return ptr to parser */ - return p; -} - -/* _pico_free_parser: - * frees an existing pico parser object. - */ -void _pico_free_parser( picoParser_t *p ) -{ - /* sanity check */ - if (p == NULL) return; - - /* free the parser */ - if (p->token != NULL) - { - _pico_free( p->token ); - } - _pico_free( p ); -} - -/* _pico_parse_ex: - * reads the next token from given pico parser object. if param - * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when - * the EOF is reached. if 'allowLFs' is 0 it will return 0 when - * the EOL is reached. if 'handleQuoted' is 1 the parser function - * will handle "quoted" strings and return the data between the - * quotes as token. returns 0 on end/error or 1 on success. -sea - */ -int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ) -{ - int hasLFs = 0; - char *old; - - /* sanity checks */ - if( p == NULL || p->buffer == NULL || - p->cursor < p->buffer || - p->cursor >= p->max ) - { - return 0; - } - /* clear parser token */ - p->tokenSize = 0; - p->token[ 0 ] = '\0'; - old = p->cursor; - - /* skip whitespaces */ - while( p->cursor < p->max && *p->cursor <= 32 ) - { - if (*p->cursor == '\n') - { - p->curLine++; - hasLFs++; - } - p->cursor++; - } - /* return if we're not allowed to go beyond lfs */ - if ((hasLFs > 0) && !allowLFs) - { - p->cursor = old; - return 0; - } - /* get next quoted string */ - if (*p->cursor == '\"' && handleQuoted) - { - p->cursor++; - while (p->cursor < p->max && *p->cursor) - { - if (*p->cursor == '\\') - { - if (*(p->cursor+1) == '"') - { - p->cursor++; - } - p->token[ p->tokenSize++ ] = *p->cursor++; - continue; - } - else if (*p->cursor == '\"') - { - p->cursor++; - break; - } - else if (*p->cursor == '\n') - { - p->curLine++; - } - p->token[ p->tokenSize++ ] = *p->cursor++; - } - /* terminate token */ - p->token[ p->tokenSize ] = '\0'; - return 1; - } - /* otherwise get next word */ - while( p->cursor < p->max && *p->cursor > 32 ) - { - if (*p->cursor == '\n') - { - p->curLine++; - } - p->token[ p->tokenSize++ ] = *p->cursor++; - } - /* terminate token */ - p->token[ p->tokenSize ] = '\0'; - return 1; -} - -/* _pico_parse_first: - * reads the first token from the next line and returns - * a pointer to it. returns NULL on EOL or EOF. -sea - */ -char *_pico_parse_first( picoParser_t *p ) -{ - /* sanity check */ - if (p == NULL) return NULL; - - /* try to read next token (with lfs & quots) */ - if (!_pico_parse_ex( p,1,1 )) - return NULL; - - /* return ptr to the token string */ - return p->token; -} - -/* _pico_parse: - * reads the next token from the parser and returns a pointer - * to it. quoted strings are handled as usual. returns NULL - * on EOL or EOF. -sea - */ -char *_pico_parse( picoParser_t *p, int allowLFs ) -{ - /* sanity check */ - if (p == NULL) return NULL; - - /* try to read next token (with quots) */ - if (!_pico_parse_ex( p,allowLFs,1 )) - return NULL; - - /* return ptr to the token string */ - return p->token; -} - -/* _pico_parse_skip_rest: - * skips the rest of the current line in parser. - */ -void _pico_parse_skip_rest( picoParser_t *p ) -{ - while( _pico_parse_ex( p,0,0 ) ) ; -} - -/* _pico_parse_skip_braced: - * parses/skips over a braced section. returns 1 on success - * or 0 on error (when there was no closing bracket and the - * end of buffer was reached or when the opening bracket was - * missing). - */ -int _pico_parse_skip_braced( picoParser_t *p ) -{ - int firstToken = 1; - int level; - - /* sanity check */ - if (p == NULL) return 0; - - /* set the initial level for parsing */ - level = 0; - - /* skip braced section */ - while( 1 ) - { - /* read next token (lfs allowed) */ - if (!_pico_parse_ex( p,1,1 )) - { - /* end of parser buffer reached */ - return 0; - } - /* first token must be an opening bracket */ - if (firstToken && p->token[0] != '{') - { - /* opening bracket missing */ - return 0; - } - /* we only check this once */ - firstToken = 0; - - /* update level */ - if (p->token[1] == '\0') - { - if (p->token[0] == '{') level++; - if (p->token[0] == '}') level--; - } - /* break if we're back at our starting level */ - if (level == 0) break; - } - /* successfully skipped braced section */ - return 1; -} - -int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ) -{ - if (!_pico_parse_ex( p,allowLFs,1 )) - return 0; - if (!strcmp(p->token,str)) - return 1; - return 0; -} - -int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ) -{ - if (!_pico_parse_ex( p,allowLFs,1 )) - return 0; - if (!_pico_stricmp(p->token,str)) - return 1; - return 0; -} - -int _pico_parse_int( picoParser_t *p, int *out ) -{ - char *token; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* get token and turn it into an integer */ - *out = 0; - token = _pico_parse( p,0 ); - if (token == NULL) return 0; - *out = atoi( token ); - - /* success */ - return 1; -} - -int _pico_parse_int_def( picoParser_t *p, int *out, int def ) -{ - char *token; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* get token and turn it into an integer */ - *out = def; - token = _pico_parse( p,0 ); - if (token == NULL) return 0; - *out = atoi( token ); - - /* success */ - return 1; -} - -int _pico_parse_float( picoParser_t *p, float *out ) -{ - char *token; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* get token and turn it into a float */ - *out = 0.0f; - token = _pico_parse( p,0 ); - if (token == NULL) return 0; - *out = (float) atof( token ); - - /* success */ - return 1; -} - -int _pico_parse_float_def( picoParser_t *p, float *out, float def ) -{ - char *token; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* get token and turn it into a float */ - *out = def; - token = _pico_parse( p,0 ); - if (token == NULL) return 0; - *out = (float) atof( token ); - - /* success */ - return 1; -} - -int _pico_parse_vec( picoParser_t *p, picoVec3_t out ) -{ - char *token; - int i; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* zero out outination vector */ - _pico_zero_vec( out ); - - /* parse three vector components */ - for (i=0; i<3; i++) - { - token = _pico_parse( p,0 ); - if (token == NULL) - { - _pico_zero_vec( out ); - return 0; - } - out[ i ] = (float) atof( token ); - } - /* success */ - return 1; -} - -int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ) -{ - char *token; - int i; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* assign default vector value */ - _pico_copy_vec( def,out ); - - /* parse three vector components */ - for (i=0; i<3; i++) - { - token = _pico_parse( p,0 ); - if (token == NULL) - { - _pico_copy_vec( def,out ); - return 0; - } - out[ i ] = (float) atof( token ); - } - /* success */ - return 1; -} - -int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ) -{ - char *token; - int i; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* zero out outination vector */ - _pico_zero_vec2( out ); - - /* parse two vector components */ - for (i=0; i<2; i++) - { - token = _pico_parse( p,0 ); - if (token == NULL) - { - _pico_zero_vec2( out ); - return 0; - } - out[ i ] = (float) atof( token ); - } - /* success */ - return 1; -} - -int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ) -{ - char *token; - int i; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* assign default vector value */ - _pico_copy_vec2( def,out ); - - /* parse two vector components */ - for (i=0; i<2; i++) - { - token = _pico_parse( p,0 ); - if (token == NULL) - { - _pico_copy_vec2( def,out ); - return 0; - } - out[ i ] = (float) atof( token ); - } - /* success */ - return 1; -} - -int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ) -{ - char *token; - int i; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* zero out outination vector */ - _pico_zero_vec4( out ); - - /* parse four vector components */ - for (i=0; i<4; i++) - { - token = _pico_parse( p,0 ); - if (token == NULL) - { - _pico_zero_vec4( out ); - return 0; - } - out[ i ] = (float) atof( token ); - } - /* success */ - return 1; -} - -int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ) -{ - char *token; - int i; - - /* sanity checks */ - if (p == NULL || out == NULL) - return 0; - - /* assign default vector value */ - _pico_copy_vec4( def,out ); - - /* parse four vector components */ - for (i=0; i<4; i++) - { - token = _pico_parse( p,0 ); - if (token == NULL) - { - _pico_copy_vec4( def,out ); - return 0; - } - out[ i ] = (float) atof( token ); - } - /* success */ - return 1; -} - -/* _pico_new_memstream: - * allocates a new memorystream object. - */ -picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ) -{ - picoMemStream_t *s; - - /* sanity check */ - if( buffer == NULL || bufSize <= 0 ) - return NULL; - - /* allocate stream */ - s = _pico_alloc( sizeof(picoMemStream_t) ); - if (s == NULL) return NULL; - memset( s,0,sizeof(picoMemStream_t) ); - - /* setup */ - s->buffer = buffer; - s->curPos = buffer; - s->bufSize = bufSize; - s->flag = 0; - - /* return ptr to stream */ - return s; -} - -/* _pico_free_memstream: - * frees an existing pico memorystream object. - */ -void _pico_free_memstream( picoMemStream_t *s ) -{ - /* sanity check */ - if (s == NULL) return; - - /* free the stream */ - _pico_free( s ); -} - -/* _pico_memstream_read: - * reads data from a pico memorystream into a buffer. - */ -int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ) -{ - int ret = 1; - - /* sanity checks */ - if (s == NULL || buffer == NULL) - return 0; - - if (s->curPos + len > s->buffer + s->bufSize) - { - s->flag |= PICO_IOEOF; - len = s->buffer + s->bufSize - s->curPos; - ret = 0; - } - - /* read the data */ - memcpy( buffer, s->curPos, len ); - s->curPos += len; - return ret; -} - -/* _pico_memstream_read: - * reads a character from a pico memorystream - */ -int _pico_memstream_getc( picoMemStream_t *s ) -{ - int c = 0; - - /* sanity check */ - if (s == NULL) - return -1; - - /* read the character */ - if (_pico_memstream_read( s, &c, 1) == 0) - return -1; - - return c; -} - -/* _pico_memstream_seek: - * sets the current read position to a different location - */ -int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ) -{ - int overflow; - - /* sanity check */ - if (s == NULL) - return -1; - - if (origin == PICO_SEEK_SET) - { - s->curPos = s->buffer + offset; - overflow = s->curPos - ( s->buffer + s->bufSize ); - if (overflow > 0) - { - s->curPos = s->buffer + s->bufSize; - return offset - overflow; - } - return 0; - } - else if (origin == PICO_SEEK_CUR) - { - s->curPos += offset; - overflow = s->curPos - ( s->buffer + s->bufSize ); - if (overflow > 0) - { - s->curPos = s->buffer + s->bufSize; - return offset - overflow; - } - return 0; - } - else if (origin == PICO_SEEK_END) - { - s->curPos = ( s->buffer + s->bufSize ) - offset; - overflow = s->buffer - s->curPos; - if (overflow > 0) - { - s->curPos = s->buffer; - return offset - overflow; - } - return 0; - } - - return -1; -} - -/* _pico_memstream_tell: - * returns the current read position in the pico memorystream - */ -long _pico_memstream_tell( picoMemStream_t *s ) -{ - /* sanity check */ - if (s == NULL) - return -1; - - return s->curPos - s->buffer; -} +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOINTERNAL_C + + + +/* todo: + * - fix p->curLine for parser routines. increased twice + */ + +/* dependencies */ +#include +#include "picointernal.h" + + + +/* function pointers */ +void *(*_pico_ptr_malloc )( size_t ) = malloc; +void (*_pico_ptr_free )( void* ) = free; +void (*_pico_ptr_load_file )( char*, unsigned char**, int* ) = NULL; +void (*_pico_ptr_free_file )( void* ) = NULL; +void (*_pico_ptr_print )( int, const char* ) = NULL; + +typedef union +{ + float f; + char c[4]; +} +floatSwapUnion; + +/* _pico_alloc: + * kludged memory allocation wrapper + */ +void *_pico_alloc( size_t size ) +{ + void *ptr; + + /* some sanity checks */ + if( size == 0 ) + return NULL; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate memory */ + ptr = _pico_ptr_malloc(size); + if (ptr == NULL) + return NULL; + + /* zero out allocated memory */ + memset(ptr,0,size); + + /* return pointer to allocated memory */ + return ptr; +} + +/* _pico_calloc: + * _pico_calloc wrapper + */ +void *_pico_calloc( size_t num, size_t size ) +{ + void *ptr; + + /* some sanity checks */ + if( num == 0 || size == 0 ) + return NULL; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate memory */ + ptr = _pico_ptr_malloc(num*size); + if (ptr == NULL) + return NULL; + + /* zero out allocated memory */ + memset(ptr,0,num*size); + + /* return pointer to allocated memory */ + return ptr; +} + +/* _pico_realloc: + * memory reallocation wrapper (note: only grows, + * but never shrinks or frees) + */ +void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ) +{ + void *ptr2; + + /* sanity checks */ + if( ptr == NULL ) + return NULL; + if( newSize < oldSize ) + return *ptr; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate new pointer */ + ptr2 = _pico_alloc( newSize ); + if( ptr2 == NULL ) + return NULL; + + /* copy */ + if( *ptr != NULL ) + { + memcpy( ptr2, *ptr, oldSize ); + _pico_free( *ptr ); + } + + /* fix up and return */ + *ptr = ptr2; + return *ptr; +} + +/* _pico_clone_alloc: + * handy function for quick string allocation/copy. it clones + * the given string and returns a pointer to the new allocated + * clone (which must be freed by caller of course) or returns + * NULL on memory alloc or param errors. if 'size' is -1 the + * length of the input string is used, otherwise 'size' is used + * as custom clone size (the string is cropped to fit into mem + * if needed). -sea + */ +char *_pico_clone_alloc( char *str, int size ) +{ + char *cloned; + size_t cloneSize; + + /* sanity check */ + if (str == NULL) return NULL; + + /* set real size of cloned string */ + cloneSize = (size < 0) ? strlen(str) : size; + + /* allocate memory */ + cloned = _pico_alloc( cloneSize+1 ); /* bugfix! */ + if (cloned == NULL) + return NULL; + + /* zero out memory allocated by cloned string */ + memset( cloned,0,cloneSize ); + + /* copy input string to cloned string */ + if (cloneSize < strlen( str )) { + memcpy( cloned,str,cloneSize ); + cloned[ cloneSize ] = '\0'; + } else { + strcpy( cloned,str ); + } + /* return ptr to cloned string */ + return cloned; +} + +/* _pico_free: + * wrapper around the free function pointer + */ +void _pico_free( void *ptr ) +{ + /* sanity checks */ + if( ptr == NULL ) + return; + if (_pico_ptr_free == NULL) + return; + + /* free the allocated memory */ + _pico_ptr_free( ptr ); +} + +/* _pico_load_file: + * wrapper around the loadfile function pointer + */ +void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ) +{ + /* sanity checks */ + if( name == NULL ) + { + *bufSize = -1; + return; + } + if (_pico_ptr_load_file == NULL) + { + *bufSize = -1; + return; + } + /* do the actual call to read in the file; */ + /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */ + _pico_ptr_load_file( name,buffer,bufSize ); +} + +/* _pico_free_file: + * wrapper around the file free function pointer + */ +void _pico_free_file( void *buffer ) +{ + /* sanity checks */ + if( buffer == NULL ) + return; + + /* use default free */ + if( _pico_ptr_free_file == NULL ) + { + free( buffer ); + return; + } + /* free the allocated file */ + _pico_ptr_free_file( buffer ); +} + +/* _pico_printf: + * wrapper around the print function pointer -sea + */ +void _pico_printf( int level, const char *format, ...) +{ + char str[4096]; + va_list argptr; + + /* sanity checks */ + if( format == NULL ) + return; + if (_pico_ptr_print == NULL) + return; + + /* format string */ + va_start( argptr,format ); + vsprintf( str,format,argptr ); + va_end( argptr ); + + /* remove linefeeds */ + if (str[ strlen(str)-1 ] == '\n') + str[ strlen(str)-1 ] = '\0'; + + /* do the actual call */ + _pico_ptr_print( level,str ); +} + +/* _pico_strltrim: + * left trims the given string -sea + */ +char *_pico_strltrim( char *str ) +{ + char *str1 = str, *str2 = str; + + while (isspace(*str2)) str2++; + if( str2 != str ) + while( *str2 != '\0' ) /* fix: ydnar */ + *str1++ = *str2++; + return str; +} + +/* _pico_strrtrim: + * right trims the given string -sea + */ +char *_pico_strrtrim( char *str ) +{ + if (str && *str) + { + char *str1 = str; + int allspace = 1; + + while (*str1) + { + if (allspace && !isspace(*str1)) allspace = 0; + str1++; + } + if (allspace) *str = '\0'; + else { + str1--; + while ((isspace(*str1)) && (str1 >= str)) + *str1-- = '\0'; + } + } + return str; +} + +/* _pico_strlwr: + * pico internal string-to-lower routine. + */ +char *_pico_strlwr( char *str ) +{ + char *cp; + for (cp=str; *cp; ++cp) + { + if ('A' <= *cp && *cp <= 'Z') + { + *cp += ('a' - 'A'); + } + } + return str; +} + +/* _pico_strchcount: + * counts how often the given char appears in str. -sea + */ +int _pico_strchcount( char *str, int ch ) +{ + int count = 0; + while (*str++) if (*str == ch) count++; + return count; +} + +void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ) +{ + int i; + for (i=0; i<3; i++) + { + mins[i] = +999999; + maxs[i] = -999999; + } +} + +void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ) +{ + int i; + for (i=0; i<3; i++) + { + float value = p[i]; + if (value < mins[i]) mins[i] = value; + if (value > maxs[i]) maxs[i] = value; + } +} + +void _pico_zero_vec( picoVec3_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0; +} + +void _pico_zero_vec2( picoVec2_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = 0; +} + +void _pico_zero_vec4( picoVec4_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0; +} + +void _pico_set_vec( picoVec3_t v, float a, float b, float c ) +{ + v[ 0 ] = a; + v[ 1 ] = b; + v[ 2 ] = c; +} + +void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ) +{ + v[ 0 ] = a; + v[ 1 ] = b; + v[ 2 ] = c; + v[ 3 ] = d; +} + +void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; +} + +void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; +} + +void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; + dest[ 3 ] = src[ 3 ]; +} + +/* ydnar */ +picoVec_t _pico_normalize_vec( picoVec3_t vec ) +{ + double len, ilen; + + len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] ); + if( len == 0.0 ) return 0.0; + ilen = 1.0 / len; + vec[ 0 ] *= (picoVec_t) ilen; + vec[ 1 ] *= (picoVec_t) ilen; + vec[ 2 ] *= (picoVec_t) ilen; + return (picoVec_t) len; +} + +void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 0 ] + b[ 0 ]; + dest[ 1 ] = a[ 1 ] + b[ 1 ]; + dest[ 2 ] = a[ 2 ] + b[ 2 ]; +} + +void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 0 ] - b[ 0 ]; + dest[ 1 ] = a[ 1 ] - b[ 1 ]; + dest[ 2 ] = a[ 2 ] - b[ 2 ]; +} + +void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ) +{ + dest[ 0 ] = v[ 0 ] * scale; + dest[ 1 ] = v[ 1 ] * scale; + dest[ 2 ] = v[ 2 ] * scale; +} + +void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ) +{ + dest[ 0 ] = v[ 0 ] * scale; + dest[ 1 ] = v[ 1 ] * scale; + dest[ 2 ] = v[ 2 ] * scale; + dest[ 3 ] = v[ 3 ] * scale; +} + +picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ) +{ + return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; +} + +void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ]; + dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ]; + dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ]; +} + +picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ) +{ + picoVec3_t ba, ca; + + _pico_subtract_vec( b, a, ba ); + _pico_subtract_vec( c, a, ca ); + _pico_cross_vec( ca, ba, plane ); + plane[ 3 ] = _pico_dot_vec( a, plane ); + return _pico_normalize_vec( plane ); +} + +/* separate from _pico_set_vec4 */ +void _pico_set_color( picoColor_t c, int r, int g, int b, int a ) +{ + c[ 0 ] = r; + c[ 1 ] = g; + c[ 2 ] = b; + c[ 3 ] = a; +} + +void _pico_copy_color( picoColor_t src, picoColor_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; + dest[ 3 ] = src[ 3 ]; +} + +#ifdef __BIG_ENDIAN__ + +int _pico_big_long ( int src ) { return src; } +short _pico_big_short( short src ) { return src; } +float _pico_big_float( float src ) { return src; } + +int _pico_little_long( int src ) +{ + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); +} + +short _pico_little_short( short src ) +{ + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); +} + +float _pico_little_float( float src ) +{ + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; +} +#else /*__BIG_ENDIAN__*/ + +int _pico_little_long ( int src ) { return src; } +short _pico_little_short( short src ) { return src; } +float _pico_little_float( float src ) { return src; } + +int _pico_big_long( int src ) +{ + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); +} + +short _pico_big_short( short src ) +{ + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); +} + +float _pico_big_float( float src ) +{ + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; +} +#endif /*__BIG_ENDIAN__*/ + +/* _pico_stristr: + * case-insensitive strstr. -sea + */ +char *_pico_stristr( char *str, const char *substr ) +{ + const int sublen = strlen(substr); + while (*str) + { + if (!_pico_strnicmp(str,substr,sublen)) break; + str++; + } + if (!(*str)) str = NULL; + return str; +} + +/* +_pico_unixify() +changes dos \ style path separators to / +*/ + +void _pico_unixify( char *path ) +{ + if( path == NULL ) + return; + while( *path ) + { + if( *path == '\\' ) + *path = '/'; + path++; + } +} + +/* _pico_nofname: + * removes file name portion from given file path and converts + * the directory separators to un*x style. returns 1 on success + * or 0 when 'destSize' was exceeded. -sea + */ +int _pico_nofname( const char *path, char *dest, int destSize ) +{ + int left = destSize; + char *temp = dest; + + while ((*dest = *path) != '\0') + { + if (*dest == '/' || *dest == '\\') + { + temp = (dest + 1); + *dest = '/'; + } + dest++; path++; + + if (--left < 1) + { + *temp = '\0'; + return 0; + } + } + *temp = '\0'; + return 1; +} + +/* _pico_nopath: + * returns ptr to filename portion in given path or an empty + * string otherwise. given 'path' is not altered. -sea + */ +char *_pico_nopath( const char *path ) +{ + char *src; + src = (char *)path + (strlen(path) - 1); + + if (path == NULL) return (char *)""; + if (!strchr((char *)path,'/') && !strchr((char *)path,'\\')) + return ((char *)path); + + while ((src--) != path) + { + if (*src == '/' || *src == '\\') + return (++src); + } + return (char *)""; +} + +/* _pico_setfext: + * sets/changes the file extension for the given filename + * or filepath's filename portion. the given 'path' *is* + * altered. leave 'ext' empty to remove extension. -sea + */ +char *_pico_setfext( char *path, const char *ext ) +{ + char *src; + int remfext = 0; + + src = path + (strlen(path) - 1); + + if (ext == NULL) ext = ""; + if (strlen(ext ) < 1) remfext = 1; + if (strlen(path) < 1) + return path; + + while ((src--) != path) + { + if (*src == '/' || *src == '\\') + return path; + + if (*src == '.') + { + if (remfext) + { + *src = '\0'; + return path; + } + *(++src) = '\0'; + break; + } + } + strcat(path,ext); + return path; +} + +/* _pico_getline: + * extracts one line from the given buffer and stores it in dest. + * returns -1 on error or the length of the line on success. i've + * removed string trimming here. this can be done manually by the + * calling func. + */ +int _pico_getline( char *buf, int bufsize, char *dest, int destsize ) +{ + int pos; + + /* check output */ + if (dest == NULL || destsize < 1) return -1; + memset( dest,0,destsize ); + + /* check input */ + if (buf == NULL || bufsize < 1) + return -1; + + /* get next line */ + for (pos=0; poscursor == NULL) + return; + + /* skin white spaces */ + while( 1 ) + { + /* sanity checks */ + if (p->cursor < p->buffer || + p->cursor >= p->max) + { + return; + } + /* break for chars other than white spaces */ + if (*p->cursor > 0x20) break; + if (*p->cursor == 0x00) return; + + /* a bit of linefeed handling */ + if (*p->cursor == '\n') + { + *hasLFs = 1; + p->curLine++; + } + /* go to next character */ + p->cursor++; + } +} + +/* _pico_new_parser: + * allocates a new ascii parser object. + */ +picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ) +{ + picoParser_t *p; + + /* sanity check */ + if( buffer == NULL || bufSize <= 0 ) + return NULL; + + /* allocate reader */ + p = _pico_alloc( sizeof(picoParser_t) ); + if (p == NULL) return NULL; + memset( p,0,sizeof(picoParser_t) ); + + /* allocate token space */ + p->tokenSize = 0; + p->tokenMax = 1024; + p->token = _pico_alloc( p->tokenMax ); + if( p->token == NULL ) + { + _pico_free( p ); + return NULL; + } + /* setup */ + p->buffer = buffer; + p->cursor = buffer; + p->bufSize = bufSize; + p->max = p->buffer + bufSize; + p->curLine = 1; /* sea: new */ + + /* return ptr to parser */ + return p; +} + +/* _pico_free_parser: + * frees an existing pico parser object. + */ +void _pico_free_parser( picoParser_t *p ) +{ + /* sanity check */ + if (p == NULL) return; + + /* free the parser */ + if (p->token != NULL) + { + _pico_free( p->token ); + } + _pico_free( p ); +} + +/* _pico_parse_ex: + * reads the next token from given pico parser object. if param + * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when + * the EOF is reached. if 'allowLFs' is 0 it will return 0 when + * the EOL is reached. if 'handleQuoted' is 1 the parser function + * will handle "quoted" strings and return the data between the + * quotes as token. returns 0 on end/error or 1 on success. -sea + */ +int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ) +{ + int hasLFs = 0; + char *old; + + /* sanity checks */ + if( p == NULL || p->buffer == NULL || + p->cursor < p->buffer || + p->cursor >= p->max ) + { + return 0; + } + /* clear parser token */ + p->tokenSize = 0; + p->token[ 0 ] = '\0'; + old = p->cursor; + + /* skip whitespaces */ + while( p->cursor < p->max && *p->cursor <= 32 ) + { + if (*p->cursor == '\n') + { + p->curLine++; + hasLFs++; + } + p->cursor++; + } + /* return if we're not allowed to go beyond lfs */ + if ((hasLFs > 0) && !allowLFs) + { + p->cursor = old; + return 0; + } + /* get next quoted string */ + if (*p->cursor == '\"' && handleQuoted) + { + p->cursor++; + while (p->cursor < p->max && *p->cursor) + { + if (*p->cursor == '\\') + { + if (*(p->cursor+1) == '"') + { + p->cursor++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + continue; + } + else if (*p->cursor == '\"') + { + p->cursor++; + break; + } + else if (*p->cursor == '\n') + { + p->curLine++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + } + /* terminate token */ + p->token[ p->tokenSize ] = '\0'; + return 1; + } + /* otherwise get next word */ + while( p->cursor < p->max && *p->cursor > 32 ) + { + if (*p->cursor == '\n') + { + p->curLine++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + } + /* terminate token */ + p->token[ p->tokenSize ] = '\0'; + return 1; +} + +/* _pico_parse_first: + * reads the first token from the next line and returns + * a pointer to it. returns NULL on EOL or EOF. -sea + */ +char *_pico_parse_first( picoParser_t *p ) +{ + /* sanity check */ + if (p == NULL) return NULL; + + /* try to read next token (with lfs & quots) */ + if (!_pico_parse_ex( p,1,1 )) + return NULL; + + /* return ptr to the token string */ + return p->token; +} + +/* _pico_parse: + * reads the next token from the parser and returns a pointer + * to it. quoted strings are handled as usual. returns NULL + * on EOL or EOF. -sea + */ +char *_pico_parse( picoParser_t *p, int allowLFs ) +{ + /* sanity check */ + if (p == NULL) return NULL; + + /* try to read next token (with quots) */ + if (!_pico_parse_ex( p,allowLFs,1 )) + return NULL; + + /* return ptr to the token string */ + return p->token; +} + +/* _pico_parse_skip_rest: + * skips the rest of the current line in parser. + */ +void _pico_parse_skip_rest( picoParser_t *p ) +{ + while( _pico_parse_ex( p,0,0 ) ) ; +} + +/* _pico_parse_skip_braced: + * parses/skips over a braced section. returns 1 on success + * or 0 on error (when there was no closing bracket and the + * end of buffer was reached or when the opening bracket was + * missing). + */ +int _pico_parse_skip_braced( picoParser_t *p ) +{ + int firstToken = 1; + int level; + + /* sanity check */ + if (p == NULL) return 0; + + /* set the initial level for parsing */ + level = 0; + + /* skip braced section */ + while( 1 ) + { + /* read next token (lfs allowed) */ + if (!_pico_parse_ex( p,1,1 )) + { + /* end of parser buffer reached */ + return 0; + } + /* first token must be an opening bracket */ + if (firstToken && p->token[0] != '{') + { + /* opening bracket missing */ + return 0; + } + /* we only check this once */ + firstToken = 0; + + /* update level */ + if (p->token[1] == '\0') + { + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + } + /* break if we're back at our starting level */ + if (level == 0) break; + } + /* successfully skipped braced section */ + return 1; +} + +int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ) +{ + if (!_pico_parse_ex( p,allowLFs,1 )) + return 0; + if (!strcmp(p->token,str)) + return 1; + return 0; +} + +int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ) +{ + if (!_pico_parse_ex( p,allowLFs,1 )) + return 0; + if (!_pico_stricmp(p->token,str)) + return 1; + return 0; +} + +int _pico_parse_int( picoParser_t *p, int *out ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into an integer */ + *out = 0; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = atoi( token ); + + /* success */ + return 1; +} + +int _pico_parse_int_def( picoParser_t *p, int *out, int def ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into an integer */ + *out = def; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = atoi( token ); + + /* success */ + return 1; +} + +int _pico_parse_float( picoParser_t *p, float *out ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into a float */ + *out = 0.0f; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = (float) atof( token ); + + /* success */ + return 1; +} + +int _pico_parse_float_def( picoParser_t *p, float *out, float def ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into a float */ + *out = def; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = (float) atof( token ); + + /* success */ + return 1; +} + +int _pico_parse_vec( picoParser_t *p, picoVec3_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec( out ); + + /* parse three vector components */ + for (i=0; i<3; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec( def,out ); + + /* parse three vector components */ + for (i=0; i<3; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec2( out ); + + /* parse two vector components */ + for (i=0; i<2; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec2( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec2( def,out ); + + /* parse two vector components */ + for (i=0; i<2; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec2( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec4( out ); + + /* parse four vector components */ + for (i=0; i<4; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec4( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec4( def,out ); + + /* parse four vector components */ + for (i=0; i<4; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec4( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +/* _pico_new_memstream: + * allocates a new memorystream object. + */ +picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ) +{ + picoMemStream_t *s; + + /* sanity check */ + if( buffer == NULL || bufSize <= 0 ) + return NULL; + + /* allocate stream */ + s = _pico_alloc( sizeof(picoMemStream_t) ); + if (s == NULL) return NULL; + memset( s,0,sizeof(picoMemStream_t) ); + + /* setup */ + s->buffer = buffer; + s->curPos = buffer; + s->bufSize = bufSize; + s->flag = 0; + + /* return ptr to stream */ + return s; +} + +/* _pico_free_memstream: + * frees an existing pico memorystream object. + */ +void _pico_free_memstream( picoMemStream_t *s ) +{ + /* sanity check */ + if (s == NULL) return; + + /* free the stream */ + _pico_free( s ); +} + +/* _pico_memstream_read: + * reads data from a pico memorystream into a buffer. + */ +int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ) +{ + int ret = 1; + + /* sanity checks */ + if (s == NULL || buffer == NULL) + return 0; + + if (s->curPos + len > s->buffer + s->bufSize) + { + s->flag |= PICO_IOEOF; + len = s->buffer + s->bufSize - s->curPos; + ret = 0; + } + + /* read the data */ + memcpy( buffer, s->curPos, len ); + s->curPos += len; + return ret; +} + +/* _pico_memstream_read: + * reads a character from a pico memorystream + */ +int _pico_memstream_getc( picoMemStream_t *s ) +{ + int c = 0; + + /* sanity check */ + if (s == NULL) + return -1; + + /* read the character */ + if (_pico_memstream_read( s, &c, 1) == 0) + return -1; + + return c; +} + +/* _pico_memstream_seek: + * sets the current read position to a different location + */ +int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ) +{ + int overflow; + + /* sanity check */ + if (s == NULL) + return -1; + + if (origin == PICO_SEEK_SET) + { + s->curPos = s->buffer + offset; + overflow = s->curPos - ( s->buffer + s->bufSize ); + if (overflow > 0) + { + s->curPos = s->buffer + s->bufSize; + return offset - overflow; + } + return 0; + } + else if (origin == PICO_SEEK_CUR) + { + s->curPos += offset; + overflow = s->curPos - ( s->buffer + s->bufSize ); + if (overflow > 0) + { + s->curPos = s->buffer + s->bufSize; + return offset - overflow; + } + return 0; + } + else if (origin == PICO_SEEK_END) + { + s->curPos = ( s->buffer + s->bufSize ) - offset; + overflow = s->buffer - s->curPos; + if (overflow > 0) + { + s->curPos = s->buffer; + return offset - overflow; + } + return 0; + } + + return -1; +} + +/* _pico_memstream_tell: + * returns the current read position in the pico memorystream + */ +long _pico_memstream_tell( picoMemStream_t *s ) +{ + /* sanity check */ + if (s == NULL) + return -1; + + return s->curPos - s->buffer; +} diff --git a/libs/picomodel/picointernal.h b/libs/picomodel/picointernal.h index 37686ce1..8a3ee68d 100644 --- a/libs/picomodel/picointernal.h +++ b/libs/picomodel/picointernal.h @@ -1,205 +1,205 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#ifndef PICOINTERNAL_H -#define PICOINTERNAL_H - -#ifdef __cplusplus -extern "C" -{ -#endif - - -/* dependencies */ -#include -#include -#include -#include -#include -#include - -#include "picomodel.h" - - -/* os dependant replacements */ -#if WIN32 || _WIN32 - #define _pico_stricmp stricmp - #define _pico_strnicmp strnicmp -#else - #define _pico_stricmp strcasecmp - #define _pico_strnicmp strncasecmp -#endif - - -/* constants */ -#define PICO_PI 3.14159265358979323846 - -#define PICO_SEEK_SET 0 -#define PICO_SEEK_CUR 1 -#define PICO_SEEK_END 2 - -#define PICO_IOEOF 1 -#define PICO_IOERR 2 - -/* types */ -typedef struct picoParser_s -{ - char *buffer; - int bufSize; - char *token; - int tokenSize; - int tokenMax; - char *cursor; - char *max; - int curLine; -} -picoParser_t; - -typedef struct picoMemStream_s -{ - picoByte_t *buffer; - int bufSize; - picoByte_t *curPos; - int flag; -} -picoMemStream_t; - - -/* variables */ -extern const picoModule_t *picoModules[]; - -extern void *(*_pico_ptr_malloc)( size_t ); -extern void (*_pico_ptr_free)( void* ); -extern void (*_pico_ptr_load_file)( char*, unsigned char**, int* ); -extern void (*_pico_ptr_free_file)( void* ); -extern void (*_pico_ptr_print)( int, const char* ); - - - -/* prototypes */ - -/* memory */ -void *_pico_alloc( size_t size ); -void *_pico_calloc( size_t num, size_t size ); -void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ); -char *_pico_clone_alloc( char *str, int size ); -void _pico_free( void *ptr ); - -/* files */ -void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ); -void _pico_free_file( void *buffer ); - -/* strings */ -char *_pico_strltrim( char *str ); -char *_pico_strrtrim( char *str ); -int _pico_strchcount( char *str, int ch ); -void _pico_printf( int level, const char *format, ... ); -char *_pico_stristr( char *str, const char *substr ); -void _pico_unixify( char *path ); -int _pico_nofname( const char *path, char *dest, int destSize ); -char *_pico_nopath( const char *path ); -char *_pico_setfext( char *path, const char *ext ); -int _pico_getline( char *buf, int bufsize, char *dest, int destsize ); -char *_pico_strlwr( char *str ); - -/* vectors */ -void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ); -void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ); -void _pico_zero_vec( picoVec3_t vec ); -void _pico_zero_vec2( picoVec2_t vec ); -void _pico_zero_vec4( picoVec4_t vec ); -void _pico_set_vec( picoVec3_t v, float a, float b, float c ); -void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ); -void _pico_set_color( picoColor_t c, int r, int g, int b, int a ); -void _pico_copy_color( picoColor_t src, picoColor_t dest ); -void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ); -void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ); -picoVec_t _pico_normalize_vec( picoVec3_t vec ); -void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); -void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); -picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ); -void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); -picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ); -void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ); -void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ); - -/* endian */ -int _pico_big_long( int src ); -short _pico_big_short( short src ); -float _pico_big_float( float src ); - -int _pico_little_long( int src ); -short _pico_little_short( short src ); -float _pico_little_float( float src ); - -/* pico ascii parser */ -picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ); -void _pico_free_parser( picoParser_t *p ); -int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ); -char *_pico_parse_first( picoParser_t *p ); -char *_pico_parse( picoParser_t *p, int allowLFs ); -void _pico_parse_skip_rest( picoParser_t *p ); -int _pico_parse_skip_braced( picoParser_t *p ); -int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ); -int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ); -int _pico_parse_int( picoParser_t *p, int *out ); -int _pico_parse_int_def( picoParser_t *p, int *out, int def ); -int _pico_parse_float( picoParser_t *p, float *out ); -int _pico_parse_float_def( picoParser_t *p, float *out, float def ); -int _pico_parse_vec( picoParser_t *p, picoVec3_t out); -int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def); -int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ); -int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ); -int _pico_parse_vec4( picoParser_t *p, picoVec4_t out); -int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def); - -/* pico memory stream */ -picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ); -void _pico_free_memstream( picoMemStream_t *s ); -int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ); -int _pico_memstream_getc( picoMemStream_t *s ); -int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ); -long _pico_memstream_tell( picoMemStream_t *s ); -#define _pico_memstream_eof( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOEOF) -#define _pico_memstream_error( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOERR) - -/* end marker */ -#ifdef __cplusplus -} -#endif - -#endif +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef PICOINTERNAL_H +#define PICOINTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* dependencies */ +#include +#include +#include +#include +#include +#include + +#include "picomodel.h" + + +/* os dependant replacements */ +#if WIN32 || _WIN32 + #define _pico_stricmp stricmp + #define _pico_strnicmp strnicmp +#else + #define _pico_stricmp strcasecmp + #define _pico_strnicmp strncasecmp +#endif + + +/* constants */ +#define PICO_PI 3.14159265358979323846 + +#define PICO_SEEK_SET 0 +#define PICO_SEEK_CUR 1 +#define PICO_SEEK_END 2 + +#define PICO_IOEOF 1 +#define PICO_IOERR 2 + +/* types */ +typedef struct picoParser_s +{ + char *buffer; + int bufSize; + char *token; + int tokenSize; + int tokenMax; + char *cursor; + char *max; + int curLine; +} +picoParser_t; + +typedef struct picoMemStream_s +{ + picoByte_t *buffer; + int bufSize; + picoByte_t *curPos; + int flag; +} +picoMemStream_t; + + +/* variables */ +extern const picoModule_t *picoModules[]; + +extern void *(*_pico_ptr_malloc)( size_t ); +extern void (*_pico_ptr_free)( void* ); +extern void (*_pico_ptr_load_file)( char*, unsigned char**, int* ); +extern void (*_pico_ptr_free_file)( void* ); +extern void (*_pico_ptr_print)( int, const char* ); + + + +/* prototypes */ + +/* memory */ +void *_pico_alloc( size_t size ); +void *_pico_calloc( size_t num, size_t size ); +void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ); +char *_pico_clone_alloc( char *str, int size ); +void _pico_free( void *ptr ); + +/* files */ +void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ); +void _pico_free_file( void *buffer ); + +/* strings */ +char *_pico_strltrim( char *str ); +char *_pico_strrtrim( char *str ); +int _pico_strchcount( char *str, int ch ); +void _pico_printf( int level, const char *format, ... ); +char *_pico_stristr( char *str, const char *substr ); +void _pico_unixify( char *path ); +int _pico_nofname( const char *path, char *dest, int destSize ); +char *_pico_nopath( const char *path ); +char *_pico_setfext( char *path, const char *ext ); +int _pico_getline( char *buf, int bufsize, char *dest, int destsize ); +char *_pico_strlwr( char *str ); + +/* vectors */ +void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ); +void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ); +void _pico_zero_vec( picoVec3_t vec ); +void _pico_zero_vec2( picoVec2_t vec ); +void _pico_zero_vec4( picoVec4_t vec ); +void _pico_set_vec( picoVec3_t v, float a, float b, float c ); +void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ); +void _pico_set_color( picoColor_t c, int r, int g, int b, int a ); +void _pico_copy_color( picoColor_t src, picoColor_t dest ); +void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ); +void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ); +picoVec_t _pico_normalize_vec( picoVec3_t vec ); +void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ); +void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ); +void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ); +void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ); + +/* endian */ +int _pico_big_long( int src ); +short _pico_big_short( short src ); +float _pico_big_float( float src ); + +int _pico_little_long( int src ); +short _pico_little_short( short src ); +float _pico_little_float( float src ); + +/* pico ascii parser */ +picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ); +void _pico_free_parser( picoParser_t *p ); +int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ); +char *_pico_parse_first( picoParser_t *p ); +char *_pico_parse( picoParser_t *p, int allowLFs ); +void _pico_parse_skip_rest( picoParser_t *p ); +int _pico_parse_skip_braced( picoParser_t *p ); +int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ); +int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ); +int _pico_parse_int( picoParser_t *p, int *out ); +int _pico_parse_int_def( picoParser_t *p, int *out, int def ); +int _pico_parse_float( picoParser_t *p, float *out ); +int _pico_parse_float_def( picoParser_t *p, float *out, float def ); +int _pico_parse_vec( picoParser_t *p, picoVec3_t out); +int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def); +int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ); +int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ); +int _pico_parse_vec4( picoParser_t *p, picoVec4_t out); +int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def); + +/* pico memory stream */ +picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ); +void _pico_free_memstream( picoMemStream_t *s ); +int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ); +int _pico_memstream_getc( picoMemStream_t *s ); +int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ); +long _pico_memstream_tell( picoMemStream_t *s ); +#define _pico_memstream_eof( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOEOF) +#define _pico_memstream_error( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOERR) + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel/picomodel.c b/libs/picomodel/picomodel.c index ed4f8b21..d7790c37 100644 --- a/libs/picomodel/picomodel.c +++ b/libs/picomodel/picomodel.c @@ -1,1995 +1,1995 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define PICOMODEL_C - - - -/* dependencies */ -#include "picointernal.h" - - - -/* -PicoInit() -initializes the picomodel library -*/ - -int PicoInit( void ) -{ - /* successfully initialized -sea */ - return 1; -} - - - -/* -PicoShutdown() -shuts the pico model library down -*/ - -void PicoShutdown( void ) -{ - /* do something interesting here in the future */ - return; -} - - - -/* -PicoError() -returns last picomodel error code (see PME_* defines) -*/ - -int PicoError( void ) -{ - /* todo: do something here */ - return 0; -} - - - -/* -PicoSetMallocFunc() -sets the ptr to the malloc function -*/ - -void PicoSetMallocFunc( void *(*func)( size_t ) ) -{ - if( func != NULL ) - _pico_ptr_malloc = func; -} - - - -/* -PicoSetFreeFunc() -sets the ptr to the free function -*/ - -void PicoSetFreeFunc( void (*func)( void* ) ) -{ - if( func != NULL ) - _pico_ptr_free = func; -} - - - -/* -PicoSetLoadFileFunc() -sets the ptr to the file load function -*/ - -void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ) -{ - if( func != NULL ) - _pico_ptr_load_file = func; -} - - - -/* -PicoSetFreeFileFunc() -sets the ptr to the free function -*/ - -void PicoSetFreeFileFunc( void (*func)( void* ) ) -{ - if( func != NULL ) - _pico_ptr_free_file = func; -} - - - -/* -PicoSetPrintFunc() -sets the ptr to the print function -*/ - -void PicoSetPrintFunc( void (*func)( int, const char* ) ) -{ - if( func != NULL ) - _pico_ptr_print = func; -} - - - -/* -PicoLoadModel() -the meat and potatoes function -*/ - -picoModel_t *PicoLoadModel( char *fileName, int frameNum ) -{ - const picoModule_t **modules, *pm; - picoModel_t *model; - picoByte_t *buffer; - int bufSize; - char *modelFileName, *remapFileName; - - - /* init */ - model = NULL; - - /* make sure we've got a file name */ - if( fileName == NULL ) - { - _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" ); - return NULL; - } - - /* load file data (buffer is allocated by host app) */ - _pico_load_file( fileName, &buffer, &bufSize ); - if( bufSize < 0 ) - { - _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName ); - return NULL; - } - - /* get ptr to list of supported modules */ - modules = PicoModuleList( NULL ); - - /* run it through the various loader functions and try */ - /* to find a loader that fits the given file data */ - for( ; *modules != NULL; modules++ ) - { - /* get module */ - pm = *modules; - - /* sanity check */ - if( pm == NULL) - break; - - /* module must be able to load */ - if( pm->canload == NULL || pm->load == NULL ) - continue; - - /* see whether this module can load the model file or not */ - if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) - { - /* use loader provided by module to read the model data */ - model = pm->load( fileName, frameNum, buffer, bufSize ); - if( model == NULL ) - { - _pico_free_file( buffer ); - return NULL; - } - - /* assign pointer to file format module */ - model->module = pm; - - /* get model file name */ - modelFileName = PicoGetModelFileName( model ); - - /* apply model remappings from .remap */ - if( strlen( modelFileName ) ) - { - /* alloc copy of model file name */ - remapFileName = _pico_alloc( strlen( modelFileName ) + 20 ); - if( remapFileName != NULL ) - { - /* copy model file name and change extension */ - strcpy( remapFileName, modelFileName ); - _pico_setfext( remapFileName, "remap" ); - - /* try to remap model; we don't handle the result */ - PicoRemapModel( model, remapFileName ); - - /* free the remap file name string */ - _pico_free( remapFileName ); - } - } - - /* model was loaded, so break out of loop */ - break; - } - } - - /* free memory used by file buffer */ - if( buffer) - _pico_free_file( buffer ); - - /* return */ - return model; -} - - - -/* ---------------------------------------------------------------------------- -models ----------------------------------------------------------------------------- */ - -/* -PicoNewModel() -creates a new pico model -*/ - -picoModel_t *PicoNewModel( void ) -{ - picoModel_t *model; - - /* allocate */ - model = _pico_alloc( sizeof(picoModel_t) ); - if( model == NULL ) - return NULL; - - /* clear */ - memset( model,0,sizeof(picoModel_t) ); - - /* model set up */ - _pico_zero_bounds( model->mins,model->maxs ); - - /* set initial frame count to 1 -sea */ - model->numFrames = 1; - - /* return ptr to new model */ - return model; -} - - - -/* -PicoFreeModel() -frees a model and all associated data -*/ - -void PicoFreeModel( picoModel_t *model ) -{ - int i; - - - /* sanity check */ - if( model == NULL ) - return; - - /* free bits */ - if( model->name ) - _pico_free( model->name ); - - /* free shaders */ - for( i = 0; i < model->numShaders; i++ ) - PicoFreeShader( model->shader[ i ] ); - free( model->shader ); - - /* free surfaces */ - for( i = 0; i < model->numSurfaces; i++ ) - PicoFreeSurface( model->surface[ i ] ); - free( model->surface ); - - /* free the model */ - _pico_free( model ); -} - - - -/* -PicoAdjustModel() -adjusts a models's memory allocations to handle the requested sizes. -will always grow, never shrink -*/ - -int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ) -{ - /* dummy check */ - if( model == NULL ) - return 0; - - /* bare minimums */ - /* sea: null surface/shader fix (1s=>0s) */ - if( numShaders < 0 ) - numShaders = 0; - if( numSurfaces < 0 ) - numSurfaces = 0; - - /* additional shaders? */ - while( numShaders > model->maxShaders ) - { - model->maxShaders += PICO_GROW_SHADERS; - if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) - return 0; - } - - /* set shader count to higher */ - if( numShaders > model->numShaders ) - model->numShaders = numShaders; - - /* additional surfaces? */ - while( numSurfaces > model->maxSurfaces ) - { - model->maxSurfaces += PICO_GROW_SURFACES; - if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) - return 0; - } - - /* set shader count to higher */ - if( numSurfaces > model->numSurfaces ) - model->numSurfaces = numSurfaces; - - /* return ok */ - return 1; -} - - - -/* ---------------------------------------------------------------------------- -shaders ----------------------------------------------------------------------------- */ - -/* -PicoNewShader() -creates a new pico shader and returns its index. -sea -*/ - -picoShader_t *PicoNewShader( picoModel_t *model ) -{ - picoShader_t *shader; - - - /* allocate and clear */ - shader = _pico_alloc( sizeof(picoShader_t) ); - if( shader == NULL ) - return NULL; - memset( shader, 0, sizeof(picoShader_t) ); - - /* attach it to the model */ - if( model != NULL ) - { - /* adjust model */ - if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) - { - _pico_free( shader ); - return NULL; - } - /* attach */ - model->shader[ model->numShaders - 1 ] = shader; - shader->model = model; - } - /* setup default shader colors */ - _pico_set_color( shader->ambientColor,0,0,0,0 ); - _pico_set_color( shader->diffuseColor,255,255,255,1 ); - _pico_set_color( shader->specularColor,0,0,0,0 ); - - /* no need to do this, but i do it anyway */ - shader->transparency = 0; - shader->shininess = 0; - - /* return the newly created shader */ - return shader; -} - - - -/* -PicoFreeShader() -frees a shader and all associated data -sea -*/ - -void PicoFreeShader( picoShader_t *shader ) -{ - /* dummy check */ - if( shader == NULL ) - return; - - /* free bits */ - if( shader->name ) - _pico_free( shader->name ); - if( shader->mapName ) - _pico_free( shader->mapName ); - - /* free the shader */ - _pico_free( shader ); -} - - - -/* -PicoFindShader() -finds a named shader in a model -*/ - -picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ) -{ - int i; - - - /* sanity checks */ - if( model == NULL || name == NULL ) /* sea: null name fix */ - return NULL; - - /* walk list */ - for( i = 0; i < model->numShaders; i++ ) - { - /* skip null shaders or shaders with null names */ - if( model->shader[ i ] == NULL || - model->shader[ i ]->name == NULL ) - continue; - - /* compare the shader name with name we're looking for */ - if( caseSensitive ) - { - if( !strcmp( name, model->shader[ i ]->name ) ) - return model->shader[ i ]; - } - else if( !_pico_stricmp( name, model->shader[ i ]->name ) ) - return model->shader[ i ]; - } - - /* named shader not found */ - return NULL; -} - - - -/* ---------------------------------------------------------------------------- -surfaces ----------------------------------------------------------------------------- */ - -/* -PicoNewSurface() -creates a new pico surface -*/ - -picoSurface_t *PicoNewSurface( picoModel_t *model ) -{ - picoSurface_t *surface; - char surfaceName[64]; - - /* allocate and clear */ - surface = _pico_alloc( sizeof( *surface ) ); - if( surface == NULL ) - return NULL; - memset( surface, 0, sizeof( *surface ) ); - - /* attach it to the model */ - if( model != NULL ) - { - /* adjust model */ - if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) ) - { - _pico_free( surface ); - return NULL; - } - - /* attach */ - model->surface[ model->numSurfaces - 1 ] = surface; - surface->model = model; - - /* set default name */ - sprintf( surfaceName, "Unnamed_%d", model->numSurfaces ); - PicoSetSurfaceName( surface, surfaceName ); - } - - /* return */ - return surface; -} - - - -/* -PicoFreeSurface() -frees a surface and all associated data -*/ -void PicoFreeSurface( picoSurface_t *surface ) -{ - int i; - - - /* dummy check */ - if( surface == NULL ) - return; - - /* free bits */ - _pico_free( surface->xyz ); - _pico_free( surface->normal ); - _pico_free( surface->index ); - _pico_free( surface->faceNormal ); - - /* free arrays */ - for( i = 0; i < surface->numSTArrays; i++ ) - _pico_free( surface->st[ i ] ); - free( surface->st ); - for( i = 0; i < surface->numColorArrays; i++ ) - _pico_free( surface->color[ i ] ); - free( surface->color ); - - /* free the surface */ - _pico_free( surface ); -} - - - -/* -PicoAdjustSurface() -adjusts a surface's memory allocations to handle the requested sizes. -will always grow, never shrink -*/ - -int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ) -{ - int i; - - - /* dummy check */ - if( surface == NULL ) - return 0; - - /* bare minimums */ - if( numVertexes < 1 ) - numVertexes = 1; - if( numSTArrays < 1 ) - numSTArrays = 1; - if( numColorArrays < 1 ) - numColorArrays = 1; - if( numIndexes < 1 ) - numIndexes = 1; - - /* additional vertexes? */ - while( numVertexes > surface->maxVertexes ) /* fix */ - { - surface->maxVertexes += PICO_GROW_VERTEXES; - if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) - return 0; - if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) - return 0; - for( i = 0; i < surface->numSTArrays; i++ ) - if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) - return 0; - for( i = 0; i < surface->numColorArrays; i++ ) - if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) - return 0; - } - - /* set vertex count to higher */ - if( numVertexes > surface->numVertexes ) - surface->numVertexes = numVertexes; - - /* additional st arrays? */ - while( numSTArrays > surface->maxSTArrays ) /* fix */ - { - surface->maxSTArrays += PICO_GROW_ARRAYS; - if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) - return 0; - while( surface->numSTArrays < numSTArrays ) - { - surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); - memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); - surface->numSTArrays++; - } - } - - /* additional color arrays? */ - while( numColorArrays > surface->maxColorArrays ) /* fix */ - { - surface->maxColorArrays += PICO_GROW_ARRAYS; - if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) - return 0; - while( surface->numColorArrays < numColorArrays ) - { - surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); - memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); - surface->numColorArrays++; - } - } - - /* additional indexes? */ - while( numIndexes > surface->maxIndexes ) /* fix */ - { - surface->maxIndexes += PICO_GROW_INDEXES; - if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) - return 0; - } - - /* set index count to higher */ - if( numIndexes > surface->numIndexes ) - surface->numIndexes = numIndexes; - - /* additional face normals? */ - while( numFaceNormals > surface->maxFaceNormals ) /* fix */ - { - surface->maxFaceNormals += PICO_GROW_FACES; - if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) - return 0; - } - - /* set face normal count to higher */ - if( numFaceNormals > surface->numFaceNormals ) - surface->numFaceNormals = numFaceNormals; - - /* return ok */ - return 1; -} - - -/* PicoFindSurface: - * Finds first matching named surface in a model. - */ -picoSurface_t *PicoFindSurface( - picoModel_t *model, char *name, int caseSensitive ) -{ - int i; - - /* sanity check */ - if( model == NULL || name == NULL ) - return NULL; - - /* walk list */ - for( i = 0; i < model->numSurfaces; i++ ) - { - /* skip null surfaces or surfaces with null names */ - if( model->surface[ i ] == NULL || - model->surface[ i ]->name == NULL ) - continue; - - /* compare the surface name with name we're looking for */ - if (caseSensitive) { - if( !strcmp(name,model->surface[ i ]->name) ) - return model->surface[ i ]; - } else { - if( !_pico_stricmp(name,model->surface[ i ]->name) ) - return model->surface[ i ]; - } - } - /* named surface not found */ - return NULL; -} - - - -/*---------------------------------------------------------------------------- - PicoSet*() Setter Functions -----------------------------------------------------------------------------*/ - -void PicoSetModelName( picoModel_t *model, char *name ) -{ - if( model == NULL || name == NULL ) - return; - if( model->name != NULL ) - _pico_free( model->name ); - - model->name = _pico_clone_alloc( name,-1 ); -} - - - -void PicoSetModelFileName( picoModel_t *model, char *fileName ) -{ - if( model == NULL || fileName == NULL ) - return; - if( model->fileName != NULL ) - _pico_free( model->fileName ); - - model->fileName = _pico_clone_alloc( fileName,-1 ); -} - - - -void PicoSetModelFrameNum( picoModel_t *model, int frameNum ) -{ - if( model == NULL ) - return; - model->frameNum = frameNum; -} - - - -void PicoSetModelNumFrames( picoModel_t *model, int numFrames ) -{ - if( model == NULL ) - return; - model->numFrames = numFrames; -} - - - -void PicoSetModelData( picoModel_t *model, void *data ) -{ - if( model == NULL ) - return; - model->data = data; -} - - - -void PicoSetShaderName( picoShader_t *shader, char *name ) -{ - if( shader == NULL || name == NULL ) - return; - if( shader->name != NULL ) - _pico_free( shader->name ); - - shader->name = _pico_clone_alloc( name,-1 ); -} - - - -void PicoSetShaderMapName( picoShader_t *shader, char *mapName ) -{ - if( shader == NULL || mapName == NULL ) - return; - if( shader->mapName != NULL ) - _pico_free( shader->mapName ); - - shader->mapName = _pico_clone_alloc( mapName,-1 ); -} - - - -void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ) -{ - if( shader == NULL || color == NULL ) - return; - shader->ambientColor[ 0 ] = color[ 0 ]; - shader->ambientColor[ 1 ] = color[ 1 ]; - shader->ambientColor[ 2 ] = color[ 2 ]; - shader->ambientColor[ 3 ] = color[ 3 ]; -} - - - -void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ) -{ - if( shader == NULL || color == NULL ) - return; - shader->diffuseColor[ 0 ] = color[ 0 ]; - shader->diffuseColor[ 1 ] = color[ 1 ]; - shader->diffuseColor[ 2 ] = color[ 2 ]; - shader->diffuseColor[ 3 ] = color[ 3 ]; -} - - - -void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ) -{ - if( shader == NULL || color == NULL ) - return; - shader->specularColor[ 0 ] = color[ 0 ]; - shader->specularColor[ 1 ] = color[ 1 ]; - shader->specularColor[ 2 ] = color[ 2 ]; - shader->specularColor[ 3 ] = color[ 3 ]; -} - - - -void PicoSetShaderTransparency( picoShader_t *shader, float value ) -{ - if( shader == NULL ) - return; - shader->transparency = value; - - /* cap to 0..1 range */ - if (shader->transparency < 0.0) - shader->transparency = 0.0; - if (shader->transparency > 1.0) - shader->transparency = 1.0; -} - - - -void PicoSetShaderShininess( picoShader_t *shader, float value ) -{ - if( shader == NULL ) - return; - shader->shininess = value; - - /* cap to 0..127 range */ - if (shader->shininess < 0.0) - shader->shininess = 0.0; - if (shader->shininess > 127.0) - shader->shininess = 127.0; -} - - - -void PicoSetSurfaceData( picoSurface_t *surface, void *data ) -{ - if( surface == NULL ) - return; - surface->data = data; -} - - - -void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ) -{ - if( surface == NULL ) - return; - surface->type = type; -} - - - -void PicoSetSurfaceName( picoSurface_t *surface, char *name ) -{ - if( surface == NULL || name == NULL ) - return; - if( surface->name != NULL ) - _pico_free( surface->name ); - - surface->name = _pico_clone_alloc( name,-1 ); -} - - - -void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ) -{ - if( surface == NULL ) - return; - surface->shader = shader; -} - - - -void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ) -{ - if( surface == NULL || num < 0 || xyz == NULL ) - return; - if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) - return; - _pico_copy_vec( xyz, surface->xyz[ num ] ); - if( surface->model != NULL ) - _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs ); -} - - - -void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) -{ - if( surface == NULL || num < 0 || normal == NULL ) - return; - if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) - return; - _pico_copy_vec( normal, surface->normal[ num ] ); -} - - - -void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ) -{ - if( surface == NULL || num < 0 || st == NULL ) - return; - if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) - return; - surface->st[ array ][ num ][ 0 ] = st[ 0 ]; - surface->st[ array ][ num ][ 1 ] = st[ 1 ]; -} - - - -void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ) -{ - if( surface == NULL || num < 0 || color == NULL ) - return; - if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) - return; - surface->color[ array ][ num ][ 0 ] = color[ 0 ]; - surface->color[ array ][ num ][ 1 ] = color[ 1 ]; - surface->color[ array ][ num ][ 2 ] = color[ 2 ]; - surface->color[ array ][ num ][ 3 ] = color[ 3 ]; -} - - - -void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ) -{ - if( surface == NULL || num < 0 ) - return; - if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) - return; - surface->index[ num ] = index; -} - - - -void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ) -{ - if( num < 0 || index == NULL || count < 1 ) - return; - if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) - return; - memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) ); -} - - - -void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) -{ - if( surface == NULL || num < 0 || normal == NULL ) - return; - if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) - return; - _pico_copy_vec( normal, surface->faceNormal[ num ] ); -} - - -void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ) -{ - if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) - return; - surface->special[ num ] = special; -} - - - -/*---------------------------------------------------------------------------- - PicoGet*() Getter Functions -----------------------------------------------------------------------------*/ - -char *PicoGetModelName( picoModel_t *model ) -{ - if( model == NULL ) - return NULL; - if( model->name == NULL) - return (char*) ""; - return model->name; -} - - - -char *PicoGetModelFileName( picoModel_t *model ) -{ - if( model == NULL ) - return NULL; - if( model->fileName == NULL) - return (char*) ""; - return model->fileName; -} - - - -int PicoGetModelFrameNum( picoModel_t *model ) -{ - if( model == NULL ) - return 0; - return model->frameNum; -} - - - -int PicoGetModelNumFrames( picoModel_t *model ) -{ - if( model == NULL ) - return 0; - return model->numFrames; -} - - - -void *PicoGetModelData( picoModel_t *model ) -{ - if( model == NULL ) - return NULL; - return model->data; -} - - - -int PicoGetModelNumShaders( picoModel_t *model ) -{ - if( model == NULL ) - return 0; - return model->numShaders; -} - - - -picoShader_t *PicoGetModelShader( picoModel_t *model, int num ) -{ - /* a few sanity checks */ - if( model == NULL ) - return NULL; - if( model->shader == NULL) - return NULL; - if( num < 0 || num >= model->numShaders ) - return NULL; - - /* return the shader */ - return model->shader[ num ]; -} - - - -int PicoGetModelNumSurfaces( picoModel_t *model ) -{ - if( model == NULL ) - return 0; - return model->numSurfaces; -} - - - -picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ) -{ - /* a few sanity checks */ - if( model == NULL ) - return NULL; - if( model->surface == NULL) - return NULL; - if( num < 0 || num >= model->numSurfaces ) - return NULL; - - /* return the surface */ - return model->surface[ num ]; -} - - - -int PicoGetModelTotalVertexes( picoModel_t *model ) -{ - int i, count; - - - if( model == NULL ) - return 0; - if( model->surface == NULL ) - return 0; - - count = 0; - for( i = 0; i < model->numSurfaces; i++ ) - count += PicoGetSurfaceNumVertexes( model->surface[ i ] ); - - return count; -} - - - -int PicoGetModelTotalIndexes( picoModel_t *model ) -{ - int i, count; - - - if( model == NULL ) - return 0; - if( model->surface == NULL ) - return 0; - - count = 0; - for( i = 0; i < model->numSurfaces; i++ ) - count += PicoGetSurfaceNumIndexes( model->surface[ i ] ); - - return count; -} - - - -char *PicoGetShaderName( picoShader_t *shader ) -{ - if( shader == NULL ) - return NULL; - if( shader->name == NULL) - return (char*) ""; - return shader->name; -} - - - -char *PicoGetShaderMapName( picoShader_t *shader ) -{ - if( shader == NULL ) - return NULL; - if( shader->mapName == NULL) - return (char*) ""; - return shader->mapName; -} - - - -picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ) -{ - if( shader == NULL ) - return NULL; - return shader->ambientColor; -} - - - -picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ) -{ - if( shader == NULL ) - return NULL; - return shader->diffuseColor; -} - - - -picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ) -{ - if( shader == NULL ) - return NULL; - return shader->specularColor; -} - - - -float PicoGetShaderTransparency( picoShader_t *shader ) -{ - if( shader == NULL ) - return 0.0f; - return shader->transparency; -} - - - -float PicoGetShaderShininess( picoShader_t *shader ) -{ - if( shader == NULL ) - return 0.0f; - return shader->shininess; -} - - - -void *PicoGetSurfaceData( picoSurface_t *surface ) -{ - if( surface == NULL ) - return NULL; - return surface->data; -} - - - -picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ) -{ - if( surface == NULL ) - return PICO_BAD; - return surface->type; -} - - - -char *PicoGetSurfaceName( picoSurface_t *surface ) -{ - if( surface == NULL ) - return NULL; - if( surface->name == NULL ) - return (char*) ""; - return surface->name; -} - - - -picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ) -{ - if( surface == NULL ) - return NULL; - return surface->shader; -} - - - -int PicoGetSurfaceNumVertexes( picoSurface_t *surface ) -{ - if( surface == NULL ) - return 0; - return surface->numVertexes; -} - - - -picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ) -{ - if( surface == NULL || num < 0 || num > surface->numVertexes ) - return NULL; - return surface->xyz[ num ]; -} - - - -picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ) -{ - if( surface == NULL || num < 0 || num > surface->numVertexes ) - return NULL; - return surface->normal[ num ]; -} - - - -picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ) -{ - if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) - return NULL; - return surface->st[ array ][ num ]; -} - - - -picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ) -{ - if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) - return NULL; - return surface->color[ array ][ num ]; -} - - - -int PicoGetSurfaceNumIndexes( picoSurface_t *surface ) -{ - if( surface == NULL ) - return 0; - return surface->numIndexes; -} - - - -picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ) -{ - if( surface == NULL || num < 0 || num > surface->numIndexes ) - return 0; - return surface->index[ num ]; -} - - - -picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ) -{ - if( surface == NULL || num < 0 || num > surface->numIndexes ) - return NULL; - return &surface->index[ num ]; -} - - -picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ) -{ - if( surface == NULL || num < 0 || num > surface->numFaceNormals ) - return NULL; - return surface->faceNormal[ num ]; -} - - -int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ) -{ - if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) - return 0; - return surface->special[ num ]; -} - - - -/* ---------------------------------------------------------------------------- -hashtable related functions ----------------------------------------------------------------------------- */ - -/* hashtable code for faster vertex lookups */ -//#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */ -#define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */ - -int PicoGetHashTableSize( void ) -{ - return HASHTABLE_SIZE; -} - -#define HASH_USE_EPSILON - -#ifdef HASH_USE_EPSILON -#define HASH_XYZ_EPSILON 0.01f -#define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON -#define HASH_ST_EPSILON 0.0001f -#define HASH_NORMAL_EPSILON 0.02f -#endif - -unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ) -{ - unsigned int hash = 0; - -#ifndef HASH_USE_EPSILON - hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15); - hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10); - hash += (*((unsigned int*) &xyz[ 1 ]) << 3); - hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6); - hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11); - hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16); -#else - picoVec3_t xyz_epsilonspace; - - _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace ); - xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]); - xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]); - xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]); - - hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15); - hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10); - hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3); - hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6); - hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11); - hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16); -#endif - - //hash = hash & (HASHTABLE_SIZE-1); - hash = hash % (HASHTABLE_SIZE); - return hash; -} - -picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ) -{ - picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); - - memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); - - return hashTable; -} - -void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ) -{ - int i; - picoVertexCombinationHash_t *vertexCombinationHash; - picoVertexCombinationHash_t *nextVertexCombinationHash; - - /* dummy check */ - if (hashTable == NULL) - return; - - for( i = 0; i < HASHTABLE_SIZE; i++ ) - { - if (hashTable[ i ]) - { - nextVertexCombinationHash = NULL; - - for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash ) - { - nextVertexCombinationHash = vertexCombinationHash->next; - if (vertexCombinationHash->data != NULL) - { - _pico_free( vertexCombinationHash->data ); - } - _pico_free( vertexCombinationHash ); - } - } - } - - _pico_free( hashTable ); -} - -picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ) -{ - unsigned int hash; - picoVertexCombinationHash_t *vertexCombinationHash; - - /* dumy check */ - if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) - return NULL; - - hash = PicoVertexCoordGenerateHash( xyz ); - - for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next ) - { -#ifndef HASH_USE_EPSILON - /* check xyz */ - if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) ) - continue; - - /* check normal */ - if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) ) - continue; - - /* check st */ - if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) - continue; -#else - /* check xyz */ - if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON || - ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON || - ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON ) - continue; - - /* check normal */ - if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON || - ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON || - ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON ) - continue; - - /* check st */ - if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON || - ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON ) - continue; -#endif - - /* check color */ - if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) ) - continue; - - /* gotcha */ - return vertexCombinationHash; - } - - return NULL; -} - -picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ) -{ - unsigned int hash; - picoVertexCombinationHash_t *vertexCombinationHash; - - /* dumy check */ - if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) - return NULL; - - vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) ); - - if (!vertexCombinationHash) - return NULL; - - hash = PicoVertexCoordGenerateHash( xyz ); - - _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz ); - _pico_copy_vec( normal, vertexCombinationHash->vcd.normal ); - _pico_copy_vec2( st, vertexCombinationHash->vcd.st ); - _pico_copy_color( color, vertexCombinationHash->vcd.color ); - vertexCombinationHash->index = index; - vertexCombinationHash->data = NULL; - vertexCombinationHash->next = hashTable[ hash ]; - hashTable[ hash ] = vertexCombinationHash; - - return vertexCombinationHash; -} - -/* ---------------------------------------------------------------------------- -specialized routines ----------------------------------------------------------------------------- */ - -/* -PicoFindSurfaceVertex() -finds a vertex matching the set parameters -fixme: needs non-naive algorithm -*/ - -int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ) -{ - int i, j; - - - /* dummy check */ - if( surface == NULL || surface->numVertexes <= 0 ) - return -1; - - /* walk vertex list */ - for( i = 0; i < surface->numVertexes; i++ ) - { - /* check xyz */ - if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) ) - continue; - - /* check normal */ - if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) ) - continue; - - /* check st */ - if( numSTs > 0 && st != NULL ) - { - for( j = 0; j < numSTs; j++ ) - { - if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) - break; - } - if( j != numSTs ) - continue; - } - - /* check color */ - if( numColors > 0 && color != NULL ) - { - for( j = 0; j < numSTs; j++ ) - { - if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) ) - break; - } - if( j != numColors ) - continue; - } - - /* vertex matches */ - return i; - } - - /* nada */ - return -1; -} - - - -/* -PicoFixSurfaceNormals() -fixes broken normals (certain formats bork normals) -*/ - -#define MAX_NORMAL_VOTES 128 -#define EQUAL_NORMAL_EPSILON 0.01 -#define BAD_NORMAL_EPSILON 0.5 - -void PicoFixSurfaceNormals( picoSurface_t *surface ) -{ - int i, j, k, a, b, c, numVotes, faceIndex; - picoVec3_t votes[ MAX_NORMAL_VOTES ]; - picoVec3_t *normals, diff; - picoVec4_t plane; - - - /* dummy check */ - if( surface == NULL || surface->numVertexes == 0 ) - return; - - /* fixme: handle other surface types */ - if( surface->type != PICO_TRIANGLES ) - return; - - /* allocate normal storage */ - normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) ); - if( normals == NULL ) - { - _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" ); - return; - } - - /* zero it out */ - memset( normals, 0, surface->numVertexes * sizeof( *normals ) ); - - /* walk vertex list */ - for( i = 0; i < surface->numVertexes; i++ ) - { - /* zero out votes */ - numVotes = 0; - - /* find all the triangles that reference this vertex */ - for( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ ) - { - /* get triangle */ - a = surface->index[ j ]; - b = surface->index[ j + 1 ]; - c = surface->index[ j + 2 ]; - - /* ignore degenerate triangles */ - if( a == b || b == c || c == a ) - continue; - - /* ignore indexes out of range */ - if( a < 0 || a >= surface->numVertexes || - b < 0 || b >= surface->numVertexes || - c < 0 || c >= surface->numVertexes ) - continue; - - /* test triangle */ - if( a == i || b == i || c == i ) - { - /* if this surface has face normals */ - if( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) - { - _pico_copy_vec( surface->faceNormal[ faceIndex ], plane ); - if( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) - { - /* if null normal, make plane from the 3 points */ - if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) - { - continue; - } - } - } - /* make a plane from the 3 points */ - else if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) - { - continue; - } - - /* see if this normal has already been voted */ - for( k = 0; k < numVotes; k++ ) - { - _pico_subtract_vec( plane, votes[ k ], diff ); - if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON && - fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON && - fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) - break; - } - - /* add a new vote? */ - if( k == numVotes && numVotes < MAX_NORMAL_VOTES ) - { - _pico_copy_vec( plane, votes[ numVotes ] ); - numVotes++; - } - } - } - - /* tally votes */ - if( numVotes > 0 ) - { - /* create average normal */ - _pico_zero_vec( normals[ i ] ); - for( k = 0; k < numVotes; k++ ) - _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] ); - - /* normalize it */ - if( _pico_normalize_vec( normals[ i ] ) ) - { - /* test against actual normal */ - if( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) - { - //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i, - //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ], - //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] ); - _pico_copy_vec( normals[ i ], surface->normal[ i ] ); - } - } - } - } - - /* free normal storage */ - _pico_free( normals ); -} - - - - -/* -PicoRemapModel() - sea -remaps model material/etc. information using the remappings -contained in the given 'remapFile' (full path to the ascii file to open) -returns 1 on success or 0 on error -*/ - -#define _prm_error_return \ -{ \ - _pico_free_parser( p ); \ - _pico_free_file( remapBuffer ); \ - return 0; \ -} - -int PicoRemapModel( picoModel_t *model, char *remapFile ) -{ - picoParser_t *p; - picoByte_t *remapBuffer; - int remapBufSize; - - - /* sanity checks */ - if( model == NULL || remapFile == NULL ) - return 0; - - /* load remap file contents */ - _pico_load_file( remapFile,&remapBuffer,&remapBufSize ); - - /* check result */ - if( remapBufSize == 0 ) - return 1; /* file is empty: no error */ - if( remapBufSize < 0 ) - return 0; /* load failed: error */ - - /* create a new pico parser */ - p = _pico_new_parser( remapBuffer, remapBufSize ); - if (p == NULL) - { - /* ram is really cheap nowadays... */ - _prm_error_return; - } - - /* doo teh parse */ - while( 1 ) - { - /* get next token in remap file */ - if (!_pico_parse( p,1 )) - break; - - /* skip over c++ style comment lines */ - if (!_pico_stricmp(p->token,"//")) - { - _pico_parse_skip_rest( p ); - continue; - } - - /* block for quick material shader name remapping */ - /* materials { "m" (=>|->|=) "s" } */ - if( !_pico_stricmp(p->token, "materials" ) ) - { - int level = 1; - - /* check bracket */ - if (!_pico_parse_check( p,1,"{" )) - _prm_error_return; - - /* process assignments */ - while( 1 ) - { - picoShader_t *shader; - char *materialName; - - - /* get material name */ - if (_pico_parse( p,1 ) == NULL) break; - if (!strlen(p->token)) continue; - materialName = _pico_clone_alloc( p->token,-1 ); - if (materialName == NULL) - _prm_error_return; - - /* handle levels */ - if (p->token[0] == '{') level++; - if (p->token[0] == '}') level--; - if (!level) break; - - /* get next token (assignment token or shader name) */ - if (!_pico_parse( p,0 )) - { - _pico_free( materialName ); - _prm_error_return; - } - /* skip assignment token (if present) */ - if (!strcmp(p->token,"=>") || - !strcmp(p->token,"->") || - !strcmp(p->token,"=")) - { - /* simply grab the next token */ - if (!_pico_parse( p,0 )) - { - _pico_free( materialName ); - _prm_error_return; - } - } - /* try to find material by name */ - shader = PicoFindShader( model,materialName,0 ); - - /* we've found a material matching the name */ - if (shader != NULL) - { - PicoSetShaderName( shader,p->token ); - } - /* free memory used by material name */ - _pico_free( materialName ); - - /* skip rest */ - _pico_parse_skip_rest( p ); - } - } - /* block for detailed single material remappings */ - /* materials[ "m" ] { key data... } */ - else if (!_pico_stricmp(p->token,"materials[")) - { - picoShader_t *shader; - char *tempMaterialName; - int level = 1; - - /* get material name */ - if (!_pico_parse( p,0 )) - _prm_error_return; - - /* temporary copy of material name */ - tempMaterialName = _pico_clone_alloc( p->token,-1 ); - if (tempMaterialName == NULL) - _prm_error_return; - - /* check square closing bracket */ - if (!_pico_parse_check( p,0,"]" )) - _prm_error_return; - - /* try to find material by name */ - shader = PicoFindShader( model,tempMaterialName,0 ); - - /* free memory used by temporary material name */ - _pico_free( tempMaterialName ); - - /* we haven't found a material matching the name */ - /* so we simply skip the braced section now and */ - /* continue parsing with the next main token */ - if (shader == NULL) - { - _pico_parse_skip_braced( p ); - continue; - } - /* check opening bracket */ - if (!_pico_parse_check( p,1,"{" )) - _prm_error_return; - - /* process material info keys */ - while( 1 ) - { - /* get key name */ - if (_pico_parse( p,1 ) == NULL) break; - if (!strlen(p->token)) continue; - - /* handle levels */ - if (p->token[0] == '{') level++; - if (p->token[0] == '}') level--; - if (!level) break; - - /* remap shader name */ - if (!_pico_stricmp(p->token,"shader")) - { - if (!_pico_parse( p,0 )) _prm_error_return; - PicoSetShaderName( shader,p->token ); - } - /* remap shader map name */ - else if (!_pico_stricmp(p->token,"mapname")) - { - if (!_pico_parse( p,0 )) _prm_error_return; - PicoSetShaderMapName( shader,p->token ); - } - /* remap shader's ambient color */ - else if (!_pico_stricmp(p->token,"ambient")) - { - picoColor_t color; - picoVec3_t v; - - /* get vector from parser */ - if (!_pico_parse_vec( p,v )) _prm_error_return; - - /* store as color */ - color[ 0 ] = (picoByte_t)v[ 0 ]; - color[ 1 ] = (picoByte_t)v[ 1 ]; - color[ 2 ] = (picoByte_t)v[ 2 ]; - - /* set new ambient color */ - PicoSetShaderAmbientColor( shader,color ); - } - /* remap shader's diffuse color */ - else if (!_pico_stricmp(p->token,"diffuse")) - { - picoColor_t color; - picoVec3_t v; - - /* get vector from parser */ - if (!_pico_parse_vec( p,v )) _prm_error_return; - - /* store as color */ - color[ 0 ] = (picoByte_t)v[ 0 ]; - color[ 1 ] = (picoByte_t)v[ 1 ]; - color[ 2 ] = (picoByte_t)v[ 2 ]; - - /* set new ambient color */ - PicoSetShaderDiffuseColor( shader,color ); - } - /* remap shader's specular color */ - else if (!_pico_stricmp(p->token,"specular")) - { - picoColor_t color; - picoVec3_t v; - - /* get vector from parser */ - if (!_pico_parse_vec( p,v )) _prm_error_return; - - /* store as color */ - color[ 0 ] = (picoByte_t)v[ 0 ]; - color[ 1 ] = (picoByte_t)v[ 1 ]; - color[ 2 ] = (picoByte_t)v[ 2 ]; - - /* set new ambient color */ - PicoSetShaderSpecularColor( shader,color ); - } - /* skip rest */ - _pico_parse_skip_rest( p ); - } - } - /* end 'materials[' */ - } - - /* free both parser and file buffer */ - _pico_free_parser( p ); - _pico_free_file( remapBuffer ); - - /* return with success */ - return 1; -} - - -/* -PicoAddTriangleToModel() - jhefty -A nice way to add individual triangles to the model. -Chooses an appropriate surface based on the shader, or adds a new surface if necessary -*/ - -void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, - int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, - picoShader_t* shader ) -{ - int i,j; - int vertDataIndex; - picoSurface_t* workSurface = NULL; - - /* see if a surface already has the shader */ - for ( i = 0 ; i < model->numSurfaces ; i++ ) - { - workSurface = model->surface[i]; - if ( workSurface->shader == shader ) - { - break; - } - } - - /* no surface uses this shader yet, so create a new surface */ - if ( !workSurface || i >=model->numSurfaces ) - { - /* create a new surface in the model for the unique shader */ - workSurface = PicoNewSurface(model); - if ( !workSurface ) - { - _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" ); - return; - } - - /* do surface setup */ - PicoSetSurfaceType( workSurface, PICO_TRIANGLES ); - PicoSetSurfaceName( workSurface, shader->name ); - PicoSetSurfaceShader( workSurface, shader ); - } - - /* add the triangle data to the surface */ - for ( i = 0 ; i < 3 ; i++ ) - { - /* get the next free spot in the index array */ - int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface ); - - /* get the index of the vertex that we're going to store at newVertIndex */ - vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i]); - - /* the vertex wasn't found, so create a new vertex in the pool from the data we have */ - if ( vertDataIndex == -1 ) - { - /* find the next spot for a new vertex */ - vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface ); - - /* assign the data to it */ - PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] ); - PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] ); - - /* make sure to copy over all available ST's and colors for the vertex */ - for ( j = 0 ; j < numColors ; j++ ) - { - PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] ); - } - for ( j = 0 ; j < numSTs ; j++ ) - { - PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] ); - } - } - - /* add this vertex to the triangle */ - PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex ); - } -} +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOMODEL_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* +PicoInit() +initializes the picomodel library +*/ + +int PicoInit( void ) +{ + /* successfully initialized -sea */ + return 1; +} + + + +/* +PicoShutdown() +shuts the pico model library down +*/ + +void PicoShutdown( void ) +{ + /* do something interesting here in the future */ + return; +} + + + +/* +PicoError() +returns last picomodel error code (see PME_* defines) +*/ + +int PicoError( void ) +{ + /* todo: do something here */ + return 0; +} + + + +/* +PicoSetMallocFunc() +sets the ptr to the malloc function +*/ + +void PicoSetMallocFunc( void *(*func)( size_t ) ) +{ + if( func != NULL ) + _pico_ptr_malloc = func; +} + + + +/* +PicoSetFreeFunc() +sets the ptr to the free function +*/ + +void PicoSetFreeFunc( void (*func)( void* ) ) +{ + if( func != NULL ) + _pico_ptr_free = func; +} + + + +/* +PicoSetLoadFileFunc() +sets the ptr to the file load function +*/ + +void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ) +{ + if( func != NULL ) + _pico_ptr_load_file = func; +} + + + +/* +PicoSetFreeFileFunc() +sets the ptr to the free function +*/ + +void PicoSetFreeFileFunc( void (*func)( void* ) ) +{ + if( func != NULL ) + _pico_ptr_free_file = func; +} + + + +/* +PicoSetPrintFunc() +sets the ptr to the print function +*/ + +void PicoSetPrintFunc( void (*func)( int, const char* ) ) +{ + if( func != NULL ) + _pico_ptr_print = func; +} + + + +/* +PicoLoadModel() +the meat and potatoes function +*/ + +picoModel_t *PicoLoadModel( char *fileName, int frameNum ) +{ + const picoModule_t **modules, *pm; + picoModel_t *model; + picoByte_t *buffer; + int bufSize; + char *modelFileName, *remapFileName; + + + /* init */ + model = NULL; + + /* make sure we've got a file name */ + if( fileName == NULL ) + { + _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" ); + return NULL; + } + + /* load file data (buffer is allocated by host app) */ + _pico_load_file( fileName, &buffer, &bufSize ); + if( bufSize < 0 ) + { + _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName ); + return NULL; + } + + /* get ptr to list of supported modules */ + modules = PicoModuleList( NULL ); + + /* run it through the various loader functions and try */ + /* to find a loader that fits the given file data */ + for( ; *modules != NULL; modules++ ) + { + /* get module */ + pm = *modules; + + /* sanity check */ + if( pm == NULL) + break; + + /* module must be able to load */ + if( pm->canload == NULL || pm->load == NULL ) + continue; + + /* see whether this module can load the model file or not */ + if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) + { + /* use loader provided by module to read the model data */ + model = pm->load( fileName, frameNum, buffer, bufSize ); + if( model == NULL ) + { + _pico_free_file( buffer ); + return NULL; + } + + /* assign pointer to file format module */ + model->module = pm; + + /* get model file name */ + modelFileName = PicoGetModelFileName( model ); + + /* apply model remappings from .remap */ + if( strlen( modelFileName ) ) + { + /* alloc copy of model file name */ + remapFileName = _pico_alloc( strlen( modelFileName ) + 20 ); + if( remapFileName != NULL ) + { + /* copy model file name and change extension */ + strcpy( remapFileName, modelFileName ); + _pico_setfext( remapFileName, "remap" ); + + /* try to remap model; we don't handle the result */ + PicoRemapModel( model, remapFileName ); + + /* free the remap file name string */ + _pico_free( remapFileName ); + } + } + + /* model was loaded, so break out of loop */ + break; + } + } + + /* free memory used by file buffer */ + if( buffer) + _pico_free_file( buffer ); + + /* return */ + return model; +} + + + +/* ---------------------------------------------------------------------------- +models +---------------------------------------------------------------------------- */ + +/* +PicoNewModel() +creates a new pico model +*/ + +picoModel_t *PicoNewModel( void ) +{ + picoModel_t *model; + + /* allocate */ + model = _pico_alloc( sizeof(picoModel_t) ); + if( model == NULL ) + return NULL; + + /* clear */ + memset( model,0,sizeof(picoModel_t) ); + + /* model set up */ + _pico_zero_bounds( model->mins,model->maxs ); + + /* set initial frame count to 1 -sea */ + model->numFrames = 1; + + /* return ptr to new model */ + return model; +} + + + +/* +PicoFreeModel() +frees a model and all associated data +*/ + +void PicoFreeModel( picoModel_t *model ) +{ + int i; + + + /* sanity check */ + if( model == NULL ) + return; + + /* free bits */ + if( model->name ) + _pico_free( model->name ); + + /* free shaders */ + for( i = 0; i < model->numShaders; i++ ) + PicoFreeShader( model->shader[ i ] ); + free( model->shader ); + + /* free surfaces */ + for( i = 0; i < model->numSurfaces; i++ ) + PicoFreeSurface( model->surface[ i ] ); + free( model->surface ); + + /* free the model */ + _pico_free( model ); +} + + + +/* +PicoAdjustModel() +adjusts a models's memory allocations to handle the requested sizes. +will always grow, never shrink +*/ + +int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ) +{ + /* dummy check */ + if( model == NULL ) + return 0; + + /* bare minimums */ + /* sea: null surface/shader fix (1s=>0s) */ + if( numShaders < 0 ) + numShaders = 0; + if( numSurfaces < 0 ) + numSurfaces = 0; + + /* additional shaders? */ + while( numShaders > model->maxShaders ) + { + model->maxShaders += PICO_GROW_SHADERS; + if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) + return 0; + } + + /* set shader count to higher */ + if( numShaders > model->numShaders ) + model->numShaders = numShaders; + + /* additional surfaces? */ + while( numSurfaces > model->maxSurfaces ) + { + model->maxSurfaces += PICO_GROW_SURFACES; + if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) + return 0; + } + + /* set shader count to higher */ + if( numSurfaces > model->numSurfaces ) + model->numSurfaces = numSurfaces; + + /* return ok */ + return 1; +} + + + +/* ---------------------------------------------------------------------------- +shaders +---------------------------------------------------------------------------- */ + +/* +PicoNewShader() +creates a new pico shader and returns its index. -sea +*/ + +picoShader_t *PicoNewShader( picoModel_t *model ) +{ + picoShader_t *shader; + + + /* allocate and clear */ + shader = _pico_alloc( sizeof(picoShader_t) ); + if( shader == NULL ) + return NULL; + memset( shader, 0, sizeof(picoShader_t) ); + + /* attach it to the model */ + if( model != NULL ) + { + /* adjust model */ + if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) + { + _pico_free( shader ); + return NULL; + } + /* attach */ + model->shader[ model->numShaders - 1 ] = shader; + shader->model = model; + } + /* setup default shader colors */ + _pico_set_color( shader->ambientColor,0,0,0,0 ); + _pico_set_color( shader->diffuseColor,255,255,255,1 ); + _pico_set_color( shader->specularColor,0,0,0,0 ); + + /* no need to do this, but i do it anyway */ + shader->transparency = 0; + shader->shininess = 0; + + /* return the newly created shader */ + return shader; +} + + + +/* +PicoFreeShader() +frees a shader and all associated data -sea +*/ + +void PicoFreeShader( picoShader_t *shader ) +{ + /* dummy check */ + if( shader == NULL ) + return; + + /* free bits */ + if( shader->name ) + _pico_free( shader->name ); + if( shader->mapName ) + _pico_free( shader->mapName ); + + /* free the shader */ + _pico_free( shader ); +} + + + +/* +PicoFindShader() +finds a named shader in a model +*/ + +picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ) +{ + int i; + + + /* sanity checks */ + if( model == NULL || name == NULL ) /* sea: null name fix */ + return NULL; + + /* walk list */ + for( i = 0; i < model->numShaders; i++ ) + { + /* skip null shaders or shaders with null names */ + if( model->shader[ i ] == NULL || + model->shader[ i ]->name == NULL ) + continue; + + /* compare the shader name with name we're looking for */ + if( caseSensitive ) + { + if( !strcmp( name, model->shader[ i ]->name ) ) + return model->shader[ i ]; + } + else if( !_pico_stricmp( name, model->shader[ i ]->name ) ) + return model->shader[ i ]; + } + + /* named shader not found */ + return NULL; +} + + + +/* ---------------------------------------------------------------------------- +surfaces +---------------------------------------------------------------------------- */ + +/* +PicoNewSurface() +creates a new pico surface +*/ + +picoSurface_t *PicoNewSurface( picoModel_t *model ) +{ + picoSurface_t *surface; + char surfaceName[64]; + + /* allocate and clear */ + surface = _pico_alloc( sizeof( *surface ) ); + if( surface == NULL ) + return NULL; + memset( surface, 0, sizeof( *surface ) ); + + /* attach it to the model */ + if( model != NULL ) + { + /* adjust model */ + if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) ) + { + _pico_free( surface ); + return NULL; + } + + /* attach */ + model->surface[ model->numSurfaces - 1 ] = surface; + surface->model = model; + + /* set default name */ + sprintf( surfaceName, "Unnamed_%d", model->numSurfaces ); + PicoSetSurfaceName( surface, surfaceName ); + } + + /* return */ + return surface; +} + + + +/* +PicoFreeSurface() +frees a surface and all associated data +*/ +void PicoFreeSurface( picoSurface_t *surface ) +{ + int i; + + + /* dummy check */ + if( surface == NULL ) + return; + + /* free bits */ + _pico_free( surface->xyz ); + _pico_free( surface->normal ); + _pico_free( surface->index ); + _pico_free( surface->faceNormal ); + + /* free arrays */ + for( i = 0; i < surface->numSTArrays; i++ ) + _pico_free( surface->st[ i ] ); + free( surface->st ); + for( i = 0; i < surface->numColorArrays; i++ ) + _pico_free( surface->color[ i ] ); + free( surface->color ); + + /* free the surface */ + _pico_free( surface ); +} + + + +/* +PicoAdjustSurface() +adjusts a surface's memory allocations to handle the requested sizes. +will always grow, never shrink +*/ + +int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ) +{ + int i; + + + /* dummy check */ + if( surface == NULL ) + return 0; + + /* bare minimums */ + if( numVertexes < 1 ) + numVertexes = 1; + if( numSTArrays < 1 ) + numSTArrays = 1; + if( numColorArrays < 1 ) + numColorArrays = 1; + if( numIndexes < 1 ) + numIndexes = 1; + + /* additional vertexes? */ + while( numVertexes > surface->maxVertexes ) /* fix */ + { + surface->maxVertexes += PICO_GROW_VERTEXES; + if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) + return 0; + if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) + return 0; + for( i = 0; i < surface->numSTArrays; i++ ) + if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) + return 0; + for( i = 0; i < surface->numColorArrays; i++ ) + if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) + return 0; + } + + /* set vertex count to higher */ + if( numVertexes > surface->numVertexes ) + surface->numVertexes = numVertexes; + + /* additional st arrays? */ + while( numSTArrays > surface->maxSTArrays ) /* fix */ + { + surface->maxSTArrays += PICO_GROW_ARRAYS; + if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) + return 0; + while( surface->numSTArrays < numSTArrays ) + { + surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); + memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); + surface->numSTArrays++; + } + } + + /* additional color arrays? */ + while( numColorArrays > surface->maxColorArrays ) /* fix */ + { + surface->maxColorArrays += PICO_GROW_ARRAYS; + if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) + return 0; + while( surface->numColorArrays < numColorArrays ) + { + surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); + memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); + surface->numColorArrays++; + } + } + + /* additional indexes? */ + while( numIndexes > surface->maxIndexes ) /* fix */ + { + surface->maxIndexes += PICO_GROW_INDEXES; + if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) + return 0; + } + + /* set index count to higher */ + if( numIndexes > surface->numIndexes ) + surface->numIndexes = numIndexes; + + /* additional face normals? */ + while( numFaceNormals > surface->maxFaceNormals ) /* fix */ + { + surface->maxFaceNormals += PICO_GROW_FACES; + if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) + return 0; + } + + /* set face normal count to higher */ + if( numFaceNormals > surface->numFaceNormals ) + surface->numFaceNormals = numFaceNormals; + + /* return ok */ + return 1; +} + + +/* PicoFindSurface: + * Finds first matching named surface in a model. + */ +picoSurface_t *PicoFindSurface( + picoModel_t *model, char *name, int caseSensitive ) +{ + int i; + + /* sanity check */ + if( model == NULL || name == NULL ) + return NULL; + + /* walk list */ + for( i = 0; i < model->numSurfaces; i++ ) + { + /* skip null surfaces or surfaces with null names */ + if( model->surface[ i ] == NULL || + model->surface[ i ]->name == NULL ) + continue; + + /* compare the surface name with name we're looking for */ + if (caseSensitive) { + if( !strcmp(name,model->surface[ i ]->name) ) + return model->surface[ i ]; + } else { + if( !_pico_stricmp(name,model->surface[ i ]->name) ) + return model->surface[ i ]; + } + } + /* named surface not found */ + return NULL; +} + + + +/*---------------------------------------------------------------------------- + PicoSet*() Setter Functions +----------------------------------------------------------------------------*/ + +void PicoSetModelName( picoModel_t *model, char *name ) +{ + if( model == NULL || name == NULL ) + return; + if( model->name != NULL ) + _pico_free( model->name ); + + model->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetModelFileName( picoModel_t *model, char *fileName ) +{ + if( model == NULL || fileName == NULL ) + return; + if( model->fileName != NULL ) + _pico_free( model->fileName ); + + model->fileName = _pico_clone_alloc( fileName,-1 ); +} + + + +void PicoSetModelFrameNum( picoModel_t *model, int frameNum ) +{ + if( model == NULL ) + return; + model->frameNum = frameNum; +} + + + +void PicoSetModelNumFrames( picoModel_t *model, int numFrames ) +{ + if( model == NULL ) + return; + model->numFrames = numFrames; +} + + + +void PicoSetModelData( picoModel_t *model, void *data ) +{ + if( model == NULL ) + return; + model->data = data; +} + + + +void PicoSetShaderName( picoShader_t *shader, char *name ) +{ + if( shader == NULL || name == NULL ) + return; + if( shader->name != NULL ) + _pico_free( shader->name ); + + shader->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetShaderMapName( picoShader_t *shader, char *mapName ) +{ + if( shader == NULL || mapName == NULL ) + return; + if( shader->mapName != NULL ) + _pico_free( shader->mapName ); + + shader->mapName = _pico_clone_alloc( mapName,-1 ); +} + + + +void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->ambientColor[ 0 ] = color[ 0 ]; + shader->ambientColor[ 1 ] = color[ 1 ]; + shader->ambientColor[ 2 ] = color[ 2 ]; + shader->ambientColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->diffuseColor[ 0 ] = color[ 0 ]; + shader->diffuseColor[ 1 ] = color[ 1 ]; + shader->diffuseColor[ 2 ] = color[ 2 ]; + shader->diffuseColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->specularColor[ 0 ] = color[ 0 ]; + shader->specularColor[ 1 ] = color[ 1 ]; + shader->specularColor[ 2 ] = color[ 2 ]; + shader->specularColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderTransparency( picoShader_t *shader, float value ) +{ + if( shader == NULL ) + return; + shader->transparency = value; + + /* cap to 0..1 range */ + if (shader->transparency < 0.0) + shader->transparency = 0.0; + if (shader->transparency > 1.0) + shader->transparency = 1.0; +} + + + +void PicoSetShaderShininess( picoShader_t *shader, float value ) +{ + if( shader == NULL ) + return; + shader->shininess = value; + + /* cap to 0..127 range */ + if (shader->shininess < 0.0) + shader->shininess = 0.0; + if (shader->shininess > 127.0) + shader->shininess = 127.0; +} + + + +void PicoSetSurfaceData( picoSurface_t *surface, void *data ) +{ + if( surface == NULL ) + return; + surface->data = data; +} + + + +void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ) +{ + if( surface == NULL ) + return; + surface->type = type; +} + + + +void PicoSetSurfaceName( picoSurface_t *surface, char *name ) +{ + if( surface == NULL || name == NULL ) + return; + if( surface->name != NULL ) + _pico_free( surface->name ); + + surface->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ) +{ + if( surface == NULL ) + return; + surface->shader = shader; +} + + + +void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ) +{ + if( surface == NULL || num < 0 || xyz == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) + return; + _pico_copy_vec( xyz, surface->xyz[ num ] ); + if( surface->model != NULL ) + _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs ); +} + + + +void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) +{ + if( surface == NULL || num < 0 || normal == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) + return; + _pico_copy_vec( normal, surface->normal[ num ] ); +} + + + +void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ) +{ + if( surface == NULL || num < 0 || st == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) + return; + surface->st[ array ][ num ][ 0 ] = st[ 0 ]; + surface->st[ array ][ num ][ 1 ] = st[ 1 ]; +} + + + +void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ) +{ + if( surface == NULL || num < 0 || color == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) + return; + surface->color[ array ][ num ][ 0 ] = color[ 0 ]; + surface->color[ array ][ num ][ 1 ] = color[ 1 ]; + surface->color[ array ][ num ][ 2 ] = color[ 2 ]; + surface->color[ array ][ num ][ 3 ] = color[ 3 ]; +} + + + +void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ) +{ + if( surface == NULL || num < 0 ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) + return; + surface->index[ num ] = index; +} + + + +void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ) +{ + if( num < 0 || index == NULL || count < 1 ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) + return; + memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) ); +} + + + +void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) +{ + if( surface == NULL || num < 0 || normal == NULL ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) + return; + _pico_copy_vec( normal, surface->faceNormal[ num ] ); +} + + +void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ) +{ + if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) + return; + surface->special[ num ] = special; +} + + + +/*---------------------------------------------------------------------------- + PicoGet*() Getter Functions +----------------------------------------------------------------------------*/ + +char *PicoGetModelName( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + if( model->name == NULL) + return (char*) ""; + return model->name; +} + + + +char *PicoGetModelFileName( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + if( model->fileName == NULL) + return (char*) ""; + return model->fileName; +} + + + +int PicoGetModelFrameNum( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->frameNum; +} + + + +int PicoGetModelNumFrames( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numFrames; +} + + + +void *PicoGetModelData( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + return model->data; +} + + + +int PicoGetModelNumShaders( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numShaders; +} + + + +picoShader_t *PicoGetModelShader( picoModel_t *model, int num ) +{ + /* a few sanity checks */ + if( model == NULL ) + return NULL; + if( model->shader == NULL) + return NULL; + if( num < 0 || num >= model->numShaders ) + return NULL; + + /* return the shader */ + return model->shader[ num ]; +} + + + +int PicoGetModelNumSurfaces( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numSurfaces; +} + + + +picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ) +{ + /* a few sanity checks */ + if( model == NULL ) + return NULL; + if( model->surface == NULL) + return NULL; + if( num < 0 || num >= model->numSurfaces ) + return NULL; + + /* return the surface */ + return model->surface[ num ]; +} + + + +int PicoGetModelTotalVertexes( picoModel_t *model ) +{ + int i, count; + + + if( model == NULL ) + return 0; + if( model->surface == NULL ) + return 0; + + count = 0; + for( i = 0; i < model->numSurfaces; i++ ) + count += PicoGetSurfaceNumVertexes( model->surface[ i ] ); + + return count; +} + + + +int PicoGetModelTotalIndexes( picoModel_t *model ) +{ + int i, count; + + + if( model == NULL ) + return 0; + if( model->surface == NULL ) + return 0; + + count = 0; + for( i = 0; i < model->numSurfaces; i++ ) + count += PicoGetSurfaceNumIndexes( model->surface[ i ] ); + + return count; +} + + + +char *PicoGetShaderName( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + if( shader->name == NULL) + return (char*) ""; + return shader->name; +} + + + +char *PicoGetShaderMapName( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + if( shader->mapName == NULL) + return (char*) ""; + return shader->mapName; +} + + + +picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->ambientColor; +} + + + +picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->diffuseColor; +} + + + +picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->specularColor; +} + + + +float PicoGetShaderTransparency( picoShader_t *shader ) +{ + if( shader == NULL ) + return 0.0f; + return shader->transparency; +} + + + +float PicoGetShaderShininess( picoShader_t *shader ) +{ + if( shader == NULL ) + return 0.0f; + return shader->shininess; +} + + + +void *PicoGetSurfaceData( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + return surface->data; +} + + + +picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ) +{ + if( surface == NULL ) + return PICO_BAD; + return surface->type; +} + + + +char *PicoGetSurfaceName( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + if( surface->name == NULL ) + return (char*) ""; + return surface->name; +} + + + +picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + return surface->shader; +} + + + +int PicoGetSurfaceNumVertexes( picoSurface_t *surface ) +{ + if( surface == NULL ) + return 0; + return surface->numVertexes; +} + + + +picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->xyz[ num ]; +} + + + +picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->normal[ num ]; +} + + + +picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ) +{ + if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->st[ array ][ num ]; +} + + + +picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ) +{ + if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->color[ array ][ num ]; +} + + + +int PicoGetSurfaceNumIndexes( picoSurface_t *surface ) +{ + if( surface == NULL ) + return 0; + return surface->numIndexes; +} + + + +picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numIndexes ) + return 0; + return surface->index[ num ]; +} + + + +picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numIndexes ) + return NULL; + return &surface->index[ num ]; +} + + +picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numFaceNormals ) + return NULL; + return surface->faceNormal[ num ]; +} + + +int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) + return 0; + return surface->special[ num ]; +} + + + +/* ---------------------------------------------------------------------------- +hashtable related functions +---------------------------------------------------------------------------- */ + +/* hashtable code for faster vertex lookups */ +//#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */ +#define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */ + +int PicoGetHashTableSize( void ) +{ + return HASHTABLE_SIZE; +} + +#define HASH_USE_EPSILON + +#ifdef HASH_USE_EPSILON +#define HASH_XYZ_EPSILON 0.01f +#define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON +#define HASH_ST_EPSILON 0.0001f +#define HASH_NORMAL_EPSILON 0.02f +#endif + +unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ) +{ + unsigned int hash = 0; + +#ifndef HASH_USE_EPSILON + hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15); + hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10); + hash += (*((unsigned int*) &xyz[ 1 ]) << 3); + hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6); + hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11); + hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16); +#else + picoVec3_t xyz_epsilonspace; + + _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace ); + xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]); + xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]); + xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]); + + hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10); + hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6); + hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16); +#endif + + //hash = hash & (HASHTABLE_SIZE-1); + hash = hash % (HASHTABLE_SIZE); + return hash; +} + +picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ) +{ + picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); + + memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); + + return hashTable; +} + +void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ) +{ + int i; + picoVertexCombinationHash_t *vertexCombinationHash; + picoVertexCombinationHash_t *nextVertexCombinationHash; + + /* dummy check */ + if (hashTable == NULL) + return; + + for( i = 0; i < HASHTABLE_SIZE; i++ ) + { + if (hashTable[ i ]) + { + nextVertexCombinationHash = NULL; + + for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash ) + { + nextVertexCombinationHash = vertexCombinationHash->next; + if (vertexCombinationHash->data != NULL) + { + _pico_free( vertexCombinationHash->data ); + } + _pico_free( vertexCombinationHash ); + } + } + } + + _pico_free( hashTable ); +} + +picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ) +{ + unsigned int hash; + picoVertexCombinationHash_t *vertexCombinationHash; + + /* dumy check */ + if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) + return NULL; + + hash = PicoVertexCoordGenerateHash( xyz ); + + for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next ) + { +#ifndef HASH_USE_EPSILON + /* check xyz */ + if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) ) + continue; + + /* check normal */ + if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) ) + continue; + + /* check st */ + if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) + continue; +#else + /* check xyz */ + if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON || + ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON || + ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON ) + continue; + + /* check normal */ + if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON || + ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON || + ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON ) + continue; + + /* check st */ + if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON || + ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON ) + continue; +#endif + + /* check color */ + if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) ) + continue; + + /* gotcha */ + return vertexCombinationHash; + } + + return NULL; +} + +picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ) +{ + unsigned int hash; + picoVertexCombinationHash_t *vertexCombinationHash; + + /* dumy check */ + if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) + return NULL; + + vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) ); + + if (!vertexCombinationHash) + return NULL; + + hash = PicoVertexCoordGenerateHash( xyz ); + + _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz ); + _pico_copy_vec( normal, vertexCombinationHash->vcd.normal ); + _pico_copy_vec2( st, vertexCombinationHash->vcd.st ); + _pico_copy_color( color, vertexCombinationHash->vcd.color ); + vertexCombinationHash->index = index; + vertexCombinationHash->data = NULL; + vertexCombinationHash->next = hashTable[ hash ]; + hashTable[ hash ] = vertexCombinationHash; + + return vertexCombinationHash; +} + +/* ---------------------------------------------------------------------------- +specialized routines +---------------------------------------------------------------------------- */ + +/* +PicoFindSurfaceVertex() +finds a vertex matching the set parameters +fixme: needs non-naive algorithm +*/ + +int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ) +{ + int i, j; + + + /* dummy check */ + if( surface == NULL || surface->numVertexes <= 0 ) + return -1; + + /* walk vertex list */ + for( i = 0; i < surface->numVertexes; i++ ) + { + /* check xyz */ + if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) ) + continue; + + /* check normal */ + if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) ) + continue; + + /* check st */ + if( numSTs > 0 && st != NULL ) + { + for( j = 0; j < numSTs; j++ ) + { + if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) + break; + } + if( j != numSTs ) + continue; + } + + /* check color */ + if( numColors > 0 && color != NULL ) + { + for( j = 0; j < numSTs; j++ ) + { + if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) ) + break; + } + if( j != numColors ) + continue; + } + + /* vertex matches */ + return i; + } + + /* nada */ + return -1; +} + + + +/* +PicoFixSurfaceNormals() +fixes broken normals (certain formats bork normals) +*/ + +#define MAX_NORMAL_VOTES 128 +#define EQUAL_NORMAL_EPSILON 0.01 +#define BAD_NORMAL_EPSILON 0.5 + +void PicoFixSurfaceNormals( picoSurface_t *surface ) +{ + int i, j, k, a, b, c, numVotes, faceIndex; + picoVec3_t votes[ MAX_NORMAL_VOTES ]; + picoVec3_t *normals, diff; + picoVec4_t plane; + + + /* dummy check */ + if( surface == NULL || surface->numVertexes == 0 ) + return; + + /* fixme: handle other surface types */ + if( surface->type != PICO_TRIANGLES ) + return; + + /* allocate normal storage */ + normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) ); + if( normals == NULL ) + { + _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" ); + return; + } + + /* zero it out */ + memset( normals, 0, surface->numVertexes * sizeof( *normals ) ); + + /* walk vertex list */ + for( i = 0; i < surface->numVertexes; i++ ) + { + /* zero out votes */ + numVotes = 0; + + /* find all the triangles that reference this vertex */ + for( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ ) + { + /* get triangle */ + a = surface->index[ j ]; + b = surface->index[ j + 1 ]; + c = surface->index[ j + 2 ]; + + /* ignore degenerate triangles */ + if( a == b || b == c || c == a ) + continue; + + /* ignore indexes out of range */ + if( a < 0 || a >= surface->numVertexes || + b < 0 || b >= surface->numVertexes || + c < 0 || c >= surface->numVertexes ) + continue; + + /* test triangle */ + if( a == i || b == i || c == i ) + { + /* if this surface has face normals */ + if( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) + { + _pico_copy_vec( surface->faceNormal[ faceIndex ], plane ); + if( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) + { + /* if null normal, make plane from the 3 points */ + if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) + { + continue; + } + } + } + /* make a plane from the 3 points */ + else if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) + { + continue; + } + + /* see if this normal has already been voted */ + for( k = 0; k < numVotes; k++ ) + { + _pico_subtract_vec( plane, votes[ k ], diff ); + if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) + break; + } + + /* add a new vote? */ + if( k == numVotes && numVotes < MAX_NORMAL_VOTES ) + { + _pico_copy_vec( plane, votes[ numVotes ] ); + numVotes++; + } + } + } + + /* tally votes */ + if( numVotes > 0 ) + { + /* create average normal */ + _pico_zero_vec( normals[ i ] ); + for( k = 0; k < numVotes; k++ ) + _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] ); + + /* normalize it */ + if( _pico_normalize_vec( normals[ i ] ) ) + { + /* test against actual normal */ + if( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) + { + //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i, + //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ], + //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] ); + _pico_copy_vec( normals[ i ], surface->normal[ i ] ); + } + } + } + } + + /* free normal storage */ + _pico_free( normals ); +} + + + + +/* +PicoRemapModel() - sea +remaps model material/etc. information using the remappings +contained in the given 'remapFile' (full path to the ascii file to open) +returns 1 on success or 0 on error +*/ + +#define _prm_error_return \ +{ \ + _pico_free_parser( p ); \ + _pico_free_file( remapBuffer ); \ + return 0; \ +} + +int PicoRemapModel( picoModel_t *model, char *remapFile ) +{ + picoParser_t *p; + picoByte_t *remapBuffer; + int remapBufSize; + + + /* sanity checks */ + if( model == NULL || remapFile == NULL ) + return 0; + + /* load remap file contents */ + _pico_load_file( remapFile,&remapBuffer,&remapBufSize ); + + /* check result */ + if( remapBufSize == 0 ) + return 1; /* file is empty: no error */ + if( remapBufSize < 0 ) + return 0; /* load failed: error */ + + /* create a new pico parser */ + p = _pico_new_parser( remapBuffer, remapBufSize ); + if (p == NULL) + { + /* ram is really cheap nowadays... */ + _prm_error_return; + } + + /* doo teh parse */ + while( 1 ) + { + /* get next token in remap file */ + if (!_pico_parse( p,1 )) + break; + + /* skip over c++ style comment lines */ + if (!_pico_stricmp(p->token,"//")) + { + _pico_parse_skip_rest( p ); + continue; + } + + /* block for quick material shader name remapping */ + /* materials { "m" (=>|->|=) "s" } */ + if( !_pico_stricmp(p->token, "materials" ) ) + { + int level = 1; + + /* check bracket */ + if (!_pico_parse_check( p,1,"{" )) + _prm_error_return; + + /* process assignments */ + while( 1 ) + { + picoShader_t *shader; + char *materialName; + + + /* get material name */ + if (_pico_parse( p,1 ) == NULL) break; + if (!strlen(p->token)) continue; + materialName = _pico_clone_alloc( p->token,-1 ); + if (materialName == NULL) + _prm_error_return; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + /* get next token (assignment token or shader name) */ + if (!_pico_parse( p,0 )) + { + _pico_free( materialName ); + _prm_error_return; + } + /* skip assignment token (if present) */ + if (!strcmp(p->token,"=>") || + !strcmp(p->token,"->") || + !strcmp(p->token,"=")) + { + /* simply grab the next token */ + if (!_pico_parse( p,0 )) + { + _pico_free( materialName ); + _prm_error_return; + } + } + /* try to find material by name */ + shader = PicoFindShader( model,materialName,0 ); + + /* we've found a material matching the name */ + if (shader != NULL) + { + PicoSetShaderName( shader,p->token ); + } + /* free memory used by material name */ + _pico_free( materialName ); + + /* skip rest */ + _pico_parse_skip_rest( p ); + } + } + /* block for detailed single material remappings */ + /* materials[ "m" ] { key data... } */ + else if (!_pico_stricmp(p->token,"materials[")) + { + picoShader_t *shader; + char *tempMaterialName; + int level = 1; + + /* get material name */ + if (!_pico_parse( p,0 )) + _prm_error_return; + + /* temporary copy of material name */ + tempMaterialName = _pico_clone_alloc( p->token,-1 ); + if (tempMaterialName == NULL) + _prm_error_return; + + /* check square closing bracket */ + if (!_pico_parse_check( p,0,"]" )) + _prm_error_return; + + /* try to find material by name */ + shader = PicoFindShader( model,tempMaterialName,0 ); + + /* free memory used by temporary material name */ + _pico_free( tempMaterialName ); + + /* we haven't found a material matching the name */ + /* so we simply skip the braced section now and */ + /* continue parsing with the next main token */ + if (shader == NULL) + { + _pico_parse_skip_braced( p ); + continue; + } + /* check opening bracket */ + if (!_pico_parse_check( p,1,"{" )) + _prm_error_return; + + /* process material info keys */ + while( 1 ) + { + /* get key name */ + if (_pico_parse( p,1 ) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + /* remap shader name */ + if (!_pico_stricmp(p->token,"shader")) + { + if (!_pico_parse( p,0 )) _prm_error_return; + PicoSetShaderName( shader,p->token ); + } + /* remap shader map name */ + else if (!_pico_stricmp(p->token,"mapname")) + { + if (!_pico_parse( p,0 )) _prm_error_return; + PicoSetShaderMapName( shader,p->token ); + } + /* remap shader's ambient color */ + else if (!_pico_stricmp(p->token,"ambient")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderAmbientColor( shader,color ); + } + /* remap shader's diffuse color */ + else if (!_pico_stricmp(p->token,"diffuse")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderDiffuseColor( shader,color ); + } + /* remap shader's specular color */ + else if (!_pico_stricmp(p->token,"specular")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderSpecularColor( shader,color ); + } + /* skip rest */ + _pico_parse_skip_rest( p ); + } + } + /* end 'materials[' */ + } + + /* free both parser and file buffer */ + _pico_free_parser( p ); + _pico_free_file( remapBuffer ); + + /* return with success */ + return 1; +} + + +/* +PicoAddTriangleToModel() - jhefty +A nice way to add individual triangles to the model. +Chooses an appropriate surface based on the shader, or adds a new surface if necessary +*/ + +void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, + int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, + picoShader_t* shader ) +{ + int i,j; + int vertDataIndex; + picoSurface_t* workSurface = NULL; + + /* see if a surface already has the shader */ + for ( i = 0 ; i < model->numSurfaces ; i++ ) + { + workSurface = model->surface[i]; + if ( workSurface->shader == shader ) + { + break; + } + } + + /* no surface uses this shader yet, so create a new surface */ + if ( !workSurface || i >=model->numSurfaces ) + { + /* create a new surface in the model for the unique shader */ + workSurface = PicoNewSurface(model); + if ( !workSurface ) + { + _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" ); + return; + } + + /* do surface setup */ + PicoSetSurfaceType( workSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( workSurface, shader->name ); + PicoSetSurfaceShader( workSurface, shader ); + } + + /* add the triangle data to the surface */ + for ( i = 0 ; i < 3 ; i++ ) + { + /* get the next free spot in the index array */ + int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface ); + + /* get the index of the vertex that we're going to store at newVertIndex */ + vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i]); + + /* the vertex wasn't found, so create a new vertex in the pool from the data we have */ + if ( vertDataIndex == -1 ) + { + /* find the next spot for a new vertex */ + vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface ); + + /* assign the data to it */ + PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] ); + PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] ); + + /* make sure to copy over all available ST's and colors for the vertex */ + for ( j = 0 ; j < numColors ; j++ ) + { + PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] ); + } + for ( j = 0 ; j < numSTs ; j++ ) + { + PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] ); + } + } + + /* add this vertex to the triangle */ + PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex ); + } +} diff --git a/libs/picomodel/picomodules.c b/libs/picomodel/picomodules.c index 060912f5..add477b5 100644 --- a/libs/picomodel/picomodules.c +++ b/libs/picomodel/picomodules.c @@ -1,92 +1,92 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define PICOMODULES_C - - - -/* dependencies */ -#include "picointernal.h" - - - -/* external modules */ -extern const picoModule_t picoModuleMD3; -extern const picoModule_t picoModule3DS; -extern const picoModule_t picoModuleASE; -extern const picoModule_t picoModuleOBJ; -extern const picoModule_t picoModuleMS3D; -extern const picoModule_t picoModuleMDC; -extern const picoModule_t picoModuleMD2; -extern const picoModule_t picoModuleFM; -extern const picoModule_t picoModuleLWO; - - - -/* list of all supported file format modules */ -const picoModule_t *picoModules[] = -{ - &picoModuleMD3, /* quake3 arena md3 */ - &picoModule3DS, /* autodesk 3ds */ - &picoModuleASE, /* autodesk ase */ - &picoModuleMS3D, /* milkshape3d */ - &picoModuleMDC, /* return to castle wolfenstein mdc */ - &picoModuleMD2, /* quake2 md2 */ - &picoModuleFM, /* heretic2 fm */ - &picoModuleOBJ, /* wavefront object */ - &picoModuleLWO, /* lightwave object */ - NULL /* arnold */ -}; - - - -/* -PicoModuleList() -returns a pointer to the module list and optionally stores -the number of supported modules in 'numModules'. Note that -this param can be NULL when the count is not needed. -*/ - -const picoModule_t **PicoModuleList( int *numModules ) -{ - /* get module count */ - if( numModules != NULL ) - for( (*numModules) = 0; picoModules[ *numModules ] != NULL; (*numModules)++ ); - - /* return list of modules */ - return (const picoModule_t**) picoModules; -} +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOMODULES_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* external modules */ +extern const picoModule_t picoModuleMD3; +extern const picoModule_t picoModule3DS; +extern const picoModule_t picoModuleASE; +extern const picoModule_t picoModuleOBJ; +extern const picoModule_t picoModuleMS3D; +extern const picoModule_t picoModuleMDC; +extern const picoModule_t picoModuleMD2; +extern const picoModule_t picoModuleFM; +extern const picoModule_t picoModuleLWO; + + + +/* list of all supported file format modules */ +const picoModule_t *picoModules[] = +{ + &picoModuleMD3, /* quake3 arena md3 */ + &picoModule3DS, /* autodesk 3ds */ + &picoModuleASE, /* autodesk ase */ + &picoModuleMS3D, /* milkshape3d */ + &picoModuleMDC, /* return to castle wolfenstein mdc */ + &picoModuleMD2, /* quake2 md2 */ + &picoModuleFM, /* heretic2 fm */ + &picoModuleOBJ, /* wavefront object */ + &picoModuleLWO, /* lightwave object */ + NULL /* arnold */ +}; + + + +/* +PicoModuleList() +returns a pointer to the module list and optionally stores +the number of supported modules in 'numModules'. Note that +this param can be NULL when the count is not needed. +*/ + +const picoModule_t **PicoModuleList( int *numModules ) +{ + /* get module count */ + if( numModules != NULL ) + for( (*numModules) = 0; picoModules[ *numModules ] != NULL; (*numModules)++ ); + + /* return list of modules */ + return (const picoModule_t**) picoModules; +} diff --git a/libs/picomodel/pm_3ds.c b/libs/picomodel/pm_3ds.c index 1ad95b1c..0f2b41f7 100644 --- a/libs/picomodel/pm_3ds.c +++ b/libs/picomodel/pm_3ds.c @@ -1,771 +1,771 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define PM_3DS_C - -/* dependencies */ -#include "picointernal.h" - -/* ydnar */ -static picoColor_t white = { 255,255,255,255 }; - -/* remarks: - * - 3ds file version is stored in pico special field 0 on load (ydnar: removed) - * todo: - * - sometimes there is one unnamed surface 0 having 0 verts as - * well as 0 faces. this error occurs since pm 0.6 (ydnar?) - */ -/* uncomment when debugging this module */ -/* #define DEBUG_PM_3DS -#define DEBUG_PM_3DS_EX */ - -/* structure holding persistent 3ds loader specific data used */ -/* to store formerly static vars to keep the module reentrant */ -/* safe. put everything that needs to be static in here. */ -typedef struct S3dsLoaderPers -{ - picoModel_t *model; /* ptr to output model */ - picoSurface_t *surface; /* ptr to current surface */ - picoShader_t *shader; /* ptr to current shader */ - picoByte_t *bufptr; /* ptr to raw data */ - char *basename; /* ptr to model base name (eg. jeep) */ - int cofs; - int maxofs; -} -T3dsLoaderPers; - -/* 3ds chunk types that we use */ -enum { - /* primary chunk */ - CHUNK_MAIN = 0x4D4D, - - /* main chunks */ - CHUNK_VERSION = 0x0002, - CHUNK_EDITOR_CONFIG = 0x3D3E, - CHUNK_EDITOR_DATA = 0x3D3D, - CHUNK_KEYFRAME_DATA = 0xB000, - - /* editor data sub chunks */ - CHUNK_MATERIAL = 0xAFFF, - CHUNK_OBJECT = 0x4000, - - /* material sub chunks */ - CHUNK_MATNAME = 0xA000, - CHUNK_MATDIFFUSE = 0xA020, - CHUNK_MATMAP = 0xA200, - CHUNK_MATMAPFILE = 0xA300, - - /* lets us know we're reading a new object */ - CHUNK_OBJECT_MESH = 0x4100, - - /* object mesh sub chunks */ - CHUNK_OBJECT_VERTICES = 0x4110, - CHUNK_OBJECT_FACES = 0x4120, - CHUNK_OBJECT_MATERIAL = 0x4130, - CHUNK_OBJECT_UV = 0x4140, -}; -#ifdef DEBUG_PM_3DS -static struct -{ - int id; - char *name; -} -debugChunkNames[] = -{ - { CHUNK_MAIN , "CHUNK_MAIN" }, - { CHUNK_VERSION , "CHUNK_VERSION" }, - { CHUNK_EDITOR_CONFIG , "CHUNK_EDITOR_CONFIG" }, - { CHUNK_EDITOR_DATA , "CHUNK_EDITOR_DATA" }, - { CHUNK_KEYFRAME_DATA , "CHUNK_KEYFRAME_DATA" }, - { CHUNK_MATERIAL , "CHUNK_MATERIAL" }, - { CHUNK_OBJECT , "CHUNK_OBJECT" }, - { CHUNK_MATNAME , "CHUNK_MATNAME" }, - { CHUNK_MATDIFFUSE , "CHUNK_MATDIFFUSE" }, - { CHUNK_MATMAP , "CHUNK_MATMAP" }, - { CHUNK_MATMAPFILE , "CHUNK_MATMAPFILE" }, - { CHUNK_OBJECT_MESH , "CHUNK_OBJECT_MESH" }, - { CHUNK_OBJECT_VERTICES , "CHUNK_OBJECT_VERTICES" }, - { CHUNK_OBJECT_FACES , "CHUNK_OBJECT_FACES" }, - { CHUNK_OBJECT_MATERIAL , "CHUNK_OBJECT_MATERIAL" }, - { CHUNK_OBJECT_UV , "CHUNK_OBJECT_UV" }, - { 0 , NULL } -}; -static char *DebugGetChunkName (int id) -{ - int i,max; /* imax? ;) */ - max = sizeof(debugChunkNames) / sizeof(debugChunkNames[0]); - - for (i=0; ilen)) - return PICO_PMV_ERROR_SIZE; - - /* check 3ds magic */ - if (_pico_little_short(chunk->id) != CHUNK_MAIN) - return PICO_PMV_ERROR_IDENT; - - /* file seems to be a valid 3ds */ - return PICO_PMV_OK; -} - -static T3dsChunk *GetChunk (T3dsLoaderPers *pers) -{ - T3dsChunk *chunk; - - /* sanity check */ - if (pers->cofs > pers->maxofs) return 0; - -#ifdef DEBUG_PM_3DS -/* printf("GetChunk: pers->cofs %x\n",pers->cofs); */ -#endif - /* fill in pointer to chunk */ - chunk = (T3dsChunk *)&pers->bufptr[ pers->cofs ]; - if (!chunk) return NULL; - - chunk->id = _pico_little_short(chunk->id ); - chunk->len = _pico_little_long (chunk->len); - - /* advance in buffer */ - pers->cofs += sizeof(T3dsChunk); - - /* this means yay */ - return chunk; -} - -static int GetASCIIZ (T3dsLoaderPers *pers, char *dest, int max) -{ - int pos = 0; - int ch; - - for (;;) - { - ch = pers->bufptr[ pers->cofs++ ]; - if (ch == '\0') break; - if (pers->cofs >= pers->maxofs) - { - dest[ pos ] = '\0'; - return 0; - } - dest[ pos++ ] = ch; - if (pos >= max) break; - } - dest[ pos ] = '\0'; - return 1; -} - -static picoByte_t GetByte (T3dsLoaderPers *pers) -{ - picoByte_t *value; - - /* sanity check */ - if (pers->cofs > pers->maxofs) return 0; - - /* get and return value */ - value = (picoByte_t *)(pers->bufptr + pers->cofs); - pers->cofs += 1; - return *value; -} - -static int GetWord (T3dsLoaderPers *pers) -{ - unsigned short *value; - - /* sanity check */ - if (pers->cofs > pers->maxofs) return 0; - - /* get and return value */ - value = (unsigned short *)(pers->bufptr + pers->cofs); - pers->cofs += 2; - return _pico_little_short(*value); -} - -static float GetFloat (T3dsLoaderPers *pers) -{ - float *value; - - /* sanity check */ - if (pers->cofs > pers->maxofs) return 0; - - /* get and return value */ - value = (float *)(pers->bufptr + pers->cofs); - pers->cofs += 4; - return _pico_little_float(*value); -} - -static int GetMeshVertices (T3dsLoaderPers *pers) -{ - int numVerts; - int i; - - /* get number of verts for this surface */ - numVerts = GetWord(pers); - -#ifdef DEBUG_PM_3DS - printf("GetMeshVertices: numverts %d\n",numVerts); -#endif - /* read in vertices for current surface */ - for (i=0; isurface,i,v ); - PicoSetSurfaceColor( pers->surface,0,i,white ); /* ydnar */ - -#ifdef DEBUG_PM_3DS_EX - printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]); -#endif - } - /* success (no errors occured) */ - return 1; -} - -static int GetMeshFaces (T3dsLoaderPers *pers) -{ - int numFaces; - int i; - - /* get number of faces for this surface */ - numFaces = GetWord(pers); - -#ifdef DEBUG_PM_3DS - printf("GetMeshFaces: numfaces %d\n",numFaces); -#endif - /* read in vertex indices for current surface */ - for (i=0; isurface, (i * 3 + 0), (picoIndex_t)face.a ); - PicoSetSurfaceIndex( pers->surface, (i * 3 + 1), (picoIndex_t)face.b ); - PicoSetSurfaceIndex( pers->surface, (i * 3 + 2), (picoIndex_t)face.c ); - -#ifdef DEBUG_PM_3DS_EX - printf("Face: a: %d b: %d c: %d (%d)\n",face.a,face.b,face.c,face.visible); -#endif - } - /* success (no errors occured) */ - return 1; -} - -static int GetMeshTexCoords (T3dsLoaderPers *pers) -{ - int numTexCoords; - int i; - - /* get number of uv coords for this surface */ - numTexCoords = GetWord(pers); - -#ifdef DEBUG_PM_3DS - printf("GetMeshTexCoords: numcoords %d\n",numTexCoords); -#endif - /* read in uv coords for current surface */ - for (i=0; isurface == NULL) - continue; - - /* add current uv */ - PicoSetSurfaceST( pers->surface,0,i,uv ); - -#ifdef DEBUG_PM_3DS_EX - printf("u: %f v: %f\n",uv[0],uv[1]); -#endif - } - /* success (no errors occured) */ - return 1; -} - -static int GetMeshShader (T3dsLoaderPers *pers) -{ - char shaderName[255] = { 0 }; - picoShader_t *shader; - int numSharedVerts; - int setShaderName = 0; - int i; - - /* the shader is either the color or the texture map of the */ - /* object. it can also hold other information like the brightness, */ - /* shine, etc. stuff we don't really care about. we just want the */ - /* color, or the texture map file name really */ - - /* get in the shader name */ - if (!GetASCIIZ(pers,shaderName,sizeof(shaderName))) - return 0; - - /* now that we have the shader name we need to go through all of */ - /* the shaders and check the name against each shader. when we */ - /* find a shader in our shader list that matches this name we */ - /* just read in, then we assign the shader's id of the object to */ - /* that shader */ - - /* get shader id for shader name */ - shader = PicoFindShader( pers->model, shaderName, 1 ); - - /* we've found a matching shader */ - if ((shader != NULL) && pers->surface) - { - char mapName[1024+1]; - char *mapNamePtr; - memset( mapName,0,sizeof(mapName) ); - - /* get ptr to shader's map name */ - mapNamePtr = PicoGetShaderMapName( shader ); - - /* we have a valid map name ptr */ - if (mapNamePtr != NULL) - { - char temp[128]; - char *name; - - /* copy map name to local buffer */ - strcpy( mapName,mapNamePtr ); - - /* extract file name */ - name = _pico_nopath( mapName ); - strncpy( temp, name, sizeof(temp) ); - - /* remove file extension */ - /* name = _pico_setfext( name,"" ); */ - - /* assign default name if no name available */ - if (strlen(temp) < 1) - strcpy(temp,pers->basename); - - /* build shader name */ - _pico_strlwr( temp ); /* gaynux update -sea */ - sprintf( mapName,"models/mapobjects/%s/%s",pers->basename,temp ); - - /* set shader name */ - /* PicoSetShaderName( shader,mapName ); */ /* ydnar: this will screw up the named shader */ - - /* set surface's shader index */ - PicoSetSurfaceShader( pers->surface, shader ); - - setShaderName = 1; - } - } - /* we didn't set a shader name; throw out warning */ - if (!setShaderName) - { - _pico_printf( PICO_WARNING,"3DS mesh is missing shader name"); - } - /* we don't process the list of shared vertices here; there is a */ - /* short int that gives the number of faces of the mesh concerned */ - /* by this shader, then there is the list itself of these faces. */ - /* 0000 means the first face of the (4120) face list */ - - /* get number of shared verts */ - numSharedVerts = GetWord(pers); - -#ifdef DEBUG_PM_3DS - printf("GetMeshShader: uses shader '%s' (nsv %d)\n",shaderName,numSharedVerts); -#endif - /* skip list of shared verts */ - for (i=0; ishader ) - { - PicoSetShaderDiffuseColor( pers->shader,color ); - } -#ifdef DEBUG_PM_3DS - printf("GetDiffuseColor: %d %d %d\n",color[0],color[1],color[2]); -#endif - /* success (no errors occured) */ - return 1; -} - -static int DoNextEditorDataChunk (T3dsLoaderPers *pers, long endofs) -{ - T3dsChunk *chunk; - -#ifdef DEBUG_PM_3DS_EX - printf("DoNextEditorDataChunk: endofs %d\n",endofs); -#endif - while (pers->cofs < endofs) - { - long nextofs = pers->cofs; - if ((chunk = GetChunk(pers)) == NULL) return 0; - if (!chunk->len) return 0; - nextofs += chunk->len; - -#ifdef DEBUG_PM_3DS_EX - printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); -#endif - /*** meshes ***/ - if (chunk->id == CHUNK_OBJECT) - { - picoSurface_t *surface; - char surfaceName[ 0xff ] = { 0 }; - - /* read in surface name */ - if( !GetASCIIZ(pers,surfaceName,sizeof(surfaceName)) ) - return 0; /* this is bad */ - -//PicoGetSurfaceName - /* ignore NULL name surfaces */ -// if( surfaceName - - /* allocate a pico surface */ - surface = PicoNewSurface( pers->model ); - if( surface == NULL ) - { - pers->surface = NULL; - return 0; /* this is bad too */ - } - /* assign ptr to current surface */ - pers->surface = surface; - - /* 3ds models surfaces are all triangle meshes */ - PicoSetSurfaceType( pers->surface,PICO_TRIANGLES ); - - /* set surface name */ - PicoSetSurfaceName( pers->surface,surfaceName ); - - /* continue mess with object's sub chunks */ - DoNextEditorDataChunk(pers,nextofs); - continue; - } - if (chunk->id == CHUNK_OBJECT_MESH) - { - /* continue mess with mesh's sub chunks */ - if (!DoNextEditorDataChunk(pers,nextofs)) return 0; - continue; - } - if (chunk->id == CHUNK_OBJECT_VERTICES) - { - if (!GetMeshVertices(pers)) return 0; - continue; - } - if (chunk->id == CHUNK_OBJECT_FACES) - { - if (!GetMeshFaces(pers)) return 0; - continue; - } - if (chunk->id == CHUNK_OBJECT_UV) - { - if (!GetMeshTexCoords(pers)) return 0; - continue; - } - if (chunk->id == CHUNK_OBJECT_MATERIAL) - { - if (!GetMeshShader(pers)) return 0; - continue; - } - /*** materials ***/ - if (chunk->id == CHUNK_MATERIAL) - { - /* new shader specific things should be */ - /* initialized right here */ - picoShader_t *shader; - - /* allocate a pico shader */ - shader = PicoNewShader( pers->model ); /* ydnar */ - if( shader == NULL ) - { - pers->shader = NULL; - return 0; /* this is bad too */ - } - - /* assign ptr to current shader */ - pers->shader = shader; - - /* continue and process the material's sub chunks */ - DoNextEditorDataChunk(pers,nextofs); - continue; - } - if (chunk->id == CHUNK_MATNAME) - { - /* new material's names should be stored here. note that */ - /* GetMeshMaterial returns the name of the material that */ - /* is used by the mesh. new material names are set HERE. */ - /* but for now we skip the new material's name ... */ - if (pers->shader) - { - char *name = (char *)(pers->bufptr + pers->cofs); - PicoSetShaderName( pers->shader,name ); -#ifdef DEBUG_PM_3DS - printf("NewShader: '%s'\n",name); -#endif - } - } - if (chunk->id == CHUNK_MATDIFFUSE) - { - /* todo: color for last inserted new material should be */ - /* stored somewhere by GetDiffuseColor */ - if (!GetDiffuseColor(pers)) return 0; - - /* rest of chunk is skipped here */ - } - if (chunk->id == CHUNK_MATMAP) - { - /* continue and process the material map sub chunks */ - DoNextEditorDataChunk(pers,nextofs); - continue; - } - if (chunk->id == CHUNK_MATMAPFILE) - { - /* map file name for last inserted new material should */ - /* be stored here. but for now we skip this too ... */ - if( pers->shader ) - { - char *name = (char *)(pers->bufptr + pers->cofs); - PicoSetShaderMapName( pers->shader,name ); -#ifdef DEBUG_PM_3DS - printf("NewShaderMapfile: '%s'\n",name); -#endif - } - } - /*** keyframes ***/ - if (chunk->id == CHUNK_KEYFRAME_DATA) - { - /* well umm, this is a bit too much since we don't really */ - /* need model animation sequences right now. we skip this */ -#ifdef DEBUG_PM_3DS - printf("KeyframeData: len %d\n",chunk->len); -#endif - } - /* skip unknown chunk */ - pers->cofs = nextofs; - if (pers->cofs >= pers->maxofs) break; - } - return 1; -} - -static int DoNextChunk (T3dsLoaderPers *pers, int endofs) -{ - T3dsChunk *chunk; - -#ifdef DEBUG_PM_3DS - printf("DoNextChunk: endofs %d\n",endofs); -#endif - while (pers->cofs < endofs) - { - long nextofs = pers->cofs; - if ((chunk = GetChunk(pers)) == NULL) return 0; - if (!chunk->len) return 0; - nextofs += chunk->len; - -#ifdef DEBUG_PM_3DS_EX - printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); -#endif - /*** version ***/ - if (chunk->id == CHUNK_VERSION) - { - /* at this point i get the 3ds file version. since there */ - /* might be new additions to the 3ds file format in 4.0 */ - /* it might be a good idea to store the version somewhere */ - /* for later handling or message displaying */ - - /* get the version */ - int version; - version = GetWord(pers); - GetWord(pers); -#ifdef DEBUG_PM_3DS - printf("FileVersion: %d\n",version); -#endif - - /* throw out a warning for version 4 models */ - if (version == 4) - { - _pico_printf( PICO_WARNING, - "3DS version is 4. Model might load incorrectly."); - } - /* store the 3ds file version in pico special field 0 */ - /* PicoSetSurfaceSpecial(pers->surface,0,version); */ /* ydnar: this was causing a crash accessing uninitialized surface */ - - /* rest of chunk is skipped here */ - } - /*** editor data ***/ - if (chunk->id == CHUNK_EDITOR_DATA) - { - if (!DoNextEditorDataChunk(pers,nextofs)) return 0; - continue; - } - /* skip unknown chunk */ - pers->cofs = nextofs; - if (pers->cofs >= pers->maxofs) break; - } - return 1; -} - -/* _3ds_load: - * loads an autodesk 3ds model file. -*/ -static picoModel_t *_3ds_load( PM_PARAMS_LOAD ) -{ - T3dsLoaderPers pers; - picoModel_t *model; - char basename[128]; - - /* create a new pico model */ - model = PicoNewModel(); - if (model == NULL) - { - /* user must have some serious ram problems ;) */ - return NULL; - } - /* get model's base name (eg. jeep from c:\models\jeep.3ds) */ - memset( basename,0,sizeof(basename) ); - strncpy( basename,_pico_nopath(fileName),sizeof(basename) ); - _pico_setfext( basename,"" ); - - /* initialize persistant vars (formerly static) */ - pers.model = model; - pers.bufptr = (picoByte_t *)buffer; - pers.basename = (char *)basename; - pers.maxofs = bufSize; - pers.cofs = 0L; - - /* do model setup */ - PicoSetModelFrameNum( model,frameNum ); - PicoSetModelName( model,fileName ); - PicoSetModelFileName( model,fileName ); - - /* skip first chunk in file (magic) */ - GetChunk(&pers); - - /* process chunks */ - if (!DoNextChunk(&pers,pers.maxofs)) - { - /* well, bleh i guess */ - PicoFreeModel(model); - return NULL; - } - /* return allocated pico model */ - return model; -} - -/* pico file format module definition */ -const picoModule_t picoModule3DS = -{ - "0.86-b", /* module version string */ - "Autodesk 3Dstudio", /* module display name */ - "seaw0lf", /* author's name */ - "2002 seaw0lf", /* module copyright */ - { - "3ds",NULL,NULL,NULL /* default extensions to use */ - }, - _3ds_canload, /* validation routine */ - _3ds_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_3DS_C + +/* dependencies */ +#include "picointernal.h" + +/* ydnar */ +static picoColor_t white = { 255,255,255,255 }; + +/* remarks: + * - 3ds file version is stored in pico special field 0 on load (ydnar: removed) + * todo: + * - sometimes there is one unnamed surface 0 having 0 verts as + * well as 0 faces. this error occurs since pm 0.6 (ydnar?) + */ +/* uncomment when debugging this module */ +/* #define DEBUG_PM_3DS +#define DEBUG_PM_3DS_EX */ + +/* structure holding persistent 3ds loader specific data used */ +/* to store formerly static vars to keep the module reentrant */ +/* safe. put everything that needs to be static in here. */ +typedef struct S3dsLoaderPers +{ + picoModel_t *model; /* ptr to output model */ + picoSurface_t *surface; /* ptr to current surface */ + picoShader_t *shader; /* ptr to current shader */ + picoByte_t *bufptr; /* ptr to raw data */ + char *basename; /* ptr to model base name (eg. jeep) */ + int cofs; + int maxofs; +} +T3dsLoaderPers; + +/* 3ds chunk types that we use */ +enum { + /* primary chunk */ + CHUNK_MAIN = 0x4D4D, + + /* main chunks */ + CHUNK_VERSION = 0x0002, + CHUNK_EDITOR_CONFIG = 0x3D3E, + CHUNK_EDITOR_DATA = 0x3D3D, + CHUNK_KEYFRAME_DATA = 0xB000, + + /* editor data sub chunks */ + CHUNK_MATERIAL = 0xAFFF, + CHUNK_OBJECT = 0x4000, + + /* material sub chunks */ + CHUNK_MATNAME = 0xA000, + CHUNK_MATDIFFUSE = 0xA020, + CHUNK_MATMAP = 0xA200, + CHUNK_MATMAPFILE = 0xA300, + + /* lets us know we're reading a new object */ + CHUNK_OBJECT_MESH = 0x4100, + + /* object mesh sub chunks */ + CHUNK_OBJECT_VERTICES = 0x4110, + CHUNK_OBJECT_FACES = 0x4120, + CHUNK_OBJECT_MATERIAL = 0x4130, + CHUNK_OBJECT_UV = 0x4140, +}; +#ifdef DEBUG_PM_3DS +static struct +{ + int id; + char *name; +} +debugChunkNames[] = +{ + { CHUNK_MAIN , "CHUNK_MAIN" }, + { CHUNK_VERSION , "CHUNK_VERSION" }, + { CHUNK_EDITOR_CONFIG , "CHUNK_EDITOR_CONFIG" }, + { CHUNK_EDITOR_DATA , "CHUNK_EDITOR_DATA" }, + { CHUNK_KEYFRAME_DATA , "CHUNK_KEYFRAME_DATA" }, + { CHUNK_MATERIAL , "CHUNK_MATERIAL" }, + { CHUNK_OBJECT , "CHUNK_OBJECT" }, + { CHUNK_MATNAME , "CHUNK_MATNAME" }, + { CHUNK_MATDIFFUSE , "CHUNK_MATDIFFUSE" }, + { CHUNK_MATMAP , "CHUNK_MATMAP" }, + { CHUNK_MATMAPFILE , "CHUNK_MATMAPFILE" }, + { CHUNK_OBJECT_MESH , "CHUNK_OBJECT_MESH" }, + { CHUNK_OBJECT_VERTICES , "CHUNK_OBJECT_VERTICES" }, + { CHUNK_OBJECT_FACES , "CHUNK_OBJECT_FACES" }, + { CHUNK_OBJECT_MATERIAL , "CHUNK_OBJECT_MATERIAL" }, + { CHUNK_OBJECT_UV , "CHUNK_OBJECT_UV" }, + { 0 , NULL } +}; +static char *DebugGetChunkName (int id) +{ + int i,max; /* imax? ;) */ + max = sizeof(debugChunkNames) / sizeof(debugChunkNames[0]); + + for (i=0; ilen)) + return PICO_PMV_ERROR_SIZE; + + /* check 3ds magic */ + if (_pico_little_short(chunk->id) != CHUNK_MAIN) + return PICO_PMV_ERROR_IDENT; + + /* file seems to be a valid 3ds */ + return PICO_PMV_OK; +} + +static T3dsChunk *GetChunk (T3dsLoaderPers *pers) +{ + T3dsChunk *chunk; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + +#ifdef DEBUG_PM_3DS +/* printf("GetChunk: pers->cofs %x\n",pers->cofs); */ +#endif + /* fill in pointer to chunk */ + chunk = (T3dsChunk *)&pers->bufptr[ pers->cofs ]; + if (!chunk) return NULL; + + chunk->id = _pico_little_short(chunk->id ); + chunk->len = _pico_little_long (chunk->len); + + /* advance in buffer */ + pers->cofs += sizeof(T3dsChunk); + + /* this means yay */ + return chunk; +} + +static int GetASCIIZ (T3dsLoaderPers *pers, char *dest, int max) +{ + int pos = 0; + int ch; + + for (;;) + { + ch = pers->bufptr[ pers->cofs++ ]; + if (ch == '\0') break; + if (pers->cofs >= pers->maxofs) + { + dest[ pos ] = '\0'; + return 0; + } + dest[ pos++ ] = ch; + if (pos >= max) break; + } + dest[ pos ] = '\0'; + return 1; +} + +static picoByte_t GetByte (T3dsLoaderPers *pers) +{ + picoByte_t *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (picoByte_t *)(pers->bufptr + pers->cofs); + pers->cofs += 1; + return *value; +} + +static int GetWord (T3dsLoaderPers *pers) +{ + unsigned short *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (unsigned short *)(pers->bufptr + pers->cofs); + pers->cofs += 2; + return _pico_little_short(*value); +} + +static float GetFloat (T3dsLoaderPers *pers) +{ + float *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (float *)(pers->bufptr + pers->cofs); + pers->cofs += 4; + return _pico_little_float(*value); +} + +static int GetMeshVertices (T3dsLoaderPers *pers) +{ + int numVerts; + int i; + + /* get number of verts for this surface */ + numVerts = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshVertices: numverts %d\n",numVerts); +#endif + /* read in vertices for current surface */ + for (i=0; isurface,i,v ); + PicoSetSurfaceColor( pers->surface,0,i,white ); /* ydnar */ + +#ifdef DEBUG_PM_3DS_EX + printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshFaces (T3dsLoaderPers *pers) +{ + int numFaces; + int i; + + /* get number of faces for this surface */ + numFaces = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshFaces: numfaces %d\n",numFaces); +#endif + /* read in vertex indices for current surface */ + for (i=0; isurface, (i * 3 + 0), (picoIndex_t)face.a ); + PicoSetSurfaceIndex( pers->surface, (i * 3 + 1), (picoIndex_t)face.b ); + PicoSetSurfaceIndex( pers->surface, (i * 3 + 2), (picoIndex_t)face.c ); + +#ifdef DEBUG_PM_3DS_EX + printf("Face: a: %d b: %d c: %d (%d)\n",face.a,face.b,face.c,face.visible); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshTexCoords (T3dsLoaderPers *pers) +{ + int numTexCoords; + int i; + + /* get number of uv coords for this surface */ + numTexCoords = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshTexCoords: numcoords %d\n",numTexCoords); +#endif + /* read in uv coords for current surface */ + for (i=0; isurface == NULL) + continue; + + /* add current uv */ + PicoSetSurfaceST( pers->surface,0,i,uv ); + +#ifdef DEBUG_PM_3DS_EX + printf("u: %f v: %f\n",uv[0],uv[1]); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshShader (T3dsLoaderPers *pers) +{ + char shaderName[255] = { 0 }; + picoShader_t *shader; + int numSharedVerts; + int setShaderName = 0; + int i; + + /* the shader is either the color or the texture map of the */ + /* object. it can also hold other information like the brightness, */ + /* shine, etc. stuff we don't really care about. we just want the */ + /* color, or the texture map file name really */ + + /* get in the shader name */ + if (!GetASCIIZ(pers,shaderName,sizeof(shaderName))) + return 0; + + /* now that we have the shader name we need to go through all of */ + /* the shaders and check the name against each shader. when we */ + /* find a shader in our shader list that matches this name we */ + /* just read in, then we assign the shader's id of the object to */ + /* that shader */ + + /* get shader id for shader name */ + shader = PicoFindShader( pers->model, shaderName, 1 ); + + /* we've found a matching shader */ + if ((shader != NULL) && pers->surface) + { + char mapName[1024+1]; + char *mapNamePtr; + memset( mapName,0,sizeof(mapName) ); + + /* get ptr to shader's map name */ + mapNamePtr = PicoGetShaderMapName( shader ); + + /* we have a valid map name ptr */ + if (mapNamePtr != NULL) + { + char temp[128]; + char *name; + + /* copy map name to local buffer */ + strcpy( mapName,mapNamePtr ); + + /* extract file name */ + name = _pico_nopath( mapName ); + strncpy( temp, name, sizeof(temp) ); + + /* remove file extension */ + /* name = _pico_setfext( name,"" ); */ + + /* assign default name if no name available */ + if (strlen(temp) < 1) + strcpy(temp,pers->basename); + + /* build shader name */ + _pico_strlwr( temp ); /* gaynux update -sea */ + sprintf( mapName,"models/mapobjects/%s/%s",pers->basename,temp ); + + /* set shader name */ + /* PicoSetShaderName( shader,mapName ); */ /* ydnar: this will screw up the named shader */ + + /* set surface's shader index */ + PicoSetSurfaceShader( pers->surface, shader ); + + setShaderName = 1; + } + } + /* we didn't set a shader name; throw out warning */ + if (!setShaderName) + { + _pico_printf( PICO_WARNING,"3DS mesh is missing shader name"); + } + /* we don't process the list of shared vertices here; there is a */ + /* short int that gives the number of faces of the mesh concerned */ + /* by this shader, then there is the list itself of these faces. */ + /* 0000 means the first face of the (4120) face list */ + + /* get number of shared verts */ + numSharedVerts = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshShader: uses shader '%s' (nsv %d)\n",shaderName,numSharedVerts); +#endif + /* skip list of shared verts */ + for (i=0; ishader ) + { + PicoSetShaderDiffuseColor( pers->shader,color ); + } +#ifdef DEBUG_PM_3DS + printf("GetDiffuseColor: %d %d %d\n",color[0],color[1],color[2]); +#endif + /* success (no errors occured) */ + return 1; +} + +static int DoNextEditorDataChunk (T3dsLoaderPers *pers, long endofs) +{ + T3dsChunk *chunk; + +#ifdef DEBUG_PM_3DS_EX + printf("DoNextEditorDataChunk: endofs %d\n",endofs); +#endif + while (pers->cofs < endofs) + { + long nextofs = pers->cofs; + if ((chunk = GetChunk(pers)) == NULL) return 0; + if (!chunk->len) return 0; + nextofs += chunk->len; + +#ifdef DEBUG_PM_3DS_EX + printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); +#endif + /*** meshes ***/ + if (chunk->id == CHUNK_OBJECT) + { + picoSurface_t *surface; + char surfaceName[ 0xff ] = { 0 }; + + /* read in surface name */ + if( !GetASCIIZ(pers,surfaceName,sizeof(surfaceName)) ) + return 0; /* this is bad */ + +//PicoGetSurfaceName + /* ignore NULL name surfaces */ +// if( surfaceName + + /* allocate a pico surface */ + surface = PicoNewSurface( pers->model ); + if( surface == NULL ) + { + pers->surface = NULL; + return 0; /* this is bad too */ + } + /* assign ptr to current surface */ + pers->surface = surface; + + /* 3ds models surfaces are all triangle meshes */ + PicoSetSurfaceType( pers->surface,PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( pers->surface,surfaceName ); + + /* continue mess with object's sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_OBJECT_MESH) + { + /* continue mess with mesh's sub chunks */ + if (!DoNextEditorDataChunk(pers,nextofs)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_VERTICES) + { + if (!GetMeshVertices(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_FACES) + { + if (!GetMeshFaces(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_UV) + { + if (!GetMeshTexCoords(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_MATERIAL) + { + if (!GetMeshShader(pers)) return 0; + continue; + } + /*** materials ***/ + if (chunk->id == CHUNK_MATERIAL) + { + /* new shader specific things should be */ + /* initialized right here */ + picoShader_t *shader; + + /* allocate a pico shader */ + shader = PicoNewShader( pers->model ); /* ydnar */ + if( shader == NULL ) + { + pers->shader = NULL; + return 0; /* this is bad too */ + } + + /* assign ptr to current shader */ + pers->shader = shader; + + /* continue and process the material's sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_MATNAME) + { + /* new material's names should be stored here. note that */ + /* GetMeshMaterial returns the name of the material that */ + /* is used by the mesh. new material names are set HERE. */ + /* but for now we skip the new material's name ... */ + if (pers->shader) + { + char *name = (char *)(pers->bufptr + pers->cofs); + PicoSetShaderName( pers->shader,name ); +#ifdef DEBUG_PM_3DS + printf("NewShader: '%s'\n",name); +#endif + } + } + if (chunk->id == CHUNK_MATDIFFUSE) + { + /* todo: color for last inserted new material should be */ + /* stored somewhere by GetDiffuseColor */ + if (!GetDiffuseColor(pers)) return 0; + + /* rest of chunk is skipped here */ + } + if (chunk->id == CHUNK_MATMAP) + { + /* continue and process the material map sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_MATMAPFILE) + { + /* map file name for last inserted new material should */ + /* be stored here. but for now we skip this too ... */ + if( pers->shader ) + { + char *name = (char *)(pers->bufptr + pers->cofs); + PicoSetShaderMapName( pers->shader,name ); +#ifdef DEBUG_PM_3DS + printf("NewShaderMapfile: '%s'\n",name); +#endif + } + } + /*** keyframes ***/ + if (chunk->id == CHUNK_KEYFRAME_DATA) + { + /* well umm, this is a bit too much since we don't really */ + /* need model animation sequences right now. we skip this */ +#ifdef DEBUG_PM_3DS + printf("KeyframeData: len %d\n",chunk->len); +#endif + } + /* skip unknown chunk */ + pers->cofs = nextofs; + if (pers->cofs >= pers->maxofs) break; + } + return 1; +} + +static int DoNextChunk (T3dsLoaderPers *pers, int endofs) +{ + T3dsChunk *chunk; + +#ifdef DEBUG_PM_3DS + printf("DoNextChunk: endofs %d\n",endofs); +#endif + while (pers->cofs < endofs) + { + long nextofs = pers->cofs; + if ((chunk = GetChunk(pers)) == NULL) return 0; + if (!chunk->len) return 0; + nextofs += chunk->len; + +#ifdef DEBUG_PM_3DS_EX + printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); +#endif + /*** version ***/ + if (chunk->id == CHUNK_VERSION) + { + /* at this point i get the 3ds file version. since there */ + /* might be new additions to the 3ds file format in 4.0 */ + /* it might be a good idea to store the version somewhere */ + /* for later handling or message displaying */ + + /* get the version */ + int version; + version = GetWord(pers); + GetWord(pers); +#ifdef DEBUG_PM_3DS + printf("FileVersion: %d\n",version); +#endif + + /* throw out a warning for version 4 models */ + if (version == 4) + { + _pico_printf( PICO_WARNING, + "3DS version is 4. Model might load incorrectly."); + } + /* store the 3ds file version in pico special field 0 */ + /* PicoSetSurfaceSpecial(pers->surface,0,version); */ /* ydnar: this was causing a crash accessing uninitialized surface */ + + /* rest of chunk is skipped here */ + } + /*** editor data ***/ + if (chunk->id == CHUNK_EDITOR_DATA) + { + if (!DoNextEditorDataChunk(pers,nextofs)) return 0; + continue; + } + /* skip unknown chunk */ + pers->cofs = nextofs; + if (pers->cofs >= pers->maxofs) break; + } + return 1; +} + +/* _3ds_load: + * loads an autodesk 3ds model file. +*/ +static picoModel_t *_3ds_load( PM_PARAMS_LOAD ) +{ + T3dsLoaderPers pers; + picoModel_t *model; + char basename[128]; + + /* create a new pico model */ + model = PicoNewModel(); + if (model == NULL) + { + /* user must have some serious ram problems ;) */ + return NULL; + } + /* get model's base name (eg. jeep from c:\models\jeep.3ds) */ + memset( basename,0,sizeof(basename) ); + strncpy( basename,_pico_nopath(fileName),sizeof(basename) ); + _pico_setfext( basename,"" ); + + /* initialize persistant vars (formerly static) */ + pers.model = model; + pers.bufptr = (picoByte_t *)buffer; + pers.basename = (char *)basename; + pers.maxofs = bufSize; + pers.cofs = 0L; + + /* do model setup */ + PicoSetModelFrameNum( model,frameNum ); + PicoSetModelName( model,fileName ); + PicoSetModelFileName( model,fileName ); + + /* skip first chunk in file (magic) */ + GetChunk(&pers); + + /* process chunks */ + if (!DoNextChunk(&pers,pers.maxofs)) + { + /* well, bleh i guess */ + PicoFreeModel(model); + return NULL; + } + /* return allocated pico model */ + return model; +} + +/* pico file format module definition */ +const picoModule_t picoModule3DS = +{ + "0.86-b", /* module version string */ + "Autodesk 3Dstudio", /* module display name */ + "seaw0lf", /* author's name */ + "2002 seaw0lf", /* module copyright */ + { + "3ds",NULL,NULL,NULL /* default extensions to use */ + }, + _3ds_canload, /* validation routine */ + _3ds_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_ase.c b/libs/picomodel/pm_ase.c index e8c5751d..ae5698df 100644 --- a/libs/picomodel/pm_ase.c +++ b/libs/picomodel/pm_ase.c @@ -1,1001 +1,1001 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other aseMaterialList provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - -/* marker */ -#define PM_ASE_C - -/* uncomment when debugging this module */ -//#define DEBUG_PM_ASE -//#define DEBUG_PM_ASE_EX - - -/* dependencies */ -#include "picointernal.h" - -#ifdef DEBUG_PM_ASE -#include "time.h" -#endif - -/* plain white */ -static picoColor_t white = { 255, 255, 255, 255 }; - -/* jhefty - multi-subobject material support */ - -/* Material/SubMaterial management */ -/* A material should have 1..n submaterials assigned to it */ - -typedef struct aseSubMaterial_s -{ - struct aseSubMaterial_s* next; - int subMtlId; - picoShader_t* shader; - -} aseSubMaterial_t; - -typedef struct aseMaterial_s -{ - struct aseMaterial_s* next; - struct aseSubMaterial_s* subMtls; - int mtlId; -} aseMaterial_t; - -/* Material/SubMaterial management functions */ -static aseMaterial_t* _ase_get_material ( aseMaterial_t* list , int mtlIdParent ) -{ - aseMaterial_t* mtl = list; - - while ( mtl ) - { - if ( mtlIdParent == mtl->mtlId ) - { - break; - } - mtl = mtl->next; - } - return mtl; -} - -static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int mtlIdParent , int subMtlId ) -{ - aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent ); - aseSubMaterial_t* subMtl = NULL; - - if ( !parent ) - { - _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent ); - return NULL; - } - - subMtl = parent->subMtls; - while ( subMtl ) - { - if ( subMtlId == subMtl->subMtlId ) - { - break; - } - subMtl = subMtl->next; - } - return subMtl; -} - -static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ) -{ - aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) ); - mtl->mtlId = mtlIdParent; - mtl->subMtls = NULL; - mtl->next = *list; - *list = mtl; - - return mtl; -} - -static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader ) -{ - aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent ); - aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) ); - - if ( !parent ) - { - parent = _ase_add_material ( list , mtlIdParent ); - } - - subMtl->shader = shader; - subMtl->subMtlId = subMtlId; - subMtl->next = parent->subMtls; - parent->subMtls = subMtl; - - return subMtl; -} - -static void _ase_free_materials( aseMaterial_t **list ) -{ - aseMaterial_t* mtl = *list; - aseSubMaterial_t* subMtl = NULL; - - aseMaterial_t* mtlTemp = NULL; - aseSubMaterial_t* subMtlTemp = NULL; - - while ( mtl ) - { - subMtl = mtl->subMtls; - while ( subMtl ) - { - subMtlTemp = subMtl->next; - _pico_free ( subMtl ); - subMtl = subMtlTemp; - } - mtlTemp = mtl->next; - _pico_free ( mtl ); - mtl = mtlTemp; - } - (*list) = NULL; -} - -#ifdef DEBUG_PM_ASE -static void _ase_print_materials( aseMaterial_t *list ) -{ - aseMaterial_t* mtl = list; - aseSubMaterial_t* subMtl = NULL; - - while ( mtl ) - { - _pico_printf ( PICO_NORMAL , "ASE Material %i" , mtl->mtlId ); - subMtl = mtl->subMtls; - while ( subMtl ) - { - _pico_printf ( PICO_NORMAL , " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name ); - subMtl = subMtl->next; - } - mtl = mtl->next; - } -} -#endif //DEBUG_PM_ASE - -/* ASE Face management */ -/* These are used to keep an association between a submaterial and a face definition */ -/* They are kept in parallel with the current picoSurface, */ -/* and are used by _ase_submit_triangles to lookup the proper material/submaterial IDs */ -typedef struct aseFace_s -{ - struct aseFace_s* next; - int mtlId; - int subMtlId; - int index[9]; -} aseFace_t; - -/* ASE Face management functions */ -void _ase_add_face( aseFace_t **list, aseFace_t **tail, aseFace_t *newFace ) -{ - aseFace_t* face = *list; - aseFace_t* tempFace = NULL; - - /* insert as head of list */ - if ( !(*list) ) - { - *list = newFace; - } - else - { - (*tail)->next = newFace; - } - - *tail = newFace; - newFace->next = NULL; - - //tag the color indices so we can detect them and apply the default color to them - newFace->index[6] = -1; - newFace->index[7] = -1; - newFace->index[8] = -1; -} - -aseFace_t* _ase_get_face_for_index( aseFace_t *list, int index ) -{ - int counter = 0; - aseFace_t* face = list; - - while ( counter < index ) - { - face = face->next; - counter++; - } - return face; -} -static void _ase_free_faces (aseFace_t** list, aseFace_t** tail ) -{ - aseFace_t* face = *list; - aseFace_t* tempFace = NULL; - - while ( face ) - { - tempFace = face->next; - _pico_free ( face ); - face = tempFace; - } - - (*list) = NULL; - (*tail) = NULL; -} - -/* todo: - * - apply material specific uv offsets to uv coordinates - */ - -/* _ase_canload: - * validates a 3dsmax ase model file. - */ -static int _ase_canload( PM_PARAMS_CANLOAD ) -{ - picoParser_t *p; - - - /* quick data length validation */ - if( bufSize < 80 ) - return PICO_PMV_ERROR_SIZE; - - /* keep the friggin compiler happy */ - *fileName = *fileName; - - /* create pico parser */ - p = _pico_new_parser( (picoByte_t*) buffer, bufSize ); - if( p == NULL ) - return PICO_PMV_ERROR_MEMORY; - - /* get first token */ - if( _pico_parse_first( p ) == NULL) - { - return PICO_PMV_ERROR_IDENT; - } - - /* check first token */ - if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) ) - { - _pico_free_parser( p ); - return PICO_PMV_ERROR_IDENT; - } - - /* free the pico parser object */ - _pico_free_parser( p ); - - /* file seems to be a valid ase file */ - return PICO_PMV_OK; -} - - - -/* _ase_submit_triangles - jhefty - use the surface and the current face list to look up material/submaterial IDs - and submit them to the model for proper processing - -The following still holds from ydnar's _ase_make_surface: - indexes 0 1 2 = vert indexes - indexes 3 4 5 = st indexes - indexes 6 7 8 = color indexes (new) -*/ - -static void _ase_submit_triangles ( picoSurface_t* surface , picoModel_t* model , aseMaterial_t* materials , aseFace_t* faces ) -{ - aseFace_t* face; - aseSubMaterial_t* subMtl; - picoVec3_t* xyz[3]; - picoVec3_t* normal[3]; - picoVec2_t* st[3]; - picoColor_t* color[3]; - int i; - - face = faces; - while ( face != NULL ) - { - /* look up the shader for the material/submaterial pair */ - subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId ); - if( subMtl == NULL ) - { - /* ydnar: trying default submaterial */ - subMtl = _ase_get_submaterial( materials, face->mtlId, 0 ); - if( subMtl == NULL ) - { - _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", face->mtlId, face->subMtlId ); - return; - } - } - - /* we pull the data from the surface using the facelist data */ - for ( i = 0 ; i < 3 ; i ++ ) - { - xyz[i] = (picoVec3_t*) PicoGetSurfaceXYZ ( surface, face->index[ i ] ); - normal[i] = (picoVec3_t*) PicoGetSurfaceNormal( surface, face->index[ i ] ); - st[i] = (picoVec2_t*) PicoGetSurfaceST ( surface, 0, face->index[ i + 3 ] ); - - if ( face->index [ i + 6] >= 0 ) - { - color[i] = (picoColor_t*)PicoGetSurfaceColor ( surface, 0, face->index[ i + 6 ] ); - } - else - { - color[i] = &white; - } - - } - - /* submit the triangle to the model */ - PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader ); - - /* advance to the next face */ - face = face->next; - } -} - -/* _ase_load: - * loads a 3dsmax ase model file. -*/ -static picoModel_t *_ase_load( PM_PARAMS_LOAD ) -{ - picoModel_t *model; - picoSurface_t *surface = NULL; - picoParser_t *p; - char lastNodeName[ 1024 ]; - - aseFace_t* faces = NULL; - aseFace_t* facesTail = NULL; - aseMaterial_t* materials = NULL; - -#ifdef DEBUG_PM_ASE - clock_t start, finish; - double elapsed; - start = clock(); -#endif - - /* helper */ - #define _ase_error_return(m) \ - { \ - _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \ - _pico_free_parser( p ); \ - PicoFreeModel( model ); \ - return NULL; \ - } - /* create a new pico parser */ - p = _pico_new_parser( (picoByte_t *)buffer,bufSize ); - if (p == NULL) return NULL; - - /* create a new pico model */ - model = PicoNewModel(); - if (model == NULL) - { - _pico_free_parser( p ); - return NULL; - } - /* do model setup */ - PicoSetModelFrameNum( model, frameNum ); - PicoSetModelName( model, fileName ); - PicoSetModelFileName( model, fileName ); - - /* initialize some stuff */ - memset( lastNodeName,0,sizeof(lastNodeName) ); - - /* parse ase model file */ - while( 1 ) - { - /* get first token on line */ - if (_pico_parse_first( p ) == NULL) - break; - - /* we just skip empty lines */ - if (p->token == NULL || !strlen( p->token )) - continue; - - /* we skip invalid ase statements */ - if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}') - { - _pico_parse_skip_rest( p ); - continue; - } - /* remember node name */ - if (!_pico_stricmp(p->token,"*node_name")) - { - /* read node name */ - char *ptr = _pico_parse( p,0 ); - if (ptr == NULL) - _ase_error_return("Node name parse error"); - - /* remember node name */ - strncpy( lastNodeName,ptr,sizeof(lastNodeName) ); - } - /* model mesh (originally contained within geomobject) */ - else if (!_pico_stricmp(p->token,"*mesh")) - { - /* finish existing surface */ - //_ase_make_surface( model, &surface ); - _ase_submit_triangles (surface, model ,materials,faces); - _ase_free_faces (&faces,&facesTail); - - /* allocate new pico surface */ - surface = PicoNewSurface( NULL ); - if (surface == NULL) - { - PicoFreeModel( model ); - return NULL; - } - } - /* mesh material reference. this usually comes at the end of */ - /* geomobjects after the mesh blocks. we must assume that the */ - /* new mesh was already created so all we can do here is assign */ - /* the material reference id (shader index) now. */ - else if (!_pico_stricmp(p->token,"*material_ref")) - { - int mtlId; - aseFace_t* face; - - /* we must have a valid surface */ - if( surface == NULL ) - _ase_error_return("Missing mesh for material reference"); - - /* get the material ref (0..n) */ - if (!_pico_parse_int( p,&mtlId) ) - _ase_error_return("Missing material reference ID"); - - /* fix up all of the aseFaceList in the surface to point to the parent material */ - /* we've already saved off their subMtl */ - face = faces; - while ( face != NULL ) - { - face->mtlId = mtlId; - face = face->next; - } - } - /* model mesh vertex */ - else if (!_pico_stricmp(p->token,"*mesh_vertex")) - { - picoVec3_t v; - int index; - - /* we must have a valid surface */ - if( surface == NULL ) - continue; - - /* get vertex data (orig: index +y -x +z) */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("Vertex parse error"); - if (!_pico_parse_vec( p,v )) - _ase_error_return("Vertex parse error"); - - /* set vertex */ - PicoSetSurfaceXYZ( surface,index,v ); - } - /* model mesh vertex normal */ - else if (!_pico_stricmp(p->token,"*mesh_vertexnormal")) - { - picoVec3_t v; - int index; - - /* we must have a valid surface */ - if( surface == NULL ) - continue; - - /* get vertex data (orig: index +y -x +z) */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("Vertex parse error"); - if (!_pico_parse_vec( p,v )) - _ase_error_return("Vertex parse error"); - - /* set vertex */ - PicoSetSurfaceNormal( surface,index,v ); - } - /* model mesh face */ - else if (!_pico_stricmp(p->token,"*mesh_face")) - { - picoIndex_t indexes[3]; - int index; - - /* we must have a valid surface */ - if( surface == NULL ) - continue; - - /* get face index */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("Face parse error"); - - /* get 1st vertex index */ - _pico_parse( p,0 ); - if (!_pico_parse_int( p,&indexes[0] )) - _ase_error_return("Face parse error"); - - /* get 2nd vertex index */ - _pico_parse( p,0 ); - if (!_pico_parse_int( p,&indexes[1] )) - _ase_error_return("Face parse error"); - - /* get 3rd vertex index */ - _pico_parse( p,0 ); - if (!_pico_parse_int( p,&indexes[2] )) - _ase_error_return("Face parse error"); - - /* set face indexes (note interleaved offset!) */ - PicoSetSurfaceIndex( surface, (index * 9 + 0), indexes[2] ); - PicoSetSurfaceIndex( surface, (index * 9 + 1), indexes[1] ); - PicoSetSurfaceIndex( surface, (index * 9 + 2), indexes[0] ); - - /* parse to the subMaterial ID */ - while ( 1 ) - { - _pico_parse (p,0); - if (!_pico_stricmp (p->token,"*MESH_MTLID" )) - { - aseFace_t* newFace; - int subMtlId; - - _pico_parse_int ( p , &subMtlId ); - newFace = _pico_calloc ( 1 , sizeof ( aseFace_t )); - - /* we fix up the mtlId later when we parse the material_ref */ - newFace->mtlId = 0; - newFace->subMtlId = subMtlId; - newFace->index[0] = indexes[2]; - newFace->index[1] = indexes[1]; - newFace->index[2] = indexes[0]; - - _ase_add_face ( &faces,&facesTail,newFace ); - break; - } - } - - } - /* model texture vertex */ - else if (!_pico_stricmp(p->token,"*mesh_tvert")) - { - picoVec2_t uv; - int index; - - /* we must have a valid surface */ - if( surface == NULL ) - continue; - - /* get uv vertex index */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("UV vertex parse error"); - - /* get uv vertex s */ - if (!_pico_parse_float( p,&uv[0] )) - _ase_error_return("UV vertex parse error"); - - /* get uv vertex t */ - if (!_pico_parse_float( p,&uv[1] )) - _ase_error_return("UV vertex parse error"); - - /* ydnar: invert t */ - uv[ 1 ] = 1.0f - uv[ 1 ]; - - /* set texture vertex */ - PicoSetSurfaceST( surface,0,index,uv ); - } - /* ydnar: model mesh texture face */ - else if( !_pico_stricmp( p->token, "*mesh_tface" ) ) - { - picoIndex_t indexes[3]; - int index; - aseFace_t* face; - - /* we must have a valid surface */ - if( surface == NULL ) - continue; - - /* get face index */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("Texture face parse error"); - - /* get 1st vertex index */ - if (!_pico_parse_int( p,&indexes[0] )) - _ase_error_return("Texture face parse error"); - - /* get 2nd vertex index */ - if (!_pico_parse_int( p,&indexes[1] )) - _ase_error_return("Texture face parse error"); - - /* get 3rd vertex index */ - if (!_pico_parse_int( p,&indexes[2] )) - _ase_error_return("Texture face parse error"); - - /* set face indexes (note interleaved offset!) */ - PicoSetSurfaceIndex( surface, (index * 9 + 3), indexes[2] ); - PicoSetSurfaceIndex( surface, (index * 9 + 4), indexes[1] ); - PicoSetSurfaceIndex( surface, (index * 9 + 5), indexes[0] ); - - face = _ase_get_face_for_index(faces,index); - face->index[3] = indexes[2]; - face->index[4] = indexes[1]; - face->index[5] = indexes[0]; - } - /* model color vertex */ - else if (!_pico_stricmp(p->token,"*mesh_vertcol")) - { - picoColor_t color; - int index; - float colorInput; - - /* we must have a valid surface */ - if( surface == NULL ) - continue; - - /* get color vertex index */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("UV vertex parse error"); - - /* get R component */ - if (!_pico_parse_float( p,&colorInput )) - _ase_error_return("color vertex parse error"); - color[0] = (picoByte_t)(colorInput * 255); - - /* get G component */ - if (!_pico_parse_float( p,&colorInput )) - _ase_error_return("color vertex parse error"); - color[1] = (picoByte_t)(colorInput * 255); - - /* get B component */ - if (!_pico_parse_float( p,&colorInput )) - _ase_error_return("color vertex parse error"); - color[2] = (picoByte_t)(colorInput * 255); - - /* leave alpha alone since we don't get any data from the ASE format */ - color[3] = 255; - - /* set texture vertex */ - PicoSetSurfaceColor( surface,0,index,color ); - } - /* model color face */ - else if (!_pico_stricmp(p->token,"*mesh_cface")) - { - picoIndex_t indexes[3]; - int index; - aseFace_t* face; - - /* we must have a valid surface */ - if( surface == NULL ) - continue; - - /* get face index */ - if (!_pico_parse_int( p,&index )) - _ase_error_return("Face parse error"); - - /* get 1st cvertex index */ - // _pico_parse( p,0 ); - if (!_pico_parse_int( p,&indexes[0] )) - _ase_error_return("Face parse error"); - - /* get 2nd cvertex index */ - // _pico_parse( p,0 ); - if (!_pico_parse_int( p,&indexes[1] )) - _ase_error_return("Face parse error"); - - /* get 3rd cvertex index */ - // _pico_parse( p,0 ); - if (!_pico_parse_int( p,&indexes[2] )) - _ase_error_return("Face parse error"); - - /* set face indexes (note interleaved offset!) */ - PicoSetSurfaceIndex( surface, (index * 9 + 6), indexes[2] ); - PicoSetSurfaceIndex( surface, (index * 9 + 7), indexes[1] ); - PicoSetSurfaceIndex( surface, (index * 9 + 8), indexes[0] ); - - face = _ase_get_face_for_index(faces,index); - face->index[6] = indexes[2]; - face->index[7] = indexes[1]; - face->index[8] = indexes[0]; - } - /* model material */ - else if( !_pico_stricmp( p->token, "*material" ) ) - { - aseSubMaterial_t* subMaterial = NULL; - picoShader_t *shader; - int level = 1, index; - char materialName[ 1024 ]; - float transValue = 0.0f, shineValue = 1.0f; - picoColor_t ambientColor, diffuseColor, specularColor; - char *mapname = NULL; - int subMtlId, subMaterialLevel = -1; - - - /* get material index */ - _pico_parse_int( p,&index ); - - /* check brace */ - if (!_pico_parse_check(p,1,"{")) - _ase_error_return("Material missing opening brace"); - - /* parse material block */ - while( 1 ) - { - /* get next token */ - if (_pico_parse(p,1) == NULL) break; - if (!strlen(p->token)) continue; - - /* handle levels */ - if (p->token[0] == '{') level++; - if (p->token[0] == '}') level--; - if (!level) break; - - if( level == subMaterialLevel ) - { - /* set material name */ - PicoSetShaderName( shader, materialName); - - /* set shader's transparency */ - PicoSetShaderTransparency( shader,transValue ); - - /* set shader's ambient color */ - PicoSetShaderAmbientColor( shader,ambientColor ); - - /* set diffuse alpha to transparency */ - diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); - - /* set shader's diffuse color */ - PicoSetShaderDiffuseColor( shader,diffuseColor ); - - /* set shader's specular color */ - PicoSetShaderSpecularColor( shader,specularColor ); - - /* set shader's shininess */ - PicoSetShaderShininess( shader,shineValue ); - - /* set material map name */ - PicoSetShaderMapName( shader, mapname ); - - subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader ); - subMaterialLevel = -1; - } - - /* parse submaterial index */ - if (!_pico_stricmp(p->token,"*submaterial")) - { - /* allocate new pico shader */ - _pico_parse_int( p , &subMtlId ); - - shader = PicoNewShader( model ); - if (shader == NULL) - { - PicoFreeModel( model ); - return NULL; - } - subMaterialLevel = level; - } - /* parse material name */ - else if (!_pico_stricmp(p->token,"*material_name")) - { - char* name = _pico_parse(p,0); - if ( name == NULL) - _ase_error_return("Missing material name"); - - strcpy ( materialName , name ); - /* skip rest and continue with next token */ - _pico_parse_skip_rest( p ); - continue; - } - /* parse material transparency */ - else if (!_pico_stricmp(p->token,"*material_transparency")) - { - /* get transparency value from ase */ - if (!_pico_parse_float( p,&transValue )) - _ase_error_return("Material transparency parse error"); - - /* skip rest and continue with next token */ - _pico_parse_skip_rest( p ); - continue; - } - /* parse material shininess */ - else if (!_pico_stricmp(p->token,"*material_shine")) - { - /* remark: - * - not sure but instead of '*material_shine' i might - * need to use '*material_shinestrength' */ - - /* get shine value from ase */ - if (!_pico_parse_float( p,&shineValue )) - _ase_error_return("Material shine parse error"); - - /* scale ase shine range 0..1 to pico range 0..127 */ - shineValue *= 128.0; - - /* skip rest and continue with next token */ - _pico_parse_skip_rest( p ); - continue; - } - /* parse ambient material color */ - else if (!_pico_stricmp(p->token,"*material_ambient")) - { - picoVec3_t vec; - /* get r,g,b float values from ase */ - if (!_pico_parse_vec( p,vec )) - _ase_error_return("Material color parse error"); - - /* setup 0..255 range color values */ - ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); - ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); - ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); - ambientColor[ 3 ] = (int)( 255 ); - - /* skip rest and continue with next token */ - _pico_parse_skip_rest( p ); - continue; - } - /* parse diffuse material color */ - else if (!_pico_stricmp(p->token,"*material_diffuse")) - { - picoVec3_t vec; - - /* get r,g,b float values from ase */ - if (!_pico_parse_vec( p,vec )) - _ase_error_return("Material color parse error"); - - /* setup 0..255 range color */ - diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); - diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); - diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); - diffuseColor[ 3 ] = (int)( 255 ); - - /* skip rest and continue with next token */ - _pico_parse_skip_rest( p ); - continue; - } - /* parse specular material color */ - else if (!_pico_stricmp(p->token,"*material_specular")) - { - picoVec3_t vec; - - /* get r,g,b float values from ase */ - if (!_pico_parse_vec( p,vec )) - _ase_error_return("Material color parse error"); - - /* setup 0..255 range color */ - specularColor[ 0 ] = (int)( vec[ 0 ] * 255 ); - specularColor[ 1 ] = (int)( vec[ 1 ] * 255 ); - specularColor[ 2 ] = (int)( vec[ 2 ] * 255 ); - specularColor[ 3 ] = (int)( 255 ); - - /* skip rest and continue with next token */ - _pico_parse_skip_rest( p ); - continue; - } - /* material diffuse map */ - else if (!_pico_stricmp(p->token,"*map_diffuse") ) - { - int sublevel = 0; - - /* parse material block */ - while( 1 ) - { - /* get next token */ - if (_pico_parse(p,1) == NULL) break; - if (!strlen(p->token)) continue; - - /* handle levels */ - if (p->token[0] == '{') sublevel++; - if (p->token[0] == '}') sublevel--; - if (!sublevel) break; - - /* parse diffuse map bitmap */ - if (!_pico_stricmp(p->token,"*bitmap")) - { - char* name = _pico_parse(p,0); - if (name == NULL) - _ase_error_return("Missing material map bitmap name"); - mapname = _pico_alloc ( strlen ( name ) + 1 ); - strcpy ( mapname, name ); - /* skip rest and continue with next token */ - _pico_parse_skip_rest( p ); - continue; - } - } - } - /* end map_diffuse block */ - } - /* end material block */ - - if( subMaterial == NULL ) - { - /* allocate new pico shader */ - shader = PicoNewShader( model ); - if (shader == NULL) - { - PicoFreeModel( model ); - return NULL; - } - - /* set material name */ - PicoSetShaderName( shader,materialName ); - - /* set shader's transparency */ - PicoSetShaderTransparency( shader,transValue ); - - /* set shader's ambient color */ - PicoSetShaderAmbientColor( shader,ambientColor ); - - /* set diffuse alpha to transparency */ - diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); - - /* set shader's diffuse color */ - PicoSetShaderDiffuseColor( shader,diffuseColor ); - - /* set shader's specular color */ - PicoSetShaderSpecularColor( shader,specularColor ); - - /* set shader's shininess */ - PicoSetShaderShininess( shader,shineValue ); - - /* set material map name */ - PicoSetShaderMapName( shader, mapname ); - - /* this is just a material with 1 submaterial */ - subMaterial = _ase_add_submaterial( &materials, index, 0, shader ); - } - - /* ydnar: free mapname */ - if( mapname != NULL ) - _pico_free( mapname ); - } // !_pico_stricmp ( "*material" ) - - /* skip unparsed rest of line and continue */ - _pico_parse_skip_rest( p ); - } - - /* ydnar: finish existing surface */ -// _ase_make_surface( model, &surface ); - _ase_submit_triangles (surface, model ,materials,faces); - _ase_free_faces (&faces,&facesTail); - -#ifdef DEBUG_PM_ASE - _ase_print_materials(materials); - finish = clock(); - elapsed = (double)(finish - start) / CLOCKS_PER_SEC; - _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed ); -#endif //DEBUG_PM_ASE - - _ase_free_materials(&materials); - - /* return allocated pico model */ - return model; -} - -/* pico file format module definition */ -const picoModule_t picoModuleASE = -{ - "1.0", /* module version string */ - "Autodesk 3DSMAX ASCII", /* module display name */ - "Jared Hefty, seaw0lf", /* author's name */ - "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */ - { - "ase",NULL,NULL,NULL /* default extensions to use */ - }, - _ase_canload, /* validation routine */ - _ase_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other aseMaterialList provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + +/* marker */ +#define PM_ASE_C + +/* uncomment when debugging this module */ +//#define DEBUG_PM_ASE +//#define DEBUG_PM_ASE_EX + + +/* dependencies */ +#include "picointernal.h" + +#ifdef DEBUG_PM_ASE +#include "time.h" +#endif + +/* plain white */ +static picoColor_t white = { 255, 255, 255, 255 }; + +/* jhefty - multi-subobject material support */ + +/* Material/SubMaterial management */ +/* A material should have 1..n submaterials assigned to it */ + +typedef struct aseSubMaterial_s +{ + struct aseSubMaterial_s* next; + int subMtlId; + picoShader_t* shader; + +} aseSubMaterial_t; + +typedef struct aseMaterial_s +{ + struct aseMaterial_s* next; + struct aseSubMaterial_s* subMtls; + int mtlId; +} aseMaterial_t; + +/* Material/SubMaterial management functions */ +static aseMaterial_t* _ase_get_material ( aseMaterial_t* list , int mtlIdParent ) +{ + aseMaterial_t* mtl = list; + + while ( mtl ) + { + if ( mtlIdParent == mtl->mtlId ) + { + break; + } + mtl = mtl->next; + } + return mtl; +} + +static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int mtlIdParent , int subMtlId ) +{ + aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent ); + aseSubMaterial_t* subMtl = NULL; + + if ( !parent ) + { + _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent ); + return NULL; + } + + subMtl = parent->subMtls; + while ( subMtl ) + { + if ( subMtlId == subMtl->subMtlId ) + { + break; + } + subMtl = subMtl->next; + } + return subMtl; +} + +static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ) +{ + aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) ); + mtl->mtlId = mtlIdParent; + mtl->subMtls = NULL; + mtl->next = *list; + *list = mtl; + + return mtl; +} + +static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader ) +{ + aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent ); + aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) ); + + if ( !parent ) + { + parent = _ase_add_material ( list , mtlIdParent ); + } + + subMtl->shader = shader; + subMtl->subMtlId = subMtlId; + subMtl->next = parent->subMtls; + parent->subMtls = subMtl; + + return subMtl; +} + +static void _ase_free_materials( aseMaterial_t **list ) +{ + aseMaterial_t* mtl = *list; + aseSubMaterial_t* subMtl = NULL; + + aseMaterial_t* mtlTemp = NULL; + aseSubMaterial_t* subMtlTemp = NULL; + + while ( mtl ) + { + subMtl = mtl->subMtls; + while ( subMtl ) + { + subMtlTemp = subMtl->next; + _pico_free ( subMtl ); + subMtl = subMtlTemp; + } + mtlTemp = mtl->next; + _pico_free ( mtl ); + mtl = mtlTemp; + } + (*list) = NULL; +} + +#ifdef DEBUG_PM_ASE +static void _ase_print_materials( aseMaterial_t *list ) +{ + aseMaterial_t* mtl = list; + aseSubMaterial_t* subMtl = NULL; + + while ( mtl ) + { + _pico_printf ( PICO_NORMAL , "ASE Material %i" , mtl->mtlId ); + subMtl = mtl->subMtls; + while ( subMtl ) + { + _pico_printf ( PICO_NORMAL , " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name ); + subMtl = subMtl->next; + } + mtl = mtl->next; + } +} +#endif //DEBUG_PM_ASE + +/* ASE Face management */ +/* These are used to keep an association between a submaterial and a face definition */ +/* They are kept in parallel with the current picoSurface, */ +/* and are used by _ase_submit_triangles to lookup the proper material/submaterial IDs */ +typedef struct aseFace_s +{ + struct aseFace_s* next; + int mtlId; + int subMtlId; + int index[9]; +} aseFace_t; + +/* ASE Face management functions */ +void _ase_add_face( aseFace_t **list, aseFace_t **tail, aseFace_t *newFace ) +{ + aseFace_t* face = *list; + aseFace_t* tempFace = NULL; + + /* insert as head of list */ + if ( !(*list) ) + { + *list = newFace; + } + else + { + (*tail)->next = newFace; + } + + *tail = newFace; + newFace->next = NULL; + + //tag the color indices so we can detect them and apply the default color to them + newFace->index[6] = -1; + newFace->index[7] = -1; + newFace->index[8] = -1; +} + +aseFace_t* _ase_get_face_for_index( aseFace_t *list, int index ) +{ + int counter = 0; + aseFace_t* face = list; + + while ( counter < index ) + { + face = face->next; + counter++; + } + return face; +} +static void _ase_free_faces (aseFace_t** list, aseFace_t** tail ) +{ + aseFace_t* face = *list; + aseFace_t* tempFace = NULL; + + while ( face ) + { + tempFace = face->next; + _pico_free ( face ); + face = tempFace; + } + + (*list) = NULL; + (*tail) = NULL; +} + +/* todo: + * - apply material specific uv offsets to uv coordinates + */ + +/* _ase_canload: + * validates a 3dsmax ase model file. + */ +static int _ase_canload( PM_PARAMS_CANLOAD ) +{ + picoParser_t *p; + + + /* quick data length validation */ + if( bufSize < 80 ) + return PICO_PMV_ERROR_SIZE; + + /* keep the friggin compiler happy */ + *fileName = *fileName; + + /* create pico parser */ + p = _pico_new_parser( (picoByte_t*) buffer, bufSize ); + if( p == NULL ) + return PICO_PMV_ERROR_MEMORY; + + /* get first token */ + if( _pico_parse_first( p ) == NULL) + { + return PICO_PMV_ERROR_IDENT; + } + + /* check first token */ + if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) ) + { + _pico_free_parser( p ); + return PICO_PMV_ERROR_IDENT; + } + + /* free the pico parser object */ + _pico_free_parser( p ); + + /* file seems to be a valid ase file */ + return PICO_PMV_OK; +} + + + +/* _ase_submit_triangles - jhefty + use the surface and the current face list to look up material/submaterial IDs + and submit them to the model for proper processing + +The following still holds from ydnar's _ase_make_surface: + indexes 0 1 2 = vert indexes + indexes 3 4 5 = st indexes + indexes 6 7 8 = color indexes (new) +*/ + +static void _ase_submit_triangles ( picoSurface_t* surface , picoModel_t* model , aseMaterial_t* materials , aseFace_t* faces ) +{ + aseFace_t* face; + aseSubMaterial_t* subMtl; + picoVec3_t* xyz[3]; + picoVec3_t* normal[3]; + picoVec2_t* st[3]; + picoColor_t* color[3]; + int i; + + face = faces; + while ( face != NULL ) + { + /* look up the shader for the material/submaterial pair */ + subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId ); + if( subMtl == NULL ) + { + /* ydnar: trying default submaterial */ + subMtl = _ase_get_submaterial( materials, face->mtlId, 0 ); + if( subMtl == NULL ) + { + _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", face->mtlId, face->subMtlId ); + return; + } + } + + /* we pull the data from the surface using the facelist data */ + for ( i = 0 ; i < 3 ; i ++ ) + { + xyz[i] = (picoVec3_t*) PicoGetSurfaceXYZ ( surface, face->index[ i ] ); + normal[i] = (picoVec3_t*) PicoGetSurfaceNormal( surface, face->index[ i ] ); + st[i] = (picoVec2_t*) PicoGetSurfaceST ( surface, 0, face->index[ i + 3 ] ); + + if ( face->index [ i + 6] >= 0 ) + { + color[i] = (picoColor_t*)PicoGetSurfaceColor ( surface, 0, face->index[ i + 6 ] ); + } + else + { + color[i] = &white; + } + + } + + /* submit the triangle to the model */ + PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader ); + + /* advance to the next face */ + face = face->next; + } +} + +/* _ase_load: + * loads a 3dsmax ase model file. +*/ +static picoModel_t *_ase_load( PM_PARAMS_LOAD ) +{ + picoModel_t *model; + picoSurface_t *surface = NULL; + picoParser_t *p; + char lastNodeName[ 1024 ]; + + aseFace_t* faces = NULL; + aseFace_t* facesTail = NULL; + aseMaterial_t* materials = NULL; + +#ifdef DEBUG_PM_ASE + clock_t start, finish; + double elapsed; + start = clock(); +#endif + + /* helper */ + #define _ase_error_return(m) \ + { \ + _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \ + _pico_free_parser( p ); \ + PicoFreeModel( model ); \ + return NULL; \ + } + /* create a new pico parser */ + p = _pico_new_parser( (picoByte_t *)buffer,bufSize ); + if (p == NULL) return NULL; + + /* create a new pico model */ + model = PicoNewModel(); + if (model == NULL) + { + _pico_free_parser( p ); + return NULL; + } + /* do model setup */ + PicoSetModelFrameNum( model, frameNum ); + PicoSetModelName( model, fileName ); + PicoSetModelFileName( model, fileName ); + + /* initialize some stuff */ + memset( lastNodeName,0,sizeof(lastNodeName) ); + + /* parse ase model file */ + while( 1 ) + { + /* get first token on line */ + if (_pico_parse_first( p ) == NULL) + break; + + /* we just skip empty lines */ + if (p->token == NULL || !strlen( p->token )) + continue; + + /* we skip invalid ase statements */ + if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}') + { + _pico_parse_skip_rest( p ); + continue; + } + /* remember node name */ + if (!_pico_stricmp(p->token,"*node_name")) + { + /* read node name */ + char *ptr = _pico_parse( p,0 ); + if (ptr == NULL) + _ase_error_return("Node name parse error"); + + /* remember node name */ + strncpy( lastNodeName,ptr,sizeof(lastNodeName) ); + } + /* model mesh (originally contained within geomobject) */ + else if (!_pico_stricmp(p->token,"*mesh")) + { + /* finish existing surface */ + //_ase_make_surface( model, &surface ); + _ase_submit_triangles (surface, model ,materials,faces); + _ase_free_faces (&faces,&facesTail); + + /* allocate new pico surface */ + surface = PicoNewSurface( NULL ); + if (surface == NULL) + { + PicoFreeModel( model ); + return NULL; + } + } + /* mesh material reference. this usually comes at the end of */ + /* geomobjects after the mesh blocks. we must assume that the */ + /* new mesh was already created so all we can do here is assign */ + /* the material reference id (shader index) now. */ + else if (!_pico_stricmp(p->token,"*material_ref")) + { + int mtlId; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + _ase_error_return("Missing mesh for material reference"); + + /* get the material ref (0..n) */ + if (!_pico_parse_int( p,&mtlId) ) + _ase_error_return("Missing material reference ID"); + + /* fix up all of the aseFaceList in the surface to point to the parent material */ + /* we've already saved off their subMtl */ + face = faces; + while ( face != NULL ) + { + face->mtlId = mtlId; + face = face->next; + } + } + /* model mesh vertex */ + else if (!_pico_stricmp(p->token,"*mesh_vertex")) + { + picoVec3_t v; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get vertex data (orig: index +y -x +z) */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Vertex parse error"); + if (!_pico_parse_vec( p,v )) + _ase_error_return("Vertex parse error"); + + /* set vertex */ + PicoSetSurfaceXYZ( surface,index,v ); + } + /* model mesh vertex normal */ + else if (!_pico_stricmp(p->token,"*mesh_vertexnormal")) + { + picoVec3_t v; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get vertex data (orig: index +y -x +z) */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Vertex parse error"); + if (!_pico_parse_vec( p,v )) + _ase_error_return("Vertex parse error"); + + /* set vertex */ + PicoSetSurfaceNormal( surface,index,v ); + } + /* model mesh face */ + else if (!_pico_stricmp(p->token,"*mesh_face")) + { + picoIndex_t indexes[3]; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Face parse error"); + + /* get 1st vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Face parse error"); + + /* get 2nd vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Face parse error"); + + /* get 3rd vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 0), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 1), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 2), indexes[0] ); + + /* parse to the subMaterial ID */ + while ( 1 ) + { + _pico_parse (p,0); + if (!_pico_stricmp (p->token,"*MESH_MTLID" )) + { + aseFace_t* newFace; + int subMtlId; + + _pico_parse_int ( p , &subMtlId ); + newFace = _pico_calloc ( 1 , sizeof ( aseFace_t )); + + /* we fix up the mtlId later when we parse the material_ref */ + newFace->mtlId = 0; + newFace->subMtlId = subMtlId; + newFace->index[0] = indexes[2]; + newFace->index[1] = indexes[1]; + newFace->index[2] = indexes[0]; + + _ase_add_face ( &faces,&facesTail,newFace ); + break; + } + } + + } + /* model texture vertex */ + else if (!_pico_stricmp(p->token,"*mesh_tvert")) + { + picoVec2_t uv; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get uv vertex index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("UV vertex parse error"); + + /* get uv vertex s */ + if (!_pico_parse_float( p,&uv[0] )) + _ase_error_return("UV vertex parse error"); + + /* get uv vertex t */ + if (!_pico_parse_float( p,&uv[1] )) + _ase_error_return("UV vertex parse error"); + + /* ydnar: invert t */ + uv[ 1 ] = 1.0f - uv[ 1 ]; + + /* set texture vertex */ + PicoSetSurfaceST( surface,0,index,uv ); + } + /* ydnar: model mesh texture face */ + else if( !_pico_stricmp( p->token, "*mesh_tface" ) ) + { + picoIndex_t indexes[3]; + int index; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Texture face parse error"); + + /* get 1st vertex index */ + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Texture face parse error"); + + /* get 2nd vertex index */ + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Texture face parse error"); + + /* get 3rd vertex index */ + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Texture face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 3), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 4), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 5), indexes[0] ); + + face = _ase_get_face_for_index(faces,index); + face->index[3] = indexes[2]; + face->index[4] = indexes[1]; + face->index[5] = indexes[0]; + } + /* model color vertex */ + else if (!_pico_stricmp(p->token,"*mesh_vertcol")) + { + picoColor_t color; + int index; + float colorInput; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get color vertex index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("UV vertex parse error"); + + /* get R component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[0] = (picoByte_t)(colorInput * 255); + + /* get G component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[1] = (picoByte_t)(colorInput * 255); + + /* get B component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[2] = (picoByte_t)(colorInput * 255); + + /* leave alpha alone since we don't get any data from the ASE format */ + color[3] = 255; + + /* set texture vertex */ + PicoSetSurfaceColor( surface,0,index,color ); + } + /* model color face */ + else if (!_pico_stricmp(p->token,"*mesh_cface")) + { + picoIndex_t indexes[3]; + int index; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Face parse error"); + + /* get 1st cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Face parse error"); + + /* get 2nd cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Face parse error"); + + /* get 3rd cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 6), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 7), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 8), indexes[0] ); + + face = _ase_get_face_for_index(faces,index); + face->index[6] = indexes[2]; + face->index[7] = indexes[1]; + face->index[8] = indexes[0]; + } + /* model material */ + else if( !_pico_stricmp( p->token, "*material" ) ) + { + aseSubMaterial_t* subMaterial = NULL; + picoShader_t *shader; + int level = 1, index; + char materialName[ 1024 ]; + float transValue = 0.0f, shineValue = 1.0f; + picoColor_t ambientColor, diffuseColor, specularColor; + char *mapname = NULL; + int subMtlId, subMaterialLevel = -1; + + + /* get material index */ + _pico_parse_int( p,&index ); + + /* check brace */ + if (!_pico_parse_check(p,1,"{")) + _ase_error_return("Material missing opening brace"); + + /* parse material block */ + while( 1 ) + { + /* get next token */ + if (_pico_parse(p,1) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + if( level == subMaterialLevel ) + { + /* set material name */ + PicoSetShaderName( shader, materialName); + + /* set shader's transparency */ + PicoSetShaderTransparency( shader,transValue ); + + /* set shader's ambient color */ + PicoSetShaderAmbientColor( shader,ambientColor ); + + /* set diffuse alpha to transparency */ + diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); + + /* set shader's diffuse color */ + PicoSetShaderDiffuseColor( shader,diffuseColor ); + + /* set shader's specular color */ + PicoSetShaderSpecularColor( shader,specularColor ); + + /* set shader's shininess */ + PicoSetShaderShininess( shader,shineValue ); + + /* set material map name */ + PicoSetShaderMapName( shader, mapname ); + + subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader ); + subMaterialLevel = -1; + } + + /* parse submaterial index */ + if (!_pico_stricmp(p->token,"*submaterial")) + { + /* allocate new pico shader */ + _pico_parse_int( p , &subMtlId ); + + shader = PicoNewShader( model ); + if (shader == NULL) + { + PicoFreeModel( model ); + return NULL; + } + subMaterialLevel = level; + } + /* parse material name */ + else if (!_pico_stricmp(p->token,"*material_name")) + { + char* name = _pico_parse(p,0); + if ( name == NULL) + _ase_error_return("Missing material name"); + + strcpy ( materialName , name ); + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse material transparency */ + else if (!_pico_stricmp(p->token,"*material_transparency")) + { + /* get transparency value from ase */ + if (!_pico_parse_float( p,&transValue )) + _ase_error_return("Material transparency parse error"); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse material shininess */ + else if (!_pico_stricmp(p->token,"*material_shine")) + { + /* remark: + * - not sure but instead of '*material_shine' i might + * need to use '*material_shinestrength' */ + + /* get shine value from ase */ + if (!_pico_parse_float( p,&shineValue )) + _ase_error_return("Material shine parse error"); + + /* scale ase shine range 0..1 to pico range 0..127 */ + shineValue *= 128.0; + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse ambient material color */ + else if (!_pico_stricmp(p->token,"*material_ambient")) + { + picoVec3_t vec; + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color values */ + ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); + ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); + ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); + ambientColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse diffuse material color */ + else if (!_pico_stricmp(p->token,"*material_diffuse")) + { + picoVec3_t vec; + + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color */ + diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); + diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); + diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); + diffuseColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse specular material color */ + else if (!_pico_stricmp(p->token,"*material_specular")) + { + picoVec3_t vec; + + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color */ + specularColor[ 0 ] = (int)( vec[ 0 ] * 255 ); + specularColor[ 1 ] = (int)( vec[ 1 ] * 255 ); + specularColor[ 2 ] = (int)( vec[ 2 ] * 255 ); + specularColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* material diffuse map */ + else if (!_pico_stricmp(p->token,"*map_diffuse") ) + { + int sublevel = 0; + + /* parse material block */ + while( 1 ) + { + /* get next token */ + if (_pico_parse(p,1) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') sublevel++; + if (p->token[0] == '}') sublevel--; + if (!sublevel) break; + + /* parse diffuse map bitmap */ + if (!_pico_stricmp(p->token,"*bitmap")) + { + char* name = _pico_parse(p,0); + if (name == NULL) + _ase_error_return("Missing material map bitmap name"); + mapname = _pico_alloc ( strlen ( name ) + 1 ); + strcpy ( mapname, name ); + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + } + } + /* end map_diffuse block */ + } + /* end material block */ + + if( subMaterial == NULL ) + { + /* allocate new pico shader */ + shader = PicoNewShader( model ); + if (shader == NULL) + { + PicoFreeModel( model ); + return NULL; + } + + /* set material name */ + PicoSetShaderName( shader,materialName ); + + /* set shader's transparency */ + PicoSetShaderTransparency( shader,transValue ); + + /* set shader's ambient color */ + PicoSetShaderAmbientColor( shader,ambientColor ); + + /* set diffuse alpha to transparency */ + diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); + + /* set shader's diffuse color */ + PicoSetShaderDiffuseColor( shader,diffuseColor ); + + /* set shader's specular color */ + PicoSetShaderSpecularColor( shader,specularColor ); + + /* set shader's shininess */ + PicoSetShaderShininess( shader,shineValue ); + + /* set material map name */ + PicoSetShaderMapName( shader, mapname ); + + /* this is just a material with 1 submaterial */ + subMaterial = _ase_add_submaterial( &materials, index, 0, shader ); + } + + /* ydnar: free mapname */ + if( mapname != NULL ) + _pico_free( mapname ); + } // !_pico_stricmp ( "*material" ) + + /* skip unparsed rest of line and continue */ + _pico_parse_skip_rest( p ); + } + + /* ydnar: finish existing surface */ +// _ase_make_surface( model, &surface ); + _ase_submit_triangles (surface, model ,materials,faces); + _ase_free_faces (&faces,&facesTail); + +#ifdef DEBUG_PM_ASE + _ase_print_materials(materials); + finish = clock(); + elapsed = (double)(finish - start) / CLOCKS_PER_SEC; + _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed ); +#endif //DEBUG_PM_ASE + + _ase_free_materials(&materials); + + /* return allocated pico model */ + return model; +} + +/* pico file format module definition */ +const picoModule_t picoModuleASE = +{ + "1.0", /* module version string */ + "Autodesk 3DSMAX ASCII", /* module display name */ + "Jared Hefty, seaw0lf", /* author's name */ + "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */ + { + "ase",NULL,NULL,NULL /* default extensions to use */ + }, + _ase_canload, /* validation routine */ + _ase_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_fm.c b/libs/picomodel/pm_fm.c index c6f8e538..bb3216c3 100644 --- a/libs/picomodel/pm_fm.c +++ b/libs/picomodel/pm_fm.c @@ -1,670 +1,670 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - -/* -Nurail: Used pm_md3.c (Randy Reddig) as a template. -*/ - -/* marker */ -#define PM_FM_C - -/* dependencies */ -#include "pm_fm.h" - -//#define FM_VERBOSE_DBG 0 -#undef FM_VERBOSE_DBG -#undef FM_DBG - -typedef struct index_LUT_s -{ - short Vert; - short ST; - struct index_LUT_s *next; - -} index_LUT_t; - -typedef struct index_DUP_LUT_s -{ - short ST; - short OldVert; - -} index_DUP_LUT_t; - - -// _fm_canload() -static int _fm_canload( PM_PARAMS_CANLOAD ) -{ - fm_t fm; - unsigned char *bb; - int fm_file_pos; - - bb = (unsigned char *) buffer; - - // Header - fm.fm_header_hdr = (fm_chunk_header_t *) bb; - fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident ); -#endif - if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); -#endif - return PICO_PMV_ERROR_IDENT; - } - - // check fm - if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); -#endif - return PICO_PMV_ERROR_VERSION; - } - - // Skin - fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident ); -#endif - if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); -#endif - return PICO_PMV_ERROR_IDENT; - } - - // check fm - if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); -#endif - return PICO_PMV_ERROR_VERSION; - } - - // st - fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident ); -#endif - if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); -#endif - return PICO_PMV_ERROR_IDENT; - } - - // check fm - if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); -#endif - return PICO_PMV_ERROR_VERSION; - } - - // tri - fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident ); -#endif - if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); -#endif - return PICO_PMV_ERROR_IDENT; - } - - // check fm - if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); -#endif - return PICO_PMV_ERROR_VERSION; - } - - // frame - fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t); -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident ); -#endif - if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); -#endif - return PICO_PMV_ERROR_IDENT; - } - - // check fm - if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) - { -#ifdef FM_DBG - _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); -#endif - return PICO_PMV_ERROR_VERSION; - } - - // file seems to be a valid fm - return PICO_PMV_OK; -} - - - -// _fm_load() loads a Heretic 2 model file. -static picoModel_t *_fm_load( PM_PARAMS_LOAD ) -{ - int i, j, dups, dup_index; - int fm_file_pos; - short tot_numVerts; - index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; - index_DUP_LUT_t *p_index_LUT_DUPS; - - fm_vert_normal_t *vert; - - char skinname[FM_SKINPATHSIZE]; - fm_t fm; - fm_header_t *fm_head; - fm_st_t *texCoord; - fm_xyz_st_t *tri_verts; - fm_xyz_st_t *triangle; - fm_frame_t *frame; - - picoByte_t *bb; - picoModel_t *picoModel; - picoSurface_t *picoSurface; - picoShader_t *picoShader; - picoVec3_t xyz, normal; - picoVec2_t st; - picoColor_t color; - - - // fm loading - _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); - - bb = (picoByte_t*) buffer; - - // Header Header - fm.fm_header_hdr = (fm_chunk_header_t *) bb; - fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; - if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) - { - _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); - return NULL; - } - - if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) - { - _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); - return NULL; - } - - // Skin Header - fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; - if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) - { - _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); - return NULL; - } - - if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) - { - _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); - return NULL; - } - - // ST Header - fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; - if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) - { - _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); - return NULL; - } - - if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) - { - _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); - return NULL; - } - - // Tris Header - fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; - if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) - { - _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); - return NULL; - } - - if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) - { - _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); - return NULL; - } - - // Frame Header - fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); - fm_file_pos += sizeof(fm_chunk_header_t); - if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) - { - _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); - return NULL; - } - - if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) - { - _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); - return NULL; - } - - // Header - fm_file_pos = sizeof(fm_chunk_header_t); - fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos); - fm_file_pos += fm.fm_header_hdr->size; - - // Skin - fm_file_pos += sizeof(fm_chunk_header_t); - fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos); - fm_file_pos += fm.fm_skin_hdr->size; - - // ST - fm_file_pos += sizeof(fm_chunk_header_t); - texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos); - fm_file_pos += fm.fm_st_hdr->size; - - // Tri - fm_file_pos += sizeof(fm_chunk_header_t); - tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos); - fm_file_pos += fm.fm_tri_hdr->size; - - // Frame - fm_file_pos += sizeof(fm_chunk_header_t); - frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos); - - // do frame check - if( fm_head->numFrames < 1 ) - { - _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); - return NULL; - } - - if( frameNum < 0 || frameNum >= fm_head->numFrames ) - { - _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" ); - return NULL; - } - - // swap fm - fm_head->skinWidth = _pico_little_long( fm_head->skinWidth ); - fm_head->skinHeight = _pico_little_long( fm_head->skinHeight ); - fm_head->frameSize = _pico_little_long( fm_head->frameSize ); - - fm_head->numSkins = _pico_little_long( fm_head->numSkins ); - fm_head->numXYZ = _pico_little_long( fm_head->numXYZ ); - fm_head->numST = _pico_little_long( fm_head->numST ); - fm_head->numTris = _pico_little_long( fm_head->numTris ); - fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds ); - fm_head->numFrames = _pico_little_long( fm_head->numFrames ); - - // swap frame scale and translation - for( i = 0; i < 3; i++ ) - { - frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] ); - frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] ); - } - - // swap triangles - triangle = tri_verts; - for( i = 0; i < fm_head->numTris; i++, triangle++ ) - { - for( j = 0; j < 3; j++ ) - { - triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); - triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); - } - } - - // swap st coords - for( i = 0; i < fm_head->numST; i++ ) - { - texCoord->s = _pico_little_short( texCoord[i].s ); - texCoord->t = _pico_little_short( texCoord[i].t ); - } - // set Skin Name - strncpy(skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE ); - -#ifdef FM_VERBOSE_DBG - // Print out md2 values - _pico_printf(PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname ); -#endif - - // detox Skin name - _pico_setfext( skinname, "" ); - _pico_unixify( skinname ); - - /* create new pico model */ - picoModel = PicoNewModel(); - if( picoModel == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); - return NULL; - } - - /* do model setup */ - PicoSetModelFrameNum( picoModel, frameNum ); - PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */ - PicoSetModelName( picoModel, fileName ); - PicoSetModelFileName( picoModel, fileName ); - - // allocate new pico surface - picoSurface = PicoNewSurface( picoModel ); - if( picoSurface == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); - PicoFreeModel( picoModel ); - return NULL; - } - - - PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); - PicoSetSurfaceName( picoSurface, frame->header.name ); - picoShader = PicoNewShader( picoModel ); - if( picoShader == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); - PicoFreeModel( picoModel ); - return NULL; - } - - PicoSetShaderName( picoShader, skinname ); - - // associate current surface with newly created shader - PicoSetSurfaceShader( picoSurface, picoShader ); - - // Init LUT for Verts - p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ); - for(i=0; inumXYZ; i++) - { - p_index_LUT[i].Vert = -1; - p_index_LUT[i].ST = -1; - p_index_LUT[i].next = NULL; - } - - // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. - tot_numVerts = fm_head->numXYZ; - dups = 0; - triangle = tri_verts; - - for(i=0; inumTris; i++) - { - for(j=0; j<3; j++) - { - if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry - p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j]; - - else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry - { -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); -#endif - continue; - } - else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry - { // Add first entry of LL from Main - p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); - if (p_index_LUT2 == NULL) - _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); - p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; - p_index_LUT2->Vert = dups; - p_index_LUT2->ST = triangle->index_st[j]; - p_index_LUT2->next = NULL; -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]); -#endif - triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk - dups++; - } - else // Try to find in LL from Main Entry - { - p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next; - while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL - { - p_index_LUT3 = p_index_LUT2; - p_index_LUT2 = p_index_LUT2->next; - } - p_index_LUT2 = p_index_LUT3; - - if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it - { - triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); -#endif - continue; - } - - if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. - { - // Add the Entry - p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); - if (p_index_LUT3 == NULL) - _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); - p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; - p_index_LUT3->Vert = dups; - p_index_LUT3->ST = triangle->index_st[j]; - p_index_LUT3->next = NULL; -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]); -#endif - triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk - dups++; - } - } -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); -#endif - } - triangle++; - } - - // malloc and build array for Dup STs - p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); - if (p_index_LUT_DUPS == NULL) - _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); - - dup_index = 0; - for(i=0; inumXYZ; i++) - { - p_index_LUT2 = p_index_LUT[i].next; - while (p_index_LUT2 != NULL) - { - p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; - p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; - dup_index++; - p_index_LUT2 = p_index_LUT2->next; - } - } -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, " Dups = %d\n", dups); - _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index); -#endif - for(i=0; inumXYZ; i++) - { -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST); -#endif - if (p_index_LUT[i].next != NULL) - { - - p_index_LUT2 = p_index_LUT[i].next; - do { -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST); -#endif - p_index_LUT2 = p_index_LUT2->next; - } while ( p_index_LUT2 != NULL); - - } -#ifdef FM_VERBOSE_DBG - _pico_printf( PICO_NORMAL, "\n"); -#endif - } - - -#ifdef FM_VERBOSE_DBG - for(i=0; inumTris; i++) - { - for(j=0; j<3; j++) - _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); - _pico_printf( PICO_NORMAL, "\n"); - triangle++; - } -#endif - // Build Picomodel - triangle = tri_verts; - for( j = 0; j < fm_head->numTris; j++, triangle++ ) - { - PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); - PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); - PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); - } - - vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) ); - for(i=0; i< fm_head->numXYZ; i++, vert++) - { - /* set vertex origin */ - xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0]; - xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1]; - xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2]; - PicoSetSurfaceXYZ( picoSurface, i , xyz ); - - /* set normal */ - normal[ 0 ] = fm_normals[vert->lightnormalindex][0]; - normal[ 1 ] = fm_normals[vert->lightnormalindex][1]; - normal[ 2 ] = fm_normals[vert->lightnormalindex][2]; - PicoSetSurfaceNormal( picoSurface, i , normal ); - - /* set st coords */ - st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth)); - st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight)); - PicoSetSurfaceST( picoSurface, 0, i , st ); - } - - if (dups) - { - for(i=0; iverts[j].v[0] * frame->header.scale[0] + frame->header.translate[0]; - xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1]; - xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2]; - PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz ); - - /* set normal */ - normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0]; - normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1]; - normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2]; - PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal ); - - /* set st coords */ - st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth)); - st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight)); - PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st ); - } - } - - /* set color */ - PicoSetSurfaceColor( picoSurface, 0, 0, color ); - - // Free up malloc'ed LL entries - for(i=0; inumXYZ; i++) - { - if(p_index_LUT[i].next != NULL) - { - p_index_LUT2 = p_index_LUT[i].next; - do { - p_index_LUT3 = p_index_LUT2->next; - _pico_free(p_index_LUT2); - p_index_LUT2 = p_index_LUT3; - dups--; - } while (p_index_LUT2 != NULL); - } - } - - if (dups) - _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); - - // Free malloc'ed LUTs - _pico_free(p_index_LUT); - _pico_free(p_index_LUT_DUPS); - - /* return the new pico model */ - return picoModel; - -} - - - -/* pico file format module definition */ -const picoModule_t picoModuleFM = -{ - "0.85", /* module version string */ - "Heretic 2 FM", /* module display name */ - "Nurail", /* author's name */ - "2003 Nurail", /* module copyright */ - { - "fm", NULL, NULL, NULL /* default extensions to use */ - }, - _fm_canload, /* validation routine */ - _fm_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +/* +Nurail: Used pm_md3.c (Randy Reddig) as a template. +*/ + +/* marker */ +#define PM_FM_C + +/* dependencies */ +#include "pm_fm.h" + +//#define FM_VERBOSE_DBG 0 +#undef FM_VERBOSE_DBG +#undef FM_DBG + +typedef struct index_LUT_s +{ + short Vert; + short ST; + struct index_LUT_s *next; + +} index_LUT_t; + +typedef struct index_DUP_LUT_s +{ + short ST; + short OldVert; + +} index_DUP_LUT_t; + + +// _fm_canload() +static int _fm_canload( PM_PARAMS_CANLOAD ) +{ + fm_t fm; + unsigned char *bb; + int fm_file_pos; + + bb = (unsigned char *) buffer; + + // Header + fm.fm_header_hdr = (fm_chunk_header_t *) bb; + fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident ); +#endif + if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // Skin + fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident ); +#endif + if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // st + fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident ); +#endif + if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // tri + fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident ); +#endif + if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // frame + fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t); +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident ); +#endif + if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // file seems to be a valid fm + return PICO_PMV_OK; +} + + + +// _fm_load() loads a Heretic 2 model file. +static picoModel_t *_fm_load( PM_PARAMS_LOAD ) +{ + int i, j, dups, dup_index; + int fm_file_pos; + short tot_numVerts; + index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; + index_DUP_LUT_t *p_index_LUT_DUPS; + + fm_vert_normal_t *vert; + + char skinname[FM_SKINPATHSIZE]; + fm_t fm; + fm_header_t *fm_head; + fm_st_t *texCoord; + fm_xyz_st_t *tri_verts; + fm_xyz_st_t *triangle; + fm_frame_t *frame; + + picoByte_t *bb; + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + // fm loading + _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); + + bb = (picoByte_t*) buffer; + + // Header Header + fm.fm_header_hdr = (fm_chunk_header_t *) bb; + fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; + if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); + return NULL; + } + + // Skin Header + fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; + if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); + return NULL; + } + + // ST Header + fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; + if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); + return NULL; + } + + // Tris Header + fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; + if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); + return NULL; + } + + // Frame Header + fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t); + if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); + return NULL; + } + + // Header + fm_file_pos = sizeof(fm_chunk_header_t); + fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_header_hdr->size; + + // Skin + fm_file_pos += sizeof(fm_chunk_header_t); + fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_skin_hdr->size; + + // ST + fm_file_pos += sizeof(fm_chunk_header_t); + texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_st_hdr->size; + + // Tri + fm_file_pos += sizeof(fm_chunk_header_t); + tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_tri_hdr->size; + + // Frame + fm_file_pos += sizeof(fm_chunk_header_t); + frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos); + + // do frame check + if( fm_head->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); + return NULL; + } + + if( frameNum < 0 || frameNum >= fm_head->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" ); + return NULL; + } + + // swap fm + fm_head->skinWidth = _pico_little_long( fm_head->skinWidth ); + fm_head->skinHeight = _pico_little_long( fm_head->skinHeight ); + fm_head->frameSize = _pico_little_long( fm_head->frameSize ); + + fm_head->numSkins = _pico_little_long( fm_head->numSkins ); + fm_head->numXYZ = _pico_little_long( fm_head->numXYZ ); + fm_head->numST = _pico_little_long( fm_head->numST ); + fm_head->numTris = _pico_little_long( fm_head->numTris ); + fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds ); + fm_head->numFrames = _pico_little_long( fm_head->numFrames ); + + // swap frame scale and translation + for( i = 0; i < 3; i++ ) + { + frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] ); + frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] ); + } + + // swap triangles + triangle = tri_verts; + for( i = 0; i < fm_head->numTris; i++, triangle++ ) + { + for( j = 0; j < 3; j++ ) + { + triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); + triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); + } + } + + // swap st coords + for( i = 0; i < fm_head->numST; i++ ) + { + texCoord->s = _pico_little_short( texCoord[i].s ); + texCoord->t = _pico_little_short( texCoord[i].t ); + } + // set Skin Name + strncpy(skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE ); + +#ifdef FM_VERBOSE_DBG + // Print out md2 values + _pico_printf(PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname ); +#endif + + // detox Skin name + _pico_setfext( skinname, "" ); + _pico_unixify( skinname ); + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + // allocate new pico surface + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + return NULL; + } + + + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( picoSurface, frame->header.name ); + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + PicoSetShaderName( picoShader, skinname ); + + // associate current surface with newly created shader + PicoSetSurfaceShader( picoSurface, picoShader ); + + // Init LUT for Verts + p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ); + for(i=0; inumXYZ; i++) + { + p_index_LUT[i].Vert = -1; + p_index_LUT[i].ST = -1; + p_index_LUT[i].next = NULL; + } + + // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. + tot_numVerts = fm_head->numXYZ; + dups = 0; + triangle = tri_verts; + + for(i=0; inumTris; i++) + { + for(j=0; j<3; j++) + { + if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry + p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j]; + + else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry + { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + continue; + } + else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry + { // Add first entry of LL from Main + p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT2 == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; + p_index_LUT2->Vert = dups; + p_index_LUT2->ST = triangle->index_st[j]; + p_index_LUT2->next = NULL; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]); +#endif + triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk + dups++; + } + else // Try to find in LL from Main Entry + { + p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next; + while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL + { + p_index_LUT3 = p_index_LUT2; + p_index_LUT2 = p_index_LUT2->next; + } + p_index_LUT2 = p_index_LUT3; + + if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it + { + triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + continue; + } + + if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. + { + // Add the Entry + p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT3 == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; + p_index_LUT3->Vert = dups; + p_index_LUT3->ST = triangle->index_st[j]; + p_index_LUT3->next = NULL; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]); +#endif + triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk + dups++; + } + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + } + triangle++; + } + + // malloc and build array for Dup STs + p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); + if (p_index_LUT_DUPS == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + + dup_index = 0; + for(i=0; inumXYZ; i++) + { + p_index_LUT2 = p_index_LUT[i].next; + while (p_index_LUT2 != NULL) + { + p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; + p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; + dup_index++; + p_index_LUT2 = p_index_LUT2->next; + } + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " Dups = %d\n", dups); + _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index); +#endif + for(i=0; inumXYZ; i++) + { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST); +#endif + if (p_index_LUT[i].next != NULL) + { + + p_index_LUT2 = p_index_LUT[i].next; + do { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST); +#endif + p_index_LUT2 = p_index_LUT2->next; + } while ( p_index_LUT2 != NULL); + + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "\n"); +#endif + } + + +#ifdef FM_VERBOSE_DBG + for(i=0; inumTris; i++) + { + for(j=0; j<3; j++) + _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); + _pico_printf( PICO_NORMAL, "\n"); + triangle++; + } +#endif + // Build Picomodel + triangle = tri_verts; + for( j = 0; j < fm_head->numTris; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); + PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); + PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); + } + + vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) ); + for(i=0; i< fm_head->numXYZ; i++, vert++) + { + /* set vertex origin */ + xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0]; + xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1]; + xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2]; + PicoSetSurfaceXYZ( picoSurface, i , xyz ); + + /* set normal */ + normal[ 0 ] = fm_normals[vert->lightnormalindex][0]; + normal[ 1 ] = fm_normals[vert->lightnormalindex][1]; + normal[ 2 ] = fm_normals[vert->lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i , st ); + } + + if (dups) + { + for(i=0; iverts[j].v[0] * frame->header.scale[0] + frame->header.translate[0]; + xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1]; + xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2]; + PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz ); + + /* set normal */ + normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0]; + normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1]; + normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st ); + } + } + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, 0, color ); + + // Free up malloc'ed LL entries + for(i=0; inumXYZ; i++) + { + if(p_index_LUT[i].next != NULL) + { + p_index_LUT2 = p_index_LUT[i].next; + do { + p_index_LUT3 = p_index_LUT2->next; + _pico_free(p_index_LUT2); + p_index_LUT2 = p_index_LUT3; + dups--; + } while (p_index_LUT2 != NULL); + } + } + + if (dups) + _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); + + // Free malloc'ed LUTs + _pico_free(p_index_LUT); + _pico_free(p_index_LUT_DUPS); + + /* return the new pico model */ + return picoModel; + +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleFM = +{ + "0.85", /* module version string */ + "Heretic 2 FM", /* module display name */ + "Nurail", /* author's name */ + "2003 Nurail", /* module copyright */ + { + "fm", NULL, NULL, NULL /* default extensions to use */ + }, + _fm_canload, /* validation routine */ + _fm_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_fm.h b/libs/picomodel/pm_fm.h index ce43d334..3fd5148e 100644 --- a/libs/picomodel/pm_fm.h +++ b/libs/picomodel/pm_fm.h @@ -1,367 +1,367 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - -// This header file is based from the following: - -/* - FlexModel.H - Header file for FlexModel file structure - - By Chris Burke - serotonin@earthlink.net -*/ - -#ifndef __PM_FM_H__ -#define __PM_FM_H__ - -#include "picointernal.h" - - -// -// Absolute limits (from QData / QMView source) -// -#define MAX_FM_TRIANGLES 2048 -#define MAX_FM_VERTS 2048 -#define MAX_FM_FRAMES 2048 -#define MAX_FM_SKINS 64 -#define MAX_FM_SKINNAME 64 -#define MAX_FM_MESH_NODES 16 - -#define DTRIVERTX_V0 0 -#define DTRIVERTX_V1 1 -#define DTRIVERTX_V2 2 -#define DTRIVERTX_LNI 3 -#define DTRIVERTX_SIZE 4 - -#define SKINPAGE_WIDTH 640 -#define SKINPAGE_HEIGHT 480 - -#define ENCODED_WIDTH_X 92 -#define ENCODED_WIDTH_Y 475 -#define ENCODED_HEIGHT_X 128 -#define ENCODED_HEIGHT_Y 475 - -#define SCALE_ADJUST_FACTOR 0.96 - -#define INFO_HEIGHT 5 -#define INFO_Y (SKINPAGE_HEIGHT-INFO_HEIGHT) - -#ifndef byte - #define byte unsigned char -#endif - - -// -// Generic header on every chunk -// -#define FM_MAXCHUNKIDENT 32L -typedef struct -{ - char ident[FM_MAXCHUNKIDENT]; - unsigned int version; - unsigned int size; -} fm_chunk_header_t; - -// -// The format of the "header" chunk -// -#define FM_HEADERCHUNKNAME "header" -#define FM_HEADERCHUNKVER 2 -#define FM_HEADERCHUNKSIZE 40 -typedef struct -{ - int skinWidth; // in pixels - int skinHeight; // in pixels - int frameSize; // size of each frame (in bytes) - int numSkins; // number of skins - int numXYZ; // number of unique vertices in 3D space - int numST; // number of unique vertices in texture space - int numTris; // number of unique triangles - int numGLCmds; // # 32-bit elements in strip/fan command list - int numFrames; // number of animation frames - int numMeshNodes; // number of mesh nodes -} fm_header_t; - -// -// The format of an entry in the "skin" chunk. -// The number of entries is given in the fmheader chunk -// -#define FM_SKINCHUNKNAME "skin" -#define FM_SKINCHUNKVER 1 -#define FM_MAXPATHLENGTH 64L -#define FM_SKINPATHSIZE (FM_MAXPATHLENGTH) -typedef struct -{ - char path[FM_SKINPATHSIZE]; // path, relative to 'base' -} fm_skinpath_t; - -// -// The format of the "st coord" chunk. This is a list -// of unique skin texture (u, v) coordinates to be mapped -// to verteces of the model -// -#define FM_STCOORDCHUNKNAME "st coord" -#define FM_STCOORDCHUNKVER 1 -#define FM_STCOORDUVSIZE (2L + 2L) - -typedef struct -{ - short s; - short t; -} fm_st_t; - -// -// The format of the "tris" chunk. This is a list of vertex indeces -// in 3D space, and the corresponding vertex indeces in texture space. -// -#define FM_TRISCHUNKNAME "tris" -#define FM_TRISCHUNKVER 1 -#define FM_TRISINFOSIZE (2L*3 + 2L*3) - -typedef struct -{ - short index_xyz[3]; - short index_st[3]; -} fm_xyz_st_t; - - -// -// The format of the "frames" chunk. This is a list of animation -// frames, each specifying the coordinates and "light normal" index -// of every vertex of the model in 3D space. -// -#define FM_FRAMESCHUNKNAME "frames" -#define FM_FRAMESCHUNKVER 1 - -#define FM_NUMVERTEXNORMALS 162 - -// Frame info -typedef struct -{ - byte v[3]; // scaled by header info - byte lightnormalindex; // index in canned table of closest vertex normal -} fm_vert_normal_t; - -typedef struct -{ - float scale[3]; // multiply byte verts by this - float translate[3]; // then add this - char name[16]; // frame name -} fm_framehdr_t; - -typedef struct -{ - fm_framehdr_t header; // One header per frame - fm_vert_normal_t verts[1]; // variable number of these -} fm_frame_t; - -typedef struct -{ - fm_chunk_header_t *fm_header_hdr; - fm_header_t *fm_header; - fm_chunk_header_t *fm_skin_hdr; - fm_skinpath_t *fm_skin; - fm_chunk_header_t *fm_st_hdr; - fm_st_t *fm_st; - fm_chunk_header_t *fm_tri_hdr; - fm_xyz_st_t *fm_tri; - fm_chunk_header_t *fm_frame_hdr; - fm_frame_t *fm_frame; -} fm_t; - -float fm_normals[FM_NUMVERTEXNORMALS][3] = { - {-0.525731f, 0.000000f, 0.850651f}, - {-0.442863f, 0.238856f, 0.864188f}, - {-0.295242f, 0.000000f, 0.955423f}, - {-0.309017f, 0.500000f, 0.809017f}, - {-0.162460f, 0.262866f, 0.951056f}, - {0.000000f, 0.000000f, 1.000000f}, - {0.000000f, 0.850651f, 0.525731f}, - {-0.147621f, 0.716567f, 0.681718f}, - {0.147621f, 0.716567f, 0.681718f}, - {0.000000f, 0.525731f, 0.850651f}, - {0.309017f, 0.500000f, 0.809017f}, - {0.525731f, 0.000000f, 0.850651f}, - {0.295242f, 0.000000f, 0.955423f}, - {0.442863f, 0.238856f, 0.864188f}, - {0.162460f, 0.262866f, 0.951056f}, - {-0.681718f, 0.147621f, 0.716567f}, - {-0.809017f, 0.309017f, 0.500000f}, - {-0.587785f, 0.425325f, 0.688191f}, - {-0.850651f, 0.525731f, 0.000000f}, - {-0.864188f, 0.442863f, 0.238856f}, - {-0.716567f, 0.681718f, 0.147621f}, - {-0.688191f, 0.587785f, 0.425325f}, - {-0.500000f, 0.809017f, 0.309017f}, - {-0.238856f, 0.864188f, 0.442863f}, - {-0.425325f, 0.688191f, 0.587785f}, - {-0.716567f, 0.681718f, -0.147621f}, - {-0.500000f, 0.809017f, -0.309017f}, - {-0.525731f, 0.850651f, 0.000000f}, - {0.000000f, 0.850651f, -0.525731f}, - {-0.238856f, 0.864188f, -0.442863f}, - {0.000000f, 0.955423f, -0.295242f}, - {-0.262866f, 0.951056f, -0.162460f}, - {0.000000f, 1.000000f, 0.000000f}, - {0.000000f, 0.955423f, 0.295242f}, - {-0.262866f, 0.951056f, 0.162460f}, - {0.238856f, 0.864188f, 0.442863f}, - {0.262866f, 0.951056f, 0.162460f}, - {0.500000f, 0.809017f, 0.309017f}, - {0.238856f, 0.864188f, -0.442863f}, - {0.262866f, 0.951056f, -0.162460f}, - {0.500000f, 0.809017f, -0.309017f}, - {0.850651f, 0.525731f, 0.000000f}, - {0.716567f, 0.681718f, 0.147621f}, - {0.716567f, 0.681718f, -0.147621f}, - {0.525731f, 0.850651f, 0.000000f}, - {0.425325f, 0.688191f, 0.587785f}, - {0.864188f, 0.442863f, 0.238856f}, - {0.688191f, 0.587785f, 0.425325f}, - {0.809017f, 0.309017f, 0.500000f}, - {0.681718f, 0.147621f, 0.716567f}, - {0.587785f, 0.425325f, 0.688191f}, - {0.955423f, 0.295242f, 0.000000f}, - {1.000000f, 0.000000f, 0.000000f}, - {0.951056f, 0.162460f, 0.262866f}, - {0.850651f, -0.525731f, 0.000000f}, - {0.955423f, -0.295242f, 0.000000f}, - {0.864188f, -0.442863f, 0.238856f}, - {0.951056f, -0.162460f, 0.262866f}, - {0.809017f, -0.309017f, 0.500000f}, - {0.681718f, -0.147621f, 0.716567f}, - {0.850651f, 0.000000f, 0.525731f}, - {0.864188f, 0.442863f, -0.238856f}, - {0.809017f, 0.309017f, -0.500000f}, - {0.951056f, 0.162460f, -0.262866f}, - {0.525731f, 0.000000f, -0.850651f}, - {0.681718f, 0.147621f, -0.716567f}, - {0.681718f, -0.147621f, -0.716567f}, - {0.850651f, 0.000000f, -0.525731f}, - {0.809017f, -0.309017f, -0.500000f}, - {0.864188f, -0.442863f, -0.238856f}, - {0.951056f, -0.162460f, -0.262866f}, - {0.147621f, 0.716567f, -0.681718f}, - {0.309017f, 0.500000f, -0.809017f}, - {0.425325f, 0.688191f, -0.587785f}, - {0.442863f, 0.238856f, -0.864188f}, - {0.587785f, 0.425325f, -0.688191f}, - {0.688191f, 0.587785f, -0.425325f}, - {-0.147621f, 0.716567f, -0.681718f}, - {-0.309017f, 0.500000f, -0.809017f}, - {0.000000f, 0.525731f, -0.850651f}, - {-0.525731f, 0.000000f, -0.850651f}, - {-0.442863f, 0.238856f, -0.864188f}, - {-0.295242f, 0.000000f, -0.955423f}, - {-0.162460f, 0.262866f, -0.951056f}, - {0.000000f, 0.000000f, -1.000000f}, - {0.295242f, 0.000000f, -0.955423f}, - {0.162460f, 0.262866f, -0.951056f}, - {-0.442863f, -0.238856f, -0.864188f}, - {-0.309017f, -0.500000f, -0.809017f}, - {-0.162460f, -0.262866f, -0.951056f}, - {0.000000f, -0.850651f, -0.525731f}, - {-0.147621f, -0.716567f, -0.681718f}, - {0.147621f, -0.716567f, -0.681718f}, - {0.000000f, -0.525731f, -0.850651f}, - {0.309017f, -0.500000f, -0.809017f}, - {0.442863f, -0.238856f, -0.864188f}, - {0.162460f, -0.262866f, -0.951056f}, - {0.238856f, -0.864188f, -0.442863f}, - {0.500000f, -0.809017f, -0.309017f}, - {0.425325f, -0.688191f, -0.587785f}, - {0.716567f, -0.681718f, -0.147621f}, - {0.688191f, -0.587785f, -0.425325f}, - {0.587785f, -0.425325f, -0.688191f}, - {0.000000f, -0.955423f, -0.295242f}, - {0.000000f, -1.000000f, 0.000000f}, - {0.262866f, -0.951056f, -0.162460f}, - {0.000000f, -0.850651f, 0.525731f}, - {0.000000f, -0.955423f, 0.295242f}, - {0.238856f, -0.864188f, 0.442863f}, - {0.262866f, -0.951056f, 0.162460f}, - {0.500000f, -0.809017f, 0.309017f}, - {0.716567f, -0.681718f, 0.147621f}, - {0.525731f, -0.850651f, 0.000000f}, - {-0.238856f, -0.864188f, -0.442863f}, - {-0.500000f, -0.809017f, -0.309017f}, - {-0.262866f, -0.951056f, -0.162460f}, - {-0.850651f, -0.525731f, 0.000000f}, - {-0.716567f, -0.681718f, -0.147621f}, - {-0.716567f, -0.681718f, 0.147621f}, - {-0.525731f, -0.850651f, 0.000000f}, - {-0.500000f, -0.809017f, 0.309017f}, - {-0.238856f, -0.864188f, 0.442863f}, - {-0.262866f, -0.951056f, 0.162460f}, - {-0.864188f, -0.442863f, 0.238856f}, - {-0.809017f, -0.309017f, 0.500000f}, - {-0.688191f, -0.587785f, 0.425325f}, - {-0.681718f, -0.147621f, 0.716567f}, - {-0.442863f, -0.238856f, 0.864188f}, - {-0.587785f, -0.425325f, 0.688191f}, - {-0.309017f, -0.500000f, 0.809017f}, - {-0.147621f, -0.716567f, 0.681718f}, - {-0.425325f, -0.688191f, 0.587785f}, - {-0.162460f, -0.262866f, 0.951056f}, - {0.442863f, -0.238856f, 0.864188f}, - {0.162460f, -0.262866f, 0.951056f}, - {0.309017f, -0.500000f, 0.809017f}, - {0.147621f, -0.716567f, 0.681718f}, - {0.000000f, -0.525731f, 0.850651f}, - {0.425325f, -0.688191f, 0.587785f}, - {0.587785f, -0.425325f, 0.688191f}, - {0.688191f, -0.587785f, 0.425325f}, - {-0.955423f, 0.295242f, 0.000000f}, - {-0.951056f, 0.162460f, 0.262866f}, - {-1.000000f, 0.000000f, 0.000000f}, - {-0.850651f, 0.000000f, 0.525731f}, - {-0.955423f, -0.295242f, 0.000000f}, - {-0.951056f, -0.162460f, 0.262866f}, - {-0.864188f, 0.442863f, -0.238856f}, - {-0.951056f, 0.162460f, -0.262866f}, - {-0.809017f, 0.309017f, -0.500000f}, - {-0.864188f, -0.442863f, -0.238856f}, - {-0.951056f, -0.162460f, -0.262866f}, - {-0.809017f, -0.309017f, -0.500000f}, - {-0.681718f, 0.147621f, -0.716567f}, - {-0.681718f, -0.147621f, -0.716567f}, - {-0.850651f, 0.000000f, -0.525731f}, - {-0.688191f, 0.587785f, -0.425325f}, - {-0.587785f, 0.425325f, -0.688191f}, - {-0.425325f, 0.688191f, -0.587785f}, - {-0.425325f, -0.688191f, -0.587785f}, - {-0.587785f, -0.425325f, -0.688191f}, - {-0.688191f, -0.587785f, -0.425325f}, -}; - -#endif +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +// This header file is based from the following: + +/* + FlexModel.H - Header file for FlexModel file structure + + By Chris Burke + serotonin@earthlink.net +*/ + +#ifndef __PM_FM_H__ +#define __PM_FM_H__ + +#include "picointernal.h" + + +// +// Absolute limits (from QData / QMView source) +// +#define MAX_FM_TRIANGLES 2048 +#define MAX_FM_VERTS 2048 +#define MAX_FM_FRAMES 2048 +#define MAX_FM_SKINS 64 +#define MAX_FM_SKINNAME 64 +#define MAX_FM_MESH_NODES 16 + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +#define SKINPAGE_WIDTH 640 +#define SKINPAGE_HEIGHT 480 + +#define ENCODED_WIDTH_X 92 +#define ENCODED_WIDTH_Y 475 +#define ENCODED_HEIGHT_X 128 +#define ENCODED_HEIGHT_Y 475 + +#define SCALE_ADJUST_FACTOR 0.96 + +#define INFO_HEIGHT 5 +#define INFO_Y (SKINPAGE_HEIGHT-INFO_HEIGHT) + +#ifndef byte + #define byte unsigned char +#endif + + +// +// Generic header on every chunk +// +#define FM_MAXCHUNKIDENT 32L +typedef struct +{ + char ident[FM_MAXCHUNKIDENT]; + unsigned int version; + unsigned int size; +} fm_chunk_header_t; + +// +// The format of the "header" chunk +// +#define FM_HEADERCHUNKNAME "header" +#define FM_HEADERCHUNKVER 2 +#define FM_HEADERCHUNKSIZE 40 +typedef struct +{ + int skinWidth; // in pixels + int skinHeight; // in pixels + int frameSize; // size of each frame (in bytes) + int numSkins; // number of skins + int numXYZ; // number of unique vertices in 3D space + int numST; // number of unique vertices in texture space + int numTris; // number of unique triangles + int numGLCmds; // # 32-bit elements in strip/fan command list + int numFrames; // number of animation frames + int numMeshNodes; // number of mesh nodes +} fm_header_t; + +// +// The format of an entry in the "skin" chunk. +// The number of entries is given in the fmheader chunk +// +#define FM_SKINCHUNKNAME "skin" +#define FM_SKINCHUNKVER 1 +#define FM_MAXPATHLENGTH 64L +#define FM_SKINPATHSIZE (FM_MAXPATHLENGTH) +typedef struct +{ + char path[FM_SKINPATHSIZE]; // path, relative to 'base' +} fm_skinpath_t; + +// +// The format of the "st coord" chunk. This is a list +// of unique skin texture (u, v) coordinates to be mapped +// to verteces of the model +// +#define FM_STCOORDCHUNKNAME "st coord" +#define FM_STCOORDCHUNKVER 1 +#define FM_STCOORDUVSIZE (2L + 2L) + +typedef struct +{ + short s; + short t; +} fm_st_t; + +// +// The format of the "tris" chunk. This is a list of vertex indeces +// in 3D space, and the corresponding vertex indeces in texture space. +// +#define FM_TRISCHUNKNAME "tris" +#define FM_TRISCHUNKVER 1 +#define FM_TRISINFOSIZE (2L*3 + 2L*3) + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} fm_xyz_st_t; + + +// +// The format of the "frames" chunk. This is a list of animation +// frames, each specifying the coordinates and "light normal" index +// of every vertex of the model in 3D space. +// +#define FM_FRAMESCHUNKNAME "frames" +#define FM_FRAMESCHUNKVER 1 + +#define FM_NUMVERTEXNORMALS 162 + +// Frame info +typedef struct +{ + byte v[3]; // scaled by header info + byte lightnormalindex; // index in canned table of closest vertex normal +} fm_vert_normal_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name +} fm_framehdr_t; + +typedef struct +{ + fm_framehdr_t header; // One header per frame + fm_vert_normal_t verts[1]; // variable number of these +} fm_frame_t; + +typedef struct +{ + fm_chunk_header_t *fm_header_hdr; + fm_header_t *fm_header; + fm_chunk_header_t *fm_skin_hdr; + fm_skinpath_t *fm_skin; + fm_chunk_header_t *fm_st_hdr; + fm_st_t *fm_st; + fm_chunk_header_t *fm_tri_hdr; + fm_xyz_st_t *fm_tri; + fm_chunk_header_t *fm_frame_hdr; + fm_frame_t *fm_frame; +} fm_t; + +float fm_normals[FM_NUMVERTEXNORMALS][3] = { + {-0.525731f, 0.000000f, 0.850651f}, + {-0.442863f, 0.238856f, 0.864188f}, + {-0.295242f, 0.000000f, 0.955423f}, + {-0.309017f, 0.500000f, 0.809017f}, + {-0.162460f, 0.262866f, 0.951056f}, + {0.000000f, 0.000000f, 1.000000f}, + {0.000000f, 0.850651f, 0.525731f}, + {-0.147621f, 0.716567f, 0.681718f}, + {0.147621f, 0.716567f, 0.681718f}, + {0.000000f, 0.525731f, 0.850651f}, + {0.309017f, 0.500000f, 0.809017f}, + {0.525731f, 0.000000f, 0.850651f}, + {0.295242f, 0.000000f, 0.955423f}, + {0.442863f, 0.238856f, 0.864188f}, + {0.162460f, 0.262866f, 0.951056f}, + {-0.681718f, 0.147621f, 0.716567f}, + {-0.809017f, 0.309017f, 0.500000f}, + {-0.587785f, 0.425325f, 0.688191f}, + {-0.850651f, 0.525731f, 0.000000f}, + {-0.864188f, 0.442863f, 0.238856f}, + {-0.716567f, 0.681718f, 0.147621f}, + {-0.688191f, 0.587785f, 0.425325f}, + {-0.500000f, 0.809017f, 0.309017f}, + {-0.238856f, 0.864188f, 0.442863f}, + {-0.425325f, 0.688191f, 0.587785f}, + {-0.716567f, 0.681718f, -0.147621f}, + {-0.500000f, 0.809017f, -0.309017f}, + {-0.525731f, 0.850651f, 0.000000f}, + {0.000000f, 0.850651f, -0.525731f}, + {-0.238856f, 0.864188f, -0.442863f}, + {0.000000f, 0.955423f, -0.295242f}, + {-0.262866f, 0.951056f, -0.162460f}, + {0.000000f, 1.000000f, 0.000000f}, + {0.000000f, 0.955423f, 0.295242f}, + {-0.262866f, 0.951056f, 0.162460f}, + {0.238856f, 0.864188f, 0.442863f}, + {0.262866f, 0.951056f, 0.162460f}, + {0.500000f, 0.809017f, 0.309017f}, + {0.238856f, 0.864188f, -0.442863f}, + {0.262866f, 0.951056f, -0.162460f}, + {0.500000f, 0.809017f, -0.309017f}, + {0.850651f, 0.525731f, 0.000000f}, + {0.716567f, 0.681718f, 0.147621f}, + {0.716567f, 0.681718f, -0.147621f}, + {0.525731f, 0.850651f, 0.000000f}, + {0.425325f, 0.688191f, 0.587785f}, + {0.864188f, 0.442863f, 0.238856f}, + {0.688191f, 0.587785f, 0.425325f}, + {0.809017f, 0.309017f, 0.500000f}, + {0.681718f, 0.147621f, 0.716567f}, + {0.587785f, 0.425325f, 0.688191f}, + {0.955423f, 0.295242f, 0.000000f}, + {1.000000f, 0.000000f, 0.000000f}, + {0.951056f, 0.162460f, 0.262866f}, + {0.850651f, -0.525731f, 0.000000f}, + {0.955423f, -0.295242f, 0.000000f}, + {0.864188f, -0.442863f, 0.238856f}, + {0.951056f, -0.162460f, 0.262866f}, + {0.809017f, -0.309017f, 0.500000f}, + {0.681718f, -0.147621f, 0.716567f}, + {0.850651f, 0.000000f, 0.525731f}, + {0.864188f, 0.442863f, -0.238856f}, + {0.809017f, 0.309017f, -0.500000f}, + {0.951056f, 0.162460f, -0.262866f}, + {0.525731f, 0.000000f, -0.850651f}, + {0.681718f, 0.147621f, -0.716567f}, + {0.681718f, -0.147621f, -0.716567f}, + {0.850651f, 0.000000f, -0.525731f}, + {0.809017f, -0.309017f, -0.500000f}, + {0.864188f, -0.442863f, -0.238856f}, + {0.951056f, -0.162460f, -0.262866f}, + {0.147621f, 0.716567f, -0.681718f}, + {0.309017f, 0.500000f, -0.809017f}, + {0.425325f, 0.688191f, -0.587785f}, + {0.442863f, 0.238856f, -0.864188f}, + {0.587785f, 0.425325f, -0.688191f}, + {0.688191f, 0.587785f, -0.425325f}, + {-0.147621f, 0.716567f, -0.681718f}, + {-0.309017f, 0.500000f, -0.809017f}, + {0.000000f, 0.525731f, -0.850651f}, + {-0.525731f, 0.000000f, -0.850651f}, + {-0.442863f, 0.238856f, -0.864188f}, + {-0.295242f, 0.000000f, -0.955423f}, + {-0.162460f, 0.262866f, -0.951056f}, + {0.000000f, 0.000000f, -1.000000f}, + {0.295242f, 0.000000f, -0.955423f}, + {0.162460f, 0.262866f, -0.951056f}, + {-0.442863f, -0.238856f, -0.864188f}, + {-0.309017f, -0.500000f, -0.809017f}, + {-0.162460f, -0.262866f, -0.951056f}, + {0.000000f, -0.850651f, -0.525731f}, + {-0.147621f, -0.716567f, -0.681718f}, + {0.147621f, -0.716567f, -0.681718f}, + {0.000000f, -0.525731f, -0.850651f}, + {0.309017f, -0.500000f, -0.809017f}, + {0.442863f, -0.238856f, -0.864188f}, + {0.162460f, -0.262866f, -0.951056f}, + {0.238856f, -0.864188f, -0.442863f}, + {0.500000f, -0.809017f, -0.309017f}, + {0.425325f, -0.688191f, -0.587785f}, + {0.716567f, -0.681718f, -0.147621f}, + {0.688191f, -0.587785f, -0.425325f}, + {0.587785f, -0.425325f, -0.688191f}, + {0.000000f, -0.955423f, -0.295242f}, + {0.000000f, -1.000000f, 0.000000f}, + {0.262866f, -0.951056f, -0.162460f}, + {0.000000f, -0.850651f, 0.525731f}, + {0.000000f, -0.955423f, 0.295242f}, + {0.238856f, -0.864188f, 0.442863f}, + {0.262866f, -0.951056f, 0.162460f}, + {0.500000f, -0.809017f, 0.309017f}, + {0.716567f, -0.681718f, 0.147621f}, + {0.525731f, -0.850651f, 0.000000f}, + {-0.238856f, -0.864188f, -0.442863f}, + {-0.500000f, -0.809017f, -0.309017f}, + {-0.262866f, -0.951056f, -0.162460f}, + {-0.850651f, -0.525731f, 0.000000f}, + {-0.716567f, -0.681718f, -0.147621f}, + {-0.716567f, -0.681718f, 0.147621f}, + {-0.525731f, -0.850651f, 0.000000f}, + {-0.500000f, -0.809017f, 0.309017f}, + {-0.238856f, -0.864188f, 0.442863f}, + {-0.262866f, -0.951056f, 0.162460f}, + {-0.864188f, -0.442863f, 0.238856f}, + {-0.809017f, -0.309017f, 0.500000f}, + {-0.688191f, -0.587785f, 0.425325f}, + {-0.681718f, -0.147621f, 0.716567f}, + {-0.442863f, -0.238856f, 0.864188f}, + {-0.587785f, -0.425325f, 0.688191f}, + {-0.309017f, -0.500000f, 0.809017f}, + {-0.147621f, -0.716567f, 0.681718f}, + {-0.425325f, -0.688191f, 0.587785f}, + {-0.162460f, -0.262866f, 0.951056f}, + {0.442863f, -0.238856f, 0.864188f}, + {0.162460f, -0.262866f, 0.951056f}, + {0.309017f, -0.500000f, 0.809017f}, + {0.147621f, -0.716567f, 0.681718f}, + {0.000000f, -0.525731f, 0.850651f}, + {0.425325f, -0.688191f, 0.587785f}, + {0.587785f, -0.425325f, 0.688191f}, + {0.688191f, -0.587785f, 0.425325f}, + {-0.955423f, 0.295242f, 0.000000f}, + {-0.951056f, 0.162460f, 0.262866f}, + {-1.000000f, 0.000000f, 0.000000f}, + {-0.850651f, 0.000000f, 0.525731f}, + {-0.955423f, -0.295242f, 0.000000f}, + {-0.951056f, -0.162460f, 0.262866f}, + {-0.864188f, 0.442863f, -0.238856f}, + {-0.951056f, 0.162460f, -0.262866f}, + {-0.809017f, 0.309017f, -0.500000f}, + {-0.864188f, -0.442863f, -0.238856f}, + {-0.951056f, -0.162460f, -0.262866f}, + {-0.809017f, -0.309017f, -0.500000f}, + {-0.681718f, 0.147621f, -0.716567f}, + {-0.681718f, -0.147621f, -0.716567f}, + {-0.850651f, 0.000000f, -0.525731f}, + {-0.688191f, 0.587785f, -0.425325f}, + {-0.587785f, 0.425325f, -0.688191f}, + {-0.425325f, 0.688191f, -0.587785f}, + {-0.425325f, -0.688191f, -0.587785f}, + {-0.587785f, -0.425325f, -0.688191f}, + {-0.688191f, -0.587785f, -0.425325f}, +}; + +#endif diff --git a/libs/picomodel/pm_lwo.c b/libs/picomodel/pm_lwo.c index ba83ceb5..d7b3bc8a 100644 --- a/libs/picomodel/pm_lwo.c +++ b/libs/picomodel/pm_lwo.c @@ -1,430 +1,430 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - -/* marker */ -#define PM_LWO_C - -/* dependencies */ -#include "picointernal.h" -#include "lwo/lwo2.h" - -/* uncomment when debugging this module */ -/*#define DEBUG_PM_LWO*/ - -#ifdef DEBUG_PM_LWO -#include "time.h" -#endif - -/* helper functions */ -static const char *lwo_lwIDToStr( unsigned int lwID ) -{ - static char lwIDStr[5]; - - if (!lwID) - { - return "n/a"; - } - - lwIDStr[ 0 ] = (char)((lwID) >> 24); - lwIDStr[ 1 ] = (char)((lwID) >> 16); - lwIDStr[ 2 ] = (char)((lwID) >> 8); - lwIDStr[ 3 ] = (char)((lwID)); - lwIDStr[ 4 ] = '\0'; - - return lwIDStr; -} - -/* -_lwo_canload() -validates a LightWave Object model file. btw, i use the -preceding underscore cause it's a static func referenced -by one structure only. -*/ -static int _lwo_canload( PM_PARAMS_CANLOAD ) -{ - picoMemStream_t *s; - unsigned int failID = 0; - int failpos = -1; - int ret; - - /* create a new pico memorystream */ - s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); - if (s == NULL) - { - return PICO_PMV_ERROR_MEMORY; - } - - ret = lwValidateObject( fileName, s, &failID, &failpos ); - - _pico_free_memstream( s ); - - return ret; -} - -/* -_lwo_load() -loads a LightWave Object model file. -*/ -static picoModel_t *_lwo_load( PM_PARAMS_LOAD ) -{ - picoMemStream_t *s; - unsigned int failID = 0; - int failpos = -1; - lwObject *obj; - lwSurface *surface; - lwLayer *layer; - lwPoint *pt; - lwPolygon *pol; - lwPolVert *v; - lwVMapPt *vm; - char name[ 64 ]; - int i, j, k, numverts; - - picoModel_t *picoModel; - picoSurface_t *picoSurface; - picoShader_t *picoShader; - picoVec3_t xyz, normal; - picoVec2_t st; - picoColor_t color; - - int defaultSTAxis[ 2 ]; - picoVec2_t defaultXYZtoSTScale; - - picoVertexCombinationHash_t **hashTable; - picoVertexCombinationHash_t *vertexCombinationHash; - -#ifdef DEBUG_PM_LWO - clock_t load_start, load_finish, convert_start, convert_finish; - double load_elapsed, convert_elapsed; - - load_start = clock(); -#endif - - /* do frame check */ - if( frameNum < 0 || frameNum >= 1 ) - { - _pico_printf( PICO_ERROR, "Invalid or out-of-range LWO frame specified" ); - return NULL; - } - - /* create a new pico memorystream */ - s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); - if (s == NULL) - { - return NULL; - } - - obj = lwGetObject( fileName, s, &failID, &failpos ); - - _pico_free_memstream( s ); - - if( !obj ) { - _pico_printf( PICO_ERROR, "Couldn't load LWO file, failed on ID '%s', position %d", lwo_lwIDToStr( failID ), failpos ); - return NULL; - } - -#ifdef DEBUG_PM_LWO - convert_start = load_finish = clock(); - load_elapsed = (double)(load_finish - load_start) / CLOCKS_PER_SEC; -#endif - - /* ------------------------------------------------- - pico model creation - ------------------------------------------------- */ - - /* create a new pico model */ - picoModel = PicoNewModel(); - if (picoModel == NULL) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); - return NULL; - } - - /* do model setup */ - PicoSetModelFrameNum( picoModel, frameNum ); - PicoSetModelNumFrames( picoModel, 1 ); - PicoSetModelName( picoModel, fileName ); - PicoSetModelFileName( picoModel, fileName ); - - /* create all polygons from layer[ 0 ] that belong to this surface */ - layer = &obj->layer[0]; - - /* warn the user that other layers are discarded */ - if (obj->nlayers > 1) - { - _pico_printf( PICO_WARNING, "LWO loader discards any geometry data not in Layer 1 (%d layers found)", obj->nlayers ); - } - - /* initialize dummy normal */ - normal[ 0 ] = normal[ 1 ] = normal[ 2 ] = 0.f; - - /* setup default st map */ - st[ 0 ] = st[ 1 ] = 0.f; /* st[0] holds max, st[1] holds max par one */ - defaultSTAxis[ 0 ] = 0; - defaultSTAxis[ 1 ] = 1; - for( i = 0; i < 3; i++ ) - { - float min = layer->bbox[ i ]; - float max = layer->bbox[ i + 3 ]; - float size = max - min; - - if (size > st[ 0 ]) - { - defaultSTAxis[ 1 ] = defaultSTAxis[ 0 ]; - defaultSTAxis[ 0 ] = i; - - st[ 1 ] = st[ 0 ]; - st[ 0 ] = size; - } - else if (size > st[ 1 ]) - { - defaultSTAxis[ 1 ] = i; - st[ 1 ] = size; - } - } - defaultXYZtoSTScale[ 0 ] = 4.f / st[ 0 ]; - defaultXYZtoSTScale[ 1 ] = 4.f / st[ 1 ]; - - /* LWO surfaces become pico surfaces */ - surface = obj->surf; - while (surface) - { - /* allocate new pico surface */ - picoSurface = PicoNewSurface( picoModel ); - if (picoSurface == NULL) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); - PicoFreeModel( picoModel ); - lwFreeObject( obj ); - return NULL; - } - - /* LWO model surfaces are all triangle meshes */ - PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); - - /* set surface name */ - PicoSetSurfaceName( picoSurface, surface->name ); - - /* create new pico shader */ - picoShader = PicoNewShader( picoModel ); - if (picoShader == NULL) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); - PicoFreeModel( picoModel ); - lwFreeObject( obj ); - return NULL; - } - - /* detox and set shader name */ - strncpy( name, surface->name, sizeof(name) ); - _pico_setfext( name, "" ); - _pico_unixify( name ); - PicoSetShaderName( picoShader, name ); - - /* associate current surface with newly created shader */ - PicoSetSurfaceShader( picoSurface, picoShader ); - - /* copy indices and vertex data */ - numverts = 0; - - hashTable = PicoNewVertexCombinationHashTable(); - - if (hashTable == NULL) - { - _pico_printf( PICO_ERROR, "Unable to allocate hash table" ); - PicoFreeModel( picoModel ); - lwFreeObject( obj ); - return NULL; - } - - for( i = 0, pol = layer->polygon.pol; i < layer->polygon.count; i++, pol++ ) - { - /* does this polygon belong to this surface? */ - if (pol->surf != surface) - continue; - - /* we only support polygons of the FACE type */ - if (pol->type != ID_FACE) - { - _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it's type != FACE (%s)", lwo_lwIDToStr( pol->type ) ); - continue; - } - - /* NOTE: LWO has support for non-convex polygons, do we want to store them as well? */ - if (pol->nverts != 3) - { - _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it has != 3 verts (%d)", pol->nverts ); - continue; - } - - for( j = 0, v = pol->v; j < 3; j++, v++ ) - { - pt = &layer->point.pt[ v->index ]; - - /* setup data */ - xyz[ 0 ] = pt->pos[ 0 ]; - xyz[ 1 ] = pt->pos[ 2 ]; - xyz[ 2 ] = pt->pos[ 1 ]; - - normal[ 0 ] = v->norm[ 0 ]; - normal[ 1 ] = v->norm[ 2 ]; - normal[ 2 ] = v->norm[ 1 ]; - - st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ]; - st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ]; - - color[ 0 ] = (picoByte_t)(surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); - color[ 1 ] = (picoByte_t)(surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); - color[ 2 ] = (picoByte_t)(surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); - color[ 3 ] = 0xFF; - - /* set from points */ - for( k = 0, vm = pt->vm; k < pt->nvmaps; k++, vm++ ) - { - if (vm->vmap->type == LWID_('T','X','U','V')) - { - /* set st coords */ - st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; - st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; - } - else if (vm->vmap->type == LWID_('R','G','B','A')) - { - /* set rgba */ - color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); - color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); - color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); - color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); - } - } - - /* override with polygon data */ - for( k = 0, vm = v->vm; k < v->nvmaps; k++, vm++ ) - { - if (vm->vmap->type == LWID_('T','X','U','V')) - { - /* set st coords */ - st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; - st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; - } - else if (vm->vmap->type == LWID_('R','G','B','A')) - { - /* set rgba */ - color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); - color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); - color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); - color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); - } - } - - /* find vertex in this surface and if we can't find it there create it */ - vertexCombinationHash = PicoFindVertexCombinationInHashTable( hashTable, xyz, normal, st, color ); - - if (vertexCombinationHash) - { - /* found an existing one */ - PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), vertexCombinationHash->index ); - } - else - { - /* it is a new one */ - vertexCombinationHash = PicoAddVertexCombinationToHashTable( hashTable, xyz, normal, st, color, (picoIndex_t) numverts ); - - if (vertexCombinationHash == NULL) - { - _pico_printf( PICO_ERROR, "Unable to allocate hash bucket entry table" ); - PicoFreeVertexCombinationHashTable( hashTable ); - PicoFreeModel( picoModel ); - lwFreeObject( obj ); - return NULL; - } - - /* add the vertex to this surface */ - PicoSetSurfaceXYZ( picoSurface, numverts, xyz ); - - /* set dummy normal */ - PicoSetSurfaceNormal( picoSurface, numverts, normal ); - - /* set color */ - PicoSetSurfaceColor( picoSurface, 0, numverts, color ); - - /* set st coords */ - PicoSetSurfaceST( picoSurface, 0, numverts, st ); - - /* set index */ - PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), (picoIndex_t) numverts ); - - numverts++; - } - } - } - - /* free the hashtable */ - PicoFreeVertexCombinationHashTable( hashTable ); - - /* get next surface */ - surface = surface->next; - } - -#ifdef DEBUG_PM_LWO - load_start = convert_finish = clock(); -#endif - - lwFreeObject( obj ); - -#ifdef DEBUG_PM_LWO - load_finish = clock(); - load_elapsed += (double)(load_finish - load_start) / CLOCKS_PER_SEC; - convert_elapsed = (double)(convert_finish - convert_start) / CLOCKS_PER_SEC; - _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s) (loading: %-.2fs converting: %-.2fs)\n", load_elapsed + convert_elapsed, load_elapsed, convert_elapsed ); -#endif - - /* return the new pico model */ - return picoModel; -} - -/* pico file format module definition */ -const picoModule_t picoModuleLWO = -{ - "1.0", /* module version string */ - "LightWave Object", /* module display name */ - "Arnout van Meer", /* author's name */ - "2003 Arnout van Meer, 2000 Ernie Wright", /* module copyright */ - { - "lwo", NULL, NULL, NULL /* default extensions to use */ - }, - _lwo_canload, /* validation routine */ - _lwo_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +/* marker */ +#define PM_LWO_C + +/* dependencies */ +#include "picointernal.h" +#include "lwo/lwo2.h" + +/* uncomment when debugging this module */ +/*#define DEBUG_PM_LWO*/ + +#ifdef DEBUG_PM_LWO +#include "time.h" +#endif + +/* helper functions */ +static const char *lwo_lwIDToStr( unsigned int lwID ) +{ + static char lwIDStr[5]; + + if (!lwID) + { + return "n/a"; + } + + lwIDStr[ 0 ] = (char)((lwID) >> 24); + lwIDStr[ 1 ] = (char)((lwID) >> 16); + lwIDStr[ 2 ] = (char)((lwID) >> 8); + lwIDStr[ 3 ] = (char)((lwID)); + lwIDStr[ 4 ] = '\0'; + + return lwIDStr; +} + +/* +_lwo_canload() +validates a LightWave Object model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ +static int _lwo_canload( PM_PARAMS_CANLOAD ) +{ + picoMemStream_t *s; + unsigned int failID = 0; + int failpos = -1; + int ret; + + /* create a new pico memorystream */ + s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); + if (s == NULL) + { + return PICO_PMV_ERROR_MEMORY; + } + + ret = lwValidateObject( fileName, s, &failID, &failpos ); + + _pico_free_memstream( s ); + + return ret; +} + +/* +_lwo_load() +loads a LightWave Object model file. +*/ +static picoModel_t *_lwo_load( PM_PARAMS_LOAD ) +{ + picoMemStream_t *s; + unsigned int failID = 0; + int failpos = -1; + lwObject *obj; + lwSurface *surface; + lwLayer *layer; + lwPoint *pt; + lwPolygon *pol; + lwPolVert *v; + lwVMapPt *vm; + char name[ 64 ]; + int i, j, k, numverts; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + int defaultSTAxis[ 2 ]; + picoVec2_t defaultXYZtoSTScale; + + picoVertexCombinationHash_t **hashTable; + picoVertexCombinationHash_t *vertexCombinationHash; + +#ifdef DEBUG_PM_LWO + clock_t load_start, load_finish, convert_start, convert_finish; + double load_elapsed, convert_elapsed; + + load_start = clock(); +#endif + + /* do frame check */ + if( frameNum < 0 || frameNum >= 1 ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range LWO frame specified" ); + return NULL; + } + + /* create a new pico memorystream */ + s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); + if (s == NULL) + { + return NULL; + } + + obj = lwGetObject( fileName, s, &failID, &failpos ); + + _pico_free_memstream( s ); + + if( !obj ) { + _pico_printf( PICO_ERROR, "Couldn't load LWO file, failed on ID '%s', position %d", lwo_lwIDToStr( failID ), failpos ); + return NULL; + } + +#ifdef DEBUG_PM_LWO + convert_start = load_finish = clock(); + load_elapsed = (double)(load_finish - load_start) / CLOCKS_PER_SEC; +#endif + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create a new pico model */ + picoModel = PicoNewModel(); + if (picoModel == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, 1 ); + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* create all polygons from layer[ 0 ] that belong to this surface */ + layer = &obj->layer[0]; + + /* warn the user that other layers are discarded */ + if (obj->nlayers > 1) + { + _pico_printf( PICO_WARNING, "LWO loader discards any geometry data not in Layer 1 (%d layers found)", obj->nlayers ); + } + + /* initialize dummy normal */ + normal[ 0 ] = normal[ 1 ] = normal[ 2 ] = 0.f; + + /* setup default st map */ + st[ 0 ] = st[ 1 ] = 0.f; /* st[0] holds max, st[1] holds max par one */ + defaultSTAxis[ 0 ] = 0; + defaultSTAxis[ 1 ] = 1; + for( i = 0; i < 3; i++ ) + { + float min = layer->bbox[ i ]; + float max = layer->bbox[ i + 3 ]; + float size = max - min; + + if (size > st[ 0 ]) + { + defaultSTAxis[ 1 ] = defaultSTAxis[ 0 ]; + defaultSTAxis[ 0 ] = i; + + st[ 1 ] = st[ 0 ]; + st[ 0 ] = size; + } + else if (size > st[ 1 ]) + { + defaultSTAxis[ 1 ] = i; + st[ 1 ] = size; + } + } + defaultXYZtoSTScale[ 0 ] = 4.f / st[ 0 ]; + defaultXYZtoSTScale[ 1 ] = 4.f / st[ 1 ]; + + /* LWO surfaces become pico surfaces */ + surface = obj->surf; + while (surface) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if (picoSurface == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* LWO model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader */ + picoShader = PicoNewShader( picoModel ); + if (picoShader == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* detox and set shader name */ + strncpy( name, surface->name, sizeof(name) ); + _pico_setfext( name, "" ); + _pico_unixify( name ); + PicoSetShaderName( picoShader, name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indices and vertex data */ + numverts = 0; + + hashTable = PicoNewVertexCombinationHashTable(); + + if (hashTable == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate hash table" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + for( i = 0, pol = layer->polygon.pol; i < layer->polygon.count; i++, pol++ ) + { + /* does this polygon belong to this surface? */ + if (pol->surf != surface) + continue; + + /* we only support polygons of the FACE type */ + if (pol->type != ID_FACE) + { + _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it's type != FACE (%s)", lwo_lwIDToStr( pol->type ) ); + continue; + } + + /* NOTE: LWO has support for non-convex polygons, do we want to store them as well? */ + if (pol->nverts != 3) + { + _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it has != 3 verts (%d)", pol->nverts ); + continue; + } + + for( j = 0, v = pol->v; j < 3; j++, v++ ) + { + pt = &layer->point.pt[ v->index ]; + + /* setup data */ + xyz[ 0 ] = pt->pos[ 0 ]; + xyz[ 1 ] = pt->pos[ 2 ]; + xyz[ 2 ] = pt->pos[ 1 ]; + + normal[ 0 ] = v->norm[ 0 ]; + normal[ 1 ] = v->norm[ 2 ]; + normal[ 2 ] = v->norm[ 1 ]; + + st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ]; + st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ]; + + color[ 0 ] = (picoByte_t)(surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = 0xFF; + + /* set from points */ + for( k = 0, vm = pt->vm; k < pt->nvmaps; k++, vm++ ) + { + if (vm->vmap->type == LWID_('T','X','U','V')) + { + /* set st coords */ + st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; + st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; + } + else if (vm->vmap->type == LWID_('R','G','B','A')) + { + /* set rgba */ + color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); + } + } + + /* override with polygon data */ + for( k = 0, vm = v->vm; k < v->nvmaps; k++, vm++ ) + { + if (vm->vmap->type == LWID_('T','X','U','V')) + { + /* set st coords */ + st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; + st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; + } + else if (vm->vmap->type == LWID_('R','G','B','A')) + { + /* set rgba */ + color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); + } + } + + /* find vertex in this surface and if we can't find it there create it */ + vertexCombinationHash = PicoFindVertexCombinationInHashTable( hashTable, xyz, normal, st, color ); + + if (vertexCombinationHash) + { + /* found an existing one */ + PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), vertexCombinationHash->index ); + } + else + { + /* it is a new one */ + vertexCombinationHash = PicoAddVertexCombinationToHashTable( hashTable, xyz, normal, st, color, (picoIndex_t) numverts ); + + if (vertexCombinationHash == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate hash bucket entry table" ); + PicoFreeVertexCombinationHashTable( hashTable ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* add the vertex to this surface */ + PicoSetSurfaceXYZ( picoSurface, numverts, xyz ); + + /* set dummy normal */ + PicoSetSurfaceNormal( picoSurface, numverts, normal ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, numverts, color ); + + /* set st coords */ + PicoSetSurfaceST( picoSurface, 0, numverts, st ); + + /* set index */ + PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), (picoIndex_t) numverts ); + + numverts++; + } + } + } + + /* free the hashtable */ + PicoFreeVertexCombinationHashTable( hashTable ); + + /* get next surface */ + surface = surface->next; + } + +#ifdef DEBUG_PM_LWO + load_start = convert_finish = clock(); +#endif + + lwFreeObject( obj ); + +#ifdef DEBUG_PM_LWO + load_finish = clock(); + load_elapsed += (double)(load_finish - load_start) / CLOCKS_PER_SEC; + convert_elapsed = (double)(convert_finish - convert_start) / CLOCKS_PER_SEC; + _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s) (loading: %-.2fs converting: %-.2fs)\n", load_elapsed + convert_elapsed, load_elapsed, convert_elapsed ); +#endif + + /* return the new pico model */ + return picoModel; +} + +/* pico file format module definition */ +const picoModule_t picoModuleLWO = +{ + "1.0", /* module version string */ + "LightWave Object", /* module display name */ + "Arnout van Meer", /* author's name */ + "2003 Arnout van Meer, 2000 Ernie Wright", /* module copyright */ + { + "lwo", NULL, NULL, NULL /* default extensions to use */ + }, + _lwo_canload, /* validation routine */ + _lwo_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_md2.c b/libs/picomodel/pm_md2.c index 2351ea58..8a603a5d 100644 --- a/libs/picomodel/pm_md2.c +++ b/libs/picomodel/pm_md2.c @@ -1,670 +1,670 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - -/* -Nurail: Used pm_md3.c (Randy Reddig) as a template. -*/ - - -/* marker */ -#define PM_MD2_C - -/* dependencies */ -#include "picointernal.h" - - -/* md2 model format */ -#define MD2_MAGIC "IDP2" -#define MD2_VERSION 8 - -#define MD2_NUMVERTEXNORMALS 162 -#define MD2_MAX_SKINNAME 64 -#define MD2_MAX_TRIANGLES 4096 -#define MD2_MAX_VERTS 2048 -#define MD2_MAX_FRAMES 512 -#define MD2_MAX_MD2SKINS 32 -#define MD2_MAX_SKINNAME 64 - -#ifndef byte - #define byte unsigned char -#endif - -typedef struct index_LUT_s -{ - short Vert; - short ST; - struct index_LUT_s *next; - -} index_LUT_t; - -typedef struct index_DUP_LUT_s -{ - short ST; - short OldVert; - -} index_DUP_LUT_t; - -typedef struct -{ - short s; - short t; -} md2St_t; - -typedef struct -{ - short index_xyz[3]; - short index_st[3]; -} md2Triangle_t; - -typedef struct -{ - byte v[3]; // scaled byte to fit in frame mins/maxs - byte lightnormalindex; -} md2XyzNormal_t; - -typedef struct md2Frame_s -{ - float scale[3]; // multiply byte verts by this - float translate[3]; // then add this - char name[16]; // frame name from grabbing - md2XyzNormal_t verts[1]; // variable sized -} -md2Frame_t; - - -/* md2 model file md2 structure */ -typedef struct md2_s -{ - char magic[ 4 ]; - int version; - - int skinWidth; - int skinHeight; - int frameSize; - - int numSkins; - int numXYZ; - int numST; - int numTris; - int numGLCmds; - int numFrames; - - int ofsSkins; - int ofsST; - int ofsTris; - int ofsFrames; - int ofsGLCmds; - int ofsEnd; -} -md2_t; - -float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] = -{ - { -0.525731f, 0.000000f, 0.850651f }, - { -0.442863f, 0.238856f, 0.864188f }, - { -0.295242f, 0.000000f, 0.955423f }, - { -0.309017f, 0.500000f, 0.809017f }, - { -0.162460f, 0.262866f, 0.951056f }, - { 0.000000f, 0.000000f, 1.000000f }, - { 0.000000f, 0.850651f, 0.525731f }, - { -0.147621f, 0.716567f, 0.681718f }, - { 0.147621f, 0.716567f, 0.681718f }, - { 0.000000f, 0.525731f, 0.850651f }, - { 0.309017f, 0.500000f, 0.809017f }, - { 0.525731f, 0.000000f, 0.850651f }, - { 0.295242f, 0.000000f, 0.955423f }, - { 0.442863f, 0.238856f, 0.864188f }, - { 0.162460f, 0.262866f, 0.951056f }, - { -0.681718f, 0.147621f, 0.716567f }, - { -0.809017f, 0.309017f, 0.500000f }, - { -0.587785f, 0.425325f, 0.688191f }, - { -0.850651f, 0.525731f, 0.000000f }, - { -0.864188f, 0.442863f, 0.238856f }, - { -0.716567f, 0.681718f, 0.147621f }, - { -0.688191f, 0.587785f, 0.425325f }, - { -0.500000f, 0.809017f, 0.309017f }, - { -0.238856f, 0.864188f, 0.442863f }, - { -0.425325f, 0.688191f, 0.587785f }, - { -0.716567f, 0.681718f, -0.147621f }, - { -0.500000f, 0.809017f, -0.309017f }, - { -0.525731f, 0.850651f, 0.000000f }, - { 0.000000f, 0.850651f, -0.525731f }, - { -0.238856f, 0.864188f, -0.442863f }, - { 0.000000f, 0.955423f, -0.295242f }, - { -0.262866f, 0.951056f, -0.162460f }, - { 0.000000f, 1.000000f, 0.000000f }, - { 0.000000f, 0.955423f, 0.295242f }, - { -0.262866f, 0.951056f, 0.162460f }, - { 0.238856f, 0.864188f, 0.442863f }, - { 0.262866f, 0.951056f, 0.162460f }, - { 0.500000f, 0.809017f, 0.309017f }, - { 0.238856f, 0.864188f, -0.442863f }, - { 0.262866f, 0.951056f, -0.162460f }, - { 0.500000f, 0.809017f, -0.309017f }, - { 0.850651f, 0.525731f, 0.000000f }, - { 0.716567f, 0.681718f, 0.147621f }, - { 0.716567f, 0.681718f, -0.147621f }, - { 0.525731f, 0.850651f, 0.000000f }, - { 0.425325f, 0.688191f, 0.587785f }, - { 0.864188f, 0.442863f, 0.238856f }, - { 0.688191f, 0.587785f, 0.425325f }, - { 0.809017f, 0.309017f, 0.500000f }, - { 0.681718f, 0.147621f, 0.716567f }, - { 0.587785f, 0.425325f, 0.688191f }, - { 0.955423f, 0.295242f, 0.000000f }, - { 1.000000f, 0.000000f, 0.000000f }, - { 0.951056f, 0.162460f, 0.262866f }, - { 0.850651f, -0.525731f, 0.000000f }, - { 0.955423f, -0.295242f, 0.000000f }, - { 0.864188f, -0.442863f, 0.238856f }, - { 0.951056f, -0.162460f, 0.262866f }, - { 0.809017f, -0.309017f, 0.500000f }, - { 0.681718f, -0.147621f, 0.716567f }, - { 0.850651f, 0.000000f, 0.525731f }, - { 0.864188f, 0.442863f, -0.238856f }, - { 0.809017f, 0.309017f, -0.500000f }, - { 0.951056f, 0.162460f, -0.262866f }, - { 0.525731f, 0.000000f, -0.850651f }, - { 0.681718f, 0.147621f, -0.716567f }, - { 0.681718f, -0.147621f, -0.716567f }, - { 0.850651f, 0.000000f, -0.525731f }, - { 0.809017f, -0.309017f, -0.500000f }, - { 0.864188f, -0.442863f, -0.238856f }, - { 0.951056f, -0.162460f, -0.262866f }, - { 0.147621f, 0.716567f, -0.681718f }, - { 0.309017f, 0.500000f, -0.809017f }, - { 0.425325f, 0.688191f, -0.587785f }, - { 0.442863f, 0.238856f, -0.864188f }, - { 0.587785f, 0.425325f, -0.688191f }, - { 0.688191f, 0.587785f, -0.425325f }, - { -0.147621f, 0.716567f, -0.681718f }, - { -0.309017f, 0.500000f, -0.809017f }, - { 0.000000f, 0.525731f, -0.850651f }, - { -0.525731f, 0.000000f, -0.850651f }, - { -0.442863f, 0.238856f, -0.864188f }, - { -0.295242f, 0.000000f, -0.955423f }, - { -0.162460f, 0.262866f, -0.951056f }, - { 0.000000f, 0.000000f, -1.000000f }, - { 0.295242f, 0.000000f, -0.955423f }, - { 0.162460f, 0.262866f, -0.951056f }, - { -0.442863f, -0.238856f, -0.864188f }, - { -0.309017f, -0.500000f, -0.809017f }, - { -0.162460f, -0.262866f, -0.951056f }, - { 0.000000f, -0.850651f, -0.525731f }, - { -0.147621f, -0.716567f, -0.681718f }, - { 0.147621f, -0.716567f, -0.681718f }, - { 0.000000f, -0.525731f, -0.850651f }, - { 0.309017f, -0.500000f, -0.809017f }, - { 0.442863f, -0.238856f, -0.864188f }, - { 0.162460f, -0.262866f, -0.951056f }, - { 0.238856f, -0.864188f, -0.442863f }, - { 0.500000f, -0.809017f, -0.309017f }, - { 0.425325f, -0.688191f, -0.587785f }, - { 0.716567f, -0.681718f, -0.147621f }, - { 0.688191f, -0.587785f, -0.425325f }, - { 0.587785f, -0.425325f, -0.688191f }, - { 0.000000f, -0.955423f, -0.295242f }, - { 0.000000f, -1.000000f, 0.000000f }, - { 0.262866f, -0.951056f, -0.162460f }, - { 0.000000f, -0.850651f, 0.525731f }, - { 0.000000f, -0.955423f, 0.295242f }, - { 0.238856f, -0.864188f, 0.442863f }, - { 0.262866f, -0.951056f, 0.162460f }, - { 0.500000f, -0.809017f, 0.309017f }, - { 0.716567f, -0.681718f, 0.147621f }, - { 0.525731f, -0.850651f, 0.000000f }, - { -0.238856f, -0.864188f, -0.442863f }, - { -0.500000f, -0.809017f, -0.309017f }, - { -0.262866f, -0.951056f, -0.162460f }, - { -0.850651f, -0.525731f, 0.000000f }, - { -0.716567f, -0.681718f, -0.147621f }, - { -0.716567f, -0.681718f, 0.147621f }, - { -0.525731f, -0.850651f, 0.000000f }, - { -0.500000f, -0.809017f, 0.309017f }, - { -0.238856f, -0.864188f, 0.442863f }, - { -0.262866f, -0.951056f, 0.162460f }, - { -0.864188f, -0.442863f, 0.238856f }, - { -0.809017f, -0.309017f, 0.500000f }, - { -0.688191f, -0.587785f, 0.425325f }, - { -0.681718f, -0.147621f, 0.716567f }, - { -0.442863f, -0.238856f, 0.864188f }, - { -0.587785f, -0.425325f, 0.688191f }, - { -0.309017f, -0.500000f, 0.809017f }, - { -0.147621f, -0.716567f, 0.681718f }, - { -0.425325f, -0.688191f, 0.587785f }, - { -0.162460f, -0.262866f, 0.951056f }, - { 0.442863f, -0.238856f, 0.864188f }, - { 0.162460f, -0.262866f, 0.951056f }, - { 0.309017f, -0.500000f, 0.809017f }, - { 0.147621f, -0.716567f, 0.681718f }, - { 0.000000f, -0.525731f, 0.850651f }, - { 0.425325f, -0.688191f, 0.587785f }, - { 0.587785f, -0.425325f, 0.688191f }, - { 0.688191f, -0.587785f, 0.425325f }, - { -0.955423f, 0.295242f, 0.000000f }, - { -0.951056f, 0.162460f, 0.262866f }, - { -1.000000f, 0.000000f, 0.000000f }, - { -0.850651f, 0.000000f, 0.525731f }, - { -0.955423f, -0.295242f, 0.000000f }, - { -0.951056f, -0.162460f, 0.262866f }, - { -0.864188f, 0.442863f, -0.238856f }, - { -0.951056f, 0.162460f, -0.262866f }, - { -0.809017f, 0.309017f, -0.500000f }, - { -0.864188f, -0.442863f, -0.238856f }, - { -0.951056f, -0.162460f, -0.262866f }, - { -0.809017f, -0.309017f, -0.500000f }, - { -0.681718f, 0.147621f, -0.716567f }, - { -0.681718f, -0.147621f, -0.716567f }, - { -0.850651f, 0.000000f, -0.525731f }, - { -0.688191f, 0.587785f, -0.425325f }, - { -0.587785f, 0.425325f, -0.688191f }, - { -0.425325f, 0.688191f, -0.587785f }, - { -0.425325f, -0.688191f, -0.587785f }, - { -0.587785f, -0.425325f, -0.688191f }, - { -0.688191f, -0.587785f, -0.425325f }, -}; - - -// _md2_canload() - -static int _md2_canload( PM_PARAMS_CANLOAD ) -{ - md2_t *md2; - - /* to keep the compiler happy */ - *fileName = *fileName; - - /* sanity check */ - if( bufSize < ( sizeof( *md2 ) * 2) ) - return PICO_PMV_ERROR_SIZE; - - /* set as md2 */ - md2 = (md2_t*) buffer; - - /* check md2 magic */ - if( *((int*) md2->magic) != *((int*) MD2_MAGIC) ) - return PICO_PMV_ERROR_IDENT; - - /* check md2 version */ - if( _pico_little_long( md2->version ) != MD2_VERSION ) - return PICO_PMV_ERROR_VERSION; - - /* file seems to be a valid md2 */ - return PICO_PMV_OK; -} - - - -// _md2_load() loads a quake2 md2 model file. - - -static picoModel_t *_md2_load( PM_PARAMS_LOAD ) -{ - int i, j, dups, dup_index; - short tot_numVerts; - index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; - index_DUP_LUT_t *p_index_LUT_DUPS; - md2Triangle_t *p_md2Triangle; - - char skinname[ MD2_MAX_SKINNAME ]; - md2_t *md2; - md2St_t *texCoord; - md2Frame_t *frame; - md2Triangle_t *triangle; - md2XyzNormal_t *vertex; - - picoByte_t *bb; - picoModel_t *picoModel; - picoSurface_t *picoSurface; - picoShader_t *picoShader; - picoVec3_t xyz, normal; - picoVec2_t st; - picoColor_t color; - - - // md2 loading - _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); - - /* set as md2 */ - bb = (picoByte_t*) buffer; - md2 = (md2_t*) buffer; - - /* check ident and version */ - if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION ) - { - /* not an md2 file (todo: set error) */ - _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName ); - return NULL; - } - - // swap md2 - md2->version = _pico_little_long( md2->version ); - - md2->skinWidth = _pico_little_long( md2->skinWidth ); - md2->skinHeight = _pico_little_long( md2->skinHeight ); - md2->frameSize = _pico_little_long( md2->frameSize ); - - md2->numSkins = _pico_little_long( md2->numSkins ); - md2->numXYZ = _pico_little_long( md2->numXYZ ); - md2->numST = _pico_little_long( md2->numST ); - md2->numTris = _pico_little_long( md2->numTris ); - md2->numGLCmds = _pico_little_long( md2->numGLCmds ); - md2->numFrames = _pico_little_long( md2->numFrames ); - - md2->ofsSkins = _pico_little_long( md2->ofsSkins ); - md2->ofsST = _pico_little_long( md2->ofsST ); - md2->ofsTris = _pico_little_long( md2->ofsTris ); - md2->ofsFrames = _pico_little_long( md2->ofsFrames ); - md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds ); - md2->ofsEnd = _pico_little_long( md2->ofsEnd ); - - // do frame check - if( md2->numFrames < 1 ) - { - _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); - return NULL; - } - - if( frameNum < 0 || frameNum >= md2->numFrames ) - { - _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" ); - return NULL; - } - - // Setup Frame - frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum)); - - // swap frame scale and translation - for( i = 0; i < 3; i++ ) - { - frame->scale[ i ] = _pico_little_float( frame->scale[ i ] ); - frame->translate[ i ] = _pico_little_float( frame->translate[ i ] ); - } - - // swap triangles - triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); - for( i = 0; i < md2->numTris; i++, triangle++ ) - { - for( j = 0; j < 3; j++ ) - { - triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); - triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); - } - } - - // swap st coords - texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); - for( i = 0; i < md2->numST; i++, texCoord++ ) - { - texCoord->s = _pico_little_short( texCoord->s ); - texCoord->t = _pico_little_short( texCoord->t ); - } - - // set Skin Name - strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME ); - - // Print out md2 values - _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname ); - - // detox Skin name - _pico_setfext( skinname, "" ); - _pico_unixify( skinname ); - - /* create new pico model */ - picoModel = PicoNewModel(); - if( picoModel == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); - return NULL; - } - - /* do model setup */ - PicoSetModelFrameNum( picoModel, frameNum ); - PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */ - PicoSetModelName( picoModel, fileName ); - PicoSetModelFileName( picoModel, fileName ); - - // allocate new pico surface - picoSurface = PicoNewSurface( picoModel ); - if( picoSurface == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); - PicoFreeModel( picoModel ); - return NULL; - } - - - PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); - PicoSetSurfaceName( picoSurface, frame->name ); - picoShader = PicoNewShader( picoModel ); - if( picoShader == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); - PicoFreeModel( picoModel ); - return NULL; - } - - PicoSetShaderName( picoShader, skinname ); - - // associate current surface with newly created shader - PicoSetSurfaceShader( picoSurface, picoShader ); - - // Init LUT for Verts - p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ); - for(i=0; inumXYZ; i++) - { - p_index_LUT[i].Vert = -1; - p_index_LUT[i].ST = -1; - p_index_LUT[i].next = NULL; - } - - // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. - tot_numVerts = md2->numXYZ; - dups = 0; - for(i=0; inumTris; i++) - { - p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i)); - for(j=0; j<3; j++) - { - if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry - p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j]; - - else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry - continue; - - else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry - { // Add first entry of LL from Main - p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); - if (p_index_LUT2 == NULL) - _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); - p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; - p_index_LUT2->Vert = dups; - p_index_LUT2->ST = p_md2Triangle->index_st[j]; - p_index_LUT2->next = NULL; - p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk - dups++; - } - else // Try to find in LL from Main Entry - { - p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next; - while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL - { - p_index_LUT3 = p_index_LUT2; - p_index_LUT2 = p_index_LUT2->next; - } - p_index_LUT2 = p_index_LUT3; - - if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it - { - p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk - continue; - } - - if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. - { - // Add the Entry - p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); - if (p_index_LUT3 == NULL) - _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); - p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; - p_index_LUT3->Vert = p_md2Triangle->index_xyz[j]; - p_index_LUT3->ST = p_md2Triangle->index_st[j]; - p_index_LUT3->next = NULL; - p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk - dups++; - } - } - } - } - - // malloc and build array for Dup STs - p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); - if (p_index_LUT_DUPS == NULL) - _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); - - dup_index = 0; - for(i=0; inumXYZ; i++) - { - p_index_LUT2 = p_index_LUT[i].next; - while (p_index_LUT2 != NULL) - { - p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; - p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; - dup_index++; - p_index_LUT2 = p_index_LUT2->next; - } - } - - // Build Picomodel - triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); - texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); - vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) ); - for( j = 0; j < md2->numTris; j++, triangle++ ) - { - PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); - PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); - PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); - } - - for(i=0; i< md2->numXYZ; i++, vertex++) - { - /* set vertex origin */ - xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0]; - xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1]; - xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2]; - PicoSetSurfaceXYZ( picoSurface, i , xyz ); - - /* set normal */ - normal[ 0 ] = md2_normals[vertex->lightnormalindex][0]; - normal[ 1 ] = md2_normals[vertex->lightnormalindex][1]; - normal[ 2 ] = md2_normals[vertex->lightnormalindex][2]; - PicoSetSurfaceNormal( picoSurface, i , normal ); - - /* set st coords */ - st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth)); - st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight)); - PicoSetSurfaceST( picoSurface, 0, i , st ); - } - - if (dups) - { - for(i=0; iverts[j].v[0] * frame->scale[0] + frame->translate[0]; - xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1]; - xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2]; - PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz ); - - /* set normal */ - normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0]; - normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1]; - normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2]; - PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal ); - - /* set st coords */ - st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth)); - st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight)); - PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st ); - } - } - - /* set color */ - PicoSetSurfaceColor( picoSurface, 0, 0, color ); - - // Free up malloc'ed LL entries - for(i=0; inumXYZ; i++) - { - if(p_index_LUT[i].next != NULL) - { - p_index_LUT2 = p_index_LUT[i].next; - do { - p_index_LUT3 = p_index_LUT2->next; - _pico_free(p_index_LUT2); - p_index_LUT2 = p_index_LUT3; - dups--; - } while (p_index_LUT2 != NULL); - } - } - - if (dups) - _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); - - // Free malloc'ed LUTs - _pico_free(p_index_LUT); - _pico_free(p_index_LUT_DUPS); - - /* return the new pico model */ - return picoModel; - -} - - - -/* pico file format module definition */ -const picoModule_t picoModuleMD2 = -{ - "0.875", /* module version string */ - "Quake 2 MD2", /* module display name */ - "Nurail", /* author's name */ - "2003 Nurail", /* module copyright */ - { - "md2", NULL, NULL, NULL /* default extensions to use */ - }, - _md2_canload, /* validation routine */ - _md2_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + +/* +Nurail: Used pm_md3.c (Randy Reddig) as a template. +*/ + + +/* marker */ +#define PM_MD2_C + +/* dependencies */ +#include "picointernal.h" + + +/* md2 model format */ +#define MD2_MAGIC "IDP2" +#define MD2_VERSION 8 + +#define MD2_NUMVERTEXNORMALS 162 +#define MD2_MAX_SKINNAME 64 +#define MD2_MAX_TRIANGLES 4096 +#define MD2_MAX_VERTS 2048 +#define MD2_MAX_FRAMES 512 +#define MD2_MAX_MD2SKINS 32 +#define MD2_MAX_SKINNAME 64 + +#ifndef byte + #define byte unsigned char +#endif + +typedef struct index_LUT_s +{ + short Vert; + short ST; + struct index_LUT_s *next; + +} index_LUT_t; + +typedef struct index_DUP_LUT_s +{ + short ST; + short OldVert; + +} index_DUP_LUT_t; + +typedef struct +{ + short s; + short t; +} md2St_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} md2Triangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} md2XyzNormal_t; + +typedef struct md2Frame_s +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + md2XyzNormal_t verts[1]; // variable sized +} +md2Frame_t; + + +/* md2 model file md2 structure */ +typedef struct md2_s +{ + char magic[ 4 ]; + int version; + + int skinWidth; + int skinHeight; + int frameSize; + + int numSkins; + int numXYZ; + int numST; + int numTris; + int numGLCmds; + int numFrames; + + int ofsSkins; + int ofsST; + int ofsTris; + int ofsFrames; + int ofsGLCmds; + int ofsEnd; +} +md2_t; + +float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] = +{ + { -0.525731f, 0.000000f, 0.850651f }, + { -0.442863f, 0.238856f, 0.864188f }, + { -0.295242f, 0.000000f, 0.955423f }, + { -0.309017f, 0.500000f, 0.809017f }, + { -0.162460f, 0.262866f, 0.951056f }, + { 0.000000f, 0.000000f, 1.000000f }, + { 0.000000f, 0.850651f, 0.525731f }, + { -0.147621f, 0.716567f, 0.681718f }, + { 0.147621f, 0.716567f, 0.681718f }, + { 0.000000f, 0.525731f, 0.850651f }, + { 0.309017f, 0.500000f, 0.809017f }, + { 0.525731f, 0.000000f, 0.850651f }, + { 0.295242f, 0.000000f, 0.955423f }, + { 0.442863f, 0.238856f, 0.864188f }, + { 0.162460f, 0.262866f, 0.951056f }, + { -0.681718f, 0.147621f, 0.716567f }, + { -0.809017f, 0.309017f, 0.500000f }, + { -0.587785f, 0.425325f, 0.688191f }, + { -0.850651f, 0.525731f, 0.000000f }, + { -0.864188f, 0.442863f, 0.238856f }, + { -0.716567f, 0.681718f, 0.147621f }, + { -0.688191f, 0.587785f, 0.425325f }, + { -0.500000f, 0.809017f, 0.309017f }, + { -0.238856f, 0.864188f, 0.442863f }, + { -0.425325f, 0.688191f, 0.587785f }, + { -0.716567f, 0.681718f, -0.147621f }, + { -0.500000f, 0.809017f, -0.309017f }, + { -0.525731f, 0.850651f, 0.000000f }, + { 0.000000f, 0.850651f, -0.525731f }, + { -0.238856f, 0.864188f, -0.442863f }, + { 0.000000f, 0.955423f, -0.295242f }, + { -0.262866f, 0.951056f, -0.162460f }, + { 0.000000f, 1.000000f, 0.000000f }, + { 0.000000f, 0.955423f, 0.295242f }, + { -0.262866f, 0.951056f, 0.162460f }, + { 0.238856f, 0.864188f, 0.442863f }, + { 0.262866f, 0.951056f, 0.162460f }, + { 0.500000f, 0.809017f, 0.309017f }, + { 0.238856f, 0.864188f, -0.442863f }, + { 0.262866f, 0.951056f, -0.162460f }, + { 0.500000f, 0.809017f, -0.309017f }, + { 0.850651f, 0.525731f, 0.000000f }, + { 0.716567f, 0.681718f, 0.147621f }, + { 0.716567f, 0.681718f, -0.147621f }, + { 0.525731f, 0.850651f, 0.000000f }, + { 0.425325f, 0.688191f, 0.587785f }, + { 0.864188f, 0.442863f, 0.238856f }, + { 0.688191f, 0.587785f, 0.425325f }, + { 0.809017f, 0.309017f, 0.500000f }, + { 0.681718f, 0.147621f, 0.716567f }, + { 0.587785f, 0.425325f, 0.688191f }, + { 0.955423f, 0.295242f, 0.000000f }, + { 1.000000f, 0.000000f, 0.000000f }, + { 0.951056f, 0.162460f, 0.262866f }, + { 0.850651f, -0.525731f, 0.000000f }, + { 0.955423f, -0.295242f, 0.000000f }, + { 0.864188f, -0.442863f, 0.238856f }, + { 0.951056f, -0.162460f, 0.262866f }, + { 0.809017f, -0.309017f, 0.500000f }, + { 0.681718f, -0.147621f, 0.716567f }, + { 0.850651f, 0.000000f, 0.525731f }, + { 0.864188f, 0.442863f, -0.238856f }, + { 0.809017f, 0.309017f, -0.500000f }, + { 0.951056f, 0.162460f, -0.262866f }, + { 0.525731f, 0.000000f, -0.850651f }, + { 0.681718f, 0.147621f, -0.716567f }, + { 0.681718f, -0.147621f, -0.716567f }, + { 0.850651f, 0.000000f, -0.525731f }, + { 0.809017f, -0.309017f, -0.500000f }, + { 0.864188f, -0.442863f, -0.238856f }, + { 0.951056f, -0.162460f, -0.262866f }, + { 0.147621f, 0.716567f, -0.681718f }, + { 0.309017f, 0.500000f, -0.809017f }, + { 0.425325f, 0.688191f, -0.587785f }, + { 0.442863f, 0.238856f, -0.864188f }, + { 0.587785f, 0.425325f, -0.688191f }, + { 0.688191f, 0.587785f, -0.425325f }, + { -0.147621f, 0.716567f, -0.681718f }, + { -0.309017f, 0.500000f, -0.809017f }, + { 0.000000f, 0.525731f, -0.850651f }, + { -0.525731f, 0.000000f, -0.850651f }, + { -0.442863f, 0.238856f, -0.864188f }, + { -0.295242f, 0.000000f, -0.955423f }, + { -0.162460f, 0.262866f, -0.951056f }, + { 0.000000f, 0.000000f, -1.000000f }, + { 0.295242f, 0.000000f, -0.955423f }, + { 0.162460f, 0.262866f, -0.951056f }, + { -0.442863f, -0.238856f, -0.864188f }, + { -0.309017f, -0.500000f, -0.809017f }, + { -0.162460f, -0.262866f, -0.951056f }, + { 0.000000f, -0.850651f, -0.525731f }, + { -0.147621f, -0.716567f, -0.681718f }, + { 0.147621f, -0.716567f, -0.681718f }, + { 0.000000f, -0.525731f, -0.850651f }, + { 0.309017f, -0.500000f, -0.809017f }, + { 0.442863f, -0.238856f, -0.864188f }, + { 0.162460f, -0.262866f, -0.951056f }, + { 0.238856f, -0.864188f, -0.442863f }, + { 0.500000f, -0.809017f, -0.309017f }, + { 0.425325f, -0.688191f, -0.587785f }, + { 0.716567f, -0.681718f, -0.147621f }, + { 0.688191f, -0.587785f, -0.425325f }, + { 0.587785f, -0.425325f, -0.688191f }, + { 0.000000f, -0.955423f, -0.295242f }, + { 0.000000f, -1.000000f, 0.000000f }, + { 0.262866f, -0.951056f, -0.162460f }, + { 0.000000f, -0.850651f, 0.525731f }, + { 0.000000f, -0.955423f, 0.295242f }, + { 0.238856f, -0.864188f, 0.442863f }, + { 0.262866f, -0.951056f, 0.162460f }, + { 0.500000f, -0.809017f, 0.309017f }, + { 0.716567f, -0.681718f, 0.147621f }, + { 0.525731f, -0.850651f, 0.000000f }, + { -0.238856f, -0.864188f, -0.442863f }, + { -0.500000f, -0.809017f, -0.309017f }, + { -0.262866f, -0.951056f, -0.162460f }, + { -0.850651f, -0.525731f, 0.000000f }, + { -0.716567f, -0.681718f, -0.147621f }, + { -0.716567f, -0.681718f, 0.147621f }, + { -0.525731f, -0.850651f, 0.000000f }, + { -0.500000f, -0.809017f, 0.309017f }, + { -0.238856f, -0.864188f, 0.442863f }, + { -0.262866f, -0.951056f, 0.162460f }, + { -0.864188f, -0.442863f, 0.238856f }, + { -0.809017f, -0.309017f, 0.500000f }, + { -0.688191f, -0.587785f, 0.425325f }, + { -0.681718f, -0.147621f, 0.716567f }, + { -0.442863f, -0.238856f, 0.864188f }, + { -0.587785f, -0.425325f, 0.688191f }, + { -0.309017f, -0.500000f, 0.809017f }, + { -0.147621f, -0.716567f, 0.681718f }, + { -0.425325f, -0.688191f, 0.587785f }, + { -0.162460f, -0.262866f, 0.951056f }, + { 0.442863f, -0.238856f, 0.864188f }, + { 0.162460f, -0.262866f, 0.951056f }, + { 0.309017f, -0.500000f, 0.809017f }, + { 0.147621f, -0.716567f, 0.681718f }, + { 0.000000f, -0.525731f, 0.850651f }, + { 0.425325f, -0.688191f, 0.587785f }, + { 0.587785f, -0.425325f, 0.688191f }, + { 0.688191f, -0.587785f, 0.425325f }, + { -0.955423f, 0.295242f, 0.000000f }, + { -0.951056f, 0.162460f, 0.262866f }, + { -1.000000f, 0.000000f, 0.000000f }, + { -0.850651f, 0.000000f, 0.525731f }, + { -0.955423f, -0.295242f, 0.000000f }, + { -0.951056f, -0.162460f, 0.262866f }, + { -0.864188f, 0.442863f, -0.238856f }, + { -0.951056f, 0.162460f, -0.262866f }, + { -0.809017f, 0.309017f, -0.500000f }, + { -0.864188f, -0.442863f, -0.238856f }, + { -0.951056f, -0.162460f, -0.262866f }, + { -0.809017f, -0.309017f, -0.500000f }, + { -0.681718f, 0.147621f, -0.716567f }, + { -0.681718f, -0.147621f, -0.716567f }, + { -0.850651f, 0.000000f, -0.525731f }, + { -0.688191f, 0.587785f, -0.425325f }, + { -0.587785f, 0.425325f, -0.688191f }, + { -0.425325f, 0.688191f, -0.587785f }, + { -0.425325f, -0.688191f, -0.587785f }, + { -0.587785f, -0.425325f, -0.688191f }, + { -0.688191f, -0.587785f, -0.425325f }, +}; + + +// _md2_canload() + +static int _md2_canload( PM_PARAMS_CANLOAD ) +{ + md2_t *md2; + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *md2 ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as md2 */ + md2 = (md2_t*) buffer; + + /* check md2 magic */ + if( *((int*) md2->magic) != *((int*) MD2_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check md2 version */ + if( _pico_little_long( md2->version ) != MD2_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid md2 */ + return PICO_PMV_OK; +} + + + +// _md2_load() loads a quake2 md2 model file. + + +static picoModel_t *_md2_load( PM_PARAMS_LOAD ) +{ + int i, j, dups, dup_index; + short tot_numVerts; + index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; + index_DUP_LUT_t *p_index_LUT_DUPS; + md2Triangle_t *p_md2Triangle; + + char skinname[ MD2_MAX_SKINNAME ]; + md2_t *md2; + md2St_t *texCoord; + md2Frame_t *frame; + md2Triangle_t *triangle; + md2XyzNormal_t *vertex; + + picoByte_t *bb; + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + // md2 loading + _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); + + /* set as md2 */ + bb = (picoByte_t*) buffer; + md2 = (md2_t*) buffer; + + /* check ident and version */ + if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION ) + { + /* not an md2 file (todo: set error) */ + _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName ); + return NULL; + } + + // swap md2 + md2->version = _pico_little_long( md2->version ); + + md2->skinWidth = _pico_little_long( md2->skinWidth ); + md2->skinHeight = _pico_little_long( md2->skinHeight ); + md2->frameSize = _pico_little_long( md2->frameSize ); + + md2->numSkins = _pico_little_long( md2->numSkins ); + md2->numXYZ = _pico_little_long( md2->numXYZ ); + md2->numST = _pico_little_long( md2->numST ); + md2->numTris = _pico_little_long( md2->numTris ); + md2->numGLCmds = _pico_little_long( md2->numGLCmds ); + md2->numFrames = _pico_little_long( md2->numFrames ); + + md2->ofsSkins = _pico_little_long( md2->ofsSkins ); + md2->ofsST = _pico_little_long( md2->ofsST ); + md2->ofsTris = _pico_little_long( md2->ofsTris ); + md2->ofsFrames = _pico_little_long( md2->ofsFrames ); + md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds ); + md2->ofsEnd = _pico_little_long( md2->ofsEnd ); + + // do frame check + if( md2->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); + return NULL; + } + + if( frameNum < 0 || frameNum >= md2->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" ); + return NULL; + } + + // Setup Frame + frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum)); + + // swap frame scale and translation + for( i = 0; i < 3; i++ ) + { + frame->scale[ i ] = _pico_little_float( frame->scale[ i ] ); + frame->translate[ i ] = _pico_little_float( frame->translate[ i ] ); + } + + // swap triangles + triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); + for( i = 0; i < md2->numTris; i++, triangle++ ) + { + for( j = 0; j < 3; j++ ) + { + triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); + triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); + } + } + + // swap st coords + texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); + for( i = 0; i < md2->numST; i++, texCoord++ ) + { + texCoord->s = _pico_little_short( texCoord->s ); + texCoord->t = _pico_little_short( texCoord->t ); + } + + // set Skin Name + strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME ); + + // Print out md2 values + _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname ); + + // detox Skin name + _pico_setfext( skinname, "" ); + _pico_unixify( skinname ); + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + // allocate new pico surface + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + return NULL; + } + + + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( picoSurface, frame->name ); + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + PicoSetShaderName( picoShader, skinname ); + + // associate current surface with newly created shader + PicoSetSurfaceShader( picoSurface, picoShader ); + + // Init LUT for Verts + p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ); + for(i=0; inumXYZ; i++) + { + p_index_LUT[i].Vert = -1; + p_index_LUT[i].ST = -1; + p_index_LUT[i].next = NULL; + } + + // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. + tot_numVerts = md2->numXYZ; + dups = 0; + for(i=0; inumTris; i++) + { + p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i)); + for(j=0; j<3; j++) + { + if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry + p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j]; + + else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry + continue; + + else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry + { // Add first entry of LL from Main + p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT2 == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; + p_index_LUT2->Vert = dups; + p_index_LUT2->ST = p_md2Triangle->index_st[j]; + p_index_LUT2->next = NULL; + p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk + dups++; + } + else // Try to find in LL from Main Entry + { + p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next; + while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL + { + p_index_LUT3 = p_index_LUT2; + p_index_LUT2 = p_index_LUT2->next; + } + p_index_LUT2 = p_index_LUT3; + + if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it + { + p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk + continue; + } + + if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. + { + // Add the Entry + p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT3 == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; + p_index_LUT3->Vert = p_md2Triangle->index_xyz[j]; + p_index_LUT3->ST = p_md2Triangle->index_st[j]; + p_index_LUT3->next = NULL; + p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk + dups++; + } + } + } + } + + // malloc and build array for Dup STs + p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); + if (p_index_LUT_DUPS == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + + dup_index = 0; + for(i=0; inumXYZ; i++) + { + p_index_LUT2 = p_index_LUT[i].next; + while (p_index_LUT2 != NULL) + { + p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; + p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; + dup_index++; + p_index_LUT2 = p_index_LUT2->next; + } + } + + // Build Picomodel + triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); + texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); + vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) ); + for( j = 0; j < md2->numTris; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); + PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); + PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); + } + + for(i=0; i< md2->numXYZ; i++, vertex++) + { + /* set vertex origin */ + xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0]; + xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1]; + xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2]; + PicoSetSurfaceXYZ( picoSurface, i , xyz ); + + /* set normal */ + normal[ 0 ] = md2_normals[vertex->lightnormalindex][0]; + normal[ 1 ] = md2_normals[vertex->lightnormalindex][1]; + normal[ 2 ] = md2_normals[vertex->lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i , st ); + } + + if (dups) + { + for(i=0; iverts[j].v[0] * frame->scale[0] + frame->translate[0]; + xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1]; + xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2]; + PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz ); + + /* set normal */ + normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0]; + normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1]; + normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st ); + } + } + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, 0, color ); + + // Free up malloc'ed LL entries + for(i=0; inumXYZ; i++) + { + if(p_index_LUT[i].next != NULL) + { + p_index_LUT2 = p_index_LUT[i].next; + do { + p_index_LUT3 = p_index_LUT2->next; + _pico_free(p_index_LUT2); + p_index_LUT2 = p_index_LUT3; + dups--; + } while (p_index_LUT2 != NULL); + } + } + + if (dups) + _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); + + // Free malloc'ed LUTs + _pico_free(p_index_LUT); + _pico_free(p_index_LUT_DUPS); + + /* return the new pico model */ + return picoModel; + +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMD2 = +{ + "0.875", /* module version string */ + "Quake 2 MD2", /* module display name */ + "Nurail", /* author's name */ + "2003 Nurail", /* module copyright */ + { + "md2", NULL, NULL, NULL /* default extensions to use */ + }, + _md2_canload, /* validation routine */ + _md2_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_md3.c b/libs/picomodel/pm_md3.c index 6d87469d..55022b28 100644 --- a/libs/picomodel/pm_md3.c +++ b/libs/picomodel/pm_md3.c @@ -1,425 +1,425 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define PM_MD3_C - - - -/* dependencies */ -#include "picointernal.h" - - - -/* md3 model format */ -#define MD3_MAGIC "IDP3" -#define MD3_VERSION 15 - -/* md3 vertex scale */ -#define MD3_SCALE (1.0f / 64.0f) - -/* md3 model frame information */ -typedef struct md3Frame_s -{ - float bounds[ 2 ][ 3 ]; - float localOrigin[ 3 ]; - float radius; - char creator[ 16 ]; -} -md3Frame_t; - -/* md3 model tag information */ -typedef struct md3Tag_s -{ - char name[ 64 ]; - float origin[ 3 ]; - float axis[ 3 ][ 3 ]; -} -md3Tag_t; - -/* md3 surface md3 (one object mesh) */ -typedef struct md3Surface_s -{ - char magic[ 4 ]; - char name[ 64 ]; /* polyset name */ - int flags; - int numFrames; /* all model surfaces should have the same */ - int numShaders; /* all model surfaces should have the same */ - int numVerts; - int numTriangles; - int ofsTriangles; - int ofsShaders; /* offset from start of md3Surface_t */ - int ofsSt; /* texture coords are common for all frames */ - int ofsVertexes; /* numVerts * numFrames */ - int ofsEnd; /* next surface follows */ -} -md3Surface_t; - -typedef struct md3Shader_s -{ - char name[ 64 ]; - int shaderIndex; /* for ingame use */ -} -md3Shader_t; - -typedef struct md3Triangle_s -{ - int indexes[ 3 ]; -} -md3Triangle_t; - -typedef struct md3TexCoord_s -{ - float st[ 2 ]; -} -md3TexCoord_t; - -typedef struct md3Vertex_s -{ - short xyz[ 3 ]; - short normal; -} -md3Vertex_t; - - -/* md3 model file md3 structure */ -typedef struct md3_s -{ - char magic[ 4 ]; /* MD3_MAGIC */ - int version; - char name[ 64 ]; /* model name */ - int flags; - int numFrames; - int numTags; - int numSurfaces; - int numSkins; /* number of skins for the mesh */ - int ofsFrames; /* offset for first frame */ - int ofsTags; /* numFrames * numTags */ - int ofsSurfaces; /* first surface, others follow */ - int ofsEnd; /* end of file */ -} -md3_t; - - - - -/* -_md3_canload() -validates a quake3 arena md3 model file. btw, i use the -preceding underscore cause it's a static func referenced -by one structure only. -*/ - -static int _md3_canload( PM_PARAMS_CANLOAD ) -{ - md3_t *md3; - - - /* to keep the compiler happy */ - *fileName = *fileName; - - /* sanity check */ - if( bufSize < ( sizeof( *md3 ) * 2) ) - return PICO_PMV_ERROR_SIZE; - - /* set as md3 */ - md3 = (md3_t*) buffer; - - /* check md3 magic */ - if( *((int*) md3->magic) != *((int*) MD3_MAGIC) ) - return PICO_PMV_ERROR_IDENT; - - /* check md3 version */ - if( _pico_little_long( md3->version ) != MD3_VERSION ) - return PICO_PMV_ERROR_VERSION; - - /* file seems to be a valid md3 */ - return PICO_PMV_OK; -} - - - -/* -_md3_load() -loads a quake3 arena md3 model file. -*/ - -static picoModel_t *_md3_load( PM_PARAMS_LOAD ) -{ - int i, j; - picoByte_t *bb; - md3_t *md3; - md3Surface_t *surface; - md3Shader_t *shader; - md3TexCoord_t *texCoord; - md3Frame_t *frame; - md3Triangle_t *triangle; - md3Vertex_t *vertex; - double lat, lng; - - picoModel_t *picoModel; - picoSurface_t *picoSurface; - picoShader_t *picoShader; - picoVec3_t xyz, normal; - picoVec2_t st; - picoColor_t color; - - - /* ------------------------------------------------- - md3 loading - ------------------------------------------------- */ - - - /* set as md3 */ - bb = (picoByte_t*) buffer; - md3 = (md3_t*) buffer; - - /* check ident and version */ - if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION ) - { - /* not an md3 file (todo: set error) */ - return NULL; - } - - /* swap md3; sea: swaps fixed */ - md3->version = _pico_little_long( md3->version ); - md3->numFrames = _pico_little_long( md3->numFrames ); - md3->numTags = _pico_little_long( md3->numTags ); - md3->numSurfaces = _pico_little_long( md3->numSurfaces ); - md3->numSkins = _pico_little_long( md3->numSkins ); - md3->ofsFrames = _pico_little_long( md3->ofsFrames ); - md3->ofsTags = _pico_little_long( md3->ofsTags ); - md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces ); - md3->ofsEnd = _pico_little_long( md3->ofsEnd ); - - /* do frame check */ - if( md3->numFrames < 1 ) - { - _pico_printf( PICO_ERROR, "MD3 with 0 frames" ); - return NULL; - } - - if( frameNum < 0 || frameNum >= md3->numFrames ) - { - _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" ); - return NULL; - } - - /* swap frames */ - frame = (md3Frame_t*) (bb + md3->ofsFrames ); - for( i = 0; i < md3->numFrames; i++, frame++ ) - { - frame->radius = _pico_little_float( frame->radius ); - for( j = 0; j < 3; j++ ) - { - frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); - frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); - frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); - } - } - - /* swap surfaces */ - surface = (md3Surface_t*) (bb + md3->ofsSurfaces); - for( i = 0; i < md3->numSurfaces; i++ ) - { - /* swap surface md3; sea: swaps fixed */ - surface->flags = _pico_little_long( surface->flags ); - surface->numFrames = _pico_little_long( surface->numFrames ); - surface->numShaders = _pico_little_long( surface->numShaders ); - surface->numTriangles = _pico_little_long( surface->numTriangles ); - surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); - surface->numVerts = _pico_little_long( surface->numVerts ); - surface->ofsShaders = _pico_little_long( surface->ofsShaders ); - surface->ofsSt = _pico_little_long( surface->ofsSt ); - surface->ofsVertexes = _pico_little_long( surface->ofsVertexes ); - surface->ofsEnd = _pico_little_long( surface->ofsEnd ); - - /* swap triangles */ - triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); - for( j = 0; j < surface->numTriangles; j++, triangle++ ) - { - /* sea: swaps fixed */ - triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); - triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); - triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); - } - - /* swap st coords */ - texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); - for( j = 0; j < surface->numVerts; j++, texCoord++ ) - { - texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); - texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); - } - - /* swap xyz/normals */ - vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes); - for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++) - { - vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); - vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); - vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); - vertex->normal = _pico_little_short( vertex->normal ); - } - - /* get next surface */ - surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); - } - - /* ------------------------------------------------- - pico model creation - ------------------------------------------------- */ - - /* create new pico model */ - picoModel = PicoNewModel(); - if( picoModel == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); - return NULL; - } - - /* do model setup */ - PicoSetModelFrameNum( picoModel, frameNum ); - PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */ - PicoSetModelName( picoModel, fileName ); - PicoSetModelFileName( picoModel, fileName ); - - /* md3 surfaces become picomodel surfaces */ - surface = (md3Surface_t*) (bb + md3->ofsSurfaces); - - /* run through md3 surfaces */ - for( i = 0; i < md3->numSurfaces; i++ ) - { - /* allocate new pico surface */ - picoSurface = PicoNewSurface( picoModel ); - if( picoSurface == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); - PicoFreeModel( picoModel ); /* sea */ - return NULL; - } - - /* md3 model surfaces are all triangle meshes */ - PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); - - /* set surface name */ - PicoSetSurfaceName( picoSurface, surface->name ); - - /* create new pico shader -sea */ - picoShader = PicoNewShader( picoModel ); - if( picoShader == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); - PicoFreeModel( picoModel ); - return NULL; - } - - /* detox and set shader name */ - shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders); - _pico_setfext( shader->name, "" ); - _pico_unixify( shader->name ); - PicoSetShaderName( picoShader, shader->name ); - - /* associate current surface with newly created shader */ - PicoSetSurfaceShader( picoSurface, picoShader ); - - /* copy indexes */ - triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); - - for( j = 0; j < surface->numTriangles; j++, triangle++ ) - { - PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); - PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); - PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); - } - - /* copy vertexes */ - texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); - vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) ); - _pico_set_color( color, 255, 255, 255, 255 ); - - for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ ) - { - /* set vertex origin */ - xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ]; - xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ]; - xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ]; - PicoSetSurfaceXYZ( picoSurface, j, xyz ); - - /* decode lat/lng normal to 3 float normal */ - lat = (float) ((vertex->normal >> 8) & 0xff); - lng = (float) (vertex->normal & 0xff); - lat *= PICO_PI / 128; - lng *= PICO_PI / 128; - normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); - normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); - normal[ 2 ] = (picoVec_t) cos( lng ); - PicoSetSurfaceNormal( picoSurface, j, normal ); - - /* set st coords */ - st[ 0 ] = texCoord->st[ 0 ]; - st[ 1 ] = texCoord->st[ 1 ]; - PicoSetSurfaceST( picoSurface, 0, j, st ); - - /* set color */ - PicoSetSurfaceColor( picoSurface, 0, j, color ); - } - - /* get next surface */ - surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); - } - - /* return the new pico model */ - return picoModel; -} - - - -/* pico file format module definition */ -const picoModule_t picoModuleMD3 = -{ - "1.3", /* module version string */ - "Quake 3 Arena", /* module display name */ - "Randy Reddig", /* author's name */ - "2002 Randy Reddig", /* module copyright */ - { - "md3", NULL, NULL, NULL /* default extensions to use */ - }, - _md3_canload, /* validation routine */ - _md3_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MD3_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* md3 model format */ +#define MD3_MAGIC "IDP3" +#define MD3_VERSION 15 + +/* md3 vertex scale */ +#define MD3_SCALE (1.0f / 64.0f) + +/* md3 model frame information */ +typedef struct md3Frame_s +{ + float bounds[ 2 ][ 3 ]; + float localOrigin[ 3 ]; + float radius; + char creator[ 16 ]; +} +md3Frame_t; + +/* md3 model tag information */ +typedef struct md3Tag_s +{ + char name[ 64 ]; + float origin[ 3 ]; + float axis[ 3 ][ 3 ]; +} +md3Tag_t; + +/* md3 surface md3 (one object mesh) */ +typedef struct md3Surface_s +{ + char magic[ 4 ]; + char name[ 64 ]; /* polyset name */ + int flags; + int numFrames; /* all model surfaces should have the same */ + int numShaders; /* all model surfaces should have the same */ + int numVerts; + int numTriangles; + int ofsTriangles; + int ofsShaders; /* offset from start of md3Surface_t */ + int ofsSt; /* texture coords are common for all frames */ + int ofsVertexes; /* numVerts * numFrames */ + int ofsEnd; /* next surface follows */ +} +md3Surface_t; + +typedef struct md3Shader_s +{ + char name[ 64 ]; + int shaderIndex; /* for ingame use */ +} +md3Shader_t; + +typedef struct md3Triangle_s +{ + int indexes[ 3 ]; +} +md3Triangle_t; + +typedef struct md3TexCoord_s +{ + float st[ 2 ]; +} +md3TexCoord_t; + +typedef struct md3Vertex_s +{ + short xyz[ 3 ]; + short normal; +} +md3Vertex_t; + + +/* md3 model file md3 structure */ +typedef struct md3_s +{ + char magic[ 4 ]; /* MD3_MAGIC */ + int version; + char name[ 64 ]; /* model name */ + int flags; + int numFrames; + int numTags; + int numSurfaces; + int numSkins; /* number of skins for the mesh */ + int ofsFrames; /* offset for first frame */ + int ofsTags; /* numFrames * numTags */ + int ofsSurfaces; /* first surface, others follow */ + int ofsEnd; /* end of file */ +} +md3_t; + + + + +/* +_md3_canload() +validates a quake3 arena md3 model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ + +static int _md3_canload( PM_PARAMS_CANLOAD ) +{ + md3_t *md3; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *md3 ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as md3 */ + md3 = (md3_t*) buffer; + + /* check md3 magic */ + if( *((int*) md3->magic) != *((int*) MD3_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check md3 version */ + if( _pico_little_long( md3->version ) != MD3_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid md3 */ + return PICO_PMV_OK; +} + + + +/* +_md3_load() +loads a quake3 arena md3 model file. +*/ + +static picoModel_t *_md3_load( PM_PARAMS_LOAD ) +{ + int i, j; + picoByte_t *bb; + md3_t *md3; + md3Surface_t *surface; + md3Shader_t *shader; + md3TexCoord_t *texCoord; + md3Frame_t *frame; + md3Triangle_t *triangle; + md3Vertex_t *vertex; + double lat, lng; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + /* ------------------------------------------------- + md3 loading + ------------------------------------------------- */ + + + /* set as md3 */ + bb = (picoByte_t*) buffer; + md3 = (md3_t*) buffer; + + /* check ident and version */ + if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION ) + { + /* not an md3 file (todo: set error) */ + return NULL; + } + + /* swap md3; sea: swaps fixed */ + md3->version = _pico_little_long( md3->version ); + md3->numFrames = _pico_little_long( md3->numFrames ); + md3->numTags = _pico_little_long( md3->numTags ); + md3->numSurfaces = _pico_little_long( md3->numSurfaces ); + md3->numSkins = _pico_little_long( md3->numSkins ); + md3->ofsFrames = _pico_little_long( md3->ofsFrames ); + md3->ofsTags = _pico_little_long( md3->ofsTags ); + md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces ); + md3->ofsEnd = _pico_little_long( md3->ofsEnd ); + + /* do frame check */ + if( md3->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "MD3 with 0 frames" ); + return NULL; + } + + if( frameNum < 0 || frameNum >= md3->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" ); + return NULL; + } + + /* swap frames */ + frame = (md3Frame_t*) (bb + md3->ofsFrames ); + for( i = 0; i < md3->numFrames; i++, frame++ ) + { + frame->radius = _pico_little_float( frame->radius ); + for( j = 0; j < 3; j++ ) + { + frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); + frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); + frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); + } + } + + /* swap surfaces */ + surface = (md3Surface_t*) (bb + md3->ofsSurfaces); + for( i = 0; i < md3->numSurfaces; i++ ) + { + /* swap surface md3; sea: swaps fixed */ + surface->flags = _pico_little_long( surface->flags ); + surface->numFrames = _pico_little_long( surface->numFrames ); + surface->numShaders = _pico_little_long( surface->numShaders ); + surface->numTriangles = _pico_little_long( surface->numTriangles ); + surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); + surface->numVerts = _pico_little_long( surface->numVerts ); + surface->ofsShaders = _pico_little_long( surface->ofsShaders ); + surface->ofsSt = _pico_little_long( surface->ofsSt ); + surface->ofsVertexes = _pico_little_long( surface->ofsVertexes ); + surface->ofsEnd = _pico_little_long( surface->ofsEnd ); + + /* swap triangles */ + triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + /* sea: swaps fixed */ + triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); + triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); + triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); + } + + /* swap st coords */ + texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); + for( j = 0; j < surface->numVerts; j++, texCoord++ ) + { + texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); + texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); + } + + /* swap xyz/normals */ + vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes); + for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++) + { + vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); + vertex->normal = _pico_little_short( vertex->normal ); + } + + /* get next surface */ + surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* md3 surfaces become picomodel surfaces */ + surface = (md3Surface_t*) (bb + md3->ofsSurfaces); + + /* run through md3 surfaces */ + for( i = 0; i < md3->numSurfaces; i++ ) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); /* sea */ + return NULL; + } + + /* md3 model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader -sea */ + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + /* detox and set shader name */ + shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders); + _pico_setfext( shader->name, "" ); + _pico_unixify( shader->name ); + PicoSetShaderName( picoShader, shader->name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indexes */ + triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); + + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); + } + + /* copy vertexes */ + texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); + vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) ); + _pico_set_color( color, 255, 255, 255, 255 ); + + for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ ) + { + /* set vertex origin */ + xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ]; + xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ]; + xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ]; + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + /* decode lat/lng normal to 3 float normal */ + lat = (float) ((vertex->normal >> 8) & 0xff); + lng = (float) (vertex->normal & 0xff); + lat *= PICO_PI / 128; + lng *= PICO_PI / 128; + normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); + normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); + normal[ 2 ] = (picoVec_t) cos( lng ); + PicoSetSurfaceNormal( picoSurface, j, normal ); + + /* set st coords */ + st[ 0 ] = texCoord->st[ 0 ]; + st[ 1 ] = texCoord->st[ 1 ]; + PicoSetSurfaceST( picoSurface, 0, j, st ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, j, color ); + } + + /* get next surface */ + surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* return the new pico model */ + return picoModel; +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMD3 = +{ + "1.3", /* module version string */ + "Quake 3 Arena", /* module display name */ + "Randy Reddig", /* author's name */ + "2002 Randy Reddig", /* module copyright */ + { + "md3", NULL, NULL, NULL /* default extensions to use */ + }, + _md3_canload, /* validation routine */ + _md3_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_mdc.c b/libs/picomodel/pm_mdc.c index 3036d112..27e612e8 100644 --- a/libs/picomodel/pm_mdc.c +++ b/libs/picomodel/pm_mdc.c @@ -1,750 +1,750 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define PM_MDC_C - - - -/* dependencies */ -#include "picointernal.h" - -/* mdc model format */ -#define MDC_MAGIC "IDPC" -#define MDC_VERSION 2 - -/* mdc vertex scale */ -#define MDC_SCALE (1.0f / 64.0f) -#define MDC_MAX_OFS 127.0f -#define MDC_DIST_SCALE 0.05f - -/* mdc decoding normal table */ -double mdcNormals[ 256 ][ 3 ] = -{ - { 1.000000, 0.000000, 0.000000 }, - { 0.980785, 0.195090, 0.000000 }, - { 0.923880, 0.382683, 0.000000 }, - { 0.831470, 0.555570, 0.000000 }, - { 0.707107, 0.707107, 0.000000 }, - { 0.555570, 0.831470, 0.000000 }, - { 0.382683, 0.923880, 0.000000 }, - { 0.195090, 0.980785, 0.000000 }, - { -0.000000, 1.000000, 0.000000 }, - { -0.195090, 0.980785, 0.000000 }, - { -0.382683, 0.923880, 0.000000 }, - { -0.555570, 0.831470, 0.000000 }, - { -0.707107, 0.707107, 0.000000 }, - { -0.831470, 0.555570, 0.000000 }, - { -0.923880, 0.382683, 0.000000 }, - { -0.980785, 0.195090, 0.000000 }, - { -1.000000, -0.000000, 0.000000 }, - { -0.980785, -0.195090, 0.000000 }, - { -0.923880, -0.382683, 0.000000 }, - { -0.831470, -0.555570, 0.000000 }, - { -0.707107, -0.707107, 0.000000 }, - { -0.555570, -0.831469, 0.000000 }, - { -0.382684, -0.923880, 0.000000 }, - { -0.195090, -0.980785, 0.000000 }, - { 0.000000, -1.000000, 0.000000 }, - { 0.195090, -0.980785, 0.000000 }, - { 0.382684, -0.923879, 0.000000 }, - { 0.555570, -0.831470, 0.000000 }, - { 0.707107, -0.707107, 0.000000 }, - { 0.831470, -0.555570, 0.000000 }, - { 0.923880, -0.382683, 0.000000 }, - { 0.980785, -0.195090, 0.000000 }, - { 0.980785, 0.000000, -0.195090 }, - { 0.956195, 0.218245, -0.195090 }, - { 0.883657, 0.425547, -0.195090 }, - { 0.766809, 0.611510, -0.195090 }, - { 0.611510, 0.766809, -0.195090 }, - { 0.425547, 0.883657, -0.195090 }, - { 0.218245, 0.956195, -0.195090 }, - { -0.000000, 0.980785, -0.195090 }, - { -0.218245, 0.956195, -0.195090 }, - { -0.425547, 0.883657, -0.195090 }, - { -0.611510, 0.766809, -0.195090 }, - { -0.766809, 0.611510, -0.195090 }, - { -0.883657, 0.425547, -0.195090 }, - { -0.956195, 0.218245, -0.195090 }, - { -0.980785, -0.000000, -0.195090 }, - { -0.956195, -0.218245, -0.195090 }, - { -0.883657, -0.425547, -0.195090 }, - { -0.766809, -0.611510, -0.195090 }, - { -0.611510, -0.766809, -0.195090 }, - { -0.425547, -0.883657, -0.195090 }, - { -0.218245, -0.956195, -0.195090 }, - { 0.000000, -0.980785, -0.195090 }, - { 0.218245, -0.956195, -0.195090 }, - { 0.425547, -0.883657, -0.195090 }, - { 0.611510, -0.766809, -0.195090 }, - { 0.766809, -0.611510, -0.195090 }, - { 0.883657, -0.425547, -0.195090 }, - { 0.956195, -0.218245, -0.195090 }, - { 0.923880, 0.000000, -0.382683 }, - { 0.892399, 0.239118, -0.382683 }, - { 0.800103, 0.461940, -0.382683 }, - { 0.653281, 0.653281, -0.382683 }, - { 0.461940, 0.800103, -0.382683 }, - { 0.239118, 0.892399, -0.382683 }, - { -0.000000, 0.923880, -0.382683 }, - { -0.239118, 0.892399, -0.382683 }, - { -0.461940, 0.800103, -0.382683 }, - { -0.653281, 0.653281, -0.382683 }, - { -0.800103, 0.461940, -0.382683 }, - { -0.892399, 0.239118, -0.382683 }, - { -0.923880, -0.000000, -0.382683 }, - { -0.892399, -0.239118, -0.382683 }, - { -0.800103, -0.461940, -0.382683 }, - { -0.653282, -0.653281, -0.382683 }, - { -0.461940, -0.800103, -0.382683 }, - { -0.239118, -0.892399, -0.382683 }, - { 0.000000, -0.923880, -0.382683 }, - { 0.239118, -0.892399, -0.382683 }, - { 0.461940, -0.800103, -0.382683 }, - { 0.653281, -0.653282, -0.382683 }, - { 0.800103, -0.461940, -0.382683 }, - { 0.892399, -0.239117, -0.382683 }, - { 0.831470, 0.000000, -0.555570 }, - { 0.790775, 0.256938, -0.555570 }, - { 0.672673, 0.488726, -0.555570 }, - { 0.488726, 0.672673, -0.555570 }, - { 0.256938, 0.790775, -0.555570 }, - { -0.000000, 0.831470, -0.555570 }, - { -0.256938, 0.790775, -0.555570 }, - { -0.488726, 0.672673, -0.555570 }, - { -0.672673, 0.488726, -0.555570 }, - { -0.790775, 0.256938, -0.555570 }, - { -0.831470, -0.000000, -0.555570 }, - { -0.790775, -0.256938, -0.555570 }, - { -0.672673, -0.488726, -0.555570 }, - { -0.488725, -0.672673, -0.555570 }, - { -0.256938, -0.790775, -0.555570 }, - { 0.000000, -0.831470, -0.555570 }, - { 0.256938, -0.790775, -0.555570 }, - { 0.488725, -0.672673, -0.555570 }, - { 0.672673, -0.488726, -0.555570 }, - { 0.790775, -0.256938, -0.555570 }, - { 0.707107, 0.000000, -0.707107 }, - { 0.653281, 0.270598, -0.707107 }, - { 0.500000, 0.500000, -0.707107 }, - { 0.270598, 0.653281, -0.707107 }, - { -0.000000, 0.707107, -0.707107 }, - { -0.270598, 0.653282, -0.707107 }, - { -0.500000, 0.500000, -0.707107 }, - { -0.653281, 0.270598, -0.707107 }, - { -0.707107, -0.000000, -0.707107 }, - { -0.653281, -0.270598, -0.707107 }, - { -0.500000, -0.500000, -0.707107 }, - { -0.270598, -0.653281, -0.707107 }, - { 0.000000, -0.707107, -0.707107 }, - { 0.270598, -0.653281, -0.707107 }, - { 0.500000, -0.500000, -0.707107 }, - { 0.653282, -0.270598, -0.707107 }, - { 0.555570, 0.000000, -0.831470 }, - { 0.481138, 0.277785, -0.831470 }, - { 0.277785, 0.481138, -0.831470 }, - { -0.000000, 0.555570, -0.831470 }, - { -0.277785, 0.481138, -0.831470 }, - { -0.481138, 0.277785, -0.831470 }, - { -0.555570, -0.000000, -0.831470 }, - { -0.481138, -0.277785, -0.831470 }, - { -0.277785, -0.481138, -0.831470 }, - { 0.000000, -0.555570, -0.831470 }, - { 0.277785, -0.481138, -0.831470 }, - { 0.481138, -0.277785, -0.831470 }, - { 0.382683, 0.000000, -0.923880 }, - { 0.270598, 0.270598, -0.923880 }, - { -0.000000, 0.382683, -0.923880 }, - { -0.270598, 0.270598, -0.923880 }, - { -0.382683, -0.000000, -0.923880 }, - { -0.270598, -0.270598, -0.923880 }, - { 0.000000, -0.382683, -0.923880 }, - { 0.270598, -0.270598, -0.923880 }, - { 0.195090, 0.000000, -0.980785 }, - { -0.000000, 0.195090, -0.980785 }, - { -0.195090, -0.000000, -0.980785 }, - { 0.000000, -0.195090, -0.980785 }, - { 0.980785, 0.000000, 0.195090 }, - { 0.956195, 0.218245, 0.195090 }, - { 0.883657, 0.425547, 0.195090 }, - { 0.766809, 0.611510, 0.195090 }, - { 0.611510, 0.766809, 0.195090 }, - { 0.425547, 0.883657, 0.195090 }, - { 0.218245, 0.956195, 0.195090 }, - { -0.000000, 0.980785, 0.195090 }, - { -0.218245, 0.956195, 0.195090 }, - { -0.425547, 0.883657, 0.195090 }, - { -0.611510, 0.766809, 0.195090 }, - { -0.766809, 0.611510, 0.195090 }, - { -0.883657, 0.425547, 0.195090 }, - { -0.956195, 0.218245, 0.195090 }, - { -0.980785, -0.000000, 0.195090 }, - { -0.956195, -0.218245, 0.195090 }, - { -0.883657, -0.425547, 0.195090 }, - { -0.766809, -0.611510, 0.195090 }, - { -0.611510, -0.766809, 0.195090 }, - { -0.425547, -0.883657, 0.195090 }, - { -0.218245, -0.956195, 0.195090 }, - { 0.000000, -0.980785, 0.195090 }, - { 0.218245, -0.956195, 0.195090 }, - { 0.425547, -0.883657, 0.195090 }, - { 0.611510, -0.766809, 0.195090 }, - { 0.766809, -0.611510, 0.195090 }, - { 0.883657, -0.425547, 0.195090 }, - { 0.956195, -0.218245, 0.195090 }, - { 0.923880, 0.000000, 0.382683 }, - { 0.892399, 0.239118, 0.382683 }, - { 0.800103, 0.461940, 0.382683 }, - { 0.653281, 0.653281, 0.382683 }, - { 0.461940, 0.800103, 0.382683 }, - { 0.239118, 0.892399, 0.382683 }, - { -0.000000, 0.923880, 0.382683 }, - { -0.239118, 0.892399, 0.382683 }, - { -0.461940, 0.800103, 0.382683 }, - { -0.653281, 0.653281, 0.382683 }, - { -0.800103, 0.461940, 0.382683 }, - { -0.892399, 0.239118, 0.382683 }, - { -0.923880, -0.000000, 0.382683 }, - { -0.892399, -0.239118, 0.382683 }, - { -0.800103, -0.461940, 0.382683 }, - { -0.653282, -0.653281, 0.382683 }, - { -0.461940, -0.800103, 0.382683 }, - { -0.239118, -0.892399, 0.382683 }, - { 0.000000, -0.923880, 0.382683 }, - { 0.239118, -0.892399, 0.382683 }, - { 0.461940, -0.800103, 0.382683 }, - { 0.653281, -0.653282, 0.382683 }, - { 0.800103, -0.461940, 0.382683 }, - { 0.892399, -0.239117, 0.382683 }, - { 0.831470, 0.000000, 0.555570 }, - { 0.790775, 0.256938, 0.555570 }, - { 0.672673, 0.488726, 0.555570 }, - { 0.488726, 0.672673, 0.555570 }, - { 0.256938, 0.790775, 0.555570 }, - { -0.000000, 0.831470, 0.555570 }, - { -0.256938, 0.790775, 0.555570 }, - { -0.488726, 0.672673, 0.555570 }, - { -0.672673, 0.488726, 0.555570 }, - { -0.790775, 0.256938, 0.555570 }, - { -0.831470, -0.000000, 0.555570 }, - { -0.790775, -0.256938, 0.555570 }, - { -0.672673, -0.488726, 0.555570 }, - { -0.488725, -0.672673, 0.555570 }, - { -0.256938, -0.790775, 0.555570 }, - { 0.000000, -0.831470, 0.555570 }, - { 0.256938, -0.790775, 0.555570 }, - { 0.488725, -0.672673, 0.555570 }, - { 0.672673, -0.488726, 0.555570 }, - { 0.790775, -0.256938, 0.555570 }, - { 0.707107, 0.000000, 0.707107 }, - { 0.653281, 0.270598, 0.707107 }, - { 0.500000, 0.500000, 0.707107 }, - { 0.270598, 0.653281, 0.707107 }, - { -0.000000, 0.707107, 0.707107 }, - { -0.270598, 0.653282, 0.707107 }, - { -0.500000, 0.500000, 0.707107 }, - { -0.653281, 0.270598, 0.707107 }, - { -0.707107, -0.000000, 0.707107 }, - { -0.653281, -0.270598, 0.707107 }, - { -0.500000, -0.500000, 0.707107 }, - { -0.270598, -0.653281, 0.707107 }, - { 0.000000, -0.707107, 0.707107 }, - { 0.270598, -0.653281, 0.707107 }, - { 0.500000, -0.500000, 0.707107 }, - { 0.653282, -0.270598, 0.707107 }, - { 0.555570, 0.000000, 0.831470 }, - { 0.481138, 0.277785, 0.831470 }, - { 0.277785, 0.481138, 0.831470 }, - { -0.000000, 0.555570, 0.831470 }, - { -0.277785, 0.481138, 0.831470 }, - { -0.481138, 0.277785, 0.831470 }, - { -0.555570, -0.000000, 0.831470 }, - { -0.481138, -0.277785, 0.831470 }, - { -0.277785, -0.481138, 0.831470 }, - { 0.000000, -0.555570, 0.831470 }, - { 0.277785, -0.481138, 0.831470 }, - { 0.481138, -0.277785, 0.831470 }, - { 0.382683, 0.000000, 0.923880 }, - { 0.270598, 0.270598, 0.923880 }, - { -0.000000, 0.382683, 0.923880 }, - { -0.270598, 0.270598, 0.923880 }, - { -0.382683, -0.000000, 0.923880 }, - { -0.270598, -0.270598, 0.923880 }, - { 0.000000, -0.382683, 0.923880 }, - { 0.270598, -0.270598, 0.923880 }, - { 0.195090, 0.000000, 0.980785 }, - { -0.000000, 0.195090, 0.980785 }, - { -0.195090, -0.000000, 0.980785 }, - { 0.000000, -0.195090, 0.980785 } -}; - -/* mdc model frame information */ -typedef struct mdcFrame_s -{ - float bounds[ 2 ][ 3 ]; - float localOrigin[ 3 ]; - float radius; - char creator[ 16 ]; -} -mdcFrame_t; - -/* mdc model tag information */ -typedef struct mdcTag_s -{ - short xyz[3]; - short angles[3]; -} -mdcTag_t; - -/* mdc surface mdc (one object mesh) */ -typedef struct mdcSurface_s -{ - char magic[ 4 ]; - char name[ 64 ]; /* polyset name */ - int flags; - int numCompFrames; /* all surfaces in a model should have the same */ - int numBaseFrames; /* ditto */ - int numShaders; /* all model surfaces should have the same */ - int numVerts; - int numTriangles; - int ofsTriangles; - int ofsShaders; /* offset from start of mdcSurface_t */ - int ofsSt; /* texture coords are common for all frames */ - int ofsXyzNormals; /* numVerts * numBaseFrames */ - int ofsXyzCompressed; /* numVerts * numCompFrames */ - - int ofsFrameBaseFrames; /* numFrames */ - int ofsFrameCompFrames; /* numFrames */ - int ofsEnd; /* next surface follows */ -} -mdcSurface_t; - -typedef struct mdcShader_s -{ - char name[ 64 ]; - int shaderIndex; /* for ingame use */ -} -mdcShader_t; - -typedef struct mdcTriangle_s -{ - int indexes[ 3 ]; -} -mdcTriangle_t; - -typedef struct mdcTexCoord_s -{ - float st[ 2 ]; -} -mdcTexCoord_t; - -typedef struct mdcVertex_s -{ - short xyz[ 3 ]; - short normal; -} -mdcVertex_t; - -typedef struct mdcXyzCompressed_s -{ - unsigned int ofsVec; /* offset direction from the last base frame */ -} -mdcXyzCompressed_t; - - -/* mdc model file mdc structure */ -typedef struct mdc_s -{ - char magic[ 4 ]; /* MDC_MAGIC */ - int version; - char name[ 64 ]; /* model name */ - int flags; - int numFrames; - int numTags; - int numSurfaces; - int numSkins; /* number of skins for the mesh */ - int ofsFrames; /* offset for first frame */ - int ofsTagNames; /* numTags */ - int ofsTags; /* numFrames * numTags */ - int ofsSurfaces; /* first surface, others follow */ - int ofsEnd; /* end of file */ -} -mdc_t; - - - - -/* -_mdc_canload() -validates a Return to Castle Wolfenstein model file. btw, i use the -preceding underscore cause it's a static func referenced -by one structure only. -*/ - -static int _mdc_canload( PM_PARAMS_CANLOAD ) -{ - mdc_t *mdc; - - - /* to keep the compiler happy */ - *fileName = *fileName; - - /* sanity check */ - if( bufSize < ( sizeof( *mdc ) * 2) ) - return PICO_PMV_ERROR_SIZE; - - /* set as mdc */ - mdc = (mdc_t*) buffer; - - /* check mdc magic */ - if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) ) - return PICO_PMV_ERROR_IDENT; - - /* check mdc version */ - if( _pico_little_long( mdc->version ) != MDC_VERSION ) - return PICO_PMV_ERROR_VERSION; - - /* file seems to be a valid mdc */ - return PICO_PMV_OK; -} - - - -/* -_mdc_load() -loads a Return to Castle Wolfenstein mdc model file. -*/ - -static picoModel_t *_mdc_load( PM_PARAMS_LOAD ) -{ - int i, j; - picoByte_t *bb; - mdc_t *mdc; - mdcSurface_t *surface; - mdcShader_t *shader; - mdcTexCoord_t *texCoord; - mdcFrame_t *frame; - mdcTriangle_t *triangle; - mdcVertex_t *vertex; - mdcXyzCompressed_t *vertexComp; - short *mdcShort, *mdcCompVert; - double lat, lng; - - picoModel_t *picoModel; - picoSurface_t *picoSurface; - picoShader_t *picoShader; - picoVec3_t xyz, normal; - picoVec2_t st; - picoColor_t color; - - - /* ------------------------------------------------- - mdc loading - ------------------------------------------------- */ - - - /* set as mdc */ - bb = (picoByte_t*) buffer; - mdc = (mdc_t*) buffer; - - /* check ident and version */ - if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) || _pico_little_long( mdc->version ) != MDC_VERSION ) - { - /* not an mdc file (todo: set error) */ - return NULL; - } - - /* swap mdc */ - mdc->version = _pico_little_long( mdc->version ); - mdc->numFrames = _pico_little_long( mdc->numFrames ); - mdc->numTags = _pico_little_long( mdc->numTags ); - mdc->numSurfaces = _pico_little_long( mdc->numSurfaces ); - mdc->numSkins = _pico_little_long( mdc->numSkins ); - mdc->ofsFrames = _pico_little_long( mdc->ofsFrames ); - mdc->ofsTags = _pico_little_long( mdc->ofsTags ); - mdc->ofsTagNames = _pico_little_long( mdc->ofsTagNames ); - mdc->ofsSurfaces = _pico_little_long( mdc->ofsSurfaces ); - mdc->ofsEnd = _pico_little_long( mdc->ofsEnd ); - - /* do frame check */ - if( mdc->numFrames < 1 ) - { - _pico_printf( PICO_ERROR, "MDC with 0 frames" ); - return NULL; - } - - if( frameNum < 0 || frameNum >= mdc->numFrames ) - { - _pico_printf( PICO_ERROR, "Invalid or out-of-range MDC frame specified" ); - return NULL; - } - - /* swap frames */ - frame = (mdcFrame_t*) (bb + mdc->ofsFrames ); - for( i = 0; i < mdc->numFrames; i++, frame++ ) - { - frame->radius = _pico_little_float( frame->radius ); - for( j = 0; j < 3; j++ ) - { - frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); - frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); - frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); - } - } - - /* swap surfaces */ - surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); - for( i = 0; i < mdc->numSurfaces; i++ ) - { - /* swap surface mdc */ - surface->flags = _pico_little_long( surface->flags ); - surface->numBaseFrames = _pico_little_long( surface->numBaseFrames ); - surface->numCompFrames = _pico_little_long( surface->numCompFrames ); - surface->numShaders = _pico_little_long( surface->numShaders ); - surface->numTriangles = _pico_little_long( surface->numTriangles ); - surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); - surface->numVerts = _pico_little_long( surface->numVerts ); - surface->ofsShaders = _pico_little_long( surface->ofsShaders ); - surface->ofsSt = _pico_little_long( surface->ofsSt ); - surface->ofsXyzNormals = _pico_little_long( surface->ofsXyzNormals ); - surface->ofsXyzCompressed = _pico_little_long( surface->ofsXyzCompressed ); - surface->ofsFrameBaseFrames = _pico_little_long( surface->ofsFrameBaseFrames ); - surface->ofsFrameCompFrames = _pico_little_long( surface->ofsFrameCompFrames ); - surface->ofsEnd = _pico_little_long( surface->ofsEnd ); - - /* swap triangles */ - triangle = (mdcTriangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); - for( j = 0; j < surface->numTriangles; j++, triangle++ ) - { - /* sea: swaps fixed */ - triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); - triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); - triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); - } - - /* swap st coords */ - texCoord = (mdcTexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); - for( j = 0; j < surface->numVerts; j++, texCoord++ ) - { - texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); - texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); - } - - /* swap xyz/normals */ - vertex = (mdcVertex_t*) ((picoByte_t*) surface + surface->ofsXyzNormals); - for( j = 0; j < (surface->numVerts * surface->numBaseFrames); j++, vertex++) - { - vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); - vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); - vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); - vertex->normal = _pico_little_short( vertex->normal ); - } - - /* swap xyz/compressed */ - vertexComp = (mdcXyzCompressed_t*) ((picoByte_t*) surface + surface->ofsXyzCompressed); - for( j = 0; j < (surface->numVerts * surface->numCompFrames); j++, vertexComp++) - { - vertexComp->ofsVec = _pico_little_long( vertexComp->ofsVec ); - } - - /* swap base frames */ - mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameBaseFrames); - for( j = 0; j < mdc->numFrames; j++, mdcShort++) - { - *mdcShort = _pico_little_short( *mdcShort ); - } - - /* swap compressed frames */ - mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameCompFrames); - for( j = 0; j < mdc->numFrames; j++, mdcShort++) - { - *mdcShort = _pico_little_short( *mdcShort ); - } - - /* get next surface */ - surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); - } - - /* ------------------------------------------------- - pico model creation - ------------------------------------------------- */ - - /* create new pico model */ - picoModel = PicoNewModel(); - if( picoModel == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); - return NULL; - } - - /* do model setup */ - PicoSetModelFrameNum( picoModel, frameNum ); - PicoSetModelNumFrames( picoModel, mdc->numFrames ); /* sea */ - PicoSetModelName( picoModel, fileName ); - PicoSetModelFileName( picoModel, fileName ); - - /* mdc surfaces become picomodel surfaces */ - surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); - - /* run through mdc surfaces */ - for( i = 0; i < mdc->numSurfaces; i++ ) - { - /* allocate new pico surface */ - picoSurface = PicoNewSurface( picoModel ); - if( picoSurface == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); - PicoFreeModel( picoModel ); /* sea */ - return NULL; - } - - /* mdc model surfaces are all triangle meshes */ - PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); - - /* set surface name */ - PicoSetSurfaceName( picoSurface, surface->name ); - - /* create new pico shader -sea */ - picoShader = PicoNewShader( picoModel ); - if( picoShader == NULL ) - { - _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); - PicoFreeModel( picoModel ); - return NULL; - } - - /* detox and set shader name */ - shader = (mdcShader_t*) ((picoByte_t*) surface + surface->ofsShaders); - _pico_setfext( shader->name, "" ); - _pico_unixify( shader->name ); - PicoSetShaderName( picoShader, shader->name ); - - /* associate current surface with newly created shader */ - PicoSetSurfaceShader( picoSurface, picoShader ); - - /* copy indexes */ - triangle = (mdcTriangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); - - for( j = 0; j < surface->numTriangles; j++, triangle++ ) - { - PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); - PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); - PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); - } - - /* copy vertexes */ - texCoord = (mdcTexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); - mdcShort = (short *) ((picoByte_t *) surface + surface->ofsXyzNormals) + ((int)*((short *) ((picoByte_t *) surface + surface->ofsFrameBaseFrames) + frameNum) * surface->numVerts * 4); - if( surface->numCompFrames > 0 ) - { - mdcCompVert = (short *) ((picoByte_t *) surface + surface->ofsFrameCompFrames) + frameNum; - if( *mdcCompVert >= 0 ) - vertexComp = (mdcXyzCompressed_t *) ((picoByte_t *) surface + surface->ofsXyzCompressed) + (*mdcCompVert * surface->numVerts); - } - _pico_set_color( color, 255, 255, 255, 255 ); - - for( j = 0; j < surface->numVerts; j++, texCoord++, mdcShort+=4 ) - { - /* set vertex origin */ - xyz[ 0 ] = MDC_SCALE * mdcShort[ 0 ]; - xyz[ 1 ] = MDC_SCALE * mdcShort[ 1 ]; - xyz[ 2 ] = MDC_SCALE * mdcShort[ 2 ]; - - /* add compressed ofsVec */ - if( surface->numCompFrames > 0 && *mdcCompVert >= 0 ) - { - xyz[ 0 ] += ((float) ((vertexComp->ofsVec) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; - xyz[ 1 ] += ((float) ((vertexComp->ofsVec >> 8) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; - xyz[ 2 ] += ((float) ((vertexComp->ofsVec >> 16) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; - PicoSetSurfaceXYZ( picoSurface, j, xyz ); - - normal[ 0 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 0 ]; - normal[ 1 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 1 ]; - normal[ 2 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 2 ]; - PicoSetSurfaceNormal( picoSurface, j, normal ); - - vertexComp++; - } - else - { - PicoSetSurfaceXYZ( picoSurface, j, xyz ); - - /* decode lat/lng normal to 3 float normal */ - lat = (float) ((*(mdcShort + 3) >> 8) & 0xff); - lng = (float) (*(mdcShort + 3) & 0xff); - lat *= PICO_PI / 128; - lng *= PICO_PI / 128; - normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); - normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); - normal[ 2 ] = (picoVec_t) cos( lng ); - PicoSetSurfaceNormal( picoSurface, j, normal ); - } - - /* set st coords */ - st[ 0 ] = texCoord->st[ 0 ]; - st[ 1 ] = texCoord->st[ 1 ]; - PicoSetSurfaceST( picoSurface, 0, j, st ); - - /* set color */ - PicoSetSurfaceColor( picoSurface, 0, j, color ); - } - - /* get next surface */ - surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); - } - - /* return the new pico model */ - return picoModel; -} - - - -/* pico file format module definition */ -const picoModule_t picoModuleMDC = -{ - "1.3", /* module version string */ - "RtCW MDC", /* module display name */ - "Arnout van Meer", /* author's name */ - "2002 Arnout van Meer", /* module copyright */ - { - "mdc", NULL, NULL, NULL /* default extensions to use */ - }, - _mdc_canload, /* validation routine */ - _mdc_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +Neither the names of the copyright holders nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MDC_C + + + +/* dependencies */ +#include "picointernal.h" + +/* mdc model format */ +#define MDC_MAGIC "IDPC" +#define MDC_VERSION 2 + +/* mdc vertex scale */ +#define MDC_SCALE (1.0f / 64.0f) +#define MDC_MAX_OFS 127.0f +#define MDC_DIST_SCALE 0.05f + +/* mdc decoding normal table */ +double mdcNormals[ 256 ][ 3 ] = +{ + { 1.000000, 0.000000, 0.000000 }, + { 0.980785, 0.195090, 0.000000 }, + { 0.923880, 0.382683, 0.000000 }, + { 0.831470, 0.555570, 0.000000 }, + { 0.707107, 0.707107, 0.000000 }, + { 0.555570, 0.831470, 0.000000 }, + { 0.382683, 0.923880, 0.000000 }, + { 0.195090, 0.980785, 0.000000 }, + { -0.000000, 1.000000, 0.000000 }, + { -0.195090, 0.980785, 0.000000 }, + { -0.382683, 0.923880, 0.000000 }, + { -0.555570, 0.831470, 0.000000 }, + { -0.707107, 0.707107, 0.000000 }, + { -0.831470, 0.555570, 0.000000 }, + { -0.923880, 0.382683, 0.000000 }, + { -0.980785, 0.195090, 0.000000 }, + { -1.000000, -0.000000, 0.000000 }, + { -0.980785, -0.195090, 0.000000 }, + { -0.923880, -0.382683, 0.000000 }, + { -0.831470, -0.555570, 0.000000 }, + { -0.707107, -0.707107, 0.000000 }, + { -0.555570, -0.831469, 0.000000 }, + { -0.382684, -0.923880, 0.000000 }, + { -0.195090, -0.980785, 0.000000 }, + { 0.000000, -1.000000, 0.000000 }, + { 0.195090, -0.980785, 0.000000 }, + { 0.382684, -0.923879, 0.000000 }, + { 0.555570, -0.831470, 0.000000 }, + { 0.707107, -0.707107, 0.000000 }, + { 0.831470, -0.555570, 0.000000 }, + { 0.923880, -0.382683, 0.000000 }, + { 0.980785, -0.195090, 0.000000 }, + { 0.980785, 0.000000, -0.195090 }, + { 0.956195, 0.218245, -0.195090 }, + { 0.883657, 0.425547, -0.195090 }, + { 0.766809, 0.611510, -0.195090 }, + { 0.611510, 0.766809, -0.195090 }, + { 0.425547, 0.883657, -0.195090 }, + { 0.218245, 0.956195, -0.195090 }, + { -0.000000, 0.980785, -0.195090 }, + { -0.218245, 0.956195, -0.195090 }, + { -0.425547, 0.883657, -0.195090 }, + { -0.611510, 0.766809, -0.195090 }, + { -0.766809, 0.611510, -0.195090 }, + { -0.883657, 0.425547, -0.195090 }, + { -0.956195, 0.218245, -0.195090 }, + { -0.980785, -0.000000, -0.195090 }, + { -0.956195, -0.218245, -0.195090 }, + { -0.883657, -0.425547, -0.195090 }, + { -0.766809, -0.611510, -0.195090 }, + { -0.611510, -0.766809, -0.195090 }, + { -0.425547, -0.883657, -0.195090 }, + { -0.218245, -0.956195, -0.195090 }, + { 0.000000, -0.980785, -0.195090 }, + { 0.218245, -0.956195, -0.195090 }, + { 0.425547, -0.883657, -0.195090 }, + { 0.611510, -0.766809, -0.195090 }, + { 0.766809, -0.611510, -0.195090 }, + { 0.883657, -0.425547, -0.195090 }, + { 0.956195, -0.218245, -0.195090 }, + { 0.923880, 0.000000, -0.382683 }, + { 0.892399, 0.239118, -0.382683 }, + { 0.800103, 0.461940, -0.382683 }, + { 0.653281, 0.653281, -0.382683 }, + { 0.461940, 0.800103, -0.382683 }, + { 0.239118, 0.892399, -0.382683 }, + { -0.000000, 0.923880, -0.382683 }, + { -0.239118, 0.892399, -0.382683 }, + { -0.461940, 0.800103, -0.382683 }, + { -0.653281, 0.653281, -0.382683 }, + { -0.800103, 0.461940, -0.382683 }, + { -0.892399, 0.239118, -0.382683 }, + { -0.923880, -0.000000, -0.382683 }, + { -0.892399, -0.239118, -0.382683 }, + { -0.800103, -0.461940, -0.382683 }, + { -0.653282, -0.653281, -0.382683 }, + { -0.461940, -0.800103, -0.382683 }, + { -0.239118, -0.892399, -0.382683 }, + { 0.000000, -0.923880, -0.382683 }, + { 0.239118, -0.892399, -0.382683 }, + { 0.461940, -0.800103, -0.382683 }, + { 0.653281, -0.653282, -0.382683 }, + { 0.800103, -0.461940, -0.382683 }, + { 0.892399, -0.239117, -0.382683 }, + { 0.831470, 0.000000, -0.555570 }, + { 0.790775, 0.256938, -0.555570 }, + { 0.672673, 0.488726, -0.555570 }, + { 0.488726, 0.672673, -0.555570 }, + { 0.256938, 0.790775, -0.555570 }, + { -0.000000, 0.831470, -0.555570 }, + { -0.256938, 0.790775, -0.555570 }, + { -0.488726, 0.672673, -0.555570 }, + { -0.672673, 0.488726, -0.555570 }, + { -0.790775, 0.256938, -0.555570 }, + { -0.831470, -0.000000, -0.555570 }, + { -0.790775, -0.256938, -0.555570 }, + { -0.672673, -0.488726, -0.555570 }, + { -0.488725, -0.672673, -0.555570 }, + { -0.256938, -0.790775, -0.555570 }, + { 0.000000, -0.831470, -0.555570 }, + { 0.256938, -0.790775, -0.555570 }, + { 0.488725, -0.672673, -0.555570 }, + { 0.672673, -0.488726, -0.555570 }, + { 0.790775, -0.256938, -0.555570 }, + { 0.707107, 0.000000, -0.707107 }, + { 0.653281, 0.270598, -0.707107 }, + { 0.500000, 0.500000, -0.707107 }, + { 0.270598, 0.653281, -0.707107 }, + { -0.000000, 0.707107, -0.707107 }, + { -0.270598, 0.653282, -0.707107 }, + { -0.500000, 0.500000, -0.707107 }, + { -0.653281, 0.270598, -0.707107 }, + { -0.707107, -0.000000, -0.707107 }, + { -0.653281, -0.270598, -0.707107 }, + { -0.500000, -0.500000, -0.707107 }, + { -0.270598, -0.653281, -0.707107 }, + { 0.000000, -0.707107, -0.707107 }, + { 0.270598, -0.653281, -0.707107 }, + { 0.500000, -0.500000, -0.707107 }, + { 0.653282, -0.270598, -0.707107 }, + { 0.555570, 0.000000, -0.831470 }, + { 0.481138, 0.277785, -0.831470 }, + { 0.277785, 0.481138, -0.831470 }, + { -0.000000, 0.555570, -0.831470 }, + { -0.277785, 0.481138, -0.831470 }, + { -0.481138, 0.277785, -0.831470 }, + { -0.555570, -0.000000, -0.831470 }, + { -0.481138, -0.277785, -0.831470 }, + { -0.277785, -0.481138, -0.831470 }, + { 0.000000, -0.555570, -0.831470 }, + { 0.277785, -0.481138, -0.831470 }, + { 0.481138, -0.277785, -0.831470 }, + { 0.382683, 0.000000, -0.923880 }, + { 0.270598, 0.270598, -0.923880 }, + { -0.000000, 0.382683, -0.923880 }, + { -0.270598, 0.270598, -0.923880 }, + { -0.382683, -0.000000, -0.923880 }, + { -0.270598, -0.270598, -0.923880 }, + { 0.000000, -0.382683, -0.923880 }, + { 0.270598, -0.270598, -0.923880 }, + { 0.195090, 0.000000, -0.980785 }, + { -0.000000, 0.195090, -0.980785 }, + { -0.195090, -0.000000, -0.980785 }, + { 0.000000, -0.195090, -0.980785 }, + { 0.980785, 0.000000, 0.195090 }, + { 0.956195, 0.218245, 0.195090 }, + { 0.883657, 0.425547, 0.195090 }, + { 0.766809, 0.611510, 0.195090 }, + { 0.611510, 0.766809, 0.195090 }, + { 0.425547, 0.883657, 0.195090 }, + { 0.218245, 0.956195, 0.195090 }, + { -0.000000, 0.980785, 0.195090 }, + { -0.218245, 0.956195, 0.195090 }, + { -0.425547, 0.883657, 0.195090 }, + { -0.611510, 0.766809, 0.195090 }, + { -0.766809, 0.611510, 0.195090 }, + { -0.883657, 0.425547, 0.195090 }, + { -0.956195, 0.218245, 0.195090 }, + { -0.980785, -0.000000, 0.195090 }, + { -0.956195, -0.218245, 0.195090 }, + { -0.883657, -0.425547, 0.195090 }, + { -0.766809, -0.611510, 0.195090 }, + { -0.611510, -0.766809, 0.195090 }, + { -0.425547, -0.883657, 0.195090 }, + { -0.218245, -0.956195, 0.195090 }, + { 0.000000, -0.980785, 0.195090 }, + { 0.218245, -0.956195, 0.195090 }, + { 0.425547, -0.883657, 0.195090 }, + { 0.611510, -0.766809, 0.195090 }, + { 0.766809, -0.611510, 0.195090 }, + { 0.883657, -0.425547, 0.195090 }, + { 0.956195, -0.218245, 0.195090 }, + { 0.923880, 0.000000, 0.382683 }, + { 0.892399, 0.239118, 0.382683 }, + { 0.800103, 0.461940, 0.382683 }, + { 0.653281, 0.653281, 0.382683 }, + { 0.461940, 0.800103, 0.382683 }, + { 0.239118, 0.892399, 0.382683 }, + { -0.000000, 0.923880, 0.382683 }, + { -0.239118, 0.892399, 0.382683 }, + { -0.461940, 0.800103, 0.382683 }, + { -0.653281, 0.653281, 0.382683 }, + { -0.800103, 0.461940, 0.382683 }, + { -0.892399, 0.239118, 0.382683 }, + { -0.923880, -0.000000, 0.382683 }, + { -0.892399, -0.239118, 0.382683 }, + { -0.800103, -0.461940, 0.382683 }, + { -0.653282, -0.653281, 0.382683 }, + { -0.461940, -0.800103, 0.382683 }, + { -0.239118, -0.892399, 0.382683 }, + { 0.000000, -0.923880, 0.382683 }, + { 0.239118, -0.892399, 0.382683 }, + { 0.461940, -0.800103, 0.382683 }, + { 0.653281, -0.653282, 0.382683 }, + { 0.800103, -0.461940, 0.382683 }, + { 0.892399, -0.239117, 0.382683 }, + { 0.831470, 0.000000, 0.555570 }, + { 0.790775, 0.256938, 0.555570 }, + { 0.672673, 0.488726, 0.555570 }, + { 0.488726, 0.672673, 0.555570 }, + { 0.256938, 0.790775, 0.555570 }, + { -0.000000, 0.831470, 0.555570 }, + { -0.256938, 0.790775, 0.555570 }, + { -0.488726, 0.672673, 0.555570 }, + { -0.672673, 0.488726, 0.555570 }, + { -0.790775, 0.256938, 0.555570 }, + { -0.831470, -0.000000, 0.555570 }, + { -0.790775, -0.256938, 0.555570 }, + { -0.672673, -0.488726, 0.555570 }, + { -0.488725, -0.672673, 0.555570 }, + { -0.256938, -0.790775, 0.555570 }, + { 0.000000, -0.831470, 0.555570 }, + { 0.256938, -0.790775, 0.555570 }, + { 0.488725, -0.672673, 0.555570 }, + { 0.672673, -0.488726, 0.555570 }, + { 0.790775, -0.256938, 0.555570 }, + { 0.707107, 0.000000, 0.707107 }, + { 0.653281, 0.270598, 0.707107 }, + { 0.500000, 0.500000, 0.707107 }, + { 0.270598, 0.653281, 0.707107 }, + { -0.000000, 0.707107, 0.707107 }, + { -0.270598, 0.653282, 0.707107 }, + { -0.500000, 0.500000, 0.707107 }, + { -0.653281, 0.270598, 0.707107 }, + { -0.707107, -0.000000, 0.707107 }, + { -0.653281, -0.270598, 0.707107 }, + { -0.500000, -0.500000, 0.707107 }, + { -0.270598, -0.653281, 0.707107 }, + { 0.000000, -0.707107, 0.707107 }, + { 0.270598, -0.653281, 0.707107 }, + { 0.500000, -0.500000, 0.707107 }, + { 0.653282, -0.270598, 0.707107 }, + { 0.555570, 0.000000, 0.831470 }, + { 0.481138, 0.277785, 0.831470 }, + { 0.277785, 0.481138, 0.831470 }, + { -0.000000, 0.555570, 0.831470 }, + { -0.277785, 0.481138, 0.831470 }, + { -0.481138, 0.277785, 0.831470 }, + { -0.555570, -0.000000, 0.831470 }, + { -0.481138, -0.277785, 0.831470 }, + { -0.277785, -0.481138, 0.831470 }, + { 0.000000, -0.555570, 0.831470 }, + { 0.277785, -0.481138, 0.831470 }, + { 0.481138, -0.277785, 0.831470 }, + { 0.382683, 0.000000, 0.923880 }, + { 0.270598, 0.270598, 0.923880 }, + { -0.000000, 0.382683, 0.923880 }, + { -0.270598, 0.270598, 0.923880 }, + { -0.382683, -0.000000, 0.923880 }, + { -0.270598, -0.270598, 0.923880 }, + { 0.000000, -0.382683, 0.923880 }, + { 0.270598, -0.270598, 0.923880 }, + { 0.195090, 0.000000, 0.980785 }, + { -0.000000, 0.195090, 0.980785 }, + { -0.195090, -0.000000, 0.980785 }, + { 0.000000, -0.195090, 0.980785 } +}; + +/* mdc model frame information */ +typedef struct mdcFrame_s +{ + float bounds[ 2 ][ 3 ]; + float localOrigin[ 3 ]; + float radius; + char creator[ 16 ]; +} +mdcFrame_t; + +/* mdc model tag information */ +typedef struct mdcTag_s +{ + short xyz[3]; + short angles[3]; +} +mdcTag_t; + +/* mdc surface mdc (one object mesh) */ +typedef struct mdcSurface_s +{ + char magic[ 4 ]; + char name[ 64 ]; /* polyset name */ + int flags; + int numCompFrames; /* all surfaces in a model should have the same */ + int numBaseFrames; /* ditto */ + int numShaders; /* all model surfaces should have the same */ + int numVerts; + int numTriangles; + int ofsTriangles; + int ofsShaders; /* offset from start of mdcSurface_t */ + int ofsSt; /* texture coords are common for all frames */ + int ofsXyzNormals; /* numVerts * numBaseFrames */ + int ofsXyzCompressed; /* numVerts * numCompFrames */ + + int ofsFrameBaseFrames; /* numFrames */ + int ofsFrameCompFrames; /* numFrames */ + int ofsEnd; /* next surface follows */ +} +mdcSurface_t; + +typedef struct mdcShader_s +{ + char name[ 64 ]; + int shaderIndex; /* for ingame use */ +} +mdcShader_t; + +typedef struct mdcTriangle_s +{ + int indexes[ 3 ]; +} +mdcTriangle_t; + +typedef struct mdcTexCoord_s +{ + float st[ 2 ]; +} +mdcTexCoord_t; + +typedef struct mdcVertex_s +{ + short xyz[ 3 ]; + short normal; +} +mdcVertex_t; + +typedef struct mdcXyzCompressed_s +{ + unsigned int ofsVec; /* offset direction from the last base frame */ +} +mdcXyzCompressed_t; + + +/* mdc model file mdc structure */ +typedef struct mdc_s +{ + char magic[ 4 ]; /* MDC_MAGIC */ + int version; + char name[ 64 ]; /* model name */ + int flags; + int numFrames; + int numTags; + int numSurfaces; + int numSkins; /* number of skins for the mesh */ + int ofsFrames; /* offset for first frame */ + int ofsTagNames; /* numTags */ + int ofsTags; /* numFrames * numTags */ + int ofsSurfaces; /* first surface, others follow */ + int ofsEnd; /* end of file */ +} +mdc_t; + + + + +/* +_mdc_canload() +validates a Return to Castle Wolfenstein model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ + +static int _mdc_canload( PM_PARAMS_CANLOAD ) +{ + mdc_t *mdc; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *mdc ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as mdc */ + mdc = (mdc_t*) buffer; + + /* check mdc magic */ + if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check mdc version */ + if( _pico_little_long( mdc->version ) != MDC_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid mdc */ + return PICO_PMV_OK; +} + + + +/* +_mdc_load() +loads a Return to Castle Wolfenstein mdc model file. +*/ + +static picoModel_t *_mdc_load( PM_PARAMS_LOAD ) +{ + int i, j; + picoByte_t *bb; + mdc_t *mdc; + mdcSurface_t *surface; + mdcShader_t *shader; + mdcTexCoord_t *texCoord; + mdcFrame_t *frame; + mdcTriangle_t *triangle; + mdcVertex_t *vertex; + mdcXyzCompressed_t *vertexComp; + short *mdcShort, *mdcCompVert; + double lat, lng; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + /* ------------------------------------------------- + mdc loading + ------------------------------------------------- */ + + + /* set as mdc */ + bb = (picoByte_t*) buffer; + mdc = (mdc_t*) buffer; + + /* check ident and version */ + if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) || _pico_little_long( mdc->version ) != MDC_VERSION ) + { + /* not an mdc file (todo: set error) */ + return NULL; + } + + /* swap mdc */ + mdc->version = _pico_little_long( mdc->version ); + mdc->numFrames = _pico_little_long( mdc->numFrames ); + mdc->numTags = _pico_little_long( mdc->numTags ); + mdc->numSurfaces = _pico_little_long( mdc->numSurfaces ); + mdc->numSkins = _pico_little_long( mdc->numSkins ); + mdc->ofsFrames = _pico_little_long( mdc->ofsFrames ); + mdc->ofsTags = _pico_little_long( mdc->ofsTags ); + mdc->ofsTagNames = _pico_little_long( mdc->ofsTagNames ); + mdc->ofsSurfaces = _pico_little_long( mdc->ofsSurfaces ); + mdc->ofsEnd = _pico_little_long( mdc->ofsEnd ); + + /* do frame check */ + if( mdc->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "MDC with 0 frames" ); + return NULL; + } + + if( frameNum < 0 || frameNum >= mdc->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MDC frame specified" ); + return NULL; + } + + /* swap frames */ + frame = (mdcFrame_t*) (bb + mdc->ofsFrames ); + for( i = 0; i < mdc->numFrames; i++, frame++ ) + { + frame->radius = _pico_little_float( frame->radius ); + for( j = 0; j < 3; j++ ) + { + frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); + frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); + frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); + } + } + + /* swap surfaces */ + surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); + for( i = 0; i < mdc->numSurfaces; i++ ) + { + /* swap surface mdc */ + surface->flags = _pico_little_long( surface->flags ); + surface->numBaseFrames = _pico_little_long( surface->numBaseFrames ); + surface->numCompFrames = _pico_little_long( surface->numCompFrames ); + surface->numShaders = _pico_little_long( surface->numShaders ); + surface->numTriangles = _pico_little_long( surface->numTriangles ); + surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); + surface->numVerts = _pico_little_long( surface->numVerts ); + surface->ofsShaders = _pico_little_long( surface->ofsShaders ); + surface->ofsSt = _pico_little_long( surface->ofsSt ); + surface->ofsXyzNormals = _pico_little_long( surface->ofsXyzNormals ); + surface->ofsXyzCompressed = _pico_little_long( surface->ofsXyzCompressed ); + surface->ofsFrameBaseFrames = _pico_little_long( surface->ofsFrameBaseFrames ); + surface->ofsFrameCompFrames = _pico_little_long( surface->ofsFrameCompFrames ); + surface->ofsEnd = _pico_little_long( surface->ofsEnd ); + + /* swap triangles */ + triangle = (mdcTriangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + /* sea: swaps fixed */ + triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); + triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); + triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); + } + + /* swap st coords */ + texCoord = (mdcTexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); + for( j = 0; j < surface->numVerts; j++, texCoord++ ) + { + texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); + texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); + } + + /* swap xyz/normals */ + vertex = (mdcVertex_t*) ((picoByte_t*) surface + surface->ofsXyzNormals); + for( j = 0; j < (surface->numVerts * surface->numBaseFrames); j++, vertex++) + { + vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); + vertex->normal = _pico_little_short( vertex->normal ); + } + + /* swap xyz/compressed */ + vertexComp = (mdcXyzCompressed_t*) ((picoByte_t*) surface + surface->ofsXyzCompressed); + for( j = 0; j < (surface->numVerts * surface->numCompFrames); j++, vertexComp++) + { + vertexComp->ofsVec = _pico_little_long( vertexComp->ofsVec ); + } + + /* swap base frames */ + mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameBaseFrames); + for( j = 0; j < mdc->numFrames; j++, mdcShort++) + { + *mdcShort = _pico_little_short( *mdcShort ); + } + + /* swap compressed frames */ + mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameCompFrames); + for( j = 0; j < mdc->numFrames; j++, mdcShort++) + { + *mdcShort = _pico_little_short( *mdcShort ); + } + + /* get next surface */ + surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, mdc->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* mdc surfaces become picomodel surfaces */ + surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); + + /* run through mdc surfaces */ + for( i = 0; i < mdc->numSurfaces; i++ ) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); /* sea */ + return NULL; + } + + /* mdc model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader -sea */ + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + /* detox and set shader name */ + shader = (mdcShader_t*) ((picoByte_t*) surface + surface->ofsShaders); + _pico_setfext( shader->name, "" ); + _pico_unixify( shader->name ); + PicoSetShaderName( picoShader, shader->name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indexes */ + triangle = (mdcTriangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); + + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); + } + + /* copy vertexes */ + texCoord = (mdcTexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); + mdcShort = (short *) ((picoByte_t *) surface + surface->ofsXyzNormals) + ((int)*((short *) ((picoByte_t *) surface + surface->ofsFrameBaseFrames) + frameNum) * surface->numVerts * 4); + if( surface->numCompFrames > 0 ) + { + mdcCompVert = (short *) ((picoByte_t *) surface + surface->ofsFrameCompFrames) + frameNum; + if( *mdcCompVert >= 0 ) + vertexComp = (mdcXyzCompressed_t *) ((picoByte_t *) surface + surface->ofsXyzCompressed) + (*mdcCompVert * surface->numVerts); + } + _pico_set_color( color, 255, 255, 255, 255 ); + + for( j = 0; j < surface->numVerts; j++, texCoord++, mdcShort+=4 ) + { + /* set vertex origin */ + xyz[ 0 ] = MDC_SCALE * mdcShort[ 0 ]; + xyz[ 1 ] = MDC_SCALE * mdcShort[ 1 ]; + xyz[ 2 ] = MDC_SCALE * mdcShort[ 2 ]; + + /* add compressed ofsVec */ + if( surface->numCompFrames > 0 && *mdcCompVert >= 0 ) + { + xyz[ 0 ] += ((float) ((vertexComp->ofsVec) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + xyz[ 1 ] += ((float) ((vertexComp->ofsVec >> 8) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + xyz[ 2 ] += ((float) ((vertexComp->ofsVec >> 16) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + normal[ 0 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 0 ]; + normal[ 1 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 1 ]; + normal[ 2 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 2 ]; + PicoSetSurfaceNormal( picoSurface, j, normal ); + + vertexComp++; + } + else + { + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + /* decode lat/lng normal to 3 float normal */ + lat = (float) ((*(mdcShort + 3) >> 8) & 0xff); + lng = (float) (*(mdcShort + 3) & 0xff); + lat *= PICO_PI / 128; + lng *= PICO_PI / 128; + normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); + normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); + normal[ 2 ] = (picoVec_t) cos( lng ); + PicoSetSurfaceNormal( picoSurface, j, normal ); + } + + /* set st coords */ + st[ 0 ] = texCoord->st[ 0 ]; + st[ 1 ] = texCoord->st[ 1 ]; + PicoSetSurfaceST( picoSurface, 0, j, st ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, j, color ); + } + + /* get next surface */ + surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* return the new pico model */ + return picoModel; +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMDC = +{ + "1.3", /* module version string */ + "RtCW MDC", /* module display name */ + "Arnout van Meer", /* author's name */ + "2002 Arnout van Meer", /* module copyright */ + { + "mdc", NULL, NULL, NULL /* default extensions to use */ + }, + _mdc_canload, /* validation routine */ + _mdc_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_ms3d.c b/libs/picomodel/pm_ms3d.c index 4bbd9b38..27147bc0 100644 --- a/libs/picomodel/pm_ms3d.c +++ b/libs/picomodel/pm_ms3d.c @@ -1,494 +1,494 @@ -/* ----------------------------------------------------------------------------- - -PicoModel Library - -Copyright (c) 2002, Randy Reddig & seaw0lf -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this list -of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, this -list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -Neither the names of the copyright holders nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------ */ - - - -/* marker */ -#define PM_MS3D_C - -/* dependencies */ -#include "picointernal.h" - -/* disable warnings */ -#ifdef _WIN32 -#pragma warning( disable:4100 ) /* unref param */ -#endif - -/* remarks: - * - loader seems stable - * todo: - * - fix uv coordinate problem - * - check for buffer overflows ('bufptr' accesses) - */ -/* uncomment when debugging this module */ - #define DEBUG_PM_MS3D - #define DEBUG_PM_MS3D_EX - -/* plain white */ -static picoColor_t white = { 255,255,255,255 }; - -/* ms3d limits */ -#define MS3D_MAX_VERTS 8192 -#define MS3D_MAX_TRIS 16384 -#define MS3D_MAX_GROUPS 128 -#define MS3D_MAX_MATERIALS 128 -#define MS3D_MAX_JOINTS 128 -#define MS3D_MAX_KEYFRAMES 216 - -/* ms3d flags */ -#define MS3D_SELECTED 1 -#define MS3D_HIDDEN 2 -#define MS3D_SELECTED2 4 -#define MS3D_DIRTY 8 - -/* this freaky loader needs byte alignment */ -#pragma pack(push, 1) - -/* ms3d header */ -typedef struct SMsHeader -{ - char magic[10]; - int version; -} -TMsHeader; - -/* ms3d vertex */ -typedef struct SMsVertex -{ - unsigned char flags; /* sel, sel2, or hidden */ - float xyz[3]; - char boneID; /* -1 means 'no bone' */ - unsigned char refCount; -} -TMsVertex; - -/* ms3d triangle */ -typedef struct SMsTriangle -{ - unsigned short flags; /* sel, sel2, or hidden */ - unsigned short vertexIndices[3]; - float vertexNormals[3][3]; - float s[3]; - float t[3]; - unsigned char smoothingGroup; /* 1 - 32 */ - unsigned char groupIndex; -} -TMsTriangle; - -/* ms3d material */ -typedef struct SMsMaterial -{ - char name[32]; - float ambient[4]; - float diffuse[4]; - float specular[4]; - float emissive[4]; - float shininess; /* range 0..128 */ - float transparency; /* range 0..1 */ - unsigned char mode; - char texture [128]; /* texture.bmp */ - char alphamap[128]; /* alpha.bmp */ -} -TMsMaterial; - -// ms3d group (static part) -// followed by a variable size block (see below) -typedef struct SMsGroup -{ - unsigned char flags; // sel, hidden - char name[32]; - unsigned short numTriangles; -/* - unsigned short triangleIndices[ numTriangles ]; - char materialIndex; // -1 means 'no material' -*/ -} -TMsGroup; - -// ms3d joint -typedef struct SMsJoint -{ - unsigned char flags; - char name[32]; - char parentName[32]; - float rotation[3]; - float translation[3]; - unsigned short numRotationKeyframes; - unsigned short numTranslationKeyframes; -} -TMsJoint; - -// ms3d keyframe -typedef struct SMsKeyframe -{ - float time; - float parameter[3]; -} -TMsKeyframe; - -/* restore previous data alignment */ -#pragma pack(pop) - -/* _ms3d_canload: - * validates a milkshape3d model file. - */ -static int _ms3d_canload( PM_PARAMS_CANLOAD ) -{ - TMsHeader *hdr; - - - /* to keep the compiler happy */ - *fileName = *fileName; - - /* sanity check */ - if (bufSize < sizeof(TMsHeader)) - return PICO_PMV_ERROR_SIZE; - - /* get ms3d header */ - hdr = (TMsHeader *)buffer; - - /* check ms3d magic */ - if (strncmp(hdr->magic,"MS3D000000",10) != 0) - return PICO_PMV_ERROR_IDENT; - - /* check ms3d version */ - if (_pico_little_long(hdr->version) < 3 || - _pico_little_long(hdr->version) > 4) - { - _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." ); - return PICO_PMV_ERROR_VERSION; - } - /* file seems to be a valid ms3d */ - return PICO_PMV_OK; -} - -static unsigned char *GetWord( unsigned char *bufptr, int *out ) -{ - if (bufptr == NULL) return NULL; - *out = _pico_little_short( *(unsigned short *)bufptr ); - return( bufptr + 2 ); -} - -/* _ms3d_load: - * loads a milkshape3d model file. -*/ -static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ) -{ - picoModel_t *model; - unsigned char *bufptr; - int shaderRefs[ MS3D_MAX_GROUPS ]; - int numGroups; - int numMaterials; -// unsigned char *ptrToGroups; - int numVerts; - unsigned char *ptrToVerts; - int numTris; - unsigned char *ptrToTris; - int i,k,m; - - /* create new pico model */ - model = PicoNewModel(); - if (model == NULL) return NULL; - - /* do model setup */ - PicoSetModelFrameNum( model, frameNum ); - PicoSetModelName( model, fileName ); - PicoSetModelFileName( model, fileName ); - - /* skip header */ - bufptr = (unsigned char *)buffer + sizeof(TMsHeader); - - /* get number of vertices */ - bufptr = GetWord( bufptr,&numVerts ); - ptrToVerts = bufptr; - -#ifdef DEBUG_PM_MS3D - printf("NumVertices: %d\n",numVerts); -#endif - /* swap verts */ - for (i=0; ixyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] ); - vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] ); - vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] ); - -#ifdef DEBUG_PM_MS3D_EX_ - printf("Vertex: x: %f y: %f z: %f\n", - msvd[i]->vertex[0], - msvd[i]->vertex[1], - msvd[i]->vertex[2]); -#endif - } - /* get number of triangles */ - bufptr = GetWord( bufptr,&numTris ); - ptrToTris = bufptr; - -#ifdef DEBUG_PM_MS3D - printf("NumTriangles: %d\n",numTris); -#endif - /* swap tris */ - for (i=0; iflags = _pico_little_short( triangle->flags ); - - /* run through all tri verts */ - for (k=0; k<3; k++) - { - /* swap tex coords */ - triangle->s[ k ] = _pico_little_float( triangle->s[ k ] ); - triangle->t[ k ] = _pico_little_float( triangle->t[ k ] ); - - /* swap fields */ - triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] ); - triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] ); - triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] ); - triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] ); - - /* check for out of range indices */ - if (triangle->vertexIndices[ k ] >= numVerts) - { - _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts-1); - PicoFreeModel( model ); - return NULL; /* yuck */ - } - } - } - /* get number of groups */ - bufptr = GetWord( bufptr,&numGroups ); -// ptrToGroups = bufptr; - -#ifdef DEBUG_PM_MS3D - printf("NumGroups: %d\n",numGroups); -#endif - /* run through all groups in model */ - for (i=0; i