Skip to content

Instantly share code, notes, and snippets.

@umurgdk
Created August 1, 2017 08:54
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 umurgdk/2814a7fea4ff93864577206908ca46db to your computer and use it in GitHub Desktop.
Save umurgdk/2814a7fea4ff93864577206908ca46db to your computer and use it in GitHub Desktop.
extern crate cgmath;
extern crate specs;
#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
// Logging
#[macro_use]
extern crate log;
extern crate log_panics;
#[cfg(target_os = "android")]
extern crate android_logger;
#[cfg(not(target_os = "android"))]
extern crate env_logger;
#[cfg(target_os = "android")]
extern crate android_glue;
use std::f32;
use std::time;
use cgmath::*;
use gfx::Factory;
use gfx::traits::FactoryExt;
use gfx::Device;
use gfx::handle::Buffer;
use gfx::IndexBuffer;
use glutin::GlContext;
type ColorFormat = gfx::format::Rgba8;
type DepthFormat = gfx::format::DepthStencil;
#[cfg(target_os = "android")]
const MAX_SPRITES: usize = 1_000;
#[cfg(not(target_os = "android"))]
const MAX_SPRITES: usize = 50_000;
const NUM_VERTICES: usize = MAX_SPRITES * 4;
const NUM_INDICES: usize = MAX_SPRITES * 6;
gfx_defines! {
vertex Vertex {
position: [f32; 2] = "a_pos",
color: [f32; 3] = "a_color",
}
constant Mvp {
model: [[f32; 4]; 4] = "u_model",
view: [[f32; 4]; 4] = "u_view",
projection: [[f32; 4]; 4] = "u_projection",
}
pipeline pipe {
vbuf: gfx::VertexBuffer<Vertex> = (),
model: gfx::Global<[[f32; 4]; 4]> = "u_model",
view: gfx::Global<[[f32; 4]; 4]> = "u_view",
projection: gfx::Global<[[f32; 4]; 4]> = "u_projection",
out: gfx::RenderTarget<ColorFormat> = "target0",
}
}
fn create_quad(pos: [f32; 2], size: [f32; 2], color: [f32; 3]) -> [Vertex; 4] {
[
Vertex { position: [pos[0], pos[1] + size[1]], color },
Vertex { position: [pos[0] + size[0], pos[1] + size[1]], color },
Vertex { position: [pos[0] + size[0], pos[1]], color },
Vertex { position: [pos[0], pos[1]], color },
]
}
fn get_dimensions(window: &glutin::GlWindow) -> (u32, u32) {
window.get_inner_size().expect("Failed to get window dimensions")
}
fn projection_from_window_dimensions(window: &glutin::GlWindow) -> [[f32; 4]; 4] {
let (width, height) = get_dimensions(window);
ortho(0.0, width as f32, 0.0, height as f32, -5.0, 5.0).into()
}
fn calculate_sprite_size(width: u32, num_columns: usize) -> (f32, f32) {
let sprite_gap = (width as f32 / num_columns as f32) / 2.0;
let sprite_size = width as f32 / num_columns as f32 - sprite_gap;
(sprite_size.max(5.0), sprite_gap.max(2.5))
}
fn transform_vertex(vertex: &mut Vertex, mat: &cgmath::Matrix4<f32>) {
let mut position = mat * vec4(vertex.position[0], vertex.position[1], 0.0, 1.0);
vertex.position[0] = position.x;
vertex.position[1] = position.y;
}
fn main() {
println!("hunger: main()");
#[cfg(target_os = "android")]
android_logger::init_once(log::LogLevel::Trace);
#[cfg(not(target_os = "android"))]
env_logger::init().expect("Failed to initialize env_logger");
println!("hunger: initializing log_panics");
info!("hunger: initializing log_panics");
error!("hunger: err initializing log_panics");
log_panics::init_namespace(Some("hunger"));
info!("Hunger start working...");
error!("Hunger start working...");
#[cfg(target_os = "android")]
android_glue::write_log("Creating event loop...");
info!("Creating event loop.");
let mut events_loop = glutin::EventsLoop::new();
// Initialize window
let (window, mut device, mut factory, main_color, mut main_depth) = {
let builder = glutin::WindowBuilder::new()
.with_title("Hunger")
.with_dimensions(1600, 1200);
let api_request = glutin::GlRequest::GlThenGles {
opengl_version: (3, 2),
opengles_version: (3, 0)
};
let context = glutin::ContextBuilder::new()
.with_vsync(true)
.with_gl(api_request);
gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop)
};
info!("Window created!");
// Initialize rendering
let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
let pso = factory.create_pipeline_simple(
include_bytes!("../assets/shaders/gles2/sprite.vert"),
include_bytes!("../assets/shaders/gles2/sprite.frag"),
pipe::new()
).expect("Failed to create pipeline state object");
info!("Pipeline created.");
let upload_buffer: Buffer<_, Vertex> = factory.create_upload_buffer(NUM_VERTICES)
.expect("Failed to create upload buffer");
let vertex_buffer: Buffer<_, Vertex> =
factory.create_buffer(
NUM_VERTICES,
gfx::buffer::Role::Vertex,
gfx::memory::Usage::Data,
gfx::TRANSFER_DST).unwrap();
let index_buffer: IndexBuffer<_> = {
let mut indices: Vec<u32> = vec![0u32; NUM_INDICES];
let mut vertex_offset = 0;
for quad in indices.as_mut_slice().chunks_mut(6) {
quad[0] = vertex_offset + 0;
quad[1] = vertex_offset + 3;
quad[2] = vertex_offset + 2;
quad[3] = vertex_offset + 0;
quad[4] = vertex_offset + 2;
quad[5] = vertex_offset + 1;
vertex_offset += 4;
}
factory.create_index_buffer(indices.as_slice())
};
let mut data = pipe::Data {
vbuf: vertex_buffer.clone(),
model: Matrix4::identity().into(),
view: Matrix4::identity().into(),
projection: projection_from_window_dimensions(&window),
out: main_color
};
// let mut mvp = Mvp {
// model: cgmath::Matrix4::identity().into(),
// view: cgmath::Matrix4::identity().into(),
// projection: projection_from_window_dimensions(&window),
// };
// encoder.update_constant_buffer(&data.mvp, &mvp);
let mut slice = gfx::Slice {
start: 0u32,
end: 0u32,
base_vertex: 0,
instances: None,
buffer: index_buffer
};
let mut num_sprites = 0usize;
let mut num_columns = 100usize;
let (mut sprite_size, mut sprite_gap) = {
let (width, _) = get_dimensions(&window);
calculate_sprite_size(width, num_columns)
};
let mut frames = 0;
let mut beginning = time::Instant::now();
let mut every_second = time::Instant::now();
let mut fast_time = time::Instant::now();
let mut t_time = 0.0f32;
let mut running = true;
info!("Game loop starting...");
while running {
info!("Polling events...");
events_loop.poll_events(|ev| {
if let glutin::Event::WindowEvent { event: glutin::WindowEvent::Closed, .. } = ev {
running = false;
} else if let glutin::Event::WindowEvent { event: glutin::WindowEvent::Resized(width, height), .. } = ev {
gfx_window_glutin::update_views(&window, &mut data.out, &mut main_depth);
data.projection = projection_from_window_dimensions(&window);
// encoder.update_constant_buffer(&data.mvp, &mvp);
let (width, _) = get_dimensions(&window);
let (size, gap) = calculate_sprite_size(width, num_columns);
sprite_size = size;
sprite_gap = gap;
}
});
// Each second
let now = time::Instant::now();
if now.duration_since(every_second).as_secs() >= 1 {
info!("FPS: {}", frames);
info!("Number of sprites: {}", num_sprites);
frames = 0;
every_second = now.clone();
}
if num_sprites < MAX_SPRITES - 10 {
num_sprites += 10;
}
if t_time < f32::MAX - 2.0 {
t_time += 0.16;
} else {
t_time = 0.0;
}
// Fill vertex buffer
info!("Going to fill the vertex buffer...");
{
// TODO: Implement ring buffers
// Fill upload buffer
{
info!("Creating upload buffer mapper...");
let mut writer = factory.write_mapping(&upload_buffer).unwrap();
let mut vertices: &mut [Vertex] = &mut writer;
info!("Writing some data into it...");
let mut vertex_index = 0;
for i in 0..num_sprites {
let col = (i % num_columns) as f32;
let row = (i as f32 / num_columns as f32).floor();
let position = [
col * sprite_size + col * sprite_gap,
row * sprite_size + row * sprite_gap
];
let mut quad_vertices = create_quad(position, [sprite_size, sprite_size], [1.0, 1.0, 1.0]);
let rotation = Matrix4::from_axis_angle(Vector3::unit_z(), Rad((0.05 * t_time).sin() * (f32::consts::PI * 2.0)));
transform_vertex(&mut quad_vertices[0], &rotation);
transform_vertex(&mut quad_vertices[1], &rotation);
transform_vertex(&mut quad_vertices[2], &rotation);
transform_vertex(&mut quad_vertices[3], &rotation);
vertices[vertex_index + 0] = quad_vertices[0];
vertices[vertex_index + 1] = quad_vertices[1];
vertices[vertex_index + 2] = quad_vertices[2];
vertices[vertex_index + 3] = quad_vertices[3];
vertex_index += 4;
info!("{} vertices written...", vertex_index);
}
}
// Copy upload buffer to vertex buffer
info!("Copying upload buffer to vertex buffer...");
encoder.copy_buffer(&upload_buffer, &vertex_buffer, 0, 0, (num_sprites * 4) as usize);
slice.end = num_sprites as u32 * 6;
}
info!("Clear, draw, swap...");
encoder.clear(&data.out, [0.1, 0.07, 0.01, 1.0]);
encoder.draw(&slice, &pso, &data);
encoder.flush(&mut device);
window.swap_buffers().unwrap();
device.cleanup();
frames += 1;
}
println!("Hello, world!");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment