terça-feira, 22 de maio de 2012

OpenGL com wxWidgets

Introdução
   Para utilizar opengl com wxWidgets nós dispomos da classe wxGLCanvas. Esta classe possui os métodos SetColor(const wxString& cor) que seta a cor da janela de vizualização usando um nome de cor pré-definido, sendo portanto, uma alternativa para a função OpenGL 'glColor3f', SetCurrent(), que seta o estado representado pelo contexto de renderização OpenGL e SwapBuffers(), que é o método reponsável pela troca dos buffers atual e de fundo e vice-versa, permitindo dessa forma, que os comando OpenGL prévios (de fundo) sejam mostrados na janela de vizualização.

Exemplo
   No nosso exemplo fazer escrever uma aplicação que mostra um cubo em 3 dimensões tendo cada face uma cor. Através do movimento da 'rodinha' do mouse nosso cubo poderá ser girado em torno dos eixos x e z em ambos os sentidos, mostrando suas diferentes faces.



//main.h
#ifndef _glpane
#define _glpane

#include "wx/wx.h"
#include "wx/glcanvas.h"

class PainelGL : public wxGLCanvas
{
    public:
        float rot;
        PainelGL(wxFrame* pai);
        void resized(wxSizeEvent& evt);
        void Desenha(wxPaintEvent& evt);
        void preparaViewport3D(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y);
        //evento responsável pela rotação
        void mouseWheelMoved(wxMouseEvent& evt);

        DECLARE_EVENT_TABLE()
};

class MinhaApp : public wxApp
{
    virtual bool OnInit();
    wxFrame *janela;
    PainelGL *glPainel;
};
#endif

//main.cpp
#include "wx/sizer.h"
#include "wx/glcanvas.h"
#include "main.h"

#ifdef __WXMAC__
#include "OpenGL/glu.h"
#include "OpenGL/gl.h"
#else
#include <GL/glu.h>
#include <GL/gl.h>
#endif

IMPLEMENT_APP(MinhaApp)

bool MinhaApp::OnInit()
{
    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    janela = new wxFrame(NULL, -1, _("OpenGL com wxWidgets"), wxDefaultPosition, wxSize(400,400));
    glPainel = new PainelGL(janela);   
    sizer->Add(glPainel, 1, wxEXPAND);
    janela->SetSizer(sizer);
    janela->SetAutoLayout(true);
    janela->Show();
    return true;
}

BEGIN_EVENT_TABLE(PainelGL, wxGLCanvas)   
    EVT_MOUSEWHEEL(PainelGL::mouseWheelMoved)
    EVT_PAINT(PainelGL::Desenha)
END_EVENT_TABLE()

void PainelGL::mouseWheelMoved(wxMouseEvent& evt)
{
    //o metodo GetWheelRotation nos indica o sentido da rotação da 'rodinha' do mouse, positivo/negativo - pra frente/pra tras
    if(evt.GetWheelRotation() > 0)
        rot += 0.5f;
    else
        rot -= 0.5f;
    //atualizamos o desenho mostrando a rotação
    Refresh();
}

PainelGL::PainelGL(wxFrame *pai) :
    wxGLCanvas(pai, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
    //inicializamos o valor de rotação   
    rot = 0.5f;
    SetBackgroundStyle(wxBG_STYLE_CUSTOM);
}

void PainelGL::resized(wxSizeEvent& evt)
{
    //atualizamos o desenho no caso de redimensionamento da janela
    Refresh();
}

void PainelGL::preparaViewport3D(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y)
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //fundo preto
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST); //habilita teste de profundidade   
    //testa se o valor de profundidade é menor ou igual o valor armazenado
      //passando no caso de ser verdadeiro    
    glDepthFunc(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glEnable(GL_COLOR_MATERIAL);
    //define dimensões da viewport
    glViewport(topleft_x, topleft_y, bottomrigth_x, bottomrigth_y);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
   
    float ratio = (float) (bottomrigth_x ) / (float) (bottomrigth_y );
    gluPerspective(45 /*angulo de visao*/, ratio, 0.2 /*corte pra perto*/, 200 /*corte pra longe*/);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void PainelGL::Desenha(wxPaintEvent& evt)
{
    if(!IsShown())
        return;

    wxGLCanvas::SetCurrent();
    wxPaintDC(this);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
    preparaViewport3D(0,0,GetSize().x, GetSize().y);
    glLoadIdentity();

    glColor4f(0,0,1,1);
    glTranslatef(0,0,-5);

    //rotação  nos eixos x e z
    glRotatef(rot,   1.0f, 0.0f, 1.0f);
    glBegin(GL_QUADS); //começamos a desenhar o cubo
        glColor3f(0.0f,1.0f,0.0f); //verde
        glVertex3f(1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(1.0f, 1.0f, 1.0f);

        glColor3f(1.0f, 0.5f, 0.0f); //laranja
        glVertex3f(1.0f, -1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);

        glColor3f(1.0f, 0.0f, 0.0f); //vermelho
        glVertex3f(1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);
        glVertex3f(1.0f, -1.0f, 1.0f);

        glColor3f(1.0f, 1.0f, 0.0f); //amarelo
        glVertex3f(1.0f, -1.0f, -1.0f);
         glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(1.0f, 1.0f, -1.0f);

        glColor3f(0.0f, 0.0f, 1.0f); //azul
        glVertex3f(-1.0f, 1.0f, 1.0f);
        glVertex3f(-1.0f, 1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, -1.0f);
        glVertex3f(-1.0f, -1.0f, 1.0f);

        glColor3f(1.0f, 0.0f, 1.0f); //violeta
        glVertex3f(1.0f, 1.0f, -1.0f);
        glVertex3f(1.0f, 1.0f, 1.0f);
        glVertex3f(1.0f, -1.0f, 1.0f);
        glVertex3f(1.0f, -1.0f, -1.0f);
    glEnd();

    glFlush();
    SwapBuffers();   
}

Para compilar:
g++ main.cpp -o exemplo_gl `wx-config --libs --cxxflags --gl-libs` -lGLU

Referências:
http://wiki.wxwidgets.org/WxGLCanvas

http://docs.wxwidgets.org/trunk/classwx_g_l_canvas.html#a9f9ab3909606484e717904064d4e7b4f
http://nehe.gamedev.net/tutorial/3d_shapes/10035/


2 comentários:

  1. Gostei do seu blog, acho que você poderia colocar muito mais coisas sobre wxWidgets já que é uma biblioteca muito ampla, coloquei um link para seu blog no meu ultimo post da uma olhada http://digitandocodigos.wordpress.com/2012/11/02/orfao-do-qt/

    ResponderExcluir
  2. Com certeza Pablo, o assunto é muito vasto, mas ando meio sem tempo ultimamente, assim que sobrar um tempinho darei andamento às postagens. Muito obrigado pela referência no seu blog, espero que meus artigos tenham o ajudado de alguma maneira. Abraço.

    ResponderExcluir