Пример #1
0
  bool QuadMesh::verify () 
  {
    /*! verify consistent size of vertex arrays */
    if (numTimeSteps == 2 && vertices[0].size() != vertices[1].size())
        return false;

    /*! verify proper quad indices */
    for (size_t i=0; i<quads.size(); i++) {     
      if (quads[i].v[0] >= numVertices()) return false; 
      if (quads[i].v[1] >= numVertices()) return false; 
      if (quads[i].v[2] >= numVertices()) return false; 
      if (quads[i].v[3] >= numVertices()) return false; 
    }

    /*! verify proper quad vertices */
    for (size_t j=0; j<numTimeSteps; j++) 
    {
      BufferT<Vec3fa>& verts = vertices[j];
      for (size_t i=0; i<verts.size(); i++) {
	if (!isvalid(verts[i])) 
	  return false;
      }
    }
    return true;
  }
Пример #2
0
//------------------------------------------------------------------------------
// Utilities
//------------------------------------------------------------------------------
/// Print the Polygon data to the console for debugging
void Polygon::echo( void ) {
    printf( "Verts %d: ", numVertices( ) );
    for( unsigned int j = 0; j < numVertices( ); j++ ) {
        if( j > 0 )
            printf( "," );
        printf( " %d", getVertex( j ) );
    }
    printf( "\n" );
}
Пример #3
0
	//return the current simplex
int SpuVoronoiSimplexSolver::getSimplex(btPoint3 *pBuf, btPoint3 *qBuf, btVector3 *yBuf) const
{
	int i;
	for (i=0;i<numVertices();i++)
	{
		yBuf[i] = m_simplexVectorW[i];
		pBuf[i] = m_simplexPointsP[i];
		qBuf[i] = m_simplexPointsQ[i];
	}
	return numVertices();
}
Пример #4
0
void	SpuVoronoiSimplexSolver::reduceVertices (const SpuUsageBitfield& usedVerts)
{
	if ((numVertices() >= 4) && (!usedVerts.usedVertexD))
		removeVertex(3);

	if ((numVertices() >= 3) && (!usedVerts.usedVertexC))
		removeVertex(2);

	if ((numVertices() >= 2) && (!usedVerts.usedVertexB))
		removeVertex(1);
	
	if ((numVertices() >= 1) && (!usedVerts.usedVertexA))
		removeVertex(0);

}
Пример #5
0
/*
 * Returns the number of edges from head on
 */
