Text archives Help
- From: abe@sci.utah.edu
- To: manta@sci.utah.edu
- Subject: [MANTA] r427 - in branches/itanium2: . Core Core/Geometry Engine/Control Engine/Display Interface Model/Groups Model/Materials Model/Primitives Model/Readers Model/Readers/glm StandAlone fox scenes
- Date: Sat, 9 Jul 2005 13:54:03 -0600 (MDT)
Author: abe
Date: Sat Jul 9 13:53:42 2005
New Revision: 427
Added:
branches/itanium2/Model/Groups/RealisticBvh.cc
branches/itanium2/Model/Groups/RealisticBvh.h
branches/itanium2/Model/Readers/glm/
branches/itanium2/Model/Readers/glm/glm.cc
branches/itanium2/Model/Readers/glm/glm.h
branches/itanium2/scenes/objviewer.cc
Modified:
branches/itanium2/CMakeLists.txt
branches/itanium2/Core/CMakeLists.txt
branches/itanium2/Core/Geometry/BBox.h
branches/itanium2/Core/Geometry/PointVector.cc
branches/itanium2/Core/Geometry/PointVector.h
branches/itanium2/Core/Geometry/Ray.h
branches/itanium2/Engine/Control/RTRT.cc
branches/itanium2/Engine/Display/CMakeLists.txt
branches/itanium2/Engine/Display/GLXImageDisplay.cc
branches/itanium2/Interface/Context.h
branches/itanium2/Interface/Material.h
branches/itanium2/Interface/Object.h
branches/itanium2/Interface/Primitive.h
branches/itanium2/Interface/RTRTInterface.h
branches/itanium2/Model/Groups/CMakeLists.txt
branches/itanium2/Model/Groups/kdtree.cc
branches/itanium2/Model/Groups/varray.h
branches/itanium2/Model/Materials/CMakeLists.txt
branches/itanium2/Model/Materials/Dielectric.cc
branches/itanium2/Model/Materials/Lambertian.cc
branches/itanium2/Model/Materials/Lambertian.h
branches/itanium2/Model/Primitives/PrimitiveCommon.h
branches/itanium2/Model/Primitives/Triangle.h
branches/itanium2/Model/Readers/CMakeLists.txt
branches/itanium2/StandAlone/manta.cc
branches/itanium2/StandAlone/manta_tile_size.pl
branches/itanium2/fox/CMakeLists.txt
branches/itanium2/fox/FMantaWindow.cc
branches/itanium2/fox/FMantaWindow.h
branches/itanium2/fox/fox_manta.cc
branches/itanium2/scenes/CMakeLists.txt
Log:
A scenes/objviewer.cc
M scenes/CMakeLists.txt
Added test scene which will load a wavefront obj file.
M Core/Geometry/BBox.h
M Core/Geometry/PointVector.cc
M Core/Geometry/Ray.h
M Core/Geometry/PointVector.h
Merged changes from trunk/Core/Geometry/
M Core/CMakeLists.txt
M StandAlone/manta_tile_size.pl
M StandAlone/manta.cc
Small changes to enable simple batch script benchmarking. Also added
benchmark script for tile sizes.
M fox/FMantaWindow.cc
M fox/FMantaWindow.h
M fox/fox_manta.cc
M fox/CMakeLists.txt
Incremental changes to demo viewer.
M Model/Primitives/Triangle.h
M Model/Primitives/PrimitiveCommon.h
M Interface/Material.h
M Interface/Context.h
M Interface/Object.h
M Interface/Primitive.h
M Interface/RTRTInterface.h
*** Removed unimplemented private copy constructors/operators.
I think I should be able to define a Manta Object and have the ability to
copy it.
M Model/Groups/kdtree.cc
Examined some performance issues with the kdtree code.
A Model/Groups/RealisticBvh.cc
A Model/Groups/RealisticBvh.h
Added a simple bvh implementation, based on that found in "Realistic Ray
Tracing"
M Model/Groups/varray.h
M Model/Groups/CMakeLists.txt
M Model/Materials/Dielectric.cc
M Model/Materials/Lambertian.cc
M Model/Materials/Lambertian.h
M Model/Materials/CMakeLists.txt
Removed LitPrimitive related code, activeLights etc. I think that this code
was broken after I implemented move-able lights.
A Model/Readers/glm
A Model/Readers/glm/glm.cc
A Model/Readers/glm/glm.h
Added Nate Robin's glm obj reader. This combined with changes that James and
I have made is a pretty complete implementation.
M Model/Readers/CMakeLists.txt
M Engine/Control/RTRT.cc
M Engine/Display/GLXImageDisplay.cc
Added some debugging code to the floating point framebuffer type. This is
used by the profiling package, which I haven't checked in yet.
M Engine/Display/CMakeLists.txt
M CMakeLists.txt
Modified: branches/itanium2/CMakeLists.txt
==============================================================================
--- branches/itanium2/CMakeLists.txt (original)
+++ branches/itanium2/CMakeLists.txt Sat Jul 9 13:53:42 2005
@@ -24,6 +24,7 @@
ENDIF(CMAKE_SYSTEM MATCHES IRIX)
+
IF (APPLE)
SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -g -fgcse-sm -funroll-loops
-fstrict-aliasing -fsched-interblock -falign-loops=16 -falign-jumps=16
-falign-functions=16 -falign-jumps-max-skip=15 -falign-loops-max-skip=15
-ffast-math -freorder-blocks -mpowerpc-gpopt -force_cpusubtype_ALL -mtune=G5
-mcpu=G5 -mpowerpc64 -faltivec -mabi=altivec -mpowerpc-gfxopt" CACHE STRING
"Optimized Flags" FORCE)
ENDIF (APPLE)
@@ -57,9 +58,18 @@
SUBDIRS(glfw)
ENDIF(BUILD_GLFW)
+# Check to see whether the histx performance monitoring tools should
+# be built on IA64.
+SET(BUILD_HISTX_MANTA 0 CACHE BOOL "Build Histx-Manta tools")
+IF(BUILD_HISTX_MANTA)
+ SUBDIRS(histx)
+ENDIF(BUILD_HISTX_MANTA)
+
# Check to see whether the optional fox/ directory should be included.
SET(BUILD_FOX 0 CACHE BOOL "Build fox frontend.")
IF(BUILD_FOX)
SUBDIRS(fox)
ENDIF(BUILD_FOX)
+
+
Modified: branches/itanium2/Core/CMakeLists.txt
==============================================================================
--- branches/itanium2/Core/CMakeLists.txt (original)
+++ branches/itanium2/Core/CMakeLists.txt Sat Jul 9 13:53:42 2005
@@ -8,6 +8,7 @@
SET (CORE_SOURCES ${CORE_SOURCES}
Geometry/PointVector.h
Geometry/PointVector.cc
+ Geometry/BBox.h
)
SET (CORE_SOURCES ${CORE_SOURCES}
Exceptions/BadPrimitive.h
Modified: branches/itanium2/Core/Geometry/BBox.h
==============================================================================
--- branches/itanium2/Core/Geometry/BBox.h (original)
+++ branches/itanium2/Core/Geometry/BBox.h Sat Jul 9 13:53:42 2005
@@ -4,6 +4,12 @@
#include <SCIRun/Core/Math/MiscMath.h>
+#include <sgi_stl_warnings_off.h>
+#include <limits>
+#include <sgi_stl_warnings_on.h>
+
+#include <assert.h>
+
namespace Manta {
class BBox {
public:
@@ -13,9 +19,21 @@
bounds[0] = min_;
bounds[1] = max_;
}
- BBox() { }
- ~BBox() { }
-
+ BBox() {
+ // Need to initialize min and max.
+ reset();
+ }
+ ~BBox() {
+ }
+
+ // This resets min and max to an uninitialized state that will
+ // accept new bounds [MAX, -MAX].
+ void reset() {
+ Real max_val = std::numeric_limits<Real>::max();
+ bounds[0] = Point( max_val, max_val, max_val);
+ bounds[1] = Point(-max_val, -max_val, -max_val);
+ }
+
Vector diagonal() const {
return bounds[1] - bounds[0];
}
@@ -33,7 +51,7 @@
void extendByPoint(const PointT<T,3>& p) {
bounds[0] = Min(bounds[0],
Point((Point::ScalarType)p[0],(Point::ScalarType)p[1],(Point::ScalarType)p[2]));
bounds[1] = Max(bounds[1],
Point((Point::ScalarType)p[0],(Point::ScalarType)p[1],(Point::ScalarType)p[2]));
- }
+ }
void extendBySphere(const Point& p, Real radius) {
bounds[0] = Min(bounds[0], p-Vector(radius, radius, radius));
Modified: branches/itanium2/Core/Geometry/PointVector.cc
==============================================================================
--- branches/itanium2/Core/Geometry/PointVector.cc (original)
+++ branches/itanium2/Core/Geometry/PointVector.cc Sat Jul 9 13:53:42
2005
@@ -1,17 +1,20 @@
#include <Core/Geometry/PointVector.h>
+
+#include <sgi_stl_warnings_off.h>
#include <iostream>
+#include <sgi_stl_warnings_on.h>
namespace Manta {
template<typename T, int Dim>
- inline std::ostream &operator<< (std::ostream &os, const VectorT<T,Dim>
&v) {
+ std::ostream &operator<< (std::ostream &os, const VectorT<T,Dim> &v) {
for (int i=0;i<Dim;++i)
os << v[i] << " ";
return os;
}
template<typename T, int Dim>
- inline std::ostream &operator<< (std::ostream &os, const PointT<T,Dim> &v)
{
+ std::ostream &operator<< (std::ostream &os, const PointT<T,Dim> &v) {
for (int i=0;i<Dim;++i)
os << v[i] << " ";
return os;
Modified: branches/itanium2/Core/Geometry/PointVector.h
==============================================================================
--- branches/itanium2/Core/Geometry/PointVector.h (original)
+++ branches/itanium2/Core/Geometry/PointVector.h Sat Jul 9 13:53:42
2005
@@ -17,10 +17,14 @@
VectorT() {
}
+#ifndef SWIG
VectorT(T x, T y) {
+ typedef char unnamed[ Dim == 2 ? 1 : 0 ];
data[0] = x; data[1] = y;
}
+#endif
VectorT(T x, T y, T z) {
+ typedef char unnamed[ Dim == 3 ? 1 : 0 ];
data[0] = x; data[1] = y; data[2] = z;
}
@@ -36,12 +40,13 @@
data[i] = (T)copy[i];
}
- template< typename S >
- VectorT<T, Dim>& operator=(const VectorT<S, Dim>& copy) {
+#ifndef SWIG
+ VectorT<T, Dim>& operator=(const VectorT<T, Dim>& copy) {
for(int i=0;i<Dim;i++)
data[i] = (T)copy[i];
return *this;
}
+#endif
~VectorT() {
}
@@ -50,20 +55,30 @@
return data[0];
}
T y() const {
+ typedef char unnamed[ Dim >=2 ? 1 : 0 ];
return data[1];
}
T z() const {
+ typedef char unnamed[ Dim >= 3 ? 1 : 0 ];
return data[2];
}
+#ifndef SWIG
const T &operator[](int i) const {
return data[i];
}
T &operator[] ( int i ) {
return data[i];
- }
-
+ }
const T *operator &() const { return data; }
+#else
+ %extend {
+ T& __getitem__( int i ) {
+ return self->operator[](i);
+ }
+ }
+#endif
+
VectorT<T, Dim> operator+(const VectorT<T, Dim>& v) const {
VectorT<T, Dim> result;
for(int i=0;i<Dim;i++)
@@ -227,11 +242,14 @@
PointT() {
}
+#ifndef SWIG
PointT(T x, T y) {
- char unnamed[ Dim == 2 ? 1 : 0 ];
+ typedef char unnamed[ Dim == 2 ? 1 : 0 ];
data[0] = x; data[1] = y;
}
+#endif
PointT(T x, T y, T z) {
+ typedef char unnamed[ Dim == 3 ? 1 : 0 ];
data[0] = x; data[1] = y; data[2] = z;
}
@@ -245,13 +263,15 @@
for (int i=0;i<Dim;++i)
data[i] = copy[i];
}
-
+
+#ifndef SWIG
template< typename S >
PointT<T, Dim>& operator=(const PointT<S, Dim>& copy) {
for(int i=0;i<Dim;i++)
data[i] = (T)copy[i];
return *this;
}
+#endif
~PointT() {
}
@@ -263,8 +283,10 @@
return data[1];
}
T z() const {
+ typedef char unnamed[ Dim == 3 ? 1 : 0 ];
return data[2];
}
+#ifndef SWIG
T operator[](int i) const {
return data[i];
}
@@ -273,6 +295,13 @@
}
const T *operator& () const { return data; };
+#else
+ %extend {
+ T& __getitem__( int i ) {
+ return self->operator[](i);
+ }
+ }
+#endif
VectorT<T, Dim> operator-(const PointT<T, Dim>& p) const {
VectorT<T, Dim> result;
Modified: branches/itanium2/Core/Geometry/Ray.h
==============================================================================
--- branches/itanium2/Core/Geometry/Ray.h (original)
+++ branches/itanium2/Core/Geometry/Ray.h Sat Jul 9 13:53:42 2005
@@ -15,12 +15,14 @@
{
}
+#ifndef SWIG
Ray& operator=(const Ray& copy)
{
orig=copy.orig;
dir=copy.dir;
return *this;
}
+#endif
void set(const Point& origin, const Vector& direction)
{
Modified: branches/itanium2/Engine/Control/RTRT.cc
==============================================================================
--- branches/itanium2/Engine/Control/RTRT.cc (original)
+++ branches/itanium2/Engine/Control/RTRT.cc Sat Jul 9 13:53:42 2005
@@ -678,7 +678,7 @@
if(depth == 1 && context.getMaxDepth() > 1)
depth = 2; // Prefer double-buffering
- cerr << "RTRT::setupPipelines:: depth = "<< depth << "\n";
+ //cerr << "RTRT::setupPipelines:: depth = "<< depth << "\n";
// Set the pipeline depth.
channel->pipelineDepth = depth;
@@ -994,18 +994,18 @@
}
Scene* newScene = 0;
- std::cout << "Scene suffix: " << suffix << std::endl;
+ std::cerr << "Scene suffix: " << suffix << std::endl;
if((suffix == "mo") || (suffix == "so") || (suffix == "dylib")) {
// Do this twice - once silently and once printing errors
- std::cout << "Reading .mo or .so scene" << std::endl;
+ std::cerr << "Reading .mo or .so scene" << std::endl;
newScene = readMOScene(name, args, false);
if(!newScene)
readMOScene(name, args, true);
} else {
// Try reading it as an MO
- std::cout << "Appending .mo to scene" << std::endl;
+ std::cerr << "Appending .mo to scene" << std::endl;
newScene = readMOScene(name+".mo", args, false);
Modified: branches/itanium2/Engine/Display/CMakeLists.txt
==============================================================================
--- branches/itanium2/Engine/Display/CMakeLists.txt (original)
+++ branches/itanium2/Engine/Display/CMakeLists.txt Sat Jul 9 13:53:42
2005
@@ -10,6 +10,7 @@
Display/FileDisplay.cc
Display/GLXImageDisplay.h
Display/GLXImageDisplay.cc
-
+ Display/GLXMultipipeImageDisplay.h
+ Display/GLXMultipipeImageDisplay.cc
)
Modified: branches/itanium2/Engine/Display/GLXImageDisplay.cc
==============================================================================
--- branches/itanium2/Engine/Display/GLXImageDisplay.cc (original)
+++ branches/itanium2/Engine/Display/GLXImageDisplay.cc Sat Jul 9 13:53:42
2005
@@ -79,6 +79,7 @@
image->getResolution( stereo, xres, yres );
+
// This code is from OpenGLImageDisplay.
glViewport(0, 0, xres, yres);
glMatrixMode(GL_PROJECTION);
@@ -118,6 +119,34 @@
}
} else if(typeid(*image) ==
typeid(SimpleImage<RGBAfloatPixel>)){
const SimpleImage<RGBAfloatPixel>* si =
dynamic_cast<const SimpleImage<RGBAfloatPixel>*>(image);
+
+
+
///////////////////////////////////////////////////////////////////////////
+ // Assuming this is a performance image: normalize
the image values.
+ int total_size = xres * yres;
+ RGBAfloatPixel *pixel = si->getRaw(0);
+
+ float max_p, min_p;
+ max_p = min_p = pixel[0].r;
+
+ // Determine min and max.
+ for (int i=1;i<total_size;++i) {
+ if (pixel[i].r > max_p) max_p = pixel[i].r;
+ else if (pixel[i].r < min_p) min_p =
pixel[i].r;
+ }
+
+ // Determine scale and bias.
+ float scale = 1.0 / (max_p - min_p);
+
+ for (int i=0;i<total_size;++i) {
+ float v = (pixel[i].r - min_p) * scale;
+ pixel[i].r = pixel[i].g = pixel[i].b =
pixel[i].a = v;
+ }
+
+
///////////////////////////////////////////////////////////////////////////
+
+
+
if(stereo){
glDrawBuffer(GL_BACK_LEFT);
glRasterPos2i(0,0);
Modified: branches/itanium2/Interface/Context.h
==============================================================================
--- branches/itanium2/Interface/Context.h (original)
+++ branches/itanium2/Interface/Context.h Sat Jul 9 13:53:42 2005
@@ -164,6 +164,7 @@
};
class PreprocessContext {
public:
+ PreprocessContext() { }; // Lights are dynamic now. This
context isn't needed.
PreprocessContext(RTRTInterface* /*rtrt_int*/, LightSet* globalLights)
: globalLights(globalLights)
{
Modified: branches/itanium2/Interface/Material.h
==============================================================================
--- branches/itanium2/Interface/Material.h (original)
+++ branches/itanium2/Interface/Material.h Sat Jul 9 13:53:42 2005
@@ -18,8 +18,8 @@
virtual void preprocess(const PreprocessContext&) = 0;
virtual void shade(const RenderContext& context, RayPacket& rays) const
= 0;
private:
- Material(const Material&);
- Material& operator=(const Material&);
+ // Material(const Material&);
+ // Material& operator=(const Material&);
};
}
Modified: branches/itanium2/Interface/Object.h
==============================================================================
--- branches/itanium2/Interface/Object.h (original)
+++ branches/itanium2/Interface/Object.h Sat Jul 9 13:53:42 2005
@@ -3,6 +3,7 @@
#define Manta_Interface_Object_h
namespace Manta {
+
class BBox;
class PreprocessContext;
class RayPacket;
@@ -14,12 +15,11 @@
virtual ~Object();
virtual void preprocess(const PreprocessContext& context) = 0;
- virtual void computeBounds(const PreprocessContext& context,
- BBox& bbox) const = 0;
+ virtual void computeBounds(const PreprocessContext& context, BBox& bbox)
const = 0;
virtual void intersect(const RenderContext& context, RayPacket& rays)
const = 0;
private:
- Object(const Object&);
- Object& operator=(const Object&);
+ // Object(const Object&);
+ // Object& operator=(const Object&);
};
}
Modified: branches/itanium2/Interface/Primitive.h
==============================================================================
--- branches/itanium2/Interface/Primitive.h (original)
+++ branches/itanium2/Interface/Primitive.h Sat Jul 9 13:53:42 2005
@@ -19,8 +19,9 @@
RayPacket& rays) const = 0;
virtual void setTexCoordMapper(const TexCoordMapper* new_tex) = 0;
private:
- Primitive(const Primitive&);
- Primitive& operator=(const Primitive&);
+ // These undefined private methods make it so that primitives
cannot be copied.
+ // Primitive(const Primitive&);
+ // Primitive& operator=(const Primitive&);
};
}
Modified: branches/itanium2/Interface/RTRTInterface.h
==============================================================================
--- branches/itanium2/Interface/RTRTInterface.h (original)
+++ branches/itanium2/Interface/RTRTInterface.h Sat Jul 9 13:53:42 2005
@@ -74,6 +74,7 @@
virtual listType listLoadBalancers() const = 0;
// PixelSamplers
+ virtual void setPixelSampler( PixelSampler *sampler_ ) = 0;
typedef PixelSampler* (*PixelSamplerCreator)(const vector<string>& args);
virtual bool selectPixelSampler(const string& spec) = 0;
virtual void registerComponent(const string& name, PixelSamplerCreator
creator) = 0;
Modified: branches/itanium2/Model/Groups/CMakeLists.txt
==============================================================================
--- branches/itanium2/Model/Groups/CMakeLists.txt (original)
+++ branches/itanium2/Model/Groups/CMakeLists.txt Sat Jul 9 13:53:42
2005
@@ -2,8 +2,8 @@
SET (Manta_Groups_SRCS
Groups/BVH.h
Groups/BVH.cc
-# Groups/Bvh.h
-# Groups/Bvh.cc
+ Groups/RealisticBvh.h
+ Groups/RealisticBvh.cc
Groups/Group.h
Groups/Group.cc
Groups/kdtree.h
Added: branches/itanium2/Model/Groups/RealisticBvh.cc
==============================================================================
--- (empty file)
+++ branches/itanium2/Model/Groups/RealisticBvh.cc Sat Jul 9 13:53:42
2005
@@ -0,0 +1,173 @@
+
+#include <Interface/Context.h>
+#include <Interface/RayPacket.h>
+
+#include <Model/Groups/RealisticBvh.h>
+#include <Model/Intersections/AxisAlignedBox.h>
+
+
+using namespace Manta;
+
+RealisticBvh::RealisticBvh( Object *child0, Object *child1 ) {
+
+ child[0] = child0;
+ child[1] = child1;
+
+ PreprocessContext context;
+
+ // Update the bounding box of this node.
+ child0->computeBounds( context, bounds );
+ child1->computeBounds( context, bounds );
+}
+
+// Rearrange the pointers in the input array around a pivot point.
+int RealisticBvh::qsplit( Object **array, int size, Real pivot, int axis ) {
+
+ PreprocessContext context;
+
+ int ret_val = 0;
+ for (int i=0; i<size;++i) {
+
+ // Get the bounds of the object.
+ BBox bounds;
+ array[i]->computeBounds( context, bounds );
+
+ // Find the centroid of those bounds.
+ Real centroid = (bounds[0][axis] + bounds[1][axis]) * 0.5;
+
+ if (centroid < pivot) {
+ Object *tmp = array[i];
+ array[i] = array[ret_val];
+ array[ret_val] = tmp;
+ ++ret_val;
+ }
+ }
+
+ if ((ret_val == 0) || (ret_val == size))
+ ret_val = size / 2;
+
+ return ret_val;
+}
+
+Object *RealisticBvh::build_branch( Object **array, int size, int axis ) {
+
+ // Check to exit conditions.
+ if (size == 1)
+ return array[0];
+ if (size == 2)
+ return new RealisticBvh( array[0], array[1] );
+
+ // Create a new node.
+ RealisticBvh *new_node = new RealisticBvh();
+
+ PreprocessContext context;
+
+ // Compute the bounds of the array.
+ for (int i=0;i<size;++i) {
+ array[i]->computeBounds( context, new_node->bounds );
+ }
+
+ // new_node->bounds.extendByPoint(
new_node->bounds[0]+(Vector(new_node->bounds[0])*0.1) );
+ // new_node->bounds.extendByPoint(
new_node->bounds[1]+(Vector(new_node->bounds[1])*0.1) );
+
+ // Find a pivot point.
+ Point pivot((Vector(new_node->bounds[0]) +
Vector(new_node->bounds[1])) * 0.5);
+
+ // Split along the axis.
+ int mid_point = qsplit( array, size, pivot[axis], axis );
+
+ // Create new left and right children.
+ new_node->child[0] = build_branch( array, mid_point, (axis+1)%3 );
+ new_node->child[1] = build_branch( array+mid_point, size-mid_point,
(axis+1)%3 );
+
+ return new_node;
+}
+
+// Construct a bvh given an array of object pointers.
+RealisticBvh::RealisticBvh( Object **array, int size ) {
+
+ // Check to exit conditions.
+ PreprocessContext context;
+
+ // Compute the bounds of the array.
+ for (int i=0;i<size;++i) {
+ array[i]->computeBounds( context, bounds );
+ }
+
+ // Find a pivot point.
+ Point pivot((Vector(bounds[0]) + Vector(bounds[1])) * 0.5);
+
+ // Split along the axis.
+ int mid_point = qsplit( array, size, pivot[0], 0 );
+
+ // Create new left and right children.
+ child[0] = build_branch( array, mid_point, 1 );
+ child[1] = build_branch( array+mid_point, size-mid_point, 1 );
+
+}
+
+void RealisticBvh::preprocess(const PreprocessContext& context) {
+
+ // Build occurs in the constructor.
+}
+
+void RealisticBvh::computeBounds(const PreprocessContext& context, BBox&
bbox) const {
+
+ // Bound the bvh.
+ bbox.extendByBox( bounds );
+}
+
+void RealisticBvh::intersect(const RenderContext& context, RayPacket& rays)
const {
+
+ rays.computeInverseDirections();
+
+ // Intersect the ray packet with the bounds of this node.
+ bool bbox_intersect[RayPacket::MaxSize];
+
+ for(int i=0;i<rays.getSize();i++) {
+
+ RayPacket::Element& e = rays.get(i);
+
+ // Check to see if the ray hits this node's bounding box.
+ Real min_t, max_t;
+ bbox_intersect[i] = Intersection::intersectAaBox( bounds,
min_t, max_t, e.ray,
+
e.signMask,
e.inverseDirection );
+ }
+
+ // Find runs of rays which intersect this bounding box and intersect
those
+ // with the children.
+ int begin = 0;
+ int end = 0;
+
+ while (begin < rays.getSize()) {
+
+ // Find the beginning of a run.
+ while ((begin < rays.getSize()) && (!bbox_intersect[begin]))
+ ++begin;
+
+ // Find the end of this run.
+ end = begin;
+ while ((end < rays.getSize()) && (bbox_intersect[end]))
+ ++end;
+
+ if ((end > begin) && (begin < rays.getSize())) {
+ // Create a sub packet.
+ RayPacket sub_packet( rays, begin, end );
+
+ // Intersect with both children.
+ child[0]->intersect( context, sub_packet );
+ child[1]->intersect( context, sub_packet );
+
+ }
+
+ begin = end;
+ }
+
+}
+
+
+
+
+
+
+
Added: branches/itanium2/Model/Groups/RealisticBvh.h
==============================================================================
--- (empty file)
+++ branches/itanium2/Model/Groups/RealisticBvh.h Sat Jul 9 13:53:42
2005
@@ -0,0 +1,40 @@
+
+
+
+#ifndef Manta_Model_RealisticBvh__H
+#define Manta_Model_RealisticBvh__H
+
+#include <Interface/Object.h>
+#include <Core/Geometry/BBox.h>
+
+namespace Manta {
+
+ // This class follows the implementation from
+ // "Realistic Ray Tracing"
+
+ // This bvh contains pointers to objects in it's leaves.
+ class RealisticBvh : public Object {
+ protected:
+ BBox bounds; // Bounds of this node.
+ Object *child[2]; // Childern of this node.
+
+ // Protected constructors.
+ RealisticBvh( Object *child0, Object *child1 );
+ RealisticBvh() { child[0] = child[1] = 0; };
+
+ static int qsplit( Object **array, int size, Real pivot, int
axis );
+ static Object *build_branch( Object **array, int size, int
axis );
+
+ public:
+ // Construct a BVH from an array of objects.
+ RealisticBvh( Object **array, int size );
+
+ // Public interface.
+ void preprocess (const PreprocessContext& context);
+ void computeBounds(const PreprocessContext& context, BBox& bbox) const;
+ void intersect (const RenderContext& context, RayPacket& rays) const;
+ };
+};
+
+#endif
+
Modified: branches/itanium2/Model/Groups/kdtree.cc
==============================================================================
--- branches/itanium2/Model/Groups/kdtree.cc (original)
+++ branches/itanium2/Model/Groups/kdtree.cc Sat Jul 9 13:53:42 2005
@@ -31,7 +31,7 @@
float *t, float *u,
float *v,
const float *edge1,
const float *edge2);
-inline int intersectTriangle3Edge(const Ray &ray, const Triangle &tri,
+int intersectTriangle3Edge(const Vectorf &direction, const Pointf &origin,
const Triangle &tri,
float &t, float &u,
float &v );
///////////////////////////////////////////////////////////////////////////////
@@ -80,6 +80,7 @@
_rawData += 3;
}
}
+
// Otherwise don't swap.
else {
for (int j=0; j<3; ++j) {
@@ -112,10 +113,7 @@
(**tris)[i].payload = ((r<<16)+(g<<8)+b);
// Compute the normal.
- Vectorf v01, v02;
- v01 = (**tris)[i][1] - (**tris)[i][0];
- v02 = (**tris)[i][2] - (**tris)[i][0];
- (*perVertNormals)[3*i] = Cross(v01, v02).normal();
+ (*perVertNormals)[3*i] = Cross((**tris)[i].edge1,
(**tris)[i].edge2).normal();
// Copy normals to each vertex.
(*perVertNormals)[3*i+1] = (*perVertNormals)[3*i+2] =
(*perVertNormals)[3*i];
@@ -254,8 +252,6 @@
int LoadBin_V3C1(const char *filename, VArray<Triangle> **tris, /*Vectorf
**perVertNormals,*/ Vectorf **perVertNormals, BBox &bounds, int np ) {
-
-
FILE *f;
if ((f=fopen(filename, "r")) == NULL) {
fprintf(stderr, "Cannot open file: %s\n", filename);
@@ -270,17 +266,6 @@
int nFloats = fileSize/4;
float *rawData = new float [fileSize / 4];
- //
- // touch data for good distribution
- //
- long i;
-
- // #pragma omp parallel for private (i)
-
- // for (i=0; i<nFloats; i+=1024*4) {
- // rawData[i] = 0;
- // }
-
fseek(f, 0, SEEK_SET);
double time_begin = Time::currentSeconds();
@@ -315,8 +300,6 @@
// Create worker threads to preprocess and bound the data.
Thread **workers = new Thread *[ np ];
-
-
CacheAlignedBBox *worker_box = new CacheAlignedBBox[ np ];
int work_per_thread = nTris / np;
@@ -357,77 +340,9 @@
delete [] workers;
delete [] worker_box;
-#if 0
- float *_rawData;
- // #pragma omp parallel for private (_rawData, i)
- for (i=0; i<nTris; i++) {
-
- // Offset into the data.
- _rawData = rawData + 12 * i;
-
- // Check to see if we are on a big endian system
- // Data was generate on Altix (little endian)
- if (is_big_endian()) {
- for (int j=0; j<3; ++j) {
- (**tris)[i][j] = Pointf( endian_swap(
_rawData[0] ),
- endian_swap(
_rawData[1] ),
-
endian_swap( _rawData[2]
));
- _rawData += 3;
- }
- }
- // Otherwise don't swap.
- else {
- for (int j=0; j<3; ++j) {
- (**tris)[i][j] = Pointf( _rawData[0],
_rawData[1], _rawData[2] );
- _rawData += 3;
- }
- }
-
- long r, g, b;
-
- // Check for big endian data.
- if (is_big_endian()) {
- r = int(endian_swap(_rawData[0]) * 255 + .5f);
- g = int(endian_swap(_rawData[1]) * 255 + .5f);
- b = int(endian_swap(_rawData[2]) * 255 + .5f);
- _rawData += 3;
- }
- else {
- r = int(_rawData[0] * 255 + .5f);
- g = int(_rawData[1] * 255 + .5f);
- b = int(_rawData[2] * 255 + .5f);
- _rawData += 3;
- }
-
- // Compute edges.
- (**tris)[i].edge1 = (**tris)[i][1] - (**tris)[i][0];
- (**tris)[i].edge2 = (**tris)[i][2] - (**tris)[i][0];
-
- //
- (**tris)[i].payload = ((r<<16)+(g<<8)+b);
-
- // Compute the normal.
- Vectorf v01, v02;
- v01 = (**tris)[i][1] - (**tris)[i][0];
- v02 = (**tris)[i][2] - (**tris)[i][0];
- (*perVertNormals)[3*i] = Cross(v01, v02).normal();
-
- // Copy normals to each vertex.
- (*perVertNormals)[3*i+1] = (*perVertNormals)[3*i+2] =
(*perVertNormals)[3*i];
-
- // Update the bounding box of the whole scene
- for (long j=0; j<3; j++) {
- Triangle &tri = (**tris)[i];
- bounds.extendByPoint( tri[0] );
- bounds.extendByPoint( tri[1] );
- bounds.extendByPoint( tri[2] );
- }
-
- }
-#endif
time_end = Time::currentSeconds();
- std::cout << "Time to parse triangles: " << (time_end -
time_begin)/60.0 << " Minutes." << std::endl;
+ std::cout << "Time to parse triangles: " << (time_end - time_begin)
<< " Seconds." << std::endl;
std::cout << "Triangles loaded: " << nTris << std::endl;
time_begin = Time::currentSeconds();
@@ -466,7 +381,7 @@
long long totalNumFloats = nFloatPerTri * nTris;
float *rawData = new float [totalNumFloats];
long i;
-#pragma omp parallel for private (i)
+// #pragma omp parallel for private (i)
// Zero out the raw data.
memset( rawData, 0x0, totalNumFloats*sizeof(float) );
@@ -482,7 +397,7 @@
*perVertNormals = new Vectorf [nTris*3];
float *_rawData;
-#pragma omp parallel for private (_rawData, i)
+// #pragma omp parallel for private (_rawData, i)
for (i=0; i<nTris; i++) {
_rawData = rawData + 12 * i;
@@ -659,39 +574,40 @@
return 1;
}
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// INTERSECT TRIANGLES INTERSECT TRIANGLES INTERSECT TRIANGLES INTERSECT
TRI
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
int KDTree::intersectTriangles(const Ray* ray, unsigned int listBegin, int
listSize, float maxDist, void *userData) const
{
int i;
RayTriIntersectUserData *ud = (RayTriIntersectUserData*)userData;
float nearest_u, nearest_v;
- int nearest_tri=-1;
+ int nearest_tri = -1;
+
+ Vectorf direction = ray->direction();
+ Pointf origin = ray->origin();
- /* Intersect the ray with all the bounding boxes */
+ // Intersect the ray with all the triangles.
int listEnd = listBegin+listSize;
for (i = listBegin; i < listEnd; i++) {
int triIdx = triIndices->get(i);
Triangle &tri = tris->get(triIdx);
float t, u, v;
- // if (intersectTriangle3Edge( *ray, tri, t, u, v )) {
-
- Vectorf direction = ray->direction();
- Pointf origin = ray->origin();
+ if (intersectTriangle3Edge( direction, origin, tri, t, u, v
)) {
+ // if(intersect_triangle3_edge( &origin, &direction, &tri[0],
&tri[1], &tri[2], &t, &u, &v, &tri.edge1, &tri.edge2 )) {
- if(intersect_triangle3(
-
&origin, &direction,
-
&tri[0], &tri[1], &tri[2],
-
&t, &u, &v/*,
-
&tri.edge1, &tri.edge2*/)) {
-
+ // Check to see if the t value is closer.
if (t < maxDist) {
maxDist = t;
- nearest_u= u;
- nearest_v= v;
+ nearest_u = u;
+ nearest_v = v;
nearest_tri = triIdx;
}
}
- }
+ }
if (nearest_tri >= 0) {
ud->rayHit.t = maxDist;
@@ -699,9 +615,11 @@
ud->rayHit.v = nearest_v;
ud->rayHitTriIndex = nearest_tri;
return 1;
- } else
+
+ } else {
return 0;
}
+}
// Traversal Stack Entry.
struct TravStackEntry {
@@ -712,8 +630,10 @@
};
///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
// This is the Manta interface method.
///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
void KDTree::intersect(const RenderContext& context, RayPacket& rays) const
{
@@ -743,38 +663,8 @@
// Send the ray to the _intersect function.
isectData.rayHitTriIndex = -1;
_intersect( &e.ray, e, isectData, (float)minDist,
(float)maxDist);
-#if 0
- // Check to see if the ray hit any triangles.
- if (isectData.rayHitTriIndex >= 0) {
-
- e.normal =
normals[isectData.rayHitTriIndex*3]; // Is this safe??? What if the hit()
function fails?
-
- // Check against the hit record, Note that
tex coord mapper is null.
- if (e.hitInfo.hit(isectData.rayHit.t,
lambMat, this, 0 )) {
-
e.hitInfo.scratchpad<ScratchPadInfo>().normal =
normals[isectData.rayHitTriIndex*3];
-
e.hitInfo.scratchpad<ScratchPadInfo>().payload =
tris->get(isectData.rayHitTriIndex).payload;
- }
- }
-#endif
- }
-#if 0
-
- // Send the ray to the _intersect function.
- isectData.rayHitTriIndex = -1;
- _intersect( &e.ray, e, &isectData, 0,
numeric_limits<float>::max());
-
- // Check to see if the ray hit any triangles.
- if (isectData.rayHitTriIndex >= 0) {
-
- e.normal = normals[isectData.rayHitTriIndex*3]; // Is
this safe??? What if the hit() function fails?
-
- // Check against the hit record, Note that tex coord
mapper is null.
- if (e.hitInfo.hit(isectData.rayHit.t, lambMat, this,
0 )) {
- e.hitInfo.scratchpad<ScratchPadInfo>().normal
= normals[isectData.rayHitTriIndex*3];
-
e.hitInfo.scratchpad<ScratchPadInfo>().payload =
tris->get(isectData.rayHitTriIndex).payload;
- }
+
}
-#endif
}
}
@@ -791,10 +681,11 @@
///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
// This function performs the KD-Tree Traversal.
///////////////////////////////////////////////////////////////////////////////
-void KDTree::_intersect(
-
const Ray* ray, RayPacket::Element &e,
RayTriIntersectUserData &isectData,
+///////////////////////////////////////////////////////////////////////////////
+void KDTree::_intersect(const Ray* ray, RayPacket::Element &e,
RayTriIntersectUserData &isectData,
float minDist, float maxDist) const
{
@@ -861,7 +752,7 @@
if (intersectTriangles(ray, nearNode->listBegin(),
nearNode->listSize(), travStack[exitPos].t, &isectData) &&
(isectData.rayHitTriIndex >= 0)) {
- e.normal =
normals[isectData.rayHitTriIndex*3]; // Is this safe??? What if the hit()
function fails?
+ e.normal =
normals[isectData.rayHitTriIndex*3];
// Check against the hit record, Note that
tex coord mapper is null.
if (e.hitInfo.hit(isectData.rayHit.t,
lambMat, this, 0 )) {
@@ -913,189 +804,6 @@
(dest)[0]=(v1)[0]-(v2)[0]; \
(dest)[1]=(v1)[1]-(v2)[1]; \
(dest)[2]=(v1)[2]-(v2)[2];
-#if 0
-
-/* the original jgt code */
-inline int intersect_triangle(const float orig[3], const float dir[3],
-
const float vert0[3], const float
vert1[3], const float vert2[3],
-
float *t, float *u, float *v)
-{
- float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
- float det,inv_det;
-
- /* find vectors for two edges sharing vert0 */
- SUB(edge1, vert1, vert0);
- SUB(edge2, vert2, vert0);
-
- /* begin calculating determinant - also used to calculate U parameter
*/
- CROSS(pvec, dir, edge2);
-
- /* if determinant is near zero, ray lies in plane of triangle */
- det = DOT(edge1, pvec);
-
- if (det > -EPSILON && det < EPSILON)
- return 0;
- inv_det = 1.0f/ det;
-
- /* calculate distance from vert0 to ray origin */
- SUB(tvec, orig, vert0);
-
- /* calculate U parameter and test bounds */
- *u = DOT(tvec, pvec) * inv_det;
- if (*u < 0.0f || *u > 1.0)
- return 0;
-
- /* prepare to test V parameter */
- CROSS(qvec, tvec, edge1);
-
- /* calculate V parameter and test bounds */
- *v = DOT(dir, qvec) * inv_det;
- if (*v < 0.0f || *u + *v > 1.0)
- return 0;
-
- /* calculate t, ray intersects triangle */
- *t = DOT(edge2, qvec) * inv_det;
-
- return 1;
-}
-
-
-/* code rewritten to do tests on the sign of the determinant */
-/* the division is at the end in the code */
-inline int intersect_triangle1(float orig[3], float dir[3],
-
float vert0[3], float vert1[3],
float vert2[3],
-
float *t, float *u, float *v)
-{
- float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
- float det,inv_det;
-
- /* find vectors for two edges sharing vert0 */
- SUB(edge1, vert1, vert0);
- SUB(edge2, vert2, vert0);
-
- /* begin calculating determinant - also used to calculate U parameter
*/
- CROSS(pvec, dir, edge2);
-
- /* if determinant is near zero, ray lies in plane of triangle */
- det = DOT(edge1, pvec);
-
- if (det > EPSILON)
- {
- /* calculate distance from vert0 to ray origin */
- SUB(tvec, orig, vert0);
-
- /* calculate U parameter and test bounds */
- *u = DOT(tvec, pvec);
- if (*u < 0.0f || *u > det)
- return 0;
-
- /* prepare to test V parameter */
- CROSS(qvec, tvec, edge1);
-
- /* calculate V parameter and test bounds */
- *v = DOT(dir, qvec);
- if (*v < 0.0f || *u + *v > det)
- return 0;
-
- }
- else if(det < -EPSILON)
- {
- /* calculate distance from vert0 to ray origin */
- SUB(tvec, orig, vert0);
-
- /* calculate U parameter and test bounds */
- *u = DOT(tvec, pvec);
- /* printf("*u=%f\n",(float)*u); */
- /* printf("det=%f\n",det); */
- if (*u > 0.0f || *u < det)
- return 0;
-
- /* prepare to test V parameter */
- CROSS(qvec, tvec, edge1);
-
- /* calculate V parameter and test bounds */
- *v = DOT(dir, qvec) ;
- if (*v > 0.0f || *u + *v < det)
- return 0;
- }
- else return 0; /* ray is parallell to the plane of the triangle */
-
-
- inv_det = 1.0f/ det;
-
- /* calculate t, ray intersects triangle */
- *t = DOT(edge2, qvec) * inv_det;
- (*u) *= inv_det;
- (*v) *= inv_det;
-
- return 1;
-}
-
-/* code rewritten to do tests on the sign of the determinant */
-/* the division is before the test of the sign of the det */
-inline int intersect_triangle2(float orig[3], float dir[3],
-
float vert0[3], float vert1[3],
float vert2[3],
-
float *t, float *u, float *v)
-{
- float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
- float det,inv_det;
-
- /* find vectors for two edges sharing vert0 */
- SUB(edge1, vert1, vert0);
- SUB(edge2, vert2, vert0);
-
- /* begin calculating determinant - also used to calculate U parameter
*/
- CROSS(pvec, dir, edge2);
-
- /* if determinant is near zero, ray lies in plane of triangle */
- det = DOT(edge1, pvec);
-
- /* calculate distance from vert0 to ray origin */
- SUB(tvec, orig, vert0);
- inv_det = 1.0f/ det;
-
- if (det > EPSILON)
- {
- /* calculate U parameter and test bounds */
- *u = DOT(tvec, pvec);
- if (*u < 0.0f || *u > det)
- return 0;
-
- /* prepare to test V parameter */
- CROSS(qvec, tvec, edge1);
-
- /* calculate V parameter and test bounds */
- *v = DOT(dir, qvec);
- if (*v < 0.0f || *u + *v > det)
- return 0;
-
- }
- else if(det < -EPSILON)
- {
- /* calculate U parameter and test bounds */
- *u = DOT(tvec, pvec);
- if (*u > 0.0f || *u < det)
- return 0;
-
- /* prepare to test V parameter */
- CROSS(qvec, tvec, edge1);
-
- /* calculate V parameter and test bounds */
- *v = DOT(dir, qvec) ;
- if (*v > 0.0f || *u + *v < det)
- return 0;
- }
- else return 0; /* ray is parallell to the plane of the triangle */
-
- /* calculate t, ray intersects triangle */
- *t = DOT(edge2, qvec) * inv_det;
- (*u) *= inv_det;
- (*v) *= inv_det;
-
- return 1;
-}
-
-#endif
/* code rewritten to do tests on the sign of the determinant */
/* the division is before the test of the sign of the det */
@@ -1216,139 +924,69 @@
return 1;
}
-inline int intersectTriangle3Edge(const Ray &ray, const Triangle &tri,
-
float &t, float &u,
float &v )
+int intersectTriangle3Edge(const Vectorf &direction, const Pointf &origin,
const Triangle &tri,
+
float &t, float &u, float &v )
{
- // float edge1[3], edge2[3];
- Vector tvec, pvec, qvec;
- Real det,inv_det;
+
+ Vectorf tvec, pvec, qvec;
+
+
+ // Vectorf edge1 = ( tri.edge1 );
+ // Vectorf edge2 = ( tri.edge2 );
/* begin calculating determinant - also used to calculate U parameter
*/
- pvec = Cross( ray.direction(), Vector(tri.edge2) );
+ pvec = Cross( direction, tri.edge2 );
// CROSS(pvec, dir, edge2);
/* if determinant is near zero, ray lies in plane of triangle */
// det = DOT(edge1, pvec);
- det = Dot( Vector(tri.edge1), pvec );
+ float det = Dot( tri.edge1, pvec );
/* calculate distance from vert0 to ray origin */
// SUB(tvec, orig, vert0);
- tvec = ray.origin() - tri[0];
- inv_det = 1.0/ det;
+ tvec = origin - tri[0];
- qvec = Cross( tvec, Vector(tri.edge1) );
+ qvec = Cross( tvec, tri.edge1 );
// CROSS(qvec, tvec, edge1);
/* calculate U parameter */
// float uu = DOT(tvec, pvec);
// float vv;
- Real uu = Dot( tvec, pvec );
- Real vv;
+ float uu = Dot( tvec, pvec );
+ float vv;
- if (det > 1e-5)
- {
+ if (det > 1e-5f) {
if (uu < 0.0 || uu > det)
- return 0;
+ return 0;
/* calculate V parameter and test bounds */
- vv = Dot( ray.direction(), qvec );
+ vv = Dot( direction, qvec );
if (vv < 0.0 || uu + vv > det)
- return 0;
+ return 0;
}
- else if(det < -1e-5)
- {
+ else if(det < -1e-5f) {
if (uu > 0.0 || uu < det)
- return 0;
+ return 0;
/* calculate V parameter and test bounds */
- vv = Dot(ray.direction(), qvec) ;
- if (vv > 0.0f || uu + vv < det)
- return 0;
+ vv = Dot(direction, qvec) ;
+ if (vv > 0.0 || uu + vv < det)
+ return 0;
+ }
+ else {
+ return 0; /* ray is parallell to the plane of the triangle */
}
- else return 0; /* ray is parallell to the plane of the triangle */
-
- t = Dot( Vector(tri.edge2), qvec ) * inv_det;
- u = uu * inv_det;
- v = vv * inv_det;
-
- return 1;
-}
-#if 0
-inline void rays_intersect_triangle3(const float orig[3], const float *dir,
-
int nRays,
-
float
vert0[3], float vert1[3], float vert2[3],
-
int
hits[], float t[], float u[], float v[])
-{
- float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
- float det,inv_det;
-
- /* find vectors for two edges sharing vert0 */
- SUB(edge1, vert1, vert0);
- SUB(edge2, vert2, vert0);
- /* calculate distance from vert0 to ray origin */
- SUB(tvec, orig, vert0);
+ float inv_det = 1.0f / det;
- CROSS(qvec, tvec, edge1);
-
- float uu, vv;
- for (int i=0; i<nRays; i++, dir+=3) {
- /* begin calculating determinant - also used to calculate U
parameter */
- CROSS(pvec, dir, edge2);
-
- /* if determinant is near zero, ray lies in plane of triangle
*/
- det = DOT(edge1, pvec);
- //fprintf(stderr, "dir:%f %f %f; det: %f\n", dir[0], dir[1],
dir[2], det);
-
- /* calculate distance from vert0 to ray origin */
- // SUB(tvec, orig, vert0);
- inv_det = 1.0f/ det;
-
- // CROSS(qvec, tvec, edge1);
-
- /* calculate U parameter and test bounds */
- uu = DOT(tvec, pvec);
- if (det > EPSILON) {
- if (uu < 0.0f || uu > det) {
- hits[i] = 0;
- continue;
- }
-
- /* calculate V parameter and
test bounds */
- vv = DOT(dir, qvec);
- if (vv < 0.0f || uu + vv >
det) {
- hits[i] = 0;
- continue;
- }
- }
- else if(det < -EPSILON)
- {
- if (uu > 0.0f || uu < det) {
- hits[i] = 0;
- continue;
- }
-
- /* calculate V parameter and
test bounds */
- vv = DOT(dir, qvec) ;
- if (vv > 0.0f || uu + vv <
det) {
- hits[i] = 0;
- continue;
- }
- } else {
- hits[i] = 0;
- continue;
- }
-
- t[i] = DOT(edge2, qvec) * inv_det;
- u[i] = uu*inv_det;
- v[i] = vv*inv_det;
- hits[i] = 1;
- }
+ t = (Dot( tri.edge2, qvec ) * inv_det);
+ u = (uu * inv_det);
+ v = (vv * inv_det);
+ return 1;
}
-#endif
Modified: branches/itanium2/Model/Groups/varray.h
==============================================================================
--- branches/itanium2/Model/Groups/varray.h (original)
+++ branches/itanium2/Model/Groups/varray.h Sat Jul 9 13:53:42 2005
@@ -106,13 +106,13 @@
}
inline T &operator[](int i) {
- if (array && i < curLen)
+ //if (array && i < curLen)
return array[i];
- else {
- fprintf(stderr, "VArray(%p)::[] reference out of
bound (idx:%d size:%d)\n", this, i, curLen);
- assert(0);
- return array[0];
- }
+ //else {
+ // fprintf(stderr, "VArray(%p)::[] reference out of
bound (idx:%d size:%d)\n", this, i, curLen);
+ // assert(0);
+ // return array[0];
+ //}
}
inline T & get(int i) {
Modified: branches/itanium2/Model/Materials/CMakeLists.txt
==============================================================================
--- branches/itanium2/Model/Materials/CMakeLists.txt (original)
+++ branches/itanium2/Model/Materials/CMakeLists.txt Sat Jul 9 13:53:42
2005
@@ -2,13 +2,22 @@
SET (Manta_Materials_SRCS
+ Materials/Checker.h
Materials/Checker.cc
+ Materials/Dielectric.h
Materials/Dielectric.cc
+ Materials/Flat.h
Materials/Flat.cc
+ Materials/Lambertian.h
Materials/Lambertian.cc
+ Materials/LitMaterial.h
Materials/LitMaterial.cc
+ Materials/MetalMaterial.h
Materials/MetalMaterial.cc
+ Materials/Phong.h
Materials/Phong.cc
+ Materials/LambertianAlt.h
Materials/LambertianAlt.cc
+ Materials/NormalMaterial.h
Materials/NormalMaterial.cc # Shade the material using it's normal.
)
Modified: branches/itanium2/Model/Materials/Dielectric.cc
==============================================================================
--- branches/itanium2/Model/Materials/Dielectric.cc (original)
+++ branches/itanium2/Model/Materials/Dielectric.cc Sat Jul 9 13:53:42
2005
@@ -15,9 +15,9 @@
using namespace Manta;
Dielectric::Dielectric(const Color& diffuse, const Color& specular,
- int specpow, double n, double nt)
- : diffuse(diffuse), specular(specular), specpow(specpow),
- n(n), nt(nt)
+
int specpow, double n, double nt)
+: diffuse(diffuse), specular(specular), specpow(specpow),
+n(n), nt(nt)
{
}
@@ -31,73 +31,78 @@
// object and are all of the same material
rays.normalizeDirections();
-
+
// Compute normals
rays.computeNormals(context);
-
+
+
+ Scene *scene = (Scene*)context.scene;
+ LightSet *activeLights = scene->getLights();
+
// Compute ambient contributions for all rays
activeLights->getAmbientLight()->computeAmbient(context, rays);
-
+
RayPacketData data;
int start = 0;
do {
RayPacket shadowRays(data, 0, rays.getDepth(), 0);
int end = context.shadowAlgorithm->computeShadows(context, activeLights,
- rays, start,
shadowRays);
+
rays, start,
shadowRays);
if(shadowRays.getFlags() & RayPacket::NormalizedDirections){
for(int i=start;i<end;i++){
- RayPacket::Element& e = rays.get(i);
- Color totalDiffuse(e.ambientLight);
- Color totalSpecular = Color::black();
- for(int j=e.shadowBegin;j<e.shadowEnd;j++){
- RayPacket::Element& s = shadowRays.get(j);
- if(!s.hitInfo.wasHit()){
- double cos_theta = Dot(s.ray.direction(), e.normal);
- totalDiffuse += s.light*cos_theta;
- Vector H = s.ray.direction()-e.ray.direction();
- H.normalize();
- double cos_alpha = Dot(H, e.normal);
- if(cos_alpha > 0)
- totalSpecular += s.light * ipow(cos_alpha, specpow);
- }
- }
- rays.setResult(i, diffuse*totalDiffuse+specular*totalSpecular);
+ RayPacket::Element& e = rays.get(i);
+ Color totalDiffuse(e.ambientLight);
+ Color totalSpecular = Color::black();
+ for(int j=e.shadowBegin;j<e.shadowEnd;j++){
+ RayPacket::Element& s =
shadowRays.get(j);
+ if(!s.hitInfo.wasHit()){
+ double cos_theta =
Dot(s.ray.direction(), e.normal);
+ totalDiffuse +=
s.light*cos_theta;
+ Vector H =
s.ray.direction()-e.ray.direction();
+ H.normalize();
+ double cos_alpha = Dot(H,
e.normal);
+ if(cos_alpha > 0)
+ totalSpecular +=
s.light * ipow(cos_alpha, specpow);
+ }
+ }
+ rays.setResult(i,
diffuse*totalDiffuse+specular*totalSpecular);
}
} else {
for(int i=start;i<end;i++){
- RayPacket::Element& e = rays.get(i);
- Color totalDiffuse(e.ambientLight);
- Color totalSpecular = Color::black();
- for(int j=e.shadowBegin;j<e.shadowEnd;j++){
- RayPacket::Element& s = shadowRays.get(j);
- if(!s.hitInfo.wasHit()){
- s.ray.normalizeDirection();
- double cos_theta = Dot(s.ray.direction(), e.normal);
- totalDiffuse += s.light*cos_theta;
- Vector H = s.ray.direction()-e.ray.direction();
- H.normalize();
- double cos_alpha = Dot(H, e.normal);
- if(cos_alpha > 0)
- totalSpecular += s.light * ipow(cos_alpha, specpow);
- }
- }
- rays.setResult(i, diffuse*totalDiffuse+specular*totalSpecular);
+ RayPacket::Element& e = rays.get(i);
+ Color totalDiffuse(e.ambientLight);
+ Color totalSpecular = Color::black();
+ for(int j=e.shadowBegin;j<e.shadowEnd;j++){
+ RayPacket::Element& s =
shadowRays.get(j);
+ if(!s.hitInfo.wasHit()){
+ s.ray.normalizeDirection();
+ double cos_theta =
Dot(s.ray.direction(), e.normal);
+ totalDiffuse +=
s.light*cos_theta;
+ Vector H =
s.ray.direction()-e.ray.direction();
+ H.normalize();
+ double cos_alpha = Dot(H,
e.normal);
+ if(cos_alpha > 0)
+ totalSpecular +=
s.light * ipow(cos_alpha, specpow);
+ }
+ }
+ rays.setResult(i,
diffuse*totalDiffuse+specular*totalSpecular);
}
}
start = end;
} while(start < rays.getSize());
-
+
int maxdepth = 5;
if(rays.getDepth() < maxdepth) {
// Compute refractions
- double *c = new double[rays.getSize()];
- double *tst = new double[rays.getSize()];
- Color *col = new Color[rays.getSize()];
+ double c[RayPacket::MaxSize];
+ double tst[RayPacket::MaxSize];
+ Color col[RayPacket::MaxSize];
+
RayPacketData rfdata;
RayPacket refr_rays(rfdata, rays.getSize(), rays.getDepth()+1,
- RayPacket::NormalizedDirections);
+
RayPacket::NormalizedDirections);
refr_rays.useLocalColors();
rays.computeHitPositions();
@@ -112,22 +117,22 @@
double y = refr_dir.y()*0.00001-e.hitPosition.y();
double z = refr_dir.z()*0.00001-e.hitPosition.z();
r.ray.set(Point(x,y,z), refr_dir);
-
+
if(Dot(d,norm) < 0) {
- c[i] = -Dot(e.ray.direction(), e.normal);
- col[i] = Color::white();
+ c[i] = -Dot(e.ray.direction(), e.normal);
+ col[i] = Color::white();
}
else {
- c[i] = Dot(refr_dir, e.normal);
- double tmpt = e.hitInfo.minT();
- col[i] = e.color->attenuate(-tmpt);
+ c[i] = Dot(refr_dir, e.normal);
+ double tmpt = e.hitInfo.minT();
+ col[i] = e.color->attenuate(-tmpt);
}
}
// Compute reflections
RayPacketData rdata;
RayPacket refl_rays(rdata, rays.getSize(), rays.getDepth()+1,
- RayPacket::NormalizedDirections);
+
RayPacket::NormalizedDirections);
refl_rays.useLocalColors();
double *refl = new double[rays.getSize()];
for(int i=0;i<rays.getSize();i++) {
@@ -152,17 +157,13 @@
RayPacket::Element& rl = refl_rays.get(i);
RayPacket::Element& rf = refr_rays.get(i);
if(tst[i] < 0) {
- *e.color = col[i]*(*rl.color);
+ *e.color += col[i]*(*rl.color);
}
else {
- *e.color = col[i]*(((*rl.color) * refl[i]) +
- ((*rf.color) * (1-refl[i])));
+ *e.color += col[i]*(((*rl.color) * refl[i]) +
+
((*rf.color) * (1-refl[i])));
}
}
- delete [] c;
- delete [] tst;
- delete [] refl;
- delete [] col;
}
}
Modified: branches/itanium2/Model/Materials/Lambertian.cc
==============================================================================
--- branches/itanium2/Model/Materials/Lambertian.cc (original)
+++ branches/itanium2/Model/Materials/Lambertian.cc Sat Jul 9 13:53:42
2005
@@ -7,6 +7,7 @@
#include <Interface/AmbientLight.h>
#include <Interface/Context.h>
#include <Interface/ShadowAlgorithm.h>
+#include <Interface/Scene.h>
#include <Model/Textures/Constant.h>
using namespace Manta;
@@ -38,7 +39,8 @@
colortex->mapValues(context, rays, colors);
// Compute ambient contributions for all rays
- activeLights->getAmbientLight()->computeAmbient(context, rays);
+ Scene *scene = (Scene*)context.scene;
+ scene->getLights()->getAmbientLight()->computeAmbient(context, rays);
#if 0
RayPacket::Iterator ray_iter = rays.begin(); // Iterate across the
ray packet making shadow rays.
@@ -52,7 +54,7 @@
for (;ray_iter<ray_end;++ray_iter) {
// Create a shadow ray packet.
- ray_last = context.shadowAlgorithm->computeShadows( context,
activeLights,
+ ray_last = context.shadowAlgorithm->computeShadows( context,
scene->getLights(),
ray_iter,
ray_end,
shadow_rays );
@@ -83,7 +85,7 @@
int start = 0;
do {
RayPacket shadowRays(data, 0, rays.getDepth(), 0);
- int end = context.shadowAlgorithm->computeShadows(context, activeLights,
+ int end = context.shadowAlgorithm->computeShadows(context,
scene->getLights(),
rays, start,
shadowRays);
if(shadowRays.getFlags() & RayPacket::NormalizedDirections){
for(int i=start;i<end;i++){
Modified: branches/itanium2/Model/Materials/Lambertian.h
==============================================================================
--- branches/itanium2/Model/Materials/Lambertian.h (original)
+++ branches/itanium2/Model/Materials/Lambertian.h Sat Jul 9 13:53:42
2005
@@ -13,6 +13,7 @@
public:
Lambertian(const Color& color);
Lambertian(const Texture<Color>* colorfn);
+ Lambertian() { };
virtual ~Lambertian();
virtual void shade(const RenderContext& context, RayPacket& rays) const;
Modified: branches/itanium2/Model/Primitives/PrimitiveCommon.h
==============================================================================
--- branches/itanium2/Model/Primitives/PrimitiveCommon.h (original)
+++ branches/itanium2/Model/Primitives/PrimitiveCommon.h Sat Jul 9
13:53:42 2005
@@ -9,6 +9,7 @@
class PrimitiveCommon : public Primitive {
public:
PrimitiveCommon(Material* material, const TexCoordMapper* tex = 0);
+ PrimitiveCommon() { }; // Empty default constructor (used
for an array of some primitive)
virtual ~PrimitiveCommon();
virtual void preprocess(const PreprocessContext&);
Modified: branches/itanium2/Model/Primitives/Triangle.h
==============================================================================
--- branches/itanium2/Model/Primitives/Triangle.h (original)
+++ branches/itanium2/Model/Primitives/Triangle.h Sat Jul 9 13:53:42
2005
@@ -14,6 +14,7 @@
double a,b;
};
+ Triangle() { };
Triangle(Material* mat, const Point& _p1, const Point& _p2, const Point&
_p3);
virtual ~Triangle();
Modified: branches/itanium2/Model/Readers/CMakeLists.txt
==============================================================================
--- branches/itanium2/Model/Readers/CMakeLists.txt (original)
+++ branches/itanium2/Model/Readers/CMakeLists.txt Sat Jul 9 13:53:42
2005
@@ -1,4 +1,11 @@
SET (Manta_Readers_SRCS
Readers/PlyReader.cc
- Readers/rply/rply.c)
+ Readers/rply/rply.c
+ Readers/glm/glm.h
+ Readers/glm/glm.cc)
+
+# Apple places malloc.h in /usr/include/malloc/malloc.h
+IF (APPLE)
+ INCLUDE_DIRECTORIES(/usr/include/malloc/)
+ENDIF (APPLE)
\ No newline at end of file
Added: branches/itanium2/Model/Readers/glm/glm.cc
==============================================================================
--- (empty file)
+++ branches/itanium2/Model/Readers/glm/glm.cc Sat Jul 9 13:53:42 2005
@@ -0,0 +1,1873 @@
+/*
+ * GLM library. Wavefront .obj file format reader/writer/manipulator.
+ *
+ * Written by Nate Robins, 1997.
+ * email: ndr@pobox.com
+ * www:
http://www.pobox.com/~ndr
+ */
+
+
+/* includes */
+#include <Model/Readers/glm/glm.h>
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <malloc.h>
+#include <stdlib.h>
+
+#include <limits.h>
+
+/* defines */
+#define T(x) model->triangles[(x)]
+
+namespace Glm {
+
+/* enums */
+enum { X, Y, Z, W }; /* elements of a vertex */
+
+
+/* typedefs */
+
+/* _GLMnode: general purpose node
+ */
+typedef struct _GLMnode {
+ unsigned int index;
+ bool averaged;
+ struct _GLMnode* next;
+} GLMnode;
+
+
+/* private functions */
+
+/* _glmMax: returns the maximum of two floats */
+
+static float
+_glmMax(float a, float b)
+{
+ if (a > b)
+ return a;
+ return b;
+}
+
+/* _glmAbs: returns the absolute value of a float */
+static float
+_glmAbs(float f)
+{
+ if (f < 0)
+ return -f;
+ return f;
+}
+
+/* _glmDot: compute the dot product of two vectors
+ *
+ * u - array of 3 floats (float u[3])
+ * v - array of 3 floats (float v[3])
+ */
+static float
+_glmDot(float* u, float* v)
+{
+ assert(u);
+ assert(v);
+
+ /* compute the dot product */
+ return u[X] * v[X] + u[Y] * v[Y] + u[Z] * v[Z];
+}
+
+/* _glmCross: compute the cross product of two vectors
+ *
+ * u - array of 3 floats (float u[3])
+ * v - array of 3 floats (float v[3])
+ * n - array of 3 floats (float n[3]) to return the cross product in
+ */
+static void
+_glmCross(float* u, float* v, float* n)
+{
+ assert(u);
+ assert(v);
+ assert(n);
+
+ /* compute the cross product (u x v for right-handed [ccw]) */
+ n[X] = u[Y] * v[Z] - u[Z] * v[Y];
+ n[Y] = u[Z] * v[X] - u[X] * v[Z];
+ n[Z] = u[X] * v[Y] - u[Y] * v[X];
+}
+
+/* _glmNormalize: normalize a vector
+ *
+ * n - array of 3 floats (float n[3]) to be normalized
+ */
+static void
+_glmNormalize(float* n)
+{
+ float l;
+
+ assert(n);
+
+ /* normalize */
+ l = (float)sqrt(n[X] * n[X] + n[Y] * n[Y] + n[Z] * n[Z]);
+ n[0] /= l;
+ n[1] /= l;
+ n[2] /= l;
+}
+
+/* _glmEqual: compares two vectors and returns true if they are
+ * equal (within a certain threshold) or false if not. An epsilon
+ * that works fairly well is 0.000001.
+ *
+ * u - array of 3 floats (float u[3])
+ * v - array of 3 floats (float v[3])
+ */
+static bool
+_glmEqual(float* u, float* v, float epsilon)
+{
+ if (_glmAbs(u[0] - v[0]) < epsilon &&
+ _glmAbs(u[1] - v[1]) < epsilon &&
+ _glmAbs(u[2] - v[2]) < epsilon)
+ {
+ return true;
+ }
+ return false;
+}
+
+/* _glmWeldVectors: eliminate (weld) vectors that are within an
+ * epsilon of each other.
+ *
+ * vectors - array of float[3]'s to be welded
+ * numvectors - number of float[3]'s in vectors
+ * epsilon - maximum difference between vectors
+ *
+ */
+float*
+_glmWeldVectors(float* vectors, unsigned int* numvectors, float epsilon)
+{
+ float* copies;
+ unsigned int copied;
+ unsigned int i, j;
+
+ copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1));
+ memcpy(copies, vectors, (sizeof(float) * 3 * (*numvectors + 1)));
+
+ copied = 1;
+ for (i = 1; i <= *numvectors; i++) {
+ for (j = 1; j <= copied; j++) {
+ if (_glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) {
+ goto duplicate;
+ }
+ }
+
+ /* must not be any duplicates -- add to the copies array */
+ copies[3 * copied + 0] = vectors[3 * i + 0];
+ copies[3 * copied + 1] = vectors[3 * i + 1];
+ copies[3 * copied + 2] = vectors[3 * i + 2];
+ j = copied; /* pass this along for below
*/
+ copied++;
+
+ duplicate:
+ /* set the first component of this vector to point at the correct
+ index into the new copies array */
+ vectors[3 * i + 0] = (float)j;
+ }
+
+ *numvectors = copied-1;
+ return copies;
+}
+
+/* _glmFindGroup: Find a group in the model
+ */
+GLMgroup*
+_glmFindGroup(GLMmodel* model, char* name)
+{
+ GLMgroup* group;
+
+ assert(model);
+
+ group = model->groups;
+ while(group) {
+ if (!strcmp(name, group->name))
+ break;
+ group = group->next;
+ }
+
+ return group;
+}
+
+/* _glmAddGroup: Add a group to the model
+ */
+GLMgroup*
+_glmAddGroup(GLMmodel* model, char* name)
+{
+ GLMgroup* group;
+
+ group = _glmFindGroup(model, name);
+ if (!group) {
+ group = (GLMgroup*)malloc(sizeof(GLMgroup));
+ group->name = strdup(name);
+ group->material = 0;
+ group->numtriangles = 0;
+ group->triangles = NULL;
+ group->next = model->groups;
+ model->groups = group;
+ model->numgroups++;
+ }
+
+ return group;
+}
+
+/* _glmFindGroup: Find a material in the model
+ */
+unsigned int
+_glmFindMaterial(GLMmodel* model, char* name)
+{
+ unsigned int i;
+
+ for (i = 0; i < model->nummaterials; i++) {
+ if (!strcmp(model->materials[i].name, name))
+ goto found;
+ }
+
+ /* didn't find the name, so set it as the default material */
+ printf("_glmFindMaterial(): can't find material \"%s\".\n", name);
+ i = 0;
+
+ found:
+ return i;
+}
+
+
+/* _glmDirName: return the directory given a path
+ *
+ * path - filesystem path
+ *
+ * The return value should be free'd.
+ */
+static char*
+_glmDirName(char* path)
+{
+ char* dir;
+ char* s;
+
+ dir = strdup(path);
+
+ s = strrchr(dir, '/');
+ if (s)
+ s[1] = '\0';
+ else
+ dir[0] = '\0';
+
+ return dir;
+}
+
+
+/* _glmReadMTL: read a wavefront material library file
+ *
+ * model - properly initialized GLMmodel structure
+ * name - name of the material library
+ */
+static int
+_glmReadMTL(GLMmodel* model, char* name)
+{
+ FILE* file;
+ char* dir;
+ char* filename;
+ char buf[128];
+ unsigned int nummaterials, i;
+
+ dir = _glmDirName(model->pathname);
+ filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1));
+ strcpy(filename, dir);
+ strcat(filename, name);
+ free(dir);
+
+ /* open the file */
+ file = fopen(filename, "r");
+ if (!file) {
+ fprintf(stderr, "_glmReadMTL() failed: can't open material file
\"%s\".\n",
+ filename);
+ free(filename);
+ return 1;
+ }
+ free(filename);
+
+ /* count the number of materials in the file */
+ nummaterials = 1;
+ while(fscanf(file, "%s", buf) != EOF) {
+ switch(buf[0]) {
+ case '#': /* comment */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ case 'n': /* newmtl */
+ fgets(buf, sizeof(buf), file);
+ nummaterials++;
+ sscanf(buf, "%s %s", buf, buf);
+ break;
+ default:
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ }
+ }
+
+ rewind(file);
+
+ /* allocate memory for the materials */
+ model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) *
nummaterials);
+ model->nummaterials = nummaterials;
+
+ /* set the default material */
+ for (i = 0; i < nummaterials; i++) {
+ model->materials[i].name = NULL;
+ model->materials[i].shininess = 0;
+ model->materials[i].diffuse[0] = 0.8;
+ model->materials[i].diffuse[1] = 0.8;
+ model->materials[i].diffuse[2] = 0.8;
+ model->materials[i].diffuse[3] = 1.0;
+ model->materials[i].ambient[0] = 0.2;
+ model->materials[i].ambient[1] = 0.2;
+ model->materials[i].ambient[2] = 0.2;
+ model->materials[i].ambient[3] = 1.0;
+ model->materials[i].specular[0] = 0.0;
+ model->materials[i].specular[1] = 0.0;
+ model->materials[i].specular[2] = 0.0;
+ model->materials[i].specular[3] = 1.0;
+ }
+ model->materials[0].name = strdup("default");
+
+ /* now, read in the data */
+ nummaterials = 0;
+ while(fscanf(file, "%s", buf) != EOF) {
+ switch(buf[0]) {
+ case '#': /* comment */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ case 'n': /* newmtl */
+ fgets(buf, sizeof(buf), file);
+ sscanf(buf, "%s %s", buf, buf);
+ nummaterials++;
+ model->materials[nummaterials].name = strdup(buf);
+ break;
+ case 'N':
+ fscanf(file, "%f", &model->materials[nummaterials].shininess);
+ /* wavefront shininess is from [0, 1000], so scale for OpenGL */
+ model->materials[nummaterials].shininess /= 1000.0;
+ model->materials[nummaterials].shininess *= 128.0;
+ break;
+ case 'K':
+ switch(buf[1]) {
+ case 'd':
+ fscanf(file, "%f %f %f",
+ &model->materials[nummaterials].diffuse[0],
+ &model->materials[nummaterials].diffuse[1],
+ &model->materials[nummaterials].diffuse[2]);
+ break;
+ case 's':
+ fscanf(file, "%f %f %f",
+ &model->materials[nummaterials].specular[0],
+ &model->materials[nummaterials].specular[1],
+ &model->materials[nummaterials].specular[2]);
+ break;
+ case 'a':
+ fscanf(file, "%f %f %f",
+ &model->materials[nummaterials].ambient[0],
+ &model->materials[nummaterials].ambient[1],
+ &model->materials[nummaterials].ambient[2]);
+ break;
+ default:
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ }
+ break;
+ default:
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ }
+ }
+ return 0;
+}
+
+/* _glmWriteMTL: write a wavefront material library file
+ *
+ * model - properly initialized GLMmodel structure
+ * modelpath - pathname of the model being written
+ * mtllibname - name of the material library to be written
+ */
+static int
+_glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname)
+{
+ FILE* file;
+ char* dir;
+ char* filename;
+ GLMmaterial* material;
+ unsigned int i;
+
+ dir = _glmDirName(modelpath);
+ filename = (char*)malloc(sizeof(char) * (strlen(dir) +
strlen(mtllibname)));
+ strcpy(filename, dir);
+ strcat(filename, mtllibname);
+ free(dir);
+
+ /* open the file */
+ file = fopen(filename, "w");
+ if (!file) {
+ fprintf(stderr, "_glmWriteMTL() failed: can't open file \"%s\".\n",
+ filename);
+ free(filename);
+ return 1;
+ }
+ free(filename);
+
+ /* spit out a header */
+ fprintf(file, "# \n");
+ fprintf(file, "# Wavefront MTL generated by GLM library\n");
+ fprintf(file, "# \n");
+ fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n");
+ fprintf(file, "# email: ndr@pobox.com\n");
+ fprintf(file, "# www:
http://www.pobox.com/~ndr\n");
+ fprintf(file, "# \n\n");
+
+ for (i = 0; i < model->nummaterials; i++) {
+ material = &model->materials[i];
+ fprintf(file, "newmtl %s\n", material->name);
+ fprintf(file, "Ka %f %f %f\n",
+ material->ambient[0], material->ambient[1], material->ambient[2]);
+ fprintf(file, "Kd %f %f %f\n",
+ material->diffuse[0], material->diffuse[1], material->diffuse[2]);
+ fprintf(file, "Ks %f %f %f\n",
+
material->specular[0],material->specular[1],material->specular[2]);
+ fprintf(file, "Ns %f\n", material->shininess);
+ fprintf(file, "\n");
+ }
+ return 0;
+}
+
+/* _glmFirstPass: first pass at a Wavefront OBJ file that gets all the
+ * statistics of the model (such as #vertices, #normals, etc)
+ *
+ * model - properly initialized GLMmodel structure
+ * file - (fopen'd) file descriptor
+ */
+static int
+_glmFirstPass(GLMmodel* model, FILE* file)
+{
+ unsigned int numvertices; /* number of vertices in model */
+ unsigned int numnormals; /* number of normals in model
*/
+ unsigned int numtexcoords; /* number of texcoords in
model */
+ unsigned int numtriangles; /* number of triangles in
model */
+
+
+
+ GLMgroup* group; /* current group */
+ int v, n, t;
+ char buf[128];
+
+ /* make a default group */
+ group = _glmAddGroup(model, "default");
+
+ numvertices = numnormals = numtexcoords = numtriangles = 0;
+
+ while(fscanf(file, "%s", buf) != EOF) {
+ switch(buf[0]) {
+ case '#': /* comment */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ case 'v': /* v, vn, vt */
+ switch(buf[1]) {
+ case '\0': { /* vertex */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+
+ // TODO: Check if colors for this vertex
+ float vx,vy,vz;
+ int val = -1;
+ sscanf(buf,"%f %f %f %d",&vx, &vy, &vz, &val);
+ if (val >= 0) {
+ model->usePerVertexColors = true;
+ }
+
+ numvertices++;
+ break;
+ }
+ case 'n': /* normal */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ numnormals++;
+ break;
+ case 't': /* texcoord */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ numtexcoords++;
+ break;
+ default:
+ printf("_glmFirstPass(): Unknown token \"%s\".\n", buf);
+ /* Could error out here, but we'll just skip it for now.*/
+ /* return 1; */
+ break;
+ }
+ break;
+ case 'm':
+ fgets(buf, sizeof(buf), file);
+ sscanf(buf, "%s %s", buf, buf);
+ model->mtllibname = strdup(buf);
+ if (_glmReadMTL(model, buf)) {
+ /* Uh oh. Trouble reading in the material file. */
+ return 1;
+ }
+ break;
+ case 'u':
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ case 'o':
+ case 'g': /* group */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ sscanf(buf, "%s", buf);
+ group = _glmAddGroup(model, buf);
+ break;
+ case 'f': /* face */
+ v = n = t = 0;
+ fscanf(file, "%s", buf);
+ /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
+ if (strstr(buf, "//")) {
+ /* v//n */
+ sscanf(buf, "%d//%d", &v, &n);
+ fscanf(file, "%d//%d", &v, &n);
+ fscanf(file, "%d//%d", &v, &n);
+ numtriangles++;
+ group->numtriangles++;
+ while(fscanf(file, "%d//%d", &v, &n) > 0) {
+ numtriangles++;
+ group->numtriangles++;
+ }
+ } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
+ /* v/t/n */
+ fscanf(file, "%d/%d/%d", &v, &t, &n);
+ fscanf(file, "%d/%d/%d", &v, &t, &n);
+ numtriangles++;
+ group->numtriangles++;
+ while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
+ numtriangles++;
+ group->numtriangles++;
+ }
+ } else if (sscanf(buf, "%d/%d", &v, &t) == 2) {
+ /* v/t */
+ fscanf(file, "%d/%d", &v, &t);
+ fscanf(file, "%d/%d", &v, &t);
+ numtriangles++;
+ group->numtriangles++;
+ while(fscanf(file, "%d/%d", &v, &t) > 0) {
+ numtriangles++;
+ group->numtriangles++;
+ }
+ } else {
+ /* v */
+ fscanf(file, "%d", &v);
+ fscanf(file, "%d", &v);
+ numtriangles++;
+ group->numtriangles++;
+ while(fscanf(file, "%d", &v) > 0) {
+ numtriangles++;
+ group->numtriangles++;
+ }
+ }
+ break;
+
+ default:
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ }
+ }
+
+ // #if 0
+ /* announce the model statistics */
+ // printf(" Vertices: %d\n", numvertices);
+ // printf(" Normals: %d\n", numnormals);
+ // printf(" Texcoords: %d\n", numtexcoords);
+ // printf(" Triangles: %d\n", numtriangles);
+ // printf(" Groups: %d\n", model->numgroups);
+ // #endif
+
+ /* set the stats in the model structure */
+ model->numvertices = numvertices;
+ model->numnormals = numnormals;
+ model->numtexcoords = numtexcoords;
+ model->numtriangles = numtriangles;
+
+ /* allocate memory for the triangles in each group */
+ group = model->groups;
+ while(group) {
+ group->triangles = (unsigned int*)malloc(sizeof(unsigned int) *
group->numtriangles);
+ group->numtriangles = 0;
+ group = group->next;
+ }
+ return 0;
+}
+
+/* _glmSecondPass: second pass at a Wavefront OBJ file that gets all
+ * the data.
+ *
+ * model - properly initialized GLMmodel structure
+ * file - (fopen'd) file descriptor
+ */
+static void
+_glmSecondPass(GLMmodel* model, FILE* file)
+{
+ unsigned int numvertices; /* number of vertices in model */
+ unsigned int numnormals; /* number of normals in model
*/
+ unsigned int numtexcoords; /* number of texcoords in
model */
+ unsigned int numtriangles; /* number of triangles in
model */
+ float* vertices; /* array of vertices */
+ unsigned char* vertexColors; /* array of vertex colors */
+ float* normals; /* array of normals */
+ float* texcoords; /* array of texture coordinates */
+ GLMgroup* group; /* current group pointer */
+ unsigned int material; /* current material */
+ int v, n, t;
+ char buf[128];
+
+ /* set the pointer shortcuts */
+ vertices = model->vertices;
+ vertexColors = model->vertexColors;
+ normals = model->normals;
+ texcoords = model->texcoords;
+ group = model->groups;
+
+ /* on the second pass through the file, read all the data into the
+ allocated arrays */
+ numvertices = numnormals = numtexcoords = 1;
+ numtriangles = 0;
+ material = 0;
+ while(fscanf(file, "%s", buf) != EOF) {
+ switch(buf[0]) {
+ case '#': /* comment */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ case 'v': /* v, vn, vt */
+ switch(buf[1]) {
+ case '\0': /* vertex */
+ if (!model->usePerVertexColors) {
+ fscanf(file, "%f %f %f",
+ &vertices[3 * numvertices + X],
+ &vertices[3 * numvertices + Y],
+ &vertices[3 * numvertices + Z]);
+ }
+ else {
+ int r,g,b;
+ fscanf(file, "%f %f %f %d %d %d",
+ &vertices[3 * numvertices + X],
+ &vertices[3 * numvertices + Y],
+ &vertices[3 * numvertices + Z], &r, &g, &b);
+ vertexColors[3 * numvertices + X] = (unsigned char)r;
+ vertexColors[3 * numvertices + Y] = (unsigned char)g;
+ vertexColors[3 * numvertices + Z] = (unsigned char)b;
+ }
+ numvertices++;
+ break;
+ case 'n': /* normal */
+ fscanf(file, "%f %f %f",
+ &normals[3 * numnormals + X],
+ &normals[3 * numnormals + Y],
+ &normals[3 * numnormals + Z]);
+ numnormals++;
+ break;
+ case 't': /* texcoord */
+ fscanf(file, "%f %f",
+ &texcoords[2 * numtexcoords + X],
+ &texcoords[2 * numtexcoords + Y]);
+ numtexcoords++;
+ break;
+ }
+ break;
+ case 'u':
+ fgets(buf, sizeof(buf), file);
+ sscanf(buf, "%s %s", buf, buf);
+ group->material = material = _glmFindMaterial(model, buf);
+ break;
+ case 'o':
+ case 'g': /* group */
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ sscanf(buf, "%s", buf);
+ group = _glmFindGroup(model, buf);
+ group->material = material;
+ break;
+ case 'f': /* face */
+ v = n = t = 0;
+ fscanf(file, "%s", buf);
+ /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
+ if (strstr(buf, "//")) {
+ /* v//n */
+ sscanf(buf, "%d//%d", &v, &n);
+ T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).nindices[0] = n;
+ fscanf(file, "%d//%d", &v, &n);
+ T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).nindices[1] = n;
+ fscanf(file, "%d//%d", &v, &n);
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).nindices[2] = n;
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ while(fscanf(file, "%d//%d", &v, &n) > 0) {
+ T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
+ T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
+ T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
+ T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).nindices[2] = n;
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ }
+ } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
+ /* v/t/n */
+ T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[0] = t;
+ T(numtriangles).nindices[0] = n;
+ fscanf(file, "%d/%d/%d", &v, &t, &n);
+ T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[1] = t;
+ T(numtriangles).nindices[1] = n;
+ fscanf(file, "%d/%d/%d", &v, &t, &n);
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[2] = t;
+ T(numtriangles).nindices[2] = n;
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
+ T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
+ T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
+ T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
+ T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
+ T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
+ T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[2] = t;
+ T(numtriangles).nindices[2] = n;
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ }
+ } else if (sscanf(buf, "%d/%d", &v, &t) == 2) {
+ /* v/t */
+ T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[0] = t;
+ fscanf(file, "%d/%d", &v, &t);
+ T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[1] = t;
+ fscanf(file, "%d/%d", &v, &t);
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[2] = t;
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ while(fscanf(file, "%d/%d", &v, &t) > 0) {
+ T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
+ T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
+ T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
+ T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ T(numtriangles).tindices[2] = t;
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ }
+ } else {
+ /* v */
+ sscanf(buf, "%d", &v);
+ T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v);
+ fscanf(file, "%d", &v);
+ T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+ fscanf(file, "%d", &v);
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ while(fscanf(file, "%d", &v) > 0) {
+ T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
+ T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
+ T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
+ group->triangles[group->numtriangles++] = numtriangles;
+ numtriangles++;
+ }
+ }
+ break;
+
+ default:
+ /* eat up rest of line */
+ fgets(buf, sizeof(buf), file);
+ break;
+ }
+ }
+
+#if 0
+ /* announce the memory requirements */
+ printf(" Memory: %d bytes\n",
+ numvertices * 3*sizeof(float) +
+ numnormals * 3*sizeof(float) * (numnormals ? 1 : 0) +
+ numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) +
+ numtriangles * sizeof(GLMtriangle));
+#endif
+}
+
+
+
+
+/* public functions */
+
+/* glmUnitize: "unitize" a model by translating it to the origin and
+ * scaling it to fit in a unit cube around the origin. Returns the
+ * scalefactor used.
+ *
+ * model - properly initialized GLMmodel structure
+ */
+float
+glmUnitize(GLMmodel* model)
+{
+ unsigned int i;
+ float maxx, minx, maxy, miny, maxz, minz;
+ float cx, cy, cz, w, h, d;
+ float scale;
+
+ assert(model);
+ assert(model->vertices);
+
+ /* get the max/mins */
+ maxx = minx = model->vertices[3 + X];
+ maxy = miny = model->vertices[3 + Y];
+ maxz = minz = model->vertices[3 + Z];
+ for (i = 1; i <= model->numvertices; i++) {
+ if (maxx < model->vertices[3 * i + X])
+ maxx = model->vertices[3 * i + X];
+ if (minx > model->vertices[3 * i + X])
+ minx = model->vertices[3 * i + X];
+
+ if (maxy < model->vertices[3 * i + Y])
+ maxy = model->vertices[3 * i + Y];
+ if (miny > model->vertices[3 * i + Y])
+ miny = model->vertices[3 * i + Y];
+
+ if (maxz < model->vertices[3 * i + Z])
+ maxz = model->vertices[3 * i + Z];
+ if (minz > model->vertices[3 * i + Z])
+ minz = model->vertices[3 * i + Z];
+ }
+
+ /* calculate model width, height, and depth */
+ w = _glmAbs(maxx) + _glmAbs(minx);
+ h = _glmAbs(maxy) + _glmAbs(miny);
+ d = _glmAbs(maxz) + _glmAbs(minz);
+
+ /* calculate center of the model */
+ cx = (maxx + minx) / 2.0;
+ cy = (maxy + miny) / 2.0;
+ cz = (maxz + minz) / 2.0;
+
+ /* calculate unitizing scale factor */
+ scale = 2.0 / _glmMax(_glmMax(w, h), d);
+
+ /* translate around center then scale */
+ for (i = 1; i <= model->numvertices; i++) {
+ model->vertices[3 * i + X] -= cx;
+ model->vertices[3 * i + Y] -= cy;
+ model->vertices[3 * i + Z] -= cz;
+ model->vertices[3 * i + X] *= scale;
+ model->vertices[3 * i + Y] *= scale;
+ model->vertices[3 * i + Z] *= scale;
+ }
+
+ return scale;
+}
+
+/* glmDimensions: Calculates the dimensions (width, height, depth) of
+ * a model.
+ *
+ * model - initialized GLMmodel structure
+ * dimensions - array of 3 floats (float dimensions[3])
+ */
+void
+glmDimensions(GLMmodel* model, float* dimensions)
+{
+ unsigned int i;
+ float maxx, minx, maxy, miny, maxz, minz;
+
+ assert(model);
+ assert(model->vertices);
+ assert(dimensions);
+
+ /* get the max/mins */
+ maxx = minx = model->vertices[3 + X];
+ maxy = miny = model->vertices[3 + Y];
+ maxz = minz = model->vertices[3 + Z];
+ for (i = 1; i <= model->numvertices; i++) {
+ if (maxx < model->vertices[3 * i + X])
+ maxx = model->vertices[3 * i + X];
+ if (minx > model->vertices[3 * i + X])
+ minx = model->vertices[3 * i + X];
+
+ if (maxy < model->vertices[3 * i + Y])
+ maxy = model->vertices[3 * i + Y];
+ if (miny > model->vertices[3 * i + Y])
+ miny = model->vertices[3 * i + Y];
+
+ if (maxz < model->vertices[3 * i + Z])
+ maxz = model->vertices[3 * i + Z];
+ if (minz > model->vertices[3 * i + Z])
+ minz = model->vertices[3 * i + Z];
+ }
+
+ /* calculate model width, height, and depth */
+ dimensions[X] = _glmAbs(maxx) + _glmAbs(minx);
+ dimensions[Y] = _glmAbs(maxy) + _glmAbs(miny);
+ dimensions[Z] = _glmAbs(maxz) + _glmAbs(minz);
+}
+
+/*
+ * glmBoundingBox: Calculates the min/max positions of the model
+ */
+void
+glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos)
+{
+ unsigned int i;
+ float maxx, minx, maxy, miny, maxz, minz;
+
+ assert(model);
+ assert(model->vertices);
+ assert(minpos);
+ assert(maxpos);
+
+ /* get the max/mins */
+ maxx = minx = model->vertices[3 + X];
+ maxy = miny = model->vertices[3 + Y];
+ maxz = minz = model->vertices[3 + Z];
+ for (i = 1; i <= model->numvertices; i++) {
+ if (maxx < model->vertices[3 * i + X])
+ maxx = model->vertices[3 * i + X];
+ if (minx > model->vertices[3 * i + X])
+ minx = model->vertices[3 * i + X];
+
+ if (maxy < model->vertices[3 * i + Y])
+ maxy = model->vertices[3 * i + Y];
+ if (miny > model->vertices[3 * i + Y])
+ miny = model->vertices[3 * i + Y];
+
+ if (maxz < model->vertices[3 * i + Z])
+ maxz = model->vertices[3 * i + Z];
+ if (minz > model->vertices[3 * i + Z])
+ minz = model->vertices[3 * i + Z];
+ }
+
+ minpos[0] = minx;
+ minpos[1] = miny;
+ minpos[2] = minz;
+ maxpos[0] = maxx;
+ maxpos[1] = maxy;
+ maxpos[2] = maxz;
+
+}
+
+/* glmScale: Scales a model by a given amount.
+ *
+ * model - properly initialized GLMmodel structure
+ * scale - scalefactor (0.5 = half as large, 2.0 = twice as large)
+ */
+void
+glmScale(GLMmodel* model, float scale)
+{
+ unsigned int i;
+
+ for (i = 1; i <= model->numvertices; i++) {
+ model->vertices[3 * i + X] *= scale;
+ model->vertices[3 * i + Y] *= scale;
+ model->vertices[3 * i + Z] *= scale;
+ }
+}
+
+/* glmReverseWinding: Reverse the polygon winding for all polygons in
+ * this model. Default winding is counter-clockwise. Also changes
+ * the direction of the normals.
+ *
+ * model - properly initialized GLMmodel structure
+ */
+void
+glmReverseWinding(GLMmodel* model)
+{
+ unsigned int i, swap;
+
+ assert(model);
+
+ for (i = 0; i < model->numtriangles; i++) {
+ swap = T(i).vindices[0];
+ T(i).vindices[0] = T(i).vindices[2];
+ T(i).vindices[2] = swap;
+
+ if (model->numnormals) {
+ swap = T(i).nindices[0];
+ T(i).nindices[0] = T(i).nindices[2];
+ T(i).nindices[2] = swap;
+ }
+
+ if (model->numtexcoords) {
+ swap = T(i).tindices[0];
+ T(i).tindices[0] = T(i).tindices[2];
+ T(i).tindices[2] = swap;
+ }
+ }
+
+ /* reverse facet normals */
+ for (i = 1; i <= model->numfacetnorms; i++) {
+ model->facetnorms[3 * i + X] = -model->facetnorms[3 * i + X];
+ model->facetnorms[3 * i + Y] = -model->facetnorms[3 * i + Y];
+ model->facetnorms[3 * i + Z] = -model->facetnorms[3 * i + Z];
+ }
+
+ /* reverse vertex normals */
+ for (i = 1; i <= model->numnormals; i++) {
+ model->normals[3 * i + X] = -model->normals[3 * i + X];
+ model->normals[3 * i + Y] = -model->normals[3 * i + Y];
+ model->normals[3 * i + Z] = -model->normals[3 * i + Z];
+ }
+}
+
+/* glmFacetNormals: Generates facet normals for a model (by taking the
+ * cross product of the two vectors derived from the sides of each
+ * triangle). Assumes a counter-clockwise winding.
+ *
+ * model - initialized GLMmodel structure
+ */
+void
+glmFacetNormals(GLMmodel* model)
+{
+ unsigned int i;
+ float u[3];
+ float v[3];
+
+ assert(model);
+ assert(model->vertices);
+
+ /* clobber any old facetnormals */
+ if (model->facetnorms)
+ free(model->facetnorms);
+
+ /* allocate memory for the new facet normals */
+ model->numfacetnorms = model->numtriangles;
+ model->facetnorms = (float*)malloc(sizeof(float) *
+ 3 * (model->numfacetnorms + 1));
+
+ for (i = 0; i < model->numtriangles; i++) {
+ model->triangles[i].findex = i+1;
+
+ u[X] = model->vertices[3 * T(i).vindices[1] + X] -
+ model->vertices[3 * T(i).vindices[0] + X];
+ u[Y] = model->vertices[3 * T(i).vindices[1] + Y] -
+ model->vertices[3 * T(i).vindices[0] + Y];
+ u[Z] = model->vertices[3 * T(i).vindices[1] + Z] -
+ model->vertices[3 * T(i).vindices[0] + Z];
+
+ v[X] = model->vertices[3 * T(i).vindices[2] + X] -
+ model->vertices[3 * T(i).vindices[0] + X];
+ v[Y] = model->vertices[3 * T(i).vindices[2] + Y] -
+ model->vertices[3 * T(i).vindices[0] + Y];
+ v[Z] = model->vertices[3 * T(i).vindices[2] + Z] -
+ model->vertices[3 * T(i).vindices[0] + Z];
+
+ _glmCross(u, v, &model->facetnorms[3 * (i+1)]);
+ _glmNormalize(&model->facetnorms[3 * (i+1)]);
+ }
+}
+
+/* glmVertexNormals: Generates smooth vertex normals for a model.
+ * First builds a list of all the triangles each vertex is in. Then
+ * loops through each vertex in the the list averaging all the facet
+ * normals of the triangles each vertex is in. Finally, sets the
+ * normal index in the triangle for the vertex to the generated smooth
+ * normal. If the dot product of a facet normal and the facet normal
+ * associated with the first triangle in the list of triangles the
+ * current vertex is in is greater than the cosine of the angle
+ * parameter to the function, that facet normal is not added into the
+ * average normal calculation and the corresponding vertex is given
+ * the facet normal. This tends to preserve hard edges. The angle to
+ * use depends on the model, but 90 degrees is usually a good start.
+ *
+ * model - initialized GLMmodel structure
+ * angle - maximum angle (in degrees) to smooth across
+ */
+void
+glmVertexNormals(GLMmodel* model, float angle)
+{
+ GLMnode* node;
+ GLMnode* tail;
+ GLMnode** members;
+ float* normals;
+ unsigned int numnormals;
+ float average[3];
+ float dot, cos_angle;
+ unsigned int i, avg;
+
+ assert(model);
+ assert(model->facetnorms);
+
+ /* calculate the cosine of the angle (in degrees) */
+ cos_angle = cos(angle * M_PI / 180.0);
+
+ /* nuke any previous normals */
+ if (model->normals)
+ free(model->normals);
+
+ /* allocate space for new normals */
+ model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */
+ model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1));
+
+ /* allocate a structure that will hold a linked list of triangle
+ indices for each vertex */
+ members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1));
+ for (i = 1; i <= model->numvertices; i++)
+ members[i] = NULL;
+
+ /* for every triangle, create a node for each vertex in it */
+ for (i = 0; i < model->numtriangles; i++) {
+ node = (GLMnode*)malloc(sizeof(GLMnode));
+ node->index = i;
+ node->next = members[T(i).vindices[0]];
+ members[T(i).vindices[0]] = node;
+
+ node = (GLMnode*)malloc(sizeof(GLMnode));
+ node->index = i;
+ node->next = members[T(i).vindices[1]];
+ members[T(i).vindices[1]] = node;
+
+ node = (GLMnode*)malloc(sizeof(GLMnode));
+ node->index = i;
+ node->next = members[T(i).vindices[2]];
+ members[T(i).vindices[2]] = node;
+ }
+
+ /* calculate the average normal for each vertex */
+ numnormals = 1;
+ for (i = 1; i <= model->numvertices; i++) {
+ /* calculate an average normal for this vertex by averaging the
+ facet normal of every triangle this vertex is in */
+ node = members[i];
+ if (!node)
+ fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n");
+ average[0] = 0.0; average[1] = 0.0; average[2] = 0.0;
+ avg = 0;
+ while (node) {
+ /* only average if the dot product of the angle between the two
+ facet normals is greater than the cosine of the threshold
+ angle -- or, said another way, the angle between the two
+ facet normals is less than (or equal to) the threshold angle */
+ dot = _glmDot(&model->facetnorms[3 * T(node->index).findex],
+ &model->facetnorms[3 * T(members[i]->index).findex]);
+ if (dot > cos_angle) {
+ node->averaged = true;
+ average[0] += model->facetnorms[3 * T(node->index).findex + 0];
+ average[1] += model->facetnorms[3 * T(node->index).findex + 1];
+ average[2] += model->facetnorms[3 * T(node->index).findex + 2];
+ avg = 1; /* we averaged at least one normal! */
+ } else {
+ node->averaged = false;
+ }
+ node = node->next;
+ }
+
+ if (avg) {
+ /* normalize the averaged normal */
+ _glmNormalize(average);
+
+ /* add the normal to the vertex normals list */
+ model->normals[3 * numnormals + 0] = average[0];
+ model->normals[3 * numnormals + 1] = average[1];
+ model->normals[3 * numnormals + 2] = average[2];
+ avg = numnormals;
+ numnormals++;
+ }
+
+ /* set the normal of this vertex in each triangle it is in */
+ node = members[i];
+ while (node) {
+ if (node->averaged) {
+ /* if this node was averaged, use the average normal */
+ if (T(node->index).vindices[0] == i)
+ T(node->index).nindices[0] = avg;
+ else if (T(node->index).vindices[1] == i)
+ T(node->index).nindices[1] = avg;
+ else if (T(node->index).vindices[2] == i)
+ T(node->index).nindices[2] = avg;
+ } else {
+ /* if this node wasn't averaged, use the facet normal */
+ model->normals[3 * numnormals + 0] =
+ model->facetnorms[3 * T(node->index).findex + 0];
+ model->normals[3 * numnormals + 1] =
+ model->facetnorms[3 * T(node->index).findex + 1];
+ model->normals[3 * numnormals + 2] =
+ model->facetnorms[3 * T(node->index).findex + 2];
+ if (T(node->index).vindices[0] == i)
+ T(node->index).nindices[0] = numnormals;
+ else if (T(node->index).vindices[1] == i)
+ T(node->index).nindices[1] = numnormals;
+ else if (T(node->index).vindices[2] == i)
+ T(node->index).nindices[2] = numnormals;
+ numnormals++;
+ }
+ node = node->next;
+ }
+ }
+
+ model->numnormals = numnormals - 1;
+
+ /* free the member information */
+ for (i = 1; i <= model->numvertices; i++) {
+ node = members[i];
+ while (node) {
+ tail = node;
+ node = node->next;
+ free(tail);
+ }
+ }
+ free(members);
+
+ /* pack the normals array (we previously allocated the maximum
+ number of normals that could possibly be created (numtriangles *
+ 3), so get rid of some of them (usually alot unless none of the
+ facet normals were averaged)) */
+ normals = model->normals;
+ model->normals = (float*)malloc(sizeof(float)* 3* (model->numnormals+1));
+ for (i = 1; i <= model->numnormals; i++) {
+ model->normals[3 * i + 0] = normals[3 * i + 0];
+ model->normals[3 * i + 1] = normals[3 * i + 1];
+ model->normals[3 * i + 2] = normals[3 * i + 2];
+ }
+ free(normals);
+
+ printf("glmVertexNormals(): %d normals generated\n", model->numnormals);
+}
+
+
+/* glmLinearTexture: Generates texture coordinates according to a
+ * linear projection of the texture map. It generates these by
+ * linearly mapping the vertices onto a square.
+ *
+ * model - pointer to initialized GLMmodel structure
+ */
+void
+glmLinearTexture(GLMmodel* model)
+{
+ GLMgroup *group;
+ float dimensions[3];
+ float x, y, scalefactor;
+ unsigned int i;
+
+ assert(model);
+
+ if (model->texcoords)
+ free(model->texcoords);
+ model->numtexcoords = model->numvertices;
+ model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
+
+ glmDimensions(model, dimensions);
+ scalefactor = 2.0 /
+ _glmAbs(_glmMax(_glmMax(dimensions[0], dimensions[1]), dimensions[2]));
+
+ /* do the calculations */
+ for(i = 1; i <= model->numvertices; i++) {
+ x = model->vertices[3 * i + 0] * scalefactor;
+ y = model->vertices[3 * i + 2] * scalefactor;
+ model->texcoords[2 * i + 0] = (x + 1.0) / 2.0;
+ model->texcoords[2 * i + 1] = (y + 1.0) / 2.0;
+ }
+
+ /* go through and put texture coordinate indices in all the triangles */
+ group = model->groups;
+ while(group) {
+ for(i = 0; i < group->numtriangles; i++) {
+ T(group->triangles[i]).tindices[0] =
T(group->triangles[i]).vindices[0];
+ T(group->triangles[i]).tindices[1] =
T(group->triangles[i]).vindices[1];
+ T(group->triangles[i]).tindices[2] =
T(group->triangles[i]).vindices[2];
+ }
+ group = group->next;
+ }
+
+#if 0
+ printf("glmLinearTexture(): generated %d linear texture coordinates\n",
+ model->numtexcoords);
+#endif
+}
+
+/* glmSpheremapTexture: Generates texture coordinates according to a
+ * spherical projection of the texture map. Sometimes referred to as
+ * spheremap, or reflection map texture coordinates. It generates
+ * these by using the normal to calculate where that vertex would map
+ * onto a sphere. Since it is impossible to map something flat
+ * perfectly onto something spherical, there is distortion at the
+ * poles. This particular implementation causes the poles along the X
+ * axis to be distorted.
+ *
+ * model - pointer to initialized GLMmodel structure
+ */
+void
+glmSpheremapTexture(GLMmodel* model)
+{
+ GLMgroup* group;
+ float theta, phi, rho, x, y, z, r;
+ unsigned int i;
+
+ assert(model);
+ assert(model->normals);
+
+ if (model->texcoords)
+ free(model->texcoords);
+ model->numtexcoords = model->numnormals;
+ model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
+
+ /* do the calculations */
+ for (i = 1; i <= model->numnormals; i++) {
+ z = model->normals[3 * i + 0]; /* re-arrange for pole distortion */
+ y = model->normals[3 * i + 1];
+ x = model->normals[3 * i + 2];
+ r = sqrt((x * x) + (y * y));
+ rho = sqrt((r * r) + (z * z));
+
+ if(r == 0.0) {
+ theta = 0.0;
+ phi = 0.0;
+ } else {
+ if(z == 0.0)
+ phi = 3.14159265 / 2.0;
+ else
+ phi = acos(z / rho);
+
+#if WE_DONT_NEED_THIS_CODE
+ if(x == 0.0)
+ theta = 3.14159265 / 2.0; /* asin(y / r); */
+ else
+ theta = acos(x / r);
+#endif
+
+ if(y == 0.0)
+ theta = 3.141592365 / 2.0; /* acos(x / r); */
+ else
+ theta = asin(y / r) + (3.14159265 / 2.0);
+ }
+
+ model->texcoords[2 * i + 0] = theta / 3.14159265;
+ model->texcoords[2 * i + 1] = phi / 3.14159265;
+ }
+
+ /* go through and put texcoord indices in all the triangles */
+ group = model->groups;
+ while(group) {
+ for (i = 0; i < group->numtriangles; i++) {
+ T(group->triangles[i]).tindices[0] =
T(group->triangles[i]).nindices[0];
+ T(group->triangles[i]).tindices[1] =
T(group->triangles[i]).nindices[1];
+ T(group->triangles[i]).tindices[2] =
T(group->triangles[i]).nindices[2];
+ }
+ group = group->next;
+ }
+
+#if 0
+ printf("glmSpheremapTexture(): generated %d spheremap texture
coordinates\n",
+ model->numtexcoords);
+#endif
+}
+
+/* glmDelete: Deletes a GLMmodel structure.
+ *
+ * model - initialized GLMmodel structure
+ */
+void
+glmDelete(GLMmodel* model)
+{
+ GLMgroup* group;
+ unsigned int i;
+
+ assert(model);
+
+ if (model->pathname) free(model->pathname);
+ if (model->mtllibname) free(model->mtllibname);
+ if (model->vertices) free(model->vertices);
+ if (model->normals) free(model->normals);
+ if (model->texcoords) free(model->texcoords);
+ if (model->facetnorms) free(model->facetnorms);
+ if (model->triangles) free(model->triangles);
+ if (model->materials) {
+ for (i = 0; i < model->nummaterials; i++)
+ if (model->materials[i].name) free(model->materials[i].name);
+ free(model->materials);
+ }
+ while(model->groups) {
+ group = model->groups;
+ /* Take the group off the linked list. */
+ model->groups = model->groups->next;
+ if (group->name) free(group->name);
+ if (group->triangles) free(group->triangles);
+ free(group);
+ }
+
+ free(model);
+}
+
+/* glmReadOBJ: Reads a model description from a Wavefront .OBJ file.
+ * Returns a pointer to the created object which should be free'd with
+ * glmDelete().
+ *
+ * filename - name of the file containing the Wavefront .OBJ format data.
+ */
+GLMmodel*
+glmReadOBJ(const char* filename)
+{
+ GLMmodel* model;
+ FILE* file;
+
+ /* open the file */
+ file = fopen(filename, "r");
+ if (!file) {
+ perror("glmReadOBJ() failed: can't open data file");
+ return 0;
+ }
+
+#if 0
+ /* announce the model name */
+ printf("Model: %s\n", filename);
+#endif
+
+ /* allocate a new model */
+ model = (GLMmodel*)malloc(sizeof(GLMmodel));
+ model->pathname = strdup(filename);
+ model->mtllibname = NULL;
+ model->numvertices = 0;
+ model->vertices = NULL;
+ model->numnormals = 0;
+ model->normals = NULL;
+ model->numtexcoords = 0;
+ model->texcoords = NULL;
+ model->numfacetnorms = 0;
+ model->facetnorms = NULL;
+ model->numtriangles = 0;
+ model->triangles = NULL;
+ model->nummaterials = 0;
+ model->materials = NULL;
+ model->numgroups = 0;
+ model->groups = NULL;
+ model->position[0] = 0.0;
+ model->position[1] = 0.0;
+ model->position[2] = 0.0;
+
+ /* make a first pass through the file to get a count of the number
+ of vertices, normals, texcoords & triangles */
+ if (_glmFirstPass(model, file)) {
+ /* There was a problem here, so cleanup and exit. */
+ glmDelete(model);
+ fclose(file);
+ return 0;
+ }
+
+ /* allocate memory */
+ model->vertices = (float*)malloc(sizeof(float) *
+ 3 * (model->numvertices + 1));
+ model->vertexColors = (unsigned char*)malloc(sizeof(unsigned char) *
+ 3 * (model->numvertices + 1));
+ model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
+ model->numtriangles);
+ if (model->numnormals) {
+ model->normals = (float*)malloc(sizeof(float) *
+ 3 * (model->numnormals + 1));
+ }
+ if (model->numtexcoords) {
+ model->texcoords = (float*)malloc(sizeof(float) *
+ 2 * (model->numtexcoords + 1));
+ }
+
+ /* rewind to beginning of file and read in the data this pass */
+ rewind(file);
+
+ _glmSecondPass(model, file);
+
+ /* close the file */
+ fclose(file);
+
+ return model;
+}
+
+/* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to
+ * a file.
+ *
+ * model - initialized GLMmodel structure
+ * filename - name of the file to write the Wavefront .OBJ format data to
+ * mode - a bitwise or of values describing what is written to the file
+ * GLM_NONE - render with only vertices
+ * GLM_FLAT - render with facet normals
+ * GLM_SMOOTH - render with vertex normals
+ * GLM_TEXTURE - render with texture coords
+ * GLM_COLOR - render with colors (color material)
+ * GLM_MATERIAL - render with materials
+ * GLM_COLOR and GLM_MATERIAL should not both be specified.
+ * GLM_FLAT and GLM_SMOOTH should not both be specified.
+ */
+int
+glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode)
+{
+ unsigned int i;
+ FILE* file;
+ GLMgroup* group;
+
+ assert(model);
+
+ /* do a bit of warning */
+ if (mode & GLM_FLAT && !model->facetnorms) {
+ printf("glmWriteOBJ() warning: flat normal output requested "
+ "with no facet normals defined.\n");
+ mode &= ~GLM_FLAT;
+ }
+ if (mode & GLM_SMOOTH && !model->normals) {
+ printf("glmWriteOBJ() warning: smooth normal output requested "
+ "with no normals defined.\n");
+ mode &= ~GLM_SMOOTH;
+ }
+ if (mode & GLM_TEXTURE && !model->texcoords) {
+ printf("glmWriteOBJ() warning: texture coordinate output requested "
+ "with no texture coordinates defined.\n");
+ mode &= ~GLM_TEXTURE;
+ }
+ if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
+ printf("glmWriteOBJ() warning: flat normal output requested "
+ "and smooth normal output requested (using smooth).\n");
+ mode &= ~GLM_FLAT;
+ }
+
+ /* open the file */
+ file = fopen(filename, "w");
+ if (!file) {
+ fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to
write.\n",
+ filename);
+ return 1;
+ }
+
+ /* spit out a header */
+ fprintf(file, "# \n");
+ fprintf(file, "# Wavefront OBJ generated by GLM library\n");
+ fprintf(file, "# \n");
+ fprintf(file, "# GLM library copyright (C) 1997 by Nate Robins\n");
+ fprintf(file, "# email: ndr@pobox.com\n");
+ fprintf(file, "# www:
http://www.pobox.com/~ndr\n");
+ fprintf(file, "# \n");
+
+ if (mode & GLM_MATERIAL && model->mtllibname) {
+ fprintf(file, "\nmtllib %s\n\n", model->mtllibname);
+ if (_glmWriteMTL(model, filename, model->mtllibname)) {
+ /* Problem opening up the material file for output. */
+ fclose(file);
+ return 1;
+ }
+ }
+
+ /* spit out the vertices */
+ fprintf(file, "\n");
+ fprintf(file, "# %d vertices\n", model->numvertices);
+ for (i = 1; i <= model->numvertices; i++) {
+ fprintf(file, "v %f %f %f\n",
+ model->vertices[3 * i + 0],
+ model->vertices[3 * i + 1],
+ model->vertices[3 * i + 2]);
+ }
+
+ /* spit out the smooth/flat normals */
+ if (mode & GLM_SMOOTH) {
+ fprintf(file, "\n");
+ fprintf(file, "# %u normals\n", model->numnormals);
+ for (i = 1; i <= model->numnormals; i++) {
+ fprintf(file, "vn %f %f %f\n",
+ model->normals[3 * i + 0],
+ model->normals[3 * i + 1],
+ model->normals[3 * i + 2]);
+ }
+ } else if (mode & GLM_FLAT) {
+ fprintf(file, "\n");
+ fprintf(file, "# %u normals\n", model->numfacetnorms);
+ for (i = 1; i <= model->numnormals; i++) {
+ fprintf(file, "vn %f %f %f\n",
+ model->facetnorms[3 * i + 0],
+ model->facetnorms[3 * i + 1],
+ model->facetnorms[3 * i + 2]);
+ }
+ }
+
+ /* spit out the texture coordinates */
+ if (mode & GLM_TEXTURE) {
+ fprintf(file, "\n");
+ fprintf(file, "# %u texcoords\n", model->numtexcoords);
+ for (i = 1; i <= model->numtexcoords; i++) {
+ fprintf(file, "vt %f %f\n",
+ model->texcoords[2 * i + 0],
+ model->texcoords[2 * i + 1]);
+ }
+ }
+
+ fprintf(file, "\n");
+ fprintf(file, "# %u groups\n", model->numgroups);
+ fprintf(file, "# %u faces (triangles)\n", model->numtriangles);
+ fprintf(file, "\n");
+
+ group = model->groups;
+ while(group) {
+ fprintf(file, "g %s\n", group->name);
+ if (mode & GLM_MATERIAL)
+ fprintf(file, "usemtl %s\n", model->materials[group->material].name);
+ for (i = 0; i < group->numtriangles; i++) {
+ if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) {
+ fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
+ T(group->triangles[i]).vindices[0],
+ T(group->triangles[i]).nindices[0],
+ T(group->triangles[i]).tindices[0],
+ T(group->triangles[i]).vindices[1],
+ T(group->triangles[i]).nindices[1],
+ T(group->triangles[i]).tindices[1],
+ T(group->triangles[i]).vindices[2],
+ T(group->triangles[i]).nindices[2],
+ T(group->triangles[i]).tindices[2]);
+ } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) {
+ fprintf(file, "f %d/%d %d/%d %d/%d\n",
+ T(group->triangles[i]).vindices[0],
+ T(group->triangles[i]).findex,
+ T(group->triangles[i]).vindices[1],
+ T(group->triangles[i]).findex,
+ T(group->triangles[i]).vindices[2],
+ T(group->triangles[i]).findex);
+ } else if (mode & GLM_TEXTURE) {
+ fprintf(file, "f %d/%d %d/%d %d/%d\n",
+ T(group->triangles[i]).vindices[0],
+ T(group->triangles[i]).tindices[0],
+ T(group->triangles[i]).vindices[1],
+ T(group->triangles[i]).tindices[1],
+ T(group->triangles[i]).vindices[2],
+ T(group->triangles[i]).tindices[2]);
+ } else if (mode & GLM_SMOOTH) {
+ fprintf(file, "f %d//%d %d//%d %d//%d\n",
+ T(group->triangles[i]).vindices[0],
+ T(group->triangles[i]).nindices[0],
+ T(group->triangles[i]).vindices[1],
+ T(group->triangles[i]).nindices[1],
+ T(group->triangles[i]).vindices[2],
+ T(group->triangles[i]).nindices[2]);
+ } else if (mode & GLM_FLAT) {
+ fprintf(file, "f %d//%d %d//%d %d//%d\n",
+ T(group->triangles[i]).vindices[0],
+ T(group->triangles[i]).findex,
+ T(group->triangles[i]).vindices[1],
+ T(group->triangles[i]).findex,
+ T(group->triangles[i]).vindices[2],
+ T(group->triangles[i]).findex);
+ } else {
+ fprintf(file, "f %d %d %d\n",
+ T(group->triangles[i]).vindices[0],
+ T(group->triangles[i]).vindices[1],
+ T(group->triangles[i]).vindices[2]);
+ }
+ }
+ fprintf(file, "\n");
+ group = group->next;
+ }
+
+ fclose(file);
+ return 0;
+}
+
+/* glmWeld: eliminate (weld) vectors that are within an epsilon of
+ * each other.
+ *
+ * model - initialized GLMmodel structure
+ * epsilon - maximum difference between vertices
+ * ( 0.00001 is a good start for a unitized model)
+ *
+ */
+void
+glmWeld(GLMmodel* model, float epsilon)
+{
+ float* vectors;
+ float* copies;
+ unsigned int numvectors;
+ unsigned int i;
+
+ /* vertices */
+ numvectors = model->numvertices;
+ vectors = model->vertices;
+ copies = _glmWeldVectors(vectors, &numvectors, epsilon);
+
+ printf("glmWeld(): %d redundant vertices.\n",
+ model->numvertices - numvectors - 1);
+
+ for (i = 0; i < model->numtriangles; i++) {
+ T(i).vindices[0] = (unsigned int)vectors[3 * T(i).vindices[0] + 0];
+ T(i).vindices[1] = (unsigned int)vectors[3 * T(i).vindices[1] + 0];
+ T(i).vindices[2] = (unsigned int)vectors[3 * T(i).vindices[2] + 0];
+ }
+
+ /* free space for old vertices */
+ free(vectors);
+
+ /* allocate space for the new vertices */
+ model->numvertices = numvectors;
+ model->vertices = (float*)malloc(sizeof(float) *
+ 3 * (model->numvertices + 1));
+
+ /* copy the optimized vertices into the actual vertex list */
+ for (i = 1; i <= model->numvertices; i++) {
+ model->vertices[3 * i + 0] = copies[3 * i + 0];
+ model->vertices[3 * i + 1] = copies[3 * i + 1];
+ model->vertices[3 * i + 2] = copies[3 * i + 2];
+ }
+
+ free(copies);
+}
+
+#if 0 /** This is left in only as a reference to how to get to the data. */
+/* glmDraw: Renders the model to the current OpenGL context using the
+ * mode specified.
+ *
+ * model - initialized GLMmodel structure
+ * mode - a bitwise OR of values describing what is to be rendered.
+ * GLM_NONE - render with only vertices
+ * GLM_FLAT - render with facet normals
+ * GLM_SMOOTH - render with vertex normals
+ * GLM_TEXTURE - render with texture coords
+ * GLM_COLOR - render with colors (color material)
+ * GLM_MATERIAL - render with materials
+ * GLM_COLOR and GLM_MATERIAL should not both be specified.
+ * GLM_FLAT and GLM_SMOOTH should not both be specified.
+ */
+GLvoid
+glmDraw(GLMmodel* model, unsigned int mode)
+{
+ unsigned int i;
+ GLMgroup* group;
+
+ assert(model);
+ assert(model->vertices);
+
+ /* do a bit of warning */
+ if (mode & GLM_FLAT && !model->facetnorms) {
+ printf("glmDraw() warning: flat render mode requested "
+ "with no facet normals defined.\n");
+ mode &= ~GLM_FLAT;
+ }
+ if (mode & GLM_SMOOTH && !model->normals) {
+ printf("glmDraw() warning: smooth render mode requested "
+ "with no normals defined.\n");
+ mode &= ~GLM_SMOOTH;
+ }
+ if (mode & GLM_TEXTURE && !model->texcoords) {
+ printf("glmDraw() warning: texture render mode requested "
+ "with no texture coordinates defined.\n");
+ mode &= ~GLM_TEXTURE;
+ }
+ if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
+ printf("glmDraw() warning: flat render mode requested "
+ "and smooth render mode requested (using smooth).\n");
+ mode &= ~GLM_FLAT;
+ }
+ if (mode & GLM_COLOR && !model->materials) {
+ printf("glmDraw() warning: color render mode requested "
+ "with no materials defined.\n");
+ mode &= ~GLM_COLOR;
+ }
+ if (mode & GLM_MATERIAL && !model->materials) {
+ printf("glmDraw() warning: material render mode requested "
+ "with no materials defined.\n");
+ mode &= ~GLM_MATERIAL;
+ }
+ if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
+ printf("glmDraw() warning: color and material render mode requested "
+ "using only material mode\n");
+ mode &= ~GLM_COLOR;
+ }
+ if (mode & GLM_COLOR)
+ glEnable(GL_COLOR_MATERIAL);
+ if (mode & GLM_MATERIAL)
+ glDisable(GL_COLOR_MATERIAL);
+
+ glPushMatrix();
+ glTranslatef(model->position[0], model->position[1], model->position[2]);
+
+ glBegin(GL_TRIANGLES);
+ group = model->groups;
+ while (group) {
+ if (mode & GLM_MATERIAL) {
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,
+ model->materials[group->material].ambient);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,
+ model->materials[group->material].diffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,
+ model->materials[group->material].specular);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS,
+ model->materials[group->material].shininess);
+ }
+
+ if (mode & GLM_COLOR) {
+ glColor3fv(model->materials[group->material].diffuse);
+ }
+
+ for (i = 0; i < group->numtriangles; i++) {
+ if (mode & GLM_FLAT)
+ glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]);
+
+ if (mode & GLM_SMOOTH)
+ glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[0]]);
+ if (mode & GLM_TEXTURE)
+
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]);
+
+ if (model->usePerVertexColors) {
+ glColor3ubv( &model->vertexColors[3 *
T(group->triangles[i]).vindices[0]] );
+ }
+
+ glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[0]]);
+#if 0
+ printf("%f %f %f\n",
+ model->vertices[3 * T(group->triangles[i]).vindices[0] + X],
+ model->vertices[3 * T(group->triangles[i]).vindices[0] + Y],
+ model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]);
+#endif
+
+ if (mode & GLM_SMOOTH)
+ glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[1]]);
+ if (mode & GLM_TEXTURE)
+
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]);
+ if (model->usePerVertexColors) {
+ glColor3ubv( &model->vertexColors[3 *
T(group->triangles[i]).vindices[1]] );
+ }
+ glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[1]]);
+#if 0
+ printf("%f %f %f\n",
+ model->vertices[3 * T(group->triangles[i]).vindices[1] + X],
+ model->vertices[3 * T(group->triangles[i]).vindices[1] + Y],
+ model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]);
+#endif
+
+ if (mode & GLM_SMOOTH)
+ glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[2]]);
+ if (mode & GLM_TEXTURE)
+
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]);
+ if (model->usePerVertexColors) {
+ glColor3ubv( &model->vertexColors[3 *
T(group->triangles[i]).vindices[2]] );
+ }
+ glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[2]]);
+#if 0
+ printf("%f %f %f\n",
+ model->vertices[3 * T(group->triangles[i]).vindices[2] + X],
+ model->vertices[3 * T(group->triangles[i]).vindices[2] + Y],
+ model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]);
+#endif
+
+ }
+
+ group = group->next;
+ }
+ glEnd();
+
+ glPopMatrix();
+}
+#endif
+
+};
Added: branches/itanium2/Model/Readers/glm/glm.h
==============================================================================
--- (empty file)
+++ branches/itanium2/Model/Readers/glm/glm.h Sat Jul 9 13:53:42 2005
@@ -0,0 +1,250 @@
+/*
+ * GLM library. Wavefront .obj file format reader/writer/manipulator.
+ *
+ * Written by Nate Robins, 1997.
+ * email: ndr@pobox.com
+ * www:
http://www.pobox.com/~ndr
+ */
+
+#ifndef RTRT_GLM_H
+#define RTRT_GLM_H
+
+namespace Glm {
+
+/* includes */
+
+/* defines */
+#if 0
+#define GLM_NONE (0) /* render with only vertices */
+#define GLM_FLAT (1 << 0) /* render with facet normals */
+#define GLM_SMOOTH (1 << 1) /* render with vertex normals */
+#define GLM_TEXTURE (1 << 2) /* render with texture coords */
+#define GLM_COLOR (1 << 3) /* render with colors */
+#define GLM_MATERIAL (1 << 4) /* render with materials */
+#endif
+
+ enum {
+ GLM_NONE = (0),
+ GLM_FLAT = (1 << 0),
+ GLM_SMOOTH = (1 << 1),
+ GLM_TEXTURE = (1 << 2),
+ GLM_COLOR = (1 << 3),
+ GLM_MATERIAL = (1 << 4)
+ };
+
+ /* structs */
+
+ /* GLMmaterial: Structure that defines a material in a model.
+ */
+ typedef struct _GLMmaterial
+ {
+ char* name; /* name of material */
+ float diffuse[4]; /* diffuse component
*/
+ float ambient[4]; /* ambient component
*/
+ float specular[4]; /* specular component
*/
+ float emmissive[4]; /* emmissive
component */
+ float shininess; /* specular exponent
*/
+ } GLMmaterial;
+
+ /* GLMtriangle: Structure that defines a triangle in a model.
+ */
+ typedef struct {
+ unsigned int vindices[3]; /* array of triangle
vertex indices */
+ unsigned int nindices[3]; /* array of triangle
normal indices */
+ unsigned int tindices[3]; /* array of triangle
texcoord indices*/
+ unsigned int findex; /* index of triangle
facet normal */
+ } GLMtriangle;
+
+ /* GLMgroup: Structure that defines a group in a model.
+ */
+ typedef struct _GLMgroup {
+ char* name; /* name of this group */
+ unsigned int numtriangles; /* number of triangles in
this group */
+ unsigned int* triangles; /* array of triangle
indices */
+ unsigned int material; /* index to material
for group */
+ struct _GLMgroup* next; /* pointer to next group in
model */
+ } GLMgroup;
+
+ /* GLMmodel: Structure that defines a model.
+ */
+ typedef struct {
+ char* pathname; /* path to this model
*/
+ char* mtllibname; /* name of the
material library */
+
+ unsigned int numvertices; /* number of vertices
in model */
+ float* vertices; /* array of vertices
+
[x1,y1,z1,x2,y2,z2...] */
+ unsigned char* vertexColors; /* array of vertex
colors */
+
+ unsigned int numnormals; /* number of normals
in model */
+ float* normals; /* array of normals */
+
+ unsigned int numtexcoords; /* number of
texcoords in model */
+ float* texcoords; /* array of texture
coordinates */
+
+ unsigned int numfacetnorms; /* number of
facetnorms in model */
+ float* facetnorms; /* array of
facetnorms */
+
+ unsigned int numtriangles; /* number of
triangles in model */
+ GLMtriangle* triangles; /* array of triangles */
+
+ unsigned int nummaterials; /* number of
materials in model */
+ GLMmaterial* materials; /* array of materials */
+
+ /* This is the thing you will want to iterate over. Each
group has
+ an associated list of triangles, material, and name.
*/
+ unsigned int numgroups; /* number of groups
in model */
+ GLMgroup* groups; /* linked list of
groups */
+
+ float position[3]; /* position of the
model */
+
+ bool usePerVertexColors; /* Are there per vertex
colors? */
+
+ } GLMmodel;
+
+
+ /* public functions */
+
+ /* glmUnitize: "unitize" a model by translating it to the origin and
+ * scaling it to fit in a unit cube around the origin. Returns the
+ * scalefactor used.
+ *
+ * model - properly initialized GLMmodel structure
+ */
+ float
+ glmUnitize(GLMmodel* model);
+
+ /*
+ * glmBoundingBox: Calculates the min/max positions of the model
+ */
+ void
+ glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos);
+
+
+ /* glmDimensions: Calculates the dimensions (width, height, depth) of
+ * a model.
+ *
+ * model - initialized GLMmodel structure
+ * dimensions - array of 3 floats (float dimensions[3])
+ */
+ void
+ glmDimensions(GLMmodel* model, float* dimensions);
+
+ /* glmScale: Scales a model by a given amount.
+ *
+ * model - properly initialized GLMmodel structure
+ * scale - scalefactor (0.5 = half as large, 2.0 = twice as large)
+ */
+ void
+ glmScale(GLMmodel* model, float scale);
+
+ /* glmReverseWinding: Reverse the polygon winding for all polygons in
+ * this model. Default winding is counter-clockwise. Also changes
+ * the direction of the normals.
+ *
+ * model - properly initialized GLMmodel structure
+ */
+ void
+ glmReverseWinding(GLMmodel* model);
+
+ /* glmFacetNormals: Generates facet normals for a model (by taking the
+ * cross product of the two vectors derived from the sides of each
+ * triangle). Assumes a counter-clockwise winding.
+ *
+ * model - initialized GLMmodel structure
+ */
+ void
+ glmFacetNormals(GLMmodel* model);
+
+ /* glmVertexNormals: Generates smooth vertex normals for a model.
+ * First builds a list of all the triangles each vertex is in. Then
+ * loops through each vertex in the the list averaging all the facet
+ * normals of the triangles each vertex is in. Finally, sets the
+ * normal index in the triangle for the vertex to the generated smooth
+ * normal. If the dot product of a facet normal and the facet normal
+ * associated with the first triangle in the list of triangles the
+ * current vertex is in is greater than the cosine of the angle
+ * parameter to the function, that facet normal is not added into the
+ * average normal calculation and the corresponding vertex is given
+ * the facet normal. This tends to preserve hard edges. The angle to
+ * use depends on the model, but 90 degrees is usually a good start.
+ *
+ * model - initialized GLMmodel structure
+ * angle - maximum angle (in degrees) to smooth across
+ */
+ void
+ glmVertexNormals(GLMmodel* model, float angle);
+
+ /* glmLinearTexture: Generates texture coordinates according to a
+ * linear projection of the texture map. It generates these by
+ * linearly mapping the vertices onto a square.
+ *
+ * model - pointer to initialized GLMmodel structure
+ */
+ void
+ glmLinearTexture(GLMmodel* model);
+
+ /* glmSpheremapTexture: Generates texture coordinates according to a
+ * spherical projection of the texture map. Sometimes referred to as
+ * spheremap, or reflection map texture coordinates. It generates
+ * these by using the normal to calculate where that vertex would map
+ * onto a sphere. Since it is impossible to map something flat
+ * perfectly onto something spherical, there is distortion at the
+ * poles. This particular implementation causes the poles along the X
+ * axis to be distorted.
+ *
+ * model - pointer to initialized GLMmodel structure
+ */
+ void
+ glmSpheremapTexture(GLMmodel* model);
+
+ /* glmDelete: Deletes a GLMmodel structure.
+ *
+ * model - initialized GLMmodel structure
+ */
+ void
+ glmDelete(GLMmodel* model);
+
+ /* glmReadOBJ: Reads a model description from a Wavefront .OBJ file.
+ * Returns a pointer to the created object which should be free'd with
+ * glmDelete().
+ *
+ * filename - name of the file containing the Wavefront .OBJ format
data.
+ *
+ * returns 0 if there was a problem reading the file.
+ */
+ GLMmodel*
+ glmReadOBJ(const char* filename);
+
+ /* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to
+ * a file.
+ *
+ * model - initialized GLMmodel structure
+ * filename - name of the file to write the Wavefront .OBJ format
data to
+ * mode - a bitwise or of values describing what is written to
the file
+ * GLM_NONE - write only vertices
+ * GLM_FLAT - write facet normals
+ * GLM_SMOOTH - write vertex normals
+ * GLM_TEXTURE - write texture coords
+ * GLM_FLAT and GLM_SMOOTH should not both be specified.
+ *
+ * returns 1 if there was error, 0 otherwise.
+ *
+ */
+ int
+ glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode);
+
+ /* glmWeld: eliminate (weld) vectors that are within an epsilon of
+ * each other.
+ *
+ * model - initialized GLMmodel structure
+ * epsilon - maximum difference between vertices
+ * ( 0.00001 is a good start for a unitized model)
+ *
+ */
+ void
+ glmWeld(GLMmodel* model, float epsilon);
+
+};
+
+#endif
Modified: branches/itanium2/StandAlone/manta.cc
==============================================================================
--- branches/itanium2/StandAlone/manta.cc (original)
+++ branches/itanium2/StandAlone/manta.cc Sat Jul 9 13:53:42 2005
@@ -74,15 +74,15 @@
BenchHelper(RTRTInterface* rtrt, long numFrames);
void start(int, int);
void stop(int, int);
-
+
private:
- RTRTInterface* rtrt;
+ RTRTInterface* rtrt;
double startTime;
long numFrames;
};
BenchHelper::BenchHelper(RTRTInterface* rtrt, long numFrames)
- : rtrt(rtrt), numFrames(numFrames)
+: rtrt(rtrt), numFrames(numFrames)
{
}
@@ -95,8 +95,9 @@
{
double dt = Time::currentSeconds()-startTime;
double fps = static_cast<double>(numFrames)/dt;
- cout << "Benchmark completed in " << dt << " seconds (" << numFrames << "
frames, " << fps << " frames per second)\n";
- rtrt->finish();
+ // cout << "Benchmark completed in " << dt << " seconds (" << numFrames <<
" frames, " << fps << " frames per second)\n";
+ std::cout << fps << std::endl;
+ rtrt->finish();
delete this;
}
@@ -106,13 +107,13 @@
#if HAVE_IEEEFP_H
fpsetmask(FP_X_OFL|FP_X_DZ|FP_X_INV);
#endif
-
-
+
+
// Copy args into a vector<string>
vector<string> args;
for(int i=1;i<argc;i++)
args.push_back(argv[i]);
-
+
try {
RTRTInterface* rtrt = createRTRT();
if(getenv("MANTA_SCENEPATH"))
@@ -138,35 +139,35 @@
int xres = 512, yres = 512;
bool channelCreated=false;
bool haveUI = false;
-
+
int argc = static_cast<int>(args.size());
for(int i=0;i<argc;i++){
string arg = args[i];
if(arg == "-help"){
- usage(rtrt);
+ usage(rtrt);
} else if(arg == "-bench"){
- long numFrames = 100;
- long warmup = 10;
- if(getLongArg(i, args, numFrames)){
- getLongArg(i, args, warmup);
- }
- BenchHelper* b = new BenchHelper(rtrt, numFrames);
- // Ask for two callbacks, one at frame "warmup", and one at
- // frame warmup+numFrames
- rtrt->addOneShotCallback(RTRTInterface::Absolute, warmup,
- Callback::create(b, &BenchHelper::start));
- rtrt->addOneShotCallback(RTRTInterface::Absolute, warmup+numFrames,
- Callback::create(b, &BenchHelper::stop));
+ long numFrames = 100;
+ long warmup = 10;
+ if(getLongArg(i, args, numFrames)){
+ getLongArg(i, args, warmup);
+ }
+ BenchHelper* b = new BenchHelper(rtrt,
numFrames);
+ // Ask for two callbacks, one at frame
"warmup", and one at
+ // frame warmup+numFrames
+
rtrt->addOneShotCallback(RTRTInterface::Absolute, warmup,
+
Callback::create(b,
&BenchHelper::start));
+
rtrt->addOneShotCallback(RTRTInterface::Absolute, warmup+numFrames,
+
Callback::create(b,
&BenchHelper::stop));
} else if(arg == "-camera"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- currentCamera = rtrt->createCamera(s);
- if(!currentCamera){
- cerr << "Error creating camera: " << s << ", available cameras
are:\n";
- printList(cerr, rtrt->listCameras());
- exit(1);
- }
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ currentCamera = rtrt->createCamera(s);
+ if(!currentCamera){
+ cerr << "Error creating camera: " <<
s << ", available cameras are:\n";
+ printList(cerr, rtrt->listCameras());
+ exit(1);
+ }
} else if(arg == "-idlemode"){
string s;
if(!getStringArg(i, args, s))
@@ -177,112 +178,112 @@
exit(1);
}
} else if(arg == "-imagedisplay"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- if(!rtrt->createChannel(s, currentCamera, false, xres, yres)){
- cerr << "Invalid image display: " << s << ", available image
displays are:\n";
- printList(cerr, rtrt->listImageDisplays());
- exit(1);
- }
- channelCreated=true;
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ if(!rtrt->createChannel(s, currentCamera,
false, xres, yres)){
+ cerr << "Invalid image display: " <<
s << ", available image displays are:\n";
+ printList(cerr,
rtrt->listImageDisplays());
+ exit(1);
+ }
+ channelCreated=true;
} else if(arg == "-imagetraverser"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- if(!rtrt->selectImageTraverser(s)){
- cerr << "Invalid image traverser: " << s << ", available image
traversers are:\n";
- printList(cerr, rtrt->listImageTraversers());
- exit(1);
- }
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ if(!rtrt->selectImageTraverser(s)){
+ cerr << "Invalid image traverser: "
<< s << ", available image traversers are:\n";
+ printList(cerr,
rtrt->listImageTraversers());
+ exit(1);
+ }
} else if(arg == "-imagetype"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- if(!rtrt->selectImageType(s)){
- cerr << "Invalid image type: " << s << ", available image types
are:\n";
- printList(cerr, rtrt->listImageTypes());
- exit(1);
- }
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ if(!rtrt->selectImageType(s)){
+ cerr << "Invalid image type: " << s
<< ", available image types are:\n";
+ printList(cerr,
rtrt->listImageTypes());
+ exit(1);
+ }
} else if(arg == "-loadbalancer"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- if(!rtrt->selectLoadBalancer(s)){
- cerr << "Invalid load balancer: " << s << ", available load
balancers are:\n";
- printList(cerr, rtrt->listLoadBalancers());
- exit(1);
- }
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ if(!rtrt->selectLoadBalancer(s)){
+ cerr << "Invalid load balancer: " <<
s << ", available load balancers are:\n";
+ printList(cerr,
rtrt->listLoadBalancers());
+ exit(1);
+ }
} else if(arg == "-np"){
- long np;
- if(!getLongArg(i, args, np))
- usage(rtrt);
- rtrt->changeNumWorkers(static_cast<int>(np));
+ long np;
+ if(!getLongArg(i, args, np))
+ usage(rtrt);
+ rtrt->changeNumWorkers(static_cast<int>(np));
} else if(arg == "-pixelsampler"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- if(!rtrt->selectPixelSampler(s)){
- cerr << "Invalid pixel sampler: " << s << ", available pixel
samplers are:\n";
- printList(cerr, rtrt->listPixelSamplers());
- exit(1);
- }
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ if(!rtrt->selectPixelSampler(s)){
+ cerr << "Invalid pixel sampler: " <<
s << ", available pixel samplers are:\n";
+ printList(cerr,
rtrt->listPixelSamplers());
+ exit(1);
+ }
} else if(arg == "-renderer"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- if(!rtrt->selectRenderer(s)){
- cerr << "Invalid renderer: " << s << ", available renderers are:\n";
- printList(cerr, rtrt->listRenderers());
- exit(1);
- }
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ if(!rtrt->selectRenderer(s)){
+ cerr << "Invalid renderer: " << s <<
", available renderers are:\n";
+ printList(cerr,
rtrt->listRenderers());
+ exit(1);
+ }
} else if(arg == "-res"){
- if(!getResolutionArg(i, args, xres, yres)){
- cerr << "Error parsing resolution: " << args[i+1] << '\n';
- usage(rtrt);
- }
+ if(!getResolutionArg(i, args, xres, yres)){
+ cerr << "Error parsing resolution: "
<< args[i+1] << '\n';
+ usage(rtrt);
+ }
} else if(arg == "-scene"){
- if(rtrt->haveScene())
- cerr << "WARNING: multiple scenes specified, will use last one\n";
- string scene;
- if(!getStringArg(i, args, scene))
- usage(rtrt);
- if(!rtrt->readScene(scene)){
- cerr << "Error reading scene: " << scene << '\n';
- exit(1);
- }
+ if(rtrt->haveScene())
+ cerr << "WARNING: multiple scenes
specified, will use last one\n";
+ string scene;
+ if(!getStringArg(i, args, scene))
+ usage(rtrt);
+ if(!rtrt->readScene(scene)){
+ cerr << "Error reading scene: " <<
scene << '\n';
+ exit(1);
+ }
} else if(arg == "-shadows"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- if(!rtrt->selectShadowAlgorithm(s)){
- cerr << "Invalid shadow algorithm: " << s << ", available shadow
algorithms are:\n";
- printList(cerr, rtrt->listShadowAlgorithms());
- exit(1);
- }
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ if(!rtrt->selectShadowAlgorithm(s)){
+ cerr << "Invalid shadow algorithm: "
<< s << ", available shadow algorithms are:\n";
+ printList(cerr,
rtrt->listShadowAlgorithms());
+ exit(1);
+ }
} else if(arg == "-ui"){
- string s;
- if(!getStringArg(i, args, s))
- usage(rtrt);
- UserInterface* ui = rtrt->createUserInterface(s);
- if(!ui){
- cerr << "Unknown user interface: " << s << ", available user
interfaces are:\n";
- printList(cerr, rtrt->listUserInterfaces());
- exit(1);
- }
- ui->startup();
- haveUI = true;
+ string s;
+ if(!getStringArg(i, args, s))
+ usage(rtrt);
+ UserInterface* ui =
rtrt->createUserInterface(s);
+ if(!ui){
+ cerr << "Unknown user interface: " <<
s << ", available user interfaces are:\n";
+ printList(cerr,
rtrt->listUserInterfaces());
+ exit(1);
+ }
+ ui->startup();
+ haveUI = true;
} else {
- cerr << "Unknown argument: " << arg << '\n';
- usage(rtrt);
+ cerr << "Unknown argument: " << arg << '\n';
+ usage(rtrt);
}
}
if(!haveUI){
UserInterface* ui = rtrt->createUserInterface("X");
if(!ui){
- cerr << "Cannot find default user interface: X, available user
interfaces are:\n";
- printList(cerr, rtrt->listUserInterfaces());
- exit(1);
+ cerr << "Cannot find default user interface:
X, available user interfaces are:\n";
+ printList(cerr, rtrt->listUserInterfaces());
+ exit(1);
}
ui->startup();
}
@@ -299,11 +300,11 @@
if(e.stackTrace())
cerr << "Stack trace: " << e.stackTrace() << '\n';
exit(1);
-
+
} catch (std::exception e){
cerr << "Caught std exception: " << e.what() << '\n';
exit(1);
-
+
} catch(...){
cerr << "Caught unknown exception\n";
exit(1);
@@ -331,28 +332,28 @@
scene->setBackground(new
ConstantBackground(ColorDB::getNamedColor("SkyBlue3")*0.5));
Material* red=new Phong(Color(RGBColor(.6,0,0)),
Color(RGBColor(.6,.6,.6)), 32, 0.4);
-
+
Material* plane_matl = new Phong(new
CheckerTexture<Color>(Color(RGBColor(.6,.6,.6)),
-
Color(RGBColor(0,0,0)),
- Vector(1,0,0),
- Vector(0,1,0)),
- new
Constant<Color>(Color(RGBColor(.6,.6,.6))),
- 32,
- new CheckerTexture<double>(0.2, 0.5,
- Vector(1,0,0),
- Vector(0,1,0)));
-
-
+
Color(RGBColor(0,0,0)),
+
Vector(1,0,0),
+
Vector(0,1,0)),
+
new
Constant<Color>(Color(RGBColor(.6,.6,.6))),
+
32,
+
new
CheckerTexture<double>(0.2, 0.5,
+
Vector(1,0,0),
+
Vector(0,1,0)));
+
+
Group* world = new Group();
Primitive* floor = new Parallelogram(plane_matl, Point(-20,-20,0),
- Vector(40,0,0), Vector(0,40,0));
+
Vector(40,0,0), Vector(0,40,0));
// Setup world-space texture coordinates for the checkerboard floor
UniformMapper* uniformmap = new UniformMapper();
floor->setTexCoordMapper(uniformmap);
world->add(floor);
world->add(new Sphere(red, Point(0,0,1.2), 1.0));
scene->setObject(world);
-
+
LightSet* lights = new LightSet();
lights->add(new PointLight(Point(0,5,8), Color(RGBColor(.6,.1,.1))));
lights->add(new PointLight(Point(5,0,8), Color(RGBColor(.1,.6,.1))));
Modified: branches/itanium2/StandAlone/manta_tile_size.pl
==============================================================================
--- branches/itanium2/StandAlone/manta_tile_size.pl (original)
+++ branches/itanium2/StandAlone/manta_tile_size.pl Sat Jul 9 13:53:42
2005
@@ -1,14 +1,21 @@
#!/usr/bin/perl
-
+# Perl script for testing different tile sizes.
+# Use
+# cat manta_tile_size_1_to_32.txt | unu save -f nrrd | unu reshape -s 32 32
| unu rmap -m ~/data/colormap/rainbow3x12.nrrd | unu resample -s = 512 512 -k
box | unu quantize -b 8 | unu save -f png -o tile.png
+# to produce a nice colormapped image.
+#
+# Abe Stephens abe@sgi.com
######################################################################
# Default args.
-$np = 1;
-@min = (1, 1);
-@max = (32, 32);
-@bench = (5, 5);
-$file = 0;
+$np = 1;
+@min = (1, 1);
+@max = (32, 32);
+@bench = (5, 5);
+$file = 0;
+$scene = 0;
+$camera = 0;
######################################################################
# Parse args.
@@ -44,6 +51,12 @@
$bench[0] = $ARGV[++$i];
$bench[1] = $ARGV[++$i];
}
+ elsif ($ARGV[$i] eq "-camera") {
+ $camera = $ARGV[++$i];
+ }
+ elsif ($ARGV[$i] eq "-scene") {
+ $scene = $ARGV[++$i];
+ }
}
# Determine output file.
@@ -88,6 +101,14 @@
" -bench " . $bench[0] . " " . $bench[1] . " " .
" -imagetraverser \"tiled( -tilesize " . $x . "x" . $y . " )\" ";
+ if ($camera) {
+ $command = $command . " -camera \"$camera\"";
+ }
+
+ if ($scene) {
+ $command = $command . " -scene \"$scene\"";
+ }
+
print "" . ($iter+1) . " of " . $total .
" (" . (($iter+1)/$total*100) . "%)\n";
print $command . "\n";
@@ -108,5 +129,8 @@
}
}
+
+# Produce a plot.
+print "cat $file | unu save -f nrrd | unu reshape -s 32 32 | unu rmap -m
~/data/colormap/rainbow3x12.nrrd | unu resample -s = 512 512 -k box | unu
quantize -b 8 | unu save -f png -o tile.png\n"
Modified: branches/itanium2/fox/CMakeLists.txt
==============================================================================
--- branches/itanium2/fox/CMakeLists.txt (original)
+++ branches/itanium2/fox/CMakeLists.txt Sat Jul 9 13:53:42 2005
@@ -7,7 +7,13 @@
SET(FOX_STATIC FOX-1.5 CACHE STRING "")
INCLUDE_DIRECTORIES(${FOX_INCLUDE})
- LINK_DIRECTORIES (${FOX_LIB} )
+ LINK_DIRECTORIES (${FOX_LIB})
+
+ # Check to see if histx should be included.
+ IF(HISTX_PATH)
+ INCLUDE_DIRECTORIES(${HISTX_INCLUDE})
+ LINK_DIRECTORIES (${HISTX_LIB} )
+ ENDIF(HISTX_PATH)
ADD_EXECUTABLE(fox_manta fox_manta.cc
FMantaImageFrame.cc
@@ -40,4 +46,9 @@
-lm
-lXcursor
-lXrandr)
+ IF(HISTX_PATH)
+ TARGET_LINK_LIBRARIES(fox_manta Manta_histx
+ ${HISTX_LINK} )
+ ENDIF(HISTX_PATH)
+
ENDIF(FOX_PATH)
Modified: branches/itanium2/fox/FMantaWindow.cc
==============================================================================
--- branches/itanium2/fox/FMantaWindow.cc (original)
+++ branches/itanium2/fox/FMantaWindow.cc Sat Jul 9 13:53:42 2005
@@ -4,6 +4,7 @@
#include <fox/FMantaImageFrame.h>
#include <SCIRun/Core/Thread/Thread.h>
+#include <Core/Exceptions/IllegalArgument.h>
#include <Interface/Scene.h>
#include <Interface/Object.h>
@@ -49,6 +50,9 @@
FXMAPFUNC(SEL_COMMAND, FMantaWindow::ID_JITTER8_SAMPLER,
FMantaWindow::onPixelSampler ),
FXMAPFUNC(SEL_COMMAND, FMantaWindow::ID_TEXT_SAMPLER,
FMantaWindow::onPixelSamplerText ),
+ // Traversers
+ FXMAPFUNC(SEL_COMMAND, FMantaWindow::ID_TEXT_TRAVERSER,
FMantaWindow::onTraverserText ),
+
// Cutting planes.
FXMAPFUNC(SEL_LEFTBUTTONPRESS, FMantaImageFrame::ID_PIXEL_SELECT,
FMantaWindow::onAddCuttingPlane )
};
@@ -94,6 +98,11 @@
new FXMenuCommand( sampler_menu, "Jitter 8 Samples", 0, this,
ID_JITTER8_SAMPLER );
new FXMenuCommand( sampler_menu, "Enter Text...", 0, this,
ID_TEXT_SAMPLER );
new FXMenuTitle( menu_bar, "Samplers", 0, sampler_menu );
+
+ // Traverser Menu.
+ traverser_menu = new FXMenuPane( this );
+ new FXMenuCommand( traverser_menu, "Enter Text...", 0, this,
ID_TEXT_TRAVERSER );
+ new FXMenuTitle( menu_bar, "Traversers", 0, traverser_menu );
// Options menu.
options_menu = new FXMenuPane( this );
@@ -131,7 +140,7 @@
camera_bookmark_list = new FXListBox( frame, this, ID_BOOKMARK_LIST,
LAYOUT_FILL_X|LAYOUT_BOTTOM|COMBOBOX_REPLACE,0,0,0,20 );
camera_bookmark_list->setNumVisible( 5 );
- new FXButton( frame, "Add", 0, this, ID_ADD_BOOKMARK );
+ // new FXButton( frame, "Add", 0, this, ID_ADD_BOOKMARK );
}
// Quit the program.
@@ -316,6 +325,18 @@
return 1;
}
+long FMantaWindow::onTraverserText( FXObject *sender, FXSelector key, void
*data ) {
+
+ // Collect a string from the user.
+ FXString description;
+ if (FXInputDialog::getString(description, getApp(), "Enter Text",
"Image Traverser Spec:", 0 )) {
+ manta_interface->addTransaction("Image Traverser.",
+
Callback::create(this,&FMantaWindow::mantaTraverser,string(description.text())));
+ }
+
+ return 1;
+}
+
long FMantaWindow::onAddCuttingPlane( FXObject *sender, FXSelector key, void
*data ) {
FXEvent *event = (FXEvent *)data;
@@ -453,7 +474,7 @@
delete old_camera;
// This is unsafe.
-manta_frame->getNavigator()->resetToCamera(
new_camera->getPosition(),new_camera->getLookAt(),new_camera->getUp());
+ manta_frame->getNavigator()->resetToCamera(
new_camera->getPosition(),new_camera->getLookAt(),new_camera->getUp());
}
void FMantaWindow::mantaShadowAlgorithm( const string text ) const {
@@ -461,10 +482,14 @@
// Determine the channel number.
int channel = manta_frame->getMantaChannel();
- // Update the shadow algorithm.
- if (!manta_interface->selectShadowAlgorithm( text )) {
- std::cout << "Could not select shadow algorithm " << text <<
std::endl;
+ try {
+ if (!manta_interface->selectShadowAlgorithm( text )) {
+ std::cout << "Could not select shadow algorithm " <<
text << std::endl;
+ }
}
+ catch (IllegalArgument e) {
+ std::cout << "Caught IllegalArgument exception" << std::endl;
+ };
}
void FMantaWindow::mantaPixelSampler( const string text ) const {
@@ -472,9 +497,30 @@
// Determine the channel number.
int channel = manta_frame->getMantaChannel();
- if (!manta_interface->selectPixelSampler( text )) {
- std::cout << "Could not select pixel sampler " << text <<
std::endl;
+ try {
+ if (!manta_interface->selectPixelSampler( text )) {
+ std::cout << "Could not select pixel sampler " <<
text << std::endl;
+ }
+ }
+ catch (IllegalArgument e) {
+ std::cout << "Caught IllegalArgument exception" <<
std::endl;
+ };
+}
+
+
+void FMantaWindow::mantaTraverser( const string text ) const {
+
+ // Determine the channel number.
+ int channel = manta_frame->getMantaChannel();
+
+ try {
+ if (!manta_interface->selectImageTraverser( text )) {
+ std::cout << "Could not select pixel sampler " <<
text << std::endl;
+ }
}
+ catch (IllegalArgument e) {
+ std::cout << "Caught IllegalArgument exception" << std::endl;
+ };
}
///////////////////////////////////////////////////////////////////////////////
Modified: branches/itanium2/fox/FMantaWindow.h
==============================================================================
--- branches/itanium2/fox/FMantaWindow.h (original)
+++ branches/itanium2/fox/FMantaWindow.h Sat Jul 9 13:53:42 2005
@@ -37,6 +37,7 @@
FXMenuPane *camera_menu;
FXMenuPane *shadow_menu;
FXMenuPane *sampler_menu;
+ FXMenuPane *traverser_menu;
FXMenuPane *options_menu;
FXMenuCommand *cutting_flip;
@@ -89,6 +90,9 @@
ID_JITTER8_SAMPLER,
ID_TEXT_SAMPLER, // User wants to enter a
description manually.
+ // Image traverser options.
+ ID_TEXT_TRAVERSER,
+
// Cutting planes.
ID_ADD_CUTTING_PLANE,
@@ -122,6 +126,7 @@
long onShadowAlgorithmText( FXObject *sender, FXSelector key,
void *data );
long onPixelSampler ( FXObject *sender, FXSelector key,
void *data );
long onPixelSamplerText( FXObject *sender, FXSelector key,
void *data );
+ long onTraverserText ( FXObject *sender, FXSelector key,
void *data );
long onAddCuttingPlane( FXObject *sender, FXSelector key,
void *data );
// Accessors.
@@ -144,6 +149,9 @@
// This method is called by the manta thread to replace the
shadow algorithm.
void mantaPixelSampler( const string shadow_text ) const;
+
+ // This method is called by the manta thread to replace the
image traverser.
+ void mantaTraverser( const string shadow_text ) const;
// This method is called by the manta thread to add a cutting
plane.
void mantaAddCuttingPlane( Point point, Vector normal ) const;
Modified: branches/itanium2/fox/fox_manta.cc
==============================================================================
--- branches/itanium2/fox/fox_manta.cc (original)
+++ branches/itanium2/fox/fox_manta.cc Sat Jul 9 13:53:42 2005
@@ -15,6 +15,8 @@
#include <fox/FMantaQuakeNav.h>
#include <fox/FMantaTrackballNav.h>
+#include <histx/SingleSamplerCounter.h>
+
#include <string>
#include <stdlib.h>
@@ -70,9 +72,11 @@
manta_interface->setScenePath (".");
manta_interface->changeNumWorkers ( np );
manta_interface->selectImageType ( "rgba8" );
+ // manta_interface->selectImageType ( "rgbafloat" );
manta_interface->selectLoadBalancer ( "workqueue" );
manta_interface->selectImageTraverser ( "tiled" );
- //manta_interface->selectPixelSampler ( "jittersample(
-numberOfSamples 4 )" );
+ // manta_interface->selectPixelSampler ( "jittersample(
-numberOfSamples 4 )" );
+ // manta_interface->setPixelSampler ( new
Histx_Manta::SingleSamplerCounter );
manta_interface->selectPixelSampler ( "singlesample" );
manta_interface->selectRenderer ( "raytracer" );
manta_interface->selectShadowAlgorithm( "hard" );
Modified: branches/itanium2/scenes/CMakeLists.txt
==============================================================================
--- branches/itanium2/scenes/CMakeLists.txt (original)
+++ branches/itanium2/scenes/CMakeLists.txt Sat Jul 9 13:53:42 2005
@@ -50,5 +50,11 @@
TARGET_LINK_LIBRARIES(scene_boeing777 ${manta_scene_link})
ENDIF(SCENE_BOEING777)
+SET(SCENE_OBJVIEWER 0 CACHE BOOL "Wavefront Obj file viewer.")
+IF(SCENE_OBJVIEWER)
+ ADD_LIBRARY(scene_objviewer objviewer.cc)
+ TARGET_LINK_LIBRARIES(scene_objviewer ${manta_scene_link})
+ENDIF(SCENE_OBJVIEWER)
+
############################################################
Added: branches/itanium2/scenes/objviewer.cc
==============================================================================
--- (empty file)
+++ branches/itanium2/scenes/objviewer.cc Sat Jul 9 13:53:42 2005
@@ -0,0 +1,214 @@
+
+#include <MantaTypes.h>
+
+#include <Core/Geometry/PointVector.h>
+#include <Core/Exceptions/IllegalArgument.h>
+#include <Core/Util/Args.h>
+
+#include <Interface/Context.h>
+#include <Interface/LightSet.h>
+#include <Interface/RTRTInterface.h>
+#include <Interface/Scene.h>
+#include <Interface/Material.h>
+
+#include <Model/Primitives/Triangle.h>
+#include <Model/Primitives/Parallelogram.h>
+#include <Model/Primitives/Cube.h>
+#include <Model/Materials/Lambertian.h>
+#include <Model/Materials/Phong.h>
+#include <Model/Materials/Dielectric.h>
+#include <Model/Materials/NormalMaterial.h>
+#include <Model/Groups/Group.h>
+#include <Model/Groups/RealisticBvh.h>
+#include <Model/Lights/HeadLight.h>
+#include <Model/AmbientLights/ConstantAmbient.h>
+#include <Model/Backgrounds/ConstantBackground.h>
+#include <Model/Readers/glm/glm.h>
+#include <Model/Textures/CheckerTexture.h>
+#include <Model/Textures/Constant.h>
+
+#include <SCIRun/Core/Thread/Time.h>
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+using namespace Manta;
+using namespace SCIRun;
+using namespace Glm;
+
+///////////////////////////////////////////////////////////////////////////
+// This function loads a specified .obj file into a runtime acceleration
+// structure for rendering.
+extern "C"
+Scene* make_scene(const ReadContext& context, const vector<string>& args) {
+
+ string file_name;
+
+ // Check the arguments.
+ for (int i=0;i<args.size();++i) {
+
+ if (args[i] == "-file") {
+ // Read in the file name.
+ if (!getStringArg(i, args, file_name))
+ throw IllegalArgument("objviewer -file
<filename>", i, args);
+ }
+ }
+
+ // Load in the file using glm.
+ GLMmodel *model = glmReadOBJ( file_name.c_str() );
+ if (model == 0) {
+ std::cout << "Error cannot read model from file." <<
std::endl;
+ return 0;
+ }
+
+ // Flip the face winding.
+ glmReverseWinding( model );
+ // glmScale( model, 10.0 );
+
+
/////////////////////////////////////////////////////////////////////////////
+ // Allocate storage for primitives and materials.
+ int total_triangles = model->numtriangles;
+ Triangle *triangle_array = new Triangle[ total_triangles ];
+ Material **material_array = new Material *[ model->nummaterials ];
+
+ int tri = 0;
+ int mtl = 0;
+
+ // Read in the materials.
+ for (int i=0;i<model->nummaterials;++i) {
+
+ float c0 = model->materials[i].diffuse[0];
+ float c1 = model->materials[i].diffuse[1];
+ float c2 = model->materials[i].diffuse[2];
+
+ Color diffuse(RGB( c0, c1, c2 ));
+
+ // Check the material name.
+ string mtl_name = model->materials[i].name;
+ if (mtl_name.find("Clear")==0) {
+
+ // Note that the first material added by blender is
always an
+ // unused default material..
+ material_array[i-1] = new Dielectric( diffuse,
Color(RGB(0.6,0.6,0.8)), 128, 1.2, 1.2 );
+ }
+ else {
+ material_array[i-1] = new Lambertian( diffuse );
+ }
+ }
+
+ // Lambertian *default_material = new Lambertian( Color(RGB( 1.0,
0.0, 0.0 ) ) );
+ Material *default_material = new NormalMaterial();
+
+ // Read in the groups.
+ GLMgroup *group = model->groups;
+ while (group != 0) {
+
+ // Determine the material for this group.
+ Material *material;
+ if ((group->material-1) < model->nummaterials) {
+ material = material_array[group->material-1];
+ }
+ else {
+ material = default_material;
+ }
+
+ // Copy out triangles.
+ int total_faces = group->numtriangles;
+ for (int i=0;i<total_faces;++i) {
+
+ Point vertex[3];
+ for (int v=0;v<3;++v) {
+ int index = model->triangles[
group->triangles[i] ].vindices[v];
+ float *f = model->vertices+(index*3);
+ // Copy out the vertex.
+ vertex[v][0] = f[0];
+ vertex[v][1] = f[1];
+ vertex[v][2] = f[2];
+ }
+
+ // Create a new triangle.
+ triangle_array[tri++] =
+ Triangle( material, vertex[0], vertex[1],
vertex[2] );
+ }
+
+ // Move to the next group.
+ group = group->next;
+ ++mtl;
+ }
+
+ std::cerr << "Total triangles added: " << tri << std::endl;
+
+
/////////////////////////////////////////////////////////////////////////////
+ // Create an acceleration structure.
+ double time_begin = Time::currentSeconds();
+
+ // Make an array of pointers to triangles for input to the bvh.
+ Object **triangle_ptr_array = new Object *[ total_triangles ];
+ for (int i=0;i<total_triangles;++i) {
+ triangle_ptr_array[i] = triangle_array+i;
+ }
+
+ // Construct the bvh.
+ RealisticBvh *bvh = new RealisticBvh( triangle_ptr_array,
total_triangles );
+
+ double time_end = Time::currentSeconds();
+
+ std::cerr << "Bvh creation time: " << (time_end - time_begin)
+ << " seconds." << std::endl;
+
+
+
/////////////////////////////////////////////////////////////////////////////
+ // Check the size of bounding boxes.
+ PreprocessContext p_context;
+
+ BBox bounds;
+ bvh->computeBounds( p_context, bounds );
+
+ std::cerr << "Bvh: Bounding box " << bounds[0] << " : " << bounds[1]
<< std::endl;
+
+
/////////////////////////////////////////////////////////////////////////////
+ // Create the scene.
+ Scene *scene = new Scene();
+
+ // Add a head light.
+ LightSet *lights = new LightSet();
+ lights->add( new HeadLight( 2.0, Color(RGB(1.0,1.0,1.0)) ));
+ lights->setAmbientLight( new ConstantAmbient( Color(RGB(0.2,0.2,0.2)
) ));
+ scene->setLights( lights );
+
+ Material* red=new Lambertian(Color(RGBColor(.6,0,0)));
+ Material* yellow=new Lambertian(Color(RGBColor(.6,.6,0)));
+
+
+ // Add a checkerboard floor.
+ Material* plane_matl = new Phong(new
CheckerTexture<Color>(Color(RGBColor(.6,.6,0)),
+
Color(RGBColor(0,0,0)),
+
Vector(1,0,0),
+
Vector(0,1,0)),
+
new
Constant<Color>(Color(RGBColor(.6,.6,.6))),
+
32,
+
new
CheckerTexture<double>(0.2, 0.5,
+
Vector(1,0,0),
+
Vector(0,1,0)));
+
+ Parallelogram* floor = new Parallelogram(plane_matl,
Point(-20,-20,bounds[0][2]),
+
Vector(40,0,0), Vector(0,40,0));
+ Group *manta_group = new Group();
+ manta_group->add( floor );
+ // manta_group->add( new Cube( red, bounds[0], bounds[1] ) );
+ manta_group->add( bvh );
+
+ // Add the bvh to the scene.
+ scene->setObject( manta_group );
+
+ // Background.
+ scene->setBackground( new ConstantBackground( Color(RGB(0.8, 0.8,
0.8)) ) );
+
+ return scene;
+}
+
+
+
+
\ No newline at end of file
- [MANTA] r427 - in branches/itanium2: . Core Core/Geometry Engine/Control Engine/Display Interface Model/Groups Model/Materials Model/Primitives Model/Readers Model/Readers/glm StandAlone fox scenes, abe, 07/09/2005
Archive powered by MHonArc 2.6.16.