/*************************************************************************** * obj.cpp is part of Math Graphic Library * Copyright (C) 2007-2016 Alexey Balakin * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 3 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include "mgl2/canvas.h" #include "mgl2/canvas_cf.h" #undef _GR_ #define _GR_ ((mglCanvas *)(*gr)) #define _Gr_ ((mglCanvas *)(gr)) int MGL_NO_EXPORT mgl_tga_save(const char *fname, int w, int h, unsigned char **p); int MGL_NO_EXPORT mgl_pnga_save(const char *fname, int w, int h, unsigned char **p); void MGL_NO_EXPORT mgl_printf(void *fp, bool gz, const char *str, ...); //----------------------------------------------------------------------------- #include #include #include #include #include #include #include /* Size prefixes for printf/scanf for size_t and ptrdiff_t */ #ifdef _MSC_VER # define PRIuS "Iu" /* printf size_t */ # define PRIdS "Id" /* printf ptrdiff_t */ #else # define PRIuS "zu" /* printf size_t */ # define PRIdS "zd" /* printf ptrdiff_t */ #endif //----------------------------------------------------------------------------- void mglTexture::GetRGBAOBJ(unsigned char *f) const { const size_t bw = 128; //border width register size_t i,j,i0; mglColor c1,c2,c; for(i=0;i<256;i++) { c1 = col[2*i]; c2 = col[2*i+1]; for(j=0;j<512;j++) { i0 = 4*(j+512*(255-i)); if (j511-bw) c = c2; else c = c1 + (c2-c1)*((j-bw)/(255.)); f[i0] = int(255*c.r); f[i0+1] = int(255*c.g); f[i0+2] = int(255*c.b); f[i0+3] = int(255*c.a); } } } //----------------------------------------------------------------------------- struct ObjUV { ObjUV() : u(0.0), v(0.0) {} ObjUV(mreal U, mreal V) : u(U), v(V) {} mreal u; mreal v; void Set(mreal U, mreal V) { u = U; v = V; } bool operator==(const ObjUV &c) const { return u==c.u && v==c.v; } bool operator!=(const ObjUV &c) const { return !(u==c.u && v==c.v); } bool operator<(const ObjUV &c) const { if(u!=c.u) return (u texturecoords; FILE* const fp; ObjUVs(FILE *f) : fp(f) {} size_t addTextureCoords(mreal ta, mreal c, size_t ntxt) { const mreal gap = 1./512; const mreal u = 0.25+0.5*(ta*(1-2*gap)+gap); const mreal v = ((c-floor(c))*(1-2*gap) + gap + floor(c))/ntxt; const ObjUV point(u, v); std::map::iterator pPoint = texturecoords.find(point); if(pPoint!=texturecoords.end()) return pPoint->second; else { const size_t point_index = texturecoords.size()+1; texturecoords.insert(std::make_pair(point,point_index)); fprintf(fp,"vt %.15g %.15g\n",u,v); return point_index; } } }; class ObjXYZ { public : mreal x; mreal y; mreal z; ObjXYZ() : x(0), y(0), z(0) {} ObjXYZ(mreal fx, mreal fy, mreal fz) : x(fx), y(fy), z(fz) {} void Set(mreal fx, mreal fy, mreal fz) { x = fx; y = fy; z = fz; } mreal Dot(const ObjXYZ & sPt) const { return(x*sPt.x)+(y*sPt.y)+(z*sPt.z); } mreal LengthSquared() { return(x*x+y*y+z*z); } friend ObjXYZ operator + (const ObjXYZ& a, const ObjXYZ& b) { return ObjXYZ(a.x+b.x,a.y+b.y,a.z+b.z); } friend ObjXYZ operator - (const ObjXYZ& a) { return ObjXYZ(-a.x,-a.y,-a.z); } friend ObjXYZ operator - (const ObjXYZ& a, const ObjXYZ& b) { return ObjXYZ(a.x-b.x,a.y-b.y,a.z-b.z); } friend ObjXYZ operator * (const ObjXYZ& a, const mreal d) { return ObjXYZ(a.x*d,a.y*d,a.z*d); } friend ObjXYZ operator * (const mreal d, const ObjXYZ& a) { return ObjXYZ(a.x*d,a.y*d,a.z*d); } friend ObjXYZ operator / (const ObjXYZ& a, const mreal d) { return ObjXYZ(a.x/d,a.y/d,a.z/d); } friend ObjXYZ operator * (const ObjXYZ& a, const ObjXYZ& b) { return ObjXYZ((a.y*b.z)-(a.z*b.y), (a.z*b.x)-(a.x*b.z), (a.x*b.y)-(a.y*b.x)); } mreal Length() { return sqrt(x*x+y*y+z*z); } bool Normalize() { mreal fLength=Length(); if(fLength < FLT_EPSILON) return false; mreal factor=1.0/fLength; x *= factor; y *= factor; z *= factor; return true; } bool operator==(const ObjXYZ &v) const { return x==v.x && y==v.y && z==v.z; } bool operator!=(const ObjXYZ &v) const { return !(x==v.x && y==v.y && z==v.z); } bool operator<(const ObjXYZ &v) const { if(x!=v.x) return (x vertexcoords; FILE* const fp; ObjXYZs(FILE *f) : fp(f) {} size_t addVertexCoords(mreal x, mreal y, mreal z) { const ObjXYZ point(x,y,z); std::map::iterator pPoint = vertexcoords.find(point); if(pPoint!=vertexcoords.end()) return pPoint->second; else { const size_t point_index = vertexcoords.size()+1; vertexcoords.insert(std::make_pair(point,point_index)); fprintf(fp,"v %.15g %.15g %.15g\n",x,y,z); return point_index; } } }; struct ObjTriangle { size_t p1, p2, p3; size_t t1, t2, t3; ObjTriangle() : p1(0), p2(0), p3(0), t1(0), t2(0), t3(0) {} ObjTriangle(size_t P1, size_t T1, size_t P2, size_t T2, size_t P3, size_t T3) : p1(P1), p2(P2), p3(P3), t1(T1), t2(T2), t3(T3) {} }; struct ObjLine { size_t p1, p2; ObjLine() : p1(0), p2(0) {} ObjLine(size_t P1, size_t P2) : p1(P1), p2(P2) {} }; struct ObjGroup { std::deque triangles; mglColor commoncolor; bool samecolor; std::map > lines; std::map > points; FILE* const fp; ObjXYZs &vertexcoords; ObjGroup(FILE *f,ObjXYZs& v) : commoncolor(NC), samecolor(true), fp(f), vertexcoords(v) {} // const HMGL gr; // ObjGroup(const HMGL g) : samecolor(true), gr(g) {} void addSegment(size_t m, size_t p1, size_t p2) { lines[m].push_back(ObjLine(p1,p2)); } void addLines(size_t m, size_t n, const size_t* p) { for (size_t i=0; i >::const_iterator pm = lines.begin(); pm != lines.end(); pm++) { fprintf(fp,"usemtl Material%" PRIuS "\n", pm->first); for(std::deque::const_iterator pl = pm->second.begin(); pl != pm->second.end(); pl++) fprintf(fp,"l %" PRIuS " %" PRIuS "\n", pl->p1, pl->p2); } } void writePoints() { for(std::map >::const_iterator pm = points.begin(); pm != points.end(); pm++) { fprintf(fp,"usemtl Material%" PRIuS "\n", pm->first); for(std::deque::const_iterator pp = pm->second.begin(); pp != pm->second.end(); pp++) fprintf(fp,"p %" PRIuS "\n", *pp); } } void writeTriangles() { for(std::deque::const_iterator pt = triangles.begin(); pt != triangles.end(); pt++) fprintf(fp,"f %" PRIuS " %" PRIuS " %" PRIuS "\n", pt->p1, pt->p2, pt->p3); } void writeTexturedTriangles() { for(std::deque::const_iterator pt = triangles.begin(); pt != triangles.end(); pt++) fprintf(fp,"f %" PRIuS "/%" PRIuS " %" PRIuS "/%" PRIuS " %" PRIuS "/%" PRIuS "\n", pt->p1,pt->t1, pt->p2,pt->t2, pt->p3,pt->t3); } }; struct lt_mglColor { bool operator()(const mglColor& c1, const mglColor& c2) const { if(c1.r!=c2.r) return (c1.r colormap; struct ObjMaterials { colormap materialmap; FILE* const fp; ObjMaterials(FILE *f) : fp(f) {} size_t addColor(const mglColor& color) { colormap::iterator pc = materialmap.find(color); if(pc!=materialmap.end()) return pc->second; else { const size_t color_index = materialmap.size(); materialmap.insert(std::make_pair(color,color_index)); fprintf(fp,"newmtl Material%" PRIuS "\n", color_index); fprintf(fp,"Ka 0.1 0.1 0.1\n"); fprintf(fp,"Kd %g %g %g\n", color.r, color.g, color.b); fprintf(fp,"Ks 0.0 0.0 0.0\n"); fprintf(fp,"d %g\nillum 2\nNs 15.0\n",color.a); return color_index; } } size_t addColor(mreal r, mreal g, mreal b, mreal a) { const mglColor color(r,g,b,a); return addColor(color); } size_t addColorInfo(const mglPnt& p) { return addColor(p.r,p.g,p.b,p.a); } }; size_t MGL_LOCAL_CONST power_of_two(size_t input) { size_t value = 1; while ( value < input ) value <<= 1; return value; } void MGL_EXPORT mgl_write_obj(HMGL gr, const char *fname,const char *descr, int use_png) { if(gr->GetPrmNum()==0) return; // nothing to do register size_t i,j; { long mmin=0,mmax=0,m; for(i=0;iGrp.size();i++) // prepare array of indirect indexing { m = gr->Grp[i].Id; if(mmmax) mmax=m; } long *ng = new long[mmax-mmin+1]; for(i=0;iGrp.size();i++) ng[gr->Grp[i].Id-mmin] = i; for(i=0;iGetPrmNum());i++) // collect data for groups // it is rather expensive (extra 4b per primitive) but need for export to 3D { m = gr->GetPrm(i,false).id-mmin; if(m>=0 && mGrp[ng[m]].p.push_back(i); } delete []ng; } const size_t len=strlen(fname); const size_t ntxt=gr->GetTxtNum(); const size_t Ntxt=power_of_two(ntxt); const size_t pntnum = gr->GetPntNum(); char *tname = new char[len+5]; strcpy(tname,fname); FILE *fp=fopen(fname,"wt"); ObjXYZs vertexcoords(fp); std::vector vcs(pntnum); // vertex coord ids ObjUVs texturecoords(fp); std::vector tcs(pntnum); // texture coord ids // center point mglPnt p0; const mreal width = dynamic_cast(gr)->GetWidth(); const mreal height = dynamic_cast(gr)->GetHeight(); const mreal depth = sqrt(width*height); p0.x = width/2.; p0.y = height/2.; p0.z = (1.f-sqrt(width*height)/(2*depth))*depth; // vertices definition fprintf(fp,"# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname); for(i=0;iGetPnt(i); vcs[i] = vertexcoords.addVertexCoords(pp.x-p0.x, pp.y-p0.y, pp.z-p0.z); tcs[i] = texturecoords.addTextureCoords(pp.ta, pp.c, Ntxt); } // prepare MTL file tname[len-4]='.'; tname[len-3]='m'; tname[len-2]='t'; tname[len-1]='l'; FILE *fpmat=fopen(tname,"wt"); tname[len-4]='\0'; fprintf(fpmat,"newmtl Material\n"); fprintf(fpmat,"Ka 0.0 0.0 0.0\n"); fprintf(fpmat,"Kd 1.0 1.0 1.0\n"); fprintf(fpmat,"Ks 0.0 0.0 0.0\n"); fprintf(fpmat,"d 1.0\nillum 2\n"); if(use_png) fprintf(fpmat,"map_Kd %s_txt.png\n",tname); else fprintf(fpmat,"map_Kd %s_txt.tga\n",tname); if(use_png) strcat(tname,"_txt.png"); else strcat(tname,"_txt.tga"); // prepare texture file (TGA or PNG) const size_t txtwidth = 512; unsigned char *buf = new unsigned char[4*256*txtwidth*Ntxt]; unsigned char **pbuf= (unsigned char **)malloc(256*Ntxt*sizeof(unsigned char *)); for(i=0;i<256*Ntxt;i++) pbuf[i] = buf+4*txtwidth*i; for(i=0;iGetTxt(i).GetRGBAOBJ(buf+(Ntxt-1-i)*256*txtwidth*4); for(i=ntxt;iGrp.size();i++) { std::vector &p = gr->Grp[i].p; ObjGroup grp(fp, vertexcoords); for(j=0;jGetPrm(p[j],false); register long n1=q.n1,n2=q.n2,n3=q.n3,n4=q.n4; switch(q.type) { case 0: if (gr->GetPnt(q.n1).a > mgl_min_a) { const mglPnt p = gr->GetPnt(q.n1) - p0; const mreal size = q.s; const char type = q.n4; mreal ss=size; const mglColor c(p.r, p.g, p.b, p.a); if(!strchr("xsSoO",type)) ss *= 1.1; if(type=='.' || ss==0) { const size_t m = materials.addColor(c); grp.addPoint(m, vcs[n1]); } else switch(type) { case 'P': { const size_t m = materials.addColor(c); const mreal P[5][3] = { { p.x-ss,p.y-ss,p.z }, { p.x+ss,p.y-ss,p.z }, { p.x+ss,p.y+ss,p.z }, { p.x-ss,p.y+ss,p.z }, { p.x-ss,p.y-ss,p.z } }; grp.addLines(m, 5, P); } case '+': { const size_t m = materials.addColor(c); const mreal P1[2][3] = { { p.x-ss,p.y,p.z }, { p.x+ss,p.y,p.z } }; grp.addLines(m, 2, P1); const mreal P2[2][3] = { { p.x,p.y-ss,p.z }, { p.x,p.y+ss,p.z } }; grp.addLines(m, 2, P2); } break; case 'X': { const size_t m = materials.addColor(c); const mreal P[5][3] = { { p.x-ss,p.y-ss,p.z }, { p.x+ss,p.y-ss,p.z }, { p.x+ss,p.y+ss,p.z }, { p.x-ss,p.y+ss,p.z }, { p.x-ss,p.y-ss,p.z } }; grp.addLines(m, 5, P); const mreal P1[2][3] = { { p.x-ss,p.y-ss,p.z }, { p.x+ss,p.y+ss,p.z } }; grp.addLines(m, 2, P1); const mreal P2[2][3] = { { p.x+ss,p.y-ss,p.z }, { p.x-ss,p.y+ss,p.z } }; grp.addLines(m, 2, P2); } break; case 'x': { const size_t m = materials.addColor(c); const mreal P1[2][3] = { { p.x-ss,p.y-ss,p.z }, { p.x+ss,p.y+ss,p.z } }; grp.addLines(m, 2, P1); const mreal P2[2][3] = { { p.x+ss,p.y-ss,p.z }, { p.x-ss,p.y+ss,p.z } }; grp.addLines(m, 2, P2); } break; case 'S': { const size_t ti = tcs[n1]; grp.addColourInfo(p); const size_t pi1 = vertexcoords.addVertexCoords(p.x-ss,p.y-ss,p.z); const size_t pi2 = vertexcoords.addVertexCoords(p.x+ss,p.y-ss,p.z); const size_t pi3 = vertexcoords.addVertexCoords(p.x-ss,p.y+ss,p.z); const size_t pi4 = vertexcoords.addVertexCoords(p.x+ss,p.y+ss,p.z); grp.addTriangle(pi1, ti, pi2, ti, pi3, ti); grp.addTriangle(pi4, ti, pi3, ti, pi2, ti); } break; case 's': { const size_t m = materials.addColor(c); const mreal P[5][3] = { { p.x-ss,p.y-ss,p.z }, { p.x+ss,p.y-ss,p.z }, { p.x+ss,p.y+ss,p.z }, { p.x-ss,p.y+ss,p.z }, { p.x-ss,p.y-ss,p.z } }; grp.addLines(m, 5, P); } break; case 'D': { const size_t ti = tcs[n1]; grp.addColourInfo(p); const size_t pi1 = vertexcoords.addVertexCoords(p.x,p.y-ss,p.z); const size_t pi2 = vertexcoords.addVertexCoords(p.x+ss,p.y,p.z); const size_t pi3 = vertexcoords.addVertexCoords(p.x-ss,p.y,p.z); const size_t pi4 = vertexcoords.addVertexCoords(p.x,p.y+ss,p.z); grp.addTriangle(pi1, ti, pi2, ti, pi3, ti); grp.addTriangle(pi4, ti, pi3, ti, pi2, ti); } break; case 'd': { const size_t m = materials.addColor(c); const mreal P[5][3] = { { p.x,p.y-ss,p.z }, { p.x+ss,p.y,p.z }, { p.x,p.y+ss,p.z }, { p.x-ss,p.y,p.z }, { p.x,p.y-ss,p.z } }; grp.addLines(m, 5, P); } break; case 'Y': { const size_t m = materials.addColor(c); const mreal P1[3][3] = { { p.x, p.y-ss, p.z }, { p.x, p.y, p.z }, { p.x+0.8*ss,p.y+0.6*ss,p.z } }; grp.addLines(m, 3, P1); const mreal P2[2][3] = { { p.x, p.y, p.z }, { p.x-0.8*ss,p.y+0.6*ss,p.z } }; grp.addLines(m, 2, P2); } break; case '*': { const size_t m = materials.addColor(c); const mreal P1[2][3] = { { p.x-ss,p.y,p.z }, { p.x+ss,p.y,p.z } }; grp.addLines(m, 2, P1); const mreal P2[2][3] = { { p.x-0.6*ss,p.y-0.8*ss,p.z }, { p.x+0.6*ss,p.y+0.8*ss,p.z } }; grp.addLines(m, 2, P2); const mreal P3[2][3] = { { p.x-0.6*ss,p.y+0.8*ss,p.z }, { p.x+0.6*ss,p.y-0.8*ss,p.z } }; grp.addLines(m, 2, P3); } break; case 'T': { const size_t ti = tcs[n1]; grp.addColourInfo(p); const size_t pi1 = vertexcoords.addVertexCoords(p.x-ss,p.y-ss/2,p.z); const size_t pi2 = vertexcoords.addVertexCoords(p.x+ss,p.y-ss/2,p.z); const size_t pi3 = vertexcoords.addVertexCoords(p.x,p.y+ss,p.z); grp.addTriangle(pi1, ti, pi2, ti, pi3, ti); } break; case '^': { const size_t m = materials.addColor(c); const mreal P[4][3] = { { p.x-ss,p.y-ss/2,p.z }, { p.x+ss,p.y-ss/2,p.z }, { p.x, p.y+ss, p.z }, { p.x-ss,p.y-ss/2,p.z } }; grp.addLines(m, 4, P); } break; case 'V': { const size_t ti = tcs[n1]; grp.addColourInfo(p); const size_t pi1 = vertexcoords.addVertexCoords(p.x-ss,p.y+ss/2,p.z); const size_t pi2 = vertexcoords.addVertexCoords(p.x,p.y-ss,p.z); const size_t pi3 = vertexcoords.addVertexCoords(p.x+ss,p.y+ss/2,p.z); grp.addTriangle(pi1, ti, pi2, ti, pi3, ti); } break; case 'v': { const size_t m = materials.addColor(c); const mreal P[4][3] = { { p.x-ss,p.y+ss/2,p.z }, { p.x+ss,p.y+ss/2,p.z }, { p.x, p.y-ss, p.z }, { p.x-ss,p.y+ss/2,p.z } }; grp.addLines(m, 4, P); } break; case 'L': { const size_t ti = tcs[n1]; grp.addColourInfo(p); const size_t pi1 = vertexcoords.addVertexCoords(p.x+ss/2,p.y+ss,p.z); const size_t pi2 = vertexcoords.addVertexCoords(p.x-ss, p.y, p.z); const size_t pi3 = vertexcoords.addVertexCoords(p.x+ss/2,p.y-ss,p.z); grp.addTriangle(pi1, ti, pi2, ti, pi3, ti); } break; case '<': { const size_t m = materials.addColor(c); const mreal P[4][3] = { { p.x+ss/2,p.y+ss,p.z }, { p.x+ss/2,p.y-ss,p.z }, { p.x-ss, p.y, p.z }, { p.x+ss/2,p.y+ss,p.z } }; grp.addLines(m, 4, P); } break; case 'R': { const size_t ti = tcs[n1]; grp.addColourInfo(p); const size_t pi1 = vertexcoords.addVertexCoords(p.x-ss/2,p.y+ss,p.z); const size_t pi2 = vertexcoords.addVertexCoords(p.x-ss/2,p.y-ss,p.z); const size_t pi3 = vertexcoords.addVertexCoords(p.x+ss, p.y, p.z); grp.addTriangle(pi1, ti, pi2, ti, pi3, ti); } break; case '>': { const size_t m = materials.addColor(c); const mreal P[4][3] = { { p.x-ss/2,p.y+ss,p.z }, { p.x-ss/2,p.y-ss,p.z }, { p.x+ss, p.y, p.z }, { p.x-ss/2,p.y+ss,p.z } }; grp.addLines(m, 4, P); } break; case 'O': { const size_t ti = tcs[n1]; grp.addColourInfo(p); const size_t cpi=vertexcoords.addVertexCoords(p.x, p.y, p.z); size_t pnti[21]; for(size_t k=0;k<=20;k++) pnti[k]=vertexcoords.addVertexCoords(p.x+ss*cos(k*M_PI/10),p.y+ss*sin(k*M_PI/10),p.z); for(size_t k=0;k<20;k++) { grp.addTriangle(pnti[k], ti, pnti[k+1], ti, cpi, ti); } } break; case 'C': { const size_t m = materials.addColor(c); grp.addPoint(m, vcs[n1]); } case 'o': { const size_t m = materials.addColor(c); mreal P[21][3]; for(size_t k=0;k<=20;k++) { P[k][0] = p.x+ss*cos(k*M_PI/10); P[k][1] = p.y+ss*sin(k*M_PI/10); P[k][2] = p.z; } grp.addLines(m, 21, P); } break; } } break; case 1: if (gr->GetPnt(q.n1).a > mgl_min_a || gr->GetPnt(q.n2).a > mgl_min_a) { const mglPnt& p1 = gr->GetPnt(q.n1); const mglPnt& p2 = gr->GetPnt(q.n2); const size_t m = materials.addColor((p1.r+p2.r)/2, (p1.g+p2.g)/2, (p1.b+p2.b)/2, (p1.a+p2.a)/2); grp.addSegment(m, vcs[n1], vcs[n2]); } break; case 2: if (gr->GetPnt(q.n1).a > mgl_min_a || gr->GetPnt(q.n2).a > mgl_min_a || gr->GetPnt(q.n3).a > mgl_min_a) { grp.addTriangle(vcs[n1],tcs[n1], vcs[n2],tcs[n2], vcs[n3],tcs[n3]); grp.addColourInfo(gr->GetPnt(n1)); grp.addColourInfo(gr->GetPnt(n2)); grp.addColourInfo(gr->GetPnt(n3)); } break; case 3: if (gr->GetPnt(q.n1).a > mgl_min_a || gr->GetPnt(q.n2).a > mgl_min_a || gr->GetPnt(q.n3).a > mgl_min_a || gr->GetPnt(q.n4).a > mgl_min_a) { grp.addTriangle(vcs[n1],tcs[n1], vcs[n2],tcs[n2], vcs[n3],tcs[n3]); grp.addTriangle(vcs[n2],tcs[n2], vcs[n4],tcs[n4], vcs[n3],tcs[n3]); grp.addColourInfo(gr->GetPnt(n1)); grp.addColourInfo(gr->GetPnt(n2)); grp.addColourInfo(gr->GetPnt(n3)); grp.addColourInfo(gr->GetPnt(n4)); } break; case 4: { const mglPnt p = gr->GetPnt(q.n1) - p0; const mreal f = q.p/2, dx=p.u/2, dy=p.v/2; const mreal c=q.s*cos(q.w*M_PI/180), s=-q.s*sin(q.w*M_PI/180); const double b[4] = {c,-s, s,c}; long ik,il=0; const mglGlyph &g = gr->GetGlf(q.n4); const mreal dd = 0.004; if(q.n3&8) { const size_t p_4 = vertexcoords.addVertexCoords(p.x+b[0]*dx+b[1]*(dy-dd),p.y+b[2]*dx+b[3]*(dy-dd),p.z); const size_t p_3 = vertexcoords.addVertexCoords(p.x+b[0]*dx+b[1]*(dy+dd),p.y+b[2]*dx+b[3]*(dy+dd),p.z); const size_t p_2 = vertexcoords.addVertexCoords(p.x+b[0]*(dx+f)+b[1]*(dy-dd),p.y+b[2]*dx+b[3]*(dy-dd),p.z); const size_t p_1 = vertexcoords.addVertexCoords(p.x+b[0]*(dx+f)+b[1]*(dy+dd),p.y+b[2]*dx+b[3]*(dy+dd),p.z); if(!(q.n3&4)) // glyph_line(p,f,true, d); { const size_t ti = tcs[n1]; grp.addColourInfo(p); grp.addMonoTriangle(ti, p_1, p_3, p_2); grp.addMonoTriangle(ti, p_4, p_2, p_3); } else // glyph_line(p,f,false, d); { const size_t m = materials.addColor(p.r, p.g, p.b, p.a); grp.addSegment(m, p_1, p_2); grp.addSegment(m, p_3, p_4); grp.addSegment(m, p_1, p_3); grp.addSegment(m, p_2, p_4); } } else { if(!(q.n3&4)) // glyph_fill(p,f,g, d); { for(ik=0;ikGrp[i].Lbl.c_str()); if (!grp.triangles.empty()) { if (grp.samecolor) { fprintf(fp,"usemtl Material%" PRIuS "\n", materials.addColor(grp.commoncolor)); grp.writeTriangles(); } else { fprintf(fp,"usemtl Material\n"); grp.writeTexturedTriangles(); } } grp.writeLines(); grp.writePoints(); gr->Grp[i].p.clear(); // we don't need indexes anymore } fclose(fp); fclose(fpmat); delete []tname; } void MGL_EXPORT mgl_write_obj_(uintptr_t *gr, const char *fname,const char *descr, int *use_png,int l,int n) { char *s=new char[l+1]; memcpy(s,fname,l); s[l]='\0'; char *d=new char[n+1]; memcpy(d,descr,n); d[n]='\0'; mgl_write_obj(_GR_,s,d,*use_png); delete []s; delete []d; } //-----------------------------------------------------------------------------