int numVertices(vertexSet * head)
{
  if(head == NULL)
    return 0;
  else
    return 1 + numVertices(head->nextVertex);
}
Пример #6
0
B Graph::walkBreadthFirst(int from, B body) const
{
    std::vector<bool> was(numVertices(), false);
    std::queue<int> vertices;

    was[from] = true;
    vertices.push(from);

    while (!vertices.empty())
    {
        int vertex = vertices.front();
        vertices.pop();

        std::list<GraphEdge>::const_iterator edge = edges_[vertex].begin();
        for (; edge != edges_[vertex].end(); ++edge)
        {
            if (!was[edge->to])
            {
                body(*edge);
                was[edge->to] = true;
                vertices.push(edge->to);
            }
        }
    }

    return body;
}
Пример #7
0
void Muscle::create(	btSoftBodyWorldInfo& worldInfo)
{
    int nodeCount = numVertices();

    btVector3*		x=new btVector3[nodeCount];
    btScalar*		m=new btScalar[nodeCount];

    int nFascicle = 0;
    for(std::vector<MuscleFascicle>::iterator it = m_fascicles.begin() ; it != m_fascicles.end(); ++it) {
        for(int i = 0; i < (*it).numVertices(); i++) {
            int vert = vertexIdx(nFascicle, i);
            x[vert] = (*it).vertexAt(i);
            m[vert] = 0.1f;
        }
        nFascicle++;
    }

    m_dynBody = new btSoftBody(&worldInfo,nodeCount,x,m);

    delete[] x;
    delete[] m;

    nFascicle = 0;
    for(std::vector<MuscleFascicle>::iterator it = m_fascicles.begin() ; it != m_fascicles.end(); ++it) {
        for(int i = 1; i < (*it).numVertices(); i++) {
            int vert = vertexIdx(nFascicle, i);
            m_dynBody->appendLink(vert-1, vert);
        }
        nFascicle++;
    }

    m_dynBody->m_materials[0]->m_kLST	= 0.1326945;
}
Пример #8
0
Polygon3::IndexedVertex const &
Polygon3::getVertex(long poly_index) const
{
  debugAssertM(poly_index >= 0 && poly_index < numVertices(), "Polygon3: Vertex index out of bounds");

  return vertices[(size_t)poly_index];
}
Пример #9
0
  void NativeCurves::setBuffer(RTCBufferType type, void* ptr, size_t offset, size_t stride, size_t size) 
  { 
    if (scene->isStatic() && scene->isBuild())
      throw_RTCError(RTC_INVALID_OPERATION,"static geometries cannot get modified");

    /* verify that all accesses are 4 bytes aligned */
    if (((size_t(ptr) + offset) & 0x3) || (stride & 0x3)) 
      throw_RTCError(RTC_INVALID_OPERATION,"data must be 4 bytes aligned");

    unsigned bid = type & 0xFFFF;
    if (type >= RTC_VERTEX_BUFFER0 && type < RTCBufferType(RTC_VERTEX_BUFFER0 + numTimeSteps)) 
    {
      size_t t = type - RTC_VERTEX_BUFFER0;
      vertices[t].set(ptr,offset,stride,size); 
      vertices[t].checkPadding16();
    } 
    else if (type >= RTC_USER_VERTEX_BUFFER0 && type < RTC_USER_VERTEX_BUFFER0+RTC_MAX_USER_VERTEX_BUFFERS)
    {
      if (bid >= userbuffers.size()) userbuffers.resize(bid+1);
      userbuffers[bid] = APIBuffer<char>(scene->device,numVertices(),stride);
      userbuffers[bid].set(ptr,offset,stride,size);  
      userbuffers[bid].checkPadding16();
    }
    else if (type == RTC_INDEX_BUFFER) 
    {
      if (isEnabled() && size != (size_t)-1) disabling();
      curves.set(ptr,offset,stride,size); 
      setNumPrimitives(size);
      if (isEnabled() && size != (size_t)-1) enabling();
    }
    else 
        throw_RTCError(RTC_INVALID_ARGUMENT,"unknown buffer type"); 
  }
Пример #10
0
bool btVoronoiSimplexSolver::inSimplex(const btVector3& w)
{
	bool found = false;
	int i, numverts = numVertices();
	//btScalar maxV = btScalar(0.);
	
	//w is in the current (reduced) simplex
	for (i=0;i<numverts;i++)
	{
#ifdef BT_USE_EQUAL_VERTEX_THRESHOLD
		if ( m_simplexVectorW[i].distance2(w) <= m_equalVertexThreshold)
#else
		if (m_simplexVectorW[i] == w)
#endif
		{
			found = true;
			break;
		}
	}

	//check in case lastW is already removed
	if (w == m_lastW)
		return true;
    	
	return found;
}
Пример #11
0
  void BezierCurves::setBuffer(RTCBufferType type, void* ptr, size_t offset, size_t stride) 
  { 
    if (parent->isStatic() && parent->isBuild())
      throw_RTCError(RTC_INVALID_OPERATION,"static geometries cannot get modified");

    /* verify that all accesses are 4 bytes aligned */
    if (((size_t(ptr) + offset) & 0x3) || (stride & 0x3)) 
      throw_RTCError(RTC_INVALID_OPERATION,"data must be 4 bytes aligned");

    /* verify that all vertex accesses are 16 bytes aligned */
#if defined(__MIC__) && 0
    if (type == RTC_VERTEX_BUFFER0 || type == RTC_VERTEX_BUFFER1) {
      if (((size_t(ptr) + offset) & 0xF) || (stride & 0xF))
        throw_RTCError(RTC_INVALID_OPERATION,"data must be 16 bytes aligned");
    }
#endif

    switch (type) {
    case RTC_INDEX_BUFFER  : 
      curves.set(ptr,offset,stride); 
      break;
    case RTC_VERTEX_BUFFER0: 
      vertices[0].set(ptr,offset,stride); 
      vertices[0].checkPadding16();
      break;
    case RTC_VERTEX_BUFFER1: 
      vertices[1].set(ptr,offset,stride); 
      vertices[1].checkPadding16();
      break;
    case RTC_USER_VERTEX_BUFFER0  : 
      if (userbuffers[0] == nullptr) userbuffers[0].reset(new Buffer(parent->device,numVertices(),stride)); 
      userbuffers[0]->set(ptr,offset,stride);  
      userbuffers[0]->checkPadding16();
      break;
    case RTC_USER_VERTEX_BUFFER1  : 
      if (userbuffers[1] == nullptr) userbuffers[1].reset(new Buffer(parent->device,numVertices(),stride)); 
      userbuffers[1]->set(ptr,offset,stride);  
      userbuffers[1]->checkPadding16();
      break;
    default: 
      throw_RTCError(RTC_INVALID_ARGUMENT,"unknown buffer type"); 
      break;
    }
  }
