I'm unfamiliar with the general way of changing the defaults, and diving into the source code of the bevy_mod_picking library didn't reveal any obvious answers for me (a newcomer to rust).
I would like to change the highlighted colours of the picked/selected mesh. I got this far:
commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane { size: set_size*1.2 })),
material: transparent_material,
transform: Transform::from_xyz(0.0, 1.0, 0.0),
..default()
}).insert_bundle(PickableBundle{
highlight: highlight::Highlight {
// how to change this to a transparent colour?
..default()
},
..default()
});
Looking into the highlighting.rs or the bevy_mod_picking library, I see this line:
/// Marker component to flag an entity as highlightable
#[derive(Component, Clone, Debug, Default)]
pub struct Highlight;
However, the word "Highlight" doesn't appear in any further code leaving me wondering as to what to do next to modify the colours. There are some default colours defined further down, but they use different structs such as Highlightable, so I was quite lost after that. I would like to have a transparent colour as I don't want to see the highlighting at all in my use case.
Would be good to get an answer on the above + provide some kind of reference to this coding pattern for future reference.
Seems immediately after I've asked here, somehow the answer magically came to me via a reddit post.
This is the modified code that does what I want:
commands.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane { size: set_size*1.2 })),
material: transparent_material.clone(),
transform: Transform::from_xyz(0.0, 1.0, 0.0),
..default()
}).insert_bundle(PickableBundle{
highlight: highlight::Highlight {
..default()
},
..default()
}).insert(Highlighting{
initial: transparent_material.clone(),
hovered: Some(transparent_material.clone()),
pressed: Some(transparent_material.clone()),
selected:Some(transparent_material.clone()),
});
I haven't learnt anything of course so if a question with an explanation comes along then I'll accept it over this one.
Related
Recently I started to learn Rust and one of my main struggles is converting years of Object Oriented thinking into procedural code.
I'm trying to parse a XML that have tags that are processed by an specific handler that can deal with the data it gets from the children.
Further more I have some field members that are common between them and I would prefer not to have to write the same fields to all the handlers.
I tried my hand on it and my code came out like this:
use roxmltree::Node; // roxmltree = "0.14.0"
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
let tag_handler: dyn XMLTagHandler = match tag_name {
"name" => NameHandler::new(),
"phone" => PhoneHandler::new(),
_ => DefaultHandler::new()
}
if tag_handler.is_recursive() {
for child in node.children() {
let child_value = get_data_from(&child);
// do something with child value
}
}
let value: String = tag_handler.value()
value
}
// consider that handlers are on my project and can be adapted to my needs, and that XMLTagHandler is the trait that they share in common.
My main issues with this are:
This feels like a Object oriented approach to it;
is_recursive needs to be reimplemented to each struct because they traits cannot have field members, and I will have to add more fields later, which means more boilerplate for each new field;
I could use one type for a Handler and pass to it a function pointer, but this approach seems dirty. e.g.:=> Handler::new(my_other_params, phone_handler_func)
This feels like a Object oriented approach to it
Actually, I don't think so. This code is in clear violation of the Tell-Don't-Ask principle, which falls out from the central idea of object-oriented programming: the encapsulation of data and related behavior into objects. The objects (NameHandler, PhoneHandler, etc.) don't have enough knowledge about what they are to do things on their own, so get_data_from has to query them for information and decide what to do, rather than simply sending a message and letting the object figure out how to deal with it.
So let's start by moving the knowledge about what to do with each kind of tag into the handler itself:
trait XmlTagHandler {
fn foreach_child<F: FnMut(&Node)>(&self, node: &Node, callback: F);
}
impl XmlTagHandler for NameHandler {
fn foreach_child<F: FnMut(&Node)>(&self, _node: &Node, _callback: F) {
// "name" is not a recursive tag, so do nothing
}
}
impl XmlTagHandler for DefaultHandler {
fn foreach_child<F: FnMut(&Node)>(&self, node: &Node, callback: F) {
// all other tags may be recursive
for child in node.children() {
callback(child);
}
}
}
This way you call foreach_child on every kind of Handler, and let the handler itself decide whether the right action is to recurse or not. After all, that's why they have different types -- right?
To get rid of the dyn part, which is unnecessary, let's write a little generic helper function that uses XmlTagHandler to handle one specific kind of tag, and modify get_data_from so it just dispatches to the correct parameterized version of it. (I'll suppose that XmlTagHandler also has a new function so that you can create one generically.)
fn handle_tag<H: XmlTagHandler>(node: &Node) -> String {
let handler = H::new();
handler.foreach_child(node, |child| {
// do something with child value
});
handler.value()
}
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
match tag_name {
"name" => handle_tag::<NameHandler>(node),
"phone" => handle_tag::<PhoneHandler>(node),
_ => handle_tag::<DefaultHandler>(node),
}
}
If you don't like handle_tag::<SomeHandler>(node), also consider making handle_tag a provided method of XmlTagHandler, so you can instead write SomeHandler::handle(node).
Note that I have not really changed any of the data structures. Your presumption of an XmlTagHandler trait and various Handler implementors is a pretty normal way to organize code. However, in this case, it doesn't offer any real improvement over just writing three separate functions:
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
match tag_name {
"name" => get_name_from(node),
"phone" => get_phone_from(node),
_ => get_other_from(node),
}
}
In some languages, such as Java, all code has to be part of some class – so you can find yourself writing classes that don't exist for any other reason than to group related things together. In Rust you don't need to do this, so make sure that any added complication such as XmlTagHandler is actually pulling its weight.
is_recursive needs to be reimplemented to each struct because they traits cannot have field members, and I will have to add more fields later, which means more boilerplate for each new field
Without more information about the fields, it's impossible to really understand what problem you're facing here; however, in general, if there is a family of structs that have some data in common, you may want to make a generic struct instead of a trait. See the answers to How to reuse codes for Binary Search Tree, Red-Black Tree, and AVL Tree? for more suggestions.
I could use one type for a Handler and pass to it a function pointer, but this approach seems dirty
Elegance is sometimes a useful thing, but it is subjective. I would recommend closures rather than function pointers, but this suggestion doesn't seem "dirty" to me. Making closures and putting them in data structures is a very normal way to write Rust code. If you can elaborate on what you don't like about it, perhaps someone could point out ways to improve it.
I have started out learning Rust and is currently trying to write a small neural network as personal exercise. I want to define a struct for my forthcoming Layers/Clusters/Groups of nodes. My initial definition looks like this:
struct Layer {
name: String, // Human readable name
id: String, // UUID in the future
order: u8, // int for sorting
width: u8, // Number of nodes
input: [&'Self], // References to other Layers that feed input into this
}
The thing I am struggling with is the input field which should contain a list of references to other Layer-instances. I will know at compile time how many each Layer will have in the list so it wont have to me mutable. Is it possible to do this? I cant find a solution on the Google machine or in "the book".
Please advise.
Is it possible to do this? I cant find a solution on the Google machine or in "the book".
Possible yes, though I would not recommend it.
Let's start with the possible: &Self would be a "layer reference" with an unnamed lifetime, a lifetime name is for the form '<symbol>, so when you write &'Self you're specifying a reference of lifetime 'Self, but you're never specifying the type being refered to, which is why rustc complains about "expected type".
If you add a "proper" lifetime name, and parametrize the structure, it compiles fine:
struct Layer<'sublayers> {
name: String, // Human readable name
id: String, // UUID in the future
order: u8, // int for sorting
width: u8, // Number of nodes
input: [&'sublayers Self], // References to other Layers that feed input into this
}
However I would not recommend it as the last member being a slice means it's a DST which are difficult to work with at the best of time -- as the nomicon specifically notes "custom DSTs are a largely half-baked feature for now".
Since Rust doesn't yet have const generics proper you can't use an array you'd parameterize through layer either (e.g. Layer<const Size> and input: [&Self;Size], maybe one day), so you probably want something like a vector or a slice reference e.g.
struct Layer<'slice, 'sublayers: 'slice> {
name: String, // Human readable name
id: String, // UUID in the future
order: u8, // int for sorting
width: u8, // Number of nodes
input: &'slice [&'sublayers Self], // References to other Layers that feed input into this
}
I'm trying to set a specific anchor point when creating a link. I believe I'm doing everything correctly, but the anchor options are being ignored. In fact, any options I pass in are being ignored.
My code looks something like this:
new joint.shapes.standard.Link().target({id: 'xxx'}, {
anchor: {
name: 'center',
args: { dy: -15 }
}
});
The target id is being correctly handled, but whatever I pass in the second parameter is totally ignored.
Has anyone come across this before?
After experimenting, I worked out that when passing an object with id, rather than parsing a target element, that the opts need to go inside the object with the id. This is not documented AFAIK.
i.e.
.target({id: element.id, opts})
In my specific case, I'm passing the following:
.target({ id: to.id, anchor: { name: 'center', args: { dy: -15 }}})
This seems to work correctly
All the examples I find online that talk about how to style a feature depending on one of its properties use a switch statement that evaluates whether that property corresponds to a specific value.
For example this is taken form one of Leaflet's official tutorials:
L.geoJSON(states, {
style: function(feature) {
switch (feature.properties.party) {
case 'Republican': return {color: "#ff0000"};
case 'Democrat': return {color: "#0000ff"};
}
}
}).addTo(map);
What if I wanted to determine the feature's color depending on a numeric treshold? Say all features that have propertyX (which is a number) bigger than a certain value get colored red, otherwise blue.
I found this post where one user explains that switch statements are not made for comparisons; how can I do one then?
If use an external function (see code below) the latter seems to not be able to access the feature's properties.
L.geoJSON(states, {
style: styling
}).addTo(map);
function styling () {
if (feature.properties.numericProp > 100) {
return {color: "red"}
} else {
return {color: "blue"}
}
}
The feature gets passed a parameter of your function, you forgot to add it:
function styling (feature) {
// feature is now available
}
I have an Ogre material and, since i'm not happy with the GPU filtering, i want to make a manual mipmapping, i.e, i create all the textures, and then i set up a lod-based strategy to load the correct texture.
The problem is: it doensn't matter which strategy i use, neither the lod_value, my material does not change the texture. What should i do?
I'm reading the manual but it really didn't help.
Here is my code:
material shader/content
{
lod_values 100.0
technique t1
{
lod_index 0
pass
{
scene_blend alpha_blend
depth_write off
texture_unit
{
filtering none
texture menu_image.png
}
}
}
technique t2
{
lod_index 1
pass
{
scene_blend alpha_blend
depth_write off
texture_unit
{
filtering none
texture menutest.png
}
}
}
}
What you have posted seems correct.
Which image shows? I assume menu_image.png.
Things to try:
Are you sure menutest.png is loaded along with your other ogre assets?
Are there any relevant messages in your ogre logs?
What version of Ogre are you using? Try lod_distances instead of lod_values
Could there be code modifying the material/techniques at runtime?