@@ 1,4 1,6 @@
use std::collections::HashMap;
+use std::mem;
+use std::mem::swap;
use std::num::NonZeroU32;
use std::sync::Arc;
@@ 43,42 45,31 @@ use crate::platform::websocket::Ws;
use crate::ui::{draw_ui, init_ui};
use assets::AssetLoader;
use crate::networking::websocket::Websocket;
+use crate::rendering::MaybeRenderer::{Initialized, Initializing};
+use crate::rendering::renderer::{RenderCreateContext, Renderer};
pub mod assets;
+mod renderer;
+
+enum MaybeRenderer {
+ Uninitialized(RenderCreateContext),
+ Initializing,
+ Initialized(Renderer)
+}
-#[derive(Default)]
pub struct App {
window: Option<Window>,
world: World,
+ renderer: MaybeRenderer,
- program: Option<glow::Program>,
- vertex_array: Option<glow::VertexArray>,
- vertex_buffer: Option<glow::Buffer>,
- element_buffer: Option<glow::Buffer>,
#[cfg(not(target_arch = "wasm32"))]
gl_surface: Option<Surface<WindowSurface>>,
#[cfg(not(target_arch = "wasm32"))]
gl_context: Option<PossiblyCurrentContext>,
- egui_glow: Option<EguiGlow>,
gl: Option<Arc<glow::Context>>,
- textures: HashMap<String, glow::Texture>,
-
- send_packet_events: Events<SendPacket>,
- recv_packet_events: Events<RecvPacket>,
- planet_types: HashMap<PlanetType, (Entity, u32)>, // (world entity, server id)
-
- up: bool,
- down: bool,
- left: bool,
- right: bool,
-
- mouse_pos: PhysicalPosition<f64>,
}
-const VERTICES: [f32; 16] = [
- -1.0, -1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 0.0,
-];
-const INDICES: [u32; 6] = [0, 1, 2, 2, 3, 0];
+
impl App {
pub fn new(
@@ 87,10 78,18 @@ impl App {
recv_packet_events: Events<RecvPacket>,
) -> Self {
Self {
+ window: None,
world,
- send_packet_events,
- recv_packet_events,
- ..Default::default()
+ renderer: MaybeRenderer::Uninitialized(RenderCreateContext {
+ send_packet_events,
+ recv_packet_events,
+ planet_types: Default::default(),
+ }),
+ #[cfg(not(target_arch = "wasm32"))]
+ gl_context: None,
+ #[cfg(not(target_arch = "wasm32"))]
+ gl_surface: None,
+ gl: None,
}
}
}
@@ 210,87 209,7 @@ impl ApplicationHandler for App {
(Arc::new(gl), "#version 300 es")
};
- unsafe {
- let shaders = [
- (
- "vertex",
- include_str!("../assets/shaders/vertex.glsl"),
- glow::VERTEX_SHADER,
- ),
- (
- "fragment",
- include_str!("../assets/shaders/fragment.glsl"),
- glow::FRAGMENT_SHADER,
- ),
- ];
- let program = gl.create_program().expect("Failed to create program");
-
- for (name, source, shader_type) in shaders {
- let shader = gl
- .create_shader(shader_type)
- .expect("Failed to create vertex shader");
- gl.shader_source(shader, &format!("{}\n{}", shader_version, source));
- gl.compile_shader(shader);
- if !gl.get_shader_compile_status(shader) {
- tracing::error!(
- "error in {} shader: {}",
- name,
- gl.get_shader_info_log(shader)
- );
- }
- gl.attach_shader(program, shader);
- gl.delete_shader(shader);
- }
- gl.link_program(program);
-
- gl.use_program(Some(program));
-
- let vertex_array = gl
- .create_vertex_array()
- .expect("Failed to create vertex array");
- gl.bind_vertex_array(Some(vertex_array));
- let vertex_buffer = gl.create_buffer().expect("Failed to create vertex buffer");
- gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer));
- let element_buffer = gl.create_buffer().expect("Failed to create element buffer");
- gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(element_buffer));
- gl.buffer_data_u8_slice(
- glow::ARRAY_BUFFER,
- std::slice::from_raw_parts(VERTICES.as_ptr() as *const u8, size_of_val(&VERTICES)),
- glow::STATIC_DRAW,
- );
- gl.buffer_data_u8_slice(
- glow::ELEMENT_ARRAY_BUFFER,
- std::slice::from_raw_parts(INDICES.as_ptr() as *const u8, size_of_val(&INDICES)),
- glow::STATIC_DRAW,
- );
- gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 4 * size_of::<f32>() as i32, 0);
- gl.enable_vertex_attrib_array(0);
- gl.vertex_attrib_pointer_f32(
- 1,
- 2,
- glow::FLOAT,
- false,
- 4 * size_of::<f32>() as i32,
- 2 * size_of::<f32>() as i32,
- );
- gl.enable_vertex_attrib_array(1);
-
- gl.clear_color(0.1, 0.1, 0.1, 1.0);
- gl.viewport(
- 0,
- 0,
- window.inner_size().width as i32,
- window.inner_size().height as i32,
- );
- gl.enable(glow::BLEND);
- gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
-
- self.program = Some(program);
- self.vertex_array = Some(vertex_array);
- self.vertex_buffer = Some(vertex_buffer);
- self.element_buffer = Some(element_buffer);
- }
#[cfg(target_arch = "wasm32")]
web_sys::window().unwrap().set_onresize(Some(
Closure::<dyn Fn(Event)>::new(move |_| {
@@ 322,11 241,14 @@ impl ApplicationHandler for App {
.unchecked_ref(),
));
- let egui_glow = egui_glow::EguiGlow::new(event_loop, gl.clone(), None, None, true);
+ let mut rcc = Initializing;
+ swap(&mut self.renderer, &mut rcc);
+ let MaybeRenderer::Uninitialized(rcc) = rcc else { unreachable!() };
- init_ui(egui_glow.egui_ctx.clone());
+ let renderer = unsafe { Renderer::new(gl.clone(), event_loop, rcc) };
+
+ self.renderer = Initialized(renderer);
- self.egui_glow = Some(egui_glow);
self.gl = Some(gl);
}
fn window_event(
@@ 335,14 257,13 @@ impl ApplicationHandler for App {
_window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
- let event_response = self
- .egui_glow
- .as_mut()
- .unwrap()
- .on_window_event(self.window.as_ref().unwrap(), &event);
- if event_response.consumed {
- return;
+ let Initialized(renderer) = &mut self.renderer else {return};
+ let Some(window) = &self.window else { return };
+
+ if renderer.egui_glow.on_window_event(window, &event).consumed {
+ return; // egui ate it
}
+
match event {
WindowEvent::CloseRequested => {
event_loop.exit();
@@ 358,13 279,13 @@ impl ApplicationHandler for App {
let mut camera = self.world.get_resource_mut::<Camera>().unwrap();
camera.width = size.width;
camera.height = size.height;
-
+/*
unsafe {
self.gl
.as_ref()
.unwrap()
.viewport(0, 0, size.width as i32, size.height as i32);
- }
+ }*/
}
WindowEvent::MouseWheel { delta, .. } => {
let mut camera = self.world.get_resource_mut::<Camera>().unwrap();
@@ 386,57 307,57 @@ impl ApplicationHandler for App {
match event.state {
ElementState::Pressed => match key {
KeyCode::KeyW => {
- self.up = true;
+ renderer.up = true;
matched = true;
}
KeyCode::KeyS => {
- self.down = true;
+ renderer.down = true;
matched = true;
}
KeyCode::KeyA => {
- self.left = true;
+ renderer.left = true;
matched = true;
}
KeyCode::KeyD => {
- self.right = true;
+ renderer.right = true;
matched = true;
}
_ => matched = false,
},
ElementState::Released => match key {
KeyCode::KeyW => {
- self.up = false;
+ renderer.up = false;
matched = true;
}
KeyCode::KeyS => {
- self.down = false;
+ renderer.down = false;
matched = true;
}
KeyCode::KeyA => {
- self.left = false;
+ renderer.left = false;
matched = true;
}
KeyCode::KeyD => {
- self.right = false;
+ renderer.right = false;
matched = true;
}
_ => matched = false,
},
}
if matched {
- self.send_packet_events
+ renderer.send_packet_events
.send(SendPacket(Packet::PlayerInput {
- up: self.up,
- down: self.down,
- left: self.left,
- right: self.right,
+ up: renderer.up,
+ down: renderer.down,
+ left: renderer.left,
+ right: renderer.right,
}));
}
}
PhysicalKey::Unidentified(_) => {} // unsupported
}
}
- WindowEvent::CursorMoved { position, .. } => self.mouse_pos = position,
+ WindowEvent::CursorMoved { position, .. } => renderer.mouse_pos = position,
WindowEvent::MouseInput { state, button, .. } => {
let button = match button {
MouseButton::Left => ButtonType::Left,
@@ 459,9 380,9 @@ impl ApplicationHandler for App {
let camera = self.world.get_resource::<Camera>().unwrap();
let view = camera.to_cursor_matrix();
let pos =
- view * Vector3::new(self.mouse_pos.x as f32, self.mouse_pos.y as f32, 1.0);
+ view * Vector3::new(renderer.mouse_pos.x as f32, renderer.mouse_pos.y as f32, 1.0);
let pos = pos / pos.z;
- self.send_packet_events
+ renderer.send_packet_events
.send(SendPacket(Packet::PlayerMouseInput {
x: pos.x,
y: pos.y,
@@ 473,185 394,37 @@ impl ApplicationHandler for App {
}
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
+ let Initialized(renderer) = &mut self.renderer else { return };
+ let Some(window) = &self.window else { return };
+
let mut ws = self
.world
.get_resource_mut::<Ws>()
.expect("Failed to get Ws resource");
#[cfg(target_arch = "wasm32")]
while let Ok(Some(packet)) = ws.receiver.try_next() {
- self.recv_packet_events.send(RecvPacket(packet));
+ renderer.recv_packet_events.send(RecvPacket(packet));
}
#[cfg(not(target_arch = "wasm32"))]
while let Ok(packet) = ws.receiver.try_recv() {
- self.recv_packet_events.send(RecvPacket(packet));
+ renderer.recv_packet_events.send(RecvPacket(packet));
}
- self.send_packet_events.update();
- self.recv_packet_events.update();
+ renderer.send_packet_events.update();
+ renderer.recv_packet_events.update();
process_packets(
&mut self.world,
- &mut self.send_packet_events,
- &mut self.recv_packet_events,
- &mut self.planet_types,
+ &mut renderer.send_packet_events,
+ &mut renderer.recv_packet_events,
+ &mut renderer.planet_types,
);
let gl = self.gl.as_ref().unwrap();
-
- let player = self.world.query_filtered::<&Transform, With<Player>>();
-
- self.egui_glow
- .as_mut()
- .unwrap()
- .run(self.window.as_ref().unwrap(), |ctx| {
- draw_ui(ctx, &mut self.world, &mut self.send_packet_events);
- });
-
- let camera = self.world.get_resource::<Camera>().unwrap();
- let x_scale = camera.zoom / camera.width as f32 * 2.0;
- let y_scale = camera.zoom / camera.height as f32 * 2.0;
- let view = &[
- x_scale,
- 0.0,
- 0.0,
- camera.x * x_scale,
- 0.0,
- y_scale,
- 0.0,
- camera.y * y_scale,
- 0.0,
- 0.0,
- 1.0,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- 1.0,
- ];
-
- let mut sprite_query = self.world.query::<(&Transform, &mut Texture)>();
-
- let mut sprites = Vec::new();
- for (transform, texture) in sprite_query.iter(&self.world) {
- sprites.push((transform, texture));
- }
-
unsafe {
- gl.clear(glow::COLOR_BUFFER_BIT);
- gl.use_program(self.program);
- gl.bind_vertex_array(self.vertex_array);
- gl.bind_buffer(glow::ARRAY_BUFFER, self.vertex_buffer);
- gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, self.element_buffer);
- gl.active_texture(glow::TEXTURE0);
-
- let view_loc = gl.get_uniform_location(self.program.unwrap(), "view");
- let model_loc = gl.get_uniform_location(self.program.unwrap(), "model");
-
- gl.uniform_matrix_4_f32_slice(view_loc.as_ref(), true, view);
-
- if !self.textures.contains_key("starfield.svg") {
- let assets = self.world.resource::<crate::platform::assets::Assets>();
- match assets.get("starfield.svg") {
- Some(image) => {
- let texture_object = gl
- .create_texture()
- .expect("Failed to create texture object");
- gl.bind_texture(glow::TEXTURE_2D, Some(texture_object));
- gl.tex_parameter_i32(
- glow::TEXTURE_2D,
- glow::TEXTURE_MIN_FILTER,
- glow::LINEAR_MIPMAP_LINEAR as i32,
- );
- gl.tex_image_2d(
- glow::TEXTURE_2D,
- 0,
- glow::RGBA as i32,
- image.width as i32,
- image.height as i32,
- 0,
- glow::RGBA,
- glow::UNSIGNED_BYTE,
- PixelUnpackData::Slice(Some(&image.bytes)),
- );
- gl.generate_mipmap(glow::TEXTURE_2D);
-
- self.textures
- .insert("starfield.svg".to_string(), texture_object);
- }
- None => {}
- }
- }
- if self.textures.contains_key("starfield.svg") {
- gl.bind_texture(
- glow::TEXTURE_2D,
- self.textures.get("starfield.svg").copied(),
- );
-
- let camera = self.world.get_resource::<Camera>().unwrap();
- let x = -(camera.x + camera.x.signum() * 200.0) + camera.x % 400.0;
- let y = -(camera.y + camera.y.signum() * 200.0) + camera.y % 400.0;
- let x_range = camera.width as f32 / camera.zoom / 400.0;
- let y_range = camera.height as f32 / camera.zoom / 400.0;
- for i in ((-x_range / 2.0) as i32 - 1)..=((x_range / 2.0) as i32 + 1) {
- for j in ((-y_range / 2.0) as i32 - 1)..=((y_range / 2.0) as i32 + 1) {
- let model =
- Translation3::new(x + (i * 400) as f32, y + (j * 400) as f32, 0.0)
- .to_homogeneous()
- * Scale3::new(200.0, 200.0, 1.0).to_homogeneous();
- gl.uniform_matrix_4_f32_slice(model_loc.as_ref(), false, model.as_slice());
- gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0);
- }
- }
- }
-
- for (transform, texture) in sprites {
- if !self.textures.contains_key(&texture.name) {
- let assets = self.world.resource::<crate::platform::assets::Assets>();
- let image = match assets.get(texture.name.clone()) {
- Some(t) => t,
- None => continue,
- };
-
- let texture_object = gl
- .create_texture()
- .expect("Failed to create texture object");
- gl.bind_texture(glow::TEXTURE_2D, Some(texture_object));
- gl.tex_parameter_i32(
- glow::TEXTURE_2D,
- glow::TEXTURE_MIN_FILTER,
- glow::LINEAR_MIPMAP_LINEAR as i32,
- );
- gl.tex_image_2d(
- glow::TEXTURE_2D,
- 0,
- glow::RGBA as i32,
- image.width as i32,
- image.height as i32,
- 0,
- glow::RGBA,
- glow::UNSIGNED_BYTE,
- PixelUnpackData::Slice(Some(&image.bytes)),
- );
- gl.generate_mipmap(glow::TEXTURE_2D);
-
- self.textures.insert(texture.name.clone(), texture_object);
- }
- // now the texture must exist
-
- let model = transform.to_matrix();
- let model = model.as_slice();
- gl.uniform_matrix_4_f32_slice(model_loc.as_ref(), false, model);
-
- gl.bind_texture(glow::TEXTURE_2D, self.textures.get(&texture.name).copied());
- gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0);
- }
+ renderer.draw(gl, window, &mut self.world);
}
- self.egui_glow
- .as_mut()
- .unwrap()
- .paint(self.window.as_ref().unwrap());
-
#[cfg(not(target_arch = "wasm32"))]
self.gl_surface
.as_ref()
@@ 663,8 436,8 @@ impl ApplicationHandler for App {
.world
.get_resource_mut::<Ws>()
.expect("Failed to get Ws resource");
- let mut send_event_cursor = self.send_packet_events.get_cursor();
- for event in send_event_cursor.read(&self.send_packet_events) {
+ let mut send_event_cursor = renderer.send_packet_events.get_cursor();
+ for event in send_event_cursor.read(&renderer.send_packet_events) {
ws.send_packet(event.0.clone());
}
@@ 0,0 1,297 @@
+use std::collections::HashMap;
+use std::sync::Arc;
+use bevy_ecs::entity::Entity;
+use bevy_ecs::event::Events;
+use bevy_ecs::prelude::With;
+use bevy_ecs::world::World;
+use egui::Window;
+use egui_glow::EguiGlow;
+use glow::PixelUnpackData;
+use nalgebra::{Scale3, Translation3};
+use winit::dpi::PhysicalPosition;
+use winit::event_loop::ActiveEventLoop;
+use starkingdoms_common::PlanetType;
+use crate::components::{Camera, Player, RecvPacket, SendPacket, Texture, Transform};
+use crate::ui::draw_ui;
+use crate::rendering::assets::AssetLoader;
+
+pub struct Renderer {
+ program: glow::Program,
+ vertex_array: glow::VertexArray,
+ vertex_buffer: glow::Buffer,
+ element_buffer: glow::Buffer,
+ pub egui_glow: EguiGlow,
+ textures: HashMap<String, glow::Texture>,
+ pub(crate) send_packet_events: Events<SendPacket>,
+ pub(crate) recv_packet_events: Events<RecvPacket>,
+ pub(crate) planet_types: HashMap<PlanetType, (Entity, u32)>, // (world entity, server id)
+
+ pub(crate) up: bool,
+ pub(crate) down: bool,
+ pub(crate) left: bool,
+ pub(crate) right: bool,
+
+ pub(crate) mouse_pos: PhysicalPosition<f64>,
+}
+
+pub struct RenderCreateContext {
+ pub send_packet_events: Events<SendPacket>,
+ pub recv_packet_events: Events<RecvPacket>,
+ pub planet_types: HashMap<PlanetType, (Entity, u32)>
+}
+
+const VERTICES: [f32; 16] = [
+ -1.0, -1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 0.0,
+];
+const INDICES: [u32; 6] = [0, 1, 2, 2, 3, 0];
+
+impl Renderer {
+ pub unsafe fn new(gl: Arc<glow::Context>, event_loop: &ActiveEventLoop, ctx: RenderCreateContext) -> Self {
+ use glow::HasContext as _;
+
+ let shaders = [
+ (
+ "vertex",
+ include_str!("../assets/shaders/vertex.glsl"),
+ glow::VERTEX_SHADER,
+ ),
+ (
+ "fragment",
+ include_str!("../assets/shaders/fragment.glsl"),
+ glow::FRAGMENT_SHADER,
+ ),
+ ];
+ let program = gl.create_program().expect("Failed to create program");
+
+ for (name, source, shader_type) in shaders {
+ let shader = gl
+ .create_shader(shader_type)
+ .expect("Failed to create vertex shader");
+ gl.shader_source(shader, source);
+ gl.compile_shader(shader);
+ if !gl.get_shader_compile_status(shader) {
+ tracing::error!(
+ "error in {} shader: {}",
+ name,
+ gl.get_shader_info_log(shader)
+ );
+ }
+ gl.attach_shader(program, shader);
+ gl.delete_shader(shader);
+ }
+ gl.link_program(program);
+
+ gl.use_program(Some(program));
+
+ let vertex_array = gl
+ .create_vertex_array()
+ .expect("Failed to create vertex array");
+ gl.bind_vertex_array(Some(vertex_array));
+ let vertex_buffer = gl.create_buffer().expect("Failed to create vertex buffer");
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(vertex_buffer));
+ let element_buffer = gl.create_buffer().expect("Failed to create element buffer");
+ gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(element_buffer));
+ gl.buffer_data_u8_slice(
+ glow::ARRAY_BUFFER,
+ std::slice::from_raw_parts(VERTICES.as_ptr() as *const u8, size_of_val(&VERTICES)),
+ glow::STATIC_DRAW,
+ );
+ gl.buffer_data_u8_slice(
+ glow::ELEMENT_ARRAY_BUFFER,
+ std::slice::from_raw_parts(INDICES.as_ptr() as *const u8, size_of_val(&INDICES)),
+ glow::STATIC_DRAW,
+ );
+
+ gl.vertex_attrib_pointer_f32(0, 2, glow::FLOAT, false, 4 * size_of::<f32>() as i32, 0);
+ gl.enable_vertex_attrib_array(0);
+ gl.vertex_attrib_pointer_f32(
+ 1,
+ 2,
+ glow::FLOAT,
+ false,
+ 4 * size_of::<f32>() as i32,
+ 2 * size_of::<f32>() as i32,
+ );
+ gl.enable_vertex_attrib_array(1);
+
+ gl.clear_color(0.1, 0.1, 0.1, 1.0);
+ gl.enable(glow::BLEND);
+ gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
+
+
+ let egui_glow = EguiGlow::new(event_loop, gl.clone(), None, None, true);
+
+ crate::ui::init_ui(egui_glow.egui_ctx.clone());
+
+ Self {
+ program,
+ vertex_array,
+ vertex_buffer,
+ element_buffer,
+ egui_glow,
+ textures: HashMap::new(),
+ send_packet_events: ctx.send_packet_events,
+ recv_packet_events: ctx.recv_packet_events,
+ planet_types: ctx.planet_types,
+ left: false,
+ right: false,
+ up: false,
+ down: false,
+ mouse_pos: Default::default(),
+ }
+ }
+
+ pub unsafe fn draw(&mut self, gl: &glow::Context, window: &winit::window::Window, world: &mut World) {
+ use glow::HasContext as _;
+
+ let player = world.query_filtered::<&Transform, With<Player>>();
+
+ // draw the UI
+ self.egui_glow
+ .run(window, |ctx| {
+ draw_ui(ctx, &mut *world, &mut self.send_packet_events);
+ });
+
+ let camera = world.get_resource::<Camera>().unwrap();
+ let x_scale = camera.zoom / camera.width as f32 * 2.0;
+ let y_scale = camera.zoom / camera.height as f32 * 2.0;
+ let view = &[
+ x_scale,
+ 0.0,
+ 0.0,
+ camera.x * x_scale,
+ 0.0,
+ y_scale,
+ 0.0,
+ camera.y * y_scale,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ ];
+
+ let mut sprite_query = world.query::<(&Transform, &mut Texture)>();
+
+ let mut sprites = Vec::new();
+ for (transform, texture) in sprite_query.iter(&world) {
+ sprites.push((transform, texture));
+ }
+
+ gl.clear(glow::COLOR_BUFFER_BIT);
+ gl.use_program(Some(self.program));
+ gl.bind_vertex_array(Some(self.vertex_array));
+ gl.bind_buffer(glow::ARRAY_BUFFER, Some(self.vertex_buffer));
+ gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(self.element_buffer));
+ gl.active_texture(glow::TEXTURE0);
+
+ let view_loc = gl.get_uniform_location(self.program, "view");
+ let model_loc = gl.get_uniform_location(self.program, "model");
+
+ gl.uniform_matrix_4_f32_slice(view_loc.as_ref(), true, view);
+
+ if !self.textures.contains_key("starfield.svg") {
+ let assets = world.resource::<crate::platform::assets::Assets>();
+ match assets.get("starfield.svg") {
+ Some(image) => {
+ let texture_object = gl
+ .create_texture()
+ .expect("Failed to create texture object");
+ gl.bind_texture(glow::TEXTURE_2D, Some(texture_object));
+ gl.tex_parameter_i32(
+ glow::TEXTURE_2D,
+ glow::TEXTURE_MIN_FILTER,
+ glow::LINEAR_MIPMAP_LINEAR as i32,
+ );
+ gl.tex_image_2d(
+ glow::TEXTURE_2D,
+ 0,
+ glow::RGBA as i32,
+ image.width as i32,
+ image.height as i32,
+ 0,
+ glow::RGBA,
+ glow::UNSIGNED_BYTE,
+ PixelUnpackData::Slice(Some(&image.bytes)),
+ );
+ gl.generate_mipmap(glow::TEXTURE_2D);
+
+ self.textures
+ .insert("starfield.svg".to_string(), texture_object);
+ }
+ None => {}
+ }
+ }
+ if self.textures.contains_key("starfield.svg") {
+ gl.bind_texture(
+ glow::TEXTURE_2D,
+ self.textures.get("starfield.svg").copied(),
+ );
+
+ let camera = world.get_resource::<Camera>().unwrap();
+ let x = -(camera.x + camera.x.signum() * 200.0) + camera.x % 400.0;
+ let y = -(camera.y + camera.y.signum() * 200.0) + camera.y % 400.0;
+ let x_range = camera.width as f32 / camera.zoom / 400.0;
+ let y_range = camera.height as f32 / camera.zoom / 400.0;
+ for i in ((-x_range / 2.0) as i32 - 1)..=((x_range / 2.0) as i32 + 1) {
+ for j in ((-y_range / 2.0) as i32 - 1)..=((y_range / 2.0) as i32 + 1) {
+ let model =
+ Translation3::new(x + (i * 400) as f32, y + (j * 400) as f32, 0.0)
+ .to_homogeneous()
+ * Scale3::new(200.0, 200.0, 1.0).to_homogeneous();
+ gl.uniform_matrix_4_f32_slice(model_loc.as_ref(), false, model.as_slice());
+ gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0);
+ }
+ }
+ }
+
+ for (transform, texture) in sprites {
+ if !self.textures.contains_key(&texture.name) {
+ let assets = world.resource::<crate::platform::assets::Assets>();
+ let image = match assets.get(texture.name.clone()) {
+ Some(t) => t,
+ None => continue,
+ };
+
+ let texture_object = gl
+ .create_texture()
+ .expect("Failed to create texture object");
+ gl.bind_texture(glow::TEXTURE_2D, Some(texture_object));
+ gl.tex_parameter_i32(
+ glow::TEXTURE_2D,
+ glow::TEXTURE_MIN_FILTER,
+ glow::LINEAR_MIPMAP_LINEAR as i32,
+ );
+ gl.tex_image_2d(
+ glow::TEXTURE_2D,
+ 0,
+ glow::RGBA as i32,
+ image.width as i32,
+ image.height as i32,
+ 0,
+ glow::RGBA,
+ glow::UNSIGNED_BYTE,
+ PixelUnpackData::Slice(Some(&image.bytes)),
+ );
+ gl.generate_mipmap(glow::TEXTURE_2D);
+
+ self.textures.insert(texture.name.clone(), texture_object);
+ }
+ // now the texture must exist
+
+ let model = transform.to_matrix();
+ let model = model.as_slice();
+ gl.uniform_matrix_4_f32_slice(model_loc.as_ref(), false, model);
+
+ gl.bind_texture(glow::TEXTURE_2D, self.textures.get(&texture.name).copied());
+ gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0);
+ }
+
+ // paint UI
+ self.egui_glow
+ .paint(window);
+ }
+}<
\ No newline at end of file