Пример #12
0
B Graph::forEach(B body) const
{
    for (int i = 0; i < numVertices(); ++i)
    {
        std::list<GraphEdge>::const_iterator edge = edges_[i].begin();
        for (; edge != edges_[i].end(); ++edge)
            body(*edge);
    }
    return body;
}
Пример #13
0
char SkeletonSubspaceDeformer::solve()
{
	if(!m_skeleton) return 0;

	Vector3F * p = deformedP();
	for(unsigned i = 0; i < numVertices(); i++)
	    p[i] = combine(i);

	return 1;
}
Пример #14
0
 void NativeCurvesISA::commit_helper()
 {
   if (native_curves.size() != curves.size()) 
   {
     native_curves = APIBuffer<unsigned>(scene->device,curves.size(),sizeof(unsigned int),true);
     parallel_for(size_t(0), curves.size(), size_t(1024), [&] ( const range<size_t> r) {
         for (size_t i=r.begin(); i<r.end(); i++) {
           if (curves[i]+3 >= numVertices()) native_curves[i] = 0xFFFFFFF0; // invalid curves stay invalid this way
           else                              native_curves[i] = unsigned(4*i);
         }
       });
   }
   
   if (native_vertices.size() != vertices.size())
     native_vertices.resize(vertices.size());
   
   parallel_for(vertices.size(), [&] ( const size_t i ) {
       
       if (native_vertices[i].size() != 4*curves.size())
         native_vertices[i] = APIBuffer<Vec3fa>(scene->device,4*curves.size(),sizeof(Vec3fa),true);
       
       parallel_for(size_t(0), curves.size(), size_t(1024), [&] ( const range<size_t> rj ) {
           
           for (size_t j=rj.begin(); j<rj.end(); j++)
           {
             const unsigned id = curves[j];
             if (id+3 >= numVertices()) continue; // ignore invalid curves
             const Vec3fa v0 = vertices[i][id+0];
             const Vec3fa v1 = vertices[i][id+1];
             const Vec3fa v2 = vertices[i][id+2];
             const Vec3fa v3 = vertices[i][id+3];
             const InputCurve3fa icurve(v0,v1,v2,v3);
             OutputCurve3fa ocurve; convert<Vec3fa>(icurve,ocurve);
             native_vertices[i].store(4*j+0,ocurve.v0);
             native_vertices[i].store(4*j+1,ocurve.v1);
             native_vertices[i].store(4*j+2,ocurve.v2);
             native_vertices[i].store(4*j+3,ocurve.v3);
           }
         });
     });
   native_vertices0 = native_vertices[0];
 }
Пример #15
0
void Renderable::render()
{
	switch (primitiveType()) {
	case kPrimitiveTypeTriangles:
		glDrawArrays(GL_TRIANGLES, 0, numVertices());
		break;

	default:
		break;
	}
}
Пример #16
0
Vector3F QuadraticCurve::interpolate(float param) const
{
	unsigned k0 = 0;
	unsigned k1 = numVertices() - 1;
	
	if(param <= 0.f) return m_cvs[k0];
	if(param >= 1.f) return m_cvs[k1];
	
	findNeighborKnots(param, k0, k1);
	
	return interpolateStraight(param - m_knots[k0], k0, k1);
}
Пример #17
0
btScalar SpuVoronoiSimplexSolver::maxVertex()
{
	int i, numverts = numVertices();
	btScalar maxV = btScalar(0.);
	for (i=0;i<numverts;i++)
	{
		btScalar curLen2 = m_simplexVectorW[i].length2();
		if (maxV < curLen2)
			maxV = curLen2;
	}
	return maxV;
}
Пример #18
0
	bool BspSceneFile::loadVertices(std::istream& bspStream, const Q3Bsp::DirEntry& verticesEntry) {
		if (!bspStream.seekg(verticesEntry.offset, std::ios::beg)) {
			return false;
		}
		
		std::size_t numVertices(verticesEntry.length / sizeof(Q3Bsp::Vertex));
		m_vertices.reserve(numVertices);
		
		if (!bspStream.read(reinterpret_cast<char*>(&m_vertices[0]), verticesEntry.length)) {
			return false;
		}
		return true;
	}
