update
This commit is contained in:
@@ -51,3 +51,9 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
bincode = "1.3"
|
||||
earcutr = "0.4"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
|
||||
@@ -510,6 +510,68 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="loading-screen">
|
||||
<div class="spinner"></div>
|
||||
<div class="loading-text">Loading Maps...</div>
|
||||
</div>
|
||||
<style>
|
||||
#loading-screen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #1a1a1a;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
transition: opacity 0.5s ease-out;
|
||||
}
|
||||
|
||||
#loading-screen.fade-out {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 50%;
|
||||
border-top-color: #007AFF;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="light"] #loading-screen {
|
||||
background-color: #f5f5f7;
|
||||
}
|
||||
|
||||
[data-theme="light"] .loading-text {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="light"] .spinner {
|
||||
border-color: rgba(0, 0, 0, 0.1);
|
||||
border-top-color: #007AFF;
|
||||
}
|
||||
</style>
|
||||
<div id="user-location"></div>
|
||||
<div id="compass">
|
||||
<div class="direction n">N</div>
|
||||
|
||||
@@ -14,6 +14,19 @@ pub fn project(lat: f64, lon: f64) -> (f32, f32) {
|
||||
(x, y)
|
||||
}
|
||||
|
||||
/// High precision Web Mercator Projection
|
||||
/// Returns (x, y) in range [0.0, 1.0] for the whole world as f64
|
||||
pub fn project_high_precision(lat: f64, lon: f64) -> (f64, f64) {
|
||||
let x = (lon + 180.0) / 360.0;
|
||||
let lat_rad = lat.to_radians();
|
||||
let y = (1.0 - (lat_rad.tan() + (1.0 / lat_rad.cos())).ln() / std::f64::consts::PI) / 2.0;
|
||||
|
||||
let x = if x.is_finite() { x.clamp(0.0, 1.0) } else { 0.5 };
|
||||
let y = if y.is_finite() { y.clamp(0.0, 1.0) } else { 0.5 };
|
||||
|
||||
(x, y)
|
||||
}
|
||||
|
||||
/// Kalman filter for smoothing GPS location updates
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KalmanFilter {
|
||||
|
||||
@@ -222,7 +222,9 @@ pub fn extract_labels(tile_data: &TileData) -> Vec<CachedLabel> {
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Process Railways (Transit line labels like S1, U3, etc.)
|
||||
// 3. Process Railways (Transit line labels like S1, U3, etc.) - Grouped to reduce clutter
|
||||
let mut transit_groups: HashMap<String, Vec<&crate::types::MapWay>> = HashMap::new();
|
||||
|
||||
for railway in &tile_data.railways {
|
||||
// Get line reference (e.g., "S1", "U3", "S8") - stored as 'line_ref' by importer
|
||||
let line_ref = railway.tags.get("line_ref").map(|s| s.as_str());
|
||||
@@ -232,42 +234,53 @@ pub fn extract_labels(tile_data: &TileData) -> Vec<CachedLabel> {
|
||||
if railway_type == Some("tram") { continue; }
|
||||
let Some(line_ref) = line_ref else { continue; };
|
||||
if line_ref.is_empty() { continue; }
|
||||
|
||||
// Parse points to find midpoint
|
||||
let mut parsed_points: Vec<[f64; 2]> = Vec::new();
|
||||
for chunk in railway.points.chunks(8) {
|
||||
if chunk.len() < 8 { break; }
|
||||
let lat = f32::from_le_bytes(chunk[0..4].try_into().unwrap_or([0u8; 4])) as f64;
|
||||
let lon = f32::from_le_bytes(chunk[4..8].try_into().unwrap_or([0u8; 4])) as f64;
|
||||
parsed_points.push([lat, lon]);
|
||||
|
||||
transit_groups.entry(line_ref.to_string())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(railway);
|
||||
}
|
||||
|
||||
// Process each transit line group and pick the best segment(s) for labeling
|
||||
for (line_ref, segments) in transit_groups {
|
||||
// Sort segments by length (number of points as proxy) descending
|
||||
// We only label the top 1 longest segment per tile to avoid spam
|
||||
let best_segment = segments.iter().max_by_key(|r| r.points.len());
|
||||
|
||||
if let Some(railway) = best_segment {
|
||||
// Parse points to find midpoint
|
||||
let mut parsed_points: Vec<[f64; 2]> = Vec::new();
|
||||
for chunk in railway.points.chunks(8) {
|
||||
if chunk.len() < 8 { break; }
|
||||
let lat = f32::from_le_bytes(chunk[0..4].try_into().unwrap_or([0u8; 4])) as f64;
|
||||
let lon = f32::from_le_bytes(chunk[4..8].try_into().unwrap_or([0u8; 4])) as f64;
|
||||
parsed_points.push([lat, lon]);
|
||||
}
|
||||
if parsed_points.len() < 2 { continue; }
|
||||
|
||||
// Use midpoint for label placement
|
||||
let mid_idx = parsed_points.len() / 2;
|
||||
let mid_point = parsed_points[mid_idx];
|
||||
|
||||
// Determine category based on line prefix
|
||||
let category = if line_ref.starts_with('S') {
|
||||
"sbahn"
|
||||
} else if line_ref.starts_with('U') {
|
||||
"ubahn"
|
||||
} else {
|
||||
"rail"
|
||||
};
|
||||
|
||||
candidates.push(CachedLabel {
|
||||
name: line_ref.to_string(),
|
||||
lat: mid_point[0],
|
||||
lon: mid_point[1],
|
||||
label_type: LabelType::Transit,
|
||||
rotation: 0.0, // Transit labels are always horizontal
|
||||
priority: 150, // Very high priority - above cities
|
||||
min_zoom: 100.0, // Show at most zoom levels
|
||||
category: category.to_string(),
|
||||
});
|
||||
}
|
||||
if parsed_points.len() < 2 { continue; }
|
||||
|
||||
// Use midpoint for label placement
|
||||
let mid_idx = parsed_points.len() / 2;
|
||||
let mid_point = parsed_points[mid_idx];
|
||||
|
||||
// Determine category based on line prefix
|
||||
let category = if line_ref.starts_with('S') {
|
||||
"sbahn"
|
||||
} else if line_ref.starts_with('U') {
|
||||
"ubahn"
|
||||
} else {
|
||||
"rail"
|
||||
};
|
||||
// Debug logging removed for production performance
|
||||
// web_sys::console::log_1(&format!("Transit label found: {} at ({}, {})", line_ref, mid_point[0], mid_point[1]).into());
|
||||
|
||||
candidates.push(CachedLabel {
|
||||
name: line_ref.to_string(),
|
||||
lat: mid_point[0],
|
||||
lon: mid_point[1],
|
||||
label_type: LabelType::Transit,
|
||||
rotation: 0.0, // Transit labels are always horizontal
|
||||
priority: 150, // Very high priority - above cities
|
||||
min_zoom: 100.0, // Show at most zoom levels
|
||||
category: category.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
candidates
|
||||
|
||||
@@ -25,6 +25,7 @@ use winit::{
|
||||
window::WindowBuilder,
|
||||
platform::web::WindowExtWebSys,
|
||||
};
|
||||
use web_sys::Window; // Ensure web_sys Window is available if needed, though usually covered by wasm_bindgen
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use crate::domain::camera::Camera;
|
||||
@@ -291,6 +292,20 @@ pub async fn run() {
|
||||
}
|
||||
}
|
||||
|
||||
// Hide loading screen
|
||||
if let Some(loader) = window_doc.get_element_by_id("loading-screen") {
|
||||
let _ = loader.class_list().add_1("fade-out");
|
||||
// Remove after transition
|
||||
let closure = wasm_bindgen::closure::Closure::<dyn FnMut()>::new(move || {
|
||||
let _ = loader.set_attribute("style", "display: none;");
|
||||
});
|
||||
window_doc.default_view().unwrap().set_timeout_with_callback_and_timeout_and_arguments_0(
|
||||
closure.as_ref().unchecked_ref(),
|
||||
500,
|
||||
).unwrap();
|
||||
closure.forget();
|
||||
}
|
||||
|
||||
// Event Loop
|
||||
event_loop.run(move |event, elwt| {
|
||||
elwt.set_control_flow(winit::event_loop::ControlFlow::Wait);
|
||||
@@ -381,7 +396,7 @@ pub async fn run() {
|
||||
for tile in tiles_to_process {
|
||||
// Call RenderService static helper? Or just logic.
|
||||
// I put logic in RenderService::create_tile_buffers which takes state.
|
||||
RenderService::create_tile_buffers(&device, &mut state_guard, tile);
|
||||
RenderService::create_tile_buffers(&device, &mut state_guard, tile, &render_service.tile_bind_group_layout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,6 +582,7 @@ pub async fn run() {
|
||||
rpass.set_bind_group(0, &camera_bind_group, &[]);
|
||||
for buffers in &tiles_to_render {
|
||||
if buffers.railway_vertex_count > 0 {
|
||||
rpass.set_bind_group(1, &buffers.tile_bind_group, &[]);
|
||||
rpass.set_vertex_buffer(0, buffers.railway_vertex_buffer.slice(..));
|
||||
rpass.draw(0..buffers.railway_vertex_count, 0..1);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@ fn dot(a: [f32; 2], b: [f32; 2]) -> f32 {
|
||||
|
||||
/// Generate thick railway geometry (quads)
|
||||
pub fn generate_railway_geometry(points: &[[f32; 2]], color: [f32; 3], railway_type: f32) -> Vec<RailwayVertex> {
|
||||
let vertices = Vec::new();
|
||||
if points.len() < 2 { return vertices; }
|
||||
if points.len() < 2 { return Vec::new(); }
|
||||
|
||||
// Computes normals for each segment
|
||||
let mut segment_normals = Vec::with_capacity(points.len() - 1);
|
||||
@@ -25,7 +24,7 @@ pub fn generate_railway_geometry(points: &[[f32; 2]], color: [f32; 3], railway_t
|
||||
let dx = p2[0] - p1[0];
|
||||
let dy = p2[1] - p1[1];
|
||||
let len = (dx*dx + dy*dy).sqrt();
|
||||
if len < 0.000001 {
|
||||
if len < 0.000000001 {
|
||||
segment_normals.push([0.0, 0.0]); // Degenerate
|
||||
} else {
|
||||
segment_normals.push([-dy/len, dx/len]);
|
||||
@@ -84,7 +83,7 @@ pub fn generate_railway_geometry(points: &[[f32; 2]], color: [f32; 3], railway_t
|
||||
}
|
||||
|
||||
// Triangulate
|
||||
let mut triangle_vertices = Vec::with_capacity((points.len() - 1) * 6);
|
||||
let mut triangle_vertices: Vec<RailwayVertex> = Vec::with_capacity((points.len() - 1) * 6);
|
||||
for i in 0..points.len()-1 {
|
||||
// Skip degenerate segment
|
||||
if dot(segment_normals[i], segment_normals[i]) == 0.0 { continue; }
|
||||
@@ -107,14 +106,78 @@ pub fn generate_railway_geometry(points: &[[f32; 2]], color: [f32; 3], railway_t
|
||||
triangle_vertices.push(v4);
|
||||
triangle_vertices.push(v3);
|
||||
}
|
||||
|
||||
// Start Cap (at index 0)
|
||||
if points.len() >= 2 {
|
||||
let p0 = points[0];
|
||||
let p1 = points[1];
|
||||
let tangent = normalize([p1[0]-p0[0], p1[1]-p0[1]]);
|
||||
let neg_tangent = [-tangent[0], -tangent[1]];
|
||||
|
||||
let v_left = point_pairs[0];
|
||||
let v_right = point_pairs[1];
|
||||
|
||||
let cap_tris: Vec<RailwayVertex> = generate_railway_caps(p0, v_left, v_right, neg_tangent);
|
||||
triangle_vertices.extend(cap_tris);
|
||||
}
|
||||
|
||||
// End Cap (at index len-1)
|
||||
if points.len() >= 2 {
|
||||
let last = points.len() - 1;
|
||||
let p_last = points[last];
|
||||
let p_prev = points[last-1];
|
||||
let tangent = normalize([p_last[0]-p_prev[0], p_last[1]-p_prev[1]]);
|
||||
|
||||
let v_left = point_pairs[last*2];
|
||||
let v_right = point_pairs[last*2 + 1];
|
||||
|
||||
let cap_tris: Vec<RailwayVertex> = generate_railway_caps(p_last, v_left, v_right, tangent);
|
||||
triangle_vertices.extend(cap_tris);
|
||||
}
|
||||
|
||||
triangle_vertices
|
||||
}
|
||||
|
||||
pub fn generate_railway_caps(
|
||||
p: [f32; 2],
|
||||
v_left: RailwayVertex,
|
||||
v_right: RailwayVertex,
|
||||
tangent_direction: [f32; 2] // Direction to extrude (outwards from line)
|
||||
) -> Vec<RailwayVertex> {
|
||||
// Generate two new vertices that are extruded "outwards" along the tangent
|
||||
// Vertex shader uses: pos = center + normal * width
|
||||
// We want: pos = center + (normal_component + tangent_component) * width
|
||||
// So we just add the tangent to the normal vector of the existing vertices.
|
||||
|
||||
// Left Cap Vertex
|
||||
let v_cap_left = RailwayVertex {
|
||||
center: p,
|
||||
normal: [v_left.normal[0] + tangent_direction[0], v_left.normal[1] + tangent_direction[1]],
|
||||
..v_left
|
||||
};
|
||||
|
||||
// Right Cap Vertex
|
||||
let v_cap_right = RailwayVertex {
|
||||
center: p,
|
||||
normal: [v_right.normal[0] + tangent_direction[0], v_right.normal[1] + tangent_direction[1]],
|
||||
..v_right
|
||||
};
|
||||
|
||||
// Return as a quad strip sequence (v_left, v_cap_left, v_cap_right, etc for triangulation)
|
||||
// Actually method above expects triangles.
|
||||
// T1: v_left, v_cap_left, v_cap_right
|
||||
// T2: v_left, v_cap_right, v_right
|
||||
vec![
|
||||
v_left, v_cap_left, v_cap_right,
|
||||
v_left, v_cap_right, v_right
|
||||
]
|
||||
}
|
||||
|
||||
pub fn create_railway_pipeline(
|
||||
device: &wgpu::Device,
|
||||
format: &wgpu::TextureFormat,
|
||||
bind_group_layout: &wgpu::BindGroupLayout
|
||||
bind_group_layout: &wgpu::BindGroupLayout,
|
||||
tile_bind_group_layout: &wgpu::BindGroupLayout
|
||||
) -> wgpu::RenderPipeline {
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
@@ -125,6 +188,13 @@ pub fn create_railway_pipeline(
|
||||
};
|
||||
@group(0) @binding(0)
|
||||
var<uniform> camera: CameraUniform;
|
||||
|
||||
struct TileUniform {
|
||||
origin: vec2<f32>,
|
||||
scale: f32,
|
||||
};
|
||||
@group(1) @binding(0)
|
||||
var<uniform> tile: TileUniform;
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) center: vec2<f32>,
|
||||
@@ -153,11 +223,20 @@ pub fn create_railway_pipeline(
|
||||
base_pixels = 2.0; // U-Bahn - thinner
|
||||
}
|
||||
|
||||
// Using 1000.0 constant to make lines thicker (visible on standard screens)
|
||||
// Calculate line width in WORLD coordinates
|
||||
// camera.params.x = zoom / aspect (World -> Clip X scale)
|
||||
// We want: width_world * scale_x = width_clip
|
||||
// width_clip = pixel_width / screen_width * 2.0
|
||||
// For now, continuing with previous scale factor logic approx:
|
||||
let width = base_pixels / (camera.params.x * 1000.0);
|
||||
|
||||
let offset = model.normal * width;
|
||||
let world_pos = model.center + offset;
|
||||
|
||||
// Tile-Relative to World Coordinate Transformation
|
||||
// model.center is 0.0-1.0 relative to tile
|
||||
// tile.origin is top-left of tile in world coords
|
||||
// tile.scale is size of tile in world coords
|
||||
let world_pos = tile.origin + (model.center * tile.scale) + offset;
|
||||
|
||||
let x = world_pos.x * camera.params.x + camera.params.z;
|
||||
let y = world_pos.y * camera.params.y + camera.params.w;
|
||||
@@ -193,12 +272,12 @@ pub fn create_railway_pipeline(
|
||||
// When transit mode is OFF: Dim/hide railways
|
||||
if (!is_transit_mode) {
|
||||
// Transit mode is OFF - hide all railways
|
||||
return vec4<f32>(final_color, 0.0);
|
||||
discard;
|
||||
} else {
|
||||
// Transit mode is ON - show railways
|
||||
// Dim non-colored railways slightly to emphasize colored ones
|
||||
if (!has_color) {
|
||||
return vec4<f32>(mix(final_color, vec3<f32>(0.5, 0.5, 0.5), 0.3), 0.5);
|
||||
return vec4<f32>(mix(final_color, vec3<f32>(0.5, 0.5, 0.5), 0.3), 1.0);
|
||||
}
|
||||
return vec4<f32>(final_color, 1.0);
|
||||
}
|
||||
@@ -208,7 +287,7 @@ pub fn create_railway_pipeline(
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Railway Pipeline Layout"),
|
||||
bind_group_layouts: &[bind_group_layout],
|
||||
bind_group_layouts: &[bind_group_layout, tile_bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
@@ -227,7 +306,7 @@ pub fn create_railway_pipeline(
|
||||
entry_point: "fs_main",
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: *format,
|
||||
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
|
||||
@@ -70,7 +70,7 @@ impl RenderService {
|
||||
building_pipeline: create_colored_building_pipeline(device, format, camera_layout),
|
||||
water_pipeline: create_water_pipeline(device, format, camera_layout, &tile_bind_group_layout),
|
||||
water_line_pipeline: create_water_line_pipeline(device, format, camera_layout),
|
||||
railway_pipeline: create_railway_pipeline(device, format, camera_layout),
|
||||
railway_pipeline: create_railway_pipeline(device, format, camera_layout, &tile_bind_group_layout),
|
||||
motorway_outline: create_road_motorway_outline_pipeline(device, format, camera_layout),
|
||||
motorway_fill: create_road_motorway_pipeline(device, format, camera_layout),
|
||||
primary_outline: create_road_primary_outline_pipeline(device, format, camera_layout),
|
||||
@@ -86,7 +86,7 @@ impl RenderService {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_tile_buffers(device: &wgpu::Device, state: &mut AppState, tile: (i32, i32, i32)) {
|
||||
pub fn create_tile_buffers(device: &wgpu::Device, state: &mut AppState, tile: (i32, i32, i32), tile_bind_group_layout: &wgpu::BindGroupLayout) {
|
||||
// Build vertex data for each feature type - roads use RoadVertex
|
||||
let mut road_motorway_vertex_data: Vec<RoadVertex> = Vec::new();
|
||||
let mut road_primary_vertex_data: Vec<RoadVertex> = Vec::new();
|
||||
@@ -164,7 +164,6 @@ impl RenderService {
|
||||
Some("fire_station") | Some("courthouse") | Some("embassy")
|
||||
);
|
||||
|
||||
// Assign color based on building type (light theme colors)
|
||||
// Assign color based on building type (light theme colors)
|
||||
// Colors darkened for better visibility against #F5F4F0 background
|
||||
let color: [f32; 3] = if is_public_amenity {
|
||||
@@ -267,21 +266,43 @@ impl RenderService {
|
||||
|
||||
// Process railways
|
||||
if let Some(railways) = state.railways.get(&tile) {
|
||||
// Calculate tile origin and scale for relative coordinates (re-calculated here for loop)
|
||||
let (z, x, y) = tile;
|
||||
let tile_count = 2_f64.powi(z);
|
||||
let tile_size = 1.0 / tile_count;
|
||||
let tile_origin_x = x as f64 * tile_size;
|
||||
let tile_origin_y = y as f64 * tile_size;
|
||||
|
||||
for railway in railways {
|
||||
let mut centers: Vec<[f32; 2]> = Vec::new();
|
||||
|
||||
// CRITICAL FIX: Match labels.rs logic - read as F32 (8 bytes per point)
|
||||
// Previous logic used 16 bytes (f64), but if labels are working, data MUST be f32.
|
||||
for chunk in railway.points.chunks(8) {
|
||||
if chunk.len() < 8 { break; }
|
||||
let lat = f32::from_le_bytes(chunk[0..4].try_into().unwrap_or([0u8; 4]));
|
||||
let lon = f32::from_le_bytes(chunk[4..8].try_into().unwrap_or([0u8; 4]));
|
||||
let (x, y) = project(lat as f64, lon as f64);
|
||||
centers.push([x as f32, y as f32]);
|
||||
|
||||
// Read as f32 then cast to f64 for projection precision
|
||||
let lat = f32::from_le_bytes(chunk[0..4].try_into().unwrap_or([0u8; 4])) as f64;
|
||||
let lon = f32::from_le_bytes(chunk[4..8].try_into().unwrap_or([0u8; 4])) as f64;
|
||||
|
||||
// Project to global
|
||||
let (gx, gy) = crate::geo::project_high_precision(lat, lon);
|
||||
|
||||
// Convert to tile-relative (0.0 - 1.0)
|
||||
let rx = ((gx - tile_origin_x) / tile_size) as f32;
|
||||
let ry = ((gy - tile_origin_y) / tile_size) as f32;
|
||||
|
||||
centers.push([rx, ry]);
|
||||
}
|
||||
|
||||
// Determine color
|
||||
// ... (rest of logic)
|
||||
|
||||
// Get color from tags (OSM uses 'colour', but also check 'color')
|
||||
let color = railway.tags.get("colour")
|
||||
.or_else(|| railway.tags.get("color"))
|
||||
.and_then(|c| parse_hex_color(c))
|
||||
.unwrap_or([0.5, 0.5, 0.5]); // Default gray if no color
|
||||
.unwrap_or([0.5, 0.5, 0.5]); // Default to grey if no color specified
|
||||
|
||||
// Determine railway type - only S-Bahn and U-Bahn, skip tram
|
||||
// 0.0 = S-Bahn (solid line with white outline, wider)
|
||||
@@ -392,21 +413,6 @@ impl RenderService {
|
||||
// Get RenderService to access tile_bind_group_layout
|
||||
// We need to pass it from lib.rs or store it somewhere accessible
|
||||
// For now, we'll recreate it (not ideal but functional)
|
||||
let tile_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::VERTEX,
|
||||
ty: wgpu::BindingType::Buffer {
|
||||
ty: wgpu::BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
}
|
||||
],
|
||||
label: Some("tile_bind_group_layout"),
|
||||
});
|
||||
|
||||
let tile_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &tile_bind_group_layout,
|
||||
|
||||
Reference in New Issue
Block a user