Add auto uv unwrapping.
Use https://github.com/Thekla/thekla_atlas to generate the texture. This commit still have some issues, some faces not satisfy thekla_atlas in some cases. - Add texture preview widget. - Fix single node black color issue. - Export texture in .gltf file. - Fix node order random issue in mesh generation.master
parent
dff57427a4
commit
1376af237b
|
@ -446,3 +446,55 @@ https://www.reddit.com/r/gamedev/comments/5iuf3h/i_am_writting_a_3d_monster_mode
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<h1>thekla_atlas</h1>
|
||||||
|
<pre>
|
||||||
|
Copyright (c) 2013 Thekla, Inc
|
||||||
|
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h1>nvmesh</h1>
|
||||||
|
<pre>
|
||||||
|
public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h1>poshlib</h1>
|
||||||
|
<pre>
|
||||||
|
Copyright (c) 2004, Brian Hook
|
||||||
|
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.
|
||||||
|
|
||||||
|
* The names of this package'ss contributors contributors may not
|
||||||
|
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.
|
||||||
|
</pre>
|
||||||
|
|
|
@ -7,7 +7,7 @@ The core mesh algorithms of Dust3D written in Rust language, located in meshlite
|
||||||
|
|
||||||
https://github.com/huxingyi/meshlite
|
https://github.com/huxingyi/meshlite
|
||||||
|
|
||||||
The UI of Dust3D built in Qt5, the only thirdparty dependency is CGAL library, however, CGAL will introduce some new dependencies, such as boost and gmp library.
|
The UI of Dust3D built in Qt5, the only thirdparty dependency which should been compiled separately is the CGAL library, however, CGAL will introduce some new dependencies, such as boost and gmp library.
|
||||||
|
|
||||||
Prerequisites
|
Prerequisites
|
||||||
===============
|
===============
|
||||||
|
|
|
@ -31,9 +31,8 @@ Save all openned window.
|
||||||
Export...
|
Export...
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
If you want mesh only result, export as Wavefront (.obj) format.
|
If you want mesh only result, export as Wavefront (.obj) format.
|
||||||
Choose GL Transmission Format (.gltf) to export all results in one gltf file, the results including autogenerated Meshes, Skeleton, and Materials.
|
Choose GL Transmission Format (.gltf) to export all results in one gltf file, the results including autogenerated Meshes, Skeleton, and Texture.
|
||||||
Because .gltf is a very new format, not every 3D software officially supports it, and there are some plugins for blender to support gltf export and import, but mostly are buggy at current stage.
|
Because .gltf is a very new format, not every 3D software officially supports it, you can use Don McCurdy's online website, glTF Viewer https://gltf-viewer.donmccurdy.com/ to check your exported result, make sure you drag the folder which including the .gltf file and .png texture file into the website.
|
||||||
You can use Don McCurdy's online website, glTF Viewer https://gltf-viewer.donmccurdy.com/ to check your exported result.
|
|
||||||
|
|
||||||
Change Turnaround...
|
Change Turnaround...
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -114,6 +113,11 @@ Toggle Bones
|
||||||
The skeleton would also been autogenerated after meshes got generated.
|
The skeleton would also been autogenerated after meshes got generated.
|
||||||
Toggle this item to show or hide the Rendered Skeleton from canvas.
|
Toggle this item to show or hide the Rendered Skeleton from canvas.
|
||||||
|
|
||||||
|
Show Texture
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
The texture would also been autogenerated after meshes got generated.
|
||||||
|
Click the recycle button in the up-left corner to regenerate if the texture is not good.
|
||||||
|
|
||||||
Show Parts List
|
Show Parts List
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
The Parts List Panel is a tool window, if you closed it by accident, you can show it back here.
|
The Parts List Panel is a tool window, if you closed it by accident, you can show it back here.
|
||||||
|
|
185
dust3d.pro
185
dust3d.pro
|
@ -59,8 +59,8 @@ HEADERS += src/aboutwidget.h
|
||||||
SOURCES += src/meshgenerator.cpp
|
SOURCES += src/meshgenerator.cpp
|
||||||
HEADERS += src/meshgenerator.h
|
HEADERS += src/meshgenerator.h
|
||||||
|
|
||||||
SOURCES += src/util.cpp
|
SOURCES += src/dust3dutil.cpp
|
||||||
HEADERS += src/util.h
|
HEADERS += src/dust3dutil.h
|
||||||
|
|
||||||
SOURCES += src/turnaroundloader.cpp
|
SOURCES += src/turnaroundloader.cpp
|
||||||
HEADERS += src/turnaroundloader.h
|
HEADERS += src/turnaroundloader.h
|
||||||
|
@ -86,8 +86,8 @@ HEADERS += src/mesh.h
|
||||||
SOURCES += src/meshutil.cpp
|
SOURCES += src/meshutil.cpp
|
||||||
HEADERS += src/meshutil.h
|
HEADERS += src/meshutil.h
|
||||||
|
|
||||||
SOURCES += src/uvunwrapper.cpp
|
SOURCES += src/texturegenerator.cpp
|
||||||
HEADERS += src/uvunwrapper.h
|
HEADERS += src/texturegenerator.h
|
||||||
|
|
||||||
SOURCES += src/skeletongenerator.cpp
|
SOURCES += src/skeletongenerator.cpp
|
||||||
HEADERS += src/skeletongenerator.h
|
HEADERS += src/skeletongenerator.h
|
||||||
|
@ -95,6 +95,9 @@ HEADERS += src/skeletongenerator.h
|
||||||
SOURCES += src/meshresultcontext.cpp
|
SOURCES += src/meshresultcontext.cpp
|
||||||
HEADERS += src/meshresultcontext.h
|
HEADERS += src/meshresultcontext.h
|
||||||
|
|
||||||
|
SOURCES += src/meshresultpostprocessor.cpp
|
||||||
|
HEADERS += src/meshresultpostprocessor.h
|
||||||
|
|
||||||
SOURCES += src/positionmap.cpp
|
SOURCES += src/positionmap.cpp
|
||||||
HEADERS += src/positionmap.h
|
HEADERS += src/positionmap.h
|
||||||
|
|
||||||
|
@ -107,6 +110,9 @@ HEADERS += src/logbrowserdialog.h
|
||||||
SOURCES += src/floatnumberwidget.cpp
|
SOURCES += src/floatnumberwidget.cpp
|
||||||
HEADERS += src/floatnumberwidget.h
|
HEADERS += src/floatnumberwidget.h
|
||||||
|
|
||||||
|
SOURCES += src/textureguidewidget.cpp
|
||||||
|
HEADERS += src/textureguidewidget.h
|
||||||
|
|
||||||
SOURCES += src/main.cpp
|
SOURCES += src/main.cpp
|
||||||
|
|
||||||
HEADERS += src/version.h
|
HEADERS += src/version.h
|
||||||
|
@ -181,6 +187,177 @@ unix:!macx {
|
||||||
|
|
||||||
INCLUDEPATH += thirdparty/json
|
INCLUDEPATH += thirdparty/json
|
||||||
|
|
||||||
|
INCLUDEPATH += thirdparty/thekla_atlas/src
|
||||||
|
INCLUDEPATH += thirdparty/thekla_atlas/extern/poshlib
|
||||||
|
INCLUDEPATH += thirdparty/thekla_atlas/src/nvmesh
|
||||||
|
INCLUDEPATH += thirdparty/thekla_atlas/src/nvmesh/param
|
||||||
|
INCLUDEPATH += thirdparty/thekla_atlas/src/nvcore
|
||||||
|
INCLUDEPATH += thirdparty/thekla_atlas/src/nvimage
|
||||||
|
INCLUDEPATH += thirdparty/thekla_atlas/src/nvmath
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/extern/poshlib/posh.c
|
||||||
|
HEADERS += thirdparty/thekla_atlas/extern/poshlib/posh.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/thekla/thekla_atlas.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/thekla/thekla_atlas.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/Stream.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvcore/Debug.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/Debug.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/StdStream.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvcore/StrLib.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/StrLib.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/Utils.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvcore/Array.inl
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/Array.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvcore/Memory.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/Memory.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvcore/RadixSort.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/RadixSort.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvcore/HashMap.inl
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/HashMap.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/Hash.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvcore/ForEach.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/nvmesh.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/nvmesh.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/BaseMesh.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/BaseMesh.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/MeshBuilder.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/MeshBuilder.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/TriMesh.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/TriMesh.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/QuadTriMesh.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/QuadTriMesh.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/MeshTopology.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/MeshTopology.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/halfedge/Edge.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/halfedge/Edge.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/halfedge/Mesh.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/halfedge/Mesh.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/halfedge/Face.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/halfedge/Face.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/halfedge/Vertex.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/halfedge/Vertex.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/geometry/Bounds.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/geometry/Bounds.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/geometry/Measurements.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/geometry/Measurements.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/raster/Raster.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/raster/raster.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/raster/ClippedTriangle.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/Atlas.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/Atlas.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/AtlasBuilder.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/AtlasBuilder.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/AtlasPacker.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/AtlasPacker.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/ConformalMap.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/ConformalMap.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/LeastSquaresConformalMap.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/LeastSquaresConformalMap.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/OrthogonalProjectionMap.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/OrthogonalProjectionMap.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/ParameterizationQuality.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/ParameterizationQuality.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/SingleFaceMap.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/SingleFaceMap.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/param/Util.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/param/Util.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/weld/VertexWeld.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/weld/VertexWeld.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/weld/Weld.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmesh/weld/Snap.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmesh/weld/Snap.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvimage/Image.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvimage/Image.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvimage/BitMap.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvimage/BitMap.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvimage/nvimage.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Basis.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Basis.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Box.inl
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Box.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Box.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Color.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/ConvexHull.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/ConvexHull.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Fitting.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Fitting.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/KahanSum.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Matrix.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Plane.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Plane.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/ProximityGrid.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/ProximityGrid.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Quaternion.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Random.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Random.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Solver.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Solver.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Sparse.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Sparse.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/TypeSerialization.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/TypeSerialization.h
|
||||||
|
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Vector.inl
|
||||||
|
SOURCES += thirdparty/thekla_atlas/src/nvmath/Vector.cpp
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/Vector.h
|
||||||
|
|
||||||
|
HEADERS += thirdparty/thekla_atlas/src/nvmath/ftoi.h
|
||||||
|
|
||||||
INCLUDEPATH += $$MESHLITE_DIR
|
INCLUDEPATH += $$MESHLITE_DIR
|
||||||
LIBS += -L$$MESHLITE_DIR -l$$MESHLITE_LIBNAME
|
LIBS += -L$$MESHLITE_DIR -l$$MESHLITE_LIBNAME
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "util.h"
|
#include "dust3dutil.h"
|
||||||
|
|
||||||
QString valueOfKeyInMapOrEmpty(const std::map<QString, QString> &map, const QString &key)
|
QString valueOfKeyInMapOrEmpty(const std::map<QString, QString> &map, const QString &key)
|
||||||
{
|
{
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef UTIL_H
|
#ifndef DUST3D_UTIL_H
|
||||||
#define UTIL_H
|
#define DUST3D_UTIL_H
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cmath>
|
#include <cmath>
|
|
@ -2,6 +2,8 @@
|
||||||
#include <QQuaternion>
|
#include <QQuaternion>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
#include "gltffile.h"
|
#include "gltffile.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -15,7 +17,8 @@
|
||||||
// http://quaternions.online/
|
// http://quaternions.online/
|
||||||
// https://en.m.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions?wprov=sfla1
|
// https://en.m.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions?wprov=sfla1
|
||||||
|
|
||||||
GLTFFileWriter::GLTFFileWriter(MeshResultContext &resultContext)
|
GLTFFileWriter::GLTFFileWriter(MeshResultContext &resultContext, const QString &filename) :
|
||||||
|
m_filename(filename)
|
||||||
{
|
{
|
||||||
const BmeshNode *rootNode = resultContext.centerBmeshNode();
|
const BmeshNode *rootNode = resultContext.centerBmeshNode();
|
||||||
if (!rootNode) {
|
if (!rootNode) {
|
||||||
|
@ -23,6 +26,10 @@ GLTFFileWriter::GLTFFileWriter(MeshResultContext &resultContext)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFileInfo nameInfo(filename);
|
||||||
|
QString textureFilenameWithoutPath = nameInfo.completeBaseName() + ".png";
|
||||||
|
m_textureFilename = nameInfo.path() + QDir::separator() + textureFilenameWithoutPath;
|
||||||
|
|
||||||
JointInfo rootHandleJoint;
|
JointInfo rootHandleJoint;
|
||||||
{
|
{
|
||||||
rootHandleJoint.jointIndex = m_tracedJoints.size();
|
rootHandleJoint.jointIndex = m_tracedJoints.size();
|
||||||
|
@ -118,22 +125,34 @@ GLTFFileWriter::GLTFFileWriter(MeshResultContext &resultContext)
|
||||||
alignBinaries();
|
alignBinaries();
|
||||||
bufferViewIndex++;
|
bufferViewIndex++;
|
||||||
|
|
||||||
|
m_json["textures"][0]["sampler"] = 0;
|
||||||
|
m_json["textures"][0]["source"] = 0;
|
||||||
|
|
||||||
|
m_json["images"][0]["uri"] = textureFilenameWithoutPath.toUtf8().constData();
|
||||||
|
|
||||||
|
m_json["samplers"][0]["magFilter"] = 9729;
|
||||||
|
m_json["samplers"][0]["minFilter"] = 9987;
|
||||||
|
m_json["samplers"][0]["wrapS"] = 33648;
|
||||||
|
m_json["samplers"][0]["wrapT"] = 33648;
|
||||||
|
|
||||||
int primitiveIndex = 0;
|
int primitiveIndex = 0;
|
||||||
for (const auto &part: resultContext.resultParts()) {
|
for (const auto &part: resultContext.parts()) {
|
||||||
int bufferViewFromOffset;
|
int bufferViewFromOffset;
|
||||||
|
|
||||||
m_json["meshes"][0]["primitives"][primitiveIndex]["indices"] = bufferViewIndex;
|
m_json["meshes"][0]["primitives"][primitiveIndex]["indices"] = bufferViewIndex;
|
||||||
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["POSITION"] = bufferViewIndex + 1;
|
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["POSITION"] = bufferViewIndex + 1;
|
||||||
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["JOINTS_0"] = bufferViewIndex + 2;
|
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["JOINTS_0"] = bufferViewIndex + 2;
|
||||||
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["WEIGHTS_0"] = bufferViewIndex + 3;
|
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["WEIGHTS_0"] = bufferViewIndex + 3;
|
||||||
|
m_json["meshes"][0]["primitives"][primitiveIndex]["attributes"]["TEXCOORD_0"] = bufferViewIndex + 4;
|
||||||
m_json["meshes"][0]["primitives"][primitiveIndex]["material"] = primitiveIndex;
|
m_json["meshes"][0]["primitives"][primitiveIndex]["material"] = primitiveIndex;
|
||||||
|
/*
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorFactor"] = {
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorFactor"] = {
|
||||||
part.second.color.redF(),
|
part.second.color.redF(),
|
||||||
part.second.color.greenF(),
|
part.second.color.greenF(),
|
||||||
part.second.color.blueF(),
|
part.second.color.blueF(),
|
||||||
1.0
|
1.0
|
||||||
};
|
};*/
|
||||||
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["baseColorTexture"]["index"] = 0;
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = 0.0;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["metallicFactor"] = 0.0;
|
||||||
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = 1.0;
|
m_json["materials"][primitiveIndex]["pbrMetallicRoughness"]["roughnessFactor"] = 1.0;
|
||||||
|
|
||||||
|
@ -235,12 +254,32 @@ GLTFFileWriter::GLTFFileWriter(MeshResultContext &resultContext)
|
||||||
m_json["accessors"][bufferViewIndex]["count"] = part.second.weights.size();
|
m_json["accessors"][bufferViewIndex]["count"] = part.second.weights.size();
|
||||||
m_json["accessors"][bufferViewIndex]["type"] = "VEC4";
|
m_json["accessors"][bufferViewIndex]["type"] = "VEC4";
|
||||||
bufferViewIndex++;
|
bufferViewIndex++;
|
||||||
|
|
||||||
|
bufferViewFromOffset = (int)binaries.size();
|
||||||
|
m_json["bufferViews"][bufferViewIndex]["buffer"] = 0;
|
||||||
|
m_json["bufferViews"][bufferViewIndex]["byteOffset"] = bufferViewFromOffset;
|
||||||
|
for (const auto &it: part.second.vertexUvs) {
|
||||||
|
stream << (float)it.uv[0] << (float)it.uv[1];
|
||||||
|
}
|
||||||
|
m_json["bufferViews"][bufferViewIndex]["byteLength"] = binaries.size() - bufferViewFromOffset;
|
||||||
|
alignBinaries();
|
||||||
|
m_json["accessors"][bufferViewIndex]["bufferView"] = bufferViewIndex;
|
||||||
|
m_json["accessors"][bufferViewIndex]["byteOffset"] = 0;
|
||||||
|
m_json["accessors"][bufferViewIndex]["componentType"] = 5126;
|
||||||
|
m_json["accessors"][bufferViewIndex]["count"] = part.second.vertexUvs.size();
|
||||||
|
m_json["accessors"][bufferViewIndex]["type"] = "VEC2";
|
||||||
|
bufferViewIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_json["buffers"][0]["uri"] = QString("data:application/octet-stream;base64," + binaries.toBase64()).toUtf8().constData();
|
m_json["buffers"][0]["uri"] = QString("data:application/octet-stream;base64," + binaries.toBase64()).toUtf8().constData();
|
||||||
m_json["buffers"][0]["byteLength"] = binaries.size();
|
m_json["buffers"][0]["byteLength"] = binaries.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString &GLTFFileWriter::textureFilenameInGltf()
|
||||||
|
{
|
||||||
|
return m_textureFilename;
|
||||||
|
}
|
||||||
|
|
||||||
void GLTFFileWriter::traceBoneFromJoint(MeshResultContext &resultContext, std::pair<int, int> node, std::set<std::pair<int, int>> &visitedNodes, std::set<std::pair<std::pair<int, int>, std::pair<int, int>>> &connections, int parentIndex)
|
void GLTFFileWriter::traceBoneFromJoint(MeshResultContext &resultContext, std::pair<int, int> node, std::set<std::pair<int, int>> &visitedNodes, std::set<std::pair<std::pair<int, int>, std::pair<int, int>>> &connections, int parentIndex)
|
||||||
{
|
{
|
||||||
if (visitedNodes.find(node) != visitedNodes.end())
|
if (visitedNodes.find(node) != visitedNodes.end())
|
||||||
|
@ -303,9 +342,9 @@ void GLTFFileWriter::traceBoneFromJoint(MeshResultContext &resultContext, std::p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLTFFileWriter::save(const QString &filename)
|
bool GLTFFileWriter::save()
|
||||||
{
|
{
|
||||||
QFile file(filename);
|
QFile file(m_filename);
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,18 @@ class GLTFFileWriter : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
GLTFFileWriter(MeshResultContext &resultContext);
|
GLTFFileWriter(MeshResultContext &resultContext, const QString &filename);
|
||||||
bool save(const QString &filename);
|
bool save();
|
||||||
void traceBones(MeshResultContext &resultContext);
|
void traceBones(MeshResultContext &resultContext);
|
||||||
void traceBoneFromJoint(MeshResultContext &resultContext, std::pair<int, int> node, std::set<std::pair<int, int>> &visitedNodes, std::set<std::pair<std::pair<int, int>, std::pair<int, int>>> &connections, int parentIndex);
|
void traceBoneFromJoint(MeshResultContext &resultContext, std::pair<int, int> node, std::set<std::pair<int, int>> &visitedNodes, std::set<std::pair<std::pair<int, int>, std::pair<int, int>>> &connections, int parentIndex);
|
||||||
|
const QString &textureFilenameInGltf();
|
||||||
private:
|
private:
|
||||||
QByteArray m_data;
|
QByteArray m_data;
|
||||||
std::vector<JointInfo> m_tracedJoints;
|
std::vector<JointInfo> m_tracedJoints;
|
||||||
std::map<std::pair<int, int>, int> m_tracedNodeToJointIndexMap;
|
std::map<std::pair<int, int>, int> m_tracedNodeToJointIndexMap;
|
||||||
QString getMatrixStringInColumnOrder(const QMatrix4x4 &mat);
|
QString getMatrixStringInColumnOrder(const QMatrix4x4 &mat);
|
||||||
|
QString m_filename;
|
||||||
|
QString m_textureFilename;
|
||||||
private:
|
private:
|
||||||
nlohmann::json m_json;
|
nlohmann::json m_json;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include "meshgenerator.h"
|
#include "meshgenerator.h"
|
||||||
#include "util.h"
|
#include "dust3dutil.h"
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
#include "meshlite.h"
|
#include "meshlite.h"
|
||||||
#include "modelofflinerender.h"
|
#include "modelofflinerender.h"
|
||||||
|
@ -120,8 +120,8 @@ void MeshGenerator::loadGeneratedPositionsToMeshResultContext(void *meshliteCont
|
||||||
for (int i = 0, positionIndex = 0; i < positionCount; i++, positionIndex+=3) {
|
for (int i = 0, positionIndex = 0; i < positionCount; i++, positionIndex+=3) {
|
||||||
ResultVertex vertex;
|
ResultVertex vertex;
|
||||||
vertex.position = QVector3D(positionBuffer[positionIndex + 0], positionBuffer[positionIndex + 1], positionBuffer[positionIndex + 2]);
|
vertex.position = QVector3D(positionBuffer[positionIndex + 0], positionBuffer[positionIndex + 1], positionBuffer[positionIndex + 2]);
|
||||||
verticesMap[i] = m_meshResultContext->resultVertices.size();
|
verticesMap[i] = m_meshResultContext->vertices.size();
|
||||||
m_meshResultContext->resultVertices.push_back(vertex);
|
m_meshResultContext->vertices.push_back(vertex);
|
||||||
}
|
}
|
||||||
int faceCount = meshlite_get_face_count(meshliteContext, triangulatedMeshId);
|
int faceCount = meshlite_get_face_count(meshliteContext, triangulatedMeshId);
|
||||||
int triangleIndexBufferLen = faceCount * 3;
|
int triangleIndexBufferLen = faceCount * 3;
|
||||||
|
@ -137,7 +137,7 @@ void MeshGenerator::loadGeneratedPositionsToMeshResultContext(void *meshliteCont
|
||||||
triangle.indicies[1] = verticesMap[triangleIndexBuffer[triangleVertIndex + 1]];
|
triangle.indicies[1] = verticesMap[triangleIndexBuffer[triangleVertIndex + 1]];
|
||||||
triangle.indicies[2] = verticesMap[triangleIndexBuffer[triangleVertIndex + 2]];
|
triangle.indicies[2] = verticesMap[triangleIndexBuffer[triangleVertIndex + 2]];
|
||||||
triangle.normal = QVector3D(normalBuffer[normalIndex + 0], normalBuffer[normalIndex + 1], normalBuffer[normalIndex + 2]);
|
triangle.normal = QVector3D(normalBuffer[normalIndex + 0], normalBuffer[normalIndex + 1], normalBuffer[normalIndex + 2]);
|
||||||
m_meshResultContext->resultTriangles.push_back(triangle);
|
m_meshResultContext->triangles.push_back(triangle);
|
||||||
}
|
}
|
||||||
delete[] positionBuffer;
|
delete[] positionBuffer;
|
||||||
delete[] triangleIndexBuffer;
|
delete[] triangleIndexBuffer;
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "meshresultcontext.h"
|
#include "meshresultcontext.h"
|
||||||
|
#include "thekla_atlas.h"
|
||||||
|
#include "positionmap.h"
|
||||||
|
|
||||||
struct HalfColorEdge
|
struct HalfColorEdge
|
||||||
{
|
{
|
||||||
|
@ -29,9 +31,11 @@ MeshResultContext::MeshResultContext() :
|
||||||
m_centerBmeshNodeResolved(false),
|
m_centerBmeshNodeResolved(false),
|
||||||
m_bmeshEdgeDirectionsResolved(false),
|
m_bmeshEdgeDirectionsResolved(false),
|
||||||
m_bmeshNodeNeighborsResolved(false),
|
m_bmeshNodeNeighborsResolved(false),
|
||||||
m_vertexWeightResolved(false),
|
m_vertexWeightsResolved(false),
|
||||||
m_centerBmeshNode(nullptr),
|
m_centerBmeshNode(nullptr),
|
||||||
m_resultPartsResolved(false)
|
m_resultPartsResolved(false),
|
||||||
|
m_resultTriangleUvsResolved(false),
|
||||||
|
m_resultRearrangedVerticesResolved(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,12 +101,12 @@ void MeshResultContext::calculateTriangleSourceNodes(std::vector<std::pair<int,
|
||||||
positionMap.addPosition(it.position.x(), it.position.y(), it.position.z(),
|
positionMap.addPosition(it.position.x(), it.position.y(), it.position.z(),
|
||||||
std::make_pair(it.bmeshId, it.nodeId));
|
std::make_pair(it.bmeshId, it.nodeId));
|
||||||
}
|
}
|
||||||
for (auto x = 0u; x < resultTriangles.size(); x++) {
|
for (auto x = 0u; x < triangles.size(); x++) {
|
||||||
const auto triangle = &resultTriangles[x];
|
const auto triangle = &triangles[x];
|
||||||
std::vector<std::pair<std::pair<int, int>, int>> colorTypes;
|
std::vector<std::pair<std::pair<int, int>, int>> colorTypes;
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
int index = triangle->indicies[i];
|
int index = triangle->indicies[i];
|
||||||
ResultVertex *resultVertex = &resultVertices[index];
|
ResultVertex *resultVertex = &vertices[index];
|
||||||
std::pair<int, int> source;
|
std::pair<int, int> source;
|
||||||
if (positionMap.findPosition(resultVertex->position.x(), resultVertex->position.y(), resultVertex->position.z(), &source)) {
|
if (positionMap.findPosition(resultVertex->position.x(), resultVertex->position.y(), resultVertex->position.z(), &source)) {
|
||||||
bool colorExisted = false;
|
bool colorExisted = false;
|
||||||
|
@ -149,7 +153,7 @@ void MeshResultContext::calculateTriangleSourceNodes(std::vector<std::pair<int,
|
||||||
std::map<std::pair<int, int>, int> brokenTriangleMapByEdge;
|
std::map<std::pair<int, int>, int> brokenTriangleMapByEdge;
|
||||||
std::vector<CandidateEdge> candidateEdges;
|
std::vector<CandidateEdge> candidateEdges;
|
||||||
for (const auto &x: brokenTriangleSet) {
|
for (const auto &x: brokenTriangleSet) {
|
||||||
const auto triangle = &resultTriangles[x];
|
const auto triangle = &triangles[x];
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
int oppositeStartIndex = triangle->indicies[(i + 1) % 3];
|
int oppositeStartIndex = triangle->indicies[(i + 1) % 3];
|
||||||
int oppositeStopIndex = triangle->indicies[i];
|
int oppositeStopIndex = triangle->indicies[i];
|
||||||
|
@ -160,11 +164,11 @@ void MeshResultContext::calculateTriangleSourceNodes(std::vector<std::pair<int,
|
||||||
if (findOpposite == halfColorEdgeMap.end())
|
if (findOpposite == halfColorEdgeMap.end())
|
||||||
continue;
|
continue;
|
||||||
QVector3D selfPositions[3] = {
|
QVector3D selfPositions[3] = {
|
||||||
resultVertices[triangle->indicies[i]].position, // A
|
vertices[triangle->indicies[i]].position, // A
|
||||||
resultVertices[triangle->indicies[(i + 1) % 3]].position, // B
|
vertices[triangle->indicies[(i + 1) % 3]].position, // B
|
||||||
resultVertices[triangle->indicies[(i + 2) % 3]].position // C
|
vertices[triangle->indicies[(i + 2) % 3]].position // C
|
||||||
};
|
};
|
||||||
QVector3D oppositeCornPosition = resultVertices[findOpposite->second.cornVertexIndex].position; // D
|
QVector3D oppositeCornPosition = vertices[findOpposite->second.cornVertexIndex].position; // D
|
||||||
QVector3D AB = selfPositions[1] - selfPositions[0];
|
QVector3D AB = selfPositions[1] - selfPositions[0];
|
||||||
float length = AB.length();
|
float length = AB.length();
|
||||||
QVector3D AC = selfPositions[2] - selfPositions[0];
|
QVector3D AC = selfPositions[2] - selfPositions[0];
|
||||||
|
@ -213,7 +217,7 @@ void MeshResultContext::calculateTriangleSourceNodes(std::vector<std::pair<int,
|
||||||
brokenTriangleSet.erase(x);
|
brokenTriangleSet.erase(x);
|
||||||
triangleSourceNodes[x] = candidate.source;
|
triangleSourceNodes[x] = candidate.source;
|
||||||
//qDebug() << "resolved triangle:" << x;
|
//qDebug() << "resolved triangle:" << x;
|
||||||
const auto triangle = &resultTriangles[x];
|
const auto triangle = &triangles[x];
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
int oppositeStartIndex = triangle->indicies[(i + 1) % 3];
|
int oppositeStartIndex = triangle->indicies[(i + 1) % 3];
|
||||||
int oppositeStopIndex = triangle->indicies[i];
|
int oppositeStopIndex = triangle->indicies[i];
|
||||||
|
@ -226,7 +230,6 @@ void MeshResultContext::calculateTriangleSourceNodes(std::vector<std::pair<int,
|
||||||
|
|
||||||
void MeshResultContext::calculateTriangleColors(std::vector<QColor> &triangleColors)
|
void MeshResultContext::calculateTriangleColors(std::vector<QColor> &triangleColors)
|
||||||
{
|
{
|
||||||
PositionMap<QColor> positionColorMap;
|
|
||||||
std::map<std::pair<int, int>, QColor> nodeColorMap;
|
std::map<std::pair<int, int>, QColor> nodeColorMap;
|
||||||
for (const auto &it: bmeshNodes) {
|
for (const auto &it: bmeshNodes) {
|
||||||
nodeColorMap[std::make_pair(it.bmeshId, it.nodeId)] = it.color;
|
nodeColorMap[std::make_pair(it.bmeshId, it.nodeId)] = it.color;
|
||||||
|
@ -298,8 +301,8 @@ void MeshResultContext::calculateBmeshConnectivity()
|
||||||
void MeshResultContext::calculateTriangleEdgeSourceMap(std::map<std::pair<int, int>, std::pair<int, int>> &triangleEdgeSourceMap)
|
void MeshResultContext::calculateTriangleEdgeSourceMap(std::map<std::pair<int, int>, std::pair<int, int>> &triangleEdgeSourceMap)
|
||||||
{
|
{
|
||||||
const std::vector<std::pair<int, int>> sourceNodes = triangleSourceNodes();
|
const std::vector<std::pair<int, int>> sourceNodes = triangleSourceNodes();
|
||||||
for (auto x = 0u; x < resultTriangles.size(); x++) {
|
for (auto x = 0u; x < triangles.size(); x++) {
|
||||||
const auto triangle = &resultTriangles[x];
|
const auto triangle = &triangles[x];
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
int startIndex = triangle->indicies[i];
|
int startIndex = triangle->indicies[i];
|
||||||
int stopIndex = triangle->indicies[(i + 1) % 3];
|
int stopIndex = triangle->indicies[(i + 1) % 3];
|
||||||
|
@ -400,11 +403,11 @@ void MeshResultContext::calculateBmeshEdgeDirections()
|
||||||
bmeshEdges = rearrangedEdges;
|
bmeshEdges = rearrangedEdges;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::vector<ResultVertexWeight>> &MeshResultContext::resultVertexWeights()
|
const std::vector<std::vector<ResultVertexWeight>> &MeshResultContext::vertexWeights()
|
||||||
{
|
{
|
||||||
if (!m_vertexWeightResolved) {
|
if (!m_vertexWeightsResolved) {
|
||||||
calculateVertexWeights(m_resultVertexWeights);
|
calculateVertexWeights(m_resultVertexWeights);
|
||||||
m_vertexWeightResolved = true;
|
m_vertexWeightsResolved = true;
|
||||||
}
|
}
|
||||||
return m_resultVertexWeights;
|
return m_resultVertexWeights;
|
||||||
}
|
}
|
||||||
|
@ -412,11 +415,11 @@ const std::vector<std::vector<ResultVertexWeight>> &MeshResultContext::resultVer
|
||||||
void MeshResultContext::calculateVertexWeights(std::vector<std::vector<ResultVertexWeight>> &vertexWeights)
|
void MeshResultContext::calculateVertexWeights(std::vector<std::vector<ResultVertexWeight>> &vertexWeights)
|
||||||
{
|
{
|
||||||
vertexWeights.clear();
|
vertexWeights.clear();
|
||||||
vertexWeights.resize(resultVertices.size());
|
vertexWeights.resize(vertices.size());
|
||||||
for (auto i = 0u; i < resultTriangles.size(); i++) {
|
for (auto i = 0u; i < triangles.size(); i++) {
|
||||||
std::pair<int, int> sourceNode = triangleSourceNodes()[i];
|
std::pair<int, int> sourceNode = triangleSourceNodes()[i];
|
||||||
for (int j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
int vertexIndex = resultTriangles[i].indicies[j];
|
int vertexIndex = triangles[i].indicies[j];
|
||||||
Q_ASSERT(vertexIndex < (int)vertexWeights.size());
|
Q_ASSERT(vertexIndex < (int)vertexWeights.size());
|
||||||
int foundSourceNodeIndex = -1;
|
int foundSourceNodeIndex = -1;
|
||||||
for (auto k = 0u; k < vertexWeights[vertexIndex].size(); k++) {
|
for (auto k = 0u; k < vertexWeights[vertexIndex].size(); k++) {
|
||||||
|
@ -445,7 +448,7 @@ void MeshResultContext::calculateVertexWeights(std::vector<std::vector<ResultVer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<int, ResultPart> &MeshResultContext::resultParts()
|
const std::map<int, ResultPart> &MeshResultContext::parts()
|
||||||
{
|
{
|
||||||
if (!m_resultPartsResolved) {
|
if (!m_resultPartsResolved) {
|
||||||
calculateResultParts(m_resultParts);
|
calculateResultParts(m_resultParts);
|
||||||
|
@ -454,11 +457,20 @@ const std::map<int, ResultPart> &MeshResultContext::resultParts()
|
||||||
return m_resultParts;
|
return m_resultParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<ResultTriangleUv> &MeshResultContext::triangleUvs()
|
||||||
|
{
|
||||||
|
if (!m_resultTriangleUvsResolved) {
|
||||||
|
calculateResultTriangleUvs(m_resultTriangleUvs, m_seamVertices);
|
||||||
|
m_resultTriangleUvsResolved = true;
|
||||||
|
}
|
||||||
|
return m_resultTriangleUvs;
|
||||||
|
}
|
||||||
|
|
||||||
void MeshResultContext::calculateResultParts(std::map<int, ResultPart> &parts)
|
void MeshResultContext::calculateResultParts(std::map<int, ResultPart> &parts)
|
||||||
{
|
{
|
||||||
std::map<std::pair<int, int>, int> oldVertexToNewMap;
|
std::map<std::pair<int, int>, int> oldVertexToNewMap;
|
||||||
for (auto x = 0u; x < resultTriangles.size(); x++) {
|
for (auto x = 0u; x < triangles.size(); x++) {
|
||||||
const auto &triangle = resultTriangles[x];
|
const auto &triangle = triangles[x];
|
||||||
const auto &sourceNode = triangleSourceNodes()[x];
|
const auto &sourceNode = triangleSourceNodes()[x];
|
||||||
auto it = parts.find(sourceNode.first);
|
auto it = parts.find(sourceNode.first);
|
||||||
if (it == parts.end()) {
|
if (it == parts.end()) {
|
||||||
|
@ -472,10 +484,15 @@ void MeshResultContext::calculateResultParts(std::map<int, ResultPart> &parts)
|
||||||
for (auto i = 0u; i < 3; i++) {
|
for (auto i = 0u; i < 3; i++) {
|
||||||
auto key = std::make_pair(sourceNode.first, triangle.indicies[i]);
|
auto key = std::make_pair(sourceNode.first, triangle.indicies[i]);
|
||||||
const auto &it = oldVertexToNewMap.find(key);
|
const auto &it = oldVertexToNewMap.find(key);
|
||||||
if (it == oldVertexToNewMap.end()) {
|
if (it == oldVertexToNewMap.end() || m_seamVertices.end() != m_seamVertices.find(triangle.indicies[i])) {
|
||||||
int newIndex = resultPart.vertices.size();
|
int newIndex = resultPart.vertices.size();
|
||||||
resultPart.vertices.push_back(resultVertices[triangle.indicies[i]]);
|
resultPart.vertices.push_back(vertices[triangle.indicies[i]]);
|
||||||
resultPart.weights.push_back(resultVertexWeights()[triangle.indicies[i]]);
|
ResultVertexUv vertexUv;
|
||||||
|
vertexUv.uv[0] = triangleUvs()[x].uv[i][0];
|
||||||
|
vertexUv.uv[1] = triangleUvs()[x].uv[i][1];
|
||||||
|
resultPart.vertexUvs.push_back(vertexUv);
|
||||||
|
resultPart.weights.push_back(vertexWeights()[triangle.indicies[i]]);
|
||||||
|
if (it == oldVertexToNewMap.end())
|
||||||
oldVertexToNewMap.insert(std::make_pair(key, newIndex));
|
oldVertexToNewMap.insert(std::make_pair(key, newIndex));
|
||||||
newTriangle.indicies[i] = newIndex;
|
newTriangle.indicies[i] = newIndex;
|
||||||
} else {
|
} else {
|
||||||
|
@ -483,5 +500,165 @@ void MeshResultContext::calculateResultParts(std::map<int, ResultPart> &parts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultPart.triangles.push_back(newTriangle);
|
resultPart.triangles.push_back(newTriangle);
|
||||||
|
resultPart.uvs.push_back(triangleUvs()[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshResultContext::calculateResultTriangleUvs(std::vector<ResultTriangleUv> &uvs, std::set<int> &seamVertices)
|
||||||
|
{
|
||||||
|
using namespace Thekla;
|
||||||
|
|
||||||
|
const std::vector<ResultRearrangedVertex> &choosenVertices = rearrangedVertices();
|
||||||
|
const std::vector<ResultRearrangedTriangle> &choosenTriangles = rearrangedTriangles();
|
||||||
|
|
||||||
|
Atlas_Input_Mesh inputMesh;
|
||||||
|
|
||||||
|
inputMesh.vertex_count = choosenVertices.size();
|
||||||
|
inputMesh.vertex_array = new Atlas_Input_Vertex[inputMesh.vertex_count];
|
||||||
|
inputMesh.face_count = choosenTriangles.size();
|
||||||
|
inputMesh.face_array = new Atlas_Input_Face[inputMesh.face_count];
|
||||||
|
for (auto i = 0; i < inputMesh.vertex_count; i++) {
|
||||||
|
const ResultRearrangedVertex *src = &choosenVertices[i];
|
||||||
|
Atlas_Input_Vertex *dest = &inputMesh.vertex_array[i];
|
||||||
|
dest->position[0] = src->position.x();
|
||||||
|
dest->position[1] = src->position.y();
|
||||||
|
dest->position[2] = src->position.z();
|
||||||
|
dest->normal[0] = 0;
|
||||||
|
dest->normal[1] = 0;
|
||||||
|
dest->normal[2] = 0;
|
||||||
|
dest->uv[0] = 0;
|
||||||
|
dest->uv[1] = 0;
|
||||||
|
dest->first_colocal = i;
|
||||||
|
}
|
||||||
|
std::map<std::pair<int, int>, int> edgeToFaceIndexMap;
|
||||||
|
for (auto i = 0; i < inputMesh.face_count; i++) {
|
||||||
|
const ResultRearrangedTriangle *src = &choosenTriangles[i];
|
||||||
|
Atlas_Input_Face *dest = &inputMesh.face_array[i];
|
||||||
|
dest->material_index = abs(triangleSourceNodes()[src->originalIndex].first);
|
||||||
|
dest->vertex_index[0] = src->indicies[0];
|
||||||
|
dest->vertex_index[1] = src->indicies[1];
|
||||||
|
dest->vertex_index[2] = src->indicies[2];
|
||||||
|
edgeToFaceIndexMap[std::make_pair(src->indicies[0], src->indicies[1])] = src->originalIndex;
|
||||||
|
edgeToFaceIndexMap[std::make_pair(src->indicies[1], src->indicies[2])] = src->originalIndex;
|
||||||
|
edgeToFaceIndexMap[std::make_pair(src->indicies[2], src->indicies[0])] = src->originalIndex;
|
||||||
|
for (auto j = 0; j < 3; j++) {
|
||||||
|
Atlas_Input_Vertex *vertex = &inputMesh.vertex_array[src->indicies[j]];
|
||||||
|
vertex->normal[0] += src->normal.x();
|
||||||
|
vertex->normal[1] += src->normal.y();
|
||||||
|
vertex->normal[2] += src->normal.z();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto i = 0; i < inputMesh.vertex_count; i++) {
|
||||||
|
Atlas_Input_Vertex *dest = &inputMesh.vertex_array[i];
|
||||||
|
QVector3D normal(dest->normal[0], dest->normal[1], dest->normal[2]);
|
||||||
|
normal.normalize();
|
||||||
|
dest->normal[0] = normal.x();
|
||||||
|
dest->normal[1] = normal.y();
|
||||||
|
dest->normal[2] = normal.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
Atlas_Options atlasOptions;
|
||||||
|
atlas_set_default_options(&atlasOptions);
|
||||||
|
|
||||||
|
atlasOptions.packer_options.witness.packing_quality = 4;
|
||||||
|
|
||||||
|
Atlas_Error error = Atlas_Error_Success;
|
||||||
|
Atlas_Output_Mesh *outputMesh = atlas_generate(&inputMesh, &atlasOptions, &error);
|
||||||
|
|
||||||
|
PositionMap<int> uvPositionAndIndexMap;
|
||||||
|
|
||||||
|
uvs.resize(triangles.size());
|
||||||
|
std::set<int> refs;
|
||||||
|
for (auto i = 0; i < outputMesh->index_count; i += 3) {
|
||||||
|
Atlas_Output_Vertex *outputVertices[] = {
|
||||||
|
&outputMesh->vertex_array[outputMesh->index_array[i + 0]],
|
||||||
|
&outputMesh->vertex_array[outputMesh->index_array[i + 1]],
|
||||||
|
&outputMesh->vertex_array[outputMesh->index_array[i + 2]]
|
||||||
|
};
|
||||||
|
int faceIndex = edgeToFaceIndexMap[std::make_pair(outputVertices[0]->xref, outputVertices[1]->xref)];
|
||||||
|
Q_ASSERT(faceIndex == edgeToFaceIndexMap[std::make_pair(outputVertices[1]->xref, outputVertices[2]->xref)]);
|
||||||
|
Q_ASSERT(faceIndex == edgeToFaceIndexMap[std::make_pair(outputVertices[2]->xref, outputVertices[0]->xref)]);
|
||||||
|
int firstIndex = 0;
|
||||||
|
for (auto j = 0; j < 3; j++) {
|
||||||
|
if (choosenVertices[outputVertices[0]->xref].originalIndex == triangles[faceIndex].indicies[j]) {
|
||||||
|
firstIndex = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto j = 0; j < 3; j++) {
|
||||||
|
Atlas_Output_Vertex *from = outputVertices[j];
|
||||||
|
ResultTriangleUv *to = &uvs[faceIndex];
|
||||||
|
to->resolved = true;
|
||||||
|
int toIndex = (firstIndex + j) % 3;
|
||||||
|
to->uv[toIndex][0] = (float)from->uv[0] / outputMesh->atlas_width;
|
||||||
|
to->uv[toIndex][1] = (float)from->uv[1] / outputMesh->atlas_height;
|
||||||
|
int originalRef = choosenVertices[from->xref].originalIndex;
|
||||||
|
if (refs.find(originalRef) == refs.end()) {
|
||||||
|
refs.insert(originalRef);
|
||||||
|
uvPositionAndIndexMap.addPosition(from->uv[0], from->uv[1], (float)originalRef, 0);
|
||||||
|
} else {
|
||||||
|
if (!uvPositionAndIndexMap.findPosition(from->uv[0], from->uv[1], (float)originalRef, nullptr)) {
|
||||||
|
seamVertices.insert(originalRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int unresolvedUvFaceCount = 0;
|
||||||
|
for (auto i = 0u; i < uvs.size(); i++) {
|
||||||
|
ResultTriangleUv *uv = &uvs[i];
|
||||||
|
if (!uv->resolved) {
|
||||||
|
unresolvedUvFaceCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << "unresolvedUvFaceCount:" << unresolvedUvFaceCount;
|
||||||
|
|
||||||
|
atlas_free(outputMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<ResultRearrangedVertex> &MeshResultContext::rearrangedVertices()
|
||||||
|
{
|
||||||
|
if (!m_resultRearrangedVerticesResolved) {
|
||||||
|
calculateResultRearrangedVertices(m_rearrangedVertices, m_rearrangedTriangles);
|
||||||
|
m_resultRearrangedVerticesResolved = true;
|
||||||
|
}
|
||||||
|
return m_rearrangedVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<ResultRearrangedTriangle> &MeshResultContext::rearrangedTriangles()
|
||||||
|
{
|
||||||
|
if (!m_resultRearrangedVerticesResolved) {
|
||||||
|
calculateResultRearrangedVertices(m_rearrangedVertices, m_rearrangedTriangles);
|
||||||
|
m_resultRearrangedVerticesResolved = true;
|
||||||
|
}
|
||||||
|
return m_rearrangedTriangles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshResultContext::calculateResultRearrangedVertices(std::vector<ResultRearrangedVertex> &rearrangedVertices, std::vector<ResultRearrangedTriangle> &rearrangedTriangles)
|
||||||
|
{
|
||||||
|
std::map<std::pair<int, int>, int> oldVertexToNewMap;
|
||||||
|
rearrangedVertices.clear();
|
||||||
|
rearrangedTriangles.clear();
|
||||||
|
for (auto x = 0u; x < triangles.size(); x++) {
|
||||||
|
const auto &triangle = triangles[x];
|
||||||
|
const auto &sourceNode = triangleSourceNodes()[x];
|
||||||
|
ResultRearrangedTriangle newTriangle;
|
||||||
|
newTriangle.normal = triangle.normal;
|
||||||
|
newTriangle.originalIndex = x;
|
||||||
|
for (auto i = 0u; i < 3; i++) {
|
||||||
|
auto key = std::make_pair(sourceNode.first, triangle.indicies[i]);
|
||||||
|
const auto &it = oldVertexToNewMap.find(key);
|
||||||
|
if (it == oldVertexToNewMap.end()) {
|
||||||
|
ResultRearrangedVertex rearrangedVertex;
|
||||||
|
rearrangedVertex.originalIndex = triangle.indicies[i];
|
||||||
|
rearrangedVertex.position = vertices[triangle.indicies[i]].position;
|
||||||
|
int newIndex = rearrangedVertices.size();
|
||||||
|
rearrangedVertices.push_back(rearrangedVertex);
|
||||||
|
oldVertexToNewMap.insert(std::make_pair(key, newIndex));
|
||||||
|
newTriangle.indicies[i] = newIndex;
|
||||||
|
} else {
|
||||||
|
newTriangle.indicies[i] = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rearrangedTriangles.push_back(newTriangle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,12 +51,38 @@ struct ResultVertexWeight
|
||||||
float weight;
|
float weight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ResultTriangleUv
|
||||||
|
{
|
||||||
|
float uv[3][2];
|
||||||
|
bool resolved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResultVertexUv
|
||||||
|
{
|
||||||
|
float uv[2];
|
||||||
|
};
|
||||||
|
|
||||||
struct ResultPart
|
struct ResultPart
|
||||||
{
|
{
|
||||||
QColor color;
|
QColor color;
|
||||||
std::vector<ResultVertex> vertices;
|
std::vector<ResultVertex> vertices;
|
||||||
std::vector<std::vector<ResultVertexWeight>> weights;
|
std::vector<std::vector<ResultVertexWeight>> weights;
|
||||||
std::vector<ResultTriangle> triangles;
|
std::vector<ResultTriangle> triangles;
|
||||||
|
std::vector<ResultTriangleUv> uvs;
|
||||||
|
std::vector<ResultVertexUv> vertexUvs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResultRearrangedVertex
|
||||||
|
{
|
||||||
|
QVector3D position;
|
||||||
|
int originalIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResultRearrangedTriangle
|
||||||
|
{
|
||||||
|
int indicies[3];
|
||||||
|
QVector3D normal;
|
||||||
|
int originalIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MeshResultContext
|
class MeshResultContext
|
||||||
|
@ -65,8 +91,8 @@ public:
|
||||||
std::vector<BmeshNode> bmeshNodes;
|
std::vector<BmeshNode> bmeshNodes;
|
||||||
std::vector<BmeshVertex> bmeshVertices;
|
std::vector<BmeshVertex> bmeshVertices;
|
||||||
std::vector<BmeshEdge> bmeshEdges;
|
std::vector<BmeshEdge> bmeshEdges;
|
||||||
std::vector<ResultVertex> resultVertices;
|
std::vector<ResultVertex> vertices;
|
||||||
std::vector<ResultTriangle> resultTriangles;
|
std::vector<ResultTriangle> triangles;
|
||||||
MeshResultContext();
|
MeshResultContext();
|
||||||
public:
|
public:
|
||||||
const std::vector<std::pair<int, int>> &triangleSourceNodes();
|
const std::vector<std::pair<int, int>> &triangleSourceNodes();
|
||||||
|
@ -77,8 +103,11 @@ public:
|
||||||
void resolveBmeshConnectivity();
|
void resolveBmeshConnectivity();
|
||||||
void resolveBmeshEdgeDirections();
|
void resolveBmeshEdgeDirections();
|
||||||
const std::map<std::pair<int, int>, std::vector<std::pair<int, int>>> &nodeNeighbors();
|
const std::map<std::pair<int, int>, std::vector<std::pair<int, int>>> &nodeNeighbors();
|
||||||
const std::vector<std::vector<ResultVertexWeight>> &resultVertexWeights();
|
const std::vector<std::vector<ResultVertexWeight>> &vertexWeights();
|
||||||
const std::map<int, ResultPart> &resultParts();
|
const std::map<int, ResultPart> &parts();
|
||||||
|
const std::vector<ResultTriangleUv> &triangleUvs();
|
||||||
|
const std::vector<ResultRearrangedVertex> &rearrangedVertices();
|
||||||
|
const std::vector<ResultRearrangedTriangle> &rearrangedTriangles();
|
||||||
private:
|
private:
|
||||||
bool m_triangleSourceResolved;
|
bool m_triangleSourceResolved;
|
||||||
bool m_triangleColorResolved;
|
bool m_triangleColorResolved;
|
||||||
|
@ -88,9 +117,11 @@ private:
|
||||||
bool m_centerBmeshNodeResolved;
|
bool m_centerBmeshNodeResolved;
|
||||||
bool m_bmeshEdgeDirectionsResolved;
|
bool m_bmeshEdgeDirectionsResolved;
|
||||||
bool m_bmeshNodeNeighborsResolved;
|
bool m_bmeshNodeNeighborsResolved;
|
||||||
bool m_vertexWeightResolved;
|
bool m_vertexWeightsResolved;
|
||||||
BmeshNode *m_centerBmeshNode;
|
BmeshNode *m_centerBmeshNode;
|
||||||
bool m_resultPartsResolved;
|
bool m_resultPartsResolved;
|
||||||
|
bool m_resultTriangleUvsResolved;
|
||||||
|
bool m_resultRearrangedVerticesResolved;
|
||||||
private:
|
private:
|
||||||
std::vector<std::pair<int, int>> m_triangleSourceNodes;
|
std::vector<std::pair<int, int>> m_triangleSourceNodes;
|
||||||
std::vector<QColor> m_triangleColors;
|
std::vector<QColor> m_triangleColors;
|
||||||
|
@ -99,6 +130,10 @@ private:
|
||||||
std::map<std::pair<int, int>, std::vector<std::pair<int, int>>> m_nodeNeighbors;
|
std::map<std::pair<int, int>, std::vector<std::pair<int, int>>> m_nodeNeighbors;
|
||||||
std::vector<std::vector<ResultVertexWeight>> m_resultVertexWeights;
|
std::vector<std::vector<ResultVertexWeight>> m_resultVertexWeights;
|
||||||
std::map<int, ResultPart> m_resultParts;
|
std::map<int, ResultPart> m_resultParts;
|
||||||
|
std::vector<ResultTriangleUv> m_resultTriangleUvs;
|
||||||
|
std::set<int> m_seamVertices;
|
||||||
|
std::vector<ResultRearrangedVertex> m_rearrangedVertices;
|
||||||
|
std::vector<ResultRearrangedTriangle> m_rearrangedTriangles;
|
||||||
private:
|
private:
|
||||||
void calculateTriangleSourceNodes(std::vector<std::pair<int, int>> &triangleSourceNodes);
|
void calculateTriangleSourceNodes(std::vector<std::pair<int, int>> &triangleSourceNodes);
|
||||||
void calculateTriangleColors(std::vector<QColor> &triangleColors);
|
void calculateTriangleColors(std::vector<QColor> &triangleColors);
|
||||||
|
@ -112,6 +147,8 @@ private:
|
||||||
void calculateBmeshNodeNeighbors(std::map<std::pair<int, int>, std::vector<std::pair<int, int>>> &nodeNeighbors);
|
void calculateBmeshNodeNeighbors(std::map<std::pair<int, int>, std::vector<std::pair<int, int>>> &nodeNeighbors);
|
||||||
void calculateVertexWeights(std::vector<std::vector<ResultVertexWeight>> &vertexWeights);
|
void calculateVertexWeights(std::vector<std::vector<ResultVertexWeight>> &vertexWeights);
|
||||||
void calculateResultParts(std::map<int, ResultPart> &parts);
|
void calculateResultParts(std::map<int, ResultPart> &parts);
|
||||||
|
void calculateResultTriangleUvs(std::vector<ResultTriangleUv> &uvs, std::set<int> &seamVertices);
|
||||||
|
void calculateResultRearrangedVertices(std::vector<ResultRearrangedVertex> &rearrangedVertices, std::vector<ResultRearrangedTriangle> &rearrangedTriangles);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include "meshresultpostprocessor.h"
|
||||||
|
|
||||||
|
MeshResultPostProcessor::MeshResultPostProcessor(const MeshResultContext &meshResultContext)
|
||||||
|
{
|
||||||
|
m_meshResultContext = new MeshResultContext;
|
||||||
|
*m_meshResultContext = meshResultContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshResultPostProcessor::~MeshResultPostProcessor()
|
||||||
|
{
|
||||||
|
delete m_meshResultContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshResultContext *MeshResultPostProcessor::takePostProcessedResultContext()
|
||||||
|
{
|
||||||
|
MeshResultContext *resultContext = m_meshResultContext;
|
||||||
|
m_meshResultContext = nullptr;
|
||||||
|
return resultContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshResultPostProcessor::process()
|
||||||
|
{
|
||||||
|
if (!m_meshResultContext->bmeshNodes.empty()) {
|
||||||
|
m_meshResultContext->resolveBmeshConnectivity();
|
||||||
|
m_meshResultContext->resolveBmeshEdgeDirections();
|
||||||
|
m_meshResultContext->rearrangedVertices();
|
||||||
|
m_meshResultContext->rearrangedTriangles();
|
||||||
|
m_meshResultContext->parts();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef MESH_RESULT_POST_PROCESSOR_H
|
||||||
|
#define MESH_RESULT_POST_PROCESSOR_H
|
||||||
|
#include <QObject>
|
||||||
|
#include "meshresultcontext.h"
|
||||||
|
|
||||||
|
class MeshResultPostProcessor : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MeshResultPostProcessor(const MeshResultContext &meshResultContext);
|
||||||
|
~MeshResultPostProcessor();
|
||||||
|
MeshResultContext *takePostProcessedResultContext();
|
||||||
|
signals:
|
||||||
|
void finished();
|
||||||
|
public slots:
|
||||||
|
void process();
|
||||||
|
private:
|
||||||
|
MeshResultContext *m_meshResultContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -7,7 +7,7 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
#include "util.h"
|
#include "dust3dutil.h"
|
||||||
#include "skeletonxml.h"
|
#include "skeletonxml.h"
|
||||||
|
|
||||||
unsigned long SkeletonDocument::m_maxSnapshot = 1000;
|
unsigned long SkeletonDocument::m_maxSnapshot = 1000;
|
||||||
|
@ -21,6 +21,9 @@ SkeletonDocument::SkeletonDocument() :
|
||||||
xlocked(false),
|
xlocked(false),
|
||||||
ylocked(false),
|
ylocked(false),
|
||||||
zlocked(false),
|
zlocked(false),
|
||||||
|
textureGuideImage(nullptr),
|
||||||
|
textureImage(nullptr),
|
||||||
|
textureBorderImage(nullptr),
|
||||||
// private
|
// private
|
||||||
m_resultMeshIsObsolete(false),
|
m_resultMeshIsObsolete(false),
|
||||||
m_meshGenerator(nullptr),
|
m_meshGenerator(nullptr),
|
||||||
|
@ -30,7 +33,11 @@ SkeletonDocument::SkeletonDocument() :
|
||||||
m_resultSkeletonIsObsolete(false),
|
m_resultSkeletonIsObsolete(false),
|
||||||
m_skeletonGenerator(nullptr),
|
m_skeletonGenerator(nullptr),
|
||||||
m_resultSkeletonMesh(nullptr),
|
m_resultSkeletonMesh(nullptr),
|
||||||
m_currentSkeletonResultContext(new MeshResultContext)
|
m_textureIsObsolete(false),
|
||||||
|
m_textureGenerator(nullptr),
|
||||||
|
m_postProcessResultIsObsolete(false),
|
||||||
|
m_postProcessor(nullptr),
|
||||||
|
m_postProcessedResultContext(new MeshResultContext)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +45,10 @@ SkeletonDocument::~SkeletonDocument()
|
||||||
{
|
{
|
||||||
delete m_resultMesh;
|
delete m_resultMesh;
|
||||||
delete m_resultSkeletonMesh;
|
delete m_resultSkeletonMesh;
|
||||||
delete m_currentSkeletonResultContext;
|
delete m_postProcessedResultContext;
|
||||||
|
delete textureGuideImage;
|
||||||
|
delete textureImage;
|
||||||
|
delete textureBorderImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocument::uiReady()
|
void SkeletonDocument::uiReady()
|
||||||
|
@ -863,6 +873,52 @@ void SkeletonDocument::generateMesh()
|
||||||
thread->start();
|
thread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonDocument::generateTexture()
|
||||||
|
{
|
||||||
|
if (nullptr != m_textureGenerator) {
|
||||||
|
m_textureIsObsolete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Texture guide generating..";
|
||||||
|
|
||||||
|
m_textureIsObsolete = false;
|
||||||
|
|
||||||
|
QThread *thread = new QThread;
|
||||||
|
m_textureGenerator = new TextureGenerator(*m_postProcessedResultContext);
|
||||||
|
m_textureGenerator->moveToThread(thread);
|
||||||
|
connect(thread, &QThread::started, m_textureGenerator, &TextureGenerator::process);
|
||||||
|
connect(m_textureGenerator, &TextureGenerator::finished, this, &SkeletonDocument::textureReady);
|
||||||
|
connect(m_textureGenerator, &TextureGenerator::finished, thread, &QThread::quit);
|
||||||
|
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonDocument::textureReady()
|
||||||
|
{
|
||||||
|
delete textureGuideImage;
|
||||||
|
textureGuideImage = m_textureGenerator->takeResultTextureGuideImage();
|
||||||
|
|
||||||
|
delete textureImage;
|
||||||
|
textureImage = m_textureGenerator->takeResultTextureImage();
|
||||||
|
|
||||||
|
delete textureBorderImage;
|
||||||
|
textureBorderImage = m_textureGenerator->takeResultTextureBorderImage();
|
||||||
|
|
||||||
|
delete m_textureGenerator;
|
||||||
|
m_textureGenerator = nullptr;
|
||||||
|
|
||||||
|
qDebug() << "Texture guide generation done";
|
||||||
|
|
||||||
|
emit resultTextureChanged();
|
||||||
|
|
||||||
|
if (m_textureIsObsolete) {
|
||||||
|
generateTexture();
|
||||||
|
} else {
|
||||||
|
checkExportReadyState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonDocument::generateSkeleton()
|
void SkeletonDocument::generateSkeleton()
|
||||||
{
|
{
|
||||||
if (nullptr != m_skeletonGenerator) {
|
if (nullptr != m_skeletonGenerator) {
|
||||||
|
@ -874,13 +930,8 @@ void SkeletonDocument::generateSkeleton()
|
||||||
|
|
||||||
m_resultSkeletonIsObsolete = false;
|
m_resultSkeletonIsObsolete = false;
|
||||||
|
|
||||||
if (!m_currentMeshResultContext) {
|
|
||||||
qDebug() << "Skeleton is null";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QThread *thread = new QThread;
|
QThread *thread = new QThread;
|
||||||
m_skeletonGenerator = new SkeletonGenerator(*m_currentMeshResultContext);
|
m_skeletonGenerator = new SkeletonGenerator(*m_postProcessedResultContext);
|
||||||
m_skeletonGenerator->moveToThread(thread);
|
m_skeletonGenerator->moveToThread(thread);
|
||||||
connect(thread, &QThread::started, m_skeletonGenerator, &SkeletonGenerator::process);
|
connect(thread, &QThread::started, m_skeletonGenerator, &SkeletonGenerator::process);
|
||||||
connect(m_skeletonGenerator, &SkeletonGenerator::finished, this, &SkeletonDocument::skeletonReady);
|
connect(m_skeletonGenerator, &SkeletonGenerator::finished, this, &SkeletonDocument::skeletonReady);
|
||||||
|
@ -896,11 +947,6 @@ void SkeletonDocument::skeletonReady()
|
||||||
delete m_resultSkeletonMesh;
|
delete m_resultSkeletonMesh;
|
||||||
m_resultSkeletonMesh = resultSkeletonMesh;
|
m_resultSkeletonMesh = resultSkeletonMesh;
|
||||||
|
|
||||||
MeshResultContext *resultContext = m_skeletonGenerator->takeResultContext();
|
|
||||||
|
|
||||||
delete m_currentSkeletonResultContext;
|
|
||||||
m_currentSkeletonResultContext = resultContext;
|
|
||||||
|
|
||||||
delete m_skeletonGenerator;
|
delete m_skeletonGenerator;
|
||||||
m_skeletonGenerator = nullptr;
|
m_skeletonGenerator = nullptr;
|
||||||
|
|
||||||
|
@ -910,12 +956,57 @@ void SkeletonDocument::skeletonReady()
|
||||||
|
|
||||||
if (m_resultSkeletonIsObsolete) {
|
if (m_resultSkeletonIsObsolete) {
|
||||||
generateSkeleton();
|
generateSkeleton();
|
||||||
|
} else {
|
||||||
|
checkExportReadyState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshResultContext &SkeletonDocument::currentSkeletonResultContext()
|
void SkeletonDocument::postProcess()
|
||||||
{
|
{
|
||||||
return *m_currentSkeletonResultContext;
|
if (nullptr != m_postProcessor) {
|
||||||
|
m_postProcessResultIsObsolete = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Post processing..";
|
||||||
|
|
||||||
|
m_postProcessResultIsObsolete = false;
|
||||||
|
|
||||||
|
if (!m_currentMeshResultContext) {
|
||||||
|
qDebug() << "Mesh is null";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QThread *thread = new QThread;
|
||||||
|
m_postProcessor = new MeshResultPostProcessor(*m_currentMeshResultContext);
|
||||||
|
m_postProcessor->moveToThread(thread);
|
||||||
|
connect(thread, &QThread::started, m_postProcessor, &MeshResultPostProcessor::process);
|
||||||
|
connect(m_postProcessor, &MeshResultPostProcessor::finished, this, &SkeletonDocument::postProcessedMeshResultReady);
|
||||||
|
connect(m_postProcessor, &MeshResultPostProcessor::finished, thread, &QThread::quit);
|
||||||
|
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||||
|
thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonDocument::postProcessedMeshResultReady()
|
||||||
|
{
|
||||||
|
delete m_postProcessedResultContext;
|
||||||
|
m_postProcessedResultContext = m_postProcessor->takePostProcessedResultContext();
|
||||||
|
|
||||||
|
delete m_postProcessor;
|
||||||
|
m_postProcessor = nullptr;
|
||||||
|
|
||||||
|
qDebug() << "Post process done";
|
||||||
|
|
||||||
|
emit postProcessedResultChanged();
|
||||||
|
|
||||||
|
if (m_postProcessResultIsObsolete) {
|
||||||
|
postProcess();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshResultContext &SkeletonDocument::currentPostProcessedResultContext()
|
||||||
|
{
|
||||||
|
return *m_postProcessedResultContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocument::setPartLockState(QUuid partId, bool locked)
|
void SkeletonDocument::setPartLockState(QUuid partId, bool locked)
|
||||||
|
@ -1176,3 +1267,23 @@ void SkeletonDocument::setZlockState(bool locked)
|
||||||
zlocked = locked;
|
zlocked = locked;
|
||||||
emit zlockStateChanged();
|
emit zlockStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkeletonDocument::isExportReady() const
|
||||||
|
{
|
||||||
|
if (m_resultMeshIsObsolete ||
|
||||||
|
m_resultSkeletonIsObsolete ||
|
||||||
|
m_textureIsObsolete ||
|
||||||
|
m_postProcessResultIsObsolete ||
|
||||||
|
m_meshGenerator ||
|
||||||
|
m_skeletonGenerator ||
|
||||||
|
m_textureGenerator ||
|
||||||
|
m_postProcessor)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeletonDocument::checkExportReadyState()
|
||||||
|
{
|
||||||
|
if (isExportReady())
|
||||||
|
emit exportReady();
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "meshgenerator.h"
|
#include "meshgenerator.h"
|
||||||
#include "skeletongenerator.h"
|
#include "skeletongenerator.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
|
#include "texturegenerator.h"
|
||||||
|
#include "meshresultpostprocessor.h"
|
||||||
|
|
||||||
class SkeletonNode
|
class SkeletonNode
|
||||||
{
|
{
|
||||||
|
@ -186,6 +188,8 @@ signals:
|
||||||
void editModeChanged();
|
void editModeChanged();
|
||||||
void skeletonChanged();
|
void skeletonChanged();
|
||||||
void resultSkeletonChanged();
|
void resultSkeletonChanged();
|
||||||
|
void resultTextureChanged();
|
||||||
|
void postProcessedResultChanged();
|
||||||
void partLockStateChanged(QUuid partId);
|
void partLockStateChanged(QUuid partId);
|
||||||
void partVisibleStateChanged(QUuid partId);
|
void partVisibleStateChanged(QUuid partId);
|
||||||
void partSubdivStateChanged(QUuid partId);
|
void partSubdivStateChanged(QUuid partId);
|
||||||
|
@ -206,6 +210,7 @@ signals:
|
||||||
void partUnchecked(QUuid partId);
|
void partUnchecked(QUuid partId);
|
||||||
void enableBackgroundBlur();
|
void enableBackgroundBlur();
|
||||||
void disableBackgroundBlur();
|
void disableBackgroundBlur();
|
||||||
|
void exportReady();
|
||||||
public: // need initialize
|
public: // need initialize
|
||||||
float originX;
|
float originX;
|
||||||
float originY;
|
float originY;
|
||||||
|
@ -214,6 +219,9 @@ public: // need initialize
|
||||||
bool xlocked;
|
bool xlocked;
|
||||||
bool ylocked;
|
bool ylocked;
|
||||||
bool zlocked;
|
bool zlocked;
|
||||||
|
QImage *textureGuideImage;
|
||||||
|
QImage *textureImage;
|
||||||
|
QImage *textureBorderImage;
|
||||||
public:
|
public:
|
||||||
SkeletonDocument();
|
SkeletonDocument();
|
||||||
~SkeletonDocument();
|
~SkeletonDocument();
|
||||||
|
@ -239,7 +247,8 @@ public:
|
||||||
bool isNodeEditable(QUuid nodeId) const;
|
bool isNodeEditable(QUuid nodeId) const;
|
||||||
bool isEdgeEditable(QUuid edgeId) const;
|
bool isEdgeEditable(QUuid edgeId) const;
|
||||||
bool originSettled() const;
|
bool originSettled() const;
|
||||||
MeshResultContext ¤tSkeletonResultContext();
|
MeshResultContext ¤tPostProcessedResultContext();
|
||||||
|
bool isExportReady() const;
|
||||||
public slots:
|
public slots:
|
||||||
void removeNode(QUuid nodeId);
|
void removeNode(QUuid nodeId);
|
||||||
void removeEdge(QUuid edgeId);
|
void removeEdge(QUuid edgeId);
|
||||||
|
@ -257,6 +266,10 @@ public slots:
|
||||||
void meshReady();
|
void meshReady();
|
||||||
void generateSkeleton();
|
void generateSkeleton();
|
||||||
void skeletonReady();
|
void skeletonReady();
|
||||||
|
void generateTexture();
|
||||||
|
void textureReady();
|
||||||
|
void postProcess();
|
||||||
|
void postProcessedMeshResultReady();
|
||||||
void setPartLockState(QUuid partId, bool locked);
|
void setPartLockState(QUuid partId, bool locked);
|
||||||
void setPartVisibleState(QUuid partId, bool visible);
|
void setPartVisibleState(QUuid partId, bool visible);
|
||||||
void setPartSubdivState(QUuid partId, bool subdived);
|
void setPartSubdivState(QUuid partId, bool subdived);
|
||||||
|
@ -285,6 +298,7 @@ private:
|
||||||
bool isPartReadonly(QUuid partId) const;
|
bool isPartReadonly(QUuid partId) const;
|
||||||
QUuid createNode(float x, float y, float z, float radius, QUuid fromNodeId);
|
QUuid createNode(float x, float y, float z, float radius, QUuid fromNodeId);
|
||||||
void settleOrigin();
|
void settleOrigin();
|
||||||
|
void checkExportReadyState();
|
||||||
private: // need initialize
|
private: // need initialize
|
||||||
bool m_resultMeshIsObsolete;
|
bool m_resultMeshIsObsolete;
|
||||||
MeshGenerator *m_meshGenerator;
|
MeshGenerator *m_meshGenerator;
|
||||||
|
@ -294,7 +308,11 @@ private: // need initialize
|
||||||
bool m_resultSkeletonIsObsolete;
|
bool m_resultSkeletonIsObsolete;
|
||||||
SkeletonGenerator *m_skeletonGenerator;
|
SkeletonGenerator *m_skeletonGenerator;
|
||||||
Mesh *m_resultSkeletonMesh;
|
Mesh *m_resultSkeletonMesh;
|
||||||
MeshResultContext *m_currentSkeletonResultContext;
|
bool m_textureIsObsolete;
|
||||||
|
TextureGenerator *m_textureGenerator;
|
||||||
|
bool m_postProcessResultIsObsolete;
|
||||||
|
MeshResultPostProcessor *m_postProcessor;
|
||||||
|
MeshResultContext *m_postProcessedResultContext;
|
||||||
private:
|
private:
|
||||||
static unsigned long m_maxSnapshot;
|
static unsigned long m_maxSnapshot;
|
||||||
std::deque<SkeletonHistoryItem> m_undoItems;
|
std::deque<SkeletonHistoryItem> m_undoItems;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "skeletonsnapshot.h"
|
#include "skeletonsnapshot.h"
|
||||||
#include "skeletonxml.h"
|
#include "skeletonxml.h"
|
||||||
#include "logbrowser.h"
|
#include "logbrowser.h"
|
||||||
#include "util.h"
|
#include "dust3dutil.h"
|
||||||
#include "aboutwidget.h"
|
#include "aboutwidget.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "gltffile.h"
|
#include "gltffile.h"
|
||||||
|
@ -45,7 +45,7 @@ void outputMessage(QtMsgType type, const QMessageLogContext &context, const QStr
|
||||||
g_logBrowser->outputMessage(type, msg);
|
g_logBrowser->outputMessage(type, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocumentWindow::SkeletonDocumentWindow::showAcknowlegements()
|
void SkeletonDocumentWindow::showAcknowlegements()
|
||||||
{
|
{
|
||||||
if (!g_acknowlegementsWidget) {
|
if (!g_acknowlegementsWidget) {
|
||||||
g_acknowlegementsWidget = new QTextBrowser;
|
g_acknowlegementsWidget = new QTextBrowser;
|
||||||
|
@ -61,7 +61,7 @@ void SkeletonDocumentWindow::SkeletonDocumentWindow::showAcknowlegements()
|
||||||
g_acknowlegementsWidget->raise();
|
g_acknowlegementsWidget->raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocumentWindow::SkeletonDocumentWindow::showAbout()
|
void SkeletonDocumentWindow::showAbout()
|
||||||
{
|
{
|
||||||
if (!g_aboutWidget) {
|
if (!g_aboutWidget) {
|
||||||
g_aboutWidget = new AboutWidget;
|
g_aboutWidget = new AboutWidget;
|
||||||
|
@ -71,10 +71,28 @@ void SkeletonDocumentWindow::SkeletonDocumentWindow::showAbout()
|
||||||
g_aboutWidget->raise();
|
g_aboutWidget->raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonDocumentWindow::showTextureGuidePreview()
|
||||||
|
{
|
||||||
|
if (!m_textureGuideWidget) {
|
||||||
|
m_textureGuideWidget = new TextureGuideWidget;
|
||||||
|
connect(m_textureGuideWidget, &TextureGuideWidget::regenerate, m_document, &SkeletonDocument::generateMesh);
|
||||||
|
}
|
||||||
|
if (m_textureGuideWidget->isHidden()) {
|
||||||
|
if (m_document->textureGuideImage) {
|
||||||
|
m_textureGuideWidget->updateGuideImage(*m_document->textureGuideImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_textureGuideWidget->show();
|
||||||
|
m_textureGuideWidget->activateWindow();
|
||||||
|
m_textureGuideWidget->raise();
|
||||||
|
}
|
||||||
|
|
||||||
SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
m_document(nullptr),
|
m_document(nullptr),
|
||||||
m_firstShow(true),
|
m_firstShow(true),
|
||||||
m_documentSaved(true)
|
m_documentSaved(true),
|
||||||
|
m_textureGuideWidget(nullptr),
|
||||||
|
m_exportRequired(false)
|
||||||
{
|
{
|
||||||
if (!g_logBrowser) {
|
if (!g_logBrowser) {
|
||||||
g_logBrowser = new LogBrowser;
|
g_logBrowser = new LogBrowser;
|
||||||
|
@ -231,12 +249,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
connect(m_exportModelAction, &QAction::triggered, this, &SkeletonDocumentWindow::exportModelResult, Qt::QueuedConnection);
|
connect(m_exportModelAction, &QAction::triggered, this, &SkeletonDocumentWindow::exportModelResult, Qt::QueuedConnection);
|
||||||
m_exportMenu->addAction(m_exportModelAction);
|
m_exportMenu->addAction(m_exportModelAction);
|
||||||
|
|
||||||
m_exportModelAndMaterialsAction = new QAction(tr("Model and Materials(.obj)..."), this);
|
|
||||||
connect(m_exportModelAndMaterialsAction, &QAction::triggered, this, &SkeletonDocumentWindow::exportModelAndMaterialResult, Qt::QueuedConnection);
|
|
||||||
//m_exportMenu->addAction(m_exportModelAndMaterialsAction);
|
|
||||||
|
|
||||||
m_exportSkeletonAction = new QAction(tr("GL Transmission Format (.gltf)..."), this);
|
m_exportSkeletonAction = new QAction(tr("GL Transmission Format (.gltf)..."), this);
|
||||||
connect(m_exportSkeletonAction, &QAction::triggered, this, &SkeletonDocumentWindow::exportSkeletonResult, Qt::QueuedConnection);
|
connect(m_exportSkeletonAction, &QAction::triggered, this, &SkeletonDocumentWindow::exportGltfResult, Qt::QueuedConnection);
|
||||||
m_exportMenu->addAction(m_exportSkeletonAction);
|
m_exportMenu->addAction(m_exportSkeletonAction);
|
||||||
|
|
||||||
m_changeTurnaroundAction = new QAction(tr("Change Turnaround..."), this);
|
m_changeTurnaroundAction = new QAction(tr("Change Turnaround..."), this);
|
||||||
|
@ -245,7 +259,6 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
|
|
||||||
connect(m_fileMenu, &QMenu::aboutToShow, [=]() {
|
connect(m_fileMenu, &QMenu::aboutToShow, [=]() {
|
||||||
m_exportModelAction->setEnabled(m_graphicsWidget->hasItems());
|
m_exportModelAction->setEnabled(m_graphicsWidget->hasItems());
|
||||||
m_exportModelAndMaterialsAction->setEnabled(m_graphicsWidget->hasItems());
|
|
||||||
m_exportSkeletonAction->setEnabled(m_graphicsWidget->hasItems());
|
m_exportSkeletonAction->setEnabled(m_graphicsWidget->hasItems());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -341,6 +354,14 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
});
|
});
|
||||||
m_viewMenu->addAction(m_resetModelWidgetPosAction);
|
m_viewMenu->addAction(m_resetModelWidgetPosAction);
|
||||||
|
|
||||||
|
m_toggleWireframeAction = new QAction(tr("Toggle Wireframe"), this);
|
||||||
|
connect(m_toggleWireframeAction, &QAction::triggered, [=]() {
|
||||||
|
m_modelRenderWidget->toggleWireframe();
|
||||||
|
});
|
||||||
|
m_viewMenu->addAction(m_toggleWireframeAction);
|
||||||
|
|
||||||
|
m_viewMenu->addSeparator();
|
||||||
|
|
||||||
m_toggleSkeletonWidgetAction = new QAction(tr("Toggle Bones"), this);
|
m_toggleSkeletonWidgetAction = new QAction(tr("Toggle Bones"), this);
|
||||||
connect(m_toggleSkeletonWidgetAction, &QAction::triggered, [=]() {
|
connect(m_toggleSkeletonWidgetAction, &QAction::triggered, [=]() {
|
||||||
if (m_skeletonRenderWidget->isVisible()) {
|
if (m_skeletonRenderWidget->isVisible()) {
|
||||||
|
@ -355,17 +376,21 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
});
|
});
|
||||||
m_viewMenu->addAction(m_toggleSkeletonWidgetAction);
|
m_viewMenu->addAction(m_toggleSkeletonWidgetAction);
|
||||||
|
|
||||||
|
m_viewMenu->addSeparator();
|
||||||
|
|
||||||
|
m_showTextureGuidePreviewAction = new QAction(tr("Show Texture"), this);
|
||||||
|
connect(m_showTextureGuidePreviewAction, &QAction::triggered, this, &SkeletonDocumentWindow::showTextureGuidePreview);
|
||||||
|
m_viewMenu->addAction(m_showTextureGuidePreviewAction);
|
||||||
|
|
||||||
|
m_viewMenu->addSeparator();
|
||||||
|
|
||||||
m_showPartsListAction = new QAction(tr("Show Parts List"), this);
|
m_showPartsListAction = new QAction(tr("Show Parts List"), this);
|
||||||
connect(m_showPartsListAction, &QAction::triggered, [=]() {
|
connect(m_showPartsListAction, &QAction::triggered, [=]() {
|
||||||
partListWidget->show();
|
partListWidget->show();
|
||||||
});
|
});
|
||||||
m_viewMenu->addAction(m_showPartsListAction);
|
m_viewMenu->addAction(m_showPartsListAction);
|
||||||
|
|
||||||
m_toggleWireframeAction = new QAction(tr("Toggle Wireframe"), this);
|
m_viewMenu->addSeparator();
|
||||||
connect(m_toggleWireframeAction, &QAction::triggered, [=]() {
|
|
||||||
m_modelRenderWidget->toggleWireframe();
|
|
||||||
});
|
|
||||||
m_viewMenu->addAction(m_toggleWireframeAction);
|
|
||||||
|
|
||||||
m_showDebugDialogAction = new QAction(tr("Show Debug Dialog"), this);
|
m_showDebugDialogAction = new QAction(tr("Show Debug Dialog"), this);
|
||||||
connect(m_showDebugDialogAction, &QAction::triggered, g_logBrowser, &LogBrowser::showDialog);
|
connect(m_showDebugDialogAction, &QAction::triggered, g_logBrowser, &LogBrowser::showDialog);
|
||||||
|
@ -437,6 +462,12 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
m_document->setZlockState(!m_document->zlocked);
|
m_document->setZlockState(!m_document->zlocked);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(m_document, &SkeletonDocument::resultTextureChanged, [=]() {
|
||||||
|
if (m_document->textureGuideImage && m_textureGuideWidget && m_textureGuideWidget->isVisible()) {
|
||||||
|
m_textureGuideWidget->updateGuideImage(*m_document->textureGuideImage);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_document, &SkeletonDocument::editModeChanged, graphicsWidget, &SkeletonGraphicsWidget::editModeChanged);
|
connect(m_document, &SkeletonDocument::editModeChanged, graphicsWidget, &SkeletonGraphicsWidget::editModeChanged);
|
||||||
|
|
||||||
connect(graphicsWidget, &SkeletonGraphicsWidget::addNode, m_document, &SkeletonDocument::addNode);
|
connect(graphicsWidget, &SkeletonGraphicsWidget::addNode, m_document, &SkeletonDocument::addNode);
|
||||||
|
@ -502,7 +533,9 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
connect(m_document, &SkeletonDocument::partUnchecked, partListWidget, &SkeletonPartListWidget::partUnchecked);
|
connect(m_document, &SkeletonDocument::partUnchecked, partListWidget, &SkeletonPartListWidget::partUnchecked);
|
||||||
|
|
||||||
connect(m_document, &SkeletonDocument::skeletonChanged, m_document, &SkeletonDocument::generateMesh);
|
connect(m_document, &SkeletonDocument::skeletonChanged, m_document, &SkeletonDocument::generateMesh);
|
||||||
connect(m_document, &SkeletonDocument::resultMeshChanged, m_document, &SkeletonDocument::generateSkeleton);
|
connect(m_document, &SkeletonDocument::resultMeshChanged, m_document, &SkeletonDocument::postProcess);
|
||||||
|
connect(m_document, &SkeletonDocument::postProcessedResultChanged, m_document, &SkeletonDocument::generateSkeleton);
|
||||||
|
connect(m_document, &SkeletonDocument::postProcessedResultChanged, m_document, &SkeletonDocument::generateTexture);
|
||||||
|
|
||||||
connect(m_document, &SkeletonDocument::resultMeshChanged, [=]() {
|
connect(m_document, &SkeletonDocument::resultMeshChanged, [=]() {
|
||||||
m_modelRenderWidget->updateMesh(m_document->takeResultMesh());
|
m_modelRenderWidget->updateMesh(m_document->takeResultMesh());
|
||||||
|
@ -527,6 +560,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() :
|
||||||
connect(m_document, &SkeletonDocument::ylockStateChanged, this, &SkeletonDocumentWindow::updateYlockButtonState);
|
connect(m_document, &SkeletonDocument::ylockStateChanged, this, &SkeletonDocumentWindow::updateYlockButtonState);
|
||||||
connect(m_document, &SkeletonDocument::zlockStateChanged, this, &SkeletonDocumentWindow::updateZlockButtonState);
|
connect(m_document, &SkeletonDocument::zlockStateChanged, this, &SkeletonDocumentWindow::updateZlockButtonState);
|
||||||
|
|
||||||
|
connect(m_document, &SkeletonDocument::exportReady, this, &SkeletonDocumentWindow::checkDelayedExport);
|
||||||
|
|
||||||
connect(this, &SkeletonDocumentWindow::initialized, m_document, &SkeletonDocument::uiReady);
|
connect(this, &SkeletonDocumentWindow::initialized, m_document, &SkeletonDocument::uiReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,6 +701,10 @@ void SkeletonDocumentWindow::initLockButton(QPushButton *button)
|
||||||
|
|
||||||
SkeletonDocumentWindow::~SkeletonDocumentWindow()
|
SkeletonDocumentWindow::~SkeletonDocumentWindow()
|
||||||
{
|
{
|
||||||
|
if (m_textureGuideWidget) {
|
||||||
|
delete m_textureGuideWidget;
|
||||||
|
m_textureGuideWidget = nullptr;
|
||||||
|
}
|
||||||
g_documentWindows.erase(this);
|
g_documentWindows.erase(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -796,29 +835,30 @@ void SkeletonDocumentWindow::exportModelResult()
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonDocumentWindow::exportModelAndMaterialResult()
|
void SkeletonDocumentWindow::exportGltfResult()
|
||||||
{
|
{
|
||||||
QString filename = QFileDialog::getSaveFileName(this, QString(), QString(),
|
if (!m_document->isExportReady()) {
|
||||||
tr("Wavefront (*.obj)"));
|
m_exportRequired = true;
|
||||||
if (filename.isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
||||||
m_modelRenderWidget->exportMeshAsObjPlusMaterials(filename);
|
|
||||||
QApplication::restoreOverrideCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkeletonDocumentWindow::exportSkeletonResult()
|
m_exportRequired = false;
|
||||||
{
|
|
||||||
QString filename = QFileDialog::getSaveFileName(this, QString(), QString(),
|
QString filename = QFileDialog::getSaveFileName(this, QString(), QString(),
|
||||||
tr("glTF (*.gltf)"));
|
tr("GL Transmission Format (.gltf)"));
|
||||||
if (filename.isEmpty()) {
|
if (filename.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
MeshResultContext skeletonResult = m_document->currentSkeletonResultContext();
|
MeshResultContext skeletonResult = m_document->currentPostProcessedResultContext();
|
||||||
GLTFFileWriter gltfFileWriter(skeletonResult);
|
GLTFFileWriter gltfFileWriter(skeletonResult, filename);
|
||||||
gltfFileWriter.save(filename);
|
gltfFileWriter.save();
|
||||||
|
if (m_document->textureImage)
|
||||||
|
m_document->textureImage->save(gltfFileWriter.textureFilenameInGltf());
|
||||||
|
QFileInfo nameInfo(filename);
|
||||||
|
QString guideFilename = nameInfo.path() + QDir::separator() + nameInfo.completeBaseName() + "-BORDER.png";
|
||||||
|
if (m_document->textureBorderImage)
|
||||||
|
m_document->textureBorderImage->save(guideFilename);
|
||||||
QApplication::restoreOverrideCursor();
|
QApplication::restoreOverrideCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,3 +885,10 @@ void SkeletonDocumentWindow::updateZlockButtonState()
|
||||||
else
|
else
|
||||||
m_zlockButton->setStyleSheet("QPushButton {color: #aaebc4}");
|
m_zlockButton->setStyleSheet("QPushButton {color: #aaebc4}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkeletonDocumentWindow::checkDelayedExport()
|
||||||
|
{
|
||||||
|
if (!m_exportRequired)
|
||||||
|
return;
|
||||||
|
exportGltfResult();
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <QTextBrowser>
|
#include <QTextBrowser>
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
#include "modelwidget.h"
|
#include "modelwidget.h"
|
||||||
|
#include "textureguidewidget.h"
|
||||||
|
|
||||||
class SkeletonGraphicsWidget;
|
class SkeletonGraphicsWidget;
|
||||||
|
|
||||||
|
@ -33,8 +34,7 @@ public slots:
|
||||||
void saveTo(const QString &saveAsFilename);
|
void saveTo(const QString &saveAsFilename);
|
||||||
void open();
|
void open();
|
||||||
void exportModelResult();
|
void exportModelResult();
|
||||||
void exportModelAndMaterialResult();
|
void exportGltfResult();
|
||||||
void exportSkeletonResult();
|
|
||||||
void newWindow();
|
void newWindow();
|
||||||
void newDocument();
|
void newDocument();
|
||||||
void saveAs();
|
void saveAs();
|
||||||
|
@ -48,6 +48,8 @@ public slots:
|
||||||
void updateXlockButtonState();
|
void updateXlockButtonState();
|
||||||
void updateYlockButtonState();
|
void updateYlockButtonState();
|
||||||
void updateZlockButtonState();
|
void updateZlockButtonState();
|
||||||
|
void showTextureGuidePreview();
|
||||||
|
void checkDelayedExport();
|
||||||
private:
|
private:
|
||||||
void initAwesomeButton(QPushButton *button);
|
void initAwesomeButton(QPushButton *button);
|
||||||
void initLockButton(QPushButton *button);
|
void initLockButton(QPushButton *button);
|
||||||
|
@ -57,6 +59,8 @@ private:
|
||||||
SkeletonDocument *m_document;
|
SkeletonDocument *m_document;
|
||||||
bool m_firstShow;
|
bool m_firstShow;
|
||||||
bool m_documentSaved;
|
bool m_documentSaved;
|
||||||
|
TextureGuideWidget *m_textureGuideWidget;
|
||||||
|
bool m_exportRequired;
|
||||||
private:
|
private:
|
||||||
QString m_currentFilename;
|
QString m_currentFilename;
|
||||||
|
|
||||||
|
@ -75,7 +79,6 @@ private:
|
||||||
QAction *m_changeTurnaroundAction;
|
QAction *m_changeTurnaroundAction;
|
||||||
|
|
||||||
QAction *m_exportModelAction;
|
QAction *m_exportModelAction;
|
||||||
QAction *m_exportModelAndMaterialsAction;
|
|
||||||
QAction *m_exportSkeletonAction;
|
QAction *m_exportSkeletonAction;
|
||||||
|
|
||||||
QMenu *m_editMenu;
|
QMenu *m_editMenu;
|
||||||
|
@ -101,6 +104,7 @@ private:
|
||||||
QAction *m_showPartsListAction;
|
QAction *m_showPartsListAction;
|
||||||
QAction *m_showDebugDialogAction;
|
QAction *m_showDebugDialogAction;
|
||||||
QAction *m_toggleWireframeAction;
|
QAction *m_toggleWireframeAction;
|
||||||
|
QAction *m_showTextureGuidePreviewAction;
|
||||||
|
|
||||||
QMenu *m_helpMenu;
|
QMenu *m_helpMenu;
|
||||||
QAction *m_viewSourceAction;
|
QAction *m_viewSourceAction;
|
||||||
|
|
|
@ -76,18 +76,8 @@ struct BmeshNodeDistWithWorldCenter
|
||||||
float dist2;
|
float dist2;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SkeletonGenerator::combineAllBmeshSkeletons()
|
|
||||||
{
|
|
||||||
m_meshResultContext->resolveBmeshConnectivity();
|
|
||||||
m_meshResultContext->resolveBmeshEdgeDirections();
|
|
||||||
m_meshResultContext->resultParts();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkeletonGenerator::process()
|
void SkeletonGenerator::process()
|
||||||
{
|
{
|
||||||
if (!m_meshResultContext->bmeshNodes.empty())
|
|
||||||
combineAllBmeshSkeletons();
|
|
||||||
|
|
||||||
m_resultSkeletonMesh = createSkeletonMesh();
|
m_resultSkeletonMesh = createSkeletonMesh();
|
||||||
|
|
||||||
this->moveToThread(QGuiApplication::instance()->thread());
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <QMatrix4x4>
|
#include <QMatrix4x4>
|
||||||
#include "skeletongraphicswidget.h"
|
#include "skeletongraphicswidget.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "util.h"
|
#include "dust3dutil.h"
|
||||||
#include "skeletonxml.h"
|
#include "skeletonxml.h"
|
||||||
|
|
||||||
SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document) :
|
SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument *document) :
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
#include "turnaroundloader.h"
|
#include "turnaroundloader.h"
|
||||||
#include "theme.h"
|
#include "theme.h"
|
||||||
#include "util.h"
|
#include "dust3dutil.h"
|
||||||
|
|
||||||
class SkeletonGraphicsOriginItem : public QGraphicsPolygonItem
|
class SkeletonGraphicsOriginItem : public QGraphicsPolygonItem
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "skeletonsnapshot.h"
|
#include "skeletonsnapshot.h"
|
||||||
#include "util.h"
|
#include "dust3dutil.h"
|
||||||
|
|
||||||
void SkeletonSnapshot::resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile, const QString &partId)
|
void SkeletonSnapshot::resolveBoundingBox(QRectF *mainProfile, QRectF *sideProfile, const QString &partId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include "texturegenerator.h"
|
||||||
|
#include "theme.h"
|
||||||
|
|
||||||
|
int TextureGenerator::m_textureWidth = 256;
|
||||||
|
int TextureGenerator::m_textureHeight = 256;
|
||||||
|
|
||||||
|
TextureGenerator::TextureGenerator(const MeshResultContext &meshResultContext) :
|
||||||
|
m_resultTextureGuideImage(nullptr),
|
||||||
|
m_resultTextureImage(nullptr),
|
||||||
|
m_resultTextureBorderImage(nullptr)
|
||||||
|
{
|
||||||
|
m_resultContext = new MeshResultContext();
|
||||||
|
*m_resultContext = meshResultContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureGenerator::~TextureGenerator()
|
||||||
|
{
|
||||||
|
delete m_resultContext;
|
||||||
|
delete m_resultTextureGuideImage;
|
||||||
|
delete m_resultTextureImage;
|
||||||
|
delete m_resultTextureBorderImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage *TextureGenerator::takeResultTextureGuideImage()
|
||||||
|
{
|
||||||
|
QImage *resultTextureGuideImage = m_resultTextureGuideImage;
|
||||||
|
m_resultTextureGuideImage = nullptr;
|
||||||
|
return resultTextureGuideImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage *TextureGenerator::takeResultTextureImage()
|
||||||
|
{
|
||||||
|
QImage *resultTextureImage = m_resultTextureImage;
|
||||||
|
m_resultTextureImage = nullptr;
|
||||||
|
return resultTextureImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage *TextureGenerator::takeResultTextureBorderImage()
|
||||||
|
{
|
||||||
|
QImage *resultTextureBorderImage = m_resultTextureBorderImage;
|
||||||
|
m_resultTextureBorderImage = nullptr;
|
||||||
|
return resultTextureBorderImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshResultContext *TextureGenerator::takeResultContext()
|
||||||
|
{
|
||||||
|
MeshResultContext *resultContext = m_resultContext;
|
||||||
|
m_resultTextureImage = nullptr;
|
||||||
|
return resultContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureGenerator::process()
|
||||||
|
{
|
||||||
|
const std::vector<QColor> &triangleColors = m_resultContext->triangleColors();
|
||||||
|
const std::vector<ResultTriangleUv> &triangleUvs = m_resultContext->triangleUvs();
|
||||||
|
|
||||||
|
m_resultTextureGuideImage = new QImage(TextureGenerator::m_textureWidth, TextureGenerator::m_textureHeight, QImage::Format_ARGB32);
|
||||||
|
m_resultTextureGuideImage->fill(Theme::black);
|
||||||
|
|
||||||
|
m_resultTextureImage = new QImage(TextureGenerator::m_textureWidth, TextureGenerator::m_textureHeight, QImage::Format_ARGB32);
|
||||||
|
m_resultTextureImage->fill(Qt::transparent);
|
||||||
|
|
||||||
|
m_resultTextureBorderImage = new QImage(TextureGenerator::m_textureWidth, TextureGenerator::m_textureHeight, QImage::Format_ARGB32);
|
||||||
|
m_resultTextureBorderImage->fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter guidePainter;
|
||||||
|
guidePainter.begin(m_resultTextureGuideImage);
|
||||||
|
guidePainter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
guidePainter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
QColor borderColor = Qt::darkGray;
|
||||||
|
QPen pen(borderColor);
|
||||||
|
|
||||||
|
QPainter texturePainter;
|
||||||
|
texturePainter.begin(m_resultTextureImage);
|
||||||
|
texturePainter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
texturePainter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
|
||||||
|
QPainter textureBorderPainter;
|
||||||
|
textureBorderPainter.begin(m_resultTextureBorderImage);
|
||||||
|
textureBorderPainter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
textureBorderPainter.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
|
||||||
|
// round 1, paint background
|
||||||
|
for (auto i = 0u; i < triangleUvs.size(); i++) {
|
||||||
|
QPainterPath path;
|
||||||
|
const ResultTriangleUv *uv = &triangleUvs[i];
|
||||||
|
for (auto j = 0; j < 3; j++) {
|
||||||
|
if (0 == j) {
|
||||||
|
path.moveTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
||||||
|
} else {
|
||||||
|
path.lineTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QPen textureBorderPen(triangleColors[i]);
|
||||||
|
textureBorderPen.setWidth(10);
|
||||||
|
texturePainter.setPen(textureBorderPen);
|
||||||
|
texturePainter.setBrush(QBrush(triangleColors[i]));
|
||||||
|
texturePainter.drawPath(path);
|
||||||
|
}
|
||||||
|
// round 2, real paint
|
||||||
|
texturePainter.setPen(Qt::NoPen);
|
||||||
|
guidePainter.setPen(Qt::NoPen);
|
||||||
|
for (auto i = 0u; i < triangleUvs.size(); i++) {
|
||||||
|
QPainterPath path;
|
||||||
|
const ResultTriangleUv *uv = &triangleUvs[i];
|
||||||
|
for (auto j = 0; j < 3; j++) {
|
||||||
|
if (0 == j) {
|
||||||
|
path.moveTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
||||||
|
} else {
|
||||||
|
path.lineTo(uv->uv[j][0] * TextureGenerator::m_textureWidth, uv->uv[j][1] * TextureGenerator::m_textureHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guidePainter.fillPath(path, QBrush(triangleColors[i]));
|
||||||
|
texturePainter.fillPath(path, QBrush(triangleColors[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
pen.setWidth(0);
|
||||||
|
guidePainter.setPen(pen);
|
||||||
|
textureBorderPainter.setPen(pen);
|
||||||
|
for (auto i = 0u; i < triangleUvs.size(); i++) {
|
||||||
|
const ResultTriangleUv *uv = &triangleUvs[i];
|
||||||
|
for (auto j = 0; j < 3; j++) {
|
||||||
|
int from = j;
|
||||||
|
int to = (j + 1) % 3;
|
||||||
|
guidePainter.drawLine(uv->uv[from][0] * TextureGenerator::m_textureWidth, uv->uv[from][1] * TextureGenerator::m_textureHeight,
|
||||||
|
uv->uv[to][0] * TextureGenerator::m_textureWidth, uv->uv[to][1] * TextureGenerator::m_textureHeight);
|
||||||
|
textureBorderPainter.drawLine(uv->uv[from][0] * TextureGenerator::m_textureWidth, uv->uv[from][1] * TextureGenerator::m_textureHeight,
|
||||||
|
uv->uv[to][0] * TextureGenerator::m_textureWidth, uv->uv[to][1] * TextureGenerator::m_textureHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
texturePainter.end();
|
||||||
|
guidePainter.end();
|
||||||
|
textureBorderPainter.end();
|
||||||
|
|
||||||
|
this->moveToThread(QGuiApplication::instance()->thread());
|
||||||
|
|
||||||
|
emit finished();
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef TEXTURE_GENERATOR_H
|
||||||
|
#define TEXTURE_GENERATOR_H
|
||||||
|
#include <QObject>
|
||||||
|
#include <vector>
|
||||||
|
#include <QImage>
|
||||||
|
#include "meshresultcontext.h"
|
||||||
|
|
||||||
|
class TextureGenerator : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
TextureGenerator(const MeshResultContext &meshResultContext);
|
||||||
|
~TextureGenerator();
|
||||||
|
QImage *takeResultTextureGuideImage();
|
||||||
|
QImage *takeResultTextureImage();
|
||||||
|
QImage *takeResultTextureBorderImage();
|
||||||
|
MeshResultContext *takeResultContext();
|
||||||
|
signals:
|
||||||
|
void finished();
|
||||||
|
public slots:
|
||||||
|
void process();
|
||||||
|
public:
|
||||||
|
static int m_textureWidth;
|
||||||
|
static int m_textureHeight;
|
||||||
|
private:
|
||||||
|
MeshResultContext *m_resultContext;
|
||||||
|
QImage *m_resultTextureGuideImage;
|
||||||
|
QImage *m_resultTextureImage;
|
||||||
|
QImage *m_resultTextureBorderImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,73 @@
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QSizePolicy>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include "textureguidewidget.h"
|
||||||
|
#include "aboutwidget.h"
|
||||||
|
#include "version.h"
|
||||||
|
#include "theme.h"
|
||||||
|
|
||||||
|
TextureGuideWidget::TextureGuideWidget() :
|
||||||
|
m_previewLabel(nullptr)
|
||||||
|
{
|
||||||
|
QVBoxLayout *toolButtonLayout = new QVBoxLayout;
|
||||||
|
toolButtonLayout->setSpacing(0);
|
||||||
|
toolButtonLayout->setContentsMargins(5, 10, 4, 0);
|
||||||
|
|
||||||
|
m_previewLabel = new QLabel;
|
||||||
|
m_previewLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
QPushButton *regenerateButton = new QPushButton(QChar(fa::recycle));
|
||||||
|
initAwesomeButton(regenerateButton);
|
||||||
|
connect(regenerateButton, &QPushButton::clicked, this, &TextureGuideWidget::regenerate);
|
||||||
|
|
||||||
|
toolButtonLayout->addWidget(regenerateButton);
|
||||||
|
toolButtonLayout->addStretch();
|
||||||
|
|
||||||
|
QGridLayout *containerLayout = new QGridLayout;
|
||||||
|
containerLayout->setSpacing(0);
|
||||||
|
containerLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
containerLayout->addWidget(m_previewLabel);
|
||||||
|
containerLayout->setRowStretch(0, 1);
|
||||||
|
containerLayout->setColumnStretch(0, 1);
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
mainLayout->setSpacing(0);
|
||||||
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
mainLayout->addLayout(toolButtonLayout);
|
||||||
|
mainLayout->addLayout(containerLayout);
|
||||||
|
|
||||||
|
setLayout(mainLayout);
|
||||||
|
setMinimumSize(128, 128);
|
||||||
|
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
|
setWindowTitle(APP_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureGuideWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
resizeImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureGuideWidget::resizeImage()
|
||||||
|
{
|
||||||
|
QPixmap pixmap = QPixmap::fromImage(m_image);
|
||||||
|
m_previewLabel->setPixmap(pixmap.scaled(m_previewLabel->width(), m_previewLabel->height(), Qt::KeepAspectRatio));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureGuideWidget::updateGuideImage(const QImage &image)
|
||||||
|
{
|
||||||
|
m_image = image;
|
||||||
|
resizeImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureGuideWidget::initAwesomeButton(QPushButton *button)
|
||||||
|
{
|
||||||
|
button->setFont(Theme::awesome()->font(Theme::toolIconFontSize));
|
||||||
|
button->setFixedSize(Theme::toolIconSize, Theme::toolIconSize);
|
||||||
|
button->setStyleSheet("QPushButton {color: #f7d9c8}");
|
||||||
|
button->setFocusPolicy(Qt::NoFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef TEXTURE_GUIDE_WIDGET_H
|
||||||
|
#define TEXTURE_GUIDE_WIDGET_H
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
class TextureGuideWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
signals:
|
||||||
|
void regenerate();
|
||||||
|
public:
|
||||||
|
TextureGuideWidget();
|
||||||
|
void updateGuideImage(const QImage &image);
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *event);
|
||||||
|
private:
|
||||||
|
void resizeImage();
|
||||||
|
void initAwesomeButton(QPushButton *button);
|
||||||
|
private:
|
||||||
|
QLabel *m_previewLabel;
|
||||||
|
QImage m_image;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,2 +0,0 @@
|
||||||
#include "uvunwrapper.h"
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef UV_UNWRAPPER_H
|
|
||||||
#define UV_UNWRAPPER_H
|
|
||||||
|
|
||||||
class UvUnwrapper
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
Binary file not shown.
Binary file not shown.
|
@ -46,6 +46,9 @@ int meshlite_bmesh_generate_mesh(void *context, int bmesh_id);
|
||||||
int meshlite_bmesh_get_node_base_norm(void *context, int bmesh_id, int node_id, float *norm_buffer);
|
int meshlite_bmesh_get_node_base_norm(void *context, int bmesh_id, int node_id, float *norm_buffer);
|
||||||
int meshlite_bmesh_destroy(void *context, int bmesh_id);
|
int meshlite_bmesh_destroy(void *context, int bmesh_id);
|
||||||
int meshlite_bmesh_error_count(void *context, int bmesh_id);
|
int meshlite_bmesh_error_count(void *context, int bmesh_id);
|
||||||
|
int meshlite_bmesh_add_seam_requirement(void *context, int bmesh_id);
|
||||||
|
int meshlite_bmesh_get_seam_count(void *context, int bmesh_id);
|
||||||
|
int meshlite_bmesh_get_seam_index_array(void *context, int bmesh_id, int *buffer, int max_buffer_len);
|
||||||
int meshlite_combine_adj_faces(void *context, int mesh_id);
|
int meshlite_combine_adj_faces(void *context, int mesh_id);
|
||||||
int meshlite_combine_coplanar_faces(void *context, int mesh_id);
|
int meshlite_combine_coplanar_faces(void *context, int mesh_id);
|
||||||
int meshlite_trim(void *context, int mesh_id, int normalize);
|
int meshlite_trim(void *context, int mesh_id, int normalize);
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -46,6 +46,9 @@ int meshlite_bmesh_generate_mesh(void *context, int bmesh_id);
|
||||||
int meshlite_bmesh_get_node_base_norm(void *context, int bmesh_id, int node_id, float *norm_buffer);
|
int meshlite_bmesh_get_node_base_norm(void *context, int bmesh_id, int node_id, float *norm_buffer);
|
||||||
int meshlite_bmesh_destroy(void *context, int bmesh_id);
|
int meshlite_bmesh_destroy(void *context, int bmesh_id);
|
||||||
int meshlite_bmesh_error_count(void *context, int bmesh_id);
|
int meshlite_bmesh_error_count(void *context, int bmesh_id);
|
||||||
|
int meshlite_bmesh_add_seam_requirement(void *context, int bmesh_id);
|
||||||
|
int meshlite_bmesh_get_seam_count(void *context, int bmesh_id);
|
||||||
|
int meshlite_bmesh_get_seam_index_array(void *context, int bmesh_id, int *buffer, int max_buffer_len);
|
||||||
int meshlite_combine_adj_faces(void *context, int mesh_id);
|
int meshlite_combine_adj_faces(void *context, int mesh_id);
|
||||||
int meshlite_combine_coplanar_faces(void *context, int mesh_id);
|
int meshlite_combine_coplanar_faces(void *context, int mesh_id);
|
||||||
int meshlite_trim(void *context, int mesh_id, int normalize);
|
int meshlite_trim(void *context, int mesh_id, int normalize);
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
*.c text
|
||||||
|
*.cpp text
|
||||||
|
*.h text
|
||||||
|
*.md text
|
||||||
|
*.txt text
|
||||||
|
|
||||||
|
*.sln text eol=crlf
|
||||||
|
*.vcproj text eol=crlf
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
|
||||||
|
# CMake generated project
|
||||||
|
build
|
|
@ -0,0 +1,25 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.8)
|
||||||
|
project(thekla_atlas)
|
||||||
|
|
||||||
|
#add_definitions(-DNV_OS_DARWIN=1)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
src
|
||||||
|
src/nvcore
|
||||||
|
extern/tinyobj
|
||||||
|
extern/poshlib)
|
||||||
|
|
||||||
|
add_subdirectory(extern/poshlib)
|
||||||
|
add_subdirectory(src/nvcore)
|
||||||
|
add_subdirectory(src/nvimage)
|
||||||
|
add_subdirectory(src/nvmath)
|
||||||
|
add_subdirectory(src/nvmesh)
|
||||||
|
|
||||||
|
add_executable(
|
||||||
|
thekla_atlas_test
|
||||||
|
src/thekla/thekla_atlas_test.cpp
|
||||||
|
src/thekla/thekla_atlas.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
thekla_atlas_test
|
||||||
|
nvmesh)
|
|
@ -0,0 +1,8 @@
|
||||||
|
Copyright (c) 2013 Thekla, Inc
|
||||||
|
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,20 @@
|
||||||
|
thekla_atlas
|
||||||
|
============
|
||||||
|
|
||||||
|
This tool performs mesh segmentation, surface parameterization, and chart packing.
|
||||||
|
|
||||||
|
This is especially useful when generating light maps for meshes that do not have artist-supplied uv's.
|
||||||
|
|
||||||
|
### How to build (Windows)
|
||||||
|
|
||||||
|
Open `vc9/thekla.sln` using Visual Studio.
|
||||||
|
|
||||||
|
### How to build (OS X)
|
||||||
|
|
||||||
|
Use cmake. For example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ brew install cmake # Install cmake
|
||||||
|
$ cmake -H. -Bbuild # Create makefiles
|
||||||
|
$ cmake --build build # Invoke the build
|
||||||
|
```
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
SET(POSHLIB_SRCS
|
||||||
|
posh.c
|
||||||
|
posh.h)
|
||||||
|
|
||||||
|
ADD_LIBRARY(posh STATIC ${POSHLIB_SRCS})
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,431 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="9.00"
|
||||||
|
Name="nvcore"
|
||||||
|
ProjectGUID="{42FA3213-9A92-455E-8F39-5500B2303CCD}"
|
||||||
|
RootNamespace="nvcore"
|
||||||
|
TargetFrameworkVersion="196613"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
<Platform
|
||||||
|
Name="x64"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
AdditionalIncludeDirectories="../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
EnableEnhancedInstructionSet="2"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
WholeProgramOptimization="false"
|
||||||
|
AdditionalIncludeDirectories="../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
PrecompiledHeaderThrough="nvcore.h"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Array.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Array.inl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\BitArray.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Debug.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Debug.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\DefsVcWin32.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\FileSystem.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\FileSystem.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\ForEach.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Hash.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\HashMap.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\HashMap.inl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Memory.cpp"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Memory.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\nvcore.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\extern\poshlib\posh.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Ptr.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\RadixSort.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\RadixSort.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\RefCounted.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\scanf.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\StdStream.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Stream.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\StrLib.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\StrLib.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvcore\Utils.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,311 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="9.00"
|
||||||
|
Name="nvimage"
|
||||||
|
ProjectGUID="{AACBE57F-FF9D-4D15-86DD-A30232EB9102}"
|
||||||
|
RootNamespace="nvimage"
|
||||||
|
TargetFrameworkVersion="196613"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
<Platform
|
||||||
|
Name="x64"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib,../../../extern/stb"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib,../../../extern/stb"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib,../../../extern/stb"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
EnableEnhancedInstructionSet="2"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
WholeProgramOptimization="false"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib,../../../extern/stb"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
PrecompiledHeaderThrough="nvimage.h"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvimage\BitMap.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvimage\BitMap.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvimage\Image.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvimage\Image.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,448 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="9.00"
|
||||||
|
Name="nvmath"
|
||||||
|
ProjectGUID="{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}"
|
||||||
|
RootNamespace="nvmath"
|
||||||
|
TargetFrameworkVersion="196613"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
<Platform
|
||||||
|
Name="x64"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
EnableEnhancedInstructionSet="2"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
WholeProgramOptimization="false"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Basis.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Basis.h"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Box.cpp"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Box.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Box.inl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Color.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\ConvexHull.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\ConvexHull.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Fitting.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Fitting.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\ftoi.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\KahanSum.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Matrix.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Matrix.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Morton.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Matrix.inl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\nvmath.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Plane.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Plane.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Plane.inl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\ProximityGrid.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\ProximityGrid.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Quaternion.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Random.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Random.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Solver.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Solver.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Sparse.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Sparse.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Sphere.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Sphere.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\TypeSerialization.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\TypeSerialization.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Vector.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmath\Vector.inl"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,626 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="9.00"
|
||||||
|
Name="nvmesh"
|
||||||
|
ProjectGUID="{3943D773-05FE-43E7-A122-F5E534F73D33}"
|
||||||
|
RootNamespace="nvmesh"
|
||||||
|
TargetFrameworkVersion="196613"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
<Platform
|
||||||
|
Name="x64"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../src/nvmesh,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../src/nvmesh,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
BasicRuntimeChecks="0"
|
||||||
|
RuntimeLibrary="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../src/nvmesh,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
EnableEnhancedInstructionSet="2"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="2"
|
||||||
|
WholeProgramOptimization="0"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="3"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
FavorSizeOrSpeed="1"
|
||||||
|
OmitFramePointers="true"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../src/nvmesh,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
StringPooling="true"
|
||||||
|
ExceptionHandling="0"
|
||||||
|
RuntimeLibrary="0"
|
||||||
|
BufferSecurityCheck="false"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
UsePrecompiledHeader="2"
|
||||||
|
PrecompiledHeaderThrough="nvmesh.h"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
ShowIncludes="false"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<Filter
|
||||||
|
Name="geometry"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\geometry\Measurements.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\geometry\Measurements.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="halfedge"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Edge.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Edge.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Face.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Face.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Mesh.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Mesh.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Vertex.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\halfedge\Vertex.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="param"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\Atlas.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\Atlas.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\AtlasBuilder.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\AtlasBuilder.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\AtlasPacker.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\AtlasPacker.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\BoundaryMap.cpp"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\BoundaryMap.h"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\ConformalMap.cpp"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\ConformalMap.h"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|x64"
|
||||||
|
ExcludedFromBuild="true"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\LeastSquaresConformalMap.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\LeastSquaresConformalMap.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\OrthogonalProjectionMap.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\OrthogonalProjectionMap.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\ParameterizationQuality.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\ParameterizationQuality.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\SingleFaceMap.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\SingleFaceMap.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\Util.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\param\Util.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="raster"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\raster\ClippedTriangle.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\raster\Raster.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\raster\Raster.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="weld"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\weld\Weld.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\MeshBuilder.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\MeshBuilder.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\MeshTopology.cpp"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\MeshTopology.h"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\nvmesh.cpp"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|x64"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
UsePrecompiledHeader="1"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\nvmesh\nvmesh.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,79 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||||
|
# Visual Studio 2008
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "thekla_atlas", "thekla_atlas\thekla_atlas.vcproj", "{EF943121-21F5-44B6-A8B5-C628F95CE070}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD} = {42FA3213-9A92-455E-8F39-5500B2303CCD}
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33} = {3943D773-05FE-43E7-A122-F5E534F73D33}
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B} = {D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102} = {AACBE57F-FF9D-4D15-86DD-A30232EB9102}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nv", "nv", "{382CF634-AF73-4943-83D6-C1D5BA499CC2}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nvcore", "nvcore\nvcore.vcproj", "{42FA3213-9A92-455E-8F39-5500B2303CCD}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nvmath", "nvmath\nvmath.vcproj", "{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nvmesh", "nvmesh\nvmesh.vcproj", "{3943D773-05FE-43E7-A122-F5E534F73D33}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nvimage", "nvimage\nvimage.vcproj", "{AACBE57F-FF9D-4D15-86DD-A30232EB9102}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Win32 = Debug|Win32
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{EF943121-21F5-44B6-A8B5-C628F95CE070}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{EF943121-21F5-44B6-A8B5-C628F95CE070}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{EF943121-21F5-44B6-A8B5-C628F95CE070}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{EF943121-21F5-44B6-A8B5-C628F95CE070}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{EF943121-21F5-44B6-A8B5-C628F95CE070}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{EF943121-21F5-44B6-A8B5-C628F95CE070}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{EF943121-21F5-44B6-A8B5-C628F95CE070}.Release|x64.Build.0 = Release|x64
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD}.Release|x64.Build.0 = Release|x64
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B}.Release|x64.Build.0 = Release|x64
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33}.Release|x64.Build.0 = Release|x64
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{42FA3213-9A92-455E-8F39-5500B2303CCD} = {382CF634-AF73-4943-83D6-C1D5BA499CC2}
|
||||||
|
{D8B7F575-E8F5-4F1A-A4A4-EB9CC9A0766B} = {382CF634-AF73-4943-83D6-C1D5BA499CC2}
|
||||||
|
{3943D773-05FE-43E7-A122-F5E534F73D33} = {382CF634-AF73-4943-83D6-C1D5BA499CC2}
|
||||||
|
{AACBE57F-FF9D-4D15-86DD-A30232EB9102} = {382CF634-AF73-4943-83D6-C1D5BA499CC2}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
|
@ -0,0 +1,297 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="9.00"
|
||||||
|
Name="thekla_atlas"
|
||||||
|
ProjectGUID="{EF943121-21F5-44B6-A8B5-C628F95CE070}"
|
||||||
|
RootNamespace="thekla_atlas"
|
||||||
|
Keyword="Win32Proj"
|
||||||
|
TargetFrameworkVersion="196613"
|
||||||
|
>
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"
|
||||||
|
/>
|
||||||
|
<Platform
|
||||||
|
Name="x64"
|
||||||
|
/>
|
||||||
|
</Platforms>
|
||||||
|
<ToolFiles>
|
||||||
|
</ToolFiles>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;THEKLA_ATLAS_EXPORTS"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="3"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="4"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="0"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;THEKLA_ATLAS_EXPORTS"
|
||||||
|
MinimalRebuild="true"
|
||||||
|
BasicRuntimeChecks="3"
|
||||||
|
RuntimeLibrary="3"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="1"
|
||||||
|
WholeProgramOptimization="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;THEKLA_ATLAS_EXPORTS"
|
||||||
|
RuntimeLibrary="2"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|x64"
|
||||||
|
OutputDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
IntermediateDirectory="$(ConfigurationName)\$(PlatformName)"
|
||||||
|
ConfigurationType="4"
|
||||||
|
CharacterSet="1"
|
||||||
|
WholeProgramOptimization="1"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
TargetEnvironment="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
Optimization="2"
|
||||||
|
EnableIntrinsicFunctions="true"
|
||||||
|
AdditionalIncludeDirectories="../../..,../../../src,../../../extern/poshlib"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;THEKLA_ATLAS_EXPORTS"
|
||||||
|
RuntimeLibrary="2"
|
||||||
|
EnableFunctionLevelLinking="true"
|
||||||
|
UsePrecompiledHeader="0"
|
||||||
|
WarningLevel="3"
|
||||||
|
DebugInformationFormat="3"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLibrarianTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCALinkTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXDCMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCBscMakeTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCFxCopTool"
|
||||||
|
/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"
|
||||||
|
/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\thekla\thekla_atlas.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\thekla\thekla_atlas.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\thekla\thekla_atlas_test.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\thekla\thekla_mesh_load.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef NV_CONFIG
|
||||||
|
#define NV_CONFIG
|
||||||
|
|
||||||
|
#if NV_OS_DARWIN
|
||||||
|
|
||||||
|
// Hardcoded.
|
||||||
|
|
||||||
|
#define NV_HAVE_UNISTD_H
|
||||||
|
#define NV_HAVE_STDARG_H
|
||||||
|
#define NV_HAVE_SIGNAL_H
|
||||||
|
#define NV_HAVE_EXECINFO_H
|
||||||
|
//#define NV_HAVE_MALLOC_H
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
//#define HAVE_UNISTD_H
|
||||||
|
#define NV_HAVE_STDARG_H
|
||||||
|
//#define HAVE_SIGNAL_H
|
||||||
|
//#define HAVE_EXECINFO_H
|
||||||
|
//#define HAVE_MALLOC_H
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#define HAVE_OPENMP // Only in MSVC pro edition.
|
||||||
|
|
||||||
|
//#cmakedefine HAVE_PNG
|
||||||
|
//#cmakedefine HAVE_JPEG
|
||||||
|
//#cmakedefine HAVE_TIFF
|
||||||
|
//#cmakedefine HAVE_OPENEXR
|
||||||
|
//#cmakedefine HAVE_FREEIMAGE
|
||||||
|
#if !NV_OS_IOS
|
||||||
|
#define NV_HAVE_STBIMAGE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#cmakedefine HAVE_MAYA
|
||||||
|
|
||||||
|
#endif // NV_CONFIG
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef NV_CONFIG
|
||||||
|
#define NV_CONFIG
|
||||||
|
|
||||||
|
#cmakedefine NV_HAVE_UNISTD_H
|
||||||
|
#cmakedefine NV_HAVE_STDARG_H
|
||||||
|
#cmakedefine NV_HAVE_SIGNAL_H
|
||||||
|
#cmakedefine NV_HAVE_EXECINFO_H
|
||||||
|
#cmakedefine NV_HAVE_MALLOC_H
|
||||||
|
|
||||||
|
#cmakedefine NV_HAVE_OPENMP
|
||||||
|
#cmakedefine NV_HAVE_DISPATCH_H
|
||||||
|
|
||||||
|
#define NV_HAVE_STBIMAGE
|
||||||
|
//#cmakedefine NV_HAVE_PNG
|
||||||
|
//#cmakedefine NV_HAVE_JPEG
|
||||||
|
//#cmakedefine NV_HAVE_TIFF
|
||||||
|
//#cmakedefine NV_HAVE_OPENEXR
|
||||||
|
//#cmakedefine NV_HAVE_FREEIMAGE
|
||||||
|
|
||||||
|
#cmakedefine NV_HAVE_MAYA
|
||||||
|
|
||||||
|
#endif // NV_CONFIG
|
|
@ -0,0 +1,184 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_ARRAY_H
|
||||||
|
#define NV_CORE_ARRAY_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
This array class requires the elements to be relocable; it uses memmove and realloc. Ideally I should be
|
||||||
|
using swap, but I honestly don't care. The only thing that you should be aware of is that internal pointers
|
||||||
|
are not supported.
|
||||||
|
|
||||||
|
Note also that push_back and resize does not support inserting arguments elements that are in the same
|
||||||
|
container. This is forbidden to prevent an extra copy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
#include "ForEach.h" // PseudoIndex
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
class Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement for std::vector that is easier to debug and provides
|
||||||
|
* some nice foreach enumerators.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
class NVCORE_CLASS Array {
|
||||||
|
public:
|
||||||
|
typedef uint size_type;
|
||||||
|
|
||||||
|
// Default constructor.
|
||||||
|
NV_FORCEINLINE Array() : m_buffer(NULL), m_capacity(0), m_size(0) {}
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
NV_FORCEINLINE Array(const Array & a) : m_buffer(NULL), m_capacity(0), m_size(0) {
|
||||||
|
copy(a.m_buffer, a.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor that initializes the vector with the given elements.
|
||||||
|
NV_FORCEINLINE Array(const T * ptr, uint num) : m_buffer(NULL), m_capacity(0), m_size(0) {
|
||||||
|
copy(ptr, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate array.
|
||||||
|
NV_FORCEINLINE explicit Array(uint capacity) : m_buffer(NULL), m_capacity(0), m_size(0) {
|
||||||
|
setArrayCapacity(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor.
|
||||||
|
NV_FORCEINLINE ~Array() {
|
||||||
|
clear();
|
||||||
|
free<T>(m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Const element access.
|
||||||
|
NV_FORCEINLINE const T & operator[]( uint index ) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(index < m_size);
|
||||||
|
return m_buffer[index];
|
||||||
|
}
|
||||||
|
NV_FORCEINLINE const T & at( uint index ) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(index < m_size);
|
||||||
|
return m_buffer[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Element access.
|
||||||
|
NV_FORCEINLINE T & operator[] ( uint index )
|
||||||
|
{
|
||||||
|
nvDebugCheck(index < m_size);
|
||||||
|
return m_buffer[index];
|
||||||
|
}
|
||||||
|
NV_FORCEINLINE T & at( uint index )
|
||||||
|
{
|
||||||
|
nvDebugCheck(index < m_size);
|
||||||
|
return m_buffer[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get vector size.
|
||||||
|
NV_FORCEINLINE uint size() const { return m_size; }
|
||||||
|
|
||||||
|
/// Get vector size.
|
||||||
|
NV_FORCEINLINE uint count() const { return m_size; }
|
||||||
|
|
||||||
|
/// Get vector capacity.
|
||||||
|
NV_FORCEINLINE uint capacity() const { return m_capacity; }
|
||||||
|
|
||||||
|
/// Get const vector pointer.
|
||||||
|
NV_FORCEINLINE const T * buffer() const { return m_buffer; }
|
||||||
|
|
||||||
|
/// Get vector pointer.
|
||||||
|
NV_FORCEINLINE T * buffer() { return m_buffer; }
|
||||||
|
|
||||||
|
/// Provide begin/end pointers for C++11 range-based for loops.
|
||||||
|
NV_FORCEINLINE T * begin() { return m_buffer; }
|
||||||
|
NV_FORCEINLINE T * end() { return m_buffer + m_size; }
|
||||||
|
NV_FORCEINLINE const T * begin() const { return m_buffer; }
|
||||||
|
NV_FORCEINLINE const T * end() const { return m_buffer + m_size; }
|
||||||
|
|
||||||
|
/// Is vector empty.
|
||||||
|
NV_FORCEINLINE bool isEmpty() const { return m_size == 0; }
|
||||||
|
|
||||||
|
/// Is a null vector.
|
||||||
|
NV_FORCEINLINE bool isNull() const { return m_buffer == NULL; }
|
||||||
|
|
||||||
|
|
||||||
|
T & append();
|
||||||
|
void push_back( const T & val );
|
||||||
|
void pushBack( const T & val );
|
||||||
|
Array<T> & append( const T & val );
|
||||||
|
Array<T> & operator<< ( T & t );
|
||||||
|
void pop_back();
|
||||||
|
void popBack(uint count = 1);
|
||||||
|
void popFront(uint count = 1);
|
||||||
|
const T & back() const;
|
||||||
|
T & back();
|
||||||
|
const T & front() const;
|
||||||
|
T & front();
|
||||||
|
bool contains(const T & e) const;
|
||||||
|
bool find(const T & element, uint * indexPtr) const;
|
||||||
|
bool find(const T & element, uint begin, uint end, uint * indexPtr) const;
|
||||||
|
void removeAt(uint index);
|
||||||
|
bool remove(const T & element);
|
||||||
|
void insertAt(uint index, const T & val = T());
|
||||||
|
void append(const Array<T> & other);
|
||||||
|
void append(const T other[], uint count);
|
||||||
|
void replaceWithLast(uint index);
|
||||||
|
void resize(uint new_size);
|
||||||
|
void resize(uint new_size, const T & elem);
|
||||||
|
void fill(const T & elem);
|
||||||
|
void clear();
|
||||||
|
void shrink();
|
||||||
|
void reserve(uint desired_size);
|
||||||
|
void copy(const T * data, uint count);
|
||||||
|
Array<T> & operator=( const Array<T> & a );
|
||||||
|
T * release();
|
||||||
|
|
||||||
|
|
||||||
|
// Array enumerator.
|
||||||
|
typedef uint PseudoIndex;
|
||||||
|
|
||||||
|
NV_FORCEINLINE PseudoIndex start() const { return 0; }
|
||||||
|
NV_FORCEINLINE bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); return i == this->m_size; }
|
||||||
|
NV_FORCEINLINE void advance(PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); i++; }
|
||||||
|
|
||||||
|
#if NV_NEED_PSEUDOINDEX_WRAPPER
|
||||||
|
NV_FORCEINLINE T & operator[]( const PseudoIndexWrapper & i ) {
|
||||||
|
return m_buffer[i(this)];
|
||||||
|
}
|
||||||
|
NV_FORCEINLINE const T & operator[]( const PseudoIndexWrapper & i ) const {
|
||||||
|
return m_buffer[i(this)];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Friends.
|
||||||
|
template <typename Typ>
|
||||||
|
friend Stream & operator<< ( Stream & s, Array<Typ> & p );
|
||||||
|
|
||||||
|
template <typename Typ>
|
||||||
|
friend void swap(Array<Typ> & a, Array<Typ> & b);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void setArraySize(uint new_size);
|
||||||
|
void setArrayCapacity(uint new_capacity);
|
||||||
|
|
||||||
|
T * m_buffer;
|
||||||
|
uint m_capacity;
|
||||||
|
uint m_size;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#include "Array.inl"
|
||||||
|
|
||||||
|
#endif // NV_CORE_ARRAY_H
|
|
@ -0,0 +1,452 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_ARRAY_INL
|
||||||
|
#define NV_CORE_ARRAY_INL
|
||||||
|
|
||||||
|
#include "Array.h"
|
||||||
|
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "Utils.h" // swap
|
||||||
|
|
||||||
|
#include <string.h> // memmove
|
||||||
|
#include <new> // for placement new
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE T & Array<T>::append()
|
||||||
|
{
|
||||||
|
uint old_size = m_size;
|
||||||
|
uint new_size = m_size + 1;
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
construct_range(m_buffer, new_size, old_size);
|
||||||
|
|
||||||
|
return m_buffer[old_size]; // Return reference to last element.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push an element at the end of the vector.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::push_back( const T & val )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
nvDebugCheck(&val < m_buffer || &val >= m_buffer+m_size);
|
||||||
|
|
||||||
|
uint old_size = m_size;
|
||||||
|
uint new_size = m_size + 1;
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
construct_range(m_buffer, new_size, old_size, val);
|
||||||
|
#else
|
||||||
|
uint new_size = m_size + 1;
|
||||||
|
|
||||||
|
if (new_size > m_capacity)
|
||||||
|
{
|
||||||
|
// @@ Is there any way to avoid this copy?
|
||||||
|
// @@ Can we create a copy without side effects? Ie. without calls to constructor/destructor. Use alloca + memcpy?
|
||||||
|
// @@ Assert instead of copy?
|
||||||
|
const T copy(val); // create a copy in case value is inside of this array.
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
new (m_buffer+new_size-1) T(copy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_size = new_size;
|
||||||
|
new(m_buffer+new_size-1) T(val);
|
||||||
|
}
|
||||||
|
#endif // 0/1
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::pushBack( const T & val )
|
||||||
|
{
|
||||||
|
push_back(val);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE Array<T> & Array<T>::append( const T & val )
|
||||||
|
{
|
||||||
|
push_back(val);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Qt like push operator.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE Array<T> & Array<T>::operator<< ( T & t )
|
||||||
|
{
|
||||||
|
push_back(t);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop the element at the end of the vector.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::pop_back()
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
resize( m_size - 1 );
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::popBack(uint count)
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_size >= count);
|
||||||
|
resize(m_size - count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::popFront(uint count)
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_size >= count);
|
||||||
|
//resize(m_size - count);
|
||||||
|
|
||||||
|
if (m_size == count) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
destroy_range(m_buffer, 0, count);
|
||||||
|
|
||||||
|
memmove(m_buffer, m_buffer + count, sizeof(T) * (m_size - count));
|
||||||
|
|
||||||
|
m_size -= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get back element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE const T & Array<T>::back() const
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[m_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get back element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE T & Array<T>::back()
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[m_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get front element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE const T & Array<T>::front() const
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get front element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE T & Array<T>::front()
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given element is contained in the array.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE bool Array<T>::contains(const T & e) const
|
||||||
|
{
|
||||||
|
return find(e, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if element found.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE bool Array<T>::find(const T & element, uint * indexPtr) const
|
||||||
|
{
|
||||||
|
return find(element, 0, m_size, indexPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if element found within the given range.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE bool Array<T>::find(const T & element, uint begin, uint end, uint * indexPtr) const
|
||||||
|
{
|
||||||
|
return ::nv::find(element, m_buffer, begin, end, indexPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the element at the given index. This is an expensive operation!
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::removeAt(uint index)
|
||||||
|
{
|
||||||
|
nvDebugCheck(index >= 0 && index < m_size);
|
||||||
|
|
||||||
|
if (m_size == 1) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_buffer[index].~T();
|
||||||
|
|
||||||
|
memmove(m_buffer+index, m_buffer+index+1, sizeof(T) * (m_size - 1 - index));
|
||||||
|
m_size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the first instance of the given element.
|
||||||
|
template <typename T>
|
||||||
|
bool Array<T>::remove(const T & element)
|
||||||
|
{
|
||||||
|
uint index;
|
||||||
|
if (find(element, &index)) {
|
||||||
|
removeAt(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the given element at the given index shifting all the elements up.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::insertAt(uint index, const T & val/*=T()*/)
|
||||||
|
{
|
||||||
|
nvDebugCheck( index >= 0 && index <= m_size );
|
||||||
|
|
||||||
|
setArraySize(m_size + 1);
|
||||||
|
|
||||||
|
if (index < m_size - 1) {
|
||||||
|
memmove(m_buffer+index+1, m_buffer+index, sizeof(T) * (m_size - 1 - index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy-construct into the newly opened slot.
|
||||||
|
new(m_buffer+index) T(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the given data to our vector.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::append(const Array<T> & other)
|
||||||
|
{
|
||||||
|
append(other.m_buffer, other.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the given data to our vector.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::append(const T other[], uint count)
|
||||||
|
{
|
||||||
|
if (count > 0) {
|
||||||
|
const uint old_size = m_size;
|
||||||
|
|
||||||
|
setArraySize(m_size + count);
|
||||||
|
|
||||||
|
for (uint i = 0; i < count; i++ ) {
|
||||||
|
new(m_buffer + old_size + i) T(other[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the given element by replacing it with the last one.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::replaceWithLast(uint index)
|
||||||
|
{
|
||||||
|
nvDebugCheck( index < m_size );
|
||||||
|
nv::swap(m_buffer[index], back()); // @@ Is this OK when index == size-1?
|
||||||
|
(m_buffer+m_size-1)->~T();
|
||||||
|
m_size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the vector preserving existing elements.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::resize(uint new_size)
|
||||||
|
{
|
||||||
|
uint old_size = m_size;
|
||||||
|
|
||||||
|
// Destruct old elements (if we're shrinking).
|
||||||
|
destroy_range(m_buffer, new_size, old_size);
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
// Call default constructors
|
||||||
|
construct_range(m_buffer, new_size, old_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resize the vector preserving existing elements and initializing the
|
||||||
|
// new ones with the given value.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::resize(uint new_size, const T & elem)
|
||||||
|
{
|
||||||
|
nvDebugCheck(&elem < m_buffer || &elem > m_buffer+m_size);
|
||||||
|
|
||||||
|
uint old_size = m_size;
|
||||||
|
|
||||||
|
// Destruct old elements (if we're shrinking).
|
||||||
|
destroy_range(m_buffer, new_size, old_size);
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
// Call copy constructors
|
||||||
|
construct_range(m_buffer, new_size, old_size, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill array with the given value.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::fill(const T & elem)
|
||||||
|
{
|
||||||
|
fill(m_buffer, m_size, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the buffer.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::clear()
|
||||||
|
{
|
||||||
|
nvDebugCheck(isValidPtr(m_buffer));
|
||||||
|
|
||||||
|
// Destruct old elements
|
||||||
|
destroy_range(m_buffer, 0, m_size);
|
||||||
|
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shrink the allocated vector.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::shrink()
|
||||||
|
{
|
||||||
|
if (m_size < m_capacity) {
|
||||||
|
setArrayCapacity(m_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate space.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::reserve(uint desired_size)
|
||||||
|
{
|
||||||
|
if (desired_size > m_capacity) {
|
||||||
|
setArrayCapacity(desired_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy elements to this array. Resizes it if needed.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::copy(const T * data, uint count)
|
||||||
|
{
|
||||||
|
#if 1 // More simple, but maybe not be as efficient?
|
||||||
|
destroy_range(m_buffer, 0, m_size);
|
||||||
|
|
||||||
|
setArraySize(count);
|
||||||
|
|
||||||
|
construct_range(m_buffer, count, 0, data);
|
||||||
|
#else
|
||||||
|
const uint old_size = m_size;
|
||||||
|
|
||||||
|
destroy_range(m_buffer, count, old_size);
|
||||||
|
|
||||||
|
setArraySize(count);
|
||||||
|
|
||||||
|
copy_range(m_buffer, data, old_size);
|
||||||
|
|
||||||
|
construct_range(m_buffer, count, old_size, data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment operator.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE Array<T> & Array<T>::operator=( const Array<T> & a )
|
||||||
|
{
|
||||||
|
copy(a.m_buffer, a.m_size);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release ownership of allocated memory and returns pointer to it.
|
||||||
|
template <typename T>
|
||||||
|
T * Array<T>::release() {
|
||||||
|
T * tmp = m_buffer;
|
||||||
|
m_buffer = NULL;
|
||||||
|
m_capacity = 0;
|
||||||
|
m_size = 0;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Change array size.
|
||||||
|
template <typename T>
|
||||||
|
inline void Array<T>::setArraySize(uint new_size) {
|
||||||
|
m_size = new_size;
|
||||||
|
|
||||||
|
if (new_size > m_capacity) {
|
||||||
|
uint new_buffer_size;
|
||||||
|
if (m_capacity == 0) {
|
||||||
|
// first allocation is exact
|
||||||
|
new_buffer_size = new_size;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// following allocations grow array by 25%
|
||||||
|
new_buffer_size = new_size + (new_size >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
setArrayCapacity( new_buffer_size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change array capacity.
|
||||||
|
template <typename T>
|
||||||
|
inline void Array<T>::setArrayCapacity(uint new_capacity) {
|
||||||
|
nvDebugCheck(new_capacity >= m_size);
|
||||||
|
|
||||||
|
if (new_capacity == 0) {
|
||||||
|
// free the buffer.
|
||||||
|
if (m_buffer != NULL) {
|
||||||
|
free<T>(m_buffer);
|
||||||
|
m_buffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// realloc the buffer
|
||||||
|
m_buffer = realloc<T>(m_buffer, new_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_capacity = new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array serialization.
|
||||||
|
template <typename Typ>
|
||||||
|
inline Stream & operator<< ( Stream & s, Array<Typ> & p )
|
||||||
|
{
|
||||||
|
if (s.isLoading()) {
|
||||||
|
uint size;
|
||||||
|
s << size;
|
||||||
|
p.resize( size );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s << p.m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < p.m_size; i++) {
|
||||||
|
s << p.m_buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the members of the two given vectors.
|
||||||
|
template <typename Typ>
|
||||||
|
inline void swap(Array<Typ> & a, Array<Typ> & b)
|
||||||
|
{
|
||||||
|
nv::swap(a.m_buffer, b.m_buffer);
|
||||||
|
nv::swap(a.m_capacity, b.m_capacity);
|
||||||
|
nv::swap(a.m_size, b.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
// IC: These functions are for compatibility with the Foreach macro in The Witness.
|
||||||
|
template <typename T> inline int item_count(const nv::Array<T> & array) { return array.count(); }
|
||||||
|
template <typename T> inline const T & item_at(const nv::Array<T> & array, int i) { return array.at(i); }
|
||||||
|
template <typename T> inline T & item_at(nv::Array<T> & array, int i) { return array.at(i); }
|
||||||
|
template <typename T> inline int item_advance(const nv::Array<T> & array, int i) { return ++i; }
|
||||||
|
template <typename T> inline int item_remove(nv::Array<T> & array, int i) { array.replaceWithLast(i); return i - 1; }
|
||||||
|
|
||||||
|
template <typename T> inline int item_count(const nv::Array<T> * array) { return array->count(); }
|
||||||
|
template <typename T> inline const T & item_at(const nv::Array<T> * array, int i) { return array->at(i); }
|
||||||
|
template <typename T> inline T & item_at(nv::Array<T> * array, int i) { return array->at(i); }
|
||||||
|
template <typename T> inline int item_advance(const nv::Array<T> * array, int i) { return ++i; }
|
||||||
|
template <typename T> inline int item_remove(nv::Array<T> * array, int i) { array->replaceWithLast(i); return i - 1; }
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_CORE_ARRAY_INL
|
|
@ -0,0 +1,250 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_BITARRAY_H
|
||||||
|
#define NV_CORE_BITARRAY_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
#include "Array.inl"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
// @@ Uh, this could be much faster.
|
||||||
|
inline uint countSetBits(uint32 x) {
|
||||||
|
uint count = 0;
|
||||||
|
for(; x != 0; x >>= 1) {
|
||||||
|
count += (x & 1);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@ This is even more lame. What was I thinking?
|
||||||
|
inline uint countSetBits(uint32 x, int bits) {
|
||||||
|
uint count = 0;
|
||||||
|
for(; x != 0 && bits != 0; x >>= 1, bits--) {
|
||||||
|
count += (x & 1);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See "Conditionally set or clear bits without branching" at http://graphics.stanford.edu/~seander/bithacks.html
|
||||||
|
inline uint setBits(uint w, uint m, bool b) {
|
||||||
|
return (w & ~m) | (-int(b) & m);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Simple bit array.
|
||||||
|
class BitArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
BitArray() {}
|
||||||
|
BitArray(uint sz) {
|
||||||
|
resize(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint size() const { return m_size; }
|
||||||
|
void clear() { resize(0); }
|
||||||
|
|
||||||
|
void resize(uint new_size)
|
||||||
|
{
|
||||||
|
m_size = new_size;
|
||||||
|
m_wordArray.resize( (m_size + 31) >> 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize(uint new_size, bool init)
|
||||||
|
{
|
||||||
|
//if (new_size == m_size) return;
|
||||||
|
|
||||||
|
uint old_size = m_size;
|
||||||
|
uint size_mod_32 = old_size & 31;
|
||||||
|
uint last_word_index = ((old_size + 31) >> 5) - 1;
|
||||||
|
uint mask = (1 << size_mod_32) - 1;
|
||||||
|
|
||||||
|
uint init_dword;
|
||||||
|
if (init) {
|
||||||
|
if (size_mod_32) m_wordArray[last_word_index] |= ~mask;
|
||||||
|
init_dword = ~0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (size_mod_32) m_wordArray[last_word_index] &= mask;
|
||||||
|
init_dword = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size = new_size;
|
||||||
|
m_wordArray.resize((new_size + 31) >> 5, init_dword);
|
||||||
|
|
||||||
|
// Make sure new bits are initialized correctly.
|
||||||
|
/*for (uint i = old_size; i < new_size; i++) {
|
||||||
|
nvCheck(bitAt(i) == init);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get bit.
|
||||||
|
bool bitAt(uint b) const
|
||||||
|
{
|
||||||
|
nvDebugCheck( b < m_size );
|
||||||
|
return (m_wordArray[b >> 5] & (1 << (b & 31))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// It may be useful to pack mulitple bit arrays together interleaving their bits.
|
||||||
|
uint bitsAt(uint idx, uint count) const
|
||||||
|
{
|
||||||
|
//nvDebugCheck(count == 2 || count == 4 || count == 8 || count == 16 || count == 32);
|
||||||
|
nvDebugCheck(count == 2); // @@ Hardcoded for two.
|
||||||
|
uint b = idx * count;
|
||||||
|
nvDebugCheck(b < m_size);
|
||||||
|
return (m_wordArray[b >> 5] & (0x3 << (b & 31))) >> (b & 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
// It would be useful to have a function to set two bits simultaneously.
|
||||||
|
/*void setBitsAt(uint idx, uint count, uint bits) const
|
||||||
|
{
|
||||||
|
//nvDebugCheck(count == 2 || count == 4 || count == 8 || count == 16 || count == 32);
|
||||||
|
nvDebugCheck(count == 2); // @@ Hardcoded for two.
|
||||||
|
uint b = idx * count;
|
||||||
|
nvDebugCheck(b < m_size);
|
||||||
|
return (m_wordArray[b >> 5] & (0x3 << (b & 31))) >> (b & 31);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Set a bit.
|
||||||
|
void setBitAt(uint idx)
|
||||||
|
{
|
||||||
|
nvDebugCheck(idx < m_size);
|
||||||
|
m_wordArray[idx >> 5] |= (1 << (idx & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear a bit.
|
||||||
|
void clearBitAt(uint idx)
|
||||||
|
{
|
||||||
|
nvDebugCheck(idx < m_size);
|
||||||
|
m_wordArray[idx >> 5] &= ~(1 << (idx & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle a bit.
|
||||||
|
void toggleBitAt(uint idx)
|
||||||
|
{
|
||||||
|
nvDebugCheck(idx < m_size);
|
||||||
|
m_wordArray[idx >> 5] ^= (1 << (idx & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a bit to the given value. @@ Rename modifyBitAt?
|
||||||
|
void setBitAt(uint idx, bool b)
|
||||||
|
{
|
||||||
|
nvDebugCheck(idx < m_size);
|
||||||
|
m_wordArray[idx >> 5] = setBits(m_wordArray[idx >> 5], 1 << (idx & 31), b);
|
||||||
|
nvDebugCheck(bitAt(idx) == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(bool value)
|
||||||
|
{
|
||||||
|
resize(m_size + 1);
|
||||||
|
setBitAt(m_size - 1, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clear all the bits.
|
||||||
|
void clearAll()
|
||||||
|
{
|
||||||
|
memset(m_wordArray.buffer(), 0, m_wordArray.size() * sizeof(uint));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set all the bits.
|
||||||
|
void setAll()
|
||||||
|
{
|
||||||
|
memset(m_wordArray.buffer(), 0xFF, m_wordArray.size() * sizeof(uint));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle all the bits.
|
||||||
|
void toggleAll()
|
||||||
|
{
|
||||||
|
const uint wordCount = m_wordArray.count();
|
||||||
|
for(uint b = 0; b < wordCount; b++) {
|
||||||
|
m_wordArray[b] ^= 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of bits set.
|
||||||
|
uint countSetBits() const
|
||||||
|
{
|
||||||
|
const uint num = m_wordArray.size();
|
||||||
|
if( num == 0 ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint count = 0;
|
||||||
|
for(uint i = 0; i < num - 1; i++) {
|
||||||
|
count += nv::countSetBits(m_wordArray[i]);
|
||||||
|
}
|
||||||
|
count += nv::countSetBits(m_wordArray[num - 1], m_size & 31);
|
||||||
|
|
||||||
|
//piDebugCheck(count + countClearBits() == m_size);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of bits clear.
|
||||||
|
uint countClearBits() const {
|
||||||
|
|
||||||
|
const uint num = m_wordArray.size();
|
||||||
|
if( num == 0 ) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint count = 0;
|
||||||
|
for(uint i = 0; i < num - 1; i++) {
|
||||||
|
count += nv::countSetBits(~m_wordArray[i]);
|
||||||
|
}
|
||||||
|
count += nv::countSetBits(~m_wordArray[num - 1], m_size & 31);
|
||||||
|
|
||||||
|
//piDebugCheck(count + countSetBits() == m_size);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void swap(BitArray & a, BitArray & b)
|
||||||
|
{
|
||||||
|
swap(a.m_size, b.m_size);
|
||||||
|
swap(a.m_wordArray, b.m_wordArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator &= (const BitArray & other) {
|
||||||
|
if (other.m_size != m_size) {
|
||||||
|
resize(other.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint wordCount = m_wordArray.count();
|
||||||
|
for (uint i = 0; i < wordCount; i++) {
|
||||||
|
m_wordArray[i] &= other.m_wordArray[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator |= (const BitArray & other) {
|
||||||
|
if (other.m_size != m_size) {
|
||||||
|
resize(other.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint wordCount = m_wordArray.count();
|
||||||
|
for (uint i = 0; i < wordCount; i++) {
|
||||||
|
m_wordArray[i] |= other.m_wordArray[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Number of bits stored.
|
||||||
|
uint m_size;
|
||||||
|
|
||||||
|
// Array of bits.
|
||||||
|
Array<uint> m_wordArray;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_BITARRAY_H
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
PROJECT(nvcore)
|
||||||
|
|
||||||
|
SET(CORE_SRCS
|
||||||
|
nvcore.h
|
||||||
|
DefsGnucDarwin.h
|
||||||
|
DefsGnucLinux.h
|
||||||
|
DefsGnucWin32.h
|
||||||
|
DefsVcWin32.h
|
||||||
|
Ptr.h
|
||||||
|
RefCounted.h
|
||||||
|
BitArray.h
|
||||||
|
Memory.h
|
||||||
|
Memory.cpp
|
||||||
|
Debug.h
|
||||||
|
Debug.cpp
|
||||||
|
StrLib.h
|
||||||
|
StrLib.cpp
|
||||||
|
Stream.h
|
||||||
|
StdStream.h
|
||||||
|
FileSystem.h
|
||||||
|
FileSystem.cpp
|
||||||
|
RadixSort.h
|
||||||
|
RadixSort.cpp)
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
# For Windows64 in MSVC we need to add the assembly version of vsscanf
|
||||||
|
IF(MSVC AND NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
||||||
|
SET(VSSCANF_ASM_NAME "vsscanf_proxy_win64")
|
||||||
|
IF(MSVC_IDE)
|
||||||
|
# $(IntDir) is a macro expanded to the intermediate directory of the selected solution configuration
|
||||||
|
SET(VSSCANF_ASM_INTDIR "$(IntDir)")
|
||||||
|
ELSE(MSVC_IDE)
|
||||||
|
# For some reason the NMake generator doesn't work properly with the generated .obj source:
|
||||||
|
# it requires the absolute path. So this is a hack which worked as of cmake 2.6.0 patch 0
|
||||||
|
GET_FILENAME_COMPONENT(VSSCANF_ASM_INTDIR
|
||||||
|
"${nvcore_BINARY_DIR}/CMakeFiles/nvcore.dir" ABSOLUTE)
|
||||||
|
ENDIF(MSVC_IDE)
|
||||||
|
|
||||||
|
SET(VSSCANF_ASM_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${VSSCANF_ASM_NAME}.masm")
|
||||||
|
SET(VSSCANF_ASM_OBJ "${VSSCANF_ASM_INTDIR}/${VSSCANF_ASM_NAME}.obj")
|
||||||
|
|
||||||
|
# Adds the assembly output to the sources and adds the custom command to generate it
|
||||||
|
SET(CORE_SRCS
|
||||||
|
${CORE_SRCS}
|
||||||
|
${VSSCANF_ASM_OBJ}
|
||||||
|
)
|
||||||
|
ADD_CUSTOM_COMMAND(OUTPUT ${VSSCANF_ASM_OBJ}
|
||||||
|
MAIN_DEPENDENCY ${VSSCANF_ASM_SRC}
|
||||||
|
COMMAND ml64
|
||||||
|
ARGS /nologo /Fo ${VSSCANF_ASM_OBJ} /c /Cx ${VSSCANF_ASM_SRC}
|
||||||
|
)
|
||||||
|
ENDIF(MSVC AND NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
||||||
|
|
||||||
|
# targets
|
||||||
|
ADD_DEFINITIONS(-DNVCORE_EXPORTS)
|
||||||
|
|
||||||
|
IF(UNIX)
|
||||||
|
SET(LIBS ${LIBS} ${CMAKE_DL_LIBS})
|
||||||
|
ENDIF(UNIX)
|
||||||
|
|
||||||
|
IF(NVCORE_SHARED)
|
||||||
|
ADD_DEFINITIONS(-DNVCORE_SHARED=1)
|
||||||
|
ADD_LIBRARY(nvcore SHARED ${CORE_SRCS})
|
||||||
|
ELSE(NVCORE_SHARED)
|
||||||
|
ADD_LIBRARY(nvcore ${CORE_SRCS})
|
||||||
|
ENDIF(NVCORE_SHARED)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(nvcore ${LIBS})
|
||||||
|
|
||||||
|
INSTALL(TARGETS nvcore
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib/static)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,246 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_DEBUG_H
|
||||||
|
#define NV_CORE_DEBUG_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
|
||||||
|
#include <stdarg.h> // va_list
|
||||||
|
|
||||||
|
#if NV_OS_IOS //ACS: maybe we want this for OSX too?
|
||||||
|
# ifdef __APPLE__
|
||||||
|
# include <TargetConditionals.h>
|
||||||
|
# include <signal.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Make sure we are using our assert.
|
||||||
|
#undef assert
|
||||||
|
|
||||||
|
#define NV_ABORT_DEBUG 1
|
||||||
|
#define NV_ABORT_IGNORE 2
|
||||||
|
#define NV_ABORT_EXIT 3
|
||||||
|
|
||||||
|
#define nvNoAssert(exp) \
|
||||||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
||||||
|
(void)sizeof(exp); \
|
||||||
|
NV_MULTI_LINE_MACRO_END
|
||||||
|
|
||||||
|
#if NV_NO_ASSERT
|
||||||
|
|
||||||
|
# define nvAssert(exp) nvNoAssert(exp)
|
||||||
|
# define nvCheck(exp) nvNoAssert(exp)
|
||||||
|
# define nvDebugAssert(exp) nvNoAssert(exp)
|
||||||
|
# define nvDebugCheck(exp) nvNoAssert(exp)
|
||||||
|
# define nvDebugBreak() nvNoAssert(0)
|
||||||
|
|
||||||
|
#else // NV_NO_ASSERT
|
||||||
|
|
||||||
|
# if NV_CC_MSVC
|
||||||
|
// @@ Does this work in msvc-6 and earlier?
|
||||||
|
# define nvDebugBreak() __debugbreak()
|
||||||
|
//# define nvDebugBreak() __asm { int 3 }
|
||||||
|
# elif NV_OS_ORBIS
|
||||||
|
# define nvDebugBreak() __debugbreak()
|
||||||
|
# elif NV_OS_IOS && TARGET_OS_IPHONE
|
||||||
|
# define nvDebugBreak() raise(SIGINT)
|
||||||
|
# elif NV_CC_CLANG
|
||||||
|
# define nvDebugBreak() __builtin_debugtrap()
|
||||||
|
# elif NV_CC_GNUC
|
||||||
|
//# define nvDebugBreak() __builtin_debugtrap() // Does GCC have debugtrap?
|
||||||
|
# define nvDebugBreak() __builtin_trap()
|
||||||
|
/*
|
||||||
|
# elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN
|
||||||
|
// @@ Use __builtin_trap() on GCC
|
||||||
|
# define nvDebugBreak() __asm__ volatile ("trap")
|
||||||
|
# elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN
|
||||||
|
# define nvDebugBreak() __asm__ volatile ("int3")
|
||||||
|
# elif NV_CC_GNUC && NV_CPU_X86
|
||||||
|
# define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) )
|
||||||
|
# elif NV_OS_ORBIS
|
||||||
|
# define nvDebugBreak() __asm volatile ("int $0x41")
|
||||||
|
# else
|
||||||
|
# include <signal.h>
|
||||||
|
# define nvDebugBreak() raise(SIGTRAP);
|
||||||
|
// define nvDebugBreak() *((int *)(0)) = 0
|
||||||
|
*/
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if NV_CC_MSVC
|
||||||
|
# define nvExpect(expr) (expr)
|
||||||
|
#else
|
||||||
|
# define nvExpect(expr) __builtin_expect((expr) != 0, true)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NV_CC_CLANG
|
||||||
|
# if __has_feature(attribute_analyzer_noreturn)
|
||||||
|
# define NV_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
|
||||||
|
# else
|
||||||
|
# define NV_ANALYZER_NORETURN
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define NV_ANALYZER_NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define nvDebugBreakOnce() \
|
||||||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
||||||
|
static bool firstTime = true; \
|
||||||
|
if (firstTime) { firstTime = false; nvDebugBreak(); } \
|
||||||
|
NV_MULTI_LINE_MACRO_END
|
||||||
|
|
||||||
|
#define nvAssertMacro(exp) \
|
||||||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
||||||
|
if (!nvExpect(exp)) { \
|
||||||
|
if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \
|
||||||
|
nvDebugBreak(); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
NV_MULTI_LINE_MACRO_END
|
||||||
|
|
||||||
|
// GCC, LLVM need "##" before the __VA_ARGS__, MSVC doesn't care
|
||||||
|
#define nvAssertMacroWithIgnoreAll(exp,...) \
|
||||||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
||||||
|
static bool ignoreAll = false; \
|
||||||
|
if (!ignoreAll && !nvExpect(exp)) { \
|
||||||
|
int _result = nvAbort(#exp, __FILE__, __LINE__, __FUNC__, ##__VA_ARGS__); \
|
||||||
|
if (_result == NV_ABORT_DEBUG) { \
|
||||||
|
nvDebugBreak(); \
|
||||||
|
} else if (_result == NV_ABORT_IGNORE) { \
|
||||||
|
ignoreAll = true; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
NV_MULTI_LINE_MACRO_END
|
||||||
|
|
||||||
|
// Interesting assert macro from Insomniac:
|
||||||
|
// http://www.gdcvault.com/play/1015319/Developing-Imperfect-Software-How-to
|
||||||
|
// Used as follows:
|
||||||
|
// if (nvCheck(i < count)) {
|
||||||
|
// normal path
|
||||||
|
// } else {
|
||||||
|
// fixup code.
|
||||||
|
// }
|
||||||
|
// This style of macro could be combined with __builtin_expect to let the compiler know failure is unlikely.
|
||||||
|
#define nvCheckMacro(exp) \
|
||||||
|
(\
|
||||||
|
(exp) ? true : ( \
|
||||||
|
(nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) ? (nvDebugBreak(), true) : ( false ) \
|
||||||
|
) \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#define nvAssert(exp) nvAssertMacro(exp)
|
||||||
|
#define nvCheck(exp) nvAssertMacro(exp)
|
||||||
|
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
# define nvDebugAssert(exp) nvAssertMacro(exp)
|
||||||
|
# define nvDebugCheck(exp) nvAssertMacro(exp)
|
||||||
|
#else // _DEBUG
|
||||||
|
# define nvDebugAssert(exp) nvNoAssert(exp)
|
||||||
|
# define nvDebugCheck(exp) nvNoAssert(exp)
|
||||||
|
#endif // _DEBUG
|
||||||
|
|
||||||
|
#endif // NV_NO_ASSERT
|
||||||
|
|
||||||
|
// Use nvAssume for very simple expresions only: nvAssume(0), nvAssume(value == true), etc.
|
||||||
|
/*#if !defined(_DEBUG)
|
||||||
|
# if NV_CC_MSVC
|
||||||
|
# define nvAssume(exp) __assume(exp)
|
||||||
|
# else
|
||||||
|
# define nvAssume(exp) nvCheck(exp)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define nvAssume(exp) nvCheck(exp)
|
||||||
|
#endif*/
|
||||||
|
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
# if NV_CC_MSVC
|
||||||
|
# define nvUnreachable() nvAssert(0 && "unreachable"); __assume(0)
|
||||||
|
# else
|
||||||
|
# define nvUnreachable() nvAssert(0 && "unreachable"); __builtin_unreachable()
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if NV_CC_MSVC
|
||||||
|
# define nvUnreachable() __assume(0)
|
||||||
|
# else
|
||||||
|
# define nvUnreachable() __builtin_unreachable()
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define nvError(x) nvAbort(x, __FILE__, __LINE__, __FUNC__)
|
||||||
|
#define nvWarning(x) nvDebugPrint("*** Warning %s/%d: %s\n", __FILE__, __LINE__, (x))
|
||||||
|
|
||||||
|
#ifndef NV_DEBUG_PRINT
|
||||||
|
#define NV_DEBUG_PRINT 1 //defined(_DEBUG)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NV_DEBUG_PRINT
|
||||||
|
#define nvDebug(...) nvDebugPrint(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
#define nvDebug(...) __noop(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define nvDebug(...) ((void)0) // Non-msvc platforms do not evaluate arguments?
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = NULL, const char * msg = NULL, ...) __attribute__((format (printf, 5, 6))) NV_ANALYZER_NORETURN;
|
||||||
|
NVCORE_API void NV_CDECL nvDebugPrint( const char *msg, ... ) __attribute__((format (printf, 1, 2)));
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
inline bool isValidPtr(const void * ptr) {
|
||||||
|
#if NV_OS_DARWIN
|
||||||
|
return true; // IC: Not sure what ranges are OK on OSX.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NV_CPU_X86_64
|
||||||
|
if (ptr == NULL) return true;
|
||||||
|
if (reinterpret_cast<uint64>(ptr) < 0x10000ULL) return false;
|
||||||
|
if (reinterpret_cast<uint64>(ptr) >= 0x000007FFFFFEFFFFULL) return false;
|
||||||
|
#else
|
||||||
|
if (reinterpret_cast<uintptr_t>(ptr) == 0xcccccccc) return false;
|
||||||
|
if (reinterpret_cast<uintptr_t>(ptr) == 0xcdcdcdcd) return false;
|
||||||
|
if (reinterpret_cast<uintptr_t>(ptr) == 0xdddddddd) return false;
|
||||||
|
if (reinterpret_cast<uintptr_t>(ptr) == 0xffffffff) return false;
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message handler interface.
|
||||||
|
struct MessageHandler {
|
||||||
|
virtual void log(const char * str, va_list arg) = 0;
|
||||||
|
virtual ~MessageHandler() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assert handler interface.
|
||||||
|
struct AssertHandler {
|
||||||
|
virtual int assertion(const char *exp, const char *file, int line, const char *func, const char *msg, va_list arg) = 0;
|
||||||
|
virtual ~AssertHandler() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace debug
|
||||||
|
{
|
||||||
|
NVCORE_API void dumpInfo();
|
||||||
|
NVCORE_API void dumpCallstack( MessageHandler *messageHandler, int callstackLevelsToSkip = 0 );
|
||||||
|
|
||||||
|
NVCORE_API void setMessageHandler( MessageHandler * messageHandler );
|
||||||
|
NVCORE_API void resetMessageHandler();
|
||||||
|
|
||||||
|
NVCORE_API void setAssertHandler( AssertHandler * assertHanlder );
|
||||||
|
NVCORE_API void resetAssertHandler();
|
||||||
|
|
||||||
|
NVCORE_API void enableSigHandler(bool interactive);
|
||||||
|
NVCORE_API void disableSigHandler();
|
||||||
|
|
||||||
|
NVCORE_API bool isDebuggerPresent();
|
||||||
|
NVCORE_API bool attachToDebugger();
|
||||||
|
|
||||||
|
NVCORE_API void terminate(int code);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_DEBUG_H
|
|
@ -0,0 +1,57 @@
|
||||||
|
#ifndef NV_CORE_H
|
||||||
|
#error "Do not include this file directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h> // uint8_t, int8_t, ... uintptr_t
|
||||||
|
#include <stddef.h> // operator new, size_t, NULL
|
||||||
|
|
||||||
|
// Function linkage
|
||||||
|
#define DLL_IMPORT
|
||||||
|
#if __GNUC__ >= 4
|
||||||
|
# define DLL_EXPORT __attribute__((visibility("default")))
|
||||||
|
# define DLL_EXPORT_CLASS DLL_EXPORT
|
||||||
|
#else
|
||||||
|
# define DLL_EXPORT
|
||||||
|
# define DLL_EXPORT_CLASS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Function calling modes
|
||||||
|
#if NV_CPU_X86
|
||||||
|
# define NV_CDECL __attribute__((cdecl))
|
||||||
|
# define NV_STDCALL __attribute__((stdcall))
|
||||||
|
#else
|
||||||
|
# define NV_CDECL
|
||||||
|
# define NV_STDCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NV_FASTCALL __attribute__((fastcall))
|
||||||
|
#define NV_FORCEINLINE __attribute__((always_inline)) inline
|
||||||
|
#define NV_DEPRECATED __attribute__((deprecated))
|
||||||
|
#if NV_OS_IOS
|
||||||
|
#define NV_THREAD_LOCAL // @@ IC: Looks like iOS does not have support for TLS declarations.
|
||||||
|
#else
|
||||||
|
#define NV_THREAD_LOCAL __thread
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC__ > 2
|
||||||
|
#define NV_PURE __attribute__((pure))
|
||||||
|
#define NV_CONST __attribute__((const))
|
||||||
|
#else
|
||||||
|
#define NV_PURE
|
||||||
|
#define NV_CONST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NV_NOINLINE __attribute__((noinline))
|
||||||
|
|
||||||
|
// Define __FUNC__ properly.
|
||||||
|
#if __STDC_VERSION__ < 199901L
|
||||||
|
# if __GNUC__ >= 2
|
||||||
|
# define __FUNC__ __PRETTY_FUNCTION__ // __FUNCTION__
|
||||||
|
# else
|
||||||
|
# define __FUNC__ "<unknown>"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define __FUNC__ __PRETTY_FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define restrict __restrict__
|
|
@ -0,0 +1,59 @@
|
||||||
|
#ifndef NV_CORE_H
|
||||||
|
#error "Do not include this file directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h> // uint8_t, int8_t, ... uintptr_t
|
||||||
|
#include <stddef.h> // operator new, size_t, NULL
|
||||||
|
|
||||||
|
// Function linkage
|
||||||
|
#define DLL_IMPORT
|
||||||
|
#if __GNUC__ >= 4
|
||||||
|
# define DLL_EXPORT __attribute__((visibility("default")))
|
||||||
|
# define DLL_EXPORT_CLASS DLL_EXPORT
|
||||||
|
#else
|
||||||
|
# define DLL_EXPORT
|
||||||
|
# define DLL_EXPORT_CLASS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Function calling modes
|
||||||
|
#if NV_CPU_X86
|
||||||
|
# define NV_CDECL __attribute__((cdecl))
|
||||||
|
# define NV_STDCALL __attribute__((stdcall))
|
||||||
|
#else
|
||||||
|
# define NV_CDECL
|
||||||
|
# define NV_STDCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NV_FASTCALL __attribute__((fastcall))
|
||||||
|
//#if __GNUC__ > 3
|
||||||
|
// It seems that GCC does not assume always_inline implies inline. I think this depends on the GCC version :(
|
||||||
|
#define NV_FORCEINLINE inline __attribute__((always_inline))
|
||||||
|
//#else
|
||||||
|
// Some compilers complain that inline and always_inline are redundant.
|
||||||
|
//#define NV_FORCEINLINE __attribute__((always_inline))
|
||||||
|
//#endif
|
||||||
|
#define NV_DEPRECATED __attribute__((deprecated))
|
||||||
|
#define NV_THREAD_LOCAL __thread
|
||||||
|
|
||||||
|
#if __GNUC__ > 2
|
||||||
|
#define NV_PURE __attribute__((pure))
|
||||||
|
#define NV_CONST __attribute__((const))
|
||||||
|
#else
|
||||||
|
#define NV_PURE
|
||||||
|
#define NV_CONST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NV_NOINLINE __attribute__((noinline))
|
||||||
|
|
||||||
|
// Define __FUNC__ properly.
|
||||||
|
#if __STDC_VERSION__ < 199901L
|
||||||
|
# if __GNUC__ >= 2
|
||||||
|
# define __FUNC__ __PRETTY_FUNCTION__ // __FUNCTION__
|
||||||
|
# else
|
||||||
|
# define __FUNC__ "<unknown>"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define __FUNC__ __PRETTY_FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define restrict __restrict__
|
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef NV_CORE_H
|
||||||
|
#error "Do not include this file directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include <cstddef> // size_t, NULL
|
||||||
|
|
||||||
|
// Function linkage
|
||||||
|
#define DLL_IMPORT __declspec(dllimport)
|
||||||
|
#define DLL_EXPORT __declspec(dllexport)
|
||||||
|
#define DLL_EXPORT_CLASS DLL_EXPORT
|
||||||
|
|
||||||
|
// Function calling modes
|
||||||
|
#if NV_CPU_X86
|
||||||
|
# define NV_CDECL __attribute__((cdecl))
|
||||||
|
# define NV_STDCALL __attribute__((stdcall))
|
||||||
|
#else
|
||||||
|
# define NV_CDECL
|
||||||
|
# define NV_STDCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NV_FASTCALL __attribute__((fastcall))
|
||||||
|
#define NV_FORCEINLINE __attribute__((always_inline))
|
||||||
|
#define NV_DEPRECATED __attribute__((deprecated))
|
||||||
|
|
||||||
|
#if __GNUC__ > 2
|
||||||
|
#define NV_PURE __attribute__((pure))
|
||||||
|
#define NV_CONST __attribute__((const))
|
||||||
|
#else
|
||||||
|
#define NV_PURE
|
||||||
|
#define NV_CONST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NV_NOINLINE __attribute__((noinline))
|
||||||
|
|
||||||
|
// Define __FUNC__ properly.
|
||||||
|
#if __STDC_VERSION__ < 199901L
|
||||||
|
# if __GNUC__ >= 2
|
||||||
|
# define __FUNC__ __PRETTY_FUNCTION__ // __FUNCTION__
|
||||||
|
# else
|
||||||
|
# define __FUNC__ "<unknown>"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define __FUNC__ __PRETTY_FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define restrict __restrict__
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Type definitions
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef signed char int8;
|
||||||
|
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef signed short int16;
|
||||||
|
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
typedef signed int int32;
|
||||||
|
|
||||||
|
typedef unsigned long long uint64;
|
||||||
|
typedef signed long long int64;
|
||||||
|
|
||||||
|
// Aliases
|
||||||
|
typedef uint32 uint;
|
||||||
|
*/
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#ifndef NV_CORE_H
|
||||||
|
#error "Do not include this file directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Function linkage
|
||||||
|
#define DLL_IMPORT __declspec(dllimport)
|
||||||
|
#define DLL_EXPORT __declspec(dllexport)
|
||||||
|
#define DLL_EXPORT_CLASS DLL_EXPORT
|
||||||
|
|
||||||
|
// Function calling modes
|
||||||
|
#define NV_CDECL __cdecl
|
||||||
|
#define NV_STDCALL __stdcall
|
||||||
|
#define NV_FASTCALL __fastcall
|
||||||
|
#define NV_DEPRECATED
|
||||||
|
|
||||||
|
#define NV_PURE
|
||||||
|
#define NV_CONST
|
||||||
|
|
||||||
|
// Set standard function names.
|
||||||
|
#if _MSC_VER < 1900
|
||||||
|
# define snprintf _snprintf
|
||||||
|
#endif
|
||||||
|
#if _MSC_VER < 1500
|
||||||
|
# define vsnprintf _vsnprintf
|
||||||
|
#endif
|
||||||
|
#if _MSC_VER < 1700
|
||||||
|
# define strtoll _strtoi64
|
||||||
|
# define strtoull _strtoui64
|
||||||
|
#endif
|
||||||
|
//#define chdir _chdir
|
||||||
|
#define getcwd _getcwd
|
||||||
|
|
||||||
|
#if _MSC_VER <= 1600
|
||||||
|
#define va_copy(a, b) (a) = (b)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined restrict
|
||||||
|
#define restrict
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Ignore gcc attributes.
|
||||||
|
#define __attribute__(X)
|
||||||
|
|
||||||
|
#if !defined __FUNC__
|
||||||
|
#define __FUNC__ __FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NV_NOINLINE __declspec(noinline)
|
||||||
|
#define NV_FORCEINLINE __forceinline
|
||||||
|
|
||||||
|
#define NV_THREAD_LOCAL __declspec(thread)
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Type definitions
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef signed char int8;
|
||||||
|
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef signed short int16;
|
||||||
|
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
typedef signed int int32;
|
||||||
|
|
||||||
|
typedef unsigned __int64 uint64;
|
||||||
|
typedef signed __int64 int64;
|
||||||
|
|
||||||
|
// Aliases
|
||||||
|
typedef uint32 uint;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Unwanted VC++ warnings to disable.
|
||||||
|
/*
|
||||||
|
#pragma warning(disable : 4244) // conversion to float, possible loss of data
|
||||||
|
#pragma warning(disable : 4245) // conversion from 'enum ' to 'unsigned long', signed/unsigned mismatch
|
||||||
|
#pragma warning(disable : 4100) // unreferenced formal parameter
|
||||||
|
#pragma warning(disable : 4514) // unreferenced inline function has been removed
|
||||||
|
#pragma warning(disable : 4710) // inline function not expanded
|
||||||
|
#pragma warning(disable : 4127) // Conditional expression is constant
|
||||||
|
#pragma warning(disable : 4305) // truncation from 'const double' to 'float'
|
||||||
|
#pragma warning(disable : 4505) // unreferenced local function has been removed
|
||||||
|
|
||||||
|
#pragma warning(disable : 4702) // unreachable code in inline expanded function
|
||||||
|
#pragma warning(disable : 4711) // function selected for automatic inlining
|
||||||
|
#pragma warning(disable : 4725) // Pentium fdiv bug
|
||||||
|
|
||||||
|
#pragma warning(disable : 4786) // Identifier was truncated and cannot be debugged.
|
||||||
|
|
||||||
|
#pragma warning(disable : 4675) // resolved overload was found by argument-dependent lookup
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma warning(1 : 4705) // Report unused local variables.
|
||||||
|
#pragma warning(1 : 4555) // Expression has no effect.
|
|
@ -0,0 +1,75 @@
|
||||||
|
// This code is in the public domain -- castano@gmail.com
|
||||||
|
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
#define _CRT_NONSTDC_NO_WARNINGS // _chdir is defined deprecated, but that's a bug, chdir is deprecated, _chdir is *not*.
|
||||||
|
//#include <shlwapi.h> // PathFileExists
|
||||||
|
#include <windows.h> // GetFileAttributes
|
||||||
|
#include <direct.h> // _mkdir
|
||||||
|
#elif NV_OS_XBOX
|
||||||
|
#include <Xtl.h>
|
||||||
|
#elif NV_OS_DURANGO
|
||||||
|
#include <Windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h> // remove, unlink
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
|
||||||
|
bool FileSystem::exists(const char * path)
|
||||||
|
{
|
||||||
|
#if NV_OS_UNIX
|
||||||
|
return access(path, F_OK|R_OK) == 0;
|
||||||
|
//struct stat buf;
|
||||||
|
//return stat(path, &buf) == 0;
|
||||||
|
#elif NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
|
||||||
|
// PathFileExists requires linking to shlwapi.lib
|
||||||
|
//return PathFileExists(path) != 0;
|
||||||
|
return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
|
||||||
|
#else
|
||||||
|
if (FILE * fp = fopen(path, "r"))
|
||||||
|
{
|
||||||
|
fclose(fp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::createDirectory(const char * path)
|
||||||
|
{
|
||||||
|
#if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
|
||||||
|
return CreateDirectoryA(path, NULL) != 0;
|
||||||
|
#elif NV_OS_ORBIS
|
||||||
|
// not implemented
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return mkdir(path, 0777) != -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::changeDirectory(const char * path)
|
||||||
|
{
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
return _chdir(path) != -1;
|
||||||
|
#elif NV_OS_XBOX || NV_OS_DURANGO
|
||||||
|
// Xbox doesn't support Current Working Directory!
|
||||||
|
return false;
|
||||||
|
#elif NV_OS_ORBIS
|
||||||
|
// Orbis doesn't support Current Working Directory!
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return chdir(path) != -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::removeFile(const char * path)
|
||||||
|
{
|
||||||
|
// @@ Use unlink or remove?
|
||||||
|
return remove(path) == 0;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
// This code is in the public domain -- castano@gmail.com
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_FILESYSTEM_H
|
||||||
|
#define NV_CORE_FILESYSTEM_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace FileSystem
|
||||||
|
{
|
||||||
|
NVCORE_API bool exists(const char * path);
|
||||||
|
NVCORE_API bool createDirectory(const char * path);
|
||||||
|
NVCORE_API bool changeDirectory(const char * path);
|
||||||
|
NVCORE_API bool removeFile(const char * path);
|
||||||
|
|
||||||
|
} // FileSystem namespace
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_CORE_FILESYSTEM_H
|
|
@ -0,0 +1,71 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_FOREACH_H
|
||||||
|
#define NV_CORE_FOREACH_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
These foreach macros are very non-standard and somewhat confusing, but I like them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if NV_CC_CPP11
|
||||||
|
|
||||||
|
#define NV_FOREACH(i, container) \
|
||||||
|
for (auto i = (container).start(); !(container).isDone(i); (container).advance(i))
|
||||||
|
|
||||||
|
#elif NV_CC_GNUC // If typeof is available:
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ideally we would like to write this:
|
||||||
|
|
||||||
|
#define NV_FOREACH(i, container) \
|
||||||
|
for(decltype(container)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i))
|
||||||
|
|
||||||
|
But gcc versions prior to 4.7 required an intermediate type. See:
|
||||||
|
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=6709
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NV_FOREACH(i, container) \
|
||||||
|
typedef typeof(container) NV_STRING_JOIN2(cont,__LINE__); \
|
||||||
|
for(NV_STRING_JOIN2(cont,__LINE__)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i))
|
||||||
|
|
||||||
|
#else // If typeof not available:
|
||||||
|
|
||||||
|
#define NV_NEED_PSEUDOINDEX_WRAPPER 1
|
||||||
|
|
||||||
|
#include <new> // placement new
|
||||||
|
|
||||||
|
struct PseudoIndexWrapper {
|
||||||
|
template <typename T>
|
||||||
|
PseudoIndexWrapper(const T & container) {
|
||||||
|
nvStaticCheck(sizeof(typename T::PseudoIndex) <= sizeof(memory));
|
||||||
|
new (memory) typename T::PseudoIndex(container.start());
|
||||||
|
}
|
||||||
|
// PseudoIndex cannot have a dtor!
|
||||||
|
|
||||||
|
template <typename T> typename T::PseudoIndex & operator()(const T * /*container*/) {
|
||||||
|
return *reinterpret_cast<typename T::PseudoIndex *>(memory);
|
||||||
|
}
|
||||||
|
template <typename T> const typename T::PseudoIndex & operator()(const T * /*container*/) const {
|
||||||
|
return *reinterpret_cast<const typename T::PseudoIndex *>(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 memory[4]; // Increase the size if we have bigger enumerators.
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NV_FOREACH(i, container) \
|
||||||
|
for(PseudoIndexWrapper i(container); !(container).isDone(i(&(container))); (container).advance(i(&(container))))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Declare foreach keyword.
|
||||||
|
#if !defined NV_NO_USE_KEYWORDS
|
||||||
|
# define foreach NV_FOREACH
|
||||||
|
# define foreach_index NV_FOREACH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_CORE_FOREACH_H
|
|
@ -0,0 +1,83 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_HASH_H
|
||||||
|
#define NV_CORE_HASH_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
inline uint sdbmHash(const void * data_in, uint size, uint h = 5381)
|
||||||
|
{
|
||||||
|
const uint8 * data = (const uint8 *) data_in;
|
||||||
|
uint i = 0;
|
||||||
|
while (i < size) {
|
||||||
|
h = (h << 16) + (h << 6) - h + (uint) data[i++];
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that this hash does not handle NaN properly.
|
||||||
|
inline uint sdbmFloatHash(const float * f, uint count, uint h = 5381)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
//nvDebugCheck(nv::isFinite(*f));
|
||||||
|
union { float f; uint32 i; } x = { f[i] };
|
||||||
|
if (x.i == 0x80000000) x.i = 0;
|
||||||
|
h = sdbmHash(&x, 4, h);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline uint hash(const T & t, uint h = 5381)
|
||||||
|
{
|
||||||
|
return sdbmHash(&t, sizeof(T), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline uint hash(const float & f, uint h)
|
||||||
|
{
|
||||||
|
return sdbmFloatHash(&f, 1, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Functors for hash table:
|
||||||
|
template <typename Key> struct Hash
|
||||||
|
{
|
||||||
|
uint operator()(const Key & k) const {
|
||||||
|
return hash(k);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Key> struct Equal
|
||||||
|
{
|
||||||
|
bool operator()(const Key & k0, const Key & k1) const {
|
||||||
|
return k0 == k1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// @@ Move to Utils.h?
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
struct Pair {
|
||||||
|
T1 first;
|
||||||
|
T2 second;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
bool operator==(const Pair<T1,T2> & p0, const Pair<T1,T2> & p1) {
|
||||||
|
return p0.first == p1.first && p0.second == p1.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
uint hash(const Pair<T1,T2> & p, uint h = 5381) {
|
||||||
|
return hash(p.second, hash(p.first));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_HASH_H
|
|
@ -0,0 +1,174 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_HASHMAP_H
|
||||||
|
#define NV_CORE_HASHMAP_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
HashMap based on Thatcher Ulrich <tu@tulrich.com> container, donated to the Public Domain.
|
||||||
|
|
||||||
|
I'd like to do something to reduce the amount of code generated with this template. The type of
|
||||||
|
U is largely irrelevant to the generated code, except for calls to constructors and destructors,
|
||||||
|
but the combination of all T and U pairs, generate a large amounts of code.
|
||||||
|
|
||||||
|
HashMap is not used in NVTT, so it could be removed from the repository.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
#include "ForEach.h"
|
||||||
|
#include "Hash.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
class Stream;
|
||||||
|
|
||||||
|
/** Thatcher Ulrich's hash table.
|
||||||
|
*
|
||||||
|
* Hash table, linear probing, internal chaining. One
|
||||||
|
* interesting/nice thing about this implementation is that the table
|
||||||
|
* itself is a flat chunk of memory containing no pointers, only
|
||||||
|
* relative indices. If the key and value types of the hash contain
|
||||||
|
* no pointers, then the hash can be serialized using raw IO. Could
|
||||||
|
* come in handy.
|
||||||
|
*
|
||||||
|
* Never shrinks, unless you explicitly clear() it. Expands on
|
||||||
|
* demand, though. For best results, if you know roughly how big your
|
||||||
|
* table will be, default it to that size when you create it.
|
||||||
|
*/
|
||||||
|
template<typename T, typename U, typename H = Hash<T>, typename E = Equal<T> >
|
||||||
|
class NVCORE_CLASS HashMap
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(HashMap);
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Default ctor.
|
||||||
|
HashMap() : entry_count(0), size_mask(-1), table(NULL) { }
|
||||||
|
|
||||||
|
/// Ctor with size hint.
|
||||||
|
explicit HashMap(int size_hint) : entry_count(0), size_mask(-1), table(NULL) { setCapacity(size_hint); }
|
||||||
|
|
||||||
|
/// Dtor.
|
||||||
|
~HashMap() { clear(); }
|
||||||
|
|
||||||
|
|
||||||
|
void set(const T& key, const U& value);
|
||||||
|
void add(const T& key, const U& value);
|
||||||
|
bool remove(const T& key);
|
||||||
|
void clear();
|
||||||
|
bool isEmpty() const;
|
||||||
|
bool get(const T& key, U* value = NULL, T* other_key = NULL) const;
|
||||||
|
bool contains(const T & key) const;
|
||||||
|
int size() const;
|
||||||
|
int count() const;
|
||||||
|
int capacity() const;
|
||||||
|
void checkExpand();
|
||||||
|
void resize(int n);
|
||||||
|
|
||||||
|
void setCapacity(int new_size);
|
||||||
|
|
||||||
|
// Behaves much like std::pair.
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
int next_in_chain; // internal chaining for collisions
|
||||||
|
uint hash_value; // avoids recomputing. Worthwhile?
|
||||||
|
T key;
|
||||||
|
U value;
|
||||||
|
|
||||||
|
Entry() : next_in_chain(-2) {}
|
||||||
|
Entry(const Entry& e) : next_in_chain(e.next_in_chain), hash_value(e.hash_value), key(e.key), value(e.value) {}
|
||||||
|
Entry(const T& k, const U& v, int next, int hash) : next_in_chain(next), hash_value(hash), key(k), value(v) {}
|
||||||
|
|
||||||
|
bool isEmpty() const { return next_in_chain == -2; }
|
||||||
|
bool isEndOfChain() const { return next_in_chain == -1; }
|
||||||
|
bool isTombstone() const { return hash_value == TOMBSTONE_HASH; }
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
key.~T(); // placement delete
|
||||||
|
value.~U(); // placement delete
|
||||||
|
next_in_chain = -2;
|
||||||
|
hash_value = ~TOMBSTONE_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeTombstone() {
|
||||||
|
key.~T();
|
||||||
|
value.~U();
|
||||||
|
hash_value = TOMBSTONE_HASH;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// HashMap enumerator.
|
||||||
|
typedef int PseudoIndex;
|
||||||
|
PseudoIndex start() const { PseudoIndex i = 0; findNext(i); return i; }
|
||||||
|
bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); return i == size_mask+1; };
|
||||||
|
void advance(PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); i++; findNext(i); }
|
||||||
|
|
||||||
|
#if NV_NEED_PSEUDOINDEX_WRAPPER
|
||||||
|
Entry & operator[]( const PseudoIndexWrapper & i ) {
|
||||||
|
Entry & e = entry(i(this));
|
||||||
|
nvDebugCheck(e.isTombstone() == false);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
const Entry & operator[]( const PseudoIndexWrapper & i ) const {
|
||||||
|
const Entry & e = entry(i(this));
|
||||||
|
nvDebugCheck(e.isTombstone() == false);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
Entry & operator[](const PseudoIndex & i) {
|
||||||
|
Entry & e = entry(i);
|
||||||
|
nvDebugCheck(e.isTombstone() == false);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
const Entry & operator[](const PseudoIndex & i) const {
|
||||||
|
const Entry & e = entry(i);
|
||||||
|
nvDebugCheck(e.isTombstone() == false);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// By default we serialize the key-value pairs compactl y.
|
||||||
|
template<typename _T, typename _U, typename _H, typename _E>
|
||||||
|
friend Stream & operator<< (Stream & s, HashMap<_T, _U, _H, _E> & map);
|
||||||
|
|
||||||
|
// This requires more storage, but saves us from rehashing the elements.
|
||||||
|
template<typename _T, typename _U, typename _H, typename _E>
|
||||||
|
friend Stream & rawSerialize(Stream & s, HashMap<_T, _U, _H, _E> & map);
|
||||||
|
|
||||||
|
/// Swap the members of this vector and the given vector.
|
||||||
|
template<typename _T, typename _U, typename _H, typename _E>
|
||||||
|
friend void swap(HashMap<_T, _U, _H, _E> & a, HashMap<_T, _U, _H, _E> & b);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const uint TOMBSTONE_HASH = (uint) -1;
|
||||||
|
|
||||||
|
uint compute_hash(const T& key) const;
|
||||||
|
|
||||||
|
// Find the index of the matching entry. If no match, then return -1.
|
||||||
|
int findIndex(const T& key) const;
|
||||||
|
|
||||||
|
// Return the index of the newly cleared element.
|
||||||
|
int removeTombstone(int index);
|
||||||
|
|
||||||
|
// Helpers.
|
||||||
|
Entry & entry(int index);
|
||||||
|
const Entry & entry(int index) const;
|
||||||
|
|
||||||
|
void setRawCapacity(int new_size);
|
||||||
|
|
||||||
|
// Move the enumerator to the next valid element.
|
||||||
|
void findNext(PseudoIndex & i) const;
|
||||||
|
|
||||||
|
|
||||||
|
int entry_count;
|
||||||
|
int size_mask;
|
||||||
|
Entry * table;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_HASHMAP_H
|
|
@ -0,0 +1,550 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_HASHMAP_INL
|
||||||
|
#define NV_CORE_HASHMAP_INL
|
||||||
|
|
||||||
|
#include "HashMap.h"
|
||||||
|
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "Utils.h" // swap
|
||||||
|
|
||||||
|
#include <new> // for placement new
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
// Set a new or existing value under the key, to the value.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::set(const T& key, const U& value)
|
||||||
|
{
|
||||||
|
int index = findIndex(key);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
entry(index).value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry under key doesn't exist.
|
||||||
|
add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Add a new value to the hash table, under the specified key.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::add(const T& key, const U& value)
|
||||||
|
{
|
||||||
|
nvCheck(findIndex(key) == -1);
|
||||||
|
|
||||||
|
checkExpand();
|
||||||
|
nvCheck(table != NULL);
|
||||||
|
entry_count++;
|
||||||
|
|
||||||
|
const uint hash_value = compute_hash(key);
|
||||||
|
const int index = hash_value & size_mask;
|
||||||
|
|
||||||
|
Entry * natural_entry = &(entry(index));
|
||||||
|
|
||||||
|
if (natural_entry->isEmpty())
|
||||||
|
{
|
||||||
|
// Put the new entry in.
|
||||||
|
new (natural_entry) Entry(key, value, -1, hash_value);
|
||||||
|
}
|
||||||
|
else if (natural_entry->isTombstone()) {
|
||||||
|
// Put the new entry in, without disturbing the rest of the chain.
|
||||||
|
int next_in_chain = natural_entry->next_in_chain;
|
||||||
|
new (natural_entry) Entry(key, value, next_in_chain, hash_value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Find a blank spot.
|
||||||
|
int blank_index = index;
|
||||||
|
for (int search_count = 0; ; search_count++)
|
||||||
|
{
|
||||||
|
blank_index = (blank_index + 1) & size_mask;
|
||||||
|
if (entry(blank_index).isEmpty()) break; // found it
|
||||||
|
if (entry(blank_index).isTombstone()) {
|
||||||
|
blank_index = removeTombstone(blank_index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nvCheck(search_count < this->size_mask);
|
||||||
|
}
|
||||||
|
Entry * blank_entry = &entry(blank_index);
|
||||||
|
|
||||||
|
if (int(natural_entry->hash_value & size_mask) == index)
|
||||||
|
{
|
||||||
|
// Collision. Link into this chain.
|
||||||
|
|
||||||
|
// Move existing list head.
|
||||||
|
new (blank_entry) Entry(*natural_entry); // placement new, copy ctor
|
||||||
|
|
||||||
|
// Put the new info in the natural entry.
|
||||||
|
natural_entry->key = key;
|
||||||
|
natural_entry->value = value;
|
||||||
|
natural_entry->next_in_chain = blank_index;
|
||||||
|
natural_entry->hash_value = hash_value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Existing entry does not naturally
|
||||||
|
// belong in this slot. Existing
|
||||||
|
// entry must be moved.
|
||||||
|
|
||||||
|
// Find natural location of collided element (i.e. root of chain)
|
||||||
|
int collided_index = natural_entry->hash_value & size_mask;
|
||||||
|
for (int search_count = 0; ; search_count++)
|
||||||
|
{
|
||||||
|
Entry * e = &entry(collided_index);
|
||||||
|
if (e->next_in_chain == index)
|
||||||
|
{
|
||||||
|
// Here's where we need to splice.
|
||||||
|
new (blank_entry) Entry(*natural_entry);
|
||||||
|
e->next_in_chain = blank_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
collided_index = e->next_in_chain;
|
||||||
|
nvCheck(collided_index >= 0 && collided_index <= size_mask);
|
||||||
|
nvCheck(search_count <= size_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the new data in the natural entry.
|
||||||
|
natural_entry->key = key;
|
||||||
|
natural_entry->value = value;
|
||||||
|
natural_entry->hash_value = hash_value;
|
||||||
|
natural_entry->next_in_chain = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the first value under the specified key.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
bool HashMap<T, U, H, E>::remove(const T& key)
|
||||||
|
{
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = findIndex(key);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry * pos = &entry(index);
|
||||||
|
|
||||||
|
int natural_index = (int) (pos->hash_value & size_mask);
|
||||||
|
|
||||||
|
if (index != natural_index) {
|
||||||
|
// We're not the head of our chain, so we can
|
||||||
|
// be spliced out of it.
|
||||||
|
|
||||||
|
// Iterate up the chain, and splice out when
|
||||||
|
// we get to m_index.
|
||||||
|
Entry* e = &entry(natural_index);
|
||||||
|
while (e->next_in_chain != index) {
|
||||||
|
nvDebugCheck(e->isEndOfChain() == false);
|
||||||
|
e = &entry(e->next_in_chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->isTombstone() && pos->isEndOfChain()) {
|
||||||
|
// Tombstone has nothing else to point
|
||||||
|
// to, so mark it empty.
|
||||||
|
e->next_in_chain = -2;
|
||||||
|
} else {
|
||||||
|
e->next_in_chain = pos->next_in_chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos->clear();
|
||||||
|
}
|
||||||
|
else if (pos->isEndOfChain() == false) {
|
||||||
|
// We're the head of our chain, and there are
|
||||||
|
// additional elements.
|
||||||
|
//
|
||||||
|
// We need to put a tombstone here.
|
||||||
|
//
|
||||||
|
// We can't clear the element, because the
|
||||||
|
// rest of the elements in the chain must be
|
||||||
|
// linked to this position.
|
||||||
|
//
|
||||||
|
// We can't move any of the succeeding
|
||||||
|
// elements in the chain (i.e. to fill this
|
||||||
|
// entry), because we don't want to invalidate
|
||||||
|
// any other existing iterators.
|
||||||
|
pos->makeTombstone();
|
||||||
|
} else {
|
||||||
|
// We're the head of the chain, but we're the
|
||||||
|
// only member of the chain.
|
||||||
|
pos->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
entry_count--;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove all entries from the hash table.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::clear()
|
||||||
|
{
|
||||||
|
if (table != NULL)
|
||||||
|
{
|
||||||
|
// Delete the entries.
|
||||||
|
for (int i = 0, n = size_mask; i <= n; i++)
|
||||||
|
{
|
||||||
|
Entry * e = &entry(i);
|
||||||
|
if (e->isEmpty() == false && e->isTombstone() == false)
|
||||||
|
{
|
||||||
|
e->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(table);
|
||||||
|
table = NULL;
|
||||||
|
entry_count = 0;
|
||||||
|
size_mask = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true if the hash is empty.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
bool HashMap<T, U, H, E>::isEmpty() const
|
||||||
|
{
|
||||||
|
return table == NULL || entry_count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Retrieve the value under the given key.
|
||||||
|
// - If there's no value under the key, then return false and leave *value alone.
|
||||||
|
// - If there is a value, return true, and set *value to the entry's value.
|
||||||
|
// - If value == NULL, return true or false according to the presence of the key, but don't touch *value.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
bool HashMap<T, U, H, E>::get(const T& key, U* value/*= NULL*/, T* other_key/*= NULL*/) const
|
||||||
|
{
|
||||||
|
int index = findIndex(key);
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
if (value != NULL) {
|
||||||
|
*value = entry(index).value; // take care with side-effects!
|
||||||
|
}
|
||||||
|
if (other_key != NULL) {
|
||||||
|
*other_key = entry(index).key;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if the given key is contained in the hash.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
bool HashMap<T, U, H, E>::contains(const T & key) const
|
||||||
|
{
|
||||||
|
return get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of entries in the hash.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
int HashMap<T, U, H, E>::size() const
|
||||||
|
{
|
||||||
|
return entry_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of entries in the hash.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
int HashMap<T, U, H, E>::count() const
|
||||||
|
{
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
int HashMap<T, U, H, E>::capacity() const
|
||||||
|
{
|
||||||
|
return size_mask+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resize the hash table to fit one more entry. Often this doesn't involve any action.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::checkExpand()
|
||||||
|
{
|
||||||
|
if (table == NULL) {
|
||||||
|
// Initial creation of table. Make a minimum-sized table.
|
||||||
|
setRawCapacity(16);
|
||||||
|
}
|
||||||
|
else if (entry_count * 3 > (size_mask + 1) * 2) {
|
||||||
|
// Table is more than 2/3rds full. Expand.
|
||||||
|
setRawCapacity(entry_count * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Hint the bucket count to >= n.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::resize(int n)
|
||||||
|
{
|
||||||
|
// Not really sure what this means in relation to
|
||||||
|
// STLport's hash_map... they say they "increase the
|
||||||
|
// bucket count to at least n" -- but does that mean
|
||||||
|
// their real capacity after resize(n) is more like
|
||||||
|
// n*2 (since they do linked-list chaining within
|
||||||
|
// buckets?).
|
||||||
|
setCapacity(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Size the hash so that it can comfortably contain the given number of elements. If the hash already contains more
|
||||||
|
// elements than new_size, then this may be a no-op.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::setCapacity(int new_size)
|
||||||
|
{
|
||||||
|
int new_raw_size = (new_size * 3) / 2;
|
||||||
|
if (new_raw_size < size()) { return; }
|
||||||
|
|
||||||
|
setRawCapacity(new_raw_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// By default we serialize the key-value pairs compactly.
|
||||||
|
template<typename _T, typename _U, typename _H, typename _E>
|
||||||
|
Stream & operator<< (Stream & s, HashMap<_T, _U, _H, _E> & map)
|
||||||
|
{
|
||||||
|
typedef typename HashMap<_T, _U, _H, _E>::Entry HashMapEntry;
|
||||||
|
|
||||||
|
int entry_count = map.entry_count;
|
||||||
|
s << entry_count;
|
||||||
|
|
||||||
|
if (s.isLoading()) {
|
||||||
|
map.clear();
|
||||||
|
if(entry_count == 0) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
map.entry_count = entry_count;
|
||||||
|
map.size_mask = nextPowerOfTwo(U32(entry_count)) - 1;
|
||||||
|
map.table = malloc<HashMapEntry>(map.size_mask + 1);
|
||||||
|
|
||||||
|
for (int i = 0; i <= map.size_mask; i++) {
|
||||||
|
map.table[i].next_in_chain = -2; // mark empty
|
||||||
|
}
|
||||||
|
|
||||||
|
_T key;
|
||||||
|
_U value;
|
||||||
|
for (int i = 0; i < entry_count; i++) {
|
||||||
|
s << key << value;
|
||||||
|
map.add(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int i = 0;
|
||||||
|
map.findNext(i);
|
||||||
|
while (i != map.size_mask+1) {
|
||||||
|
HashMapEntry & e = map.entry(i);
|
||||||
|
|
||||||
|
s << e.key << e.value;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
map.findNext(i);
|
||||||
|
}
|
||||||
|
//for(HashMap<_T, _U, _H, _E>::PseudoIndex i((map).start()); !(map).isDone(i); (map).advance(i)) {
|
||||||
|
//foreach(i, map) {
|
||||||
|
// s << map[i].key << map[i].value;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This requires more storage, but saves us from rehashing the elements.
|
||||||
|
template<typename _T, typename _U, typename _H, typename _E>
|
||||||
|
Stream & rawSerialize(Stream & s, HashMap<_T, _U, _H, _E> & map)
|
||||||
|
{
|
||||||
|
typedef typename HashMap<_T, _U, _H, _E>::Entry HashMapEntry;
|
||||||
|
|
||||||
|
if (s.isLoading()) {
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
s << map.size_mask;
|
||||||
|
|
||||||
|
if (map.size_mask != -1) {
|
||||||
|
s << map.entry_count;
|
||||||
|
|
||||||
|
if (s.isLoading()) {
|
||||||
|
map.table = new HashMapEntry[map.size_mask+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i <= map.size_mask; i++) {
|
||||||
|
HashMapEntry & e = map.table[i];
|
||||||
|
s << e.next_in_chain << e.hash_value;
|
||||||
|
s << e.key;
|
||||||
|
s << e.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the members of this vector and the given vector.
|
||||||
|
template<typename _T, typename _U, typename _H, typename _E>
|
||||||
|
void swap(HashMap<_T, _U, _H, _E> & a, HashMap<_T, _U, _H, _E> & b)
|
||||||
|
{
|
||||||
|
swap(a.entry_count, b.entry_count);
|
||||||
|
swap(a.size_mask, b.size_mask);
|
||||||
|
swap(a.table, b.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
uint HashMap<T, U, H, E>::compute_hash(const T& key) const
|
||||||
|
{
|
||||||
|
H hash;
|
||||||
|
uint hash_value = hash(key);
|
||||||
|
if (hash_value == TOMBSTONE_HASH) {
|
||||||
|
hash_value ^= 0x8000;
|
||||||
|
}
|
||||||
|
return hash_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the index of the matching entry. If no match, then return -1.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
int HashMap<T, U, H, E>::findIndex(const T& key) const
|
||||||
|
{
|
||||||
|
if (table == NULL) return -1;
|
||||||
|
|
||||||
|
E equal;
|
||||||
|
|
||||||
|
uint hash_value = compute_hash(key);
|
||||||
|
int index = hash_value & size_mask;
|
||||||
|
|
||||||
|
const Entry * e = &entry(index);
|
||||||
|
if (e->isEmpty()) return -1;
|
||||||
|
if (e->isTombstone() == false && int(e->hash_value & size_mask) != index) {
|
||||||
|
// occupied by a collider
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
nvCheck(e->isTombstone() || (e->hash_value & size_mask) == (hash_value & size_mask));
|
||||||
|
|
||||||
|
if (e->hash_value == hash_value && equal(e->key, key))
|
||||||
|
{
|
||||||
|
// Found it.
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
nvDebugCheck(e->isTombstone() || !equal(e->key, key)); // keys are equal, but hash differs!
|
||||||
|
|
||||||
|
// Keep looking through the chain.
|
||||||
|
index = e->next_in_chain;
|
||||||
|
if (index == -1) break; // end of chain
|
||||||
|
|
||||||
|
nvCheck(index >= 0 && index <= size_mask);
|
||||||
|
e = &entry(index);
|
||||||
|
|
||||||
|
nvCheck(e->isEmpty() == false || e->isTombstone());
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the index of the newly cleared element.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
int HashMap<T, U, H, E>::removeTombstone(int index) {
|
||||||
|
Entry* e = &entry(index);
|
||||||
|
nvCheck(e->isTombstone());
|
||||||
|
nvCheck(!e->isEndOfChain());
|
||||||
|
|
||||||
|
// Move the next element of the chain into the
|
||||||
|
// tombstone slot, and return the vacated element.
|
||||||
|
int new_blank_index = e->next_in_chain;
|
||||||
|
Entry* new_blank = &entry(new_blank_index);
|
||||||
|
new (e) Entry(*new_blank);
|
||||||
|
new_blank->clear();
|
||||||
|
return new_blank_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
typename HashMap<T, U, H, E>::Entry & HashMap<T, U, H, E>::entry(int index)
|
||||||
|
{
|
||||||
|
nvDebugCheck(table != NULL);
|
||||||
|
nvDebugCheck(index >= 0 && index <= size_mask);
|
||||||
|
return table[index];
|
||||||
|
}
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
const typename HashMap<T, U, H, E>::Entry & HashMap<T, U, H, E>::entry(int index) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(table != NULL);
|
||||||
|
nvDebugCheck(index >= 0 && index <= size_mask);
|
||||||
|
return table[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resize the hash table to the given size (Rehash the contents of the current table). The arg is the number of
|
||||||
|
// hash table entries, not the number of elements we should actually contain (which will be less than this).
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::setRawCapacity(int new_size)
|
||||||
|
{
|
||||||
|
if (new_size <= 0) {
|
||||||
|
// Special case.
|
||||||
|
clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force new_size to be a power of two.
|
||||||
|
new_size = nextPowerOfTwo(U32(new_size));
|
||||||
|
|
||||||
|
HashMap<T, U, H, E> new_hash;
|
||||||
|
new_hash.table = malloc<Entry>(new_size);
|
||||||
|
nvDebugCheck(new_hash.table != NULL);
|
||||||
|
|
||||||
|
new_hash.entry_count = 0;
|
||||||
|
new_hash.size_mask = new_size - 1;
|
||||||
|
for (int i = 0; i < new_size; i++)
|
||||||
|
{
|
||||||
|
new_hash.entry(i).next_in_chain = -2; // mark empty
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy stuff to new_hash
|
||||||
|
if (table != NULL)
|
||||||
|
{
|
||||||
|
for (int i = 0, n = size_mask; i <= n; i++)
|
||||||
|
{
|
||||||
|
Entry * e = &entry(i);
|
||||||
|
if (e->isEmpty() == false && e->isTombstone() == false)
|
||||||
|
{
|
||||||
|
// Insert old entry into new hash.
|
||||||
|
new_hash.add(e->key, e->value);
|
||||||
|
e->clear(); // placement delete of old element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete our old data buffer.
|
||||||
|
free(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steal new_hash's data.
|
||||||
|
entry_count = new_hash.entry_count;
|
||||||
|
size_mask = new_hash.size_mask;
|
||||||
|
table = new_hash.table;
|
||||||
|
new_hash.entry_count = 0;
|
||||||
|
new_hash.size_mask = -1;
|
||||||
|
new_hash.table = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the enumerator to the next valid element.
|
||||||
|
template<typename T, typename U, typename H, typename E>
|
||||||
|
void HashMap<T, U, H, E>::findNext(PseudoIndex & i) const {
|
||||||
|
while (i <= size_mask) {
|
||||||
|
const Entry & e = entry(i);
|
||||||
|
if (e.isEmpty() == false && e.isTombstone() == false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_HASHMAP_INL
|
|
@ -0,0 +1,149 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define USE_EFENCE 0
|
||||||
|
|
||||||
|
#if USE_EFENCE
|
||||||
|
extern "C" void *EF_malloc(size_t size);
|
||||||
|
extern "C" void *EF_realloc(void * oldBuffer, size_t newSize);
|
||||||
|
extern "C" void EF_free(void * address);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
#if NV_OVERRIDE_ALLOC
|
||||||
|
|
||||||
|
void * malloc(size_t size)
|
||||||
|
{
|
||||||
|
#if USE_EFENCE
|
||||||
|
return EF_malloc(size);
|
||||||
|
#else
|
||||||
|
return ::malloc(size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void * debug_malloc(size_t size, const char * file, int line)
|
||||||
|
{
|
||||||
|
NV_UNUSED(file);
|
||||||
|
NV_UNUSED(line);
|
||||||
|
#if USE_EFENCE
|
||||||
|
return EF_malloc(size);
|
||||||
|
#else
|
||||||
|
return ::malloc(size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void * ptr)
|
||||||
|
{
|
||||||
|
#if USE_EFENCE
|
||||||
|
return EF_free(const_cast<void *>(ptr));
|
||||||
|
#else
|
||||||
|
::free(const_cast<void *>(ptr));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void * realloc(void * ptr, size_t size)
|
||||||
|
{
|
||||||
|
nvDebugCheck(ptr != NULL || size != 0); // undefined realloc behavior.
|
||||||
|
#if USE_EFENCE
|
||||||
|
return EF_realloc(ptr, size);
|
||||||
|
#else
|
||||||
|
return ::realloc(ptr, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* No need to override this unless we want line info.
|
||||||
|
void * operator new (size_t size) throw()
|
||||||
|
{
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete (void *p) throw()
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void * operator new [] (size_t size) throw()
|
||||||
|
{
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete [] (void * p) throw()
|
||||||
|
{
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 0 // Code from Apple:
|
||||||
|
void* operator new(std::size_t sz) throw (std::bad_alloc)
|
||||||
|
{
|
||||||
|
void *result = std::malloc (sz == 0 ? 1 : sz);
|
||||||
|
if (result == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
gNewCounter++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
void operator delete(void* p) throw()
|
||||||
|
{
|
||||||
|
if (p == NULL)
|
||||||
|
return;
|
||||||
|
std::free (p);
|
||||||
|
gDeleteCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* These are the 'nothrow' versions of the above operators.
|
||||||
|
The system version will try to call a std::new_handler if they
|
||||||
|
fail, but your overriding versions are not required to do this. */
|
||||||
|
void* operator new(std::size_t sz, const std::nothrow_t&) throw()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
void * result = ::operator new (sz); // calls our overridden operator new
|
||||||
|
return result;
|
||||||
|
} catch (std::bad_alloc &) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void operator delete(void* p, const std::nothrow_t&) throw()
|
||||||
|
{
|
||||||
|
::operator delete (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // 0
|
||||||
|
|
||||||
|
#endif // NV_OVERRIDE_ALLOC
|
||||||
|
|
||||||
|
void * nv::aligned_malloc(size_t size, size_t alignment)
|
||||||
|
{
|
||||||
|
// alignment must be a power of two, multiple of sizeof(void*)
|
||||||
|
nvDebugCheck(isPowerOfTwo(alignment));
|
||||||
|
nvDebugCheck((alignment & (sizeof(void*) - 1)) == 0);
|
||||||
|
|
||||||
|
#if NV_OS_WIN32 || NV_OS_DURANGO
|
||||||
|
return _aligned_malloc(size, alignment);
|
||||||
|
#elif NV_OS_DARWIN && !NV_OS_IOS
|
||||||
|
void * ptr = NULL;
|
||||||
|
posix_memalign(&ptr, alignment, size);
|
||||||
|
return ptr;
|
||||||
|
#elif NV_OS_LINUX
|
||||||
|
return memalign(alignment, size);
|
||||||
|
#else // NV_OS_ORBIS || NV_OS_IOS
|
||||||
|
// @@ IC: iOS appears to be 16 byte aligned, should we check alignment and assert if we request a higher alignment factor?
|
||||||
|
return ::malloc(size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv::aligned_free(void * ptr)
|
||||||
|
{
|
||||||
|
#if NV_OS_WIN32 || NV_OS_DURANGO
|
||||||
|
_aligned_free(ptr);
|
||||||
|
#else
|
||||||
|
::free(ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_MEMORY_H
|
||||||
|
#define NV_CORE_MEMORY_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
|
||||||
|
#include <stdlib.h> // malloc(), realloc() and free()
|
||||||
|
#include <string.h> // memset
|
||||||
|
//#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
//#include <new> // new and delete
|
||||||
|
|
||||||
|
#define TRACK_MEMORY_LEAKS 0
|
||||||
|
#if TRACK_MEMORY_LEAKS
|
||||||
|
#include <vld.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if NV_CC_GNUC
|
||||||
|
# define NV_ALIGN_16 __attribute__ ((__aligned__ (16)))
|
||||||
|
#else
|
||||||
|
# define NV_ALIGN_16 __declspec(align(16))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define NV_OVERRIDE_ALLOC 0
|
||||||
|
|
||||||
|
#if NV_OVERRIDE_ALLOC
|
||||||
|
|
||||||
|
// Custom memory allocator
|
||||||
|
extern "C" {
|
||||||
|
NVCORE_API void * malloc(size_t size);
|
||||||
|
NVCORE_API void * debug_malloc(size_t size, const char * file, int line);
|
||||||
|
NVCORE_API void free(void * ptr);
|
||||||
|
NVCORE_API void * realloc(void * ptr, size_t size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define new new(__FILE__, __LINE__)
|
||||||
|
#define malloc(i) debug_malloc(i, __FILE__, __LINE__)
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nv {
|
||||||
|
NVCORE_API void * aligned_malloc(size_t size, size_t alignment);
|
||||||
|
NVCORE_API void aligned_free(void * );
|
||||||
|
|
||||||
|
// C++ helpers.
|
||||||
|
template <typename T> NV_FORCEINLINE T * malloc(size_t count) {
|
||||||
|
return (T *)::malloc(sizeof(T) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> NV_FORCEINLINE T * realloc(T * ptr, size_t count) {
|
||||||
|
return (T *)::realloc(ptr, sizeof(T) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> NV_FORCEINLINE void free(const T * ptr) {
|
||||||
|
::free((void *)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> NV_FORCEINLINE void zero(T & data) {
|
||||||
|
memset(&data, 0, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_MEMORY_H
|
|
@ -0,0 +1,322 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#ifndef NV_CORE_PTR_H
|
||||||
|
#define NV_CORE_PTR_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
|
||||||
|
#include "RefCounted.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
class WeakProxy;
|
||||||
|
|
||||||
|
/** Simple auto pointer template class.
|
||||||
|
*
|
||||||
|
* This is very similar to the standard auto_ptr class, but with some
|
||||||
|
* additional limitations to make its use less error prone:
|
||||||
|
* - Copy constructor and assignment operator are disabled.
|
||||||
|
* - reset method is removed.
|
||||||
|
*
|
||||||
|
* The semantics of the standard auto_ptr are not clear and change depending
|
||||||
|
* on the std implementation. For a discussion of the problems of auto_ptr read:
|
||||||
|
* http://www.awprofessional.com/content/images/020163371X/autoptrupdate\auto_ptr_update.html
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
class AutoPtr
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(AutoPtr);
|
||||||
|
NV_FORBID_HEAPALLOC();
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Ctor.
|
||||||
|
AutoPtr(T * p = NULL) : m_ptr(p) { }
|
||||||
|
|
||||||
|
template <class Q>
|
||||||
|
AutoPtr(Q * p) : m_ptr(static_cast<T *>(p)) { }
|
||||||
|
|
||||||
|
/// Dtor. Deletes owned pointer.
|
||||||
|
~AutoPtr() {
|
||||||
|
delete m_ptr;
|
||||||
|
m_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delete owned pointer and assign new one.
|
||||||
|
void operator=( T * p ) {
|
||||||
|
if (p != m_ptr)
|
||||||
|
{
|
||||||
|
delete m_ptr;
|
||||||
|
m_ptr = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Q>
|
||||||
|
void operator=( Q * p ) {
|
||||||
|
if (p != m_ptr)
|
||||||
|
{
|
||||||
|
delete m_ptr;
|
||||||
|
m_ptr = static_cast<T *>(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Member access.
|
||||||
|
T * operator -> () const {
|
||||||
|
nvDebugCheck(m_ptr != NULL);
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get reference.
|
||||||
|
T & operator*() const {
|
||||||
|
nvDebugCheck(m_ptr != NULL);
|
||||||
|
return *m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get pointer.
|
||||||
|
T * ptr() const { return m_ptr; }
|
||||||
|
|
||||||
|
/// Relinquish ownership of the underlying pointer and returns that pointer.
|
||||||
|
T * release() {
|
||||||
|
T * tmp = m_ptr;
|
||||||
|
m_ptr = NULL;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Const pointer equal comparation.
|
||||||
|
friend bool operator == (const AutoPtr<T> & ap, const T * const p) {
|
||||||
|
return (ap.ptr() == p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Const pointer nequal comparation.
|
||||||
|
friend bool operator != (const AutoPtr<T> & ap, const T * const p) {
|
||||||
|
return (ap.ptr() != p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Const pointer equal comparation.
|
||||||
|
friend bool operator == (const T * const p, const AutoPtr<T> & ap) {
|
||||||
|
return (ap.ptr() == p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Const pointer nequal comparation.
|
||||||
|
friend bool operator != (const T * const p, const AutoPtr<T> & ap) {
|
||||||
|
return (ap.ptr() != p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T * m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Smart pointer template class.
|
||||||
|
template <class BaseClass>
|
||||||
|
class SmartPtr {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// BaseClass must implement addRef() and release().
|
||||||
|
typedef SmartPtr<BaseClass> ThisType;
|
||||||
|
|
||||||
|
/// Default ctor.
|
||||||
|
SmartPtr() : m_ptr(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Other type assignment.
|
||||||
|
template <class OtherBase>
|
||||||
|
SmartPtr( const SmartPtr<OtherBase> & tc )
|
||||||
|
{
|
||||||
|
m_ptr = static_cast<BaseClass *>( tc.ptr() );
|
||||||
|
if (m_ptr) {
|
||||||
|
m_ptr->addRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy ctor.
|
||||||
|
SmartPtr( const ThisType & bc )
|
||||||
|
{
|
||||||
|
m_ptr = bc.ptr();
|
||||||
|
if (m_ptr) {
|
||||||
|
m_ptr->addRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy cast ctor. SmartPtr(NULL) is valid.
|
||||||
|
explicit SmartPtr( BaseClass * bc )
|
||||||
|
{
|
||||||
|
m_ptr = bc;
|
||||||
|
if (m_ptr) {
|
||||||
|
m_ptr->addRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dtor.
|
||||||
|
~SmartPtr()
|
||||||
|
{
|
||||||
|
set(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// -> operator.
|
||||||
|
BaseClass * operator -> () const
|
||||||
|
{
|
||||||
|
nvCheck( m_ptr != NULL );
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// * operator.
|
||||||
|
BaseClass & operator*() const
|
||||||
|
{
|
||||||
|
nvCheck( m_ptr != NULL );
|
||||||
|
return *m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get pointer.
|
||||||
|
BaseClass * ptr() const
|
||||||
|
{
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Other type assignment.
|
||||||
|
template <class OtherBase>
|
||||||
|
void operator = ( const SmartPtr<OtherBase> & tc )
|
||||||
|
{
|
||||||
|
set( static_cast<BaseClass *>(tc.ptr()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This type assignment.
|
||||||
|
void operator = ( const ThisType & bc )
|
||||||
|
{
|
||||||
|
set( bc.ptr() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pointer assignment.
|
||||||
|
void operator = ( BaseClass * bc )
|
||||||
|
{
|
||||||
|
set( bc );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Other type equal comparation.
|
||||||
|
template <class OtherBase>
|
||||||
|
bool operator == ( const SmartPtr<OtherBase> & other ) const
|
||||||
|
{
|
||||||
|
return m_ptr == other.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This type equal comparation.
|
||||||
|
bool operator == ( const ThisType & bc ) const
|
||||||
|
{
|
||||||
|
return m_ptr == bc.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Const pointer equal comparation.
|
||||||
|
bool operator == ( const BaseClass * const bc ) const
|
||||||
|
{
|
||||||
|
return m_ptr == bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Other type not equal comparation.
|
||||||
|
template <class OtherBase>
|
||||||
|
bool operator != ( const SmartPtr<OtherBase> & other ) const
|
||||||
|
{
|
||||||
|
return m_ptr != other.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Other type not equal comparation.
|
||||||
|
bool operator != ( const ThisType & bc ) const
|
||||||
|
{
|
||||||
|
return m_ptr != bc.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Const pointer not equal comparation.
|
||||||
|
bool operator != (const BaseClass * const bc) const
|
||||||
|
{
|
||||||
|
return m_ptr != bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This type lower than comparation.
|
||||||
|
bool operator < (const ThisType & p) const
|
||||||
|
{
|
||||||
|
return m_ptr < p.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const {
|
||||||
|
return isValidPtr(m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Set this pointer.
|
||||||
|
void set( BaseClass * p )
|
||||||
|
{
|
||||||
|
if (p) p->addRef();
|
||||||
|
if (m_ptr) m_ptr->release();
|
||||||
|
m_ptr = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
BaseClass * m_ptr;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Smart pointer template class.
|
||||||
|
template <class T>
|
||||||
|
class WeakPtr {
|
||||||
|
public:
|
||||||
|
|
||||||
|
WeakPtr() {}
|
||||||
|
|
||||||
|
WeakPtr(T * p) { operator=(p); }
|
||||||
|
WeakPtr(const SmartPtr<T> & p) { operator=(p.ptr()); }
|
||||||
|
|
||||||
|
// Default constructor and assignment from weak_ptr<T> are OK.
|
||||||
|
|
||||||
|
void operator=(T * p)
|
||||||
|
{
|
||||||
|
if (p) {
|
||||||
|
m_proxy = p->getWeakProxy();
|
||||||
|
nvDebugCheck(m_proxy != NULL);
|
||||||
|
nvDebugCheck(m_proxy->ptr() == p);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_proxy = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const SmartPtr<T> & ptr) { operator=(ptr.ptr()); }
|
||||||
|
|
||||||
|
bool operator==(const SmartPtr<T> & p) const { return ptr() == p.ptr(); }
|
||||||
|
bool operator!=(const SmartPtr<T> & p) const { return ptr() != p.ptr(); }
|
||||||
|
|
||||||
|
bool operator==(const WeakPtr<T> & p) const { return ptr() == p.ptr(); }
|
||||||
|
bool operator!=(const WeakPtr<T> & p) const { return ptr() != p.ptr(); }
|
||||||
|
|
||||||
|
bool operator==(T * p) const { return ptr() == p; }
|
||||||
|
bool operator!=(T * p) const { return ptr() != p; }
|
||||||
|
|
||||||
|
T * operator->() const
|
||||||
|
{
|
||||||
|
T * p = ptr();
|
||||||
|
nvDebugCheck(p != NULL);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
T * ptr() const
|
||||||
|
{
|
||||||
|
if (m_proxy != NULL) {
|
||||||
|
return static_cast<T *>(m_proxy->ptr());
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
mutable SmartPtr<WeakProxy> m_proxy;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_PTR_H
|
|
@ -0,0 +1,285 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#include "RadixSort.h"
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
#include <string.h> // memset
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
static inline void FloatFlip(uint32 & f) {
|
||||||
|
//uint32 mask = -int32(f >> 31) | 0x80000000; // Michael Herf.
|
||||||
|
int32 mask = (int32(f) >> 31) | 0x80000000; // Warren Hunt, Manchor Ko.
|
||||||
|
f ^= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void IFloatFlip(uint32 & f) {
|
||||||
|
uint32 mask = ((f >> 31) - 1) | 0x80000000; // Michael Herf.
|
||||||
|
//uint32 mask = (int32(f ^ 0x80000000) >> 31) | 0x80000000; // Warren Hunt, Manchor Ko. @@ Correct, but fails in release on gcc-4.2.1
|
||||||
|
f ^= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void createHistograms(const T * buffer, uint count, uint * histogram)
|
||||||
|
{
|
||||||
|
const uint bucketCount = sizeof(T); // (8 * sizeof(T)) / log2(radix)
|
||||||
|
|
||||||
|
// Init bucket pointers.
|
||||||
|
uint * h[bucketCount];
|
||||||
|
for (uint i = 0; i < bucketCount; i++) {
|
||||||
|
#if NV_BIG_ENDIAN
|
||||||
|
h[sizeof(T)-1-i] = histogram + 256 * i;
|
||||||
|
#else
|
||||||
|
h[i] = histogram + 256 * i;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear histograms.
|
||||||
|
memset(histogram, 0, 256 * bucketCount * sizeof(uint));
|
||||||
|
|
||||||
|
// @@ Add support for signed integers.
|
||||||
|
|
||||||
|
// Build histograms.
|
||||||
|
const uint8 * p = (const uint8 *)buffer; // @@ Does this break aliasing rules?
|
||||||
|
const uint8 * pe = p + count * sizeof(T);
|
||||||
|
|
||||||
|
while (p != pe) {
|
||||||
|
h[0][*p++]++, h[1][*p++]++, h[2][*p++]++, h[3][*p++]++;
|
||||||
|
if (bucketCount == 8) h[4][*p++]++, h[5][*p++]++, h[6][*p++]++, h[7][*p++]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
template <>
|
||||||
|
void createHistograms<float>(const float * buffer, uint count, uint * histogram)
|
||||||
|
{
|
||||||
|
// Init bucket pointers.
|
||||||
|
uint32 * h[4];
|
||||||
|
for (uint i = 0; i < 4; i++) {
|
||||||
|
#if NV_BIG_ENDIAN
|
||||||
|
h[3-i] = histogram + 256 * i;
|
||||||
|
#else
|
||||||
|
h[i] = histogram + 256 * i;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear histograms.
|
||||||
|
memset(histogram, 0, 256 * 4 * sizeof(uint32));
|
||||||
|
|
||||||
|
// Build histograms.
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
uint32 fi = FloatFlip(buffer[i]);
|
||||||
|
|
||||||
|
h[0][fi & 0xFF]++;
|
||||||
|
h[1][(fi >> 8) & 0xFF]++;
|
||||||
|
h[2][(fi >> 16) & 0xFF]++;
|
||||||
|
h[3][fi >> 24]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
RadixSort::RadixSort() : m_size(0), m_ranks(NULL), m_ranks2(NULL), m_validRanks(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RadixSort::RadixSort(uint reserve_count) : m_size(0), m_ranks(NULL), m_ranks2(NULL), m_validRanks(false)
|
||||||
|
{
|
||||||
|
checkResize(reserve_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
RadixSort::~RadixSort()
|
||||||
|
{
|
||||||
|
// Release everything
|
||||||
|
free(m_ranks2);
|
||||||
|
free(m_ranks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RadixSort::resize(uint count)
|
||||||
|
{
|
||||||
|
m_ranks2 = realloc<uint>(m_ranks2, count);
|
||||||
|
m_ranks = realloc<uint>(m_ranks, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RadixSort::checkResize(uint count)
|
||||||
|
{
|
||||||
|
if (count != m_size)
|
||||||
|
{
|
||||||
|
if (count > m_size) resize(count);
|
||||||
|
m_size = count;
|
||||||
|
m_validRanks = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> inline void RadixSort::insertionSort(const T * input, uint count)
|
||||||
|
{
|
||||||
|
if (!m_validRanks) {
|
||||||
|
/*for (uint i = 0; i < count; i++) {
|
||||||
|
m_ranks[i] = i;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
m_ranks[0] = 0;
|
||||||
|
for (uint i = 1; i != count; ++i)
|
||||||
|
{
|
||||||
|
int rank = m_ranks[i] = i;
|
||||||
|
|
||||||
|
uint j = i;
|
||||||
|
while (j != 0 && input[rank] < input[m_ranks[j-1]])
|
||||||
|
{
|
||||||
|
m_ranks[j] = m_ranks[j-1];
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
if (i != j)
|
||||||
|
{
|
||||||
|
m_ranks[j] = rank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_validRanks = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (uint i = 1; i != count; ++i)
|
||||||
|
{
|
||||||
|
int rank = m_ranks[i];
|
||||||
|
|
||||||
|
uint j = i;
|
||||||
|
while (j != 0 && input[rank] < input[m_ranks[j-1]])
|
||||||
|
{
|
||||||
|
m_ranks[j] = m_ranks[j-1];
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
if (i != j)
|
||||||
|
{
|
||||||
|
m_ranks[j] = rank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> inline void RadixSort::radixSort(const T * input, uint count)
|
||||||
|
{
|
||||||
|
const uint P = sizeof(T); // pass count
|
||||||
|
|
||||||
|
// Allocate histograms & offsets on the stack
|
||||||
|
uint histogram[256 * P];
|
||||||
|
uint * link[256];
|
||||||
|
|
||||||
|
createHistograms(input, count, histogram);
|
||||||
|
|
||||||
|
// Radix sort, j is the pass number (0=LSB, P=MSB)
|
||||||
|
for (uint j = 0; j < P; j++)
|
||||||
|
{
|
||||||
|
// Pointer to this bucket.
|
||||||
|
const uint * h = &histogram[j * 256];
|
||||||
|
|
||||||
|
const uint8 * inputBytes = (const uint8*)input; // @@ Is this aliasing legal?
|
||||||
|
|
||||||
|
#if NV_BIG_ENDIAN
|
||||||
|
inputBytes += P - 1 - j;
|
||||||
|
#else
|
||||||
|
inputBytes += j;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (h[inputBytes[0]] == count) {
|
||||||
|
// Skip this pass, all values are the same.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create offsets
|
||||||
|
link[0] = m_ranks2;
|
||||||
|
for (uint i = 1; i < 256; i++) link[i] = link[i-1] + h[i-1];
|
||||||
|
|
||||||
|
// Perform Radix Sort
|
||||||
|
if (!m_validRanks)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
*link[inputBytes[i*P]]++ = i;
|
||||||
|
}
|
||||||
|
m_validRanks = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
const uint idx = m_ranks[i];
|
||||||
|
*link[inputBytes[idx*P]]++ = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap pointers for next pass. Valid indices - the most recent ones - are in m_ranks after the swap.
|
||||||
|
swap(m_ranks, m_ranks2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// All values were equal, generate linear ranks.
|
||||||
|
if (!m_validRanks)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
m_ranks[i] = i;
|
||||||
|
}
|
||||||
|
m_validRanks = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RadixSort & RadixSort::sort(const uint32 * input, uint count)
|
||||||
|
{
|
||||||
|
if (input == NULL || count == 0) return *this;
|
||||||
|
|
||||||
|
// Resize lists if needed
|
||||||
|
checkResize(count);
|
||||||
|
|
||||||
|
if (count < 32) {
|
||||||
|
insertionSort(input, count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
radixSort<uint32>(input, count);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RadixSort & RadixSort::sort(const uint64 * input, uint count)
|
||||||
|
{
|
||||||
|
if (input == NULL || count == 0) return *this;
|
||||||
|
|
||||||
|
// Resize lists if needed
|
||||||
|
checkResize(count);
|
||||||
|
|
||||||
|
if (count < 64) {
|
||||||
|
insertionSort(input, count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
radixSort(input, count);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
RadixSort& RadixSort::sort(const float * input, uint count)
|
||||||
|
{
|
||||||
|
if (input == NULL || count == 0) return *this;
|
||||||
|
|
||||||
|
// Resize lists if needed
|
||||||
|
checkResize(count);
|
||||||
|
|
||||||
|
if (count < 32) {
|
||||||
|
insertionSort(input, count);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// @@ Avoid touching the input multiple times.
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
FloatFlip((uint32 &)input[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
radixSort<uint32>((const uint32 *)input, count);
|
||||||
|
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
IFloatFlip((uint32 &)input[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_RADIXSORT_H
|
||||||
|
#define NV_CORE_RADIXSORT_H
|
||||||
|
|
||||||
|
// Based on Pierre Terdiman's and Michael Herf's source code.
|
||||||
|
// http://www.codercorner.com/RadixSortRevisited.htm
|
||||||
|
// http://www.stereopsis.com/radix.html
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
#include "Array.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
class NVCORE_CLASS RadixSort
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(RadixSort);
|
||||||
|
public:
|
||||||
|
// Constructor/Destructor
|
||||||
|
RadixSort();
|
||||||
|
RadixSort(uint reserve_count);
|
||||||
|
~RadixSort();
|
||||||
|
|
||||||
|
// Invalidate ranks.
|
||||||
|
RadixSort & reset() { m_validRanks = false; return *this; }
|
||||||
|
|
||||||
|
// Sorting methods.
|
||||||
|
RadixSort & sort(const uint32 * input, uint count);
|
||||||
|
RadixSort & sort(const uint64 * input, uint count);
|
||||||
|
RadixSort & sort(const float * input, uint count);
|
||||||
|
|
||||||
|
// Helpers.
|
||||||
|
RadixSort & sort(const Array<uint32> & input);
|
||||||
|
RadixSort & sort(const Array<uint64> & input);
|
||||||
|
RadixSort & sort(const Array<float> & input);
|
||||||
|
|
||||||
|
// Access to results. m_ranks is a list of indices in sorted order, i.e. in the order you may further process your data
|
||||||
|
inline const uint * ranks() const { nvDebugCheck(m_validRanks); return m_ranks; }
|
||||||
|
inline uint * ranks() { nvDebugCheck(m_validRanks); return m_ranks; }
|
||||||
|
inline uint rank(uint i) const { nvDebugCheck(m_validRanks); return m_ranks[i]; }
|
||||||
|
|
||||||
|
// query whether the sort has been performed
|
||||||
|
inline bool valid() const { return m_validRanks; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint m_size;
|
||||||
|
uint * m_ranks;
|
||||||
|
uint * m_ranks2;
|
||||||
|
bool m_validRanks;
|
||||||
|
|
||||||
|
// Internal methods
|
||||||
|
template <typename T> void insertionSort(const T * input, uint count);
|
||||||
|
template <typename T> void radixSort(const T * input, uint count);
|
||||||
|
|
||||||
|
void checkResize(uint nb);
|
||||||
|
void resize(uint nb);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline RadixSort & RadixSort::sort(const Array<uint32> & input) {
|
||||||
|
return sort(input.buffer(), input.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RadixSort & RadixSort::sort(const Array<uint64> & input) {
|
||||||
|
return sort(input.buffer(), input.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline RadixSort & RadixSort::sort(const Array<float> & input) {
|
||||||
|
return sort(input.buffer(), input.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_CORE_RADIXSORT_H
|
|
@ -0,0 +1,149 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#ifndef NV_CORE_REFCOUNTED_H
|
||||||
|
#define NV_CORE_REFCOUNTED_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
|
||||||
|
#define NV_DECLARE_PTR(Class) \
|
||||||
|
template <class T> class SmartPtr; \
|
||||||
|
typedef SmartPtr<class Class> Class ## Ptr; \
|
||||||
|
typedef SmartPtr<const class Class> Class ## ConstPtr
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
/// Weak proxy.
|
||||||
|
class WeakProxy
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(WeakProxy);
|
||||||
|
public:
|
||||||
|
/// Ctor.
|
||||||
|
WeakProxy(void * ptr) : m_count(0), m_ptr(ptr) { }
|
||||||
|
|
||||||
|
/// Dtor.
|
||||||
|
~WeakProxy()
|
||||||
|
{
|
||||||
|
nvCheck( m_count == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase reference count.
|
||||||
|
uint addRef() const
|
||||||
|
{
|
||||||
|
m_count++;
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrease reference count and remove when 0.
|
||||||
|
uint release() const
|
||||||
|
{
|
||||||
|
nvCheck( m_count > 0 );
|
||||||
|
|
||||||
|
m_count--;
|
||||||
|
if( m_count == 0 ) {
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// WeakPtr's call this to determine if their pointer is valid or not.
|
||||||
|
bool isAlive() const {
|
||||||
|
return m_ptr != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only the actual object should call this.
|
||||||
|
void notifyObjectDied() {
|
||||||
|
m_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return proxy pointer.
|
||||||
|
void * ptr() const {
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mutable int m_count;
|
||||||
|
void * m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Reference counted base class to be used with SmartPtr and WeakPtr.
|
||||||
|
class RefCounted
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(RefCounted);
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Ctor.
|
||||||
|
RefCounted() : m_count(0), m_weak_proxy(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Virtual dtor.
|
||||||
|
virtual ~RefCounted()
|
||||||
|
{
|
||||||
|
nvCheck( m_count == 0 );
|
||||||
|
releaseWeakProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Increase reference count.
|
||||||
|
uint addRef() const
|
||||||
|
{
|
||||||
|
m_count++;
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Decrease reference count and remove when 0.
|
||||||
|
uint release() const
|
||||||
|
{
|
||||||
|
nvCheck( m_count > 0 );
|
||||||
|
|
||||||
|
m_count--;
|
||||||
|
if( m_count == 0 ) {
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get weak proxy.
|
||||||
|
WeakProxy * getWeakProxy() const
|
||||||
|
{
|
||||||
|
if (m_weak_proxy == NULL) {
|
||||||
|
m_weak_proxy = new WeakProxy((void *)this);
|
||||||
|
m_weak_proxy->addRef();
|
||||||
|
}
|
||||||
|
return m_weak_proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release the weak proxy.
|
||||||
|
void releaseWeakProxy() const
|
||||||
|
{
|
||||||
|
if (m_weak_proxy != NULL) {
|
||||||
|
m_weak_proxy->notifyObjectDied();
|
||||||
|
m_weak_proxy->release();
|
||||||
|
m_weak_proxy = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get reference count.
|
||||||
|
int refCount() const
|
||||||
|
{
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
mutable int m_count;
|
||||||
|
mutable WeakProxy * m_weak_proxy;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_CORE_REFCOUNTED_H
|
|
@ -0,0 +1,474 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
//#pragma once
|
||||||
|
//#ifndef NV_CORE_STDSTREAM_H
|
||||||
|
//#define NV_CORE_STDSTREAM_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "Array.h"
|
||||||
|
|
||||||
|
#include <stdio.h> // fopen
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
// Portable version of fopen.
|
||||||
|
inline FILE * fileOpen(const char * fileName, const char * mode)
|
||||||
|
{
|
||||||
|
nvCheck(fileName != NULL);
|
||||||
|
#if NV_CC_MSVC && _MSC_VER >= 1400
|
||||||
|
FILE * fp;
|
||||||
|
if (fopen_s(&fp, fileName, mode) == 0) {
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
return fopen(fileName, mode);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Base stdio stream.
|
||||||
|
class NVCORE_CLASS StdStream : public Stream
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(StdStream);
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Ctor.
|
||||||
|
StdStream( FILE * fp, bool autoclose ) : m_fp(fp), m_autoclose(autoclose) { }
|
||||||
|
|
||||||
|
/// Dtor.
|
||||||
|
virtual ~StdStream()
|
||||||
|
{
|
||||||
|
if( m_fp != NULL && m_autoclose ) {
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
_fclose_nolock( m_fp );
|
||||||
|
#else
|
||||||
|
fclose( m_fp );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Stream implementation. */
|
||||||
|
//@{
|
||||||
|
virtual void seek( uint pos )
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_fp != NULL);
|
||||||
|
nvDebugCheck(pos <= size());
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
_fseek_nolock(m_fp, pos, SEEK_SET);
|
||||||
|
#else
|
||||||
|
fseek(m_fp, pos, SEEK_SET);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint tell() const
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_fp != NULL);
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
return _ftell_nolock(m_fp);
|
||||||
|
#else
|
||||||
|
return (uint)ftell(m_fp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint size() const
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_fp != NULL);
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
uint pos = _ftell_nolock(m_fp);
|
||||||
|
_fseek_nolock(m_fp, 0, SEEK_END);
|
||||||
|
uint end = _ftell_nolock(m_fp);
|
||||||
|
_fseek_nolock(m_fp, pos, SEEK_SET);
|
||||||
|
#else
|
||||||
|
uint pos = (uint)ftell(m_fp);
|
||||||
|
fseek(m_fp, 0, SEEK_END);
|
||||||
|
uint end = (uint)ftell(m_fp);
|
||||||
|
fseek(m_fp, pos, SEEK_SET);
|
||||||
|
#endif
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isError() const
|
||||||
|
{
|
||||||
|
return m_fp == NULL || ferror( m_fp ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void clearError()
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_fp != NULL);
|
||||||
|
clearerr(m_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@ The original implementation uses feof, which only returns true when we attempt to read *past* the end of the stream.
|
||||||
|
// That is, if we read the last byte of a file, then isAtEnd would still return false, even though the stream pointer is at the file end. This is not the intent and was inconsistent with the implementation of the MemoryStream, a better
|
||||||
|
// implementation uses use ftell and fseek to determine our location within the file.
|
||||||
|
virtual bool isAtEnd() const
|
||||||
|
{
|
||||||
|
if (m_fp == NULL) return true;
|
||||||
|
//nvDebugCheck(m_fp != NULL);
|
||||||
|
//return feof( m_fp ) != 0;
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
uint pos = _ftell_nolock(m_fp);
|
||||||
|
_fseek_nolock(m_fp, 0, SEEK_END);
|
||||||
|
uint end = _ftell_nolock(m_fp);
|
||||||
|
_fseek_nolock(m_fp, pos, SEEK_SET);
|
||||||
|
#else
|
||||||
|
uint pos = (uint)ftell(m_fp);
|
||||||
|
fseek(m_fp, 0, SEEK_END);
|
||||||
|
uint end = (uint)ftell(m_fp);
|
||||||
|
fseek(m_fp, pos, SEEK_SET);
|
||||||
|
#endif
|
||||||
|
return pos == end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always true.
|
||||||
|
virtual bool isSeekable() const { return true; }
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
FILE * m_fp;
|
||||||
|
bool m_autoclose;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Standard output stream.
|
||||||
|
class NVCORE_CLASS StdOutputStream : public StdStream
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(StdOutputStream);
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Construct stream by file name.
|
||||||
|
StdOutputStream( const char * name ) : StdStream(fileOpen(name, "wb"), /*autoclose=*/true) { }
|
||||||
|
|
||||||
|
/// Construct stream by file handle.
|
||||||
|
StdOutputStream( FILE * fp, bool autoclose ) : StdStream(fp, autoclose)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @name Stream implementation. */
|
||||||
|
//@{
|
||||||
|
/// Write data.
|
||||||
|
virtual uint serialize( void * data, uint len )
|
||||||
|
{
|
||||||
|
nvDebugCheck(data != NULL);
|
||||||
|
nvDebugCheck(m_fp != NULL);
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
return (uint)_fwrite_nolock(data, 1, len, m_fp);
|
||||||
|
#elif NV_OS_LINUX
|
||||||
|
return (uint)fwrite_unlocked(data, 1, len, m_fp);
|
||||||
|
#elif NV_OS_DARWIN
|
||||||
|
// @@ No error checking, always returns len.
|
||||||
|
for (uint i = 0; i < len; i++) {
|
||||||
|
putc_unlocked(((char *)data)[i], m_fp);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
#else
|
||||||
|
return (uint)fwrite(data, 1, len, m_fp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isLoading() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isSaving() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//@}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Standard input stream.
|
||||||
|
class NVCORE_CLASS StdInputStream : public StdStream
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(StdInputStream);
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Construct stream by file name.
|
||||||
|
StdInputStream( const char * name ) : StdStream(fileOpen(name, "rb"), /*autoclose=*/true) { }
|
||||||
|
|
||||||
|
/// Construct stream by file handle.
|
||||||
|
StdInputStream( FILE * fp, bool autoclose=true ) : StdStream(fp, autoclose)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @name Stream implementation. */
|
||||||
|
//@{
|
||||||
|
/// Read data.
|
||||||
|
virtual uint serialize( void * data, uint len )
|
||||||
|
{
|
||||||
|
nvDebugCheck(data != NULL);
|
||||||
|
nvDebugCheck(m_fp != NULL);
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
return (uint)_fread_nolock(data, 1, len, m_fp);
|
||||||
|
#elif NV_OS_LINUX
|
||||||
|
return (uint)fread_unlocked(data, 1, len, m_fp);
|
||||||
|
#elif NV_OS_DARWIN
|
||||||
|
// This is rather lame. Not sure if it's faster than the locked version.
|
||||||
|
for (uint i = 0; i < len; i++) {
|
||||||
|
((char *)data)[i] = getc_unlocked(m_fp);
|
||||||
|
if (feof_unlocked(m_fp) != 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
#else
|
||||||
|
return (uint)fread(data, 1, len, m_fp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isLoading() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isSaving() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//@}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Memory input stream.
|
||||||
|
class NVCORE_CLASS MemoryInputStream : public Stream
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(MemoryInputStream);
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Ctor.
|
||||||
|
MemoryInputStream( const uint8 * mem, uint size ) : m_mem(mem), m_ptr(mem), m_size(size) { }
|
||||||
|
|
||||||
|
/** @name Stream implementation. */
|
||||||
|
//@{
|
||||||
|
/// Read data.
|
||||||
|
virtual uint serialize( void * data, uint len )
|
||||||
|
{
|
||||||
|
nvDebugCheck(data != NULL);
|
||||||
|
nvDebugCheck(!isError());
|
||||||
|
|
||||||
|
uint left = m_size - tell();
|
||||||
|
if (len > left) len = left;
|
||||||
|
|
||||||
|
memcpy( data, m_ptr, len );
|
||||||
|
m_ptr += len;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void seek( uint pos )
|
||||||
|
{
|
||||||
|
nvDebugCheck(!isError());
|
||||||
|
m_ptr = m_mem + pos;
|
||||||
|
nvDebugCheck(!isError());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint tell() const
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_ptr >= m_mem);
|
||||||
|
return uint(m_ptr - m_mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint size() const
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isError() const
|
||||||
|
{
|
||||||
|
return m_mem == NULL || m_ptr > m_mem + m_size || m_ptr < m_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void clearError()
|
||||||
|
{
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isAtEnd() const
|
||||||
|
{
|
||||||
|
return m_ptr == m_mem + m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always true.
|
||||||
|
virtual bool isSeekable() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isLoading() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isSaving() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//@}
|
||||||
|
|
||||||
|
const uint8 * ptr() const { return m_ptr; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const uint8 * m_mem;
|
||||||
|
const uint8 * m_ptr;
|
||||||
|
uint m_size;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Buffer output stream.
|
||||||
|
class NVCORE_CLASS BufferOutputStream : public Stream
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(BufferOutputStream);
|
||||||
|
public:
|
||||||
|
|
||||||
|
BufferOutputStream(Array<uint8> & buffer) : m_buffer(buffer) { }
|
||||||
|
|
||||||
|
virtual uint serialize( void * data, uint len )
|
||||||
|
{
|
||||||
|
nvDebugCheck(data != NULL);
|
||||||
|
m_buffer.append((uint8 *)data, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void seek( uint /*pos*/ ) { /*Not implemented*/ }
|
||||||
|
virtual uint tell() const { return m_buffer.size(); }
|
||||||
|
virtual uint size() const { return m_buffer.size(); }
|
||||||
|
|
||||||
|
virtual bool isError() const { return false; }
|
||||||
|
virtual void clearError() {}
|
||||||
|
|
||||||
|
virtual bool isAtEnd() const { return true; }
|
||||||
|
virtual bool isSeekable() const { return false; }
|
||||||
|
virtual bool isLoading() const { return false; }
|
||||||
|
virtual bool isSaving() const { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Array<uint8> & m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Protected input stream.
|
||||||
|
class NVCORE_CLASS ProtectedStream : public Stream
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(ProtectedStream);
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Ctor.
|
||||||
|
ProtectedStream( Stream & s ) : m_s(&s), m_autodelete(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ctor.
|
||||||
|
ProtectedStream( Stream * s, bool autodelete = true ) :
|
||||||
|
m_s(s), m_autodelete(autodelete)
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_s != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dtor.
|
||||||
|
virtual ~ProtectedStream()
|
||||||
|
{
|
||||||
|
if( m_autodelete ) {
|
||||||
|
delete m_s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @name Stream implementation. */
|
||||||
|
//@{
|
||||||
|
/// Read data.
|
||||||
|
virtual uint serialize( void * data, uint len )
|
||||||
|
{
|
||||||
|
nvDebugCheck(data != NULL);
|
||||||
|
len = m_s->serialize( data, len );
|
||||||
|
|
||||||
|
if( m_s->isError() ) {
|
||||||
|
#if NV_OS_ORBIS
|
||||||
|
//SBtodoORBIS disabled (no exceptions)
|
||||||
|
#else
|
||||||
|
throw;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void seek( uint pos )
|
||||||
|
{
|
||||||
|
m_s->seek( pos );
|
||||||
|
|
||||||
|
if( m_s->isError() ) {
|
||||||
|
#if NV_OS_ORBIS
|
||||||
|
//SBtodoORBIS disabled (no exceptions)
|
||||||
|
#else
|
||||||
|
throw;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint tell() const
|
||||||
|
{
|
||||||
|
return m_s->tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint size() const
|
||||||
|
{
|
||||||
|
return m_s->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isError() const
|
||||||
|
{
|
||||||
|
return m_s->isError();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void clearError()
|
||||||
|
{
|
||||||
|
m_s->clearError();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isAtEnd() const
|
||||||
|
{
|
||||||
|
return m_s->isAtEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isSeekable() const
|
||||||
|
{
|
||||||
|
return m_s->isSeekable();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isLoading() const
|
||||||
|
{
|
||||||
|
return m_s->isLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isSaving() const
|
||||||
|
{
|
||||||
|
return m_s->isSaving();
|
||||||
|
}
|
||||||
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Stream * const m_s;
|
||||||
|
bool const m_autodelete;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
//#endif // NV_CORE_STDSTREAM_H
|
|
@ -0,0 +1,796 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#include "StrLib.h"
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Utils.h" // swap
|
||||||
|
|
||||||
|
#include <math.h> // log
|
||||||
|
#include <stdio.h> // vsnprintf
|
||||||
|
#include <string.h> // strlen, strcmp, etc.
|
||||||
|
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
#include <stdarg.h> // vsnprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static char * strAlloc(uint size)
|
||||||
|
{
|
||||||
|
return malloc<char>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * strReAlloc(char * str, uint size)
|
||||||
|
{
|
||||||
|
return realloc<char>(str, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strFree(const char * str)
|
||||||
|
{
|
||||||
|
return free<char>(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static char * strDup( const char * str )
|
||||||
|
{
|
||||||
|
nvDebugCheck( str != NULL );
|
||||||
|
uint len = uint(strlen( str ) + 1);
|
||||||
|
char * dup = strAlloc( len );
|
||||||
|
memcpy( dup, str, len );
|
||||||
|
return dup;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// helper function for integer to string conversion.
|
||||||
|
static char * i2a( uint i, char *a, uint r )
|
||||||
|
{
|
||||||
|
if( i / r > 0 ) {
|
||||||
|
a = i2a( i / r, a, r );
|
||||||
|
}
|
||||||
|
*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % r];
|
||||||
|
return a + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locale independent functions.
|
||||||
|
static inline char toUpper( char c ) {
|
||||||
|
return (c<'a' || c>'z') ? (c) : (c+'A'-'a');
|
||||||
|
}
|
||||||
|
static inline char toLower( char c ) {
|
||||||
|
return (c<'A' || c>'Z') ? (c) : (c+'a'-'A');
|
||||||
|
}
|
||||||
|
static inline bool isAlpha( char c ) {
|
||||||
|
return (c>='a' && c<='z') || (c>='A' && c<='Z');
|
||||||
|
}
|
||||||
|
static inline bool isDigit( char c ) {
|
||||||
|
return c>='0' && c<='9';
|
||||||
|
}
|
||||||
|
static inline bool isAlnum( char c ) {
|
||||||
|
return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint nv::strLen(const char * str)
|
||||||
|
{
|
||||||
|
nvDebugCheck(str != NULL);
|
||||||
|
return U32(strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv::strDiff(const char * s1, const char * s2)
|
||||||
|
{
|
||||||
|
nvDebugCheck(s1 != NULL);
|
||||||
|
nvDebugCheck(s2 != NULL);
|
||||||
|
return strcmp(s1, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nv::strCaseDiff(const char * s1, const char * s2)
|
||||||
|
{
|
||||||
|
nvDebugCheck(s1 != NULL);
|
||||||
|
nvDebugCheck(s1 != NULL);
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
return _stricmp(s1, s2);
|
||||||
|
#else
|
||||||
|
return strcasecmp(s1, s2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::strEqual(const char * s1, const char * s2)
|
||||||
|
{
|
||||||
|
if (s1 == s2) return true;
|
||||||
|
if (s1 == NULL || s2 == NULL) return false;
|
||||||
|
return strcmp(s1, s2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::strCaseEqual(const char * s1, const char * s2)
|
||||||
|
{
|
||||||
|
if (s1 == s2) return true;
|
||||||
|
if (s1 == NULL || s2 == NULL) return false;
|
||||||
|
return strCaseDiff(s1, s2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::strBeginsWith(const char * str, const char * prefix)
|
||||||
|
{
|
||||||
|
//return strstr(str, prefix) == dst;
|
||||||
|
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::strEndsWith(const char * str, const char * suffix)
|
||||||
|
{
|
||||||
|
uint ml = strLen(str);
|
||||||
|
uint sl = strLen(suffix);
|
||||||
|
if (ml < sl) return false;
|
||||||
|
return strncmp(str + ml - sl, suffix, sl) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@ Add asserts to detect overlap between dst and src?
|
||||||
|
void nv::strCpy(char * dst, uint size, const char * src)
|
||||||
|
{
|
||||||
|
nvDebugCheck(dst != NULL);
|
||||||
|
nvDebugCheck(src != NULL);
|
||||||
|
#if NV_CC_MSVC && _MSC_VER >= 1400
|
||||||
|
strcpy_s(dst, size, src);
|
||||||
|
#else
|
||||||
|
NV_UNUSED(size);
|
||||||
|
strcpy(dst, src);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv::strCpy(char * dst, uint size, const char * src, uint len)
|
||||||
|
{
|
||||||
|
nvDebugCheck(dst != NULL);
|
||||||
|
nvDebugCheck(src != NULL);
|
||||||
|
#if NV_CC_MSVC && _MSC_VER >= 1400
|
||||||
|
strncpy_s(dst, size, src, len);
|
||||||
|
#else
|
||||||
|
int n = min(len+1, size);
|
||||||
|
strncpy(dst, src, n);
|
||||||
|
dst[n-1] = '\0';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv::strCat(char * dst, uint size, const char * src)
|
||||||
|
{
|
||||||
|
nvDebugCheck(dst != NULL);
|
||||||
|
nvDebugCheck(src != NULL);
|
||||||
|
#if NV_CC_MSVC && _MSC_VER >= 1400
|
||||||
|
strcat_s(dst, size, src);
|
||||||
|
#else
|
||||||
|
NV_UNUSED(size);
|
||||||
|
strcat(dst, src);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
NVCORE_API const char * nv::strSkipWhiteSpace(const char * str)
|
||||||
|
{
|
||||||
|
nvDebugCheck(str != NULL);
|
||||||
|
while (*str == ' ') str++;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
NVCORE_API char * nv::strSkipWhiteSpace(char * str)
|
||||||
|
{
|
||||||
|
nvDebugCheck(str != NULL);
|
||||||
|
while (*str == ' ') str++;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Pattern matching routine. I don't remember where did I get this. */
|
||||||
|
bool nv::strMatch(const char * str, const char * pat)
|
||||||
|
{
|
||||||
|
nvDebugCheck(str != NULL);
|
||||||
|
nvDebugCheck(pat != NULL);
|
||||||
|
|
||||||
|
char c2;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (*pat==0) {
|
||||||
|
if (*str==0) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
if ((*str==0) && (*pat!='*')) return false;
|
||||||
|
if (*pat=='*') {
|
||||||
|
pat++;
|
||||||
|
if (*pat==0) return true;
|
||||||
|
while (true) {
|
||||||
|
if (strMatch(str, pat)) return true;
|
||||||
|
if (*str==0) return false;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*pat=='?') goto match;
|
||||||
|
if (*pat=='[') {
|
||||||
|
pat++;
|
||||||
|
while (true) {
|
||||||
|
if ((*pat==']') || (*pat==0)) return false;
|
||||||
|
if (*pat==*str) break;
|
||||||
|
if (pat[1] == '-') {
|
||||||
|
c2 = pat[2];
|
||||||
|
if (c2==0) return false;
|
||||||
|
if ((*pat<=*str) && (c2>=*str)) break;
|
||||||
|
if ((*pat>=*str) && (c2<=*str)) break;
|
||||||
|
pat+=2;
|
||||||
|
}
|
||||||
|
pat++;
|
||||||
|
}
|
||||||
|
while (*pat!=']') {
|
||||||
|
if (*pat==0) {
|
||||||
|
pat--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pat++;
|
||||||
|
}
|
||||||
|
goto match;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pat == NV_PATH_SEPARATOR) {
|
||||||
|
pat++;
|
||||||
|
if (*pat==0) return false;
|
||||||
|
}
|
||||||
|
if (*pat!=*str) return false;
|
||||||
|
|
||||||
|
match:
|
||||||
|
pat++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::isNumber(const char * str) {
|
||||||
|
while(*str != '\0') {
|
||||||
|
if (!isDigit(*str)) return false;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Empty string. */
|
||||||
|
StringBuilder::StringBuilder() : m_size(0), m_str(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Preallocate space. */
|
||||||
|
StringBuilder::StringBuilder( uint size_hint ) : m_size(size_hint)
|
||||||
|
{
|
||||||
|
nvDebugCheck(m_size > 0);
|
||||||
|
m_str = strAlloc(m_size);
|
||||||
|
*m_str = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy ctor. */
|
||||||
|
StringBuilder::StringBuilder( const StringBuilder & s ) : m_size(0), m_str(NULL)
|
||||||
|
{
|
||||||
|
copy(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy string. */
|
||||||
|
StringBuilder::StringBuilder(const char * s) : m_size(0), m_str(NULL)
|
||||||
|
{
|
||||||
|
if (s != NULL) {
|
||||||
|
copy(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy string. */
|
||||||
|
StringBuilder::StringBuilder(const char * s, uint len) : m_size(0), m_str(NULL)
|
||||||
|
{
|
||||||
|
copy(s, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Delete the string. */
|
||||||
|
StringBuilder::~StringBuilder()
|
||||||
|
{
|
||||||
|
strFree(m_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Format a string safely. */
|
||||||
|
StringBuilder & StringBuilder::format( const char * fmt, ... )
|
||||||
|
{
|
||||||
|
nvDebugCheck(fmt != NULL);
|
||||||
|
va_list arg;
|
||||||
|
va_start( arg, fmt );
|
||||||
|
|
||||||
|
formatList( fmt, arg );
|
||||||
|
|
||||||
|
va_end( arg );
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Format a string safely. */
|
||||||
|
StringBuilder & StringBuilder::formatList( const char * fmt, va_list arg )
|
||||||
|
{
|
||||||
|
nvDebugCheck(fmt != NULL);
|
||||||
|
|
||||||
|
if (m_size == 0) {
|
||||||
|
m_size = 64;
|
||||||
|
m_str = strAlloc( m_size );
|
||||||
|
}
|
||||||
|
|
||||||
|
va_list tmp;
|
||||||
|
va_copy(tmp, arg);
|
||||||
|
#if NV_CC_MSVC && _MSC_VER >= 1400
|
||||||
|
int n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp);
|
||||||
|
#else
|
||||||
|
int n = vsnprintf(m_str, m_size, fmt, tmp);
|
||||||
|
#endif
|
||||||
|
va_end(tmp);
|
||||||
|
|
||||||
|
while( n < 0 || n >= int(m_size) ) {
|
||||||
|
if( n > -1 ) {
|
||||||
|
m_size = n + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_str = strReAlloc(m_str, m_size);
|
||||||
|
|
||||||
|
va_copy(tmp, arg);
|
||||||
|
#if NV_CC_MSVC && _MSC_VER >= 1400
|
||||||
|
n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp);
|
||||||
|
#else
|
||||||
|
n = vsnprintf(m_str, m_size, fmt, tmp);
|
||||||
|
#endif
|
||||||
|
va_end(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
nvDebugCheck(n < int(m_size));
|
||||||
|
|
||||||
|
// Make sure it's null terminated.
|
||||||
|
nvDebugCheck(m_str[n] == '\0');
|
||||||
|
//str[n] = '\0';
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Append a character.
|
||||||
|
StringBuilder & StringBuilder::append( char c )
|
||||||
|
{
|
||||||
|
return append(&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a string.
|
||||||
|
StringBuilder & StringBuilder::append( const char * s )
|
||||||
|
{
|
||||||
|
return append(s, U32(strlen( s )));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append a string.
|
||||||
|
StringBuilder & StringBuilder::append(const char * s, uint len)
|
||||||
|
{
|
||||||
|
nvDebugCheck(s != NULL);
|
||||||
|
|
||||||
|
uint offset = length();
|
||||||
|
const uint size = offset + len + 1;
|
||||||
|
reserve(size);
|
||||||
|
strCpy(m_str + offset, len + 1, s, len);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder & StringBuilder::append(const StringBuilder & str)
|
||||||
|
{
|
||||||
|
return append(str.m_str, str.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Append a formatted string. */
|
||||||
|
StringBuilder & StringBuilder::appendFormat( const char * fmt, ... )
|
||||||
|
{
|
||||||
|
nvDebugCheck( fmt != NULL );
|
||||||
|
|
||||||
|
va_list arg;
|
||||||
|
va_start( arg, fmt );
|
||||||
|
|
||||||
|
appendFormatList( fmt, arg );
|
||||||
|
|
||||||
|
va_end( arg );
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Append a formatted string. */
|
||||||
|
StringBuilder & StringBuilder::appendFormatList( const char * fmt, va_list arg )
|
||||||
|
{
|
||||||
|
nvDebugCheck( fmt != NULL );
|
||||||
|
|
||||||
|
va_list tmp;
|
||||||
|
va_copy(tmp, arg);
|
||||||
|
|
||||||
|
if (m_size == 0) {
|
||||||
|
formatList(fmt, arg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StringBuilder tmp_str;
|
||||||
|
tmp_str.formatList( fmt, tmp );
|
||||||
|
append( tmp_str.str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(tmp);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append n spaces.
|
||||||
|
StringBuilder & StringBuilder::appendSpace(uint n)
|
||||||
|
{
|
||||||
|
if (m_str == NULL) {
|
||||||
|
m_size = n + 1;
|
||||||
|
m_str = strAlloc(m_size);
|
||||||
|
memset(m_str, ' ', m_size);
|
||||||
|
m_str[n] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint len = strLen(m_str);
|
||||||
|
if (m_size < len + n + 1) {
|
||||||
|
m_size = len + n + 1;
|
||||||
|
m_str = strReAlloc(m_str, m_size);
|
||||||
|
}
|
||||||
|
memset(m_str + len, ' ', n);
|
||||||
|
m_str[len+n] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Convert number to string in the given base. */
|
||||||
|
StringBuilder & StringBuilder::number( int i, int base )
|
||||||
|
{
|
||||||
|
nvCheck( base >= 2 );
|
||||||
|
nvCheck( base <= 36 );
|
||||||
|
|
||||||
|
// @@ This needs to be done correctly.
|
||||||
|
// length = floor(log(i, base));
|
||||||
|
uint len = uint(log(float(i)) / log(float(base)) + 2); // one more if negative
|
||||||
|
reserve(len);
|
||||||
|
|
||||||
|
if( i < 0 ) {
|
||||||
|
*m_str = '-';
|
||||||
|
*i2a(uint(-i), m_str+1, base) = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*i2a(i, m_str, base) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Convert number to string in the given base. */
|
||||||
|
StringBuilder & StringBuilder::number( uint i, int base )
|
||||||
|
{
|
||||||
|
nvCheck( base >= 2 );
|
||||||
|
nvCheck( base <= 36 );
|
||||||
|
|
||||||
|
// @@ This needs to be done correctly.
|
||||||
|
// length = floor(log(i, base));
|
||||||
|
uint len = uint(log(float(i)) / log(float(base)) - 0.5f + 1);
|
||||||
|
reserve(len);
|
||||||
|
|
||||||
|
*i2a(i, m_str, base) = 0;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Resize the string preserving the contents. */
|
||||||
|
StringBuilder & StringBuilder::reserve( uint size_hint )
|
||||||
|
{
|
||||||
|
nvCheck(size_hint != 0);
|
||||||
|
if (size_hint > m_size) {
|
||||||
|
m_str = strReAlloc(m_str, size_hint);
|
||||||
|
m_size = size_hint;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Copy a string safely. */
|
||||||
|
StringBuilder & StringBuilder::copy(const char * s)
|
||||||
|
{
|
||||||
|
nvCheck( s != NULL );
|
||||||
|
const uint str_size = uint(strlen( s )) + 1;
|
||||||
|
reserve(str_size);
|
||||||
|
memcpy(m_str, s, str_size);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy a string safely. */
|
||||||
|
StringBuilder & StringBuilder::copy(const char * s, uint len)
|
||||||
|
{
|
||||||
|
nvCheck( s != NULL );
|
||||||
|
const uint str_size = len + 1;
|
||||||
|
reserve(str_size);
|
||||||
|
strCpy(m_str, str_size, s, len);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Copy an StringBuilder. */
|
||||||
|
StringBuilder & StringBuilder::copy( const StringBuilder & s )
|
||||||
|
{
|
||||||
|
if (s.m_str == NULL) {
|
||||||
|
nvCheck( s.m_size == 0 );
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reserve( s.m_size );
|
||||||
|
strCpy( m_str, s.m_size, s.m_str );
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringBuilder::endsWith(const char * str) const
|
||||||
|
{
|
||||||
|
uint l = uint(strlen(str));
|
||||||
|
uint ml = uint(strlen(m_str));
|
||||||
|
if (ml < l) return false;
|
||||||
|
return strncmp(m_str + ml - l, str, l) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringBuilder::beginsWith(const char * str) const
|
||||||
|
{
|
||||||
|
size_t l = strlen(str);
|
||||||
|
return strncmp(m_str, str, l) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find given char starting from the end.
|
||||||
|
char * StringBuilder::reverseFind(char c)
|
||||||
|
{
|
||||||
|
int length = (int)strlen(m_str) - 1;
|
||||||
|
while (length >= 0 && m_str[length] != c) {
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
if (length >= 0) {
|
||||||
|
return m_str + length;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Reset the string. */
|
||||||
|
void StringBuilder::reset()
|
||||||
|
{
|
||||||
|
m_size = 0;
|
||||||
|
strFree( m_str );
|
||||||
|
m_str = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Release the allocated string. */
|
||||||
|
char * StringBuilder::release()
|
||||||
|
{
|
||||||
|
char * str = m_str;
|
||||||
|
m_size = 0;
|
||||||
|
m_str = NULL;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take ownership of string.
|
||||||
|
void StringBuilder::acquire(char * str)
|
||||||
|
{
|
||||||
|
if (str) {
|
||||||
|
m_size = strLen(str) + 1;
|
||||||
|
m_str = str;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_size = 0;
|
||||||
|
m_str = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap strings.
|
||||||
|
void nv::swap(StringBuilder & a, StringBuilder & b) {
|
||||||
|
swap(a.m_size, b.m_size);
|
||||||
|
swap(a.m_str, b.m_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get the file name from a path.
|
||||||
|
const char * Path::fileName() const
|
||||||
|
{
|
||||||
|
return fileName(m_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get the extension from a file path.
|
||||||
|
const char * Path::extension() const
|
||||||
|
{
|
||||||
|
return extension(m_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static */void Path::translatePath(char * path, char pathSeparator/*= NV_PATH_SEPARATOR*/) {
|
||||||
|
if (path != NULL) {
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
if (path[i] == '\0') break;
|
||||||
|
if (path[i] == '\\' || path[i] == '/') path[i] = pathSeparator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggles path separators (ie. \\ into /).
|
||||||
|
void Path::translatePath(char pathSeparator/*=NV_PATH_SEPARATOR*/)
|
||||||
|
{
|
||||||
|
if (!isNull()) {
|
||||||
|
translatePath(m_str, pathSeparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Path::appendSeparator(char pathSeparator/*=NV_PATH_SEPARATOR*/)
|
||||||
|
{
|
||||||
|
nvCheck(!isNull());
|
||||||
|
|
||||||
|
const uint l = length();
|
||||||
|
|
||||||
|
if (m_str[l] != '\\' && m_str[l] != '/') {
|
||||||
|
char separatorString[] = { pathSeparator, '\0' };
|
||||||
|
append(separatorString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip the file name from a path.
|
||||||
|
* @warning path cannot end with '/' o '\\', can't it?
|
||||||
|
*/
|
||||||
|
void Path::stripFileName()
|
||||||
|
{
|
||||||
|
nvCheck( m_str != NULL );
|
||||||
|
|
||||||
|
int length = (int)strlen(m_str) - 1;
|
||||||
|
while (length > 0 && m_str[length] != '/' && m_str[length] != '\\'){
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
if( length ) {
|
||||||
|
m_str[length+1] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_str[0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Strip the extension from a path name.
|
||||||
|
void Path::stripExtension()
|
||||||
|
{
|
||||||
|
nvCheck( m_str != NULL );
|
||||||
|
|
||||||
|
int length = (int)strlen(m_str) - 1;
|
||||||
|
while (length > 0 && m_str[length] != '.') {
|
||||||
|
length--;
|
||||||
|
if( m_str[length] == NV_PATH_SEPARATOR ) {
|
||||||
|
return; // no extension
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (length > 0) {
|
||||||
|
m_str[length] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get the path separator.
|
||||||
|
// static
|
||||||
|
char Path::separator()
|
||||||
|
{
|
||||||
|
return NV_PATH_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
const char * Path::fileName(const char * str)
|
||||||
|
{
|
||||||
|
nvCheck( str != NULL );
|
||||||
|
|
||||||
|
int length = (int)strlen(str) - 1;
|
||||||
|
while (length >= 0 && str[length] != '\\' && str[length] != '/') {
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &str[length+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
const char * Path::extension(const char * str)
|
||||||
|
{
|
||||||
|
nvCheck( str != NULL );
|
||||||
|
|
||||||
|
int length, l;
|
||||||
|
l = length = (int)strlen( str );
|
||||||
|
while (length > 0 && str[length] != '.') {
|
||||||
|
length--;
|
||||||
|
if (str[length] == '\\' || str[length] == '/') {
|
||||||
|
return &str[l]; // no extension
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (length == 0) {
|
||||||
|
return &str[l];
|
||||||
|
}
|
||||||
|
return &str[length];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Clone this string
|
||||||
|
String String::clone() const
|
||||||
|
{
|
||||||
|
String str(data);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::setString(const char * str)
|
||||||
|
{
|
||||||
|
if (str == NULL) {
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
allocString( str );
|
||||||
|
addRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::setString(const char * str, uint length)
|
||||||
|
{
|
||||||
|
nvDebugCheck(str != NULL);
|
||||||
|
|
||||||
|
allocString(str, length);
|
||||||
|
addRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::setString(const StringBuilder & str)
|
||||||
|
{
|
||||||
|
if (str.str() == NULL) {
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
allocString(str.str());
|
||||||
|
addRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add reference count.
|
||||||
|
void String::addRef()
|
||||||
|
{
|
||||||
|
if (data != NULL)
|
||||||
|
{
|
||||||
|
setRefCount(getRefCount() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrease reference count.
|
||||||
|
void String::release()
|
||||||
|
{
|
||||||
|
if (data != NULL)
|
||||||
|
{
|
||||||
|
const uint16 count = getRefCount();
|
||||||
|
setRefCount(count - 1);
|
||||||
|
if (count - 1 == 0) {
|
||||||
|
free(data - 2);
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::allocString(const char * str, uint len)
|
||||||
|
{
|
||||||
|
const char * ptr = malloc<char>(2 + len + 1);
|
||||||
|
|
||||||
|
setData( ptr );
|
||||||
|
setRefCount( 0 );
|
||||||
|
|
||||||
|
// Copy string.
|
||||||
|
strCpy(const_cast<char *>(data), len+1, str, len);
|
||||||
|
|
||||||
|
// Add terminating character.
|
||||||
|
const_cast<char *>(data)[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv::swap(String & a, String & b) {
|
||||||
|
swap(a.data, b.data);
|
||||||
|
}
|
|
@ -0,0 +1,433 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_STRING_H
|
||||||
|
#define NV_CORE_STRING_H
|
||||||
|
|
||||||
|
#include "Debug.h"
|
||||||
|
#include "Hash.h" // hash
|
||||||
|
|
||||||
|
//#include <string.h> // strlen, etc.
|
||||||
|
|
||||||
|
#if NV_OS_WIN32
|
||||||
|
#define NV_PATH_SEPARATOR '\\'
|
||||||
|
#else
|
||||||
|
#define NV_PATH_SEPARATOR '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
NVCORE_API uint strHash(const char * str, uint h) NV_PURE;
|
||||||
|
|
||||||
|
/// String hash based on Bernstein's hash.
|
||||||
|
inline uint strHash(const char * data, uint h = 5381)
|
||||||
|
{
|
||||||
|
uint i = 0;
|
||||||
|
while(data[i] != 0) {
|
||||||
|
h = (33 * h) ^ uint(data[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> struct Hash<const char *> {
|
||||||
|
uint operator()(const char * str) const { return strHash(str); }
|
||||||
|
};
|
||||||
|
|
||||||
|
NVCORE_API uint strLen(const char * str) NV_PURE; // Asserts on NULL strings.
|
||||||
|
|
||||||
|
NVCORE_API int strDiff(const char * s1, const char * s2) NV_PURE; // Asserts on NULL strings.
|
||||||
|
NVCORE_API int strCaseDiff(const char * s1, const char * s2) NV_PURE; // Asserts on NULL strings.
|
||||||
|
NVCORE_API bool strEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings.
|
||||||
|
NVCORE_API bool strCaseEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings.
|
||||||
|
|
||||||
|
template <> struct Equal<const char *> {
|
||||||
|
bool operator()(const char * a, const char * b) const { return strEqual(a, b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
NVCORE_API bool strBeginsWith(const char * dst, const char * prefix) NV_PURE;
|
||||||
|
NVCORE_API bool strEndsWith(const char * dst, const char * suffix) NV_PURE;
|
||||||
|
|
||||||
|
|
||||||
|
NVCORE_API void strCpy(char * dst, uint size, const char * src);
|
||||||
|
NVCORE_API void strCpy(char * dst, uint size, const char * src, uint len);
|
||||||
|
NVCORE_API void strCat(char * dst, uint size, const char * src);
|
||||||
|
|
||||||
|
NVCORE_API const char * strSkipWhiteSpace(const char * str);
|
||||||
|
NVCORE_API char * strSkipWhiteSpace(char * str);
|
||||||
|
|
||||||
|
NVCORE_API bool strMatch(const char * str, const char * pat) NV_PURE;
|
||||||
|
|
||||||
|
NVCORE_API bool isNumber(const char * str) NV_PURE;
|
||||||
|
|
||||||
|
/* @@ Implement these two functions and modify StringBuilder to use them?
|
||||||
|
NVCORE_API void strFormat(const char * dst, const char * fmt, ...);
|
||||||
|
NVCORE_API void strFormatList(const char * dst, const char * fmt, va_list arg);
|
||||||
|
|
||||||
|
template <size_t count> void strFormatSafe(char (&buffer)[count], const char *fmt, ...) __attribute__((format (printf, 2, 3)));
|
||||||
|
template <size_t count> void strFormatSafe(char (&buffer)[count], const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
strFormatList(buffer, count, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
template <size_t count> void strFormatListSafe(char (&buffer)[count], const char *fmt, va_list arg) {
|
||||||
|
va_list tmp;
|
||||||
|
va_copy(tmp, args);
|
||||||
|
strFormatList(buffer, count, fmt, tmp);
|
||||||
|
va_end(tmp);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
template <int count> void strCpySafe(char (&buffer)[count], const char *src) {
|
||||||
|
strCpy(buffer, count, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int count> void strCatSafe(char (&buffer)[count], const char * src) {
|
||||||
|
strCat(buffer, count, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// String builder.
|
||||||
|
class NVCORE_CLASS StringBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
StringBuilder();
|
||||||
|
explicit StringBuilder( uint size_hint );
|
||||||
|
StringBuilder(const char * str);
|
||||||
|
StringBuilder(const char * str, uint len);
|
||||||
|
StringBuilder(const StringBuilder & other);
|
||||||
|
|
||||||
|
~StringBuilder();
|
||||||
|
|
||||||
|
StringBuilder & format( const char * format, ... ) __attribute__((format (printf, 2, 3)));
|
||||||
|
StringBuilder & formatList( const char * format, va_list arg );
|
||||||
|
|
||||||
|
StringBuilder & append(char c);
|
||||||
|
StringBuilder & append(const char * str);
|
||||||
|
StringBuilder & append(const char * str, uint len);
|
||||||
|
StringBuilder & append(const StringBuilder & str);
|
||||||
|
StringBuilder & appendFormat(const char * format, ...) __attribute__((format (printf, 2, 3)));
|
||||||
|
StringBuilder & appendFormatList(const char * format, va_list arg);
|
||||||
|
|
||||||
|
StringBuilder & appendSpace(uint n);
|
||||||
|
|
||||||
|
StringBuilder & number( int i, int base = 10 );
|
||||||
|
StringBuilder & number( uint i, int base = 10 );
|
||||||
|
|
||||||
|
StringBuilder & reserve(uint size_hint);
|
||||||
|
StringBuilder & copy(const char * str);
|
||||||
|
StringBuilder & copy(const char * str, uint len);
|
||||||
|
StringBuilder & copy(const StringBuilder & str);
|
||||||
|
|
||||||
|
StringBuilder & toLower();
|
||||||
|
StringBuilder & toUpper();
|
||||||
|
|
||||||
|
bool endsWith(const char * str) const;
|
||||||
|
bool beginsWith(const char * str) const;
|
||||||
|
|
||||||
|
char * reverseFind(char c);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
bool isNull() const { return m_size == 0; }
|
||||||
|
|
||||||
|
// const char * accessors
|
||||||
|
//operator const char * () const { return m_str; }
|
||||||
|
//operator char * () { return m_str; }
|
||||||
|
const char * str() const { return m_str; }
|
||||||
|
char * str() { return m_str; }
|
||||||
|
|
||||||
|
char * release(); // Release ownership of string.
|
||||||
|
void acquire(char *); // Take ownership of string.
|
||||||
|
|
||||||
|
/// Implement value semantics.
|
||||||
|
StringBuilder & operator=( const StringBuilder & s ) {
|
||||||
|
return copy(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement value semantics.
|
||||||
|
StringBuilder & operator=( const char * s ) {
|
||||||
|
return copy(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equal operator.
|
||||||
|
bool operator==( const StringBuilder & s ) const {
|
||||||
|
return strMatch(s.m_str, m_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the exact length.
|
||||||
|
uint length() const { return isNull() ? 0 : strLen(m_str); }
|
||||||
|
|
||||||
|
/// Return the size of the string container.
|
||||||
|
uint capacity() const { return m_size; }
|
||||||
|
|
||||||
|
/// Return the hash of the string.
|
||||||
|
uint hash() const { return isNull() ? 0 : strHash(m_str); }
|
||||||
|
|
||||||
|
// Swap strings.
|
||||||
|
friend void swap(StringBuilder & a, StringBuilder & b);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/// Size of the string container.
|
||||||
|
uint m_size;
|
||||||
|
|
||||||
|
/// String.
|
||||||
|
char * m_str;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Path string. @@ This should be called PathBuilder.
|
||||||
|
class NVCORE_CLASS Path : public StringBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Path() : StringBuilder() {}
|
||||||
|
explicit Path(int size_hint) : StringBuilder(size_hint) {}
|
||||||
|
Path(const char * str) : StringBuilder(str) {}
|
||||||
|
Path(const Path & path) : StringBuilder(path) {}
|
||||||
|
|
||||||
|
const char * fileName() const;
|
||||||
|
const char * extension() const;
|
||||||
|
|
||||||
|
void translatePath(char pathSeparator = NV_PATH_SEPARATOR);
|
||||||
|
|
||||||
|
void appendSeparator(char pathSeparator = NV_PATH_SEPARATOR);
|
||||||
|
|
||||||
|
void stripFileName();
|
||||||
|
void stripExtension();
|
||||||
|
|
||||||
|
// statics
|
||||||
|
NVCORE_API static char separator();
|
||||||
|
NVCORE_API static const char * fileName(const char *);
|
||||||
|
NVCORE_API static const char * extension(const char *);
|
||||||
|
|
||||||
|
NVCORE_API static void translatePath(char * path, char pathSeparator = NV_PATH_SEPARATOR);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// String class.
|
||||||
|
class NVCORE_CLASS String
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Constructs a null string. @sa isNull()
|
||||||
|
String()
|
||||||
|
{
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a shared copy of str.
|
||||||
|
String(const String & str)
|
||||||
|
{
|
||||||
|
data = str.data;
|
||||||
|
if (data != NULL) addRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a shared string from a standard string.
|
||||||
|
String(const char * str)
|
||||||
|
{
|
||||||
|
setString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a shared string from a standard string.
|
||||||
|
String(const char * str, int length)
|
||||||
|
{
|
||||||
|
setString(str, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a shared string from a StringBuilder.
|
||||||
|
String(const StringBuilder & str)
|
||||||
|
{
|
||||||
|
setString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dtor.
|
||||||
|
~String()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
String clone() const;
|
||||||
|
|
||||||
|
/// Release the current string and allocate a new one.
|
||||||
|
const String & operator=( const char * str )
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
setString( str );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Release the current string and allocate a new one.
|
||||||
|
const String & operator=( const StringBuilder & str )
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
setString( str );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement value semantics.
|
||||||
|
String & operator=( const String & str )
|
||||||
|
{
|
||||||
|
if (str.data != data)
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
data = str.data;
|
||||||
|
addRef();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equal operator.
|
||||||
|
bool operator==( const String & str ) const
|
||||||
|
{
|
||||||
|
return strMatch(str.data, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Equal operator.
|
||||||
|
bool operator==( const char * str ) const
|
||||||
|
{
|
||||||
|
return strMatch(str, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Not equal operator.
|
||||||
|
bool operator!=( const String & str ) const
|
||||||
|
{
|
||||||
|
return !strMatch(str.data, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Not equal operator.
|
||||||
|
bool operator!=( const char * str ) const
|
||||||
|
{
|
||||||
|
return !strMatch(str, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this string is the null string.
|
||||||
|
bool isNull() const { return data == NULL; }
|
||||||
|
|
||||||
|
/// Return the exact length.
|
||||||
|
uint length() const { nvDebugCheck(data != NULL); return strLen(data); }
|
||||||
|
|
||||||
|
/// Return the hash of the string.
|
||||||
|
uint hash() const { nvDebugCheck(data != NULL); return strHash(data); }
|
||||||
|
|
||||||
|
/// const char * cast operator.
|
||||||
|
operator const char * () const { return data; }
|
||||||
|
|
||||||
|
/// Get string pointer.
|
||||||
|
const char * str() const { return data; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Add reference count.
|
||||||
|
void addRef();
|
||||||
|
|
||||||
|
// Decrease reference count.
|
||||||
|
void release();
|
||||||
|
|
||||||
|
uint16 getRefCount() const
|
||||||
|
{
|
||||||
|
nvDebugCheck(data != NULL);
|
||||||
|
return *reinterpret_cast<const uint16 *>(data - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRefCount(uint16 count) {
|
||||||
|
nvDebugCheck(data != NULL);
|
||||||
|
nvCheck(count < 0xFFFF);
|
||||||
|
*reinterpret_cast<uint16 *>(const_cast<char *>(data - 2)) = uint16(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setData(const char * str) {
|
||||||
|
data = str + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocString(const char * str)
|
||||||
|
{
|
||||||
|
allocString(str, strLen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
void allocString(const char * str, uint length);
|
||||||
|
|
||||||
|
void setString(const char * str);
|
||||||
|
void setString(const char * str, uint length);
|
||||||
|
void setString(const StringBuilder & str);
|
||||||
|
|
||||||
|
// Swap strings.
|
||||||
|
friend void swap(String & a, String & b);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const char * data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct Hash<String> {
|
||||||
|
uint operator()(const String & str) const { return str.hash(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Like AutoPtr, but for const char strings.
|
||||||
|
class AutoString
|
||||||
|
{
|
||||||
|
NV_FORBID_COPY(AutoString);
|
||||||
|
NV_FORBID_HEAPALLOC();
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Ctor.
|
||||||
|
AutoString(const char * p = NULL) : m_ptr(p) { }
|
||||||
|
|
||||||
|
#if NV_CC_CPP11
|
||||||
|
// Move ctor.
|
||||||
|
AutoString(AutoString && ap) : m_ptr(ap.m_ptr) { ap.m_ptr = NULL; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Dtor. Deletes owned pointer.
|
||||||
|
~AutoString() {
|
||||||
|
delete [] m_ptr;
|
||||||
|
m_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete owned pointer and assign new one.
|
||||||
|
void operator=(const char * p) {
|
||||||
|
if (p != m_ptr)
|
||||||
|
{
|
||||||
|
delete [] m_ptr;
|
||||||
|
m_ptr = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pointer.
|
||||||
|
const char * ptr() const { return m_ptr; }
|
||||||
|
operator const char *() const { return m_ptr; }
|
||||||
|
|
||||||
|
// Relinquish ownership of the underlying pointer and returns that pointer.
|
||||||
|
const char * release() {
|
||||||
|
const char * tmp = m_ptr;
|
||||||
|
m_ptr = NULL;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// comparison operators.
|
||||||
|
friend bool operator == (const AutoString & ap, const char * const p) {
|
||||||
|
return (ap.ptr() == p);
|
||||||
|
}
|
||||||
|
friend bool operator != (const AutoString & ap, const char * const p) {
|
||||||
|
return (ap.ptr() != p);
|
||||||
|
}
|
||||||
|
friend bool operator == (const char * const p, const AutoString & ap) {
|
||||||
|
return (ap.ptr() == p);
|
||||||
|
}
|
||||||
|
friend bool operator != (const char * const p, const AutoString & ap) {
|
||||||
|
return (ap.ptr() != p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char * m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_STRING_H
|
|
@ -0,0 +1,164 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_STREAM_H
|
||||||
|
#define NV_CORE_STREAM_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Base stream class.
|
||||||
|
class NVCORE_CLASS Stream {
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum ByteOrder {
|
||||||
|
LittleEndian = false,
|
||||||
|
BigEndian = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Get the byte order of the system.
|
||||||
|
static ByteOrder getSystemByteOrder() {
|
||||||
|
#if NV_LITTLE_ENDIAN
|
||||||
|
return LittleEndian;
|
||||||
|
#else
|
||||||
|
return BigEndian;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Ctor.
|
||||||
|
Stream() : m_byteOrder(LittleEndian) { }
|
||||||
|
|
||||||
|
/// Virtual destructor.
|
||||||
|
virtual ~Stream() {}
|
||||||
|
|
||||||
|
/// Set byte order.
|
||||||
|
void setByteOrder(ByteOrder bo) { m_byteOrder = bo; }
|
||||||
|
|
||||||
|
/// Get byte order.
|
||||||
|
ByteOrder byteOrder() const { return m_byteOrder; }
|
||||||
|
|
||||||
|
|
||||||
|
/// Serialize the given data.
|
||||||
|
virtual uint serialize( void * data, uint len ) = 0;
|
||||||
|
|
||||||
|
/// Move to the given position in the archive.
|
||||||
|
virtual void seek( uint pos ) = 0;
|
||||||
|
|
||||||
|
/// Return the current position in the archive.
|
||||||
|
virtual uint tell() const = 0;
|
||||||
|
|
||||||
|
/// Return the current size of the archive.
|
||||||
|
virtual uint size() const = 0;
|
||||||
|
|
||||||
|
/// Determine if there has been any error.
|
||||||
|
virtual bool isError() const = 0;
|
||||||
|
|
||||||
|
/// Clear errors.
|
||||||
|
virtual void clearError() = 0;
|
||||||
|
|
||||||
|
/// Return true if the stream is at the end.
|
||||||
|
virtual bool isAtEnd() const = 0;
|
||||||
|
|
||||||
|
/// Return true if the stream is seekable.
|
||||||
|
virtual bool isSeekable() const = 0;
|
||||||
|
|
||||||
|
/// Return true if this is an input stream.
|
||||||
|
virtual bool isLoading() const = 0;
|
||||||
|
|
||||||
|
/// Return true if this is an output stream.
|
||||||
|
virtual bool isSaving() const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void advance(uint offset) { seek(tell() + offset); }
|
||||||
|
|
||||||
|
|
||||||
|
// friends
|
||||||
|
friend Stream & operator<<( Stream & s, bool & c ) {
|
||||||
|
#if NV_OS_DARWIN && !NV_CC_CPP11
|
||||||
|
nvStaticCheck(sizeof(bool) == 4);
|
||||||
|
uint8 b = c ? 1 : 0;
|
||||||
|
s.serialize( &b, 1 );
|
||||||
|
c = (b != 0);
|
||||||
|
#else
|
||||||
|
nvStaticCheck(sizeof(bool) == 1);
|
||||||
|
s.serialize( &c, 1 );
|
||||||
|
#endif
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, char & c ) {
|
||||||
|
nvStaticCheck(sizeof(char) == 1);
|
||||||
|
s.serialize( &c, 1 );
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, uint8 & c ) {
|
||||||
|
nvStaticCheck(sizeof(uint8) == 1);
|
||||||
|
s.serialize( &c, 1 );
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, int8 & c ) {
|
||||||
|
nvStaticCheck(sizeof(int8) == 1);
|
||||||
|
s.serialize( &c, 1 );
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, uint16 & c ) {
|
||||||
|
nvStaticCheck(sizeof(uint16) == 2);
|
||||||
|
return s.byteOrderSerialize( &c, 2 );
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, int16 & c ) {
|
||||||
|
nvStaticCheck(sizeof(int16) == 2);
|
||||||
|
return s.byteOrderSerialize( &c, 2 );
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, uint32 & c ) {
|
||||||
|
nvStaticCheck(sizeof(uint32) == 4);
|
||||||
|
return s.byteOrderSerialize( &c, 4 );
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, int32 & c ) {
|
||||||
|
nvStaticCheck(sizeof(int32) == 4);
|
||||||
|
return s.byteOrderSerialize( &c, 4 );
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, uint64 & c ) {
|
||||||
|
nvStaticCheck(sizeof(uint64) == 8);
|
||||||
|
return s.byteOrderSerialize( &c, 8 );
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, int64 & c ) {
|
||||||
|
nvStaticCheck(sizeof(int64) == 8);
|
||||||
|
return s.byteOrderSerialize( &c, 8 );
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, float & c ) {
|
||||||
|
nvStaticCheck(sizeof(float) == 4);
|
||||||
|
return s.byteOrderSerialize( &c, 4 );
|
||||||
|
}
|
||||||
|
friend Stream & operator<<( Stream & s, double & c ) {
|
||||||
|
nvStaticCheck(sizeof(double) == 8);
|
||||||
|
return s.byteOrderSerialize( &c, 8 );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/// Serialize in the stream byte order.
|
||||||
|
Stream & byteOrderSerialize( void * v, uint len ) {
|
||||||
|
if( m_byteOrder == getSystemByteOrder() ) {
|
||||||
|
serialize( v, len );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for( uint i = len; i > 0; i-- ) {
|
||||||
|
serialize( (uint8 *)v + i - 1, 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ByteOrder m_byteOrder;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_STREAM_H
|
|
@ -0,0 +1,315 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_UTILS_H
|
||||||
|
#define NV_CORE_UTILS_H
|
||||||
|
|
||||||
|
#include "Debug.h" // nvDebugCheck
|
||||||
|
|
||||||
|
#include <new> // for placement new
|
||||||
|
|
||||||
|
|
||||||
|
// Just in case. Grrr.
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
|
#define NV_INT8_MIN (-128)
|
||||||
|
#define NV_INT8_MAX 127
|
||||||
|
#define NV_UINT8_MAX 255
|
||||||
|
#define NV_INT16_MIN (-32767-1)
|
||||||
|
#define NV_INT16_MAX 32767
|
||||||
|
#define NV_UINT16_MAX 0xffff
|
||||||
|
#define NV_INT32_MIN (-2147483647-1)
|
||||||
|
#define NV_INT32_MAX 2147483647
|
||||||
|
#define NV_UINT32_MAX 0xffffffff
|
||||||
|
#define NV_INT64_MAX POSH_I64(9223372036854775807)
|
||||||
|
#define NV_INT64_MIN (-POSH_I64(9223372036854775807)-1)
|
||||||
|
#define NV_UINT64_MAX POSH_U64(0xffffffffffffffff)
|
||||||
|
|
||||||
|
#define NV_HALF_MAX 65504.0F
|
||||||
|
#define NV_FLOAT_MAX 3.402823466e+38F
|
||||||
|
|
||||||
|
#define NV_INTEGER_TO_FLOAT_MAX 16777217 // Largest integer such that it and all smaller integers can be stored in a 32bit float.
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
// Less error prone than casting. From CB:
|
||||||
|
// http://cbloomrants.blogspot.com/2011/06/06-17-11-c-casting-is-devil.html
|
||||||
|
|
||||||
|
// These intentionally look like casts.
|
||||||
|
|
||||||
|
// uint64 casts:
|
||||||
|
template <typename T> inline uint64 U64(T x) { return x; }
|
||||||
|
//template <> inline uint64 U64<uint64>(uint64 x) { return x; }
|
||||||
|
template <> inline uint64 U64<int64>(int64 x) { nvDebugCheck(x >= 0); return (uint64)x; }
|
||||||
|
//template <> inline uint64 U32<uint32>(uint32 x) { return x; }
|
||||||
|
template <> inline uint64 U64<int32>(int32 x) { nvDebugCheck(x >= 0); return (uint64)x; }
|
||||||
|
//template <> inline uint64 U64<uint16>(uint16 x) { return x; }
|
||||||
|
template <> inline uint64 U64<int16>(int16 x) { nvDebugCheck(x >= 0); return (uint64)x; }
|
||||||
|
//template <> inline uint64 U64<uint8>(uint8 x) { return x; }
|
||||||
|
template <> inline uint64 U64<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint64)x; }
|
||||||
|
|
||||||
|
// int64 casts:
|
||||||
|
template <typename T> inline int64 I64(T x) { return x; }
|
||||||
|
template <> inline int64 I64<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT64_MAX); return (int64)x; }
|
||||||
|
//template <> inline uint64 U64<int64>(int64 x) { return x; }
|
||||||
|
//template <> inline uint64 U32<uint32>(uint32 x) { return x; }
|
||||||
|
//template <> inline uint64 U64<int32>(int32 x) { return x; }
|
||||||
|
//template <> inline uint64 U64<uint16>(uint16 x) { return x; }
|
||||||
|
//template <> inline uint64 U64<int16>(int16 x) { return x; }
|
||||||
|
//template <> inline uint64 U64<uint8>(uint8 x) { return x; }
|
||||||
|
//template <> inline uint64 U64<int8>(int8 x) { return x; }
|
||||||
|
|
||||||
|
// uint32 casts:
|
||||||
|
template <typename T> inline uint32 U32(T x) { return x; }
|
||||||
|
template <> inline uint32 U32<uint64>(uint64 x) { nvDebugCheck(x <= NV_UINT32_MAX); return (uint32)x; }
|
||||||
|
template <> inline uint32 U32<int64>(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT32_MAX); return (uint32)x; }
|
||||||
|
//template <> inline uint32 U32<uint32>(uint32 x) { return x; }
|
||||||
|
template <> inline uint32 U32<int32>(int32 x) { nvDebugCheck(x >= 0); return (uint32)x; }
|
||||||
|
//template <> inline uint32 U32<uint16>(uint16 x) { return x; }
|
||||||
|
template <> inline uint32 U32<int16>(int16 x) { nvDebugCheck(x >= 0); return (uint32)x; }
|
||||||
|
//template <> inline uint32 U32<uint8>(uint8 x) { return x; }
|
||||||
|
template <> inline uint32 U32<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint32)x; }
|
||||||
|
|
||||||
|
// int32 casts:
|
||||||
|
template <typename T> inline int32 I32(T x) { return x; }
|
||||||
|
template <> inline int32 I32<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT32_MAX); return (int32)x; }
|
||||||
|
template <> inline int32 I32<int64>(int64 x) { nvDebugCheck(x >= NV_INT32_MIN && x <= NV_UINT32_MAX); return (int32)x; }
|
||||||
|
template <> inline int32 I32<uint32>(uint32 x) { nvDebugCheck(x <= NV_INT32_MAX); return (int32)x; }
|
||||||
|
//template <> inline int32 I32<int32>(int32 x) { return x; }
|
||||||
|
//template <> inline int32 I32<uint16>(uint16 x) { return x; }
|
||||||
|
//template <> inline int32 I32<int16>(int16 x) { return x; }
|
||||||
|
//template <> inline int32 I32<uint8>(uint8 x) { return x; }
|
||||||
|
//template <> inline int32 I32<int8>(int8 x) { return x; }
|
||||||
|
|
||||||
|
// uint16 casts:
|
||||||
|
template <typename T> inline uint16 U16(T x) { return x; }
|
||||||
|
template <> inline uint16 U16<uint64>(uint64 x) { nvDebugCheck(x <= NV_UINT16_MAX); return (uint16)x; }
|
||||||
|
template <> inline uint16 U16<int64>(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT16_MAX); return (uint16)x; }
|
||||||
|
template <> inline uint16 U16<uint32>(uint32 x) { nvDebugCheck(x <= NV_UINT16_MAX); return (uint16)x; }
|
||||||
|
template <> inline uint16 U16<int32>(int32 x) { nvDebugCheck(x >= 0 && x <= NV_UINT16_MAX); return (uint16)x; }
|
||||||
|
//template <> inline uint16 U16<uint16>(uint16 x) { return x; }
|
||||||
|
template <> inline uint16 U16<int16>(int16 x) { nvDebugCheck(x >= 0); return (uint16)x; }
|
||||||
|
//template <> inline uint16 U16<uint8>(uint8 x) { return x; }
|
||||||
|
template <> inline uint16 U16<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint16)x; }
|
||||||
|
|
||||||
|
// int16 casts:
|
||||||
|
template <typename T> inline int16 I16(T x) { return x; }
|
||||||
|
template <> inline int16 I16<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; }
|
||||||
|
template <> inline int16 I16<int64>(int64 x) { nvDebugCheck(x >= NV_INT16_MIN && x <= NV_UINT16_MAX); return (int16)x; }
|
||||||
|
template <> inline int16 I16<uint32>(uint32 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; }
|
||||||
|
template <> inline int16 I16<int32>(int32 x) { nvDebugCheck(x >= NV_INT16_MIN && x <= NV_UINT16_MAX); return (int16)x; }
|
||||||
|
template <> inline int16 I16<uint16>(uint16 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; }
|
||||||
|
//template <> inline int16 I16<int16>(int16 x) { return x; }
|
||||||
|
//template <> inline int16 I16<uint8>(uint8 x) { return x; }
|
||||||
|
//template <> inline int16 I16<int8>(int8 x) { return x; }
|
||||||
|
|
||||||
|
// uint8 casts:
|
||||||
|
template <typename T> inline uint8 U8(T x) { return x; }
|
||||||
|
template <> inline uint8 U8<uint64>(uint64 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; }
|
||||||
|
template <> inline uint8 U8<int64>(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; }
|
||||||
|
template <> inline uint8 U8<uint32>(uint32 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; }
|
||||||
|
template <> inline uint8 U8<int32>(int32 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; }
|
||||||
|
template <> inline uint8 U8<uint16>(uint16 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; }
|
||||||
|
template <> inline uint8 U8<int16>(int16 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; }
|
||||||
|
//template <> inline uint8 U8<uint8>(uint8 x) { return x; }
|
||||||
|
template <> inline uint8 U8<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint8)x; }
|
||||||
|
//template <> inline uint8 U8<float>(int8 x) { nvDebugCheck(x >= 0.0f && x <= 255.0f); return (uint8)x; }
|
||||||
|
|
||||||
|
// int8 casts:
|
||||||
|
template <typename T> inline int8 I8(T x) { return x; }
|
||||||
|
template <> inline int8 I8<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||||
|
template <> inline int8 I8<int64>(int64 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
|
||||||
|
template <> inline int8 I8<uint32>(uint32 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||||
|
template <> inline int8 I8<int32>(int32 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
|
||||||
|
template <> inline int8 I8<uint16>(uint16 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||||
|
template <> inline int8 I8<int16>(int16 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
|
||||||
|
template <> inline int8 I8<uint8>(uint8 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||||
|
//template <> inline int8 I8<int8>(int8 x) { return x; }
|
||||||
|
|
||||||
|
// float casts:
|
||||||
|
template <typename T> inline float F32(T x) { return x; }
|
||||||
|
template <> inline float F32<uint64>(uint64 x) { nvDebugCheck(x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
|
||||||
|
template <> inline float F32<int64>(int64 x) { nvDebugCheck(x >= -NV_INTEGER_TO_FLOAT_MAX && x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
|
||||||
|
template <> inline float F32<uint32>(uint32 x) { nvDebugCheck(x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
|
||||||
|
template <> inline float F32<int32>(int32 x) { nvDebugCheck(x >= -NV_INTEGER_TO_FLOAT_MAX && x <= NV_INTEGER_TO_FLOAT_MAX); return (float)x; }
|
||||||
|
// The compiler should not complain about these conversions:
|
||||||
|
//template <> inline float F32<uint16>(uint16 x) { nvDebugCheck(return (float)x; }
|
||||||
|
//template <> inline float F32<int16>(int16 x) { nvDebugCheck(return (float)x; }
|
||||||
|
//template <> inline float F32<uint8>(uint8 x) { nvDebugCheck(return (float)x; }
|
||||||
|
//template <> inline float F32<int8>(int8 x) { nvDebugCheck(return (float)x; }
|
||||||
|
|
||||||
|
|
||||||
|
/// Swap two values.
|
||||||
|
template <typename T>
|
||||||
|
inline void swap(T & a, T & b)
|
||||||
|
{
|
||||||
|
T temp(a);
|
||||||
|
a = b;
|
||||||
|
b = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum of the two arguments. For floating point values, it returns the second value if the first is NaN.
|
||||||
|
template <typename T>
|
||||||
|
//inline const T & max(const T & a, const T & b)
|
||||||
|
inline T max(const T & a, const T & b)
|
||||||
|
{
|
||||||
|
return (b < a) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum of the four arguments.
|
||||||
|
template <typename T>
|
||||||
|
//inline const T & max4(const T & a, const T & b, const T & c)
|
||||||
|
inline T max4(const T & a, const T & b, const T & c, const T & d)
|
||||||
|
{
|
||||||
|
return max(max(a, b), max(c, d));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum of the three arguments.
|
||||||
|
template <typename T>
|
||||||
|
//inline const T & max3(const T & a, const T & b, const T & c)
|
||||||
|
inline T max3(const T & a, const T & b, const T & c)
|
||||||
|
{
|
||||||
|
return max(a, max(b, c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the minimum of two values.
|
||||||
|
template <typename T>
|
||||||
|
//inline const T & min(const T & a, const T & b)
|
||||||
|
inline T min(const T & a, const T & b)
|
||||||
|
{
|
||||||
|
return (a < b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the maximum of the three arguments.
|
||||||
|
template <typename T>
|
||||||
|
//inline const T & min3(const T & a, const T & b, const T & c)
|
||||||
|
inline T min3(const T & a, const T & b, const T & c)
|
||||||
|
{
|
||||||
|
return min(a, min(b, c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clamp between two values.
|
||||||
|
template <typename T>
|
||||||
|
//inline const T & clamp(const T & x, const T & a, const T & b)
|
||||||
|
inline T clamp(const T & x, const T & a, const T & b)
|
||||||
|
{
|
||||||
|
return min(max(x, a), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the next power of two.
|
||||||
|
* @see http://graphics.stanford.edu/~seander/bithacks.html
|
||||||
|
* @warning Behaviour for 0 is undefined.
|
||||||
|
* @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x
|
||||||
|
* @note nextPowerOfTwo(x) = 2 << log2(x-1)
|
||||||
|
*/
|
||||||
|
inline uint32 nextPowerOfTwo(uint32 x)
|
||||||
|
{
|
||||||
|
nvDebugCheck( x != 0 );
|
||||||
|
#if 1 // On modern CPUs this is supposed to be as fast as using the bsr instruction.
|
||||||
|
x--;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
return x+1;
|
||||||
|
#else
|
||||||
|
uint p = 1;
|
||||||
|
while( x > p ) {
|
||||||
|
p += p;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64 nextPowerOfTwo(uint64 x)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x != 0);
|
||||||
|
uint p = 1;
|
||||||
|
while (x > p) {
|
||||||
|
p += p;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@ Should I just use a macro instead?
|
||||||
|
template <typename T>
|
||||||
|
inline bool isPowerOfTwo(T n)
|
||||||
|
{
|
||||||
|
return (n & (n-1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @@ Move this to utils?
|
||||||
|
/// Delete all the elements of a container.
|
||||||
|
template <typename T>
|
||||||
|
void deleteAll(T & container)
|
||||||
|
{
|
||||||
|
for (typename T::PseudoIndex i = container.start(); !container.isDone(i); container.advance(i))
|
||||||
|
{
|
||||||
|
delete container[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// @@ Specialize these methods for numeric, pointer, and pod types.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void construct_range(T * restrict ptr, uint new_size, uint old_size) {
|
||||||
|
for (uint i = old_size; i < new_size; i++) {
|
||||||
|
new(ptr+i) T; // placement new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void construct_range(T * restrict ptr, uint new_size, uint old_size, const T & elem) {
|
||||||
|
for (uint i = old_size; i < new_size; i++) {
|
||||||
|
new(ptr+i) T(elem); // placement new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void construct_range(T * restrict ptr, uint new_size, uint old_size, const T * src) {
|
||||||
|
for (uint i = old_size; i < new_size; i++) {
|
||||||
|
new(ptr+i) T(src[i]); // placement new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void destroy_range(T * restrict ptr, uint new_size, uint old_size) {
|
||||||
|
for (uint i = new_size; i < old_size; i++) {
|
||||||
|
(ptr+i)->~T(); // Explicit call to the destructor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void fill(T * restrict dst, uint count, const T & value) {
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
dst[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void copy_range(T * restrict dst, const T * restrict src, uint count) {
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool find(const T & element, const T * restrict ptr, uint begin, uint end, uint * index) {
|
||||||
|
for (uint i = begin; i < end; i++) {
|
||||||
|
if (ptr[i] == element) {
|
||||||
|
if (index != NULL) *index = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_UTILS_H
|
|
@ -0,0 +1,357 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_H
|
||||||
|
#define NV_CORE_H
|
||||||
|
|
||||||
|
// Function linkage
|
||||||
|
#if NVCORE_SHARED
|
||||||
|
#ifdef NVCORE_EXPORTS
|
||||||
|
#define NVCORE_API DLL_EXPORT
|
||||||
|
#define NVCORE_CLASS DLL_EXPORT_CLASS
|
||||||
|
#else
|
||||||
|
#define NVCORE_API DLL_IMPORT
|
||||||
|
#define NVCORE_CLASS DLL_IMPORT
|
||||||
|
#endif
|
||||||
|
#else // NVCORE_SHARED
|
||||||
|
#define NVCORE_API
|
||||||
|
#define NVCORE_CLASS
|
||||||
|
#endif // NVCORE_SHARED
|
||||||
|
|
||||||
|
|
||||||
|
// Platform definitions
|
||||||
|
#include <posh.h>
|
||||||
|
|
||||||
|
// OS:
|
||||||
|
// NV_OS_WIN32
|
||||||
|
// NV_OS_WIN64
|
||||||
|
// NV_OS_MINGW
|
||||||
|
// NV_OS_CYGWIN
|
||||||
|
// NV_OS_LINUX
|
||||||
|
// NV_OS_UNIX
|
||||||
|
// NV_OS_DARWIN
|
||||||
|
// NV_OS_XBOX
|
||||||
|
// NV_OS_ORBIS
|
||||||
|
// NV_OS_IOS
|
||||||
|
|
||||||
|
#define NV_OS_STRING POSH_OS_STRING
|
||||||
|
|
||||||
|
#if defined POSH_OS_LINUX
|
||||||
|
# define NV_OS_LINUX 1
|
||||||
|
# define NV_OS_UNIX 1
|
||||||
|
#elif defined POSH_OS_ORBIS
|
||||||
|
# define NV_OS_ORBIS 1
|
||||||
|
#elif defined POSH_OS_FREEBSD
|
||||||
|
# define NV_OS_FREEBSD 1
|
||||||
|
# define NV_OS_UNIX 1
|
||||||
|
#elif defined POSH_OS_OPENBSD
|
||||||
|
# define NV_OS_OPENBSD 1
|
||||||
|
# define NV_OS_UNIX 1
|
||||||
|
#elif defined POSH_OS_CYGWIN32
|
||||||
|
# define NV_OS_CYGWIN 1
|
||||||
|
#elif defined POSH_OS_MINGW
|
||||||
|
# define NV_OS_MINGW 1
|
||||||
|
# define NV_OS_WIN32 1
|
||||||
|
#elif defined POSH_OS_OSX
|
||||||
|
# define NV_OS_OSX 1 // IC: Adding this, because iOS defines NV_OS_DARWIN too.
|
||||||
|
# define NV_OS_DARWIN 1
|
||||||
|
# define NV_OS_UNIX 1
|
||||||
|
#elif defined POSH_OS_IOS
|
||||||
|
# define NV_OS_DARWIN 1 //ACS should we keep this on IOS?
|
||||||
|
# define NV_OS_UNIX 1
|
||||||
|
# define NV_OS_IOS 1
|
||||||
|
#elif defined POSH_OS_UNIX
|
||||||
|
# define NV_OS_UNIX 1
|
||||||
|
#elif defined POSH_OS_WIN64
|
||||||
|
# define NV_OS_WIN32 1
|
||||||
|
# define NV_OS_WIN64 1
|
||||||
|
#elif defined POSH_OS_WIN32
|
||||||
|
# define NV_OS_WIN32 1
|
||||||
|
#elif defined POSH_OS_XBOX
|
||||||
|
# define NV_OS_XBOX 1
|
||||||
|
#elif defined POSH_OS_DURANGO
|
||||||
|
# define NV_OS_DURANGO 1
|
||||||
|
#else
|
||||||
|
# error "Unsupported OS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Is this a console OS? (i.e. connected to a TV)
|
||||||
|
#if NV_OS_ORBIS || NV_OS_XBOX || NV_OS_DURANGO
|
||||||
|
# define NV_OS_CONSOLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Threading:
|
||||||
|
// some platforms don't implement __thread or similar for thread-local-storage
|
||||||
|
#if NV_OS_UNIX || NV_OS_ORBIS || NV_OS_IOS //ACStodoIOS darwin instead of ios?
|
||||||
|
# define NV_OS_USE_PTHREAD 1
|
||||||
|
# if NV_OS_IOS
|
||||||
|
# define NV_OS_HAS_TLS_QUALIFIER 0
|
||||||
|
# else
|
||||||
|
# define NV_OS_HAS_TLS_QUALIFIER 1
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define NV_OS_USE_PTHREAD 0
|
||||||
|
# define NV_OS_HAS_TLS_QUALIFIER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// CPUs:
|
||||||
|
// NV_CPU_X86
|
||||||
|
// NV_CPU_X86_64
|
||||||
|
// NV_CPU_PPC
|
||||||
|
// NV_CPU_ARM
|
||||||
|
|
||||||
|
#define NV_CPU_STRING POSH_CPU_STRING
|
||||||
|
|
||||||
|
#if defined POSH_CPU_X86_64
|
||||||
|
//# define NV_CPU_X86 1
|
||||||
|
# define NV_CPU_X86_64 1
|
||||||
|
#elif defined POSH_CPU_X86
|
||||||
|
# define NV_CPU_X86 1
|
||||||
|
#elif defined POSH_CPU_PPC
|
||||||
|
# define NV_CPU_PPC 1
|
||||||
|
#elif defined POSH_CPU_STRONGARM
|
||||||
|
# define NV_CPU_ARM 1
|
||||||
|
#else
|
||||||
|
# error "Unsupported CPU"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Compiler:
|
||||||
|
// NV_CC_GNUC
|
||||||
|
// NV_CC_MSVC
|
||||||
|
// NV_CC_CLANG
|
||||||
|
|
||||||
|
#if defined POSH_COMPILER_CLANG
|
||||||
|
# define NV_CC_CLANG 1
|
||||||
|
# define NV_CC_GNUC 1 // Clang is compatible with GCC.
|
||||||
|
# define NV_CC_STRING "clang"
|
||||||
|
#elif defined POSH_COMPILER_GCC
|
||||||
|
# define NV_CC_GNUC 1
|
||||||
|
# define NV_CC_STRING "gcc"
|
||||||
|
#elif defined POSH_COMPILER_MSVC
|
||||||
|
# define NV_CC_MSVC 1
|
||||||
|
# define NV_CC_STRING "msvc"
|
||||||
|
#else
|
||||||
|
# error "Unsupported compiler"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
#define NV_CC_CPP11 (__cplusplus > 199711L || _MSC_VER >= 1800) // Visual Studio 2013 has all the features we use, but doesn't advertise full C++11 support yet.
|
||||||
|
#else
|
||||||
|
// @@ IC: This works in CLANG, about GCC?
|
||||||
|
// @@ ES: Doesn't work in gcc. These 3 features are available in GCC >= 4.4.
|
||||||
|
#ifdef __clang__
|
||||||
|
#define NV_CC_CPP11 (__has_feature(cxx_deleted_functions) && __has_feature(cxx_rvalue_references) && __has_feature(cxx_static_assert))
|
||||||
|
#elif defined __GNUC__
|
||||||
|
#define NV_CC_CPP11 ( __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Endiannes:
|
||||||
|
#define NV_LITTLE_ENDIAN POSH_LITTLE_ENDIAN
|
||||||
|
#define NV_BIG_ENDIAN POSH_BIG_ENDIAN
|
||||||
|
#define NV_ENDIAN_STRING POSH_ENDIAN_STRING
|
||||||
|
|
||||||
|
|
||||||
|
// Define the right printf prefix for size_t arguments:
|
||||||
|
#if POSH_64BIT_POINTER
|
||||||
|
# define NV_SIZET_PRINTF_PREFIX POSH_I64_PRINTF_PREFIX
|
||||||
|
#else
|
||||||
|
# define NV_SIZET_PRINTF_PREFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// cmake config
|
||||||
|
#include "nvconfig.h"
|
||||||
|
|
||||||
|
#if NV_OS_DARWIN
|
||||||
|
#include <stdint.h>
|
||||||
|
//#include <inttypes.h>
|
||||||
|
|
||||||
|
// Type definitions:
|
||||||
|
typedef uint8_t uint8;
|
||||||
|
typedef int8_t int8;
|
||||||
|
|
||||||
|
typedef uint16_t uint16;
|
||||||
|
typedef int16_t int16;
|
||||||
|
|
||||||
|
typedef uint32_t uint32;
|
||||||
|
typedef int32_t int32;
|
||||||
|
|
||||||
|
typedef uint64_t uint64;
|
||||||
|
typedef int64_t int64;
|
||||||
|
|
||||||
|
// POSH gets this wrong due to __LP64__
|
||||||
|
#undef POSH_I64_PRINTF_PREFIX
|
||||||
|
#define POSH_I64_PRINTF_PREFIX "ll"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Type definitions:
|
||||||
|
typedef posh_u8_t uint8;
|
||||||
|
typedef posh_i8_t int8;
|
||||||
|
|
||||||
|
typedef posh_u16_t uint16;
|
||||||
|
typedef posh_i16_t int16;
|
||||||
|
|
||||||
|
typedef posh_u32_t uint32;
|
||||||
|
typedef posh_i32_t int32;
|
||||||
|
|
||||||
|
//#if NV_OS_DARWIN
|
||||||
|
// OSX-64 is supposed to be LP64 (longs and pointers are 64 bits), thus uint64 is defined as
|
||||||
|
// unsigned long. However, some OSX headers define it as unsigned long long, producing errors,
|
||||||
|
// even though both types are 64 bit. Ideally posh should handle that, but it has not been
|
||||||
|
// updated in ages, so here I'm just falling back to the standard C99 types defined in inttypes.h
|
||||||
|
//#include <inttypes.h>
|
||||||
|
//typedef posh_u64_t uint64_t;
|
||||||
|
//typedef posh_i64_t int64_t;
|
||||||
|
//#else
|
||||||
|
typedef posh_u64_t uint64;
|
||||||
|
typedef posh_i64_t int64;
|
||||||
|
//#endif
|
||||||
|
#if NV_OS_DARWIN
|
||||||
|
// To avoid duplicate definitions.
|
||||||
|
#define _UINT64
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Aliases
|
||||||
|
typedef uint32 uint;
|
||||||
|
|
||||||
|
|
||||||
|
// Version string:
|
||||||
|
#define NV_VERSION_STRING \
|
||||||
|
NV_OS_STRING "/" NV_CC_STRING "/" NV_CPU_STRING"/" \
|
||||||
|
NV_ENDIAN_STRING"-endian - " __DATE__ "-" __TIME__
|
||||||
|
|
||||||
|
|
||||||
|
// Disable copy constructor and assignment operator.
|
||||||
|
#if NV_CC_CPP11
|
||||||
|
#define NV_FORBID_COPY(C) \
|
||||||
|
C( const C & ) = delete; \
|
||||||
|
C &operator=( const C & ) = delete
|
||||||
|
#else
|
||||||
|
#define NV_FORBID_COPY(C) \
|
||||||
|
private: \
|
||||||
|
C( const C & ); \
|
||||||
|
C &operator=( const C & )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Disable dynamic allocation on the heap.
|
||||||
|
// See Prohibiting Heap-Based Objects in More Effective C++.
|
||||||
|
#define NV_FORBID_HEAPALLOC() \
|
||||||
|
private: \
|
||||||
|
void *operator new(size_t size); \
|
||||||
|
void *operator new[](size_t size)
|
||||||
|
//static void *operator new(size_t size); \
|
||||||
|
//static void *operator new[](size_t size);
|
||||||
|
|
||||||
|
// String concatenation macros.
|
||||||
|
#define NV_STRING_JOIN2(arg1, arg2) NV_DO_STRING_JOIN2(arg1, arg2)
|
||||||
|
#define NV_DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
|
||||||
|
#define NV_STRING_JOIN3(arg1, arg2, arg3) NV_DO_STRING_JOIN3(arg1, arg2, arg3)
|
||||||
|
#define NV_DO_STRING_JOIN3(arg1, arg2, arg3) arg1 ## arg2 ## arg3
|
||||||
|
#define NV_STRING2(x) #x
|
||||||
|
#define NV_STRING(x) NV_STRING2(x)
|
||||||
|
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
#define NV_MULTI_LINE_MACRO_BEGIN do {
|
||||||
|
#define NV_MULTI_LINE_MACRO_END \
|
||||||
|
__pragma(warning(push)) \
|
||||||
|
__pragma(warning(disable:4127)) \
|
||||||
|
} while(false) \
|
||||||
|
__pragma(warning(pop))
|
||||||
|
#else
|
||||||
|
#define NV_MULTI_LINE_MACRO_BEGIN do {
|
||||||
|
#define NV_MULTI_LINE_MACRO_END } while(false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NV_CC_CPP11
|
||||||
|
#define nvStaticCheck(x) static_assert((x), "Static assert "#x" failed")
|
||||||
|
#else
|
||||||
|
#define nvStaticCheck(x) typedef char NV_STRING_JOIN2(__static_assert_,__LINE__)[(x)]
|
||||||
|
#endif
|
||||||
|
#define NV_COMPILER_CHECK(x) nvStaticCheck(x) // I like this name best.
|
||||||
|
|
||||||
|
// Make sure type definitions are fine.
|
||||||
|
NV_COMPILER_CHECK(sizeof(int8) == 1);
|
||||||
|
NV_COMPILER_CHECK(sizeof(uint8) == 1);
|
||||||
|
NV_COMPILER_CHECK(sizeof(int16) == 2);
|
||||||
|
NV_COMPILER_CHECK(sizeof(uint16) == 2);
|
||||||
|
NV_COMPILER_CHECK(sizeof(int32) == 4);
|
||||||
|
NV_COMPILER_CHECK(sizeof(uint32) == 4);
|
||||||
|
NV_COMPILER_CHECK(sizeof(int32) == 4);
|
||||||
|
NV_COMPILER_CHECK(sizeof(uint32) == 4);
|
||||||
|
|
||||||
|
#include <stddef.h> // for size_t
|
||||||
|
template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
|
||||||
|
#define NV_ARRAY_SIZE(x) sizeof(ArraySizeHelper(x))
|
||||||
|
//#define NV_ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
||||||
|
#if 0 // Disabled in The Witness.
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
#define NV_MESSAGE(x) message(__FILE__ "(" NV_STRING(__LINE__) ") : " x)
|
||||||
|
#else
|
||||||
|
#define NV_MESSAGE(x) message(x)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define NV_MESSAGE(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Startup initialization macro.
|
||||||
|
#define NV_AT_STARTUP(some_code) \
|
||||||
|
namespace { \
|
||||||
|
static struct NV_STRING_JOIN2(AtStartup_, __LINE__) { \
|
||||||
|
NV_STRING_JOIN2(AtStartup_, __LINE__)() { some_code; } \
|
||||||
|
} \
|
||||||
|
NV_STRING_JOIN3(AtStartup_, __LINE__, Instance); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicate the compiler that the parameter is not used to suppress compier warnings.
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
#define NV_UNUSED(a) ((a)=(a))
|
||||||
|
#else
|
||||||
|
#define NV_UNUSED(a) _Pragma(NV_STRING(unused(a)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Null index. @@ Move this somewhere else... it's only used by nvmesh.
|
||||||
|
//const unsigned int NIL = unsigned int(~0);
|
||||||
|
#define NIL uint(~0)
|
||||||
|
|
||||||
|
// Null pointer.
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Platform includes
|
||||||
|
#if NV_CC_MSVC
|
||||||
|
# if NV_OS_WIN32
|
||||||
|
# include "DefsVcWin32.h"
|
||||||
|
# elif NV_OS_XBOX
|
||||||
|
# include "DefsVcXBox.h"
|
||||||
|
# elif NV_OS_DURANGO
|
||||||
|
# include "DefsVcDurango.h"
|
||||||
|
# else
|
||||||
|
# error "MSVC: Platform not supported"
|
||||||
|
# endif
|
||||||
|
#elif NV_CC_GNUC
|
||||||
|
# if NV_OS_LINUX
|
||||||
|
# include "DefsGnucLinux.h"
|
||||||
|
# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD
|
||||||
|
# include "DefsGnucDarwin.h"
|
||||||
|
# elif NV_OS_ORBIS
|
||||||
|
# include "DefsOrbis.h"
|
||||||
|
# elif NV_OS_MINGW
|
||||||
|
# include "DefsGnucWin32.h"
|
||||||
|
# elif NV_OS_CYGWIN
|
||||||
|
# error "GCC: Cygwin not supported"
|
||||||
|
# else
|
||||||
|
# error "GCC: Platform not supported"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NV_CORE_H
|
|
@ -0,0 +1,641 @@
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 1990, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to Berkeley by
|
||||||
|
* Chris Torek.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. 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.
|
||||||
|
* 4. Neither the name of the University 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 REGENTS 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.
|
||||||
|
*
|
||||||
|
* From: Id: vfscanf.c,v 1.13 1998/09/25 12:20:27 obrien Exp
|
||||||
|
* From: static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
|
||||||
|
* From: static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma warning(disable : 4244) // conversion from '*' to '*', possible loss of data
|
||||||
|
#pragma warning(disable : 4018) // signed/unsigned mismatch
|
||||||
|
#pragma warning(disable : 4267) // '=' : conversion from 'size_t' to 'int', possible loss of data
|
||||||
|
|
||||||
|
#define strtoq _strtoi64
|
||||||
|
#define strtouq _strtoui64
|
||||||
|
#define bcopy(b1,b2,len) (memmove((b2), (b1), (len)), (void) 0)
|
||||||
|
|
||||||
|
typedef int long long quad_t;
|
||||||
|
typedef unsigned long long u_quad_t;
|
||||||
|
typedef unsigned char u_char;
|
||||||
|
|
||||||
|
#define BUF 32 /* Maximum length of numeric string. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags used during conversion.
|
||||||
|
*/
|
||||||
|
#define LONG 0x01 /* l: long or double */
|
||||||
|
#define SHORT 0x04 /* h: short */
|
||||||
|
#define SUPPRESS 0x08 /* suppress assignment */
|
||||||
|
#define POINTER 0x10 /* weird %p pointer (`fake hex') */
|
||||||
|
#define NOSKIP 0x20 /* do not skip blanks */
|
||||||
|
#define QUAD 0x400
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following are used in numeric conversions only:
|
||||||
|
* SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
|
||||||
|
* SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
|
||||||
|
*/
|
||||||
|
#define SIGNOK 0x40 /* +/- is (still) legal */
|
||||||
|
#define NDIGITS 0x80 /* no digits detected */
|
||||||
|
|
||||||
|
#define DPTOK 0x100 /* (float) decimal point is still legal */
|
||||||
|
#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */
|
||||||
|
|
||||||
|
#define PFXOK 0x100 /* 0x prefix is (still) legal */
|
||||||
|
#define NZDIGITS 0x200 /* no zero digits detected */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversion types.
|
||||||
|
*/
|
||||||
|
#define CT_CHAR 0 /* %c conversion */
|
||||||
|
#define CT_CCL 1 /* %[...] conversion */
|
||||||
|
#define CT_STRING 2 /* %s conversion */
|
||||||
|
#define CT_INT 3 /* integer, i.e., strtoq or strtouq */
|
||||||
|
typedef u_quad_t (*ccfntype)(const char *, char **, int);
|
||||||
|
|
||||||
|
static const u_char *__sccl(char *, const u_char *);
|
||||||
|
|
||||||
|
int
|
||||||
|
vsscanf(const char *inp, char const *fmt0, va_list ap)
|
||||||
|
{
|
||||||
|
int inr;
|
||||||
|
const u_char *fmt = (const u_char *)fmt0;
|
||||||
|
int c; /* character from format, or conversion */
|
||||||
|
size_t width; /* field width, or 0 */
|
||||||
|
char *p; /* points into all kinds of strings */
|
||||||
|
int n; /* handy integer */
|
||||||
|
int flags; /* flags as defined above */
|
||||||
|
char *p0; /* saves original value of p when necessary */
|
||||||
|
int nassigned; /* number of fields assigned */
|
||||||
|
int nconversions; /* number of conversions */
|
||||||
|
int nread; /* number of characters consumed from fp */
|
||||||
|
int base; /* base argument to strtoq/strtouq */
|
||||||
|
ccfntype ccfn; /* conversion function (strtoq/strtouq) */
|
||||||
|
char ccltab[256]; /* character class table for %[...] */
|
||||||
|
char buf[BUF]; /* buffer for numeric conversions */
|
||||||
|
|
||||||
|
/* `basefix' is used to avoid `if' tests in the integer scanner */
|
||||||
|
static short basefix[17] =
|
||||||
|
{ 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
|
||||||
|
|
||||||
|
inr = strlen(inp);
|
||||||
|
|
||||||
|
nassigned = 0;
|
||||||
|
nconversions = 0;
|
||||||
|
nread = 0;
|
||||||
|
base = 0; /* XXX just to keep gcc happy */
|
||||||
|
ccfn = NULL; /* XXX just to keep gcc happy */
|
||||||
|
for (;;) {
|
||||||
|
c = *fmt++;
|
||||||
|
if (c == 0)
|
||||||
|
return (nassigned);
|
||||||
|
if (isspace(c)) {
|
||||||
|
while (inr > 0 && isspace(*inp))
|
||||||
|
nread++, inr--, inp++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c != '%')
|
||||||
|
goto literal;
|
||||||
|
width = 0;
|
||||||
|
flags = 0;
|
||||||
|
/*
|
||||||
|
* switch on the format. continue if done;
|
||||||
|
* break once format type is derived.
|
||||||
|
*/
|
||||||
|
again: c = *fmt++;
|
||||||
|
switch (c) {
|
||||||
|
case '%':
|
||||||
|
literal:
|
||||||
|
if (inr <= 0)
|
||||||
|
goto input_failure;
|
||||||
|
if (*inp != c)
|
||||||
|
goto match_failure;
|
||||||
|
inr--, inp++;
|
||||||
|
nread++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
flags |= SUPPRESS;
|
||||||
|
goto again;
|
||||||
|
case 'l':
|
||||||
|
flags |= LONG;
|
||||||
|
goto again;
|
||||||
|
case 'q':
|
||||||
|
flags |= QUAD;
|
||||||
|
goto again;
|
||||||
|
case 'h':
|
||||||
|
flags |= SHORT;
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
width = width * 10 + c - '0';
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
case 'd':
|
||||||
|
c = CT_INT;
|
||||||
|
ccfn = (ccfntype)strtoq;
|
||||||
|
base = 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i':
|
||||||
|
c = CT_INT;
|
||||||
|
ccfn = (ccfntype)strtoq;
|
||||||
|
base = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
c = CT_INT;
|
||||||
|
ccfn = strtouq;
|
||||||
|
base = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
c = CT_INT;
|
||||||
|
ccfn = strtouq;
|
||||||
|
base = 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
flags |= PFXOK; /* enable 0x prefixing */
|
||||||
|
c = CT_INT;
|
||||||
|
ccfn = strtouq;
|
||||||
|
base = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
c = CT_STRING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
fmt = __sccl(ccltab, fmt);
|
||||||
|
flags |= NOSKIP;
|
||||||
|
c = CT_CCL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
flags |= NOSKIP;
|
||||||
|
c = CT_CHAR;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p': /* pointer format is like hex */
|
||||||
|
flags |= POINTER | PFXOK;
|
||||||
|
c = CT_INT;
|
||||||
|
ccfn = strtouq;
|
||||||
|
base = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
nconversions++;
|
||||||
|
if (flags & SUPPRESS) /* ??? */
|
||||||
|
continue;
|
||||||
|
if (flags & SHORT)
|
||||||
|
*va_arg(ap, short *) = nread;
|
||||||
|
else if (flags & LONG)
|
||||||
|
*va_arg(ap, long *) = nread;
|
||||||
|
else if (flags & QUAD)
|
||||||
|
*va_arg(ap, quad_t *) = nread;
|
||||||
|
else
|
||||||
|
*va_arg(ap, int *) = nread;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have a conversion that requires input.
|
||||||
|
*/
|
||||||
|
if (inr <= 0)
|
||||||
|
goto input_failure;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Consume leading white space, except for formats
|
||||||
|
* that suppress this.
|
||||||
|
*/
|
||||||
|
if ((flags & NOSKIP) == 0) {
|
||||||
|
while (isspace(*inp)) {
|
||||||
|
nread++;
|
||||||
|
if (--inr > 0)
|
||||||
|
inp++;
|
||||||
|
else
|
||||||
|
goto input_failure;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Note that there is at least one character in
|
||||||
|
* the buffer, so conversions that do not set NOSKIP
|
||||||
|
* can no longer result in an input failure.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do the conversion.
|
||||||
|
*/
|
||||||
|
switch (c) {
|
||||||
|
|
||||||
|
case CT_CHAR:
|
||||||
|
/* scan arbitrary characters (sets NOSKIP) */
|
||||||
|
if (width == 0)
|
||||||
|
width = 1;
|
||||||
|
if (flags & SUPPRESS) {
|
||||||
|
size_t sum = 0;
|
||||||
|
for (;;) {
|
||||||
|
if ((n = inr) < width) {
|
||||||
|
sum += n;
|
||||||
|
width -= n;
|
||||||
|
inp += n;
|
||||||
|
if (sum == 0)
|
||||||
|
goto input_failure;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
sum += width;
|
||||||
|
inr -= width;
|
||||||
|
inp += width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nread += sum;
|
||||||
|
} else {
|
||||||
|
bcopy(inp, va_arg(ap, char *), width);
|
||||||
|
inr -= width;
|
||||||
|
inp += width;
|
||||||
|
nread += width;
|
||||||
|
nassigned++;
|
||||||
|
}
|
||||||
|
nconversions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CT_CCL:
|
||||||
|
/* scan a (nonempty) character class (sets NOSKIP) */
|
||||||
|
if (width == 0)
|
||||||
|
width = (size_t)~0; /* `infinity' */
|
||||||
|
/* take only those things in the class */
|
||||||
|
if (flags & SUPPRESS) {
|
||||||
|
n = 0;
|
||||||
|
while (ccltab[(unsigned char)*inp]) {
|
||||||
|
n++, inr--, inp++;
|
||||||
|
if (--width == 0)
|
||||||
|
break;
|
||||||
|
if (inr <= 0) {
|
||||||
|
if (n == 0)
|
||||||
|
goto input_failure;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n == 0)
|
||||||
|
goto match_failure;
|
||||||
|
} else {
|
||||||
|
p0 = p = va_arg(ap, char *);
|
||||||
|
while (ccltab[(unsigned char)*inp]) {
|
||||||
|
inr--;
|
||||||
|
*p++ = *inp++;
|
||||||
|
if (--width == 0)
|
||||||
|
break;
|
||||||
|
if (inr <= 0) {
|
||||||
|
if (p == p0)
|
||||||
|
goto input_failure;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n = p - p0;
|
||||||
|
if (n == 0)
|
||||||
|
goto match_failure;
|
||||||
|
*p = 0;
|
||||||
|
nassigned++;
|
||||||
|
}
|
||||||
|
nread += n;
|
||||||
|
nconversions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CT_STRING:
|
||||||
|
/* like CCL, but zero-length string OK, & no NOSKIP */
|
||||||
|
if (width == 0)
|
||||||
|
width = (size_t)~0;
|
||||||
|
if (flags & SUPPRESS) {
|
||||||
|
n = 0;
|
||||||
|
while (!isspace(*inp)) {
|
||||||
|
n++, inr--, inp++;
|
||||||
|
if (--width == 0)
|
||||||
|
break;
|
||||||
|
if (inr <= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nread += n;
|
||||||
|
} else {
|
||||||
|
p0 = p = va_arg(ap, char *);
|
||||||
|
while (!isspace(*inp)) {
|
||||||
|
inr--;
|
||||||
|
*p++ = *inp++;
|
||||||
|
if (--width == 0)
|
||||||
|
break;
|
||||||
|
if (inr <= 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
nread += p - p0;
|
||||||
|
nassigned++;
|
||||||
|
}
|
||||||
|
nconversions++;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case CT_INT:
|
||||||
|
/* scan an integer as if by strtoq/strtouq */
|
||||||
|
#ifdef hardway
|
||||||
|
if (width == 0 || width > sizeof(buf) - 1)
|
||||||
|
width = sizeof(buf) - 1;
|
||||||
|
#else
|
||||||
|
/* size_t is unsigned, hence this optimisation */
|
||||||
|
if (--width > sizeof(buf) - 2)
|
||||||
|
width = sizeof(buf) - 2;
|
||||||
|
width++;
|
||||||
|
#endif
|
||||||
|
flags |= SIGNOK | NDIGITS | NZDIGITS;
|
||||||
|
for (p = buf; width; width--) {
|
||||||
|
c = *inp;
|
||||||
|
/*
|
||||||
|
* Switch on the character; `goto ok'
|
||||||
|
* if we accept it as a part of number.
|
||||||
|
*/
|
||||||
|
switch (c) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The digit 0 is always legal, but is
|
||||||
|
* special. For %i conversions, if no
|
||||||
|
* digits (zero or nonzero) have been
|
||||||
|
* scanned (only signs), we will have
|
||||||
|
* base==0. In that case, we should set
|
||||||
|
* it to 8 and enable 0x prefixing.
|
||||||
|
* Also, if we have not scanned zero digits
|
||||||
|
* before this, do not turn off prefixing
|
||||||
|
* (someone else will turn it off if we
|
||||||
|
* have scanned any nonzero digits).
|
||||||
|
*/
|
||||||
|
case '0':
|
||||||
|
if (base == 0) {
|
||||||
|
base = 8;
|
||||||
|
flags |= PFXOK;
|
||||||
|
}
|
||||||
|
if (flags & NZDIGITS)
|
||||||
|
flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
|
||||||
|
else
|
||||||
|
flags &= ~(SIGNOK|PFXOK|NDIGITS);
|
||||||
|
goto ok;
|
||||||
|
|
||||||
|
/* 1 through 7 always legal */
|
||||||
|
case '1': case '2': case '3':
|
||||||
|
case '4': case '5': case '6': case '7':
|
||||||
|
base = basefix[base];
|
||||||
|
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||||
|
goto ok;
|
||||||
|
|
||||||
|
/* digits 8 and 9 ok iff decimal or hex */
|
||||||
|
case '8': case '9':
|
||||||
|
base = basefix[base];
|
||||||
|
if (base <= 8)
|
||||||
|
break; /* not legal here */
|
||||||
|
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||||
|
goto ok;
|
||||||
|
|
||||||
|
/* letters ok iff hex */
|
||||||
|
case 'A': case 'B': case 'C':
|
||||||
|
case 'D': case 'E': case 'F':
|
||||||
|
case 'a': case 'b': case 'c':
|
||||||
|
case 'd': case 'e': case 'f':
|
||||||
|
/* no need to fix base here */
|
||||||
|
if (base <= 10)
|
||||||
|
break; /* not legal here */
|
||||||
|
flags &= ~(SIGNOK | PFXOK | NDIGITS);
|
||||||
|
goto ok;
|
||||||
|
|
||||||
|
/* sign ok only as first character */
|
||||||
|
case '+': case '-':
|
||||||
|
if (flags & SIGNOK) {
|
||||||
|
flags &= ~SIGNOK;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* x ok iff flag still set & 2nd char */
|
||||||
|
case 'x': case 'X':
|
||||||
|
if (flags & PFXOK && p == buf + 1) {
|
||||||
|
base = 16; /* if %i */
|
||||||
|
flags &= ~PFXOK;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we got here, c is not a legal character
|
||||||
|
* for a number. Stop accumulating digits.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
ok:
|
||||||
|
/*
|
||||||
|
* c is legal: store it and look at the next.
|
||||||
|
*/
|
||||||
|
*p++ = c;
|
||||||
|
if (--inr > 0)
|
||||||
|
inp++;
|
||||||
|
else
|
||||||
|
break; /* end of input */
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If we had only a sign, it is no good; push
|
||||||
|
* back the sign. If the number ends in `x',
|
||||||
|
* it was [sign] '0' 'x', so push back the x
|
||||||
|
* and treat it as [sign] '0'.
|
||||||
|
*/
|
||||||
|
if (flags & NDIGITS) {
|
||||||
|
if (p > buf) {
|
||||||
|
inp--;
|
||||||
|
inr++;
|
||||||
|
}
|
||||||
|
goto match_failure;
|
||||||
|
}
|
||||||
|
c = ((u_char *)p)[-1];
|
||||||
|
if (c == 'x' || c == 'X') {
|
||||||
|
--p;
|
||||||
|
inp--;
|
||||||
|
inr++;
|
||||||
|
}
|
||||||
|
if ((flags & SUPPRESS) == 0) {
|
||||||
|
u_quad_t res;
|
||||||
|
|
||||||
|
*p = 0;
|
||||||
|
res = (*ccfn)(buf, (char **)NULL, base);
|
||||||
|
if (flags & POINTER)
|
||||||
|
*va_arg(ap, void **) =
|
||||||
|
(void *)(uintptr_t)res;
|
||||||
|
else if (flags & SHORT)
|
||||||
|
*va_arg(ap, short *) = res;
|
||||||
|
else if (flags & LONG)
|
||||||
|
*va_arg(ap, long *) = res;
|
||||||
|
else if (flags & QUAD)
|
||||||
|
*va_arg(ap, quad_t *) = res;
|
||||||
|
else
|
||||||
|
*va_arg(ap, int *) = res;
|
||||||
|
nassigned++;
|
||||||
|
}
|
||||||
|
nread += p - buf;
|
||||||
|
nconversions++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input_failure:
|
||||||
|
return (nconversions != 0 ? nassigned : -1);
|
||||||
|
match_failure:
|
||||||
|
return (nassigned);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill in the given table from the scanset at the given format
|
||||||
|
* (just after `['). Return a pointer to the character past the
|
||||||
|
* closing `]'. The table has a 1 wherever characters should be
|
||||||
|
* considered part of the scanset.
|
||||||
|
*/
|
||||||
|
static const u_char *
|
||||||
|
__sccl(char *tab, const u_char *fmt)
|
||||||
|
{
|
||||||
|
int c, n, v;
|
||||||
|
|
||||||
|
/* first `clear' the whole table */
|
||||||
|
c = *fmt++; /* first char hat => negated scanset */
|
||||||
|
if (c == '^') {
|
||||||
|
v = 1; /* default => accept */
|
||||||
|
c = *fmt++; /* get new first char */
|
||||||
|
} else
|
||||||
|
v = 0; /* default => reject */
|
||||||
|
|
||||||
|
/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
|
||||||
|
for (n = 0; n < 256; n++)
|
||||||
|
tab[n] = v; /* memset(tab, v, 256) */
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return (fmt - 1);/* format ended before closing ] */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now set the entries corresponding to the actual scanset
|
||||||
|
* to the opposite of the above.
|
||||||
|
*
|
||||||
|
* The first character may be ']' (or '-') without being special;
|
||||||
|
* the last character may be '-'.
|
||||||
|
*/
|
||||||
|
v = 1 - v;
|
||||||
|
for (;;) {
|
||||||
|
tab[c] = v; /* take character c */
|
||||||
|
doswitch:
|
||||||
|
n = *fmt++; /* and examine the next */
|
||||||
|
switch (n) {
|
||||||
|
|
||||||
|
case 0: /* format ended too soon */
|
||||||
|
return (fmt - 1);
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
/*
|
||||||
|
* A scanset of the form
|
||||||
|
* [01+-]
|
||||||
|
* is defined as `the digit 0, the digit 1,
|
||||||
|
* the character +, the character -', but
|
||||||
|
* the effect of a scanset such as
|
||||||
|
* [a-zA-Z0-9]
|
||||||
|
* is implementation defined. The V7 Unix
|
||||||
|
* scanf treats `a-z' as `the letters a through
|
||||||
|
* z', but treats `a-a' as `the letter a, the
|
||||||
|
* character -, and the letter a'.
|
||||||
|
*
|
||||||
|
* For compatibility, the `-' is not considerd
|
||||||
|
* to define a range if the character following
|
||||||
|
* it is either a close bracket (required by ANSI)
|
||||||
|
* or is not numerically greater than the character
|
||||||
|
* we just stored in the table (c).
|
||||||
|
*/
|
||||||
|
n = *fmt;
|
||||||
|
if (n == ']' || n < c) {
|
||||||
|
c = '-';
|
||||||
|
break; /* resume the for(;;) */
|
||||||
|
}
|
||||||
|
fmt++;
|
||||||
|
/* fill in the range */
|
||||||
|
do {
|
||||||
|
tab[++c] = v;
|
||||||
|
} while (c < n);
|
||||||
|
c = n;
|
||||||
|
/*
|
||||||
|
* Alas, the V7 Unix scanf also treats formats
|
||||||
|
* such as [a-c-e] as `the letters a through e'.
|
||||||
|
* This too is permitted by the standard....
|
||||||
|
*/
|
||||||
|
goto doswitch;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ']': /* end of scanset */
|
||||||
|
return (fmt);
|
||||||
|
|
||||||
|
default: /* just another character */
|
||||||
|
c = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int
|
||||||
|
sscanf(const char *ibuf, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ret = vsscanf(ibuf, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,27 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#include "BitMap.h"
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
void BitMap::resize(uint w, uint h, bool initValue)
|
||||||
|
{
|
||||||
|
BitArray tmp(w*h);
|
||||||
|
|
||||||
|
if (initValue) tmp.setAll();
|
||||||
|
else tmp.clearAll();
|
||||||
|
|
||||||
|
// @@ Copying one bit at a time. This could be much faster.
|
||||||
|
for (uint y = 0; y < m_height; y++)
|
||||||
|
{
|
||||||
|
for (uint x = 0; x < m_width; x++)
|
||||||
|
{
|
||||||
|
//tmp.setBitAt(y*w + x, bitAt(x, y));
|
||||||
|
if (bitAt(x, y) != initValue) tmp.toggleBitAt(y*w + x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(m_bitArray, tmp);
|
||||||
|
m_width = w;
|
||||||
|
m_height = h;
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_IMAGE_BITMAP_H
|
||||||
|
#define NV_IMAGE_BITMAP_H
|
||||||
|
|
||||||
|
#include "nvimage.h"
|
||||||
|
|
||||||
|
#include "nvcore/BitArray.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
/// Bit map. This should probably be called BitImage.
|
||||||
|
class NVIMAGE_CLASS BitMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BitMap() : m_width(0), m_height(0) {}
|
||||||
|
BitMap(uint w, uint h) : m_width(w), m_height(h), m_bitArray(w*h) {}
|
||||||
|
|
||||||
|
uint width() const { return m_width; }
|
||||||
|
uint height() const { return m_height; }
|
||||||
|
|
||||||
|
void resize(uint w, uint h, bool initValue);
|
||||||
|
|
||||||
|
bool bitAt(uint x, uint y) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(x < m_width && y < m_height);
|
||||||
|
return m_bitArray.bitAt(y * m_width + x);
|
||||||
|
}
|
||||||
|
bool bitAt(uint idx) const
|
||||||
|
{
|
||||||
|
return m_bitArray.bitAt(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBitAt(uint x, uint y)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x < m_width && y < m_height);
|
||||||
|
m_bitArray.setBitAt(y * m_width + x);
|
||||||
|
}
|
||||||
|
void setBitAt(uint idx)
|
||||||
|
{
|
||||||
|
m_bitArray.setBitAt(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearBitAt(uint x, uint y)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x < m_width && y < m_height);
|
||||||
|
m_bitArray.clearBitAt(y * m_width + x);
|
||||||
|
}
|
||||||
|
void clearBitAt(uint idx)
|
||||||
|
{
|
||||||
|
m_bitArray.clearBitAt(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearAll()
|
||||||
|
{
|
||||||
|
m_bitArray.clearAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAll()
|
||||||
|
{
|
||||||
|
m_bitArray.setAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleAll()
|
||||||
|
{
|
||||||
|
m_bitArray.toggleAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void swap(BitMap & a, BitMap & b)
|
||||||
|
{
|
||||||
|
nvCheck(a.m_width == b.m_width);
|
||||||
|
nvCheck(a.m_height == b.m_height);
|
||||||
|
swap(a.m_bitArray, b.m_bitArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint m_width;
|
||||||
|
uint m_height;
|
||||||
|
BitArray m_bitArray;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_IMAGE_BITMAP_H
|
|
@ -0,0 +1,51 @@
|
||||||
|
PROJECT(nvimage)
|
||||||
|
|
||||||
|
SET(IMAGE_SRCS
|
||||||
|
nvimage.h
|
||||||
|
BitMap.h BitMap.cpp
|
||||||
|
Image.h Image.cpp)
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
IF(PNG_FOUND)
|
||||||
|
SET(LIBS ${LIBS} ${PNG_LIBRARIES})
|
||||||
|
INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})
|
||||||
|
ENDIF(PNG_FOUND)
|
||||||
|
|
||||||
|
IF(JPEG_FOUND)
|
||||||
|
SET(LIBS ${LIBS} ${JPEG_LIBRARIES})
|
||||||
|
INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})
|
||||||
|
ENDIF(JPEG_FOUND)
|
||||||
|
|
||||||
|
IF(TIFF_FOUND)
|
||||||
|
SET(LIBS ${LIBS} ${TIFF_LIBRARIES})
|
||||||
|
INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
|
||||||
|
ENDIF(TIFF_FOUND)
|
||||||
|
|
||||||
|
IF(OPENEXR_FOUND)
|
||||||
|
SET(LIBS ${LIBS} ${OPENEXR_LIBRARIES})
|
||||||
|
INCLUDE_DIRECTORIES(${OPENEXR_INCLUDE_PATHS})
|
||||||
|
ENDIF(OPENEXR_FOUND)
|
||||||
|
|
||||||
|
IF(FREEIMAGE_FOUND)
|
||||||
|
SET(LIBS ${LIBS} ${FREEIMAGE_LIBRARIES})
|
||||||
|
INCLUDE_DIRECTORIES(${FREEIMAGE_INCLUDE_PATH})
|
||||||
|
ENDIF(FREEIMAGE_FOUND)
|
||||||
|
|
||||||
|
# targets
|
||||||
|
ADD_DEFINITIONS(-DNVIMAGE_EXPORTS)
|
||||||
|
|
||||||
|
IF(NVIMAGE_SHARED)
|
||||||
|
ADD_DEFINITIONS(-DNVIMAGE_SHARED=1)
|
||||||
|
ADD_LIBRARY(nvimage SHARED ${IMAGE_SRCS})
|
||||||
|
ELSE(NVIMAGE_SHARED)
|
||||||
|
ADD_LIBRARY(nvimage ${IMAGE_SRCS})
|
||||||
|
ENDIF(NVIMAGE_SHARED)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(nvimage ${LIBS} nvcore nvmath posh)
|
||||||
|
|
||||||
|
INSTALL(TARGETS nvimage
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib/static)
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#include "Image.h"
|
||||||
|
//#include "ImageIO.h"
|
||||||
|
|
||||||
|
#include "nvmath/Color.h"
|
||||||
|
|
||||||
|
#include "nvcore/Debug.h"
|
||||||
|
#include "nvcore/Ptr.h"
|
||||||
|
#include "nvcore/Utils.h" // swap
|
||||||
|
#include "nvcore/Memory.h" // realloc, free
|
||||||
|
|
||||||
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(const Image & img) : m_data(NULL)
|
||||||
|
{
|
||||||
|
allocate(img.m_width, img.m_height, img.m_depth);
|
||||||
|
m_format = img.m_format;
|
||||||
|
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height * m_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::~Image()
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Image & Image::operator=(const Image & img)
|
||||||
|
{
|
||||||
|
allocate(img.m_width, img.m_height, m_depth);
|
||||||
|
m_format = img.m_format;
|
||||||
|
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height * m_depth);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Image::allocate(uint w, uint h, uint d/*= 1*/)
|
||||||
|
{
|
||||||
|
m_width = w;
|
||||||
|
m_height = h;
|
||||||
|
m_depth = d;
|
||||||
|
m_data = realloc<Color32>(m_data, w * h * d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::acquire(Color32 * data, uint w, uint h, uint d/*= 1*/)
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
m_width = w;
|
||||||
|
m_height = h;
|
||||||
|
m_depth = d;
|
||||||
|
m_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::resize(uint w, uint h, uint d/*= 1*/) {
|
||||||
|
|
||||||
|
Image img;
|
||||||
|
img.allocate(w, h, d);
|
||||||
|
|
||||||
|
Color32 background(0,0,0,0);
|
||||||
|
|
||||||
|
// Copy image.
|
||||||
|
uint x, y, z;
|
||||||
|
for(z = 0; z < min(d, m_depth); z++) {
|
||||||
|
for(y = 0; y < min(h, m_height); y++) {
|
||||||
|
for(x = 0; x < min(w, m_width); x++) {
|
||||||
|
img.pixel(x, y, z) = pixel(x, y, z);
|
||||||
|
}
|
||||||
|
for(; x < w; x++) {
|
||||||
|
img.pixel(x, y, z) = background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(; y < h; y++) {
|
||||||
|
for(x = 0; x < w; x++) {
|
||||||
|
img.pixel(x, y, z) = background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(; z < d; z++) {
|
||||||
|
for(y = 0; y < h; y++) {
|
||||||
|
for(x = 0; x < w; x++) {
|
||||||
|
img.pixel(x, y, z) = background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(m_width, img.m_width);
|
||||||
|
swap(m_height, img.m_height);
|
||||||
|
swap(m_depth, img.m_depth);
|
||||||
|
swap(m_format, img.m_format);
|
||||||
|
swap(m_data, img.m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*bool Image::load(const char * name)
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
|
||||||
|
AutoPtr<Image> img(ImageIO::load(name));
|
||||||
|
if (img == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
swap(m_width, img->m_width);
|
||||||
|
swap(m_height, img->m_height);
|
||||||
|
swap(m_depth, img->m_depth);
|
||||||
|
swap(m_format, img->m_format);
|
||||||
|
swap(m_data, img->m_data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
void Image::wrap(void * data, uint w, uint h, uint d)
|
||||||
|
{
|
||||||
|
free();
|
||||||
|
m_data = (Color32 *)data;
|
||||||
|
m_width = w;
|
||||||
|
m_height = h;
|
||||||
|
m_depth = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::unwrap()
|
||||||
|
{
|
||||||
|
m_data = NULL;
|
||||||
|
m_width = 0;
|
||||||
|
m_height = 0;
|
||||||
|
m_depth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Image::free()
|
||||||
|
{
|
||||||
|
::free(m_data);
|
||||||
|
m_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint Image::width() const
|
||||||
|
{
|
||||||
|
return m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint Image::height() const
|
||||||
|
{
|
||||||
|
return m_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint Image::depth() const
|
||||||
|
{
|
||||||
|
return m_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color32 * Image::scanline(uint h) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(h < m_height);
|
||||||
|
return m_data + h * m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color32 * Image::scanline(uint h)
|
||||||
|
{
|
||||||
|
nvDebugCheck(h < m_height);
|
||||||
|
return m_data + h * m_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color32 * Image::pixels() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color32 * Image::pixels()
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Color32 & Image::pixel(uint idx) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(idx < m_width * m_height * m_depth);
|
||||||
|
return m_data[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
Color32 & Image::pixel(uint idx)
|
||||||
|
{
|
||||||
|
nvDebugCheck(idx < m_width * m_height * m_depth);
|
||||||
|
return m_data[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Image::Format Image::format() const
|
||||||
|
{
|
||||||
|
return m_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::setFormat(Image::Format f)
|
||||||
|
{
|
||||||
|
m_format = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::fill(Color32 c)
|
||||||
|
{
|
||||||
|
const uint size = m_width * m_height * m_depth;
|
||||||
|
for (uint i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
m_data[i] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_IMAGE_IMAGE_H
|
||||||
|
#define NV_IMAGE_IMAGE_H
|
||||||
|
|
||||||
|
#include "nvimage.h"
|
||||||
|
#include "nvcore/Debug.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
class Color32;
|
||||||
|
|
||||||
|
/// 32 bit RGBA image.
|
||||||
|
class NVIMAGE_CLASS Image
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Format
|
||||||
|
{
|
||||||
|
Format_RGB,
|
||||||
|
Format_ARGB,
|
||||||
|
};
|
||||||
|
|
||||||
|
Image();
|
||||||
|
Image(const Image & img);
|
||||||
|
~Image();
|
||||||
|
|
||||||
|
const Image & operator=(const Image & img);
|
||||||
|
|
||||||
|
|
||||||
|
void allocate(uint w, uint h, uint d = 1);
|
||||||
|
void acquire(Color32 * data, uint w, uint h, uint d = 1);
|
||||||
|
//bool load(const char * name);
|
||||||
|
|
||||||
|
void resize(uint w, uint h, uint d = 1);
|
||||||
|
|
||||||
|
void wrap(void * data, uint w, uint h, uint d = 1);
|
||||||
|
void unwrap();
|
||||||
|
|
||||||
|
uint width() const;
|
||||||
|
uint height() const;
|
||||||
|
uint depth() const;
|
||||||
|
|
||||||
|
const Color32 * scanline(uint h) const;
|
||||||
|
Color32 * scanline(uint h);
|
||||||
|
|
||||||
|
const Color32 * pixels() const;
|
||||||
|
Color32 * pixels();
|
||||||
|
|
||||||
|
const Color32 & pixel(uint idx) const;
|
||||||
|
Color32 & pixel(uint idx);
|
||||||
|
|
||||||
|
const Color32 & pixel(uint x, uint y, uint z = 0) const;
|
||||||
|
Color32 & pixel(uint x, uint y, uint z = 0);
|
||||||
|
|
||||||
|
Format format() const;
|
||||||
|
void setFormat(Format f);
|
||||||
|
|
||||||
|
void fill(Color32 c);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void free();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint m_width;
|
||||||
|
uint m_height;
|
||||||
|
uint m_depth;
|
||||||
|
Format m_format;
|
||||||
|
Color32 * m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline const Color32 & Image::pixel(uint x, uint y, uint z) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(x < m_width && y < m_height && z < m_depth);
|
||||||
|
return pixel((z * m_height + y) * m_width + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Color32 & Image::pixel(uint x, uint y, uint z)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x < m_width && y < m_height && z < m_depth);
|
||||||
|
return pixel((z * m_height + y) * m_width + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_IMAGE_IMAGE_H
|
|
@ -0,0 +1,48 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_IMAGE_H
|
||||||
|
#define NV_IMAGE_H
|
||||||
|
|
||||||
|
#include "nvcore/nvcore.h"
|
||||||
|
#include "nvcore/Debug.h" // nvDebugCheck
|
||||||
|
#include "nvcore/Utils.h" // isPowerOfTwo
|
||||||
|
|
||||||
|
// Function linkage
|
||||||
|
#if NVIMAGE_SHARED
|
||||||
|
#ifdef NVIMAGE_EXPORTS
|
||||||
|
#define NVIMAGE_API DLL_EXPORT
|
||||||
|
#define NVIMAGE_CLASS DLL_EXPORT_CLASS
|
||||||
|
#else
|
||||||
|
#define NVIMAGE_API DLL_IMPORT
|
||||||
|
#define NVIMAGE_CLASS DLL_IMPORT
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define NVIMAGE_API
|
||||||
|
#define NVIMAGE_CLASS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv {
|
||||||
|
|
||||||
|
// Some utility functions:
|
||||||
|
|
||||||
|
inline uint computeBitPitch(uint w, uint bitsize, uint alignmentInBits)
|
||||||
|
{
|
||||||
|
nvDebugCheck(isPowerOfTwo(alignmentInBits));
|
||||||
|
|
||||||
|
return ((w * bitsize + alignmentInBits - 1) / alignmentInBits) * alignmentInBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint computeBytePitch(uint w, uint bitsize, uint alignmentInBytes)
|
||||||
|
{
|
||||||
|
uint pitch = computeBitPitch(w, bitsize, 8*alignmentInBytes);
|
||||||
|
nvDebugCheck((pitch & 7) == 0);
|
||||||
|
|
||||||
|
return (pitch + 7) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_IMAGE_H
|
|
@ -0,0 +1,270 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#include "Basis.h"
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
|
||||||
|
/// Normalize basis vectors.
|
||||||
|
void Basis::normalize(float epsilon /*= NV_EPSILON*/)
|
||||||
|
{
|
||||||
|
normal = ::normalizeSafe(normal, Vector3(0.0f), epsilon);
|
||||||
|
tangent = ::normalizeSafe(tangent, Vector3(0.0f), epsilon);
|
||||||
|
bitangent = ::normalizeSafe(bitangent, Vector3(0.0f), epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Gram-Schmidt orthogonalization.
|
||||||
|
/// @note Works only if the vectors are close to orthogonal.
|
||||||
|
void Basis::orthonormalize(float epsilon /*= NV_EPSILON*/)
|
||||||
|
{
|
||||||
|
// N' = |N|
|
||||||
|
// T' = |T - (N' dot T) N'|
|
||||||
|
// B' = |B - (N' dot B) N' - (T' dot B) T'|
|
||||||
|
|
||||||
|
normal = ::normalize(normal, epsilon);
|
||||||
|
|
||||||
|
tangent -= normal * dot(normal, tangent);
|
||||||
|
tangent = ::normalize(tangent, epsilon);
|
||||||
|
|
||||||
|
bitangent -= normal * dot(normal, bitangent);
|
||||||
|
bitangent -= tangent * dot(tangent, bitangent);
|
||||||
|
bitangent = ::normalize(bitangent, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Robust orthonormalization.
|
||||||
|
/// Returns an orthonormal basis even when the original is degenerate.
|
||||||
|
void Basis::robustOrthonormalize(float epsilon /*= NV_EPSILON*/)
|
||||||
|
{
|
||||||
|
// Normalize all vectors.
|
||||||
|
normalize(epsilon);
|
||||||
|
|
||||||
|
if (lengthSquared(normal) < epsilon*epsilon)
|
||||||
|
{
|
||||||
|
// Build normal from tangent and bitangent.
|
||||||
|
normal = cross(tangent, bitangent);
|
||||||
|
|
||||||
|
if (lengthSquared(normal) < epsilon*epsilon)
|
||||||
|
{
|
||||||
|
// Arbitrary basis.
|
||||||
|
tangent = Vector3(1, 0, 0);
|
||||||
|
bitangent = Vector3(0, 1, 0);
|
||||||
|
normal = Vector3(0, 0, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
normal = nv::normalize(normal, epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project tangents to normal plane.
|
||||||
|
tangent -= normal * dot(normal, tangent);
|
||||||
|
bitangent -= normal * dot(normal, bitangent);
|
||||||
|
|
||||||
|
if (lengthSquared(tangent) < epsilon*epsilon)
|
||||||
|
{
|
||||||
|
if (lengthSquared(bitangent) < epsilon*epsilon)
|
||||||
|
{
|
||||||
|
// Arbitrary basis.
|
||||||
|
buildFrameForDirection(normal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Build tangent from bitangent.
|
||||||
|
bitangent = nv::normalize(bitangent, epsilon);
|
||||||
|
|
||||||
|
tangent = cross(bitangent, normal);
|
||||||
|
nvDebugCheck(isNormalized(tangent, epsilon));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tangent = nv::normalize(tangent, epsilon);
|
||||||
|
#if 0
|
||||||
|
bitangent -= tangent * dot(tangent, bitangent);
|
||||||
|
|
||||||
|
if (lengthSquared(bitangent) < epsilon*epsilon)
|
||||||
|
{
|
||||||
|
bitangent = cross(tangent, normal);
|
||||||
|
nvDebugCheck(isNormalized(bitangent, epsilon));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bitangent = nv::normalize(bitangent, epsilon);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (lengthSquared(bitangent) < epsilon*epsilon)
|
||||||
|
{
|
||||||
|
// Build bitangent from tangent.
|
||||||
|
bitangent = cross(tangent, normal);
|
||||||
|
nvDebugCheck(isNormalized(bitangent, epsilon));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bitangent = nv::normalize(bitangent, epsilon);
|
||||||
|
|
||||||
|
// At this point tangent and bitangent are orthogonal to normal, but we don't know whether their orientation.
|
||||||
|
|
||||||
|
Vector3 bisector;
|
||||||
|
if (lengthSquared(tangent + bitangent) < epsilon*epsilon)
|
||||||
|
{
|
||||||
|
bisector = tangent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bisector = nv::normalize(tangent + bitangent);
|
||||||
|
}
|
||||||
|
Vector3 axis = nv::normalize(cross(bisector, normal));
|
||||||
|
|
||||||
|
//nvDebugCheck(isNormalized(axis, epsilon));
|
||||||
|
nvDebugCheck(equal(dot(axis, tangent), -dot(axis, bitangent), epsilon));
|
||||||
|
|
||||||
|
if (dot(axis, tangent) > 0)
|
||||||
|
{
|
||||||
|
tangent = bisector + axis;
|
||||||
|
bitangent = bisector - axis;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tangent = bisector - axis;
|
||||||
|
bitangent = bisector + axis;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the resulting tangents are still perpendicular to the normal.
|
||||||
|
tangent -= normal * dot(normal, tangent);
|
||||||
|
bitangent -= normal * dot(normal, bitangent);
|
||||||
|
|
||||||
|
// Double check.
|
||||||
|
nvDebugCheck(equal(dot(normal, tangent), 0.0f, epsilon));
|
||||||
|
nvDebugCheck(equal(dot(normal, bitangent), 0.0f, epsilon));
|
||||||
|
|
||||||
|
// Normalize.
|
||||||
|
tangent = nv::normalize(tangent);
|
||||||
|
bitangent = nv::normalize(bitangent);
|
||||||
|
|
||||||
|
// If tangent and bitangent are not orthogonal, then derive bitangent from tangent, just in case...
|
||||||
|
if (!equal(dot(tangent, bitangent), 0.0f, epsilon)) {
|
||||||
|
bitangent = cross(tangent, normal);
|
||||||
|
bitangent = nv::normalize(bitangent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*// Check vector lengths.
|
||||||
|
if (!isNormalized(normal, epsilon))
|
||||||
|
{
|
||||||
|
nvDebug("%f %f %f\n", normal.x, normal.y, normal.z);
|
||||||
|
nvDebug("%f %f %f\n", tangent.x, tangent.y, tangent.z);
|
||||||
|
nvDebug("%f %f %f\n", bitangent.x, bitangent.y, bitangent.z);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
nvDebugCheck(isNormalized(normal, epsilon));
|
||||||
|
nvDebugCheck(isNormalized(tangent, epsilon));
|
||||||
|
nvDebugCheck(isNormalized(bitangent, epsilon));
|
||||||
|
|
||||||
|
// Check vector angles.
|
||||||
|
nvDebugCheck(equal(dot(normal, tangent), 0.0f, epsilon));
|
||||||
|
nvDebugCheck(equal(dot(normal, bitangent), 0.0f, epsilon));
|
||||||
|
nvDebugCheck(equal(dot(tangent, bitangent), 0.0f, epsilon));
|
||||||
|
|
||||||
|
// Check vector orientation.
|
||||||
|
const float det = dot(cross(normal, tangent), bitangent);
|
||||||
|
nvDebugCheck(equal(det, 1.0f, epsilon) || equal(det, -1.0f, epsilon));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Build an arbitrary frame for the given direction.
|
||||||
|
void Basis::buildFrameForDirection(Vector3::Arg d, float angle/*= 0*/)
|
||||||
|
{
|
||||||
|
nvCheck(isNormalized(d));
|
||||||
|
normal = d;
|
||||||
|
|
||||||
|
// Choose minimum axis.
|
||||||
|
if (fabsf(normal.x) < fabsf(normal.y) && fabsf(normal.x) < fabsf(normal.z))
|
||||||
|
{
|
||||||
|
tangent = Vector3(1, 0, 0);
|
||||||
|
}
|
||||||
|
else if (fabsf(normal.y) < fabsf(normal.z))
|
||||||
|
{
|
||||||
|
tangent = Vector3(0, 1, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tangent = Vector3(0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ortogonalize
|
||||||
|
tangent -= normal * dot(normal, tangent);
|
||||||
|
tangent = ::normalize(tangent);
|
||||||
|
|
||||||
|
bitangent = cross(normal, tangent);
|
||||||
|
|
||||||
|
// Rotate frame around normal according to angle.
|
||||||
|
if (angle != 0.0f) {
|
||||||
|
float c = cosf(angle);
|
||||||
|
float s = sinf(angle);
|
||||||
|
Vector3 tmp = c * tangent - s * bitangent;
|
||||||
|
bitangent = s * tangent + c * bitangent;
|
||||||
|
tangent = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Basis::isValid() const
|
||||||
|
{
|
||||||
|
if (equal(normal, Vector3(0.0f))) return false;
|
||||||
|
if (equal(tangent, Vector3(0.0f))) return false;
|
||||||
|
if (equal(bitangent, Vector3(0.0f))) return false;
|
||||||
|
|
||||||
|
if (equal(determinant(), 0.0f)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Transform by this basis. (From this basis to object space).
|
||||||
|
Vector3 Basis::transform(Vector3::Arg v) const
|
||||||
|
{
|
||||||
|
Vector3 o = tangent * v.x;
|
||||||
|
o += bitangent * v.y;
|
||||||
|
o += normal * v.z;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transform by the transpose. (From object space to this basis).
|
||||||
|
Vector3 Basis::transformT(Vector3::Arg v)
|
||||||
|
{
|
||||||
|
return Vector3(dot(tangent, v), dot(bitangent, v), dot(normal, v));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transform by the inverse. (From object space to this basis).
|
||||||
|
/// @note Uses Cramer's rule so the inverse is not accurate if the basis is ill-conditioned.
|
||||||
|
Vector3 Basis::transformI(Vector3::Arg v) const
|
||||||
|
{
|
||||||
|
const float det = determinant();
|
||||||
|
nvDebugCheck(!equal(det, 0.0f, 0.0f));
|
||||||
|
|
||||||
|
const float idet = 1.0f / det;
|
||||||
|
|
||||||
|
// Rows of the inverse matrix.
|
||||||
|
Vector3 r0(
|
||||||
|
(bitangent.y * normal.z - bitangent.z * normal.y),
|
||||||
|
-(bitangent.x * normal.z - bitangent.z * normal.x),
|
||||||
|
(bitangent.x * normal.y - bitangent.y * normal.x));
|
||||||
|
|
||||||
|
Vector3 r1(
|
||||||
|
-(tangent.y * normal.z - tangent.z * normal.y),
|
||||||
|
(tangent.x * normal.z - tangent.z * normal.x),
|
||||||
|
-(tangent.x * normal.y - tangent.y * normal.x));
|
||||||
|
|
||||||
|
Vector3 r2(
|
||||||
|
(tangent.y * bitangent.z - tangent.z * bitangent.y),
|
||||||
|
-(tangent.x * bitangent.z - tangent.z * bitangent.x),
|
||||||
|
(tangent.x * bitangent.y - tangent.y * bitangent.x));
|
||||||
|
|
||||||
|
return Vector3(dot(v, r0), dot(v, r1), dot(v, r2)) * idet;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_BASIS_H
|
||||||
|
#define NV_MATH_BASIS_H
|
||||||
|
|
||||||
|
#include "nvmath.h"
|
||||||
|
#include "Vector.inl"
|
||||||
|
#include "Matrix.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Basis class to compute tangent space basis, ortogonalizations and to
|
||||||
|
/// transform vectors from one space to another.
|
||||||
|
class Basis
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Create a null basis.
|
||||||
|
Basis() : tangent(0, 0, 0), bitangent(0, 0, 0), normal(0, 0, 0) {}
|
||||||
|
|
||||||
|
/// Create a basis given three vectors.
|
||||||
|
Basis(Vector3::Arg n, Vector3::Arg t, Vector3::Arg b) : tangent(t), bitangent(b), normal(n) {}
|
||||||
|
|
||||||
|
/// Create a basis with the given tangent vectors and the handness.
|
||||||
|
Basis(Vector3::Arg n, Vector3::Arg t, float sign)
|
||||||
|
{
|
||||||
|
build(n, t, sign);
|
||||||
|
}
|
||||||
|
|
||||||
|
NVMATH_API void normalize(float epsilon = NV_EPSILON);
|
||||||
|
NVMATH_API void orthonormalize(float epsilon = NV_EPSILON);
|
||||||
|
NVMATH_API void robustOrthonormalize(float epsilon = NV_EPSILON);
|
||||||
|
NVMATH_API void buildFrameForDirection(Vector3::Arg d, float angle = 0);
|
||||||
|
|
||||||
|
/// Calculate the determinant [ F G N ] to obtain the handness of the basis.
|
||||||
|
float handness() const
|
||||||
|
{
|
||||||
|
return determinant() > 0.0f ? 1.0f : -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build a basis from 2 vectors and a handness flag.
|
||||||
|
void build(Vector3::Arg n, Vector3::Arg t, float sign)
|
||||||
|
{
|
||||||
|
normal = n;
|
||||||
|
tangent = t;
|
||||||
|
bitangent = sign * cross(t, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the determinant of this basis.
|
||||||
|
float determinant() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
tangent.x * bitangent.y * normal.z - tangent.z * bitangent.y * normal.x +
|
||||||
|
tangent.y * bitangent.z * normal.x - tangent.y * bitangent.x * normal.z +
|
||||||
|
tangent.z * bitangent.x * normal.y - tangent.x * bitangent.z * normal.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
// Get transform matrix for this basis.
|
||||||
|
NVMATH_API Matrix matrix() const;
|
||||||
|
|
||||||
|
// Transform by this basis. (From this basis to object space).
|
||||||
|
NVMATH_API Vector3 transform(Vector3::Arg v) const;
|
||||||
|
|
||||||
|
// Transform by the transpose. (From object space to this basis).
|
||||||
|
NVMATH_API Vector3 transformT(Vector3::Arg v);
|
||||||
|
|
||||||
|
// Transform by the inverse. (From object space to this basis).
|
||||||
|
NVMATH_API Vector3 transformI(Vector3::Arg v) const;
|
||||||
|
|
||||||
|
|
||||||
|
Vector3 tangent;
|
||||||
|
Vector3 bitangent;
|
||||||
|
Vector3 normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_MATH_BASIS_H
|
|
@ -0,0 +1,119 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#include "Box.h"
|
||||||
|
#include "Box.inl"
|
||||||
|
#include "Sphere.h"
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Clip the given segment against this box.
|
||||||
|
bool Box::clipSegment(const Vector3 & origin, const Vector3 & dir, float * t_near, float * t_far) const {
|
||||||
|
|
||||||
|
// Avoid aliasing.
|
||||||
|
float tnear = *t_near;
|
||||||
|
float tfar = *t_far;
|
||||||
|
|
||||||
|
// clip ray segment to box
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
const float pos = origin.component[i] + tfar * dir.component[i];
|
||||||
|
const float dt = tfar - tnear;
|
||||||
|
|
||||||
|
if (dir.component[i] < 0) {
|
||||||
|
|
||||||
|
// clip end point
|
||||||
|
if (pos < minCorner.component[i]) {
|
||||||
|
tfar = tnear + dt * (origin.component[i] - minCorner.component[i]) / (origin.component[i] - pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clip start point
|
||||||
|
if (origin.component[i] > maxCorner.component[i]) {
|
||||||
|
tnear = tnear + dt * (origin.component[i] - maxCorner.component[i]) / (tfar * dir.component[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// clip end point
|
||||||
|
if (pos > maxCorner.component[i]) {
|
||||||
|
tfar = tnear + dt * (maxCorner.component[i] - origin.component[i]) / (pos - origin.component[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clip start point
|
||||||
|
if (origin.component[i] < minCorner.component[i]) {
|
||||||
|
tnear = tnear + dt * (minCorner.component[i] - origin.component[i]) / (tfar * dir.component[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tnear > tfar) {
|
||||||
|
// Clipped away.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return result.
|
||||||
|
*t_near = tnear;
|
||||||
|
*t_far = tfar;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float nv::distanceSquared(const Box &box, const Vector3 &point) {
|
||||||
|
Vector3 closest;
|
||||||
|
|
||||||
|
if (point.x < box.minCorner.x) closest.x = box.minCorner.x;
|
||||||
|
else if (point.x > box.maxCorner.x) closest.x = box.maxCorner.x;
|
||||||
|
else closest.x = point.x;
|
||||||
|
|
||||||
|
if (point.y < box.minCorner.y) closest.y = box.minCorner.y;
|
||||||
|
else if (point.y > box.maxCorner.y) closest.y = box.maxCorner.y;
|
||||||
|
else closest.y = point.y;
|
||||||
|
|
||||||
|
if (point.z < box.minCorner.z) closest.z = box.minCorner.z;
|
||||||
|
else if (point.z > box.maxCorner.z) closest.z = box.maxCorner.z;
|
||||||
|
else closest.z = point.z;
|
||||||
|
|
||||||
|
return lengthSquared(point - closest);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::overlap(const Box &box, const Sphere &sphere) {
|
||||||
|
return distanceSquared(box, sphere.center) < sphere.radius * sphere.radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool nv::intersect(const Box & box, const Vector3 & p, const Vector3 & id, float * t /*= NULL*/) {
|
||||||
|
// Precompute these in ray structure?
|
||||||
|
int sdx = (id.x < 0);
|
||||||
|
int sdy = (id.y < 0);
|
||||||
|
int sdz = (id.z < 0);
|
||||||
|
|
||||||
|
float tmin = (box.corner( sdx).x - p.x) * id.x;
|
||||||
|
float tmax = (box.corner(1-sdx).x - p.x) * id.x;
|
||||||
|
float tymin = (box.corner( sdy).y - p.y) * id.y;
|
||||||
|
float tymax = (box.corner(1-sdy).y - p.y) * id.y;
|
||||||
|
|
||||||
|
if ((tmin > tymax) || (tymin > tmax))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tymin > tmin) tmin = tymin;
|
||||||
|
if (tymax < tmax) tmax = tymax;
|
||||||
|
|
||||||
|
float tzmin = (box.corner( sdz).z - p.z) * id.z;
|
||||||
|
float tzmax = (box.corner(1-sdz).z - p.z) * id.z;
|
||||||
|
|
||||||
|
if ((tmin > tzmax) || (tzmin > tmax))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tzmin > tmin) tmin = tzmin;
|
||||||
|
if (tzmax < tmax) tmax = tzmax;
|
||||||
|
|
||||||
|
if (tmax < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (t != NULL) *t = tmin;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_BOX_H
|
||||||
|
#define NV_MATH_BOX_H
|
||||||
|
|
||||||
|
#include "Vector.h"
|
||||||
|
|
||||||
|
#include <float.h> // FLT_MAX
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
class Vector;
|
||||||
|
class Stream;
|
||||||
|
class Sphere;
|
||||||
|
|
||||||
|
// Axis Aligned Bounding Box.
|
||||||
|
class Box
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
inline Box() {}
|
||||||
|
inline Box(const Box & b) : minCorner(b.minCorner), maxCorner(b.maxCorner) {}
|
||||||
|
inline Box(const Vector3 & mins, const Vector3 & maxs) : minCorner(mins), maxCorner(maxs) {}
|
||||||
|
|
||||||
|
Box & operator=(const Box & b);
|
||||||
|
|
||||||
|
operator const float * () const { return reinterpret_cast<const float *>(this); }
|
||||||
|
|
||||||
|
// Clear the bounds.
|
||||||
|
void clearBounds();
|
||||||
|
|
||||||
|
// min < max
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
// Build a cube centered on center and with edge = 2*dist
|
||||||
|
void cube(const Vector3 & center, float dist);
|
||||||
|
|
||||||
|
// Build a box, given center and extents.
|
||||||
|
void setCenterExtents(const Vector3 & center, const Vector3 & extents);
|
||||||
|
|
||||||
|
// Get box center.
|
||||||
|
Vector3 center() const;
|
||||||
|
|
||||||
|
// Return extents of the box.
|
||||||
|
Vector3 extents() const;
|
||||||
|
|
||||||
|
// Return extents of the box.
|
||||||
|
float extents(uint axis) const;
|
||||||
|
|
||||||
|
// Add a point to this box.
|
||||||
|
void addPointToBounds(const Vector3 & p);
|
||||||
|
|
||||||
|
// Add a box to this box.
|
||||||
|
void addBoxToBounds(const Box & b);
|
||||||
|
|
||||||
|
// Add sphere to this box.
|
||||||
|
void addSphereToBounds(const Vector3 & p, float r);
|
||||||
|
|
||||||
|
// Translate box.
|
||||||
|
void translate(const Vector3 & v);
|
||||||
|
|
||||||
|
// Scale the box.
|
||||||
|
void scale(float s);
|
||||||
|
|
||||||
|
// Expand the box by a fixed amount.
|
||||||
|
void expand(float r);
|
||||||
|
|
||||||
|
// Get the area of the box.
|
||||||
|
float area() const;
|
||||||
|
|
||||||
|
// Get the volume of the box.
|
||||||
|
float volume() const;
|
||||||
|
|
||||||
|
// Return true if the box contains the given point.
|
||||||
|
bool contains(const Vector3 & p) const;
|
||||||
|
|
||||||
|
// Split the given box in 8 octants and assign the ith one to this box.
|
||||||
|
void setOctant(const Box & box, const Vector3 & center, int i);
|
||||||
|
|
||||||
|
|
||||||
|
// Clip the given segment against this box.
|
||||||
|
bool clipSegment(const Vector3 & origin, const Vector3 & dir, float * t_near, float * t_far) const;
|
||||||
|
|
||||||
|
|
||||||
|
friend Stream & operator<< (Stream & s, Box & box);
|
||||||
|
|
||||||
|
const Vector3 & corner(int i) const { return (&minCorner)[i]; }
|
||||||
|
|
||||||
|
Vector3 minCorner;
|
||||||
|
Vector3 maxCorner;
|
||||||
|
};
|
||||||
|
|
||||||
|
float distanceSquared(const Box &box, const Vector3 &point);
|
||||||
|
bool overlap(const Box &box, const Sphere &sphere);
|
||||||
|
|
||||||
|
// p is ray origin, id is inverse ray direction.
|
||||||
|
bool intersect(const Box & box, const Vector3 & p, const Vector3 & id, float * t);
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#include "box.inl"
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_MATH_BOX_H
|
|
@ -0,0 +1,154 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_BOX_INL
|
||||||
|
#define NV_MATH_BOX_INL
|
||||||
|
|
||||||
|
#include "Box.h"
|
||||||
|
#include "Vector.inl"
|
||||||
|
|
||||||
|
#include <float.h> // FLT_MAX
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
// Default ctor.
|
||||||
|
//inline Box::Box() { };
|
||||||
|
|
||||||
|
// Copy ctor.
|
||||||
|
//inline Box::Box(const Box & b) : minCorner(b.minCorner), maxCorner(b.maxCorner) { }
|
||||||
|
|
||||||
|
// Init ctor.
|
||||||
|
//inline Box::Box(const Vector3 & mins, const Vector3 & maxs) : minCorner(mins), maxCorner(maxs) { }
|
||||||
|
|
||||||
|
// Assignment operator.
|
||||||
|
inline Box & Box::operator=(const Box & b) { minCorner = b.minCorner; maxCorner = b.maxCorner; return *this; }
|
||||||
|
|
||||||
|
// Clear the bounds.
|
||||||
|
inline void Box::clearBounds()
|
||||||
|
{
|
||||||
|
minCorner.set(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||||
|
maxCorner.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
// min < max
|
||||||
|
inline bool Box::isValid() const
|
||||||
|
{
|
||||||
|
return minCorner.x <= maxCorner.x && minCorner.y <= maxCorner.y && minCorner.z <= maxCorner.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a cube centered on center and with edge = 2*dist
|
||||||
|
inline void Box::cube(const Vector3 & center, float dist)
|
||||||
|
{
|
||||||
|
setCenterExtents(center, Vector3(dist));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a box, given center and extents.
|
||||||
|
inline void Box::setCenterExtents(const Vector3 & center, const Vector3 & extents)
|
||||||
|
{
|
||||||
|
minCorner = center - extents;
|
||||||
|
maxCorner = center + extents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get box center.
|
||||||
|
inline Vector3 Box::center() const
|
||||||
|
{
|
||||||
|
return (minCorner + maxCorner) * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return extents of the box.
|
||||||
|
inline Vector3 Box::extents() const
|
||||||
|
{
|
||||||
|
return (maxCorner - minCorner) * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return extents of the box.
|
||||||
|
inline float Box::extents(uint axis) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(axis < 3);
|
||||||
|
if (axis == 0) return (maxCorner.x - minCorner.x) * 0.5f;
|
||||||
|
if (axis == 1) return (maxCorner.y - minCorner.y) * 0.5f;
|
||||||
|
if (axis == 2) return (maxCorner.z - minCorner.z) * 0.5f;
|
||||||
|
nvUnreachable();
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a point to this box.
|
||||||
|
inline void Box::addPointToBounds(const Vector3 & p)
|
||||||
|
{
|
||||||
|
minCorner = min(minCorner, p);
|
||||||
|
maxCorner = max(maxCorner, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a box to this box.
|
||||||
|
inline void Box::addBoxToBounds(const Box & b)
|
||||||
|
{
|
||||||
|
minCorner = min(minCorner, b.minCorner);
|
||||||
|
maxCorner = max(maxCorner, b.maxCorner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add sphere to this box.
|
||||||
|
inline void Box::addSphereToBounds(const Vector3 & p, float r) {
|
||||||
|
minCorner = min(minCorner, p - Vector3(r));
|
||||||
|
maxCorner = min(maxCorner, p + Vector3(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate box.
|
||||||
|
inline void Box::translate(const Vector3 & v)
|
||||||
|
{
|
||||||
|
minCorner += v;
|
||||||
|
maxCorner += v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale the box.
|
||||||
|
inline void Box::scale(float s)
|
||||||
|
{
|
||||||
|
minCorner *= s;
|
||||||
|
maxCorner *= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand the box by a fixed amount.
|
||||||
|
inline void Box::expand(float r) {
|
||||||
|
minCorner -= Vector3(r,r,r);
|
||||||
|
maxCorner += Vector3(r,r,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the area of the box.
|
||||||
|
inline float Box::area() const
|
||||||
|
{
|
||||||
|
const Vector3 d = extents();
|
||||||
|
return 8.0f * (d.x*d.y + d.x*d.z + d.y*d.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the volume of the box.
|
||||||
|
inline float Box::volume() const
|
||||||
|
{
|
||||||
|
Vector3 d = extents();
|
||||||
|
return 8.0f * (d.x * d.y * d.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if the box contains the given point.
|
||||||
|
inline bool Box::contains(const Vector3 & p) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
minCorner.x < p.x && minCorner.y < p.y && minCorner.z < p.z &&
|
||||||
|
maxCorner.x > p.x && maxCorner.y > p.y && maxCorner.z > p.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the given box in 8 octants and assign the ith one to this box.
|
||||||
|
inline void Box::setOctant(const Box & box, const Vector3 & center, int i)
|
||||||
|
{
|
||||||
|
minCorner = box.minCorner;
|
||||||
|
maxCorner = box.maxCorner;
|
||||||
|
|
||||||
|
if (i & 4) minCorner.x = center.x;
|
||||||
|
else maxCorner.x = center.x;
|
||||||
|
if (i & 2) minCorner.y = center.y;
|
||||||
|
else maxCorner.y = center.y;
|
||||||
|
if (i & 1) minCorner.z = center.z;
|
||||||
|
else maxCorner.z = center.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_MATH_BOX_INL
|
|
@ -0,0 +1,38 @@
|
||||||
|
PROJECT(nvmath)
|
||||||
|
|
||||||
|
SET(MATH_SRCS
|
||||||
|
nvmath.h
|
||||||
|
Basis.h Basis.cpp
|
||||||
|
Box.h
|
||||||
|
Color.h
|
||||||
|
ConvexHull.h ConvexHull.cpp
|
||||||
|
Fitting.h Fitting.cpp
|
||||||
|
KahanSum.h
|
||||||
|
Matrix.h
|
||||||
|
Plane.h Plane.cpp
|
||||||
|
ProximityGrid.h ProximityGrid.cpp
|
||||||
|
Quaternion.h
|
||||||
|
Random.h Random.cpp
|
||||||
|
Solver.h Solver.cpp
|
||||||
|
Sparse.h Sparse.cpp
|
||||||
|
TypeSerialization.h TypeSerialization.cpp
|
||||||
|
Vector.h)
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
# targets
|
||||||
|
ADD_DEFINITIONS(-DNVMATH_EXPORTS)
|
||||||
|
|
||||||
|
IF(NVMATH_SHARED)
|
||||||
|
ADD_DEFINITIONS(-DNVMATH_SHARED=1)
|
||||||
|
ADD_LIBRARY(nvmath SHARED ${MATH_SRCS})
|
||||||
|
ELSE(NVMATH_SHARED)
|
||||||
|
ADD_LIBRARY(nvmath ${MATH_SRCS})
|
||||||
|
ENDIF(NVMATH_SHARED)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(nvmath ${LIBS} nvcore)
|
||||||
|
|
||||||
|
INSTALL(TARGETS nvmath
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib/static)
|
|
@ -0,0 +1,150 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_COLOR_H
|
||||||
|
#define NV_MATH_COLOR_H
|
||||||
|
|
||||||
|
#include "nvmath.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
/// 64 bit color stored as BGRA.
|
||||||
|
class NVMATH_CLASS Color64
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Color64() { }
|
||||||
|
Color64(const Color64 & c) : u(c.u) { }
|
||||||
|
Color64(uint16 R, uint16 G, uint16 B, uint16 A) { setRGBA(R, G, B, A); }
|
||||||
|
explicit Color64(uint64 U) : u(U) { }
|
||||||
|
|
||||||
|
void setRGBA(uint16 R, uint16 G, uint16 B, uint16 A)
|
||||||
|
{
|
||||||
|
r = R;
|
||||||
|
g = G;
|
||||||
|
b = B;
|
||||||
|
a = A;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator uint64 () const {
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
#if NV_LITTLE_ENDIAN
|
||||||
|
uint16 r, a, b, g;
|
||||||
|
#else
|
||||||
|
uint16 a: 16;
|
||||||
|
uint16 r: 16;
|
||||||
|
uint16 g: 16;
|
||||||
|
uint16 b: 16;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
uint64 u;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 32 bit color stored as BGRA.
|
||||||
|
class NVMATH_CLASS Color32
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Color32() { }
|
||||||
|
Color32(const Color32 & c) : u(c.u) { }
|
||||||
|
Color32(uint8 R, uint8 G, uint8 B) { setRGBA(R, G, B, 0xFF); }
|
||||||
|
Color32(uint8 R, uint8 G, uint8 B, uint8 A) { setRGBA( R, G, B, A); }
|
||||||
|
//Color32(uint8 c[4]) { setRGBA(c[0], c[1], c[2], c[3]); }
|
||||||
|
//Color32(float R, float G, float B) { setRGBA(uint(R*255), uint(G*255), uint(B*255), 0xFF); }
|
||||||
|
//Color32(float R, float G, float B, float A) { setRGBA(uint(R*255), uint(G*255), uint(B*255), uint(A*255)); }
|
||||||
|
explicit Color32(uint32 U) : u(U) { }
|
||||||
|
|
||||||
|
void setRGBA(uint8 R, uint8 G, uint8 B, uint8 A)
|
||||||
|
{
|
||||||
|
r = R;
|
||||||
|
g = G;
|
||||||
|
b = B;
|
||||||
|
a = A;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBGRA(uint8 B, uint8 G, uint8 R, uint8 A = 0xFF)
|
||||||
|
{
|
||||||
|
r = R;
|
||||||
|
g = G;
|
||||||
|
b = B;
|
||||||
|
a = A;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator uint32 () const {
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
#if NV_LITTLE_ENDIAN
|
||||||
|
uint8 b, g, r, a;
|
||||||
|
#else
|
||||||
|
uint8 a: 8;
|
||||||
|
uint8 r: 8;
|
||||||
|
uint8 g: 8;
|
||||||
|
uint8 b: 8;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
uint8 component[4];
|
||||||
|
uint32 u;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// 16 bit 565 BGR color.
|
||||||
|
class NVMATH_CLASS Color16
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Color16() { }
|
||||||
|
Color16(const Color16 & c) : u(c.u) { }
|
||||||
|
explicit Color16(uint16 U) : u(U) { }
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
#if NV_LITTLE_ENDIAN
|
||||||
|
uint16 b : 5;
|
||||||
|
uint16 g : 6;
|
||||||
|
uint16 r : 5;
|
||||||
|
#else
|
||||||
|
uint16 r : 5;
|
||||||
|
uint16 g : 6;
|
||||||
|
uint16 b : 5;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
uint16 u;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 16 bit 4444 BGRA color.
|
||||||
|
class NVMATH_CLASS Color16_4444
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Color16_4444() { }
|
||||||
|
Color16_4444(const Color16_4444 & c) : u(c.u) { }
|
||||||
|
explicit Color16_4444(uint16 U) : u(U) { }
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
#if NV_LITTLE_ENDIAN
|
||||||
|
uint16 b : 4;
|
||||||
|
uint16 g : 4;
|
||||||
|
uint16 r : 4;
|
||||||
|
uint16 a : 4;
|
||||||
|
#else
|
||||||
|
uint16 a : 4;
|
||||||
|
uint16 r : 4;
|
||||||
|
uint16 g : 4;
|
||||||
|
uint16 b : 4;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
uint16 u;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_MATH_COLOR_H
|
|
@ -0,0 +1,120 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#include "ConvexHull.h"
|
||||||
|
|
||||||
|
#include "Vector.inl"
|
||||||
|
|
||||||
|
#include "nvcore/RadixSort.h"
|
||||||
|
#include "nvcore/Array.inl"
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
inline static float triangleArea(Vector2::Arg v1, Vector2::Arg v2, Vector2::Arg v3)
|
||||||
|
{
|
||||||
|
return 0.5f * (v3.x * v1.y + v1.x * v2.y + v2.x * v3.y - v2.x * v1.y - v3.x * v2.y - v1.x * v3.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Compute the convex hull using Graham Scan.
|
||||||
|
void nv::convexHull(const Array<Vector2> & input, Array<Vector2> & output, float epsilon/*=0*/)
|
||||||
|
{
|
||||||
|
const uint inputCount = input.count();
|
||||||
|
|
||||||
|
Array<float> coords;
|
||||||
|
coords.resize(inputCount);
|
||||||
|
|
||||||
|
for (uint i = 0; i < inputCount; i++) {
|
||||||
|
coords[i] = input[i].x;
|
||||||
|
}
|
||||||
|
|
||||||
|
RadixSort radix;
|
||||||
|
radix.sort(coords);
|
||||||
|
|
||||||
|
const uint * ranks = radix.ranks();
|
||||||
|
|
||||||
|
Array<Vector2> top(inputCount);
|
||||||
|
Array<Vector2> bottom(inputCount);
|
||||||
|
|
||||||
|
Vector2 P = input[ranks[0]];
|
||||||
|
Vector2 Q = input[ranks[inputCount-1]];
|
||||||
|
|
||||||
|
float topy = max(P.y, Q.y);
|
||||||
|
float boty = min(P.y, Q.y);
|
||||||
|
|
||||||
|
for (uint i = 0; i < inputCount; i++) {
|
||||||
|
Vector2 p = input[ranks[i]];
|
||||||
|
if (p.y >= boty) top.append(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < inputCount; i++) {
|
||||||
|
Vector2 p = input[ranks[inputCount-1-i]];
|
||||||
|
if (p.y <= topy) bottom.append(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter top list.
|
||||||
|
output.clear();
|
||||||
|
output.append(top[0]);
|
||||||
|
output.append(top[1]);
|
||||||
|
|
||||||
|
for (uint i = 2; i < top.count(); ) {
|
||||||
|
Vector2 a = output[output.count()-2];
|
||||||
|
Vector2 b = output[output.count()-1];
|
||||||
|
Vector2 c = top[i];
|
||||||
|
|
||||||
|
float area = triangleArea(a, b, c);
|
||||||
|
|
||||||
|
if (area >= -epsilon) {
|
||||||
|
output.popBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area < -epsilon || output.count() == 1) {
|
||||||
|
output.append(c);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint top_count = output.count();
|
||||||
|
output.append(bottom[1]);
|
||||||
|
|
||||||
|
// Filter bottom list.
|
||||||
|
for (uint i = 2; i < bottom.count(); ) {
|
||||||
|
Vector2 a = output[output.count()-2];
|
||||||
|
Vector2 b = output[output.count()-1];
|
||||||
|
Vector2 c = bottom[i];
|
||||||
|
|
||||||
|
float area = triangleArea(a, b, c);
|
||||||
|
|
||||||
|
if (area >= -epsilon) {
|
||||||
|
output.popBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area < -epsilon || output.count() == top_count) {
|
||||||
|
output.append(c);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicate element.
|
||||||
|
nvDebugCheck(output.front() == output.back());
|
||||||
|
output.popBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void testConvexHull() {
|
||||||
|
|
||||||
|
Array<Vector2> points;
|
||||||
|
points.append(Vector2(1.00, 1.00));
|
||||||
|
points.append(Vector2(0.00, 0.00));
|
||||||
|
points.append(Vector2(1.00, 1.00));
|
||||||
|
points.append(Vector2(1.00, -1.00));
|
||||||
|
points.append(Vector2(2.00, 5.00));
|
||||||
|
points.append(Vector2(-5.00, 3.00));
|
||||||
|
points.append(Vector2(-4.00, -3.00));
|
||||||
|
points.append(Vector2(7.00, -4.00));
|
||||||
|
|
||||||
|
Array<Vector2> hull;
|
||||||
|
convexHull(points, hull);
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_CONVEXHULL_H
|
||||||
|
#define NV_MATH_CONVEXHULL_H
|
||||||
|
|
||||||
|
#include "nvmath.h"
|
||||||
|
#include "nvcore/Array.h"
|
||||||
|
|
||||||
|
namespace nv {
|
||||||
|
class Vector2;
|
||||||
|
|
||||||
|
void convexHull(const Array<Vector2> & input, Array<Vector2> & output, float epsilon = 0);
|
||||||
|
|
||||||
|
} // namespace nv
|
||||||
|
|
||||||
|
#endif // NV_MATH_CONVEXHULL_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,50 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_FITTING_H
|
||||||
|
#define NV_MATH_FITTING_H
|
||||||
|
|
||||||
|
#include "Vector.h"
|
||||||
|
#include "Plane.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
namespace Fit
|
||||||
|
{
|
||||||
|
Vector3 computeCentroid(int n, const Vector3 * points);
|
||||||
|
Vector3 computeCentroid(int n, const Vector3 * points, const float * weights, const Vector3 & metric);
|
||||||
|
|
||||||
|
Vector4 computeCentroid(int n, const Vector4 * points);
|
||||||
|
Vector4 computeCentroid(int n, const Vector4 * points, const float * weights, const Vector4 & metric);
|
||||||
|
|
||||||
|
Vector3 computeCovariance(int n, const Vector3 * points, float * covariance);
|
||||||
|
Vector3 computeCovariance(int n, const Vector3 * points, const float * weights, const Vector3 & metric, float * covariance);
|
||||||
|
|
||||||
|
Vector4 computeCovariance(int n, const Vector4 * points, float * covariance);
|
||||||
|
Vector4 computeCovariance(int n, const Vector4 * points, const float * weights, const Vector4 & metric, float * covariance);
|
||||||
|
|
||||||
|
Vector3 computePrincipalComponent_PowerMethod(int n, const Vector3 * points);
|
||||||
|
Vector3 computePrincipalComponent_PowerMethod(int n, const Vector3 * points, const float * weights, const Vector3 & metric);
|
||||||
|
|
||||||
|
Vector3 computePrincipalComponent_EigenSolver(int n, const Vector3 * points);
|
||||||
|
Vector3 computePrincipalComponent_EigenSolver(int n, const Vector3 * points, const float * weights, const Vector3 & metric);
|
||||||
|
|
||||||
|
Vector4 computePrincipalComponent_EigenSolver(int n, const Vector4 * points);
|
||||||
|
Vector4 computePrincipalComponent_EigenSolver(int n, const Vector4 * points, const float * weights, const Vector4 & metric);
|
||||||
|
|
||||||
|
Vector3 computePrincipalComponent_SVD(int n, const Vector3 * points);
|
||||||
|
Vector4 computePrincipalComponent_SVD(int n, const Vector4 * points);
|
||||||
|
|
||||||
|
Plane bestPlane(int n, const Vector3 * points);
|
||||||
|
bool isPlanar(int n, const Vector3 * points, float epsilon = NV_EPSILON);
|
||||||
|
|
||||||
|
bool eigenSolveSymmetric3(const float matrix[6], float eigenValues[3], Vector3 eigenVectors[3]);
|
||||||
|
bool eigenSolveSymmetric4(const float matrix[10], float eigenValues[4], Vector4 eigenVectors[4]);
|
||||||
|
|
||||||
|
// Returns number of clusters [1-4].
|
||||||
|
int compute4Means(int n, const Vector3 * points, const float * weights, const Vector3 & metric, Vector3 * cluster);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_MATH_FITTING_H
|
|
@ -0,0 +1,39 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_KAHANSUM_H
|
||||||
|
#define NV_MATH_KAHANSUM_H
|
||||||
|
|
||||||
|
#include "nvmath.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
class KahanSum
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KahanSum() : accum(0.0f), err(0) {};
|
||||||
|
|
||||||
|
void add(float f)
|
||||||
|
{
|
||||||
|
float compensated = f + err;
|
||||||
|
float tmp = accum + compensated;
|
||||||
|
err = accum - tmp;
|
||||||
|
err += compensated;
|
||||||
|
accum = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sum() const
|
||||||
|
{
|
||||||
|
return accum;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float accum;
|
||||||
|
float err;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NV_MATH_KAHANSUM_H
|
|
@ -0,0 +1,441 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#include "Matrix.inl"
|
||||||
|
#include "Vector.inl"
|
||||||
|
|
||||||
|
#include "nvcore/Array.inl"
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
#if !NV_CC_MSVC && !NV_OS_ORBIS
|
||||||
|
#include <alloca.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace nv;
|
||||||
|
|
||||||
|
|
||||||
|
// Given a matrix a[1..n][1..n], this routine replaces it by the LU decomposition of a rowwise
|
||||||
|
// permutation of itself. a and n are input. a is output, arranged as in equation (2.3.14) above;
|
||||||
|
// indx[1..n] is an output vector that records the row permutation effected by the partial
|
||||||
|
// pivoting; d is output as -1 depending on whether the number of row interchanges was even
|
||||||
|
// or odd, respectively. This routine is used in combination with lubksb to solve linear equations
|
||||||
|
// or invert a matrix.
|
||||||
|
static bool ludcmp(float **a, int n, int *indx, float *d)
|
||||||
|
{
|
||||||
|
const float TINY = 1.0e-20f;
|
||||||
|
|
||||||
|
float * vv = (float*)alloca(sizeof(float) * n); // vv stores the implicit scaling of each row.
|
||||||
|
|
||||||
|
*d = 1.0; // No row interchanges yet.
|
||||||
|
for (int i = 0; i < n; i++) { // Loop over rows to get the implicit scaling information.
|
||||||
|
|
||||||
|
float big = 0.0;
|
||||||
|
for (int j = 0; j < n; j++) {
|
||||||
|
big = max(big, fabsf(a[i][j]));
|
||||||
|
}
|
||||||
|
if (big == 0) {
|
||||||
|
return false; // Singular matrix
|
||||||
|
}
|
||||||
|
|
||||||
|
// No nonzero largest element.
|
||||||
|
vv[i] = 1.0f / big; // Save the scaling.
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < n; j++) { // This is the loop over columns of Crout's method.
|
||||||
|
for (int i = 0; i < j; i++) { // This is equation (2.3.12) except for i = j.
|
||||||
|
float sum = a[i][j];
|
||||||
|
for (int k = 0; k < i; k++) sum -= a[i][k]*a[k][j];
|
||||||
|
a[i][j] = sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
int imax = -1;
|
||||||
|
float big = 0.0; // Initialize for the search for largest pivot element.
|
||||||
|
for (int i = j; i < n; i++) { // This is i = j of equation (2.3.12) and i = j+ 1 : : : N
|
||||||
|
float sum = a[i][j]; // of equation (2.3.13).
|
||||||
|
for (int k = 0; k < j; k++) {
|
||||||
|
sum -= a[i][k]*a[k][j];
|
||||||
|
}
|
||||||
|
a[i][j]=sum;
|
||||||
|
|
||||||
|
float dum = vv[i]*fabs(sum);
|
||||||
|
if (dum >= big) {
|
||||||
|
// Is the figure of merit for the pivot better than the best so far?
|
||||||
|
big = dum;
|
||||||
|
imax = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nvDebugCheck(imax != -1);
|
||||||
|
|
||||||
|
if (j != imax) { // Do we need to interchange rows?
|
||||||
|
for (int k = 0; k < n; k++) { // Yes, do so...
|
||||||
|
swap(a[imax][k], a[j][k]);
|
||||||
|
}
|
||||||
|
*d = -(*d); // ...and change the parity of d.
|
||||||
|
vv[imax]=vv[j]; // Also interchange the scale factor.
|
||||||
|
}
|
||||||
|
|
||||||
|
indx[j]=imax;
|
||||||
|
if (a[j][j] == 0.0) a[j][j] = TINY;
|
||||||
|
|
||||||
|
// If the pivot element is zero the matrix is singular (at least to the precision of the
|
||||||
|
// algorithm). For some applications on singular matrices, it is desirable to substitute
|
||||||
|
// TINY for zero.
|
||||||
|
if (j != n-1) { // Now, finally, divide by the pivot element.
|
||||||
|
float dum = 1.0f / a[j][j];
|
||||||
|
for (int i = j+1; i < n; i++) a[i][j] *= dum;
|
||||||
|
}
|
||||||
|
} // Go back for the next column in the reduction.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Solves the set of n linear equations Ax = b. Here a[1..n][1..n] is input, not as the matrix
|
||||||
|
// A but rather as its LU decomposition, determined by the routine ludcmp. indx[1..n] is input
|
||||||
|
// as the permutation vector returned by ludcmp. b[1..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.
|
||||||
|
static void lubksb(float **a, int n, int *indx, float b[])
|
||||||
|
{
|
||||||
|
int ii = 0;
|
||||||
|
for (int i=0; i<n; i++) { // When ii is set to a positive value, it will become
|
||||||
|
int ip = indx[i]; // the index of the first nonvanishing element of b. We now
|
||||||
|
float sum = b[ip]; // do the forward substitution, equation (2.3.6). The
|
||||||
|
b[ip] = b[i]; // only new wrinkle is to unscramble the permutation as we go.
|
||||||
|
if (ii != 0) {
|
||||||
|
for (int j = ii-1; j < i; j++) sum -= a[i][j]*b[j];
|
||||||
|
}
|
||||||
|
else if (sum != 0.0f) {
|
||||||
|
ii = i+1; // A nonzero element was encountered, so from now on we
|
||||||
|
}
|
||||||
|
b[i] = sum; // will have to do the sums in the loop above.
|
||||||
|
}
|
||||||
|
for (int i=n-1; i>=0; i--) { // Now we do the backsubstitution, equation (2.3.7).
|
||||||
|
float sum = b[i];
|
||||||
|
for (int j = i+1; j < n; j++) {
|
||||||
|
sum -= a[i][j]*b[j];
|
||||||
|
}
|
||||||
|
b[i] = sum/a[i][i]; // Store a component of the solution vector X.
|
||||||
|
} // All done!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool nv::solveLU(const Matrix & A, const Vector4 & b, Vector4 * x)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x != NULL);
|
||||||
|
|
||||||
|
float m[4][4];
|
||||||
|
float *a[4] = {m[0], m[1], m[2], m[3]};
|
||||||
|
int idx[4];
|
||||||
|
float d;
|
||||||
|
|
||||||
|
for (int y = 0; y < 4; y++) {
|
||||||
|
for (int x = 0; x < 4; x++) {
|
||||||
|
a[x][y] = A(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create LU decomposition.
|
||||||
|
if (!ludcmp(a, 4, idx, &d)) {
|
||||||
|
// Singular matrix.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init solution.
|
||||||
|
*x = b;
|
||||||
|
|
||||||
|
// Do back substitution.
|
||||||
|
lubksb(a, 4, idx, x->component);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@ Not tested.
|
||||||
|
Matrix nv::inverseLU(const Matrix & A)
|
||||||
|
{
|
||||||
|
Vector4 Ai[4];
|
||||||
|
|
||||||
|
solveLU(A, Vector4(1, 0, 0, 0), &Ai[0]);
|
||||||
|
solveLU(A, Vector4(0, 1, 0, 0), &Ai[1]);
|
||||||
|
solveLU(A, Vector4(0, 0, 1, 0), &Ai[2]);
|
||||||
|
solveLU(A, Vector4(0, 0, 0, 1), &Ai[3]);
|
||||||
|
|
||||||
|
return Matrix(Ai[0], Ai[1], Ai[2], Ai[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool nv::solveLU(const Matrix3 & A, const Vector3 & b, Vector3 * x)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x != NULL);
|
||||||
|
|
||||||
|
float m[3][3];
|
||||||
|
float *a[3] = {m[0], m[1], m[2]};
|
||||||
|
int idx[3];
|
||||||
|
float d;
|
||||||
|
|
||||||
|
for (int y = 0; y < 3; y++) {
|
||||||
|
for (int x = 0; x < 3; x++) {
|
||||||
|
a[x][y] = A(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create LU decomposition.
|
||||||
|
if (!ludcmp(a, 3, idx, &d)) {
|
||||||
|
// Singular matrix.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init solution.
|
||||||
|
*x = b;
|
||||||
|
|
||||||
|
// Do back substitution.
|
||||||
|
lubksb(a, 3, idx, x->component);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool nv::solveCramer(const Matrix & A, const Vector4 & b, Vector4 * x)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x != NULL);
|
||||||
|
|
||||||
|
*x = transform(inverseCramer(A), b);
|
||||||
|
|
||||||
|
return true; // @@ Return false if determinant(A) == 0 !
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::solveCramer(const Matrix3 & A, const Vector3 & b, Vector3 * x)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x != NULL);
|
||||||
|
|
||||||
|
const float det = A.determinant();
|
||||||
|
if (equal(det, 0.0f)) { // @@ Use input epsilon.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix3 Ai = inverseCramer(A);
|
||||||
|
|
||||||
|
*x = transform(Ai, b);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Inverse using gaussian elimination. From Jon's code.
|
||||||
|
Matrix nv::inverse(const Matrix & m) {
|
||||||
|
|
||||||
|
Matrix A = m;
|
||||||
|
Matrix B(identity);
|
||||||
|
|
||||||
|
int i, j, k;
|
||||||
|
float max, t, det, pivot;
|
||||||
|
|
||||||
|
det = 1.0;
|
||||||
|
for (i=0; i<4; i++) { /* eliminate in column i, below diag */
|
||||||
|
max = -1.;
|
||||||
|
for (k=i; k<4; k++) /* find pivot for column i */
|
||||||
|
if (fabs(A(k, i)) > max) {
|
||||||
|
max = fabs(A(k, i));
|
||||||
|
j = k;
|
||||||
|
}
|
||||||
|
if (max<=0.) return B; /* if no nonzero pivot, PUNT */
|
||||||
|
if (j!=i) { /* swap rows i and j */
|
||||||
|
for (k=i; k<4; k++)
|
||||||
|
swap(A(i, k), A(j, k));
|
||||||
|
for (k=0; k<4; k++)
|
||||||
|
swap(B(i, k), B(j, k));
|
||||||
|
det = -det;
|
||||||
|
}
|
||||||
|
pivot = A(i, i);
|
||||||
|
det *= pivot;
|
||||||
|
for (k=i+1; k<4; k++) /* only do elems to right of pivot */
|
||||||
|
A(i, k) /= pivot;
|
||||||
|
for (k=0; k<4; k++)
|
||||||
|
B(i, k) /= pivot;
|
||||||
|
/* we know that A(i, i) will be set to 1, so don't bother to do it */
|
||||||
|
|
||||||
|
for (j=i+1; j<4; j++) { /* eliminate in rows below i */
|
||||||
|
t = A(j, i); /* we're gonna zero this guy */
|
||||||
|
for (k=i+1; k<4; k++) /* subtract scaled row i from row j */
|
||||||
|
A(j, k) -= A(i, k)*t; /* (ignore k<=i, we know they're 0) */
|
||||||
|
for (k=0; k<4; k++)
|
||||||
|
B(j, k) -= B(i, k)*t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------- backward elimination ----------*/
|
||||||
|
|
||||||
|
for (i=4-1; i>0; i--) { /* eliminate in column i, above diag */
|
||||||
|
for (j=0; j<i; j++) { /* eliminate in rows above i */
|
||||||
|
t = A(j, i); /* we're gonna zero this guy */
|
||||||
|
for (k=0; k<4; k++) /* subtract scaled row i from row j */
|
||||||
|
B(j, k) -= B(i, k)*t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Matrix3 nv::inverse(const Matrix3 & m) {
|
||||||
|
|
||||||
|
Matrix3 A = m;
|
||||||
|
Matrix3 B(identity);
|
||||||
|
|
||||||
|
int i, j, k;
|
||||||
|
float max, t, det, pivot;
|
||||||
|
|
||||||
|
det = 1.0;
|
||||||
|
for (i=0; i<3; i++) { /* eliminate in column i, below diag */
|
||||||
|
max = -1.;
|
||||||
|
for (k=i; k<3; k++) /* find pivot for column i */
|
||||||
|
if (fabs(A(k, i)) > max) {
|
||||||
|
max = fabs(A(k, i));
|
||||||
|
j = k;
|
||||||
|
}
|
||||||
|
if (max<=0.) return B; /* if no nonzero pivot, PUNT */
|
||||||
|
if (j!=i) { /* swap rows i and j */
|
||||||
|
for (k=i; k<3; k++)
|
||||||
|
swap(A(i, k), A(j, k));
|
||||||
|
for (k=0; k<3; k++)
|
||||||
|
swap(B(i, k), B(j, k));
|
||||||
|
det = -det;
|
||||||
|
}
|
||||||
|
pivot = A(i, i);
|
||||||
|
det *= pivot;
|
||||||
|
for (k=i+1; k<3; k++) /* only do elems to right of pivot */
|
||||||
|
A(i, k) /= pivot;
|
||||||
|
for (k=0; k<3; k++)
|
||||||
|
B(i, k) /= pivot;
|
||||||
|
/* we know that A(i, i) will be set to 1, so don't bother to do it */
|
||||||
|
|
||||||
|
for (j=i+1; j<3; j++) { /* eliminate in rows below i */
|
||||||
|
t = A(j, i); /* we're gonna zero this guy */
|
||||||
|
for (k=i+1; k<3; k++) /* subtract scaled row i from row j */
|
||||||
|
A(j, k) -= A(i, k)*t; /* (ignore k<=i, we know they're 0) */
|
||||||
|
for (k=0; k<3; k++)
|
||||||
|
B(j, k) -= B(i, k)*t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------- backward elimination ----------*/
|
||||||
|
|
||||||
|
for (i=3-1; i>0; i--) { /* eliminate in column i, above diag */
|
||||||
|
for (j=0; j<i; j++) { /* eliminate in rows above i */
|
||||||
|
t = A(j, i); /* we're gonna zero this guy */
|
||||||
|
for (k=0; k<3; k++) /* subtract scaled row i from row j */
|
||||||
|
B(j, k) -= B(i, k)*t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
// Copyright (C) 1999-2004 Michael Garland.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, provided that the above
|
||||||
|
// copyright notice(s) and this permission notice appear in all copies of
|
||||||
|
// the Software and that both the above copyright notice(s) and this
|
||||||
|
// permission notice appear in supporting documentation.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||||
|
// HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
|
||||||
|
// INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
|
||||||
|
// FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
//
|
||||||
|
// Except as contained in this notice, the name of a copyright holder
|
||||||
|
// shall not be used in advertising or otherwise to promote the sale, use
|
||||||
|
// or other dealings in this Software without prior written authorization
|
||||||
|
// of the copyright holder.
|
||||||
|
|
||||||
|
|
||||||
|
// Matrix inversion code for 4x4 matrices using Gaussian elimination
|
||||||
|
// with partial pivoting. This is a specialized version of a
|
||||||
|
// procedure originally due to Paul Heckbert <ph@cs.cmu.edu>.
|
||||||
|
//
|
||||||
|
// Returns determinant of A, and B=inverse(A)
|
||||||
|
// If matrix A is singular, returns 0 and leaves trash in B.
|
||||||
|
//
|
||||||
|
#define SWAP(a, b, t) {t = a; a = b; b = t;}
|
||||||
|
double invert(Mat4& B, const Mat4& m)
|
||||||
|
{
|
||||||
|
Mat4 A = m;
|
||||||
|
int i, j, k;
|
||||||
|
double max, t, det, pivot;
|
||||||
|
|
||||||
|
/*---------- forward elimination ----------*/
|
||||||
|
|
||||||
|
for (i=0; i<4; i++) /* put identity matrix in B */
|
||||||
|
for (j=0; j<4; j++)
|
||||||
|
B(i, j) = (double)(i==j);
|
||||||
|
|
||||||
|
det = 1.0;
|
||||||
|
for (i=0; i<4; i++) { /* eliminate in column i, below diag */
|
||||||
|
max = -1.;
|
||||||
|
for (k=i; k<4; k++) /* find pivot for column i */
|
||||||
|
if (fabs(A(k, i)) > max) {
|
||||||
|
max = fabs(A(k, i));
|
||||||
|
j = k;
|
||||||
|
}
|
||||||
|
if (max<=0.) return 0.; /* if no nonzero pivot, PUNT */
|
||||||
|
if (j!=i) { /* swap rows i and j */
|
||||||
|
for (k=i; k<4; k++)
|
||||||
|
SWAP(A(i, k), A(j, k), t);
|
||||||
|
for (k=0; k<4; k++)
|
||||||
|
SWAP(B(i, k), B(j, k), t);
|
||||||
|
det = -det;
|
||||||
|
}
|
||||||
|
pivot = A(i, i);
|
||||||
|
det *= pivot;
|
||||||
|
for (k=i+1; k<4; k++) /* only do elems to right of pivot */
|
||||||
|
A(i, k) /= pivot;
|
||||||
|
for (k=0; k<4; k++)
|
||||||
|
B(i, k) /= pivot;
|
||||||
|
/* we know that A(i, i) will be set to 1, so don't bother to do it */
|
||||||
|
|
||||||
|
for (j=i+1; j<4; j++) { /* eliminate in rows below i */
|
||||||
|
t = A(j, i); /* we're gonna zero this guy */
|
||||||
|
for (k=i+1; k<4; k++) /* subtract scaled row i from row j */
|
||||||
|
A(j, k) -= A(i, k)*t; /* (ignore k<=i, we know they're 0) */
|
||||||
|
for (k=0; k<4; k++)
|
||||||
|
B(j, k) -= B(i, k)*t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------- backward elimination ----------*/
|
||||||
|
|
||||||
|
for (i=4-1; i>0; i--) { /* eliminate in column i, above diag */
|
||||||
|
for (j=0; j<i; j++) { /* eliminate in rows above i */
|
||||||
|
t = A(j, i); /* we're gonna zero this guy */
|
||||||
|
for (k=0; k<4; k++) /* subtract scaled row i from row j */
|
||||||
|
B(j, k) -= B(i, k)*t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return det;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_MATH_MATRIX_H
|
||||||
|
#define NV_MATH_MATRIX_H
|
||||||
|
|
||||||
|
#include "Vector.h"
|
||||||
|
|
||||||
|
// - Matrices are stored in memory in *column major* order.
|
||||||
|
// - Points are to be though of as column vectors.
|
||||||
|
// - Transformation of a point p by a matrix M is: p' = M * p
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
enum identity_t { identity };
|
||||||
|
|
||||||
|
// 3x3 matrix.
|
||||||
|
class NVMATH_CLASS Matrix3
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Matrix3();
|
||||||
|
explicit Matrix3(float f);
|
||||||
|
explicit Matrix3(identity_t);
|
||||||
|
Matrix3(const Matrix3 & m);
|
||||||
|
Matrix3(Vector3::Arg v0, Vector3::Arg v1, Vector3::Arg v2);
|
||||||
|
|
||||||
|
float data(uint idx) const;
|
||||||
|
float & data(uint idx);
|
||||||
|
float get(uint row, uint col) const;
|
||||||
|
float operator()(uint row, uint col) const;
|
||||||
|
float & operator()(uint row, uint col);
|
||||||
|
|
||||||
|
Vector3 row(uint i) const;
|
||||||
|
Vector3 column(uint i) const;
|
||||||
|
|
||||||
|
void operator*=(float s);
|
||||||
|
void operator/=(float s);
|
||||||
|
void operator+=(const Matrix3 & m);
|
||||||
|
void operator-=(const Matrix3 & m);
|
||||||
|
|
||||||
|
void scale(float s);
|
||||||
|
void scale(Vector3::Arg s);
|
||||||
|
float determinant() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_data[9];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Solve equation system using LU decomposition and back-substitution.
|
||||||
|
extern bool solveLU(const Matrix3 & m, const Vector3 & b, Vector3 * x);
|
||||||
|
|
||||||
|
// Solve equation system using Cramer's inverse.
|
||||||
|
extern bool solveCramer(const Matrix3 & A, const Vector3 & b, Vector3 * x);
|
||||||
|
|
||||||
|
|
||||||
|
// 4x4 matrix.
|
||||||
|
class NVMATH_CLASS Matrix
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Matrix const & Arg;
|
||||||
|
|
||||||
|
Matrix();
|
||||||
|
explicit Matrix(float f);
|
||||||
|
explicit Matrix(identity_t);
|
||||||
|
Matrix(const Matrix3 & m);
|
||||||
|
Matrix(const Matrix & m);
|
||||||
|
Matrix(Vector4::Arg v0, Vector4::Arg v1, Vector4::Arg v2, Vector4::Arg v3);
|
||||||
|
//explicit Matrix(const float m[]); // m is assumed to contain 16 elements
|
||||||
|
|
||||||
|
float data(uint idx) const;
|
||||||
|
float & data(uint idx);
|
||||||
|
float get(uint row, uint col) const;
|
||||||
|
float operator()(uint row, uint col) const;
|
||||||
|
float & operator()(uint row, uint col);
|
||||||
|
const float * ptr() const;
|
||||||
|
|
||||||
|
Vector4 row(uint i) const;
|
||||||
|
Vector4 column(uint i) const;
|
||||||
|
|
||||||
|
void zero();
|
||||||
|
void identity();
|
||||||
|
|
||||||
|
void scale(float s);
|
||||||
|
void scale(Vector3::Arg s);
|
||||||
|
void translate(Vector3::Arg t);
|
||||||
|
void rotate(float theta, float v0, float v1, float v2);
|
||||||
|
float determinant() const;
|
||||||
|
|
||||||
|
void operator+=(const Matrix & m);
|
||||||
|
void operator-=(const Matrix & m);
|
||||||
|
|
||||||
|
void apply(Matrix::Arg m);
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_data[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Solve equation system using LU decomposition and back-substitution.
|
||||||
|
extern bool solveLU(const Matrix & A, const Vector4 & b, Vector4 * x);
|
||||||
|
|
||||||
|
// Solve equation system using Cramer's inverse.
|
||||||
|
extern bool solveCramer(const Matrix & A, const Vector4 & b, Vector4 * x);
|
||||||
|
|
||||||
|
// Compute inverse using LU decomposition.
|
||||||
|
extern Matrix inverseLU(const Matrix & m);
|
||||||
|
|
||||||
|
// Compute inverse using Gaussian elimination and partial pivoting.
|
||||||
|
extern Matrix inverse(const Matrix & m);
|
||||||
|
extern Matrix3 inverse(const Matrix3 & m);
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_MATH_MATRIX_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue