From 8b089c5e8c8a2140258d150ca1ce42afd3b79e1b Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Mon, 28 Feb 2000 08:22:57 +0000 Subject: [PATCH] Moved wxGLCanvas to more normal positions git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6326 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- distrib/msw/glcanvas.rsp | 69 ++- distrib/msw/tmake/filelist.txt | 7 + docs/latex/wx/classes.tex | 1 + docs/latex/wx/glcanvas.tex | 67 +++ docs/latex/wx/grid.tex | 1 - include/wx/glcanvas.h | 21 + include/wx/gtk/glcanvas.h | 169 +++++++ include/wx/gtk1/glcanvas.h | 169 +++++++ include/wx/motif/glcanvas.h | 52 +++ include/wx/msw/glcanvas.h | 174 +++++++ include/wx/msw/setup0.h | 3 + samples/opengl/cube/Makefile | 31 ++ samples/opengl/cube/cube.cpp | 508 +++++++++++++++++++++ samples/opengl/cube/cube.h | 93 ++++ samples/opengl/cube/cube.rc | 3 + samples/opengl/cube/makefile.b32 | 18 + samples/opengl/cube/makefile.bcc | 21 + samples/opengl/cube/makefile.g95 | 18 + samples/opengl/cube/makefile.unx | 23 + samples/opengl/cube/makefile.vc | 26 ++ samples/opengl/cube/makefile.wat | 17 + samples/opengl/cube/mondrian.ico | Bin 0 -> 766 bytes samples/opengl/isosurf/Makefile | 32 ++ samples/opengl/isosurf/isosurf.cpp | 412 +++++++++++++++++ samples/opengl/isosurf/isosurf.dat.gz | Bin 0 -> 65537 bytes samples/opengl/isosurf/isosurf.h | 52 +++ samples/opengl/isosurf/isosurf.rc | 3 + samples/opengl/isosurf/makefile.b32 | 22 + samples/opengl/isosurf/makefile.bcc | 25 ++ samples/opengl/isosurf/makefile.g95 | 20 + samples/opengl/isosurf/makefile.unx | 27 ++ samples/opengl/isosurf/makefile.vc | 30 ++ samples/opengl/isosurf/makefile.wat | 20 + samples/opengl/isosurf/mondrian.ico | Bin 0 -> 766 bytes samples/opengl/penguin/Makefile | 37 ++ samples/opengl/penguin/lw.cpp | 427 ++++++++++++++++++ samples/opengl/penguin/lw.h | 69 +++ samples/opengl/penguin/makefile.b32 | 18 + samples/opengl/penguin/makefile.bcc | 21 + samples/opengl/penguin/makefile.g95 | 18 + samples/opengl/penguin/makefile.unx | 21 + samples/opengl/penguin/makefile.vc | 30 ++ samples/opengl/penguin/makefile.wat | 17 + samples/opengl/penguin/penguin.cpp | 236 ++++++++++ samples/opengl/penguin/penguin.h | 84 ++++ samples/opengl/penguin/penguin.lwo | Bin 0 -> 10028 bytes samples/opengl/penguin/penguin.rc | 3 + samples/opengl/penguin/trackball.h | 78 ++++ src/generic/scrolwin.cpp | 4 + src/gtk/glcanvas.cpp | 432 ++++++++++++++++++ src/gtk1/glcanvas.cpp | 432 ++++++++++++++++++ src/motif/glcanvas.cpp | 168 +++++++ src/msw/glcanvas.cpp | 624 ++++++++++++++++++++++++++ src/msw/makefile.b32 | 5 +- src/msw/makefile.bcc | 5 +- src/msw/makefile.g95 | 1 + src/msw/makefile.vc | 3 +- src/msw/makefile.wat | 6 +- src/wxvc.dsp | 4 + src/wxvc_dll.dsp | 4 + utils/projgen/makeproj.cpp | 75 +--- 61 files changed, 4848 insertions(+), 108 deletions(-) create mode 100644 docs/latex/wx/glcanvas.tex create mode 100644 include/wx/glcanvas.h create mode 100644 include/wx/gtk/glcanvas.h create mode 100644 include/wx/gtk1/glcanvas.h create mode 100644 include/wx/motif/glcanvas.h create mode 100644 include/wx/msw/glcanvas.h create mode 100644 samples/opengl/cube/Makefile create mode 100644 samples/opengl/cube/cube.cpp create mode 100644 samples/opengl/cube/cube.h create mode 100644 samples/opengl/cube/cube.rc create mode 100644 samples/opengl/cube/makefile.b32 create mode 100644 samples/opengl/cube/makefile.bcc create mode 100644 samples/opengl/cube/makefile.g95 create mode 100644 samples/opengl/cube/makefile.unx create mode 100644 samples/opengl/cube/makefile.vc create mode 100644 samples/opengl/cube/makefile.wat create mode 100644 samples/opengl/cube/mondrian.ico create mode 100644 samples/opengl/isosurf/Makefile create mode 100644 samples/opengl/isosurf/isosurf.cpp create mode 100644 samples/opengl/isosurf/isosurf.dat.gz create mode 100644 samples/opengl/isosurf/isosurf.h create mode 100644 samples/opengl/isosurf/isosurf.rc create mode 100644 samples/opengl/isosurf/makefile.b32 create mode 100644 samples/opengl/isosurf/makefile.bcc create mode 100644 samples/opengl/isosurf/makefile.g95 create mode 100644 samples/opengl/isosurf/makefile.unx create mode 100644 samples/opengl/isosurf/makefile.vc create mode 100644 samples/opengl/isosurf/makefile.wat create mode 100644 samples/opengl/isosurf/mondrian.ico create mode 100644 samples/opengl/penguin/Makefile create mode 100644 samples/opengl/penguin/lw.cpp create mode 100644 samples/opengl/penguin/lw.h create mode 100644 samples/opengl/penguin/makefile.b32 create mode 100644 samples/opengl/penguin/makefile.bcc create mode 100644 samples/opengl/penguin/makefile.g95 create mode 100644 samples/opengl/penguin/makefile.unx create mode 100644 samples/opengl/penguin/makefile.vc create mode 100644 samples/opengl/penguin/makefile.wat create mode 100644 samples/opengl/penguin/penguin.cpp create mode 100644 samples/opengl/penguin/penguin.h create mode 100644 samples/opengl/penguin/penguin.lwo create mode 100644 samples/opengl/penguin/penguin.rc create mode 100644 samples/opengl/penguin/trackball.h create mode 100644 src/gtk/glcanvas.cpp create mode 100644 src/gtk1/glcanvas.cpp create mode 100644 src/motif/glcanvas.cpp create mode 100644 src/msw/glcanvas.cpp diff --git a/distrib/msw/glcanvas.rsp b/distrib/msw/glcanvas.rsp index 923fc507bd..d23618a158 100644 --- a/distrib/msw/glcanvas.rsp +++ b/distrib/msw/glcanvas.rsp @@ -1,42 +1,37 @@ -utils/glcanvas/Makefile.in -utils/glcanvas/docs/*.* -utils/glcanvas/win/*.cpp -utils/glcanvas/win/*.h -utils/glcanvas/win/make*.* -utils/glcanvas/gtk/*.cpp -utils/glcanvas/gtk/*.h -utils/glcanvas/gtk/make*.* -utils/glcanvas/motif/*.cpp -utils/glcanvas/motif/*.h -utils/glcanvas/motif/make*.* -utils/glcanvas/motif/*.txt -utils/glcanvas/samples/cube/*.cpp -utils/glcanvas/samples/cube/*.h -utils/glcanvas/samples/cube/*.rc -utils/glcanvas/samples/cube/*.ico -utils/glcanvas/samples/cube/*.xbm -utils/glcanvas/samples/cube/make*.* -utils/glcanvas/samples/cube/Makefile +include/wx/glcanvas.h +include/wx/motif/glcanvas.h +include/wx/gtk/glcanvas.h +include/wx/msw/glcanvas.h -utils/glcanvas/samples/isosurf/*.cpp -utils/glcanvas/samples/isosurf/*.h -utils/glcanvas/samples/isosurf/*.rc -utils/glcanvas/samples/isosurf/*.ico -utils/glcanvas/samples/isosurf/*.xbm -utils/glcanvas/samples/isosurf/*.dat.gz -utils/glcanvas/samples/isosurf/make*.* -utils/glcanvas/samples/isosurf/Makefile +src/motif/glcanvas.cpp +src/gtk/glcanvas.cpp +src/msw/glcanvas.cpp -utils/glcanvas/samples/penguin/*.cpp -utils/glcanvas/samples/penguin/*.c -utils/glcanvas/samples/penguin/*.h -utils/glcanvas/samples/penguin/*.rc -utils/glcanvas/samples/penguin/*.ico -utils/glcanvas/samples/penguin/*.xbm -utils/glcanvas/samples/penguin/*.xpm -utils/glcanvas/samples/penguin/make*.* -utils/glcanvas/samples/penguin/Makefile -utils/glcanvas/samples/penguin/penguin.lwo +samples/opengl/cube/*.cpp +samples/opengl/cube/*.h +samples/opengl/cube/*.rc +samples/opengl/cube/*.ico +samples/opengl/cube/*.xbm +samples/opengl/cube/make*.* +samples/opengl/cube/Makefile +samples/opengl/isosurf/*.cpp +samples/opengl/isosurf/*.h +samples/opengl/isosurf/*.rc +samples/opengl/isosurf/*.ico +samples/opengl/isosurf/*.xbm +samples/opengl/isosurf/*.dat.gz +samples/opengl/isosurf/make*.* +samples/opengl/isosurf/Makefile +samples/opengl/penguin/*.cpp +samples/opengl/penguin/*.c +samples/opengl/penguin/*.h +samples/opengl/penguin/*.rc +samples/opengl/penguin/*.ico +samples/opengl/penguin/*.xbm +samples/opengl/penguin/*.xpm +samples/opengl/penguin/make*.* +samples/opengl/penguin/Makefile +samples/opengl/penguin/penguin.lwo diff --git a/distrib/msw/tmake/filelist.txt b/distrib/msw/tmake/filelist.txt index e483bf786b..e5f716ff6c 100644 --- a/distrib/msw/tmake/filelist.txt +++ b/distrib/msw/tmake/filelist.txt @@ -247,6 +247,7 @@ gauge95.cpp M 32 gaugemsw.cpp M 16 gdiimage.cpp M gdiobj.cpp M +glcanvas.cpp M helpwin.cpp M icon.cpp M imaglist.cpp M 32 @@ -343,6 +344,7 @@ fontdlg.cpp R frame.cpp R gauge.cpp R gdiobj.cpp R +glcanvas.cpp R icon.cpp R listbox.cpp R main.cpp R @@ -400,6 +402,7 @@ font.cpp X frame.cpp X gauge.cpp X gdiobj.cpp X +glcanvas.cpp X icon.cpp X listbox.cpp X main.cpp X @@ -603,6 +606,7 @@ gdicmn.h W gdiobj.h W geometry.h W gifdecod.h W +glcanvas.h W grid.h W gsocket.h W hash.h W B @@ -761,6 +765,7 @@ fontdlg.h K frame.h K gauge.h K gdiobj.h K +glcanvas.h K icon.h K joystick.h K listbox.h K @@ -823,6 +828,7 @@ fontdlg.h F frame.h F gauge.h F gdiobj.h F +glcanvas.h F icon.h F joystick.h F listbox.h F @@ -891,6 +897,7 @@ gauge95.h 9 gaugemsw.h 9 gdiimage.h 9 gdiobj.h 9 +glcanvas.h 9 helpwin.h 9 icon.h 9 imaglist.h 9 diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex index fb000358a0..a6adbfd61c 100644 --- a/docs/latex/wx/classes.tex +++ b/docs/latex/wx/classes.tex @@ -94,6 +94,7 @@ \input ftp.tex \input gauge.tex \input gdiobj.tex +\input glcanvas.tex \input valgen.tex \input grid.tex \input hash.tex diff --git a/docs/latex/wx/glcanvas.tex b/docs/latex/wx/glcanvas.tex new file mode 100644 index 0000000000..fddb1541ee --- /dev/null +++ b/docs/latex/wx/glcanvas.tex @@ -0,0 +1,67 @@ +\section{\class{wxGLCanvas}}\label{wxglcanvas} + +wxGLCanvas is a class for displaying OpenGL graphics. There are +wrappers for OpenGL on Windows, and GTK+ and Motif. + +To use this class, create a wxGLCanvas window, call \helpref{wxGLCanvas::SetCurrent}{wxglcanvassetcurrent} +to direct normal OpenGL commands to the window, and then call \helpref{wxGLCanvas::SwapBuffers}{wxglcanvasswapbuffers} +to show the OpenGL buffer on the window. + +Please note that despite deriving from wxScrolledWindow, scrolling is not enabled for this class under +Windows. + +To switch wxGLCanvas support on under Windows, edit setup.h and set wxUSE\_GLCANVAS to 1. + +\wxheading{Derived from} + +\helpref{wxScrolledWindow}{wxscrolledwindow}\\ +\helpref{wxWindow}{wxwindow}\\ +\helpref{wxEvtHandler}{wxevthandler}\\ +\helpref{wxObject}{wxobject} + +\wxheading{Include files} + + + +\wxheading{Window styles} + +There are no specific window styles for this class. + +See also \helpref{window styles overview}{windowstyles}. + +\latexignore{\rtfignore{\wxheading{Members}}} + +\membersection{wxGLCanvas::wxGLCanvas}\label{wxglcanvasconstr} + +\func{void}{wxGLCanvas}{\param{wxWindow* }{parent}, \param{wxWindowID}{ id = -1}, \param{const wxPoint\&}{ pos}, + \param{const wxSize\&}{ size}, \param{long}{ style=0}, \param{const wxString\& }{name="GLCanvas"}, + \param{int*}{ attribList = 0}, \param{const wxPalette\&}{ palette = wxNullPalette}} + +\func{void}{wxGLCanvas}{\param{wxWindow* }{parent}, \param{wxGLCanvas* }{ sharedCanvas = NULL}, \param{wxWindowID}{ id = -1}, \param{const wxPoint\&}{ pos}, + \param{const wxSize\&}{ size}, \param{long}{ style=0}, \param{const wxString\& }{name="GLCanvas"}, + \param{int*}{ attribList = 0}, \param{const wxPalette\&}{ palette = wxNullPalette}} + +\func{void}{wxGLCanvas}{\param{wxWindow* }{parent}, \param{wxGLContext* }{ sharedContext = NULL}, \param{wxWindowID}{ id = -1}, \param{const wxPoint\&}{ pos}, + \param{const wxSize\&}{ size}, \param{long}{ style=0}, \param{const wxString\& }{name="GLCanvas"}, + \param{int*}{ attribList = 0}, \param{const wxPalette\&}{ palette = wxNullPalette}} + +Constructor. + +\membersection{wxGLCanvas::SetCurrent}\label{wxglcanvassetcurrent} + +\func{void}{SetCurrent}{\void} + +Sets this canvas as the current recipient of OpenGL calls. + +\membersection{wxGLCanvas::SetColour}\label{wxglcanvassetcolour} + +\func{void}{SetColour}{\param{const char*}{ colour}} + +Sets the current colour for this window, using the wxWindows colour database to find a named colour. + +\membersection{wxGLCanvas::SwapBuffers}\label{wxglcanvasswapbuffers} + +\func{void}{SwapBuffers}{\void} + +Displays the previous OpenGL commands on the window. + diff --git a/docs/latex/wx/grid.tex b/docs/latex/wx/grid.tex index 384d32438c..540ed2fed1 100644 --- a/docs/latex/wx/grid.tex +++ b/docs/latex/wx/grid.tex @@ -608,4 +608,3 @@ Call this function whenever a change has been made via the API that might alter size characteristics. You may also need to follow it with a call to AdjustScrollbars. - diff --git a/include/wx/glcanvas.h b/include/wx/glcanvas.h new file mode 100644 index 0000000000..2385447aab --- /dev/null +++ b/include/wx/glcanvas.h @@ -0,0 +1,21 @@ +#ifndef _WX_GLCANVAS_H_BASE_ +#define _WX_GLCANVAS_H_BASE_ + +#if defined(__WXMSW__) +#include "wx/msw/glcanvas.h" +#elif defined(__WXMOTIF__) +#include "wx/motif/glcanvas.h" +#elif defined(__WXGTK__) +#include "wx/gtk/glcanvas.h" +#elif defined(__WXQT__) +#include "wx/qt/glcanvas.h" +#elif defined(__WXMAC__) +#include "wx/mac/glcanvas.h" +#elif defined(__WXPM__) +#include "wx/os2/glcanvas.h" +#elif defined(__WXSTUBS__) +#include "wx/stubs/glcanvas.h" +#endif + +#endif + // _WX_GLCANVAS_H_BASE_ diff --git a/include/wx/gtk/glcanvas.h b/include/wx/gtk/glcanvas.h new file mode 100644 index 0000000000..14c439691d --- /dev/null +++ b/include/wx/gtk/glcanvas.h @@ -0,0 +1,169 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.h +// Purpose: wxGLCanvas, for using OpenGL/Mesa with wxWindows and GTK +// Author: Robert Roebling +// Modified by: +// Created: 17/8/98 +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma interface "glcanvas.h" +#endif + +#ifndef _WX_GLCANVAS_H_ +#define _WX_GLCANVAS_H_ + +#include + +#if wxUSE_GLCANVAS + +#include + +extern "C" { +#include "GL/gl.h" +#include "GL/glx.h" +#include "GL/glu.h" +} + +//--------------------------------------------------------------------------- +// Constants for attriblist +//--------------------------------------------------------------------------- + +enum +{ + WX_GL_RGBA=1, /* use true color palette */ + WX_GL_DEPTH_SIZE, /* bits for Z-buffer (0,16,32) */ + WX_GL_DOUBLEBUFFER, /* use doublebuffer */ + WX_GL_MIN_RED, /* use red buffer with most bits (> MIN_RED bits) */ + WX_GL_MIN_GREEN, /* use green buffer with most bits (> MIN_GREEN bits) */ + WX_GL_MIN_BLUE /* use blue buffer with most bits (> MIN_BLUE bits) */ +/* these are enough constants for now, the remaining will be added later */ +}; + +//--------------------------------------------------------------------------- +// classes +//--------------------------------------------------------------------------- + +class WXDLLEXPORT wxGLContext; +class WXDLLEXPORT wxGLCanvas; + +//--------------------------------------------------------------------------- +// wxGLContext +//--------------------------------------------------------------------------- + + +class WXDLLEXPORT wxGLContext: public wxObject +{ +public: + wxGLContext( bool isRGB, wxWindow *win, const wxPalette& palette = wxNullPalette ); + wxGLContext( + bool WXUNUSED(isRGB), wxWindow *win, + const wxPalette& WXUNUSED(palette), + const wxGLContext *other /* for sharing display lists */ + ); + ~wxGLContext(); + + void SetCurrent(); + void SetColour(const char *colour); + void SwapBuffers(); + + void SetupPixelFormat(); + void SetupPalette(const wxPalette& palette); + wxPalette CreateDefaultPalette(); + + inline wxPalette* GetPalette() const { return (wxPalette*) & m_palette; } + inline wxWindow* GetWindow() const { return m_window; } + inline GtkWidget* GetWidget() const { return m_widget; } + inline GLXContext GetContext() const { return m_glContext; } + +public: + GLXContext m_glContext; + + GtkWidget *m_widget; + wxPalette m_palette; + wxWindow* m_window; + +private: + DECLARE_CLASS(wxGLContext) +}; + +//--------------------------------------------------------------------------- +// wxGLContext +//--------------------------------------------------------------------------- + +class WXDLLEXPORT wxGLCanvas: public wxScrolledWindow +{ +public: + inline wxGLCanvas() { + m_glContext = (wxGLContext*) NULL; + m_sharedContext = (wxGLContext*) NULL; + m_glWidget = (GtkWidget*) NULL; + m_vi = (void*) NULL; + m_exposed = FALSE; + } + wxGLCanvas( wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + wxGLCanvas( wxWindow *parent, const wxGLContext *shared = (wxGLContext *)NULL, + wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared = (wxGLCanvas *)NULL, + wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + + bool Create( wxWindow *parent, + const wxGLContext *shared = (wxGLContext*)NULL, + const wxGLCanvas *shared_context_of = (wxGLCanvas*)NULL, + wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + + ~wxGLCanvas(); + + void SetCurrent(); + void SetColour(const char *colour); + void SwapBuffers(); + + void OnSize(wxSizeEvent& event); + + void OnInternalIdle(); + + inline wxGLContext* GetContext() const { return m_glContext; } + + // implementation + + wxGLContext *m_glContext, + *m_sharedContext; + wxGLCanvas *m_sharedContextOf; + void *m_vi; + GtkWidget *m_glWidget; + bool m_exposed; + +private: + DECLARE_EVENT_TABLE() + DECLARE_CLASS(wxGLCanvas) +}; + +#endif + // wxUSE_GLCANVAS + +#endif + // _WX_GLCANVAS_H_ + diff --git a/include/wx/gtk1/glcanvas.h b/include/wx/gtk1/glcanvas.h new file mode 100644 index 0000000000..14c439691d --- /dev/null +++ b/include/wx/gtk1/glcanvas.h @@ -0,0 +1,169 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.h +// Purpose: wxGLCanvas, for using OpenGL/Mesa with wxWindows and GTK +// Author: Robert Roebling +// Modified by: +// Created: 17/8/98 +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma interface "glcanvas.h" +#endif + +#ifndef _WX_GLCANVAS_H_ +#define _WX_GLCANVAS_H_ + +#include + +#if wxUSE_GLCANVAS + +#include + +extern "C" { +#include "GL/gl.h" +#include "GL/glx.h" +#include "GL/glu.h" +} + +//--------------------------------------------------------------------------- +// Constants for attriblist +//--------------------------------------------------------------------------- + +enum +{ + WX_GL_RGBA=1, /* use true color palette */ + WX_GL_DEPTH_SIZE, /* bits for Z-buffer (0,16,32) */ + WX_GL_DOUBLEBUFFER, /* use doublebuffer */ + WX_GL_MIN_RED, /* use red buffer with most bits (> MIN_RED bits) */ + WX_GL_MIN_GREEN, /* use green buffer with most bits (> MIN_GREEN bits) */ + WX_GL_MIN_BLUE /* use blue buffer with most bits (> MIN_BLUE bits) */ +/* these are enough constants for now, the remaining will be added later */ +}; + +//--------------------------------------------------------------------------- +// classes +//--------------------------------------------------------------------------- + +class WXDLLEXPORT wxGLContext; +class WXDLLEXPORT wxGLCanvas; + +//--------------------------------------------------------------------------- +// wxGLContext +//--------------------------------------------------------------------------- + + +class WXDLLEXPORT wxGLContext: public wxObject +{ +public: + wxGLContext( bool isRGB, wxWindow *win, const wxPalette& palette = wxNullPalette ); + wxGLContext( + bool WXUNUSED(isRGB), wxWindow *win, + const wxPalette& WXUNUSED(palette), + const wxGLContext *other /* for sharing display lists */ + ); + ~wxGLContext(); + + void SetCurrent(); + void SetColour(const char *colour); + void SwapBuffers(); + + void SetupPixelFormat(); + void SetupPalette(const wxPalette& palette); + wxPalette CreateDefaultPalette(); + + inline wxPalette* GetPalette() const { return (wxPalette*) & m_palette; } + inline wxWindow* GetWindow() const { return m_window; } + inline GtkWidget* GetWidget() const { return m_widget; } + inline GLXContext GetContext() const { return m_glContext; } + +public: + GLXContext m_glContext; + + GtkWidget *m_widget; + wxPalette m_palette; + wxWindow* m_window; + +private: + DECLARE_CLASS(wxGLContext) +}; + +//--------------------------------------------------------------------------- +// wxGLContext +//--------------------------------------------------------------------------- + +class WXDLLEXPORT wxGLCanvas: public wxScrolledWindow +{ +public: + inline wxGLCanvas() { + m_glContext = (wxGLContext*) NULL; + m_sharedContext = (wxGLContext*) NULL; + m_glWidget = (GtkWidget*) NULL; + m_vi = (void*) NULL; + m_exposed = FALSE; + } + wxGLCanvas( wxWindow *parent, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + wxGLCanvas( wxWindow *parent, const wxGLContext *shared = (wxGLContext *)NULL, + wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared = (wxGLCanvas *)NULL, + wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + + bool Create( wxWindow *parent, + const wxGLContext *shared = (wxGLContext*)NULL, + const wxGLCanvas *shared_context_of = (wxGLCanvas*)NULL, + wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, + const wxPalette& palette = wxNullPalette ); + + ~wxGLCanvas(); + + void SetCurrent(); + void SetColour(const char *colour); + void SwapBuffers(); + + void OnSize(wxSizeEvent& event); + + void OnInternalIdle(); + + inline wxGLContext* GetContext() const { return m_glContext; } + + // implementation + + wxGLContext *m_glContext, + *m_sharedContext; + wxGLCanvas *m_sharedContextOf; + void *m_vi; + GtkWidget *m_glWidget; + bool m_exposed; + +private: + DECLARE_EVENT_TABLE() + DECLARE_CLASS(wxGLCanvas) +}; + +#endif + // wxUSE_GLCANVAS + +#endif + // _WX_GLCANVAS_H_ + diff --git a/include/wx/motif/glcanvas.h b/include/wx/motif/glcanvas.h new file mode 100644 index 0000000000..b3a9ab8016 --- /dev/null +++ b/include/wx/motif/glcanvas.h @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.h +// Purpose: wxGLCanvas, for using OpenGL with wxWindows 2.0 for Motif. +// Uses the GLX extension. +// Author: Julian Smart and Wolfram Gloger +// Modified by: +// Created: 1995, 1999 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart, Wolfram Gloger +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma interface "glcanvas.h" +#endif + +#ifndef _WX_GLCANVAS_H_ +#define _WX_GLCANVAS_H_ + +#include + +#if wxUSE_GLCANVAS + +#include +#include +#include + +#include + +class WXDLLEXPORT wxGLCanvas: public wxScrolledWindow +{ +DECLARE_CLASS(wxGLCanvas) +public: + GLXContext glx_cx; + + inline wxGLCanvas() { glx_cx = 0; } + + wxGLCanvas(wxWindow *parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, + const wxString& name = "GLCanvas", int *attribList = 0, const wxPalette& palette = wxNullPalette); + ~wxGLCanvas(void); + + void SetCurrent(); + void SwapBuffers(); + void SetColour(const char *col); +}; + +#endif + // wxUSE_GLCANVAS + +#endif + // _WX_GLCANVAS_H_ diff --git a/include/wx/msw/glcanvas.h b/include/wx/msw/glcanvas.h new file mode 100644 index 0000000000..f743c5430a --- /dev/null +++ b/include/wx/msw/glcanvas.h @@ -0,0 +1,174 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.h +// Purpose: wxGLCanvas, for using OpenGL with wxWindows under Windows +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma interface "glcanvas.h" +#endif + +#ifndef _WX_GLCANVAS_H_ +#define _WX_GLCANVAS_H_ + +#include + +#if wxUSE_GLCANVAS + +#include + +#include + +#include "gl/gl.h" + +//--------------------------------------------------------------------------- +// Constants for attriblist +//--------------------------------------------------------------------------- + +enum +{ + WX_GL_RGBA=1, /* use true color palette */ + WX_GL_DEPTH_SIZE, /* bits for Z-buffer (0,16,32) */ + WX_GL_DOUBLEBUFFER, /* use doublebuffer */ + WX_GL_MIN_RED, /* use red buffer with most bits (> MIN_RED bits) */ + WX_GL_MIN_GREEN, /* use green buffer with most bits (> MIN_GREEN bits) */ + WX_GL_MIN_BLUE /* use blue buffer with most bits (> MIN_BLUE bits) */ +/* these are enough constants for now, the remaining will be added later */ +}; + +class WXDLLEXPORT wxGLCanvas; /* forward reference */ + +class WXDLLEXPORT wxGLContext: public wxObject +{ +public: + wxGLContext(bool isRGB, wxGLCanvas *win, const wxPalette& palette = wxNullPalette); + wxGLContext( + bool isRGB, wxGLCanvas *win, + const wxPalette& WXUNUSED(palette), + const wxGLContext *other /* for sharing display lists */ + ); + ~wxGLContext(); + + void SetCurrent(); + void SetColour(const char *colour); + void SwapBuffers(); + + + inline wxWindow* GetWindow() const { return m_window; } + inline WXHDC GetHDC() const { return m_hDC; } + inline HGLRC GetGLRC() const { return m_glContext; } + +public: + HGLRC m_glContext; + WXHDC m_hDC; + wxWindow* m_window; +}; + +class WXDLLEXPORT wxGLCanvas: public wxScrolledWindow +{ + DECLARE_CLASS(wxGLCanvas) + public: + wxGLCanvas(wxWindow *parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, + const wxString& name = "GLCanvas", int *attribList = 0, const wxPalette& palette = wxNullPalette); + wxGLCanvas( wxWindow *parent, const wxGLContext *shared = (wxGLContext *)NULL, + wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = "GLCanvas", + int *attribList = (int*) NULL, const wxPalette& palette = wxNullPalette ); + + wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared = (wxGLCanvas *)NULL, wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, + const wxString& name = "GLCanvas", int *attribList = 0, const wxPalette& palette = wxNullPalette ); + + ~wxGLCanvas(); + + // Replaces wxWindow::Create functionality, since we need to use a different window class + bool Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name); + + void SetCurrent(); + void SetColour(const char *colour); + void SwapBuffers(); + + void OnSize(wxSizeEvent& event); + + void OnQueryNewPalette(wxQueryNewPaletteEvent& event); + void OnPaletteChanged(wxPaletteChangedEvent& event); + + inline wxGLContext* GetContext() const { return m_glContext; } + + inline WXHDC GetHDC() const { return m_hDC; } + void SetupPixelFormat(); + void SetupPalette(const wxPalette& palette); + wxPalette CreateDefaultPalette(); + + inline wxPalette* GetPalette() const { return (wxPalette*) & m_palette; } + +protected: + wxGLContext* m_glContext; // this is typedef-ed ptr, in fact + wxPalette m_palette; + WXHDC m_hDC; + +DECLARE_EVENT_TABLE() +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Give extensions proper function names. */ + +/* N.B. - this is not completely implemented as yet */ + +/* EXT_vertex_array */ +void glArrayElementEXT(GLint i); +void glColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +void glDrawArraysEXT(GLenum mode, GLint first, GLsizei count); +void glEdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *pointer); +void glGetPointervEXT(GLenum pname, GLvoid* *params); +void glIndexPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +void glNormalPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +void glTexCoordPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +void glVertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); + +/* EXT_color_subtable */ +void glColorSubtableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *table); + +/* EXT_color_table */ +void glColorTableEXT(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); +void glCopyColorTableEXT(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); +void glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *table); +void glGetColorTableParamaterfvEXT(GLenum target, GLenum pname, GLfloat *params); +void glGetColorTavleParameterivEXT(GLenum target, GLenum pname, GLint *params); + +/* SGI_compiled_vertex_array */ +void glLockArraysSGI(GLint first, GLsizei count); +void glUnlockArraysSGI(); + +/* SGI_cull_vertex */ +void glCullParameterdvSGI(GLenum pname, GLdouble* params); +void glCullParameterfvSGI(GLenum pname, GLfloat* params); + +/* SGI_index_func */ +void glIndexFuncSGI(GLenum func, GLclampf ref); + +/* SGI_index_material */ +void glIndexMaterialSGI(GLenum face, GLenum mode); + +/* WIN_swap_hint */ +void glAddSwapHintRectWin(GLint x, GLint y, GLsizei width, GLsizei height); + +#ifdef __cplusplus +} +#endif + +#endif + // wxUSE_GLCANVAS +#endif + // _WX_GLCANVAS_H_ + diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index d8e736f282..f86739919a 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -217,6 +217,9 @@ // Recommended setting: 1 #define wxUSE_PLOT 1 +// OpenGL canvas +#define wxUSE_GLCANVAS 0 + // ---------------------------------------------------------------------------- // Postscript support settings // ---------------------------------------------------------------------------- diff --git a/samples/opengl/cube/Makefile b/samples/opengl/cube/Makefile new file mode 100644 index 0000000000..56fac3db98 --- /dev/null +++ b/samples/opengl/cube/Makefile @@ -0,0 +1,31 @@ +# +# File: Makefile +# Author: Robert Roebling +# Created: 1999 +# Updated: +# Copyright: (c) 1998 Robert Roebling +# +# Makefile for OpenGl demo (GTK version) +# +# This makefile requires wxWindows/GTK to be +# installed (possibly using "make install") +# on your system. +# + +CC = gcc +WXCONFIG=../../../wx-config +WXINCLUDE=-I../../../include +WXLIB=-L../../../lib + +cube: cube.o # glcanvas.o + $(CC) -o cube cube.o `$(WXCONFIG) --libs` $(WXLIB) -lMesaGL -lMesaGLU + +cube.o: cube.cpp + $(CC) `$(WXCONFIG) --cflags` -I../../gtk $(WXINCLUDE) -c cube.cpp + +glcanvas.o: ../../gtk/glcanvas.cpp + $(CC) `$(WXCONFIG) --cflags` `gtk-config --cflags` -I../../gtk $(WXINCLUDE) -c ../../gtk/glcanvas.cpp + +clean: + rm -f *.o cube + diff --git a/samples/opengl/cube/cube.cpp b/samples/opengl/cube/cube.cpp new file mode 100644 index 0000000000..2f145970d2 --- /dev/null +++ b/samples/opengl/cube/cube.cpp @@ -0,0 +1,508 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: cube.cpp +// Purpose: wxGLCanvas demo program +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation +#pragma interface +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/log.h" + +#include "cube.h" + +#ifndef __WXMSW__ // for wxStopWatch, see remark below +#include +#include +#else +#include +#endif + +#define ID_NEW_WINDOW 10000 +#define ID_DEF_ROTATE_LEFT_KEY 10001 +#define ID_DEF_ROTATE_RIGHT_KEY 10002 + +/*---------------------------------------------------------- + Control to get a keycode + ----------------------------------------------------------*/ +class ScanCodeCtrl : public wxTextCtrl +{ +public: + ScanCodeCtrl( wxWindow* parent, wxWindowID id, int code, + const wxPoint& pos, const wxSize& size ); + void OnChar( wxKeyEvent& event ) { } /* do nothing */ + void OnKeyDown(wxKeyEvent& event); +private: +// any class wishing to process wxWindows events must use this macro + DECLARE_EVENT_TABLE() +}; +BEGIN_EVENT_TABLE( ScanCodeCtrl, wxTextCtrl ) + EVT_CHAR( ScanCodeCtrl::OnChar ) + EVT_KEY_DOWN( ScanCodeCtrl::OnKeyDown ) +END_EVENT_TABLE() + +ScanCodeCtrl::ScanCodeCtrl( wxWindow* parent, wxWindowID id, int code, + const wxPoint& pos, const wxSize& size ) + : wxTextCtrl( parent, id, "", pos, size ) +{ wxString buf; + buf.Printf( "0x%04x", code ); + SetValue( buf ); +} + +void ScanCodeCtrl::OnKeyDown( wxKeyEvent& event ) +{ wxString buf; + buf.Printf( "0x%04x", event.KeyCode() ); + SetValue( buf ); +} + +/*------------------------------------------------------------------ + Dialog for defining a keypress +-------------------------------------------------------------------*/ + +class ScanCodeDialog : public wxDialog +{ +public: + ScanCodeDialog( wxWindow* parent, wxWindowID id, const int code, + const wxString &descr, const wxString& title ); + int GetValue(); +private: + ScanCodeCtrl *m_ScanCode; + wxTextCtrl *m_Description; +}; + +ScanCodeDialog::ScanCodeDialog( wxWindow* parent, wxWindowID id, + const int code, const wxString &descr, const wxString& title ) + : wxDialog( parent, id, title, wxPoint(-1, -1), wxSize(96*2,76*2) ) +{ + new wxStaticText( this, -1, "Scancode", wxPoint(4*2,3*2), + wxSize(31*2,12*2) ); + m_ScanCode = new ScanCodeCtrl( this, -1, code, wxPoint(37*2,6*2), + wxSize(53*2,14*2) ); + + new wxStaticText( this, -1, "Description", wxPoint(4*2,24*2), + wxSize(32*2,12*2) ); + m_Description = new wxTextCtrl( this, -1, descr, wxPoint(37*2,27*2), + wxSize(53*2,14*2) ); + + new wxButton( this, wxID_OK, "Ok", wxPoint(20*2,50*2), wxSize(20*2,13*2) ); + new wxButton( this, wxID_CANCEL, "Cancel", wxPoint(44*2,50*2), + wxSize(25*2,13*2) ); +} + +int ScanCodeDialog::GetValue() +{ + int code; + wxString buf = m_ScanCode->GetValue(); + sscanf( buf.c_str(), "%i", &code ); + return( code ); +} + +/*---------------------------------------------------------------------- + Utility function to get the elapsed time (in msec) since a given point + in time (in sec) (because current version of wxGetElapsedTime doesn´t + works right with glibc-2.1 and linux, at least for me) +-----------------------------------------------------------------------*/ +unsigned long wxStopWatch( unsigned long *sec_base ) +{ + unsigned long secs,msec; + +#ifndef __WXMSW__ // think every unice has gettimeofday + struct timeval tv; + gettimeofday( &tv, (struct timezone *)NULL ); + secs = tv.tv_sec; + msec = tv.tv_usec/1000; +#else + struct timeb tb; + + ftime( &tb ); + + secs = tb.time; + + msec = tb.millitm; + +#endif + + if( *sec_base == 0 ) + *sec_base = secs; + + return( (secs-*sec_base)*1000 + msec ); +} + +/*---------------------------------------------------------------- + Implementation of Test-GLCanvas +-----------------------------------------------------------------*/ + +BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) + EVT_SIZE(TestGLCanvas::OnSize) + EVT_PAINT(TestGLCanvas::OnPaint) + EVT_ERASE_BACKGROUND(TestGLCanvas::OnEraseBackground) + EVT_KEY_DOWN( TestGLCanvas::OnKeyDown ) + EVT_KEY_UP( TestGLCanvas::OnKeyUp ) + EVT_ENTER_WINDOW( TestGLCanvas::OnEnterWindow ) +END_EVENT_TABLE() + +unsigned long TestGLCanvas::m_secbase = 0; +int TestGLCanvas::m_TimeInitialized = 0; +unsigned long TestGLCanvas::m_xsynct; +unsigned long TestGLCanvas::m_gsynct; + +TestGLCanvas::TestGLCanvas(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name): + wxGLCanvas(parent, (wxGLCanvas*) NULL, id, pos, size, style, name ) +{ + m_init = FALSE; + m_gllist = 0; + m_rleft = WXK_LEFT; + m_rright = WXK_RIGHT; +} + +TestGLCanvas::TestGLCanvas(wxWindow *parent, const TestGLCanvas &other, + wxWindowID id, const wxPoint& pos, const wxSize& size, long style, + const wxString& name ) : + wxGLCanvas(parent, other.GetContext(), id, pos, size, style, name ) +{ + m_init = FALSE; + m_gllist = other.m_gllist; /* share display list */ + m_rleft = WXK_LEFT; + m_rright = WXK_RIGHT; +} + +TestGLCanvas::~TestGLCanvas() +{ +} + +void TestGLCanvas::Render() +{ + wxPaintDC dc(this); + +#ifndef __WXMOTIF__ + if (!GetContext()) return; +#endif + + SetCurrent(); + /* init OpenGL once, but after SetCurrent */ + if (!m_init) + { + InitGL(); + m_init = TRUE; + } + + /* clear color and depth buffers */ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if( m_gllist == 0 ) + { + m_gllist = glGenLists( 1 ); + glNewList( m_gllist, GL_COMPILE_AND_EXECUTE ); + /* draw six faces of a cube */ + glBegin(GL_QUADS); + glNormal3f( 0.0F, 0.0F, 1.0F); + glVertex3f( 0.5F, 0.5F, 0.5F); glVertex3f(-0.5F, 0.5F, 0.5F); + glVertex3f(-0.5F,-0.5F, 0.5F); glVertex3f( 0.5F,-0.5F, 0.5F); + + glNormal3f( 0.0F, 0.0F,-1.0F); + glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f(-0.5F, 0.5F,-0.5F); + glVertex3f( 0.5F, 0.5F,-0.5F); glVertex3f( 0.5F,-0.5F,-0.5F); + + glNormal3f( 0.0F, 1.0F, 0.0F); + glVertex3f( 0.5F, 0.5F, 0.5F); glVertex3f( 0.5F, 0.5F,-0.5F); + glVertex3f(-0.5F, 0.5F,-0.5F); glVertex3f(-0.5F, 0.5F, 0.5F); + + glNormal3f( 0.0F,-1.0F, 0.0F); + glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f( 0.5F,-0.5F,-0.5F); + glVertex3f( 0.5F,-0.5F, 0.5F); glVertex3f(-0.5F,-0.5F, 0.5F); + + glNormal3f( 1.0F, 0.0F, 0.0F); + glVertex3f( 0.5F, 0.5F, 0.5F); glVertex3f( 0.5F,-0.5F, 0.5F); + glVertex3f( 0.5F,-0.5F,-0.5F); glVertex3f( 0.5F, 0.5F,-0.5F); + + glNormal3f(-1.0F, 0.0F, 0.0F); + glVertex3f(-0.5F,-0.5F,-0.5F); glVertex3f(-0.5F,-0.5F, 0.5F); + glVertex3f(-0.5F, 0.5F, 0.5F); glVertex3f(-0.5F, 0.5F,-0.5F); + glEnd(); + + glEndList(); + } + else + glCallList( m_gllist ); + + glFlush(); + SwapBuffers(); +} + +void TestGLCanvas::OnEnterWindow( wxMouseEvent& event ) +{ + SetFocus(); +} + +void TestGLCanvas::OnPaint( wxPaintEvent& event ) +{ + Render(); +} + +void TestGLCanvas::OnSize(wxSizeEvent& event) +{ + int width, height; + GetClientSize(& width, & height); + +#ifndef __WXMOTIF__ + if (GetContext()) +#endif + { + SetCurrent(); + glViewport(0, 0, width, height); + } +} + +void TestGLCanvas::OnEraseBackground(wxEraseEvent& event) +{ + // Do nothing, to avoid flashing. +} + +void TestGLCanvas::InitGL() +{ + SetCurrent(); + + /* set viewing projection */ + glMatrixMode(GL_PROJECTION); + glFrustum(-0.5F, 0.5F, -0.5F, 0.5F, 1.0F, 3.0F); + + /* position viewer */ + glMatrixMode(GL_MODELVIEW); + glTranslatef(0.0F, 0.0F, -2.0F); + + /* position object */ + glRotatef(30.0F, 1.0F, 0.0F, 0.0F); + glRotatef(30.0F, 0.0F, 1.0F, 0.0F); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); +} + +GLfloat TestGLCanvas::CalcRotateSpeed( unsigned long acceltime ) +{ + GLfloat t,v; + + t = ((GLfloat)acceltime) / 1000.0f; + + if( t < 0.5f ) + v = t; + else if( t < 1.0f ) + v = t * (2.0f - t); + else + v = 0.75f; + + return(v); +} + +GLfloat TestGLCanvas::CalcRotateAngle( unsigned long lasttime, + unsigned long acceltime ) +{ + GLfloat t,s1,s2; + + t = ((GLfloat)(acceltime - lasttime)) / 1000.0f; + s1 = CalcRotateSpeed( lasttime ); + s2 = CalcRotateSpeed( acceltime ); + + return( t * (s1 + s2) * 135.0f ); +} + +void TestGLCanvas::Action( long code, unsigned long lasttime, + unsigned long acceltime ) +{ + GLfloat angle = CalcRotateAngle( lasttime, acceltime ); + + if (code == m_rleft) + Rotate( angle ); + else if (code == m_rright) + Rotate( -angle ); +} + +void TestGLCanvas::OnKeyDown( wxKeyEvent& event ) +{ + long evkey = event.KeyCode(); + if (evkey == 0) return; + + if (!m_TimeInitialized) + { + m_TimeInitialized = 1; + m_xsynct = event.m_timeStamp; + m_gsynct = wxStopWatch(&m_secbase); + + m_Key = evkey; + m_StartTime = 0; + m_LastTime = 0; + m_LastRedraw = 0; + } + + unsigned long currTime = event.m_timeStamp - m_xsynct; + + if (evkey != m_Key) + { + m_Key = evkey; + m_LastRedraw = m_StartTime = m_LastTime = currTime; + } + + if (currTime >= m_LastRedraw) // Redraw: + { + Action( m_Key, m_LastTime-m_StartTime, currTime-m_StartTime ); + + m_LastRedraw = wxStopWatch(&m_secbase) - m_gsynct; + m_LastTime = currTime; + } + + event.Skip(); +} + +void TestGLCanvas::OnKeyUp( wxKeyEvent& event ) +{ + m_Key = 0; + m_StartTime = 0; + m_LastTime = 0; + m_LastRedraw = 0; + + event.Skip(); +} + +void TestGLCanvas::Rotate( GLfloat deg ) +{ + SetCurrent(); + + glMatrixMode(GL_MODELVIEW); + glRotatef((GLfloat)deg, 0.0F, 0.0F, 1.0F); + Refresh(FALSE); +} + + +/* ----------------------------------------------------------------------- + Main Window +-------------------------------------------------------------------------*/ + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(wxID_EXIT, MyFrame::OnExit) + EVT_MENU( ID_NEW_WINDOW, MyFrame::OnNewWindow) + EVT_MENU( ID_DEF_ROTATE_LEFT_KEY, MyFrame::OnDefRotateLeftKey) + EVT_MENU( ID_DEF_ROTATE_RIGHT_KEY, MyFrame::OnDefRotateRightKey) +END_EVENT_TABLE() + +// My frame constructor +MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, + const wxSize& size, long style) + : wxFrame(frame, -1, title, pos, size, style) +{ + m_canvas = NULL; +} + +// Intercept menu commands +void MyFrame::OnExit(wxCommandEvent& event) +{ + Destroy(); +} + +void MyFrame::OnNewWindow() +{ + MyFrame *frame = new MyFrame(NULL, "Cube OpenGL Demo Clone", + wxPoint(50, 50), wxSize(400, 300)); + // Give it an icon +#ifdef wx_msw + frame->SetIcon(wxIcon("mondrian")); +#endif + + // Make a menubar + wxMenu *winMenu = new wxMenu; + + winMenu->Append(wxID_EXIT, "&Close"); + winMenu->Append(ID_NEW_WINDOW, "&New" ); + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(winMenu, "&Window"); + + winMenu = new wxMenu; + winMenu->Append(ID_DEF_ROTATE_LEFT_KEY, "Rotate &left"); + winMenu->Append(ID_DEF_ROTATE_RIGHT_KEY, "Rotate &right"); + menuBar->Append(winMenu, "&Key"); + + frame->SetMenuBar(menuBar); + + frame->m_canvas = new TestGLCanvas( frame, *m_canvas, -1, + wxPoint(0, 0), wxSize(200, 200) ); + + // Show the frame + frame->Show(TRUE); +} + +void MyFrame::OnDefRotateLeftKey() +{ + ScanCodeDialog dial( this, -1, m_canvas->m_rleft, + wxString("Left"), "Define key" ); + int result = dial.ShowModal(); + if( result == wxID_OK ) + m_canvas->m_rleft = dial.GetValue(); +} +void MyFrame::OnDefRotateRightKey() +{ + ScanCodeDialog dial( this, -1, m_canvas->m_rright, + wxString("Right"), "Define key" ); + int result = dial.ShowModal(); + if( result == wxID_OK ) + m_canvas->m_rright = dial.GetValue(); +} + +/*------------------------------------------------------------------ + Application object ( equivalent to main() ) +------------------------------------------------------------------ */ + +IMPLEMENT_APP(MyApp) + +bool MyApp::OnInit(void) +{ + wxLog::SetTraceMask(wxTraceMessages); + + // Create the main frame window + MyFrame *frame = new MyFrame(NULL, "Cube OpenGL Demo", wxPoint(50, 50), + wxSize(400, 300)); + // Give it an icon +#ifdef wx_msw + frame->SetIcon(wxIcon("mondrian")); +#endif + + // Make a menubar + wxMenu *winMenu = new wxMenu; + + winMenu->Append(wxID_EXIT, "&Close"); + winMenu->Append(ID_NEW_WINDOW, "&New" ); + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(winMenu, "&Window"); + + winMenu = new wxMenu; + winMenu->Append(ID_DEF_ROTATE_LEFT_KEY, "Rotate &left"); + winMenu->Append(ID_DEF_ROTATE_RIGHT_KEY, "Rotate &right"); + menuBar->Append(winMenu, "&Key"); + + frame->SetMenuBar(menuBar); + + frame->m_canvas = new TestGLCanvas(frame, -1, wxPoint(0, 0), wxSize(200, 200)); + + // Show the frame + frame->Show(TRUE); + + return TRUE; +} diff --git a/samples/opengl/cube/cube.h b/samples/opengl/cube/cube.h new file mode 100644 index 0000000000..66732f2453 --- /dev/null +++ b/samples/opengl/cube/cube.h @@ -0,0 +1,93 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: cube.h +// Purpose: wxGLCanvas demo program +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_CUBE_H_ +#define _WX_CUBE_H_ + +#include + +// Define a new application type +class MyApp: public wxApp +{ +public: + bool OnInit(void); +}; + +// Define a new frame type +class TestGLCanvas; +class MyFrame: public wxFrame +{ +public: + MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, + const wxSize& size, long style = wxDEFAULT_FRAME_STYLE); + + void OnExit(wxCommandEvent& event); + void OnNewWindow(); + void OnDefRotateLeftKey(); + void OnDefRotateRightKey(); + +public: + TestGLCanvas* m_canvas; + +DECLARE_EVENT_TABLE() +}; + +class TestGLCanvas: public wxGLCanvas +{ + friend class MyFrame; +public: + TestGLCanvas(wxWindow *parent, const wxWindowID id = -1, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = 0, const wxString& name = "TestGLCanvas"); + TestGLCanvas(wxWindow *parent, const TestGLCanvas &other, + const wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, + const wxString& name = "TestGLCanvas" ); + + ~TestGLCanvas(void); + + void OnPaint(wxPaintEvent& event); + void OnSize(wxSizeEvent& event); + void OnEraseBackground(wxEraseEvent& event); + void OnKeyDown(wxKeyEvent& event); + void OnKeyUp(wxKeyEvent& event); + void OnEnterWindow( wxMouseEvent& event ); + + void Render( void ); + void InitGL(void); + void Rotate( GLfloat deg ); + static GLfloat CalcRotateSpeed( unsigned long acceltime ); + static GLfloat CalcRotateAngle( unsigned long lasttime, + unsigned long acceltime ); + void Action( long code, unsigned long lasttime, + unsigned long acceltime ); + +private: + bool m_init; + GLuint m_gllist; + long m_rleft; + long m_rright; + + static unsigned long m_secbase; + static int m_TimeInitialized; + static unsigned long m_xsynct; + static unsigned long m_gsynct; + + long m_Key; + unsigned long m_StartTime; + unsigned long m_LastTime; + unsigned long m_LastRedraw; + +DECLARE_EVENT_TABLE() +}; + +#endif + diff --git a/samples/opengl/cube/cube.rc b/samples/opengl/cube/cube.rc new file mode 100644 index 0000000000..7655c62a4c --- /dev/null +++ b/samples/opengl/cube/cube.rc @@ -0,0 +1,3 @@ +mondrian ICON "mondrian.ico" +#include "wx/msw/wx.rc" + diff --git a/samples/opengl/cube/makefile.b32 b/samples/opengl/cube/makefile.b32 new file mode 100644 index 0000000000..7bc170c87a --- /dev/null +++ b/samples/opengl/cube/makefile.b32 @@ -0,0 +1,18 @@ +# +# File: makefile.b32 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: +# +# Makefile : Builds sample for 32-bit BC++ + +WXDIR = $(WXWIN) + +TARGET=cube +#EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +#EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win +OBJECTS = $(TARGET).obj + +!include $(WXDIR)\src\makeprog.b32 + diff --git a/samples/opengl/cube/makefile.bcc b/samples/opengl/cube/makefile.bcc new file mode 100644 index 0000000000..b46274d17e --- /dev/null +++ b/samples/opengl/cube/makefile.bcc @@ -0,0 +1,21 @@ +# +# File: makefile.bcc +# Author: Julian Smart +# Created: 1998 +# Updated: +# +# Builds a BC++ 16-bit sample + +!if "$(WXWIN)" == "" +!error You must define the WXWIN variable in autoexec.bat, e.g. WXWIN=c:\wx +!endif + +WXDIR = $(WXWIN) + +TARGET=cube +#EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +#EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win +OBJECTS = $(TARGET).obj + +!include $(WXDIR)\src\makeprog.bcc + diff --git a/samples/opengl/cube/makefile.g95 b/samples/opengl/cube/makefile.g95 new file mode 100644 index 0000000000..60381560ed --- /dev/null +++ b/samples/opengl/cube/makefile.g95 @@ -0,0 +1,18 @@ +# +# File: makefile.g95 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart, 1999 +# +# Makefile for wxWindows sample (Cygwin/Mingw32). + +WXDIR = ../../.. + +TARGET=cube +#EXTRACPPFLAGS=-I../../win +EXTRALIBS=-lopengl32 -lglu32 +OBJECTS = $(TARGET).o + +include $(WXDIR)/src/makeprog.g95 + diff --git a/samples/opengl/cube/makefile.unx b/samples/opengl/cube/makefile.unx new file mode 100644 index 0000000000..ecf313ff33 --- /dev/null +++ b/samples/opengl/cube/makefile.unx @@ -0,0 +1,23 @@ +# +# File: makefile.unx +# Author: Julian Smart +# Created: 1998 +# Updated: +# Copyright: (c) 1998 Julian Smart +# +# "%W% %G%" +# +# Makefile for cube example (UNIX). + +PROGRAM=cube + +OPENGLHOME=/home/jacs/mesa/Mesa-2.3 + +EXTRACPPFLAGS=-I$(OPENGLHOME)/include +EXTRALDFLAGS=-L$(OPENGLHOME)/lib +EXTRALDLIBS=-lMesaGL -lMesaGLU + +OBJECTS=$(PROGRAM).o + +include ../../../src/makeprog.env + diff --git a/samples/opengl/cube/makefile.vc b/samples/opengl/cube/makefile.vc new file mode 100644 index 0000000000..c761a91325 --- /dev/null +++ b/samples/opengl/cube/makefile.vc @@ -0,0 +1,26 @@ +# +# File: makefile.vc +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart +# +# Makefile : Builds sample (VC++, WIN32) +# Use FINAL=1 argument to nmake to build final version with no debug info. + +# Set WXDIR for your system +WXDIR = $(WXWIN) + +!if "$(FINAL)" == "1" +!else +LIBEXT=_d +!endif + +PROGRAM=cube +OBJECTS = $(PROGRAM).obj +#EXTRAINC=-I..\..\win +#EXTRALIBS=$(WXDIR)\lib\glcanvas$(LIBEXT).lib glu32.lib opengl32.lib +EXTRALIBS=glu32.lib opengl32.lib + +!include $(WXDIR)\src\makeprog.vc + diff --git a/samples/opengl/cube/makefile.wat b/samples/opengl/cube/makefile.wat new file mode 100644 index 0000000000..66cb0511c1 --- /dev/null +++ b/samples/opengl/cube/makefile.wat @@ -0,0 +1,17 @@ +# +# Makefile for WATCOM +# +# Created by Julian Smart, January 1999 +# +# + +WXDIR = $(%WXWIN) + +PROGRAM = cube +OBJECTS = $(PROGRAM).obj +#EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +#EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win + +!include $(WXDIR)\src\makeprog.wat + + diff --git a/samples/opengl/cube/mondrian.ico b/samples/opengl/cube/mondrian.ico new file mode 100644 index 0000000000000000000000000000000000000000..2310c5d275a87af295d5ea8dc79ea417a5e74c53 GIT binary patch literal 766 zcmZQzU<5)11px*Sc)`TLAO@s0fLH;D9e|jTfdxnc0Z +#include + +#include "isosurf.h" + +// The following part is taken largely unchanged from the original C Version + +#include + +GLboolean speed_test = GL_FALSE; +GLboolean use_vertex_arrays = GL_FALSE; + +GLboolean doubleBuffer = GL_TRUE; + +GLboolean smooth = GL_TRUE; +GLboolean lighting = GL_TRUE; + + +#define MAXVERTS 10000 + +static GLfloat verts[MAXVERTS][3]; +static GLfloat norms[MAXVERTS][3]; +static GLint numverts; + +static GLfloat xrot; +static GLfloat yrot; + + +static void read_surface( char *filename ) +{ + FILE *f; + + f = fopen(filename,"r"); + if (!f) { + wxString msg("Couldn't read "); + msg += filename; + wxMessageBox(msg); + return; + } + + numverts = 0; + while (!feof(f) && numvertsSetIcon(wxIcon("mondrian")); + + // Make a menubar + wxMenu *fileMenu = new wxMenu; + + fileMenu->Append(wxID_EXIT, "E&xit"); + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(fileMenu, "&File"); + frame->SetMenuBar(menuBar); + + // Make a TestGLCanvas + + // JACS +#ifdef __WXMSW__ + int *gl_attrib = NULL; +#else + int gl_attrib[20] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 1, + GLX_DOUBLEBUFFER, None }; +#endif + + if(!doubleBuffer) + { + printf("don't have double buffer, disabling\n"); +#ifdef __WXGTK__ + gl_attrib[9] = None; +#endif + doubleBuffer = GL_FALSE; + } + frame->m_canvas = new TestGLCanvas(frame, -1, wxPoint(0, 0), wxSize(200, 200), 0, "TestGLCanvas", + gl_attrib); + + // Show the frame + frame->Show(TRUE); + + frame->m_canvas->SetCurrent(); + read_surface( "isosurf.dat" ); + + Init(); + + return TRUE; +} + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(wxID_EXIT, MyFrame::OnExit) +END_EVENT_TABLE() + +// My frame constructor +MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, + const wxSize& size, long style): + wxFrame(frame, -1, title, pos, size, style) +{ + m_canvas = NULL; +} + +// Intercept menu commands +void MyFrame::OnExit(wxCommandEvent& event) +{ + Destroy(); +} + +/* + * TestGLCanvas implementation + */ + +BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) + EVT_SIZE(TestGLCanvas::OnSize) + EVT_PAINT(TestGLCanvas::OnPaint) + EVT_CHAR(TestGLCanvas::OnChar) + EVT_MOUSE_EVENTS(TestGLCanvas::OnMouseEvent) + EVT_ERASE_BACKGROUND(TestGLCanvas::OnEraseBackground) +END_EVENT_TABLE() + +TestGLCanvas::TestGLCanvas(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, int* gl_attrib): + wxGLCanvas(parent, id, pos, size, style, name, gl_attrib) +{ + parent->Show(TRUE); + SetCurrent(); + /* Make sure server supports the vertex array extension */ + char* extensions = (char *) glGetString( GL_EXTENSIONS ); + if (!extensions || !strstr( extensions, "GL_EXT_vertex_array" )) { + use_vertex_arrays = GL_FALSE; + } +} + + +TestGLCanvas::~TestGLCanvas(void) +{ +} + +void TestGLCanvas::OnPaint( wxPaintEvent& event ) +{ + // This is a dummy, to avoid an endless succession of paint messages. + // OnPaint handlers must always create a wxPaintDC. + wxPaintDC dc(this); + + draw1(); + SwapBuffers(); +} + +void TestGLCanvas::OnSize(wxSizeEvent& event) +{ + SetCurrent(); + int width, height; + GetClientSize(& width, & height); + Reshape(width, height); +} + +void TestGLCanvas::OnChar(wxKeyEvent& event) +{ + switch(event.KeyCode()) { + case WXK_ESCAPE: + exit(0); + case WXK_LEFT: + yrot -= 15.0; + break; + case WXK_RIGHT: + yrot += 15.0; + break; + case WXK_UP: + xrot += 15.0; + break; + case WXK_DOWN: + xrot -= 15.0; + break; + case 's': case 'S': + smooth = !smooth; + if (smooth) { + glShadeModel(GL_SMOOTH); + } else { + glShadeModel(GL_FLAT); + } + break; + case 'l': case 'L': + lighting = !lighting; + if (lighting) { + glEnable(GL_LIGHTING); + } else { + glDisable(GL_LIGHTING); + } + break; + default: + { + event.Skip(); + return; + } + } + + Refresh(FALSE); +} + +void TestGLCanvas::OnMouseEvent(wxMouseEvent& event) +{ + static int dragging = 0; + static float last_x, last_y; + + //printf("%f %f %d\n", event.GetX(), event.GetY(), (int)event.LeftIsDown()); + if(event.LeftIsDown()) { + if(!dragging) { + dragging = 1; + } else { + yrot += (event.GetX() - last_x)*1.0; + xrot += (event.GetY() - last_y)*1.0; + Refresh(FALSE); + } + last_x = event.GetX(); + last_y = event.GetY(); + } else + dragging = 0; +} + +void TestGLCanvas::OnEraseBackground(wxEraseEvent& event) +{ + // Do nothing, to avoid flashing. +} + diff --git a/samples/opengl/isosurf/isosurf.dat.gz b/samples/opengl/isosurf/isosurf.dat.gz new file mode 100644 index 0000000000000000000000000000000000000000..c07dc570d26c504f21d610df90b7363ba6027a2f GIT binary patch literal 65537 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� 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 qkla!vh$gU!pzjmNt1;j8x0B93 literal 0 HcmV?d00001 diff --git a/samples/opengl/isosurf/isosurf.h b/samples/opengl/isosurf/isosurf.h new file mode 100644 index 0000000000..e84098c56b --- /dev/null +++ b/samples/opengl/isosurf/isosurf.h @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: isosurf.h +// Purpose: wxGLCanvas demo program +// Author: Brian Paul (original gltk version), Wolfram Gloger +// Modified by: Julian Smart +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_ISOSURF_H_ +#define _WX_ISOSURF_H_ + +// Define a new application type +class MyApp: public wxApp +{ public: + bool OnInit(void); +}; + +class TestGLCanvas: public wxGLCanvas +{ + public: + TestGLCanvas(wxWindow *parent, const wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = "TestGLCanvas", + int* gl_attrib = NULL); + ~TestGLCanvas(void); + + void OnPaint(wxPaintEvent& event); + void OnSize(wxSizeEvent& event); + void OnEraseBackground(wxEraseEvent& event); + void OnChar(wxKeyEvent& event); + void OnMouseEvent(wxMouseEvent& event); + +DECLARE_EVENT_TABLE() +}; + +class MyFrame: public wxFrame +{ +public: + MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, + long style = wxDEFAULT_FRAME_STYLE); + + void OnExit(wxCommandEvent& event); +public: + TestGLCanvas* m_canvas; + +DECLARE_EVENT_TABLE() +}; + +#endif + diff --git a/samples/opengl/isosurf/isosurf.rc b/samples/opengl/isosurf/isosurf.rc new file mode 100644 index 0000000000..7655c62a4c --- /dev/null +++ b/samples/opengl/isosurf/isosurf.rc @@ -0,0 +1,3 @@ +mondrian ICON "mondrian.ico" +#include "wx/msw/wx.rc" + diff --git a/samples/opengl/isosurf/makefile.b32 b/samples/opengl/isosurf/makefile.b32 new file mode 100644 index 0000000000..0154a0aac0 --- /dev/null +++ b/samples/opengl/isosurf/makefile.b32 @@ -0,0 +1,22 @@ +# +# File: makefile.b32 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: +# +# Makefile : Builds sample for 32-bit BC++ + +WXDIR = $(WXWIN) + +TARGET=isosurf +# EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +# EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win +OBJECTS = $(TARGET).obj +EXTRATARGETS=isosurf.dat + +!include $(WXDIR)\src\makeprog.b32 + +isosurf.dat: isosurf.dat.gz + gzip -c -d isosurf.dat.gz > isosurf.dat + diff --git a/samples/opengl/isosurf/makefile.bcc b/samples/opengl/isosurf/makefile.bcc new file mode 100644 index 0000000000..680d8c95bf --- /dev/null +++ b/samples/opengl/isosurf/makefile.bcc @@ -0,0 +1,25 @@ +# +# File: makefile.bcc +# Author: Julian Smart +# Created: 1998 +# Updated: +# +# Builds a BC++ 16-bit sample + +!if "$(WXWIN)" == "" +!error You must define the WXWIN variable in autoexec.bat, e.g. WXWIN=c:\wx +!endif + +WXDIR = $(WXWIN) + +TARGET=isosurf +# EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +# EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win +OBJECTS = $(TARGET).obj +EXTRATARGETS=isosurf.dat + +!include $(WXDIR)\src\makeprog.bcc + +isosurf.dat: isosurf.dat.gz + gzip -c -d isosurf.dat.gz > isosurf.dat + diff --git a/samples/opengl/isosurf/makefile.g95 b/samples/opengl/isosurf/makefile.g95 new file mode 100644 index 0000000000..f0396a5d3d --- /dev/null +++ b/samples/opengl/isosurf/makefile.g95 @@ -0,0 +1,20 @@ +# +# File: makefile.g95 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart, 1999 +# +# Makefile for wxWindows sample (Cygwin/Mingw32). + +WXDIR = ../../.. + +TARGET=isosurf +# EXTRACPPFLAGS=-I../../win +EXTRALIBS=-lopengl32 -lglu32 +OBJECTS = $(TARGET).o + +include $(WXDIR)/src/makeprog.g95 + +isosurf.dat: isosurf.dat.gz + gzip -c -d isosurf.dat.gz > isosurf.dat diff --git a/samples/opengl/isosurf/makefile.unx b/samples/opengl/isosurf/makefile.unx new file mode 100644 index 0000000000..2c0a364808 --- /dev/null +++ b/samples/opengl/isosurf/makefile.unx @@ -0,0 +1,27 @@ +# +# File: makefile.unx +# Author: Julian Smart +# Created: 1998 +# Updated: +# Copyright: (c) 1998 Julian Smart +# +# "%W% %G%" +# +# Makefile for isosurf example (UNIX). + +PROGRAM=isosurf + +OPENGLHOME=/home/jacs/mesa/Mesa-2.3 + +EXTRACPPFLAGS=-I$(OPENGLHOME)/include +EXTRALDFLAGS=-L$(OPENGLHOME)/lib +EXTRALDLIBS=-lMesaGL -lMesaGLU + +OBJECTS=$(PROGRAM).o +EXTRATARGETS=isosurf.dat + +include ../../../src/makeprog.env + +isosurf.dat: isosurf.dat.gz + gzip -c -d isosurf.dat.gz > isosurf.dat + diff --git a/samples/opengl/isosurf/makefile.vc b/samples/opengl/isosurf/makefile.vc new file mode 100644 index 0000000000..9c787154f2 --- /dev/null +++ b/samples/opengl/isosurf/makefile.vc @@ -0,0 +1,30 @@ +# +# File: makefile.vc +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart +# +# Makefile : Builds sample (VC++, WIN32) +# Use FINAL=1 argument to nmake to build final version with no debug info. + +# Set WXDIR for your system +WXDIR = $(WXWIN) + +!if "$(FINAL)" == "1" +!else +LIBEXT=_d +!endif + +PROGRAM=isosurf +OBJECTS = $(PROGRAM).obj +#EXTRAINC=-I..\..\win +EXTRALIBS=glu32.lib opengl32.lib +EXTRATARGETS=isosurf.dat + +!include $(WXDIR)\src\makeprog.vc + +isosurf.dat: isosurf.dat.gz + gzip -c -d isosurf.dat.gz > isosurf.dat + + diff --git a/samples/opengl/isosurf/makefile.wat b/samples/opengl/isosurf/makefile.wat new file mode 100644 index 0000000000..ba3a87cef8 --- /dev/null +++ b/samples/opengl/isosurf/makefile.wat @@ -0,0 +1,20 @@ +# +# Makefile for WATCOM +# +# Created by Julian Smart, January 1999 +# +# + +WXDIR = $(%WXWIN) + +PROGRAM = isosurf +OBJECTS = $(PROGRAM).obj +#EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +#EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win +EXTRATARGETS=isosurf.dat + +!include $(WXDIR)\src\makeprog.wat + +isosurf.dat: isosurf.dat.gz + gzip -c -d isosurf.dat.gz > isosurf.dat + diff --git a/samples/opengl/isosurf/mondrian.ico b/samples/opengl/isosurf/mondrian.ico new file mode 100644 index 0000000000000000000000000000000000000000..2310c5d275a87af295d5ea8dc79ea417a5e74c53 GIT binary patch literal 766 zcmZQzU<5)11px*Sc)`TLAO@s0fLH;D9e|jTfdxnc0Z + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifdef __WXMSW__ +#include +#endif + +#include "lw.h" +#include +#include +#include + +#define wxInt32 int +#define wxUint32 unsigned int + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#define MK_ID(a,b,c,d) ((((wxUint32)(a))<<24)| \ + (((wxUint32)(b))<<16)| \ + (((wxUint32)(c))<< 8)| \ + (((wxUint32)(d)) )) + +#define ID_FORM MK_ID('F','O','R','M') +#define ID_LWOB MK_ID('L','W','O','B') +#define ID_PNTS MK_ID('P','N','T','S') +#define ID_SRFS MK_ID('S','R','F','S') +#define ID_SURF MK_ID('S','U','R','F') +#define ID_POLS MK_ID('P','O','L','S') +#define ID_COLR MK_ID('C','O','L','R') + +static wxInt32 read_char(FILE *f) +{ + int c = fgetc(f); + return c; +} + +static wxInt32 read_short(FILE *f) +{ + return (read_char(f)<<8) | read_char(f); +} + +static wxInt32 read_long(FILE *f) +{ + return (read_char(f)<<24) | (read_char(f)<<16) | (read_char(f)<<8) | read_char(f); +} + +static GLfloat read_float(FILE *f) +{ + wxInt32 x = read_long(f); + return *(GLfloat*)&x; +} + +static int read_string(FILE *f, char *s) +{ + int c; + int cnt = 0; + do { + c = read_char(f); + if (cnt < LW_MAX_NAME_LEN) + s[cnt] = c; + else + s[LW_MAX_NAME_LEN-1] = 0; + cnt++; + } while (c != 0); + /* if length of string (including \0) is odd skip another byte */ + if (cnt%2) { + read_char(f); + cnt++; + } + return cnt; +} + +static void read_srfs(FILE *f, int nbytes, lwObject *lwo) +{ + int guess_cnt = lwo->material_cnt; + + while (nbytes > 0) { + lwMaterial *material; + + /* allocate more memory for materials if needed */ + if (guess_cnt <= lwo->material_cnt) { + guess_cnt += guess_cnt/2 + 4; + lwo->material = (lwMaterial*) realloc(lwo->material, sizeof(lwMaterial)*guess_cnt); + } + material = lwo->material + lwo->material_cnt++; + + /* read name */ + nbytes -= read_string(f,material->name); + + /* defaults */ + material->r = 0.7; + material->g = 0.7; + material->b = 0.7; + } + lwo->material = (lwMaterial*) realloc(lwo->material, sizeof(lwMaterial)*lwo->material_cnt); +} + + +static void read_surf(FILE *f, int nbytes, lwObject *lwo) +{ + int i; + char name[LW_MAX_NAME_LEN]; + lwMaterial *material = NULL; + + /* read surface name */ + nbytes -= read_string(f,name); + + /* find material */ + for (i=0; i< lwo->material_cnt; i++) { + if (strcmp(lwo->material[i].name,name) == 0) { + material = &lwo->material[i]; + break; + } + } + + /* read values */ + while (nbytes > 0) { + int id = read_long(f); + int len = read_short(f); + nbytes -= 6 + len + (len%2); + + switch (id) { + case ID_COLR: + material->r = read_char(f) / 255.0; + material->g = read_char(f) / 255.0; + material->b = read_char(f) / 255.0; + read_char(f); /* dummy */ + break; + default: + fseek(f, len+(len%2), SEEK_CUR); + } + } +} + + +static void read_pols(FILE *f, int nbytes, lwObject *lwo) +{ + int guess_cnt = lwo->face_cnt; + + while (nbytes > 0) { + lwFace *face; + int i; + + /* allocate more memory for polygons if necessary */ + if (guess_cnt <= lwo->face_cnt) { + guess_cnt += guess_cnt + 4; + lwo->face = (lwFace*) realloc((void*) lwo->face, sizeof(lwFace)*guess_cnt); + } + face = lwo->face + lwo->face_cnt++; + + /* number of points in this face */ + face->index_cnt = read_short(f); + nbytes -= 2; + + /* allocate space for points */ + face->index = (int*) calloc(sizeof(int)*face->index_cnt,1); + + /* read points in */ + for (i=0; iindex_cnt; i++) { + face->index[i] = read_short(f); + nbytes -= 2; + } + + /* read surface material */ + face->material = read_short(f); + nbytes -= 2; + + /* skip over detail polygons */ + if (face->material < 0) { + int det_cnt; + face->material = -face->material; + det_cnt = read_short(f); + nbytes -= 2; + while (det_cnt-- > 0) { + int cnt = read_short(f); + fseek(f, cnt*2+2, SEEK_CUR); + nbytes -= cnt*2+2; + } + } + face->material -= 1; + } + /* readjust to true size */ + lwo->face = (lwFace*) realloc(lwo->face, sizeof(lwFace)*lwo->face_cnt); +} + + + +static void read_pnts(FILE *f, int nbytes, lwObject *lwo) +{ + int i; + lwo->vertex_cnt = nbytes / 12; + lwo->vertex = (float*) calloc(sizeof(GLfloat)*lwo->vertex_cnt*3, 1); + for (i=0; ivertex_cnt; i++) { + lwo->vertex[i*3+0] = read_float(f); + lwo->vertex[i*3+1] = read_float(f); + lwo->vertex[i*3+2] = read_float(f); + } +} + + + + + + +int lw_is_lwobject(const char *lw_file) +{ + FILE *f = fopen(lw_file, "rb"); + if (f) { + wxInt32 form = read_long(f); + wxInt32 nlen = read_long(f); + wxInt32 lwob = read_long(f); + fclose(f); + if (form == ID_FORM && nlen != 0 && lwob == ID_LWOB) + return TRUE; + } + return FALSE; +} + + +lwObject *lw_object_read(const char *lw_file) +{ + FILE *f = NULL; + lwObject *lw_object = NULL; + + wxInt32 form_bytes = 0; + wxInt32 read_bytes = 0; + + /* open file */ + f = fopen(lw_file, "rb"); + if (f == NULL) { + return NULL; + } + + /* check for headers */ + if (read_long(f) != ID_FORM) { + fclose(f); + return NULL; + } + form_bytes = read_long(f); + read_bytes += 4; + + if (read_long(f) != ID_LWOB) { + fclose(f); + return NULL; + } + + /* create new lwObject */ + lw_object = (lwObject*) calloc(sizeof(lwObject),1); + + /* read chunks */ + while (read_bytes < form_bytes) { + wxInt32 id = read_long(f); + wxInt32 nbytes = read_long(f); + read_bytes += 8 + nbytes + (nbytes%2); + + switch (id) { + case ID_PNTS: + read_pnts(f, nbytes, lw_object); + break; + case ID_POLS: + read_pols(f, nbytes, lw_object); + break; + case ID_SRFS: + read_srfs(f, nbytes, lw_object); + break; + case ID_SURF: + read_surf(f, nbytes, lw_object); + break; + default: + fseek(f, nbytes + (nbytes%2), SEEK_CUR); + } + } + + fclose(f); + return lw_object; +} + + + +void lw_object_free(lwObject *lw_object) +{ + if (lw_object->face) { + int i; + for (i=0; iface_cnt; i++) + free(lw_object->face[i].index); + free(lw_object->face); + } + free(lw_object->material); + free(lw_object->vertex); + free(lw_object); +} + + + + + +#define PX(i) (lw_object->vertex[face->index[i]*3+0]) +#define PY(i) (lw_object->vertex[face->index[i]*3+1]) +#define PZ(i) (lw_object->vertex[face->index[i]*3+2]) +void lw_object_show(const lwObject *lw_object) +{ + int i,j; + int prev_index_cnt = -1; + int prev_material = -1; + GLfloat prev_nx = 0; + GLfloat prev_ny = 0; + GLfloat prev_nz = 0; + + for (i=0; iface_cnt; i++) { + GLfloat ax,ay,az,bx,by,bz,nx,ny,nz,r; + const lwFace *face = lw_object->face+i; + + /* ignore faces with less than 3 points */ + if (face->index_cnt < 3) + continue; + + /* calculate normal */ + ax = PX(1) - PX(0); + ay = PY(1) - PY(0); + az = PZ(1) - PZ(0); + + bx = PX(face->index_cnt-1) - PX(0); + by = PY(face->index_cnt-1) - PY(0); + bz = PZ(face->index_cnt-1) - PZ(0); + + nx = ay * bz - az * by; + ny = az * bx - ax * bz; + nz = ax * by - ay * bx; + + r = sqrt(nx*nx + ny*ny + nz*nz); + if (r < 0.000001) /* avoid division by zero */ + continue; + nx /= r; + ny /= r; + nz /= r; + + /* glBegin/glEnd */ + if (prev_index_cnt != face->index_cnt || prev_index_cnt > 4) { + if (prev_index_cnt > 0) glEnd(); + prev_index_cnt = face->index_cnt; + switch (face->index_cnt) { + case 3: + glBegin(GL_TRIANGLES); + break; + case 4: + glBegin(GL_QUADS); + break; + default: + glBegin(GL_POLYGON); + } + } + + /* update material if necessary */ + if (prev_material != face->material) { + prev_material = face->material; + glColor3f(lw_object->material[face->material].r, + lw_object->material[face->material].g, + lw_object->material[face->material].b); + } + + /* update normal if necessary */ + if (nx != prev_nx || ny != prev_ny || nz != prev_nz) { + prev_nx = nx; + prev_ny = ny; + prev_nz = nz; + glNormal3f(nx,ny,nz); + } + + /* draw polygon/triangle/quad */ + for (j=0; jindex_cnt; j++) + glVertex3f(PX(j),PY(j),PZ(j)); + + } + + /* if glBegin was called call glEnd */ + if (prev_index_cnt > 0) + glEnd(); +} + + +GLfloat lw_object_radius(const lwObject *lwo) +{ + int i; + double max_radius = 0.0; + + for (i=0; ivertex_cnt; i++) { + GLfloat *v = &lwo->vertex[i*3]; + double r = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + if (r > max_radius) + max_radius = r; + } + return sqrt(max_radius); +} + +void lw_object_scale(lwObject *lwo, GLfloat scale) +{ + int i; + + for (i=0; ivertex_cnt; i++) { + lwo->vertex[i*3+0] *= scale; + lwo->vertex[i*3+1] *= scale; + lwo->vertex[i*3+2] *= scale; + } +} + + diff --git a/samples/opengl/penguin/lw.h b/samples/opengl/penguin/lw.h new file mode 100644 index 0000000000..b49e8ffc91 --- /dev/null +++ b/samples/opengl/penguin/lw.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 1998 Janne Löf + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef LW_H +#define LW_H + +#include + +#define LW_MAX_POINTS 200 +#define LW_MAX_NAME_LEN 500 + +typedef struct { + char name[LW_MAX_NAME_LEN]; + GLfloat r,g,b; +} lwMaterial; + +typedef struct { + int material; /* material of this face */ + int index_cnt; /* number of vertices */ + int *index; /* index to vertex */ + float *texcoord; /* u,v texture coordinates */ +} lwFace; + +typedef struct { + int face_cnt; + lwFace *face; + + int material_cnt; + lwMaterial *material; + + int vertex_cnt; + GLfloat *vertex; + +} lwObject; + +#ifdef __cplusplus +extern "C" { +#endif + +int lw_is_lwobject(const char *lw_file); +lwObject *lw_object_read(const char *lw_file); +void lw_object_free( lwObject *lw_object); +void lw_object_show(const lwObject *lw_object); + +GLfloat lw_object_radius(const lwObject *lw_object); +void lw_object_scale (lwObject *lw_object, GLfloat scale); + +#ifdef __cplusplus +} +#endif + +#endif /* LW_H */ + diff --git a/samples/opengl/penguin/makefile.b32 b/samples/opengl/penguin/makefile.b32 new file mode 100644 index 0000000000..0f8d581ddc --- /dev/null +++ b/samples/opengl/penguin/makefile.b32 @@ -0,0 +1,18 @@ +# +# File: makefile.b32 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: +# +# Makefile : Builds sample for 32-bit BC++ + +WXDIR = $(WXWIN) + +TARGET=penguin +#EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +#EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win +OBJECTS = $(TARGET).obj lw.obj trackball.obj + +!include $(WXDIR)\src\makeprog.b32 + diff --git a/samples/opengl/penguin/makefile.bcc b/samples/opengl/penguin/makefile.bcc new file mode 100644 index 0000000000..c789bde1b0 --- /dev/null +++ b/samples/opengl/penguin/makefile.bcc @@ -0,0 +1,21 @@ +# +# File: makefile.bcc +# Author: Julian Smart +# Created: 1998 +# Updated: +# +# Builds a BC++ 16-bit sample + +!if "$(WXWIN)" == "" +!error You must define the WXWIN variable in autoexec.bat, e.g. WXWIN=c:\wx +!endif + +WXDIR = $(WXWIN) + +TARGET=penguin +#EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +#EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win +OBJECTS = $(TARGET).obj + +!include $(WXDIR)\src\makeprog.bcc + diff --git a/samples/opengl/penguin/makefile.g95 b/samples/opengl/penguin/makefile.g95 new file mode 100644 index 0000000000..a15d8d0306 --- /dev/null +++ b/samples/opengl/penguin/makefile.g95 @@ -0,0 +1,18 @@ +# +# File: makefile.g95 +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart, 1999 +# +# Makefile for wxWindows sample (Cygwin/Mingw32). + +WXDIR = ../../.. + +TARGET=penguin +#EXTRACPPFLAGS=-I../../win +EXTRALIBS=-lopengl32 -lglu32 +OBJECTS = $(TARGET).o lw.o trackball.o + +include $(WXDIR)/src/makeprog.g95 + diff --git a/samples/opengl/penguin/makefile.unx b/samples/opengl/penguin/makefile.unx new file mode 100644 index 0000000000..c8d335c1bf --- /dev/null +++ b/samples/opengl/penguin/makefile.unx @@ -0,0 +1,21 @@ +# +# File: makefile.unx +# Author: Julian Smart +# Created: 1998 +# Updated: +# Copyright: (c) 1998 Julian Smart +# +# Makefile for penguin example (UNIX). + +PROGRAM=penguin + +OPENGLHOME=/home/jacs/mesa/Mesa-2.3 + +EXTRACPPFLAGS=-I$(OPENGLHOME)/include # -I../../motif +EXTRALDFLAGS=-L$(OPENGLHOME)/lib +EXTRALDLIBS=-lMesaGL -lMesaGLU + +OBJECTS=$(PROGRAM).o trackball.o lw.o + +include ../../../src/makeprog.env + diff --git a/samples/opengl/penguin/makefile.vc b/samples/opengl/penguin/makefile.vc new file mode 100644 index 0000000000..246fea6d3e --- /dev/null +++ b/samples/opengl/penguin/makefile.vc @@ -0,0 +1,30 @@ +# +# File: makefile.vc +# Author: Julian Smart +# Created: 1999 +# Updated: +# Copyright: (c) Julian Smart +# +# Makefile : Builds sample (VC++, WIN32) +# Use FINAL=1 argument to nmake to build final version with no debug info. + +# Set WXDIR for your system +WXDIR = $(WXWIN) + +!if "$(FINAL)" == "1" +!else +LIBEXT=_d +!endif + +PROGRAM=penguin +OBJECTS = $(PROGRAM).obj trackball.obj lw.obj +#EXTRAINC=-I..\..\win +EXTRALIBS=glu32.lib opengl32.lib + +!include $(WXDIR)\src\makeprog.vc + +lw.obj: lw.cpp lw.h + $(cc) @<< +$(CPPFLAGS2) /c $*.$(SRCSUFF) +<< + diff --git a/samples/opengl/penguin/makefile.wat b/samples/opengl/penguin/makefile.wat new file mode 100644 index 0000000000..c8a2f81645 --- /dev/null +++ b/samples/opengl/penguin/makefile.wat @@ -0,0 +1,17 @@ +# +# Makefile for WATCOM +# +# Created by Julian Smart, January 1999 +# +# + +WXDIR = $(%WXWIN) + +PROGRAM = penguin +OBJECTS = $(PROGRAM).obj +#EXTRALIBS=$(WXDIR)\lib\glcanvas.lib +#EXTRACPPFLAGS=-I$(WXDIR)\utils\glcanvas\win + +!include $(WXDIR)\src\makeprog.wat + + diff --git a/samples/opengl/penguin/penguin.cpp b/samples/opengl/penguin/penguin.cpp new file mode 100644 index 0000000000..8eaed6a1d9 --- /dev/null +++ b/samples/opengl/penguin/penguin.cpp @@ -0,0 +1,236 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: penguin.cpp +// Purpose: wxGLCanvas demo program +// Author: Robert Roebling +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation +#pragma interface +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "penguin.h" +#include + +#define VIEW_ASPECT 1.3 + +/* `Main program' equivalent, creating windows and returning main app frame */ +bool MyApp::OnInit(void) +{ + + /* Create the main frame window */ + MyFrame *frame = new MyFrame(NULL, "wxWindows OpenGL Demo", wxPoint(50, 50), wxSize(400, 300)); + + /* Make a menubar */ + wxMenu *fileMenu = new wxMenu; + + fileMenu->Append(wxID_EXIT, "E&xit"); + wxMenuBar *menuBar = new wxMenuBar; + menuBar->Append(fileMenu, "&File"); + frame->SetMenuBar(menuBar); + + frame->m_canvas = new TestGLCanvas(frame, -1, wxPoint(0, 0), wxSize(200, 200)); + + /* Load file wiht mesh data */ + frame->m_canvas->LoadLWO( "penguin.lwo" ); + + /* Show the frame */ + frame->Show(TRUE); + + return TRUE; +} + +IMPLEMENT_APP(MyApp) + +BEGIN_EVENT_TABLE(MyFrame, wxFrame) + EVT_MENU(wxID_EXIT, MyFrame::OnExit) +END_EVENT_TABLE() + +/* My frame constructor */ +MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, + const wxSize& size, long style): + wxFrame(frame, -1, title, pos, size, style) +{ + m_canvas = NULL; +} + +/* Intercept menu commands */ +void MyFrame::OnExit(wxCommandEvent& event) +{ + Destroy(); +} + +BEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) + EVT_SIZE(TestGLCanvas::OnSize) + EVT_PAINT(TestGLCanvas::OnPaint) + EVT_ERASE_BACKGROUND(TestGLCanvas::OnEraseBackground) + EVT_MOUSE_EVENTS(TestGLCanvas::OnMouse) +END_EVENT_TABLE() + +TestGLCanvas::TestGLCanvas(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name): + wxGLCanvas(parent, id, pos, size, style, name) +{ + block = FALSE; +} + +TestGLCanvas::~TestGLCanvas(void) +{ + /* destroy mesh */ + lw_object_free(info.lwobject); +} + +void TestGLCanvas::OnPaint( wxPaintEvent& event ) +{ + /* must always be here */ + wxPaintDC dc(this); + +#ifndef __WXMOTIF__ + if (!GetContext()) return; +#endif + + SetCurrent(); + + /* initialize OpenGL */ + if (info.do_init == TRUE) + { + InitGL(); + info.do_init = FALSE; + } + + /* view */ + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + gluPerspective( info.zoom, VIEW_ASPECT, 1, 100 ); + glMatrixMode( GL_MODELVIEW ); + + /* clear */ + glClearColor( .3, .4, .6, 1 ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + /* transformations */ + GLfloat m[4][4]; + glLoadIdentity(); + glTranslatef( 0, 0, -30 ); + build_rotmatrix( m,info.quat ); + glMultMatrixf( &m[0][0] ); + + /* draw object */ + lw_object_show( info.lwobject ); + + /* flush */ + glFlush(); + + /* swap */ + SwapBuffers(); +} + +void TestGLCanvas::OnSize(wxSizeEvent& event) +{ + int width, height; + GetClientSize(& width, & height); + +#ifndef __WXMOTIF__ + if (GetContext()) +#endif + { + SetCurrent(); + glViewport(0, 0, width, height); + } +} + +void TestGLCanvas::OnEraseBackground(wxEraseEvent& event) +{ + /* Do nothing, to avoid flashing on MSW */ +} + +void TestGLCanvas::LoadLWO(const wxString &filename) +{ + /* test if lightwave object */ + if (!lw_is_lwobject(filename)) return; + + /* read lightwave object */ + lwObject *lwobject = lw_object_read(filename); + + /* scale */ + lw_object_scale(lwobject, 10.0 / lw_object_radius(lwobject)); + + /* set up mesh info */ + info.do_init = TRUE; + info.lwobject = lwobject; + info.beginx = 0; + info.beginy = 0; + info.zoom = 45; + trackball( info.quat, 0.0, 0.0, 0.0, 0.0 ); +} + +void TestGLCanvas::OnMouse( wxMouseEvent& event ) +{ + wxSize sz(GetClientSize()); + if (event.Dragging()) + { + /* drag in progress, simulate trackball */ + float spin_quat[4]; + trackball(spin_quat, + (2.0*info.beginx - sz.x) / sz.x, + ( sz.y - 2.0*info.beginy) / sz.y, + ( 2.0*event.GetX() - sz.x) / sz.x, + ( sz.y - 2.0*event.GetY()) / sz.y); + + add_quats( spin_quat, info.quat, info.quat ); + + /* orientation has changed, redraw mesh */ + Refresh(FALSE); + } + + info.beginx = event.GetX(); + info.beginy = event.GetY(); +} + +void TestGLCanvas::InitGL(void) +{ + GLfloat light0_pos[4] = { -50.0, 50.0, 0.0, 0.0 }; + GLfloat light0_color[4] = { .6, .6, .6, 1.0 }; /* white light */ + GLfloat light1_pos[4] = { 50.0, 50.0, 0.0, 0.0 }; + GLfloat light1_color[4] = { .4, .4, 1, 1.0 }; /* cold blue light */ + + /* remove back faces */ + glDisable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + /* speedups */ + glEnable(GL_DITHER); + glShadeModel(GL_SMOOTH); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST); + + /* light */ + glLightfv(GL_LIGHT0, GL_POSITION, light0_pos); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color); + glLightfv(GL_LIGHT1, GL_POSITION, light1_pos); + glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_color); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + + glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); +} + + diff --git a/samples/opengl/penguin/penguin.h b/samples/opengl/penguin/penguin.h new file mode 100644 index 0000000000..1730b2130f --- /dev/null +++ b/samples/opengl/penguin/penguin.h @@ -0,0 +1,84 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: penguin.h +// Purpose: wxGLCanvas demo program +// Author: Robert Roebling +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PENGUIN_H_ +#define _WX_PENGUIN_H_ + + +#include "wx/defs.h" +#include "wx/app.h" +#include "wx/menu.h" +#include "wx/dcclient.h" + +#include "wx/glcanvas.h" + +extern "C" { +#include "lw.h" +#include "trackball.h" +} + +/* information needed to display lightwave mesh */ +typedef struct +{ +// gint do_init; /* true if initgl not yet called */ + int do_init; + lwObject *lwobject; /* lightwave object mesh */ + float beginx,beginy; /* position of mouse */ + float quat[4]; /* orientation of object */ + float zoom; /* field of view in degrees */ +} mesh_info; + + +/* Define a new application type */ +class MyApp: public wxApp +{ +public: + bool OnInit(void); +}; + +/* Define a new frame type */ +class TestGLCanvas; +class MyFrame: public wxFrame +{ +public: + MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, + long style = wxDEFAULT_FRAME_STYLE); + + void OnExit(wxCommandEvent& event); +public: + TestGLCanvas* m_canvas; + +DECLARE_EVENT_TABLE() +}; + + +class TestGLCanvas: public wxGLCanvas +{ + public: + TestGLCanvas(wxWindow *parent, const wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = "TestGLCanvas"); + ~TestGLCanvas(void); + + void OnPaint(wxPaintEvent& event); + void OnSize(wxSizeEvent& event); + void OnEraseBackground(wxEraseEvent& event); + void LoadLWO( const wxString &filename); + void OnMouse( wxMouseEvent& event ); + void InitGL(void); + + mesh_info info; + bool block; + +DECLARE_EVENT_TABLE() +}; + +#endif + diff --git a/samples/opengl/penguin/penguin.lwo b/samples/opengl/penguin/penguin.lwo new file mode 100644 index 0000000000000000000000000000000000000000..3f5122db827e09028d394b682ee6c0a1deec0ddd GIT binary patch literal 10028 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 PcWrX~nY%asqw)U-TLDh; literal 0 HcmV?d00001 diff --git a/samples/opengl/penguin/penguin.rc b/samples/opengl/penguin/penguin.rc new file mode 100644 index 0000000000..626b82f58a --- /dev/null +++ b/samples/opengl/penguin/penguin.rc @@ -0,0 +1,3 @@ +/* mondrian ICON "mondrian.ico" */ +#include "wx/msw/wx.rc" + diff --git a/samples/opengl/penguin/trackball.h b/samples/opengl/penguin/trackball.h new file mode 100644 index 0000000000..b676fb4e54 --- /dev/null +++ b/samples/opengl/penguin/trackball.h @@ -0,0 +1,78 @@ +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * trackball.h + * A virtual trackball implementation + * Written by Gavin Bell for Silicon Graphics, November 1988. + */ + +/* + * Pass the x and y coordinates of the last and current positions of + * the mouse, scaled so they are from (-1.0 ... 1.0). + * + * The resulting rotation is returned as a quaternion rotation in the + * first paramater. + */ +void +trackball(float q[4], float p1x, float p1y, float p2x, float p2y); + +/* + * Given two quaternions, add them together to get a third quaternion. + * Adding quaternions to get a compound rotation is analagous to adding + * translations to get a compound translation. When incrementally + * adding rotations, the first argument here should be the new + * rotation, the second and third the total rotation (which will be + * over-written with the resulting new total rotation). + */ +void +add_quats(float *q1, float *q2, float *dest); + +/* + * A useful function, builds a rotation matrix in Matrix based on + * given quaternion. + */ +void +build_rotmatrix(float m[4][4], float q[4]); + +/* + * This function computes a quaternion based on an axis (defined by + * the given vector) and an angle about which to rotate. The angle is + * expressed in radians. The result is put into the third argument. + */ +void +axis_to_quat(float a[3], float phi, float q[4]); + diff --git a/src/generic/scrolwin.cpp b/src/generic/scrolwin.cpp index 1c28693778..ada5b1c236 100644 --- a/src/generic/scrolwin.cpp +++ b/src/generic/scrolwin.cpp @@ -85,6 +85,7 @@ wxScrolledWindow::wxScrolledWindow() m_yScrollLinesPerPage = 0; m_scaleX = 1.0; m_scaleY = 1.0; + m_targetWindow = (wxWindow*) NULL; } bool wxScrolledWindow::Create(wxWindow *parent, @@ -503,6 +504,9 @@ void wxScrolledWindow::SetScrollPageSize(int orient, int pageSize) */ void wxScrolledWindow::Scroll( int x_pos, int y_pos ) { + if (!m_targetWindow) + return; + if (((x_pos == -1) || (x_pos == m_xScrollPosition)) && ((y_pos == -1) || (y_pos == m_yScrollPosition))) return; diff --git a/src/gtk/glcanvas.cpp b/src/gtk/glcanvas.cpp new file mode 100644 index 0000000000..16c1cabe06 --- /dev/null +++ b/src/gtk/glcanvas.cpp @@ -0,0 +1,432 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.cpp +// Purpose: wxGLCanvas, for using OpenGL/Mesa with wxWindows and GTK +// Author: Robert Roebling +// Modified by: +// Created: 17/08/98 +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "glcanvas.h" +#endif + +#include "wx/setup.h" + +#if wxUSE_GLCANVAS + +#include "wx/glcanvas.h" + +#include "wx/frame.h" +#include "wx/colour.h" +#include "wx/module.h" +#include "wx/app.h" + +extern "C" { +#include "gtk/gtk.h" +#include "gdk/gdk.h" +#include "gdk/gdkx.h" +} + +#include "wx/gtk/win_gtk.h" + +//--------------------------------------------------------------------------- +// global data +//--------------------------------------------------------------------------- + +XVisualInfo *g_vi = (XVisualInfo*) NULL; + +//----------------------------------------------------------------------------- +// idle system +//----------------------------------------------------------------------------- + +extern void wxapp_install_idle_handler(); +extern bool g_isIdle; + +//--------------------------------------------------------------------------- +// wxGLContext +//--------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGLContext,wxObject) + +wxGLContext::wxGLContext( bool WXUNUSED(isRGB), wxWindow *win, const wxPalette& WXUNUSED(palette) ) +{ + m_window = win; + m_widget = win->m_wxwindow; + + wxGLCanvas *gc = (wxGLCanvas*) win; + XVisualInfo *vi = (XVisualInfo *) gc->m_vi; + + wxCHECK_RET( vi, "invalid visual for OpenGl" ); + + m_glContext = glXCreateContext( GDK_DISPLAY(), vi, None, GL_TRUE ); + + wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" ); +} + +wxGLContext::wxGLContext( + bool WXUNUSED(isRGB), wxWindow *win, + const wxPalette& WXUNUSED(palette), + const wxGLContext *other /* for sharing display lists */ +) +{ + m_window = win; + m_widget = win->m_wxwindow; + + wxGLCanvas *gc = (wxGLCanvas*) win; + XVisualInfo *vi = (XVisualInfo *) gc->m_vi; + + wxCHECK_RET( vi, "invalid visual for OpenGl" ); + + if( other != 0 ) + m_glContext = glXCreateContext( GDK_DISPLAY(), vi, other->m_glContext, GL_TRUE ); + else + m_glContext = glXCreateContext( GDK_DISPLAY(), vi, None, GL_TRUE ); + + wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" ); +} + +wxGLContext::~wxGLContext() +{ + if (!m_glContext) return; + + if (m_glContext == glXGetCurrentContext()) + { + glXMakeCurrent( GDK_DISPLAY(), None, NULL); + } + + glXDestroyContext( GDK_DISPLAY(), m_glContext ); +} + +void wxGLContext::SwapBuffers() +{ + if (m_glContext) + { + GdkWindow *window = GTK_PIZZA(m_widget)->bin_window; + glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window ) ); + } +} + +void wxGLContext::SetCurrent() +{ + if (m_glContext) + { + GdkWindow *window = GTK_PIZZA(m_widget)->bin_window; + glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window), m_glContext ); + } +} + +void wxGLContext::SetColour(const char *colour) +{ + float r = 0.0; + float g = 0.0; + float b = 0.0; + wxColour *col = wxTheColourDatabase->FindColour(colour); + if (col) + { + r = (float)(col->Red()/256.0); + g = (float)(col->Green()/256.0); + b = (float)(col->Blue()/256.0); + glColor3f( r, g, b); + } +} + +void wxGLContext::SetupPixelFormat() +{ +} + +void wxGLContext::SetupPalette( const wxPalette& WXUNUSED(palette) ) +{ +} + +wxPalette wxGLContext::CreateDefaultPalette() +{ + return wxNullPalette; +} + +//----------------------------------------------------------------------------- +// "realize" from m_wxwindow +//----------------------------------------------------------------------------- + +static gint +gtk_glwindow_realized_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win ) +{ + wxGLContext *share= win->m_sharedContext; + if (share==NULL && win->m_sharedContextOf) share=win->m_sharedContextOf->GetContext(); + + win->m_glContext = new wxGLContext( TRUE, win, wxNullPalette, share ); + + return FALSE; +} + +//----------------------------------------------------------------------------- +// "map" from m_wxwindow +//----------------------------------------------------------------------------- + +static gint +gtk_glwindow_map_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win ) +{ + if (win->m_glContext/* && win->m_exposed*/) + { + wxPaintEvent event( win->GetId() ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); + + win->m_exposed = FALSE; + win->GetUpdateRegion().Clear(); + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// "expose_event" of m_wxwindow +//----------------------------------------------------------------------------- + +static void +gtk_glwindow_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxGLCanvas *win ) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + win->m_exposed = TRUE; + + win->GetUpdateRegion().Union( gdk_event->area.x, + gdk_event->area.y, + gdk_event->area.width, + gdk_event->area.height ); +} + +//----------------------------------------------------------------------------- +// "draw" of m_wxwindow +//----------------------------------------------------------------------------- + +static void +gtk_glwindow_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxGLCanvas *win ) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + win->m_exposed = TRUE; + + win->GetUpdateRegion().Union( rect->x, rect->y, + rect->width, rect->height ); +} + +//----------------------------------------------------------------------------- +// "size_allocate" of m_wxwindow +//----------------------------------------------------------------------------- + +static void +gtk_glcanvas_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxGLCanvas *win ) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + if (!win->m_hasVMT) + return; + + wxSizeEvent event( wxSize(win->m_width,win->m_height), win->GetId() ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); +} + +//--------------------------------------------------------------------------- +// wxGlCanvas +//--------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxGLCanvas, wxScrolledWindow) + EVT_SIZE(wxGLCanvas::OnSize) +END_EVENT_TABLE() + +wxGLCanvas::wxGLCanvas( wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette ) +{ + Create( parent, NULL, NULL, id, pos, size, style, name, attribList, palette ); +} + +wxGLCanvas::wxGLCanvas( wxWindow *parent, + const wxGLContext *shared, + wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette ) +{ + Create( parent, shared, NULL, id, pos, size, style, name, attribList, palette ); +} + +wxGLCanvas::wxGLCanvas( wxWindow *parent, + const wxGLCanvas *shared, + wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette ) +{ + Create( parent, NULL, shared, id, pos, size, style, name, attribList, palette ); +} + +bool wxGLCanvas::Create( wxWindow *parent, + const wxGLContext *shared, + const wxGLCanvas *shared_context_of, + wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette) +{ + m_sharedContext = (wxGLContext*)shared; // const_cast + m_sharedContextOf = (wxGLCanvas*)shared_context_of; // const_cast + m_glContext = (wxGLContext*) NULL; + + m_exposed = FALSE; + m_noExpose = TRUE; + m_nativeSizeEvent = TRUE; + + if (!attribList) + { + int data[] = { GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, // use largest available depth buffer + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 0, + None }; + attribList = (int*) data; + } + else + { + int data[512], arg=0, p=0; + + while( (attribList[arg]!=0) && (p<512) ) + { + switch( attribList[arg++] ) + { + case WX_GL_RGBA: data[p++] = GLX_RGBA; break; + case WX_GL_DOUBLEBUFFER: data[p++] = GLX_DOUBLEBUFFER; break; + case WX_GL_DEPTH_SIZE: + data[p++]=GLX_DEPTH_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_RED: + data[p++]=GLX_RED_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_GREEN: + data[p++]=GLX_GREEN_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_BLUE: + data[p++]=GLX_BLUE_SIZE; data[p++]=attribList[arg++]; break; + default: + break; + } + } + data[p] = 0; + + attribList = (int*) data; + } + + + Display *dpy = GDK_DISPLAY(); + + XVisualInfo *vi = glXChooseVisual( dpy, DefaultScreen(dpy), attribList ); + + m_vi = vi; // safe for later use + + wxCHECK_MSG( m_vi, FALSE, "required visual couldn't be found" ); + + GdkVisual *visual = gdkx_visual_get( vi->visualid ); + GdkColormap *colormap = gdk_colormap_new( gdkx_visual_get(vi->visualid), TRUE ); + + gtk_widget_push_colormap( colormap ); + gtk_widget_push_visual( visual ); + + wxScrolledWindow::Create( parent, id, pos, size, style, name ); + + m_glWidget = m_wxwindow; + + gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow), FALSE ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize", + GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback), (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "map", + GTK_SIGNAL_FUNC(gtk_glwindow_map_callback), (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event", + GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback), (gpointer)this ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw", + GTK_SIGNAL_FUNC(gtk_glwindow_draw_callback), (gpointer)this ); + + gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate", + GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback), (gpointer)this ); + + gtk_widget_pop_visual(); + gtk_widget_pop_colormap(); + + return TRUE; +} + +wxGLCanvas::~wxGLCanvas() +{ + XVisualInfo *vi = (XVisualInfo *) m_vi; + + if (vi) XFree( vi ); + if (m_glContext) delete m_glContext; +} + +void wxGLCanvas::SwapBuffers() +{ + if (m_glContext) m_glContext->SwapBuffers(); +} + +void wxGLCanvas::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + int width, height; + GetClientSize( &width, &height ); + + if (m_glContext && GTK_WIDGET_REALIZED(m_glWidget) ) + { + SetCurrent(); + + glViewport(0, 0, (GLint)width, (GLint)height ); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 ); + glMatrixMode(GL_MODELVIEW); + } +} + +void wxGLCanvas::SetCurrent() +{ + if (m_glContext) m_glContext->SetCurrent(); +} + +void wxGLCanvas::SetColour( const char *colour ) +{ + if (m_glContext) m_glContext->SetColour( colour ); +} + +void wxGLCanvas::OnInternalIdle() +{ + if (m_glContext && m_exposed) + { + wxPaintEvent event( GetId() ); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent( event ); + + m_exposed = FALSE; + GetUpdateRegion().Clear(); + } + + wxWindow::OnInternalIdle(); +} + +#endif + // wxUSE_GLCANVAS + diff --git a/src/gtk1/glcanvas.cpp b/src/gtk1/glcanvas.cpp new file mode 100644 index 0000000000..16c1cabe06 --- /dev/null +++ b/src/gtk1/glcanvas.cpp @@ -0,0 +1,432 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.cpp +// Purpose: wxGLCanvas, for using OpenGL/Mesa with wxWindows and GTK +// Author: Robert Roebling +// Modified by: +// Created: 17/08/98 +// RCS-ID: $Id$ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "glcanvas.h" +#endif + +#include "wx/setup.h" + +#if wxUSE_GLCANVAS + +#include "wx/glcanvas.h" + +#include "wx/frame.h" +#include "wx/colour.h" +#include "wx/module.h" +#include "wx/app.h" + +extern "C" { +#include "gtk/gtk.h" +#include "gdk/gdk.h" +#include "gdk/gdkx.h" +} + +#include "wx/gtk/win_gtk.h" + +//--------------------------------------------------------------------------- +// global data +//--------------------------------------------------------------------------- + +XVisualInfo *g_vi = (XVisualInfo*) NULL; + +//----------------------------------------------------------------------------- +// idle system +//----------------------------------------------------------------------------- + +extern void wxapp_install_idle_handler(); +extern bool g_isIdle; + +//--------------------------------------------------------------------------- +// wxGLContext +//--------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGLContext,wxObject) + +wxGLContext::wxGLContext( bool WXUNUSED(isRGB), wxWindow *win, const wxPalette& WXUNUSED(palette) ) +{ + m_window = win; + m_widget = win->m_wxwindow; + + wxGLCanvas *gc = (wxGLCanvas*) win; + XVisualInfo *vi = (XVisualInfo *) gc->m_vi; + + wxCHECK_RET( vi, "invalid visual for OpenGl" ); + + m_glContext = glXCreateContext( GDK_DISPLAY(), vi, None, GL_TRUE ); + + wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" ); +} + +wxGLContext::wxGLContext( + bool WXUNUSED(isRGB), wxWindow *win, + const wxPalette& WXUNUSED(palette), + const wxGLContext *other /* for sharing display lists */ +) +{ + m_window = win; + m_widget = win->m_wxwindow; + + wxGLCanvas *gc = (wxGLCanvas*) win; + XVisualInfo *vi = (XVisualInfo *) gc->m_vi; + + wxCHECK_RET( vi, "invalid visual for OpenGl" ); + + if( other != 0 ) + m_glContext = glXCreateContext( GDK_DISPLAY(), vi, other->m_glContext, GL_TRUE ); + else + m_glContext = glXCreateContext( GDK_DISPLAY(), vi, None, GL_TRUE ); + + wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" ); +} + +wxGLContext::~wxGLContext() +{ + if (!m_glContext) return; + + if (m_glContext == glXGetCurrentContext()) + { + glXMakeCurrent( GDK_DISPLAY(), None, NULL); + } + + glXDestroyContext( GDK_DISPLAY(), m_glContext ); +} + +void wxGLContext::SwapBuffers() +{ + if (m_glContext) + { + GdkWindow *window = GTK_PIZZA(m_widget)->bin_window; + glXSwapBuffers( GDK_DISPLAY(), GDK_WINDOW_XWINDOW( window ) ); + } +} + +void wxGLContext::SetCurrent() +{ + if (m_glContext) + { + GdkWindow *window = GTK_PIZZA(m_widget)->bin_window; + glXMakeCurrent( GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window), m_glContext ); + } +} + +void wxGLContext::SetColour(const char *colour) +{ + float r = 0.0; + float g = 0.0; + float b = 0.0; + wxColour *col = wxTheColourDatabase->FindColour(colour); + if (col) + { + r = (float)(col->Red()/256.0); + g = (float)(col->Green()/256.0); + b = (float)(col->Blue()/256.0); + glColor3f( r, g, b); + } +} + +void wxGLContext::SetupPixelFormat() +{ +} + +void wxGLContext::SetupPalette( const wxPalette& WXUNUSED(palette) ) +{ +} + +wxPalette wxGLContext::CreateDefaultPalette() +{ + return wxNullPalette; +} + +//----------------------------------------------------------------------------- +// "realize" from m_wxwindow +//----------------------------------------------------------------------------- + +static gint +gtk_glwindow_realized_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win ) +{ + wxGLContext *share= win->m_sharedContext; + if (share==NULL && win->m_sharedContextOf) share=win->m_sharedContextOf->GetContext(); + + win->m_glContext = new wxGLContext( TRUE, win, wxNullPalette, share ); + + return FALSE; +} + +//----------------------------------------------------------------------------- +// "map" from m_wxwindow +//----------------------------------------------------------------------------- + +static gint +gtk_glwindow_map_callback( GtkWidget * WXUNUSED(widget), wxGLCanvas *win ) +{ + if (win->m_glContext/* && win->m_exposed*/) + { + wxPaintEvent event( win->GetId() ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); + + win->m_exposed = FALSE; + win->GetUpdateRegion().Clear(); + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// "expose_event" of m_wxwindow +//----------------------------------------------------------------------------- + +static void +gtk_glwindow_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxGLCanvas *win ) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + win->m_exposed = TRUE; + + win->GetUpdateRegion().Union( gdk_event->area.x, + gdk_event->area.y, + gdk_event->area.width, + gdk_event->area.height ); +} + +//----------------------------------------------------------------------------- +// "draw" of m_wxwindow +//----------------------------------------------------------------------------- + +static void +gtk_glwindow_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxGLCanvas *win ) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + win->m_exposed = TRUE; + + win->GetUpdateRegion().Union( rect->x, rect->y, + rect->width, rect->height ); +} + +//----------------------------------------------------------------------------- +// "size_allocate" of m_wxwindow +//----------------------------------------------------------------------------- + +static void +gtk_glcanvas_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxGLCanvas *win ) +{ + if (g_isIdle) + wxapp_install_idle_handler(); + + if (!win->m_hasVMT) + return; + + wxSizeEvent event( wxSize(win->m_width,win->m_height), win->GetId() ); + event.SetEventObject( win ); + win->GetEventHandler()->ProcessEvent( event ); +} + +//--------------------------------------------------------------------------- +// wxGlCanvas +//--------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxGLCanvas, wxScrolledWindow) + EVT_SIZE(wxGLCanvas::OnSize) +END_EVENT_TABLE() + +wxGLCanvas::wxGLCanvas( wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette ) +{ + Create( parent, NULL, NULL, id, pos, size, style, name, attribList, palette ); +} + +wxGLCanvas::wxGLCanvas( wxWindow *parent, + const wxGLContext *shared, + wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette ) +{ + Create( parent, shared, NULL, id, pos, size, style, name, attribList, palette ); +} + +wxGLCanvas::wxGLCanvas( wxWindow *parent, + const wxGLCanvas *shared, + wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette ) +{ + Create( parent, NULL, shared, id, pos, size, style, name, attribList, palette ); +} + +bool wxGLCanvas::Create( wxWindow *parent, + const wxGLContext *shared, + const wxGLCanvas *shared_context_of, + wxWindowID id, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name, + int *attribList, + const wxPalette& palette) +{ + m_sharedContext = (wxGLContext*)shared; // const_cast + m_sharedContextOf = (wxGLCanvas*)shared_context_of; // const_cast + m_glContext = (wxGLContext*) NULL; + + m_exposed = FALSE; + m_noExpose = TRUE; + m_nativeSizeEvent = TRUE; + + if (!attribList) + { + int data[] = { GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, // use largest available depth buffer + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_ALPHA_SIZE, 0, + None }; + attribList = (int*) data; + } + else + { + int data[512], arg=0, p=0; + + while( (attribList[arg]!=0) && (p<512) ) + { + switch( attribList[arg++] ) + { + case WX_GL_RGBA: data[p++] = GLX_RGBA; break; + case WX_GL_DOUBLEBUFFER: data[p++] = GLX_DOUBLEBUFFER; break; + case WX_GL_DEPTH_SIZE: + data[p++]=GLX_DEPTH_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_RED: + data[p++]=GLX_RED_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_GREEN: + data[p++]=GLX_GREEN_SIZE; data[p++]=attribList[arg++]; break; + case WX_GL_MIN_BLUE: + data[p++]=GLX_BLUE_SIZE; data[p++]=attribList[arg++]; break; + default: + break; + } + } + data[p] = 0; + + attribList = (int*) data; + } + + + Display *dpy = GDK_DISPLAY(); + + XVisualInfo *vi = glXChooseVisual( dpy, DefaultScreen(dpy), attribList ); + + m_vi = vi; // safe for later use + + wxCHECK_MSG( m_vi, FALSE, "required visual couldn't be found" ); + + GdkVisual *visual = gdkx_visual_get( vi->visualid ); + GdkColormap *colormap = gdk_colormap_new( gdkx_visual_get(vi->visualid), TRUE ); + + gtk_widget_push_colormap( colormap ); + gtk_widget_push_visual( visual ); + + wxScrolledWindow::Create( parent, id, pos, size, style, name ); + + m_glWidget = m_wxwindow; + + gtk_pizza_set_clear( GTK_PIZZA(m_wxwindow), FALSE ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize", + GTK_SIGNAL_FUNC(gtk_glwindow_realized_callback), (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "map", + GTK_SIGNAL_FUNC(gtk_glwindow_map_callback), (gpointer) this ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event", + GTK_SIGNAL_FUNC(gtk_glwindow_expose_callback), (gpointer)this ); + + gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw", + GTK_SIGNAL_FUNC(gtk_glwindow_draw_callback), (gpointer)this ); + + gtk_signal_connect( GTK_OBJECT(m_widget), "size_allocate", + GTK_SIGNAL_FUNC(gtk_glcanvas_size_callback), (gpointer)this ); + + gtk_widget_pop_visual(); + gtk_widget_pop_colormap(); + + return TRUE; +} + +wxGLCanvas::~wxGLCanvas() +{ + XVisualInfo *vi = (XVisualInfo *) m_vi; + + if (vi) XFree( vi ); + if (m_glContext) delete m_glContext; +} + +void wxGLCanvas::SwapBuffers() +{ + if (m_glContext) m_glContext->SwapBuffers(); +} + +void wxGLCanvas::OnSize(wxSizeEvent& WXUNUSED(event)) +{ + int width, height; + GetClientSize( &width, &height ); + + if (m_glContext && GTK_WIDGET_REALIZED(m_glWidget) ) + { + SetCurrent(); + + glViewport(0, 0, (GLint)width, (GLint)height ); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 ); + glMatrixMode(GL_MODELVIEW); + } +} + +void wxGLCanvas::SetCurrent() +{ + if (m_glContext) m_glContext->SetCurrent(); +} + +void wxGLCanvas::SetColour( const char *colour ) +{ + if (m_glContext) m_glContext->SetColour( colour ); +} + +void wxGLCanvas::OnInternalIdle() +{ + if (m_glContext && m_exposed) + { + wxPaintEvent event( GetId() ); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent( event ); + + m_exposed = FALSE; + GetUpdateRegion().Clear(); + } + + wxWindow::OnInternalIdle(); +} + +#endif + // wxUSE_GLCANVAS + diff --git a/src/motif/glcanvas.cpp b/src/motif/glcanvas.cpp new file mode 100644 index 0000000000..1d5e2936a3 --- /dev/null +++ b/src/motif/glcanvas.cpp @@ -0,0 +1,168 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.cpp +// Purpose: wxGLCanvas, for using OpenGL with wxWindows 2.0 for Motif. +// Uses the GLX extension. +// Author: Julian Smart and Wolfram Gloger +// Modified by: +// Created: 1995, 1999 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart, Wolfram Gloger +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "glcanvas.h" +#endif + +#include "wx/setup.h" + +#if wxUSE_GLCANVAS + +#include "wx/glcanvas.h" +#include "wx/utils.h" +#include "wx/app.h" + +#include +#include "wx/motif/private.h" + +#ifdef OLD_MESA +// workaround for bug in Mesa's glx.c +static int bitcount( unsigned long n ) +{ + int bits; + for (bits=0; n>0;) { + if(n & 1) bits++; + n = n >> 1; + } + return bits; +} +#endif + +/* + * GLCanvas implementation + */ + +IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow) + +wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id = -1, const wxPoint& pos, + const wxSize& size, long style, + const wxString& name, int *attrib_list, const wxPalette& palette): + wxScrolledWindow(parent, id, pos, size, style, name) +{ + XVisualInfo *vi, vi_templ; + XWindowAttributes xwa; + int val, n; + + Display* display = (Display*) GetXDisplay(); + + glx_cx = 0; + // Check for the presence of the GLX extension + if(!glXQueryExtension(display, NULL, NULL)) { + wxDebugMsg("wxGLCanvas: GLX extension is missing\n"); + return; + } + + if(attrib_list) { + // Get an appropriate visual + vi = glXChooseVisual(display, DefaultScreen(display), attrib_list); + if(!vi) return; + + // Here we should make sure that vi is the same visual as the + // one used by the xwindow drawable in wxCanvas. However, + // there is currently no mechanism for this in wx_canvs.cc. + } else { + // By default, we use the visual of xwindow + XGetWindowAttributes(display, (Window) GetXWindow(), &xwa); + vi_templ.visualid = XVisualIDFromVisual(xwa.visual); + vi = XGetVisualInfo(display, VisualIDMask, &vi_templ, &n); + if(!vi) return; + glXGetConfig(display, vi, GLX_USE_GL, &val); + if(!val) return; + // Basically, this is it. It should be possible to use vi + // in glXCreateContext() below. But this fails with Mesa. + // I notified the Mesa author about it; there may be a fix. +#ifdef OLD_MESA + // Construct an attribute list matching the visual + int a_list[32]; + n = 0; + if(vi->c_class==TrueColor || vi->c_class==DirectColor) { // RGBA visual + a_list[n++] = GLX_RGBA; + a_list[n++] = GLX_RED_SIZE; + a_list[n++] = bitcount(vi->red_mask); + a_list[n++] = GLX_GREEN_SIZE; + a_list[n++] = bitcount(vi->green_mask); + a_list[n++] = GLX_BLUE_SIZE; + a_list[n++] = bitcount(vi->blue_mask); + glXGetConfig(display, vi, GLX_ALPHA_SIZE, &val); + a_list[n++] = GLX_ALPHA_SIZE; + a_list[n++] = val; + } else { // Color index visual + glXGetConfig(display, vi, GLX_BUFFER_SIZE, &val); + a_list[n++] = GLX_BUFFER_SIZE; + a_list[n++] = val; + } + a_list[n] = None; + XFree(vi); + vi = glXChooseVisual(display, DefaultScreen(display), a_list); + if(!vi) return; +#endif /* OLD_MESA */ + } + + // Create the GLX context and make it current + glx_cx = glXCreateContext(display, vi, 0, GL_TRUE); +#ifndef OLD_MESA + XFree(vi); +#endif + SetCurrent(); +} + +wxGLCanvas::~wxGLCanvas(void) +{ + Display* display = (Display*) GetXDisplay(); + if(glx_cx) glXDestroyContext(display, glx_cx); +} + +void wxGLCanvas::SwapBuffers() +{ + Display* display = (Display*) GetXDisplay(); + if(glx_cx) glXSwapBuffers(display, (Window) GetXWindow()); +} + +void wxGLCanvas::SetCurrent() +{ + Display* display = (Display*) GetXDisplay(); + if(glx_cx) glXMakeCurrent(display, (Window) GetXWindow(), glx_cx); +} + +void wxGLCanvas::SetColour(const char *col) +{ + wxColour *the_colour = wxTheColourDatabase->FindColour(col); + if(the_colour) { + GLboolean b; + glGetBooleanv(GL_RGBA_MODE, &b); + if(b) { + glColor3ub(the_colour->Red(), + the_colour->Green(), + the_colour->Blue()); + } else { + GLint pix = (GLint)the_colour->m_pixel; + if(pix == -1) { + XColor exact_def; + exact_def.red = (unsigned short)the_colour->Red() << 8; + exact_def.green = (unsigned short)the_colour->Green() << 8; + exact_def.blue = (unsigned short)the_colour->Blue() << 8; + exact_def.flags = DoRed | DoGreen | DoBlue; + if(!XAllocColor((Display*) GetXDisplay(), (Colormap) wxTheApp->GetMainColormap(GetXDisplay()), &exact_def)) { + wxDebugMsg("wxGLCanvas: cannot allocate color\n"); + return; + } + pix = the_colour->m_pixel = exact_def.pixel; + } + glIndexi(pix); + } + } +} + +#endif + // wxUSE_GLCANVAS + diff --git a/src/msw/glcanvas.cpp b/src/msw/glcanvas.cpp new file mode 100644 index 0000000000..dd49c13117 --- /dev/null +++ b/src/msw/glcanvas.cpp @@ -0,0 +1,624 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: glcanvas.cpp +// Purpose: wxGLCanvas, for using OpenGL with wxWindows under MS Windows +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id$ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __GNUG__ +#pragma implementation "glcanvas.h" +#endif + +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) +#pragma hdrstop +#endif + +#include + +#if wxUSE_GLCANVAS + +#ifndef WX_PRECOMP +#include +#endif + +#include + +#include + +wxChar wxGLCanvasClassName[] = wxT("wxGLCanvasClass"); + +LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam); + +/* + * GLContext implementation + */ + +wxGLContext::wxGLContext(bool isRGB, wxGLCanvas *win, const wxPalette& palette) +{ + m_window = win; + + m_hDC = win->GetHDC(); + + m_glContext = wglCreateContext((HDC) m_hDC); + wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" ); + + wglMakeCurrent((HDC) m_hDC, m_glContext); +} + +wxGLContext::wxGLContext( + bool isRGB, wxGLCanvas *win, + const wxPalette& palette, + const wxGLContext *other /* for sharing display lists */ +) +{ + m_window = win; + + m_hDC = win->GetHDC(); + + m_glContext = wglCreateContext((HDC) m_hDC); + wxCHECK_RET( m_glContext, "Couldn't create OpenGl context" ); + + if( other != 0 ) + wglShareLists( other->m_glContext, m_glContext ); + + wglMakeCurrent((HDC) m_hDC, m_glContext); +} + +wxGLContext::~wxGLContext() +{ + if (m_glContext) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(m_glContext); + } +} + +void wxGLContext::SwapBuffers() +{ + if (m_glContext) + { + wglMakeCurrent((HDC) m_hDC, m_glContext); + ::SwapBuffers((HDC) m_hDC); //blits the backbuffer into DC + } +} + +void wxGLContext::SetCurrent() +{ + if (m_glContext) + { + wglMakeCurrent((HDC) m_hDC, m_glContext); + } + +/* + setupPixelFormat(hDC); + setupPalette(hDC); +*/ +} + +void wxGLContext::SetColour(const char *colour) +{ + float r = 0.0; + float g = 0.0; + float b = 0.0; + wxColour *col = wxTheColourDatabase->FindColour(colour); + if (col) + { + r = (float)(col->Red()/256.0); + g = (float)(col->Green()/256.0); + b = (float)(col->Blue()/256.0); + glColor3f( r, g, b); + } +} + + +/* + * wxGLCanvas implementation + */ + +IMPLEMENT_CLASS(wxGLCanvas, wxScrolledWindow) + +BEGIN_EVENT_TABLE(wxGLCanvas, wxScrolledWindow) + EVT_SIZE(wxGLCanvas::OnSize) + EVT_PALETTE_CHANGED(wxGLCanvas::OnPaletteChanged) + EVT_QUERY_NEW_PALETTE(wxGLCanvas::OnQueryNewPalette) +END_EVENT_TABLE() + +wxGLCanvas::wxGLCanvas(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, + int *attribList /* not used yet! */, const wxPalette& palette): + wxScrolledWindow() +{ + m_glContext = (wxGLContext*) NULL; + + bool ret = Create(parent, id, pos, size, style, name); + + if ( ret ) + { + SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); + SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); + } + + m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); + + SetupPixelFormat(); + SetupPalette(palette); + + m_glContext = new wxGLContext(TRUE, this, palette); +} + +wxGLCanvas::wxGLCanvas( wxWindow *parent, + const wxGLContext *shared, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, + int *attribList, const wxPalette& palette ) + : wxScrolledWindow() +{ + m_glContext = (wxGLContext*) NULL; + + bool ret = Create(parent, id, pos, size, style, name); + + if ( ret ) + { + SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); + SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); + } + + m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); + + SetupPixelFormat(); + SetupPalette(palette); + + m_glContext = new wxGLContext(TRUE, this, palette, shared ); +} + +// Not very usefull for wxMSW, but this is to be wxGTK compliant + +wxGLCanvas::wxGLCanvas( wxWindow *parent, const wxGLCanvas *shared, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name, + int *attribList, const wxPalette& palette ): + wxScrolledWindow() +{ + m_glContext = (wxGLContext*) NULL; + + bool ret = Create(parent, id, pos, size, style, name); + + if ( ret ) + { + SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE)); + SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT)); + } + + m_hDC = (WXHDC) ::GetDC((HWND) GetHWND()); + + SetupPixelFormat(); + SetupPalette(palette); + + wxGLContext *sharedContext=0; + if (shared) sharedContext=shared->GetContext(); + m_glContext = new wxGLContext(TRUE, this, palette, sharedContext ); +} + +wxGLCanvas::~wxGLCanvas() +{ + if (m_glContext) + delete m_glContext; + + ::ReleaseDC((HWND) GetHWND(), (HDC) m_hDC); +} + +// Replaces wxWindow::Create functionality, since we need to use a different window class +bool wxGLCanvas::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + static bool registeredGLCanvasClass = FALSE; + + // We have to register a special window class because we need + // the CS_OWNDC style for GLCanvas. + +/* + From Angel Popov + + Here are two snips from a dicussion in the OpenGL Gamedev list that explains + how this problem can be fixed: + + "There are 5 common DCs available in Win95. These are aquired when you call + GetDC or GetDCEx from a window that does _not_ have the OWNDC flag. + OWNDC flagged windows do not get their DC from the common DC pool, the issue + is they require 800 bytes each from the limited 64Kb local heap for GDI." + + "The deal is, if you hold onto one of the 5 shared DC's too long (as GL apps + do), Win95 will actually "steal" it from you. MakeCurrent fails, + apparently, because Windows re-assigns the HDC to a different window. The + only way to prevent this, the only reliable means, is to set CS_OWNDC." +*/ + + if (!registeredGLCanvasClass) + { + WNDCLASS wndclass; + + static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_OWNDC; + + // the fields which are common to all classes + wndclass.lpfnWndProc = (WNDPROC)wxWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for? + wndclass.hInstance = wxhInstance; + wndclass.hIcon = (HICON) NULL; + wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW); + wndclass.lpszMenuName = NULL; + + // Register the GLCanvas class name + wndclass.hbrBackground = (HBRUSH)NULL; + wndclass.lpszClassName = wxGLCanvasClassName; + wndclass.style = styleNormal; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError("RegisterClass(wxGLCanvasClass)"); + + return FALSE; + } + registeredGLCanvasClass = TRUE; + } + + wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") ); + + if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) ) + return FALSE; + + parent->AddChild(this); + + DWORD msflags = 0; + if ( style & wxBORDER ) + msflags |= WS_BORDER; + if ( style & wxTHICK_FRAME ) + msflags |= WS_THICKFRAME; + + msflags |= WS_CHILD | WS_VISIBLE; + if ( style & wxCLIP_CHILDREN ) + msflags |= WS_CLIPCHILDREN; + + bool want3D; + WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D); + + // Even with extended styles, need to combine with WS_BORDER + // for them to look right. + if ( want3D || (m_windowStyle & wxSIMPLE_BORDER) || (m_windowStyle & wxRAISED_BORDER ) || + (m_windowStyle & wxSUNKEN_BORDER) || (m_windowStyle & wxDOUBLE_BORDER)) + { + msflags |= WS_BORDER; + } + + // calculate the value to return from WM_GETDLGCODE handler + if ( GetWindowStyleFlag() & wxWANTS_CHARS ) + { + // want everything: i.e. all keys and WM_CHAR message + m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS | + DLGC_WANTTAB | DLGC_WANTMESSAGE; + } + + MSWCreate(m_windowId, parent, wxGLCanvasClassName, this, NULL, + pos.x, pos.y, + WidthDefault(size.x), HeightDefault(size.y), + msflags, NULL, exStyle); + + return TRUE; + +} + +void wxGLCanvas::SetupPixelFormat() // (HDC hDC) +{ + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), /* size */ + 1, /* version */ + PFD_SUPPORT_OPENGL | + PFD_DRAW_TO_WINDOW | + PFD_DOUBLEBUFFER, /* support double-buffering */ + PFD_TYPE_RGBA, /* color type */ + 16, /* prefered color depth */ + 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ + 0, /* no alpha buffer */ + 0, /* alpha bits (ignored) */ + 0, /* no accumulation buffer */ + 0, 0, 0, 0, /* accum bits (ignored) */ + 16, /* depth buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0, /* no layer, visible, damage masks */ + }; + int pixelFormat; + + pixelFormat = ChoosePixelFormat((HDC) m_hDC, &pfd); + if (pixelFormat == 0) { + MessageBox(WindowFromDC((HDC) m_hDC), "ChoosePixelFormat failed.", "Error", + MB_ICONERROR | MB_OK); + exit(1); + } + + if (SetPixelFormat((HDC) m_hDC, pixelFormat, &pfd) != TRUE) { + MessageBox(WindowFromDC((HDC) m_hDC), "SetPixelFormat failed.", "Error", + MB_ICONERROR | MB_OK); + exit(1); + } +} + +void wxGLCanvas::SetupPalette(const wxPalette& palette) +{ + int pixelFormat = GetPixelFormat((HDC) m_hDC); + PIXELFORMATDESCRIPTOR pfd; + + DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + if (pfd.dwFlags & PFD_NEED_PALETTE) + { + } + else + { + return; + } + + m_palette = palette; + + if ( !m_palette.Ok() ) + { + m_palette = CreateDefaultPalette(); + } + + if (m_palette.Ok()) + { + SelectPalette((HDC) m_hDC, (HPALETTE) m_palette.GetHPALETTE(), FALSE); + RealizePalette((HDC) m_hDC); + } +} + +wxPalette wxGLCanvas::CreateDefaultPalette() +{ + PIXELFORMATDESCRIPTOR pfd; + int paletteSize; + int pixelFormat = GetPixelFormat((HDC) m_hDC); + + DescribePixelFormat((HDC) m_hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + + paletteSize = 1 << pfd.cColorBits; + + LOGPALETTE* pPal = + (LOGPALETTE*) malloc(sizeof(LOGPALETTE) + paletteSize * sizeof(PALETTEENTRY)); + pPal->palVersion = 0x300; + pPal->palNumEntries = paletteSize; + + /* build a simple RGB color palette */ + { + int redMask = (1 << pfd.cRedBits) - 1; + int greenMask = (1 << pfd.cGreenBits) - 1; + int blueMask = (1 << pfd.cBlueBits) - 1; + int i; + + for (i=0; ipalPalEntry[i].peRed = + (((i >> pfd.cRedShift) & redMask) * 255) / redMask; + pPal->palPalEntry[i].peGreen = + (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask; + pPal->palPalEntry[i].peBlue = + (((i >> pfd.cBlueShift) & blueMask) * 255) / blueMask; + pPal->palPalEntry[i].peFlags = 0; + } + } + + HPALETTE hPalette = CreatePalette(pPal); + free(pPal); + + wxPalette palette; + palette.SetHPALETTE((WXHPALETTE) hPalette); + + return palette; +} + +void wxGLCanvas::SwapBuffers() +{ + if (m_glContext) + m_glContext->SwapBuffers(); +} + +void wxGLCanvas::OnSize(wxSizeEvent& event) +{ + int width, height; + GetClientSize(& width, & height); + + if (m_glContext) + { + m_glContext->SetCurrent(); + + glViewport(0, 0, (GLint)width, (GLint)height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 15.0 ); + glMatrixMode(GL_MODELVIEW); + } +} + +void wxGLCanvas::SetCurrent() +{ + if (m_glContext) + { + m_glContext->SetCurrent(); + } +} + +void wxGLCanvas::SetColour(const char *colour) +{ + if (m_glContext) + m_glContext->SetColour(colour); +} + +// TODO: Have to have this called by parent frame (?) +// So we need wxFrame to call OnQueryNewPalette for all children... +void wxGLCanvas::OnQueryNewPalette(wxQueryNewPaletteEvent& event) +{ + /* realize palette if this is the current window */ + if ( GetPalette()->Ok() ) { + ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE()); + ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); + ::RealizePalette((HDC) GetHDC()); + Refresh(); + event.SetPaletteRealized(TRUE); + } + else + event.SetPaletteRealized(FALSE); +} + +// I think this doesn't have to be propagated to child windows. +void wxGLCanvas::OnPaletteChanged(wxPaletteChangedEvent& event) +{ + /* realize palette if this is *not* the current window */ + if ( GetPalette() && + GetPalette()->Ok() && (this != event.GetChangedWindow()) ) + { + ::UnrealizeObject((HPALETTE) GetPalette()->GetHPALETTE()); + ::SelectPalette((HDC) GetHDC(), (HPALETTE) GetPalette()->GetHPALETTE(), FALSE); + ::RealizePalette((HDC) GetHDC()); + Refresh(); + } +} + +/* Give extensions proper function names. */ + +/* EXT_vertex_array */ +void glArrayElementEXT(GLint i) +{ +} + +void glColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ +} + +void glDrawArraysEXT(GLenum mode, GLint first, GLsizei count) +{ +#ifdef GL_EXT_vertex_array + static PFNGLDRAWARRAYSEXTPROC proc = 0; + + if ( !proc ) + { + proc = (PFNGLDRAWARRAYSEXTPROC) wglGetProcAddress("glDrawArraysEXT"); + } + + if ( proc ) + (* proc) (mode, first, count); +#endif +} + +void glEdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *pointer) +{ +} + +void glGetPointervEXT(GLenum pname, GLvoid* *params) +{ +} + +void glIndexPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ +} + +void glNormalPointerEXT(GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ +#ifdef GL_EXT_vertex_array + static PFNGLNORMALPOINTEREXTPROC proc = 0; + + if ( !proc ) + { + proc = (PFNGLNORMALPOINTEREXTPROC) wglGetProcAddress("glNormalPointerEXT"); + } + + if ( proc ) + (* proc) (type, stride, count, pointer); +#endif +} + +void glTexCoordPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ +} + +void glVertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer) +{ +#ifdef GL_EXT_vertex_array + static PFNGLVERTEXPOINTEREXTPROC proc = 0; + + if ( !proc ) + { + proc = (PFNGLVERTEXPOINTEREXTPROC) wglGetProcAddress("glVertexPointerEXT"); + } + + if ( proc ) + (* proc) (size, type, stride, count, pointer); +#endif +} + +/* EXT_color_subtable */ +void glColorSubtableEXT(GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *table) +{ +} + +/* EXT_color_table */ +void glColorTableEXT(GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table) +{ +} + +void glCopyColorTableEXT(GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) +{ +} + +void glGetColorTableEXT(GLenum target, GLenum format, GLenum type, GLvoid *table) +{ +} + +void glGetColorTableParamaterfvEXT(GLenum target, GLenum pname, GLfloat *params) +{ +} + +void glGetColorTavleParameterivEXT(GLenum target, GLenum pname, GLint *params) +{ +} + +/* SGI_compiled_vertex_array */ +void glLockArraysSGI(GLint first, GLsizei count) +{ +} + +void glUnlockArraysSGI() +{ +} + + +/* SGI_cull_vertex */ +void glCullParameterdvSGI(GLenum pname, GLdouble* params) +{ +} + +void glCullParameterfvSGI(GLenum pname, GLfloat* params) +{ +} + +/* SGI_index_func */ +void glIndexFuncSGI(GLenum func, GLclampf ref) +{ +} + +/* SGI_index_material */ +void glIndexMaterialSGI(GLenum face, GLenum mode) +{ +} + +/* WIN_swap_hint */ +void glAddSwapHintRectWin(GLint x, GLint y, GLsizei width, GLsizei height) +{ +} + +#endif + // wxUSE_GLCANVAS diff --git a/src/msw/makefile.b32 b/src/msw/makefile.b32 index 908733e039..5259b6be0a 100644 --- a/src/msw/makefile.b32 +++ b/src/msw/makefile.b32 @@ -1,6 +1,6 @@ -# This file was automatically generated by tmake at 18:32, 2000/02/17 +# This file was automatically generated by tmake at 15:17, 2000/02/27 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE B32.T! # @@ -257,6 +257,7 @@ MSWOBJS = $(MSWDIR)\accel.obj \ $(MSWDIR)\gauge95.obj \ $(MSWDIR)\gdiimage.obj \ $(MSWDIR)\gdiobj.obj \ + $(MSWDIR)\glcanvas.obj \ $(MSWDIR)\gsocket.obj \ $(MSWDIR)\helpwin.obj \ $(MSWDIR)\icon.obj \ @@ -469,6 +470,8 @@ $(MSWDIR)\gdiimage.obj: $(MSWDIR)\gdiimage.$(SRCSUFF) $(MSWDIR)\gdiobj.obj: $(MSWDIR)\gdiobj.$(SRCSUFF) +$(MSWDIR)\glcanvas.obj: $(MSWDIR)\glcanvas.$(SRCSUFF) + $(MSWDIR)\gsocket.obj: $(MSWDIR)\gsocket.c $(MSWDIR)\helpwin.obj: $(MSWDIR)\helpwin.$(SRCSUFF) diff --git a/src/msw/makefile.bcc b/src/msw/makefile.bcc index c60cbc60b8..161d261176 100644 --- a/src/msw/makefile.bcc +++ b/src/msw/makefile.bcc @@ -1,6 +1,6 @@ -# This file was automatically generated by tmake at 18:32, 2000/02/17 +# This file was automatically generated by tmake at 15:18, 2000/02/27 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE BCC.T! # @@ -226,6 +226,7 @@ MSWOBJS = $(MSWDIR)\accel.obj \ $(MSWDIR)\gaugemsw.obj \ $(MSWDIR)\gdiimage.obj \ $(MSWDIR)\gdiobj.obj \ + $(MSWDIR)\glcanvas.obj \ $(MSWDIR)\gsocket.obj \ $(MSWDIR)\helpwin.obj \ $(MSWDIR)\icon.obj \ @@ -378,6 +379,8 @@ $(MSWDIR)\gdiimage.obj: $(MSWDIR)\gdiimage.$(SRCSUFF) $(MSWDIR)\gdiobj.obj: $(MSWDIR)\gdiobj.$(SRCSUFF) +$(MSWDIR)\glcanvas.obj: $(MSWDIR)\glcanvas.$(SRCSUFF) + $(MSWDIR)\gsocket.obj: $(MSWDIR)\gsocket.c $(MSWDIR)\helpwin.obj: $(MSWDIR)\helpwin.$(SRCSUFF) diff --git a/src/msw/makefile.g95 b/src/msw/makefile.g95 index a8e77fbb68..0762df0d7c 100644 --- a/src/msw/makefile.g95 +++ b/src/msw/makefile.g95 @@ -255,6 +255,7 @@ MSWOBJS = \ $(MSWDIR)/gauge95.$(OBJSUFF) \ $(MSWDIR)/gdiimage.$(OBJSUFF) \ $(MSWDIR)/gdiobj.$(OBJSUFF) \ + $(MSWDIR)/glcanvas.$(OBJSUFF) \ $(MSWDIR)/gsocket.$(OBJSUFF) \ $(MSWDIR)/helpwin.$(OBJSUFF) \ $(MSWDIR)/icon.$(OBJSUFF) \ diff --git a/src/msw/makefile.vc b/src/msw/makefile.vc index e555f8b83c..3ceaa58c47 100644 --- a/src/msw/makefile.vc +++ b/src/msw/makefile.vc @@ -1,4 +1,4 @@ -# This file was automatically generated by tmake at 18:32, 2000/02/17 +# This file was automatically generated by tmake at 15:17, 2000/02/27 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE VC.T! # File: makefile.vc @@ -274,6 +274,7 @@ MSWOBJS = ..\msw\$D\accel.obj \ ..\msw\$D\gauge95.obj \ ..\msw\$D\gdiimage.obj \ ..\msw\$D\gdiobj.obj \ + ..\msw\$D\glcanvas.obj \ ..\msw\$D\gsocket.obj \ ..\msw\$D\helpwin.obj \ ..\msw\$D\icon.obj \ diff --git a/src/msw/makefile.wat b/src/msw/makefile.wat index e13fc89232..c2a5bc5448 100644 --- a/src/msw/makefile.wat +++ b/src/msw/makefile.wat @@ -1,6 +1,6 @@ #!/binb/wmake.exe -# This file was automatically generated by tmake at 18:32, 2000/02/17 +# This file was automatically generated by tmake at 15:18, 2000/02/27 # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE WAT.T! # @@ -230,6 +230,7 @@ MSWOBJS = accel.obj & gaugemsw.obj & gdiimage.obj & gdiobj.obj & + glcanvas.obj & gsocket.obj & helpwin.obj & icon.obj & @@ -450,6 +451,9 @@ gdiimage.obj: $(MSWDIR)\gdiimage.cpp gdiobj.obj: $(MSWDIR)\gdiobj.cpp *$(CCC) $(CPPFLAGS) $(IFLAGS) $< +glcanvas.obj: $(MSWDIR)\glcanvas.cpp + *$(CCC) $(CPPFLAGS) $(IFLAGS) $< + gsocket.obj: $(MSWDIR)\gsocket.c *$(CC) $(CPPFLAGS) $(IFLAGS) $< diff --git a/src/wxvc.dsp b/src/wxvc.dsp index 6c87170f6c..b95508cacb 100644 --- a/src/wxvc.dsp +++ b/src/wxvc.dsp @@ -853,6 +853,10 @@ SOURCE=.\msw\gdiobj.cpp # End Source File # Begin Source File +SOURCE=.\msw\glcanvas.cpp +# End Source File +# Begin Source File + SOURCE=.\msw\gsocket.c # SUBTRACT CPP /YX /Yc /Yu # End Source File diff --git a/src/wxvc_dll.dsp b/src/wxvc_dll.dsp index edacc9f9f9..ee66692879 100644 --- a/src/wxvc_dll.dsp +++ b/src/wxvc_dll.dsp @@ -851,6 +851,10 @@ SOURCE=.\msw\gdiobj.cpp # End Source File # Begin Source File +SOURCE=.\msw\glcanvas.cpp +# End Source File +# Begin Source File + SOURCE=.\msw\gsocket.c # SUBTRACT CPP /YX /Yc /Yu # End Source File diff --git a/utils/projgen/makeproj.cpp b/utils/projgen/makeproj.cpp index fa66425fe4..c8a377f17b 100644 --- a/utils/projgen/makeproj.cpp +++ b/utils/projgen/makeproj.cpp @@ -183,6 +183,7 @@ bool MyApp::GenerateSample(const wxString& projectName, const wxString& targetNa project.SetLibDirs(wxStringList((const char*) relativeLibPath, 0)); project.SetDebugLibDirs(wxStringList((const char*) relativeDebugPath, (const char*) relativeDebugPathJPEG, (const char*) relativeDebugPathTIFF, 0)); project.SetReleaseLibDirs(wxStringList((const char*) relativeReleasePath, (const char*) relativeReleasePathJPEG, (const char*) relativeReleasePathTIFF, 0)); + project.SetExtraLibs(wxStringList("opengl32.lib", "glu32.lib", 0)); project.SetProjectName(projectName); project.SetTargetName(targetName); @@ -228,6 +229,14 @@ void MyApp::GenerateSamples(const wxString& dir) GenerateSample("NewGridVC", "griddemo", dir + wxString("/samples/newgrid"), wxStringList("griddemo.cpp", 0)); GenerateSample("HelpVC", "demo", dir + wxString("/samples/help"), wxStringList("demo.cpp", 0)); + // OpenGL samples + GenerateSample("CubeVC", "cube", dir + wxString("/samples/opengl/cube"), wxStringList("cube.cpp", "cube.h", 0), + "../../.."); + GenerateSample("IsosurfVC", "isosurf", dir + wxString("/samples/opengl/isosurf"), wxStringList("isosurf.cpp", "isousrf.h", 0), + "../../.."); + GenerateSample("PenguinVC", "penguin", dir + wxString("/samples/opengl/penguin"), wxStringList("penguin.cpp", "penguin.h", + "lw.cpp", "lw.h", "trackball.c", "trackball.h", 0), "../../.."); + // wxHTML samples GenerateSample("AboutVC", "about", dir + wxString("/samples/html/about"), wxStringList("about.cpp", 0), "../../.."); @@ -488,72 +497,6 @@ void MyApp::GenerateSamples(const wxString& dir) wxString msg("Could not generate OGL Studio project"); wxMessageBox(msg); } - - // GLCanvas cube sample - - project.SetIncludeDirs(wxStringList("../../../../include", "../../win", 0)); - project.SetResourceIncludeDirs(wxStringList("../../../../include", 0)); - project.SetLibDirs(wxStringList("../../../../lib", 0)); - project.SetDebugLibDirs(wxStringList("../../../../src/Debug", "../../win/Debug", "../../../../src/jpeg/Debug", "../../../../src/tiff/Debug", 0)); - project.SetReleaseLibDirs(wxStringList("../../../../src/Release", "../../win/Release", "../../../../src/jpeg/Release", "../../../../src/tiff/Release", 0)); - - project.SetExtraLibs(wxStringList("glcanvas.lib", "opengl32.lib", "glu32.lib", 0)); - - project.SetProjectName("CubeVC"); - project.SetTargetName("cube"); - project.SetProjectPath(dir + wxString("/utils/glcanvas/samples/cube")); - project.SetSourceFiles(wxStringList("cube.cpp", "cube.h", - 0)); - - if (!project.GenerateVCProject()) - { - wxString msg("Could not generate GLCanvas Cube project"); - wxMessageBox(msg); - } - - // GLCanvas isosurf sample - - project.SetIncludeDirs(wxStringList("../../../../include", "../../win", 0)); - project.SetResourceIncludeDirs(wxStringList("../../../../include", 0)); - project.SetLibDirs(wxStringList("../../../../lib", 0)); - project.SetDebugLibDirs(wxStringList("../../../../src/Debug", "../../win/Debug", "../../../../src/jpeg/Debug", "../../../../src/tiff/Debug", 0)); - project.SetReleaseLibDirs(wxStringList("../../../../src/Release", "../../win/Release", "../../../../src/jpeg/Release", "../../../../src/tiff/Release", 0)); - project.SetExtraLibs(wxStringList("glcanvas.lib", "opengl32.lib", "glu32.lib", 0)); - - project.SetProjectName("IsoSurfVC"); - project.SetTargetName("isosurf"); - project.SetProjectPath(dir + wxString("/utils/glcanvas/samples/isosurf")); - project.SetSourceFiles(wxStringList("isosurf.cpp", "isosurf.h", - 0)); - - if (!project.GenerateVCProject()) - { - wxString msg("Could not generate GLCanvas IsoSurf project"); - wxMessageBox(msg); - } - - // GLCanvas penguin sample - - project.SetIncludeDirs(wxStringList("../../../../include", "../../win", 0)); - project.SetResourceIncludeDirs(wxStringList("../../../../include", 0)); - project.SetLibDirs(wxStringList("../../../../lib", 0)); - project.SetDebugLibDirs(wxStringList("../../../../src/Debug", "../../win/Debug", "../../../../src/jpeg/Debug", "../../../../src/tiff/Debug", 0)); - project.SetReleaseLibDirs(wxStringList("../../../../src/Release", "../../win/Release", "../../../../src/jpeg/Release", "../../../../src/tiff/Release", 0)); - project.SetExtraLibs(wxStringList("glcanvas.lib", "opengl32.lib", "glu32.lib", 0)); - - project.SetProjectName("PenguinVC"); - project.SetTargetName("penguin"); - project.SetProjectPath(dir + wxString("/utils/glcanvas/samples/penguin")); - project.SetSourceFiles(wxStringList("penguin.cpp", "penguin.h", - "lw.cpp", "lw.h", - "trackball.c", "trackball.h", - 0)); - - if (!project.GenerateVCProject()) - { - wxString msg("Could not generate GLCanvas Penguin project"); - wxMessageBox(msg); - } } // ---------------------------------------------------------------------------- -- 2.45.2