I'm new to the rust library Nannou and I'm trying to draw pie chart.
I know that in javascript you can specify the amount of the ellipse via:
ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);
I couldn't however find anything similar in Nannou like:
draw.ellipse().angle(PI);
The nannou::draw::primitive::ellipse::Ellipse does not support sections.
However you can use the Section from nannou::geom::Ellipse.
Here is a simple example:
use nannou::{
geom::{Ellipse, Tri},
prelude::*,
};
fn main() {
nannou::sketch(view).run()
}
fn view(app: &App, frame: Frame) {
let draw = app.draw();
let win = app.window_rect();
draw.background().color(CORNFLOWERBLUE);
let t = app.time;
let radius = if win.h() < win.w() {
win.w() / 3f32
} else {
win.h() / 3f32
};
let section = Ellipse::new(Rect::from_x_y_w_h(0f32, 0f32, radius, radius), 120f32)
.section(0f32, t.sin() * 2f32 * std::f32::consts::PI);
let triangles = section.trangles();
let mut tris = Vec::new();
for t in triangles {
tris.push(Tri([
[t.0[0][0], t.0[0][1], 0f32],
[t.0[1][0], t.0[1][1], 0f32],
[t.0[2][0], t.0[2][1], 0f32],
]));
}
draw.mesh().tris(tris.into_iter()).color(RED);
draw.to_frame(app, &frame).unwrap();
}
Related
I added collision between the player and the ground, and I want to add a jumping mechanic into my game with on_ground. However, whenever I try to add status, it just stops iterating entirely.
fn collision_detection(
ground: Query<&Transform, (With<Ground>, Without<Player>)>,
mut player: Query<(&mut Transform, &mut PlayerStatus), With<Player>>,
) {
let player_size = Vec2::new(PLAYER_SIZE_X, PLAYER_SIZE_Y);
let ground_size = Vec2::new(GROUND_SIZE_X, GROUND_SIZE_Y);
for ground in ground.iter() {
for (mut player, mut status) in player.iter_mut() {
if collide(
player.translation,
player_size,
ground.translation,
ground_size,
)
.is_some()
{
status.on_ground = true;
println!("ON GROUND")
} else {
status.on_ground = false;
}
if status.on_ground {
player.translation.y += GRAVITY;
}
}
}
}
For some reason, this part wouldn't run
for (mut player, mut status) in player.iter_mut() {
if collide(
player.translation,
player_size,
ground.translation,
ground_size,
)
.is_some()
{
status.on_ground = true;
println!("ON GROUND")
} else {
status.on_ground = false;
}
if status.on_ground {
player.translation.y += GRAVITY;
}
}
It works if I only do this though:
for mut player in player.iter_mut() {
if collide(
player.translation,
player_size,
ground.translation,
ground_size,
)
.is_some()
{
player.translation.y += GRAVITY;
}
}
If you have only one player, you can use get_single_mut() instead of iter_mut() on the query.
It returns a result, so you can check in your function easily whether the player entity had been found at all. And if not send yourself some nice debugging message :)
if let Ok((mut player, mut status)) = player.get_single_mut() {
// do your collision check
} else {
// player not found in the query
}
https://docs.rs/bevy/latest/bevy/prelude/struct.Query.html#method.get_single_mut
Edit:
Looking at your comment above: if you have an already spawn entity you can always add new components to it using .insert_bundle or .insert.
How I can update child widget of gtk::Grid (gtk::Label in example) in runtime?
In example code after change value SpinButton, I add recreated Grid (fn grid()) with updated childs (I don't want remove old Grid in example).
In a real project I need to add a Grid with an updateable child element Label without recreate Grid. New values will be continuously read from the database.
Example:
pub fn test(parent: >k::Box) {
let parent_grid = gtk::Grid::new();
let parent_spin = gtk::SpinButton::with_range(0.0, 10.0, 1.0);
parent_grid.add(&parent_spin);
let parent_value = Rc::new(RefCell::new(0));
let parent_value_clone = parent_value.clone();
let parent_grid_rc = Rc::new(RefCell::new(parent_grid));
let parent_grid_rc_clone = parent_grid_rc.clone();
parent_spin.connect_value_changed(move |x| {
*parent_value_clone.borrow_mut() = x.value_as_int();
(*parent_grid_rc_clone.borrow_mut()).add(&grid(*parent_value.borrow()));
});
(*parent_grid_rc.borrow()).show_all();
parent.add(&(*parent_grid_rc.borrow()));
}
fn grid(value: i32) -> gtk::Grid {
let grid = gtk::Grid::new();
let label_box = gtk::Label::new(Some("Value: "));
let value_box = Rc::new(RefCell::new(gtk::Label::new(Some(&format!("{}", value))))); // THIS LABEL MUST BE UPDATED DURING RUNTIME
grid.add(&label_box);
grid.add(&(*value_box.borrow()));
grid.show_all();
grid
}
I'm new to this, so if there are other methods for creating dynamic objects in Rust-GTK and modifying their children, I'd love to hear about them.
Library glib helped me in my trouble.
I didn't find any clear examples on the internet, so let my solution be here.
pub fn test(parent: >k::Box) {
let parent_grid = gtk::Grid::new();
let parent_spin = gtk::SpinButton::with_range(0.0, 10.0, 1.0);
parent_grid.add(&parent_spin);
let parent_value = Rc::new(RefCell::new(0));
let parent_value_clone = parent_value.clone();
parent_spin.connect_value_changed(move |x| {
*parent_value_clone.borrow_mut() = x.value_as_int();
});
let grid = gtk::Grid::new();
let label_box = gtk::Label::new(Some("Value: "));
let value_box = gtk::Label::new(Some("Value"));
grid.add(&label_box);
grid.add(&value_box);
grid.show_all();
let update_label = move || {
println!("value={}", *parent_value.borrow());
value_box.set_text(&format!("{}",*parent_value.borrow()));
glib::Continue(true)
};
glib::timeout_add_seconds_local(2, update_label);
parent_grid.add(&grid);
parent_grid.show_all();
parent.add(&parent_grid);
}
fn grid(value: Rc<RefCell<i32>>) -> (gtk::Grid) {
let grid = gtk::Grid::new();
let label_box = gtk::Label::new(Some("Value: "));
let value_box = gtk::Label::new(Some("Value"));
grid.add(&label_box);
grid.add(&value_box);
let value = *value.borrow();
grid.show_all();
let update_label = move || {
value_box.set_text(&format!("{}",value));
glib::Continue(true)
};
glib::timeout_add_seconds_local(1, update_label);
grid
}
I'm trying to output a simple sound (a square waveform). All seems to work except no sound is going to my speakers. I found cpal as a lib to manage sound, but maybe there is a better way to handle streams. Here is my code
use cpal::{Sample};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
fn main() {
let err_fn = |err| eprintln!("an error occurred on the output audio stream: {}", err);
let host = cpal::default_host();
let device = host.default_output_device().expect("no output device available");
let supported_config = device.default_output_config().unwrap();
println!("Device: {}, Using config: {:?}", device.name().expect("flute"), supported_config);
let config = supported_config.into();
let stream = device.build_output_stream(&config, write_silence, err_fn).unwrap();
stream.play().unwrap();
std::thread::sleep(std::time::Duration::from_millis(3000));
}
fn write_silence(data: &mut [f32], _: &cpal::OutputCallbackInfo) {
let mut counter = 0;
for sample in data.iter_mut() {
let s = if (counter / 20) % 2 == 0 { &1.0 } else { &0.0 };
counter = counter + 1;
*sample = Sample::from(s);
}
println!("{:?}", data);
}
line 27 (println!("{:?}", data)) does output the samples of a square waveform.
I'm running this in the linux/crostini thing of chromebooks. It can be the problem.
Does anyone knows why it's not working ? And is cpal a good start for audio processing ?
According to the following documentation (https://developer.apple.com/documentation/uikit/uisegmentedcontrol/1618570-settitletextattributes)
I should be able to add attributes to change how it looks for a particular mode.
modalitySegmentedControl.setTitle("LDR ("+(stateController?.tdfvariables.selectedRadionuclide.name ?? "-") + ")", forSegmentAt: Constants.LDRButton)
let colorAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.systemTeal ]
modalitySegmentedControl.setTitleTextAttributes(colorAttribute, for: .selected)
In short the text on the control is basically "LDR (I-125)". Currently this code highlights the entire selection teal. I'm looking for a way to only highlight the (I-125) only with a teal color. I can do this with regular UILabels by defining a range that the attributes act upon, but I can't seem to find a way to set a specific color range with the UISegmentedControl?
Is this possible to do?
It currently looks like this:
I want the LDR to be white color and only teal on the (I-125) part.
In short I think it's not possible. Check my hacky playground:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
extension UIView {
class func getAllSubviews<T: UIView>(from parentView: UIView) -> [T] {
return parentView.subviews.flatMap { subView -> [T] in
var result = getAllSubviews(from: subView) as [T]
if let view = subView as? T { result.append(view) }
return result
}
}
class func getAllSubviews(from parentView: UIView, types: [UIView.Type]) -> [UIView] {
return parentView.subviews.flatMap { subView -> [UIView] in
var result = getAllSubviews(from: subView) as [UIView]
for type in types {
if subView.classForCoder == type {
result.append(subView)
return result
}
}
return result
}
}
func getAllSubviews<T: UIView>() -> [T] { return UIView.getAllSubviews(from: self) as [T] }
func get<T: UIView>(all type: T.Type) -> [T] { return UIView.getAllSubviews(from: self) as [T] }
func get(all types: [UIView.Type]) -> [UIView] { return UIView.getAllSubviews(from: self, types: types) }
}
class MyViewController : UIViewController {
var myString: String = "LDR (I-125)"
var myString42: String = "424242424242"
var attributedString = NSMutableAttributedString()
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let items = ["EBRT", "LDR (I-125)", "PERM"]
let modalitySegmentedControl = UISegmentedControl(items: items)
modalitySegmentedControl.frame = CGRect(x: 20, y: 200, width: 300, height: 20)
modalitySegmentedControl.backgroundColor = .white
attributedString = NSMutableAttributedString(string: myString, attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 18)])
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.red, range: NSRange(location:4, length:7))
let subviews = modalitySegmentedControl.getAllSubviews()
for view in subviews {
if view is UILabel {
if let label = view as? UILabel, label.text == myString {
print(label.attributedText)
label.attributedText = attributedString
//label.text = "42" // this works
print(label.attributedText) // looks changed
}
}
}
let subviews2 = modalitySegmentedControl.getAllSubviews()
for view in subviews2 {
if view is UILabel {
if let label = view as? UILabel, label.text == myString {
print(label.attributedText) // but it didn't change
}
}
}
let lab = UILabel()
lab.frame = CGRect(x: 40, y: 250, width: 300, height: 20)
lab.attributedText = attributedString
view.addSubview(lab)
view.addSubview(modalitySegmentedControl)
self.view = view
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
You can find specific UILabel subview of UISegmentedControl and even can change the text, but attribute changes doesn't work.
Related question: Segmented Control set attributed title in each segment
I'm new to Vulkan and graphics programming. I'm using vulkano Rust library https://github.com/vulkano-rs/vulkano (v0.17).
I want to use a compute pipeline to calculate something on a large set of circles. Circles are described as an input tuple (x, y). 2048 of them at the moment. I will make a calculation on them and output 2048 booleans depending on the outcome.
I use one buffer for inputted circles, and the other buffer for the outputted booleans.
At first I just want to make the output to be all trues.
let data_in_iter = (0..2048).map(|i| (i, i));
let data_in_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_in_iter)
.expect("failed to create buffer");
let data_out_iter = (0..2048).map(|_| false);
let data_out_buffer =
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_out_iter)
.expect("failed to create buffer");
let compute_pipeline = Arc::new({
mod cs {
vulkano_shaders::shader! {
ty: "compute",
src:
"
#version 450
layout(local_size_x = 1024, local_size_y = 1, local_size_z = 1) in;
layout(set = 0, binding = 0) buffer DataIn {
uvec2 data[];
} buf_in;
layout(set = 0, binding = 1) buffer DataOut {
bool data[];
} buf_out;
void main() {
uint idx = gl_GlobalInvocationID.x;
buf_out.data[idx] = true /* buf_in.data[idx].x + buf_in.data[idx].y < 2048 */;
}
"
}
}
let shader = cs::Shader::load(device.clone()).expect("failed to create shader module");
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &())
.expect("failed to create compute pipeline")
});
let layout = compute_pipeline.layout().descriptor_set_layout(0).unwrap();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(data_in_buffer.clone())
.unwrap()
.add_buffer(data_out_buffer.clone())
.unwrap()
.build()
.unwrap(),
);
let command_buffer =
AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family())
.unwrap()
.dispatch([2, 1, 1], compute_pipeline.clone(), set.clone(), ())
.unwrap()
.build()
.unwrap();
let future = sync::now(device.clone())
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_signal_fence_and_flush()
.unwrap();
future.wait(None).unwrap();
let content = data_out_buffer.read().unwrap();
for (n, val) in content.iter().enumerate() {
println!("{} {:?}", n, val);
}
But the output I get is:
0 true
1 false
2 false
3 false
4 true
5 false
6 false
7 false
8 true
9 false
...
2047 false
The default layout for storage buffers requires that each element of an array start at a 16-byte boundary. So what you're seeing is expected: buf_out.data[i] is written starting at byte 16*i in the output buffer.
You can either match that in your host code, or add the std430 modifier inside the layout() for DataOut. Note the same issue will affect DataIn.