Created
February 20, 2020 01:03
-
-
Save AlexCharlton/e1804966f5f8fc64d1b0b965142ff89b to your computer and use it in GitHub Desktop.
Conrod with wxWidgets POC OSX
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::env; | |
use std::error::Error; | |
use std::process::Command; | |
extern crate cc; | |
fn main() -> Result<(), Box<dyn Error>> { | |
println!("cargo:rerun-if-changed=cpp_src/wxbridge.cpp"); | |
let wx_flags = String::from_utf8(Command::new("wx-config").arg("--cxxflags").output()?.stdout)?; | |
env::set_var("CXXFLAGS", wx_flags); | |
cc::Build::new() | |
.cpp(true) | |
.file("cpp_src/wxbridge.cpp") | |
.compile("libwxbridge.a"); | |
let wx_libs = String::from_utf8(Command::new("wx-config").arg("--libs").arg("core,base,gl").output()?.stdout)?; | |
let mut iter = wx_libs.split_whitespace(); | |
while let Some(flag) = iter.next() { | |
if flag.starts_with("-l") { | |
println!("cargo:rustc-link-lib={}", &flag[2..]); | |
} else if flag.starts_with("-L") { | |
println!("cargo:rustc-link-search={}", &flag[2..]); | |
} else if flag == "-framework" { | |
println!("cargo:rustc-link-lib=framework={}", iter.next().unwrap()); | |
} | |
} | |
Ok(()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "wx-conrod-test" | |
version = "0.1.0" | |
authors = ["Alex Charlton"] | |
edition = "2018" | |
[dependencies] | |
glium = "0.24" | |
conrod_core = { path = "../conrod/conrod_core" } | |
conrod_glium = { path = "../conrod/backends/conrod_glium" } | |
[build-dependencies] | |
cc = "1.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <wx/wx.h> | |
#include "wx/glcanvas.h" | |
#include "OpenGL/gl.h" | |
class TestGLCanvas : public wxGLCanvas | |
{ | |
public: | |
TestGLCanvas(wxWindow *parent, | |
wxWindowID id = wxID_ANY, | |
int *gl_attrib = NULL); | |
virtual ~TestGLCanvas(); | |
void(*render)(); | |
void OnPaint(wxPaintEvent& event); | |
void OnSize(wxSizeEvent& event); | |
void InitGL(); | |
private: | |
wxGLContext* m_glRC; | |
wxDECLARE_EVENT_TABLE(); | |
wxDECLARE_NO_COPY_CLASS(TestGLCanvas); | |
}; | |
wxBEGIN_EVENT_TABLE(TestGLCanvas, wxGLCanvas) | |
EVT_SIZE(TestGLCanvas::OnSize) | |
EVT_PAINT(TestGLCanvas::OnPaint) | |
wxEND_EVENT_TABLE() | |
TestGLCanvas::TestGLCanvas(wxWindow *parent, | |
wxWindowID id, | |
int* gl_attrib) | |
: wxGLCanvas(parent, id, gl_attrib) | |
{ | |
m_glRC = new wxGLContext(this); | |
} | |
TestGLCanvas::~TestGLCanvas() | |
{ | |
delete m_glRC; | |
} | |
void TestGLCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) ){ | |
wxPaintDC dc(this); | |
glClear(GL_COLOR_BUFFER_BIT); | |
this->render(); | |
SwapBuffers(); | |
} | |
void TestGLCanvas::OnSize(wxSizeEvent& event) | |
{ | |
if ( !IsShownOnScreen() ) | |
return; | |
// This is normally only necessary if there is more than one wxGLCanvas | |
// or more than one wxGLContext in the application. | |
// SetCurrent(*m_glRC); | |
// It's up to the application code to update the OpenGL viewport settings. | |
// This is OK here only because there is only one canvas that uses the | |
// context. See the cube sample for that case that multiple canvases are | |
// made current with one context. | |
const wxSize size = event.GetSize() * GetContentScaleFactor(); | |
glViewport(0, 0, size.x, size.y); | |
} | |
void TestGLCanvas::InitGL() | |
{ | |
SetCurrent(*m_glRC); | |
PostSizeEventToParent(); | |
} | |
class MyFrame: public wxFrame { | |
public: | |
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); | |
TestGLCanvas *canvas; | |
private: | |
void OnHello(wxCommandEvent& event); | |
void OnExit(wxCommandEvent& event); | |
void OnAbout(wxCommandEvent& event); | |
wxDECLARE_EVENT_TABLE(); | |
}; | |
enum { | |
ID_Hello = 1 | |
}; | |
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) | |
EVT_MENU(ID_Hello, MyFrame::OnHello) | |
EVT_MENU(wxID_EXIT, MyFrame::OnExit) | |
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout) | |
wxEND_EVENT_TABLE() | |
class MyApp: public wxApp { | |
public: | |
MyFrame *frame; | |
virtual bool OnInit(); | |
}; | |
bool MyApp::OnInit() { | |
frame = new MyFrame( "Hello World", wxPoint(50, 50), wxSize(400, 200) ); | |
frame->Show( true ); | |
return true; | |
} | |
MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) | |
: wxFrame(NULL, wxID_ANY, title, pos, size) { | |
wxMenu *menuFile = new wxMenu; | |
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H", | |
"Help string shown in status bar for this menu item"); | |
menuFile->AppendSeparator(); | |
menuFile->Append(wxID_EXIT); | |
wxMenu *menuHelp = new wxMenu; | |
menuHelp->Append(wxID_ABOUT); | |
wxMenuBar *menuBar = new wxMenuBar; | |
menuBar->Append( menuFile, "&File" ); | |
menuBar->Append( menuHelp, "&Help" ); | |
SetMenuBar( menuBar ); | |
CreateStatusBar(); | |
SetStatusText( "Welcome to wxWidgets!" ); | |
Show(true); | |
int gl_attrib[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_CORE_PROFILE, WX_GL_MAJOR_VERSION, 3, WX_GL_MINOR_VERSION, 2}; | |
canvas = new TestGLCanvas(this, wxID_ANY, gl_attrib); | |
canvas->InitGL(); | |
} | |
void MyFrame::OnExit(wxCommandEvent& event) { | |
Close( true ); | |
} | |
void MyFrame::OnAbout(wxCommandEvent& event) { | |
wxMessageBox( "This is a wxWidgets' Hello world sample", | |
"About Hello World", wxOK | wxICON_INFORMATION ); | |
} | |
void MyFrame::OnHello(wxCommandEvent& event) { | |
wxLogMessage("Hello world from wxWidgets!"); | |
} | |
MyApp& wxGetApp() { return *static_cast<MyApp*>(wxApp::GetInstance()); } | |
// OSX specific | |
// https://developer.apple.com/library/archive/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_entrypts/opengl_entrypts.html#//apple_ref/doc/uid/TP40001987-CH402-SW6 | |
#import <mach-o/dyld.h> | |
void * MyNSGLGetProcAddress(const char *name) | |
{ | |
NSSymbol symbol; | |
char *symbolName; | |
symbolName = (char*) malloc(strlen (name) + 2); // 1 | |
strcpy(symbolName + 1, name); // 2 | |
symbolName[0] = '_'; // 3 | |
symbol = NULL; | |
if (NSIsSymbolNameDefined (symbolName)) // 4 | |
symbol = NSLookupAndBindSymbol (symbolName); | |
free (symbolName); // 5 | |
return symbol ? NSAddressOfSymbol (symbol) : NULL; // 6 | |
} | |
// END OSX specific | |
extern "C" { | |
void init_app() { | |
//void run_app() { | |
wxApp::SetInstance( new MyApp() ); | |
int fake_argc = 0; | |
char *fake_argv[] = {}; | |
wxEntryStart(fake_argc, fake_argv); | |
wxTheApp->OnInit(); | |
} | |
void set_render(void (*render)()) { | |
wxGetApp().frame->canvas->render = render; | |
} | |
void run_app() { | |
wxTheApp->OnRun(); | |
wxTheApp->OnExit(); | |
wxEntryCleanup(); | |
} | |
void *get_proc_address(char *name) { | |
return MyNSGLGetProcAddress(name); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cell::UnsafeCell; | |
use std::ffi::CString; | |
use std::os::raw::c_void; | |
use std::rc::Rc; | |
#[macro_use] | |
extern crate conrod_core; | |
extern crate conrod_glium; | |
extern crate glium; | |
use conrod_core::{widget, Colorable, Widget}; | |
use glium::Surface; | |
mod notsafe { | |
use std::os::raw::c_char; | |
use std::os::raw::c_void; | |
extern "C" { | |
#[link(name = "wxbridge")] | |
pub fn init_app(); | |
pub fn set_render(render: extern "C" fn()); | |
pub fn run_app(); | |
pub fn get_proc_address(symbol: *const c_char) -> *const c_void; | |
} | |
} | |
pub fn init_app() { | |
unsafe { | |
notsafe::init_app(); | |
}; | |
} | |
pub fn run_app() { | |
unsafe { | |
notsafe::run_app(); | |
}; | |
} | |
pub fn get_proc_address(symbol: &str) -> *const c_void { | |
unsafe { notsafe::get_proc_address(CString::new(symbol).unwrap().as_ptr()) } | |
} | |
pub fn set_render(render: extern "C" fn()) { | |
unsafe { | |
notsafe::set_render(render); | |
}; | |
} | |
struct Backend {} | |
unsafe impl glium::backend::Backend for Backend { | |
fn swap_buffers(&self) -> Result<(), glium::SwapBuffersError> { | |
Ok(()) | |
} | |
unsafe fn get_proc_address(&self, symbol: &str) -> *const c_void { | |
get_proc_address(symbol) | |
} | |
fn get_framebuffer_dimensions(&self) -> (u32, u32) { | |
(400, 200) | |
} | |
fn is_current(&self) -> bool { | |
true | |
} | |
unsafe fn make_current(&self) {} | |
} | |
impl conrod_glium::Display for Backend { | |
fn opengl_version(&self) -> &glium::Version { | |
&glium::Version(glium::Api::Gl, 3, 0) | |
} | |
fn framebuffer_dimensions(&self) -> (u32, u32) { | |
(400, 200) | |
} | |
fn hidpi_factor(&self) -> f64 { | |
1.0 | |
} | |
} | |
thread_local!( | |
static THREAD_CONTEXT: UnsafeCell<Rc<glium::backend::Context>> = { | |
UnsafeCell::new( | |
unsafe { | |
glium::backend::Context::new(Backend { }, false, Default::default()) | |
}.unwrap()) | |
} | |
); | |
pub fn context() -> Rc<glium::backend::Context> { | |
THREAD_CONTEXT.with(|r| unsafe { r.get().as_ref().unwrap().clone() }) | |
} | |
pub fn frame() -> glium::Frame { | |
let context = THREAD_CONTEXT.with(|r| unsafe { r.get().as_ref().unwrap() }); | |
glium::Frame::new(context.clone(), context.get_framebuffer_dimensions()) | |
} | |
extern "C" fn render() { | |
const WIDTH: u32 = 400; | |
const HEIGHT: u32 = 200; | |
let mut renderer = conrod_glium::Renderer::new(&context()).unwrap(); | |
let image_map = conrod_core::image::Map::<glium::texture::Texture2d>::new(); | |
let mut ui = conrod_core::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build(); | |
widget_ids!(struct Ids { background }); | |
let ids = Ids::new(ui.widget_id_generator()); | |
// Instantiate all widgets in the GUI. | |
{ | |
let ui = &mut ui.set_widgets(); | |
// Sets a color to clear the background with before the Ui draws our widget. | |
widget::Canvas::new() | |
.color(conrod_core::color::DARK_RED) | |
.set(ids.background, ui); | |
} | |
// Render the `Ui` and then display it on the screen. | |
if let Some(primitives) = ui.draw_if_changed() { | |
renderer.fill(&Backend {}, primitives, &image_map); | |
let mut target = frame(); | |
target.clear_color(0.0, 0.0, 0.0, 1.0); | |
renderer.draw(&context(), &mut target, &image_map).unwrap(); | |
target.finish().unwrap(); | |
} | |
} | |
fn main() { | |
init_app(); | |
set_render(render); | |
run_app(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment