#include "unit_tests.h" #include "TxsMesh.h" #include "SlideWriter.h" #include "TxsPyramid.h" #include "TiffImage.h" #include "txs_algo.h" #include "txs_multires_algo.h" #include "../ccs/Mesh.h" #include "../ccs/SlideWriter.h" #include "../ccs/TbirdUvSynth.h" #include "../ccs/BinaryWriter.h" #include "SimpleHeightFunc.h" #include "ConstHeightFunc.h" #include int addStlToTxsMesh(TxsMesh &mesh, char *stlFile); int feedTxsMeshToCcsMesh(TxsMesh &in, CCS::Mesh &out); using namespace TXS; #define TEST_RES_DIR "test_res" bool test_multires_pyramid_search() { __LOG__("START test_multires_pyramid_search"); TxsPyramid inPy(64); inPy.getLevel(3)->readFromTiff(TEST_RES_DIR"/test-py-image-64.tif"); inPy.getLevel(2)->readFromTiff(TEST_RES_DIR"/test-py-image-32.tif"); TiffImage searcherLow(TEST_RES_DIR"/test-py-searcher-low.tif"); TiffImage searcherHigh(TEST_RES_DIR"/test-py-searcher-high.tif"); int mx, my; inPy.getClosestPyramid(searcherLow, searcherHigh, 3, mx, my, 1); __LOG__("mx, my: " << mx << ", " << my); __LOG__("END test_multires_pyramid_search"); // TEMP TODO return fail/success return true; } #define NUM_DIMENSIONS 3 void feedQuadCubeToMesh(TxsMesh &mesh, TXS_REAL edgeLen = 0.10) { FLOAT hel = (FLOAT)(edgeLen * 0.5); list verts; // back verts.clear(); verts.push_back(Point(-hel, -hel, -hel)); verts.push_back(Point(-hel, hel, -hel)); verts.push_back(Point(hel, hel, -hel)); verts.push_back(Point(hel, -hel, -hel)); mesh.addFace(verts); // front verts.clear(); verts.push_back(Point(-hel, -hel, hel)); verts.push_back(Point(hel, -hel, hel)); verts.push_back(Point(hel, hel, hel)); verts.push_back(Point(-hel, hel, hel)); mesh.addFace(verts); // left verts.clear(); verts.push_back(Point(-hel, -hel, -hel)); verts.push_back(Point(-hel, -hel, hel)); verts.push_back(Point(-hel, hel, hel)); verts.push_back(Point(-hel, hel, -hel)); mesh.addFace(verts); // right verts.clear(); verts.push_back(Point(hel, -hel, -hel)); verts.push_back(Point(hel, hel, -hel)); verts.push_back(Point(hel, hel, hel)); verts.push_back(Point(hel, -hel, hel)); mesh.addFace(verts); // top verts.clear(); verts.push_back(Point(-hel, hel, hel)); verts.push_back(Point(hel, hel, hel)); verts.push_back(Point(hel, hel, -hel)); verts.push_back(Point(-hel, hel, -hel)); mesh.addFace(verts); // bottom verts.clear(); verts.push_back(Point(-hel, -hel, -hel)); verts.push_back(Point(hel, -hel, -hel)); verts.push_back(Point(hel, -hel, hel)); verts.push_back(Point(-hel, -hel, hel)); mesh.addFace(verts); } bool test_quadSynthesis() { // build input mesh TxsMesh mesh; feedQuadCubeToMesh(mesh, 0.10); mesh.doneFeedingTris(); mesh.printVertStats(); TEST_ASSERT(mesh.getVerts().size() == 8, "the quad-cube should have 8 verts"); // build input pyramid TxsPyramid inPy(64); inPy.getLevel(3)->readFromTiff(TEST_RES_DIR"/bro64.tif"); inPy.getLevel(2)->readFromTiff(TEST_RES_DIR"/bro32.tif"); inPy.getLevel(1)->readFromTiff(TEST_RES_DIR"/bro16.tif"); inPy.getLevel(0)->readFromTiff(TEST_RES_DIR"/bro08.tif"); SlideWriter slfer; // test phong shading __LOG__("begin phong shade test"); Point pt(0.049, 0.049, -0.049); TxsFace *back = *(mesh.getFaces().begin()); Vector pnorm = back->calcPhongNormalAt(pt); __LOG__("phongn orm was " << pnorm); // first, phong shade it mesh.phongShadeAllFaces(); slfer.write("out_quadcube_test_phong", &mesh); // run algo synthTexturesMultiRes(mesh, inPy); slfer.write("out_quadcube_test", &mesh); return true; } bool test_tris2quads() { TxsMesh mesh; list verts; const TXS_REAL hel = 0.05; // half edge length // face 1 verts.clear(); verts.push_back(Point(0,0,0)); verts.push_back(Point(hel, -hel, 0)); verts.push_back(Point(hel+0.01, hel+0.01, -0.1)); mesh.addFace(verts); // face 2 verts.clear(); verts.push_back(Point(0,0,0)); verts.push_back(Point(hel+0.01, hel+0.01, -0.1)); verts.push_back(Point(-hel, hel, 0)); mesh.addFace(verts); // face 3 verts.clear(); verts.push_back(Point(0,0,0)); verts.push_back(Point(-hel, hel, 0)); verts.push_back(Point(-hel-0.01, -hel-0.01, 0)); mesh.addFace(verts); // face 4 verts.clear(); verts.push_back(Point(0,0,0)); verts.push_back(Point(-hel-0.01, -hel-0.01, 0)); verts.push_back(Point(hel, -hel, 0)); mesh.addFace(verts); mesh.doneFeedingTris(); TEST_ASSERT(mesh.getVerts().size() == 5, "mesh now should have 5 verts"); __STAT__("START collapse.."); mesh.collapse_tris_into_quads_around_valence_4_verts(); __STAT__("END starting collapse.."); TEST_ASSERT(mesh.getVerts().size() == 4, "mesh now should have just 4 verts after collapse"); SlideWriter slfer; mesh.phongShadeAllFaces(); slfer.write("out_tris2quads_test", &mesh); return true; } bool test_tris2quads_tetrus() { TxsMesh mesh; addStlToTxsMesh(mesh, "tetrus-0.stl"); mesh.doneFeedingTris(); __STAT__("START collapse.."); mesh.collapse_tris_into_quads_around_valence_4_verts(); __STAT__("END starting collapse.."); mesh.phongShadeAllFaces(); SlideWriter slfer; slfer.write("out_tris2quads_tetrus", &mesh); return true; } bool test_tris2quads_weird() { TxsMesh mesh; list verts; verts.push_back(Point(-0.05, 0, 0)); verts.push_back(Point(-0.03, -0.03, -0.03)); verts.push_back(Point(-0.07, 0, -0.07)); verts.push_back(Point(-0.085, 0.035, -0.035)); mesh.addFace(verts); mesh.doneFeedingTris(); mesh.phongShadeAllFaces(); SlideWriter slfer; slfer.write("out_tris2quads_weird", &mesh); return true; } void feedQuadCubeToMesh(CCS::Mesh &mesh, TXS_REAL edgeLen = 0.10) { FLOAT hel = (FLOAT)(edgeLen * 0.5); list verts; list uvs; // blank, dummy uvs.push_back(UVs(0,0)); uvs.push_back(UVs(1,0)); uvs.push_back(UVs(1,1)); uvs.push_back(UVs(0,1)); // back verts.clear(); verts.push_back(Point(-hel, -hel, -hel)); verts.push_back(Point(-hel, hel, -hel)); verts.push_back(Point(hel, hel, -hel)); verts.push_back(Point(hel, -hel, -hel)); mesh.addFace(verts, NULL, uvs); // front verts.clear(); verts.push_back(Point(-hel, -hel, hel)); verts.push_back(Point(hel, -hel, hel)); verts.push_back(Point(hel, hel, hel)); verts.push_back(Point(-hel, hel, hel)); mesh.addFace(verts, NULL, uvs); // left verts.clear(); verts.push_back(Point(-hel, -hel, -hel)); verts.push_back(Point(-hel, -hel, hel)); verts.push_back(Point(-hel, hel, hel)); verts.push_back(Point(-hel, hel, -hel)); mesh.addFace(verts, NULL, uvs); // right verts.clear(); verts.push_back(Point(hel, -hel, -hel)); verts.push_back(Point(hel, hel, -hel)); verts.push_back(Point(hel, hel, hel)); verts.push_back(Point(hel, -hel, hel)); mesh.addFace(verts, NULL, uvs); // top verts.clear(); verts.push_back(Point(-hel, hel, hel)); verts.push_back(Point(hel, hel, hel)); verts.push_back(Point(hel, hel, -hel)); verts.push_back(Point(-hel, hel, -hel)); mesh.addFace(verts, NULL, uvs); // bottom verts.clear(); verts.push_back(Point(-hel, -hel, -hel)); verts.push_back(Point(hel, -hel, -hel)); verts.push_back(Point(hel, -hel, hel)); verts.push_back(Point(-hel, -hel, hel)); mesh.addFace(verts, NULL, uvs); } bool test_CCS_input() { CCS::Mesh mesh; feedQuadCubeToMesh(mesh); TEST_ASSERT(mesh.faces.size() == 6, "looking for 6 faces"); TEST_ASSERT(mesh.verts.size() == 8, "looking for 8 verts"); TEST_ASSERT(mesh.edges.size() == 12, "looking for 12 edges. actual: " << mesh.edges.size()); CCS::Mesh subd; mesh.subdivide(subd); TEST_ASSERT(subd.verts.size() == (6+8+12), "making sure subdiv'd mesh has 6+8+12 verts: " << subd.verts.size()); TEST_ASSERT(subd.edges.size() == 48, "subdiv'd has " << subd.edges.size() << " edges"); TEST_ASSERT(subd.faces.size() == 24, "subdiv'd has " << subd.faces.size() << " faces"); // output a scene monkey file, for fun ofstream scene; scene.open("test_CCS.scenemonkey"); list::iterator v_iter; for(v_iter = subd.verts.begin(); v_iter != subd.verts.end(); ++v_iter) { CCS::Vertex* vert = *v_iter; Point v = vert->p; v *= 100; scene << "sphere " << v(0) << " " << v(1) << " " << v(2) << " 1" << endl; } list::iterator f_iter; for(f_iter = subd.faces.begin(); f_iter != subd.faces.end(); ++f_iter) { CCS::Face* f = *f_iter; Point a, b, c; list::iterator e_iter; e_iter = f->edgeUses.begin(); a = (*e_iter).getUseStart()->p; ++e_iter; b = (*e_iter).getUseStart()->p; ++e_iter; c = (*e_iter).getUseStart()->p; a *= 100; b *= 100; c *= 100; scene << "triangle " << a(0) << " " << a(1) << " " << a(2) << " " << b(0) << " " << b(1) << " " << b(2) << " " << c(0) << " " << c(1) << " " << c(2) << endl; } // subdiv some more CCS::Mesh subd2; subd.subdivide(subd2, 4); __STAT__("writing to SLF"); CCS::SlideWriter writer; writer.write("ccs_test", &subd2, false); //writer.write("ccs_test", &mesh); __STAT__("CCS input passed"); return true; } bool test_tetrus_subdiv() { TxsMesh mesh; addStlToTxsMesh(mesh, "tetrus-0.stl"); mesh.doneFeedingTris(); mesh.collapse_tris_into_quads_around_valence_4_verts(); __STAT__("read in " << mesh.getFaces().size() << " faces from tetrus stl"); mesh.phongShadeAllFaces(); __STAT__("adding tetrus to ccs mesh"); CCS::Mesh ccsMesh; feedTxsMeshToCcsMesh(mesh, ccsMesh); __STAT__("DONE adding tetrus to ccs mesh"); TEST_ASSERT(mesh.getFaces().size() == ccsMesh.faces.size(), "txs and ccs mesh have same # of faces"); __STAT__("subdividing"); CCS::Mesh subdiv; ccsMesh.subdivide(subdiv, 4); __STAT__("writing to SLF"); CCS::SlideWriter writer; writer.write("ccs_test", &subdiv); return true; } bool test_quadCube_synth_subdiv() { TxsMesh mesh; feedQuadCubeToMesh(mesh, 0.10); mesh.doneFeedingTris(); TEST_ASSERT(mesh.getVerts().size() == 8, "the quad-cube should have 8 verts"); // build input pyramid TxsPyramid inPy(64); inPy.getLevel(3)->readFromTiff("snake64.tif"); inPy.getLevel(2)->readFromTiff("snake32.tif"); inPy.getLevel(1)->readFromTiff("snake16.tif"); inPy.getLevel(0)->readFromTiff("snake08.tif"); // run algo synthTexturesMultiRes(mesh, inPy); // output synth'd result SlideWriter slfer; slfer.write("out_quadcube_test", &mesh); //---------------------------------------- // now, subdivide it CCS::Mesh ccsMesh; feedTxsMeshToCcsMesh(mesh, ccsMesh); CCS::Mesh subdivd; ccsMesh.subdivide(subdivd, 1); // output subdiv'd CCS::SlideWriter ccsSlfer; ccsSlfer.write("out_quadcube_test_subdiv", &subdivd); // again CCS::Mesh subdivd2; subdivd.subdivide(subdivd2, 2); // output subdiv'd ccsSlfer.write("out_quadcube_test_subdiv2", &subdivd2); return true; } bool test_tris2quads_tetrus_subdiv() { TxsMesh mesh; addStlToTxsMesh(mesh, "tetrus-0.stl"); mesh.doneFeedingTris(); __STAT__("START collapse.."); mesh.collapse_tris_into_quads_around_valence_4_verts(); __STAT__("END starting collapse.."); mesh.phongShadeAllFaces(); SlideWriter slfer; slfer.write("out_tris2quads_tetrus", &mesh); return true; } bool test_averageColors() { list clrs; clrs.push_back(NormRGB(0,0,0)); clrs.push_back(NormRGB(1,1,0.5)); clrs.push_back(NormRGB(0.25,0.25,0)); clrs.push_back(NormRGB(0.75,0.75,0.5)); NormRGB avg = averageColors(clrs); TEST_ASSERT(avg.r == 0.5 && avg.g == 0.5 && avg.b == 0.25, "checking for expected average RGB values"); return true; } bool test_tbirdSynth() { // get the tbird TiffImage tbirdTxtr("ColorBird.tif"); // create a simple grid CCS::Mesh grid; Point o(0,0,0); Vector right(1,0,0); Vector up(0,1,0); for(int x = 0; x < 5; x++) { for(int y = 0; y < 5; y++) { Point sqrO = o + x*right + y*up; list verts; verts.push_back(sqrO); verts.push_back(sqrO + right); verts.push_back(sqrO + right + up); verts.push_back(sqrO + up); list uvs; uvs.push_back(UVs(0,0)); uvs.push_back(UVs(0,0)); uvs.push_back(UVs(0,0)); uvs.push_back(UVs(0,0)); grid.addFace(verts, &tbirdTxtr, uvs); } } CCS::TbirdUvSynth tbs; tbs.synth(&grid, &tbirdTxtr); CCS::SlideWriter ccsSlfer; ccsSlfer.write("test_out_tbirdSynthGrid", &grid); __STAT__("DONE test_tbirdSynth"); return true; } bool test_tetrus_tbirdSynth() { TxsMesh mesh; addStlToTxsMesh(mesh, "tetrus-0.stl"); mesh.doneFeedingTris(); mesh.collapse_tris_into_quads_around_valence_4_verts(); __STAT__("read in " << mesh.getFaces().size() << " faces from tetrus stl"); __STAT__("adding tetrus to ccs mesh"); CCS::Mesh coarse; feedTxsMeshToCcsMesh(mesh, coarse); __STAT__("DONE adding tetrus to ccs mesh"); TEST_ASSERT(mesh.getFaces().size() == coarse.faces.size(), "txs and ccs mesh have same # of faces"); __STAT__("tbird synth"); //TiffImage tbirdTxtr("ColorBird.tif"); TiffImage tbirdTxtr("BlurBird.tif"); // looks best blurred! CCS::TbirdUvSynth tbs; tbs.synth(&coarse, &tbirdTxtr); __STAT__("subdiv'ing"); CCS::Mesh subdivFlat; coarse.subdivide(subdivFlat, 3); __STAT__("writing slf"); CCS::SlideWriter ccsSlfer; ccsSlfer.write("test_out_tbirdSynthGrid", &subdivFlat); __STAT__("subdiv'ing more for displacement!"); CCS::Mesh::HeightMapFunc *hf = new SimpleHeightFunc; CCS::Mesh subdivDisp; subdivFlat.subdivide(subdivDisp, 4); // 3 is a good value here. 4 looks better, but takes like an hr subdivDisp.displaceVertsByTextures(hf); delete hf; __STAT__("writing displaced subdiv'd to binary"); CCS::BinaryWriter binner; binner.write(&subdivDisp, "tetrus_tbird_disp.ccs"); return false; } /* * Only the FAST unit tests should be ran here */ bool run_all_unit_tests() { return true && test_averageColors() && test_tetrus_tbirdSynth(); }