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