Win32 OpenGL编程系列 2D例子 -- 7巧板图形绘制

  作为学习OpenGL例子的用自然要使用OpenGL来绘制啦虽然这么简单图形根本用不着OpenGL别说我用大炮打苍蝇用牛刀杀鸡-_-!是学习OpenGL嘛所以在2D坐标系中还是使用了OpenGL 坐标系并且为了追求显示完美(主要是旋转)我选取了所有图形重心作为每个图形坐标系原点这样旋转时中心就是每个图形中心这样比使用rgnbox获取边框然后取中心旋转效果要好具体旋转效果需要自己添加代码去尝试了Rotate和RotateTo实现已经有了添加到绘制部分即可

  下面简单介绍下所有源代码

  所有 7巧板图形全部继承自CGLShape此类实现如下

// 此类实现移动旋转
 CGLShape
{
public:
    CGLShape(void)
    {
        mfPosX = 0.0;
        mfPosY = 0.0;
        mem(mfvColor, 0, (mfvColor));
        mfDegree = 0.0;
        mfSize = 1.0;
    }
    virtual ~CGLShape(void) { }
    void SetSize(GLfloat afSize) { mfSize = afSize; }
    void SetColor(GLfloat afRed, GLfloat afGreen, GLfloat afBlue, GLfloat afAlpha = 1.0)
    {
        mfvColor[0] = afRed;
        mfvColor[1] = afGreen;
        mfvColor[2] = afBlue;
        mfvColor[3] = afAlpha;
    }
    // 相对偏移(外部坐标系长度)
    void Move( aiPosX,  aiPosY) 
    {
        mfPosX  2.0f * aiPosX/(float)WIDTH;
        mfPosY  -(2.0f * aiPosY/(float)HEIGHT);
    }
    // 移动到位置(Windows坐标系点)
    void MoveTo( aiPosX,  aiPosY)
    {
        mfPosX = (2.0f * aiPosX - (float)WIDTH) / (float)WIDTH;
        mfPosY = -(2.0f * aiPosY - (float)HEIGHT) / (float)HEIGHT;
    }
    // 旋转,以逆时针为正方向
    void Rotate(GLfloat aiDegree) { mfDegree  aiDegree; }
    // 旋转到
    void RotateTo(GLfloat aiDegree) { mfDegree = aiDegree; }
    // OpenGL坐标系
    void SetPos(GLfloat afPosX, GLfloat afPosY) { mfPosX = afPosX; mfPosY = afPosY; }
    void GetPos(GLfloat& afPosX, GLfloat& afPosY) { afPosX = mfPosX; afPosY = mfPosY; }
    void Draw
    {
        glLoadIdentity;
        glColor4fv(mfvColor);
        glPushMatrix;
        glTranslatef(mfPosX, mfPosY, 0.0);
        glRotatef(mfDegree, 0.0, 0.0, 1.0);
        DrawImp;
        glPopMatrix;
    }
protected:
    // 重绘时需要,由各子类实现
    virtual void DrawImp = 0;
    // 位置信息,没有用POINT是为了将来方便移植
    GLfloat mfPosX;
    GLfloat mfPosY;
    // 颜色
    GLfloat mfvColor[4];
    // 旋转度数
    GLfloat mfDegree;
    // 大小
    GLfloat mfSize;
};


  大小颜色旋转角度都以成员变量方式保存在CGLShape中并且在Draw中已经实际完成了使用具体DrawImp交由子类实现完成具体图形绘制(此处使用template模式)具体各个实现按照 7巧板要求如下:

   3角形:

 CGLTriangle : public CGLShape
{
public:
    CGLTriangle { }
    virtual ~CGLTriangle { }
    // 重绘时需要,由各子类实现
    virtual void DrawImp
    {
         GLfloat fvTop[3] = { 0.0, (1.0/3.0), 0.0};
         GLfloat fvLeftBottom[3] = { -0.5, -(1.0/6.0), 0.0};
         GLfloat fvRightBottom[3] = { 0.5, -(1.0/6.0), 0.0};
        GLfloat fvSizeTop[3] = {fvTop[0], fvTop[1] * mfSize, fvTop[2]};
        GLfloat fvSizeLeftBottom[3] = {fvLeftBottom[0] * mfSize, fvLeftBottom[1] * mfSize, fvLeftBottom[2]};
        GLfloat fvSizeRightBottom[3] = {fvRightBottom[0] * mfSize, fvRightBottom[1] * mfSize, fvRightBottom[2]};
        glBegin(GL_TRIANGLES);
        glVertex3fv(fvSizeTop);
        glVertex3fv(fvSizeLeftBottom);
        glVertex3fv(fvSizeRightBottom);
        glEnd;
    }
};


  实际上DrawImp仅仅关心绘制个 3角形而已这里其他图形只有所以不关心大小而 3角形在 7巧板中有多个所以将大小计算放在 3角形中独立计算大小事实上更通用办法是在CShapeDraw中用 glScale实现 3角形3个顶点坐标相对来说还比较容易计算

  矩形:

 CGLRectangle: public CGLShape
{
public:
    CGLRectangle { }
    virtual ~CGLRectangle { }
    // 重绘时需要,由各子类实现
    virtual void DrawImp
    {
         GLfloat fLength = sqrt(2.0)/4.0;
         GLfloat fLengthHalf = fLength/2.0;
         GLfloat fvLeftTop[3] = { -fLengthHalf, fLengthHalf, 0.0};
         GLfloat fvRightTop[3] = { fLengthHalf, fLengthHalf, 0.0};
         GLfloat fvLeftBottom[3] = { -fLengthHalf, -fLengthHalf, 0.0};
         GLfloat fvRightBottom[3] = { fLengthHalf, -fLengthHalf, 0.0};
        // TODO: 7角板此例中方形只有个不需要考虑大小暂时不计算大小
        glColor4fv(mfvColor);
        glPushMatrix;
        glBegin(GL_QUADS);
        glVertex3fv(fvLeftTop);
        glVertex3fv(fvRightTop);
        glVertex3fv(fvRightBottom);
        glVertex3fv(fvLeftBottom);
        glEnd;
        glPopMatrix;
    }
};


  很简单不多说了DrawImp实现个矩形绘制而已 4个顶点坐标时最容易计算

  平行 4边形:

 CGLParallelogram: public CGLShape
{
public:
    CGLParallelogram { }
    virtual ~CGLParallelogram { }
    // 重绘时需要,由各子类实现
    virtual void DrawImp
    {
         GLfloat fRightBottomX = 0.375;
         GLfloat fHeight = 0.25;
         GLfloat fvLeftTop[3] = { -fRightBottomX, fHeight/2.0, 0.0};
         GLfloat fvRightTop[3] = { 0.5-fRightBottomX, fHeight/2, 0.0};
         GLfloat fvLeftBottom[3] = { fRightBottomX-0.5, -fHeight/2.0, 0.0};
         GLfloat fvRightBottom[3] = { fRightBottomX, -fHeight/2.0, 0.0};
        // TODO: 7角板此例中 4边形只有个不需要考虑大小暂时不计算大小
        glColor4fv(mfvColor);
        glPushMatrix;
        glRotatef(mfDegree, 0.0, 0.0, 1.0);
        glBegin(GL_QUADS);
        glVertex3fv(fvLeftTop);
        glVertex3fv(fvRightTop);
        glVertex3fv(fvRightBottom);
        glVertex3fv(fvLeftBottom);
        glEnd;
        glPopMatrix;
    }
};


  绘制是同样简单但是在以平行 4边形重心为原点坐标系中计算平时 4边形4个顶点坐标需要计算量上述那几个数值可不是随便掰出来

  将上述图形组合在

