Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render in-game SDF sprites with a black outline #201

Merged
merged 1 commit into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified korangar/archive/data/texture/collapsed_arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/expanded_arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/filled_box.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/marker_effect.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/marker_entity.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/marker_light.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/marker_object.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/marker_particle.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/marker_shadow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/marker_sound.png
100755 → 100644
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified korangar/archive/data/texture/unfilled_box.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions korangar/src/graphics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub use self::texture::*;
pub use self::vertices::*;
use crate::graphics::sampler::{create_new_sampler, SamplerType};
use crate::interface::layout::ScreenSize;
use crate::loaders::TextureLoader;
use crate::loaders::{ImageType, TextureLoader};
use crate::NUMBER_OF_POINT_LIGHTS_WITH_SHADOWS;

/// The size of a tile in pixel of the tile based light culling.
Expand Down Expand Up @@ -377,7 +377,7 @@ impl GlobalContext {
RgbaImage::from_raw(1, 1, vec![255, 255, 255, 255]).unwrap().as_raw(),
false,
));
let walk_indicator_texture = texture_loader.get("grid.tga").unwrap();
let walk_indicator_texture = texture_loader.get("grid.tga", ImageType::Color).unwrap();
let forward_textures = Self::create_forward_textures(device, forward_size, msaa);
let picker_textures = Self::create_picker_textures(device, screen_size);
let directional_shadow_map_texture = Self::create_directional_shadow_texture(device, directional_shadow_size);
Expand Down
4 changes: 2 additions & 2 deletions korangar/src/graphics/passes/interface/shader/rectangle.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
switch (instance.rectangle_type) {
case 1u: {
// SDF
let pixel = textureSample(texture, linear_sampler, input.texture_coordinates);
color *= vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a)));
let distance = textureSample(texture, linear_sampler, input.texture_coordinates).r;
color *= vec4(saturate((distance - 0.5) * 2.0 / fwidth(distance)));
}
case 2u: {
// Sprite (linear filtering)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
switch (instance.rectangle_type) {
case 1u: {
// SDF
let pixel = textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates);
color *= vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a)));
let distance = textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates).r;
color *= vec4(saturate((distance - 0.5) * 2.0 / fwidth(distance)));
}
case 2u: {
// Sprite (linear filtering)
Expand Down
48 changes: 40 additions & 8 deletions korangar/src/graphics/passes/postprocessing/shader/rectangle.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,61 @@ fn vs_main(
return output;
}

/// The range of the SDF border defines the outline of an SDF. msdfgen calls this pxrange.
/// We normaly use pxrange of 8 px when creating 64x64 SDFs, which results in an out border of 4 px in texture space.
const BORDER_WIDTH: f32 = 0.5;
const EDGE_VALUE: f32 = 0.5;

@fragment
fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
let instance = instance_data[input.instance_index];

var color: vec4<f32> = instance.color;

switch (instance.rectangle_type) {
case 1u: {
// SDF
let pixel = textureSample(texture, linear_sampler, input.texture_coordinates);
return vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a))) * instance.color;
let distance = textureSample(texture, linear_sampler, input.texture_coordinates).r;
let aa_width = fwidth(distance);

color *= vec4(step(EDGE_VALUE, distance));

// Outside outline
if (distance > EDGE_VALUE - BORDER_WIDTH && distance < EDGE_VALUE) {
let bias = 0.1;
let border_max = (EDGE_VALUE - BORDER_WIDTH) + bias;

// Transition from transparent to black outline
let outer_alpha = smoothstep(
border_max,
border_max + aa_width,
distance
);
color = vec4<f32>(0.0, 0.0, 0.0, outer_alpha);
}
// Inside outline
else if (distance >= EDGE_VALUE && distance < EDGE_VALUE + aa_width) {
// Transition from black outline to fill color
let inner_blend = smoothstep(
EDGE_VALUE,
EDGE_VALUE + aa_width,
distance
);
color = mix(vec4<f32>(0.0, 0.0, 0.0, 1.0), instance.color, inner_blend);
}
}
case 2u: {
// Sprite (linear filtering)
return textureSample(texture, linear_sampler, input.texture_coordinates) * instance.color;
color *= textureSample(texture, linear_sampler, input.texture_coordinates);
}
case 3u: {
// Sprite (nearest filtering)
return textureSample(texture, nearest_sampler, input.texture_coordinates) * instance.color;
}
default: {
// Solid
return instance.color;
color *= textureSample(texture, nearest_sampler, input.texture_coordinates);
}
default: {}
}

return color;
}

// Optimized version of the following truth table:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,61 @@ fn vs_main(
return output;
}

/// The range of the SDF border defines the outline of an SDF. msdfgen calls this pxrange.
/// We normaly use pxrange of 8 px when creating 64x64 SDFs, which results in an out border of 4 px in texture space.
const BORDER_WIDTH: f32 = 0.5;
const EDGE_VALUE: f32 = 0.5;

@fragment
fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
let instance = instance_data[input.instance_index];

var color: vec4<f32> = instance.color;

switch (instance.rectangle_type) {
case 1u: {
// SDF
let pixel = textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates);
return vec4(pixel.rgb, saturate((pixel.a - 0.5) * 2.0 / fwidth(pixel.a))) * instance.color;
let distance = textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates).r;
let aa_width = fwidth(distance);

