mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
Merge branch 'FyroxEngine:master' into tile-anim
This commit is contained in:
@@ -19,6 +19,7 @@ lazy_static = "1.4.0"
|
||||
ron = "0.8.0"
|
||||
serde = "^1.0.0"
|
||||
toml = { version = "0.8.10", default-features = false, features = ["parse"] }
|
||||
toml_edit = "0.22.6"
|
||||
strum = "0.26.1"
|
||||
strum_macros = "0.26.1"
|
||||
open = "5"
|
||||
|
||||
+29
-5
@@ -169,21 +169,39 @@ use plugins::inspector::InspectorPlugin;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::VecDeque,
|
||||
io::{BufRead, BufReader},
|
||||
io::{BufRead, BufReader, Cursor, Read},
|
||||
path::{Path, PathBuf},
|
||||
process::Stdio,
|
||||
rc::Rc,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::{self, channel, Receiver},
|
||||
Arc,
|
||||
Arc, LazyLock,
|
||||
},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use toml_edit::DocumentMut;
|
||||
|
||||
pub const FIXED_TIMESTEP: f32 = 1.0 / 60.0;
|
||||
pub const MSG_SYNC_FLAG: u64 = 1;
|
||||
|
||||
static EDITOR_VERSION: LazyLock<String> = LazyLock::new(|| {
|
||||
let manifest = include_bytes!("../Cargo.toml");
|
||||
let mut file = Cursor::new(&manifest);
|
||||
let mut toml = String::new();
|
||||
if file.read_to_string(&mut toml).is_ok() {
|
||||
if let Ok(document) = toml.parse::<DocumentMut>() {
|
||||
if let Some(package) = document.get("package").and_then(|i| i.as_table()) {
|
||||
if let Some(version) = package.get("version") {
|
||||
return version.to_string().replace('\"', "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"<unknown>".to_string()
|
||||
});
|
||||
|
||||
pub fn send_sync_message(ui: &UserInterface, mut msg: UiMessage) {
|
||||
msg.flags = MSG_SYNC_FLAG;
|
||||
ui.send_message(msg);
|
||||
@@ -559,6 +577,10 @@ pub struct Editor {
|
||||
|
||||
impl Editor {
|
||||
pub fn new(startup_data: Option<StartupData>) -> Self {
|
||||
// Useful for debugging purposes when users don't bother to mention editor version
|
||||
// they're using.
|
||||
Log::info(format!("Editor version: {}", &*EDITOR_VERSION));
|
||||
|
||||
let (log_message_sender, log_message_receiver) = channel();
|
||||
|
||||
Log::add_listener(log_message_sender);
|
||||
@@ -2065,9 +2087,11 @@ impl Editor {
|
||||
|
||||
let graphics_context = engine.graphics_context.as_initialized_mut();
|
||||
|
||||
graphics_context
|
||||
.window
|
||||
.set_title(&format!("Fyroxed: {}", working_directory.to_string_lossy()));
|
||||
graphics_context.window.set_title(&format!(
|
||||
"FyroxEd {}: {}",
|
||||
*EDITOR_VERSION,
|
||||
working_directory.to_string_lossy()
|
||||
));
|
||||
|
||||
match FileSystemWatcher::new(&working_directory, Duration::from_secs(1)) {
|
||||
Ok(watcher) => {
|
||||
|
||||
@@ -86,6 +86,7 @@ impl BuildWindow {
|
||||
let window = WindowBuilder::new(WidgetBuilder::new().with_width(420.0).with_height(200.0))
|
||||
.can_minimize(false)
|
||||
.can_close(false)
|
||||
.can_maximize(false)
|
||||
.open(false)
|
||||
.with_content(
|
||||
GridBuilder::new(
|
||||
@@ -96,12 +97,17 @@ impl BuildWindow {
|
||||
.with_child(
|
||||
TextBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_margin(Thickness::uniform(1.0))
|
||||
.with_margin(Thickness {
|
||||
left: 5.0,
|
||||
top: 1.0,
|
||||
right: 1.0,
|
||||
bottom: 1.0,
|
||||
})
|
||||
.on_column(0),
|
||||
)
|
||||
.with_text(format!(
|
||||
"Please wait while {project_name} is building... Build Log:"
|
||||
))
|
||||
"Please wait while {project_name} is building..."
|
||||
))
|
||||
.build(ctx),
|
||||
)
|
||||
.with_child({
|
||||
|
||||
@@ -249,3 +249,24 @@ impl Log {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! info {
|
||||
($($arg:tt)*) => {
|
||||
$crate::log::Log::info(format!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! warn {
|
||||
($($arg:tt)*) => {
|
||||
$crate::log::Log::warn(format!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! err {
|
||||
($($arg:tt)*) => {
|
||||
$crate::log::Log::err(format!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
+15
-11
@@ -40,6 +40,7 @@ use crate::{
|
||||
Complex, Const, Matrix, Matrix2, Matrix3, Matrix4, Quaternion, RawStorage, RawStorageMut,
|
||||
SVector, Scalar, UnitComplex, UnitQuaternion, Vector2, Vector3, Vector4, U1,
|
||||
},
|
||||
array_as_u8_slice_mut,
|
||||
io::{self, FileLoadError},
|
||||
pool::{Handle, Pool},
|
||||
replace_slashes,
|
||||
@@ -540,24 +541,27 @@ impl_field_data!(Vector4<u64>, FieldKind::Vector4U64);
|
||||
|
||||
impl<T> Visit for BinaryBlob<'_, T>
|
||||
where
|
||||
T: Copy,
|
||||
T: Copy + bytemuck::Pod,
|
||||
{
|
||||
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
|
||||
if visitor.reading {
|
||||
if let Some(field) = visitor.find_field(name) {
|
||||
match &field.kind {
|
||||
FieldKind::BinaryBlob(data) => {
|
||||
let mut bytes = std::mem::ManuallyDrop::new(data.clone());
|
||||
let len = data.len() / size_of::<T>();
|
||||
let mut vec = Vec::<T>::with_capacity(len);
|
||||
|
||||
// SAFETY: This is kinda safe, but may cause portability issues because of various byte order.
|
||||
// However it seems to be fine, since big-endian is pretty much dead and unused nowadays.
|
||||
*self.vec = unsafe {
|
||||
Vec::from_raw_parts(
|
||||
bytes.as_mut_ptr() as *mut T,
|
||||
bytes.len() / std::mem::size_of::<T>(),
|
||||
bytes.capacity() / std::mem::size_of::<T>(),
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
data.as_ptr(),
|
||||
array_as_u8_slice_mut(&mut vec).as_mut_ptr(),
|
||||
data.len(),
|
||||
);
|
||||
|
||||
vec.set_len(len);
|
||||
}
|
||||
|
||||
*self.vec = vec;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -18,49 +18,108 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
//! Buffer is a type-agnostic data storage located directly in GPU memory. It could be considered
|
||||
//! as a data block which content is a pile of bytes, whose meaning is defined externally.
|
||||
|
||||
use crate::error::FrameworkError;
|
||||
use bytemuck::Pod;
|
||||
use fyrox_core::{array_as_u8_slice, array_as_u8_slice_mut};
|
||||
use std::any::Any;
|
||||
|
||||
/// GPU buffer kind.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub enum BufferKind {
|
||||
/// Vertex buffer. It is used to supply vertex data (such as positions, normals, texture
|
||||
/// coordinates, etc.) to GPU.
|
||||
Vertex,
|
||||
/// Index buffer. It is used to describe how vertices forms specific types of primitives.
|
||||
/// For example a quad could be described by a set of 4 vertices, but 2 triangles which in their
|
||||
/// turn consists of 6 indices (0,1,2,0,2,3 vertex indices).
|
||||
Index,
|
||||
/// Uniform buffer. It is used to supply context-specific data that is needed for rendering.
|
||||
/// Usually it contains data that changes from frame-to-frame (world transform, color, etc.).
|
||||
Uniform,
|
||||
/// Pixel read buffer. It is a special buffer that is used to asynchronously read-back data
|
||||
/// from GPU.
|
||||
PixelRead,
|
||||
/// Pixel write buffer. It is a special buffer that is used to write some data to GPU
|
||||
/// asynchronously.
|
||||
PixelWrite,
|
||||
}
|
||||
|
||||
/// A hint for video driver that allows it to optimize buffer's content for more efficient use.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub enum BufferUsage {
|
||||
/// The buffer contents will be modified once and used at most a few times.
|
||||
/// The buffer contents are modified by the application, and used as the source for
|
||||
/// drawing and image specification commands.
|
||||
StreamDraw,
|
||||
/// The buffer contents will be modified once and used at most a few times.
|
||||
/// The buffer contents are modified by reading data from the GPU, and used to return that
|
||||
/// data when queried by the application.
|
||||
StreamRead,
|
||||
/// The buffer contents will be modified once and used at most a few times.
|
||||
/// The buffer contents are modified by the application, and used as the source for
|
||||
/// drawing and image specification commands.
|
||||
StreamCopy,
|
||||
/// The buffer contents will be modified once and used many times.
|
||||
/// The buffer contents are modified by the application, and used as the source for
|
||||
/// drawing and image specification commands.
|
||||
StaticDraw,
|
||||
/// The buffer contents will be modified once and used many times.
|
||||
/// The buffer contents are modified by reading data from the GPU, and used to return that
|
||||
/// data when queried by the application.
|
||||
StaticRead,
|
||||
/// The buffer contents will be modified once and used many times.
|
||||
/// The buffer contents are modified by reading data from the GPU, and used as the source for
|
||||
/// drawing and image specification commands.
|
||||
StaticCopy,
|
||||
/// The buffer contents will be modified repeatedly and used many times.
|
||||
/// The buffer contents are modified by the application, and used as the source for
|
||||
/// drawing and image specification commands.
|
||||
DynamicDraw,
|
||||
/// The buffer contents will be modified repeatedly and used many times.
|
||||
/// The buffer contents are modified by reading data from the GPU, and used to return that
|
||||
/// data when queried by the application.
|
||||
DynamicRead,
|
||||
/// The buffer contents will be modified repeatedly and used many times.
|
||||
/// The buffer contents are modified by reading data from the GPU, and used as the source for
|
||||
/// drawing and image specification commands.
|
||||
DynamicCopy,
|
||||
}
|
||||
|
||||
/// Buffer is a type-agnostic data storage located directly in GPU memory. It could be considered
|
||||
/// as a data block which content is a pile of bytes, whose meaning is defined externally.
|
||||
pub trait Buffer: Any {
|
||||
/// Downcasts self reference as reference to [`Any`].
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
/// Downcasts self reference as reference to [`Any`].
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
/// Returns usage kind of the buffer.
|
||||
fn usage(&self) -> BufferUsage;
|
||||
/// Returns buffer kind.
|
||||
fn kind(&self) -> BufferKind;
|
||||
/// Returns total size of the buffer in bytes.
|
||||
fn size(&self) -> usize;
|
||||
/// Writes an arbitrary number of bytes from the given slice.
|
||||
fn write_data(&self, data: &[u8]) -> Result<(), FrameworkError>;
|
||||
/// Read an arbitrary number of bytes from the buffer (GPU memory) to the given slice. The
|
||||
/// amount of the data that will be attempted to read is defined by the length of the given
|
||||
/// slice.
|
||||
fn read_data(&self, data: &mut [u8]) -> Result<(), FrameworkError>;
|
||||
}
|
||||
|
||||
impl dyn Buffer {
|
||||
/// Tries to write typed data to the buffer. The data type must implement [`Pod`] trait for
|
||||
/// safe usage.
|
||||
pub fn write_data_of_type<T: Pod>(&self, data: &[T]) -> Result<(), FrameworkError> {
|
||||
let data = array_as_u8_slice(data);
|
||||
Buffer::write_data(self, data)
|
||||
}
|
||||
|
||||
/// Tries to read data from the buffer and convert them to the given type. The data type must
|
||||
/// implement [`Pod`] trait for safe usage. The amount of the data that will be attempted to
|
||||
/// read is defined by the length of the given slice.
|
||||
pub fn read_data_of_type<T: Pod>(&self, data: &mut [T]) -> Result<(), FrameworkError> {
|
||||
let data = array_as_u8_slice_mut(data);
|
||||
Buffer::read_data(self, data)
|
||||
|
||||
@@ -83,6 +83,7 @@ pub struct VertexBufferDescriptor<'a> {
|
||||
pub struct GeometryBufferDescriptor<'a> {
|
||||
pub element_kind: ElementKind,
|
||||
pub buffers: &'a [VertexBufferDescriptor<'a>],
|
||||
pub usage: BufferUsage,
|
||||
}
|
||||
|
||||
pub trait GeometryBuffer {
|
||||
|
||||
@@ -18,17 +18,16 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::geometry_buffer::{AttributeKind, GeometryBuffer, GeometryBufferDescriptor};
|
||||
use crate::{
|
||||
buffer::{Buffer, BufferKind, BufferUsage},
|
||||
buffer::{Buffer, BufferKind},
|
||||
core::{array_as_u8_slice, math::TriangleDefinition},
|
||||
error::FrameworkError,
|
||||
geometry_buffer::{AttributeKind, GeometryBuffer, GeometryBufferDescriptor},
|
||||
gl::{buffer::GlBuffer, server::GlGraphicsServer, ToGlConstant},
|
||||
ElementKind,
|
||||
};
|
||||
use glow::HasContext;
|
||||
use std::any::Any;
|
||||
use std::{cell::Cell, marker::PhantomData, rc::Weak};
|
||||
use std::{any::Any, cell::Cell, marker::PhantomData, rc::Weak};
|
||||
|
||||
impl AttributeKind {
|
||||
fn gl_type(self) -> u32 {
|
||||
@@ -61,7 +60,7 @@ impl GlGeometryBuffer {
|
||||
|
||||
server.set_vertex_array_object(Some(vao));
|
||||
|
||||
let element_buffer = GlBuffer::new(server, 0, BufferKind::Index, BufferUsage::StaticDraw)?;
|
||||
let element_buffer = GlBuffer::new(server, 0, BufferKind::Index, desc.usage)?;
|
||||
|
||||
let mut buffers = Vec::new();
|
||||
for buffer in desc.buffers {
|
||||
|
||||
+130
-53
@@ -40,6 +40,7 @@ pub mod server;
|
||||
pub mod stats;
|
||||
pub mod uniform;
|
||||
|
||||
/// A set of possible polygon filling modes.
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
@@ -55,20 +56,21 @@ pub mod uniform;
|
||||
EnumString,
|
||||
VariantNames,
|
||||
TypeUuidProvider,
|
||||
Default,
|
||||
)]
|
||||
#[type_uuid(id = "47aff01a-7daa-427c-874c-87464a7ffe28")]
|
||||
pub enum PolygonFillMode {
|
||||
/// Only vertices of polygons are rendered. Their size is 1px by default.
|
||||
Point,
|
||||
/// Only edges of polygons are rendered using 1px lines. This mode is useful for wireframe
|
||||
/// drawing.
|
||||
Line,
|
||||
/// The entire polygon surface is rendered. This is default rendering mode.
|
||||
#[default]
|
||||
Fill,
|
||||
}
|
||||
|
||||
impl Default for PolygonFillMode {
|
||||
fn default() -> Self {
|
||||
Self::Fill
|
||||
}
|
||||
}
|
||||
|
||||
/// A function used to compare two values. Usually it is used for depth and stencil testing.
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
@@ -85,6 +87,7 @@ impl Default for PolygonFillMode {
|
||||
AsRefStr,
|
||||
EnumString,
|
||||
VariantNames,
|
||||
Default,
|
||||
)]
|
||||
pub enum CompareFunc {
|
||||
/// Never passes.
|
||||
@@ -97,6 +100,7 @@ pub enum CompareFunc {
|
||||
Equal,
|
||||
|
||||
/// Passes if the incoming value is less than or equal to the stored value.
|
||||
#[default]
|
||||
LessOrEqual,
|
||||
|
||||
/// Passes if the incoming value is greater than the stored value.
|
||||
@@ -112,12 +116,7 @@ pub enum CompareFunc {
|
||||
Always,
|
||||
}
|
||||
|
||||
impl Default for CompareFunc {
|
||||
fn default() -> Self {
|
||||
Self::LessOrEqual
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a set values (per color) for blending operation.
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
@@ -134,8 +133,10 @@ impl Default for CompareFunc {
|
||||
AsRefStr,
|
||||
EnumString,
|
||||
VariantNames,
|
||||
Default,
|
||||
)]
|
||||
pub enum BlendFactor {
|
||||
#[default]
|
||||
Zero,
|
||||
One,
|
||||
SrcColor,
|
||||
@@ -157,29 +158,38 @@ pub enum BlendFactor {
|
||||
OneMinusSrc1Alpha,
|
||||
}
|
||||
|
||||
impl Default for BlendFactor {
|
||||
fn default() -> Self {
|
||||
Self::Zero
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines an operation used in blending equation.
|
||||
#[derive(
|
||||
Copy, Clone, Hash, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize, Visit, Debug, Reflect,
|
||||
Copy,
|
||||
Clone,
|
||||
Hash,
|
||||
PartialOrd,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Ord,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Visit,
|
||||
Debug,
|
||||
Reflect,
|
||||
Default,
|
||||
)]
|
||||
pub enum BlendMode {
|
||||
/// Addition of two operands (`Source + Dest`). This is default operation.
|
||||
#[default]
|
||||
Add,
|
||||
/// Subtraction of two operands (`Source - Dest`).
|
||||
Subtract,
|
||||
/// Reverse subtraction of two operands (`Dest - Source`).
|
||||
ReverseSubtract,
|
||||
/// Per-component min function of two operands (`min(Source, Dest)`).
|
||||
Min,
|
||||
/// Per-component max function of two operands (`max(Source, Dest)`).
|
||||
Max,
|
||||
}
|
||||
|
||||
impl Default for BlendMode {
|
||||
fn default() -> Self {
|
||||
Self::Add
|
||||
}
|
||||
}
|
||||
|
||||
/// An equation used for blending a source pixel color with the destination color (the one that is
|
||||
/// already in a frame buffer). This equation has different modes for rgb/alpha parts.
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
@@ -196,21 +206,33 @@ impl Default for BlendMode {
|
||||
Reflect,
|
||||
)]
|
||||
pub struct BlendEquation {
|
||||
/// An operation for RGB part.
|
||||
pub rgb: BlendMode,
|
||||
/// An operation for alpha part.
|
||||
pub alpha: BlendMode,
|
||||
}
|
||||
|
||||
/// Blending function defines sources of data for both operands in blending equation (separately
|
||||
/// for RGB and Alpha parts). Default blending function is replacing destination values with the
|
||||
/// source ones.
|
||||
#[derive(
|
||||
Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash, Serialize, Deserialize, Visit, Debug, Reflect,
|
||||
)]
|
||||
pub struct BlendFunc {
|
||||
/// Data for source (the value that is produced by a shader) in the blending equation (RGB part).
|
||||
pub sfactor: BlendFactor,
|
||||
/// Data for destination (the value that is already in a frame buffer) in the blending equation
|
||||
/// (RGB part).
|
||||
pub dfactor: BlendFactor,
|
||||
/// Data for source (the value that is produced by a shader) in the blending equation (alpha part).
|
||||
pub alpha_sfactor: BlendFactor,
|
||||
/// Data for destination (the value that is already in a frame buffer) in the blending equation
|
||||
/// (alpha part).
|
||||
pub alpha_dfactor: BlendFactor,
|
||||
}
|
||||
|
||||
impl BlendFunc {
|
||||
/// Creates a new blending function where both RGB and Alpha parts have the same blending factor.
|
||||
pub fn new(sfactor: BlendFactor, dfactor: BlendFactor) -> Self {
|
||||
Self {
|
||||
sfactor,
|
||||
@@ -220,6 +242,7 @@ impl BlendFunc {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new blending function where RGB and Alpha parts have different blending factor.
|
||||
pub fn new_separate(
|
||||
sfactor: BlendFactor,
|
||||
dfactor: BlendFactor,
|
||||
@@ -246,13 +269,19 @@ impl Default for BlendFunc {
|
||||
}
|
||||
}
|
||||
|
||||
/// A mask that defines which colors will be stored in a frame buffer during rendering operation.
|
||||
/// By default, all colors are stored (every field is set to `true`).
|
||||
#[derive(
|
||||
Copy, Clone, PartialOrd, PartialEq, Hash, Debug, Serialize, Deserialize, Visit, Eq, Reflect,
|
||||
)]
|
||||
pub struct ColorMask {
|
||||
/// A flag, that defines whether the red channel is written or not in a frame buffer.
|
||||
pub red: bool,
|
||||
/// A flag, that defines whether the green channel is written or not in a frame buffer.
|
||||
pub green: bool,
|
||||
/// A flag, that defines whether the blue channel is written or not in a frame buffer.
|
||||
pub blue: bool,
|
||||
/// A flag, that defines whether the alpha channel is written or not in a frame buffer.
|
||||
pub alpha: bool,
|
||||
}
|
||||
|
||||
@@ -268,6 +297,7 @@ impl Default for ColorMask {
|
||||
}
|
||||
|
||||
impl ColorMask {
|
||||
/// Creates a new color mask where all the components will have the specified value.
|
||||
pub fn all(value: bool) -> Self {
|
||||
Self {
|
||||
red: value,
|
||||
@@ -278,6 +308,8 @@ impl ColorMask {
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a polygon face that will be rendered. This is usually used for back face culling.
|
||||
/// Default value is [`PolygonFace::FrontAndBack`].
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
@@ -292,25 +324,32 @@ impl ColorMask {
|
||||
AsRefStr,
|
||||
EnumString,
|
||||
VariantNames,
|
||||
Default,
|
||||
)]
|
||||
pub enum PolygonFace {
|
||||
/// Only front faces will be rendered.
|
||||
Front,
|
||||
/// Only back faces will be rendered.
|
||||
Back,
|
||||
/// Both, back and front faces will be rendered.
|
||||
#[default]
|
||||
FrontAndBack,
|
||||
}
|
||||
|
||||
impl Default for PolygonFace {
|
||||
fn default() -> Self {
|
||||
Self::FrontAndBack
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines a function that used in a stencil test.
|
||||
#[derive(
|
||||
Copy, Clone, PartialOrd, PartialEq, Hash, Debug, Serialize, Deserialize, Visit, Eq, Reflect,
|
||||
)]
|
||||
pub struct StencilFunc {
|
||||
/// A function that is used to compare two values. Default value is [`CompareFunc::Always`].
|
||||
pub func: CompareFunc,
|
||||
/// Reference value that is used to compare against the current value in the stencil buffer.
|
||||
/// Default value is 0.
|
||||
pub ref_value: u32,
|
||||
/// A mask value that is used to filter out some bits (using logical AND operation) of a value
|
||||
/// in the stencil buffer and the ref value (for example if a [`CompareFunc::Less`] is used
|
||||
/// then the entire equation will look like `(ref & mask) < (stencil & mask)`). Default value
|
||||
/// is `0xFFFFFFFF`.
|
||||
pub mask: u32,
|
||||
}
|
||||
|
||||
@@ -324,6 +363,7 @@ impl Default for StencilFunc {
|
||||
}
|
||||
}
|
||||
|
||||
/// An action with the stencil value in the stencil buffer is the stencil test passed.
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
@@ -339,9 +379,11 @@ impl Default for StencilFunc {
|
||||
AsRefStr,
|
||||
EnumString,
|
||||
VariantNames,
|
||||
Default,
|
||||
)]
|
||||
pub enum StencilAction {
|
||||
/// Keeps the current value.
|
||||
/// Keeps the current value. This is the default variant.
|
||||
#[default]
|
||||
Keep,
|
||||
|
||||
/// Sets the stencil buffer value to 0.
|
||||
@@ -372,19 +414,19 @@ pub enum StencilAction {
|
||||
Invert,
|
||||
}
|
||||
|
||||
impl Default for StencilAction {
|
||||
fn default() -> Self {
|
||||
Self::Keep
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of actions that will be performed with the stencil buffer during various testing stages.
|
||||
#[derive(
|
||||
Copy, Clone, PartialOrd, PartialEq, Hash, Debug, Serialize, Deserialize, Visit, Eq, Reflect,
|
||||
)]
|
||||
pub struct StencilOp {
|
||||
/// An action that happens when the stencil test has failed.
|
||||
pub fail: StencilAction,
|
||||
/// An action that happens when the depth test has failed.
|
||||
pub zfail: StencilAction,
|
||||
/// An action that happens when the depth test has passed.
|
||||
pub zpass: StencilAction,
|
||||
/// A mask that is used to filter out some bits (using `AND` logical operation) from the source
|
||||
/// value before writing it to the stencil buffer.
|
||||
pub write_mask: u32,
|
||||
}
|
||||
|
||||
@@ -399,43 +441,70 @@ impl Default for StencilOp {
|
||||
}
|
||||
}
|
||||
|
||||
/// A face side to cull.
|
||||
#[derive(
|
||||
Copy, Clone, PartialOrd, PartialEq, Hash, Debug, Serialize, Deserialize, Visit, Eq, Reflect,
|
||||
Copy,
|
||||
Clone,
|
||||
PartialOrd,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Debug,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Visit,
|
||||
Eq,
|
||||
Reflect,
|
||||
Default,
|
||||
)]
|
||||
pub enum CullFace {
|
||||
/// Cull only back faces.
|
||||
#[default]
|
||||
Back,
|
||||
/// Cull only front faces.
|
||||
Front,
|
||||
}
|
||||
|
||||
impl Default for CullFace {
|
||||
fn default() -> Self {
|
||||
Self::Back
|
||||
}
|
||||
}
|
||||
|
||||
/// Blending parameters (such as blending function and its equation).
|
||||
#[derive(Serialize, Deserialize, Default, Visit, Debug, PartialEq, Clone, Eq, Reflect)]
|
||||
pub struct BlendParameters {
|
||||
/// Blending function, see [`BlendFunc`] for more info.
|
||||
pub func: BlendFunc,
|
||||
/// Blending equation, see [`BlendEquation`] for more info.
|
||||
pub equation: BlendEquation,
|
||||
}
|
||||
|
||||
/// A rectangular area that defines which pixels will be rendered in a frame buffer or not.
|
||||
#[derive(Serialize, Deserialize, Default, Visit, Debug, PartialEq, Clone, Copy, Eq, Reflect)]
|
||||
pub struct ScissorBox {
|
||||
/// X coordinate of the box's origin.
|
||||
pub x: i32,
|
||||
/// Y coordinate of the box's origin. Located at the bottom of the rectangle.
|
||||
pub y: i32,
|
||||
/// Width of the box.
|
||||
pub width: i32,
|
||||
/// Height of the box.
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
/// A set of drawing parameters, that are used during draw call. It defines pretty much all pipeline
|
||||
/// settings all at once.
|
||||
#[derive(Serialize, Deserialize, Visit, Debug, PartialEq, Clone, Eq, Reflect)]
|
||||
pub struct DrawParameters {
|
||||
/// An optional cull face. If [`None`], then the culling is disabled.
|
||||
pub cull_face: Option<CullFace>,
|
||||
/// Color write mask.
|
||||
pub color_write: ColorMask,
|
||||
/// A flag, that defines whether the depth values should be written to the depth buffer or not.
|
||||
pub depth_write: bool,
|
||||
/// Stencil test options. If [`None`], then the stencil test is disabled.
|
||||
pub stencil_test: Option<StencilFunc>,
|
||||
/// Depth test options. If [`None`], then the depth test is disabled.
|
||||
pub depth_test: Option<CompareFunc>,
|
||||
/// Blending options. If [`None`], then the blending is disabled.
|
||||
pub blend: Option<BlendParameters>,
|
||||
/// Stencil operation.
|
||||
pub stencil_op: StencilOp,
|
||||
/// Optional scissor box. If [`None`], then the scissor test is disabled.
|
||||
pub scissor_box: Option<ScissorBox>,
|
||||
}
|
||||
|
||||
@@ -454,22 +523,30 @@ impl Default for DrawParameters {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
/// A range of elements (usually it's triangles) to draw in a draw call.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
|
||||
pub enum ElementRange {
|
||||
/// All available elements. This is the default option.
|
||||
#[default]
|
||||
Full,
|
||||
Specific { offset: usize, count: usize },
|
||||
}
|
||||
|
||||
impl Default for ElementRange {
|
||||
fn default() -> Self {
|
||||
Self::Full
|
||||
}
|
||||
/// Specific range of elements. Useful if you have a large buffer that contains multiple smaller
|
||||
/// elements at once.
|
||||
Specific {
|
||||
/// Offset (in elements) from the beginning of the buffer.
|
||||
offset: usize,
|
||||
/// Total count of elements to draw.
|
||||
count: usize,
|
||||
},
|
||||
}
|
||||
|
||||
/// Element kind of geometry.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ElementKind {
|
||||
/// Triangles.
|
||||
Triangle,
|
||||
/// Lines.
|
||||
Line,
|
||||
/// Points.
|
||||
Point,
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
//! Graphics server is an abstraction layer over various graphics APIs used on different platforms
|
||||
//! supported by the engine.
|
||||
|
||||
use crate::gpu_texture::{
|
||||
GpuTextureKind, MagnificationFilter, MinificationFilter, PixelKind, WrapMode,
|
||||
};
|
||||
@@ -39,6 +44,7 @@ use std::{
|
||||
rc::{Rc, Weak},
|
||||
};
|
||||
|
||||
/// Graphics server capabilities.
|
||||
#[derive(Debug)]
|
||||
pub struct ServerCapabilities {
|
||||
/// The maximum size in basic machine units of a uniform block, which must be at least 16384.
|
||||
@@ -50,32 +56,65 @@ pub struct ServerCapabilities {
|
||||
pub max_lod_bias: f32,
|
||||
}
|
||||
|
||||
/// A shared reference to a graphics server.
|
||||
pub type SharedGraphicsServer = Rc<dyn GraphicsServer>;
|
||||
|
||||
/// Graphics server is an abstraction layer over various graphics APIs used on different platforms
|
||||
/// supported by the engine. Such abstraction layer tries to provide more or less high-level and
|
||||
/// unified interface, that can be used to build graphics pipelines quickly and more or less efficiently.
|
||||
///
|
||||
/// Low-level GAPI-specific optimizations could be performed using direct access to the underlying API,
|
||||
/// by downcasting to a specific type.
|
||||
pub trait GraphicsServer: Any {
|
||||
/// Downcasts self reference as reference to [`Any`].
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
||||
/// Downcasts self reference as reference to [`Any`].
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
/// Creates a GPU buffer with the given size and kind. Usage is a hint to the video driver
|
||||
/// that allows to perform some potential performance optimizations.
|
||||
fn create_buffer(
|
||||
&self,
|
||||
size: usize,
|
||||
buffer_kind: BufferKind,
|
||||
buffer_usage: BufferUsage,
|
||||
) -> Result<Box<dyn Buffer>, FrameworkError>;
|
||||
|
||||
/// Creates a new GPU texture using the given descriptor.
|
||||
fn create_texture(
|
||||
&self,
|
||||
desc: GpuTextureDescriptor,
|
||||
) -> Result<Rc<RefCell<dyn GpuTexture>>, FrameworkError>;
|
||||
|
||||
/// Creates a new frame buffer using the given depth and color attachments. Depth attachment
|
||||
/// not exist, but there must be at least one color attachment of a format that supports rendering.
|
||||
fn create_frame_buffer(
|
||||
&self,
|
||||
depth_attachment: Option<Attachment>,
|
||||
color_attachments: Vec<Attachment>,
|
||||
) -> Result<Box<dyn FrameBuffer>, FrameworkError>;
|
||||
|
||||
/// Creates a frame buffer that "connected" to the final image that will be displayed to the
|
||||
/// screen.
|
||||
fn back_buffer(&self) -> Box<dyn FrameBuffer>;
|
||||
|
||||
/// Creates a new GPU query, that can perform asynchronous data fetching from GPU. Usually it
|
||||
/// is used to create occlusion queries.
|
||||
fn create_query(&self) -> Result<Box<dyn Query>, FrameworkError>;
|
||||
|
||||
/// Creates a new named GPU program using a pair of vertex and fragment shaders. The name could
|
||||
/// be used for debugging purposes.
|
||||
fn create_program(
|
||||
&self,
|
||||
name: &str,
|
||||
vertex_source: &str,
|
||||
fragment_source: &str,
|
||||
) -> Result<Box<dyn GpuProgram>, FrameworkError>;
|
||||
|
||||
/// Almost the same as [`Self::create_program`], but accepts additional array of resource
|
||||
/// definitions. The implementation of graphics server will generate proper resource bindings
|
||||
/// in the shader code for you.
|
||||
fn create_program_with_properties(
|
||||
&self,
|
||||
name: &str,
|
||||
@@ -83,26 +122,58 @@ pub trait GraphicsServer: Any {
|
||||
fragment_source: &str,
|
||||
properties: &[ShaderResourceDefinition],
|
||||
) -> Result<Box<dyn GpuProgram>, FrameworkError>;
|
||||
|
||||
/// Creates a new read-back buffer, that can be used to obtain texture data from GPU. It can be
|
||||
/// used to read rendering result from GPU to CPU memory and save the result to disk.
|
||||
fn create_async_read_buffer(
|
||||
&self,
|
||||
pixel_size: usize,
|
||||
pixel_count: usize,
|
||||
) -> Result<Box<dyn AsyncReadBuffer>, FrameworkError>;
|
||||
|
||||
/// Creates a new geometry buffer, which consists of one or more vertex buffers and only one
|
||||
/// element buffer. Geometry buffer could be considered as a complex mesh storage allocated on
|
||||
/// GPU.
|
||||
fn create_geometry_buffer(
|
||||
&self,
|
||||
desc: GeometryBufferDescriptor,
|
||||
) -> Result<Box<dyn GeometryBuffer>, FrameworkError>;
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
/// Creates a weak reference to the shared graphics server.
|
||||
fn weak(self: Rc<Self>) -> Weak<dyn GraphicsServer>;
|
||||
|
||||
/// Sends all scheduled GPU command buffers for execution on GPU without waiting for a certain
|
||||
/// threshold.
|
||||
fn flush(&self);
|
||||
|
||||
/// Waits until all the scheduled GPU commands are fully executed. This is blocking operation, and
|
||||
/// it blocks the current thread until all the commands are fully executed.
|
||||
fn finish(&self);
|
||||
|
||||
/// Unbinds the all bound resources from the graphics pipeline.
|
||||
fn invalidate_resource_bindings_cache(&self);
|
||||
|
||||
/// Returns GPU pipeline statistics. See [`PipelineStatistics`] for more info.
|
||||
fn pipeline_statistics(&self) -> PipelineStatistics;
|
||||
|
||||
/// Swaps the front and back buffers and thus presenting the final image on screen. There could
|
||||
/// be more than two buffers, and it is up to the graphics server implementation to choose the
|
||||
/// right amount, but it can't be less than two.
|
||||
fn swap_buffers(&self) -> Result<(), FrameworkError>;
|
||||
|
||||
/// Notifies the graphics server that the size of the back buffer has changed. It has very limited
|
||||
/// use and there are very few platforms (Linux with Wayland mostly) that needs this function to
|
||||
/// be called.
|
||||
fn set_frame_size(&self, new_size: (u32, u32));
|
||||
|
||||
/// Returns current capabilities of the graphics server. See [`ServerCapabilities`] for more info.
|
||||
fn capabilities(&self) -> ServerCapabilities;
|
||||
|
||||
/// Sets current polygon fill mode. See [`PolygonFace`] and [`PolygonFillMode`] docs for more info.
|
||||
fn set_polygon_fill_mode(&self, polygon_face: PolygonFace, polygon_fill_mode: PolygonFillMode);
|
||||
|
||||
/// A shortcut for [`Self::create_texture`], that creates a rectangular texture with the given
|
||||
/// size and pixel kind.
|
||||
fn create_2d_render_target(
|
||||
&self,
|
||||
pixel_kind: PixelKind,
|
||||
|
||||
@@ -1467,7 +1467,11 @@ impl Engine {
|
||||
params: params.clone(),
|
||||
});
|
||||
|
||||
self.sound_engine.initialize_audio_output_device()?;
|
||||
if let Err(err) = self.sound_engine.initialize_audio_output_device() {
|
||||
Log::err(format!(
|
||||
"Unable to initialize audio output device! Reason: {err:?}"
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
|
||||
@@ -125,6 +125,7 @@ impl DebugRenderer {
|
||||
],
|
||||
data: VertexBufferData::new::<Vertex>(None),
|
||||
}],
|
||||
usage: BufferUsage::DynamicDraw,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
|
||||
@@ -78,6 +78,7 @@ impl GeometryBufferExt for dyn GeometryBuffer {
|
||||
bytes: Some(data.vertex_buffer.raw_data()),
|
||||
},
|
||||
}],
|
||||
usage,
|
||||
};
|
||||
|
||||
let geometry_buffer = server.create_geometry_buffer(geometry_buffer_desc)?;
|
||||
|
||||
@@ -137,6 +137,7 @@ impl UiRenderer {
|
||||
],
|
||||
data: VertexBufferData::new::<crate::gui::draw::Vertex>(None),
|
||||
}],
|
||||
usage: BufferUsage::DynamicDraw,
|
||||
};
|
||||
|
||||
let clipping_geometry_buffer_desc = GeometryBufferDescriptor {
|
||||
@@ -155,6 +156,7 @@ impl UiRenderer {
|
||||
],
|
||||
data: VertexBufferData::new::<crate::gui::draw::Vertex>(None),
|
||||
}],
|
||||
usage: BufferUsage::DynamicDraw,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
|
||||
+38
-16
@@ -26,18 +26,18 @@
|
||||
use crate::{
|
||||
brush::Brush,
|
||||
color::draw_checker_board,
|
||||
core::{algebra::Vector2, color::Color, math::Rect, pool::Handle},
|
||||
core::{reflect::prelude::*, type_traits::prelude::*, visitor::prelude::*},
|
||||
core::{
|
||||
algebra::Vector2, color::Color, math::Rect, pool::Handle, reflect::prelude::*,
|
||||
type_traits::prelude::*, variable::InheritableVariable, visitor::prelude::*,
|
||||
},
|
||||
define_constructor,
|
||||
draw::{CommandTexture, Draw, DrawingContext},
|
||||
message::{MessageDirection, UiMessage},
|
||||
widget::{Widget, WidgetBuilder},
|
||||
BuildContext, Control, UiNode, UserInterface,
|
||||
};
|
||||
use fyrox_core::uuid_provider;
|
||||
use fyrox_core::variable::InheritableVariable;
|
||||
use fyrox_graph::constructor::{ConstructorProvider, GraphNodeConstructor};
|
||||
use fyrox_texture::TextureResource;
|
||||
use fyrox_texture::{TextureKind, TextureResource};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
/// A set of messages that could be used to alter [`Image`] widget state at runtime.
|
||||
@@ -91,19 +91,20 @@ impl ImageMessage {
|
||||
/// # };
|
||||
///
|
||||
/// fn create_image(ctx: &mut BuildContext, texture: TextureResource) -> Handle<UiNode> {
|
||||
/// // You must explicitly set width and height of the image, otherwise it will collapse to a
|
||||
/// // point and you won't see anything.
|
||||
/// let width = 100.0;
|
||||
/// let height = 100.0;
|
||||
/// ImageBuilder::new(WidgetBuilder::new().with_width(width).with_height(height))
|
||||
/// ImageBuilder::new(WidgetBuilder::new())
|
||||
/// .with_texture(texture)
|
||||
/// .build(ctx)
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// There are one common pitfall when using Image widget - you must explicitly set width and height of the image if it is
|
||||
/// not placed to some panel, that will stretch it automatically. In other words if you created an image with undefined
|
||||
/// width and height, then putting it to some container like Grid' cell will stretch the image to fit cell bounds.
|
||||
/// By default, the Image widget will try to use the size of the texture as its desired size for layout
|
||||
/// process. This means that the widget will be as large as the texture if the outer bounds allows
|
||||
/// that. You can specify the desired width and height manually and the image will shrink/expand
|
||||
/// automatically.
|
||||
///
|
||||
/// Keep in mind, that texture is a resource, and it could be loaded asynchronously, and during that
|
||||
/// process, the UI can't fetch texture's size, and it will be collapsed into a point. After it fully
|
||||
/// loaded, the widget will take texture's size as normal.
|
||||
///
|
||||
/// ## Vertical Flip
|
||||
///
|
||||
@@ -177,7 +178,8 @@ impl ImageMessage {
|
||||
/// It is useful if you have many custom UI elements packed in a single texture atlas. Drawing using atlases is much more
|
||||
/// efficient and faster. This could also be used for animations, when you have multiple frames packed in a single atlas
|
||||
/// and changing texture coordinates over the time.
|
||||
#[derive(Default, Clone, Visit, Reflect, Debug, ComponentProvider)]
|
||||
#[derive(Default, Clone, Visit, Reflect, Debug, ComponentProvider, TypeUuidProvider)]
|
||||
#[type_uuid(id = "18e18d0f-cb84-4ac1-8050-3480a2ec3de5")]
|
||||
pub struct Image {
|
||||
/// Base widget of the image.
|
||||
pub widget: Widget,
|
||||
@@ -210,9 +212,29 @@ impl ConstructorProvider<UiNode, UserInterface> for Image {
|
||||
|
||||
crate::define_widget_deref!(Image);
|
||||
|
||||
uuid_provider!(Image = "18e18d0f-cb84-4ac1-8050-3480a2ec3de5");
|
||||
|
||||
impl Control for Image {
|
||||
fn measure_override(&self, ui: &UserInterface, available_size: Vector2<f32>) -> Vector2<f32> {
|
||||
let mut size: Vector2<f32> = self.widget.measure_override(ui, available_size);
|
||||
|
||||
if let Some(texture) = self.texture.as_ref() {
|
||||
let state = texture.state();
|
||||
if let Some(data) = state.data_ref() {
|
||||
if let TextureKind::Rectangle { width, height } = data.kind() {
|
||||
let width = width as f32;
|
||||
let height = height as f32;
|
||||
if size.x < width {
|
||||
size.x = width;
|
||||
}
|
||||
if size.y < height {
|
||||
size.y = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size
|
||||
}
|
||||
|
||||
fn draw(&self, drawing_context: &mut DrawingContext) {
|
||||
let bounds = self.widget.bounding_rect();
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -55,8 +55,7 @@ use fyrox::{
|
||||
VerticalAlignment,
|
||||
},
|
||||
};
|
||||
use fyrox_build_tools::build::BuildWindow;
|
||||
use fyrox_build_tools::{BuildProfile, CommandDescriptor};
|
||||
use fyrox_build_tools::{build::BuildWindow, BuildProfile, CommandDescriptor};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
path::{Path, PathBuf},
|
||||
@@ -65,7 +64,7 @@ use std::{
|
||||
|
||||
pub enum Mode {
|
||||
Normal,
|
||||
Build {
|
||||
CommandExecution {
|
||||
queue: VecDeque<CommandDescriptor>,
|
||||
process: Option<std::process::Child>,
|
||||
current_dir: PathBuf,
|
||||
@@ -74,7 +73,7 @@ pub enum Mode {
|
||||
|
||||
impl Mode {
|
||||
pub fn is_build(&self) -> bool {
|
||||
matches!(self, Mode::Build { .. })
|
||||
matches!(self, Mode::CommandExecution { .. })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +143,7 @@ pub struct ProjectManager {
|
||||
settings_window: Option<SettingsWindow>,
|
||||
no_projects_warning: Handle<UiNode>,
|
||||
exclude_project: Handle<UiNode>,
|
||||
clean_project: Handle<UiNode>,
|
||||
pub focused: bool,
|
||||
pub update_loop_state: UpdateLoopState,
|
||||
}
|
||||
@@ -454,6 +454,7 @@ impl ProjectManager {
|
||||
(can be changed in settings).\nHotkey: Ctrl+O";
|
||||
let exclude_project_tooltip = "Removes the project from the project manager, \
|
||||
but does NOT delete it.\nHotkey: Ctrl+E";
|
||||
let clean_project_tooltip = "Removes project's build artifacts.\nHotkey: Ctrl+N";
|
||||
|
||||
let edit = make_text_and_image_button_with_tooltip(
|
||||
ctx,
|
||||
@@ -546,6 +547,19 @@ impl ProjectManager {
|
||||
Color::ORANGE,
|
||||
font_size,
|
||||
);
|
||||
let clean_project = make_text_and_image_button_with_tooltip(
|
||||
ctx,
|
||||
"Clean",
|
||||
22.0,
|
||||
22.0,
|
||||
load_image(include_bytes!("../resources/clean.png")),
|
||||
clean_project_tooltip,
|
||||
0,
|
||||
0,
|
||||
Some(11),
|
||||
Color::LIGHT_STEEL_BLUE,
|
||||
font_size,
|
||||
);
|
||||
let hot_reload = CheckBoxBuilder::new(
|
||||
WidgetBuilder::new()
|
||||
.with_tab_index(Some(4))
|
||||
@@ -568,6 +582,7 @@ impl ProjectManager {
|
||||
.with_child(run)
|
||||
.with_child(open_ide)
|
||||
.with_child(upgrade)
|
||||
.with_child(clean_project)
|
||||
.with_child(locate)
|
||||
.with_child(delete)
|
||||
.with_child(exclude_project),
|
||||
@@ -672,6 +687,7 @@ impl ProjectManager {
|
||||
settings_window: None,
|
||||
no_projects_warning,
|
||||
exclude_project,
|
||||
clean_project,
|
||||
focused: true,
|
||||
update_loop_state: Default::default(),
|
||||
}
|
||||
@@ -698,7 +714,7 @@ impl ProjectManager {
|
||||
}
|
||||
|
||||
fn handle_modes(&mut self, ui: &mut UserInterface) {
|
||||
let Mode::Build {
|
||||
let Mode::CommandExecution {
|
||||
ref mut process,
|
||||
ref mut queue,
|
||||
ref current_dir,
|
||||
@@ -916,6 +932,19 @@ impl ProjectManager {
|
||||
self.refresh(ui);
|
||||
}
|
||||
|
||||
fn on_clean_clicked(&mut self, ui: &mut UserInterface) {
|
||||
self.run_selected_project_command(
|
||||
"clean",
|
||||
vec![CommandDescriptor {
|
||||
command: "cargo".to_string(),
|
||||
args: vec!["clean".to_string()],
|
||||
environment_variables: vec![],
|
||||
}]
|
||||
.into(),
|
||||
ui,
|
||||
)
|
||||
}
|
||||
|
||||
fn on_button_click(&mut self, button: Handle<UiNode>, ui: &mut UserInterface) {
|
||||
if button == self.create {
|
||||
self.on_create_clicked(ui);
|
||||
@@ -936,11 +965,13 @@ impl ProjectManager {
|
||||
} else if button == self.locate {
|
||||
self.on_locate_click();
|
||||
} else if button == self.open_ide {
|
||||
self.on_open_ide_click();
|
||||
self.on_open_ide_click(ui);
|
||||
} else if button == self.open_settings {
|
||||
self.on_open_settings_click(ui);
|
||||
} else if button == self.exclude_project {
|
||||
self.on_exclude_project_clicked(ui);
|
||||
} else if button == self.clean_project {
|
||||
self.on_clean_clicked(ui);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -950,7 +981,7 @@ impl ProjectManager {
|
||||
Log::verify(open::that_detached(folder));
|
||||
}
|
||||
|
||||
fn on_open_ide_click(&mut self) {
|
||||
fn on_open_ide_click(&mut self, ui: &mut UserInterface) {
|
||||
let project = some_or_return!(self.selection.and_then(|i| self.settings.projects.get(i)));
|
||||
let mut open_ide_command = self.settings.open_ide_command.clone();
|
||||
if let Some(manifest_path_arg) = open_ide_command
|
||||
@@ -968,6 +999,8 @@ impl ProjectManager {
|
||||
"Unable to open the IDE using {} command. Reason: {:?}",
|
||||
open_ide_command, err
|
||||
));
|
||||
|
||||
self.on_open_settings_click(ui);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,21 +1009,40 @@ impl ProjectManager {
|
||||
self.settings_window = Some(SettingsWindow::new(&self.settings, ctx));
|
||||
}
|
||||
|
||||
fn run_selected_project_command(
|
||||
&mut self,
|
||||
action_name: &str,
|
||||
queue: VecDeque<CommandDescriptor>,
|
||||
ui: &mut UserInterface,
|
||||
) {
|
||||
let index = some_or_return!(self.selection);
|
||||
let project = some_or_return!(self.settings.projects.get(index));
|
||||
self.mode = Mode::CommandExecution {
|
||||
queue,
|
||||
process: None,
|
||||
current_dir: project.manifest_path.parent().unwrap().into(),
|
||||
};
|
||||
self.build_window = Some(BuildWindow::new(action_name, &mut ui.build_ctx()));
|
||||
}
|
||||
|
||||
fn run_build_profile(
|
||||
&mut self,
|
||||
name: &str,
|
||||
build_profile: &BuildProfile,
|
||||
ui: &mut UserInterface,
|
||||
) {
|
||||
let index = some_or_return!(self.selection);
|
||||
let project = some_or_return!(self.settings.projects.get(index));
|
||||
|
||||
self.mode = Mode::Build {
|
||||
queue: build_profile.build_and_run_queue(),
|
||||
process: None,
|
||||
current_dir: project.manifest_path.parent().unwrap().into(),
|
||||
};
|
||||
self.build_window = Some(BuildWindow::new(name, &mut ui.build_ctx()));
|
||||
let mut build_profile = build_profile.clone();
|
||||
// Force run `cargo update` before running the project to prevent various issues with
|
||||
// dependency versions incompatibility.
|
||||
build_profile.build_commands.insert(
|
||||
0,
|
||||
CommandDescriptor {
|
||||
command: "cargo".to_string(),
|
||||
args: vec!["update".to_string()],
|
||||
environment_variables: vec![],
|
||||
},
|
||||
);
|
||||
self.run_selected_project_command(name, build_profile.build_and_run_queue(), ui);
|
||||
}
|
||||
|
||||
fn on_hot_reload_changed(&mut self, value: bool, ui: &mut UserInterface) {
|
||||
@@ -1019,9 +1071,10 @@ impl ProjectManager {
|
||||
KeyCode::KeyC if modifiers.control => self.on_create_clicked(ui),
|
||||
KeyCode::KeyH if modifiers.control => self.on_hot_reload_changed(true, ui),
|
||||
KeyCode::KeyL if modifiers.control => self.on_locate_click(),
|
||||
KeyCode::KeyO if modifiers.control => self.on_open_ide_click(),
|
||||
KeyCode::KeyO if modifiers.control => self.on_open_ide_click(ui),
|
||||
KeyCode::KeyS if modifiers.control => self.on_open_settings_click(ui),
|
||||
KeyCode::KeyE if modifiers.control => self.on_exclude_project_clicked(ui),
|
||||
KeyCode::KeyN if modifiers.control => self.on_clean_clicked(ui),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
+26
-11
@@ -26,18 +26,32 @@ use std::{
|
||||
collections::HashMap,
|
||||
fmt::Display,
|
||||
fs::{create_dir_all, read_dir, remove_dir_all, File},
|
||||
io::{Read, Write},
|
||||
io::{Cursor, Read, Write},
|
||||
path::Path,
|
||||
process::Command,
|
||||
sync::LazyLock,
|
||||
};
|
||||
use toml_edit::{table, value, DocumentMut};
|
||||
use uuid::Uuid;
|
||||
|
||||
// Ideally, this should be taken from respective Cargo.toml of the engine and the editor.
|
||||
// However, it does not seem to work with builds published to crates.io, because when
|
||||
// the template generator is published, it does not have these Cargo.toml's available
|
||||
// and to solve this we just hard code these values and pray for the best.
|
||||
pub const CURRENT_VERSION: &str = "0.36.0";
|
||||
// Template generator version must match the engine version. This is checked by the CI.
|
||||
pub static CURRENT_VERSION: LazyLock<String> = LazyLock::new(|| {
|
||||
let manifest = include_bytes!("../Cargo.toml");
|
||||
|
||||
let mut file = Cursor::new(&manifest);
|
||||
let mut toml = String::new();
|
||||
if file.read_to_string(&mut toml).is_ok() {
|
||||
if let Ok(document) = toml.parse::<DocumentMut>() {
|
||||
if let Some(package) = document.get("package").and_then(|i| i.as_table()) {
|
||||
if let Some(version) = package.get("version") {
|
||||
return version.to_string().replace('\"', "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panic!("Project manager's Cargo.toml is malformed!");
|
||||
});
|
||||
|
||||
fn write_file<P: AsRef<Path>, S: AsRef<str>>(path: P, content: S) -> Result<(), String> {
|
||||
let mut file = File::create(path.as_ref()).map_err(|e| e.to_string())?;
|
||||
@@ -582,6 +596,7 @@ fn init_workspace(base_path: &Path, vcs: &str) -> Result<(), String> {
|
||||
}
|
||||
|
||||
// Write Cargo.toml
|
||||
let version = &*CURRENT_VERSION;
|
||||
write_file(
|
||||
base_path.join("Cargo.toml"),
|
||||
format!(
|
||||
@@ -591,10 +606,10 @@ members = ["editor", "executor", "executor-wasm", "executor-android", "game", "g
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies.fyrox]
|
||||
version = "{CURRENT_VERSION}"
|
||||
version = "{version}"
|
||||
default-features = false
|
||||
[workspace.dependencies.fyroxed_base]
|
||||
version = "{CURRENT_VERSION}"
|
||||
version = "{version}"
|
||||
default-features = false
|
||||
|
||||
# Separate build profiles for hot reloading. These profiles ensures that build artifacts for
|
||||
@@ -821,10 +836,10 @@ pub fn upgrade_project(root_path: &Path, version: &str, local: bool) -> Result<(
|
||||
dependencies["fyrox_scripts"] = scripts_table;
|
||||
}
|
||||
} else {
|
||||
dependencies["fyrox"] = value(CURRENT_VERSION);
|
||||
dependencies["fyroxed_base"] = value(CURRENT_VERSION);
|
||||
dependencies["fyrox"] = value(&*CURRENT_VERSION);
|
||||
dependencies["fyroxed_base"] = value(&*CURRENT_VERSION);
|
||||
if dependencies.contains_key("fyrox_scripts") {
|
||||
dependencies["fyrox_scripts"] = value(CURRENT_VERSION);
|
||||
dependencies["fyrox_scripts"] = value(&*CURRENT_VERSION);
|
||||
}
|
||||
}
|
||||
} else if version == "nightly" {
|
||||
|
||||
Reference in New Issue
Block a user