Search

2012年9月26日 星期三

wxWidgets+OpenGL+OpenCV

    也可以結合Arduino做有趣又簡單的應用,當然還是寫成Multi Thread會比較順暢。


render_data.h

#ifndef __RENDER_DATA__
#define __RENDER_DATA__

typedef struct
{
   float vertex[3];
   float texcoord[2];
}VertexTexture;

VertexTexture vertex[4] = {
   {{-0.5f,-0.5f,0.0f},{0.0f,1.0f}},
   {{0.5f,-0.5f,0.0f},{1.0f,1.0f}},
   {{-0.5f,0.5f,0.0f},{0.0f,0.0f}},
   {{0.5f,0.5f,0.0f},{1.0f,0.0f}}
};

#endif

wxGLCV.h

#ifndef __WX_GLCV__
#define __WX_GLCV__

#include <wx/wx.h>
#include <wx/glcanvas.h>

#include <cv.h>
#include <highgui.h>

#include "render_data.h"

class wxGL;

class App:public wxApp
{
   public:

   bool OnInit();
};

class Frame:public wxFrame
{
   public:

      Frame(const wxString&);
      ~Frame();

      void OnExit(wxCommandEvent&);

      void CreateUI();
      void Render(wxTimerEvent&);
      void Capture();

   private:

      wxGL *gl;
      wxTimer timer;
      wxSlider *angle[3];
      wxImage *image;
      static const unsigned long fps = 25;
      unsigned long begin,last;

      CvCapture *camera;
      IplImage *frame;
      IplImage *temp;

      DECLARE_EVENT_TABLE();
};

class wxGL:public wxGLCanvas
{
   public:

      wxGL(wxWindow*,wxWindowID,
   const wxPoint&,
   const wxSize&,
   long,const wxString);
      ~wxGL();

      void OnSize(wxSizeEvent&);

      void InitGL();
      void Render(wxImage*);
      void SetAngleXYZ(int x,int y,int z){angleX = x;angleY = y,angleZ = z;};

   private:

      bool init;
      float angleX,angleY,angleZ;
      GLuint texture_id;

      DECLARE_EVENT_TABLE();
};

enum{
   RENDER_TIMER = 1000
};

DECLARE_APP(App)
IMPLEMENT_APP(App)

BEGIN_EVENT_TABLE(wxGL,wxGLCanvas)
   EVT_SIZE(wxGL::OnSize)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(Frame,wxFrame)
   EVT_MENU(wxID_EXIT,Frame::OnExit)
   EVT_TIMER(RENDER_TIMER,Frame::Render)
END_EVENT_TABLE()

#endif

wxGLCV.cpp

#include "wxGLCV.h"

bool App::OnInit()
{
   Frame *frame = new Frame(wxT("wxGL"));

   frame->Show(true);

   return true;
}

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(800,600)),timer(this,RENDER_TIMER)
{
   CreateUI();

   begin = 0;
   last = 0;

   camera = cvCaptureFromCAM(-1);

   timer.Start(10);
}

void Frame::CreateUI()
{
   wxMenu *file = new wxMenu;
   file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("Exit"));

   wxMenuBar *bar = new wxMenuBar;
   bar->Append(file,wxT("File"));
   SetMenuBar(bar);

   wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
   this->SetSizer(top);

   wxBoxSizer *screen_box = new wxBoxSizer(wxVERTICAL);
   top->Add(screen_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

   wxPanel *panel = new wxPanel(this,wxID_ANY,wxDefaultPosition,wxSize(380,380));
   screen_box->Add(panel,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
 
   for(int i = 0;i < 3;++i){
      angle[i] = new wxSlider(this,wxID_ANY,0,0,360,wxDefaultPosition,wxSize(300,-1),wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS);
      screen_box->Add(angle[i],0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
   }

   gl = new wxGL(panel,wxID_ANY,wxDefaultPosition,wxSize(380,380),0,wxT("wxGL"));

   CreateStatusBar(2);
   SetStatusText(wxDateTime::Now().Format());

}

void Frame::Render(wxTimerEvent &event){

   begin = wxGetLocalTimeMillis().ToLong();

   gl->SetAngleXYZ(angle[0]->GetValue(),angle[1]->GetValue(),angle[2]->GetValue());

   if(begin - last > (1000 / fps)){
      last = begin;
      Capture();
      gl->Render(image);
   }

}

void Frame::Capture()
{
   frame = cvQueryFrame(camera);
   temp = cvCreateImage(cvSize(frame->width,frame->height),8,3);
   cvZero(temp);

   cvConvertImage(frame,temp,CV_CVTIMG_SWAP_RB);

   unsigned char *data;
   cvGetRawData(temp,&data);

   if(image){
      delete image;
      image = new wxImage(temp->width,temp->height,data,true);
   }
   else{
      image = new wxImage(temp->width,temp->height,data,true);
   }
}

Frame::~Frame()
{
   if(frame){
      cvReleaseImage(&frame);
   }
   if(temp){
      cvReleaseImage(&temp);
   }
   if(camera){
      cvReleaseCapture(&camera);
   }
   timer.Stop();
}

void Frame::OnExit(wxCommandEvent &event)
{
   Close();
}

wxGL::wxGL(wxWindow *paraent,wxWindowID id = wxID_ANY,
      const wxPoint &pos = wxDefaultPosition,
      const wxSize &size = wxDefaultSize,
      long style = 0,const wxString name = wxT("wxGL")):
   wxGLCanvas(paraent,(wxGLCanvas*)NULL,id,pos,size,style | wxFULL_REPAINT_ON_RESIZE,name)
{
   wxInitAllImageHandlers();
   texture_id = 0;
   init = false;
}

void wxGL::InitGL()
{
   SetCurrent();
 
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0f,1.0f,0.1f,100.0f);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);

   for(int i = 0;i < 4;++i){
      vertex[i].texcoord[1] = 1.0f - vertex[i].texcoord[1];
   }

   glEnable(GL_DEPTH_TEST);
   //glEnable(GL_CULL_FACE);
   glEnable(GL_TEXTURE_2D);
}