color *= vec4(step(EDGE_VALUE, distance));

// Outside outline
if (distance > EDGE_VALUE - BORDER_WIDTH && distance < EDGE_VALUE) {
let bias = 0.1;
let border_max = (EDGE_VALUE - BORDER_WIDTH) + bias;

// Transition from transparent to black outline
let outer_alpha = smoothstep(
border_max,
border_max + aa_width,
distance
);
color = vec4<f32>(0.0, 0.0, 0.0, outer_alpha);
}
// Inside outline
else if (distance >= EDGE_VALUE && distance < EDGE_VALUE + aa_width) {
// Transition from black outline to fill color
let inner_blend = smoothstep(
EDGE_VALUE,
EDGE_VALUE + aa_width,
distance
);
color = mix(vec4<f32>(0.0, 0.0, 0.0, 1.0), instance.color, inner_blend);
}
}
case 2u: {
// Sprite (linear filtering)
return textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates) * instance.color;
color *= textureSample(textures[instance.texture_index], linear_sampler, input.texture_coordinates);
}
case 3u: {
// Sprite (nearest filtering)
return textureSample(textures[instance.texture_index], nearest_sampler, input.texture_coordinates) * instance.color;
}
default: {
// Solid
return instance.color;
color *= textureSample(textures[instance.texture_index], nearest_sampler, input.texture_coordinates);
}
default: {}
}

return color;
}

// Optimized version of the following truth table:
Expand Down
4 changes: 2 additions & 2 deletions korangar/src/loaders/effect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use ragnarok_formats::version::InternalVersion;
use wgpu::BlendFactor;

use super::error::LoadError;
use super::TextureLoader;
use super::{ImageType, TextureLoader};
use crate::graphics::Color;
use crate::loaders::GameFileLoader;
use crate::world::{AnimationType, Effect, Frame, FrameType, Layer, MultiTexturePresent};
Expand Down Expand Up @@ -70,7 +70,7 @@ impl EffectLoader {
.into_iter()
.map(|name| {
let path = format!("effect\\{}{}", prefix, name.name);
texture_loader.get(&path).unwrap()
texture_loader.get(&path, ImageType::Color).unwrap()
})
.collect(),
{
Expand Down
4 changes: 2 additions & 2 deletions korangar/src/loaders/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use self::vertices::MAP_TILE_SIZE;
use self::vertices::{generate_tile_vertices, ground_vertices};
use super::error::LoadError;
use crate::graphics::{Buffer, ModelVertex, NativeModelVertex, Texture};
use crate::loaders::{GameFileLoader, ModelLoader, TextureAtlasFactory, TextureLoader};
use crate::loaders::{GameFileLoader, ImageType, ModelLoader, TextureAtlasFactory, TextureLoader};
use crate::world::{LightSourceKey, Model};
use crate::{EffectSourceExt, LightSourceExt, Map, Object, ObjectKey, SoundSourceExt};

Expand Down Expand Up @@ -121,7 +121,7 @@ impl MapLoader {
let water_paths = get_water_texture_paths(water_type);
water_paths
.iter()
.map(|path| texture_loader.get(path).expect("Can't load water texture"))
.map(|path| texture_loader.get(path, ImageType::Color).expect("Can't load water texture"))
.collect()
});

Expand Down
2 changes: 1 addition & 1 deletion korangar/src/loaders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use self::model::*;
pub use self::script::{ResourceMetadata, ScriptLoader};
pub use self::server::{load_client_info, ClientInfo, ServiceId};
pub use self::sprite::*;
pub use self::texture::{TextureAtlasFactory, TextureLoader};
pub use self::texture::{ImageType, TextureAtlasFactory, TextureLoader};

pub const FALLBACK_BMP_FILE: &str = "missing.bmp";
pub const FALLBACK_JPEG_FILE: &str = "missing.jpg";
Expand Down
6 changes: 3 additions & 3 deletions korangar/src/loaders/script/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use korangar_util::FileLoader;
use mlua::Lua;
use ragnarok_packets::ItemId;

use super::TextureLoader;
use super::{ImageType, TextureLoader};
use crate::graphics::Texture;
use crate::loaders::GameFileLoader;

Expand Down Expand Up @@ -152,7 +152,7 @@ end

let resource_name = self.get_item_resource_from_id(item.item_id, is_identified);
let full_path = format!("À¯ÀúÀÎÅÍÆäÀ̽º\\item\\{resource_name}.bmp");
let texture = texture_loader.get(&full_path).unwrap();
let texture = texture_loader.get(&full_path, ImageType::Color).unwrap();
let name = self.get_item_name_from_id(item.item_id, is_identified);

let metadata = ResourceMetadata { texture, name };
Expand All @@ -163,7 +163,7 @@ end
pub fn load_market_item_metadata(&self, texture_loader: &TextureLoader, item: ShopItem<NoMetadata>) -> ShopItem<ResourceMetadata> {
let resource_name = self.get_item_resource_from_id(item.item_id, true);
let full_path = format!("À¯ÀúÀÎÅÍÆäÀ̽º\\item\\{resource_name}.bmp");
let texture = texture_loader.get(&full_path).unwrap();
let texture = texture_loader.get(&full_path, ImageType::Color).unwrap();
let name = self.get_item_name_from_id(item.item_id, true);

let metadata = ResourceMetadata { texture, name };
Expand Down
Loading
Loading