// -*- mode:C++ ; compile-command: "emcc opengl.cc -I. -I.. -DHAVE_CONFIG_H -DIN_GIAC -DGIAC_GENERIC_CONSTANTS -DNO_STDEXCEPT -Os -s ALLOW_MEMORY_GROWTH=1 -s LEGACY_GL_EMULATION=1" -*- #ifndef GIAC_GGB #include "opengl.h" /* * Copyright (C) 2006,2014 B. Parisse, Institut Fourier, 38402 St Martin d'Heres * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef EMCC_GLUT #include #else #include "SDL/SDL.h" #include "SDL/SDL_opengl.h" #include #include #endif #include #include "vector.h" #include #include #include #include // for nanosleep #include #include #include // auto-recovery function #include "path.h" #ifndef IN_GIAC #include #else #include "misc.h" #endif #ifndef HAVE_PNG_H #undef HAVE_LIBPNG #endif #ifdef HAVE_LIBPNG #include #endif using namespace std; using namespace giac; #ifdef EMCC // missing from emscripten void glPointSize(GLint){ } void glColorMaterial(GLenum,GLint){} void glVertex3d(GLdouble d1,GLdouble d2,GLdouble d3){ glVertex3f(d1,d2,d3); } void glLightModeli(GLenum,GLint) {} void glLightModelf(GLenum,GLfloat) {} void glGetDoublev(GLenum i,GLdouble * d){ float f[16]; glGetFloatv(i,f); for (int i=0;i<16;++i) d[i]=f[i]; } // glRasterPos3d(GLdouble d1,GLdouble d2,GLdouble d3) is not defined // so we define it as a member of Opengl void glGetMaterialfv(GLenum,GLenum,GLfloat *){} void glLineStipple(GLint,GLushort){} void glMaterialf(GLenum,GLenum,GLfloat){} void glNormal3d(GLdouble d1,GLdouble d2,GLdouble d3){ glNormal3f(d1,d2,d3); } void glGetLightfv(GLenum,GLenum,GLfloat *){} void glClipPlane(GLenum,const GLdouble *){} #endif #ifndef NO_NAMESPACE_GIAC namespace giac { #endif // ndef NO_NAMESPACE_GIAC Xcas_config_type Xcas_config; string print_DOUBLE_(double d){ char s[256]; #ifdef IPAQ sprintf(s,"%.4g",d); #else sprintf(s,"%.5g",d); #endif return s; } // from Graph.cc bool do_helpon=true; static double pow10(double d){ return std::pow(10.,d); } void xcas_color(int color,bool dim3){ switch (color){ case FL_RED: glColor3f(1,0,0); return; case FL_BLACK: glColor3f(0,0,0); return; case FL_WHITE: glColor3f(1,1,1); return; case FL_BLUE: glColor3f(0,0,1); return; case FL_GREEN: glColor3f(0,1,0); return; case FL_CYAN: glColor3f(0,1,1); return; case FL_MAGENTA: glColor3f(1,0,1); return; case FL_YELLOW: glColor3f(1,1,0); return; } int r,g,b; arc_en_ciel(color % 0x7e,r,g,b); glColor3f(r/255.,g/255.,b/255.); } inline int Min(int i,int j) {return i>j?j:i;} inline int Max(int i,int j) {return i>j?i:j;} quaternion_double::quaternion_double(double theta_x,double theta_y,double theta_z) { *this=euler_deg_to_quaternion_double(theta_x,theta_y,theta_z); } quaternion_double euler_deg_to_quaternion_double(double a,double b,double c){ double phi=a*M_PI/180, theta=b*M_PI/180, psi=c*M_PI/180; double c1 = std::cos(phi/2); double s1 = std::sin(phi/2); double c2 = std::cos(theta/2); double s2 = std::sin(theta/2); double c3 = std::cos(psi/2); double s3 = std::sin(psi/2); double c1c2 = c1*c2; double s1s2 = s1*s2; double w =c1c2*c3 - s1s2*s3; double x =c1c2*s3 + s1s2*c3; double y =s1*c2*c3 + c1*s2*s3; double z =c1*s2*c3 - s1*c2*s3; return quaternion_double(w,x,y,z); } void quaternion_double_to_euler_deg(const quaternion_double & q,double & phi,double & theta, double & psi){ double test = q.x*q.y + q.z*q.w; if (test > 0.499) { // singularity at north pole phi = 2 * atan2(q.x,q.w) * 180/M_PI; theta = 90; psi = 0; return; } if (test < -0.499) { // singularity at south pole phi = -2 * atan2(q.x,q.w) * 180/M_PI; theta = - 90; psi = 0; return; } double sqx = q.x*q.x; double sqy = q.y*q.y; double sqz = q.z*q.z; phi = atan2(2*q.y*q.w-2*q.x*q.z , 1 - 2*sqy - 2*sqz) * 180/M_PI; theta = std::asin(2*test) * 180/M_PI; psi = atan2(2*q.x*q.w-2*q.y*q.z , 1 - 2*sqx - 2*sqz) * 180/M_PI; } quaternion_double operator * (const quaternion_double & q1,const quaternion_double & q2){ double z=q1.w*q2.z+q2.w*q1.z+q1.x*q2.y-q2.x*q1.y; double x=q1.w*q2.x+q2.w*q1.x+q1.y*q2.z-q2.y*q1.z; double y=q1.w*q2.y+q2.w*q1.y+q1.z*q2.x-q2.z*q1.x; double w=q1.w*q2.w-q1.x*q2.x-q1.y*q2.y-q1.z*q2.z; return quaternion_double(w,x,y,z); } // q must be a unit void get_axis_angle_deg(const quaternion_double & q,double &x,double &y,double & z, double &theta){ double scale=1-q.w*q.w; if (scale>1e-6){ scale=std::sqrt(scale); theta=2*std::acos(q.w)*180/M_PI; x=q.x/scale; y=q.y/scale; z=q.z/scale; } else { x=0; y=0; z=1; theta=0; } } ostream & operator << (ostream & os,const quaternion_double & q){ return os << q.w << "+" << q.x << "i+" << q.y << "j+" << q.z << "k"; } void Opengl::update_infos(const gen & g){ if (g.is_symb_of_sommet(at_equal)){ // detect a title or a x/y-axis name gen & f = g._SYMBptr->feuille; if (f.type==_VECT && f._VECTptr->size()==2){ gen & optname = f._VECTptr->front(); gen & optvalue= f._VECTptr->back(); if (optname==at_legende && optvalue.type==_VECT){ vecteur & optv=(*optvalue._VECTptr); int optvs=optv.size(); if (optvs>=1) x_axis_unit=printstring(optv[0],contextptr); if (optvs>=2) y_axis_unit=printstring(optv[1],contextptr); if (optvs>=3) z_axis_unit=printstring(optv[2],contextptr); } if (optname.type==_INT_ && optname.subtype == _INT_PLOT){ #if 0 if (optname.val==_GL_TEXTURE){ if (optvalue.type==_VECT && optvalue._VECTptr->size()==2 && optvalue._VECTptr->front().type==_STRNG && is_undef(optvalue._VECTptr->back())){ // reload cached image optvalue=optvalue._VECTptr->front(); std::map *>::iterator it,itend=texture2d_cache.end(); it=texture2d_cache.find(optvalue._STRNGptr->c_str()); if (it!=itend){ std::pair * old= it->second; delete old; texture2d_cache.erase(it); } get_texture2d(*optvalue._STRNGptr,background_image); } else { if (optvalue.type==_STRNG){ get_texture2d(*optvalue._STRNGptr,background_image); } else { background_image=0; } } } #endif if (optname.val==_TITLE ) title=printstring(optvalue,contextptr); if (optname.val==_AXES){ if (optvalue.type==_INT_) show_axes=optvalue.val; } if (optname.val==_LABELS && optvalue.type==_VECT){ vecteur & optv=(*optvalue._VECTptr); int optvs=optv.size(); if (optvs>=1) x_axis_name=printstring(optv[0],contextptr); if (optvs>=2) y_axis_name=printstring(optv[1],contextptr); if (optvs>=3) z_axis_name=printstring(optv[2],contextptr); } if (optname.val==_GL_ORTHO && optvalue==1) orthonormalize(); if (optname.val==_GL_X_AXIS_COLOR && optvalue.type==_INT_) x_axis_color=optvalue.val; if (optname.val==_GL_Y_AXIS_COLOR && optvalue.type==_INT_) y_axis_color=optvalue.val; if (optname.val==_GL_Z_AXIS_COLOR && optvalue.type==_INT_) z_axis_color=optvalue.val; if (optname.val>=_GL_X && optname.val<=_GL_Z && optvalue.is_symb_of_sommet(at_interval)){ gen optvf=evalf_double(optvalue._SYMBptr->feuille,1,contextptr); if (optvf.type==_VECT && optvf._VECTptr->size()==2){ gen a=optvf._VECTptr->front(); gen b=optvf._VECTptr->back(); if (a.type==_DOUBLE_ && b.type==_DOUBLE_){ switch (optname.val){ case _GL_X: window_xmin=a._DOUBLE_val; window_xmax=b._DOUBLE_val; break; case _GL_Y: window_ymin=a._DOUBLE_val; window_ymax=b._DOUBLE_val; break; case _GL_Z: window_zmin=a._DOUBLE_val; window_zmax=b._DOUBLE_val; break; } } } } gen optvalf=evalf_double(optvalue,1,contextptr); if (optname.val==_GL_XTICK && optvalf.type==_DOUBLE_) x_tick=optvalf._DOUBLE_val; if (optname.val==_GL_YTICK && optvalf.type==_DOUBLE_) y_tick=optvalf._DOUBLE_val; if (optname.val==_GL_ZTICK && optvalf.type==_DOUBLE_) z_tick=optvalf._DOUBLE_val; if (optname.val==_GL_ANIMATE && optvalf.type==_DOUBLE_) animation_dt=optvalf._DOUBLE_val; if (optname.val==_GL_SHOWAXES && optvalue.type==_INT_) show_axes=optvalue.val; if (optname.val==_GL_SHOWNAMES && optvalue.type==_INT_) show_names=optvalue.val; if (optname.val>=_GL_X_AXIS_NAME && optname.val<=_GL_Z_AXIS_UNIT && optvalue.type==_STRNG){ if (optname.val==_GL_X_AXIS_NAME) x_axis_name=*optvalue._STRNGptr; if (optname.val==_GL_Y_AXIS_NAME) y_axis_name=*optvalue._STRNGptr; if (optname.val==_GL_Z_AXIS_NAME) z_axis_name=*optvalue._STRNGptr; if (optname.val==_GL_X_AXIS_UNIT) x_axis_unit=*optvalue._STRNGptr; if (optname.val==_GL_Y_AXIS_UNIT) y_axis_unit=*optvalue._STRNGptr; if (optname.val==_GL_Z_AXIS_UNIT) z_axis_unit=*optvalue._STRNGptr; } if (optname.val==_GL_QUATERNION && optvalf.type==_VECT && optvalf._VECTptr->size()==4){ vecteur & optvalv=*optvalf._VECTptr; if (optvalv[0].type==_DOUBLE_ && optvalv[1].type==_DOUBLE_ && optvalv[2].type==_DOUBLE_ && optvalv[3].type==_DOUBLE_){ q.x=optvalv[0]._DOUBLE_val; q.y=optvalv[1]._DOUBLE_val; q.z=optvalv[2]._DOUBLE_val; q.w=optvalv[3]._DOUBLE_val; } } if (optname.val==_GL_LOGX && optvalue.type==_INT_){ display_mode &= (0xffff ^ 0x400); if (optvalue.val) display_mode |= 0x400; } if (optname.val==_GL_LOGY && optvalue.type==_INT_){ display_mode &= (0xffff ^ 0x800); if (optvalue.val) display_mode |= 0x800; } if (optname.val==_GL_LOGZ && optvalue.type==_INT_){ display_mode &= (0xffff ^ 0x1000); if (optvalue.val) display_mode |= 0x1000; } if (dynamic_cast(this)){ if (optname.val==_GL_ROTATION_AXIS && optvalf.type==_VECT && optvalf._VECTptr->size()==3){ vecteur & optvalv=*optvalf._VECTptr; if (optvalv[0].type==_DOUBLE_ && optvalv[1].type==_DOUBLE_ && optvalv[2].type==_DOUBLE_ ){ rotanim_rx=optvalv[0]._DOUBLE_val; rotanim_ry=optvalv[1]._DOUBLE_val; rotanim_rz=optvalv[2]._DOUBLE_val; } } if (optname.val==_GL_FLAT && optvalue.type==_INT_){ display_mode &= (0xffff ^ 0x10); if (optvalue.val) display_mode |= 0x10; } if (optname.val==_GL_LIGHT && optvalue.type==_INT_){ display_mode &= (0xffff ^ 0x8); if (optvalue.val) display_mode |= 0x8; } if (optname.val==_GL_PERSPECTIVE && optvalue.type==_INT_){ display_mode &= (0xffff ^ 0x4); if (!optvalue.val) display_mode |= 0x4; } // GL_LIGHT_MODEL_COLOR_CONTROL=GL_SEPARATE_SPECULAR_COLOR || GL_SINGLE_COLOR #ifndef WIN32 if (optname.val==_GL_LIGHT_MODEL_COLOR_CONTROL && optvalue.type==_INT_) glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL,optvalue.val); /* GL_LIGHT_MODEL_LOCAL_VIEWER=floating-point value that spec- ifies how specular reflection angles are computed. If params is 0 (or 0.0), specular reflection angles take the view direction to be parallel to and in the direction of the -z axis, regardless of the location of the vertex in eye coordi- nates. Otherwise, specular reflections are computed from the origin of the eye coordinate system. The initial value is 0. */ if (optname.val==_GL_LIGHT_MODEL_LOCAL_VIEWER){ if (optvalf.type==_DOUBLE_) glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER,optvalf._DOUBLE_val); } #endif #ifdef HAVE_LIBFLTK_GL /* GL_LIGHT_MODEL_TWO_SIDE = true /false */ if (optname.val==_GL_LIGHT_MODEL_TWO_SIDE && optvalue.type==_INT_){ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,optvalue.val); } /* GL_LIGHT_MODEL_AMBIENT=[r,g,b,a] */ if (optname.val==_GL_LIGHT_MODEL_AMBIENT && optvalf.type==_VECT && optvalf._VECTptr->size()==4){ vecteur & w=*optvalf._VECTptr; GLfloat tab[4]={w[0]._DOUBLE_val,w[1]._DOUBLE_val,w[2]._DOUBLE_val,w[3]._DOUBLE_val}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT,tab); } // gl_blend=[d,s] // habituellement gl_blend=[gl_src_alpha,gl_one_minus_src_alpha] if (optname.val==_GL_BLEND){ if (is_zero(optvalue)){ glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); if (optvalue.type==_VECT && optvalue._VECTptr->size()==2) glBlendFunc(optvalue._VECTptr->front().val,optvalue._VECTptr->back().val); if (is_minus_one(optvalue)) glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } } #endif // gl_light0=[option1=value1,...] if (optname.val>=_GL_LIGHT0 && optname.val<=_GL_LIGHT7 && optvalue.type==_VECT){ int j=optname.val-_GL_LIGHT0; // reset light0+j light_x[j]=0;light_y[j]=0;light_z[j]=0;light_w[j]=1; float di=j?0:1; light_diffuse_r[j]=di;light_diffuse_g[j]=di;light_diffuse_b[j]=di;light_diffuse_a[j]=di; light_specular_r[j]=di;light_specular_g[j]=di;light_specular_b[j]=di;light_specular_a[j]=di; light_ambient_r[j]=0;light_ambient_g[j]=0;light_ambient_b[j]=0;light_ambient_a[j]=1; light_spot_x[j]=0;light_spot_y[j]=0;light_spot_z[j]=-1;light_spot_w[j]=0; light_spot_exponent[j]=0;light_spot_cutoff[j]=180; light_0[j]=1;light_1[j]=0;light_2[j]=0; vecteur & optv=*optvalue._VECTptr; for (unsigned i=0;ifeuille.type==_VECT && g._SYMBptr->feuille._VECTptr->size()==2){ gen & optgname = optg._SYMBptr->feuille._VECTptr->front(); gen optgval = evalf_double(optg._SYMBptr->feuille._VECTptr->back(),1,contextptr); bool vect4=optgval.type==_VECT && optgval._VECTptr->size()==4; vecteur xyzw; if (vect4) xyzw=*optgval._VECTptr; switch (optgname.val){ case _GL_AMBIENT: light_ambient_r[j]=xyzw[0]._DOUBLE_val; light_ambient_g[j]=xyzw[1]._DOUBLE_val; light_ambient_b[j]=xyzw[2]._DOUBLE_val; light_ambient_a[j]=xyzw[3]._DOUBLE_val; break; case _GL_SPECULAR: light_specular_r[j]=xyzw[0]._DOUBLE_val; light_specular_g[j]=xyzw[1]._DOUBLE_val; light_specular_b[j]=xyzw[2]._DOUBLE_val; light_specular_a[j]=xyzw[3]._DOUBLE_val; break; case _GL_DIFFUSE: light_diffuse_r[j]=xyzw[0]._DOUBLE_val; light_diffuse_g[j]=xyzw[1]._DOUBLE_val; light_diffuse_b[j]=xyzw[2]._DOUBLE_val; light_diffuse_a[j]=xyzw[3]._DOUBLE_val; break; case _GL_POSITION: light_x[j]=xyzw[0]._DOUBLE_val; light_y[j]=xyzw[1]._DOUBLE_val; light_z[j]=xyzw[2]._DOUBLE_val; light_w[j]=xyzw[3]._DOUBLE_val; break; case _GL_SPOT_DIRECTION: light_spot_x[j]=xyzw[0]._DOUBLE_val; light_spot_y[j]=xyzw[1]._DOUBLE_val; light_spot_z[j]=xyzw[2]._DOUBLE_val; light_spot_w[j]=xyzw[3]._DOUBLE_val; break; case _GL_SPOT_EXPONENT: light_spot_exponent[j]=optgval._DOUBLE_val; break; case _GL_SPOT_CUTOFF: light_spot_cutoff[j]=optgval._DOUBLE_val; break; case _GL_CONSTANT_ATTENUATION: light_0[j]=optgval._DOUBLE_val; break; case _GL_LINEAR_ATTENUATION: light_1[j]=optgval._DOUBLE_val; break; case _GL_QUADRATIC_ATTENUATION: light_2[j]=optgval._DOUBLE_val; break; } } ; } // end for i } } // end opengl options } } } if (g.type==_VECT){ const_iterateur it=g._VECTptr->begin(),itend=g._VECTptr->end(); for (;it!=itend;++it) update_infos(*it); } } void Opengl::move_cfg(int i){ if (history.empty()) return; int j=i+history_pos; int s=history.size(); if (j>s) j=s; if (j<1) j=1; history_pos=j; window_xyz & h = history[j-1]; window_xmin=h.xmin; window_xmax=h.xmax; window_ymin=h.ymin; window_ymax=h.ymax; window_zmin=h.zmin; window_zmax=h.zmax; } void Opengl::push_cfg(){ int s=history.size(); if (history_pos=0){ history.erase(history.begin()+history_pos,history.end()); } history.push_back(window_xyz(window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax)); history_pos=history.size(); } void Opengl::clear_cfg(){ history_pos=0; history.clear(); } void Opengl::find_xyz(double i,double j,double k,double &x,double&y,double &z){ x=i; y=j; z=k; } static void cb_Opengl_Autoscale(Opengl * gr , void*) { if (gr) gr->autoscale(false); } static void cb_Opengl_AutoscaleFull(Opengl * gr , void*) { if (gr) gr->autoscale(true); } static void cb_Opengl_Orthonormalize(Opengl * gr , void*) { if (gr) gr->orthonormalize(); } static void cb_Opengl_Next(Opengl * gr , void*) { if (gr) gr->move_cfg(1); } static void cb_Opengl_Previous(Opengl * gr , void*) { if (gr) gr->move_cfg(-1); } static void cb_Opengl_Zoomout(Opengl * gr , void*) { if (gr) gr->zoom(1.414); } static void cb_Opengl_Zoomin(Opengl * gr , void*) { if (gr) gr->zoom(0.707); } static void cb_Opengl_Pause(Opengl * gr , void*) { if (gr) gr->paused=true; } static void cb_Opengl_Stop(Opengl * gr , void*) { if (gr){ gr->animation_dt=0; gr->animation_instructions_pos=0; } } static void cb_Opengl_Restart(Opengl * gr , void*) { if (gr) gr->paused=false; } static void cb_Opengl_Faster(Opengl * gr , void*) { if (gr){ if (gr->animation_dt) gr->animation_dt /= 2; else gr->animation_dt = 0.2; } } static void cb_Opengl_Slower(Opengl * gr , void*) { if (gr){ if (gr->animation_dt) gr->animation_dt *= 2; else gr->animation_dt = 0.2; } } static void cb_Opengl_hide(Opengl * gr , void*) { if (Opengl3d * gr3 = dynamic_cast(gr)){ gr3->below_depth_hidden=true; gr3->redraw(); } } static void cb_Opengl_show(Opengl * gr , void*) { if (Opengl3d * gr3 = dynamic_cast(gr)){ gr3->below_depth_hidden=false; gr3->redraw(); } } static void cb_Opengl_startview(Opengl * gr , void*) { if (Opengl3d * gr3 = dynamic_cast(gr)){ gr3->theta_x=-13; gr3->theta_y=-95; gr3->theta_z=-110; gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y); gr3->redraw(); } } static void cb_Opengl_xview(Opengl * gr , void*) { if (Opengl3d * gr3 = dynamic_cast(gr)){ gr3->theta_x=0; gr3->theta_y=-90; gr3->theta_z=-90; gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y); gr3->redraw(); } } static void cb_Opengl_yview(Opengl * gr , void*) { if (Opengl3d * gr3 = dynamic_cast(gr)){ gr3->theta_x=0; gr3->theta_y=-90; gr3->theta_z=0; gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y); gr3->redraw(); } } static void cb_Opengl_zview(Opengl * gr , void*) { if (Opengl3d * gr3 = dynamic_cast(gr)){ gr3->theta_x=0; gr3->theta_y=0; gr3->theta_z=0; gr3->q=euler_deg_to_quaternion_double(gr3->theta_z,gr3->theta_x,gr3->theta_y); gr3->redraw(); } } static void cb_Opengl_mouse_plan(Opengl * gr , void*) { if (Opengl3d * gr3d = dynamic_cast(gr)){ double a,b,c; gr3d->current_normal(a,b,c); gr3d->normal2plan(a,b,c); // divides a,b,c by dx^2,... double x0,y0,z0,t0; gr3d->find_xyz(gr3d->x()+gr3d->w()/2,gr3d->y()+gr3d->h()/2,gr3d->depth,x0,y0,z0); t0=a*x0+b*y0+c*z0; if (std::abs(t0)window_zmax-gr3d->window_zmin)/1000) t0=0; string s="plan("+print_DOUBLE_(a)+"*x+"+print_DOUBLE_(b)+"*y+"+print_DOUBLE_(c)+"*z="+print_DOUBLE_(t0)+")"; //in_Xcas_input_char(Fl::focus(),s,' '); } } // image of (x,y,z) by rotation around axis r(rx,ry,rz) of angle theta void rotate(double rx,double ry,double rz,double theta,double x,double y,double z,double & X,double & Y,double & Z){ /* quaternion_double q=rotation_2_quaternion_double(rx,ry,rz,theta); quaternion_double qx(x,y,z,0); quaternion_double qX=conj(q)*qx*q; */ // r(rx,ry,rz) the axis, v(x,y,z) projects on w=a*r with a such that // w.r=a*r.r=v.r double r2=rx*rx+ry*ry+rz*rz; double r=std::sqrt(r2); double a=(rx*x+ry*y+rz*z)/r2; // v=w+V, w remains stable, V=v-w=v-a*r rotates // Rv=w+RV, where RV=cos(theta)*V+sin(theta)*(r cross V)/sqrt(r2) double Vx=x-a*rx,Vy=y-a*ry,Vz=z-a*rz; // cross product of k with V double kVx=ry*Vz-rz*Vy, kVy=rz*Vx-rx*Vz,kVz=rx*Vy-ry*Vx; double c=std::cos(theta),s=std::sin(theta); X=a*rx+c*Vx+s*kVx/r; Y=a*ry+c*Vy+s*kVy/r; Z=a*rz+c*Vz+s*kVz/r; } Opengl::Opengl(int w__,int h__,double xmin,double xmax,double ymin,double ymax,double zmin,double zmax,double ortho): w_(w__),h_(h__), pushed(false), show_mouse_on_object(false), mode(255),args_tmp_push_size(0),no_handle(false), display_mode(0x45), window_xmin(xmin),window_xmax(xmax),window_ymin(ymin),window_ymax(ymax),window_zmin(zmin),window_zmax(zmax),history_pos(0), ylegende(2.5), npixels(8), show_axes(1),show_names(1), paused(true),twodim(false), ipos(0),jpos(0),depthpos(0), last_event(0),x_tick(1.0),y_tick(1.0),couleur(0),approx(true),moving(false),moving_frame(false),ntheta(24),nphi(18) { push_cfg(); legende_size=giac::LEGENDE_SIZE; x_axis_color=FL_RED; y_axis_color=FL_GREEN; z_axis_color=FL_BLUE; current_i=current_j=RAND_MAX; in_area=false; } Opengl::Opengl(int w__,int h__): w_(w__),h_(h__), pushed(false), show_mouse_on_object(false), display_mode(0x45), mode(255),args_tmp_push_size(0),no_handle(false), window_xmin(Xcas_config.window_xmin),window_xmax(Xcas_config.window_xmax),window_ymin(Xcas_config.window_ymin),window_ymax(Xcas_config.window_ymax),window_zmin(Xcas_config.window_zmin),window_zmax(Xcas_config.window_zmax),history_pos(0), ylegende(2.5), npixels(8), show_axes(1),show_names(1), paused(true),twodim(false), ipos(0),jpos(0),depthpos(0), last_event(0),x_tick(1.0),y_tick(1.0),couleur(0),approx(true),hp_pos(-1),moving(false),moving_frame(false),ntheta(24),nphi(18) { legende_size=giac::LEGENDE_SIZE; push_cfg(); x_axis_color=FL_RED; y_axis_color=FL_GREEN; z_axis_color=FL_BLUE; } Opengl::~Opengl(){ } int Opengl::x() const { return 0; } int Opengl::y() const { return 0; } int Opengl::w() const { return w_; } int Opengl::h() const { return h_; } double find_tick(double dx){ double res=std::pow(10.0,std::floor(std::log10(std::abs(dx)))); int nticks=int(dx/res); if (nticks<4) res/=5; else { if (nticks<8) res/=2; } return res; } std::string Opengl::current_config(){ string res="gl_quaternion=["; res += print_DOUBLE_(q.x); res += ","; res += print_DOUBLE_(q.y); res += ","; res += print_DOUBLE_(q.z); res += ","; res += print_DOUBLE_(q.w); res += "]"; return res; } void Opengl::reset_light(unsigned i){ light_on[i]=!i; light_x[i]=0;light_y[i]=0;light_z[i]=1;light_w[i]=0; float di=i?0:1; light_diffuse_r[i]=di;light_diffuse_g[i]=di;light_diffuse_b[i]=di;light_diffuse_a[i]=di; light_specular_r[i]=di;light_specular_g[i]=di;light_specular_b[i]=di;light_specular_a[i]=di; light_ambient_r[i]=0;light_ambient_g[i]=0;light_ambient_b[i]=0;light_ambient_a[i]=1; light_spot_x[i]=0;light_spot_y[i]=0;light_spot_z[i]=-1;light_spot_w[i]=0; light_spot_exponent[i]=0;light_spot_cutoff[i]=180; light_0[i]=1;light_1[i]=0;light_2[i]=0; } // round to 3 decimals double setup_round(double x){ if (x<0) return -setup_round(-x); if (x<1e-300) return 0; int n=int(std::floor(std::log10(x)+.5)); // round to nearest x=int(std::floor(x*std::pow(10.0,3.0-n)+.5)); x=x*std::pow(10.0,n-3.0); return x; } void Opengl::autoscale(bool fullview){ if (!plot_instructions.empty()){ // Find the largest and lowest x/y/z in objects (except lines/plans) vector vx,vy,vz; int s; bool ortho=autoscaleg(plot_instructions,vx,vy,vz,contextptr); autoscaleminmax(vx,window_xmin,window_xmax,fullview); if (display_mode & 0x400){ if (window_xmin<=0){ if (vx[0]<=0) window_xmin=-309; else window_xmin=std::log10(vx[0]); } else window_xmin=std::log10(window_xmin); if (window_xmax<=0) window_xmax=-300; else window_xmax=std::log10(window_xmax); } zoomx(1.0); autoscaleminmax(vy,window_ymin,window_ymax,fullview); if (display_mode & 0x800){ if (window_ymin<=0){ if (vy[0]<=0) window_ymin=-309; else window_ymin=std::log10(vy[0]); } else window_ymin=std::log10(window_ymin); if (window_ymax<=0) window_ymax=-300; else window_ymax=std::log10(window_ymax); } zoomy(1.0); autoscaleminmax(vz,window_zmin,window_zmax,fullview); zoomz(1.0); if (ortho) orthonormalize(); } y_tick=find_tick(window_ymax-window_ymin); redraw(); push_cfg(); } void Opengl::zoomx(double d,bool round){ double x_center=(window_xmin+window_xmax)/2; double dx=(window_xmax-window_xmin); if (dx==0) dx=gnuplot_xmax-gnuplot_xmin; dx *= d/2; x_tick = find_tick(dx); window_xmin = x_center - dx; if (round) window_xmin=int( window_xmin/x_tick -1)*x_tick; window_xmax = x_center + dx; if (round) window_xmax=int( window_xmax/x_tick +1)*x_tick; } void Opengl::zoomy(double d,bool round){ double y_center=(window_ymin+window_ymax)/2; double dy=(window_ymax-window_ymin); if (dy==0) dy=gnuplot_ymax-gnuplot_ymin; dy *= d/2; y_tick = find_tick(dy); window_ymin = y_center - dy; if (round) window_ymin=int( window_ymin/y_tick -1)*y_tick; window_ymax = y_center + dy; if (round) window_ymax=int( window_ymax/y_tick +1)*y_tick; } void Opengl::zoomz(double d,bool round){ double z_center=(window_zmin+window_zmax)/2; double dz=(window_zmax-window_zmin); if (dz==0) dz=gnuplot_zmax-gnuplot_zmin; dz *= d/2; z_tick=find_tick(dz); window_zmin = z_center - dz; if (round) window_zmin=int(window_zmin/z_tick -1)*z_tick; window_zmax = z_center + dz; if (round) window_zmax=int(window_zmax/z_tick +1)*z_tick; } void Opengl::zoom(double d){ zoomx(d); zoomy(d); zoomz(d); push_cfg(); } void Opengl::orthonormalize(){ // don't do anything in base class } void Opengl::labelsize(int i){ labelsize_=i; } int Opengl::labelsize() const{ return labelsize_; } void Opengl::redraw(){ } void Opengl::up(double d){ window_ymin += d; window_ymax += d; push_cfg(); } void Opengl::down(double d){ window_ymin -= d; window_ymax -= d; push_cfg(); } void Opengl::up_z(double d){ window_zmin += d; window_zmax += d; push_cfg(); } void Opengl::down_z(double d){ window_zmin -= d; window_zmax -= d; push_cfg(); } void Opengl::left(double d){ window_xmin -= d; window_xmax -= d; push_cfg(); } void Opengl::right(double d){ window_xmin += d; window_xmax += d; push_cfg(); } void Opengl::set_axes(int b){ show_axes = b; } void Opengl::copy(const Opengl & gr){ window_xmin=gr.window_xmin; window_xmax=gr.window_xmax; window_ymin=gr.window_ymin; window_ymax=gr.window_ymax; window_zmin=gr.window_zmin; window_zmax=gr.window_zmax; npixels=gr.npixels; show_axes=gr.show_axes; show_names=gr.show_names; history = gr.history; labelsize(gr.labelsize()); q=gr.q; display_mode=gr.display_mode; // copy lights for (int i=0;i<8;++i){ light_on[i]=gr.light_on[i]; light_x[i]=gr.light_x[i]; light_y[i]=gr.light_y[i]; light_z[i]=gr.light_z[i]; light_w[i]=gr.light_w[i];; light_diffuse_r[i]=gr.light_diffuse_r[i]; light_diffuse_g[i]=gr.light_diffuse_g[i]; light_diffuse_b[i]=gr.light_diffuse_b[i]; light_diffuse_a[i]=gr.light_diffuse_a[i]; light_specular_r[i]=gr.light_specular_r[i]; light_specular_g[i]=gr.light_specular_g[i]; light_specular_b[i]=gr.light_specular_b[i]; light_specular_a[i]=gr.light_specular_a[i]; light_ambient_r[i]=gr.light_ambient_r[i]; light_ambient_g[i]=gr.light_ambient_g[i]; light_ambient_b[i]=gr.light_ambient_b[i]; light_ambient_a[i]=gr.light_ambient_a[i]; light_spot_x[i]=gr.light_spot_x[i]; light_spot_y[i]=gr.light_spot_y[i]; light_spot_z[i]=gr.light_spot_z[i]; light_spot_w[i]=gr.light_spot_w[i]; light_spot_exponent[i]=gr.light_spot_exponent[i]; light_spot_cutoff[i]=gr.light_spot_cutoff[i]; light_0[i]=gr.light_0[i]; light_1[i]=gr.light_1[i]; light_2[i]=gr.light_2[i]; } ntheta=gr.ntheta; nphi=gr.nphi; } int round(double d){ int res=int(floor(d+0.5)); int maxpixels=10000; // maximal number of horizontal or vertical pixels if (d>maxpixels) return maxpixels; if (d<-maxpixels) return -maxpixels; return res; } string printsemi(GIAC_CONTEXT){ if (xcas_mode(contextptr)==3) return "ยง"; else return ";"; } string cas_recalc_name(){ if (getenv("XCAS_TMP")) return getenv("XCAS_TMP")+("/#c#"+print_INT_(parent_id)); #ifdef WIN32 return "#c#"+print_INT_(parent_id); #endif #ifdef IPAQ return "/tmp/#c#"+print_INT_(parent_id); #endif return home_directory()+"#c#"+print_INT_(parent_id); } void Opengl::adjust_cursor_point_type(){ if (abs_calc_mode(contextptr)==38){ double newx,newy,newz; find_xyz(current_i,current_j,current_depth,newx,newy,newz); int pos=-1; gen orig; //gen res=Opengl::geometry_round(newx,newy,newz,find_eps(),orig,pos); cursor_point_type=pos>=0?6:3; } } gen geometry_round_numeric(double x,double y,double eps,bool approx){ return approx?gen(x,y):exact_double(x,eps)+cst_i*exact_double(y,eps); } gen geometry_round_numeric(double x,double y,double z,double eps,bool approx){ return approx?makevecteur(x,y,z):makevecteur(exact_double(x,eps),exact_double(y,eps),exact_double(z,eps)); } void round3(double & x,double xmin,double xmax){ double dx=std::abs(xmax-xmin); double logdx=std::log10(dx); int ndec=int(logdx)-4; double xpow=std::pow(10.0,ndec); int newx=int(x/xpow); x=newx*xpow; } bool is_numeric(const gen & a); bool is_numeric(const vecteur & v){ const_iterateur it=v.begin(),itend=v.end(); for (;it!=itend;++it){ if (!is_numeric(*it)) return false; } return true; } bool is_numeric(const gen & a){ switch (a.type){ case _DOUBLE_: case _INT_: case _ZINT: case _REAL: return true; case _CPLX: return is_numeric(*a._CPLXptr) && is_numeric(*(a._CPLXptr+1)); case _VECT: return is_numeric(*a._VECTptr); case _FRAC: return is_numeric(a._FRACptr->num) && is_numeric(a._FRACptr->den); case _SYMB: if (a.is_symb_of_sommet(at_prod) || a.is_symb_of_sommet(at_inv) || a.is_symb_of_sommet(at_neg) || a.is_symb_of_sommet(at_plus)) return is_numeric(a._SYMBptr->feuille); default: return false; } } double Opengl::find_eps(){ double dx=window_xmax-window_xmin; double dy=window_ymax-window_ymin; double dz=window_zmax-window_zmin; double eps,epsx,epsy; int L=h()>w()?w():h(); Opengl3d * gr3d=dynamic_cast(this); epsx=(npixels*dx)/(gr3d?L:w()); epsy=(npixels*dy)/(gr3d?L:h()); eps=(epsxdy && dz >dx){ eps=npixels*dz/L; eps *= 2; } return eps; } int Opengl::handle(int event){ if (no_handle) return 0; #ifdef HAVE_LIBPTHREAD // cerr << "handle lock" << endl; int locked=pthread_mutex_trylock(&interactive_mutex); if (locked) return 0; #endif no_handle=true; bool b=io_graph(contextptr); io_graph(false,contextptr); int res=in_handle(event); io_graph(b,contextptr); no_handle=false; #ifdef HAVE_LIBPTHREAD pthread_mutex_unlock(&interactive_mutex); // cerr << "handle unlock" << endl; #endif return res; } int Opengl::handle_keyboard(int event){ #if 1 return 1; #else if (event==FL_KEYBOARD){ // Should bring this event to the current input in the parent() group switch (Fl::event_key()){ case FL_Escape: case FL_BackSpace: case FL_Tab: case FL_Enter: case FL_Print: case FL_Scroll_Lock: case FL_Pause: case FL_Insert: case FL_Home: case FL_Delete: case FL_End: case FL_Shift_L: case FL_Shift_R: case FL_Control_L: case FL_Control_R: case FL_Caps_Lock: case FL_Alt_L: case FL_Alt_R: case FL_Meta_L: case FL_Meta_R: case FL_Menu: case FL_Num_Lock: case FL_KP_Enter: return 1; case FL_Left: left((window_xmax-window_xmin)/10); return 1; case FL_Up: up((window_ymax-window_ymin)/10); return 1; case FL_Right: right((window_xmax-window_xmin)/10); return 1; case FL_Down: down((window_ymax-window_ymin)/10); return 1; case FL_Page_Up: up_z((window_zmax-window_zmin)/10); return 1; case FL_Page_Down: down_z((window_zmax-window_zmin)/10); return 1; default: char ch=Fl::event_text()?Fl::event_text()[0]:0; switch (ch){ case '-': zoom(1.414); return 1; case '+': zoom(0.707); return 1; case 'A': case 'a': autoscale(false); return 1; case 'V': case 'v': autoscale(true); return 1; case 'R': case 'r': oxyz_rotate(this,rotanim_type,rotanim_nstep,rotanim_tstep,rotanim_danim,rotanim_rx,rotanim_ry,rotanim_rz); return 1; case 'P': case 'p': paused=!paused; return 1; case 'N': case 'n': case 'F': case 'f': animation_instructions_pos++; redraw(); return 1; case 'B': case 'b': animation_instructions_pos--; redraw(); return 1; case 'C': case 'c': /* screen capture */ if (Opengl3d * gr3 = dynamic_cast(this)){ char * filename = file_chooser(gettext("Export to PNG file"),"*.png","session.png"); if(!filename) return 1; gr3->opengl2png(filename); return 1; } } } } return 0; #endif } int Opengl::in_handle(int event){ int res=handle_keyboard(event); return res?res:handle_mouse(event); } vecteur Opengl::selection2vecteur(const vector & v){ int n=v.size(); vecteur res(n); for (int i=0;ifeuille; if (g._SYMBptr->sommet==at_couleur && f.type==_VECT && !f._VECTptr->empty()){ gen col=couleur_; col.subtype=_INT_COLOR; vecteur v(*f._VECTptr); v.back()=col; return symbolic(at_couleur,gen(v,_SEQ__VECT)); } if (couleur_==default_color(contextptr)) return g; if (g._SYMBptr->sommet==at_of){ gen col=couleur_; col.subtype=_INT_COLOR; return symbolic(at_couleur,gen(makevecteur(g,col),_SEQ__VECT)); } vecteur v =gen2vecteur(f); gen col=int2color(couleur_); v.push_back(symbolic(at_equal,gen(makevecteur(at_display,col),_SEQ__VECT))); return symbolic(g._SYMBptr->sommet,(v.size()==1 && f.type!=_VECT)?f:gen(v,f.type==_VECT?f.subtype:_SEQ__VECT)); } void Opengl::set_mode(const giac::gen & f_tmp,const giac::gen & f_final,int m){ if (mode>=-1){ pushed=false; moving=moving_frame=false; history_pos=-1; mode=m; function_final=f_final; function_tmp=f_tmp; args_tmp.clear(); } } void find_dxdy(const string & legendes,int labelpos,int labelsize,int & dx,int & dy){ int l=labelsize*legendes.size()/2;//int(fl_width(legendes.c_str())); dx=3; dy=1; switch (labelpos){ case 1: dx=-l-3; break; case 2: dx=-l-3; dy=labelsize-2; break; case 3: dy=labelsize-2; break; } } string printstring(const gen & g,GIAC_CONTEXT){ if (g.type==_STRNG) return *g._STRNGptr; return g.print(contextptr); } /* void Opengl::find_title_plot(gen & title_tmp,gen & plot_tmp){ if (in_area && mode && !args_tmp.empty()){ if (args_tmp.size()>=2){ gen function=(mode==int(args_tmp.size()))?function_final:function_tmp; if (function.type==_FUNC){ bool dim2=dynamic_cast(this); vecteur args2=args_tmp; if ( *function._FUNCptr==(dim2?at_cercle:at_sphere)){ gen argv1; try { argv1=evalf(args_tmp.back(),1,contextptr); argv1=evalf_double(argv1,1,contextptr); } catch (std::runtime_error & e){ argv1=undef; } if (argv1.is_symb_of_sommet(at_pnt) ||argv1.type==_IDNT){ argv1=remove_at_pnt(argv1); if ( (argv1.type==_VECT && argv1.subtype==_POINT__VECT) || argv1.type==_CPLX || argv1.type==_IDNT) args2.back()=args_tmp.back()-args_tmp.front(); } } if (function==at_ellipse) ; title_tmp=gen(args2,_SEQ__VECT); bool b=approx_mode(contextptr); if (!b) approx_mode(true,contextptr); plot_tmp=symbolic(*function._FUNCptr,title_tmp); if (!lidnt(title_tmp).empty()) ; // cerr << plot_tmp << endl; bool bb=io_graph(contextptr); int locked=0; if (bb){ #ifdef HAVE_LIBPTHREAD // cerr << "plot title lock" << endl; locked=pthread_mutex_trylock(&interactive_mutex); #endif if (!locked) io_graph(false,contextptr); } plot_tmp=protecteval(plot_tmp,1,contextptr); if (bb && !locked){ io_graph(bb,contextptr); #ifdef HAVE_LIBPTHREAD pthread_mutex_unlock(&interactive_mutex); // cerr << "plot title unlock" << endl; #endif } if (!b) approx_mode(false,contextptr); } // end function.type==_FUNC else title_tmp=gen(args_tmp,_SEQ__VECT); } // end size()>=2 else title_tmp=args_tmp; } } */ void Opengl::autoname_plus_plus(){ string s=autoname(contextptr); giac::autoname_plus_plus(s); autoname(s,contextptr); } int contrast(Fl_Color c){ if (c<=7) return 7-c; if (c>=8 && c<0x10) return 7; if (c>=0x10 && c<0x50) return 0xf8; if (c & 0x4) return 0; return 7; } // from Graph3d.cc double giac_max(double i,double j){ return i>j?i:j; } quaternion_double rotation_2_quaternion_double(double x, double y, double z,double theta){ double t=theta*M_PI/180; double qx,qy,qz,qw,s=std::sin(t/2),c=std::cos(t/2); qx=x*s; qy=y*s; qz=z*s; qw=c; double n=std::sqrt(qx*qx+qy*qy+qz*qz+qw*qw); return quaternion_double(qw/n,qx/n,qy/n,qz/n); } Opengl3d::Opengl3d(int w__,int h__): Opengl(w__,h__), theta_z(-110),theta_x(-13),theta_y(-95), delta_theta(5),draw_mode(GL_QUADS),//glcontext(0), dragi(0),dragj(0),push_in_area(false),depth(0),below_depth_hidden(false) { // end(); // mode=0; display_mode |= 0x80; display_mode |= 0x200; couleur=_POINT_WIDTH_5; q=euler_deg_to_quaternion_double(theta_z,theta_x,theta_y); // 8 light initialization for (int i=0;i<8;++i) reset_light(i); } // t angle in radians -> r,g,b void arc_en_ciel(double t,int & r,int & g,int &b){ int k=int(t/2/M_PI*126); arc_en_ciel(k,r,g,b); } bool get_glvertex(const vecteur & v,double & d1,double & d2,double & d3,double realiscmplx,double zmin,GIAC_CONTEXT){ if (v.size()==3){ gen tmp; tmp=evalf_double(v[0],2,contextptr); if (tmp.type!=_DOUBLE_) return false; d1=tmp._DOUBLE_val; tmp=evalf_double(v[1],2,contextptr); if (tmp.type!=_DOUBLE_) return false; d2=tmp._DOUBLE_val; tmp=evalf_double(v[2],2,contextptr); if (realiscmplx){ double arg=0; if (realiscmplx<0){ d3=evalf_double(im(tmp,contextptr),2,contextptr)._DOUBLE_val-zmin; arg=-d3*realiscmplx; } else { if (tmp.type==_DOUBLE_){ d3=tmp._DOUBLE_val; if (d3<0){ arg=M_PI; d3=-d3; } } else { if (tmp.type==_CPLX && tmp._CPLXptr->type==_DOUBLE_ && (tmp._CPLXptr+1)->type==_DOUBLE_){ double r=tmp._CPLXptr->_DOUBLE_val; double i=(tmp._CPLXptr+1)->_DOUBLE_val; arg=std::atan2(i,r); d3=std::sqrt(r*r+i*i); } else return false; } } // end realiscmplx>0 // set color corresponding to argument int r,g,b; arc_en_ciel(arg,r,g,b); glColor3f(r/255.,g/255.,b/255.); // glColor4i(r,g,b,int(std::log(d3+1))); } // end if (realiscmplx) else { if (tmp.type!=_DOUBLE_) return false; d3=tmp._DOUBLE_val; } return true; } return false; } bool get_glvertex(const gen & g,double & d1,double & d2,double & d3,double realiscmplx,double zmin,GIAC_CONTEXT){ if (g.type!=_VECT) return false; return get_glvertex(*g._VECTptr,d1,d2,d3,realiscmplx,zmin,contextptr); } bool glvertex(const vecteur & v,double realiscmplx,double zmin,GIAC_CONTEXT){ double d1,d2,d3; if (get_glvertex(v,d1,d2,d3,realiscmplx,zmin,contextptr)){ glVertex3d(d1,d2,d3); return true; } return false; } // draw s at g with mode= 0 (upper right), 1, 2 or 3 void Opengl3d::legende_draw(const gen & g,const string & s,int mode){ // COUT << "legende_draw " << g << " " << s << endl; gen gf=evalf_double(g,1,contextptr); if (gf.type==_VECT && gf._VECTptr->size()==3){ double Ax=gf[0]._DOUBLE_val; double Ay=gf[1]._DOUBLE_val; double Az=gf[2]._DOUBLE_val; double Ai,Aj,Ad; int di=3,dj=1; giac::find_dxdy(s,mode,labelsize(),di,dj); find_ij(Ax,Ay,Az,Ai,Aj,Ad); find_xyz(Ai+di,Aj+dj,Ad,Ax,Ay,Az); glRasterPos3d(Ax,Ay,Az); // string s1(s); // cst_greek_translate(s1); // draw_string(s1); draw_string(s); } } void glnormal(const vecteur & v){ if (v.size()==3){ double d1=evalf_double(v[0],2,context0)._DOUBLE_val; double d2=evalf_double(v[1],2,context0)._DOUBLE_val; double d3=evalf_double(v[2],2,context0)._DOUBLE_val; glNormal3d(d1,d2,d3); } } void glnormal(double d1,double d2,double d3,double e1,double e2,double e3,double f1,double f2,double f3){ double de1(e1-d1),de2(e2-d2),de3(e3-d3),df1(f1-d1),df2(f2-d2),df3(f3-d3); glNormal3d(de2*df3-de3*df2,de3*df1-de1*df3,de1*df2-de2*df1); } void gltranslate(const vecteur & v){ if (v.size()==3){ double d1=evalf_double(v[0],2,context0)._DOUBLE_val; double d2=evalf_double(v[1],2,context0)._DOUBLE_val; double d3=evalf_double(v[2],2,context0)._DOUBLE_val; glTranslated(d1,d2,d3); } } void iso3d(const double &i1,const double &i2,const double &i3,const double &j1,const double &j2,const double &j3,const double &k1,const double &k2,const double &k3,double & x,double & y,double & z){ double X=x,Y=y,Z=z; x=i1*X+j1*Y+k1*Z; y=i2*X+j2*Y+k2*Z; z=i3*X+j3*Y+k3*Z; } #define LI 64 #define LH 64 GLubyte image[LI][LH][3]; void makeImage(void) { int i,j,c; for( i = 0 ; i < LI ; i++ ) { for( j = 0 ; j < LH ; j++ ) { c = (((i&0x8)==0)^ ((j&0x8)==0))*255; image[i][j][0] =(GLubyte) c; image[i][j][1] =(GLubyte) c; image[i][j][2] =(GLubyte) c; } } } bool test_enable_texture(void * texture){ #if 1 return false; #else if (!texture) return false; int depth=-1; if (texture->count()==1) depth=texture->d(); if (depth==3 || depth==4){ // define texture // makeImage(); char * ptr=(char *)texture->data()[0]; /* int W=texture->w(),H=texture->h(); for (int y=0;yw() and texture->h() must be a power of 2!! glTexImage2D(GL_TEXTURE_2D,0,depth, // LI,LH, texture->w(),texture->h(), 0, // GL_RGB, (depth==3?GL_RGB:GL_RGBA), GL_UNSIGNED_BYTE, // &image[0][0][0]); ptr); // not periodically glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); // adjust to nearest glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, // GL_NEAREST); GL_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, // GL_NEAREST); GL_LINEAR); // glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_MODULATE); //GL_REPLACE); glEnable(GL_TEXTURE_2D); return true; } return false; #endif } // Sphere centered at center, radius radius, i,j,k orthonormal, ntheta/nphi // number of subdivisions // mode=GL_QUADS for example void glsphere(const vecteur & center,const gen & radius,const vecteur & i0,const vecteur & j0,const vecteur & k0,int ntheta,int nphi,int mode,void * texture,GIAC_CONTEXT){ test_enable_texture(texture); double c1=evalf_double(center[0],1,contextptr)._DOUBLE_val; // center double c2=evalf_double(center[1],1,contextptr)._DOUBLE_val; double c3=evalf_double(center[2],1,contextptr)._DOUBLE_val; double r=evalf_double(radius,1,contextptr)._DOUBLE_val; double i1=evalf_double(i0[0],1,contextptr)._DOUBLE_val; double i2=evalf_double(i0[1],1,contextptr)._DOUBLE_val; double i3=evalf_double(i0[2],1,contextptr)._DOUBLE_val; double j1=evalf_double(j0[0],1,contextptr)._DOUBLE_val; double j2=evalf_double(j0[1],1,contextptr)._DOUBLE_val; double j3=evalf_double(j0[2],1,contextptr)._DOUBLE_val; double k1=evalf_double(k0[0],1,contextptr)._DOUBLE_val; double k2=evalf_double(k0[1],1,contextptr)._DOUBLE_val; double k3=evalf_double(k0[2],1,contextptr)._DOUBLE_val; double dtheta=2*M_PI/ntheta; // longitude double dphi=M_PI/nphi; // latitude double jsurtheta=0,isurphi=0,djsurtheta=1.0/ntheta,disurphi=1.0/nphi; double parallele1[ntheta+1],parallele2[ntheta+1],parallele3[ntheta+1]; double x,y,z,oldx,oldy,oldz,X,Z; // Set initial parallel to the North pole for (int j=0;j<=ntheta;++j){ parallele1[j]=k1; parallele2[j]=k2; parallele3[j]=k3; } // parallele1/2/3 contains the coordinate of the previous parallel for (int i=1;i<=nphi;i++,isurphi+=disurphi){ // longitude theta=0, latitude phi=i*dphi X=std::sin(i*dphi); Z=std::cos(i*dphi); oldx=X; oldy=0; oldz=Z; iso3d(i1,i2,i3,j1,j2,j3,k1,k2,k3,oldx,oldy,oldz); double * par1j=parallele1,* par2j=parallele2,*par3j=parallele3; jsurtheta=0; if (mode==GL_QUADS){ glBegin(GL_QUAD_STRIP); for (int j=0;j<=ntheta;++par1j,++par2j,++par3j,jsurtheta+=djsurtheta){ glNormal3d(*par1j,*par2j,*par3j); if (texture) glTexCoord2f(jsurtheta,isurphi); glVertex3d(c1+r*(*par1j),c2+r*(*par2j),c3+r*(*par3j)); if (texture) glTexCoord2f(jsurtheta,isurphi+disurphi); glVertex3d(c1+r*oldx,c2+r*oldy,c3+r*oldz); *par1j=oldx; *par2j=oldy; *par3j=oldz; // theta=j*dtheta, phi=i*dphi ++j; x=X*std::cos(j*dtheta); y=X*std::sin(j*dtheta); z=Z; iso3d(i1,i2,i3,j1,j2,j3,k1,k2,k3,x,y,z); oldx=x; oldy=y; oldz=z; } glEnd(); } else { for (int j=0;jsize()==3){ if (!is_zero(re(surface._VECTptr->back(),context0))) return false; gen s3=evalf_double(surface._VECTptr->back()/cst_i,2,context0); if (s3.type==_DOUBLE_){ double s3d = s3._DOUBLE_val; if (s3dzmax) zmax=s3d; } return true; } const_iterateur it=surface._VECTptr->begin(),itend=surface._VECTptr->end(); for (;it!=itend;++it){ if (!find_zscale(*it,zmin,zmax)) return false; } return true; } void glsurface(const gen & surfaceg,int draw_mode,void * texture,GIAC_CONTEXT){ if (!ckmatrix(surfaceg,true)) return; test_enable_texture(texture); double realiscmplx=has_i(surfaceg),zmin=1e300,zmax=-1e300; matrice & surface = *surfaceg._VECTptr; if (realiscmplx && !texture){ if (find_zscale(surface,zmin,zmax)) realiscmplx=2*M_PI/(zmin-zmax); } int n=surface.size(); if (surfaceg.subtype==_POLYEDRE__VECT){ // implicit surface drawing with the given triangulation if (draw_mode==GL_QUADS || draw_mode==GL_TRIANGLES){ glBegin(GL_TRIANGLES); for (int i=0;isize()<2){ if (texture) glDisable(GL_TEXTURE_2D); return; } gen a,b,c,d; double xt=0,yt,dxt=double(1)/n,dyt; for (int i=1;isize()==3){ closed=true; double dPx=evalf_double(dP[0],2,context0)._DOUBLE_val; if (fabs(dPx)>(window_xmax-window_xmin)*1e-6) closed=false; double dPy=evalf_double(dP[1],2,context0)._DOUBLE_val; if (fabs(dPy)>(window_ymax-window_ymin)*1e-6) closed=false; double dPz=evalf_double(dP[2],2,context0)._DOUBLE_val; if (fabs(dPz)>(window_zmax-window_zmin)*1e-6) closed=false; } return closed; } // translate giac GL constant to open GL constant unsigned gl_translate(unsigned i){ switch (i){ case _GL_LIGHT0: return GL_LIGHT0; case _GL_LIGHT1: return GL_LIGHT1; case _GL_LIGHT2: return GL_LIGHT2; case _GL_LIGHT3: return GL_LIGHT3; case _GL_LIGHT4: return GL_LIGHT4; case _GL_LIGHT5: return GL_LIGHT5; case _GL_AMBIENT: return GL_AMBIENT; case _GL_SPECULAR: return GL_SPECULAR; case _GL_DIFFUSE: return GL_DIFFUSE; case _GL_POSITION: return GL_POSITION; case _GL_SPOT_DIRECTION: return GL_SPOT_DIRECTION; case _GL_SPOT_EXPONENT: return GL_SPOT_EXPONENT; case _GL_SPOT_CUTOFF: return GL_SPOT_CUTOFF; case _GL_CONSTANT_ATTENUATION: return GL_CONSTANT_ATTENUATION; case _GL_LINEAR_ATTENUATION: return GL_LINEAR_ATTENUATION; case _GL_QUADRATIC_ATTENUATION: return GL_QUADRATIC_ATTENUATION; case _GL_LIGHT_MODEL_AMBIENT: return GL_LIGHT_MODEL_AMBIENT; case _GL_LIGHT_MODEL_LOCAL_VIEWER: return GL_LIGHT_MODEL_LOCAL_VIEWER; case _GL_LIGHT_MODEL_TWO_SIDE: return GL_LIGHT_MODEL_TWO_SIDE; #ifndef WIN32 case _GL_LIGHT_MODEL_COLOR_CONTROL: return GL_LIGHT_MODEL_COLOR_CONTROL; #endif case _GL_SMOOTH: return GL_SMOOTH; case _GL_FLAT: return GL_FLAT; case _GL_SHININESS: return GL_SHININESS; case _GL_FRONT: return GL_FRONT; case _GL_BACK: return GL_BACK; case _GL_FRONT_AND_BACK: return GL_FRONT_AND_BACK; case _GL_AMBIENT_AND_DIFFUSE: return GL_AMBIENT_AND_DIFFUSE; case _GL_EMISSION: return GL_EMISSION; #ifndef WIN32 case _GL_SEPARATE_SPECULAR_COLOR: return GL_SEPARATE_SPECULAR_COLOR; case _GL_SINGLE_COLOR: return GL_SINGLE_COLOR; #endif case _GL_BLEND: return GL_BLEND; case _GL_SRC_ALPHA: return GL_SRC_ALPHA; case _GL_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; case _GL_COLOR_INDEXES: return GL_COLOR_INDEXES; } cerr << "No GL equivalent for " << i << endl; return i; } void tran4(double * colmat){ giac::swapdouble(colmat[1],colmat[4]); giac::swapdouble(colmat[2],colmat[8]); giac::swapdouble(colmat[3],colmat[12]); giac::swapdouble(colmat[6],colmat[9]); giac::swapdouble(colmat[7],colmat[13]); giac::swapdouble(colmat[11],colmat[14]); } void get_texture(const gen & attrv1,void * & texture){ #if 0 // set texture if (attrv1.type==_STRNG){ std::map::const_iterator it,itend=texture_cache.end(); it=texture_cache.find(*attrv1._STRNGptr); if (it!=itend){ texture=it->second; // texture->uncache(); } else { texture=Fl_Shared_Image::get(attrv1._STRNGptr->c_str()); if (texture){ int W=texture->w(),H=texture->h(); // take a power of 2 near w/h W=1 << min(int(std::log(double(W))/std::log(2.)+.5),8); H=1 << min(int(std::log(double(H))/std::log(2.)+.5),8); texture=texture->copy(W,H); texture_cache[*attrv1._STRNGptr]=texture; } } } #endif } int gen2int(const gen & g){ if (g.type==_INT_) return g.val; if (g.type==_DOUBLE_) return int(g._DOUBLE_val); setsizeerr(gettext("Unable to convert to int")+g.print()); return -1; } void Opengl3d::indraw(const giac::gen & g){ if (g.type==_VECT) indraw(*g._VECTptr); if (g.is_symb_of_sommet(at_animation)){ indraw(get_animation_pnt(g,animation_instructions_pos)); return; } if (!g.is_symb_of_sommet(at_pnt)){ update_infos(g); return; } gen & f=g._SYMBptr->feuille; if (f.type!=_VECT) return; vecteur & v = *f._VECTptr; gen v0=v[0]; bool est_hyperplan=v0.is_symb_of_sommet(at_hyperplan); string legende; vecteur style(get_style(v,legende)); int styles=style.size(); // color bool hidden_name = false; int ensemble_attributs=style.front().val; if (style.front().type==_ZINT){ ensemble_attributs = mpz_get_si(*style.front()._ZINTptr); hidden_name=true; } else hidden_name=ensemble_attributs<0; int couleur=ensemble_attributs & 0x0000ff; int width =(ensemble_attributs & 0x00070000) >> 16; // 3 bits int epaisseur_point =((ensemble_attributs & 0x00380000) >> 19)+1; // 3 bits int type_line =(ensemble_attributs & 0x01c00000) >> 22; // 3 bits int type_point =(ensemble_attributs & 0x0e000000) >> 25; // 3 bits int labelpos =(ensemble_attributs & 0x30000000) >> 28; // 2 bits bool fill_polygon =(ensemble_attributs & 0x40000000) >> 30; hidden_name = hidden_name || legende.empty(); void * texture=0; glLineWidth(width+1); #if 0 // FIXME line_stipple disabled because of printing glLineStipple(1,line_stipple(type_line)); glPointSize(epaisseur_point); if (styles<=2){ glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); } else glDisable(GL_COLOR_MATERIAL); #ifndef EMCC GLfloat tab[4]={0,0,0,1}; glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,tab); glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,tab); GLfloat tab1[4]={0.2,0.2,0.2,1}; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,tab1); GLfloat tab2[4]={0.8,0.8,0.8,1}; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,tab2); #endif if (est_hyperplan){ glPolygonMode(GL_FRONT_AND_BACK,fill_polygon?GL_FILL:GL_LINE); } else { glPolygonMode(GL_FRONT_AND_BACK,fill_polygon?GL_FILL:GL_LINE); // glPolygonMode(GL_BACK,GL_POINT); // glMaterialfv(GL_BACK,GL_EMISSION,tab); // glMaterialfv(GL_BACK,GL_SPECULAR,tab); // glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,tab); } // glGetFloatv(GL_CURRENT_COLOR,tab); // set other style attributs : /* material = [gl_front|gl_back|gl_front_and_back,gl_shininess,valeur] or material = [gl_front|gl_back|gl_front_and_back, GL_AMBIENT| GL_DIFFUSE | GL_SPECULAR | GL_EMISSION | GL_AMBIENT_AND_DIFFUSE | GL_COLOR_INDEXES, [r,g,b,a] ] last arg is [ambient,diffuse,specular] for GL_COLOR_INDEXES or material=[gl_texture,"image_filename",...] */ for (int i=2;i=2 && attrv.front().type==_INT_ && attrv.front().val==_GL_TEXTURE){ get_texture(attrv[1],texture); continue; } if (attrv.size()==2 && attrv.front().type==_INT_ && attrv.front().val==_GL_MATERIAL){ gen attrm =evalf_double(attrv.back(),1,contextptr); if (debug_infolevel) cerr << "Setting material " << attrm << endl; if (attrm.type==_VECT && attrm._VECTptr->size()<=3 ){ gen attrv0=attrv.back()._VECTptr->front(); if (attrv0.type==_INT_ && attrv0.val==_GL_TEXTURE){ gen attrv1=(*attrv.back()._VECTptr)[1]; get_texture(attrv1,texture); continue; } vecteur & attrmv = *attrm._VECTptr; if (attrmv.back().type==_VECT && attrmv.back()._VECTptr->size()==4){ vecteur & w=*attrmv.back()._VECTptr; GLfloat tab[4]={w[0]._DOUBLE_val,w[1]._DOUBLE_val,w[2]._DOUBLE_val,w[3]._DOUBLE_val}; glMaterialfv(gl_translate(gen2int(attrmv[0])),gl_translate(gen2int(attrmv[1])),tab); continue; } if (attrmv.back().type==_VECT && attrmv.back()._VECTptr->size()==3){ vecteur & w=*attrmv.back()._VECTptr; GLfloat tab[3]={w[0]._DOUBLE_val,w[1]._DOUBLE_val,w[2]._DOUBLE_val}; glMaterialfv(gl_translate(gen2int(attrmv[0])),GL_COLOR_INDEXES,tab); continue; } if (attrmv.back().type==_DOUBLE_ && attrmv[1]._DOUBLE_val==_GL_SHININESS){ // glMaterialf(gl_translate(gen2int(attrmv[0])),GL_SHININESS,float(attrmv[2]._DOUBLE_val)); glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,float(attrmv[2]._DOUBLE_val)); continue; } } } } } if (texture){ fill_polygon=true; couleur=FL_WHITE; glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); } #endif bool hidden_line = fill_polygon && (width==7 || (display_mode & 0x8) || texture ); xcas_color(couleur,true); if (debug_infolevel){ cerr << "opengl displaying " << g << endl; GLint b; GLfloat posf[4],direcf[4],ambient[4],diffuse[4],specular[4],emission[4],shini[1]; GLfloat expo,cutoff; double pos[4],direc[4]; glGetIntegerv(GL_BLEND,&b); cerr << "blend " << b << endl; for (int i=0;i<8;++i){ glGetIntegerv(GL_LIGHT0+i,&b); if (b){ glGetLightfv(GL_LIGHT0+i,GL_SPOT_EXPONENT,&expo); glGetLightfv(GL_LIGHT0+i,GL_SPOT_CUTOFF,&cutoff); glGetLightfv(GL_LIGHT0+i,GL_POSITION,posf); glGetLightfv(GL_LIGHT0+i,GL_SPOT_DIRECTION,direcf); direcf[3]=0; mult4(model_inv,posf,pos); tran4(model); mult4(model,direcf,direc); tran4(model); glGetLightfv(GL_LIGHT0+i,GL_AMBIENT,ambient); glGetLightfv(GL_LIGHT0+i,GL_DIFFUSE,diffuse); glGetLightfv(GL_LIGHT0+i,GL_SPECULAR,specular); cerr << "light " << i << ": " << " pos " << pos[0] << "," << pos[1] << "," << pos[2] << "," << pos[3] << " dir " << direc[0] << "," << direc[1] << "," << direc[2] << "," << direc[3] << " ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] << " diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] << " specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] << " exponent " << expo << " cutoff " << cutoff << endl; } } // material colors glGetMaterialfv(GL_FRONT,GL_AMBIENT,ambient); glGetMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse); glGetMaterialfv(GL_FRONT,GL_SPECULAR,specular); glGetMaterialfv(GL_FRONT,GL_EMISSION,emission); glGetMaterialfv(GL_FRONT,GL_SHININESS,shini); cerr << "front " << ": " << " ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] << " diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] << " specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] << " emission " << emission[0] << "," << emission[1] << "," << emission[2] << "," << emission[3] << " shininess " << shini[0] << endl; glGetMaterialfv(GL_BACK,GL_AMBIENT,ambient); glGetMaterialfv(GL_BACK,GL_DIFFUSE,diffuse); glGetMaterialfv(GL_BACK,GL_SPECULAR,specular); glGetMaterialfv(GL_BACK,GL_EMISSION,emission); glGetMaterialfv(GL_BACK,GL_SHININESS,shini); cerr << "back " << ": " << " ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] << " diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] << " specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] << " emission " << emission[0] << "," << emission[1] << "," << emission[2] << "," << emission[3] << " shininess " << shini[0] << endl; } if (est_hyperplan){ vecteur P,n; if (!hyperplan_normal_point(v0,n,P)) return; P=*evalf_double(P,1,contextptr)._VECTptr; vecteur Porig(P); double n1=evalf_double(n[0],1,contextptr)._DOUBLE_val; double n2=evalf_double(n[1],1,contextptr)._DOUBLE_val; double n3=evalf_double(n[2],1,contextptr)._DOUBLE_val; if (fill_polygon){ glNormal3d(n1,n2,n3); if (std::abs(n1)>=std::abs(n2) && std::abs(n1)>=std::abs(n3)){ // x=a*y+b*z+c double a=-n2/n1, b=-n3/n1; double c=evalf_double(P[0]-a*P[1]-b*P[2],1,contextptr)._DOUBLE_val; double dy=(window_ymax-window_ymin)/10; double dz=(window_zmax-window_zmin)/10; for (int j=0;j<10;++j){ double y=window_ymin+j*dy; for (int k=0;k<10;++k){ double z=window_zmin+k*dz; double x=a*y+b*z+c; if (x>window_xmax || xstd::abs(n1) && std::abs(n2)>=std::abs(n3)){ // y=a*x+b*z+c double a=-n1/n2, b=-n3/n2; double c=evalf_double(P[1]-a*P[0]-b*P[2],1,contextptr)._DOUBLE_val; double dx=(window_xmax-window_xmin)/10; double dz=(window_zmax-window_zmin)/10; for (int j=0;j<10;++j){ double x=window_xmin+j*dx; for (int k=0;k<10;++k){ double z=window_zmin+k*dz; double y=a*x+b*z+c; if (y>window_ymax || ystd::abs(n1) && std::abs(n3)>std::abs(n2)){ // z=a*x+b*y+c double a=-n1/n3, b=-n2/n3; double c=evalf_double(P[2]-a*P[0]-b*P[1],1,contextptr)._DOUBLE_val; double dx=(window_xmax-window_xmin)/10; double dy=(window_ymax-window_ymin)/10; for (int j=0;j<10;++j){ double x=window_xmin+j*dx; for (int k=0;k<10;++k){ double y=window_ymin+k*dy; double z=a*x+b*y+c; if (z>window_zmax || z=std::abs(n2) && std::abs(n1)>=std::abs(n3)){ // x=a*y+b*z+c double a=-n2/n1, b=-n3/n1; double c=evalf_double(P[0]-a*P[1]-b*P[2],1,contextptr)._DOUBLE_val; double dy=(window_ymax-window_ymin)/10; for (int j=0;j<=10;++j){ double y=window_ymin+j*dy; glBegin(GL_LINES); glVertex3d(a*y+b*window_zmin+c,y,window_zmin); glVertex3d(a*y+b*window_zmax+c,y,window_zmax); glEnd(); } double dz=(window_zmax-window_zmin)/10; for (int j=0;j<=10;++j){ double z=window_zmin+j*dz; glBegin(GL_LINES); glVertex3d(a*window_ymin+b*z+c,window_ymin,z); glVertex3d(a*window_ymax+b*z+c,window_ymax,z); glEnd(); } } if (std::abs(n2)>std::abs(n1) && std::abs(n2)>=std::abs(n3)){ // y=a*x+b*z+c double a=-n1/n2, b=-n3/n2; double c=evalf_double(P[1]-a*P[0]-b*P[2],1,contextptr)._DOUBLE_val; double dx=(window_xmax-window_xmin)/10; for (int j=0;j<=10;++j){ double x=window_xmin+j*dx; glBegin(GL_LINES); glVertex3d(x,a*x+b*window_zmin+c,window_zmin); glVertex3d(x,a*x+b*window_zmax+c,window_zmax); glEnd(); } double dz=(window_zmax-window_zmin)/10; for (int j=0;j<=10;++j){ double z=window_zmin+j*dz; glBegin(GL_LINES); glVertex3d(window_xmin,a*window_xmin+b*z+c,z); glVertex3d(window_xmax,a*window_xmax+b*z+c,z); glEnd(); } } if (std::abs(n3)>std::abs(n1) && std::abs(n3)>std::abs(n2)){ // z=a*x+b*y+c double a=-n1/n3, b=-n2/n3; double c=evalf_double(P[2]-a*P[0]-b*P[1],1,contextptr)._DOUBLE_val; double dx=(window_xmax-window_xmin)/10; for (int j=0;j<=10;++j){ double x=window_xmin+j*dx; glBegin(GL_LINES); glVertex3d(x,window_ymin,a*x+b*window_ymin+c); glVertex3d(x,window_ymax,a*x+b*window_ymax+c); glEnd(); } double dy=(window_ymax-window_ymin)/10; for (int j=0;j<=10;++j){ double y=window_ymin+j*dy; glBegin(GL_LINES); glVertex3d(window_xmin,y,a*window_xmin+b*y+c); glVertex3d(window_xmax,y,a*window_xmax+b*y+c); glEnd(); } } } if (!hidden_name && show_names) legende_draw(Porig,legende,labelpos); return; } if (v0.is_symb_of_sommet(at_hypersphere)){ gen & f=v0._SYMBptr->feuille; if (f.type==_VECT && f._VECTptr->size()>=2){ vecteur & v=*f._VECTptr; // Check that center is a 3-d point if (v.front().type==_VECT && v.front()._VECTptr->size()==3){ // Radius gen r=v[1]; if (r.type==_VECT && r._VECTptr->size()==3) r=l2norm(*r._VECTptr,contextptr); // Direction of axis, parallels and meridiens vecteur dir1(makevecteur(1,0,0)),dir2(makevecteur(0,1,0)),dir3(makevecteur(0,0,1)); if (v.size()>=3 && v[2].type==_VECT && v[2]._VECTptr->size()==3){ dir3=*v[2]._VECTptr; dir3=divvecteur(dir3,sqrt(dotvecteur(dir3,dir3),contextptr)); if (v.size()>=4 && v[3].type==_VECT && v[3]._VECTptr->size()==3){ dir1=*v[3]._VECTptr; dir1=divvecteur(dir1,sqrt(dotvecteur(dir1,dir1),contextptr)); } else { if (!is_zero(dir3[0]) || !is_zero(dir3[1]) ){ dir1=makevecteur(-dir3[1],dir3[0],0); dir1=divvecteur(dir1,sqrt(dotvecteur(dir1,dir1),contextptr)); } } dir2=cross(dir3,dir1,contextptr); } // optional discretisation info for drawing if (v.size()>=5 && v[4].type==_INT_){ nphi=giac_max(absint(v[4].val),3); ntheta=ntheta; } if (v.size()>=6 && v[5].type==_INT_){ ntheta=giac_max(absint(v[5].val),3); } // Now make the sphere if (fill_polygon){ glsphere(*v.front()._VECTptr,r,dir1,dir2,dir3,ntheta,nphi,GL_QUADS,texture,contextptr); } if (!hidden_line){ if (fill_polygon) glColor3f(0,0,0); glsphere(*v.front()._VECTptr,r,dir1,dir2,dir3,giacmin(ntheta,36),giacmin(nphi,36),GL_LINE_LOOP,texture,contextptr); xcas_color(couleur,true); } if (!hidden_name && show_names) legende_draw(v.front(),legende,labelpos); } } return; } if (v0.is_symb_of_sommet(at_curve) && v0._SYMBptr->feuille.type==_VECT && !v0._SYMBptr->feuille._VECTptr->empty()){ if (f._SYMBptr->feuille._VECTptr->size()>=2){ gen f=(*v0._SYMBptr->feuille._VECTptr)[1]; if (f.type==_VECT){ // COUT << f << endl; vecteur v =*f._VECTptr; int n=v.size(); for (int i=0;ifeuille._VECTptr->front(); // f = vect[ pnt,var,xmin,xmax ] if (f.type==_VECT && f._VECTptr->size()>=4){ vecteur vf = *f._VECTptr; if (vf.size()>4){ gen poly=vf[4]; if (ckmatrix(poly)){ const_iterateur it=poly._VECTptr->begin(),itend=poly._VECTptr->end(); bool closed=fill_polygon && !(display_mode & 0x8); // ?is_approx_zero(poly._VECTptr->back()-poly._VECTptr->front(),window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax):false; if (it->_VECTptr->size()==3){ glBegin(closed?GL_POLYGON:GL_LINE_STRIP); // if (closed) ++it; for (;it!=itend;++it){ if (!glvertex(*it->_VECTptr,0,0,contextptr)){ glEnd(); glBegin(closed?GL_POLYGON:GL_LINE_STRIP); } } glEnd(); if (!hidden_name && show_names && !poly._VECTptr->empty()) legende_draw(poly._VECTptr->front(),legende,labelpos); return ; } } } gen point=vf[0]; gen var=vf[1]; gen mini=vf[2]; gen maxi=vf[3]; bool closed=false; if (fill_polygon && !(display_mode & 0x8) ) closed=is_approx_zero(subst(point,var,mini,false,contextptr)-subst(point,var,maxi,false,contextptr),window_xmin,window_xmax,window_ymin,window_ymax,window_zmin,window_zmax); int n=nphi*10; gen delta=(maxi-mini)/n; COUT << "rendering curve " << vf << " " << delta << " " << n << endl; for (int i=closed?1:0;i " << tmp << endl; return; } } else { glvertex(makevecteur(0,0,0),0,0,contextptr); glvertex(makevecteur(0,0,0),0,0,contextptr); glEnd(); COUT << "rendering err1 " << point << " " << var << " " << mini << " -> " << tmp << endl; return; } glEnd(); } if (!hidden_name && show_names) legende_draw(mini,legende,labelpos); } return; } if (v0.is_symb_of_sommet(at_hypersurface)){ gen & f = v0._SYMBptr->feuille; if (f.type!=_VECT || f._VECTptr->size()<3) return; gen & tmp = f._VECTptr->front(); if (tmp.type!=_VECT || tmp._VECTptr->size()<4) return; if (tmp._VECTptr->size()>4){ if (!fill_polygon) glsurface((*tmp._VECTptr)[4],GL_LINE_LOOP,texture,contextptr); else { glsurface((*tmp._VECTptr)[4],GL_QUADS,texture,contextptr); // glLineWidth(width+2); if (!hidden_line){ glColor3f(0,0,0); glsurface((*tmp._VECTptr)[4],GL_LINE_LOOP,texture,contextptr); xcas_color(couleur,true); } } // if (!hidden_name && show_names) legende_draw(legende.c_str()); return; } gen point = tmp._VECTptr->front(); // [x(u,v),y(u,v),z(u,v)] gen vars = (*tmp._VECTptr)[1]; // [u,v] gen mini = (*tmp._VECTptr)[2]; // [umin,vmin] gen maxi = (*tmp._VECTptr)[3]; // [umax,vmax] if (!check3dpoint(point) || vars.type!=_VECT || vars._VECTptr->size()!=2 || mini.type!=_VECT || mini._VECTptr->size()!=2 || maxi.type!=_VECT || maxi._VECTptr->size()!=2 ) return; double umin=evalf_double(mini._VECTptr->front(),1,contextptr)._DOUBLE_val; double vmin=evalf_double(mini._VECTptr->back(),1,contextptr)._DOUBLE_val; double umax=evalf_double(maxi._VECTptr->front(),1,contextptr)._DOUBLE_val; double vmax=evalf_double(maxi._VECTptr->back(),1,contextptr)._DOUBLE_val; if (fill_polygon){ glsurface(*point._VECTptr,vars,umin,umax,vmin,vmax,ntheta,nphi,GL_QUADS,contextptr); if (!hidden_line){ glColor3f(0,0,0); glsurface(*point._VECTptr,vars,umin,umax,vmin,vmax,ntheta,nphi,GL_LINE_LOOP,contextptr); xcas_color(couleur,true); } } else glsurface(*point._VECTptr,vars,umin,umax,vmin,vmax,ntheta,nphi,GL_LINE_LOOP,contextptr); // if (!hidden_name && show_names) legende_draw(?,legende,labelpos); return; } if (v0.type==_VECT && v0.subtype==_POINT__VECT && v0._VECTptr->size()==3 ){ gen A(evalf_double(v0,1,contextptr)); if (A.type==_VECT && A._VECTptr->size()==3 && type_point!=4){ double xA=A._VECTptr->front()._DOUBLE_val; double yA=(*A._VECTptr)[1]._DOUBLE_val; double zA=A._VECTptr->back()._DOUBLE_val; double iA,jA,depthA; find_ij(xA,yA,zA,iA,jA,depthA); // COUT << "point " << type_point << "," << xA << "," << yA << "," << zA << "," << iA << "," << jA << "," << depthA << endl; glLineWidth(1+epaisseur_point/2); switch(type_point){ case 0: glBegin(GL_LINES); find_xyz(iA-epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA); // COUT << xA << "," << yA << "," << zA << endl; glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA); // COUT << xA << "," << yA << "," << zA << endl; glVertex3d(xA,yA,zA); find_xyz(iA-epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA); // COUT << xA << "," << yA << "," << zA << endl; glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA); // COUT << xA << "," << yA << "," << zA << endl; glVertex3d(xA,yA,zA); glEnd(); break; case 1: // 1 losange, glBegin(GL_LINE_LOOP); find_xyz(iA-epaisseur_point,jA,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point,jA,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); glEnd(); break; case 2: // 2 croix verticale, glBegin(GL_LINES); find_xyz(iA,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA-epaisseur_point,jA,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point,jA,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); glEnd(); break; case 3: // 3 carre. glBegin(GL_LINE_LOOP); find_xyz(iA-epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA-epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); glEnd(); break; case 5: // 5 triangle, glBegin(GL_LINE_LOOP); find_xyz(iA+epaisseur_point,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA-epaisseur_point,jA,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); glEnd(); break; case 6: // 6 etoile, glBegin(GL_LINES); find_xyz(iA,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA-epaisseur_point/2,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point/2,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA-epaisseur_point/2,jA-epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); find_xyz(iA+epaisseur_point/2,jA+epaisseur_point,depthA,xA,yA,zA); glVertex3d(xA,yA,zA); glEnd(); break; default: // 7 point glBegin(GL_POINTS); glvertex(*v0._VECTptr,0,0,contextptr); glEnd(); } glLineWidth(width+1); } if (!hidden_name && show_names) legende_draw(v0,legende,labelpos); return; } if (v0.type==_VECT && v0.subtype!=_POINT__VECT){ vecteur & vv0=*v0._VECTptr; vecteur w,lastpnt; if (v0.subtype==_POLYEDRE__VECT){ // each element of v is a face const_iterateur it=vv0.begin(),itend=vv0.end(); for (;it!=itend;++it){ if (it->type==_VECT){ w = *evalf_double(*it,1,contextptr)._VECTptr; int s=w.size(); if (s<3) continue; double d1,d2,d3,e1,e2,e3,f1,f2,f3; if (get_glvertex(w[0],d1,d2,d3,0,0,contextptr) && get_glvertex(w[1],e1,e2,e3,0,0,contextptr) && get_glvertex(w[2],f1,f2,f3,0,0,contextptr) ){ glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3); if (fill_polygon){ glBegin(GL_POLYGON); glVertex3d(d1,d2,d3); glVertex3d(e1,e2,e3); glVertex3d(f1,f2,f3); for (int j=3;jsize()!=3) glvertex(vecteur(3,0),0,0,contextptr); else glvertex( lastpnt=*w[j]._VECTptr,0,0,contextptr ); } glEnd(); xcas_color(couleur,true); // FIXME?? back face /* glnormal(f1,f2,f3,e1,e2,e3,d1,d2,d3); glBegin(GL_POLYGON); for (int j=s-1;j>=3;--j){ if (w[j].type!=_VECT || w[j]._VECTptr->size()!=3) glvertex(vecteur(3,0),0,0,contextptr); else glvertex( *w[j]._VECTptr ,0,0,contextptr); } glVertex3d(f1,f2,f3); glVertex3d(e1,e2,e3); glVertex3d(d1,d2,d3); glEnd(); */ } } } } for (it=vv0.begin();it!=itend;++it){ if (it->type==_VECT){ w = *evalf_double(*it,1,contextptr)._VECTptr; int s=w.size(); if (s<3) continue; double d1,d2,d3,e1,e2,e3,f1,f2,f3; if (get_glvertex(w[0],d1,d2,d3,0,0,contextptr) && get_glvertex(w[1],e1,e2,e3,0,0,contextptr) && get_glvertex(w[2],f1,f2,f3,0,0,contextptr) ){ glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3); if (!hidden_line){ glColor3f(0,0,0); glBegin(GL_LINE_LOOP); glVertex3d(d1,d2,d3); glVertex3d(e1,e2,e3); glVertex3d(f1,f2,f3); for (int j=3;jsize()!=3) glvertex(vecteur(3,0),0,0,contextptr); else glvertex( lastpnt=*w[j]._VECTptr,0,0,contextptr ); } glEnd(); xcas_color(couleur,true); } } } // end it->type==_VECT } // end for (;it!=itend;) if (!hidden_name && show_names) legende_draw(lastpnt,legende,labelpos); return; } // end polyedre int s=vv0.size(); if (s==2 && check3dpoint(vv0.front()) && check3dpoint(vv0.back()) ){ // segment, half-line, vector or line vecteur A(*evalf_double(vv0.front(),1,contextptr)._VECTptr),B(*evalf_double(vv0.back(),1,contextptr)._VECTptr); vecteur dir(subvecteur(B,A)); double lambda=1,nu; double d1=evalf_double(dir[0],1,contextptr)._DOUBLE_val; double d2=evalf_double(dir[1],1,contextptr)._DOUBLE_val; double d3=evalf_double(dir[2],1,contextptr)._DOUBLE_val; double nd=std::sqrt(d1*d1+d2*d2+d3*d3); if (std::abs(d1)>=std::abs(d2) && std::abs(d1)>=std::abs(d3)){ nu=(window_xmin-evalf_double(A[0],1,contextptr)._DOUBLE_val)/d1; } if (std::abs(d2)>std::abs(d1) && std::abs(d2)>=std::abs(d3)){ nu=(window_ymin-evalf_double(A[1],1,contextptr)._DOUBLE_val)/d2; } if (std::abs(d3)>std::abs(d1) && std::abs(d3)>std::abs(d2)){ nu=(window_zmin-evalf_double(A[2],1,contextptr)._DOUBLE_val)/d3; } if (std::abs(d1)>=0.1*nd) lambda=giac_max(lambda,(window_xmax-window_xmin)/std::abs(d1)); if (std::abs(d2)>=0.1*nd) lambda=giac_max(lambda,(window_ymax-window_ymin)/std::abs(d2)); if (std::abs(d3)>=0.1*nd) lambda=giac_max(lambda,(window_ymax-window_ymin)/std::abs(d3)); lambda *= 2; glBegin(GL_LINE_STRIP); if (v0.subtype==_LINE__VECT){ // move A in clip A=addvecteur(A,multvecteur(nu,dir)); B=subvecteur(B,multvecteur(nu,dir)); glvertex(subvecteur(A,multvecteur(lambda,dir)),0,0,contextptr); glvertex(addvecteur(A,multvecteur(lambda,dir)),0,0,contextptr); } else { glvertex(A,0,0,contextptr); if (v0.subtype==_HALFLINE__VECT) glvertex(addvecteur(A,multvecteur(lambda,dir)),0,0,contextptr); else glvertex(B,0,0,contextptr); } glEnd(); if (v0.subtype==_VECTOR__VECT){ double xB=evalf_double(B[0],1,contextptr)._DOUBLE_val; double yB=evalf_double(B[1],1,contextptr)._DOUBLE_val; double zB=evalf_double(B[2],1,contextptr)._DOUBLE_val; double xA=evalf_double(A[0],1,contextptr)._DOUBLE_val; double yA=evalf_double(A[1],1,contextptr)._DOUBLE_val; double zA=evalf_double(A[2],1,contextptr)._DOUBLE_val; /* 2-d code */ double iA,jA,depthA,iB,jB,depthB,di,dj,dij; find_ij(xB,yB,zB,iB,jB,depthB); find_ij(xA,yA,zA,iA,jA,depthA); di=iA-iB; dj=jA-jB; dij=std::sqrt(di*di+dj*dj); if (dij){ dij /= giacmin(5,int(dij/10))+width; di/=dij; dj/=dij; double dip=-dj,djp=di; di*=std::sqrt(3.0); dj*=std::sqrt(3.0); double iC=iB+di+dip,jC=jB+dj+djp; double iD=iB+di-dip,jD=jB+dj-djp; double xC,yC,zC,xD,yD,zD; find_xyz(iC,jC,depthB,xC,yC,zC); find_xyz(iD,jD,depthB,xD,yD,zD); glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); glBegin(GL_POLYGON); glVertex3d(xB,yB,zB); glVertex3d(xC,yC,zC); glVertex3d(xD,yD,zD); glEnd(); } } if (!hidden_name && show_names && v0.subtype!=_GROUP__VECT) legende_draw(multvecteur(0.5,addvecteur(A,B)),legende,labelpos); return; } if (s>2){ // polygon bool closed=vv0.front()==vv0.back(); double d1,d2,d3,e1,e2,e3,f1,f2,f3; if (get_glvertex(vv0[0],d1,d2,d3,0,0,contextptr) && get_glvertex(vv0[1],e1,e2,e3,0,0,contextptr) && get_glvertex(vv0[2],f1,f2,f3,0,0,contextptr) ){ if (test_enable_texture(texture) && s<=5 && closed){ glBegin(GL_QUADS); glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3); glTexCoord2f(0,0); glVertex3d(d1,d2,d3); glTexCoord2f(0,1); glVertex3d(e1,e2,e3); glTexCoord2f(1,1); glVertex3d(f1,f2,f3); if (s==5){ glTexCoord2f(1,0); glvertex(*vv0[3]._VECTptr,0,0,contextptr); } else glVertex3d(d1,d2,d3); glEnd(); glDisable(GL_TEXTURE_2D); } else { // glBegin(closed?GL_POLYGON:GL_LINE_STRIP); const_iterateur it=vv0.begin(),itend=vv0.end(); for (;it!=itend;++it){ //COUT << *it << endl; if (it+1==itend) break; if (check3dpoint(*it) && check3dpoint(*(it+1))){ glBegin(GL_LINES); glnormal(d1,d2,d3,e1,e2,e3,f1,f2,f3); glvertex(*it->_VECTptr,0,0,contextptr); glvertex(*(it+1)->_VECTptr,0,0,contextptr); glEnd(); } } } if (!hidden_name && show_names && !vv0.empty()) legende_draw(vv0.front(),legende,labelpos); } return; } } } void Opengl3d::indraw(const vecteur & v){ const_iterateur it=v.begin(),itend=v.end(); for (;it!=itend;++it) indraw(*it); } void mult4(double * colmat,double * vect,double * res){ res[0]=colmat[0]*vect[0]+colmat[4]*vect[1]+colmat[8]*vect[2]+colmat[12]*vect[3]; res[1]=colmat[1]*vect[0]+colmat[5]*vect[1]+colmat[9]*vect[2]+colmat[13]*vect[3]; res[2]=colmat[2]*vect[0]+colmat[6]*vect[1]+colmat[10]*vect[2]+colmat[14]*vect[3]; res[3]=colmat[3]*vect[0]+colmat[7]*vect[1]+colmat[11]*vect[2]+colmat[15]*vect[3]; } void mult4(double * colmat,float * vect,double * res){ res[0]=colmat[0]*vect[0]+colmat[4]*vect[1]+colmat[8]*vect[2]+colmat[12]*vect[3]; res[1]=colmat[1]*vect[0]+colmat[5]*vect[1]+colmat[9]*vect[2]+colmat[13]*vect[3]; res[2]=colmat[2]*vect[0]+colmat[6]*vect[1]+colmat[10]*vect[2]+colmat[14]*vect[3]; res[3]=colmat[3]*vect[0]+colmat[7]*vect[1]+colmat[11]*vect[2]+colmat[15]*vect[3]; } void mult4(double * c,double k,double * res){ for (int i=0;i<16;i++) res[i]=k*c[i]; } double det4(double * c){ return c[0]*c[5]*c[10]*c[15]-c[0]*c[5]*c[14]*c[11]-c[0]*c[9]*c[6]*c[15]+c[0]*c[9]*c[14]*c[7]+c[0]*c[13]*c[6]*c[11]-c[0]*c[13]*c[10]*c[7]-c[4]*c[1]*c[10]*c[15]+c[4]*c[1]*c[14]*c[11]+c[4]*c[9]*c[2]*c[15]-c[4]*c[9]*c[14]*c[3]-c[4]*c[13]*c[2]*c[11]+c[4]*c[13]*c[10]*c[3]+c[8]*c[1]*c[6]*c[15]-c[8]*c[1]*c[14]*c[7]-c[8]*c[5]*c[2]*c[15]+c[8]*c[5]*c[14]*c[3]+c[8]*c[13]*c[2]*c[7]-c[8]*c[13]*c[6]*c[3]-c[12]*c[1]*c[6]*c[11]+c[12]*c[1]*c[10]*c[7]+c[12]*c[5]*c[2]*c[11]-c[12]*c[5]*c[10]*c[3]-c[12]*c[9]*c[2]*c[7]+c[12]*c[9]*c[6]*c[3]; } void inv4(double * c,double * res){ res[0]=c[5]*c[10]*c[15]-c[5]*c[14]*c[11]-c[10]*c[7]*c[13]-c[15]*c[9]*c[6]+c[14]*c[9]*c[7]+c[11]*c[6]*c[13]; res[1]=-c[1]*c[10]*c[15]+c[1]*c[14]*c[11]+c[10]*c[3]*c[13]+c[15]*c[9]*c[2]-c[14]*c[9]*c[3]-c[11]*c[2]*c[13]; res[2]=c[1]*c[6]*c[15]-c[1]*c[14]*c[7]-c[6]*c[3]*c[13]-c[15]*c[5]*c[2]+c[14]*c[5]*c[3]+c[7]*c[2]*c[13]; res[3]=-c[1]*c[6]*c[11]+c[1]*c[10]*c[7]+c[6]*c[3]*c[9]+c[11]*c[5]*c[2]-c[10]*c[5]*c[3]-c[7]*c[2]*c[9]; res[4]=-c[4]*c[10]*c[15]+c[4]*c[14]*c[11]+c[10]*c[7]*c[12]+c[15]*c[8]*c[6]-c[14]*c[8]*c[7]-c[11]*c[6]*c[12]; res[5]=c[0]*c[10]*c[15]-c[0]*c[14]*c[11]-c[10]*c[3]*c[12]-c[15]*c[8]*c[2]+c[14]*c[8]*c[3]+c[11]*c[2]*c[12]; res[6]=-c[0]*c[6]*c[15]+c[0]*c[14]*c[7]+c[6]*c[3]*c[12]+c[15]*c[4]*c[2]-c[14]*c[4]*c[3]-c[7]*c[2]*c[12]; res[7]=c[0]*c[6]*c[11]-c[0]*c[10]*c[7]-c[6]*c[3]*c[8]-c[11]*c[4]*c[2]+c[10]*c[4]*c[3]+c[7]*c[2]*c[8]; res[8]=c[4]*c[9]*c[15]-c[4]*c[13]*c[11]-c[9]*c[7]*c[12]-c[15]*c[8]*c[5]+c[13]*c[8]*c[7]+c[11]*c[5]*c[12]; res[9]=-c[0]*c[9]*c[15]+c[0]*c[13]*c[11]+c[9]*c[3]*c[12]+c[15]*c[8]*c[1]-c[13]*c[8]*c[3]-c[11]*c[1]*c[12]; res[10]=c[0]*c[5]*c[15]-c[0]*c[13]*c[7]-c[5]*c[3]*c[12]-c[15]*c[4]*c[1]+c[13]*c[4]*c[3]+c[7]*c[1]*c[12]; res[11]=-c[0]*c[5]*c[11]+c[0]*c[9]*c[7]+c[5]*c[3]*c[8]+c[11]*c[4]*c[1]-c[9]*c[4]*c[3]-c[7]*c[1]*c[8]; res[12]=-c[4]*c[9]*c[14]+c[4]*c[13]*c[10]+c[9]*c[6]*c[12]+c[14]*c[8]*c[5]-c[13]*c[8]*c[6]-c[10]*c[5]*c[12]; res[13]=c[0]*c[9]*c[14]-c[0]*c[13]*c[10]-c[9]*c[2]*c[12]-c[14]*c[8]*c[1]+c[13]*c[8]*c[2]+c[10]*c[1]*c[12]; res[14]=-c[0]*c[5]*c[14]+c[0]*c[13]*c[6]+c[5]*c[2]*c[12]+c[14]*c[4]*c[1]-c[13]*c[4]*c[2]-c[6]*c[1]*c[12]; res[15]=c[0]*c[5]*c[10]-c[0]*c[9]*c[6]-c[5]*c[2]*c[8]-c[10]*c[4]*c[1]+c[9]*c[4]*c[2]+c[6]*c[1]*c[8]; double det=det4(c); mult4(res,1/det,res); } void dim32dim2(double * view,double * proj,double * model,double x0,double y0,double z0,double & i,double & j,double & dept){ double vect[4]={x0,y0,z0,1},res1[4],res2[4]; mult4(model,vect,res1); mult4(proj,res1,res2); i=res2[0]/res2[3]; // x and y are in [-1..1] j=res2[1]/res2[3]; dept=res2[2]/res2[3]; i=view[0]+(i+1)*view[2]/2; j=view[1]+(j+1)*view[3]/2; // x and y are the distance to the BOTTOM LEFT of the window } void Opengl::glRasterPos3d(double d1,double d2,double d3){ if (Opengl3d * ptr=dynamic_cast(this)) dim32dim2(ptr->view,ptr->proj,ptr->model,d1,d2,d3,ipos,jpos,depthpos); } void dim22dim3(double * view,double * proj_inv,double * model_inv,double i,double j,double depth_,double & x,double & y,double & z){ i=(i-view[0])*2/view[2]-1; j=(j-view[1])*2/view[3]-1; double res2[4]={i,j,depth_,1},res1[4],vect[4]; mult4(proj_inv,res2,res1); mult4(model_inv,res1,vect); x=vect[0]/vect[3]; y=vect[1]/vect[3]; z=vect[2]/vect[3]; } void Opengl3d::find_ij(double x,double y,double z,double & i,double & j,double & depth_) { dim32dim2(view,proj,model,x,y,z,i,j,depth_); #ifdef __APPLE__ j=this->y()+h()-j; i=i+this->x(); #else j=h()-j; #endif // cout << i << " " << j << endl; } void Opengl3d::find_xyz(double i,double j,double depth_,double & x,double & y,double & z) { #ifdef __APPLE__ j=this->y()+h()-j; i=i-this->x(); #else j=h()-j; #endif dim22dim3(view,proj_inv,model_inv,i,j,depth_,x,y,z); } double sqrt3over2=std::sqrt(double(3.0))/2; bool find_xmin_dx(double x0,double x1,double & xmin,double & dx){ if (x0>=x1) return false; double x0x1=x1-x0; dx=std::pow(10,std::floor(std::log10(x0x1))); if (x0x1/dx>6) dx *= 2; if (x0x1/dx<1.3) dx /= 5; if (x0x1/dx<3) dx /=2; if (!dx) return false; xmin=std::ceil(x0/dx)*dx; return true; } /* font data for drawing text borrowed from freeglut */ typedef struct tagSFG_StrokeVertex SFG_StrokeVertex; struct tagSFG_StrokeVertex { GLfloat X, Y; }; typedef struct tagSFG_StrokeStrip SFG_StrokeStrip; struct tagSFG_StrokeStrip { int Number; const SFG_StrokeVertex* Vertices; }; typedef struct tagSFG_StrokeChar SFG_StrokeChar; struct tagSFG_StrokeChar { GLfloat Right; int Number; const SFG_StrokeStrip* Strips; }; typedef struct tagSFG_StrokeFont SFG_StrokeFont; struct tagSFG_StrokeFont { char* Name; /* The source font name */ int Quantity; /* Number of chars in font */ GLfloat Height; /* Height of the characters */ const SFG_StrokeChar** Characters; /* The characters mapping */ }; #include "freeglut_stroke_roman.c" /* * Draw a stroke character */ void freeglutStrokeCharacter( int character ) { const SFG_StrokeChar *schar; const SFG_StrokeStrip *strip; int i, j; schar = fgStrokeRoman.Characters[ character ]; if (!schar) return; strip = schar->Strips; for( i = 0; i < schar->Number; i++, strip++ ) { glBegin( GL_LINE_STRIP ); for( j = 0; j < strip->Number; j++ ) glVertex3f( strip->Vertices[ j ].X, strip->Vertices[ j ].Y,0); glEnd( ); glBegin( GL_POINTS ); for( j = 0; j < strip->Number; j++ ) glVertex3f( strip->Vertices[ j ].X, strip->Vertices[ j ].Y, 0 ); glEnd( ); } glTranslatef( schar->Right, 0.0, 0.0 ); } void Opengl3d::draw_string(const string & s){ //COUT << "draw_string position " << ipos-w()/2. << "," << jpos-h()/2. << " " << s << endl; glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glScalef(.2/w(),.2/h(),1.0); glTranslatef(10*(ipos-w()/2.),10*(jpos-h()/2.),0); for (unsigned i=0;i=2){ double check[16]; mult4(model,&model_inv[0],&check[0]); mult4(model,&model_inv[4],&check[4]); mult4(model,&model_inv[8],&check[8]); mult4(model,&model_inv[12],&check[12]); for (int i=0;i<16;++i){ cout << model[i] << ","; if (i%4==3) cout << endl; } cout << endl; for (int i=0;i<16;++i){ cout << model_inv[i] << ","; if (i%4==3) cout << endl; } cout << endl; for (int i=0;i<16;++i){ cout << check[i] << ","; if (i%4==3) cout << endl; } cout << endl; } // drax bool fbox=(display_mode & 0x100); bool triedre=(display_mode & 0x200); glLineStipple(1,0xffff); glLineWidth(1); //gl_color(FL_RED); glColor3f(1,0,0); if (show_axes || triedre){ glLineWidth(3); glBegin(GL_LINES); glVertex3d(0,0,0); glVertex3d(1,0,0); glEnd(); } if (show_axes){ glLineWidth(1); glBegin(GL_LINES); if (twodim) glVertex3d(window_xmin,0,0); else glVertex3d(0,0,0); glVertex3d(window_xmax,0,0); glEnd(); } if (show_axes){ glBegin(GL_LINES); glVertex3d(window_xmin,window_ymin,window_zmin); glVertex3d(window_xmax,window_ymin,window_zmin); glVertex3d(window_xmin,window_ymax,window_zmin); glVertex3d(window_xmax,window_ymax,window_zmin); if (!twodim){ glVertex3d(window_xmin,window_ymin,window_zmax); glVertex3d(window_xmax,window_ymin,window_zmax); glVertex3d(window_xmin,window_ymax,window_zmax); glVertex3d(window_xmax,window_ymax,window_zmax); } glEnd(); } // gl_color(FL_GREEN); glColor3f(0,1,0); if (show_axes || triedre){ glLineWidth(3); glBegin(GL_LINES); glVertex3d(0,0,0); glVertex3d(0,1,0); glEnd(); } if (show_axes){ glLineWidth(1); glBegin(GL_LINES); if (twodim) glVertex3d(0,window_ymin,0); else glVertex3d(0,0,0); glVertex3d(0,window_ymax,0); glEnd(); } if (show_axes){ glBegin(GL_LINES); glVertex3d(window_xmin,window_ymin,window_zmin); glVertex3d(window_xmin,window_ymax,window_zmin); glVertex3d(window_xmax,window_ymin,window_zmin); glVertex3d(window_xmax,window_ymax,window_zmin); if (!twodim){ glVertex3d(window_xmin,window_ymin,window_zmax); glVertex3d(window_xmin,window_ymax,window_zmax); glVertex3d(window_xmax,window_ymin,window_zmax); glVertex3d(window_xmax,window_ymax,window_zmax); } glEnd(); } // gl_color(FL_BLUE); glColor3f(0,0,1); if (!twodim && (show_axes || triedre)){ glLineWidth(3); glBegin(GL_LINES); glVertex3d(0,0,0); glVertex3d(0,0,1); glEnd(); } if (show_axes && !twodim){ glLineWidth(1); glBegin(GL_LINES); glVertex3d(0,0,0); glVertex3d(0,0,window_zmax); glEnd(); } if (show_axes && !twodim){ glBegin(GL_LINES); glVertex3d(window_xmin,window_ymin,window_zmin); glVertex3d(window_xmin,window_ymin,window_zmax); glVertex3d(window_xmax,window_ymax,window_zmin); glVertex3d(window_xmax,window_ymax,window_zmax); glVertex3d(window_xmin,window_ymax,window_zmin); glVertex3d(window_xmin,window_ymax,window_zmax); glVertex3d(window_xmax,window_ymin,window_zmin); glVertex3d(window_xmax,window_ymin,window_zmax); glEnd(); } if(show_axes){ // maillage glColor3f(1,0,0); glRasterPos3d(1,0,0); draw_string(x_axis_name.empty()?"x":x_axis_name); glColor3f(0,1,0); glRasterPos3d(0,1,0); draw_string(y_axis_name.empty()?"y":y_axis_name); if (!twodim){ glColor3f(0,0,1); glRasterPos3d(0,0,1); draw_string(z_axis_name.empty()?"z":z_axis_name); } if (fbox || twodim){ double xmin,dx,x,ymin,dy,y,zmin,dz,z; find_xmin_dx(window_xmin,window_xmax,xmin,dx); find_xmin_dx(window_ymin,window_ymax,ymin,dy); find_xmin_dx(window_zmin,window_zmax,zmin,dz); // COUT << "maillage " << xmin << " " << dx << " " << ymin << " " << dy << endl; glLineStipple(1,0x3333); //gl_color(FL_CYAN); glColor3f(0,1,1); if (twodim){ double taille=30; for (y=ymin;y<=window_ymax;y+=dy){ for (x=xmin;x<=window_xmax;x+=dx){ #if 0 glBegin(GL_LINE_LOOP); glVertex3d(x-dx/taille,y-dy/taille,-1); glVertex3d(x+dx/taille,y-dy/taille,-1); glVertex3d(x+dx/taille,y+dy/taille,-1); glVertex3d(x-dx/taille,y+dy/taille,-1); glEnd(); #else glBegin(GL_LINES); glVertex3d(x-dx/taille,y,-1); glVertex3d(x+dx/taille,y,-1); glVertex3d(x,y+dy/taille,-1); glVertex3d(x,y-dy/taille,-1); glEnd(); #endif } } } else { for (z=zmin;z<=window_zmax;z+=2*dz){ for (y=ymin;y<=window_ymax;y+=2*dy){ glBegin(GL_LINES); glVertex3d(window_xmin,y,z); glVertex3d(window_xmax,y,z); glEnd(); } } for (z=zmin;z<=window_zmax;z+=2*dz){ for (x=xmin;x<=window_xmax;x+=2*dx){ glBegin(GL_LINES); glVertex3d(x,window_ymin,z); glVertex3d(x,window_ymax,z); glEnd(); } } for (x=xmin;x<=window_xmax;x+=2*dx){ for (y=ymin;y<=window_ymax;y+=2*dy){ glBegin(GL_LINES); glVertex3d(x,y,window_zmin); glVertex3d(x,y,window_zmax); glEnd(); } } } glColor3f(1,0,1); glPointSize(3); for (x=xmin;x<=window_xmax;x+=dx){ round0(x,window_xmin,window_xmax); glBegin(GL_POINTS); glVertex3d(x,window_ymin,window_zmin); glEnd(); glRasterPos3d(x,window_ymin,window_zmin); string tmps=giac::print_DOUBLE_(x,2)+x_axis_unit; draw_string(tmps); } for (y=ymin;y<=window_ymax;y+=dy){ round0(y,window_ymin,window_ymax); glBegin(GL_POINTS); glVertex3d(window_xmin,y,window_zmin); glEnd(); glRasterPos3d(window_xmin,y,window_zmin); string tmps=giac::print_DOUBLE_(y,2)+y_axis_unit; draw_string(tmps); } if (!twodim){ for (z=zmin;z<=window_zmax;z+=dz){ round0(z,window_zmin,window_zmax); glBegin(GL_POINTS); glVertex3d(window_xmin,window_ymin,z); glEnd(); glRasterPos3d(window_xmin,window_ymin,z); string tmps=giac::print_DOUBLE_(z,2)+z_axis_unit; draw_string(tmps); } } } } glClipPlane(GL_CLIP_PLANE0,plan0); glClipPlane(GL_CLIP_PLANE1,plan1); glClipPlane(GL_CLIP_PLANE2,plan2); glClipPlane(GL_CLIP_PLANE3,plan3); glClipPlane(GL_CLIP_PLANE4,plan4); glClipPlane(GL_CLIP_PLANE5,plan5); // mouse plan double normal_a,normal_b,normal_c; current_normal(normal_a,normal_b,normal_c); normal2plan(normal_a,normal_b,normal_c); double plan_x0,plan_y0,plan_z0,plan_t0; find_xyz(0,0,depth,plan_x0,plan_y0,plan_z0); plan_t0=normal_a*plan_x0+normal_b*plan_y0+normal_c*plan_z0; if (std::abs(plan_t0)=2){ GLfloat posf[4],direcf[4],ambient[4],diffuse[4],specular[4]; GLfloat expo,cutoff; double pos[4],direc[4]; glGetLightfv(GL_LIGHT0+i,GL_SPOT_EXPONENT,&expo); glGetLightfv(GL_LIGHT0+i,GL_SPOT_CUTOFF,&cutoff); glGetLightfv(GL_LIGHT0+i,GL_POSITION,posf); glGetLightfv(GL_LIGHT0+i,GL_SPOT_DIRECTION,direcf); direcf[3]=0; mult4(model_inv,posf,pos); tran4(model); mult4(model,direcf,direc); tran4(model); glGetLightfv(GL_LIGHT0+i,GL_AMBIENT,ambient); glGetLightfv(GL_LIGHT0+i,GL_DIFFUSE,diffuse); glGetLightfv(GL_LIGHT0+i,GL_SPECULAR,specular); cerr << "light " << i << ": " << " pos " << pos[0] << "," << pos[1] << "," << pos[2] << "," << pos[3] << " dir " << direc[0] << "," << direc[1] << "," << direc[2] << "," << direc[3] << " ambient " << ambient[0] << "," << ambient[1] << "," << ambient[2] << "," << ambient[3] << " diffuse " << diffuse[0] << "," << diffuse[1] << "," << diffuse[2] << "," << diffuse[3] << " specular " << specular[0] << "," << specular[1] << "," << specular[2] << "," << specular[3] << " exponent " << expo << " cutoff " << cutoff << endl; } } } if (!twodim && (display_mode & 0x20)){ glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } // now draw each object if ( (display_mode & 2) && !animation_instructions.empty()) indraw(animation_instructions[animation_instructions_pos % animation_instructions.size()]); if ( display_mode & 0x40 ) indraw(trace_instructions); if (display_mode & 1) indraw(plot_instructions); if (display_mode & 0x8){ glDisable(GL_LIGHTING); for (int i=0;i<8;++i) glDisable(GL_LIGHT0+i); } if (!twodim){ glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); } gen plot_tmp,title_tmp; //find_title_plot(title_tmp,plot_tmp,contextptr); //indraw(plot_tmp); if (mode==1 && pushed && push_in_area && in_area){ // draw segment between push and current glColor3f(1,0,0); double x,y,z; glBegin(GL_LINES); find_xyz(push_i,push_j,push_depth,x,y,z); glVertex3d(x,y,z); find_xyz(current_i,current_j,current_depth,x,y,z); glVertex3d(x,y,z); glEnd(); } glDisable(GL_CLIP_PLANE0); glDisable(GL_CLIP_PLANE1); glDisable(GL_CLIP_PLANE2); glDisable(GL_CLIP_PLANE3); glDisable(GL_CLIP_PLANE4); glDisable(GL_CLIP_PLANE5); /* if( show_axes){ gl_color((display_mode & 0x8)?FL_WHITE:FL_BLACK); glRasterPos3d(window_xmin,window_ymin,window_zmin); string tmps=giac::print_DOUBLE_(window_xmin,2)+","+giac::print_DOUBLE_(window_ymin,2)+","+giac::print_DOUBLE_(window_zmin,2); draw_string(tmps); glRasterPos3d(window_xmax,window_ymax,window_zmax); tmps=giac::print_DOUBLE_(window_xmax,2)+","+giac::print_DOUBLE_(window_ymax,2)+","+giac::print_DOUBLE_(window_zmax,2); draw_string(tmps); } */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glGetDoublev(GL_PROJECTION_MATRIX,proj); // projection matrix in columns inv4(proj,proj_inv); glGetDoublev(GL_MODELVIEW_MATRIX,model); // modelview matrix in columns inv4(model,model_inv); glGetDoublev(GL_VIEWPORT,view); if (display_mode & 0x8) glColor3f(0,0,0); else glColor3f(1,1,1); double td=title.size()*labelsize()/2; // fl_width(title.c_str()); glRasterPos3d(-0.4*td/w(),-1,depth-0.001); string mytitle(title); if (!is_zero(title_tmp) && function_final.type==_FUNC) mytitle=gen(symbolic(*function_final._FUNCptr,title_tmp)).print(contextptr); if (!mytitle.empty()) draw_string(mytitle); glRasterPos3d(-1,-1,depth-0.001); if (!args_help.empty() && args_tmp.size()<= args_help.size()){ draw_string(gettext("Click ")+args_help[giacmax(1,args_tmp.size())-1]); } glRasterPos3d(-0.98,0.87,depth-0.001); if (0 && show_axes && !twodim){ glColor3f(0,0,0); string tmps=gettext("mouse plan ")+giac::print_DOUBLE_(normal_a,3)+"x+"+giac::print_DOUBLE_(normal_b,3)+"y+"+giac::print_DOUBLE_(normal_c,3)+"z="+ giac::print_DOUBLE_(plan_t0,3); // cerr << tmps << endl; draw_string(tmps); // +" Z="+giac::print_DOUBLE_(-depth,3)); } if (below_depth_hidden){ /* current mouse position double i=Fl::event_x(); double j=Fl::event_y(); j=window()->h()-j; i=(i-view[0])*2/view[2]-1; j=(j-view[1])*2/view[3]-1; */ glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); xcas_color((display_mode & 0x8)?FL_WHITE:FL_BLACK,true); glBegin(GL_POLYGON); glVertex3d(-1,-1,depth); glVertex3d(-1,1,depth); glVertex3d(1,1,depth); glVertex3d(1,-1,depth); glEnd(); } if (!twodim) glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glFlush(); glFinish(); // COUT << "display end 4" << endl; } // if printing is true, we call gl2ps to make an eps file void Opengl3d::draw(){ // cerr << "graph3d" << endl; int locked=0; #ifdef HAVE_LIBPTHREAD locked=pthread_mutex_trylock(&interactive_mutex); #endif bool b,block; if (!locked){ b=io_graph(contextptr); io_graph(contextptr)=false; block=block_signal; block_signal=true; } //glEnable(GL_SCISSOR_TEST); //glScissor(clip_x, win->h()-clip_y-clip_h, clip_w, clip_h); // lower left // glViewport(clip_x, win->h()-clip_y-clip_h, clip_w, clip_h); // lower left glViewport(0,0, w(), h()); // lower left //gl_font(FL_HELVETICA,labelsize()); // GLint viewport[4]; // glGetIntergerv(GL_VIEWPORT,viewport); //fl_push_clip(clip_x,clip_y,clip_w,clip_h); display(); if (!locked){ block_signal=block; io_graph(contextptr)=b; #ifdef HAVE_LIBPTHREAD pthread_mutex_unlock(&interactive_mutex); #endif } } Opengl3d::~Opengl3d(){ } #if 0 int Opengl3d::in_handle(int event){ int res=Opengl::in_handle(event); if (event==FL_FOCUS){ if (!paused) --animation_instructions_pos; redraw(); } if (event==FL_FOCUS || event==FL_UNFOCUS) return 1; if (event==FL_KEYBOARD){ theta_z -= int(theta_z/360)*360; theta_x -= int(theta_x/360)*360; theta_y -= int(theta_y/360)*360; switch (Fl::event_text()?Fl::event_text()[0]:0){ case 'y': theta_z += delta_theta; q=q*euler_deg_to_quaternion_double(delta_theta,0,0); redraw(); return 1; case 'z': theta_x += delta_theta; q=q*euler_deg_to_quaternion_double(0,delta_theta,0); redraw(); return 1; case 'x': theta_y += delta_theta; q=q*euler_deg_to_quaternion_double(0,0,delta_theta); redraw(); return 1; case 'Y': theta_z -= delta_theta; q=q*euler_deg_to_quaternion_double(-delta_theta,0,0); redraw(); return 1; case 'Z': theta_x -= delta_theta; q=q*euler_deg_to_quaternion_double(0,-delta_theta,0); redraw(); return 1; case 'X': theta_y -= delta_theta; q=q*euler_deg_to_quaternion_double(0,0,-delta_theta); redraw(); return 1; case 'u': case 'f': depth += 0.01; mouse_position->redraw(); redraw(); return 1; case 'd': case 'n': depth -= 0.01; mouse_position->redraw(); redraw(); return 1; case 'h': case 'H': // hide below depth below_depth_hidden=true; redraw(); return 1; case 's': case 'S': // show below depth below_depth_hidden=false; redraw(); return 1; } } current_i=Fl::event_x(); current_j=Fl::event_y(); current_depth=depth; double x,y,z; find_xyz(current_i,current_j,current_depth,x,y,z); in_area=(x>=window_xmin) && (x<=window_xmax) && (y>=window_ymin) && (y<=window_ymax) && (z>=window_zmin) && (z<=window_zmax); if (event==FL_MOUSEWHEEL){ if (!Fl::event_inside(this)) return 0; if (show_axes){ // checking in_area seems to difficult, especially if mouse plan is not viewed depth = int(1000*(depth-Fl::e_dy *0.01)+.5)/1000.0; mouse_position->redraw(); redraw(); return 1; } else { if (Fl::e_dy<0) zoom(0.8); else zoom(1.25); return 1; } } if ( (event==FL_PUSH || push_in_area)) ; else in_area=false; if (event==FL_PUSH){ if (this!=Fl::focus()){ Fl::focus(this); handle(FL_FOCUS); } push_i=current_i; push_j=current_j; push_depth=current_depth; push_in_area = in_area; pushed = true; return 1; } if (!(display_mode & 0x80) && push_in_area && (event==FL_DRAG || event==FL_RELEASE)){ double x1,y1,z1,x2,y2,z2; find_xyz(current_i,current_j,current_depth,x1,y1,z1); find_xyz(push_i,push_j,push_depth,x2,y2,z2); double newx=x1-x2, newy=y1-y2, newz=z1-z2; round3(newx,window_xmin,window_xmax); round3(newy,window_ymin,window_ymax); round3(newz,window_zmin,window_zmax); window_xmin -= newx; window_xmax -= newx; window_ymin -= newy; window_ymax -= newy; window_zmin -= newz; window_zmax -= newz; push_i = current_i; push_j = current_j; redraw(); if (event==FL_RELEASE) pushed=false; return 1; } if (event==FL_DRAG){ if (push_in_area) return 0; dragi=current_i-push_i; dragj=current_j-push_j; redraw(); return 1; } if (event==FL_RELEASE){ pushed = false; if (push_in_area) return 0; dragi=current_i-push_i; dragj=current_j-push_j; if (paused && absint(dragi)<4 && absint(dragj)<4) ++animation_instructions_pos; else q=quaternion_double(dragi*180/h(),0,0)*rotation_2_quaternion_double(1,0,0,dragj*180/w())*q; dragi=dragj=0; redraw(); return 1; } return res; } #endif // set evryone to x void Opengl3d::orthonormalize(){ if (twodim){ double ratio=double(w())/h(); double dx=(window_xmax-window_xmin)/ratio; double dy=(window_ymax-window_ymin); double x=(window_xmax+window_xmin)/2; double y=(window_ymax+window_ymin)/2; if (dx>dy){ window_ymin=y-dx/2; window_ymax=y+dx/2; } else { window_xmin=x-ratio*dy/2; window_xmax=x+ratio*dy/2; } } else { window_ymax=window_xmax; window_ymin=window_xmin; window_zmax=window_xmax; window_zmin=window_xmin; } redraw(); } #if 0 void Opengl3d::geometry_round(double x,double y,double z,double eps,gen & tmp) { tmp= geometry_round_numeric(x,y,z,eps,approx); if (tmp.type==_VECT) tmp.subtype = _POINT__VECT; selected=nearest_point(plot_instructions,tmp,eps,contextptr); // if there is a point inside selected, stop there, // otherwise find a point that is near the line int pos=findfirstpoint(selection2vecteur(selected)); if (pos<0){ // line passing through tmp double a,b,c; double i,j,k; find_ij(x,y,z,i,j,k); k--; find_xyz(i,j,k,a,b,c); gen line(makevecteur(tmp,makevecteur(a,b,c)),_LINE__VECT); /* current_normal(a,b,c); vecteur v(makevecteur(a,b,c)); gen line(makevecteur(tmp,tmp+v),_LINE__VECT); */ vector sel2=nearest_point(plot_instructions,line,eps,contextptr); pos=findfirstpoint(selection2vecteur(sel2)); if (pos>=0){ selected.insert(selected.begin(),sel2[pos]); } else { vector::const_iterator it=sel2.begin(),itend=sel2.end(); for (;it!=itend;++it) selected.push_back(*it); } if (selected.empty()){ // add hyperplans const_iterateur it=plot_instructions.begin(),itend=plot_instructions.end(); for (int pos=0;it!=itend;++it,++pos){ gen tmp=remove_at_pnt(*it); if (tmp.is_symb_of_sommet(at_hyperplan)){ vecteur v=interdroitehyperplan(line,tmp,contextptr); if (!v.empty() && !is_undef(v.front())){ gen inters=evalf_double(remove_at_pnt(v.front()),1,contextptr); if (inters.type==_VECT && inters._VECTptr->size()==3){ vecteur & xyz=*inters._VECTptr; if (xyz[0].type==_DOUBLE_ && xyz[1].type==_DOUBLE_ && xyz[2].type==_DOUBLE_){ double x=xyz[0]._DOUBLE_val; double y=xyz[1]._DOUBLE_val; double z=xyz[2]._DOUBLE_val; if (x>=window_xmin && x<=window_xmax && y>=window_ymin && y<=window_ymax && z>=window_zmin && z<=window_zmax) selected.push_back(pos); } } } } } } } } #endif void Opengl3dcfg::store(const Opengl3d * ptr) { q=ptr->q; window_xmin=ptr->window_xmin; window_xmax=ptr->window_xmax; window_ymin=ptr->window_ymin; window_ymax=ptr->window_ymax; window_zmin=ptr->window_zmin; window_zmax=ptr->window_zmax; theta_x=ptr->theta_x; theta_y=ptr->theta_y; theta_z=ptr->theta_z; twodim=ptr->twodim; plot_instructions=ptr->plot_instructions; w=ptr->w(); h=ptr->h(); } Opengl3dcfg::Opengl3dcfg(const Opengl3d * ptr){ webglhandle=0; store(ptr); } void Opengl3dcfg::load(Opengl3d * ptr) const { ptr->q=q; ptr->window_xmin=window_xmin; ptr->window_xmax=window_xmax; ptr->window_ymin=window_ymin; ptr->window_ymax=window_ymax; ptr->window_zmin=window_zmin; ptr->window_zmax=window_zmax; ptr->theta_x=theta_x; ptr->theta_y=theta_y; ptr->theta_z=theta_z; ptr->twodim=twodim; ptr->plot_instructions=plot_instructions; ptr->resize(w,h); } int keys[1000]; Opengl3d * openglptr=0; vector v3d; bool pushed=false; void sdl_loop() { SDL_EnableUNICODE( 1 ); SDL_Event event; while (SDL_PollEvent(&event)) { switch(event.type) { case SDL_MOUSEMOTION: { SDL_MouseMotionEvent *m = (SDL_MouseMotionEvent*)&event; // printf("motion: %d,%d %d,%d\n", m->x, m->y, m->xrel, m->yrel); if (!openglptr->twodim && pushed){ // COUT << "pushed " << m->xrel << "," << m->yrel << endl; openglptr->q=quaternion_double(m->xrel,0,0)*rotation_2_quaternion_double(m->yrel,0,0,1)*openglptr->q; openglptr->draw(); } break; } case SDL_MOUSEBUTTONDOWN: { pushed=true; SDL_MouseButtonEvent *m = (SDL_MouseButtonEvent*)&event; // printf("button down: %d,%d %d,%d\n", m->button, m->state, m->x, m->y); break; } case SDL_MOUSEBUTTONUP: { pushed=false; SDL_MouseButtonEvent *m = (SDL_MouseButtonEvent*)&event; // printf("button up: %d,%d %d,%d\n", m->button, m->state, m->x, m->y); break; } case SDL_KEYDOWN: if (!keys[event.key.keysym.sym]) { keys[event.key.keysym.sym] = 1; //printf("key down: sym %d scancode %d\n", event.key.keysym.sym, event.key.keysym.scancode); } break; case SDL_KEYUP: if (keys[event.key.keysym.sym]) { keys[event.key.keysym.sym] = 0; //printf("key up: sym %d scancode %d\n", event.key.keysym.sym, event.key.keysym.scancode); if (event.key.keysym.sym=='q' || event.key.keysym.sym=='Q' || event.key.keysym.sym==SDLK_ESCAPE){ // deleting openglptr does not work, don't know why... //if (openglptr){ delete openglptr; openglptr=0;} emscripten_cancel_main_loop(); SDL_Quit(); } if (openglptr){ switch (event.key.keysym.sym){ case SDLK_MINUS: case SDLK_UNDERSCORE: openglptr->zoom(1.414); openglptr->draw(); break; case SDLK_PLUS: case SDLK_EQUALS: openglptr->zoom(0.707); openglptr->draw(); break; case 'a': case 'A': openglptr->autoscale(true); openglptr->draw(); break; case SDLK_LEFT: case 'l': case 'L': openglptr->q=quaternion_double(-1,0,0)*openglptr->q; openglptr->draw(); break; case SDLK_RIGHT: case 'r': case 'R': openglptr->q=quaternion_double(1,0,0)*openglptr->q; openglptr->draw(); break; case SDLK_UP: case 'u': case 'U': openglptr->q=rotation_2_quaternion_double(-1,0,0,1)*openglptr->q; openglptr->draw(); break; case SDLK_DOWN: case 'd': case 'D': openglptr->q=rotation_2_quaternion_double(1,0,0,1)*openglptr->q; openglptr->draw(); break; } } } break; } } } int init_screen(int & w,int & h,int no){ int fs; static int oldno=-RAND_MAX; if (oldno==no) return 0; oldno=no; if (no==-1) emscripten_get_canvas_size(&w, &h, &fs); // COUT << "init_screen " << w << " " << h << endl; if (w==0) w=400; if (h==0) h=250; if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { printf("Unable to initialize SDL: %s\n", SDL_GetError()); return 1; // "unable to init SDL"; } SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* //COUT << "glinit " << no << endl; int handle=glinit( w, h, 16, SDL_OPENGL ,no); if (no>=0 && no'9'){ cmd=*ch; ++ch; --s; } for (;i'9') return -1; } if (!openglptr) openglptr = new Opengl3d (400,250); if (s){ no=atoi(ch)-1; // COUT << no << " " << v3d.size() << endl; if (no>=v3d.size() || no<0) return -1; //int ctx=emscripten_webgl_get_current_context(); v3d[no].load(openglptr); //emscripten_webgl_make_context_current(ctx); } if (openglptr){ // COUT << "cmd " << cmd << " no " << no << endl; switch (cmd){ case 'q': // emscripten_cancel_main_loop(); // SDL_Quit(); break; case ' ': fs=init_screen(w,h,no); if (fs==0){ openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; case '-': fs=init_screen(w,h,no); if (fs==0){ openglptr->zoom(1.414); openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; case '+': fs=init_screen(w,h,no); if (fs==0){ openglptr->zoom(0.707); openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; case 'a': fs=init_screen(w,h,no); if (fs==0){ openglptr->autoscale(true); openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; case 'l': fs=init_screen(w,h,no); if (fs==0){ openglptr->q=quaternion_double(-1,0,0)*openglptr->q; openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; case 'r': fs=init_screen(w,h,no); if (fs==0){ openglptr->q=quaternion_double(1,0,0)*openglptr->q; openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; case 'u': fs=init_screen(w,h,no); if (fs==0){ openglptr->q=rotation_2_quaternion_double(-1,0,0,1)*openglptr->q; openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; case 'd': fs=init_screen(w,h,no); if (fs==0){ openglptr->q=rotation_2_quaternion_double(1,0,0,1)*openglptr->q; openglptr->draw(); SDL_GL_SwapBuffers(); SDL_Quit(); } break; } if (no>=0) v3d[no].store(openglptr); return 0; } context C; gen g(ch,&C); return giac_gen_renderer(g,&C); } int giac_gen_renderer(const gen & g_,GIAC_CONTEXT){ gen g=g_; gen last=g; while (last.type==_VECT && !last._VECTptr->empty()) last=last._VECTptr->back(); if (calc_mode(contextptr)!=1 && last.is_symb_of_sommet(at_pnt)){ int w=0,h=0,fs; if (!openglptr) openglptr = new Opengl3d (400,250); fs=init_screen(w,h,-1); if (fs) return fs; v3d.push_back(openglptr); // emscripten_set_canvas_size(640, 480); if (is3d(g)){ if (openglptr->twodim){ openglptr->theta_z=-110; openglptr->theta_x=-13; openglptr->theta_y=-95; openglptr->q=euler_deg_to_quaternion_double(-110,-13,-95); } openglptr->twodim=false; openglptr->plot_instructions=vecteur(1,g); openglptr->autoscale(true); // full view openglptr->draw(); //COUT << "reset g end" << endl; } else { openglptr->twodim=true; openglptr->theta_x=0; openglptr->theta_y=0; openglptr->theta_z=0; openglptr->q=euler_deg_to_quaternion_double(0,0,0); openglptr->plot_instructions=vecteur(1,g); openglptr->autoscale(true); // full view, autoscale with 2-d objects openglptr->plot_instructions=vecteur(1,convert3d(g,contextptr)); // draw in 3-d openglptr->draw(); //g.type=0; } v3d.back().store(openglptr); SDL_GL_SwapBuffers(); // emscripten_cancel_main_loop(); // emscripten_set_main_loop(sdl_loop, 0, 0); SDL_Quit(); // WARNING: library_sdl.js SDL_Quit() is buggy, it should be /* SDL_Quit: function() { _SDL_AudioQuit(); var keyboardListeningElement = Module['keyboardListeningElement'] || document; keyboardListeningElement.removeEventListener("keydown", SDL.receiveEvent); keyboardListeningElement.removeEventListener("keyup", SDL.receiveEvent); keyboardListeningElement.removeEventListener("keypress", SDL.receiveEvent); Module.print('SDL_Quit called (and ignored)'); }, */ } return v3d.size(); } #ifndef NO_NAMESPACE_GIAC } // namespace giac #endif // ndef NO_NAMESPACE_GIAC #ifdef EMCC const char * gettext(const char * s) { return s; } #endif #endif // ndef GIAC_GGB