/********************************************************************/ /* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno */ /* All rights reserved. */ /********************************************************************/ // MGOpenGLView.cpp : インプリメンテーション ファイル // #include "MGCLStdAfx.h" #include "mg/Tolerance.h" #include "mg/Position.h" #include "mg/AttribedGel.h" #include "mg/DnameControl.h" #include "mg/Transf.h" #include "mg/Straight.h" #include "mg/CSisect.h" #include "mg/Group.h" #include "mg/GelPositions.h" #include "mg/CParam_list.h" #include "topo/Edge.h" #include "topo/Loop.h" #include "topo/Face.h" #include "topo/Shell.h" #include "mgGL/OpenGLView.h" #include "mgGL/GLAttrib.h" #include "mgGL/SysGLList.h" #include "mgGL/glViewAttrib.h" #include "mgGL/VBO.h" #include "mgGL/glslprogram.h" using namespace std; #if defined(_DEBUG) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif namespace{ int DISPNAME_BASE_ID=1; } unsigned OpenGLStartDisplayName(){ return DISPNAME_BASE_ID; } ///////////////////////////////////////////////////////////////////////////// // MGOpenGLView namespace{ GLuint glErr; const glm::vec3 ORIGIN(0.,0.,0.); }; MGOpenGLView::MGOpenGLView( bool perspective //indicates if the view is pespective or not. ):m_parent_glView(0), m_viewAttrib(perspective), m_width(0), m_height(0), m_hRC(0),m_hDC(0),m_smooth(.001f), m_pick_aperture(5.), m_display_list(0),m_dpi(96.0f){ //Smoothness is about 100 division of the screen's width curve:m_smooth(.01). //Pick aperture is 5 pixels:m_pick_aperture(5.). draw_param().set_span_length(span_length()); //set_defalut_colors(); for(int i=0; i<3; i++) m_center_current[i]=0.; } //Construct from MGglViewAttrib. MGOpenGLView::MGOpenGLView( const MGglViewAttrib& glatr ):m_parent_glView(0), m_width(0), m_height(0),m_hRC(0),m_hDC(0), m_display_list(0),m_viewAttrib(glatr), m_smooth(.001f),m_pick_aperture(5.),m_dpi(96.0f){ //Smoothness is about 100 division of the screen's width curve:m_smooth(.01). //Pick aperture is 5 pixels:m_pick_aperture(5.). draw_param().set_span_length(span_length()); //set_defalut_colors(); for(int i=0; i<3; i++) m_center_current[i]=(float)glatr.m_center[i]; } MGOpenGLView::~MGOpenGLView(){ ::wglMakeCurrent(NULL, NULL); /// OpenGLのレンダリングコンテキストの開放のみ行うこと。 } //Copy the informations of glview2 into this. //Data that is not copied from glview2 are: //m_hRC(Rendering context), m_hDC(Device Context). //m_hRC and m_hDC can be set using setDCRC(). //m_sysgllist must be made by invoking openGL's //display list generation functions. void MGOpenGLView::copy(const MGOpenGLView& glview2){ m_Bcolor=glview2.m_Bcolor; m_Gcolor=glview2.m_Gcolor; m_smooth=glview2.m_smooth; m_pick_aperture=glview2.m_pick_aperture; m_viewAttrib=glview2.m_viewAttrib; setLookAtMat(); m_hRC=glview2.m_hRC; m_hDC=glview2.m_hDC; } void MGOpenGLView::copy(const MGglViewAttrib& glatr){ m_viewAttrib=glatr; setLookAtMat(); const MGVector& upV=glatr.view_up_vector(); MGUnit_vector XAxis=upV*eye_position(); for(int i=0; i<3; i++){ m_XAxis_current[i]=(float)XAxis[i]; m_center_current[i]=(float)glatr.m_center[i]; m_up_vector_current[i]=(float)upV[i]; } draw_param().set_span_length(span_length()); } //Return display list name. mgVBO* MGOpenGLView::display_list(){ if(!has_parent_OpenGLView()) return m_display_list; return get_parent_OpenGLView()->display_list(); } const MGDrawParam& MGOpenGLView::draw_param()const{ return mgVBOElement::getDrawParam(); } MGDrawParam& MGOpenGLView::draw_param(){ return mgVBOElement::getDrawParam(); } ///Set up drawing environment. void MGOpenGLView::setupDrawEnv(const MGColor& backColor, bool selection){ if(m_width>0 && !selection) glViewport(0,0,m_width,m_height); const float* Bcolr=backColor.color(); glClearColor(Bcolr[0], Bcolr[1], Bcolr[2], Bcolr[3]); glClearDepth(1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); if(selection){ glDisable(GL_BLEND); }else{ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } glEnable(GL_POLYGON_OFFSET_FILL);// ポリゴンオフセットフィルを設定 glPolygonOffset(1., 1.); } void MGOpenGLView::execDefaultStaticAttrib(){ glDisable(GL_CULL_FACE);// 両面を描画 mgGLSL::execStaticColorAttrib(Gcolor()); mgGLSL::execStaticLineWidth(1.f); mgGLSL::execStaticLineStipple(0,0); mgGLSL::execLightMode(0);//Light Off } //Draw the scene defined in this view including the current objects as hilighted. void MGOpenGLView::drawScene(const MGPickObjects* pobjs){ makeRCCurrent(); if(has_display_list()){ setupDrawEnv(Bcolor()); glm::mat4 modelViewMatSave=m_viewAttrib.m_modelViewMat;//Save bool initialize=true; setProjectionMat2GLSL(initialize);//Set the projection matrix. setModelViewMat2GLSL();//Set the model matrix. setProjModelViewMat2GLSL(); setNdcMat2GLSL(); setDpiFactor2GLSL(); mgGLSLProgram* glsl=mgGLSLProgram::getCurrentGLSLProgram(); glsl->setFuncType(mgGLSL::standard); //1. Construction plane drawing execDefaultStaticAttrib(); MGConstructionPlane& cpl=m_viewAttrib.cplane(); if(cpl.enabled()) cpl.draw(); // glClear(GL_DEPTH_BUFFER_BIT); //2. Target objects drawing execDefaultStaticAttrib(); MGOpenGLView* gltarget=this; if(m_parent_glView) gltarget=m_parent_glView; gltarget->m_display_list->draw(viewMode()); //3. the system generated display drawing. execDefaultStaticAttrib(); gltarget->m_sysgllist.draw_list(viewMode()); //4.draw command specific pictures of parent OpenGLView. drawCommandDrawer(gltarget->m_command_drawersCommon); //5.draw command specific pictures of this OpenGLView. drawCommandDrawer(m_command_drawersSpecific); //6. current objects highlighting. highlight(pobjs); m_viewAttrib.m_modelViewMat=modelViewMatSave;//Restore. ::SwapBuffers(m_hDC); }//if(has_display_list()) glFinish(); } ///Draw std::list<mgVBO*>. void MGOpenGLView::drawCommandDrawer( std::list<mgVBO*>& drawers ){ execDefaultStaticAttrib(); std::list<mgVBO*>::iterator i=drawers.begin(), ie=drawers.end(); for(; i!=ie; i++){ mgVBO* drawer=*i; if(drawer) drawer->draw(); } } //Highlight pobjs. void MGOpenGLView::highlight(const MGPickObjects* pobjsP){ if(!pobjsP) return; int ld=line_density(); GLboolean depthEnabled=glIsEnabled(GL_DEPTH_TEST); GLboolean blendEnabled=glIsEnabled(GL_BLEND); glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); const MGPickObjects& pobjs=*pobjsP; int nHL=pobjs.size(); for(int i=0; i<nHL; i++){ pobjs[i].hilight_using_display_list(ld); } if(depthEnabled) glEnable(GL_DEPTH_TEST); if(blendEnabled) glEnable(GL_BLEND); } ///Constructglm::lookAtMatrix from eye_position() and view_up_vector(). void MGOpenGLView::setLookAtMat(){ const MGPosition& eyeP=eye_position(); glm::vec3 eye(eyeP[0],eyeP[1],eyeP[2]); const MGVector& upP=view_up_vector(); glm::vec3 up(upP[0],upP[1],upP[2]); m_lookAtMat=glm::lookAt(eye,ORIGIN,up); } //get ModelView matrix of OpenGL. void MGOpenGLView::get_model_matrix( glm::mat4& modelMat //double modelMat[16] ///<OpenGL's model matrix )const{ glm::mat4 viewMat=m_lookAtMat*m_viewAttrib.m_modelViewMat; const MGPosition& cntr=center(); glm::vec3 cntr2(-cntr[0], -cntr[1], -cntr[2]); modelMat=glm::translate(viewMat,cntr2)*m_viewAttrib.m_PreCenterMat;//glTranslated; } ///get projection matrix, given the viewport data void MGOpenGLView::get_projection_matrix( const int vp[4],///<viewport data ={left, bottom, widht, height} glm::mat4& projMat ///<OpenGL's projection matrix )const{ double height2=view_volume_height()*.5; double wide2=height2*double(vp[2])/double(vp[3]); float left=float(m_viewAttrib.m_cx-wide2), right=float(m_viewAttrib.m_cx+wide2), bottom=float(m_viewAttrib.m_cy-height2), top=float(m_viewAttrib.m_cy+height2); float znear=(float)view_volume_near(), zfar=(float)view_volume_far(); if(is_perspective()){ projMat=glm::frustum(left,right,bottom,top,znear,zfar); }else{ projMat=glm::ortho(left,right,bottom,top,znear,zfar); } } //get viewport of OpenGL. void MGOpenGLView::get_viewport( glm::ivec4& vp//int vp[4] //OpenGL's projection matrix )const{ get_viewport(&vp[0]); } void MGOpenGLView::get_viewport( int vp[4] ///<(vp[0],vp[1]) is (left,bottom) coordinates. ///<(vp[2],vp[3]) is (width, height) of the viewport. )const{ vp[0]=0; vp[1]=0; vp[2]=m_width; vp[3]=m_height; } ///get window(m_width, m_height); void MGOpenGLView::get_window(int& width, int& height)const{ width=m_width; height=m_height; } //Get the surface parameter value uv(u,v) where screen coordinate (sx,sy) is projected on. //If no projection points are found, the nearest point to a perimeter of surf will //be returned. bool MGOpenGLView::get_surface_parameter_glv( const MGFSurface& surf, int sx, int sy, //Screen coordinates. (left, bottom) is (0,0). MGPosition& uv //surface parameter (u,v) where (sx,sy) is projected on will be returned. )const{ MGStraight sl; unproject_to_sl_glv(sx,sy,sl); MGCSisect_list csis=surf.isect(sl); if(csis.size()){ uv=csis.front().param_surface(); return true; } uv=surf.closest_on_boundary(sl); return false; } //Test if this has a display list to draw. bool MGOpenGLView::has_display_list()const{ if(m_display_list) return true; if(!has_parent_OpenGLView()) return false; return get_parent_OpenGLView()->has_display_list(); } //Initialize the viewing environment. //When the eye position is necessary to update, setEyePositionUpVector() must be invoked //before initializeViewingEnvironmentByBox since the current eye position direction is used. //Initialization is done by the parameter box. void MGOpenGLView::initializeViewingEnvironmentByBox( const MGBox& box ){ m_viewAttrib.compute_viewing_environment(box); setLookAtMat(); const MGPosition& cntr=center(); for(int i=0; i<3; i++) m_center_current[i]=(float)cntr[i]; draw_param().set_span_length(span_length()); } //Update the center and the scale of the view. ///The pespectiveness and the cplane are unchanged. void MGOpenGLView::updateCenterScalle( const MGPosition& center, double diameter///<diameter of the view. This is set to m_diameter. ///<diameter of the sphere that sorround the model. ///<If diameter<=0. the current diameter is not updated. ){ for(int i=0; i<3; i++) m_center_current[i]=(float)center[i]; if(diameter<=0.) diameter=m_viewAttrib.diameter(); m_viewAttrib.compute_viewing_environment(center,diameter); setLookAtMat(); } //Initialize the viewing environment to view objects projected onto a plane. ///The pespectiveness is unchanged. //center of the object is the origin of the plane. void MGOpenGLView::update_viewing_environment( const MGPlane& plane, double diameter//diameter of the view. This is set to m_diameter. ///<diameter of the sphere that sorround the model. ){ const MGPosition& cntr=plane.root_point(); for(int i=0; i<3; i++) m_center_current[i]=(float)cntr[i]; if(diameter<=0.) diameter=m_viewAttrib.diameter(); MGPosition eyeP(0.,0.,1.); MGVector upVector(0.,1.,0.); setEyePositionUpVector(eyeP,upVector); m_viewAttrib.compute_viewing_environment(cntr,diameter); setLookAtMat(); MGMatrix mat; mat.set_xy_axis(plane.u_deriv(), plane.v_deriv()); glm::mat4 glmat;//double glmat[16]; mat.convert_to_glMatrix(glmat); m_viewAttrib.m_modelViewMat*=glmat;//glMultMatrixd(glmat); m_viewAttrib.m_cplane.set_plane(plane); } //locate the screen coordinate (x,y) in the 3D world coordinate. //(x, y)'s origin is (left, bottom) of the screen. MGPosition MGOpenGLView::locate_glv(int x, int y, MGPosition* uv)const{ MGStraight sl; unproject_to_sl_glv(x,y,sl); const MGConstructionPlane& pl=cplane(); MGPosition xyz,uv2; xyz=pl.locate(sl,uv2); if(uv) *uv=uv2; return xyz; } //construct the construction plane along with its display list. void MGOpenGLView::make_construction_plane( const MGPosition& mid, //center of the construction plane. const MGVector& uderi, //u-axis vector of the construction plane. const MGVector& vderi, //v-axis vector of the construction plane. double uspan, //span length between the lines along u-axis. double vspan, //span length between the lines along v-axis. int ulnum, //number of lines to draw along u-axis. int vlnum //number of lines to draw along v-axis. ){ m_viewAttrib.m_cplane.set_grid_data(MGPlane(uderi,vderi,mid), uspan,vspan,ulnum,vlnum); } //Make openGL display list in this glview. void MGOpenGLView::make_display_list(const MGContext& ctx,const MGGroup& grp){ //Generate OpenGL display list. if(has_parent_OpenGLView()) return; setDrawParam(ctx); m_display_list=grp.dlist_name(); grp.make_display_list(viewMode()); } #define IS_SELECTION true static const MGColor NullColor(0.,0.,0.,0.); //Function's return value is the number of hit objects. int MGOpenGLView::pick_to_select_buf( const float center[2],///<Screen coordinates. (left, bottom) is (0,0). const float delta[2],///<(aperturex, aperturey). mgVBO* display_list, //display list that includes pick objects. std::set<unsigned>& selected///Selected data will be returned. This data consist of ///the data set by selectName. ){ glm::ivec4 viewportOld; get_viewport(viewportOld);//glGetIntegerv(GL_VIEWPORT,&viewportOld[0]);//Current viewport glm::vec2 c2(center[0],center[1]); glm::vec2 delta2(delta[0],delta[1]); glm::mat4 projMatSave=m_projMat;//Save//glPushMatrix(); m_projMat=glm::pickMatrix(c2,delta2,viewportOld); setProjectionMat2GLSL(); glm::mat4 modelViewMatSave=m_viewAttrib.m_modelViewMat;//Save//glPushMatrix(); setModelViewMat2GLSL();//set_model_matrix setProjModelViewMat2GLSL(); setNdcMat2GLSL(); setDpiFactor2GLSL(); //Set the target selection viewport. delta2*=.5; glm::vec2 lowerLeft=c2-delta2;; int viewport[4]= {int(lowerLeft[0]+.5), int(lowerLeft[1]+.5),GLsizei(delta[0]), GLsizei(delta[1])}; int& x=viewport[0]; int& y=viewport[1]; int& w=viewport[2]; int& h=viewport[3]; int xOld=viewportOld[0]; int yOld=viewportOld[1]; int wOld=viewportOld[2]; int hOld=viewportOld[3]; if(x<xOld) x=xOld; if((x+w)>(xOld+wOld)) w=xOld+wOld-x; if(y<yOld) y=yOld; if((y+h)>(yOld+hOld)) h=yOld+hOld-y; if(h<=0 || w<=0) return 0; glViewport(x,y,w,h); glDrawBuffer(GL_BACK); //if((glErr=glGetError()) != GL_NO_ERROR){ // CString msg(gluErrorString(glErr)); // COUT<<"MGOpenGLView::pick_to_select_buf::glDrawBuffer::"<<(TCAST)msg<<std::endl; //} setupDrawEnv(NullColor,IS_SELECTION); //Target objects drawing display_list->selectionDraw(viewMode()); glReadBuffer(GL_BACK); extractSelected(viewport,selected); m_viewAttrib.m_modelViewMat=modelViewMatSave;//Restore.//glPopMatrix(); m_projMat=projMatSave;//glPopMatrix(); glViewport(xOld,yOld,wOld,hOld); return (int)selected.size(); } //Pick objects in the display list generated by make_display_list. //Function's return value is MGPickObject vector in m_CurrentObjects member data. //All the objects which were inside the pick aperture will be output. //This data can be accessed using current_object(), or current_PickObject(). //pick will invoke makeRCCurrent(); MGPickObjects MGOpenGLView::pick_glv( const float center[2],///<Screen coordinates. (left, bottom) is (0,0). float aperturex,///<specifies pick aperture of x and y. float aperturey,///<When <=0. value is specified, default value(the value ///<obtained by pick_aperture() will be used. const MGAbstractGels& objtypes ){ MGPickObjects pobjs; if(!has_display_list()) return pobjs; if(aperturex<=0.) aperturex=pick_aperture(); if(aperturey<=0.) aperturey=pick_aperture(); float aperture[2]={aperturex,aperturey}; std::set<unsigned> selected; makeRCCurrent(); mgVBO* vbo=display_list(); int objnum=pick_to_select_buf(center,aperture,vbo,selected); if(!objnum) return pobjs; MGDNameControl& dnc=getDNameControlInstance(); std::vector<MGPickObject> shels;//To exclude the same shell picking, shell's pickObject are stored. std::set<unsigned>::iterator i=selected.begin(), iend=selected.end(); for(; i!=iend; i++){ mgVBO* pickedi=dnc.VBO_from_dlistName(*i); if(!pickedi) continue; MGAttribedGel* objA=pickedi->gel();//Lowest name is MGObject. if(!objA) continue; MGObject* obj=dynamic_cast<MGObject*>(objA);//Lowest object pointer. if(!obj) continue;//This must not happen(Lowest name is MGObject). std::vector<mgVBO*> vbos; if(!pickedi->buildVBOHierarchy(*vbo,vbos)) continue;//This must not happen. size_t n=vbos.size();assert(n>=2); MGAttribedGel* grpA=vbo->gel();assert(grpA); MGGroup* grp=static_cast<MGGroup*>(grpA);//Top MGGroup. MGPickObject pobj(grp,obj); for(size_t k=1; k<=n-2; k++){ mgVBO* vbok=vbos[k]; MGAttribedGel* gl=vbok->gel();//Lower gel is MGGroup or MGShell. pobj.append_lower_gel(gl); } if(!pobj.is_shell_face()){ if(obj->type_is(objtypes)) pobjs.push_back(pobj); }else{ //When is_shell_face. MGShell* shelli=pobj.get_shell_of_shell_face(); if(!shelli->type_is(objtypes)) continue; //Exclude the same shell and employ the 1st face in the shell. int nzs=(int)shels.size(), j; for(j=0; j<nzs; j++) if(shels[j].get_shell_of_shell_face()==shelli) break; if(j==nzs)//if the same shell not found shels.push_back(pobj); else//if found continue; } } size_t nshel=shels.size(); for(size_t j=0; j<nshel; j++) pobjs.push_back(shels[j]); return pobjs; } class mgPerimeterSelection: public mgVBO{ public: const MGSurface& m_surf; const MGDrawParam& m_dparam; mgPerimeterSelection(const MGSurface& surf,const MGDrawParam& para) :m_surf(surf),m_dparam(para){}; ///m_gelの描画データ作成のみをおこなう。 ///すでに作成済みであっても強制的に再作成を行う。 ///m_gel=0のときはなにもしない。 void make_display_list(MGCL::VIEWMODE viewMode=MGCL::DONTCARE); ///描画関数selectionDraw()は、Object選択のための表示処理をする。 ///通常のdrawとの相違:///Colorとしてm_bufferIDを用い、size処理以外の ///attributesの処理(normal, texture, color)をしない。 void selectionDraw(MGCL::VIEWMODE viewMode=MGCL::DONTCARE); }; void mgPerimeterSelection::make_display_list(MGCL::VIEWMODE viewMode){ clearElements(mgVBO::BOTH); int nperi=m_surf.perimeter_num(); int ldensity=m_dparam.line_desity_wire_face(); for(int i=0; i<nperi; i++){ std::unique_ptr<MGCurve> peri(m_surf.perimeter_curve(i)); peri->drawWire(*this,ldensity); } setDirty(false); } void mgPerimeterSelection::selectionDraw(MGCL::VIEWMODE viewMode){ if(!is_made()) make_display_list(); mgGLSLProgram* glsl=mgGLSLProgram::getCurrentGLSLProgram(); glsl->setFuncType(mgGLSL::Select); execModelTypeAttrib(); size_t n=m_elements.size(); for(unsigned i=0; i<n; i++){ mgGLSL::setColorAsSelectionName(i+1); mgVBOElement* elmi=m_elements[i]; elmi->selectionDraw(MGCL::WIRE); } } //Pick a perimeter of the surface surf. That is, obtain the perimeter number //that passes input (sx,sy) when drawn in the current view matrix. //Function's return value is perimeter number picked. //When no perimeters are picked, -1 will be returned. int MGOpenGLView::pick_perimeter_glv( const MGSurface& surf, int sx, int sy, ///<Screen coordinates. (left, bottom) is (0,0). MGPosition* uv, //surface parameter (u,v) nearest to (sx,sy) will be returned. float aperturex,//specifies pick aperture of x and y. float aperturey//When <=0. value is specified, default value(the value //obtained by pick_aperture() will be used. ){ mgPerimeterSelection periSel(surf,draw_param()); int perimeter=-1; if(aperturex<=0.) aperturex=pick_aperture(); if(aperturey<=0.) aperturey=pick_aperture(); std::set<unsigned> selected; float center[2]={(float)sx,(float)sy}; float delta[2]={aperturex,aperturey}; pick_to_select_buf(center,delta,&periSel,selected); int objnum= (int)selected.size(); if(objnum>0){ perimeter=*(selected.begin())-1; if(uv){ // if parameter is needed double t; std::unique_ptr<MGCurve> peri(surf.perimeter_curve(perimeter)); get_near_position(peri.get(),center,t); *uv=surf.perimeter_uv(perimeter,t); } } return perimeter; } class mgEdgeSelection: public mgVBO{ public: const MGLoop& m_loop; const MGDrawParam& m_dparam; mgEdgeSelection(const MGLoop& loop,const MGDrawParam& para) :m_loop(loop),m_dparam(para){}; ///m_gelの描画データ作成のみをおこなう。 ///すでに作成済みであっても強制的に再作成を行う。 ///m_gel=0のときはなにもしない。 void make_display_list(MGCL::VIEWMODE viewMode=MGCL::DONTCARE); ///描画関数selectionDraw()は、Object選択のための表示処理をする。 ///通常のdrawとの相違:///Colorとしてm_bufferIDを用い、size処理以外の ///attributesの処理(normal, texture, color)をしない。 void selectionDraw(MGCL::VIEWMODE viewMode=MGCL::DONTCARE); }; void mgEdgeSelection::make_display_list(MGCL::VIEWMODE viewMode){ int ldensity=m_dparam.line_desity_wire_face(); int nedge=m_loop.number_of_edges(); for(int j=0; j<nedge; j++){ const MGEdge* edge2=m_loop.edge(j); MGEdge& be=*(edge2->make_binder_with_curve()); MGTrimmedCurve cij=be.trimmed_curve(); cij.drawWire(*this,ldensity); } setDirty(false); } void mgEdgeSelection::selectionDraw(MGCL::VIEWMODE viewMode){ if(!is_made()) make_display_list(); mgGLSLProgram* glsl=mgGLSLProgram::getCurrentGLSLProgram(); glsl->setFuncType(mgGLSL::Select); execModelTypeAttrib(); size_t n=m_elements.size(); for(unsigned i=0; i<n; i++){ mgGLSL::setColorAsSelectionName(i+1); mgVBOElement* elmi=m_elements[i]; elmi->selectionDraw(MGCL::WIRE); } } //Pick an edge of the face f. That is, obtain the edge number //that passes input (sx,sy) when drawn in the current view matrix. //Function's return value is the edge pointer picked. //When no edges are picked, null will be returned. const MGEdge* MGOpenGLView::pick_edge_glv( const MGFace& f, int sx, int sy, ///<Screen coordinates. (left, bottom) is (0,0). MGPosition* uv, //surface parameter (u,v) nearest to (sx,sy) will be returned. float aperturex,//specifies pick aperture of x and y. float aperturey//When <=0. value is specified, default value(the value //obtained by pick_aperture() will be used. ){ const MGEdge* edge=0; if(aperturex<=0.) aperturex=pick_aperture(); if(aperturey<=0.) aperturey=pick_aperture(); glm::ivec4 viewport;//GLint viewport[4]; get_viewport(viewport);//glGetIntegerv(GL_VIEWPORT,&viewport[0]); float centr[2]={float(sx),float(sy)}; glm::vec2 c2(centr[0],centr[1]); glm::vec2 delta(aperturex,aperturey); m_projMat=glm::pickMatrix(c2,delta,viewport); int nloop=f.number_of_loops(); for(int i=0; i<nloop; i++){ const MGLoop& li=*(f.loop(i)); mgEdgeSelection edgeSel(li,draw_param()); std::set<unsigned> selected; pick_to_select_buf(centr,&delta[0],&edgeSel,selected); size_t objnum= selected.size(); if(objnum){ edge=li.edge(*selected.begin()-1); if(uv){ MGEdge& be=*(edge->make_binder_with_curve()); MGTrimmedCurve cij=be.trimmed_curve(); double t; get_near_position(&cij,centr,t); *uv=edge->eval(be.param_pcell(t)); } break; } } return edge; } //Determine if screen coordinate (sx,sy) is closer to the start point or to the end //of the curve curve. //Functin's return value is 0: if start point, 1: if end point. int MGOpenGLView::pick_start_end_glv( const MGCurve& curve, int sx, int sy //Screen coordinates. (left, bottom) is (0,0). ){ MGStraight sl; unproject_to_sl_glv(sx,sy,sl); MGPosition P0=curve.start_point(), P1=curve.end_point(); if(sl.distance(P0)<=sl.distance(P1)) return 0; return 1; } ///Extract selectionName data from the frame buffer drawn by selectionDraw(); void MGOpenGLView::extractSelected( const int viewport[4],///Viewport of the selection target window. std::set<unsigned>& selected///Selected name data will be returned. /// This data consist of the data set by selectionDraw. ){ GLint x=viewport[0], y=viewport[1]; GLsizei width=viewport[2], height=viewport[3]; int numPixels=width*height; unsigned* pixels=new unsigned[numPixels]; for(int i=0; i<numPixels; i++) pixels[i]=0; //glFlush(); glReadPixels(x,y,width,height,GL_RGBA,GL_UNSIGNED_BYTE,pixels); //if((glErr=glGetError()) != GL_NO_ERROR){ // CString msg(gluErrorString(glErr)); // COUT<<"MGOpenGLView::extractSelected::glReadPixels::"<<(TCAST)msg<<std::endl; //} for(int i=0; i<numPixels; i++){ mgGLSLProgram::SELECT_NAME nub; nub.uiName=pixels[i]; unsigned pixeli=nub.uiName;//unsigned pixeli=pixels[i]; if(pixeli!=0){ selected.insert(pixeli); } } delete[] pixels; } //Project world coordinates to OpenGL's screen coordinates. //If modelMat, projMat, or vp is not input, project will ask OpenGL to get them. //Generally, users of project are recommended to get modelMat, projlMat, or //vp, and input them to project if continuous multiple use of project will take place. //If one of modelMat, projlMat, or vp is not input, makeRCCurrent() must be invoked //before use of project. void MGOpenGLView::project( const MGPosition& world, MGPosition& screen, const glm::mat4* modelMat, //OpenGL's model matrix const glm::mat4* projlMat, //OpenGL's projection matrix const glm::ivec4* vp //OpenGL's viewport ) const{ const glm::mat4* model=modelMat; const glm::mat4* proj=projlMat; const glm::ivec4* vp2=vp; glm::mat4 modelM, projM; glm::ivec4 vp3; if(!vp2){ vp2=&vp3; get_viewport(vp3); } if(!proj){ proj=&projM; const int* vport=&((*vp2)[0]); get_projection_matrix(vport,projM); } if(!model){ model=&modelM; get_model_matrix(modelM); } screen.resize(3); glm::vec3 obj(world[0],world[1],world[2]); glm::vec3 v=glm::project(obj,*model,*proj,*vp2); screen=MGPosition(v[0], v[1], v[2]); } //Rotate the current view by the angle along the vector(x,y,z), //performs a counterclockwise rotation of angle angle about //the vector from the origin through the point (x, y, z). ///The rotation matrix made is stored in m_PreCenterMat. void MGOpenGLView::rotate(float angle, float x, float y, float z){ const MGPosition& c=center(); glm::vec3 cntr((float)c[0],(float)c[1],(float)c[2]); glm::mat4& preM=m_viewAttrib.m_PreCenterMat; preM=glm::translate(preM,cntr); preM=glm::rotate(preM,angle,glm::vec3(x,y,z));//Rotate around center. preM=glm::translate(preM,-cntr); } ///Rotate the current view by the angle along vector around center. ///Performs a counterclockwise rotation. ///The rotation matrix made is stored in m_PreCenterMat. void MGOpenGLView::rotate(float angle, float vector[3], const MGPosition& center){ glm::vec3 vec(vector[0],vector[1],vector[2]); glm::vec3 cntr((float)center[0],(float)center[1],(float)center[2]); glm::mat4& preM=m_viewAttrib.m_PreCenterMat; preM=glm::translate(preM,cntr); preM=glm::rotate(preM,angle,vec);//Rotate around center. preM=glm::translate(preM,-cntr); } ///Rotate the current view ///by the angle[0] around m_up_vector_current(Y-direction of the screen), ///and by the angle[1] around m_XAxis_current(view-up-vector*eye-vector=X-direction of the screen). ///Rotation is performed around m_center_current. ///The rotation matrix made is stored in m_PreCenterMat. void MGOpenGLView::rotate(const float angle[2]){ glm::mat4& preM=m_viewAttrib.m_PreCenterMat; preM=glm::translate(preM,m_center_current); preM=glm::rotate(preM,angle[1],m_XAxis_current);//Rotate around center. preM=glm::rotate(preM,angle[0],m_up_vector_current);//Rotate around center. preM=glm::translate(preM,-m_center_current); } void MGOpenGLView::set_center_current(int x, int y){ MGStraight sl1, sl2; unproject_to_sl_glv(x,y,sl1); const MGPosition& C=center(); MGPosition centrOnCursor=sl1.eval(sl1.param(C)); for(int i=0; i<3; i++) m_center_current[i]=(float)centrOnCursor[i]; //std::cout<<",C=("<<m_center_current[0]<<","<<m_center_current[1]<<","<<m_center_current[2]<<")"; unproject_to_sl_glv(x,y+200,sl2); MGPosition centerUp=sl2.eval(sl2.param(C)); MGVector upV(3); for(int i=0; i<3; i++){ upV(i)=centerUp[i]-m_center_current[i]; } //std::cout<<",Y=("<<upV[0]<<","<<upV[1]<<","<<upV[2]<<")"; //double error1=upV.len(); upV.set_unit(); for(int i=0; i<3; i++){ m_up_vector_current[i]=(float)upV[i]; } const MGVector& eyeP=sl1.direction(); MGVector X=upV*eyeP.normalize();//Screnn's X-direction //std::cout<<"X=("<<X[0]<<","<<X[1]<<","<<X[2]<<")"; //double error2=X.len(); //std::cout<<"errot1,2="<<error1<<","<<error2<<std::endl; X.set_unit(); for(int i=0; i<3; i++) m_XAxis_current[i]=(float)X[i]; } ///Scale the current view by the factor and the view center. void MGOpenGLView::scale( double factor, ///< saling factor. int* center///< scaling center of the screen coordinate (sx, sy) on the view plane, ///where sx=center[0], sy=center[1] if center!=0. ){ if(center){ GLint vp[4]; get_viewport(vp);//glGetIntegerv(GL_VIEWPORT,vp); double wx,wy; screen_to_world(vp+2,double(center[0]),double(center[1]),wx,wy); m_viewAttrib.m_cx=wx-(wx-m_viewAttrib.m_cx)/factor; m_viewAttrib.m_cy=wy-(wy-m_viewAttrib.m_cy)/factor; } m_viewAttrib.m_scale*=factor; } //Get redering context. //RCは固定が前提としているので、もしdcがセットされているものにdcをsetすると //dcだけを変更することとなる void MGOpenGLView::setDCRC(HDC dc, HGLRC rc){ m_hDC=dc; m_hRC=rc; makeRCCurrent(); } void MGOpenGLView::set_window(int width, int height){ if(width<=0 || height<=0) return; m_width=width;m_height=height; } ///Set ProjModelView matrix to GLSL using setUniform(); void MGOpenGLView::setProjModelViewMat2GLSL(){ glm::mat4 ProjModelView=m_projMat*m_viewAttrib.m_modelViewMat; mgGLSLProgram* glsl=mgGLSLProgram::getCurrentGLSLProgram(); glsl->setUniform(mgGLSLProgram::modelViewProjMatrix, ProjModelView); } //Set Frustum of OpenGL. void MGOpenGLView::setProjectionMat2GLSL(bool initialize){ GLint vp[4]; get_viewport(vp); glm::mat4 projMat; get_projection_matrix(vp,projMat); if(initialize) m_projMat=projMat; else m_projMat*=projMat; mgGLSLProgram* glsl=mgGLSLProgram::getCurrentGLSLProgram(); glsl->setUniform(mgGLSLProgram::projMatrix,m_projMat); } //Set Model_View and Projection matrix of OpenGL. void MGOpenGLView::setModelViewMat2GLSL(){ get_model_matrix(m_viewAttrib.m_modelViewMat); mgGLSLProgram* glsl=mgGLSLProgram::getCurrentGLSLProgram(); glsl->setUniform(mgGLSLProgram::modelViewMatrix,m_viewAttrib.m_modelViewMat); // Normal Matrix ModelViewMatrixとNormalMatrixはセットです。 glm::mat3 normalMatrix = glm::mat3(m_viewAttrib.m_modelViewMat); glsl->setUniform(mgGLSLProgram::normalMatrix,normalMatrix); } // Anchor Point変換用の係数設定 void MGOpenGLView::setNdcMat2GLSL(){ glm::ivec4 vp; get_viewport(vp); float widthHalf = float(vp[2]- vp[0])*0.5f; float heightHalf = float(vp[3]-vp[1])*0.5f; glm::vec3 scaleFactor( 1.0f/widthHalf, 1.0f/heightHalf, 1.0f); glm::mat4 ndcMtx = glm::scale( glm::translate(glm::mat4(), glm::vec3(-widthHalf, -heightHalf, 0.0f)), scaleFactor ); mgGLSLProgram::getCurrentGLSLProgram()->setUniform(mgGLSLProgram::ndcMarix, ndcMtx); glm::mat3 ndcScaleMtx = glm::mat3(ndcMtx); mgGLSLProgram::getCurrentGLSLProgram()->setUniform(mgGLSLProgram::ndcScaleMatrix,ndcScaleMtx ); } void MGOpenGLView::setDpiFactor2GLSL(){ // output float func = m_dpi/72.0f; mgGLSLProgram::getCurrentGLSLProgram()->setUniform(mgGLSLProgram::dpiFactor,func ); } //Set the parent MGOpenGLView. void MGOpenGLView::set_parent_OpenGLView(MGOpenGLView* parent){ m_parent_glView=parent; } //Convert the screen coordinate (sx, sy) to world coordinate (wx, wy) on the //view plane. void MGOpenGLView::screen_to_world( int wh[2], //width(wh[0]) and height(wh[1]) of the screen. double sx,double sy, double& wx, double& wy )const{ double sheight=double(wh[1]), swidth=double(wh[0]); double wsratio=view_volume_height()/sheight; wx=m_viewAttrib.m_cx+wsratio*(sx-swidth*.5); wy=m_viewAttrib.m_cy+wsratio*(sy-sheight*.5); } //Translate the current view by (dx, dy). void MGOpenGLView::translate(double dx, double dy){ m_viewAttrib.m_cx-=dx/m_viewAttrib.m_scale; m_viewAttrib.m_cy-=dy/m_viewAttrib.m_scale; } //Translate the current view by (dx, dy) without current scale. void MGOpenGLView::translate_without_scale(double dx, double dy){ m_viewAttrib.m_cx-=dx; m_viewAttrib.m_cy-=dy; } //Translate and scale the current view. //(x0, y0) to (x1,y1) is the rectangle of screen coordinate whose origin is //(left,bottom). void MGOpenGLView::pan_zoom(int x0, int y0, int x1, int y1){ makeRCCurrent(); int dx=x1-x0, dy=y1-y0; if(dx==0 && dy==0) return; if(dx<0) dx*=-1;if(dy<0) dy*=-1; double sdy=double(dy); GLint vp[4]; get_viewport(vp); double sheight=double(vp[3]), swidth=double(vp[2]); if(dx){ double sdx=double(dx); double aspect=sheight/swidth; if(sdy/sdx < aspect) sdy=sdx*aspect; } double sxm=(double(x0)+double(x1))*.5; double sym=(double(y0)+double(y1))*.5; screen_to_world(&vp[0]+2,sxm,sym,m_viewAttrib.m_cx,m_viewAttrib.m_cy); double wsratio=view_volume_height()/sheight; m_viewAttrib.m_scale=diameter()/(wsratio*sdy); } //Translate and scale the current view. //box is world coordinate's box cube. void MGOpenGLView::pan_zoom(const MGBox& box){ glm::mat4 mmat; get_model_matrix(mmat); glm::ivec4 vp; get_viewport(vp); MGPosition wc=box.mid(); MGPosition sc; project(wc,sc,&mmat,0,&vp); //Set the viewing center position. screen_to_world(&vp[0]+2,sc[0],sc[1],m_viewAttrib.m_cx,m_viewAttrib.m_cy); //Set the scaling factor. float* mp=&mmat[0][0]; double p=mp[2]*wc[0]+mp[6]*wc[1]+mp[10]*wc[2]+mp[14]; p*=-.9;//was -1.0. Maybe scaled to too large object. double len=view_volume_near()*box.len()/p; m_viewAttrib.m_scale=diameter()/len; } //Convert the windows screen coordinate (x,y) to MGCL's straight line. //and get the intersection of the straight line and the construction plane. //The origin of the screen coordinate is left, bottom. Not left, top. void MGOpenGLView::unproject( int x, int y, //screen coordinate whose origin is (left, bottom). MGStraight& sl, //The straight line of (x,y) will be returnred. MGCSisect& is //the intersectio of the sl and the construction plane //will be returned. )const{ unproject_to_sl_glv(x,y,sl); if(m_viewAttrib.m_cplane.valid()) sl.relation(m_viewAttrib.m_cplane.plane(), is); else is=MGCSisect(sl.root_point(), 0.,MGPosition(0.,0.)); } //Convert the windows screen coordinate (x,y) to MGCL's straight line. //The origin of the screen coordinate is left, bottom. Not left, top. void MGOpenGLView::unproject_to_sl_glv(int x, int y, MGStraight& sl)const{ glm::ivec4 viewport;get_viewport(viewport); glm::mat4 modelMatrix, projMatrix; get_projection_matrix(&viewport[0],projMatrix); get_model_matrix(modelMatrix); glm::vec3 winPoint(x,y,0.); glm::vec3 P=glm::unProject(winPoint,modelMatrix,projMatrix,viewport); MGPosition origin(P[0],P[1],P[2]); winPoint[2]=100.; glm::vec3 Q=glm::unProject(winPoint,modelMatrix,projMatrix,viewport); MGPosition point(Q[0],Q[1],Q[2]); sl=MGStraight(MGSTRAIGHT_UNLIMIT, point-origin,origin); const MGConstructionPlane& pl=cplane(); MGPosition xyz,uv2; xyz=pl.locate(sl,uv2); sl.update_root(xyz); } void MGOpenGLView::get_near_position( const MGCurve* crv, const float center[2],///<screen coordinates whose origin is (left, bottom). double& t //parameter value of the curve crv near to (sx,sy) will be returned. ){ MGStraight sl; int sx=(int)center[0], sy=(int)center[1]; unproject_to_sl_glv(sx,sy,sl); std::unique_ptr<MGCurve> crv2(crv->clone());//std::cout<<"1:"<<(*crv2)<<std::endl; const MGPosition rp=sl.root_point(); *crv2-=rp;// std::cout<<"2:"<<(*crv2)<<std::endl; MGMatrix mat; mat.set_axis(sl.direction(),2); *crv2*=mat;// std::cout<<"2:"<<(*crv2)<<std::endl; t=crv2->closest2D(MGDefault::origin_2D()); //std::cout<<"t="<<t<<","<<crv2->eval(t)<<std::endl; } ///Enable when bEnabled=true, else disable grid snap. ///When bEnabled=true, cpnlane is enbaled. void MGOpenGLView::enable_grid_snap(bool bEnabled){ MGConstructionPlane& cpl=cplane(); if(!cpl.valid()) return; if(bEnabled){ cpl.set_bind_to_grid_enable(); }else{ cpl.set_bind_to_grid_disable(); } } // grid snap is enabled bool MGOpenGLView::is_enabled_grid_snap()const{ if(cplane().disabled()) return false; return cplane().is_bind_to_grid(); } /// Each viewport uses its own context, so we need to make sure the correct /// context is set whenever we make an OpenGL command. void MGOpenGLView::makeRCCurrent()const{ // Set current HGLRC and GlewContext. ::wglMakeCurrent( m_hDC, m_hRC ); m_currentGLView=const_cast<MGOpenGLView*>(this); }