Skip to main content

Featured

Build docker image from multiple build contexts

Build docker image from multiple build contexts Building a docker image requires specifying a source of truth to include in the image from a local directory or a remote git repository. In the previous version, the docker BuildKit allows users to specify the build context from a single source of truth only. However, the engineers may need to have the context from different locations based on the type of files. For instance, icons, images or other resources that are not included in the same package, including the resource from other docker images. Fortunately, the Docker Buildx toolkit supports multiple build context flag for Docker 1.4. Let's learn how to use this new feature. The following list is a shortcut for jumping into a specific topic handy. What version of Docker is this tutorial targeting? How to specify the version of Dockerfile frontend? Ho

[OpenGL]選取顯示的物件-2D, Pick

Ref:Nehe's Openg - Lesson 32

目前因為需要把建立在TreeICtrl的物件,丟到OpenGL上做顯示,因此需要可以抓到目前滑鼠指標放置TreeCtrl物件的位置跟對象。
目前已知的作法是透過Frustum Culling可以得知目前滑鼠所選擇的區域。但以目前的能力來講,這難度比較高。
因此這邊選用OpenGL提供的Selection Mode來達到需求。

目前要放置的對象為2D Grid,所以目前要抓的是,滑鼠指標是在那個Cell上。
程式參考Nehe的範例,但由於還有些項目跟數值不清楚,所以還是以Nehe提供的數值跟說明為主。
目前這邊是當作筆記保留,所以不加其他說明,避免誤導社會大眾。