wxGL::~wxGL()
{
}

void wxGL::OnSize(wxSizeEvent &event)
{
   wxGLCanvas::OnSize(event);

   int w,h;
   GetClientSize(&w,&h);

   if(GetContext()){
      SetCurrent();
      glViewport(0,0,(GLint)w,(GLint)h);
   }
}

void wxGL::Render(wxImage *image)
{
   wxPaintDC dc(this);

   if(!init){
      InitGL();
      init = true;
   }

   SetCurrent();

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glGenTextures(1,&texture_id);
   glBindTexture(GL_TEXTURE_2D,texture_id);
   glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,
(GLint)image->GetWidth(),(GLint)image->GetHeight(),0,
GL_RGB,GL_UNSIGNED_BYTE,image->GetData());

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);
   glRotatef(angleX,1.0f,0.0f,0.0f);
   glRotatef(angleY,0.0f,1.0f,0.0f);
   glRotatef(angleZ,0.0f,0.0f,1.0f);

   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,sizeof(VertexTexture),&vertex[0].vertex);

   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   glTexCoordPointer(2,GL_FLOAT,sizeof(VertexTexture),&vertex[0].texcoord);

   glDrawArrays(GL_TRIANGLE_STRIP,0,4);

   SwapBuffers();
}




g++ -o2 -o wxGLCV wxGLCV.cpp `wx-config --cxxflags --libs --unicode --gl-libs` `pkg-config opencv --cflags --libs`



2012年9月21日 星期五

wxWidgets With OpenGL

    最近整理硬碟突然翻到以前剛開始從MFC改用wxWidgets時寫的結合OpenGL的練習實驗,也想到還沒紀錄最基本的怎麼讓wxWidgets操作OpenGL,因為samples的方法我覺得不好,所以我覺得還是紀錄上來好了,基本上只要把wxPanel當作parent傳給wxGLCanvas就可以畫在wxPanel上,然後就可以用wxBoxSizer去layout了,用wxImage載入材質再將相關資訊bind上目標並用VA的方式畫出等等...。

render_data.h

#ifndef __RENDER_DATA__
#define __RENDER_DATA__

typedef struct
{
   float vertex[3];
   float texcoord[2];
}VertexTexture;

VertexTexture vertex[4] = {
   {{-0.5f,-0.5f,0.0f},{0.0f,1.0f}},
   {{0.5f,-0.5f,0.0f},{1.0f,1.0f}},
   {{-0.5f,0.5f,0.0f},{0.0f,0.0f}},
   {{0.5f,0.5f,0.0f},{1.0f,0.0f}}
};

#endif



wxGL.h


#ifndef __WX_GL__
#define __WX_GL__

#include <wx/wx.h>
#include <wx/glcanvas.h>

#include "render_data.h"

class wxGL;

class App:public wxApp
{
   public:

   bool OnInit();
};

class Frame:public wxFrame
{
   public:

      Frame(const wxString&);
      ~Frame();

      void OnExit(wxCommandEvent&);

      void CreateUI();
      void Render(wxTimerEvent&);

   private:

      wxGL *gl;
      wxTimer timer;
      wxSlider *angle[3];
      static const unsigned long fps = 60;
      unsigned long begin,last;

      DECLARE_EVENT_TABLE();
};

class wxGL:public wxGLCanvas
{
   public:

      wxGL(wxWindow*,wxWindowID,
   const wxPoint&,
   const wxSize&,
   long,const wxString);
      ~wxGL();

      void OnSize(wxSizeEvent&);

      void InitGL();
      void Render();
      void SetAngleXYZ(int x,int y,int z){angleX = x;angleY = y,angleZ = z;};

   private:

      bool init;
      float angleX,angleY,angleZ;
      wxImage *image;
      GLuint texture_id;

      DECLARE_EVENT_TABLE();
};

enum{
   RENDER_TIMER = 1000
};