Пример #19
0
void BccLattice::logTetrahedronMesh()
{
    Vector3F p;
    BaseLog log("./tetmesh.txt");
    
    log.write(boost::str(boost::format("static const unsigned TetraNumVertices = %1%;\n") % numVertices()));
	log.write(boost::str(boost::format("static const float TetraP[%1%][3] = {\n") % numVertices()));
	sdb::CellHash * latticeNode = cells();
    
	latticeNode->begin();
	while(!latticeNode->end()) {
	    if(latticeNode->value()->visited) {
	        p = nodeCenter(latticeNode->key());
	        log.write(boost::str(boost::format("{%1%f,%2%f,%3%f}") % p.x % p.y % p.z));
	        if(latticeNode->value()->index < numVertices()-1) log.write(",\n");
	        else log.write("\n");
	    }
	    latticeNode->next();
	}
	log.write("};\n");
	log.write(boost::str(boost::format("static const unsigned TetraNumTetrahedrons = %1%;\n") % numTetrahedrons()));
	log.write(boost::str(boost::format("static const unsigned TetraIndices[%1%][4] = {\n") % numTetrahedrons()));
	
	unsigned i, j;
	unsigned v[4];
	for(i=0; i< numTetrahedrons(); i++) {
        Tetrahedron * tet = &m_tetrahedrons[i];
        for(j=0; j< 4; j++) {
            sdb::CellValue * found = findGrid(tet->v[j]);
            v[j] = found->index;
        }
        log.write(boost::str(boost::format("{%1%,%2%,%3%,%4%}") % v[0] % v[1] % v[2] % v[3]));
	    if(i < numTetrahedrons()-1) log.write(",\n");
	    else log.write("\n");
    }
    
	log.write("};\n");
}
Пример #20
0
unsigned int Polygon<Scalar>::numIsolatedVertices() const
{
    vector<unsigned int> neighor_edge_count(numVertices(),0);
    for(unsigned int group_idx = 0; group_idx < groups_.size(); ++group_idx)
    {
        const EdgeGroup<Scalar,2> &group = groups_[group_idx];
        for(unsigned int edge_idx = 0; edge_idx < group.numEdges(); ++edge_idx)
        {
            const Edge<Scalar,2> &edge = group.edge(edge_idx);
            for(unsigned int vert_idx = 0; vert_idx < edge.numVertices(); ++vert_idx)
            {
                const Vertex<Scalar> &vertex = edge.vertex(vert_idx);
                unsigned int pos_idx = vertex.positionIndex();
                ++neighor_edge_count[pos_idx];
            }
        }
    }
    unsigned int num_isolated_vertices = 0;
    for(unsigned int i = 0; i < numVertices(); ++i)
        if(neighor_edge_count[i]>0)
            ++num_isolated_vertices;
    return num_isolated_vertices;
}
Пример #21
0
  bool TriangleMesh::verify () 
  {
    /*! verify consistent size of vertex arrays */
    if (vertices.size() == 0) return false;
    for (const auto& buffer : vertices)
      if (vertices[0].size() != buffer.size())
        return false;

    /*! verify triangle indices */
    for (size_t i=0; i<triangles.size(); i++) {     
      if (triangles[i].v[0] >= numVertices()) return false; 
      if (triangles[i].v[1] >= numVertices()) return false; 
      if (triangles[i].v[2] >= numVertices()) return false; 
    }

    /*! verify vertices */
    for (const auto& buffer : vertices)
      for (size_t i=0; i<buffer.size(); i++)
	if (!isvalid(buffer[i])) 
	  return false;

    return true;
  }