底下為實際運作流程:
1.建立滑鼠事件觸發後的函式:
 void COpenGLDrawer::OnObjectSelection(CPoint point, COLORREF clrPickColor)  
 {  
     GLuint    buffer[512];            // Set Up A Selection Buffer  
     GLint    hits = 0;                // The Number Of Objects That We Selected  
   
 //Now we set up a viewport. viewport[] will hold the current x, y, length and width of the current viewport (OpenGL Window).   
 //glGetIntegerv(GL_VIEWPORT, viewport) gets the current viewport boundries and stores them in viewport[].   
 //    Initially, the boundries are equal the the OpenGL window dimensions.   
 //    glSelectBuffer(512, buffer) tells OpenGL to use buffer for it's selection buffer.  
     // The Size Of The Viewport. [0] Is <x>, [1] Is <y>, [2] Is <length>, [3] Is <width>  
     GLint    viewport[4];  
   
     // This Sets The Array <viewport> To The Size And Location Of The Screen Relative To The Window  
     glGetIntegerv(GL_VIEWPORT, viewport);  
     glSelectBuffer(512, buffer);                        // Tell OpenGL To Use Our Array For Selection      
   
 //All of the code below is very important. The first line puts OpenGL in selection mode.   
 //    In selection mode, nothing is drawn to the screen.   
 //    Instead, information about objects rendered while in selection mode will be stored in the selection buffer.   
 //Next we initialize the name stack by calling glInitNames() and glPushName(0).   
 //    It's important to note that if the program is not in selection mode, a call to glPushName() will be ignored.   
 //    Of course we are in selection mode, but it's something to keep in mind.  
     // Puts OpenGL In Selection Mode. Nothing Will Be Drawn. Object ID's and Extents Are Stored In The Buffer.  
     (void) glRenderMode(GL_SELECT);  
   
     glInitNames();                                // Initializes The Name Stack  
     glPushName(0);                                // Push 0 (At Least One Entry) Onto The Stack  
   
 //After preparing the name stack, we have to to restrict drawing to the area just under our crosshair.   
 //    In order to do this we have to select the projection matrix. After selecting the projection matrix we push it onto the stack.   
 //    We then reset the projection matrix using glLoadIdentity().   
 //We restrict drawing using gluPickMatrix().   
 //    The first parameter is our current mouse position on the x-axis, the second parameter is the current mouse position on the y-axis,   
 //        then the width and height of the picking region. Finally the current viewport[].   
 //    The viewport[] indicates the current viewport boundaries. mouse_x and mouse_y will be the center of the picking region.          
     glMatrixMode(GL_PROJECTION);                        // Selects The Projection Matrix  
     glPushMatrix();                                // Push The Projection Matrix  
     glLoadIdentity();                            // Resets The Matrix  
   
     // This Creates A Matrix That Will Zoom Up To A Small Portion Of The Screen, Where The Mouse Is.  
     /*gluPickMatrix((GLdouble) mouse_x, (GLdouble) (viewport[3]-mouse_y), 1.0f, 1.0f, viewport);*/  
     gluPickMatrix((GLdouble) point.x, (GLdouble) (viewport[3]-point.y), 1.0f, 1.0f, viewport);        //輸入為Windows Coordinate of DrawScene  
   
 //Calling gluPerspective() multiplies the perspective matrix by the pick matrix which restricts the drawing to the area requested by   
 //    gluPickMatrix().   
 //We then switch to the modelview matrix and draw our targets by calling DrawTargets().   
 //    We draw the targets in DrawTargets() and not in Draw() because we only want selection to check for hits with objects (targets) and   
 //        not the sky, ground or crosshair.   
 //After drawing our targets, we switch back to the projection matrix and pop the stored matrix off the stack.   
 //    We then switch back to the modelview matrix.   
 //The last line of code below switches back to render mode so that objects we draw actually appear on the screen.   
 //    hits will hold the number of objects that were rendered in the viewing area requested by gluPickMatrix().  
     // Apply The Perspective Matrix  
 /*    gluPerspective(45.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 100.0f);    */  
     gluPerspective(45.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 100.0f);  
     glMatrixMode(GL_MODELVIEW);                        // Select The Modelview Matrix  
     DrawTargets();                                    // Render The Targets To The Selection Buffer  
     glMatrixMode(GL_PROJECTION);                    // Select The Projection Matrix  
     glPopMatrix();                                    // Pop The Projection Matrix  
     glMatrixMode(GL_MODELVIEW);                        // Select The Modelview Matrix  
     hits=glRenderMode(GL_RENDER);                    // Switch To Render Mode, Find Out How Many  
   
 //Now we check to see if there were more than 0 hits recorded.   
 //    If so, we set choose to equal the name of the first object drawn into the picking area.   
 //    depth holds how deep into the screen, the object is.   
 //Each hit takes 4 items in the buffer. The first item is the number of names on the name stack when the hit occured.   
 //    The second item is the minimum z value of all the verticies that intersected the viewing area at the time of the hit.   
 //    The third item is the maximum z value of all the vertices that intersected the viewing area at the time of the hit and the last item   
 //        is the content of the name stack at the time of the hit (name of the object).   
 //    We are only interested in the minimum z value and the object name in this tutorial.  
     if (hits > 0)                                // If There Were More Than 0 Hits  
     {  
         int    choose = buffer[3];                                    // Make Our Selection The First Object  
         int depth = buffer[1];                                    // Store How Far Away It Is   
 //We then loop through all of the hits to make sure none of the objects are closer than the first object hit.   
 //    If we didn't do this, and two objects were overlapping, the first object hit might behind another object,   
 //        and clicking the mouse would take away the first object, even though it was behind another object. When you shoot at something,   
 //        the closest object should be the object that gets hit.   
 //So, we check through all of the hits.   
 //    Remember that each object takes 4 items in the buffer, so to search through each hit we have to multiply the current loop value by 4.   
 //    We add 1 to get the depth of each object hit.   
 //    If the depth is less than the the current selected objects depth,   
 //        we store the name of the closer object in choose and we store the depth of the closer object in depth.   
 //    After we have looped through all of our hits, choose will hold the name of the closest object hit,   
 //        and depth will hold the depth of the closest object hit.  
 /*  
         for (int loop = 1; loop < hits; loop++)                    // Loop Through All The Detected Hits  
         {  
             // If This Object Is Closer To Us Than The One We Have Selected  
             if (buffer[loop*4+1] < GLuint(depth))  
             {  
                 choose = buffer[loop*4+3];                        // Select The Closer Object, sample use the offset 3.  
                 depth = buffer[loop*4+1];                        // Store How Far Away It Is  
             }      
         }    //End of for (int loop = 1; loop < hits; loop++)  
 */       
 //All we have to do is mark the object as being hit. We check to make sure the object has not already been hit.   
 //    If it has not been hit, we mark it as being hit by setting hit to TRUE.   
 //    We increase the players score by 1 point, and we increase the kills counter by 1.  
 /*  
         if (!object[choose].hit)                                // If The Object Hasn't Already Been Hit  
         {  
             object[choose].hit=TRUE;                            // Mark The Object As Being Hit  
             score+=1;                                            // Increase Score  
             kills+=1;                                            // Increase Level Kills  
 */  
         this->m_vcdsGrid4AStar[choose].IsWarkable = !this->m_vcdsGrid4AStar[choose].IsWarkable;  
         this->m_vcdsGrid4AStar[choose].clrSelectedColor = clrPickColor;  
   
 //I use kills to keep track of how many objects have been destroyed on each level.   
 //    I wanted each level to have more objects (making it harder to get through the level).   
 //    So I check to see if the players kills is greater than the current level multiplied by 5.   
 //    On level 1, the player only has to kill 5 objects (1*5).   
 //    On level 2 the player has to kill 10 objects (2*5), progressively getting harder each level.   
 //So, the first line of code checks to see if kills is higher than the level multiplied by 5. If so, we set miss to 0.   
 //    This sets the player morale back to 10 out of 10 (the morale is 10-miss).   
 //    We then set kills to 0 (which starts the counting process over again).   
 //Finally, we increase the value of level by 1 and check to see if we've hit the last level.   
 //    I have set the maximum level to 30 for the following two reasons... Level 30 is insanely difficult.   
 //    I am pretty sure no one will ever have that good of a game. The second reason... At the top of the code, we only set up 30 objects.   
 //    If you want more objects, you have to increase the value accordingly.   
 //It is VERY important to note that you can have a maximum of 64 objects on the screen (0-63).   
 //    If you try to render 65 or more objects, picking becomes confused, and odd things start to happen.   
 //    Everything from objects randomly exploding to your computer crashing. It's a physical limit in OpenGL (just like the 8 lights limit).   
 //If by some chance you are a god, and you finish level 30, the level will no longer increase, but your score will.   
 //    Your morale will also reset to 10 every time you finish the 30th level.  
 /*  
             if (kills>level*5)                                    // New Level Yet?  
             {  
                 miss=0;                                            // Misses Reset Back To Zero  
                 kills=0;                                        // Reset Level Kills  
                 level+=1;                                        // Increase Level  
                 if (level>30)                                    // Higher Than 30?  
                     level=30;                                    // Set Level To 30 (Are You A God?)  
             }  
         }    //End of if (!object[choose].hit)  
 */  
     }    //End of if (hits > 0)  
 }  