DECLARE_APP(App)
IMPLEMENT_APP(App)

BEGIN_EVENT_TABLE(wxGL,wxGLCanvas)
   EVT_SIZE(wxGL::OnSize)
END_EVENT_TABLE()

BEGIN_EVENT_TABLE(Frame,wxFrame)
   EVT_MENU(wxID_EXIT,Frame::OnExit)
   EVT_TIMER(RENDER_TIMER,Frame::Render)
END_EVENT_TABLE()

#endif


wxGL.cpp


#include "wxGL.h"

bool App::OnInit()
{
   Frame *frame = new Frame(wxT("wxGL"));

   frame->Show(true);

   return true;
}

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(800,600)),timer(this,RENDER_TIMER)
{
   CreateUI();

   begin = 0;
   last = 0;

   timer.Start(10);
}

void Frame::CreateUI()
{
   wxMenu *file = new wxMenu;
   file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("Exit"));

   wxMenuBar *bar = new wxMenuBar;
   bar->Append(file,wxT("File"));
   SetMenuBar(bar);

   wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
   this->SetSizer(top);

   wxBoxSizer *screen_box = new wxBoxSizer(wxVERTICAL);
   top->Add(screen_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

   wxPanel *panel = new wxPanel(this,wxID_ANY,wxDefaultPosition,wxSize(380,380));
   screen_box->Add(panel,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
 
   for(int i = 0;i < 3;++i){
      angle[i] = new wxSlider(this,wxID_ANY,0,0,360,wxDefaultPosition,wxSize(300,-1),wxSL_HORIZONTAL | wxSL_AUTOTICKS | wxSL_LABELS);
      screen_box->Add(angle[i],0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);
   }

   gl = new wxGL(panel,wxID_ANY,wxDefaultPosition,wxSize(380,380),0,wxT("wxGL"));

   CreateStatusBar(2);
   SetStatusText(wxDateTime::Now().Format());

}

void Frame::Render(wxTimerEvent &event){

   begin = wxGetLocalTimeMillis().ToLong();

   gl->SetAngleXYZ(angle[0]->GetValue(),angle[1]->GetValue(),angle[2]->GetValue());

   if(begin - last > (1000 / fps)){
      last = begin;
      gl->Render();
   }

}

Frame::~Frame()
{
   timer.Stop();
}

void Frame::OnExit(wxCommandEvent &event)
{
   Close();
}

wxGL::wxGL(wxWindow *paraent,wxWindowID id = wxID_ANY,
      const wxPoint &pos = wxDefaultPosition,
      const wxSize &size = wxDefaultSize,
      long style = 0,const wxString name = wxT("wxGL")):
   wxGLCanvas(paraent,(wxGLCanvas*)NULL,id,pos,size,style | wxFULL_REPAINT_ON_RESIZE,name)
{
   wxInitAllImageHandlers();
   image = new wxImage(wxT("lena_std.tif"));
   texture_id = 0;
   init = false;
}

void wxGL::InitGL()
{
   SetCurrent();
 
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0f,1.0f,0.1f,100.0f);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);

   for(int i = 0;i < 4;++i){
      vertex[i].texcoord[1] = 1.0f - vertex[i].texcoord[1];
   }

   glGenTextures(1,&texture_id);
   glBindTexture(GL_TEXTURE_2D,texture_id);
   glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,
(GLint)image->GetWidth(),(GLint)image->GetHeight(),0,
GL_RGB,GL_UNSIGNED_BYTE,image->GetData());

   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

   glEnable(GL_DEPTH_TEST);
   //glEnable(GL_CULL_FACE);
   glEnable(GL_TEXTURE_2D);
}

wxGL::~wxGL()
{
}

void wxGL::OnSize(wxSizeEvent &event)
{
   wxGLCanvas::OnSize(event);

   int w,h;
   GetClientSize(&w,&h);

   if(GetContext()){
      SetCurrent();
      glViewport(0,0,(GLint)w,(GLint)h);
   }
}

void wxGL::Render()
{
   wxPaintDC dc(this);

   if(!init){
      InitGL();
      init = true;
   }

   SetCurrent();

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0f,0.0f,2.0f,
0.0f,0.0f,0.0f,
0.0f,-1.0f,0.0f);
   glRotatef(angleX,1.0f,0.0f,0.0f);
   glRotatef(angleY,0.0f,1.0f,0.0f);
   glRotatef(angleZ,0.0f,0.0f,1.0f);

   glEnableClientState(GL_VERTEX_ARRAY);
   glVertexPointer(3,GL_FLOAT,sizeof(VertexTexture),&vertex[0].vertex);

   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   glTexCoordPointer(2,GL_FLOAT,sizeof(VertexTexture),&vertex[0].texcoord);

   glDrawArrays(GL_TRIANGLE_STRIP,0,4);

   SwapBuffers();
}




g++ -o2 -o wxGL wxGL.cpp `wx-config --cxxflags --libs --unicode --gl-libs`

lena_std.tif