Пример #22
0
//reads in an object from a .obj file
BasicObject::BasicObject(const std::string &filename, const float _shininess){

	shininess    = _shininess;

	_numVerticies = numVertices(filename.c_str());
	_numFaces 	  = numFaces(filename.c_str());
	_indexCount   = _numFaces * 3;

	verticies 	  = getVertices(filename.c_str(), _numVerticies);
	normals 	  = getNormals(filename.c_str(), _numVerticies);
	faces 		  = getFaces(filename.c_str(), _numFaces);
	texCoords 	  = getTextureCoords(filename.c_str(), _numVerticies);

}
Пример #23
0
  void TriangleMesh::setBuffer(RTCBufferType type, void* ptr, size_t offset, size_t stride) 
  { 
    if (parent->isStatic() && parent->isBuild()) 
      throw_RTCError(RTC_INVALID_OPERATION,"static scenes cannot get modified");

    /* verify that all accesses are 4 bytes aligned */
    if (((size_t(ptr) + offset) & 0x3) || (stride & 0x3)) 
      throw_RTCError(RTC_INVALID_OPERATION,"data must be 4 bytes aligned");

    switch (type) {
    case RTC_INDEX_BUFFER  : 
      triangles.set(ptr,offset,stride); 
      break;
    case RTC_VERTEX_BUFFER0: 
      vertices[0].set(ptr,offset,stride); 
      vertices[0].checkPadding16();
      break;
    case RTC_VERTEX_BUFFER1: 
      vertices[1].set(ptr,offset,stride); 
      vertices[1].checkPadding16();
      break;

    case RTC_USER_VERTEX_BUFFER0: 
      if (userbuffers[0] == nullptr) userbuffers[0].reset(new Buffer(parent->device,numVertices(),stride)); 
      userbuffers[0]->set(ptr,offset,stride);  
      userbuffers[0]->checkPadding16();
      break;
    case RTC_USER_VERTEX_BUFFER1: 
      if (userbuffers[1] == nullptr) userbuffers[1].reset(new Buffer(parent->device,numVertices(),stride)); 
      userbuffers[1]->set(ptr,offset,stride);  
      userbuffers[1]->checkPadding16();
      break;

    default: 
      throw_RTCError(RTC_INVALID_ARGUMENT,"unknown buffer type");
    }
  }
Пример #24
0
  bool QuadMesh::verify() 
  {
    /*! verify consistent size of vertex arrays */
    if (vertices.size() == 0) return false;
    for (const auto& buffer : vertices)
      if (buffer.size() != numVertices())
        return false;

    /*! verify quad indices */
    for (size_t i=0; i<size(); i++) {     
      if (quads[i].v[0] >= numVertices()) return false; 
      if (quads[i].v[1] >= numVertices()) return false; 
      if (quads[i].v[2] >= numVertices()) return false; 
      if (quads[i].v[3] >= numVertices()) return false; 
    }

    /*! verify vertices */
    for (const auto& buffer : vertices)
      for (size_t i=0; i<buffer.size(); i++)
	if (!isvalid(buffer[i])) 
	  return false;

    return true;
  }
Пример #25
0
  void ScanObject::m_update() {
    // TODO: Build a mesh representing the isosurface
    // FIXME: The contour value needs to be specified
    // TODO: Allow the isosurface extraction algorithm to be specified
    // TODO: Allow the resolution to be specified
    auto mesh = m_isosurfaceBuilder.buildIsosurface(
        m_scan.scalarField(),  // scalarField
        MC_SIMPLE_MARCHING_CUBES,  // algorithm
        m_resX, m_resY, m_resZ,  // res
        Vec3(-1.0f, -1.0f, -1.0f),  // min
        Vec3(1.0f, 1.0f, 1.0f)  // max
        );
    fprintf(stderr, "mesh->numVertices(): %d\n", mesh->numVertices());

    // Generate wireframe data and send it to the GL
    this->setMesh(*mesh);
  }
Пример #26
0
  bool BezierCurves::verify () 
  {
    if (numTimeSteps == 2 && vertices[0].size() != vertices[1].size())
        return false;

    for (size_t i=0; i<numPrimitives; i++) {
      if (curves[i]+3 >= numVertices()) return false;
    }
    for (size_t j=0; j<numTimeSteps; j++) {
      BufferT<Vec3fa>& verts = vertices[j];
      for (size_t i=0; i<verts.size(); i++) {
        if (!isvalid(verts[i].x)) return false;
	if (!isvalid(verts[i].y)) return false;
	if (!isvalid(verts[i].z)) return false;
	if (!isvalid(verts[i].w)) return false;
      }
    }
    return true;
  }
