Box3 plDistribComponent_old::GetFade()
{
    Point3 pmin;
    if( fCompPB->GetInt(kFadeInActive) )
    {
        pmin.Set(fCompPB->GetFloat(kFadeInTran), fCompPB->GetFloat(kFadeInOpaq), 0);
        if( pmin[0] == pmin[1] )
            pmin[2] = 0;
        else if( pmin[0] < pmin[1] )
            pmin[2] = -1.f;
        else
            pmin[2] = 1.f;
    }
    else
    {
        pmin.Set(0.f,0.f,0.f);
    }

    Point3 pmax;
    pmax.Set(fCompPB->GetFloat(kFadeOutTran), fCompPB->GetFloat(kFadeOutOpaq), 0);
    if( pmax[0] == pmax[1] )
        pmax[2] = 0;
    else if( pmax[0] < pmax[1] )
        pmax[2] = -1.f;
    else
        pmax[2] = 1.f;

    return Box3(pmin, pmax);
}
예제 #2
0
/**
*  @brief
*    Returns the position, rotation and scale of the scene node at a given time
*/
void PLSceneNode::GetPosRotScale(Point3 &vPos, Quat &qRot, Point3 &vScale, TimeValue nTime)
{
	if (m_pIGameNode) {
		// Get the position, rotation and scale - relative to the parent node
		GMatrix mParentMatrix;
		IGameNode *pIGameNodeParent = m_pIGameNode->GetNodeParent();
		if (pIGameNodeParent)
			mParentMatrix = pIGameNodeParent->GetWorldTM(nTime);
		PLTools::GetPosRotScale(m_pIGameNode->GetWorldTM(nTime)*PLTools::Inverse(mParentMatrix), vPos, qRot, vScale, IsRotationFlipped());

		// Get the scale (NOT done for special nodes!)
		if (m_nType != TypeContainer && m_nType != TypeScene && m_nType != TypeCell &&
			m_nType != TypeCamera && m_nType != TypeLight) {
			// [TODO] Do we still need this hint?
			// Check for none uniform scale
//			if (m_vScale.x != m_vScale.y || m_vScale.x != m_vScale.z || m_vScale.y != m_vScale.z) {
				// We have to use '%e' because else we may get output like '(1 1 1) is no uniform scale'
				// g_pLog->LogFLine(PLLog::Hint, "Node '%s' has a none uniform scale. (%e %e %e) This 'may' cause problems in special situations...", m_sName.c_str(), m_vScale.x, m_vScale.y, m_vScale.z);
//			}
		} else {
			// Set scale to 1
			vScale.Set(1.0f, 1.0f, 1.0f);
		}
	}
}
예제 #3
0
    // /////////////////////////////////////////////////////////////////
    //
    // /////////////////////////////////////////////////////////////////
    bool SetPoint3FromLua(const LuaPlus::LuaObject &posData, Point3 &position)
    {
        if(!posData.IsTable()) {
            return (false);
        }

        LuaPlus::LuaObject xData = posData["x"];
        LuaPlus::LuaObject yData = posData["y"];
        LuaPlus::LuaObject zData = posData["z"];

        if(!xData.IsNumber() || !yData.IsNumber() || !zData.IsNumber()) {
            return (false);
        }

        F32 x = static_cast<F32>(xData.GetNumber());
        F32 y = static_cast<F32>(yData.GetNumber());
        F32 z = static_cast<F32>(zData.GetNumber());
        position.Set(x, y, z);

        return (true);
    }
