Skip to content

Instantly share code, notes, and snippets.

@AlexCharlton
Created February 20, 2020 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexCharlton/e1804966f5f8fc64d1b0b965142ff89b to your computer and use it in GitHub Desktop.
Save AlexCharlton/e1804966f5f8fc64d1b0b965142ff89b to your computer and use it in GitHub Desktop.
Conrod with wxWidgets POC OSX
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(())
}
[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"
#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);
}
}
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