2.建立當select mode選用後,用來搜尋滑鼠指標點選的圖形。由於這邊是用線條構成的grid,所以點選時,其實是點不到繪製的物件。因此在這邊搜尋用的圖形,全部改用填滿的grid來作為搜尋的依據。
裡面有個很關鍵的一行,就是在繪製搜尋用的圖像前,要先把要繪製的view port座標移動到目前看到已經畫出來的model相同對應的位置。否則可能會造成選擇的區域不正確
 void COpenGLDrawer::DrawTargets(void)  
 {  
     glLoadIdentity();                                    // Reset The Modelview Matrix  
 /*    glTranslatef(0.0f,0.0f, -10.0f);                        // Move Into The Screen 20 Units        //NOTE:This is the KEY for Picking!!!    */  
     glTranslatef( this->m_fPosX, this->m_fPosY, -20);  
     /*for (int loop=0; loop<level; loop++)                // Loop Through 9 Objects*/  
     for ( unsigned int loop = 0 ; loop < this->m_vcdsGrid.size() ; loop++ )  
     {  
 //The first line of code is the secret to picking individual objects.   
 //    What it does is assigns a name (number) to each object. The first object drawn will be 0.   
 //    The second object will be 1, etc... If the loop was to hit 29, the last object drawn would be given the name 29.   
 //    After assigning a name to the object, we push the modelview matrix onto the stack.   
 //    It's important to note the calls to glLoadName() are ignored if the program is not in selection mode.   
 //We then move to the location on the screen where we want our object to be drawn.   
 //    We use object[loop].x to position on the x-axis, object[loop].y to position on the y-axis and object[loop].distance to position   
 //        the object on the z-axis (depth into the screen).   
 //    We have already translated 10 units into the screen, so the actual distance at which the object will be drawn is going to   
 //        be object[loop].distance-10.0f.      
         glLoadName(loop);                        // Assign Object A Name (ID)  
         glPushMatrix();                            // Push The Modelview Matrix  
         /*glTranslatef(object[loop].x,object[loop].y,object[loop].distance);    // Position The Object (x,y)*/  
           
 //Before we draw the object, we have to check if it's been hit or not.   
 //    We do this by checking to see if object[loop].hit is TRUE.   
 //    If it is, we jump to Explosion(loop) which will draw the explosion animation instead of the actual object.   
 //    If the object was not hit, we spin the object on it's z-axis by object[loop].spin degrees before we call Object().   
 //Object takes 3 parameters. The first one is the width, the second one is the height and the third one is the number of the texture to use.   
 //    To get the width and height, we use the array size[object[loop].texid].w and size[object[loop].texid].h.   
 //    This looks up the width and height from our predefined object size array at the beginning of this program.   
 //    The reason we use object[loop].texid is because it represents the type of object we are drawing.   
 //    A texid of 0 is always the blueface... a texid of 3 is always the coke can, etc.   
 //After drawing an object, we pop the matrix resetting the view, so our next object is drawn at the proper location on the screen.      
 /*        if (object[loop].hit)                        // If Object Has Been Hit  
         {  
             Explosion(loop);                        // Draw An Explosion  
         }  
         else                                // Otherwise  
         {  
             glRotatef(object[loop].spin,0.0f,0.0f,1.0f);        // Rotate The Object  
             Object(size[object[loop].texid].w,size[object[loop].texid].h,object[loop].texid);    // Draw The Object  
         }  
 */  
         //if ( !this->m_vcdsGrid4AStar[loop].IsWarkable )   
         //{  
         //    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);  
         //    glBegin(GL_QUADS);  
         //    glColor3f(0.48f, 0.44f, 1.0f);            //Light Slate Blue  
         //    glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.LB.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.LB.y);  
         //    glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.RB.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.RB.y);  
         //    glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.RT.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.RT.y);  
         //    glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.LT.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.LT.y);  
   
         //    glEnd();  
         //}    //End of if ( !this->m_vcdsGrid4AStar[loop].IsWarkable )   
   
         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);                            //Set polygon rasterization mode  
                                                                             //Must fill it and the   
         glBegin(GL_QUADS);                                                    //Start to draw squares  
         glColor3f(0.0f, 0.0f, 0.0f);        //Black  
         for ( unsigned int i = 0 ; i < this->m_vcdsGrid.size() ; i++ )  
         {  
         //3D  
             //glVertex3f(this->m_vcdsGrid[i].LB.x, this->m_vcdsGrid[i].LB.y, this->m_vcdsGrid[i].LB.z);  
             //glVertex3f(this->m_vcdsGrid[i].RB.x, this->m_vcdsGrid[i].RB.y, this->m_vcdsGrid[i].RB.z);  
             //glVertex3f(this->m_vcdsGrid[i].RT.x, this->m_vcdsGrid[i].RT.y, this->m_vcdsGrid[i].RT.z);  
             //glVertex3f(this->m_vcdsGrid[i].LT.x, this->m_vcdsGrid[i].LT.y, this->m_vcdsGrid[i].LT.z);  
   
         //2D          
             //glVertex2f(this->m_vcdsGrid[i].LB.x, this->m_vcdsGrid[i].LB.y);  
             //glVertex2f(this->m_vcdsGrid[i].RB.x, this->m_vcdsGrid[i].RB.y);  
             //glVertex2f(this->m_vcdsGrid[i].RT.x, this->m_vcdsGrid[i].RT.y);  
             //glVertex2f(this->m_vcdsGrid[i].LT.x, this->m_vcdsGrid[i].LT.y);          
             glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.LB.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.LB.y);  
             glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.RB.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.RB.y);  
             glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.RT.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.RT.y);  
             glVertex2f(this->m_vcdsGrid4AStar[loop].cdsGridInfo.LT.x, this->m_vcdsGrid4AStar[loop].cdsGridInfo.LT.y);  
   
         }    //End of for ( unsigned int i = 0 ; i < this->m_vcpGrid.size() ; i++ )  
   
         glEnd();  
   
         glPopMatrix();                            // Pop The Modelview Matrix  
     }    //End of for (int loop=0; loop<level; loop++)  
   
 }  

主要在做select動作,是透過這兩個函式,使用到的關鍵function為glInitNames()glLoadName()glPushName()

至於其他網路上的範例會在用來更新畫面的Draw()裡面放glLoadName(),目前的測試是,沒放也沒關係。所以看起來他們只是要整並更新方式而已。

Comments

Popular Posts