CGLTriangle gTriBTop;    // 上方大 3角形
CGLTriangle gTriBRight;    // 右边大 3角形
CGLTriangle gTriSLeft;    // 左上方小上角形
CGLTriangle gTriSMid;    // 中间小 3角形
CGLTriangle gTriMLeft;    // 左下方中 3角形
CGLRectangle gRectangle; // 唯正方形
CGLParallelogram gParal;    // 唯平行 4边形

//OpenGL化开始
void SceneInit( w, h)
{
    GLenum err = glewInit;
    (err != GLEW_OK)
    {
        MessageBox(NULL, _T("Error"), _T("Glew init failed."), MB_OK);
        exit(-1);
    }
    gTriBTop.SetColor(1.0, 0.0, 0.0);    // 上方大 3角形,红色,
    gTriBTop.SetPos(0.0, 1.0/3.0);    
    gTriBTop.RotateTo(180.0);
    gTriBRight.SetColor(0.0, 0.0, 1.0);    // 右边大 3角形,蓝色
    gTriBRight.SetPos(1.0/3.0, 0.0);
    gTriBRight.RotateTo(90.0);
    gTriSLeft.SetColor(1.0, 1.0, 0.0);    // 左上方小上角形,黄色
    gTriSLeft.SetSize(0.5);        // 小 3角形只有大半大
    gTriSLeft.SetPos(-(5.0/12.0), 0.25);
    gTriSLeft.RotateTo(-90.0);
    gRectangle.SetColor(1.0, 175.0/255.0, 175.0/255.0); // 唯正方形,不知道什么颜色
    gRectangle.SetPos(-0.25, 0.0);
    gRectangle.RotateTo(45.0);
    gTriSMid.SetColor(0.0, 1.0, 0.0);    // 中间小 3角形,绿色
    gTriSMid.SetSize(0.5);        // 小 3角形只有大半大
    gTriSMid.SetPos(0.0, -1.0/6.0);
    gTriMLeft.SetColor(0.0, 1.0, 1.0);    // 左下方中 3角形
    gTriMLeft.SetSize( sqrt(2.0) / 2.0 );    // 以底边计算2分的根号2倍
    gTriMLeft.SetPos(-0.5 + 1.0/6.0, -0.5 + 1.0/6.0 );
    gTriMLeft.RotateTo(135.0);
    gParal.SetColor(1.0, 0.0, 1.0);    // 唯平行 4边形,紫色
    gParal.SetPos(0.125,  -0.375);
}
void ReShape(unsigned auWidth, unsigned auHeight)
{
    glViewport(0, 0, auWidth, auHeight);
}
//这里进行所有绘图工作
void SceneShow(GLvoid)        
{
    glClear(GL_COLOR_BUFFER_BIT);    // 清空颜色缓冲区
    gTriBTop.Draw;
    gTriBRight.Draw;
    gTriSLeft.Draw;
    gRectangle.Draw;
    gTriSMid.Draw;
    gTriMLeft.Draw;
    gParal.Draw;
    glFlush;
} 


  上述代码中逻辑非常简单无非就是设定好每个图形大小位置旋转角度( 3角形需要)等每个图形绘制都是以其重心为原点所以计算实际是 7巧板每个图形重心位置计算量上述每个数值都是精确计算出来所以最后图形才能完美实际上也可以通过移动所有图形到然后记录下每个值方式来完成但是此方式可能没有完整数学描述精确效果也就没有那么完美了显示截图如下:

  

  最后演示下每个图形旋转效果:

  只需要将代码改成如下形式即可:

//这里进行所有绘图工作
void SceneShow(GLvoid)        
{
    glClear(GL_COLOR_BUFFER_BIT);    // 清空颜色缓冲区
    gTriBTop.Draw;
    gTriBRight.Draw;
    gTriSLeft.Draw;
    gRectangle.Draw;
    gTriSMid.Draw;
    gTriMLeft.Draw;
    gParal.Draw;

    gTriBTop.Rotate(1.0);
    gTriBRight.Rotate(1.0);
    gTriSLeft.Rotate(1.0);
    gRectangle.Rotate(1.0);
    gTriSMid.Rotate(1.0);
    gTriMLeft.Rotate(1.0);
    gParal.Rotate(1.0);
    glFlush;
}


  最后开始实际完成稍微复杂点图形绘制时就会发现就会发现技术学习都是比较简单但是实际使用全靠数学撑着此例算是比较简单了但是平面几何 3角等东西不懂点根本无法计算各个图形位置-_-!数学还是得学好啊

Tags: 

延伸阅读

最新评论

发表评论