1 /***************************************************************************
2  * export_3d.cpp is part of Math Graphic Library
3  * Copyright (C) 2007-2016 Alexey Balakin <mathgl.abalakin@gmail.ru>       *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU Lesser General Public License  as       *
7  *   published by the Free Software Foundation; either version 3 of the    *
8  *   License, or (at your option) any later version.                       *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU Lesser General Public     *
16  *   License along with this program; if not, write to the                 *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #include <time.h>
21 #include <stdarg.h>
22 #include "mgl2/canvas.h"
23 #include "mgl2/canvas_cf.h"
24 #undef _GR_
25 #define _GR_	((mglCanvas *)(*gr))
26 #define _Gr_	((mglCanvas *)(gr))
27 int MGL_NO_EXPORT mgl_tga_save(const char *fname, int w, int h, unsigned char **p);
28 int MGL_NO_EXPORT mgl_pnga_save(const char *fname, int w, int h, unsigned char **p);
29 void MGL_NO_EXPORT mgl_printf(void *fp, bool gz, const char *str, ...);
30 std::string MGL_NO_EXPORT mgl_sprintf(const char *str, ...);
31 //-----------------------------------------------------------------------------
GetRGBA(unsigned char * f) const32 void mglTexture::GetRGBA(unsigned char *f) const
33 {
34 	for(long i=255;i>=0;i--)
35 	{
36 		mglColor c1 = col[2*i], c2 = col[2*i+1];
37 		for(long j=0;j<256;j++)
38 		{
39 			long i0 = 4*(j+256*i);
40 			mglColor c = c1 + (c2-c1)*(j/255.);
41 			f[i0]   = int(255*c.r);
42 			f[i0+1] = int(255*c.g);
43 			f[i0+2] = int(255*c.b);
44 			f[i0+3] = int(255*c.a);
45 		}
46 	}
47 }
48 //-----------------------------------------------------------------------------
mgl_obj_glyph_old(HMGL gr,const mglPrim & q,const mglPnt & p,FILE * fp)49 void MGL_EXPORT mgl_obj_glyph_old(HMGL gr, const mglPrim &q, const mglPnt &p, FILE *fp)
50 {
51 	mreal f = q.p/2, dx=p.u/2, dy=p.v/2, x,y;
52 	mreal c=q.s*cos(q.w*M_PI/180), s=-q.s*sin(q.w*M_PI/180);
53 	if(mgl_isnan(q.s))	c=s=0;
54 	double b[4] = {c,-s, s,c};
55 	long i=q.n1+1;
56 
57 	const mglGlyph &g = gr->GetGlf(q.n4);
58 	const mreal dd = 0.004;
59 	if(q.n3&8)
60 	{
61 		fprintf(fp,"v %g %g %g\n",p.x+b[0]*dx+b[1]*(dy-dd),p.y+b[2]*dx+b[3]*(dy-dd),p.z);
62 		fprintf(fp,"v %g %g %g\n",p.x+b[0]*dx+b[1]*(dy+dd),p.y+b[2]*dx+b[3]*(dy+dd),p.z);
63 		fprintf(fp,"v %g %g %g\n",p.x+b[0]*(dx+f)+b[1]*(dy-dd),p.y+b[2]*dx+b[3]*(dy-dd),p.z);
64 		fprintf(fp,"v %g %g %g\n",p.x+b[0]*(dx+f)+b[1]*(dy+dd),p.y+b[2]*dx+b[3]*(dy+dd),p.z);
65 		if(!(q.n3&4))	// glyph_line(p,f,true, d);
66 		{
67 			fprintf(fp,"f -1/%ld -3/%ld -2/%ld\n",i,i,i);
68 			fprintf(fp,"f -4/%ld -2/%ld -3/%ld\n",i,i,i);
69 		}
70 		else	// glyph_line(p,f,false, d);
71 		{
72 			fprintf(fp,"l -1/%ld -2/%ld\n",i,i);
73 			fprintf(fp,"l -3/%ld -4/%ld\n",i,i);
74 			fprintf(fp,"l -1/%ld -3/%ld\n",i,i);
75 			fprintf(fp,"l -2/%ld -4/%ld\n",i,i);
76 		}
77 	}
78 	else
79 	{
80 		if(!(q.n3&4))	// glyph_fill(p,f,g, d);
81 		{
82 			for(long ik=0;ik<g.nt;ik++)
83 			{
84 				x = dx+f*g.trig[6*ik];		y = dy+f*g.trig[6*ik+1];
85 				fprintf(fp,"v %g %g %g\n",p.x+b[0]*x+b[1]*y,p.y+b[2]*x+b[3]*y,p.z);
86 				x = dx+f*g.trig[6*ik+2];	y = dy+f*g.trig[6*ik+3];
87 				fprintf(fp,"v %g %g %g\n",p.x+b[0]*x+b[1]*y,p.y+b[2]*x+b[3]*y,p.z);
88 				x = dx+f*g.trig[6*ik+4];	y = dy+f*g.trig[6*ik+5];
89 				fprintf(fp,"v %g %g %g\n",p.x+b[0]*x+b[1]*y,p.y+b[2]*x+b[3]*y,p.z);
90 				fprintf(fp,"f -1/%ld -3/%ld -2/%ld\n",i,i,i);
91 			}
92 		}
93 		else	// glyph_wire(p,f,g, d);
94 		{
95 			long il=0;
96 			for(long ik=0;ik<g.nl;ik++)
97 			{
98 				x = g.line[2*ik];	y = g.line[2*ik+1];
99 				if(x==0x3fff && y==0x3fff)	// line breakthrough
100 				{	il = ik+1;	continue;	}
101 				else if(ik==g.nl-1 || (g.line[2*ik+2]==0x3fff && g.line[2*ik+3]==0x3fff))
102 				{	// enclose the circle. May be in future this block should be commented
103 					x = dx+f*g.line[2*ik];		y = dy+f*g.line[2*ik+1];
104 					fprintf(fp,"v %g %g %g\n",p.x+b[0]*x+b[1]*y,p.y+b[2]*x+b[3]*y,p.z);
105 					x = dx+f*g.line[2*il];		y = dy+f*g.line[2*il+1];
106 					fprintf(fp,"v %g %g %g\n",p.x+b[0]*x+b[1]*y,p.y+b[2]*x+b[3]*y,p.z);
107 				}
108 				else
109 				{	// normal line
110 					x = dx+f*g.line[2*ik];		y = dy+f*g.line[2*ik+1];
111 					fprintf(fp,"v %g %g %g\n",p.x+b[0]*x+b[1]*y,p.y+b[2]*x+b[3]*y,p.z);
112 					x = dx+f*g.line[2*ik+2];	y = dy+f*g.line[2*ik+3];
113 					fprintf(fp,"v %g %g %g\n",p.x+b[0]*x+b[1]*y,p.y+b[2]*x+b[3]*y,p.z);
114 				}
115 				fprintf(fp,"l -1/%ld -2/%ld\n",i,i);
116 			}
117 		}
118 	}
119 }
120 //-----------------------------------------------------------------------------
121 /* M.Vidassov take/move it into src/obj.cpp */
mgl_obj_prim_old(HMGL gr,const mglPrim & q,const mglPnt & p,FILE * fp,mreal size)122 void MGL_EXPORT mgl_obj_prim_old(HMGL gr, const mglPrim &q, const mglPnt &p, FILE *fp, mreal size)
123 {
124 	char type = q.n4;	mreal ss=size;
125 	long i=q.n1+1, n1=q.n1+1,n2=q.n2+1,n3=q.n3+1,n4=q.n4+1;
126 	switch(q.type)
127 	{
128 	case 0:
129 		if(!strchr("xsSoO",type))	ss *= 1.1;
130 		if(type=='.' || ss==0)	fprintf(fp,"p %ld\n", i);
131 		else	switch(type)
132 		{
133 		case 'P':
134 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
135 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
136 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
137 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
138 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
139 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
140 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
141 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);
142 		case '+':
143 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
144 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
145 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
146 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
147 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
148 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);	break;
149 		case 'X':
150 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
151 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
152 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
153 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
154 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
155 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
156 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
157 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);
158 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);
159 			fprintf(fp,"l -2/%ld -4/%ld\n", i,i);	break;
160 		case 'x':
161 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
162 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
163 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
164 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
165 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);
166 			fprintf(fp,"l -2/%ld -4/%ld\n", i,i);	break;
167 		case 'S':
168 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
169 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
170 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
171 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
172 			fprintf(fp,"f -4/%ld -3/%ld -2/%ld -1/%ld\n",i,i,i,i);	break;
173 		case 's':
174 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
175 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
176 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
177 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
178 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
179 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
180 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
181 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);	break;
182 		case 'D':
183 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
184 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
185 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
186 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
187 			fprintf(fp,"f -4/%ld -3/%ld -2/%ld -1/%ld\n",i,i,i,i);	break;
188 		case 'd':
189 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
190 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
191 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
192 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
193 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
194 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
195 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
196 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);	break;
197 		case 'Y':
198 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
199 			fprintf(fp,"v %g %g %g\n",p.x+0.8*ss,p.y+0.6*ss,p.z);
200 			fprintf(fp,"v %g %g %g\n",p.x-0.8*ss,p.y+0.6*ss,p.z);
201 			fprintf(fp,"l -3/%ld %ld/%ld\n", i,i,i);
202 			fprintf(fp,"l -2/%ld %ld/%ld\n", i,i,i);
203 			fprintf(fp,"l -1/%ld %ld/%ld\n", i,i,i);	break;
204 		case '*':
205 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
206 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
207 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
208 			fprintf(fp,"v %g %g %g\n",p.x+0.6*ss,p.y+0.8*ss,p.z);
209 			fprintf(fp,"v %g %g %g\n",p.x-0.6*ss,p.y-0.8*ss,p.z);
210 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
211 			fprintf(fp,"v %g %g %g\n",p.x+0.6*ss,p.y-0.8*ss,p.z);
212 			fprintf(fp,"v %g %g %g\n",p.x-0.6*ss,p.y+0.8*ss,p.z);
213 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);		break;
214 		case 'T':
215 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss/2,p.z);
216 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss/2,p.z);
217 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
218 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
219 		case '^':
220 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss/2,p.z);
221 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss/2,p.z);
222 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
223 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
224 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
225 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
226 		case 'V':
227 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss/2,p.z);
228 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss/2,p.z);
229 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
230 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
231 		case 'v':
232 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss/2,p.z);
233 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss/2,p.z);
234 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
235 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
236 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
237 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
238 		case 'L':
239 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y+ss,p.z);
240 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y-ss,p.z);
241 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
242 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
243 		case '<':
244 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y+ss,p.z);
245 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y-ss,p.z);
246 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
247 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
248 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
249 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
250 		case 'R':
251 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y+ss,p.z);
252 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y-ss,p.z);
253 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
254 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
255 		case '>':
256 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y+ss,p.z);
257 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y-ss,p.z);
258 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
259 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
260 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
261 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
262 		case 'O':
263 			for(long j=0;j<=20;j++)
264 				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
265 			for(long j=0;j<20;j++)
266 				fprintf(fp,"f %ld/%ld %ld/%ld %ld/%ld\n", j-21,i, j-20,i, i,i);
267 			break;
268 		case 'C':	fprintf(fp,"p %ld\n", i);
269 		case 'o':
270 			for(long j=0;j<=20;j++)
271 				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
272 			for(long j=0;j<20;j++)
273 				fprintf(fp,"l %ld/%ld %ld/%ld\n", j-21,i, j-20,i);
274 			break;
275 		}
276 		break;
277 	case 1:	fprintf(fp,"l %ld/%ld %ld/%ld\n", n1,n1, n2,n2);	break;
278 	case 2:	fprintf(fp,"f %ld/%ld %ld/%ld %ld/%ld\n", n1,n1, n2,n2, n3,n3);	break;
279 	case 3:	fprintf(fp,"f %ld/%ld %ld/%ld %ld/%ld\n", n1,n1, n2,n2, n3,n3);
280 		fprintf(fp,"f %ld/%ld %ld/%ld %ld/%ld\n", n2,n2, n4,n4, n3,n3);	break;
281 	case 4:	mgl_obj_glyph_old(gr,q,p,fp);		break;
282 	}
283 }
284 //-----------------------------------------------------------------------------
mgl_write_obj_old(HMGL gr,const char * fname,const char * descr,int use_png)285 void MGL_EXPORT mgl_write_obj_old(HMGL gr, const char *fname,const char *descr, int use_png)
286 {
287 	if(gr->GetPrmNum()==0)	return;	// nothing to do
288 	long m1=0,m2=0;
289 	for(size_t i=0;i<gr->Grp.size();i++)	// prepare array of indirect indexing
290 	{	long m = gr->Grp[i].Id;	if(m<m1) m1=m;	if(m>m2) m2=m;	}
291 	long *ng = new long[m2-m1+1];
292 	for(size_t i=0;i<gr->Grp.size();i++)	ng[gr->Grp[i].Id-m1] = i;
293 	for(long i=0;i<gr->GetPrmNum();i++)	// collect data for groups
294 	// it is rather expensive (extra 4b per primitive) but need for export to 3D
295 	{
296 		long m = gr->GetPrm(i,false).id-m1;
297 		if(m>=0 && m<m2-m1+1)	gr->Grp[ng[m]].p.push_back(i);
298 	}
299 	delete []ng;
300 
301 	size_t len=strlen(fname),ntxt=gr->GetTxtNum();
302 	FILE *fp=fopen(fname,"wt");
303 	if(!fp)		{	gr->SetWarn(mglWarnOpen,fname);	return;	}
304 	// vertices definition
305 	const std::string loc = setlocale(LC_NUMERIC, "C");
306 	fprintf(fp,"# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname);
307 	for(long i=0;i<gr->GetPntNum();i++)
308 	{
309 		const mglPnt &pp = gr->GetPnt(i);
310 		fprintf(fp,"v %g %g %g\n",pp.x,pp.y,pp.z);
311 		fprintf(fp,"vt %g %g\n",1-pp.ta,1-pp.c/ntxt);
312 //		if(mgl_isnan(pp.u))	fprintf(fp,"vn 0 0 0\n");
313 //		else fprintf(fp,"vn %g %g %g\n",pp.u,pp.v,pp.w);
314 	}
315 	// primitive definition in groups
316 	char *tname = new char[len+15];	strcpy(tname,fname);
317 	tname[len-4]=0;	fprintf(fp,"# Primitives Definitions\nmtllib %s.mtl\nusemtl %s\n",tname,tname);
318 	for(size_t i=0;i<gr->Grp.size();i++)
319 	{
320 		fprintf(fp,"g %s\n",gr->Grp[i].Lbl.c_str());
321 		std::vector<long> &p = gr->Grp[i].p;
322 		for(size_t j=0;j<p.size();j++)
323 		{
324 			const mglPrim &q=gr->GetPrm(p[j],false);
325 			mgl_obj_prim_old(gr, q, gr->GetPnt(q.n1), fp, mgl_isnan(q.s)?0:q.s);
326 		}
327 		gr->Grp[i].p.clear();	// we don't need indexes anymore
328 	}
329 	// try to save "ungrouped" primitives
330 	fclose(fp);
331 	// prepare MTL file
332 	tname[len-4]='.';	tname[len-3]='m';	tname[len-2]='t';	tname[len-1]='l';
333 	fp=fopen(tname,"wt");
334 	tname[len-4]=0;	fprintf(fp,"newmtl %s\n",tname);
335 	fprintf(fp,"Ka 1.000 1.000 1.000\n");
336 	fprintf(fp,"Kd 1.000 1.000 1.000\n");
337 	fprintf(fp,"Ks 0.000 0.000 0.000\n");
338 	fprintf(fp,"d 1.0\nTr 0.0\nillum 2\n");
339 	if(use_png)	strcat(tname,"_texture.png");
340 //	{	tname[len-4]='.';	tname[len-3]='p';	tname[len-2]='n';	tname[len-1]='g';	}
341 	else		strcat(tname,"_texture.tga");
342 //	{	tname[len-4]='.';	tname[len-3]='t';	tname[len-2]='g';	tname[len-1]='a';	}
343 	fprintf(fp,"map_Ka %s\nmap_Kd %s\nmap_Ks %s\n",tname,tname,tname);
344 	fclose(fp);
345 	// prepare texture file (TGA or PNG)
346 	long j=gr->GetTxtNum();
347 	unsigned char *buf = new unsigned char[4*256*256*j];
348 	unsigned char **pbuf= (unsigned char **)malloc(256*j*sizeof(unsigned char *));
349 	for(long i=0;i<256*j;i++)	pbuf[i] = buf+4*256*i;
350 	for(long i=0;i<j;i++)	gr->GetTxt(i).GetRGBA(buf+i*256*256*4);
351 	if(use_png)	mgl_pnga_save(tname,256,256*j,pbuf);
352 	else		mgl_tga_save(tname,256,256*j,pbuf);
353 	free(pbuf);	delete []buf;	delete []tname;
354 	setlocale(LC_NUMERIC, loc.c_str());
355 }
mgl_write_obj_old_(uintptr_t * gr,const char * fname,const char * descr,int * use_png,int l,int n)356 void MGL_EXPORT mgl_write_obj_old_(uintptr_t *gr, const char *fname,const char *descr, int *use_png,int l,int n)
357 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
358 	char *d=new char[n+1];	memcpy(d,descr,n);	d[n]=0;
359 	mgl_write_obj_old(_GR_,s,d,*use_png);	delete []s;		delete []d;	}
360 //-----------------------------------------------------------------------------
mgl_write_stl(HMGL gr,const char * fname,const char * descr)361 void MGL_EXPORT mgl_write_stl(HMGL gr, const char *fname,const char *descr)
362 {
363 	if(gr->GetPrmNum()==0)	return;	// nothing to do
364 	FILE *fp = fopen(fname,"wt");
365 	if(!fp)		{	gr->SetWarn(mglWarnOpen,fname);	return;	}
366 	const std::string loc = setlocale(LC_NUMERIC, "C");
367 	fprintf(fp,"solid %s\n",(descr && *descr)?descr:"mathgl");
368 	mglPnt pp;
369 	for(long i=0;i<gr->GetPrmNum();i++)
370 	{
371 		const mglPrim &q=gr->GetPrm(i,false);
372 		if(q.type==2)	//	triangles
373 		{
374 			pp = gr->GetPnt(q.n1);
375 			fprintf(fp,"facet normal %.2g %.2g %.2g\nouter loop\n",pp.u,pp.v,pp.w);
376 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
377 			pp = gr->GetPnt(q.n2);
378 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
379 			pp = gr->GetPnt(q.n3);
380 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
381 			fprintf(fp,"endloop\nendfacet\n");
382 		}
383 		if(q.type==3)	//	quadrangles
384 		{
385 			pp = gr->GetPnt(q.n1);
386 			fprintf(fp,"facet normal %.2g %.2g %.2g\nouter loop\n",pp.u,pp.v,pp.w);
387 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
388 			pp = gr->GetPnt(q.n2);
389 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
390 			pp = gr->GetPnt(q.n3);
391 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
392 			fprintf(fp,"endloop\nendfacet\n");
393 			pp = gr->GetPnt(q.n1);
394 			fprintf(fp,"facet normal %.2g %.2g %.2g\nouter loop\n",pp.u,pp.v,pp.w);
395 			pp = gr->GetPnt(q.n4);
396 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
397 			pp = gr->GetPnt(q.n2);
398 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
399 			pp = gr->GetPnt(q.n3);
400 			fprintf(fp,"vertex %g %g %g\n",pp.x,pp.y,pp.z);
401 			fprintf(fp,"endloop\nendfacet\n");
402 		}
403 	}
404 	fprintf(fp,"endsolid %s",(descr && *descr)?descr:"mathgl");
405 	fclose(fp);
406 	setlocale(LC_NUMERIC, loc.c_str());
407 }
mgl_write_stl_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)408 void MGL_EXPORT mgl_write_stl_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
409 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
410 	char *d=new char[n+1];	memcpy(d,descr,n);	d[n]=0;
411 	mgl_write_stl(_GR_,s,d);	delete []s;		delete []d;	}
412 //-----------------------------------------------------------------------------
mgl_write_xyz(HMGL gr,const char * fname,const char * descr)413 void MGL_EXPORT mgl_write_xyz(HMGL gr, const char *fname,const char *descr)
414 {
415 	if(gr->GetPrmNum()==0)	return;	// nothing to do
416 
417 	FILE *fp=fopen(fname,"wt"), *ff;	// vertices definition
418 	if(!fp)		{	gr->SetWarn(mglWarnOpen,fname);	return;	}
419 	const std::string loc = setlocale(LC_NUMERIC, "C");
420 	fprintf(fp,"# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname);
421 	fprintf(fp,"# List of Vertices, with (x,y,z) coordinates.\n");
422 	for(long i=0;i<gr->GetPntNum();i++)
423 	{
424 		const mglPnt &pp = gr->GetPnt(i);
425 		fprintf(fp,"%g %g %g\n",pp.x,pp.y,pp.z);
426 	}
427 	fclose(fp);
428 
429 	// primitive definition
430 	size_t len=strlen(fname);
431 	char *tname = new char[len+2];	strcpy(tname,fname);	tname[len+1]=tname[len]=0;
432 	tname[len]='l';	fp = fopen(tname,"wt");
433 	tname[len]='f';	ff = fopen(tname,"wt");
434 	fprintf(fp,"# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname);
435 	fprintf(fp,"# Indices of vertices to connect for lines\n");
436 	fprintf(ff,"# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname);
437 	fprintf(ff,"# Indices of vertices to connect for faces\n");
438 	for(long i=0;i<gr->GetPrmNum();i++)
439 	{
440 		const mglPrim &q=gr->GetPrm(i,false);
441 		if(q.type==1)	fprintf(fp,"%ld %ld\n",q.n1+1,q.n2+1);
442 		if(q.type==2)	fprintf(ff,"%ld %ld %ld\n",q.n1+1,q.n2+1,q.n3+1);
443 		if(q.type==3)	fprintf(ff,"%ld %ld %ld\n%ld %ld %ld\n",q.n1+1,q.n2+1,q.n3+1,q.n4+1,q.n2+1,q.n3+1);
444 	}
445 	fclose(fp);	fclose(ff);	delete []tname;
446 	setlocale(LC_NUMERIC, loc.c_str());
447 }
mgl_write_xyz_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)448 void MGL_EXPORT mgl_write_xyz_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
449 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
450 	char *d=new char[n+1];	memcpy(d,descr,n);	d[n]=0;
451 	mgl_write_xyz(_GR_,s,d);	delete []s;		delete []d;	}
452 //-----------------------------------------------------------------------------
mgl_write_off(HMGL gr,const char * fname,const char * descr,int colored)453 void MGL_EXPORT mgl_write_off(HMGL gr, const char *fname,const char *descr, int colored)
454 {
455 	long nf=0;
456 	for(long i=0;i<gr->GetPrmNum();i++)	// find number of faces
457 	{
458 		const mglPrim &q=gr->GetPrm(i,false);
459 		if(q.type==2 || q.type==3)	nf++;
460 	}
461 	if(nf<=0)	return;	// nothing to do
462 
463 	FILE *fp=fopen(fname,"wt");
464 	if(!fp)		{	gr->SetWarn(mglWarnOpen,fname);	return;	}
465 	const std::string loc = setlocale(LC_NUMERIC, "C");
466 	// vertices definition
467 	if(colored)
468 		fprintf(fp,"COFF\n# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname);
469 	else
470 		fprintf(fp,"OFF\n# Created by MathGL library\n# Title: %s\n",(descr && *descr) ? descr : fname);
471 	fprintf(fp,"# List of Vertices, with (x,y,z,r,g,b,a) coordinates.\n");
472 	fprintf(fp,"%ld %ld 0\n",gr->GetPntNum(), nf);
473 	for(long i=0;i<gr->GetPntNum();i++)
474 	{
475 		const mglPnt &pp = gr->GetPnt(i);
476 		if(colored)
477 			fprintf(fp,"%g %g %g %g %g %g %g\n", pp.x, pp.y, pp.z, pp.r, pp.g, pp.b, pp.a);
478 		else	fprintf(fp,"%g %g %g\n", pp.x, pp.y, pp.z);
479 	}
480 	for(long i=0;i<gr->GetPrmNum();i++)
481 	{
482 		const mglPrim &q=gr->GetPrm(i,false);
483 		const mglPnt &p1=gr->GetPnt(q.n1);
484 		if(colored)
485 		{
486 			if(q.type==2)
487 				fprintf(fp,"3 %ld %ld %ld\n",q.n1,q.n2,q.n3);
488 			else if(q.type==3)
489 				fprintf(fp,"4 %ld %ld %ld %ld\n",q.n1,q.n2,q.n4,q.n3);
490 		}
491 		else
492 		{
493 			if(q.type==2)
494 			{
495 				const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3);
496 				if(p1.a>mgl_min_a || p2.a>mgl_min_a || p3.a>mgl_min_a)
497 					fprintf(fp,"3 %ld %ld %ld %.2g %.2g %.2g %.2g\n",q.n1,q.n2,q.n3,
498 							(p1.r+p2.r+p3.r)/3, (p1.g+p2.g+p3.g)/3, (p1.b+p2.b+p3.b)/3, (p1.a+p2.a+p3.a)/3);
499 			}
500 			else if(q.type==3)
501 			{
502 				const mglPnt &p2=gr->GetPnt(q.n2), &p3=gr->GetPnt(q.n3), &p4=gr->GetPnt(q.n4);
503 				if(p1.a>mgl_min_a || p2.a>mgl_min_a || p3.a>mgl_min_a || p4.a>mgl_min_a)
504 					fprintf(fp,"4 %ld %ld %ld %ld %.2g %.2g %.2g %.2g\n",q.n1,q.n2,q.n4,q.n3,
505 							(p1.r+p2.r+p3.r+p4.r)/4, (p1.g+p2.g+p3.g+p4.g)/4, (p1.b+p2.b+p3.b+p4.b)/4, (p1.a+p2.a+p3.a+p4.a)/4);
506 			}
507 		}
508 	}
509 	fclose(fp);
510 	setlocale(LC_NUMERIC, loc.c_str());
511 }
mgl_write_off_(uintptr_t * gr,const char * fname,const char * descr,int * colored,int l,int n)512 void MGL_EXPORT mgl_write_off_(uintptr_t *gr, const char *fname,const char *descr,int *colored,int l,int n)
513 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
514 	char *d=new char[n+1];	memcpy(d,descr,n);	d[n]=0;
515 	mgl_write_off(_GR_,s,d,*colored);	delete []s;		delete []d;	}
516 //-----------------------------------------------------------------------------
WriteJSON(const char * fname,bool force_zlib)517 bool mglCanvas::WriteJSON(const char *fname, bool force_zlib)
518 {
519 	bool fl = strcmp(fname,"-");
520 	bool gz = force_zlib || fname[strlen(fname)-1]=='z';
521 	void *fp = fl ? (gz ? (void*)gzopen(fname,"wt") : (void*)fopen(fname,"wt")) : stdout;
522 	if (!fp)	return true;
523 	std::string s=GetJSON();
524 	if(gz)	gzprintf((gzFile)fp, "%s", s.c_str());
525 	else	fprintf((FILE *)fp, "%s", s.c_str());
526 	if(fl)	{	if(gz)	gzclose((gzFile)fp);	else	fclose((FILE *)fp);	}
527 	return false;
528 }
529 //-----------------------------------------------------------------------------
mgl_get_json(HMGL gr)530 MGL_EXPORT const char *mgl_get_json(HMGL gr)
531 {
532 	static std::string json;
533 	mglCanvas *g = dynamic_cast<mglCanvas *>(gr);
534 	if(g)	json = g->GetJSON();
535 	return json.c_str();
536 }
537 //-----------------------------------------------------------------------------
GetJSON()538 std::string mglCanvas::GetJSON()
539 {
540 	ClearUnused();	// clear unused points
541 	PreparePrim(3);
542 	std::string res, buf;
543 	long ll=0,l=(long)Pnt.size();
544 	long factor = Width>1?10:10000;
545 	const std::string loc = setlocale(LC_NUMERIC, "C");
546 	res = res + mgl_sprintf("{\n\"width\":%d,\t\"height\":%d,\t\"depth\":%d,\t\"plotid\":\"%s\",\t\"npnts\":%ld,\t\"pnts\":[\n",
547 			factor*Width, factor*Height, factor*Depth, PlotId.c_str(), l);
548 	for(long i=0;i<l;i++)
549 	{
550 		const mglPnt &q=Pnt[i];
551 		res += mgl_sprintf("[%ld,%ld,%ld,%d]%c\n", long(factor*q.xx), long(factor*(Height-q.yy)), long(factor*q.zz),q.sub, i+1<l?',':' ');
552 	}
553 
554 	l = (long)Prm.size();	ll = 0;
555 	for(long i=0;i<l;i++)
556 	{	mglRGBA c;	c.c = GetPrmCol(i,false);	if(c.r[3])	ll++;	}
557 
558 	res = res + mgl_sprintf("],\t\"nprim\":%ld,\t\"prim\":[\n",ll+1);
559 
560 	std::vector<mglPoint> xy;	// vector for glyphs coordinates (to be separated from pnts)
561 	res.reserve(60*(ll+1));
562 #pragma omp parallel for private(buf)
563 	for(long i=0;i<l;i++)
564 	{
565 		const mglPrim &p=Prm[i];	mglRGBA cp;	cp.c = GetPrmCol(i,false);
566 		if(p.n1<0 || (p.type==1 && p.n2<0) || (p.type==2 && (p.n2<0 || p.n3<0)) || (p.type==3 && (p.n2<0 || p.n3<0 || p.n4<0)))
567 			continue;
568 		long n1=p.n1, n2=p.n2, n3=0, n4=(p.type==3||p.type==0)?p.n4:0;
569 		if(p.type==2 || p.type==3)	n3 = p.n3;
570 		if(p.type==4)
571 		{
572 			const mglPnt &q = Pnt[p.n1];
573 #pragma omp critical
574 			{n2 = xy.size();	xy.push_back(mglPoint(q.u,q.v,p.n2));}
575 			n3 = p.n3;	n4 = p.n4;
576 		}
577 		if(p.type==1 && n1>n2)	{	n1=p.n2;	n2=p.n1;	}
578 		long ps=p.s==p.s?long(100*factor*p.s):0, pw=p.w==p.w?long(100*p.w):0, pp=p.p==p.p?mgl_int(1e5*p.p):0;
579 		if(cp.r[3]==255 || p.type==0 || p.type==1 || p.type==4 || p.type==6)
580 			buf = mgl_sprintf("[%d,%ld,%ld,%ld,%ld,%d,%ld,%ld,%ld,0,\"#%02x%02x%02x\"],\n",
581 				p.type, n1, n2, n3, n4, p.id, ps,pw,pp, int(cp.r[0]),int(cp.r[1]),int(cp.r[2]));
582 		else if(cp.r[3])
583 			buf = mgl_sprintf("[%d,%ld,%ld,%ld,%ld,%d,%ld,%ld,%ld,0,\"rgba(%d,%d,%d,%.2g)\"],\n",
584 				p.type, n1, n2, n3, n4, p.id, ps,pw,pp, int(cp.r[0]),int(cp.r[1]),int(cp.r[2]),cp.r[3]/255.);
585 		else	buf = "";
586 #pragma omp critical
587 		res += buf;
588 	}
589 	res += "[-1,0,0,0,0,0,0,0,0,0,\"#000000\"]\n";	// need to add this empty block
590 
591 	l = (long)xy.size();
592 	res = res + mgl_sprintf("],\t\"ncoor\":%lu,\t\"coor\":[\n",(unsigned long)l);
593 	for(long i=0;i<l;i++)
594 	{
595 		const mglPoint &p=xy[i];
596 		const mglPnt &q=Pnt[int(0.5+p.z)];
597 		long px=long(100*p.x), py=long(100*p.y);
598 		if(q.u==q.u && q.v==q.v && q.w==q.w)
599 			res = res + mgl_sprintf("[%ld,%ld,%ld,%ld,%ld]%c\n", px, py, long(100*q.u), long(100*q.v), long(100*q.w), i+1<l?',':' ');
600 		else
601 			res = res + mgl_sprintf("[%ld,%ld,1e11,1e11,1e11]%c\n", px, py, i+1<l?',':' ');
602 	}
603 
604 	l = (long)Glf.size();
605 	res = res + mgl_sprintf("],\t\"nglfs\":%lu,\t\"glfs\":[\n",(unsigned long)l);
606 	for(long i=0;i<l;i++)
607 	{
608 		const mglGlyph &g=Glf[i];
609 		res = res + mgl_sprintf("[%ld,\n\t[", g.nl);
610 		for(long j=0;j<2*g.nl;j++)	res = res + mgl_sprintf("%d%c", g.line[j], j+1<2*g.nl?',':' ');
611 		res = res + mgl_sprintf("]\n]%c\n", i+1<l?',':' ');
612 	}
613 	res = res + mgl_sprintf("]\n}\n");
614 	setlocale(LC_NUMERIC, loc.c_str());
615 	return res;
616 }
617 //-----------------------------------------------------------------------------
mgl_write_json(HMGL gr,const char * fname,const char *)618 void MGL_EXPORT mgl_write_json(HMGL gr, const char *fname,const char *)
619 {	_Gr_->WriteJSON(fname);	}
mgl_write_json_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)620 void MGL_EXPORT mgl_write_json_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
621 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
622 	char *f=new char[n+1];	memcpy(f,descr,n);	f[n]=0;
623 	mgl_write_json(_GR_,s,f);	delete []s;		delete []f;	}
624 //-----------------------------------------------------------------------------
mgl_write_json_z(HMGL gr,const char * fname,const char *)625 void MGL_EXPORT mgl_write_json_z(HMGL gr, const char *fname,const char *)
626 {	_Gr_->WriteJSON(fname,true);	}
mgl_write_json_z_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)627 void MGL_EXPORT mgl_write_json_z_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
628 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
629 	char *f=new char[n+1];	memcpy(f,descr,n);	f[n]=0;
630 	mgl_write_json_z(_GR_,s,f);	delete []s;		delete []f;	}
631 //-----------------------------------------------------------------------------
ExportMGLD(const char * fname,const char * descr)632 bool mglCanvas::ExportMGLD(const char *fname, const char *descr)
633 {
634 	if(Pnt.size()<1 || Prm.size()<1)	return true;
635 	FILE *fp=fopen(fname,"wt");
636 	if(!fp)	return true;
637 	const std::string loc = setlocale(LC_NUMERIC, "C");
638 	// NOTE: I'll save Ptx. So prim type=6 is useless,and no LaTeX
639 	fprintf(fp,"MGLD %lu %lu %lu %lu %d %d\n# %s\n", (unsigned long)Pnt.size(), (unsigned long)Prm.size(), (unsigned long)Txt.size(), (unsigned long)Glf.size(), Width, Height, (descr && *descr) ? descr : fname);
640 	fprintf(fp,"# Vertexes: x y z c t ta u v w r g b a\n");
641 	for(size_t i=0;i<Pnt.size();i++)
642 	{
643 		const mglPnt &q=Pnt[i];
644 		fprintf(fp,"%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\t%.4g\n", q.xx, q.yy, q.zz, q.c, q.ta, q.ta, q.u, q.v, q.w, q.r, q.g, q.b, q.a);
645 	}
646 	fprintf(fp,"# Primitives: type n1 n2 n3 n4 id s w p\n");
647 	for(size_t i=0;i<Prm.size();i++)
648 	{
649 		const mglPrim &p=Prm[i];
650 		long long unsigned mask = p.m;
651 		fprintf(fp,"%d\t%ld\t%ld\t%ld\t%ld\t%d\t%g\t%g\t%g\t%d\t%llu\n", p.type, p.n1, p.n2, p.n3, p.n4, p.id, p.s==p.s?p.s:0, p.w==p.w?p.w:0, p.p==p.p?p.p:0, p.angl, mask);
652 	}
653 	fprintf(fp,"# Textures: smooth alpha colors\n");
654 	for(size_t i=0;i<Txt.size();i++)
655 	{
656 		const mglTexture &t=Txt[i];
657 		fprintf(fp,"%d\t%.4g\t%s\n",t.Smooth,t.Alpha,t.Sch);
658 	}
659 	fprintf(fp,"# Glyphs: nt nl [trig] [line]\n");
660 	for(size_t i=0;i<Glf.size();i++)
661 	{
662 		const mglGlyph &g=Glf[i];
663 		fprintf(fp,"%ld\t%ld\n", g.nt, g.nl);
664 		if(g.trig)
665 		{
666 			for(long j=0;j<6*g.nt;j++)	fprintf(fp,"%d\t",g.trig[j]);
667 			fprintf(fp,"\n");
668 		}
669 		if(g.line)
670 		{
671 			for(long j=0;j<2*g.nl;j++)	fprintf(fp,"%d\t",g.line[j]);
672 			fprintf(fp,"\n");
673 		}
674 	}
675 	fclose(fp);
676 	setlocale(LC_NUMERIC, loc.c_str());
677 	return false;
678 }
679 //-----------------------------------------------------------------------------
mgl_export_mgld(HMGL gr,const char * fname,const char * descr)680 void MGL_EXPORT mgl_export_mgld(HMGL gr, const char *fname,const char *descr)
681 {	_Gr_->ExportMGLD(fname, descr);	}
mgl_export_mgld_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)682 void MGL_EXPORT mgl_export_mgld_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
683 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
684 	char *f=new char[n+1];	memcpy(f,descr,n);	f[n]=0;
685 	mgl_export_mgld(_GR_,s,f);	delete []s;		delete []f;	}
686 //-----------------------------------------------------------------------------
ImportMGLD(const char * fname,bool add)687 bool mglCanvas::ImportMGLD(const char *fname, bool add)
688 {
689 	FILE *fp=fopen(fname,"rt");
690 	if(!fp)	return true;
691 	char *buf=new char[512];
692 	if(!fgets(buf,512,fp))	*buf=0;
693 	if(strncmp(buf,"MGLD",4))	{	delete []buf;	fclose(fp);	return true;	}
694 	unsigned long n=0,m=0,l=0,k=0, npnt=0, nglf=0;
695 	int w=0,h=0,d;
696 	sscanf(buf+5,"%lu%lu%lu%lu%d%d",&n,&m,&l,&k,&w,&h);
697 	if(w<=0 || h<=0)	{	w=Width;	h=Height;	}
698 	d = long(sqrt(double(w*h)));
699 	if(n==0 || m==0 || l==0)	{	delete []buf;	fclose(fp);	return true;	}
700 	const std::string loc = setlocale(LC_NUMERIC, "C");
701 	if(!add)	{	Clf();	Txt.clear();	}
702 	else	{	ClfZB();	npnt=Pnt.size();	nglf=Glf.size();	}
703 	LightScale(&B);
704 #if MGL_HAVE_PTHREAD
705 	pthread_mutex_lock(&mutexGlf);
706 	pthread_mutex_lock(&mutexPnt);
707 	pthread_mutex_lock(&mutexPrm);
708 	pthread_mutex_lock(&mutexTxt);
709 #endif
710 #pragma omp critical
711 	{
712 		Pnt.reserve(n);	Prm.reserve(m);	Txt.reserve(l);	Glf.reserve(k);
713 		mglPnt p;	float tmp;
714 		for(unsigned long i=0;i<n;i++)
715 		{
716 			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
717 			sscanf(buf,"%g%g%g%g%g%g%g%g%g%g%g%g%g", &p.xx, &p.yy, &p.zz, &p.c, &tmp, &p.ta, &p.u, &p.v, &p.w, &p.r, &p.g, &p.b, &p.a);
718 			// rescale to current image size
719 			p.xx *= Width/double(w);	p.yy *= Height/double(h);	p.zz *= Depth/double(d);
720 			Pnt.push_back(p);
721 		}
722 		mglPrim q;
723 		for(unsigned long i=0;i<m;i++)
724 		{
725 			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
726 			long long unsigned mask=MGL_SOLID_MASK;
727 			sscanf(buf,"%hd%ld%ld%ld%ld%d%g%g%g%hd%llu", &q.type, &q.n1, &q.n2, &q.n3, &q.n4, &q.id, &q.s, &q.w, &q.p, &q.angl, &mask);
728 			q.n1 = q.n1>=0?q.n1+npnt:-1;	q.n2 = q.n2>=0?q.n2+npnt:-1;
729 			switch(q.type)
730 			{
731 			case 3:	q.n4 = q.n4>=0?q.n4+npnt:-1;
732 			case 2:	q.n3 = q.n3>=0?q.n3+npnt:-1;	q.m = mask;	break;
733 			case 4:	q.s *= (Width<Height?Width:Height)/double(w<h?w:h);
734 					q.n4 = q.n4>=0?q.n4+nglf:-1;	break;
735 			}
736 			Prm.push_back(q);
737 		}
738 		mglTexture t;
739 		for(unsigned long i=0;i<l;i++)
740 		{
741 			int sm=0;	float a;
742 			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#');
743 			size_t j,k=0;
744 			for(j=0;buf[j];j++)
745 			{
746 				if(buf[j]<=' ' && k)	{	sm++;	k=0;	}
747 				if(buf[j]>' ')	k=1;
748 				if(sm==2 && k)	break;
749 			}
750 			sscanf(buf,"%d%g", &sm, &a);
751 			t.Set(buf+j, sm, a);
752 			Txt.push_back(t);
753 		}
754 		mglGlyph g;
755 		for(unsigned long i=0;i<k;i++)
756 		{
757 			do {	if(!fgets(buf,512,fp))	*buf=0;	mgl_strtrim(buf);	} while(*buf=='#' || *buf==0);
758 			long nt=0,nl=0;
759 			sscanf(buf,"%ld%ld", &nt, &nl);	g.Create(nt,nl);
760 			for(long j=0;j<6*nt;j++)	fscanf(fp,"%hd",g.trig+j);
761 			for(long j=0;j<2*nl;j++)	fscanf(fp,"%hd",g.line+j);
762 			Glf.push_back(g);
763 		}
764 	}
765 #if MGL_HAVE_PTHREAD
766 	pthread_mutex_unlock(&mutexGlf);
767 	pthread_mutex_unlock(&mutexPnt);
768 	pthread_mutex_unlock(&mutexPrm);
769 	pthread_mutex_unlock(&mutexTxt);
770 #endif
771 	setlocale(LC_NUMERIC, loc.c_str());
772 	delete []buf;	fclose(fp);	return false;
773 }
774 //-----------------------------------------------------------------------------
mgl_import_mgld(HMGL gr,const char * fname,int add)775 void MGL_EXPORT mgl_import_mgld(HMGL gr, const char *fname, int add)
776 {	_Gr_->ImportMGLD(fname, add);	}
mgl_import_mgld_(uintptr_t * gr,const char * fname,int * add,int l)777 void MGL_EXPORT mgl_import_mgld_(uintptr_t *gr, const char *fname, int *add, int l)
778 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
779 	mgl_import_mgld(_GR_,s,*add);	delete []s;	}
780 //-----------------------------------------------------------------------------
781 /*void MGL_EXPORT mgl_xgl_prim(const mglPrim &q, const mglPnt &p, FILE *fp, mreal size)
782 {
783 	char type = q.n4;	mreal ss=size*0.35;
784 	long i=q.n1;
785 	switch(q.type)
786 	{
787 	case 0:
788 		if(!strchr("xsSoO",type))	ss *= 1.1;
789 		if(type=='.' || ss==0)	fprintf(fp,"p %ld\n", i);
790 		else	switch(type)	// TODO: save mark by PATCH
791 		{
792 		case 'P':
793 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
794 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
795 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
796 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
797 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
798 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
799 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
800 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);
801 		case '+':
802 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
803 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
804 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
805 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
806 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
807 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);	break;
808 		case 'X':
809 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
810 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
811 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
812 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
813 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
814 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
815 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
816 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);
817 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);
818 			fprintf(fp,"l -2/%ld -4/%ld\n", i,i);	break;
819 		case 'x':
820 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
821 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
822 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
823 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
824 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);
825 			fprintf(fp,"l -2/%ld -4/%ld\n", i,i);	break;
826 		case 'S':
827 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
828 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
829 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
830 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
831 			fprintf(fp,"f -4/%ld -3/%ld -2/%ld -1/%ld\n",i,i,i,i);	break;
832 		case 's':
833 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss,p.z);
834 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss,p.z);
835 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss,p.z);
836 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss,p.z);
837 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
838 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
839 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
840 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);	break;
841 		case 'D':
842 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
843 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
844 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
845 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
846 			fprintf(fp,"f -4/%ld -3/%ld -2/%ld -1/%ld\n",i,i,i,i);	break;
847 		case 'd':
848 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
849 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
850 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
851 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
852 			fprintf(fp,"l -4/%ld -3/%ld\n", i,i);
853 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
854 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
855 			fprintf(fp,"l -1/%ld -4/%ld\n", i,i);	break;
856 		case 'Y':
857 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
858 			fprintf(fp,"v %g %g %g\n",p.x+0.8*ss,p.y+0.6*ss,p.z);
859 			fprintf(fp,"v %g %g %g\n",p.x-0.8*ss,p.y+0.6*ss,p.z);
860 			fprintf(fp,"l -3/%ld %ld/%ld\n", i,i,i);
861 			fprintf(fp,"l -2/%ld %ld/%ld\n", i,i,i);
862 			fprintf(fp,"l -1/%ld %ld/%ld\n", i,i,i);	break;
863 		case '*':
864 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
865 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
866 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
867 			fprintf(fp,"v %g %g %g\n",p.x+0.6*ss,p.y+0.8*ss,p.z);
868 			fprintf(fp,"v %g %g %g\n",p.x-0.6*ss,p.y-0.8*ss,p.z);
869 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
870 			fprintf(fp,"v %g %g %g\n",p.x+0.6*ss,p.y-0.8*ss,p.z);
871 			fprintf(fp,"v %g %g %g\n",p.x-0.6*ss,p.y+0.8*ss,p.z);
872 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);		break;
873 		case 'T':
874 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss/2,p.z);
875 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss/2,p.z);
876 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
877 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
878 		case '^':
879 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y-ss/2,p.z);
880 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y-ss/2,p.z);
881 			fprintf(fp,"v %g %g %g\n",p.x,p.y+ss,p.z);
882 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
883 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
884 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
885 		case 'V':
886 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss/2,p.z);
887 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss/2,p.z);
888 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
889 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
890 		case 'v':
891 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y+ss/2,p.z);
892 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y+ss/2,p.z);
893 			fprintf(fp,"v %g %g %g\n",p.x,p.y-ss,p.z);
894 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
895 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
896 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
897 		case 'L':
898 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y+ss,p.z);
899 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y-ss,p.z);
900 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
901 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
902 		case '<':
903 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y+ss,p.z);
904 			fprintf(fp,"v %g %g %g\n",p.x+ss/2,p.y-ss,p.z);
905 			fprintf(fp,"v %g %g %g\n",p.x-ss,p.y,p.z);
906 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
907 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
908 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
909 		case 'R':
910 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y+ss,p.z);
911 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y-ss,p.z);
912 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
913 			fprintf(fp,"f -3/%ld -2/%ld -1/%ld\n", i,i,i);	break;
914 		case '>':
915 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y+ss,p.z);
916 			fprintf(fp,"v %g %g %g\n",p.x-ss/2,p.y-ss,p.z);
917 			fprintf(fp,"v %g %g %g\n",p.x+ss,p.y,p.z);
918 			fprintf(fp,"l -3/%ld -2/%ld\n", i,i);
919 			fprintf(fp,"l -2/%ld -1/%ld\n", i,i);
920 			fprintf(fp,"l -1/%ld -3/%ld\n", i,i);	break;
921 		case 'O':
922 			for(long j=0;j<=20;j++)
923 				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
924 			for(long j=0;j<20;j++)
925 				fprintf(fp,"f %ld/%ld %ld/%ld %ld/%ld\n", j-21,i, j-20,i, i,i);
926 			break;
927 		case 'C':	fprintf(fp,"p %ld\n", i);
928 		case 'o':
929 			for(long j=0;j<=20;j++)
930 				fprintf(fp,"v %g %g %g\n",p.x+ss*mgl_cos[(j*36)%360],p.y+ss*mgl_cos[(270+j*36)%360],p.z);
931 			for(long j=0;j<20;j++)
932 				fprintf(fp,"l %ld/%ld %ld/%ld\n", j-21,i, j-20,i);
933 			break;
934 		}
935 		break;
936 	case 1:	fprintf(fp,"l %ld/%ld %ld/%ld\n", q.n1,q.n1, q.n2,q.n2);	break;
937 	case 2:	fprintf(fp,"f %ld/%ld/%ld %ld/%ld/%ld %ld/%ld/%ld\n",
938 		q.n1,q.n1,q.n1, q.n2,q.n2,q.n2, q.n3,q.n3,q.n3);	break;
939 	case 3:	fprintf(fp,"f %ld/%ld/%ld %ld/%ld/%ld %ld/%ld/%ld %ld/%ld/%ld\n",
940 		q.n1,q.n1,q.n1, q.n2,q.n2,q.n2, q.n3,q.n3,q.n3, q.n4,q.n4,q.n4);	break;
941 	case 4:	break;	// TODO: add glyphs export later
942 	}
943 }
944 //-----------------------------------------------------------------------------
945 void mglCanvas::WriteXGL(const char *fname,const char *descr)
946 {
947 	if(GetPrmNum()==0)	return;	// nothing to do
948 	FILE *fp=fopen(fname,"wt");
949 	if(!fp)	return true;
950 	fprintf(fp,"<WORLD>\n<NAME>%s</NAME>\n", (descr && *descr)?descr:fname);
951 	fprintf(fp,"<BACKGROUND><BACKCOLOR>%g, %g, %g</BACKCOLOR></BACKGROUND>\n", BDef[0]/255., BDef[1]/255., BDef[2]/255.);
952 	fprintf(fp,"<LIGHTING>\n<AMBIENT>%g, %g, %g</AMBIENT>\n",AmbBr, AmbBr, AmbBr);
953 	if(get(MGL_ENABLE_LIGHT))	for(size_t i=0;i<10;i++)
954 		if(light[i].n && mgl_isnan(light[i].r.x))
955 		{
956 			fprintf(fp, "<DIRECTIONALLIGHT>\n<DIRECTION>%g, %g, %g</DIRECTION>\n", light[i].d.x, light[i].d.y, light[i].d.z);
957 			fprintf(fp, "<SPECULAR>%g, %g, %g</SPECULAR>\n</DIRECTIONALLIGHT>\n", light[i].c.r, light[i].c.g, light[i].c.b);
958 		}
959 	fprintf(fp,"</LIGHTING>");
960 
961 	// TODO: add textures
962 
963 	long m1=0,m2=0,m;
964 	for(size_t i=0;i<Grp.size();i++)	// prepare array of indirect indexing
965 	{	m = Grp[i].Id;	if(m<m1) m1=m;	if(m>m2) m2=m;	}
966 	long *ng = new long[m2-m1+1];
967 	for(size_t i=0;i<Grp.size();i++)	ng[gr->Grp[i].Id-m1] = i;
968 	for(size_t i=0;i<GetPrmNum();i++)	// collect data for groups
969 	// it is rather expensive (extra 4b per primitive) but need for export to 3D
970 	{
971 		m = GetPrm(i,false).id-m1;
972 		if(m>=0 && m<m2-m1+1)	Grp[ng[m]].p.push_back(i);
973 	}
974 	delete []ng;
975 
976 	std::vector<long> p;
977 	mglPrim q;
978 	char *pg=new char[GetPntNum()];
979 	for(size_t i=0;i<Grp.size();i++)	// first write objects
980 	{
981 		p = Grp[i].p;	memset(pg,0,GetPntNum());
982 		fprintf(fp,"<OBJECT>\n<NAME>%s</NAME>\n<MESH>\n",Grp[i].Lbl.c_str());
983 		for(size_t j=0;j<p.size();j++)		// collect Pnt for this object
984 		{
985 			const mglPrim q=GetPrm(p[j],false);	pg[q.n1]=1;
986 			if(q.type==3)	{	pg[q.n2]=1;	pg[q.n3]=1;	pg[q.n4]=1;	}
987 			else if(q.type==1)	pg[q.n2]=1;
988 			else if(q.type==2)	{	pg[q.n2]=1;	pg[q.n3]=1;	}
989 		}
990 		for(size_t j=0;j<GetPntNum();j++)	if(pg[j])	// write Pnt for this object
991 		{
992 			const mglPnt s=Pnt[j];
993 			fprintf(fp,"<P ID=\"%u\">%g, %g, %g</P>\n",j, s.x, s.y, s.z);
994 			fprintf(fp,"<N ID=\"%u\">%g, %g, %g</N>\n",j, s.x, s.y, s.z);
995 		}
996 		// TODO: add line styles
997 		for(size_t j=0;j<p.size();j++)	// now write primitives itself
998 		{
999 			const mglPrim q=GetPrm(p[j],false);
1000 			mgl_xgl_prim(q, GetPnt(q.n1), fp, q.s*FontFactor());
1001 		}
1002 		fprintf(fp,"</MESH>\n</OBJECT>");	// finish with this object
1003 		Grp[i].p.clear();	// we don't need indexes anymore
1004 	}
1005 	// TODO: try to save "ungrouped" primitives
1006 
1007 	fprintf(fp,"</WORLD>");	fclose(fp);	delete []pg;
1008 }
1009 //-----------------------------------------------------------------------------
1010 void MGL_EXPORT mgl_write_xgl(HMGL gr, const char *fname,const char *descr)
1011 {	_Gr_->WriteXGL(fname,descr);	}
1012 void MGL_EXPORT mgl_write_xgl_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
1013 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
1014 	char *d=new char[n+1];	memcpy(d,descr,n);	d[n]=0;
1015 	mgl_write_xgl(_GR_,s,d);	delete []s;		delete []d;	}*/
1016 //-----------------------------------------------------------------------------
mgl_x3d_mdef(HMGL gr,void * fp,bool gz)1017 void MGL_EXPORT mgl_x3d_mdef(HMGL gr, void *fp, bool gz)
1018 {
1019 /*	bool m_p=false,m_x=false,m_d=false,m_v=false,m_t=false,
1020 	m_s=false,m_a=false,m_o=false,m_T=false,
1021 	m_V=false,m_S=false,m_D=false,m_Y=false,m_l=false,
1022 	m_L=false,m_r=false,m_R=false,m_X=false,m_P=false;
1023 	for(long i=0;i<gr->GetPrmNum();i++)
1024 	{
1025 		const mglPrim q = gr->GetPrm(i,false);
1026 		if(q.type>0)	continue;
1027 		if(q.n4=='+')	m_p = true;
1028 		if(q.n4=='x')	m_x = true;
1029 		if(q.n4=='s')	m_s = true;
1030 		if(q.n4=='d')	m_d = true;
1031 		if(q.n4=='v')	m_v = true;
1032 		if(q.n4=='^')	m_t = true;
1033 		if(q.n4=='*')	m_a = true;
1034 		if(q.n4=='o' || q.n4=='O' || q.n4=='C')	m_o = true;
1035 		if(q.n4=='S')	m_S = true;
1036 		if(q.n4=='D')	m_D = true;
1037 		if(q.n4=='V')	m_V = true;
1038 		if(q.n4=='T')	m_T = true;
1039 		if(q.n4=='<')	m_l = true;
1040 		if(q.n4=='L')	m_L = true;
1041 		if(q.n4=='>')	m_r = true;
1042 		if(q.n4=='R')	m_R = true;
1043 		if(q.n4=='Y')	m_Y = true;
1044 		if(q.n4=='P')	m_P = true;
1045 		if(q.n4=='X')	m_X = true;
1046 	}
1047 	if(m_P)	{	m_p=true;	m_s=true;	}
1048 	if(m_X)	{	m_x=true;	m_s=true;	}
1049 	if(m_p)	mgl_printf(fp, gz, "<ProtoDeclare name='m_p'><ProtoInterface/>\n<ProtoBody>"
1050 		"<LineSet vertexCount='0,1,2,3'>\n<Coordinate point='-1 0 0, 1 0 0, 0 -1 0, 0 1 0'/>"
1051 		"\n</LineSet></ProtoBody></ProtoDeclare>\n");*/
1052 	/*if(m_x)	mgl_printf(fp, gz, "/m_x {sm sm rm s2 s2 rl 0 sm 2 mul rm sm 2 mul s2 rl d0} def\n");	// TODO
1053 	 *	if(m_s)	mgl_printf(fp, gz, "/m_s {sm sm rm 0 s2 rl s2 0 rl 0 sm 2 mul rl cp d0} def\n");
1054 	 *	if(m_d)	mgl_printf(fp, gz, "/m_d {sm 0 rm ss ss rl ss sm rl sm sm rl cp d0} def\n");
1055 	 *	if(m_v)	mgl_printf(fp, gz, "/m_v {sm ss 2 div rm s2 0 rl sm sm 1.5 mul rl d0 cp} def\n");
1056 	 *	if(m_t)	mgl_printf(fp, gz, "/m_t {sm sm 2 div rm s2 0 rl sm ss 1.5 mul rl d0 cp} def\n");
1057 	 *	if(m_a)	mgl_printf(fp, gz, "/m_a {sm 0 rm s2 0 rl sm 1.6 mul sm 0.8 mul rm ss 1.2 mul ss 1.6 mul rl 0 sm 1.6 mul rm sm 1.2 mul ss 1.6 mul rl d0} def\n");
1058 	 *	if(m_o)	mgl_printf(fp, gz, "/m_o {ss 0 360 d0 arc} def\n");
1059 	 *	if(m_S)	mgl_printf(fp, gz, "/m_S {sm sm rm 0 s2 rl s2 0 rl 0 sm 2 mul rl cp} def\n");
1060 	 *	if(m_D)	mgl_printf(fp, gz, "/m_D {sm 0 rm ss ss rl ss sm rl sm sm rl cp} def\n");
1061 	 *	if(m_V)	mgl_printf(fp, gz, "/m_V {sm ss 2 div rm s2 0 rl sm sm 1.5 mul rl cp} def\n");
1062 	 *	if(m_T)	mgl_printf(fp, gz, "/m_T {sm sm 2 div rm s2 0 rl sm ss 1.5 mul rl cp} def\n");
1063 	 *	if(m_Y)	mgl_printf(fp, gz, "/m_Y {0 sm rm 0 ss rl sm ss rl s2 0 rm sm sm rl d0} def\n");
1064 	 *	if(m_r)	mgl_printf(fp, gz, "/m_r {sm 2 div sm rm 0 s2 rl ss 1.5 mul sm rl d0 cp} def\n");
1065 	 *	if(m_l)	mgl_printf(fp, gz, "/m_l {ss 2 div sm rm 0 s2 rl sm 1.5 mul sm rl d0 cp} def\n");
1066 	 *	if(m_R)	mgl_printf(fp, gz, "/m_R {sm 2 div sm rm 0 s2 rl ss 1.5 mul sm rl cp} def\n");
1067 	 *	if(m_L)	mgl_printf(fp, gz, "/m_L {ss 2 div sm rm 0 s2 rl sm 1.5 mul sm rl cp} def\n");
1068 	 *	if(m_P)	mgl_printf(fp, gz, "/m_P {m_p 0 sm rm m_s} def\n");
1069 	 *	if(m_X)	mgl_printf(fp, gz, "/m_X {m_x ss sm rm m_s} def\n");*/
1070 	//	if(m_C)	mgl_printf(fp, gz, "/m_C {m_c m_o} def\n");
1071 //	mgl_printf(fp, gz, "\n");
1072 }
1073 //-----------------------------------------------------------------------------
mgl_x3d_prim(const mglPrim & q,const mglPnt & p,const long * pnt,void * fp,bool gz,mreal size)1074 void MGL_EXPORT mgl_x3d_prim(const mglPrim &q, const mglPnt &p, const long *pnt, void *fp,bool gz, mreal size)
1075 {
1076 	// <ProtoInstance name='EmissiveMaterial'/>
1077 /*		if(q.type==0)	// mark
1078 		{
1079 			mreal x0 = p1.x,y0 = p1.y;
1080 			sprintf(str,"1 lw %.2g %.2g %.2g rgb ", cp.r,cp.g,cp.b);
1081 			wp=1;
1082 			if(q.s!=gr->mark_size()/gr->FontFactor())
1083 			{
1084 				mgl_printf(fp, gz, "/ss {%g} def\n",q.s*0.4*gr->FontFactor());
1085 				mgl_printf(fp, gz, "/s2 {%g} def\n",q.s*0.8*gr->FontFactor());
1086 				mgl_printf(fp, gz, "/sm {-%g} def\n",q.s*0.4*gr->FontFactor());
1087 			}
1088 			switch(q.n4)
1089 			{
1090 				case '+':	mgl_printf(fp, gz, "np %g %g mt m_p %sdr\n",x0,y0,str);	break;
1091 				case 'x':	mgl_printf(fp, gz, "np %g %g mt m_x %sdr\n",x0,y0,str);	break;
1092 				case 's':	mgl_printf(fp, gz, "np %g %g mt m_s %sdr\n",x0,y0,str);	break;
1093 				case 'd':	mgl_printf(fp, gz, "np %g %g mt m_d %sdr\n",x0,y0,str);	break;
1094 				case '*':	mgl_printf(fp, gz, "np %g %g mt m_a %sdr\n",x0,y0,str);	break;
1095 				case 'v':	mgl_printf(fp, gz, "np %g %g mt m_v %sdr\n",x0,y0,str);	break;
1096 				case '^':	mgl_printf(fp, gz, "np %g %g mt m_t %sdr\n",x0,y0,str);	break;
1097 				case 'S':	mgl_printf(fp, gz, "np %g %g mt m_S %sfill\n",x0,y0,str);	break;
1098 				case 'D':	mgl_printf(fp, gz, "np %g %g mt m_D %sfill\n",x0,y0,str);	break;
1099 				case 'V':	mgl_printf(fp, gz, "np %g %g mt m_V %sfill\n",x0,y0,str);	break;
1100 				case 'T':	mgl_printf(fp, gz, "np %g %g mt m_T %sfill\n",x0,y0,str);	break;
1101 				case 'o':	mgl_printf(fp, gz, "%g %g m_o %sdr\n",x0,y0,str);break;
1102 				case 'O':	mgl_printf(fp, gz, "%g %g m_o %sfill\n",x0,y0,str);break;
1103 				case 'Y':	mgl_printf(fp, gz, "np %g %g mt m_Y %sdr\n",x0,y0,str);	break;
1104 				case '<':	mgl_printf(fp, gz, "np %g %g mt m_l %sdr\n",x0,y0,str);	break;
1105 				case '>':	mgl_printf(fp, gz, "np %g %g mt m_r %sdr\n",x0,y0,str);	break;
1106 				case 'L':	mgl_printf(fp, gz, "np %g %g mt m_L %sfill\n",x0,y0,str);	break;
1107 				case 'R':	mgl_printf(fp, gz, "np %g %g mt m_R %sfill\n",x0,y0,str);	break;
1108 				case 'P':	mgl_printf(fp, gz, "np %g %g mt m_P %sdr\n",x0,y0,str);	break;
1109 				case 'X':	mgl_printf(fp, gz, "np %g %g mt m_X %sdr\n",x0,y0,str);	break;
1110 				case 'C':	mgl_printf(fp, gz, "%g %g m_o %g %g m_c %sdr\n",x0,y0,x0,y0,str);	break;
1111 				default:	mgl_printf(fp, gz, "%g %g m_c %sfill\n",x0,y0,str);
1112 			}
1113 			if(q.s!=gr->mark_size()/gr->FontFactor())
1114 			{
1115 				mgl_printf(fp, gz, "/ss {%g} def\n",0.4*gr->mark_size());
1116 				mgl_printf(fp, gz, "/s2 {%g} def\n",0.8*gr->mark_size());
1117 				mgl_printf(fp, gz, "/sm {-%g} def\n",0.4*gr->mark_size());
1118 			}
1119 		}
1120 		else if(q.type==3)	// quad
1121 		{
1122 			const mglPnt p2=gr->GetPnt(q.n2), p3=gr->GetPnt(q.n3), p4=gr->GetPnt(q.n4);
1123 			mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll %g %g ll cp %sfill\n",
1124 					   p1.x, p1.y, p2.x, p2.y, p4.x, p4.y, p3.x, p3.y, str);
1125 		}
1126 		else if(q.type==2)	// trig
1127 		{
1128 			const mglPnt p2=gr->GetPnt(q.n2), p3=gr->GetPnt(q.n3);
1129 			mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll cp %sfill\n",
1130 					   p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, str);
1131 		}
1132 		else if(q.type==1)	// line
1133 		{
1134 			sprintf(str,"%.2g lw %.2g %.2g %.2g rgb ", q.w>1 ? q.w:1., cp.r,cp.g,cp.b);
1135 			wp = q.w>1  ? q.w:1;	st = q.n3;
1136 			put_line(gr,fp,gz,i,wp,cp,st, "np %g %g mt ", "%g %g ll ", false, 1);
1137 			const char *sd = mgl_get_dash(q.n3,q.w);
1138 			if(sd && sd[0])	mgl_printf(fp, gz, "%s [%s] %g sd dr\n",str,sd,q.w*q.s);
1139 			else			mgl_printf(fp, gz, "%s d0 dr\n",str);
1140 		}
1141 		else if(q.type==4)	// glyph
1142 		{
1143 			mreal 	ss = q.s/2, xx = p1.u, yy = p1.v, zz = p1.w;
1144 			mgl_printf(fp, gz, "gsave\t%g %g translate %g %g scale %g rotate %s\n",
1145 					   p1.x, p1.y, ss, ss, -q.w, str);
1146 			if(q.n3&8)	// this is "line"
1147 			{
1148 				mreal dy = 0.004,f=fabs(zz);
1149 				mgl_printf(fp, gz, "np %g %g mt %g %g ll %g %g ll %g %g ll cp ",
1150 						   xx,yy+dy, xx+f,yy+dy, xx+f,yy-dy, xx,yy-dy);
1151 			}
1152 			else
1153 				mgl_printf(fp, gz, "%.3g %.3g translate %g %g scale %c%c_%04x ",
1154 						   xx, yy, zz, zz, q.n3&1?'b':'n', q.n3&2?'i':'n', q.n4);
1155 			if(q.n3&4)	mgl_printf(fp, gz, "dr");
1156 			else	mgl_printf(fp, gz, "eofill");
1157 			mgl_printf(fp, gz, " grestore\n");
1158 		}*/
1159 }
1160 //-----------------------------------------------------------------------------
mgl_write_x3d(HMGL gr,const char * fname,const char * descr)1161 void MGL_EXPORT mgl_write_x3d(HMGL gr, const char *fname,const char *descr)
1162 {
1163 	if(gr->GetPrmNum()<1)	return;
1164 	time_t now;	time(&now);
1165 
1166 	bool gz = fname[strlen(fname)-1]=='z';
1167 	void *fp = gz ? (void*)gzopen(fname,"wt") : (void*)fopen(fname,"wt");
1168 	if(!fp)		{	gr->SetWarn(mglWarnOpen,fname);	return;	}
1169 	const std::string loc = setlocale(LC_NUMERIC, "C");
1170 	mgl_printf(fp, gz, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1171 	mgl_printf(fp, gz, "<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n");
1172 	mgl_printf(fp, gz, "<X3D profile='Immersive'>\n<head>\n<meta name='filename' content='%s'/>\n",fname);
1173 	mgl_printf(fp, gz, "<meta name='description' content='%s'/>\n",(descr && *descr)?descr:fname);
1174 	mgl_printf(fp, gz, "<meta name='created' content='%s'/>\n",ctime(&now));
1175 	mgl_printf(fp, gz, "<meta name='generator' content='MathGL, http://mathgl.sourceforge.net/'/>\n");
1176 	mgl_printf(fp, gz, "</head>\n<Scene>\n");
1177 
1178 	// 1. first we have to define proto for marks and glyphs
1179 	mgl_x3d_mdef(gr, fp, gz);
1180 
1181 	// here should be defined textures ... but since X3D support RGBA then omit it in this version
1182 
1183 	// 2. now find group for primitives
1184 	long m1=0,m2=0,m;
1185 	for(size_t i=0;i<gr->Grp.size();i++)	// prepare array of indirect indexing
1186 	{	m = gr->Grp[i].Id;	if(m<m1) m1=m;	if(m>m2) m2=m;	}
1187 	long *ng = new long[m2-m1+1];
1188 	for(size_t i=0;i<gr->Grp.size();i++)	ng[gr->Grp[i].Id-m1] = i;
1189 	for(long i=0;i<gr->GetPrmNum();i++)	// collect data for groups
1190 	// it is rather expensive (extra 4b per primitive) but need for export to 3D
1191 	{
1192 		m = gr->GetPrm(i,false).id-m1;
1193 		if(m>=0 && m<m2-m1+1)	gr->Grp[ng[m]].p.push_back(i);
1194 	}
1195 	delete []ng;
1196 
1197 	// primitive definition in groups
1198 	long npnt = gr->GetPntNum();
1199 	long *pnt=new long[npnt];
1200 	mglPrim q;
1201 	for(size_t i=0;i<gr->Grp.size();i++)
1202 	{
1203 		mgl_printf(fp,gz,"<Group><!--%s-->\n",gr->Grp[i].Lbl.c_str());
1204 		std::vector<long> &p = gr->Grp[i].p;
1205 
1206 		// define coordinates, colors and so on
1207 		long line=-1, face=-1, other=-1;
1208 		for(size_t j=0;j<p.size();j++)	// find points for this group
1209 		{
1210 			const mglPrim &q=gr->GetPrm(p[j],false);
1211 			if(q.type==1)	line=q.n1;	// find kind of primitives in the group
1212 			if(q.type==2 || q.type==3)	face =q.n1;
1213 			if(q.type>3 || q.type==0)	other=q.n1;
1214 		}
1215 
1216 		// now save lines
1217 		if(line>=0)
1218 		{
1219 			mglColor c=gr->GetPntC(line);
1220 			bool same=true;	// check if there are the same colors for all line segments
1221 			for(size_t j=0;j<p.size();j++)
1222 			{
1223 				const mglPrim &q=gr->GetPrm(p[j],false);
1224 				if(q.type==1 && c!=gr->GetPntC(q.n1))	same=false;
1225 			}
1226 			memset(pnt,-1,npnt*sizeof(long));
1227 			for(size_t j=0,k=0;j<p.size();j++)	// rearrange points for this group
1228 			{
1229 				const mglPrim &q=gr->GetPrm(p[j],false);
1230 				if(q.type!=1)	continue;
1231 				if(q.n1>=0 && pnt[q.n1]<0)	{	pnt[q.n1]=k;	k++;	}
1232 				if(q.n2>=0 && pnt[q.n2]<0)	{	pnt[q.n2]=k;	k++;	}
1233 			}
1234 			mgl_printf(fp, gz, "<Shape><Coordinate DEF='Lpnts_%ld' point='",i);
1235 			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
1236 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.x,p.y,p.z);	}
1237 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
1238 			mgl_printf(fp, gz, "<Color DEF='Lclrs_%ld' color='",i);
1239 			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
1240 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.r,p.g,p.b);	}
1241 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
1242 
1243 			// TODO save IndexedLineSet here + manual color is same==true
1244 
1245 			mgl_printf(fp, gz, "</Shape>");
1246 		}
1247 
1248 		// now save faces
1249 		if(face>=0)
1250 		{
1251 			mglColor c=gr->GetPntC(face);
1252 			bool same=true;	// check if there are the same colors for all line segments
1253 			for(size_t j=0;j<p.size();j++)
1254 			{
1255 				const mglPrim &q=gr->GetPrm(p[j],false);
1256 				if((q.type==2 || q.type==3) && c!=gr->GetPntC(q.n1))	same=false;
1257 			}
1258 			memset(pnt,-1,npnt*sizeof(long));
1259 			for(size_t j=0,k=0;j<p.size();j++)	// rearrange points for this group
1260 			{
1261 				const mglPrim &q=gr->GetPrm(p[j],false);
1262 				if(q.type!=2 && q.type!=3)	continue;
1263 				if(q.n1>=0 && pnt[q.n1]<0)	{	pnt[q.n1]=k;	k++;	}
1264 				if(q.n2>=0 && pnt[q.n2]<0)	{	pnt[q.n2]=k;	k++;	}
1265 				if(q.n3>=0 && pnt[q.n3]<0)	{	pnt[q.n3]=k;	k++;	}
1266 				if(q.type==3 && q.n4>=0 && pnt[q.n4]<0)	{	pnt[q.n4]=k;	k++;	}
1267 			}
1268 			mgl_printf(fp, gz, "<Shape><Coordinate DEF='Fpnts_%ld' point='",i);
1269 			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
1270 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.x,p.y,p.z);	}
1271 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
1272 			mgl_printf(fp, gz, "<Color DEF='Fclrs_%ld' color='",i);
1273 			for(long j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
1274 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.r,p.g,p.b);	}
1275 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
1276 
1277 			// TODO save IndexedLineSet here + manual color is same==true
1278 
1279 			mgl_printf(fp, gz, "</Shape>");
1280 		}
1281 
1282 		// now save other primitives
1283 		if(other>=0)
1284 		{
1285 /*			memset(pnt,-1,npnt*sizeof(long));
1286 			for(j=0,k=0;j<p.size();j++)	// rearrange points for this group
1287 			{
1288 				const mglPrim &q=gr->GetPrm(p[j],false);
1289 				if(q.type!=2 && q.type!=3)	continue;
1290 				if(q.n1>=0 && pnt[q.n1]<0)	{	pnt[q.n1]=k;	k++;	}
1291 				if(q.n2>=0 && pnt[q.n2]<0)	{	pnt[q.n2]=k;	k++;	}
1292 				if(q.n3>=0 && pnt[q.n3]<0)	{	pnt[q.n3]=k;	k++;	}
1293 				if(q.type==3 && q.n4>=0 && pnt[q.n4]<0)	{	pnt[q.n4]=k;	k++;	}
1294 			}
1295 			mgl_printf(fp, gz, "<Shape><Coordinate DEF='Fpnts_%ld' point='",i);
1296 			for(j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
1297 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.x,p.y,p.z);	}
1298 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
1299 			mgl_printf(fp, gz, "<Color DEF='Fclrs_%ld' color='",i);
1300 			for(j=0;j<gr->GetPntNum();j++)	if(pnt[j]>=0)
1301 			{	const mglPnt &p=gr->GetPnt(j);	mgl_printf(fp, gz, "%g %g %g, ", p.r,p.g,p.b);	}
1302 			mgl_printf(fp, gz, "0.0 0.0 0.0'/>");
1303 
1304 			// TODO save IndexedLineSet here + manual color is same==true
1305 
1306 			mgl_printf(fp, gz, "</Shape>");*/
1307 		}
1308 		// no normals since mathgl ones are "signless" -- x3d should calculate it by itself
1309 
1310 		for(size_t j=0;j<p.size();j++)
1311 		{
1312 			const mglPrim &q=gr->GetPrm(p[j],false);	// TODO: collect by type (quads,trig,line) and draw together???
1313 			mgl_x3d_prim(q, gr->GetPnt(q.n1), pnt, fp,gz, q.s*gr->FontFactor());
1314 		}
1315 		mgl_printf(fp,gz,"</Group><!--%s-->\n",gr->Grp[i].Lbl.c_str());
1316 		gr->Grp[i].p.clear();	// we don't need indexes anymore
1317 	}
1318 	mgl_printf(fp, gz, "</Scene>\n");
1319 	if(gz)	gzclose((gzFile)fp);	else	fclose((FILE *)fp);
1320 	setlocale(LC_NUMERIC, loc.c_str());
1321 	delete []pnt;
1322 }
mgl_write_x3d_(uintptr_t * gr,const char * fname,const char * descr,int l,int n)1323 void MGL_EXPORT mgl_write_x3d_(uintptr_t *gr, const char *fname,const char *descr,int l,int n)
1324 {	char *s=new char[l+1];	memcpy(s,fname,l);	s[l]=0;
1325 char *d=new char[n+1];	memcpy(d,descr,n);	d[n]=0;
1326 mgl_write_x3d(_GR_,s,d);	delete []s;		delete []d;	}
1327 //-----------------------------------------------------------------------------
1328