mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Stop recreating vertex buffers for ui
Former-commit-id: 6e9326d1bca942e4da70281e3d86b624f9d2504a
This commit is contained in:
parent
a3d6e2eb90
commit
78fd9da4ce
voxygen/src
@ -10,7 +10,7 @@ mod util;
|
|||||||
pub use self::{
|
pub use self::{
|
||||||
consts::Consts,
|
consts::Consts,
|
||||||
mesh::{Mesh, Quad, Tri},
|
mesh::{Mesh, Quad, Tri},
|
||||||
model::Model,
|
model::{DynamicModel, Model},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
|
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
|
||||||
postprocess::{
|
postprocess::{
|
||||||
@ -40,6 +40,7 @@ pub enum RenderError {
|
|||||||
UpdateError(gfx::UpdateError<usize>),
|
UpdateError(gfx::UpdateError<usize>),
|
||||||
TexUpdateError(gfx::UpdateError<[u16; 3]>),
|
TexUpdateError(gfx::UpdateError<[u16; 3]>),
|
||||||
CombinedError(gfx::CombinedError),
|
CombinedError(gfx::CombinedError),
|
||||||
|
BufferCreationError(gfx::buffer::CreationError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to represent a specific rendering configuration.
|
/// Used to represent a specific rendering configuration.
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
// Library
|
use super::{gfx_backend, mesh::Mesh, Pipeline, RenderError};
|
||||||
use gfx::{self, traits::FactoryExt};
|
use gfx::{
|
||||||
|
buffer::Role,
|
||||||
// Local
|
memory::{Bind, Usage},
|
||||||
use super::{gfx_backend, mesh::Mesh, Pipeline};
|
traits::FactoryExt,
|
||||||
|
Factory,
|
||||||
|
};
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
/// Represents a mesh that has been sent to the GPU.
|
/// Represents a mesh that has been sent to the GPU.
|
||||||
pub struct Model<P: Pipeline> {
|
pub struct Model<P: Pipeline> {
|
||||||
@ -24,3 +27,43 @@ impl<P: Pipeline> Model<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a mesh on the GPU which can be updated dynamically
|
||||||
|
pub struct DynamicModel<P: Pipeline> {
|
||||||
|
pub vbuf: gfx::handle::Buffer<gfx_backend::Resources, P::Vertex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: Pipeline> DynamicModel<P> {
|
||||||
|
pub fn new(factory: &mut gfx_backend::Factory, size: usize) -> Result<Self, RenderError> {
|
||||||
|
Ok(Self {
|
||||||
|
vbuf: factory
|
||||||
|
.create_buffer(size, Role::Vertex, Usage::Dynamic, Bind::empty())
|
||||||
|
.map_err(|err| RenderError::BufferCreationError(err))?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a model with a slice of a portion of this model to send to the renderer
|
||||||
|
pub fn submodel(&self, range: Range<usize>) -> Model<P> {
|
||||||
|
Model {
|
||||||
|
vbuf: self.vbuf.clone(),
|
||||||
|
slice: gfx::Slice {
|
||||||
|
start: range.start as u32,
|
||||||
|
end: range.end as u32,
|
||||||
|
base_vertex: 0,
|
||||||
|
instances: None,
|
||||||
|
buffer: gfx::IndexBuffer::Auto,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
&self,
|
||||||
|
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||||
|
mesh: &Mesh<P>,
|
||||||
|
offset: usize,
|
||||||
|
) -> Result<(), RenderError> {
|
||||||
|
encoder
|
||||||
|
.update_buffer(&self.vbuf, mesh.vertices(), offset)
|
||||||
|
.map_err(|err| RenderError::UpdateError(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ use super::{
|
|||||||
consts::Consts,
|
consts::Consts,
|
||||||
gfx_backend,
|
gfx_backend,
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
model::Model,
|
model::{DynamicModel, Model},
|
||||||
pipelines::{figure, postprocess, skybox, terrain, ui, Globals},
|
pipelines::{figure, postprocess, skybox, terrain, ui, Globals},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
Pipeline, RenderError,
|
Pipeline, RenderError,
|
||||||
@ -12,7 +12,6 @@ use gfx::{
|
|||||||
handle::Sampler,
|
handle::Sampler,
|
||||||
traits::{Device, Factory, FactoryExt},
|
traits::{Device, Factory, FactoryExt},
|
||||||
};
|
};
|
||||||
use image;
|
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
/// Represents the format of the pre-processed color target.
|
/// Represents the format of the pre-processed color target.
|
||||||
@ -246,6 +245,24 @@ impl Renderer {
|
|||||||
Ok(Model::new(&mut self.factory, mesh))
|
Ok(Model::new(&mut self.factory, mesh))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new dynamic model with the specified size
|
||||||
|
pub fn create_dynamic_model<P: Pipeline>(
|
||||||
|
&mut self,
|
||||||
|
size: usize,
|
||||||
|
) -> Result<DynamicModel<P>, RenderError> {
|
||||||
|
DynamicModel::new(&mut self.factory, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update a dynamic model with a mesh and a offset
|
||||||
|
pub fn update_model<P: Pipeline>(
|
||||||
|
&mut self,
|
||||||
|
model: &DynamicModel<P>,
|
||||||
|
mesh: &Mesh<P>,
|
||||||
|
offset: usize,
|
||||||
|
) -> Result<(), RenderError> {
|
||||||
|
model.update(&mut self.encoder, mesh, offset)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new texture from the provided image.
|
/// Create a new texture from the provided image.
|
||||||
pub fn create_texture<P: Pipeline>(
|
pub fn create_texture<P: Pipeline>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -17,7 +17,8 @@ pub use widgets::toggle_button::ToggleButton;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
render::{
|
render::{
|
||||||
create_ui_quad, create_ui_tri, Mesh, Model, RenderError, Renderer, UiMode, UiPipeline,
|
create_ui_quad, create_ui_tri, DynamicModel, Mesh, RenderError, Renderer, UiMode,
|
||||||
|
UiPipeline,
|
||||||
},
|
},
|
||||||
window::Window,
|
window::Window,
|
||||||
Error,
|
Error,
|
||||||
@ -36,6 +37,7 @@ use conrod_core::{
|
|||||||
};
|
};
|
||||||
use graphic::Id as GraphicId;
|
use graphic::Id as GraphicId;
|
||||||
use scale::Scale;
|
use scale::Scale;
|
||||||
|
use std::ops::Range;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use util::{linear_to_srgb, srgb_to_linear};
|
use util::{linear_to_srgb, srgb_to_linear};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
@ -51,23 +53,20 @@ enum DrawKind {
|
|||||||
Plain,
|
Plain,
|
||||||
}
|
}
|
||||||
enum DrawCommand {
|
enum DrawCommand {
|
||||||
Draw {
|
Draw { kind: DrawKind, verts: Range<usize> },
|
||||||
kind: DrawKind,
|
|
||||||
model: Model<UiPipeline>,
|
|
||||||
},
|
|
||||||
Scissor(Aabr<u16>),
|
Scissor(Aabr<u16>),
|
||||||
}
|
}
|
||||||
impl DrawCommand {
|
impl DrawCommand {
|
||||||
fn image(model: Model<UiPipeline>) -> DrawCommand {
|
fn image(verts: Range<usize>) -> DrawCommand {
|
||||||
DrawCommand::Draw {
|
DrawCommand::Draw {
|
||||||
kind: DrawKind::Image,
|
kind: DrawKind::Image,
|
||||||
model,
|
verts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn plain(model: Model<UiPipeline>) -> DrawCommand {
|
fn plain(verts: Range<usize>) -> DrawCommand {
|
||||||
DrawCommand::Draw {
|
DrawCommand::Draw {
|
||||||
kind: DrawKind::Plain,
|
kind: DrawKind::Plain,
|
||||||
model,
|
verts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,6 +86,8 @@ pub struct Ui {
|
|||||||
cache: Cache,
|
cache: Cache,
|
||||||
// Draw commands for the next render
|
// Draw commands for the next render
|
||||||
draw_commands: Vec<DrawCommand>,
|
draw_commands: Vec<DrawCommand>,
|
||||||
|
// Model for drawing the ui
|
||||||
|
model: DynamicModel<UiPipeline>,
|
||||||
// Stores new window size for updating scaling
|
// Stores new window size for updating scaling
|
||||||
window_resized: Option<Vec2<f64>>,
|
window_resized: Option<Vec2<f64>>,
|
||||||
// Scaling of the ui
|
// Scaling of the ui
|
||||||
@ -102,8 +103,9 @@ impl Ui {
|
|||||||
ui: UiBuilder::new(win_dims).build(),
|
ui: UiBuilder::new(win_dims).build(),
|
||||||
image_map: Map::new(),
|
image_map: Map::new(),
|
||||||
cache: Cache::new(window.renderer_mut())?,
|
cache: Cache::new(window.renderer_mut())?,
|
||||||
window_resized: None,
|
|
||||||
draw_commands: vec![],
|
draw_commands: vec![],
|
||||||
|
model: window.renderer_mut().create_dynamic_model(100)?,
|
||||||
|
window_resized: None,
|
||||||
scale,
|
scale,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -192,9 +194,12 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn maintain(&mut self, renderer: &mut Renderer) {
|
pub fn maintain(&mut self, renderer: &mut Renderer) {
|
||||||
let ref mut ui = self.ui;
|
|
||||||
// Regenerate draw commands and associated models only if the ui changed
|
// Regenerate draw commands and associated models only if the ui changed
|
||||||
if let Some(mut primitives) = ui.draw_if_changed() {
|
let mut primitives = match self.ui.draw_if_changed() {
|
||||||
|
Some(primitives) => primitives,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
self.draw_commands.clear();
|
self.draw_commands.clear();
|
||||||
let mut mesh = Mesh::new();
|
let mut mesh = Mesh::new();
|
||||||
|
|
||||||
@ -206,6 +211,7 @@ impl Ui {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut current_state = State::Plain;
|
let mut current_state = State::Plain;
|
||||||
|
let mut start = 0;
|
||||||
|
|
||||||
let window_scizzor = default_scissor(renderer);
|
let window_scizzor = default_scissor(renderer);
|
||||||
let mut current_scizzor = window_scizzor;
|
let mut current_scizzor = window_scizzor;
|
||||||
@ -216,9 +222,9 @@ impl Ui {
|
|||||||
() => {
|
() => {
|
||||||
if let State::Image = current_state {
|
if let State::Image = current_state {
|
||||||
self.draw_commands
|
self.draw_commands
|
||||||
.push(DrawCommand::image(renderer.create_model(&mesh).unwrap()));
|
.push(DrawCommand::image(start..mesh.vertices().len()));
|
||||||
mesh.clear();
|
|
||||||
current_state = State::Plain;
|
current_state = State::Plain;
|
||||||
|
start = mesh.vertices().len();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -239,8 +245,8 @@ impl Ui {
|
|||||||
// Calculate minimum x and y coordinates while
|
// Calculate minimum x and y coordinates while
|
||||||
// - flipping y axis (from +up to +down)
|
// - flipping y axis (from +up to +down)
|
||||||
// - moving origin to top-left corner (from middle)
|
// - moving origin to top-left corner (from middle)
|
||||||
let min_x = ui.win_w / 2.0 + l;
|
let min_x = self.ui.win_w / 2.0 + l;
|
||||||
let min_y = ui.win_h / 2.0 - b - h;
|
let min_y = self.ui.win_h / 2.0 - b - h;
|
||||||
Aabr {
|
Aabr {
|
||||||
min: Vec2 {
|
min: Vec2 {
|
||||||
x: (min_x * p_scale_factor) as u16,
|
x: (min_x * p_scale_factor) as u16,
|
||||||
@ -256,10 +262,10 @@ impl Ui {
|
|||||||
if new_scizzor != current_scizzor {
|
if new_scizzor != current_scizzor {
|
||||||
// Finish the current command
|
// Finish the current command
|
||||||
self.draw_commands.push(match current_state {
|
self.draw_commands.push(match current_state {
|
||||||
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
State::Plain => DrawCommand::plain(start..mesh.vertices().len()),
|
||||||
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
State::Image => DrawCommand::image(start..mesh.vertices().len()),
|
||||||
});
|
});
|
||||||
mesh.clear();
|
start = mesh.vertices().len();
|
||||||
|
|
||||||
// Update the scizzor and produce a command.
|
// Update the scizzor and produce a command.
|
||||||
current_scizzor = new_scizzor;
|
current_scizzor = new_scizzor;
|
||||||
@ -267,8 +273,10 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Functions for converting for conrod scalar coords to GL vertex coords (-1.0 to 1.0)
|
// Functions for converting for conrod scalar coords to GL vertex coords (-1.0 to 1.0)
|
||||||
let vx = |x: f64| (x / ui.win_w * 2.0) as f32;
|
let ui_win_w = self.ui.win_w;
|
||||||
let vy = |y: f64| (y / ui.win_h * 2.0) as f32;
|
let ui_win_h = self.ui.win_h;
|
||||||
|
let vx = |x: f64| (x / ui_win_w * 2.0) as f32;
|
||||||
|
let vy = |y: f64| (y / ui_win_h * 2.0) as f32;
|
||||||
let gl_aabr = |rect: conrod_core::Rect| {
|
let gl_aabr = |rect: conrod_core::Rect| {
|
||||||
let (l, r, b, t) = rect.l_r_b_t();
|
let (l, r, b, t) = rect.l_r_b_t();
|
||||||
Aabr {
|
Aabr {
|
||||||
@ -298,14 +306,13 @@ impl Ui {
|
|||||||
// Switch to the image state if we are not in it already
|
// Switch to the image state if we are not in it already
|
||||||
if let State::Plain = current_state {
|
if let State::Plain = current_state {
|
||||||
self.draw_commands
|
self.draw_commands
|
||||||
.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
|
.push(DrawCommand::plain(start..mesh.vertices().len()));
|
||||||
mesh.clear();
|
start = mesh.vertices().len();
|
||||||
current_state = State::Image;
|
current_state = State::Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
let color = srgb_to_linear(
|
let color =
|
||||||
color.unwrap_or(conrod_core::color::WHITE).to_fsa().into(),
|
srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into());
|
||||||
);
|
|
||||||
|
|
||||||
let resolution = Vec2::new(
|
let resolution = Vec2::new(
|
||||||
(rect.w() * p_scale_factor) as u16,
|
(rect.w() * p_scale_factor) as u16,
|
||||||
@ -356,12 +363,7 @@ impl Ui {
|
|||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
mesh.push_quad(create_ui_quad(
|
mesh.push_quad(create_ui_quad(gl_aabr(rect), uv_aabr, color, UiMode::Image));
|
||||||
gl_aabr(rect),
|
|
||||||
uv_aabr,
|
|
||||||
color,
|
|
||||||
UiMode::Image,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
PrimitiveKind::Text {
|
PrimitiveKind::Text {
|
||||||
color,
|
color,
|
||||||
@ -373,7 +375,7 @@ impl Ui {
|
|||||||
let (screen_w, screen_h) =
|
let (screen_w, screen_h) =
|
||||||
renderer.get_resolution().map(|e| e as f32).into_tuple();
|
renderer.get_resolution().map(|e| e as f32).into_tuple();
|
||||||
// Calculate dpi factor
|
// Calculate dpi factor
|
||||||
let dpi_factor = screen_w / ui.win_w as f32;
|
let dpi_factor = screen_w / ui_win_w as f32;
|
||||||
|
|
||||||
let positioned_glyphs = text.positioned_glyphs(dpi_factor);
|
let positioned_glyphs = text.positioned_glyphs(dpi_factor);
|
||||||
let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex();
|
let (glyph_cache, cache_tex) = self.cache.glyph_cache_mut_and_tex();
|
||||||
@ -453,8 +455,7 @@ impl Ui {
|
|||||||
let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
|
let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
|
||||||
let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
|
let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
|
||||||
// If triangle is clockwise reverse it
|
// If triangle is clockwise reverse it
|
||||||
let (v1, v2): (Vec3<f32>, Vec3<f32>) =
|
let (v1, v2): (Vec3<f32>, Vec3<f32>) = ((p2 - p1).into(), (p3 - p1).into());
|
||||||
((p2 - p1).into(), (p3 - p1).into());
|
|
||||||
let triangle = if v1.cross(v2).z > 0.0 {
|
let triangle = if v1.cross(v2).z > 0.0 {
|
||||||
[p1.into_array(), p2.into_array(), p3.into_array()]
|
[p1.into_array(), p2.into_array(), p3.into_array()]
|
||||||
} else {
|
} else {
|
||||||
@ -476,10 +477,19 @@ impl Ui {
|
|||||||
}
|
}
|
||||||
// Enter the final command
|
// Enter the final command
|
||||||
self.draw_commands.push(match current_state {
|
self.draw_commands.push(match current_state {
|
||||||
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
State::Plain => DrawCommand::plain(start..mesh.vertices().len()),
|
||||||
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
State::Image => DrawCommand::image(start..mesh.vertices().len()),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// create a larger dynamic model if the mesh is larger than the current model size
|
||||||
|
if self.model.vbuf.len() < mesh.vertices().len() {
|
||||||
|
self.model = renderer
|
||||||
|
.create_dynamic_model(mesh.vertices().len() * 4 / 3)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
renderer.update_model(&self.model, &mesh, 0).unwrap();
|
||||||
|
// Update model with new mesh
|
||||||
|
|
||||||
// Handle window resizing
|
// Handle window resizing
|
||||||
if let Some(new_dims) = self.window_resized.take() {
|
if let Some(new_dims) = self.window_resized.take() {
|
||||||
self.scale.window_resized(new_dims, renderer);
|
self.scale.window_resized(new_dims, renderer);
|
||||||
@ -495,7 +505,6 @@ impl Ui {
|
|||||||
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference
|
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(&self, renderer: &mut Renderer) {
|
pub fn render(&self, renderer: &mut Renderer) {
|
||||||
let mut scissor = default_scissor(renderer);
|
let mut scissor = default_scissor(renderer);
|
||||||
@ -504,11 +513,12 @@ impl Ui {
|
|||||||
DrawCommand::Scissor(scizzor) => {
|
DrawCommand::Scissor(scizzor) => {
|
||||||
scissor = *scizzor;
|
scissor = *scizzor;
|
||||||
}
|
}
|
||||||
DrawCommand::Draw { kind, model } => {
|
DrawCommand::Draw { kind, verts } => {
|
||||||
let tex = match kind {
|
let tex = match kind {
|
||||||
DrawKind::Image => self.cache.graphic_cache_tex(),
|
DrawKind::Image => self.cache.graphic_cache_tex(),
|
||||||
DrawKind::Plain => self.cache.glyph_cache_tex(),
|
DrawKind::Plain => self.cache.glyph_cache_tex(),
|
||||||
};
|
};
|
||||||
|
let model = self.model.submodel(verts.clone());
|
||||||
renderer.render_ui_element(&model, &tex, scissor);
|
renderer.render_ui_element(&model, &tex, scissor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user