1
2 /*
3 * Ump - Unnamed Math Program
4 * Copyright (c) 2005-2006 by Mattias Hultgren <mattias_hultgren@tele2.se>
5 *
6 * See main.cpp
7 */
8
9 /*
10 This is based on $XFree86: xc/programs/glxgears/glxgears.c,v 1.3tsi Exp $
11 */
12
13 #ifdef PLOT_3D
14
15 #include <math.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <signal.h>
20 #include <unistd.h>
21
22 #include "ump_3d_viewer.h"
23 #include "main.h"
24 #include "vector.h"
25 #include "utf8_string.h"
26 #include "keyfile.h"
27
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/keysym.h>
31 #include <GL/gl.h>
32 #include <GL/glx.h>
33 #include <GL/glu.h>
34 #undef Complex
35
36
37 void addon_3d_clear(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
38 throw(error_obj);
39 void addon_3d_render(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
40 throw(error_obj);
41 void addon_3d_set_prop(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
42 throw(error_obj);
43 void addon_3d_get_prop(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
44 throw(error_obj);
45 void addon_3d_add_plane(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
46 throw(error_obj);
47
48 struct _3d_vertex
49 {
50 float x,y,z;
51 };
52
53 struct _3d_point
54 {
55 float x,y,z;
56 picture_h::colorrgb color;
57 bool isValid;
58 };
59
60 enum _3d_plane_type { _3d_plane_wireframed, _3d_plane_solid, _3d_plane_semi_solid };
61 class _3d_plane
62 {
63 public:
64 uint32 width, height;
65 _3d_point *points;
66 _3d_plane_type type;
67 GLint draw_list;
68
_3d_plane()69 _3d_plane() { width = 0; height = 0; points = 0; type = _3d_plane_solid; }
_3d_plane(const _3d_plane & src)70 _3d_plane( const _3d_plane &src ) throw(error_obj) { width=0; height=0; points=0; type=_3d_plane_solid; *this=src; }
~_3d_plane()71 ~_3d_plane() { clear(); }
operator =(const _3d_plane & src)72 void operator=(const _3d_plane &src) throw(error_obj)
73 {
74 set_size( src.width, src.height );
75 for( uint32 i=0; i<width*height; i++ )
76 points[i] = src.points[i];
77 type = src.type;
78 }
clear(void)79 void clear(void) { delete [] points; width = 0; height = 0; points = 0; }
set_size(int new_width,int new_height)80 void set_size(int new_width, int new_height) throw(error_obj)
81 {
82 clear();
83
84 if( new_width <= 0 || new_height <= 0 )
85 return;
86
87 try{ points = new _3d_point[new_width*new_height]; }
88 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
89 width = new_width;
90 height = new_height;
91 }
92 };
93
94
95 struct _3d_Properties
96 {
97 int width, height;
98 _3d_vertex look_at;
99 float camera_dist, camera_angle1, camera_angle2;
100 picture_h::colorrgb bg_color;
101 bool only_one_viewer;
102
103
104 Vector<_3d_plane> planes;
105 }_3d_prop;
106
107
render_plane(const _3d_plane * plane)108 void render_plane( const _3d_plane *plane )
109 {
110 bool prev_line_full, line_full;
111
112 if( plane->type == _3d_plane_solid )
113 glPolygonMode( GL_BACK, GL_FILL );
114 else
115 glPolygonMode( GL_BACK, GL_LINE );
116
117 if( plane->type == _3d_plane_wireframed )
118 glPolygonMode( GL_FRONT, GL_LINE );
119 else
120 glPolygonMode( GL_FRONT, GL_FILL );
121
122 line_full = true;
123 for( uint32 x=0; x<plane->width; x++ )
124 line_full &= plane->points[x].isValid;
125
126 for( uint32 y=0; y<(plane->height-1); y++ )
127 {
128 prev_line_full = line_full;
129
130 line_full = true;
131 for( uint32 x=0,tmp=(y+1)*plane->width; x<plane->width; x++ )
132 line_full &= plane->points[x + tmp].isValid;
133
134 if( prev_line_full && line_full )
135 {
136 glBegin( GL_QUAD_STRIP );
137 for( uint32 x=0; x<plane->width; x++ )
138 {
139 glColor3f( plane->points[x + (y+1)*plane->width].color.red/255.0f,
140 plane->points[x + (y+1)*plane->width].color.green/255.0f,
141 plane->points[x + (y+1)*plane->width].color.blue/255.0f );
142 glVertex3f( plane->points[x + (y+1)*plane->width].x,
143 plane->points[x + (y+1)*plane->width].y,
144 plane->points[x + (y+1)*plane->width].z );
145 glColor3f( plane->points[x + y*plane->width].color.red/255.0f,
146 plane->points[x + y*plane->width].color.green/255.0f,
147 plane->points[x + y*plane->width].color.blue/255.0f );
148 glVertex3f( plane->points[x + y*plane->width].x,
149 plane->points[x + y*plane->width].y,
150 plane->points[x + y*plane->width].z );
151 }
152 glEnd();
153 }
154 else
155 {
156 glBegin( GL_QUADS );
157 for( uint32 x=0; x<(plane->width-1); x++ )
158 {
159 if( plane->points[x + y*plane->width].isValid &&
160 plane->points[x+1 + y*plane->width].isValid &&
161 plane->points[x+1 + (y+1)*plane->width].isValid &&
162 plane->points[x + (y+1)*plane->width].isValid )
163 {
164 glColor3f( plane->points[x + y*plane->width].color.red/255.0f,
165 plane->points[x + y*plane->width].color.green/255.0f,
166 plane->points[x + y*plane->width].color.blue/255.0f );
167 glVertex3f( plane->points[x + y*plane->width].x,
168 plane->points[x + y*plane->width].y,
169 plane->points[x + y*plane->width].z );
170 glColor3f( plane->points[x+1 + y*plane->width].color.red/255.0f,
171 plane->points[x+1 + y*plane->width].color.green/255.0f,
172 plane->points[x+1 + y*plane->width].color.blue/255.0f );
173 glVertex3f( plane->points[x+1 + y*plane->width].x,
174 plane->points[x+1 + y*plane->width].y,
175 plane->points[x+1 + y*plane->width].z );
176 glColor3f( plane->points[x+1 + (y+1)*plane->width].color.red/255.0f,
177 plane->points[x+1 + (y+1)*plane->width].color.green/255.0f,
178 plane->points[x+1 + (y+1)*plane->width].color.blue/255.0f );
179 glVertex3f( plane->points[x+1 + (y+1)*plane->width].x,
180 plane->points[x+1 + (y+1)*plane->width].y,
181 plane->points[x+1 + (y+1)*plane->width].z );
182 glColor3f( plane->points[x + (y+1)*plane->width].color.red/255.0f,
183 plane->points[x + (y+1)*plane->width].color.green/255.0f,
184 plane->points[x + (y+1)*plane->width].color.blue/255.0f );
185 glVertex3f( plane->points[x + (y+1)*plane->width].x,
186 plane->points[x + (y+1)*plane->width].y,
187 plane->points[x + (y+1)*plane->width].z );
188 }
189 }
190 glEnd();
191 }
192 }
193 }
194
render_scene(const _3d_Properties & render_prop)195 void render_scene( const _3d_Properties &render_prop )
196 {
197 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
198
199 glPushMatrix();
200
201 for( int i=0; i<render_prop.planes.get_size(); i++ )
202 {
203 // draw the plane from list if it's avaliable
204 if( render_prop.planes[i]->draw_list != 0 )
205 glCallList( render_prop.planes[i]->draw_list );
206 else
207 render_plane( render_prop.planes[i] );
208 }
209
210 glPopMatrix();
211 glFlush();
212 }
213
make_window(const _3d_Properties & render_prop,Display * dpy,Window * winRet,GLXContext * ctxRet)214 void make_window( const _3d_Properties &render_prop, Display *dpy, Window *winRet,
215 GLXContext *ctxRet) throw(error_obj)
216 {
217 int attrib[] = { GLX_RGBA,
218 GLX_RED_SIZE, 1,
219 GLX_GREEN_SIZE, 1,
220 GLX_BLUE_SIZE, 1,
221 GLX_DOUBLEBUFFER,
222 GLX_DEPTH_SIZE, 1,
223 None };
224 int scrnum;
225 XSetWindowAttributes attr;
226 unsigned long mask;
227 Window root;
228 Window win;
229 GLXContext ctx;
230 XVisualInfo *visinfo;
231 GLint max[2] = { 0, 0 };
232
233 scrnum = XScreenNumberOfScreen( XDefaultScreenOfDisplay(dpy) );
234 root = XRootWindow(dpy, scrnum);
235
236 visinfo = glXChooseVisual( dpy, scrnum, attrib );
237 if( !visinfo )
238 THROW_ERROR( ErrorType_General, _("Couldn't get a RGB, Double-buffered visual.") );
239
240 // window attributes
241 attr.background_pixel = 0;
242 attr.border_pixel = 0;
243 attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone );
244 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
245 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
246
247 win = XCreateWindow( dpy, root, 0, 0, render_prop.width, render_prop.height,
248 0, visinfo->depth, InputOutput,
249 visinfo->visual, mask, &attr );
250
251 // set hints and properties
252 {
253 XSizeHints sizehints;
254 sizehints.width = render_prop.width;
255 sizehints.height = render_prop.height;
256 sizehints.flags = USSize;
257 XSetNormalHints( dpy, win, &sizehints );
258 XSetStandardProperties( dpy, win, PRG_NAME, PRG_NAME, None, (char **)NULL, 0, &sizehints);
259 }
260
261 ctx = glXCreateContext( dpy, visinfo, NULL, True );
262 if( !ctx )
263 THROW_ERROR( ErrorType_General, _("glXCreateContext failed") );
264
265 XFree(visinfo);
266
267 XMapWindow(dpy, win);
268 glXMakeCurrent(dpy, win, ctx);
269
270 // Check for maximum size supported by the GL rasterizer
271 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max);
272 if( render_prop.width > max[0] || render_prop.height > max[1] )
273 THROW_ERROR( ErrorType_General, _("Requested window size is larger than maximum supported by GL engine.") );
274
275 *winRet = win;
276 *ctxRet = ctx;
277 }
278
update_camera(const _3d_Properties & render_prop)279 void update_camera( const _3d_Properties &render_prop )
280 {
281 glLoadIdentity();
282
283 gluLookAt( render_prop.camera_dist + render_prop.look_at.x, render_prop.look_at.y, render_prop.look_at.z,
284 render_prop.look_at.x, render_prop.look_at.y, render_prop.look_at.z,
285 0.0f, 1.0f, 0.0f );
286
287 glTranslatef( render_prop.look_at.x, render_prop.look_at.y, render_prop.look_at.z );
288 glRotatef( render_prop.camera_angle1, 0.0, 1.0, 0.0);
289 glRotatef( render_prop.camera_angle2, 1.0, 0.0, 0.0);
290 glTranslatef( -render_prop.look_at.x, -render_prop.look_at.y, -render_prop.look_at.z );
291 }
292
size_changed(const _3d_Properties & render_prop,int w,int h)293 void size_changed( const _3d_Properties &render_prop, int w, int h )
294 {
295 if(h == 0)
296 h = 1;
297
298 float ratio = float(w) / float(h);
299
300 // Reset the coordinate system before modifying
301 glMatrixMode(GL_PROJECTION);
302 glLoadIdentity();
303
304 // Set the viewport to be the entire window
305 glViewport(0, 0, w, h);
306
307 // Set the correct perspective.
308 gluPerspective( 45, ratio, 1, 1000 );
309 glMatrixMode(GL_MODELVIEW);
310
311 update_camera( render_prop );
312 }
313
event_loop(_3d_Properties & render_prop,Display * dpy,Window win)314 void event_loop( _3d_Properties &render_prop, Display *dpy, Window win )
315 {
316 XEvent event;
317 char buffer[10];
318 int code;
319
320 while(true)
321 {
322 XNextEvent( dpy, &event );
323 switch( event.type )
324 {
325 case Expose:
326 render_scene( render_prop );
327 glXSwapBuffers( dpy, win );
328 break;
329 case ConfigureNotify:
330 size_changed( render_prop, event.xconfigure.width, event.xconfigure.height );
331 break;
332 case KeyPress:
333 code = XLookupKeysym(&event.xkey, 0);
334 if( code == XK_Left )
335 {
336 render_prop.camera_angle1 += 5.0f;
337 if( render_prop.camera_angle1 >= 360.0f )
338 render_prop.camera_angle1 -= 360.0f;
339 update_camera( render_prop );
340 render_scene( render_prop );
341 glXSwapBuffers( dpy, win );
342 }
343 else if( code == XK_Right )
344 {
345 render_prop.camera_angle1 -= 5.0f;
346 if( render_prop.camera_angle1 <= 0.0f )
347 render_prop.camera_angle1 += 360.0f;
348 update_camera( render_prop );
349 render_scene( render_prop );
350 glXSwapBuffers( dpy, win );
351 }
352 else if( code == XK_Page_Up )
353 {
354 render_prop.camera_dist *= 0.95f;
355 update_camera( render_prop );
356 render_scene( render_prop );
357 glXSwapBuffers( dpy, win );
358 }
359 else if( code == XK_Page_Down )
360 {
361 render_prop.camera_dist *= 1.05f;
362 update_camera( render_prop );
363 render_scene( render_prop );
364 glXSwapBuffers( dpy, win );
365 }
366 else if( code == XK_Down )
367 {
368 render_prop.camera_angle2 += 5.0f;
369 if( render_prop.camera_angle2 >= 360.0f )
370 render_prop.camera_angle2 -= 360.0f;
371 update_camera( render_prop );
372 render_scene( render_prop );
373 glXSwapBuffers( dpy, win );
374 }
375 else if( code == XK_Up )
376 {
377 render_prop.camera_angle2 -= 5.0f;
378 if( render_prop.camera_angle2 <= 0.0f )
379 render_prop.camera_angle2 += 360.0f;
380 update_camera( render_prop );
381 render_scene( render_prop );
382 glXSwapBuffers( dpy, win );
383 }
384 else if( code == XK_Escape )
385 return;
386 else
387 {
388 XLookupString( &event.xkey, buffer, sizeof(buffer), NULL, NULL );
389 switch( buffer[0] )
390 {
391 case 'Q': case 'q': case 'X': case 'x':
392 return;
393 }
394 }
395 break;
396 }
397 }
398 }
399
_3d_viewer_child(_3d_Properties render_prop)400 void _3d_viewer_child( _3d_Properties render_prop )
401 {
402 try
403 {
404 Display *disp;
405 Window win;
406 GLXContext glx_cont;
407
408 //setup a glx-window
409 disp = XOpenDisplay(NULL);
410 if( !disp )
411 THROW_ERROR( ErrorType_General, _("Couldn't open display") );
412
413 make_window( render_prop, disp, &win, &glx_cont );
414 size_changed( render_prop, render_prop.width, render_prop.height );
415
416 glClearColor( render_prop.bg_color.red/255.0f, render_prop.bg_color.green/255.0f,
417 render_prop.bg_color.blue/255.0f, 1.0f );
418 glClearDepth( 1.0f );
419 glDepthFunc( GL_LESS );
420 glEnable( GL_DEPTH_TEST );
421 glShadeModel( GL_SMOOTH );
422
423
424
425 // creating draw lists
426 for( int i=0; i<render_prop.planes.get_size(); i++ )
427 {
428 if( (render_prop.planes[i]->draw_list = glGenLists(1)) != 0 )
429 {
430 glNewList( render_prop.planes[i]->draw_list, GL_COMPILE );
431 render_plane( render_prop.planes[i] );
432 glEndList();
433 }
434 }
435
436 // enter viewing/interaction mode
437 event_loop( render_prop, disp, win );
438
439 // cleaning up
440 glXDestroyContext( disp, glx_cont );
441 XDestroyWindow( disp, win );
442 XCloseDisplay( disp );
443 }
444 catch( error_obj error )
445 {
446 printf("Error: _3d_viewer: %s\n", error.msg );
447 }
448 exit(0); // terminating the child process
449 }
450
_3d_viewer_init(void)451 void _3d_viewer_init(void) throw(error_obj)
452 {
453 math::add_function( "_3d_clear", addon_3d_clear, false, false );
454 math::add_function( "_3d_render", addon_3d_render, false, false );
455 math::add_function( "_3d_set_prop", addon_3d_set_prop, false, true );
456 math::add_function( "_3d_get_prop", addon_3d_get_prop, false, true );
457 math::add_function( "_3d_add_plane", addon_3d_add_plane, false, true );
458
459 _3d_prop.width = 400;
460 _3d_prop.height = 400;
461 _3d_prop.look_at.x = 0.0f;
462 _3d_prop.look_at.y = 0.0f;
463 _3d_prop.look_at.z = -0.0f;
464
465 _3d_prop.camera_dist = 10.0f;
466 _3d_prop.camera_angle1 = 0.0f;
467 _3d_prop.camera_angle2 = 0.0f;
468
469 _3d_prop.bg_color.red = 255;
470 _3d_prop.bg_color.green = 255;
471 _3d_prop.bg_color.blue = 255;
472
473 _3d_prop.only_one_viewer = true;
474 }
475
476
477
478
479
480
481
482
483
484
485 ///////////////////////////////////////
486 // Here comes the 3d addon functions //
487 ///////////////////////////////////////
488
addon_3d_clear(math::Variable * res,math::Variable * left,const math::Variable * right,math::VariableList * private_varlist)489 void addon_3d_clear(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
490 throw(error_obj)
491 {
492 if( left != 0 || right != 0 )
493 THROW_ERROR( ErrorType_General, "Internal error: _3d_clear wasn't called the right way" );
494
495 _3d_prop.planes.clear();
496
497 if( res != 0 )
498 res->set_void();
499 }
500
501 Vector<pid_t> pid_list;
502
addon_3d_render(math::Variable * res,math::Variable * left,const math::Variable * right,math::VariableList * private_varlist)503 void addon_3d_render(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
504 throw(error_obj)
505 {
506 pid_t child_pid;
507 if( left != 0 || right != 0 )
508 THROW_ERROR( ErrorType_General, "Internal error: _3d_render wasn't called the right way" );
509
510 if( _3d_prop.only_one_viewer )
511 {
512 // terminate all old viewers
513 for( int i=0; i<pid_list.get_size(); i++ )
514 kill( *pid_list[i], 15 );
515 }
516
517 // this loops throu all old child and removes the zombies...
518 for( int i=0; i<pid_list.get_size(); i++ )
519 {
520 if( waitpid( *pid_list[i], 0, WNOHANG ) != 0 )
521 {
522 pid_list.remove( i );
523 i--;
524 }
525 }
526
527 switch( child_pid = fork() )
528 {
529 case -1:
530 (*TEXTVIEW_FUNCTION)("\nfork failed\n");
531 break;
532 case 0:
533 _3d_viewer_child( _3d_prop );
534 break;
535 default:
536 pid_list.append( child_pid );
537 break;
538 }
539
540 if( res != 0 )
541 res->set_void();
542 }
addon_3d_set_prop(math::Variable * res,math::Variable * left,const math::Variable * right,math::VariableList * private_varlist)543 void addon_3d_set_prop(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
544 throw(error_obj)
545 {
546 Matrix matr;
547 Complex tmp;
548 const math::Array *array;
549 const utf8_string *str;
550
551 if( left != 0 || right == 0 )
552 THROW_ERROR( ErrorType_General, "Internal error: _3d_set_prop wasn't called the right way" );
553
554 if( right->get_type() != math::VariableType_Array )
555 {
556 char tmp_err[ERROR_OBJ_MSG_LEN];
557 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "_3d_set_prop" );
558 THROW_ERROR( ErrorType_General, tmp_err );
559 }
560
561 array = right->get_array();
562
563 for( uint32 i=0; i<array->get_size(); i++ )
564 {
565 if( array->get_variable(i)->get_type() != math::VariableType_String )
566 {
567 char tmp_err[ERROR_OBJ_MSG_LEN];
568 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "_3d_set_prop" );
569 THROW_ERROR( ErrorType_General, tmp_err );
570 }
571
572 str = array->get_variable(i)->get_string();
573
574 if( *str == "Width" )
575 {
576 Integer w;
577
578 if( array->get_variable(i+1)->get_type() != math::VariableType_Complex )
579 {
580 char tmp_err[ERROR_OBJ_MSG_LEN];
581 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "_3d_set_prop" );
582 THROW_ERROR( ErrorType_General, tmp_err );
583 }
584 tmp = *( array->get_variable(i+1)->get_complex() );
585
586 if( tmp.imaginary != Real(0.0) || !tmp.real.isInteger() )
587 THROW_ERROR( ErrorType_General, _("_3d_set_prop: 'Width' must be an integer.") );
588
589 tmp.real.get_top( &w );
590
591 _3d_prop.width = int( int64(w) );
592
593 i++;
594 }
595 else if( *str == "Height" )
596 {
597 Integer h;
598
599 if( array->get_variable(i+1)->get_type() != math::VariableType_Complex )
600 {
601 char tmp_err[ERROR_OBJ_MSG_LEN];
602 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "_3d_set_prop" );
603 THROW_ERROR( ErrorType_General, tmp_err );
604 }
605 tmp = *( array->get_variable(i+1)->get_complex() );
606
607 if( tmp.imaginary != Real(0.0) || !tmp.real.isInteger() )
608 THROW_ERROR( ErrorType_General, _("_3d_set_prop: 'Width' must be an integer.") );
609
610 tmp.real.get_top( &h );
611
612 _3d_prop.height = int( int64(h) );
613
614 i++;
615 }
616 else if( *str == "Camera distance" )
617 {
618 if( array->get_variable(i+1)->get_type() != math::VariableType_Complex )
619 {
620 char tmp_err[ERROR_OBJ_MSG_LEN];
621 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "_3d_set_prop" );
622 THROW_ERROR( ErrorType_General, tmp_err );
623 }
624 tmp = *( array->get_variable(i+1)->get_complex() );
625 if( tmp.imaginary != Real(0.0) || tmp.real <= Real(0.0) )
626 THROW_ERROR( ErrorType_General, _("_3d_set_prop: 'Camera distance' must be a positive real value.") );
627 _3d_prop.camera_dist = float(tmp.real);
628
629 i++;
630 }
631 else if( *str == "Look at" )
632 {
633 float x,y,z;
634
635 if( array->get_variable(i+1)->get_type() != math::VariableType_Matrix )
636 {
637 char tmp_err[ERROR_OBJ_MSG_LEN];
638 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "_3d_set_prop" );
639 THROW_ERROR( ErrorType_General, tmp_err );
640 }
641
642 matr = *( array->get_variable(i+1)->get_matrix() );
643
644 if( matr.get_height() != 3 || matr.get_width() != 1 )
645 THROW_ERROR( ErrorType_General, _("_3d_set_prop: 'Look at's vertex matrix's size dosn't match.") );
646
647 tmp = matr.get_complex( 1, 1 );
648 if( tmp.imaginary != Real(0.0) )
649 THROW_ERROR( ErrorType_General, _("_3d_set_prop: 'Look at's coordinates must be real values.") );
650 x = float(tmp.real);
651
652 tmp = matr.get_complex( 1, 2 );
653 if( tmp.imaginary != Real(0.0) )
654 THROW_ERROR( ErrorType_General, _("_3d_set_prop: \"Look at\"s coordinates must be real values.") );
655 y = float(tmp.real);
656
657 tmp = matr.get_complex( 1, 3 );
658 if( tmp.imaginary != Real(0.0) )
659 THROW_ERROR( ErrorType_General, _("_3d_set_prop: \"Look at\"s coordinates must be real values.") );
660 z = float(tmp.real);
661
662 _3d_prop.look_at.x = x;
663 _3d_prop.look_at.y = z;
664 _3d_prop.look_at.z = -y;
665
666 i++;
667 }
668 else
669 {
670 utf8_string str2( _("_3d_set_prop: Unknown property: ") );
671 str2.append( *str );
672 THROW_ERROR( ErrorType_General, str2.c_str() );
673 }
674 }
675
676 if( res != 0 )
677 res->set_void();
678 }
679
addon_3d_get_prop(math::Variable * res,math::Variable * left,const math::Variable * right,math::VariableList * private_varlist)680 void addon_3d_get_prop(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
681 throw(error_obj)
682 {
683 Matrix matr_res;
684 Complex tmp;
685 const utf8_string *str;
686
687 if( left != 0 || right == 0 )
688 THROW_ERROR( ErrorType_General, "Internal error: _3d_get_prop wasn't called the right way" );
689
690 if( res == 0 )
691 return;
692
693 if( right->get_type() != math::VariableType_String )
694 {
695 char tmp_err[ERROR_OBJ_MSG_LEN];
696 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "_3d_get_prop" );
697 THROW_ERROR( ErrorType_General, tmp_err );
698 }
699
700 str = right->get_string();
701
702 if( *str == "Width" )
703 {
704 tmp.imaginary = Real(0.0);
705 tmp.real = Real(_3d_prop.width);
706 res->set_complex( tmp );
707 }
708 else if( *str == "Height" )
709 {
710 tmp.imaginary = Real(0.0);
711 tmp.real = Real(_3d_prop.height);
712 res->set_complex( tmp );
713 }
714 else if( *str == "Camera distance" )
715 {
716 tmp.imaginary = Real(0.0);
717 tmp.real = Real(_3d_prop.camera_dist);
718 res->set_complex( tmp );
719 }
720 else if( *str == "Look at" )
721 {
722 tmp.imaginary = Real(0.0);
723 matr_res.set_size( 1, 3 );
724 tmp.real = Real(_3d_prop.look_at.x);
725 matr_res.set_complex( 1, 1, tmp );
726 tmp.real = Real(_3d_prop.look_at.y);
727 matr_res.set_complex( 1, 3, tmp );
728 tmp.real = Real(-_3d_prop.look_at.z);
729 matr_res.set_complex( 1, 2, tmp );
730
731 res->set_matrix( &matr_res );
732 }
733 else
734 {
735 char tmp_err[ERROR_OBJ_MSG_LEN];
736 snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Unknown 3d property: %s"), str->c_str() );
737 THROW_ERROR( ErrorType_General, tmp_err );
738 }
739 }
740
addon_3d_add_plane(math::Variable * res,math::Variable * left,const math::Variable * right,math::VariableList * private_varlist)741 void addon_3d_add_plane(math::Variable *res, math::Variable *left, const math::Variable *right, math::VariableList *private_varlist)
742 throw(error_obj)
743 {
744 Matrix x_matr, y_matr, z_matr;
745 floatx min=0.0, max=1.0;
746 Vector<picture_h::colorrgb> colors;
747 _3d_plane *plane;
748 _3d_point *point;
749
750 if( left != 0 || right == 0 )
751 THROW_ERROR( ErrorType_General, "Internal error: _3d_ad_plane wasn't called the right way" );
752
753
754 try{ plane = new _3d_plane; }
755 catch(...) { THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") ); }
756
757 try
758 {
759 Matrix colormatrix;
760 math::colorrgb_to_colormatrix( picture_h::color::BLUE, &colormatrix);
761 utf8_string str("Solid");
762
763 argument_check( "_3d_add_plane", right,
764 math::type_matrix, &x_matr,
765 math::type_matrix, &y_matr,
766 math::type_matrix, &z_matr,
767 math::type_string_default, &str,
768 math::type_floatx_default, &min,
769 math::type_floatx_default, &max,
770 math::type_matrix_default, &colormatrix,
771 math::type_end );
772
773 if( str == "Solid" )
774 plane->type = _3d_plane_solid;
775 else if( str == "Semi-solid" )
776 plane->type = _3d_plane_semi_solid;
777 else if( str == "Wireframed" )
778 plane->type = _3d_plane_wireframed;
779 else
780 THROW_ERROR( ErrorType_General, _("Unknown 3D plane-type") );
781
782 math::colormatrix_to_colorrgbs( colormatrix, colors );
783
784 if( min >= max )
785 THROW_ERROR( ErrorType_General, _("_3d_add_plane: Max must be larger than min.") );
786
787 if( x_matr.get_width() <= 1 || x_matr.get_height() < 1 ||
788 y_matr.get_width() <= 1 || y_matr.get_height() < 1 ||
789 z_matr.get_width() <= 1 || z_matr.get_height() <= 1 )
790 {
791 if( res != 0 )
792 res->set_void();
793 return;
794 }
795
796 if( x_matr.get_width() != z_matr.get_width() ||
797 y_matr.get_width() != z_matr.get_height() )
798 THROW_ERROR( ErrorType_General, _("_3d_add_plane: X, Y & Z's matrix sizes doesn't match.") );
799
800 plane->set_size( z_matr.get_width(), z_matr.get_height() );
801
802 for( uint32 x=0; x<plane->width; x++ )
803 {
804 for( uint32 y=0; y<plane->height; y++ )
805 {
806 point = &(plane->points[x + y*plane->width]);
807
808 if( x_matr.get_complex( x+1, 1 ).imaginary != Real(0.0) ||
809 y_matr.get_complex( y+1, 1 ).imaginary != Real(0.0) ||
810 z_matr.get_complex( x+1, y+1 ).imaginary != Real(0.0) )
811 point->isValid = false;
812 else
813 {
814 point->isValid = true;
815
816 // rearranging the axis...
817 point->x = float( x_matr.get_complex( x+1, 1 ).real );
818 point->y = float( z_matr.get_complex( x+1, y+1 ).real );
819 point->z = float( -y_matr.get_complex( y+1, 1 ).real );
820
821 math::color_list_get_color( colors, min, max,
822 z_matr.get_complex(x+1,y+1).real, &(point->color) );
823 }
824 }
825 }
826 _3d_prop.planes.append_this( plane );
827 }
828 catch(...)
829 {
830 delete plane;
831 throw;
832 }
833
834 if( res != 0 )
835 res->set_void();
836 }
837
838 #else
_3d_viewer_init(void)839 void _3d_viewer_init(void) {} // dummy function when opengl support shouldn't get compiled
840 #endif // PLOT_3D
841