Пример #1
0
void FPoly::Scale
(
    const FVector&		PreSubtract,
    const FVector&		Scale
)
{
    if (Scale.X == 1.f &&
            Scale.Y == 1.f &&
            Scale.Z == 1.f)
    {
        return;
    }

    // Scale the vertices.
    for (int32 Vertex = 0; Vertex < Vertices.Num(); Vertex++)
    {
        Vertices[Vertex] = PreSubtract + (Vertices[Vertex] - PreSubtract) * Scale;
    }

    Base = PreSubtract + (Base - PreSubtract) * Scale;

    // Scale the texture vectors.
    TextureU *= Scale;
    TextureV *= Scale;

    // Recalculate the normal. Non-uniform scale or mirroring requires this.
    CalcNormal(true);
}
Пример #2
0
LineSeg::LineSeg(const Vertex2D& p1, const Vertex2D& p2, const float _zlow, const float _zhigh)
    : v1(p1), v2(p2)
{
    m_rcHitRect.zlow = _zlow;
    m_rcHitRect.zhigh = _zhigh;
    CalcNormal();
}
Пример #3
0
void CGWorldTriangleStrip::SetRotationStripNormals()
{
    //Sets normal vectors for all the triangles assuming that
    //the represent a rectangular solid between two stations.
    ASSERT(m_iNumVertices==10);	//if not,this is some other shape
    //Could go to 11, but if the user f****d up the call into here
    //at least this won't crash

    //The pattern we used is aimed at given normals to the
    //vertices which are between the two flat surfaces.  Best is to
    //simply draw the pattern and figure out how this works for
    //yourself.
    for (int i=0; i<m_iNumVertices; i++)
    {
        int iOne,iThree;
        int iTwo=i;
        if (i%2==0)	//even
        {
            iOne=i-3;
            iThree=i+1;
        }
        else
        {
            iOne=i-1;
            iThree=i+3;
        }
        if (iOne<0)
            iOne+=10;
        if (iThree>=10)
            iThree-=10;
        CalcNormal(m_pVertices[iOne].m_fPos,m_pVertices[iTwo].m_fPos,m_pVertices[iThree].m_fPos,m_pVertices[i].m_fNormal);
    }
}
Пример #4
0
int CPolyMesh3::CalcOrgNormal()
{
	int fno;
	for( fno = 0; fno < m_facenum; fno++ ){
		int n3p = fno * 3;
		N3P* curn3p = m_n3p + n3p;

		D3DXVECTOR3 vpos[3];
		int indexno;
		for( indexno = 0; indexno < 3; indexno++ ){
			int vertno = (curn3p + indexno)->pervert->vno;
			vpos[indexno] = *( m_pointbuf + vertno );
		}

		D3DXVECTOR3 nvec;
		CalcNormal( &nvec, vpos, vpos + 1, vpos + 2 );

		for( indexno = 0; indexno < 3; indexno++ ){
			(curn3p + indexno)->perface->facenormal = nvec;
			(curn3p + indexno)->pervert->smnormal = nvec;
		}
	}

	return 0;
}
Пример #5
0
void TriObject::applyNormals()
{
	if (numfaces == 0) return;
	delete[]nx;
	delete[]ny;
	delete[]nz;
	nx = new float[numfaces / 3];
	ny = new float[numfaces / 3];
	nz = new float[numfaces / 3];
	if (nx == NULL || ny == NULL || nz == NULL)
	{
		delete[]nx;
		delete[]ny;
		delete[]nz;
		normalapplied = FALSE;
		return;
	}

	float normal[3];
	for (int i = 0; i < numfaces / 3; i++)
	{
		CalcNormal(3 * i, normal);
		ReduceToUnit(normal);
		nx[i] = normal[0];
		ny[i] = normal[1];
		nz[i] = normal[2];
	}
	normalapplied = TRUE;
}
Пример #6
0
bool HypercomplexZ3FractalRules::Iterate(const Vector3d& IPoint, const Fractal *HCompl, const Vector3d& Direction, DBL *Dist, DBL **IterStack) const
{
    int i;
    DBL xx, yy, zz, ww;
    DBL Exit_Value, F_Value, Step;
    DBL x, y, z, w;
    Vector3d H_Normal;

    x = IterStack[X][0] = IPoint[X];
    y = IterStack[Y][0] = IPoint[Y];
    z = IterStack[Z][0] = IPoint[Z];
    w = IterStack[W][0] = (HCompl->SliceDist
                           - HCompl->Slice[X]*x
                           - HCompl->Slice[Y]*y
                           - HCompl->Slice[Z]*z)/HCompl->Slice[T];

    Exit_Value = HCompl->Exit_Value;

    for (i = 1; i <= HCompl->Num_Iterations; ++i)
    {
        F_Value = x * x + y * y + z * z + w * w;

        if (F_Value > Exit_Value)
        {
            CalcNormal(H_Normal, i - 1, HCompl, IterStack);

            Step = dot(H_Normal, Direction);

            if (Step < -Fractal_Tolerance)
            {
                Step = -2.0 * Step;

                if ((F_Value > HCompl->Precision * Step) && (F_Value < 30 * HCompl->Precision * Step))
                {
                    *Dist = F_Value / Step;

                    return (false);
                }
            }

            *Dist = HCompl->Precision;

            return (false);
        }

        /*************** Case: z->z^2+c *********************/

        HSqr(xx, yy, zz, ww, x, y, z, w);

        x = IterStack[X][i] = xx + HCompl->Julia_Parm[X];
        y = IterStack[Y][i] = yy + HCompl->Julia_Parm[Y];
        z = IterStack[Z][i] = zz + HCompl->Julia_Parm[Z];
        w = IterStack[W][i] = ww + HCompl->Julia_Parm[T];
    }

    *Dist = HCompl->Precision;

    return (true);
}
Пример #7
0
Intersection *Sphere::IntersectsRay(Ray r, STTransform4 transMatrix) {
    float a, b, c;
    a = pow(r.direction.x,2) + pow(r.direction.y,2) + pow(r.direction.z,2);
    b = 2*((r.start.x - center.x)*r.direction.x + (r.start.y - center.y)*r.direction.y + (r.start.z - center.z)*r.direction.z);
    c = pow(r.start.x - center.x,2) + pow(r.start.y - center.y,2) + pow(r.start.z - center.z,2) - pow(radius,2);
    
    float discriminant = pow(b,2) - 4*a*c;

    if (discriminant < 0.0) return NULL;
    if (discriminant == 0.0) {
        float t = -b / (2*a);
        if (r.invalidT(t))  return NULL;
        
        
        STVector3 interRay = (*(r.InterpolatedRay(t)));
        
        STVector3 normal = CalcNormal(interRay, r);
        Intersection *rt = new Intersection(t, interRay, normal, r.TransformRay(transMatrix.Inverse()));
        return rt;
    } 
        float t1 = (-b - sqrt(discriminant)) / (2*a);
        float t2 = (-b + sqrt(discriminant)) / (2*a);
        
        if (r.invalidT(t1) && !r.invalidT(t2)) {
            STVector3 interRay = (*(r.InterpolatedRay(t2)));            
            STVector3 normal = CalcNormal(interRay, r);
            Intersection *rt = new Intersection(t2, interRay, normal, r.TransformRay(transMatrix.Inverse()));
            return rt;
        }
        
        if (!r.invalidT(t1) && r.invalidT(t2)) {
            STVector3 interRay = (*(r.InterpolatedRay(t1)));
            STVector3 normal = CalcNormal(interRay, r);
            Intersection *rt = new Intersection(t1, interRay, normal, r.TransformRay(transMatrix.Inverse()));
            return rt;
        }
        
        if (r.invalidT(t1) && r.invalidT(t2)) return NULL;
        
        STVector3 interRay = (*(r.InterpolatedRay(fmin(t1,t2))));
        
        STVector3 normal = CalcNormal(interRay, r);
        Intersection *rt = new Intersection(fmin(t1,t2), interRay, normal, r.TransformRay(transMatrix.Inverse()));
        return rt;
    
}
Пример #8
0
void CGWorldTriangleStrip::SetRectNormals()
{
    //Sets normal vectors for all the triangles assuming that
    //the represent a flat rectangle
    ASSERT(m_iNumVertices==4);	//if not,this is some other shape

    float fNormal[3];
    CalcNormal(m_pVertices[0].m_fPos,m_pVertices[1].m_fPos,m_pVertices[2].m_fPos,fNormal);
    for (int i=0; i<m_iNumVertices; i++)
    {
        m_pVertices[i].m_fNormal[0]=fNormal[0];
        m_pVertices[i].m_fNormal[1]=fNormal[1];
        m_pVertices[i].m_fNormal[2]=fNormal[2];
    }
}
bool ribi::Geometry::IsCounterClockwiseCartesian(
  const Coordinats3D& points,
  const Coordinat3D& observer
) const noexcept
{
  // const bool verbose{false};
  const int n_points{static_cast<int>(points.size())};
  assert(n_points == 3 || n_points == 4);
  if (n_points == 3)
  {
    const auto a = points[0];
    const auto b = points[1];
    const auto c = points[2];
    const auto normal = CalcNormal(a,b,c);
    const double direction{CalcDotProduct(normal,a - observer)};
    const bool is_counter_clockwise{direction > 0.0}; //Difference between CW ('<') and CCW ('>')
    return is_counter_clockwise;
  }
  else
  {
    assert(n_points == 4);
    //See if the points in the projection are in the same direction
    assert(Geometry().IsPlane(points));
    const std::unique_ptr<Plane> plane(new Plane(points[0],points[1],points[2]));
    assert(plane);
    const auto v =
      plane->CalcProjection(
        {
          points[0],
          points[1],
          points[2],
          points[3]
        }
      )
    ;

    //If the points are messed up, they cannot be clockwise
    if (!IsClockwiseCartesianHorizontal(v) && !IsCounterClockwiseCartesianHorizontal(v)) return false;
    //The neatly orderder point have the same winding as the first three
    std::remove_const<std::remove_reference<decltype(points)>::type>::type a;
    std::copy(points.begin() + 0,points.begin() + 3,std::back_inserter(a));
    return IsCounterClockwiseCartesian(a,observer);
  }

}
Пример #10
0
bool FPoly::IsCoplanar()
{
    // 3 or fewer vertices is automatically coplanar

    if( Vertices.Num() <= 3 )
    {
        return 1;
    }

    CalcNormal(1);

    for( int32 x = 0 ; x < Vertices.Num() ; ++x )
    {
        if( !OnPlane( Vertices[x] ) )
        {
            return 0;
        }
    }

    // If we got this far, the poly has to be coplanar.

    return 1;
}
Пример #11
0
void DrawGLScene()
{
	stVec p1,p2,p3,Norm;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor4f(1.0f,0.0f,0.0f,0.25f);
    glLoadIdentity();

    glTranslatef(0.0f,0.0f,-5.0f);
    
    glRotatef(xrot,0.1f,0.1f,0.0f);
    glRotatef(yrot,0.0f,0.001f,0.0f);
    glRotatef(zrot,0.0f,0.0f,0.001f);

	//glMaterialfv(GL_FRONT, GL_AMBIENT, LightColor);
	//glMaterialfv(GL_FRONT, GL_SPECULAR, LightColor);
	
	//glutSolidTeapot(0.2f);

	glBegin(GL_TRIANGLES);
		// Calc the top face normal
		p3.x= 0.0f; p3.y= 0.0f; p3.z= -1.0f;
		p2.x= 0.5f; p2.y= -0.5f; p2.z= 0.0f;
		p1.x= 0.5f; p1.y= 0.5f; p1.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		//glColor4f(0.0f,1.0f,1.0f,1.0f);
		glVertex3f(0.0f, 0.0f,  -1.0f);
		glVertex3f(0.5f, -0.5f,  0.0f);
		glVertex3f(0.5f, 0.5f,  0.0f);

		// Calc the top face normal
		p1.x= 0.0f; p1.y= 0.0f; p1.z= -1.0f;
		p2.x= -0.5f; p2.y= -0.5f; p2.z= 0.0f;
		p3.x= -0.5f; p3.y= 0.5f; p3.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		//glColor4f(1.0f,1.0f,0.0f,1.0f);
		glVertex3f(0.0f, 0.0f,  -1.0f);
		glVertex3f(-0.5f, -0.5f,  0.0f);
		glVertex3f(-0.5f, 0.5f,  0.0f);

		// Calc the top face normal
		p3.x= 0.0f; p3.y= 0.0f; p3.z= -1.0f;
		p2.x= -0.5f; p2.y= -0.5f; p2.z= 0.0f;
		p1.x= 0.5f; p1.y= -0.5f; p1.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		//glColor4f(0.0f,1.0f,0.0f,1.0f);
		glVertex3f(0.0f, 0.0f,  -1.0f);
		glVertex3f(-0.5f, -0.5f,  0.0f);
		glVertex3f(0.5f, -0.5f,  0.0f);

		// Calc the top face normal
		p1.x= 0.0f; p1.y= 0.0f; p1.z= -1.0f;
		p2.x= -0.5f; p2.y= 0.5f; p2.z= 0.0f;
		p3.x= 0.5f; p3.y= 0.5f; p3.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		//glColor4f(1.0f,0.0f,0.0f,1.0f);
		glVertex3f(0.0f, 0.0f,  -1.0f);
		glVertex3f(-0.5f, 0.5f,  0.0f);
		glVertex3f(0.5f, 0.5f,  0.0f);

	glEnd();

	glBegin(GL_QUADS);

		// Calc the top face normal
		p1.x= 0.25f; p1.y= 0.25f; p1.z= 0.5f;
		p2.x= -0.25f; p2.y= 0.25f; p2.z= 0.5f;
		p3.x= -0.25f; p3.y= -0.25f; p3.z= 0.5f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		glVertex3f(0.25f, 0.25f ,0.5f);
		glVertex3f(-0.25f, 0.25f ,0.5f);
		glVertex3f(-0.25f, -0.25f ,0.5f);
		glVertex3f(0.25f, -0.25f ,0.5f);

		// Calc the top face normal
		p3.x= 0.25f; p3.y= -0.25f; p3.z= 0.5f;
		p2.x= 0.25f; p2.y= 0.25f; p2.z= 0.5f;
		p1.x= 0.50f; p1.y= 0.50f; p1.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		glVertex3f(0.25f, -0.25f ,0.5f);
		glVertex3f(0.25f, 0.25f ,0.5f);
		glVertex3f(0.50f, 0.50f ,0.0f);
		glVertex3f(0.50f, -0.50f ,0.0f);

		// Calc the top face normal
		p3.x= -0.25f; p3.y= -0.25f; p3.z= 0.5f;
		p2.x= 0.25f; p2.y= -0.25f; p2.z= 0.5f;
		p1.x= 0.50f; p1.y= -0.50f; p1.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		glVertex3f(-0.25f, -0.25f ,0.5f);
		glVertex3f(0.25f, -0.25f ,0.5f);
		glVertex3f(0.50f, -0.50f ,0.0f);
		glVertex3f(-0.50f, -0.50f ,0.0f);

		// Calc the top face normal
		p1.x= -0.25f; p1.y= -0.25f; p1.z= 0.5f;
		p2.x= -0.25f; p2.y= 0.25f; p2.z= 0.5f;
		p3.x= -0.50f; p3.y= 0.50f; p3.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		glVertex3f(-0.25f, -0.25f ,0.5f);
		glVertex3f(-0.25f, 0.25f ,0.5f);
		glVertex3f(-0.50f, 0.50f ,0.0f);
		glVertex3f(-0.50f, -0.50f ,0.0f);

		// Calc the top face normal
		p1.x= -0.25f; p1.y= 0.25f; p1.z= 0.5f;
		p2.x= 0.25f; p2.y= 0.25f; p2.z= 0.5f;
		p3.x= 0.50f; p3.y= 0.50f; p3.z= 0.0f;
		Norm=CalcNormal(p1,p2,p3);
		glNormal3f(Norm.x,Norm.y,Norm.z);
		glVertex3f(-0.25f, 0.25f ,0.5f);
		glVertex3f(0.25f, 0.25f ,0.5f);
		glVertex3f(0.50f, 0.50f ,0.0f);
		glVertex3f(-0.50f, 0.50f ,0.0f);
	glEnd();

    xrot+=0.01f;
    yrot+=0.01f;
    zrot+=0.01f;

    glutSwapBuffers();
}
Пример #12
0
bool LoadObjAndConvert(float bmin[3], float bmax[3],
	std::vector<DrawObject>* drawObjects,
	std::vector<tinyobj::material_t>& materials,
	std::map<std::string, GLuint>& textures,
	const char* filename) {
	tinyobj::attrib_t attrib;
	std::vector<tinyobj::shape_t> shapes;

	timerutil tm;

	tm.start();

	std::string err;
	bool ret =
		tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, NULL);
	if (!err.empty()) {
		std::cerr << err << std::endl;
	}

	tm.end();

	if (!ret) {
		std::cerr << "Failed to load " << filename << std::endl;
		return false;
	}

	printf("Parsing time: %d [ms]\n", (int)tm.msec());

	printf("# of vertices  = %d\n", (int)(attrib.vertices.size()) / 3);
	printf("# of normals   = %d\n", (int)(attrib.normals.size()) / 3);
	printf("# of texcoords = %d\n", (int)(attrib.texcoords.size()) / 2);
	printf("# of materials = %d\n", (int)materials.size());
	printf("# of shapes    = %d\n", (int)shapes.size());

	// Append `default` material
	materials.push_back(tinyobj::material_t());

	// Load diffuse textures
	{
		for (size_t m = 0; m < materials.size(); m++) {
			tinyobj::material_t* mp = &materials[m];

			if (mp->diffuse_texname.length() > 0) {
				// Only load the texture if it is not already loaded
				if (textures.find(mp->diffuse_texname) == textures.end()) {
					GLuint texture_id;
					int w, h;
					int comp;
					unsigned char* image = stbi_load(mp->diffuse_texname.c_str(), &w, &h, &comp, STBI_default);
					if (image == nullptr) {
						std::cerr << "Unable to load texture: " << mp->diffuse_texname << std::endl;
						exit(1);
					}
					glGenTextures(1, &texture_id);
					glBindTexture(GL_TEXTURE_2D, texture_id);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
					if (comp == 3) {
						glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
					}
					else if (comp == 4) {
						glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
					}
					glBindTexture(GL_TEXTURE_2D, 0);
					stbi_image_free(image);
					textures.insert(std::make_pair(mp->diffuse_texname, texture_id));
				}
			}
		}
	}

	bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
	bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();

	{
		for (size_t s = 0; s < shapes.size(); s++) {
			DrawObject o;
			std::vector<float> vb;  // pos(3float), normal(3float), color(3float)
			for (size_t f = 0; f < shapes[s].mesh.indices.size() / 3; f++) {
				tinyobj::index_t idx0 = shapes[s].mesh.indices[3 * f + 0];
				tinyobj::index_t idx1 = shapes[s].mesh.indices[3 * f + 1];
				tinyobj::index_t idx2 = shapes[s].mesh.indices[3 * f + 2];

				int current_material_id = shapes[s].mesh.material_ids[f];

				if ((current_material_id < 0) || (current_material_id >= static_cast<int>(materials.size()))) {
					// Invaid material ID. Use default material.
					current_material_id = materials.size() - 1; // Default material is added to the last item in `materials`.
				}
				//if (current_material_id >= materials.size()) {
				//    std::cerr << "Invalid material index: " << current_material_id << std::endl;
				//}
				//
				float diffuse[3];
				for (size_t i = 0; i < 3; i++) {
					diffuse[i] = materials[current_material_id].diffuse[i];
				}
				float tc[3][2];
				if (attrib.texcoords.size() > 0) {
					assert(attrib.texcoords.size() > 2 * idx0.texcoord_index + 1);
					assert(attrib.texcoords.size() > 2 * idx1.texcoord_index + 1);
					assert(attrib.texcoords.size() > 2 * idx2.texcoord_index + 1);
					tc[0][0] = attrib.texcoords[2 * idx0.texcoord_index];
					tc[0][1] = 1.0f - attrib.texcoords[2 * idx0.texcoord_index + 1];
					tc[1][0] = attrib.texcoords[2 * idx1.texcoord_index];
					tc[1][1] = 1.0f - attrib.texcoords[2 * idx1.texcoord_index + 1];
					tc[2][0] = attrib.texcoords[2 * idx2.texcoord_index];
					tc[2][1] = 1.0f - attrib.texcoords[2 * idx2.texcoord_index + 1];
				}
				else {
					std::cerr << "Texcoordinates are not defined" << std::endl;
					exit(2);
				}

				float v[3][3];
				for (int k = 0; k < 3; k++) {
					int f0 = idx0.vertex_index;
					int f1 = idx1.vertex_index;
					int f2 = idx2.vertex_index;
					assert(f0 >= 0);
					assert(f1 >= 0);
					assert(f2 >= 0);

					v[0][k] = attrib.vertices[3 * f0 + k];
					v[1][k] = attrib.vertices[3 * f1 + k];
					v[2][k] = attrib.vertices[3 * f2 + k];
					bmin[k] = std::min(v[0][k], bmin[k]);
					bmin[k] = std::min(v[1][k], bmin[k]);
					bmin[k] = std::min(v[2][k], bmin[k]);
					bmax[k] = std::max(v[0][k], bmax[k]);
					bmax[k] = std::max(v[1][k], bmax[k]);
					bmax[k] = std::max(v[2][k], bmax[k]);
				}

				float n[3][3];
				if (attrib.normals.size() > 0) {
					int f0 = idx0.normal_index;
					int f1 = idx1.normal_index;
					int f2 = idx2.normal_index;
					assert(f0 >= 0);
					assert(f1 >= 0);
					assert(f2 >= 0);
					for (int k = 0; k < 3; k++) {
						n[0][k] = attrib.normals[3 * f0 + k];
						n[1][k] = attrib.normals[3 * f1 + k];
						n[2][k] = attrib.normals[3 * f2 + k];
					}
				}
				else {
					// compute geometric normal
					CalcNormal(n[0], v[0], v[1], v[2]);
					n[1][0] = n[0][0];
					n[1][1] = n[0][1];
					n[1][2] = n[0][2];
					n[2][0] = n[0][0];
					n[2][1] = n[0][1];
					n[2][2] = n[0][2];
				}

				for (int k = 0; k < 3; k++) {
					vb.push_back(v[k][0]);
					vb.push_back(v[k][1]);
					vb.push_back(v[k][2]);
					vb.push_back(n[k][0]);
					vb.push_back(n[k][1]);
					vb.push_back(n[k][2]);
					// Combine normal and diffuse to get color.
					float normal_factor = 0.2;
					float diffuse_factor = 1 - normal_factor;
					float c[3] = {
						n[k][0] * normal_factor + diffuse[0] * diffuse_factor,
						n[k][1] * normal_factor + diffuse[1] * diffuse_factor,
						n[k][2] * normal_factor + diffuse[2] * diffuse_factor
					};
					float len2 = c[0] * c[0] + c[1] * c[1] + c[2] * c[2];
					if (len2 > 0.0f) {
						float len = sqrtf(len2);

						c[0] /= len;
						c[1] /= len;
						c[2] /= len;
					}
					vb.push_back(c[0] * 0.5 + 0.5);
					vb.push_back(c[1] * 0.5 + 0.5);
					vb.push_back(c[2] * 0.5 + 0.5);

					vb.push_back(tc[k][0]);
					vb.push_back(tc[k][1]);
				}
			}

			o.vb = 0;
			o.numTriangles = 0;

			// OpenGL viewer does not support texturing with per-face material.
			if (shapes[s].mesh.material_ids.size() > 0 && shapes[s].mesh.material_ids.size() > s) {
				// Base case
				o.material_id = shapes[s].mesh.material_ids[s];
			}
			else {
				o.material_id = materials.size() - 1; // = ID for default material.
			}

			if (vb.size() > 0) {
				glGenBuffers(1, &o.vb);
				glBindBuffer(GL_ARRAY_BUFFER, o.vb);
				glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0),
					GL_STATIC_DRAW);
				o.numTriangles = vb.size() / (3 + 3 + 3 + 2) * 3;
				printf("shape[%d] # of triangles = %d\n", static_cast<int>(s),
					o.numTriangles);
			}

			drawObjects->push_back(o);
		}
	}

	printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
	printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);

	return true;
}
Пример #13
0
//=================================================================================================
void Terrain::SmoothNormals(VTerrain* v)
{
	assert(state > 0);
	assert(v);

	Vec3 normal, normal2;
	uint sum;

	// 1,3         4
	//(0,1)		 (1,1)
	// O-----------O
	// |\          |
	// |  \        |
	// |    \      |
	// |      \    |
	// |        \  |
	// |          \|
	// O-----------O
	//(0,0)		 (1,0)
	//  0         2,5

#undef W
#define W(xx,zz,idx) v[(x+(xx)+(z+(zz))*n_tiles)*6+(idx)]
#define CalcNormal(xx,zz,i0,i1,i2) CalculateNormal(normal2,W(xx,zz,i0).pos,W(xx,zz,i1).pos,W(xx,zz,i2).pos);\
	normal += normal2

	// wyg³adŸ normalne
	for(uint z = 0; z < n_tiles; ++z)
	{
		for(uint x = 0; x < n_tiles; ++x)
		{
			bool has_left = (x > 0),
				has_right = (x < n_tiles - 1),
				has_bottom = (z > 0),
				has_top = (z < n_tiles - 1);

			//------------------------------------------
			// PUNKT (0,0)
			sum = 1;
			normal = W(0, 0, 0).normal;

			if(has_left)
			{
				CalcNormal(-1, 0, 0, 1, 2);
				CalcNormal(-1, 0, 3, 4, 5);
				sum += 2;

				if(has_bottom)
				{
					CalcNormal(-1, -1, 3, 4, 5);
					++sum;
				}
			}
			if(has_bottom)
			{
				CalcNormal(0, -1, 0, 1, 2);
				CalcNormal(0, -1, 3, 4, 5);
				sum += 2;
			}

			normal *= (1.f / sum);
			W(0, 0, 0).normal = normal;

			//------------------------------------------
			// PUNKT (0,1)
			normal = W(0, 0, 1).normal;
			normal += W(0, 0, 3).normal;
			sum = 2;

			if(has_left)
			{
				CalcNormal(-1, 0, 3, 4, 5);
				++sum;

				if(has_top)
				{
					CalcNormal(-1, 1, 0, 1, 2);
					CalcNormal(-1, 1, 3, 4, 5);
					sum += 2;
				}
			}
			if(has_top)
			{
				CalcNormal(0, 1, 0, 1, 2);
				++sum;
			}

			normal *= (1.f / sum);
			W(0, 0, 1).normal = normal;
			W(0, 0, 3).normal = normal;

			//------------------------------------------
			// PUNKT (1,0)
			normal = W(0, 0, 2).normal;
			normal += W(0, 0, 5).normal;
			sum = 2;

			if(has_right)
			{
				CalcNormal(1, 0, 0, 1, 2);
				++sum;

				if(has_bottom)
				{
					CalcNormal(1, -1, 0, 1, 2);
					CalcNormal(1, -1, 3, 4, 5);
					sum += 2;
				}
			}
			if(has_bottom)
			{
				CalcNormal(0, -1, 3, 4, 5);
				++sum;
			}

			normal *= (1.f / sum);
			W(0, 0, 2).normal = normal;
			W(0, 0, 5).normal = normal;

			//------------------------------------------
			// PUNKT (1,1)
			normal = W(0, 0, 4).normal;
			sum = 1;

			if(has_right)
			{
				CalcNormal(1, 0, 0, 1, 2);
				CalcNormal(1, 0, 3, 4, 5);
				sum += 2;

				if(has_top)
				{
					CalcNormal(1, 1, 0, 1, 2);
					++sum;
				}
			}
			if(has_top)
			{
				CalcNormal(0, 1, 0, 1, 2);
				CalcNormal(0, 1, 3, 4, 5);
				sum += 2;
			}

			normal *= (1.f / sum);
			W(0, 0, 4).normal = normal;
		}
	}
}
Пример #14
0
void BuildGeometry (unsigned int surface, unsigned int colorScheme, unsigned int subdivisions, unsigned int xyRatio,
					GLuint * polyList, GLuint * lineList, GLuint * pointList)
{
	long i,j, index;
	long maxI = subdivisions * xyRatio, maxJ = subdivisions;
	double u, v, delta=0.001;
	recVec p1,p2;
	recVec *vertexPos = NULL,*vertexNormal = NULL;
	recColor *vertexColor = NULL;
	recTexCoord *vertexTexCoord = NULL;

	// set valid surface and color scheme
	surface %= kSurfaces;
	colorScheme %= kColorSchemes;

	// delete existing list
	if (*polyList)
		glDeleteLists (*polyList, 1);
	if (*lineList)
		glDeleteLists (*lineList, 1);
	if (*pointList)
		glDeleteLists (*pointList, 1);
	*polyList = *lineList = *pointList = 0;
	
	if (surface == kCube) // build the standard color cube (disregard color, subdivisions, and xyRatio)
		BuildCube (polyList, lineList, pointList, colorScheme);
	else {
		// build buffers
		vertexPos = (recVec*) malloc ((maxI) * (maxJ) * sizeof (recVec));
		if (vertexNormal)
			free (vertexNormal);
		vertexNormal = (recVec*) malloc ((maxI) * (maxJ) * sizeof (recVec));
		if (vertexColor)
			free (vertexColor);
		vertexColor = (recColor*) malloc ((maxI) * (maxJ) * sizeof (recColor));
		if (vertexTexCoord)
			free (vertexTexCoord);
		vertexTexCoord = (recTexCoord*) malloc ((maxI) * (maxJ) * sizeof (recTexCoord));
		if (!vertexPos || !vertexNormal || !vertexColor || !vertexTexCoord)
			return;
			
		// build surface
		for (i = 0; i < maxI; i++) {
			for (j = 0; j < maxJ; j++) {
				index = i * maxJ + j;
				u  = -PI + (i % maxI) * TWOPI / maxI;
				v  = -PI + (j % maxJ) * TWOPI / maxJ;
				vertexPos[index] = Eval(u,v, surface);
				p1 = Eval(u + delta, v, surface);
				p2 = Eval(u, v + delta, surface);
				vertexNormal[index] = CalcNormal(vertexPos[index],p1,p2);
				vertexColor[index] = getColor(u, -PI, PI, colorScheme);
				vertexTexCoord[index].s = (float) i * 5.0f / (float) maxI;
				vertexTexCoord[index].t = (float) j * 1.0f/ (float) maxJ;
			}
		}
		
		*polyList = glGenLists (1);
		glNewList(*polyList, GL_COMPILE);
			for (i=0; i< maxI; i++) {
				glBegin(GL_TRIANGLE_STRIP);
				for (j = 0; j <= maxJ; j++) {
					index = (i % maxI) * maxJ + (j % maxJ);
					glColor3fv (&vertexColor[index].r);
					glNormal3fv (&vertexNormal[index].x);
					glTexCoord2fv (&vertexTexCoord[index].s);
					glVertex3fv (&vertexPos[index].x);
		
					index = ((i + 1) % maxI) * maxJ + (j % maxJ);
					glColor3fv (&vertexColor[index].r);
					glNormal3fv (&vertexNormal[index].x);
					glTexCoord2fv (&vertexTexCoord[index].s);
					glVertex3fv (&vertexPos[index].x);
//					index = ((i - 1) % maxI) * maxJ + (j % maxJ);
				}
				glEnd ();
			}
		glEndList ();
	
		*lineList = glGenLists (1);
		glNewList(*lineList, GL_COMPILE);
			for (i=0; i< maxI; i++) {
				glBegin(GL_LINE_STRIP);
				for (j = 0; j < maxJ; j++) {
					index = i * maxJ + j;
					glColor3fv (&vertexColor[index].r);
					glVertex3fv (&vertexPos[index].x);
				}
				index = i * maxJ + 0;
				glColor3fv (&vertexColor[index].r);
				glVertex3fv (&vertexPos[index].x);
				glEnd ();
			}
			for (j=0; j< maxJ; j++) {
				glBegin(GL_LINE_STRIP);
				for (i = 0; i < maxI; i++) {
					index = i * maxJ + j;
					glColor3fv (&vertexColor[index].r);
					glVertex3fv (&vertexPos[index].x);
				}
				index = 0 + j;
				glColor3fv (&vertexColor[index].r);
				glVertex3fv (&vertexPos[index].x);
				glEnd ();
			}
		glEndList ();
	
		*pointList = glGenLists (1);
		glNewList(*pointList, GL_COMPILE);
			glBegin(GL_POINTS);
			for (i=0; i< maxI; i++) {
				for (j = 0; j < maxJ; j++) {
					index = i * maxJ + j;
					glColor3fv (&vertexColor[index].r);
					glVertex3fv (&vertexPos[index].x);
				}
			}
			glEnd ();
		glEndList ();
		free (vertexPos);
		free (vertexNormal);
		free (vertexColor);
	}
}
Пример #15
0
inline void COMap::CallResponse(long id[], long nType[], CrestObjects *pObjects)
{
	int nCollisionType=-1;
	vertex velocity[2];
	tCRNode* pCRNodes, *pCRNodes1;
	CrestInstrumentInfo *pIInfo;//tInstrumentLink* pInstrument1;
	ResponseData *pResponse;
	long nWhichI, nWhichR, nWhichT, nWhichN, nWhichS;
	bool bMedial;
	vertex loc;
	long i;

		//vertex adjust0, adjust1, loc;
		//	vertex v[3][2];
		//	float dx[3][3];

	CalcNormal(m_tp[0].pos, m_tp[0].pos+1, m_tp[0].pos+2, &(m_tp[0].n));
	CalcNormal(m_tp[1].pos, m_tp[1].pos+1, m_tp[1].pos+2, &(m_tp[1].n));

	// Instrument involved
	if(nType[0] == INSTRUMENT_TYPE || nType[1] == INSTRUMENT_TYPE)
	{
		if(nType[0] == INSTRUMENT_TYPE && nType[1] == INSTRUMENT_TYPE)
		{
			nCollisionType=I2I;
		}
		else if(nType[0] == INSTRUMENT_TYPE && nType[1] == TISSUE_TYPE)
		{
			nWhichI=0;
			nWhichT=1;
			nCollisionType=I2T;
		}
		else if(nType[0] == TISSUE_TYPE && nType[1] == INSTRUMENT_TYPE)
		{
			nWhichI=1;
			nWhichT=0;
			nCollisionType=I2T;
		}
	}// Tissue to tissue 
	else if(nType[0] == TISSUE_TYPE && nType[1] == TISSUE_TYPE)
	{
		nCollisionType=T2T;
	}

	switch(nCollisionType)
	{
		case I2T:
		{
			if(INSTRUMENT_TYPE != pObjects->GetObjectInfo(id[nWhichI])->nObjectType) return;
			else pIInfo = &(pObjects->GetObjectInfo(id[nWhichI])->IInfo);
			if(TISSUE_TYPE != pObjects->GetObjectInfo(id[nWhichT])->nObjectType) return;
			else pResponse = &(pObjects->GetObjectInfo(id[nWhichT])->Response);
			//if( NULL == (pIInfo = pObjects->GetObjectInfo(id[nWhichI])->pIInfo) ) return;
			//if( NULL == (pResponse = pObjects->GetObjectInfo(id[nWhichT])->pResponse) ) return;
			//pInstrument1->geoModel.GetDisplacement(m_tp[nWhichI].id[0], m_tp[nWhichI].v);
			//pInstrument1->geoModel.GetDisplacement(m_tp[nWhichI].id[1], m_tp[nWhichI].v+1);
			//pInstrument1->geoModel.GetDisplacement(m_tp[nWhichI].id[2], m_tp[nWhichI].v+2);
			//	//m_tp[nWhichI].v[0]=pInstrument1->velocity;
			//	//m_tp[nWhichI].v[1]=pInstrument1->velocity;
			//	//m_tp[nWhichI].v[2]=pInstrument1->velocity;
			//m_tp[nWhichT].v[0]=(pD[nWhichT]->m_CurrentSys)[m_tp[nWhichT].id[0]].v;
			//m_tp[nWhichT].v[1]=(pD[nWhichT]->m_CurrentSys)[m_tp[nWhichT].id[1]].v;
			//m_tp[nWhichT].v[2]=(pD[nWhichT]->m_CurrentSys)[m_tp[nWhichT].id[2]].v;

			bMedial = pIInfo->IsMedial(m_tp[nWhichI].id[0]);
			bMedial |= pIInfo->IsMedial(m_tp[nWhichI].id[1]);
			bMedial |= pIInfo->IsMedial(m_tp[nWhichI].id[2]);
			if(bMedial && pIInfo->GetStatus()==1)
			{
				long &nCount=pResponse->nCPos[id[nWhichI]];
				pCRNodes=pResponse->CPos[id[nWhichI]];
				for(i=0;i<3;i++)
				{
					if( nCount< CNODES_MAX && pResponse->IsNewCRNode(m_tp[nWhichT].id[i], FALSE))
					{
						//VectorDifference(m_tp[nWhichT].pos+i, m_tp[nWhichI].pos+i, &(pCRNodes[nCount].vector));
						pCRNodes[nCount].vector=*(m_tp[nWhichI].pos+i);
						pCRNodes[nCount].id=m_tp[nWhichT].id[i];
						pCRNodes[nCount].id_instrument=id[nWhichI];
						pCRNodes[nCount++].id_iNode=m_tp[nWhichI].id[i];
					}
				}
			}
			else{
				long &nCount=pResponse->nRVelocity;
				pCRNodes=pResponse->RVelocity;
				long &nCount1=pResponse->nPPos[id[nWhichI]];
				pCRNodes1=pResponse->PPos[id[nWhichI]];
				float fLength;
				vertex vn, vt, v;
				for(i=0;i<3;i++)
				{
					if(nCount1 < RNODES_MAX && pResponse->IsNewCRNode(m_tp[nWhichT].id[i], pCRNodes1, nCount1))
					{
						pCRNodes1[nCount1].id_instrument=id[nWhichI];
						//pCRNodes1[nCount1].id_iNode=m_tp[nWhichI].id[i];
						//pCRNodes1[nCount1].vector=m_tp[nWhichI].pos[i];
						pCRNodes1[nCount1++].id=m_tp[nWhichT].id[i];
					}
				}
			}
			//CColliResp::CollisionResponse(I2T, nWhichI, nWhichR, nWhichT);
			break;
		}
		//case T2T:
		//{
		//	if(!CR_TT) break;
		//	float fLength;
		//	vertex vn, vt, v, vs;
		//	vertex* pvs;

		//	nWhichN=0;
		//	nWhichS=1;
		//	
		//	long &nCount0=pD[nWhichN]->m_response_b.nRVelocity;
		//	pCRNodes=pD[nWhichN]->m_response_b.RVelocity;

		//	pvs=m_tp[nWhichS].v;
		//	vs=*(pvs);
		//	VectorSum(&vs,pvs+1,&vs);
		//	VectorSum(&vs,pvs+2,&vs);
		//	ScaleVector(&vs,1.0/3.0f,&vs);
		//	
		//	for(i=0;i<3;i++)
		//	{
		//		if(nCount0 < RNODES_MAX && IsNewCRNode(m_tp[nWhichN].id[i], TRUE, pD[nWhichN]))
		//		{
		//			v=m_tp[nWhichN].v[i];
		//			vn=m_tp[nWhichS].n;
		//			VectorDifference(&v, &vs, &loc);
		//			fLength=DotProduct(&loc, &vn);
		//			if(0.0f<=fLength) continue;
		//			ScaleVector(&vn, fLength, &vn);
		//			VectorDifference(&v, &vn, &vt);

		//			ScaleVector(&vn, 0.1f, &vn);
		//			VectorDifference(&vt, &vn, &loc); //VectorDifference(&loc, &v, &loc);
		//			//ScaleVector(&vt, 0.6f, &loc);
		//			ScaleVector(&loc, 0.1f, &loc); //0.1f
		//			pCRNodes[nCount0].vector=loc; //VectorSum(&(pCRNodes[nCount].vector),&loc,&(pCRNodes[nCount].vector));
		//			pCRNodes[nCount0++].id=m_tp[nWhichN].id[i];
		//		}
		//	}

		//	nWhichN=1;
		//	nWhichS=0;
		//	
		//	long &nCount1=pD[nWhichN]->m_response_b.nRVelocity;
		//	pCRNodes=pD[nWhichN]->m_response_b.RVelocity;

		//	pvs=m_tp[nWhichS].v;
		//	vs=*(pvs);
		//	VectorSum(&vs,pvs+1,&vs);
		//	VectorSum(&vs,pvs+2,&vs);
		//	ScaleVector(&vs,1.0/3.0f,&vs);
		//	
		//	for(i=0;i<3;i++)
		//	{
		//		if(nCount1 < RNODES_MAX && IsNewCRNode(m_tp[nWhichN].id[i], TRUE, pD[nWhichN]))
		//		{
		//			v=m_tp[nWhichN].v[i];
		//			vn=m_tp[nWhichS].n;
		//			VectorDifference(&v, &vs, &loc);
		//			fLength=DotProduct(&loc, &vn);
		//			if(0.0f<=fLength) continue;
		//			ScaleVector(&vn, fLength, &vn);
		//			VectorDifference(&v, &vn, &vt);

		//			ScaleVector(&vn, 0.5f, &vn);
		//			VectorDifference(&vt, &vn, &loc); //VectorDifference(&loc, &v, &loc);
		//			//ScaleVector(&vt, 0.6f, &loc);
		//			ScaleVector(&loc, 0.1f, &loc); //0.1f
		//			pCRNodes[nCount1].vector=loc; //VectorSum(&(pCRNodes[nCount].vector),&loc,&(pCRNodes[nCount].vector));
		//			pCRNodes[nCount1++].id=m_tp[nWhichN].id[i];
		//		}
		//	}
		//	break;
		//}
	}
}
Пример #16
0
bool HypercomplexFractalRules::Iterate(const Vector3d& IPoint, const Fractal *HCompl, const Vector3d& Direction, DBL *Dist, DBL **IterStack) const
{
    int i;
    DBL yz, xw;
    DBL Exit_Value, F_Value, Step;
    DBL x, y, z, w;
    Vector3d H_Normal;

    x = IterStack[X][0] = IPoint[X];
    y = IterStack[Y][0] = IPoint[Y];
    z = IterStack[Z][0] = IPoint[Z];
    w = IterStack[W][0] = (HCompl->SliceDist
                           - HCompl->Slice[X]*x
                           - HCompl->Slice[Y]*y
                           - HCompl->Slice[Z]*z)/HCompl->Slice[T];

    Exit_Value = HCompl->Exit_Value;

    for (i = 1; i <= HCompl->Num_Iterations; ++i)
    {
        yz = y * y + z * z;
        xw = x * x + w * w;

        if ((F_Value = xw + yz) > Exit_Value)
        {
            CalcNormal(H_Normal, i - 1, HCompl, IterStack);

            Step = dot(H_Normal, Direction);

            if (Step < -Fractal_Tolerance)
            {
                Step = -2.0 * Step;

                if ((F_Value > HCompl->Precision * Step) && (F_Value < 30 * HCompl->Precision * Step))
                {
                    *Dist = F_Value / Step;

                    return (false);
                }
            }

            *Dist = HCompl->Precision;

            return (false);
        }

        IterStack[X][i] = xw - yz + HCompl->Julia_Parm[X];
        IterStack[Y][i] = 2.0 * (x * y - z * w) + HCompl->Julia_Parm[Y];
        IterStack[Z][i] = 2.0 * (x * z - w * y) + HCompl->Julia_Parm[Z];
        IterStack[W][i] = 2.0 * (x * w + y * z) + HCompl->Julia_Parm[T];

        w = IterStack[W][i];
        x = IterStack[X][i];

        z = IterStack[Z][i];
        y = IterStack[Y][i];
    }

    *Dist = HCompl->Precision;

    return (true);
}
Пример #17
0
void ATriangle::Init()
{
	type = OBJ_TRIANGLE;
	CalcNormal();
	CalcCentroid();
}
Пример #18
0
static void check_collision ( collision_data& coldat )
{
	float radius;

	if ( coldat.BoundingSphere.x == coldat.BoundingSphere.y && coldat.BoundingSphere.x == coldat.BoundingSphere.z )
	{
		radius = coldat.BoundingSphere.x;
	}
	else
	{
		radius = 1.0f;
		
		// scale polygon
		for ( small x = 0; x < cache.count; x++ )
		{
			cache.vertex [ x ].x /= coldat.BoundingSphere.x;
			cache.vertex [ x ].y /= coldat.BoundingSphere.y;
			cache.vertex [ x ].z /= coldat.BoundingSphere.z;
		}

		CalcNormal ( cache.vertex, &cache.normal );
		D3DXVec3Normalize ( &cache.normal, &cache.normal );
	}


    D3DXVECTOR3 r;
    D3DXVECTOR3 pt = cache.vertex [ 0 ];
    D3DXVECTOR3 n  = cache.normal;
    D3DXVECTOR3 s  = coldat.src - n * radius;
	
	float t = D3DXVec3Dot ( &( s - pt ), &n );

    if ( t > coldat.dir_len )
	{
        return;
    }

    if ( t < -2 * radius )
	{
        return;
    }

    if ( t < 0.0f ) 
	{
        if ( !intersect_plane ( s, n * radius, pt, r ) )
			return;
    }
    else 
	{
     	if ( !intersect_plane ( s, coldat.dir, pt, r ) )
			return;
    }

    if ( !point_in_poly ( r ) )
	{
		D3DXVECTOR3 line_dir;
        r = closest_on_poly ( r, &line_dir );
		
		// mj change - sticky collision fix 27/08/02
		D3DXVECTOR3 ndir;
		//D3DXVec3Cross ( &ndir, &coldat.ndir, &line_dir );
		//D3DXVec3Cross ( &ndir, &line_dir, &ndir );
		//D3DXVec3Normalize ( &ndir, &ndir );

		ndir = coldat.ndir;

		t = intersect_sphere ( r, -ndir, coldat.src, radius );
	}
	else
	{
		t = intersect_sphere ( r, -coldat.ndir, coldat.src, radius );
	}

	    if ( t >= 0.0f && t <= coldat.dir_len )
		{
			if ( !coldat.found || t < coldat.dist )
			{
				coldat.found        = true;
				coldat.dist         = t;
				coldat.nearest_poly = r;
        }
    }
}
Пример #19
0
int32 FPoly::Finalize( ABrush* InOwner, int32 NoError )
{
    // Check for problems.
    Fix();
    if( Vertices.Num()<3 )
    {
        // Since we don't have enough vertices, remove this polygon from the brush
        check( InOwner );
        for( int32 p = 0 ; p < InOwner->Brush->Polys->Element.Num() ; ++p )
        {
            if( InOwner->Brush->Polys->Element[p] == *this )
            {
                InOwner->Brush->Polys->Element.RemoveAt(p);
                break;
            }
        }

// 		UE_LOG(LogPolygon, Warning, TEXT("FPoly::Finalize: Not enough vertices (%i)"), Vertices.Num() );
        if( NoError )
            return -1;
        else
        {
// 			UE_LOG(LogPolygon, Log,  TEXT("FPoly::Finalize: Not enough vertices (%i) : polygon removed from brush"), Vertices.Num() );
            return -2;
        }
    }

    // If no normal, compute from cross-product and normalize it.
    if( Normal.IsZero() && Vertices.Num()>=3 )
    {
        if( CalcNormal() )
        {
// 			UE_LOG(LogPolygon, Warning, TEXT("FPoly::Finalize: Normalization failed, verts=%i, size=%f"), Vertices.Num(), Normal.Size() );
            if( NoError )
            {
                return -1;
            }
            else
            {
                UE_LOG(LogPolygon, Error, TEXT("FPoly::Finalize: Normalization failed, verts=%d, size=%d"), Vertices.Num(), Normal.Size());
                for (int32 VertIdx = 0; VertIdx < Vertices.Num(); ++VertIdx)
                {
                    UE_LOG(LogPolygon, Error, TEXT("Vertex %d: <%.6f, %.6f, %.6f>"), VertIdx, Vertices[VertIdx].X, Vertices[VertIdx].Y, Vertices[VertIdx].Z);
                }
                ensure(false);
            }
        }
    }

    // If texture U and V coordinates weren't specified, generate them.
    if( TextureU.IsZero() && TextureV.IsZero() )
    {
        for( int32 i=1; i<Vertices.Num(); i++ )
        {
            TextureU = ((Vertices[0] - Vertices[i]) ^ Normal).GetSafeNormal();
            TextureV = (Normal ^ TextureU).GetSafeNormal();
            if( TextureU.SizeSquared()!=0 && TextureV.SizeSquared()!=0 )
                break;
        }
    }
    return 0;
}