예제 #4
0
Color MtlBlinn::Shade(const Cone &ray, const HitInfo &hInfo, const LightList &lights, int bounceCount) const{
    float bias = BIAS_SHADING;
    Color shade;
    Color rShade = Color(0,0,0);
    Color tShade = Color(0,0,0);
    const Material *mat;
    mat = hInfo.node->GetMaterial();
    const MtlBlinn* mb =static_cast<const MtlBlinn*>(mat);
//    cout<<"HInfo front: "<<hInfo.front<<endl;
    /* local copy */
    Point3 P;
    P.Set(hInfo.p.x,hInfo.p.y,hInfo.p.z);
    Cone iRay = ray;
    
    Color ambInt = mb->diffuse.Sample(hInfo.uvw, hInfo.duvw);
    Color allOther = Color(0,0,0);
    Color diffuse = mb->diffuse.Sample(hInfo.uvw, hInfo.duvw);
    Color ambComponent = Color(0,0,0);
    Point3 newN = hInfo.N;
    
    
    for ( unsigned int i=0; i<lights.size(); i++ ) {
        if(lights[i]->IsAmbient()){
//            cout<<"ambient "<<endl;
            Color intensity = lights[i]->Illuminate(hInfo.p);
            ambComponent += (ambInt * intensity);
            continue;
        }
        else{
//            cout<<"other lighting  "<<endl;
            Point3 L = -lights[i]->Direction(P);
            L.Normalize();
            
            Point3 V = ray.p - P;
            V.Normalize();
            
            Point3 LplusV = L + V;
            Point3 H = (L+V)/LplusV.Length();
            H.Normalize();
            
            float alpha = mb->glossiness;
//            Point3 N = hInfo.N;
            Point3 N = newN;
            float S = H.Dot(N);
            S = pow(S,alpha);
            float costheta = L.Dot(N)/(L.Length() * N.Length());
            Color intensity = lights[i]->Illuminate(P);
//            cout<<"costheta "<<endl;
            allOther += intensity * (costheta>0?costheta:0) * (diffuse + S * (mb->specular.Sample(hInfo.uvw, hInfo.duvw))) ;
        }
        /* finally add inta*cola + intall*costheta*(cold + s* colS)*/
        shade = ambComponent  + allOther;
    }
    
    /* Calculate refraction */
    if(refraction.GetColor().r>0 && bounceCount>0){
        //compute new jittered normal
        float gloss = refractionGlossiness;
        if(gloss){
            float random = rand()/(float)RAND_MAX;
            float rRadius = sqrtf(random) * gloss;
            random = rand()/(float)RAND_MAX;
            float rAngle =  random * 2.0 * M_PI;
            float x = rRadius * cos(rAngle);
            float y = rRadius * sin(rAngle);
            Point3 xAxis(1,0,0), yAxis(0,1,0), v1, v2, normalDir;
            normalDir = hInfo.N;
            //    normalDir.Normalize();
            if(normalDir.Dot(xAxis) > 0.7)  v1 = normalDir.Cross(yAxis);
            else v1 = normalDir.Cross(xAxis);
            v2 = v1.Cross(normalDir);
            v1.Normalize(); v2.Normalize();
            v1 *= x;
            v2 *= y;
            
            newN = hInfo.N + v1.Length() + v2.Length();
            newN.Normalize();
        }
        else{
            newN = hInfo.N;
        }
        //-------------------------------------
        
        Color reflShade = Color(0,0,0);
        float R0, Refl = 0.0f, Trans = 0.0f;
        HitInfo temp;
        temp.Init();
        
//        Point3 N = hInfo.N;
        Point3 N = newN;
//        Point3 V = Point3(iRay.p.x -  hInfo.p.x, iRay.p.y - hInfo.p.y, iRay.p.z - hInfo.p.z);
        Point3 V = Point3(hInfo.p.x - iRay.p.x, hInfo.p.y - iRay.p.y, hInfo.p.z - iRay.p.z);
        V.Normalize();
        float n1 = 1, n2 = 1;
        if(hInfo.front){ /* Hitting from outside */
//            temp.front = false;
            n2 = ior;
//            cout<<"outside "<<endl;
        }
        else if(!hInfo.front){ /* Transmission from the inside */
//            temp.front = true;
            n1 = ior;
//            cout<<"intside... "<<endl;
//            N = -hInfo.N;
            N *= -1;
        }
        float ratio_n = n1 / n2;
        
        float costheta_v = -V.Dot(N);        /* refer: http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf */

        float sin2theta_t = ratio_n * ratio_n * (1 - costheta_v * costheta_v);
        Point3 T =   ratio_n * V + (ratio_n * costheta_v - sqrtf(1 - sin2theta_t)) * N ;
//        cout<<ratio_n<<" "<<"cos_v "<<costheta_v<<" sin2theta_t "<<sin2theta_t<<endl;
        Cone tRay = Cone(hInfo.p,T);
        
        //tRay.dir.Normalize();
        tRay.p.x = tRay.p.x + bias *tRay.dir.x; /* add bias */
        tRay.p.y = tRay.p.y + bias *tRay.dir.y;
        tRay.p.z = tRay.p.z + bias *tRay.dir.z;
//        cout<<"B temp front: "<< temp.front<<endl;
        temp.timeInstance = hInfo.timeInstance;
        if(sin2theta_t <= 1){
            if(RayTrace_2(tRay, temp)){ /* ray tracing after refraction */
//                bounceCount--;
                tShade  =  temp.node->GetMaterial()->Shade(tRay,temp,lights,bounceCount);
            }
            else{ /* no hit after refraction */
                tShade = environment.SampleEnvironment(tRay.dir);
                
            }
            /* Calculate Schlick's approximation */
            
            R0 = (n1 - n2)/(n1 + n2);
            R0 *= R0;
            double  X = 0.0;
            //                if(n1 > n2){
            //                    X = 1.0 - sqrtf(1.0 - sin2theta_t);
            //                }
            //                else{ X = 1.0 - costheta_v; }
            X = 1.0 - costheta_v;
            Refl = R0 + (1.0 - R0) *  X * X * X * X * X;
            Trans = 1.0 - Refl;
            
            tShade.r *= exp(-absorption.r * temp.z);
            tShade.g *= exp(-absorption.g * temp.z);
            tShade.b *= exp(-absorption.b * temp.z);
        }
        else {/* Total internal reflection */
            Refl = 1.0f;
        }
        
            
        
        
        /* Calculate reflection due to reflectance */
        if(bounceCount >0){
//            N = hInfo.N;
            N = newN;
            Point3 V = Point3(iRay.p.x -  P.x, iRay.p.y - P.y, iRay.p.z - P.z);
            //V.Normalize();
            Point3 VR = 2 * V.Dot(N) * N - V;
            //VR.Normalize();
            Cone rRay = Cone(P + BIAS_SHADING * VR, VR);
            rRay.dir.Normalize();
            HitInfo temp1;
            temp1.Init();
            temp.timeInstance = hInfo.timeInstance;
            if(rootNode.GetNumChild()>0){
                if(RayTrace_2(rRay, temp1)){
                    bounceCount --;
                    reflShade = temp1.node->GetMaterial()->Shade(rRay, temp1, lights, bounceCount);
                }
                else{
                    reflShade = environment.SampleEnvironment(rRay.dir);
//                    reflShade = Color(1,100,1);
                }
            }
        }
        
//        cout<<"Refl: "<<Refl<<"Trans "<<Trans<<endl;
        tShade = refraction.GetColor().r * (Trans * tShade + Refl * reflShade);
        
        
    }

    /* calculate reflection*/
    if(reflection.GetColor().r>0 && bounceCount > 0){
        //compute new jittered normal
        float gloss = reflectionGlossiness;
        if(gloss){
            float random = rand()/(float)RAND_MAX;
            float rRadius = sqrtf(random) * gloss;
            random = rand()/(float)RAND_MAX;
            float rAngle =  random * 2.0 * M_PI;
            float x = rRadius * cos(rAngle);
            float y = rRadius * sin(rAngle);
            Point3 xAxis(1,0,0), yAxis(0,1,0), v1, v2, normalDir;
            normalDir = hInfo.N;
            //    normalDir.Normalize();
            if(normalDir.Dot(xAxis) > 0.7)  v1 = normalDir.Cross(yAxis);
            else v1 = normalDir.Cross(xAxis);
            v2 = v1.Cross(normalDir);
            v1.Normalize(); v2.Normalize();
            v1 *= x;
            v2 *= y;
            
            newN = hInfo.N + v1+ v2;
            newN.Normalize();
        }
        else{
            newN = hInfo.N;
        }
        //-------------------------------------
        
        Point3 N = newN;//hInfo.N;
        Point3 V = Point3(iRay.p.x -  P.x, iRay.p.y - P.y, iRay.p.z - P.z);
       // V.Normalize();
        Point3 VR = 2 * V.Dot(N) * N - V;
        Cone rRay = Cone(P + BIAS_SHADING * VR, VR);
        rRay.dir.Normalize();
        HitInfo temp;
        temp.Init();
        temp.timeInstance=hInfo.timeInstance;
        if(rootNode.GetNumChild()>0){
            if(RayTrace_2(rRay, temp)){
                bounceCount--;
                rShade = reflection.GetColor().r * temp.node->GetMaterial()->Shade(rRay, temp, lights, bounceCount);
            }
            else{
                rShade =  reflection.GetColor().r *environment.SampleEnvironment(rRay.dir);
//                rShade = Color(1,111,1);
            }
        }
    }
    
  
    
    /* Add shade with reflected and refracted colors */
    shade += (rShade + tShade);
    return shade;
};
예제 #5
0
int ExportQuake3Model(const TCHAR *filename, ExpInterface *ei, Interface *gi, int start_time, std::list<ExportNode> lTags, std::list<ExportNode> lMeshes)
{
	FILE *file;
	int i, j, totalTags, totalMeshes, current_time = 0;
	long pos_current, totalTris = 0, totalVerts = 0;
	std::list<FrameRange>::iterator range_i;
	std::vector<Point3> lFrameBBoxMin;
	std::vector<Point3> lFrameBBoxMax;
	long pos_tagstart;
	long pos_tagend;
	long pos_filesize;
	long pos_framestart;
	int lazynamesfixed = 0;
	const Point3 x_axis(1, 0, 0);
	const Point3 z_axis(0, 0, 1);

	SceneEnumProc checkScene(ei->theScene, start_time, gi);
	totalTags = (int)lTags.size();
	if (g_tag_for_pivot)
		totalTags++;
	totalMeshes = (int)lMeshes.size();

	// open file
	file = _tfopen(filename, _T("wb"));
	if (!file)
	{
		ExportError("Cannot open file '%s'.", filename);
		return FALSE;
	}
	ExportDebug("%s:", filename);

	// sync pattern and version
	putChars("IDP3", 4, file);
	put32(15, file);
	putChars("Darkplaces MD3 Exporter", 64, file);
	put32(0, file);   // flags
	
	// MD3 header
	ExportState("Writing MD3 header");
	put32(g_total_frames, file);      // how many frames
	put32(totalTags, file);	  // tagsnum
	put32(totalMeshes, file); // meshnum
	put32(1, file);   // maxskinnum
	put32(108, file); // headersize
	pos_tagstart = ftell(file); put32(0, file);   // tagstart
	pos_tagend	= ftell(file);  put32(256, file); // tagend
	pos_filesize = ftell(file); put32(512, file); // filesize
	ExportDebug("    %i frames, %i tags, %i meshes", g_total_frames, totalTags, totalMeshes);

	// frame info
	// bbox arrays get filled while exported mesh and written back then
	ExportState("Writing frame info");
	pos_framestart = ftell(file);
	lFrameBBoxMin.resize(g_total_frames);
	lFrameBBoxMax.resize(g_total_frames);
	for (i = 0; i < g_total_frames; i++)
	{
		// init frame data
		lFrameBBoxMin[i].Set(0, 0, 0);
		lFrameBBoxMax[i].Set(0, 0, 0);
		// put data
		putFloat(-1.0f, file); // bbox min vector
		putFloat(-1.0f, file);
		putFloat(-1.0f, file);	
		putFloat( 1.0f, file); // bbox max vector
		putFloat(1.0f, file);
		putFloat(1.0f, file);
		putFloat(0.0f, file);  // local origin (usually 0 0 0)
		putFloat(0.0f, file);
		putFloat(0.0f, file);
		putFloat(1.0f, file);  // radius of bounding sphere
		putChars("", 16, file);
	}

	// tags
	pos_current = ftell(file);
	fseek(file, pos_tagstart, SEEK_SET);
	put32(pos_current, file);
	fseek(file, pos_current, SEEK_SET);
	
	// for each frame range cycle all frames and write out each tag
	long pos_tags = pos_current;
	if (totalTags)
	{
		long current_frame = 0;
		ExportState("Writing %i tags", totalTags);
		for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++)
		{
			for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++)
			{
				SceneEnumProc current_scene(ei->theScene, i * g_ticks_per_frame, gi);
				current_time = current_scene.time;

				// write out tags
				if (lTags.size())
				{
					for (std::list<ExportNode>::iterator tag_i = lTags.begin(); tag_i != lTags.end(); tag_i++)
					{
						INode *node	= current_scene[tag_i->i]->node;
						Matrix3	tm = node->GetObjTMAfterWSM(current_time);

						ExportState("Writing '%s' frame %i of %i", tag_i->name, i, g_total_frames);

						// tagname
						putChars(tag_i->name, 64, file);
						// origin, rotation matrix
						Point3 row = tm.GetRow(3);
						putFloat(row.x, file);
						putFloat(row.y, file);
						putFloat(row.z, file);
						row = tm.GetRow(0);
						putFloat(row.x, file);
						putFloat(row.y, file);
						putFloat(row.z, file);
						row = tm.GetRow(1);
						putFloat(row.x, file);
						putFloat(row.y, file);
						putFloat(row.z, file);
						row = tm.GetRow(2);
						putFloat(row.x, file);
						putFloat(row.y, file);
						putFloat(row.z, file);
					}
				}

				// write the center of mass tag_pivot which is avg of all objects's pivots
				if (g_tag_for_pivot)
				{
					ExportState("Writing 'tag_pivot' frame %i of %i", i, g_total_frames);

					// write the null data as tag_pivot need to be written after actual geometry
					// (it needs information on frame bound boxes to get proper blendings)
					putChars("tag_pivot", 64, file);
					putFloat(0, file);
					putFloat(0, file);
					putFloat(0, file);
					putFloat(1, file);
					putFloat(0, file);
					putFloat(0, file);
					putFloat(0, file);
					putFloat(1, file);
					putFloat(0, file);
					putFloat(0, file);
					putFloat(0, file);
					putFloat(1, file);
				}
			}
		}
	}

	// write the tag object offsets
	pos_current = ftell(file);
	fseek(file, pos_tagend, SEEK_SET);
	put32(pos_current, file);
	fseek(file, pos_current, SEEK_SET);

	// allocate the structs used to calculate tag_pivot
	std::vector<Point3> tag_pivot_origin;
	std::vector<double> tag_pivot_volume;
	if (g_tag_for_pivot)
	{
		tag_pivot_origin.resize(g_total_frames);
		tag_pivot_volume.resize(g_total_frames);
	}

	// mesh objects
	// for each mesh object write uv and frames
	SceneEnumProc scratch(ei->theScene, start_time, gi);
	ExportState("Writing %i meshes", (int)lMeshes.size());
	for (std::list<ExportNode>::iterator mesh_i = lMeshes.begin(); mesh_i != lMeshes.end(); mesh_i++)
	{
		bool needsDel;

		ExportState("Start mesh #%i", mesh_i);
		INode *node = checkScene[mesh_i->i]->node;
		Matrix3 tm	= node->GetObjTMAfterWSM(start_time);
		TriObject *tri = GetTriObjectFromNode(node, start_time, needsDel);
		if (!tri)
			continue;

		// get mesh, compute normals
		Mesh &mesh = tri->GetMesh();
		MeshNormalSpec *meshNormalSpec = mesh.GetSpecifiedNormals();
		if (meshNormalSpec)
		{
			if (!meshNormalSpec->GetNumFaces())
				meshNormalSpec = NULL;
			else
			{
				meshNormalSpec->SetParent(&mesh);
				meshNormalSpec->CheckNormals();
			}
		}
		mesh.checkNormals(TRUE);

		// fix lazy object names
		ExportState("Attempt to fix mesh name '%s'", mesh_i->name);
		char  meshname[64];
		size_t meshnamelen = min(63, strlen(mesh_i->name));
		memset(meshname, 0, 64);
		strncpy(meshname, mesh_i->name, meshnamelen);
		meshname[meshnamelen] = 0;
		if (!strncmp("Box", meshname, 3)    || !strncmp("Sphere", meshname, 6)  || !strncmp("Cylinder", meshname, 8) ||
            !strncmp("Torus", meshname, 5)  || !strncmp("Cone", meshname, 4)    || !strncmp("GeoSphere", meshname, 9) ||
			!strncmp("Tube", meshname, 4)   || !strncmp("Pyramid", meshname, 7) || !strncmp("Plane", meshname, 5) ||
			!strncmp("Teapot", meshname, 6) || !strncmp("Object", meshname, 6))
		{
name_conflict:
			lazynamesfixed++;
			if (lazynamesfixed == 1)
				strcpy(meshname, "base");
			else
				sprintf(meshname, "base%i", lazynamesfixed);

			// check if it's not used by another mesh
			for (std::list<ExportNode>::iterator m_i = lMeshes.begin(); m_i != lMeshes.end(); m_i++)
				if (!strncmp(m_i->name, meshname, strlen(meshname)))
					goto name_conflict;
			// approve name
			ExportWarning("Lazy object name '%s' (mesh renamed to '%s').", node->GetName(), meshname);
		}

		// special mesh check
		bool shadow_or_collision = false;
		if (g_mesh_special)
			  if (!strncmp("collision", meshname, 9) || !strncmp("shadow", meshname, 6))
				shadow_or_collision = true;

		// get material
		const char *shadername = NULL;
		Texmap *tex = 0;
		Mtl *mtl = 0;
		if (!shadow_or_collision)
		{
			mtl = node->GetMtl();
			if (mtl)
			{
				// check for multi-material
				if (mtl->IsMultiMtl())
				{
					// check if it's truly multi material
					// we do support multi-material with only one texture (some importers set it)
					bool multi_material = false;
					MtlID matId = mesh.faces[0].getMatID();
					for (i = 1; i < mesh.getNumFaces(); i++)
						if (mesh.faces[i].getMatID() != matId)
							multi_material = true;

					if (multi_material)
						if (g_mesh_multimaterials == MULTIMATERIALS_NONE)
							ExportWarning("Object '%s' is multimaterial and using multiple materials on its faces, that case is not yet supported (truncating to first submaterial).", node->GetName());
					
					// switch to submaterial
					mtl = mtl->GetSubMtl(matId);
				}

				// get shader from material if supplied
				char *materialname = GetChar(mtl->GetName());
				if (g_mesh_materialasshader && (strstr(materialname, "/") != NULL || strstr(materialname, "\\") != NULL))
					shadername = GetChar(mtl->GetName());
				else
				{
					// get texture
					tex = mtl->GetSubTexmap(ID_DI);
					if (tex)
					{
						if (tex->ClassID() == Class_ID(BMTEX_CLASS_ID, 0x00))
						{
							shadername = GetChar(((BitmapTex *)tex)->GetMapName());
							if (shadername == NULL || !shadername[0])
								ExportWarning("Object '%s' material '%s' has no bitmap.", tex->GetName(), node->GetName());
						}
						else
						{
							tex = NULL;
							ExportWarning("Object '%s' has material with wrong texture type (only Bitmap are supported).", node->GetName());
						}
					}
					else
						ExportWarning("Object '%s' has material but no texture.", node->GetName());
				}
			}
			else
				ExportWarning("Object '%s' has no material.", node->GetName());
		}

		long pos_meshstart = ftell(file);

		// surface object
		ExportState("Writing mesh '%s' header", meshname);
		putChars("IDP3", 4, file);
		putChars(meshname, 64, file);
		put32(0, file); // flags
		put32(g_total_frames, file);                          // framecount
		put32(1, file);                                       // skincount
		long pos_vertexnum = ftell(file); put32(0, file);     // vertexcount
		put32(mesh.getNumFaces(), file);                      // trianglecount
		long pos_trianglestart = ftell(file); put32(0, file); // start triangles
		put32(108, file);                                     // header size
		long pos_texvecstart = ftell(file); put32(0, file);   // texvecstart
		long pos_vertexstart = ftell(file); put32(16, file);  // vertexstart
		long pos_meshsize = ftell(file); put32(32, file);	  // meshsize

		// write out a single 'skin'
		ExportState("Writing mesh %s texture", meshname);
		if (shadow_or_collision)
			putChars(meshname, 64, file);
		else if (shadername) 
			putMaterial(shadername, mtl, tex, file);
		else
			putChars("noshader", 64, file);
		put32(0, file); // flags

		// build geometry
		ExportState("Building vertexes/triangles");
		std::vector<ExportVertex>vVertexes;
		std::vector<ExportTriangle>vTriangles;
		vVertexes.resize(mesh.getNumVerts());
		int vExtraVerts = mesh.getNumVerts();
		for (i = 0; i < mesh.getNumVerts(); i++)
		{
			vVertexes[i].vert = i;
			vVertexes[i].normalfilled = false;
			// todo: check for coincident verts
		}
		int vNumExtraVerts = 0;

		// check normals
		if (!mesh.normalsBuilt && !shadow_or_collision)
			ExportWarning("Object '%s' does not have normals contructed.", node->GetName());

		// get info for triangles
		const float normal_epsilon = 0.01f;
		vTriangles.resize(mesh.getNumFaces());
		for (i = 0; i < mesh.getNumFaces(); i++)
		{
			DWORD smGroup = mesh.faces[i].getSmGroup();
			ExportState("Mesh %s: checking normals for face %i of %i", meshname, i, mesh.getNumFaces());
			for (j = 0; j < 3; j++)
			{
				int vert = mesh.faces[i].getVert(j);
				vTriangles[i].e[j] = vert;
				// find a right normal for this vertex and save its 'address'
				int vni;
				Point3 vn;
				if (!mesh.normalsBuilt || shadow_or_collision)
				{
					vn.Set(0, 0, 0);
					vni = 0;
				}
				else
				{
					int numNormals;
					RVertex *rv = mesh.getRVertPtr(vert);
					if (meshNormalSpec)
					{  
						ExportState("face %i vert %i have normal specified", i, j);
						// mesh have explicit normals (i.e. Edit Normals modifier)
						vn = meshNormalSpec->GetNormal(i, j);
						vni = meshNormalSpec->GetNormalIndex(i, j);
					}
					else if (rv && rv->rFlags & SPECIFIED_NORMAL)
					{
						ExportState("face %i vert %i have SPECIFIED_NORMAL flag", i, j);
						// SPECIFIED_NORMAL flag
						vn = rv->rn.getNormal();
						vni = 0;
					}
					else if (rv && (numNormals = rv->rFlags & NORCT_MASK) && smGroup)
					{
						// If there is only one vertex is found in the rn member.
						if (numNormals == 1)
						{
							ExportState("face %i vert %i have solid smooth group", i, j);
							vn = rv->rn.getNormal();
							vni = 0;
							
						}
						else
						{
							ExportState("face %i vert %i have mixed smoothing groups", i, j);
							// If two or more vertices are there you need to step through them
							// and find the vertex with the same smoothing group as the current face.
							// You will find multiple normals in the ern member.
							for (int k = 0; k < numNormals; k++)
							{
								if (rv->ern[k].getSmGroup() & smGroup)
								{
									vn = rv->ern[k].getNormal();
									vni = 1 + k;
								}
							}
						}
					}
					else
					{
						ExportState("face %i vert %i flat shaded", i, j);
						// Get the normal from the Face if no smoothing groups are there
						vn = mesh.getFaceNormal(i);
						vni = 0 - (i + 1);
					}
				}

				// subdivide to get all normals right
				if (!vVertexes[vert].normalfilled)
				{
					vVertexes[vert].normal = vn;
					vVertexes[vert].normalindex = vni;
					vVertexes[vert].normalfilled = true;
				}
				else if ((vVertexes[vert].normal - vn).Length() >= normal_epsilon)
				{
					// current vertex not matching normal - it was already filled by different smoothing group
					// find a vert in extra verts in case it was already created
					bool vert_found = false;
					for (int ev = vExtraVerts; ev < (int)vVertexes.size(); ev++)
					{
						if (vVertexes[ev].vert == vert && (vVertexes[ev].normal - vn).Length() < normal_epsilon)
						{
							vert_found = true;
							vTriangles[i].e[j] = ev;
							break;
						}
					}
					// we havent found a vertex, create new
					if (!vert_found)
					{
						ExportVertex NewVert;
						NewVert.vert = vVertexes[vert].vert;
						NewVert.normal = vn;
						NewVert.normalindex = vni;
						NewVert.normalfilled = true;
						vTriangles[i].e[j] = (int)vVertexes.size();
						vVertexes.push_back(NewVert);
						vNumExtraVerts++;
					}
				}
			}
		}
		int vNumExtraVertsForSmoothGroups = vNumExtraVerts;

		// generate UV map
		// VorteX: use direct maps reading since getNumTVerts()/getTVert is deprecated
		//  max sets two default mesh maps: 0 - vertex color, 1 : UVW, 2 & up are custom ones
		ExportState("Building UV map");
		std::vector<ExportUV>vUVMap;
		vUVMap.resize(vVertexes.size());
		int meshMap = 1;
		if (!mesh.mapSupport(meshMap) || !mesh.getNumMapVerts(meshMap) || shadow_or_collision)
		{
			for (i = 0; i < mesh.getNumVerts(); i++)
			{
				vUVMap[i].u = 0.5;
				vUVMap[i].v = 0.5;
			}
			if (!shadow_or_collision)
				ExportWarning("No UV mapping was found on object '%s'.", node->GetName());
		}
		else
		{
			UVVert *meshUV = mesh.mapVerts(meshMap);
			for (i = 0; i < (int)vTriangles.size(); i++)
			{
				ExportState("Mesh %s: converting tvert for face %i of %i", meshname, i, (int)vTriangles.size());
				// for 3 face vertexes
				for (j = 0; j < 3; j++)
				{
					int vert = vTriangles[i].e[j];
					int tv = mesh.tvFace[i].t[j];
					UVVert &UV = meshUV[tv];

					if (!vUVMap[vert].filled)
					{
						// fill uvMap vertex
						vUVMap[vert].u = UV.x;
						vUVMap[vert].v = UV.y;
						vUVMap[vert].filled = true;
						vUVMap[vert].tvert = tv;
					}
					else if (tv != vUVMap[vert].tvert)
					{
						// uvMap slot for this vertex has been filled
						// we should arrange triangle to other vertex, which not filled and having same shading and uv
						// check if any of the extra vertices can fit
						bool vert_found = false;
						for (int ev = vExtraVerts; ev < (int)vVertexes.size(); ev++)
						{
							if (vVertexes[ev].vert == vert && vUVMap[vert].u == UV.x &&vUVMap[vert].v == UV.y  && (vVertexes[ev].normal - vVertexes[vert].normal).Length() < normal_epsilon)
							{
								vert_found = true;
								vTriangles[i].e[j] = vVertexes[ev].vert;
								break;
							}
						}
						if (!vert_found)
						{
							// create new vert
							ExportVertex NewVert;
							NewVert.vert = vVertexes[vert].vert;
							NewVert.normal = vVertexes[vert].normal;
							NewVert.normalindex = vVertexes[vert].normalindex;
							NewVert.normalfilled = vVertexes[vert].normalfilled;
							vTriangles[i].e[j] = (int)vVertexes.size();
							vVertexes.push_back(NewVert);
							vNumExtraVerts++;
							// create new TVert
							ExportUV newUV;
							newUV.filled = true;
							newUV.u = UV.x;
							newUV.v = UV.y;
							newUV.tvert = tv;
							vUVMap.push_back(newUV);
						}
					}
				}
			}
		}
		int vNumExtraVertsForUV = (vNumExtraVerts - vNumExtraVertsForSmoothGroups);

		// print some debug stats
		ExportDebug("    mesh %s: %i vertexes +%i %s +%i UV, %i triangles", meshname, ((int)vVertexes.size() - vNumExtraVerts), vNumExtraVertsForSmoothGroups, meshNormalSpec ? "EditNormals" : "SmoothGroups", vNumExtraVertsForUV, (int)vTriangles.size());

		// fill in triangle start
		pos_current = ftell(file);
		fseek(file, pos_trianglestart, SEEK_SET);
		put32(pos_current - pos_meshstart, file);
		fseek(file, pos_current, SEEK_SET);

		// detect if object have negative scale (mirrored)
		// in this canse we should rearrange triangles counterclockwise
		// so stuff will not be inverted
		ExportState("Mesh %s: writing %i triangles", meshname, (int)vTriangles.size());
		if (DotProd(CrossProd(tm.GetRow(0), tm.GetRow(1)), tm.GetRow(2)) < 0.0)
		{
			ExportWarning("Object '%s' is mirrored (having negative scale on it's transformation)", node->GetName());
			for (i = 0; i < (int)vTriangles.size(); i++)
			{
				put32(vTriangles[i].b, file);	// vertex index
				put32(vTriangles[i].c, file);	// for 3 vertices
				put32(vTriangles[i].a, file);	// of triangle
			}
		}
		else
		{
			for (i = 0; i < (int)vTriangles.size(); i++)
			{
				put32(vTriangles[i].a, file);	// vertex index
				put32(vTriangles[i].c, file);	// for 3 vertices
				put32(vTriangles[i].b, file);	// of triangle
			}
		}

		// fill in texvecstart
		// write out UV mapping coords.
		ExportState("Mesh %s: writing %i UV vertexes", meshname, (int)vUVMap.size());
		pos_current = ftell(file);
		fseek(file, pos_texvecstart, SEEK_SET);
		put32(pos_current - pos_meshstart, file);
		fseek(file, pos_current, SEEK_SET);
		for (i = 0; i < (int)vUVMap.size(); i++)
		{
			putFloat(vUVMap[i].u, file); // texture coord u,v
			putFloat(1.0f - vUVMap[i].v, file);	// for vertex
		}
		vUVMap.clear();

		// fill in vertexstart
		pos_current = ftell(file);
		fseek(file, pos_vertexstart, SEEK_SET);
		put32(pos_current - pos_meshstart, file);
		fseek(file, pos_current, SEEK_SET);

		// fill in vertexnum
		pos_current = ftell(file);
		fseek(file, pos_vertexnum, SEEK_SET);
		put32((int)vVertexes.size(), file);
		fseek(file, pos_current, SEEK_SET);

		// write out for each frame the position of each vertex
		long current_frame = 0;
		ExportState("Mesh %s: writing %i frames", meshname, g_total_frames);
		for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++)
		{
			for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++)
			{
				bool _needsDel;

				// get triobject for current frame
				SceneEnumProc current_scene(ei->theScene, i * g_ticks_per_frame, gi);
				current_time = current_scene.time;
				INode *_node = current_scene[mesh_i->i]->node;
				TriObject *_tri	= GetTriObjectFromNode(_node, current_time, _needsDel);
				if (!_tri)
					continue;

				// get mesh, compute normals
				Mesh &_mesh	= _tri->GetMesh();
				MeshNormalSpec *_meshNormalSpec = _mesh.GetSpecifiedNormals();
				if (_meshNormalSpec)
				{
					if (!_meshNormalSpec->GetNumFaces())
						_meshNormalSpec = NULL;
					else
					{
						_meshNormalSpec->SetParent(&_mesh);
						_meshNormalSpec->CheckNormals();
					}
				}
				_mesh.checkNormals(TRUE);

				// get transformations for current frame
				Matrix3 _tm	= _node->GetObjTMAfterWSM(current_time);

				ExportState("Mesh %s: writing frame %i of %i", meshname, current_frame, g_total_frames);

				Point3 BoxMin(0, 0, 0);
				Point3 BoxMax(0, 0, 0);
				for (j = 0; j < (int)vVertexes.size(); j++) // number of vertices
				{
					ExportState("Mesh %s: transform vertex %i of %i", meshname, j, (int)vVertexes.size());

					int vert = vVertexes[j].vert;
					Point3 &v = _tm.PointTransform(_mesh.getVert(vert));
					
					// populate bbox data
					if (!shadow_or_collision)
					{
						BoxMin.x = min(BoxMin.x, v.x);
						BoxMin.y = min(BoxMin.y, v.y);
						BoxMin.z = min(BoxMin.z, v.z);
						BoxMax.x = max(BoxMax.x, v.x);
						BoxMax.y = max(BoxMax.y, v.y);
						BoxMax.z = max(BoxMax.z, v.z);
					}

					// write vertex
					double f;
					f = v.x * 64.0f; if (f < -32768.0) f = -32768.0; if (f > 32767.0) f = 32767.0; put16((short)f, file);
					f = v.y * 64.0f; if (f < -32768.0) f = -32768.0; if (f > 32767.0) f = 32767.0; put16((short)f, file);
					f = v.z * 64.0f; if (f < -32768.0) f = -32768.0; if (f > 32767.0) f = 32767.0; put16((short)f, file);

					// get normal
					ExportState("Mesh %s: transform vertex normal %i of %i", meshname, j, (int)vVertexes.size());
					Point3 n;
					if (_meshNormalSpec) // mesh have explicit normals (i.e. Edit Normals modifier)
						n = _meshNormalSpec->Normal(vVertexes[j].normalindex);
					else if (!vVertexes[j].normalfilled || !_mesh.normalsBuilt)
						n = _mesh.getNormal(vert);
					else
					{
						RVertex *rv = _mesh.getRVertPtr(vert);
						if (vVertexes[j].normalindex < 0)
							n = _mesh.getFaceNormal((0 - vVertexes[j].normalindex) - 1);
						else if (vVertexes[j].normalindex == 0)
							n = rv->rn.getNormal();
						else 
							n = rv->ern[vVertexes[j].normalindex - 1].getNormal();
					}

					// transform normal
					Point3 &nt = _tm.VectorTransform(n).Normalize();

					// encode a normal vector into a 16-bit latitude-longitude value
					double lng = acos(nt.z) * 255 / (2 * pi);
					double lat = atan2(nt.y, nt.x) * 255 / (2 * pi);
					put16((((int)lat & 0xFF) << 8) | ((int)lng & 0xFF), file);
				}

				// blend the pivot positions for tag_pivot using mesh's volumes for blending power
				if (g_tag_for_pivot && !shadow_or_collision)
				{
					ExportState("Mesh %s: writing tag_pivot", meshname);

					Point3 Size = BoxMax - BoxMin;
					double BoxVolume = pow(Size.x * Size.y * Size.z, 0.333f);

					// blend matrices
					float blend = (float)(BoxVolume / (BoxVolume + tag_pivot_volume[current_frame]));
					float iblend = 1 - blend;
					tag_pivot_volume[current_frame]   = tag_pivot_volume[current_frame] + BoxVolume;
					Point3 row = _tm.GetRow(3) - _node->GetObjOffsetPos();
					tag_pivot_origin[current_frame].x = tag_pivot_origin[current_frame].x * iblend + row.x * blend;
					tag_pivot_origin[current_frame].y = tag_pivot_origin[current_frame].y * iblend + row.y * blend;
					tag_pivot_origin[current_frame].z = tag_pivot_origin[current_frame].z * iblend + row.z * blend;
				}

				// populate bbox data for frames
				lFrameBBoxMin[current_frame].x = min(lFrameBBoxMin[current_frame].x, BoxMin.x);
				lFrameBBoxMin[current_frame].y = min(lFrameBBoxMin[current_frame].y, BoxMin.y);
				lFrameBBoxMin[current_frame].z = min(lFrameBBoxMin[current_frame].z, BoxMin.z);
				lFrameBBoxMax[current_frame].x = max(lFrameBBoxMax[current_frame].x, BoxMax.x);
				lFrameBBoxMax[current_frame].y = max(lFrameBBoxMax[current_frame].y, BoxMax.y);
				lFrameBBoxMax[current_frame].z = max(lFrameBBoxMax[current_frame].z, BoxMax.z);

				// delete the working object, if necessary.
				if (_needsDel)
					delete _tri;
			}
		}

		// delete if necessary
		if (needsDel)
			delete tri;

		// fill in meshsize
		pos_current = ftell(file);
		fseek(file, pos_meshsize, SEEK_SET);
		put32(pos_current - pos_meshstart, file);
		fseek(file, pos_current, SEEK_SET);  

		// reset back to first frame
		SceneEnumProc scratch(ei->theScene, start_time, gi);
		totalTris += (long)vTriangles.size();
		totalVerts += (long)vVertexes.size();
		vTriangles.clear();
		vVertexes.clear();
	}

	// write tag_pivot
	ExportState("Writing tag_pivot positions");
	if (g_tag_for_pivot)
	{
		pos_current = ftell(file);
		long current_frame = 0;
		for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++)
		{
			for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++)
			{
				fseek(file, pos_tags + totalTags*112*current_frame + (int)lTags.size()*112 + 64, SEEK_SET);
				// origin
				putFloat(tag_pivot_origin[current_frame].x, file);
				putFloat(tag_pivot_origin[current_frame].y, file);
				putFloat(tag_pivot_origin[current_frame].z, file);
			}
		}
		fseek(file, pos_current, SEEK_SET);
	}
	tag_pivot_volume.clear();
	tag_pivot_origin.clear();

	// write frame data
	ExportState("Writing culling info");
	long current_frame = 0;
	pos_current = ftell(file);
	for (range_i = g_frame_ranges.begin(); range_i != g_frame_ranges.end(); range_i++)
	{
		for (i = (*range_i).first; i <= (int)(*range_i).last; i++, current_frame++)
		{
			fseek(file, pos_framestart + current_frame*56, SEEK_SET);
			putFloat(lFrameBBoxMin[current_frame].x, file);	// bbox min vector
			putFloat(lFrameBBoxMin[current_frame].y, file);
			putFloat(lFrameBBoxMin[current_frame].z, file);	
			putFloat(lFrameBBoxMax[current_frame].x, file); // bbox max vector
			putFloat(lFrameBBoxMax[current_frame].y, file);
			putFloat(lFrameBBoxMax[current_frame].z, file);
			putFloat(0, file); // local origin (usually 0 0 0)
			putFloat(0, file);
			putFloat(0, file);
			putFloat(max(lFrameBBoxMin[current_frame].Length(), lFrameBBoxMax[current_frame].Length()) , file); // radius of bounding sphere
		}
	}
	fseek(file, pos_current, SEEK_SET);
	lFrameBBoxMin.clear();
	lFrameBBoxMax.clear();

	// fill in filesize
	pos_current = ftell(file);
	fseek(file, pos_filesize, SEEK_SET);
	put32(pos_current, file);
	fseek(file, pos_current, SEEK_SET);

	fclose(file);

	ExportDebug("    total: %i vertexes, %i triangles", totalVerts, totalTris);

	return TRUE;
}
예제 #6
0
Color MtlBlinn::Shade(const Ray &ray, const HitInfo &hInfo, const LightList &lights, int bounceCount) const{
    float bias = BIAS_SHADING;
    Color shade;
    Color rShade = Color(0,0,0);
    Color tShade = Color(0,0,0);
    const Material *mat;
    mat = hInfo.node->GetMaterial();
    const MtlBlinn* mb =static_cast<const MtlBlinn*>(mat);
//    cout<<"HInfo front: "<<hInfo.front<<endl;
    /* local copy */
    Point3 P;
    P.Set(hInfo.p.x,hInfo.p.y,hInfo.p.z);
    Ray iRay = ray;
    
    Color ambInt = mb->diffuse;
    Color allOther = Color(0,0,0);
    Color diffuse = mb->diffuse;;
    Color ambComponent = Color(0,0,0);
    
    for ( unsigned int i=0; i<lights.size(); i++ ) {
        if(lights[i]->IsAmbient()){
//            cout<<"ambient "<<endl;
            Color intensity = lights[i]->Illuminate(hInfo.p);
            ambComponent += (ambInt * intensity);
            continue;
        }
        else{
//            cout<<"other lighting  "<<endl;
            Point3 L = -lights[i]->Direction(P);
            L.Normalize();
            
            Point3 V = ray.p - P;
            V.Normalize();
            
            Point3 LplusV = L + V;
            Point3 H = (L+V)/LplusV.Length();
            H.Normalize();
            
            float alpha = mb->glossiness;
            Point3 N = hInfo.N;
            float S = H.Dot(N);
            S = pow(S,alpha);
            float costheta = L.Dot(N)/(L.Length() * N.Length());
            Color intensity = lights[i]->Illuminate(P);
//            cout<<"costheta "<<endl;
            allOther += intensity * (costheta>0?costheta:0) * (diffuse + S * (mb->specular)) ;
        }
        /* finally add inta*cola + intall*costheta*(cold + s* colS)*/
        shade = ambComponent  + allOther;
    }
    
    /* Calculate refraction */
    if(refraction.Grey()>0 && bounceCount>0){
        Color reflShade = Color(0,0,0);
        float R0, Refl = 0.0f, Trans = 0.0f;
        HitInfo temp;
        temp.Init();
        
        Point3 N = hInfo.N;
//        Point3 V = Point3(iRay.p.x -  hInfo.p.x, iRay.p.y - hInfo.p.y, iRay.p.z - hInfo.p.z);
        Point3 V = Point3(hInfo.p.x - iRay.p.x, hInfo.p.y - iRay.p.y, hInfo.p.z - iRay.p.z);
        V.Normalize();
        float n1 = 1, n2 = 1;
        if(hInfo.front){ /* Hitting from outside */
//            temp.front = false;
            n2 = ior;
//            cout<<"outside "<<endl;
        }
        else if(!hInfo.front){ /* Transmission from the inside */
//            temp.front = true;
            n1 = ior;
//            cout<<"intside... "<<endl;
            N = -hInfo.N;
        }
        float ratio_n = n1 / n2;
        
        float costheta_v = -V.Dot(N);        /* refer: http://graphics.stanford.edu/courses/cs148-10-summer/docs/2006--degreve--reflection_refraction.pdf */

        float sin2theta_t = ratio_n * ratio_n * (1 - costheta_v * costheta_v);
        Point3 T =   ratio_n * V + (ratio_n * costheta_v - sqrtf(1 - sin2theta_t)) * N ;
//        cout<<ratio_n<<" "<<"cos_v "<<costheta_v<<" sin2theta_t "<<sin2theta_t<<endl;
        Ray tRay = Ray(hInfo.p,T);
        
        //tRay.dir.Normalize();
        tRay.p.x = tRay.p.x + bias *tRay.dir.x; /* add bias */
        tRay.p.y = tRay.p.y + bias *tRay.dir.y;
        tRay.p.z = tRay.p.z + bias *tRay.dir.z;
//        cout<<"B temp front: "<< temp.front<<endl;
        if(sin2theta_t <= 1){
            if(RayTrace_2(tRay, temp)){
//                bounceCount--;
//                cout<<"A temp front: "<< temp.front<<endl;
                tShade  =  temp.node->GetMaterial()->Shade(tRay,temp,lights,bounceCount);
                tShade.r *= exp(-absorption.r * temp.z);
                tShade.g *= exp(-absorption.g * temp.z);
                tShade.b *= exp(-absorption.b * temp.z);
//                shade = tShade; /* remove later */
//                return shade;
               
                
                /* Calculate Schlick's approximation */
                
                R0 = (n1 - n2)/(n1 + n2);
                R0 *= R0;
                double  X = 0.0;
//                if(n1 > n2){
//                    X = 1.0 - sqrtf(1.0 - sin2theta_t);
//                }
//                else{ X = 1.0 - costheta_v; }
                X = 1.0 - costheta_v;
                Refl = R0 + (1.0 - R0) *  X * X * X * X * X;
                Trans = 1.0 - Refl;
                
            }
        }
        else {/* Total internal reflection */
            Refl = 1.0f;
        }
        
        /* Calculate reflection due to reflectance */
        if(bounceCount >0){
            N = hInfo.N;
            Point3 V = Point3(iRay.p.x -  P.x, iRay.p.y - P.y, iRay.p.z - P.z);
            //V.Normalize();
            Point3 VR = 2 * V.Dot(N) * N - V;
            //VR.Normalize();
            Ray rRay = Ray(P, VR);
            //rRay.dir.Normalize();
            rRay.p.x = rRay.p.x + bias *rRay.dir.x;
            rRay.p.y = rRay.p.y + bias *rRay.dir.y;
            rRay.p.z = rRay.p.z + bias *rRay.dir.z;
            HitInfo temp1;
            temp1.Init();
            if(rootNode.GetNumChild()>0){
                if(RayTrace_2(rRay, temp1)){
                    bounceCount --;
                    reflShade =   temp1.node->GetMaterial()->Shade(rRay, temp1, lights, bounceCount);
                }
            }
        }
        
//        cout<<"Refl: "<<Refl<<"Trans "<<Trans<<endl;
        tShade = refraction * (Trans * tShade + Refl * reflShade);
        
        
    }
    





    /* calculate reflection*/
    if(reflection.Grey()>0 && bounceCount > 0){

        Point3 N = hInfo.N;
        Point3 V = Point3(iRay.p.x -  P.x, iRay.p.y - P.y, iRay.p.z - P.z);
       // V.Normalize();
        Point3 VR = 2 * V.Dot(N) * N - V;
        Ray rRay = Ray(hInfo.p, VR);
        //rRay.dir.Normalize();
        rRay.p.x = rRay.p.x + bias *rRay.dir.x;
        rRay.p.y = rRay.p.y + bias *rRay.dir.y;
        rRay.p.z = rRay.p.z + bias *rRay.dir.z;
        HitInfo temp;
        temp.Init();
        if(rootNode.GetNumChild()>0){
            if(RayTrace_2(rRay, temp)){
                bounceCount--;
                rShade = reflection * temp.node->GetMaterial()->Shade(rRay, temp, lights, bounceCount);
            }
        }
    }
    
  
    
    /* Add shade with reflected and refracted colors */
    shade += (rShade + tShade);
    return shade;
};
예제 #7
0
void
VectorOpsTester::Test () {

    stringstream ssError;

    try {

        Point3<float> p;
        Point3<float> q;

        p.Set( 1, 2, 3 );
        q.Set( 4, 5, 6 );
        Assert( !(p == q), "== didn't work." );
        Assert( (p != q), "!= didn't work." );
        p.Set( 1, 2, 3 );
        q.Set( 1, 2, 3 );
        Assert( (p == q), "== didn't work." );
        Assert( !(p != q), "!= didn't work." );


        const int cVals = 10;
        float vals[cVals];
        for ( int n = 0; n < cVals; n++ ) {
            vals[n] = (float)random() / (float)random();
        }

        p.Set( vals[0], vals[1], vals[2] );
        q.Set( vals[3], vals[4], vals[5] );

        float dot = VectorOps::Dot( p, q );
        Assert( (fabs( dot - (p[0] * q[0] + p[1] * q[1] + p[2] * q[2])) < 0.0001),
                "dot didn't work." );



        p.Set( 0, 0, 0 );
        q.Set( 0, 0, 3 );
        Point3<float> plane( 0, 0, 2 );
        Point3<float> n( 0, 0, 1 );
        Point3<float> x;

        VectorOps::IntersectionResult rIntersect =
            VectorOps::SegmentIntersectsPlane( p, q, plane, n, x );
        Assert( (VectorOps::intersect == rIntersect),
                "SegmentIntersectsPlane failed, incorrect result" );
        Assert( (x[0] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[1] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[2] == 2),
                "SegmentIntersectsPlane failed, x was wrong" );

        p.Set( 0, 0, 0 );
        q.Set( 0, 0, 3 );
        plane.Set( 0, 0, 4 );
        n.Set( 0, 0, 1 );
        rIntersect = VectorOps::SegmentIntersectsPlane( p, q, plane, n, x );
        Assert( (VectorOps::dontIntersect == rIntersect),
                "SegmentIntersectsPlane failed, incorrect result" );
        Assert( (x[0] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[1] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[2] == 2),
                "SegmentIntersectsPlane failed, x was wrong" );

        p.Set( 0, 0, 0 );
        q.Set( 0, 0, 1 );
        plane.Set( 0, 0, 1 );
        n.Set( 0, 1, 0 );
        rIntersect = VectorOps::SegmentIntersectsPlane( p, q, plane, n, x );
        Assert( (VectorOps::segmentInPlane == rIntersect),
                "SegmentIntersectsPlane failed, incorrect result" );
        Assert( (x[0] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[1] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[2] == 2),
                "SegmentIntersectsPlane failed, x was wrong" );

        p.Set( 0, 0, 0 );
        q.Set( 0, 0, 1 );
        plane.Set( 0, 1, 0 );
        n.Set( 0, 1, 0 );
        rIntersect = VectorOps::SegmentIntersectsPlane( p, q, plane, n, x );
        Assert( (VectorOps::segmentParallelToPlane == rIntersect),
                "SegmentIntersectsPlane failed, incorrect result" );
        Assert( (x[0] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[1] == 0),
                "SegmentIntersectsPlane failed, x was wrong" );
        Assert( (x[2] == 2),
                "SegmentIntersectsPlane failed, x was wrong" );

        p.Set( 1, 0, 0 );
        q.Set( 0, 1, 0 );
        double rads = VectorOps::RadsBetweenVectors( p, q );
        Assert( fabs(rads - M_PI/2.0) < 0.0001,
                "RadsBetweenVectors was wrong" );

        Point3<float> sq[4];
        sq[0].Set( 0, 0, 0 );
        sq[1].Set( 4, 0, 0 );
        sq[2].Set( 4, 4, 0 );
        sq[3].Set( 0, 4, 0 );

        p.Set( 1.402, 3.2, 0 );
        Point3<float> v[4];
        v[0] = sq[0] - p;
        v[1] = sq[1] - p;
        v[2] = sq[2] - p;
        v[3] = sq[3] - p;

        double angle[4];
        angle[0] = VectorOps::RadsBetweenVectors( v[0], v[1] );
        angle[1] = VectorOps::RadsBetweenVectors( v[1], v[2] );
        angle[2] = VectorOps::RadsBetweenVectors( v[2], v[3] );
        angle[3] = VectorOps::RadsBetweenVectors( v[3], v[0] );
        double sum = angle[0] + angle[1] + angle[2] + angle[3];

        Assert( fabs(sum - M_PI*2.0) < 0.0001,
                "angle sum was wrong" );


        Point3<float> p1, p2, q1, q2;
        p1.Set( 0, 0, 0 );
        p2.Set( 0, 0, 2 );
        q1.Set( -1, 0, 1 );
        q2.Set( 1, 0, 1 );
        rIntersect = VectorOps::SegmentIntersectsSegment( p1, p2, q1, q2, x );
        Assert( (rIntersect == VectorOps::intersect),
                "SegmentIntersectsSegment didn't intersect" );
        {
            stringstream ssError;
            ssError << "SegmentIntersectsSegment returned incorrect intersect: "
                    << x << endl;
            Assert( (x[0] == 0 && x[1] == 0 && x[2] == 1), ssError.str() );
        }

        p1.Set( 0, 0, 0 );
        p2.Set( 0, 0, 2 );
        q1.Set( 0, 0, 2 );
        q2.Set( 0, 0, 4 );
        rIntersect = VectorOps::SegmentIntersectsSegment( p1, p2, q1, q2, x );
        Assert( (rIntersect == VectorOps::intersect),
                "SegmentIntersectsSegment didn't intersect" );
        {
            stringstream ssError;
            ssError << "SegmentIntersectsSegment returned incorrect intersect: "
                    << x << endl;
            Assert( (x[0] == 0 && x[1] == 0 && x[2] == 2), ssError.str() );
        }

        p1.Set( 0, 0, 0 );
        p2.Set( 0, 0, 2 );
        q1.Set( 0, 0, 2 );
        q2.Set( 0, 0, 2 );
        rIntersect = VectorOps::SegmentIntersectsSegment( p1, p2, q1, q2, x );
        Assert( (rIntersect == VectorOps::intersect),
                "SegmentIntersectsSegment didn't intersect" );
        {
            stringstream ssError;
            ssError << "SegmentIntersectsSegment returned incorrect intersect: "
                    << x << endl;
            Assert( (x[0] == 0 && x[1] == 0 && x[2] == 2), ssError.str() );
        }

        p1.Set( 0, 0, 2 );
        p2.Set( 0, 0, 2 );
        q1.Set( 0, 0, 2 );
        q2.Set( 0, 0, 2 );
        rIntersect = VectorOps::SegmentIntersectsSegment( p1, p2, q1, q2, x );
        Assert( (rIntersect == VectorOps::intersect),
                "SegmentIntersectsSegment didn't intersect" );
        {
            stringstream ssError;
            ssError << "SegmentIntersectsSegment returned incorrect intersect: "
                    << x << endl;
            Assert( (x[0] == 0 && x[1] == 0 && x[2] == 2), ssError.str() );
        }


    } catch ( runtime_error& e ) {
        cerr << "failed with exception: " << e.what() << endl;
        exit( 1 );
    } catch (...) {
        cerr << "failed" << endl;
        exit( 1 );
    }
}
예제 #8
0
BOOL objFileRead(const TCHAR *filename, ImpInterface *imp){
	FILE *fp;
    int i;
	tLump  *idxtable;

	if((fp = fopen(filename, "rb")) == NULL)
		return 0;

	fseek(fp, 0, SEEK_END);
	int fileSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	char *data = new char[fileSize];
	fread(data, fileSize, 1, fp);

	tHeader *header = (tHeader *)data;
	if(*(int*)header->strID != CMAPHEADER_ID)
		return 0;

	if(header->version != CMAPHEADER_VERSION)
		return 0;

	idxtable = (tLump *)header + 1;

	tVertex *Verts = (tVertex *)(data + idxtable[kVertices].offset);	
	int NumVerts = idxtable[kVertices].length / sizeof(tVertex);

	tFace *faces = (tFace *)(data + idxtable[kLeafFaces].offset);	
	int NumFaces = idxtable[kLeafFaces].length / sizeof(tFace);

	int *elems = (int *)(data + idxtable[kElements].offset);	
	int NumElems = idxtable[kElements].length / sizeof(int);

	tArea *mAreas = (tArea *)(data + idxtable[kAreas].offset);
    int NumAreas = idxtable[kAreas].length / sizeof(tArea);

	Point3 p;

	TriObject *object = CreateNewTriObject();
	if(!object)
		return 0;
	
	Mesh *msh = &object->GetMesh();

	msh->setNumVerts(NumVerts);

	for(i = 0 ; i < NumVerts ; i++){
		msh->setVert(i, Verts[i].point[0], -Verts[i].point[2], Verts[i].point[1]);
		p.Set(Verts[i].norm[0], -Verts[i].norm[2], Verts[i].norm[1]);
		msh->setNormal(i, p);
	}

	int face = 0;
	for(int k = 1 ; k < NumAreas ; k++){
		for(i = mAreas[k].startFace ; i < mAreas[k].startFace + mAreas[k].numOfFaces ; i++){
			for(int j = faces[i].startElement ; j < faces[i].startElement + faces[i].elementsSize ; j++){
				int k = j * 3;
				if(elems[k] < 0){
					elems[k] = 0;
					elems[k+1] = 1;
					elems[k+2] = 2;
					faces[i].vertexIndex = 0;
				}
				msh->setNumFaces(face + 1, TRUE);
				msh->faces[face].setVerts(faces[i].vertexIndex + elems[k + 0], 
											faces[i].vertexIndex + elems[k + 1], 
											faces[i].vertexIndex + elems[k + 2]);
				msh->faces[face].setEdgeVisFlags(1, 1, 1);
				face++;
			}
		}
	}
	
	delete [] data;

	fclose(fp);
	msh->buildNormals();
	msh->buildBoundingBox();
	msh->InvalidateEdgeList();

	ImpNode *node = imp->CreateNode();
	if(!node) {
		delete object;
		return 0;
	}
	Matrix3 tm;
	tm.IdentityMatrix();
	node->Reference(object);
	node->SetTransform(0,tm);
	imp->AddNodeToScene(node);
	node->SetName(_T("Sylphis map"));


    return TRUE;
}
예제 #9
0
void
VolumeCollectionTester::Test ( Tcl_Interp* iInterp ) {

  stringstream ssError;

  try {

    string fnMRI = "test_data/bertT1.mgz";
    VolumeCollection* vol = new VolumeCollection();
    vol->SetFileName( fnMRI );
    MRI* mri = const_cast<MRI*>(vol->GetMRI());

    Assert( (vol->GetTypeDescription() == "Volume"),
            "GetTypeDescription didn't return Volume" );

    DataManager dataMgr = DataManager::GetManager();
    MRILoader mriLoader = dataMgr.GetMRILoader();
    Assert( 1 == mriLoader.CountLoaded(),
            "CountLoaded didn't return 1" );
    Assert( 1 == mriLoader.CountReferences(mri),
            "CountReferences didn't return 1" );

    char* fnMRIC = strdup( fnMRI.c_str() );
    MRI* mriComp = MRIread( fnMRIC );

    Assert( (MRImatch( mriComp, mri )), "MRImatch failed for load" );

    MRIfree( &mriComp );


    // Save it in /tmp, load it, and match it again.
    string fnSave( "/tmp/test.mgz" );
    vol->Save( fnSave );

    VolumeCollection* testVol = new VolumeCollection();
    testVol->SetFileName( fnSave );
    MRI* testMri = const_cast<MRI*>(testVol->GetMRI());
    Assert( (MRImatch( testMri, mri )), "MRImatch failed for load after save");



    // Make an ROI and make sure it's a volume ROI.
    try {
      int roiID = vol->NewROI();
      ScubaROIVolume* roi =
        dynamic_cast<ScubaROIVolume*>(&ScubaROI::FindByID( roiID ));
      roi = NULL;
    } catch (...) {
      throw( runtime_error("typecast failed for NewROI") );
    }


    // Try our conversions.
    Point3<float> world;
    Point3<float> data;
    Point3<int> index;
    world.Set( -50, 0, -80 );
    vol->RASToMRIIndex( world.xyz(), index.xyz() );
    {
      stringstream ssError;
      ssError << "RASToMRIIndex failed. world "
      << world << " index " << index;
      Assert( (index.x() == 178 && index.y() == 208 && index.z() == 128),
              ssError.str() );
    }

    // Set a transform that scales the volume up by 2x in the world.
    ScubaTransform dataTransform;
    dataTransform.SetMainTransform( 2, 0, 0, 0,
                                    0, 2, 0, 0,
                                    0, 0, 2, 0,
                                    0, 0, 0, 1 );
    vol->SetDataToWorldTransform( dataTransform.GetID() );

    world.Set( -50, 0, -80 );
    vol->RASToDataRAS( world.xyz(), data.xyz() );
    {
      stringstream ssError;
      ssError << "RASToDataRAS failed. world "
      << world << " data " << data;
      Assert( ((FEQUAL(data.x(),-25)) &&
               (FEQUAL(data.y(),0)) &&
               (FEQUAL(data.z(),-40))),
              ssError.str() );
    }

    vol->RASToMRIIndex( world.xyz(), index.xyz() );

    if ( index.x() != 153 || index.y() != 168 || index.z() != 128 ) {
      cerr << "RASToMRIIndex with data transform failed. world "
      << world << " index " << index << endl;
      throw( runtime_error( "failed" ) );
    }


    world.Set( -50, 0, -80 );
    VolumeLocation loc( vol->MakeVolumeLocationFromRAS( world.xyz() ) );
    if ( !vol->IsInBounds( loc ) ) {
      stringstream ssError;
      ssError << "IsInBounds failed. world " << world;
      throw( runtime_error( ssError.str() ) );
    }
    world.Set( -1000, 0, 0 );
    VolumeLocation loc2( vol->MakeVolumeLocationFromRAS( world.xyz() ) );
    if ( vol->IsInBounds( loc2 ) ) {
      stringstream ssError;
      ssError << "IsInBounds failed. world " << world;
      throw( runtime_error( ssError.str() ) );
    }


    dataTransform.SetMainTransform( 2, 0, 0, 0,
                                    0, 2, 0, 0,
                                    0, 0, 2, 0,
                                    0, 0, 0, 1 );
    vol->SetDataToWorldTransform( dataTransform.GetID() );
    world.Set( 0, -1000, -254 );
    VolumeLocation loc3( vol->MakeVolumeLocationFromRAS( world.xyz() ) );
    if ( vol->IsInBounds( loc3 ) ) {
      stringstream ssError;
      vol->RASToMRIIndex( world.xyz(), index.xyz() );
      ssError << "IsRASInMRIBounds failed. world " << world
      << " index " << index;
      throw( runtime_error( ssError.str() ) );
    }


    {
      // Create a new one from template.
      VolumeCollection* vol2 = new VolumeCollection();
      vol2->MakeUsingTemplate( vol->GetID(), -1 );
      Assert( (vol->mVoxelSize[0] == vol2->mVoxelSize[0] &&
	       vol->mVoxelSize[1] == vol2->mVoxelSize[1] &&
	       vol->mVoxelSize[2] == vol2->mVoxelSize[2]),
	      "NewUsingTemplate failed, vol2 didn't match vol's voxelsize" );
      Assert( (vol->GetDataType() == vol2->GetDataType()),
	    "NewUsingTemplate(-1) failed, vol2 didn't match vol's data type" );
      delete vol2;
    }
    
    {
      VolumeCollection* vol2 = new VolumeCollection();
      vol2->MakeUsingTemplate( vol->GetID(), MRI_FLOAT );
      Assert( (vol->mVoxelSize[0] == vol2->mVoxelSize[0] &&
	       vol->mVoxelSize[1] == vol2->mVoxelSize[1] &&
	       vol->mVoxelSize[2] == vol2->mVoxelSize[2]),
	      "NewUsingTemplate failed, vol2 didn't match vol's voxelsize" );
      Assert( (MRI_FLOAT == vol2->GetDataType()),
	      "NewUsingTemplate(float) failed, vol2 wasn't a float" );
      
      int idx[3] = { 0, 0, 0 };
      VolumeLocation loc( vol2->MakeVolumeLocationFromIndex( idx ) );
      vol2->SetMRIValue( loc, 0.6789 );
      float value = vol2->GetMRINearestValue(loc);

      stringstream ssError;
      ssError << "NewUsingTemplate(float) failed value comparison, "
	      << "was expecting 0.6789 but got " << value;
      Assert( (fabs(0.6789 - value) < 0.00001), ssError.str() );
      delete vol2;
    }

    {
      VolumeCollection* vol2 = NULL;
      try {
	vol2 = new VolumeCollection();
	vol2->MakeUsingTemplate( vol->GetID(), 10000 );
	throw runtime_error( "MakeUsingTemplate(10000) didn't throw an error");
      }
      catch(...) {}
      delete vol2;
    }

    dataTransform.SetMainTransform( 1, 0, 0, 0,
                                    0, 1, 0, 0,
                                    0, 0, 1, 0,
                                    0, 0, 0, 1 );
    vol->SetDataToWorldTransform( dataTransform.GetID() );

    // FindRASPointsInSquare
    {
      Point3<float> sqRAS[4], cRAS;
      sqRAS[0].Set( 0, -3, 71 );
      sqRAS[1].Set( 0, 1, 71 );
      sqRAS[2].Set( 0, 1, 67 );
      sqRAS[3].Set( 0, -3, 67 );
      cRAS.Set( 0, -1, 69 );
      list<Point3<float> > points;
      vol->FindRASPointsInSquare( cRAS.xyz(),
                                  sqRAS[0].xyz(), sqRAS[1].xyz(),
                                  sqRAS[2].xyz(), sqRAS[3].xyz(),
                                  0, points );
      list<Point3<float> >::iterator tPoint;
      for ( tPoint = points.begin(); tPoint != points.end(); ++tPoint ) {
        Point3<float> pRAS = *tPoint;

        stringstream ssMsg;
        ssMsg << "Failed: " << pRAS << " outside of square";

        Assert( ( pRAS[0] == 0 &&
                  (pRAS[1] >= -3 && pRAS[1] <= 1) &&
                  (pRAS[2] >= 67 && pRAS[2] <= 71) ),
                ssMsg.str() );
      }
    }


    // VoxelIntersectsSegment
    {
      Point3<int> idx;
      Point3<float> segIdxA, segIdxB;
      Point3<float> intIdx;

      idx.Set( 5, 5, 5 );

      float aSegments[6][3] = { {3, 5.5, 5.5}, {6, 5.5, 5.5},
                                {5.5, 3, 5.5}, {5.5, 6, 5.5},
                                {5.5, 5.5, 3}, {5.5, 5.5, 6} };
      for ( int nSegment = 0; nSegment < 6; nSegment += 2 ) {

        segIdxA.Set( aSegments[nSegment] );
        segIdxB.Set( aSegments[nSegment+1] );

        VectorOps::IntersectionResult rInt =
          vol->VoxelIntersectsSegment( idx, segIdxA, segIdxB, intIdx );

        if ( VectorOps::intersect != rInt ) {
          cerr << "Failed VoxelIntersectsSegment test: idx " << idx
          << ", seg " << segIdxA << ", " << segIdxB << endl
          << "\tDidn't intersect" << endl;
          throw runtime_error("failed");
        }
      }

      segIdxA.Set( 0, 5.5, 5.5 );
      segIdxB.Set( 4, 5.5, 5.5 );
      VectorOps::IntersectionResult rInt =
        vol->VoxelIntersectsSegment( idx, segIdxA, segIdxB, intIdx );

      if ( VectorOps::dontIntersect != rInt ) {
        cerr << "Failed VoxelIntersectsSegment test: idx " << idx
        << ", seg " << segIdxA << ", " << segIdxB << endl
        << "\tIntersected" << endl;
        throw runtime_error("failed");
      }
    }

    // FindRASPointsOnSegment
    {

    }


    // GetVoxelsWithValue
    {
      // This is a 5cubed volume whose values are set to the x
      // coordinate. So for x=3,y=0..4,z=0..4, value = 3.
      string fnVol = "test_data/testVolumeCollection-GetVoxelsWithValue.mgh";
      ifstream fVol( fnMRI.c_str(), ios::in );
      if ( !fVol ) {
        throw runtime_error("Couldn't find necessary test data.");
      }
      fVol.close();

      VolumeCollection* vol = new VolumeCollection();
      vol->SetFileName( fnVol );
      vol->LoadVolume();

      // Get the values 0-4 and make sure we got the right voxels.
      for ( int nStructure = 0; nStructure < 5; nStructure++ ) {

        list<VolumeLocation> lLocations;
        vol->GetVoxelsWithValue( nStructure, lLocations );

        Volume3<bool> bGot( 5, 5, 5, false );
        list<VolumeLocation>::iterator tLocation;
        for ( tLocation = lLocations.begin(); tLocation != lLocations.end();
              ++tLocation ) {

          VolumeLocation loc = *(tLocation);
          bGot.Set( loc.Index()[0], loc.Index()[1], loc.Index()[2], true );
        }

        for ( int nZ = 0; nZ < 5; nZ++ ) {
          for ( int nY = 0; nY < 5; nY++ ) {
            for ( int nX = 0; nX < 5; nX++ ) {
              if ( nX == nStructure && !bGot.Get( nX, nY, nZ ) ) {
                stringstream ssErr;
                ssErr << "Failed GetVoxelsWithValue test: "
                << " nStructure = " << nStructure
                << " index " << Point3<int>(nX,nY,nZ)
                << " - was supposed to get voxel but didn't";
                throw runtime_error(ssErr.str());
              }
              if ( nX != nStructure && bGot.Get( nX, nY, nZ ) ) {
                stringstream ssErr;
                ssErr << "Failed GetVoxelsWithValue test: "
                << " nStructure = " << nStructure
                << " index " << Point3<int>(nX,nY,nZ)
                << " - wasn't supposed to get voxel but did";
                throw runtime_error(ssErr.str());
              }
            }
          }
        }
      }

      delete vol;
    }

    // GetAverageValue
    {
      // We'll use the same volume as with GetVoxelsWithValue.
      string fnVol = "test_data/testVolumeCollection-GetVoxelsWithValue.mgh";
      ifstream fVol( fnMRI.c_str(), ios::in );
      if ( !fVol ) {
        throw runtime_error("Couldn't find necessary test data.");
      }
      fVol.close();

      VolumeCollection* vol = new VolumeCollection();
      vol->SetFileName( fnVol );
      vol->LoadVolume();

      // Get values of all voxels in plane x=3 and make sure it's 3.
      list<VolumeLocation> lVoxels;
      for ( int nZ = 0; nZ < 5; nZ++ ) {
        for ( int nY = 0; nY < 5; nY++ ) {
          int index[3] = { 3, nY, nZ };
          VolumeLocation loc( vol->MakeVolumeLocationFromIndex( index ) );
          lVoxels.push_back( loc );
        }
      }
      float average = vol->GetAverageValue( lVoxels );
      if ( average != 3.0 ) {
        stringstream ssErr;
        ssErr << "Failed GetAverageValue: Getting all voxels in x=3, "
        << "average should have been 3, but was " << average;
        throw runtime_error( ssErr.str() );
      }

      // Get values of 5 voxels, one from each x plane
      // (val=0,1,2,3,4), and make sure it's 2.
      lVoxels.clear();
      for ( int nX = 0; nX < 5; nX++ ) {
        int index[3] = { nX, 3, 3 };
        VolumeLocation loc( vol->MakeVolumeLocationFromIndex( index ) );
        lVoxels.push_back( loc );
      }
      average = vol->GetAverageValue( lVoxels );
      if ( average != 2.0 ) {
        stringstream ssErr;
        ssErr << "Failed GetAverageValue: Getting voxels in different planes, "
        << "average should have been 2, but was " << average;
        throw runtime_error( ssErr.str() );
      }

      // Make sure we get an error for no voxels.
      lVoxels.clear();
      bool bDidntThrow = false;
      try {
        average = vol->GetAverageValue( lVoxels );
        bDidntThrow = true;
      } catch ( exception& e ) {}
      if ( bDidntThrow ) {
        stringstream ssErr;
        ssErr << "Failed GetAverageValue: Didn't throw with empty list";
        throw runtime_error( ssErr.str() );
      }

      delete vol;
    }


    // Check the tcl commands.
    char sCommand[1024];
    int rTcl;

    int id = vol->GetID();
    string fnTest = "test-name";
    sprintf( sCommand, "SetVolumeCollectionFileName %d test-name", id );
    rTcl = Tcl_Eval( iInterp, sCommand );
    AssertTclOK( rTcl );
    Assert( (vol->mfnMRI == fnTest),
            "Setting file name via tcl didn't work" );

    vol->SetDataToWorldTransform( 0 );

    delete vol;
    delete testVol;
  } catch ( exception& e ) {
    cerr << "failed with exception: " << e.what() << endl;
    exit( 1 );
  } catch (...) {
    cerr << "failed." << endl;
    exit( 1 );
  }
}