mirror of
https://github.com/OMGeeky/logisim.git
synced 2026-02-23 15:49:52 +01:00
implement logic to spawn block from a BlockDefinition
This commit is contained in:
2
assets/logisim/blocks/sample1.json
Normal file
2
assets/logisim/blocks/sample1.json
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
@@ -6,6 +6,32 @@ use std::ops::BitOr;
|
|||||||
|
|
||||||
const LABEL_SCALING_FACTOR: f32 = 0.2;
|
const LABEL_SCALING_FACTOR: f32 = 0.2;
|
||||||
|
|
||||||
|
#[derive(Resource, Debug, Clone)]
|
||||||
|
pub struct BlockDefinition {
|
||||||
|
id: usize,
|
||||||
|
pos: Vec2,
|
||||||
|
size: IVec2,
|
||||||
|
name: String,
|
||||||
|
color: Color,
|
||||||
|
inner_blocks: Vec<BlockDefinition>,
|
||||||
|
wires: Vec<WireDefinition>,
|
||||||
|
inputs: Vec<ConnectionDefinition>,
|
||||||
|
outputs: Vec<ConnectionDefinition>,
|
||||||
|
}
|
||||||
|
#[derive(Resource, Debug, Clone)]
|
||||||
|
pub struct WireDefinition {
|
||||||
|
connections: Vec<ConnectionDefinitionRef>,
|
||||||
|
}
|
||||||
|
#[derive(Resource, Debug, Clone, Copy)]
|
||||||
|
pub struct ConnectionDefinition {
|
||||||
|
id: usize,
|
||||||
|
value: ConnectionValues,
|
||||||
|
}
|
||||||
|
#[derive(Resource, Debug, Clone, Copy)]
|
||||||
|
pub struct ConnectionDefinitionRef {
|
||||||
|
parent_block: usize,
|
||||||
|
id: usize,
|
||||||
|
}
|
||||||
#[derive(Bundle, Debug)]
|
#[derive(Bundle, Debug)]
|
||||||
pub struct BlockBundle {
|
pub struct BlockBundle {
|
||||||
block: Block,
|
block: Block,
|
||||||
@@ -43,7 +69,7 @@ pub struct BlockVisuals {
|
|||||||
size: IVec2,
|
size: IVec2,
|
||||||
color: Color,
|
color: Color,
|
||||||
}
|
}
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug, Copy, Clone)]
|
||||||
pub struct ConnectionReference(Entity);
|
pub struct ConnectionReference(Entity);
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
@@ -324,101 +350,174 @@ impl BitOr for ConnectionValues {
|
|||||||
pub struct LogicSimPlugin;
|
pub struct LogicSimPlugin;
|
||||||
impl Plugin for LogicSimPlugin {
|
impl Plugin for LogicSimPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Startup, setup).add_systems(
|
app
|
||||||
Update,
|
//hi
|
||||||
(
|
// .insert_resource(get_sample_block())
|
||||||
(update_connection_positions, draw_connections).chain(),
|
.add_systems(Startup, setup)
|
||||||
render_blocks,
|
.add_systems(Update, spawn_block_resources)
|
||||||
scale_labels,
|
.add_systems(
|
||||||
draw_wires,
|
Update,
|
||||||
update_connection_states,
|
(
|
||||||
),
|
(update_connection_positions, draw_connections).chain(),
|
||||||
);
|
render_blocks,
|
||||||
|
scale_labels,
|
||||||
|
draw_wires,
|
||||||
|
update_connection_states,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
fn get_sample_block() -> BlockDefinition {
|
||||||
|
BlockDefinition {
|
||||||
|
id: 1,
|
||||||
|
pos: Vec2::new(0.0, 0.0),
|
||||||
|
size: IVec2::new(50, 80),
|
||||||
|
name: "AND".to_string(),
|
||||||
|
color: Color::from(RED),
|
||||||
|
inner_blocks: vec![],
|
||||||
|
wires: vec![WireDefinition {
|
||||||
|
connections: vec![
|
||||||
|
ConnectionDefinitionRef {
|
||||||
|
parent_block: 1,
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
ConnectionDefinitionRef {
|
||||||
|
parent_block: 1,
|
||||||
|
id: 2,
|
||||||
|
},
|
||||||
|
ConnectionDefinitionRef {
|
||||||
|
parent_block: 1,
|
||||||
|
id: 3,
|
||||||
|
},
|
||||||
|
ConnectionDefinitionRef {
|
||||||
|
parent_block: 1,
|
||||||
|
id: 4,
|
||||||
|
},
|
||||||
|
ConnectionDefinitionRef {
|
||||||
|
parent_block: 1,
|
||||||
|
id: 6,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
inputs: vec![
|
||||||
|
ConnectionDefinition {
|
||||||
|
id: 1,
|
||||||
|
value: ConnectionValues::HalfByte(false, true, false, true),
|
||||||
|
},
|
||||||
|
ConnectionDefinition {
|
||||||
|
id: 2,
|
||||||
|
value: ConnectionValues::HalfByte(true, false, false, true),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
outputs: vec![
|
||||||
|
ConnectionDefinition {
|
||||||
|
id: 3,
|
||||||
|
value: ConnectionValues::HalfByte(false, false, true, false),
|
||||||
|
},
|
||||||
|
ConnectionDefinition {
|
||||||
|
id: 4,
|
||||||
|
value: ConnectionValues::HalfByte(false, false, true, false),
|
||||||
|
},
|
||||||
|
ConnectionDefinition {
|
||||||
|
id: 5,
|
||||||
|
value: ConnectionValues::Byte(0b0101_1010),
|
||||||
|
},
|
||||||
|
ConnectionDefinition {
|
||||||
|
id: 6,
|
||||||
|
value: ConnectionValues::HalfByte(false, true, false, false),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn setup(commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
let block = get_sample_block();
|
||||||
|
spawn_block_definition(commands, asset_server, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_block_definition(
|
||||||
|
mut commands: Commands,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
block: BlockDefinition,
|
||||||
|
) {
|
||||||
let font = asset_server.load("fonts/arcane_nine.otf");
|
let font = asset_server.load("fonts/arcane_nine.otf");
|
||||||
let text_font = TextFont {
|
let text_font = TextFont {
|
||||||
font,
|
font,
|
||||||
font_size: 100.0,
|
font_size: 100.0,
|
||||||
..default()
|
..default()
|
||||||
};
|
};
|
||||||
|
let inputs = block.inputs.iter().map(|input| {
|
||||||
|
(
|
||||||
|
input.id,
|
||||||
|
(
|
||||||
|
InputConnection,
|
||||||
|
Connection {
|
||||||
|
values: input.value,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
let outputs = block.outputs.iter().map(|output| {
|
||||||
|
(
|
||||||
|
output.id,
|
||||||
|
(
|
||||||
|
OutputConnection,
|
||||||
|
Connection {
|
||||||
|
values: output.value,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let size = IVec2::new(50, 80);
|
let inputs: Vec<_> = inputs
|
||||||
|
.map(|(id, con)| (id, ConnectionReference(commands.spawn(con).id())))
|
||||||
|
.collect();
|
||||||
|
let outputs: Vec<_> = outputs
|
||||||
|
.map(|(id, con)| (id, ConnectionReference(commands.spawn(con).id())))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let wires = block.wires.iter().map(|wire| {
|
||||||
|
wire.connections.iter().flat_map(|con| {
|
||||||
|
if (con.parent_block != block.id) {
|
||||||
|
warn!("get connections from sub blocks is not implemented yet");
|
||||||
|
// todo!("get connections from sub blocks (not blocks outside the one containing the wire and only one level deep)");
|
||||||
|
None
|
||||||
|
} else if let Some((_, connection)) = inputs.iter().find(|(id, _)| *id == con.id) {
|
||||||
|
Some(*connection)
|
||||||
|
} else if let Some((_, connection)) = outputs.iter().find(|(id, _)| *id == con.id) {
|
||||||
|
Some(*connection)
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"could not find connection with id '{}' in block '{}",
|
||||||
|
con.id, block.id
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
for wire in wires {
|
||||||
|
commands.spawn(Wire {
|
||||||
|
connections: wire.collect(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//region connections
|
|
||||||
let input1 = (
|
|
||||||
InputConnection,
|
|
||||||
Connection {
|
|
||||||
values: ConnectionValues::HalfByte(false, true, false, true),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let input2 = (
|
|
||||||
InputConnection,
|
|
||||||
Connection {
|
|
||||||
values: ConnectionValues::HalfByte(true, false, false, true),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let output1 = (
|
|
||||||
OutputConnection,
|
|
||||||
Connection {
|
|
||||||
values: ConnectionValues::HalfByte(false, false, true, false),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let output2 = (
|
|
||||||
OutputConnection,
|
|
||||||
Connection {
|
|
||||||
values: ConnectionValues::HalfByte(false, false, true, false),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let output3 = (
|
|
||||||
OutputConnection,
|
|
||||||
Connection {
|
|
||||||
values: ConnectionValues::HalfByte(false, false, true, false),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let output4 = (
|
|
||||||
OutputConnection,
|
|
||||||
Connection {
|
|
||||||
values: ConnectionValues::HalfByte(false, true, false, false),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
let input1 = commands.spawn(input1).id();
|
|
||||||
let input2 = commands.spawn(input2).id();
|
|
||||||
let output1 = commands.spawn(output1).id();
|
|
||||||
let output2 = commands.spawn(output2).id();
|
|
||||||
let output3 = commands.spawn(output3).id();
|
|
||||||
let output4 = commands.spawn(output4).id();
|
|
||||||
//endregion
|
|
||||||
let wire1 = Wire {
|
|
||||||
connections: vec![
|
|
||||||
ConnectionReference(input1),
|
|
||||||
ConnectionReference(input2),
|
|
||||||
ConnectionReference(output1),
|
|
||||||
ConnectionReference(output2),
|
|
||||||
ConnectionReference(output4),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
commands.spawn(wire1);
|
|
||||||
commands
|
commands
|
||||||
.spawn(BlockBundle {
|
.spawn(BlockBundle {
|
||||||
block_visuals: BlockVisuals {
|
block_visuals: BlockVisuals {
|
||||||
size,
|
size: block.size,
|
||||||
color: Color::from(RED),
|
color: block.color,
|
||||||
},
|
},
|
||||||
block: Block {
|
block: Block {
|
||||||
inputs: vec![ConnectionReference(input1), ConnectionReference(input2)],
|
inputs: inputs.into_iter().map(|(_, con)| con).collect(),
|
||||||
outputs: vec![
|
outputs: outputs.into_iter().map(|(_, con)| con).collect(),
|
||||||
ConnectionReference(output1),
|
|
||||||
ConnectionReference(output2),
|
|
||||||
ConnectionReference(output3),
|
|
||||||
ConnectionReference(output4),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
global_transform: GlobalTransform::default(),
|
global_transform: GlobalTransform::default(),
|
||||||
transform: Transform::default(),
|
transform: Transform::from_translation(block.pos.extend(0.)),
|
||||||
})
|
})
|
||||||
.with_child(BlockLabelBundle::new("AND", size, text_font));
|
.with_child(BlockLabelBundle::new(block.name, block.size, text_font));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_block_resources(// mut ev_asset
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
fn render_blocks(
|
fn render_blocks(
|
||||||
blocks: Query<(&BlockVisuals, &Transform)>,
|
blocks: Query<(&BlockVisuals, &Transform)>,
|
||||||
@@ -437,7 +536,7 @@ fn update_connection_positions(
|
|||||||
mut connections: Query<&mut Transform, With<Connection>>,
|
mut connections: Query<&mut Transform, With<Connection>>,
|
||||||
canvas: Res<Canvas>,
|
canvas: Res<Canvas>,
|
||||||
) {
|
) {
|
||||||
for (block_visual, block, transform) in blocks.iter() {
|
blocks.iter().for_each(|(block_visual, block, transform)| {
|
||||||
let size = block_visual.size.as_vec2() * canvas.zoom;
|
let size = block_visual.size.as_vec2() * canvas.zoom;
|
||||||
let center = transform.translation().xy();
|
let center = transform.translation().xy();
|
||||||
let half_size = size / 2.0;
|
let half_size = size / 2.0;
|
||||||
@@ -459,7 +558,7 @@ fn update_connection_positions(
|
|||||||
&mut connections,
|
&mut connections,
|
||||||
block.outputs.len(),
|
block.outputs.len(),
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
fn update_connection_position<'a>(
|
fn update_connection_position<'a>(
|
||||||
pos: Vec2,
|
pos: Vec2,
|
||||||
@@ -547,9 +646,9 @@ fn draw_wires(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn scale_labels(mut labels: Query<&mut Transform, With<CanvasText>>, canvas: Res<Canvas>) {
|
fn scale_labels(mut labels: Query<&mut Transform, With<CanvasText>>, canvas: Res<Canvas>) {
|
||||||
for mut transform in labels.iter_mut() {
|
labels.par_iter_mut().for_each(|mut transform| {
|
||||||
transform.scale = Vec3::splat(canvas.zoom) * LABEL_SCALING_FACTOR;
|
transform.scale = Vec3::splat(canvas.zoom) * LABEL_SCALING_FACTOR;
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_connection_states(
|
fn update_connection_states(
|
||||||
|
|||||||
Reference in New Issue
Block a user