#![cfg(feature = "sm-raw-window-handle-06")]
use self::common::{ck, Buffer, Program, ResourceLoader, Shader, ShaderKind};
use euclid::default::{Point2D, Rect, Size2D, Vector2D};
use gl::types::{GLchar, GLenum, GLint, GLuint, GLvoid};
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
use surfman::{declare_surfman, SurfaceAccess, SurfaceTexture, SurfaceType};
use surfman::{Adapter, Connection, Context, ContextDescriptor, Device, GLApi, Surface};
#[cfg(not(target_os = "android"))]
use self::common::FilesystemResourceLoader;
#[cfg(not(target_os = "android"))]
use surfman::{ContextAttributeFlags, ContextAttributes, GLVersion};
#[cfg(not(target_os = "android"))]
use winit::{
dpi::PhysicalSize,
event::{DeviceEvent, Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use rwh_06::{HasDisplayHandle, HasWindowHandle};
pub mod common;
declare_surfman!();
const WINDOW_WIDTH: i32 = 800;
const WINDOW_HEIGHT: i32 = 600;
const SUBSCREEN_WIDTH: i32 = 256;
const SUBSCREEN_HEIGHT: i32 = 256;
const BALL_WIDTH: i32 = 192;
const BALL_HEIGHT: i32 = 192;
const CHECK_SIZE: f32 = 16.0;
const INITIAL_VELOCITY_X: f32 = 1.5;
const INITIAL_VELOCITY_Y: f32 = 0.0;
const GRAVITY: f32 = -0.2;
const INITIAL_ROTATION_X: f32 = 0.2;
const INITIAL_ROTATION_Y: f32 = 0.6;
const INITIAL_ROTATION_Z: f32 = 0.2;
const ROTATION_SPEED_X: f32 = 0.03;
const ROTATION_SPEED_Y: f32 = 0.01;
const ROTATION_SPEED_Z: f32 = 0.05;
const SPHERE_RADIUS: f32 = 96.0;
static QUAD_VERTEX_POSITIONS: [u8; 8] = [0, 0, 1, 0, 0, 1, 1, 1];
static CHECK_TRANSFORM: [f32; 4] = [
SUBSCREEN_WIDTH as f32 / CHECK_SIZE as f32,
0.0,
0.0,
SUBSCREEN_HEIGHT as f32 / CHECK_SIZE as f32,
];
static IDENTITY_TRANSFORM: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
static ZERO_TRANSLATION: [f32; 2] = [0.0, 0.0];
static NDC_TRANSFORM: [f32; 4] = [2.0, 0.0, 0.0, 2.0];
static NDC_TRANSLATION: [f32; 2] = [-1.0, -1.0];
static CHECK_COLOR_A: [f32; 4] = [0.8, 0.0, 0.0, 1.0];
static CHECK_COLOR_B: [f32; 4] = [0.9, 0.9, 0.9, 1.0];
static CAMERA_POSITION: [f32; 3] = [400.0, 300.0, -1000.0];
static LIGHT_POSITION: [f32; 3] = [600.0, 450.0, -500.0];
static GRIDLINE_COLOR: [f32; 4] = [
(0x9e as f32) / 255.0,
(0x2b as f32) / 255.0,
(0x86 as f32) / 255.0,
1.0,
];
static BACKGROUND_COLOR: [f32; 4] = [
(0xaa as f32) / 255.0,
(0xaa as f32) / 255.0,
(0xaa as f32) / 255.0,
1.0,
];
fn make_connection(window: &winit::window::Window) -> surfman::Connection {
let display_handle = window
.display_handle()
.expect("failed to get display handle from window");
let connection = Connection::from_display_handle(display_handle).unwrap();
connection
}
fn make_native_widget(
window: &winit::window::Window,
connection: &surfman::Connection,
window_size: Size2D<i32>,
) -> surfman::NativeWidget {
let raw_window_handle = window
.window_handle()
.expect("couldn't get window handle from window");
let native_widget = connection
.create_native_widget_from_window_handle(raw_window_handle, window_size)
.unwrap();
native_widget
}
#[cfg(target_os = "android")]
fn main() {}
#[cfg(not(target_os = "android"))]
fn main() {
use winit::{
event::RawKeyEvent,
keyboard::{KeyCode, PhysicalKey},
};
let event_loop = EventLoop::new().expect("couldn't create eventloop");
let window_size = Size2D::new(WINDOW_WIDTH, WINDOW_HEIGHT);
let physical_size = PhysicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT);
let window = WindowBuilder::new()
.with_title("Multithreaded example")
.with_inner_size(physical_size)
.build(&event_loop)
.unwrap();
window.set_visible(true);
let connection = make_connection(&window);
let window_size = window.inner_size();
let window_size = Size2D::new(window_size.width as i32, window_size.height as i32);
let native_widget = make_native_widget(&window, &connection, window_size);
let adapter = connection.create_low_power_adapter().unwrap();
let device = connection.create_device(&adapter).unwrap();
let context_attributes = ContextAttributes {
version: GLVersion::new(3, 0),
flags: ContextAttributeFlags::ALPHA,
};
let context_descriptor = device
.create_context_descriptor(&context_attributes)
.unwrap();
let surface_type = SurfaceType::Widget { native_widget };
let mut context = device.create_context(&context_descriptor, None).unwrap();
let surface = device
.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
.unwrap();
device
.bind_surface_to_context(&mut context, surface)
.unwrap();
device.make_context_current(&context).unwrap();
let mut app = App::new(
connection,
adapter,
device,
context,
Box::new(FilesystemResourceLoader),
window_size,
);
event_loop
.run(move |event, target| match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
}
| Event::DeviceEvent {
event:
DeviceEvent::Key(RawKeyEvent {
physical_key: PhysicalKey::Code(KeyCode::Escape),
..
}),
..
} => target.exit(),
_ => {
app.tick(true);
target.set_control_flow(ControlFlow::Poll)
}
})
.expect("failed to run event loop");
}
pub struct App {
main_from_worker_receiver: Receiver<Frame>,
main_to_worker_sender: Sender<Surface>,
grid_vertex_array: GridVertexArray,
blit_vertex_array: BlitVertexArray,
device: Device,
context: Context,
texture: Option<SurfaceTexture>,
frame: Frame,
window_size: Size2D<i32>,
}
impl Drop for App {
fn drop(&mut self) {
self.device.destroy_context(&mut self.context).unwrap();
}
}
impl App {
pub fn new(
connection: Connection,
adapter: Adapter,
device: Device,
mut context: Context,
resource_loader: Box<dyn ResourceLoader + Send>,
window_size: Size2D<i32>,
) -> App {
let context_descriptor = device.context_descriptor(&context);
gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));
let gl_api = device.gl_api();
let surface_gl_texture_target = device.surface_gl_texture_target();
let grid_vertex_array =
GridVertexArray::new(gl_api, surface_gl_texture_target, &*resource_loader);
let blit_vertex_array =
BlitVertexArray::new(gl_api, surface_gl_texture_target, &*resource_loader);
let (worker_to_main_sender, main_from_worker_receiver) = mpsc::channel();
let (main_to_worker_sender, worker_from_main_receiver) = mpsc::channel();
thread::spawn(move || {
worker_thread(
connection,
adapter,
context_descriptor,
window_size,
resource_loader,
worker_to_main_sender,
worker_from_main_receiver,
)
});
let mut frame = match main_from_worker_receiver.recv() {
Err(_) => panic!(),
Ok(frame) => frame,
};
let texture = Some(
device
.create_surface_texture(&mut context, frame.surface.take().unwrap())
.unwrap(),
);
App {
main_from_worker_receiver,
main_to_worker_sender,
grid_vertex_array,
blit_vertex_array,
device,
texture,
frame,
context,
window_size,
}
}
pub fn tick(&mut self, present: bool) {
let surface = self
.device
.destroy_surface_texture(&mut self.context, self.texture.take().unwrap())
.unwrap();
self.main_to_worker_sender.send(surface).unwrap();
self.frame = self.main_from_worker_receiver.recv().unwrap();
self.texture = Some(
self.device
.create_surface_texture(&mut self.context, self.frame.surface.take().unwrap())
.unwrap(),
);
unsafe {
self.device.make_context_current(&self.context).unwrap();
let framebuffer_object = self
.device
.context_surface_info(&self.context)
.ok()
.flatten()
.and_then(|surface_info| surface_info.framebuffer_object);
gl::BindFramebuffer(
gl::FRAMEBUFFER,
framebuffer_object.map_or(0, |fbo| fbo.0.get()),
);
gl::Viewport(0, 0, self.window_size.width, self.window_size.height);
gl::ClearColor(0.0, 0.0, 1.0, 1.0);
ck();
gl::Clear(gl::COLOR_BUFFER_BIT);
ck();
gl::BindVertexArray(self.grid_vertex_array.object);
ck();
gl::UseProgram(self.grid_vertex_array.grid_program.program.object);
ck();
gl::UniformMatrix2fv(
self.grid_vertex_array.grid_program.transform_uniform,
1,
gl::FALSE,
NDC_TRANSFORM.as_ptr(),
);
gl::Uniform2fv(
self.grid_vertex_array.grid_program.translation_uniform,
1,
NDC_TRANSLATION.as_ptr(),
);
gl::UniformMatrix2fv(
self.grid_vertex_array.grid_program.tex_transform_uniform,
1,
gl::FALSE,
CHECK_TRANSFORM.as_ptr(),
);
gl::Uniform2fv(
self.grid_vertex_array.grid_program.tex_translation_uniform,
1,
ZERO_TRANSLATION.as_ptr(),
);
gl::Uniform4fv(
self.grid_vertex_array.grid_program.gridline_color_uniform,
1,
GRIDLINE_COLOR.as_ptr(),
);
gl::Uniform4fv(
self.grid_vertex_array.grid_program.bg_color_uniform,
1,
BACKGROUND_COLOR.as_ptr(),
);
gl::Uniform2f(
self.grid_vertex_array.grid_program.sphere_position_uniform,
self.frame.sphere_position.x,
self.frame.sphere_position.y,
);
gl::Uniform1f(
self.grid_vertex_array.grid_program.radius_uniform,
SPHERE_RADIUS,
);
gl::Uniform3fv(
self.grid_vertex_array.grid_program.camera_position_uniform,
1,
CAMERA_POSITION.as_ptr(),
);
gl::Uniform3fv(
self.grid_vertex_array.grid_program.light_position_uniform,
1,
LIGHT_POSITION.as_ptr(),
);
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
ck();
let blit_transform: [f32; 4] = [
SUBSCREEN_WIDTH as f32 / self.window_size.width as f32 * 2.0,
0.0,
0.0,
SUBSCREEN_HEIGHT as f32 / self.window_size.height as f32 * 2.0,
];
let subscreen_translation = Point2D::new(
self.frame.viewport_origin.x / self.window_size.width as f32 * 2.0 - 1.0,
self.frame.viewport_origin.y / self.window_size.height as f32 * 2.0 - 1.0,
);
gl::BindVertexArray(self.blit_vertex_array.object);
ck();
gl::UseProgram(self.blit_vertex_array.blit_program.program.object);
ck();
gl::UniformMatrix2fv(
self.blit_vertex_array.blit_program.transform_uniform,
1,
gl::FALSE,
blit_transform.as_ptr(),
);
gl::Uniform2fv(
self.blit_vertex_array.blit_program.translation_uniform,
1,
[subscreen_translation.x, subscreen_translation.y].as_ptr(),
);
gl::UniformMatrix2fv(
self.blit_vertex_array.blit_program.tex_transform_uniform,
1,
gl::FALSE,
IDENTITY_TRANSFORM.as_ptr(),
);
gl::Uniform2fv(
self.blit_vertex_array.blit_program.tex_translation_uniform,
1,
ZERO_TRANSLATION.as_ptr(),
);
gl::ActiveTexture(gl::TEXTURE0);
ck();
gl::BindTexture(
self.device.surface_gl_texture_target(),
self.device
.surface_texture_object(self.texture.as_ref().unwrap())
.map_or(0, |tex| tex.0.get()),
);
gl::Uniform1i(self.blit_vertex_array.blit_program.source_uniform, 0);
ck();
gl::Enable(gl::BLEND);
gl::BlendEquation(gl::FUNC_ADD);
gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
ck();
gl::Disable(gl::BLEND);
}
if present {
let mut surface = self
.device
.unbind_surface_from_context(&mut self.context)
.unwrap()
.unwrap();
self.device
.present_surface(&mut self.context, &mut surface)
.unwrap();
self.device
.bind_surface_to_context(&mut self.context, surface)
.unwrap();
}
}
}
fn worker_thread(
connection: Connection,
adapter: Adapter,
context_descriptor: ContextDescriptor,
window_size: Size2D<i32>,
resource_loader: Box<dyn ResourceLoader>,
worker_to_main_sender: Sender<Frame>,
worker_from_main_receiver: Receiver<Surface>,
) {
let size = Size2D::new(SUBSCREEN_WIDTH, SUBSCREEN_HEIGHT);
let surface_type = SurfaceType::Generic { size };
let device = connection.create_device(&adapter).unwrap();
let mut context = device.create_context(&context_descriptor, None).unwrap();
let surface = device
.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
.unwrap();
device
.bind_surface_to_context(&mut context, surface)
.unwrap();
device.make_context_current(&context).unwrap();
let vertex_array = CheckVertexArray::new(
device.gl_api(),
device.surface_gl_texture_target(),
&*resource_loader,
);
let ball_origin = Point2D::new(
window_size.width as f32 * 0.5 - BALL_WIDTH as f32 * 0.5,
window_size.height as f32 * 0.65 - BALL_HEIGHT as f32 * 0.5,
);
let ball_size = Size2D::new(BALL_WIDTH as f32, BALL_HEIGHT as f32);
let mut ball_rect = Rect::new(ball_origin, ball_size);
let mut ball_velocity = Vector2D::new(INITIAL_VELOCITY_X, INITIAL_VELOCITY_Y);
let subscreen_offset = (Point2D::new(SUBSCREEN_WIDTH as f32, SUBSCREEN_HEIGHT as f32)
- Point2D::new(BALL_WIDTH as f32, BALL_HEIGHT as f32))
* 0.5;
let mut theta_x = INITIAL_ROTATION_X;
let mut theta_y = INITIAL_ROTATION_Y;
let mut theta_z = INITIAL_ROTATION_Z;
let surface_type = SurfaceType::Generic { size };
let surface = Some(
device
.create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
.unwrap(),
);
worker_to_main_sender
.send(Frame {
surface,
viewport_origin: ball_rect.origin - subscreen_offset,
sphere_position: ball_rect.center(),
})
.unwrap();
loop {
unsafe {
let framebuffer_object = device
.context_surface_info(&context)
.unwrap()
.unwrap()
.framebuffer_object;
gl::BindFramebuffer(
gl::FRAMEBUFFER,
framebuffer_object.map_or(0, |fbo| fbo.0.get()),
);
gl::Viewport(0, 0, size.width, size.height);
gl::ClearColor(0.0, 0.0, 0.0, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
gl::BindVertexArray(vertex_array.object);
ck();
gl::UseProgram(vertex_array.check_program.program.object);
ck();
gl::UniformMatrix2fv(
vertex_array.check_program.transform_uniform,
1,
gl::FALSE,
NDC_TRANSFORM.as_ptr(),
);
gl::Uniform2fv(
vertex_array.check_program.translation_uniform,
1,
NDC_TRANSLATION.as_ptr(),
);
gl::UniformMatrix2fv(
vertex_array.check_program.tex_transform_uniform,
1,
gl::FALSE,
NDC_TRANSFORM.as_ptr(),
);
gl::Uniform2fv(
vertex_array.check_program.tex_translation_uniform,
1,
NDC_TRANSLATION.as_ptr(),
);
gl::Uniform3fv(
vertex_array.check_program.rotation_uniform,
1,
[theta_x, theta_y, theta_z].as_ptr(),
);
gl::Uniform4fv(
vertex_array.check_program.color_a_uniform,
1,
CHECK_COLOR_A.as_ptr(),
);
gl::Uniform4fv(
vertex_array.check_program.color_b_uniform,
1,
CHECK_COLOR_B.as_ptr(),
);
gl::Uniform2f(
vertex_array.check_program.viewport_origin_uniform,
ball_rect.origin.x - subscreen_offset.x,
ball_rect.origin.y - subscreen_offset.y,
);
gl::Uniform1f(vertex_array.check_program.radius_uniform, SPHERE_RADIUS);
gl::Uniform3fv(
vertex_array.check_program.camera_position_uniform,
1,
CAMERA_POSITION.as_ptr(),
);
gl::Uniform3fv(
vertex_array.check_program.light_position_uniform,
1,
LIGHT_POSITION.as_ptr(),
);
gl::Uniform2f(
vertex_array.check_program.sphere_position_uniform,
ball_rect.center().x,
ball_rect.center().y,
);
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
ck();
}
let old_surface = device.unbind_surface_from_context(&mut context).unwrap();
let new_surface = match worker_from_main_receiver.recv() {
Ok(surface) => surface,
Err(_) => break,
};
device
.bind_surface_to_context(&mut context, new_surface)
.unwrap();
worker_to_main_sender
.send(Frame {
surface: old_surface,
viewport_origin: ball_rect.origin - subscreen_offset,
sphere_position: ball_rect.center(),
})
.unwrap();
ball_velocity += Vector2D::new(0.0, GRAVITY);
ball_rect = ball_rect.translate(ball_velocity);
if ball_rect.origin.y <= 0.0 {
ball_rect.origin.y = 0.0;
ball_velocity.y = f32::abs(ball_velocity.y);
}
if ball_rect.origin.x <= 0.0 {
ball_rect.origin.x = 0.0;
ball_velocity.x = f32::abs(ball_velocity.x);
}
if ball_rect.max_x() >= window_size.width as f32 {
ball_rect.origin.x = (window_size.width - BALL_WIDTH) as f32;
ball_velocity.x = -f32::abs(ball_velocity.x);
}
theta_x += ROTATION_SPEED_X;
theta_y += ROTATION_SPEED_Y;
theta_z += ROTATION_SPEED_Z;
}
device.destroy_context(&mut context).unwrap();
}
struct Frame {
surface: Option<Surface>,
viewport_origin: Point2D<f32>,
sphere_position: Point2D<f32>,
}
struct BlitVertexArray {
object: GLuint,
blit_program: BlitProgram,
#[allow(dead_code)]
position_buffer: Buffer,
}
impl BlitVertexArray {
fn new(
gl_api: GLApi,
gl_texture_target: GLenum,
resource_loader: &dyn ResourceLoader,
) -> BlitVertexArray {
let blit_program = BlitProgram::new(gl_api, gl_texture_target, resource_loader);
unsafe {
let mut vertex_array = 0;
gl::GenVertexArrays(1, &mut vertex_array);
ck();
gl::BindVertexArray(vertex_array);
ck();
let position_buffer = Buffer::from_data(&QUAD_VERTEX_POSITIONS);
gl::BindBuffer(gl::ARRAY_BUFFER, position_buffer.object);
ck();
gl::VertexAttribPointer(
blit_program.position_attribute as GLuint,
2,
gl::UNSIGNED_BYTE,
gl::FALSE,
2,
0 as _,
);
ck();
gl::EnableVertexAttribArray(blit_program.position_attribute as GLuint);
ck();
BlitVertexArray {
object: vertex_array,
blit_program,
position_buffer,
}
}
}
}
struct GridVertexArray {
object: GLuint,
grid_program: GridProgram,
#[allow(dead_code)]
position_buffer: Buffer,
}
impl GridVertexArray {
fn new(
gl_api: GLApi,
gl_texture_target: GLenum,
resource_loader: &dyn ResourceLoader,
) -> GridVertexArray {
let grid_program = GridProgram::new(gl_api, gl_texture_target, resource_loader);
unsafe {
let mut vertex_array = 0;
gl::GenVertexArrays(1, &mut vertex_array);
ck();
gl::BindVertexArray(vertex_array);
ck();
let position_buffer = Buffer::from_data(&QUAD_VERTEX_POSITIONS);
gl::BindBuffer(gl::ARRAY_BUFFER, position_buffer.object);
ck();
gl::VertexAttribPointer(
grid_program.position_attribute as GLuint,
2,
gl::UNSIGNED_BYTE,
gl::FALSE,
2,
0 as _,
);
ck();
gl::EnableVertexAttribArray(grid_program.position_attribute as GLuint);
ck();
GridVertexArray {
object: vertex_array,
grid_program,
position_buffer,
}
}
}
}
struct CheckVertexArray {
object: GLuint,
check_program: CheckProgram,
#[allow(dead_code)]
position_buffer: Buffer,
}
impl CheckVertexArray {
fn new(
gl_api: GLApi,
gl_texture_target: GLenum,
resource_loader: &dyn ResourceLoader,
) -> CheckVertexArray {
let check_program = CheckProgram::new(gl_api, gl_texture_target, resource_loader);
unsafe {
let mut vertex_array = 0;
gl::GenVertexArrays(1, &mut vertex_array);
ck();
gl::BindVertexArray(vertex_array);
ck();
let position_buffer = Buffer::from_data(&QUAD_VERTEX_POSITIONS);
gl::BindBuffer(gl::ARRAY_BUFFER, position_buffer.object);
ck();
gl::VertexAttribPointer(
check_program.position_attribute as GLuint,
2,
gl::UNSIGNED_BYTE,
gl::FALSE,
2,
0 as _,
);
ck();
gl::EnableVertexAttribArray(check_program.position_attribute as GLuint);
ck();
CheckVertexArray {
object: vertex_array,
check_program,
position_buffer,
}
}
}
}
struct BlitProgram {
program: Program,
position_attribute: GLint,
transform_uniform: GLint,
translation_uniform: GLint,
tex_transform_uniform: GLint,
tex_translation_uniform: GLint,
source_uniform: GLint,
}
impl BlitProgram {
fn new(
gl_api: GLApi,
gl_texture_target: GLenum,
resource_loader: &dyn ResourceLoader,
) -> BlitProgram {
let vertex_shader = Shader::new(
"quad",
ShaderKind::Vertex,
gl_api,
gl_texture_target,
resource_loader,
);
let fragment_shader = Shader::new(
"blit",
ShaderKind::Fragment,
gl_api,
gl_texture_target,
resource_loader,
);
let program = Program::new(vertex_shader, fragment_shader);
unsafe {
let position_attribute =
gl::GetAttribLocation(program.object, c"aPosition".as_ptr().cast());
ck();
let transform_uniform =
gl::GetUniformLocation(program.object, c"uTransform".as_ptr().cast());
ck();
let translation_uniform =
gl::GetUniformLocation(program.object, c"uTranslation".as_ptr().cast());
ck();
let tex_transform_uniform =
gl::GetUniformLocation(program.object, c"uTexTransform".as_ptr().cast());
ck();
let tex_translation_uniform =
gl::GetUniformLocation(program.object, c"uTexTranslation".as_ptr().cast());
ck();
let source_uniform = gl::GetUniformLocation(program.object, c"uSource".as_ptr().cast());
ck();
BlitProgram {
program,
position_attribute,
transform_uniform,
translation_uniform,
tex_transform_uniform,
tex_translation_uniform,
source_uniform,
}
}
}
}
struct GridProgram {
program: Program,
position_attribute: GLint,
transform_uniform: GLint,
translation_uniform: GLint,
tex_transform_uniform: GLint,
tex_translation_uniform: GLint,
gridline_color_uniform: GLint,
bg_color_uniform: GLint,
radius_uniform: GLint,
sphere_position_uniform: GLint,
camera_position_uniform: GLint,
light_position_uniform: GLint,
}
impl GridProgram {
fn new(
gl_api: GLApi,
gl_texture_target: GLenum,
resource_loader: &dyn ResourceLoader,
) -> GridProgram {
let vertex_shader = Shader::new(
"quad",
ShaderKind::Vertex,
gl_api,
gl_texture_target,
resource_loader,
);
let fragment_shader = Shader::new(
"grid",
ShaderKind::Fragment,
gl_api,
gl_texture_target,
resource_loader,
);
let program = Program::new(vertex_shader, fragment_shader);
unsafe {
let position_attribute =
gl::GetAttribLocation(program.object, c"aPosition".as_ptr().cast());
ck();
let transform_uniform =
gl::GetUniformLocation(program.object, c"uTransform".as_ptr().cast());
ck();
let translation_uniform =
gl::GetUniformLocation(program.object, c"uTranslation".as_ptr().cast());
ck();
let tex_transform_uniform =
gl::GetUniformLocation(program.object, c"uTexTransform".as_ptr().cast());
ck();
let tex_translation_uniform =
gl::GetUniformLocation(program.object, c"uTexTranslation".as_ptr().cast());
ck();
let gridline_color_uniform =
gl::GetUniformLocation(program.object, c"uGridlineColor".as_ptr().cast());
ck();
let bg_color_uniform =
gl::GetUniformLocation(program.object, c"uBGColor".as_ptr().cast());
ck();
let radius_uniform = gl::GetUniformLocation(program.object, c"uRadius".as_ptr().cast());
ck();
let camera_position_uniform =
gl::GetUniformLocation(program.object, c"uCameraPosition".as_ptr().cast());
ck();
let light_position_uniform =
gl::GetUniformLocation(program.object, c"uLightPosition".as_ptr().cast());
ck();
let sphere_position_uniform =
gl::GetUniformLocation(program.object, c"uSpherePosition".as_ptr().cast());
ck();
GridProgram {
program,
position_attribute,
transform_uniform,
translation_uniform,
tex_transform_uniform,
tex_translation_uniform,
gridline_color_uniform,
bg_color_uniform,
radius_uniform,
camera_position_uniform,
light_position_uniform,
sphere_position_uniform,
}
}
}
}
struct CheckProgram {
program: Program,
position_attribute: GLint,
transform_uniform: GLint,
translation_uniform: GLint,
tex_transform_uniform: GLint,
tex_translation_uniform: GLint,
rotation_uniform: GLint,
color_a_uniform: GLint,
color_b_uniform: GLint,
viewport_origin_uniform: GLint,
radius_uniform: GLint,
camera_position_uniform: GLint,
light_position_uniform: GLint,
sphere_position_uniform: GLint,
}
impl CheckProgram {
fn new(
gl_api: GLApi,
gl_texture_target: GLenum,
resource_loader: &dyn ResourceLoader,
) -> CheckProgram {
let vertex_shader = Shader::new(
"quad",
ShaderKind::Vertex,
gl_api,
gl_texture_target,
resource_loader,
);
let fragment_shader = Shader::new(
"check",
ShaderKind::Fragment,
gl_api,
gl_texture_target,
resource_loader,
);
let program = Program::new(vertex_shader, fragment_shader);
unsafe {
let position_attribute =
gl::GetAttribLocation(program.object, c"aPosition".as_ptr().cast());
ck();
let transform_uniform =
gl::GetUniformLocation(program.object, c"uTransform".as_ptr().cast());
ck();
let translation_uniform =
gl::GetUniformLocation(program.object, c"uTranslation".as_ptr().cast());
ck();
let tex_transform_uniform =
gl::GetUniformLocation(program.object, c"uTexTransform".as_ptr().cast());
ck();
let tex_translation_uniform =
gl::GetUniformLocation(program.object, c"uTexTranslation".as_ptr().cast());
ck();
let rotation_uniform =
gl::GetUniformLocation(program.object, c"uRotation".as_ptr().cast());
ck();
let color_a_uniform =
gl::GetUniformLocation(program.object, c"uColorA".as_ptr().cast());
ck();
let color_b_uniform =
gl::GetUniformLocation(program.object, c"uColorB".as_ptr().cast());
ck();
let viewport_origin_uniform =
gl::GetUniformLocation(program.object, c"uViewportOrigin".as_ptr().cast());
ck();
let radius_uniform = gl::GetUniformLocation(program.object, c"uRadius".as_ptr().cast());
ck();
let camera_position_uniform =
gl::GetUniformLocation(program.object, c"uCameraPosition".as_ptr().cast());
ck();
let light_position_uniform =
gl::GetUniformLocation(program.object, c"uLightPosition".as_ptr().cast());
ck();
let sphere_position_uniform =
gl::GetUniformLocation(program.object, c"uSpherePosition".as_ptr().cast());
ck();
CheckProgram {
program,
position_attribute,
transform_uniform,
translation_uniform,
tex_transform_uniform,
tex_translation_uniform,
rotation_uniform,
color_a_uniform,
color_b_uniform,
viewport_origin_uniform,
radius_uniform,
light_position_uniform,
camera_position_uniform,
sphere_position_uniform,
}
}
}
}