/********************************************************************/ /* 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. void MGOpenGLView::drawCommandDrawer( std::list& drawers ){ execDefaultStaticAttrib(); std::list::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; ihas_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///& 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+wOld)) w=xOld+wOld-x; if(y(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<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],/// 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 shels;//To exclude the same shell picking, shell's pickObject are stored. std::set::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(objA);//Lowest object pointer. if(!obj) continue;//This must not happen(Lowest name is MGObject). std::vector 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(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 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; iselectionDraw(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, /// 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 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; jmake_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; iselectionDraw(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, /// 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& 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; isetUniform(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],/// crv2(crv->clone());//std::cout<<"1:"<<(*crv2)<closest2D(MGDefault::origin_2D()); //std::cout<<"t="<eval(t)<(this); }