Add enough C bindings to recreate `canvas_minimal` in C.

Closes #12.
This commit is contained in:
Patrick Walton 2019-05-24 17:45:19 -07:00
parent 009f78ba26
commit e04cc273ee
11 changed files with 736 additions and 2 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ target
/site/package-lock.json /site/package-lock.json
/site/dist /site/dist
node_modules node_modules
/examples/c_canvas_minimal/build
# Editors # Editors
*.swp *.swp

13
Cargo.lock generated
View File

@ -1184,6 +1184,19 @@ dependencies = [
"pathfinder_gpu 0.1.0", "pathfinder_gpu 0.1.0",
] ]
[[package]]
name = "pathfinder_c"
version = "0.1.0"
dependencies = [
"gl 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_canvas 0.1.0",
"pathfinder_geometry 0.3.0",
"pathfinder_gl 0.1.0",
"pathfinder_gpu 0.1.0",
"pathfinder_renderer 0.1.0",
"pathfinder_simd 0.3.0",
]
[[package]] [[package]]
name = "pathfinder_canvas" name = "pathfinder_canvas"
version = "0.1.0" version = "0.1.0"

View File

@ -1,5 +1,6 @@
[workspace] [workspace]
members = [ members = [
"c",
"canvas", "canvas",
"demo/android/rust", "demo/android/rust",
"demo/common", "demo/common",

29
c/Cargo.toml Normal file
View File

@ -0,0 +1,29 @@
[package]
name = "pathfinder_c"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[lib]
crate-type = ["staticlib"]
[dependencies]
gl = "0.6"
[dependencies.pathfinder_canvas]
path = "../canvas"
[dependencies.pathfinder_geometry]
path = "../geometry"
[dependencies.pathfinder_gl]
path = "../gl"
[dependencies.pathfinder_gpu]
path = "../gpu"
[dependencies.pathfinder_renderer]
path = "../renderer"
[dependencies.pathfinder_simd]
path = "../simd"

View File

@ -0,0 +1,158 @@
// pathfinder/c/include/pathfinder/pathfinder.h
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#ifndef PF_PATHFINDER_H
#define PF_PATHFINDER_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// Macros
// `gl`
#define PF_GL_VERSION_GL3 0
#define PF_GL_VERSION_GLES3 1
// `gpu`
#define PF_CLEAR_FLAGS_HAS_COLOR 0x1
#define PF_CLEAR_FLAGS_HAS_DEPTH 0x2
#define PF_CLEAR_FLAGS_HAS_STENCIL 0x4
#define PF_CLEAR_FLAGS_HAS_RECT 0x8
// Types
// `canvas`
struct PFCanvas;
typedef struct PFCanvas *PFCanvasRef;
struct PFPath;
typedef struct PFPath *PFPathRef;
// `geometry`
struct PFColorF {
float r, g, b, a;
};
typedef struct PFColorF PFColorF;
struct PFPoint2DF {
float x, y;
};
typedef struct PFPoint2DF PFPoint2DF;
struct PFPoint2DI {
int32_t x, y;
};
typedef struct PFPoint2DI PFPoint2DI;
struct PFRectF {
PFPoint2DF origin, lower_right;
};
typedef struct PFRectF PFRectF;
struct PFRectI {
PFPoint2DI origin, lower_right;
};
typedef struct PFRectI PFRectI;
// `gl`
struct PFGLDevice;
typedef struct PFGLDevice *PFGLDeviceRef;
struct PFGLDestFramebuffer;
typedef struct PFGLDestFramebuffer *PFGLDestFramebufferRef;
typedef const void *(*PFGLFunctionLoader)(const char *data, void *userdata);
struct PFGLRenderer;
typedef struct PFGLRenderer *PFGLRendererRef;
typedef uint32_t PFGLVersion;
// `gpu`
typedef uint8_t PFClearFlags;
struct PFClearParams {
PFColorF color;
float depth;
uint8_t stencil;
PFRectI rect;
PFClearFlags flags;
};
typedef struct PFClearParams PFClearParams;
struct PFResourceLoader;
typedef struct PFResourceLoader *PFResourceLoaderRef;
// `renderer`
struct PFRenderOptions {
uint32_t placeholder;
};
typedef struct PFRenderOptions PFRenderOptions;
struct PFScene;
typedef struct PFScene *PFSceneRef;
struct PFSceneProxy;
typedef struct PFSceneProxy *PFSceneProxyRef;
// Functions
// `canvas`
PFCanvasRef PFCanvasCreate(const PFPoint2DF *size);
void PFCanvasDestroy(PFCanvasRef canvas);
PFSceneRef PFCanvasCreateScene(PFCanvasRef canvas);
void PFCanvasFillRect(PFCanvasRef canvas, const PFRectF *rect);
void PFCanvasStrokeRect(PFCanvasRef canvas, const PFRectF *rect);
void PFCanvasSetLineWidth(PFCanvasRef canvas, float new_line_width);
void PFCanvasFillPath(PFCanvasRef canvas, PFPathRef path);
void PFCanvasStrokePath(PFCanvasRef canvas, PFPathRef path);
PFPathRef PFPathCreate();
void PFPathDestroy(PFPathRef path);
PFPathRef PFPathClone(PFPathRef path);
void PFPathMoveTo(PFPathRef path, const PFPoint2DF *to);
void PFPathLineTo(PFPathRef path, const PFPoint2DF *to);
void PFPathQuadraticCurveTo(PFPathRef path, const PFPoint2DF *ctrl, const PFPoint2DF *to);
void PFPathBezierCurveTo(PFPathRef path,
const PFPoint2DF *ctrl0,
const PFPoint2DF *ctrl1,
const PFPoint2DF *to);
void PFPathClosePath(PFPathRef path);
// `gl`
PFGLDestFramebufferRef PFGLDestFramebufferCreateFullWindow(const PFPoint2DI *window_size);
void PFGLDestFramebufferDestroy(PFGLDestFramebufferRef dest_framebuffer);
PFGLDeviceRef PFGLDeviceCreate(PFGLVersion version, uint32_t default_framebuffer);
void PFGLDeviceDestroy(PFGLDeviceRef device);
void PFGLDeviceClear(PFGLDeviceRef device, const PFClearParams *params);
void PFGLLoadWith(PFGLFunctionLoader loader, void *userdata);
PFGLRendererRef PFGLRendererCreate(PFGLDeviceRef device,
PFResourceLoaderRef resources,
PFGLDestFramebufferRef dest_framebuffer);
void PFGLRendererDestroy(PFGLRendererRef renderer);
/// Returns a borrowed reference to the device.
PFGLDeviceRef PFGLRendererGetDevice(PFGLRendererRef renderer);
void PFSceneProxyBuildAndRenderGL(PFSceneProxyRef scene_proxy,
PFGLRendererRef renderer,
const PFRenderOptions *options);
// `gpu`
PFResourceLoaderRef PFFilesystemResourceLoaderLocate();
void PFResourceLoaderDestroy(PFResourceLoaderRef loader);
// `renderer`
PFSceneProxyRef PFSceneProxyCreateFromSceneAndRayonExecutor(PFSceneRef scene);
void PFSceneProxyDestroy(PFSceneProxyRef scene_proxy);
#ifdef __cplusplus
}
#endif
#endif

360
c/src/lib.rs Normal file
View File

@ -0,0 +1,360 @@
// pathfinder/c/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! C bindings to Pathfinder.
use gl;
use pathfinder_canvas::{CanvasRenderingContext2D, Path2D};
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32};
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
use pathfinder_geometry::color::ColorF;
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_gpu::resources::{FilesystemResourceLoader, ResourceLoader};
use pathfinder_gpu::{ClearParams, Device};
use pathfinder_renderer::concurrent::rayon::RayonExecutor;
use pathfinder_renderer::concurrent::scene_proxy::SceneProxy;
use pathfinder_renderer::gpu::renderer::{DestFramebuffer, Renderer};
use pathfinder_renderer::options::RenderOptions;
use pathfinder_renderer::scene::Scene;
use pathfinder_simd::default::F32x4;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
// Constants
pub const PF_CLEAR_FLAGS_HAS_COLOR: u8 = 0x1;
pub const PF_CLEAR_FLAGS_HAS_DEPTH: u8 = 0x2;
pub const PF_CLEAR_FLAGS_HAS_STENCIL: u8 = 0x4;
pub const PF_CLEAR_FLAGS_HAS_RECT: u8 = 0x8;
// Types
// `canvas`
pub type PFCanvasRef = *mut CanvasRenderingContext2D;
pub type PFPathRef = *mut Path2D;
// `geometry`
#[repr(C)]
pub struct PFPoint2DF {
pub x: f32,
pub y: f32,
}
#[repr(C)]
pub struct PFPoint2DI {
pub x: i32,
pub y: i32,
}
#[repr(C)]
pub struct PFRectF {
pub origin: PFPoint2DF,
pub lower_right: PFPoint2DF,
}
#[repr(C)]
pub struct PFRectI {
pub origin: PFPoint2DI,
pub lower_right: PFPoint2DI,
}
#[repr(C)]
pub struct PFColorF {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
// `gl`
pub type PFGLDeviceRef = *mut GLDevice;
pub type PFGLVersion = GLVersion;
pub type PFGLFunctionLoader = extern "C" fn(name: *const c_char, userdata: *mut c_void)
-> *const c_void;
// `gpu`
pub type PFGLDestFramebufferRef = *mut DestFramebuffer<GLDevice>;
pub type PFGLRendererRef = *mut Renderer<GLDevice>;
// FIXME(pcwalton): Double-boxing is unfortunate. Remove this when `std::raw::TraitObject` is
// stable?
pub type PFResourceLoaderRef = *mut Box<dyn ResourceLoader>;
#[repr(C)]
pub struct PFClearParams {
pub color: PFColorF,
pub depth: f32,
pub stencil: u8,
pub rect: PFRectI,
pub flags: PFClearFlags,
}
pub type PFClearFlags = u8;
// `renderer`
pub type PFSceneRef = *mut Scene;
pub type PFSceneProxyRef = *mut SceneProxy;
// TODO(pcwalton)
#[repr(C)]
pub struct PFRenderOptions {
pub placeholder: u32,
}
// `canvas`
#[no_mangle]
pub unsafe extern "C" fn PFCanvasCreate(size: *const PFPoint2DF) -> PFCanvasRef {
Box::into_raw(Box::new(CanvasRenderingContext2D::new((*size).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasDestroy(canvas: PFCanvasRef) {
drop(Box::from_raw(canvas))
}
/// Consumes the canvas.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasCreateScene(canvas: PFCanvasRef) -> PFSceneRef {
Box::into_raw(Box::new(Box::from_raw(canvas).into_scene()))
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillRect(canvas: PFCanvasRef, rect: *const PFRectF) {
(*canvas).fill_rect((*rect).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasStrokeRect(canvas: PFCanvasRef, rect: *const PFRectF) {
(*canvas).stroke_rect((*rect).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFCanvasSetLineWidth(canvas: PFCanvasRef, new_line_width: f32) {
(*canvas).set_line_width(new_line_width)
}
/// Consumes the path.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasFillPath(canvas: PFCanvasRef, path: PFPathRef) {
(*canvas).fill_path(*Box::from_raw(path))
}
/// Consumes the path.
#[no_mangle]
pub unsafe extern "C" fn PFCanvasStrokePath(canvas: PFCanvasRef, path: PFPathRef) {
(*canvas).stroke_path(*Box::from_raw(path))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathCreate() -> PFPathRef {
Box::into_raw(Box::new(Path2D::new()))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathDestroy(path: PFPathRef) {
drop(Box::from_raw(path))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathClone(path: PFPathRef) -> PFPathRef {
Box::into_raw(Box::new((*path).clone()))
}
#[no_mangle]
pub unsafe extern "C" fn PFPathMoveTo(path: PFPathRef, to: *const PFPoint2DF) {
(*path).move_to((*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathLineTo(path: PFPathRef, to: *const PFPoint2DF) {
(*path).line_to((*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathQuadraticCurveTo(path: PFPathRef,
ctrl: *const PFPoint2DF,
to: *const PFPoint2DF) {
(*path).quadratic_curve_to((*ctrl).to_rust(), (*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathBezierCurveTo(path: PFPathRef,
ctrl0: *const PFPoint2DF,
ctrl1: *const PFPoint2DF,
to: *const PFPoint2DF) {
(*path).bezier_curve_to((*ctrl0).to_rust(), (*ctrl1).to_rust(), (*to).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFPathClosePath(path: PFPathRef) {
(*path).close_path()
}
// `gl`
#[no_mangle]
pub unsafe extern "C" fn PFFilesystemResourceLoaderLocate() -> PFResourceLoaderRef {
let loader = Box::new(FilesystemResourceLoader::locate());
Box::into_raw(Box::new(loader as Box<dyn ResourceLoader>))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLLoadWith(loader: PFGLFunctionLoader, userdata: *mut c_void) {
gl::load_with(|name| {
let name = CString::new(name).unwrap();
loader(name.as_ptr(), userdata)
});
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDeviceCreate(version: PFGLVersion, default_framebuffer: u32)
-> PFGLDeviceRef {
Box::into_raw(Box::new(GLDevice::new(version, default_framebuffer)))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDeviceDestroy(device: PFGLDeviceRef) {
drop(Box::from_raw(device))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDeviceClear(device: PFGLDeviceRef, params: *const PFClearParams) {
(*device).clear(&(*params).to_rust())
}
#[no_mangle]
pub unsafe extern "C" fn PFResourceLoaderDestroy(loader: PFResourceLoaderRef) {
drop(Box::from_raw(loader))
}
// `gpu`
#[no_mangle]
pub unsafe extern "C" fn PFGLDestFramebufferCreateFullWindow(window_size: *const PFPoint2DI)
-> PFGLDestFramebufferRef {
Box::into_raw(Box::new(DestFramebuffer::full_window((*window_size).to_rust())))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLDestFramebufferDestroy(dest_framebuffer: PFGLDestFramebufferRef) {
drop(Box::from_raw(dest_framebuffer))
}
/// Takes ownership of `device` and `dest_framebuffer`, but not `resources`.
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererCreate(device: PFGLDeviceRef,
resources: PFResourceLoaderRef,
dest_framebuffer: PFGLDestFramebufferRef)
-> PFGLRendererRef {
Box::into_raw(Box::new(Renderer::new(*Box::from_raw(device),
&**resources,
*Box::from_raw(dest_framebuffer))))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererDestroy(renderer: PFGLRendererRef) {
drop(Box::from_raw(renderer))
}
#[no_mangle]
pub unsafe extern "C" fn PFGLRendererGetDevice(renderer: PFGLRendererRef) -> PFGLDeviceRef {
&mut (*renderer).device
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyBuildAndRenderGL(scene_proxy: PFSceneProxyRef,
renderer: PFGLRendererRef,
options: *const PFRenderOptions) {
(*scene_proxy).build_and_render(&mut *renderer, (*options).to_rust())
}
// `renderer`
#[no_mangle]
pub unsafe extern "C" fn PFSceneDestroy(scene: PFSceneRef) {
drop(Box::from_raw(scene))
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyCreateFromSceneAndRayonExecutor(scene: PFSceneRef)
-> PFSceneProxyRef {
Box::into_raw(Box::new(SceneProxy::from_scene(*Box::from_raw(scene), RayonExecutor)))
}
#[no_mangle]
pub unsafe extern "C" fn PFSceneProxyDestroy(scene_proxy: PFSceneProxyRef) {
drop(Box::from_raw(scene_proxy))
}
// Helpers for `geometry`
impl PFColorF {
#[inline]
pub fn to_rust(&self) -> ColorF {
ColorF(F32x4::new(self.r, self.g, self.b, self.a))
}
}
impl PFRectF {
#[inline]
pub fn to_rust(&self) -> RectF32 {
RectF32::from_points(self.origin.to_rust(), self.lower_right.to_rust())
}
}
impl PFRectI {
#[inline]
pub fn to_rust(&self) -> RectI32 {
RectI32::from_points(self.origin.to_rust(), self.lower_right.to_rust())
}
}
impl PFPoint2DF {
#[inline]
pub fn to_rust(&self) -> Point2DF32 {
Point2DF32::new(self.x, self.y)
}
}
impl PFPoint2DI {
#[inline]
pub fn to_rust(&self) -> Point2DI32 {
Point2DI32::new(self.x, self.y)
}
}
// Helpers for `gpu`
impl PFClearParams {
pub fn to_rust(&self) -> ClearParams {
ClearParams {
color: if (self.flags & PF_CLEAR_FLAGS_HAS_COLOR) != 0 {
Some(self.color.to_rust())
} else {
None
},
rect: if (self.flags & PF_CLEAR_FLAGS_HAS_RECT) != 0 {
Some(self.rect.to_rust())
} else {
None
},
depth: if (self.flags & PF_CLEAR_FLAGS_HAS_DEPTH) != 0 {
Some(self.depth)
} else {
None
},
stencil: if (self.flags & PF_CLEAR_FLAGS_HAS_STENCIL) != 0 {
Some(self.stencil)
} else {
None
},
}
}
}
// Helpers for `renderer`
impl PFRenderOptions {
pub fn to_rust(&self) -> RenderOptions {
RenderOptions::default()
}
}

View File

@ -4,6 +4,9 @@ version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"] authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018" edition = "2018"
[lib]
crate-type = ["rlib", "staticlib"]
[dependencies] [dependencies]
font-kit = "0.1" font-kit = "0.1"

View File

@ -0,0 +1,47 @@
OBJ_DIR?=build
TARGET_DIR?=build
SRC_DIR?=.
RUST_TARGET_DIR?=../../target
RUST_SRC_DIR?=../../c
RUSTFLAGS?=-C target-cpu=native
CFLAGS?=-Wall -g -I../../c/include
LIBS?=-lpathfinder_c
MKDIR?=mkdir -p
RM?=rm
CARGO?=cargo
UNAME=$(shell uname -s)
ifeq ($(UNAME),Darwin)
# FIXME(pcwalton): Don't link against HarfBuzz!!
LIBS+=-framework OpenGL -framework CoreFoundation -framework CoreGraphics -framework CoreText
LIBS+=-lharfbuzz
else
LIBS+=-lGL
endif
ifeq ($(DEBUG),)
CFLAGS+=-O2
LDFLAGS?=-L$(RUST_TARGET_DIR)/release
CARGOFLAGS?=--release
else
CFLAGS+=-O0
LDFLAGS?=-L$(RUST_TARGET_DIR)/debug
CARGOFLAGS?=
endif
all: $(TARGET_DIR)/c_canvas_minimal
.PHONY: clean rustlib
$(TARGET_DIR)/c_canvas_minimal: $(OBJ_DIR)/c_canvas_minimal.o rustlib
$(MKDIR) $(TARGET_DIR) && $(CC) $(LDFLAGS) $(LIBS) `sdl2-config --libs` -o $@ $<
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(MKDIR) $(OBJ_DIR) && $(CC) -c $(CFLAGS) `sdl2-config --cflags` -o $@ $<
rustlib:
cd $(RUST_SRC_DIR) && RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) build $(CARGOFLAGS)
clean:
$(RM) -rf $(TARGET_DIR) && $(RM) -rf $(OBJ_DIR)

View File

@ -0,0 +1,117 @@
// pathfinder/examples/c_canvas_minimal/c_canvas_minimal.c
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <pathfinder/pathfinder.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static const void *LoadGLFunction(const char *name, void *userdata);
static void SDLFailed(const char *msg);
int main(int argc, const char **argv) {
// Set up SDL2.
if (SDL_Init(SDL_INIT_EVENTS | SDL_INIT_VIDEO) != 0)
SDLFailed("Failed to initialize SDL");
// Make sure we have at least a GL 3.0 context. Pathfinder requires this.
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3) != 0)
SDLFailed("Failed to set GL major version");
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2) != 0)
SDLFailed("Failed to set GL minor version");
if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) != 0)
SDLFailed("Failed to set GL profile");
if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0)
SDLFailed("Failed to make GL context double-buffered");
// Open a window.
SDL_Window *window = SDL_CreateWindow("Minimal canvas example (C API)",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
640,
480,
SDL_WINDOW_OPENGL);
if (window == NULL)
SDLFailed("Failed to create SDL window");
// Create the GL context, and make it current.
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
if (gl_context == NULL)
SDLFailed("Failed to create GL context");
// Put the window on screen.
SDL_ShowWindow(window);
// Create a Pathfinder renderer.
PFGLLoadWith(LoadGLFunction, NULL);
PFGLDestFramebufferRef dest_framebuffer =
PFGLDestFramebufferCreateFullWindow(&(PFPoint2DI){640, 480});
PFGLRendererRef renderer = PFGLRendererCreate(PFGLDeviceCreate(PF_GL_VERSION_GL3, 0),
PFFilesystemResourceLoaderLocate(),
dest_framebuffer);
// Clear to white.
PFGLDeviceClear(PFGLRendererGetDevice(renderer), &(PFClearParams){
(PFColorF){1.0, 1.0, 1.0, 1.0}, 0.0, 0, {0}, PF_CLEAR_FLAGS_HAS_COLOR
});
// Make a canvas. We're going to draw a house.
PFCanvasRef canvas = PFCanvasCreate(&(PFPoint2DF){640.0f, 480.0f});
// Set line width.
PFCanvasSetLineWidth(canvas, 10.0f);
// Draw walls.
PFCanvasStrokeRect(canvas, &(PFRectF){{75.0f, 140.0f}, {225.0f, 250.0f}});
// Draw door.
PFCanvasFillRect(canvas, &(PFRectF){{130.0f, 190.0f}, {170.0f, 250.0f}});
// Draw roof.
PFPathRef path = PFPathCreate();
PFPathMoveTo(path, &(PFPoint2DF){50.0, 140.0});
PFPathLineTo(path, &(PFPoint2DF){150.0, 60.0});
PFPathLineTo(path, &(PFPoint2DF){250.0, 140.0});
PFPathClosePath(path);
PFCanvasStrokePath(canvas, path);
// Render the canvas to screen.
PFSceneRef scene = PFCanvasCreateScene(canvas);
PFSceneProxyRef scene_proxy = PFSceneProxyCreateFromSceneAndRayonExecutor(scene);
PFSceneProxyBuildAndRenderGL(scene_proxy, renderer, &(PFRenderOptions){0});
SDL_GL_SwapWindow(window);
// Wait for a keypress.
while (true) {
SDL_Event event;
if (SDL_WaitEvent(&event) == 0)
SDLFailed("Failed to get SDL event");
if (event.type == SDL_QUIT ||
(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) {
break;
}
}
// Finish up.
SDL_Quit();
return 0;
}
static const void *LoadGLFunction(const char *name, void *userdata) {
return SDL_GL_GetProcAddress(name);
}
static void SDLFailed(const char *msg) {
fprintf(stderr, "%s: %s\n", msg, SDL_GetError());
exit(EXIT_FAILURE);
}

View File

@ -4,6 +4,9 @@ version = "0.1.0"
edition = "2018" edition = "2018"
authors = ["Patrick Walton <pcwalton@mimiga.net>"] authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[lib]
crate-type = ["rlib", "staticlib"]
[dependencies] [dependencies]
gl = "0.6" gl = "0.6"
rustache = "0.1" rustache = "0.1"

View File

@ -859,11 +859,13 @@ impl VertexAttrTypeExt for VertexAttrType {
} }
/// The version/dialect of OpenGL we should render with. /// The version/dialect of OpenGL we should render with.
#[derive(Clone, Copy)]
#[repr(u32)]
pub enum GLVersion { pub enum GLVersion {
/// OpenGL 3.0+, core profile. /// OpenGL 3.0+, core profile.
GL3, GL3 = 0,
/// OpenGL ES 3.0+. /// OpenGL ES 3.0+.
GLES3, GLES3 = 1,
} }
impl GLVersion { impl GLVersion {