// Supakorn "Jamie" Rassameemasuang and // John C. Bowman import three; import v3dtypes; import v3dheadertypes; struct triangleGroup { triple[] positions; triple[] normals; pen[] colors; int[][] positionIndices; int[][] normalIndices; int[][] colorIndices; } struct pixel { triple point; real width; } struct CameraInformation { int canvasWidth; int canvasHeight; bool absolute; triple b; triple B; bool orthographic; real angle; real Zoom0; pair viewportshift; pair viewportmargin; light light; void setCameraInfo() { size(canvasWidth,canvasHeight); triple center=0.5*(b.z+B.z)*Z; if(orthographic) currentprojection=orthographic(Z,target=center,Zoom0, viewportshift=viewportshift); else currentprojection=perspective(Z,Y,target=center,Zoom0, degrees(2.0*atan(tan(0.5*angle)/Zoom0)), viewportshift=viewportshift, autoadjust=false); light.specular=light.diffuse; currentlight=light; } } transform3 Align(real polar, real azimuth) { return align(dir(degrees(polar),degrees(azimuth))); } struct v3dfile { file xdrfile; int version; bool hasCameraInfo=false; CameraInformation info; bool singleprecision=false; triple[] centers; material[] materials; surface[][][] surfaces; path3[][][] paths3; triangleGroup[][][] triangles; pixel[][] pixels; void initSurface(int center, int material) { if(!surfaces.initialized(center)) surfaces[center]=new surface[][]; if(!surfaces[center].initialized(material)) surfaces[center][material]=new surface[] {new surface}; } void initPath3(int center, int material) { if(!paths3.initialized(center)) paths3[center]=new path3[][]; if(!paths3[center].initialized(material)) paths3[center][material]=new path3[]; } void initTriangleGroup(int center, int material) { if (!triangles.initialized(center)) triangles[center]=new triangleGroup[][]; if(!triangles[center].initialized(material)) triangles[center][material]=new triangleGroup[]; } void initPixel(int material) { if(!pixels.initialized(material)) pixels[material]=new pixel[]; } void surface(int center, int material, patch p) { initSurface(center,material); surfaces[center][material][0].s.push(p); } void primitive(int center, int material, surface s) { initSurface(center,material); surfaces[center][material].push(s); } void path3(int center, int material, path3 p) { initPath3(center,material); paths3[center][material].push(p); } void triangleGroup(int center, int material, triangleGroup g) { initTriangleGroup(center,material); triangles[center][material].push(g); } void pixel(int material, pixel P) { initPixel(material); pixels[material].push(P); } void operator init(string name) { xdrfile=input(name, mode="xdrgz"); version=xdrfile; int doubleprecision=xdrfile; singleprecision=doubleprecision == 0; xdrfile.singlereal(singleprecision); } int getType() { return xdrfile; } void setCameraInfo() { if(hasCameraInfo) info.setCameraInfo(); } pen[] readColorData(int size=4, bool alpha=true) { xdrfile.singlereal(true); xdrfile.dimension(alpha ? 4 : 3); pen[] newPen=new pen[size]; for (int i=0; i < size; ++i) { newPen[i]=alpha ? rgba(xdrfile) : rgb((real[]) xdrfile); } xdrfile.singlereal(singleprecision); return newPen; } CameraInformation processHeader() { CameraInformation ci; int entryCount=xdrfile; for (int i=0;i0) centersFetched=xdrfile; return centersFetched; } void readBezierPatchColor() { triple[][] val=readRawPatchData(); int center=xdrfile; int material=xdrfile; pen[] colors=readColorData(4); surface(center,material,patch(val,colors=colors)); } void readBezierTriangleColor() { triple[][] val=readRawTriangleData(); int center=xdrfile; int material=xdrfile; pen[] colors=readColorData(3); surface(center,material,patch(val,triangular=true,colors=colors)); } void readSphere() { triple origin=xdrfile; real radius=xdrfile; int center=xdrfile; int material=xdrfile; surface s=shift(origin)*scale3(radius)*unitsphere; s.primitive=unitsphere.primitive; primitive(center,material,s); } void readHemisphere() { triple origin=xdrfile; real radius=xdrfile; int center=xdrfile; int material=xdrfile; real polar=xdrfile; real azimuth=xdrfile; surface s=shift(origin)*Align(polar,azimuth)*scale3(radius)*unithemisphere; s.primitive=unithemisphere.primitive; primitive(center,material,s); } void readDisk() { triple origin=xdrfile; real radius=xdrfile; int center=xdrfile; int material=xdrfile; real polar=xdrfile; real azimuth=xdrfile; surface s=shift(origin)*Align(polar,azimuth)*scale3(radius)*unitdisk; s.primitive=unitdisk.primitive; primitive(center,material,s); } void readPolygon(int n) { xdrfile.dimension(n); triple[] val=xdrfile; int center=xdrfile; int material=xdrfile; surface(center,material,patch(val)); } void readPolygonColor(int n) { xdrfile.dimension(n); triple[] val=xdrfile; int center=xdrfile; int material=xdrfile; pen[] colors=readColorData(n); surface(center,material,patch(val,colors=colors)); } void readCylinder() { triple origin=xdrfile; real radius=xdrfile; real height=xdrfile; int center=xdrfile; int material=xdrfile; real polar=xdrfile; real azimuth=xdrfile; int core=xdrfile; transform3 T=shift(origin)*Align(polar,azimuth)* scale(radius,radius,height); if(core != 0) path3(center,material,T*(O--Z)); surface s=T*unitcylinder; s.primitive=unitcylinder.primitive; primitive(center,material,s); } void readTube() { xdrfile.dimension(4); triple[] g=xdrfile; real width=xdrfile; int center=xdrfile; int material=xdrfile; int core=xdrfile; if(core != 0) path3(center,material,g[0]..controls g[1] and g[2]..g[3]); surface s=tube(g[0],g[1],g[2],g[3],width); s.primitive=primitive(drawTube(g,width,info.b,info.B), new bool(transform3 t) { return unscaled(t,X,Y); }); primitive(center,material,s); } void readCurve() { xdrfile.dimension(4); triple[] points=xdrfile; int center=xdrfile; int material=xdrfile; path3(center,material, points[0]..controls points[1] and points[2]..points[3]); } void readLine() { xdrfile.dimension(2); triple[] points=xdrfile; int center=xdrfile; int material=xdrfile; path3(center,material,points[0]--points[1]); } void readTriangles() { triangleGroup g; int nI=xdrfile; int nP=xdrfile; xdrfile.dimension(nP); g.positions=xdrfile; int nN=xdrfile; xdrfile.dimension(nN); g.normals=xdrfile; int explicitNI=xdrfile; int nC=xdrfile; int explicitCI; if (nC > 0) { g.colors=readColorData(nC); explicitCI=xdrfile; } g.positionIndices=new int[nI][3]; g.normalIndices=new int[nI][3]; int[][] colorIndices; if (nC > 0) g.colorIndices=new int[nI][3]; for (int i=0; i < nI; ++i) { xdrfile.dimension(3); g.positionIndices[i]=xdrfile; g.normalIndices[i]=explicitNI != 0 ? xdrfile : g.positionIndices[i]; g.colorIndices[i]=nC > 0 && explicitCI != 0 ? xdrfile : g.positionIndices[i]; } int center=xdrfile; int material=xdrfile; triangleGroup(center,material,g); } void readPixel() { pixel P; P.point=xdrfile; P.width=xdrfile; int material=xdrfile; pixel(material,P); } void process() { static bool processed; if(processed) return; while (!eof(xdrfile)) { int ty=getType(); if(ty == v3dtypes.header) { hasCameraInfo=true; info=processHeader(); } else if(ty == v3dtypes.material) { materials.push(readMaterial()); } else if(ty == v3dtypes.bezierPatch) { readBezierPatch(); } else if(ty == v3dtypes.bezierTriangle) { readBezierTriangle(); } else if(ty == v3dtypes.bezierPatchColor) { readBezierPatchColor(); } else if(ty == v3dtypes.bezierTriangleColor) { readBezierTriangleColor(); } else if(ty == v3dtypes.quad) { readPolygon(4); } else if(ty == v3dtypes.quadColor) { readPolygonColor(4); } else if(ty == v3dtypes.triangle) { readPolygon(3); } else if(ty == v3dtypes.triangleColor) { readPolygonColor(3); } else if(ty == v3dtypes.sphere) { readSphere(); } else if(ty == v3dtypes.halfSphere) { readHemisphere(); } else if(ty == v3dtypes.cylinder) { readCylinder(); } else if(ty == v3dtypes.tube) { readTube(); } else if(ty == v3dtypes.disk) { readDisk(); } else if(ty == v3dtypes.curve) { readCurve(); } else if(ty == v3dtypes.line) { readLine(); } else if(ty == v3dtypes.triangles) { readTriangles(); } else if(ty == v3dtypes.centers) { centers=readCenters(); } else if(ty == v3dtypes.pixel) { readPixel(); } else { // abort("Unknown type:"+string(ty)); } } processed=true; } } void importv3d(string name) { if(name == stripextension(name)) name += ".v3d"; v3dfile xf=v3dfile(name); xf.process(); xf.setCameraInfo(); for(int c=0; c < xf.surfaces.length; ++c) { triple center=c > 0 ? xf.centers[c-1] : O; render r=render(interaction(c == 0 ? Embedded : Billboard,center=center)); surface[][] S=xf.surfaces[c]; for(int m=0; m < S.length; ++m) if(S.initialized(m)) draw(S[m],xf.materials[m],r); } for(int c=0; c < xf.paths3.length; ++c) { triple center=c > 0 ? xf.centers[c-1] : O; render r=render(interaction(c == 0 ? Embedded : Billboard,center=center)); path3[][] G=xf.paths3[c]; for(int m=0; m < G.length; ++m) if(G.initialized(m)) { material material=material(xf.materials[m]); material.p[0] += thin(); draw(G[m],material,currentlight,r); } } for(int c=0;c < xf.triangles.length; ++c) { triple center=c > 0 ? xf.centers[c-1] : O; render r=render(interaction(c == 0 ? Embedded : Billboard,center=center)); triangleGroup[][] groups=xf.triangles[c]; for(int m=0; m < groups.length; ++m) { if(groups.initialized(m)) { material material=xf.materials[m]; triangleGroup[] triangleGroups=groups[m]; for(triangleGroup g : triangleGroups) { if(g.colors.length > 0) draw(g.positions,g.positionIndices,g.normals,g.normalIndices, g.colors,g.colorIndices,r); else draw(g.positions,g.positionIndices,g.normals,g.normalIndices, material,r); } } } } for(int m=0; m < xf.pixels.length; ++m) { if(xf.pixels.initialized(m)) { material material=xf.materials[m]; pixel[] pixels=xf.pixels[m]; for(pixel P : pixels) pixel(P.point,material.p[0],P.width); } } }