1 /* 3dtext.c - converts generic 3D commands to 3D data
2    Copyright (C) 1996-2017 Paul Sheer
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307, USA.
18  */
19 
20 
21 /* 3dtext */
22 
23 #include <config.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include <my_string.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29 
30 #include <X11/Intrinsic.h>
31 #include <X11/Xresource.h>
32 
33 #include "app_glob.c"
34 #include "coolwidget.h"
35 #include "widget3d.h"
36 #include "quickmath.h"
37 #include "mad.h"
38 
39 /*
40 
41    this processes a text file into a 3d world
42    the text file contains the following commands separate
43    by zero or more newlines. Charaacters after a # at the
44    beginning of a line are ignored.
45 
46 
47    # x, y, z, a, b, h, w, and c are floats. (x,y,z) is a vector.
48 
49    scale a
50    # specifies the absolute value of the maximum extent of the scene in 3D space
51    # (after offset has been subtracted (see next)). This must come first.
52 
53    offset x y z
54    # specifies the a vector that is to be subtracted from the given position of
55    # forthcoming object. Must also come before any drawing commands.
56 
57    cylinder x y z a b c r
58    # draws a cylinder beginning at (a,b,c) ending at (a,b,c)+(x,y,z) of radius r
59 
60    cappedcylinder x y z a b c r
61    # draws a cylinder beginning at (a,b,c) ending at (a,b,c)+(x,y,z) of radius r
62    # with closed ends.
63 
64    surface a b x y z x y z x y z ... x y z
65    # draws a surface of grid size a by b there must be a*b (x, y, z) points.
66 
67    trapezium x y z a b c u v w p q r
68    # draws a trapezium with one corner at (x,y,z) and the other three at (x,y,z)+(a,b,c) etc.
69 
70    pipe r a x y z x y z x y z x y z ... x y z
71    # draw a pipe with corners at (x,y,z) the pipe diameter is r and the corner radii are a
72    * the first (x,y,z) is the start the last is the finish. Points mus be more than 2a appart
73 
74    cappedpipe  r a x y z x y z x y z x y z ... x y z
75    # same with closed ends
76 
77    rectangle a b c x y z
78    # rectangle with (height,width,depth) = (x,y,z), corner at (a,b,c)
79 
80    ellipse a b c x y z
81    # an ellipse with (height,width,depth) = (x,y,z), centre at (a,b,c)
82 
83    density a
84    # will set the density of the grid making up any of the specific surfaces above.
85    # can be called before each surface command.
86 
87  */
88 
89 /* globals: */
90 
91 int GridDensity = 6;
92 double DimensionScale = 1;
93 Vec DimensionOffset =
94 {0, 0, 0};
95 
assignTD(TD_Point * p,Vec v)96 static inline void assignTD (TD_Point * p, Vec v)
97 {
98     p->x = (double) (v.x + DimensionOffset.x) * DimensionScale;
99     p->y = (double) (v.y + DimensionOffset.y) * DimensionScale;
100     p->z = (double) (v.z + DimensionOffset.z) * DimensionScale;
101 }
102 
103 
104 
105 
third_cyl(double t,TD_Point * p,Vec A,Vec X,Vec r1,Vec r2,int g,double f)106 static void third_cyl (double t, TD_Point * p, Vec A, Vec X, Vec r1, Vec r2, int g, double f)
107 {
108     int i = 0;
109     double h;
110     double alpha = t;
111     Vec rv;
112     while (alpha < (2 * PI / 3 + t + 0.001)) {
113 	for (h = 0; h <= 1; h += 0.5) {
114 	    rv = plus (plus (plus (times (r1, cos (alpha) * (1 + h * (f - 1))), times (r2, sin (alpha) * (1 + h * (f - 1)))), A), times (X, h));
115 	    assignTD (&(p[i]), rv);
116 	    i++;
117 	}
118 	alpha += (2 * PI / 3) / g;
119     }
120 }
121 
122 
123 
CDraw3DCone(const char * ident,double x,double y,double z,double a,double b,double c,double ra,double rb)124 void CDraw3DCone (const char *ident, double x, double y, double z, double a, double b, double c, double ra, double rb)
125 {
126     int g = 4 * GridDensity / 3;
127     TD_Point *p = CMalloc ((g + 1) * 3 * sizeof (TD_Point));
128     Vec r1;
129     Vec r2;
130     Vec A, X;
131     double f = rb / ra;
132     A.x = a;
133     A.y = b;
134     A.z = c;
135     X.x = x;
136     X.y = y;
137     X.z = z;
138 
139     orth_vectors (X, &r1, &r2, ra);
140 
141     third_cyl (0, p, A, X, r1, r2, g, f);
142     CInitSurfacePoints (ident, 3, g + 1, p);
143     third_cyl (2 * PI / 3, p, A, X, r1, r2, g, f);
144     CInitSurfacePoints (ident, 3, g + 1, p);
145     third_cyl (4 * PI / 3, p, A, X, r1, r2, g, f);
146     CInitSurfacePoints (ident, 3, g + 1, p);
147 
148     free (p);
149 }
150 
151 
152 
153 
CDraw3DCylinder(const char * ident,double x,double y,double z,double a,double b,double c,double r)154 void CDraw3DCylinder (const char *ident, double x, double y, double z, double a, double b, double c, double r)
155 {
156     CDraw3DCone (ident, x, y, z, a, b, c, r, r);
157 }
158 
159 
160 
CDraw3DRoundPlate(const char * ident,double x,double y,double z,double a,double b,double c,double r)161 void CDraw3DRoundPlate (const char *ident, double x, double y, double z, double a, double b, double c, double r)
162 {
163     TD_Point *p = CMalloc ((GridDensity * 4 + 1) * 2 * sizeof (TD_Point));
164     double alpha = 0;
165     Vec r1;
166     Vec r2;
167     Vec rv;
168     Vec A;
169     Vec X;
170     int i = 0;
171     A.x = a;
172     A.y = b;
173     A.z = c;
174     X.x = x;
175     X.y = y;
176     X.z = z;
177 
178     orth_vectors (X, &r1, &r2, r);
179 
180     while (alpha < (2 * PI + 0.001)) {
181 	rv = plus (plus (times (r1, cos (alpha)), times (r2, sin (alpha))), A);
182 	assignTD (&p[i], rv);
183 	i++;
184 	assignTD (&p[i], A);
185 	i++;
186 	alpha += (2 * PI) / (GridDensity * 4);
187     }
188     CInitSurfacePoints (ident, 2, GridDensity * 4 + 1, p);
189     free (p);
190 }
191 
192 
CDraw3DCappedCylinder(const char * ident,double x,double y,double z,double a,double b,double c,double r)193 void CDraw3DCappedCylinder (const char *ident, double x, double y, double z, double a, double b, double c, double r)
194 {
195     CDraw3DCylinder (ident, x, y, z, a, b, c, r);
196     CDraw3DRoundPlate (ident, -x, -y, -z, a, b, c, r);
197     CDraw3DRoundPlate (ident, x, y, z, x + a, y + b, z + c, r);
198 }
199 
200 
textformaterror(int line,const char * ident)201 void textformaterror (int line, const char *ident)
202 {
203 /* "Compile our special discription language into an actual 3D world" */
204     CErrorDialog (0, 0, 0, _ (" Compile text to 3D "),
205 		  _ (" A text format error was encounted at line %d, \n while trying to draw 3d item to widget %s "), line, ident);
206 }
207 
208 
CDraw3DScale(const char * ident,double a)209 void CDraw3DScale (const char *ident, double a)
210 {
211     DimensionScale = 32767 / a;
212 }
213 
CDraw3DOffset(const char * ident,double x,double y,double z)214 void CDraw3DOffset (const char *ident, double x, double y, double z)
215 {
216     DimensionOffset.x = x;
217     DimensionOffset.y = y;
218     DimensionOffset.z = z;
219 }
220 
CDraw3DDensity(const char * ident,double a)221 void CDraw3DDensity (const char *ident, double a)
222 {
223     GridDensity = a;
224 }
225 
draw3d_surface(const char * ident,int w,int h,Vec * v)226 void draw3d_surface (const char *ident, int w, int h, Vec * v)
227 {
228     int i;
229     TD_Point *p = CMalloc ((w + 1) * (h + 1) * sizeof (TD_Point));
230     for (i = 0; i < w * h; i++)
231 	assignTD (&p[i], v[i]);
232     CInitSurfacePoints (ident, w, h, p);
233     free (p);
234 }
235 
236 
CDraw3DSurface(const char * ident,int w,int h,...)237 void CDraw3DSurface (const char *ident, int w, int h,...)
238 {
239     va_list pa;
240     int i;
241     TD_Point *p = CMalloc (w * h * sizeof (TD_Point));
242 
243     va_start (pa, h);
244     for (i = 0; i < w * h; i++) {
245 	p[i].x = va_arg (pa, double);
246 	p[i].y = va_arg (pa, double);
247 	p[i].z = va_arg (pa, double);
248 	p[i].dirx = 0;
249 	p[i].diry = 0;
250 	p[i].dirz = 0;
251     }
252     va_end (pa);
253     CInitSurfacePoints (ident, w, h, p);
254     free (p);
255 }
256 
257 
258 
259 
260 
fxchg(double * a,double * b)261 static void fxchg (double *a, double *b)
262 {
263     double t = *a;
264     *a = *b;
265     *b = t;
266 }
267 
268 
initellipsoidpart(TD_Point * p,double x,double y,double z,double a,double b,double c,int w,int dir,double f)269 void initellipsoidpart (TD_Point * p, double x, double y, double z,
270 		  double a, double b, double c, int w, int dir, double f)
271 {
272     int i, j;
273     Vec v;
274     double r;
275     int d = 2 * w + 1;
276     Vec X;
277     X.x = x;
278     X.y = y;
279     X.z = z;
280 
281 
282     for (i = -w; i <= w; i++)
283 	for (j = -w; j <= w; j++) {
284 	    v.x = (double) j / w;
285 	    v.y = (double) i / w;
286 	    v.z = 1;
287 
288 	    switch (dir) {
289 	    case 0:
290 		v.z = -v.z;
291 		fxchg (&v.x, &v.y);
292 		break;
293 	    case 1:
294 		v.y = -v.y;
295 		fxchg (&v.x, &v.z);
296 		break;
297 	    case 2:
298 		v.z = -v.z;
299 		fxchg (&v.x, &v.z);
300 		break;
301 	    case 3:
302 		v.y = -v.y;
303 		fxchg (&v.y, &v.z);
304 		break;
305 	    case 4:
306 		v.z = -v.z;
307 		fxchg (&v.y, &v.z);
308 		break;
309 	    }
310 
311 	    r = norm (v);
312 	    v.x *= (f + (1 - f) / r) * a;
313 	    v.y *= (f + (1 - f) / r) * b;
314 	    v.z *= (f + (1 - f) / r) * c;
315 
316 	    assignTD (&p[i + w + (j + w) * d], plus (v, X));
317 	}
318 }
319 
CDraw3DEllipsoid(const char * ident,double x,double y,double z,double a,double b,double c,double f)320 void CDraw3DEllipsoid (const char *ident, double x, double y, double z, double a, double b, double c, double f)
321 {
322     int w = GridDensity / 2;
323     int g = 2 * w + 1;
324     TD_Point *p = CMalloc (g * g * sizeof (TD_Point));
325 
326     initellipsoidpart (p, x, y, z, a, b, c, w, 0, f);
327     CInitSurfacePoints (ident, g, g, p);
328     initellipsoidpart (p, x, y, z, a, b, c, w, 1, f);
329     CInitSurfacePoints (ident, g, g, p);
330     initellipsoidpart (p, x, y, z, a, b, c, w, 2, f);
331     CInitSurfacePoints (ident, g, g, p);
332     initellipsoidpart (p, x, y, z, a, b, c, w, 3, f);
333     CInitSurfacePoints (ident, g, g, p);
334     initellipsoidpart (p, x, y, z, a, b, c, w, 4, f);
335     CInitSurfacePoints (ident, g, g, p);
336     initellipsoidpart (p, x, y, z, a, b, c, w, 5, f);
337     CInitSurfacePoints (ident, g, g, p);
338     free (p);
339 }
340 
CDraw3DCappedCone(const char * ident,double x,double y,double z,double a,double b,double c,double ra,double rb)341 void CDraw3DCappedCone (const char *ident, double x, double y, double z, double a, double b, double c, double ra, double rb)
342 {
343     CDraw3DCone (ident, x, y, z, a, b, c, ra, rb);
344     CDraw3DRoundPlate (ident, -x, -y, -z, a, b, c, ra);
345     CDraw3DRoundPlate (ident, x, y, z, x + a, y + b, z + c, rb);
346 }
347 
348 
CDraw3DRectangle(const char * ident,double x,double y,double z,double a,double b,double c)349 void CDraw3DRectangle (const char *ident, double x, double y, double z, double a, double b, double c)
350 {
351     CDraw3DEllipsoid (ident, x, y, z, a, b, c, 1);
352 }
353 
354 
CDraw3DSphere(const char * ident,double x,double y,double z,double r)355 void CDraw3DSphere (const char *ident, double x, double y, double z, double r)
356 {
357     CDraw3DEllipsoid (ident, x, y, z, r, r, r, 0);
358 }
359 
360 
361 /* returns -1 on error, zero on success */
CDraw3DFromText(const char * ident,const char * text)362 int CDraw3DFromText (const char *ident, const char *text)
363 {
364     char *p = (char *) text;
365     int line = 1;
366     double x, y, z, a, b, c, r, r2;
367     Vec *v;
368     int w, h, i, k;
369 
370     do {
371 	p += strspn (p, " \t\r");
372 	if (!*p)
373 	    break;
374 	if (*p == '#' || *p == '\n') {
375 	    /* comment, do nothing */ ;
376 	} else if (!strncmp (p, "scale ", 6)) {
377 	    if (sscanf (p, "scale %lf", &x) == 1)
378 		CDraw3DScale (ident, x);
379 	    else {
380 		textformaterror (line, ident);
381 		return -1;
382 	    }
383 	} else if (!strncmp (p, "offset ", 7)) {
384 	    if (sscanf (p, "offset %lf %lf %lf", &x, &y, &z) == 3)
385 		CDraw3DOffset (ident, x, y, z);
386 	    else {
387 		textformaterror (line, ident);
388 		return -1;
389 	    }
390 	} else if (!strncmp (p, "density ", 7)) {
391 	    if (sscanf (p, "density %lf", &x) == 1)
392 		CDraw3DDensity (ident, x);
393 	    else {
394 		textformaterror (line, ident);
395 		return -1;
396 	    }
397 	} else if (!strncmp (p, "cylinder ", 8)) {
398 	    if (sscanf (p, "cylinder %lf %lf %lf %lf %lf %lf %lf", &x, &y, &z, &a, &b, &c, &r) == 7)
399 		CDraw3DCylinder (ident, x, y, z, a, b, c, r);
400 	    else {
401 		textformaterror (line, ident);
402 		return -1;
403 	    }
404 	} else if (!strncmp (p, "roundplate ", 11)) {
405 	    if (sscanf (p, "roundplate %lf %lf %lf %lf %lf %lf %lf", &x, &y, &z, &a, &b, &c, &r) == 7) {
406 		CDraw3DRoundPlate (ident, x, y, z, a, b, c, r);
407 		CDraw3DRoundPlate (ident, -x, -y, -z, a, b, c, r);
408 	    } else {
409 		textformaterror (line, ident);
410 		return -1;
411 	    }
412 	} else if (!strncmp (p, "cone ", 5)) {
413 	    if (sscanf (p, "cone %lf %lf %lf %lf %lf %lf %lf %lf", &x, &y, &z, &a, &b, &c, &r, &r2) == 8)
414 		CDraw3DCone (ident, x, y, z, a, b, c, r, r2);
415 	    else {
416 		textformaterror (line, ident);
417 		return -1;
418 	    }
419 	} else if (!strncmp (p, "cappedcone ", 11)) {
420 	    if (sscanf (p, "cappedcone %lf %lf %lf %lf %lf %lf %lf %lf", &x, &y, &z, &a, &b, &c, &r, &r2) == 8)
421 		CDraw3DCappedCone (ident, x, y, z, a, b, c, r, r2);
422 	    else {
423 		textformaterror (line, ident);
424 		return -1;
425 	    }
426 	} else if (!strncmp (p, "cappedcylinder ", 15)) {
427 	    if (sscanf (p, "cappedcylinder %lf %lf %lf %lf %lf %lf %lf", &x, &y, &z, &a, &b, &c, &r) == 7) {
428 		CDraw3DCappedCylinder (ident, x, y, z, a, b, c, r);
429 	    } else {
430 		textformaterror (line, ident);
431 		return -1;
432 	    }
433 	} else if (!strncmp (p, "ellipsoid ", 10)) {
434 	    if (sscanf (p, "ellipsoid %lf %lf %lf %lf %lf %lf %lf", &x, &y, &z, &a, &b, &c, &r) == 7) {
435 		CDraw3DEllipsoid (ident, x, y, z, a, b, c, r);
436 	    } else {
437 		textformaterror (line, ident);
438 		return -1;
439 	    }
440 	} else if (!strncmp (p, "rectangle ", 10)) {
441 	    if (sscanf (p, "rectangle %lf %lf %lf %lf %lf %lf", &x, &y, &z, &a, &b, &c) == 6) {
442 		CDraw3DRectangle (ident, x, y, z, a, b, c);
443 	    } else {
444 		textformaterror (line, ident);
445 		return -1;
446 	    }
447 	} else if (!strncmp (p, "sphere ", 7)) {
448 	    if (sscanf (p, "sphere %lf %lf %lf %lf ", &x, &y, &z, &r) == 4) {
449 		CDraw3DSphere (ident, x, y, z, r);
450 	    } else {
451 		textformaterror (line, ident);
452 		return -1;
453 	    }
454 	} else if (!strncmp (p, "surface ", 8)) {
455 	    if (sscanf (p, "surface %d %d %n", &w, &h, &i) == 2) {
456 		v = CMalloc (w * h * sizeof (Vec));
457 		for (k = 0; k < w * h; k++) {
458 		    p += i;
459 		    if (sscanf (p, "%lf %lf %lf %n", &(v[k].x), &(v[k].y), &(v[k].z), &i) != 3) {
460 			textformaterror (line, ident);
461 			free (v);
462 			return -1;
463 		    }
464 		}
465 		draw3d_surface (ident, w, h, v);
466 		free (v);
467 	    } else {
468 		textformaterror (line, ident);
469 		return -1;
470 	    }
471 	} else {
472 	    textformaterror (line, ident);
473 	    return -1;
474 	}
475 
476 	while (*p != '\n' && *p)
477 	    p++;
478 	line++;
479     } while (*(p++));
480 
481     CRedraw3DObject (ident, 1);
482     return 0;
483 }
484 
485 
486