Пример #27
0
  void TriangleMesh::write(std::ofstream& file)
  {
    int type = TRIANGLE_MESH;
    file.write((char*)&type,sizeof(int));
    file.write((char*)&numTimeSteps,sizeof(int));
    int numVerts = numVertices();
    file.write((char*)&numVerts,sizeof(int));
    int numTriangles = triangles.size();
    file.write((char*)&numTriangles,sizeof(int));

    for (size_t j=0; j<numTimeSteps; j++) {
      while ((file.tellp() % 16) != 0) { char c = 0; file.write(&c,1); }
      for (size_t i=0; i<numVerts; i++) file.write((char*)vertexPtr(i,j),sizeof(Vec3fa));  
    }

    while ((file.tellp() % 16) != 0) { char c = 0; file.write(&c,1); }
    for (size_t i=0; i<numTriangles; i++) file.write((char*)&triangle(i),sizeof(Triangle));  

  }
Пример #28
0
Visualization::Abstract::DataSet* TurbulenceGenerator::load(const char* filename) const
	{
	/* Create the data set: */
	TurbulenceGeneratorTypes::DS::Index numVertices(128,128,128);
	TurbulenceGeneratorTypes::DataSet* result=new TurbulenceGeneratorTypes::DataSet;
	result->getDs().setData(numVertices);
	
	/* Create the vertex values: */
	Noise ns(5,3);
	TurbulenceGeneratorTypes::DS::Array& vertices=result->getDs().getVertices();
	float cellSize[3]={0.05f,0.05f,0.05f};
	float minLat=Math::rad(20.0f);
	float maxLat=Math::rad(60.0f);
	float minLng=Math::rad(60.0f);
	float maxLng=Math::rad(120.0f);
	float minR=3000.0f;
	float maxR=6371.0f;
	for(TurbulenceGeneratorTypes::DS::Index index(0);index[0]<vertices.getSize(0);vertices.preInc(index))
		{
		TurbulenceGeneratorTypes::DS::GridVertex& vertex=vertices(index);
		
		/* Calculate the vertex position: */
		float lat=float(index[0])*(maxLat-minLat)/float(vertices.getSize(0)-1)+minLat;
		float lng=float(index[1])*(maxLng-minLng)/float(vertices.getSize(1)-1)+minLng;
		float r=float(index[2])*(maxR-minR)/float(vertices.getSize(2)-1)+minR;
		float xy=Math::cos(lat)*r;
		float z=Math::sin(lat)*r;
		float y=Math::sin(lng)*xy;
		float x=Math::cos(lng)*xy;
		vertex.pos=TurbulenceGeneratorTypes::DS::Point(x,y,z);
		
		/* Calculate the vertex value: */
		Noise::Point p;
		for(int i=0;i<3;++i)
			p[i]=float(index[i])*cellSize[i];
		vertex.value=ns.calcTurbulence(p,4);
		}
	
	/* Finalize the grid structure: */
	result->getDs().finalizeGrid();
	
	return result;
	}
Пример #29
0
bool SpuVoronoiSimplexSolver::inSimplex(const btVector3& w)
{
	bool found = false;
	int i, numverts = numVertices();
	//btScalar maxV = btScalar(0.);
	
	//w is in the current (reduced) simplex
	for (i=0;i<numverts;i++)
	{
		if (m_simplexVectorW[i] == w)
			found = true;
	}

	//check in case lastW is already removed
	if (w == m_lastW)
		return true;
    	
	return found;
}
Пример #30
0
  void QuadMesh::write(std::ofstream& file)
  {
    int type = QUAD_MESH;
    file.write((char*)&type,sizeof(int));
    file.write((char*)&numTimeSteps,sizeof(int));
    int numVerts = numVertices();
    file.write((char*)&numVerts,sizeof(int));
    int numQuads = quads.size();
    file.write((char*)&numQuads,sizeof(int));

    for (size_t j=0; j<numTimeSteps; j++) {
      while ((file.tellp() % 16) != 0) { char c = 0; file.write(&c,1); }
      for (size_t i=0; i<numVerts; i++) file.write((char*)vertexPtr(i,j),sizeof(Vec3fa));  
    }

    while ((file.tellp() % 16) != 0) { char c = 0; file.write(&c,1); }
    for (size_t i=0; i<numQuads; i++) file.write((char*)&quad(i),sizeof(Quad));  

  }