Skip to content

Commit

Permalink
- add to_bytes method to Texture type
Browse files Browse the repository at this point in the history
  - needed to add COPY_SRC to all textures to make this easy
- load and process skybox on GPU in skybox_procssor module and call to_bytes at the end
- make command be a CLI option instead of freestanding value (limitation of picoargs crate)
- move Controls log into example game
- add equirectangular to cubemap SDR pipeline
  • Loading branch information
Davidster committed Aug 10, 2023
1 parent 7304313 commit fa18943
Show file tree
Hide file tree
Showing 15 changed files with 547 additions and 258 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ opt-level = 3
# incremental = false
# codegen-units = 1
debug = true
debug-assertions = true
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ Hopefully one day it will be used in a real game 😃

## TODO

- stop using release build, switch to dev but with optimizations enabled, but leave debug=true for release builds.
- fix resolve_path function in file_loader so it can be used outside the context of the engine!
- path in error messages in file loader module (see TODO: there)
- renderer should not need to know about the game state!
- lift state from the ui overlay into the game state to not need to pass state around
- convert all paths to be relative to the bin
Expand Down
2 changes: 1 addition & 1 deletion clikari/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ path = "src/main.rs"
# winit.workspace = true
ikari.workspace = true
log.workspace = true
# wgpu.workspace = true
wgpu.workspace = true
anyhow.workspace = true
env_logger.workspace = true
# profiling.workspace = true
Expand Down
114 changes: 74 additions & 40 deletions clikari/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
mod skybox_processor;
mod texture_compressor;

use std::str::FromStr;

use skybox_processor::SkyboxProcessorArgs;
use texture_compressor::TextureCompressorArgs;

const HELP: &str = "\
ikari cli
Usage: clikari [COMMAND] [OPTIONS]
Commands:
compress_textures
process_skybox
Usage: clikari --command CMD [OPTIONS]
Options:
--help Optional Display this help message
--command CMD Required The command to run. Possible values include:
compress_textures
process_skybox
--help Optional Display this help message
";

const TEXTURE_COMPRESSOR_HELP: &str = "\
Compress all textures found in a given folder by recursive search
Compress all textures found in a given folder by recursive search. The compressed textures
will be stored at the same path with the same name/extension but with the '_compressed' suffix.
It will work with gltf files (ikari will look for a '_compressed' counterpart) but only if the
texture is in a separate file and not embedded in the gltf file.
Usage: clikari compress_textures --search_folder /path/to/folder [OPTIONS]
Options:
--search_folder FOLDERNAME Required The folder to search in to find textures to compress
--search_folder FOLDER Required The folder to search in to find textures to compress
--threads_per_texture VAL Optional The number of threads that will be used per texture.
Textures will also be processed in parallel if possible,
according to the formula: (cpu_count / threads_per_texture).ceil().
Expand All @@ -40,12 +44,30 @@ Pre-process skybox file(s) for use in ikari
Usage: clikari process_skybox --background_path /path/to/background.jpg [OPTIONS]
Options:
--background_path FILEPATH Required The background image of the skybox (this will be the background of your scene)
--environment_hdr_path FILEPATH Optional The hdr environment map (used for ambient lighting and reflections)
Background image is used if not defined
--help Optional Display this help message
--background_path FILE Required The background image of the skybox (this will be the background of your scene)
--environment_hdr_path FILE Optional The hdr environment map (used for ambient lighting and reflections)
Background image is used if option is not supplied
--out_path Required Output file path
--help Optional Display this help message
";

enum CommandName {
CompressTextures,
ProcessSkybox,
}

impl FromStr for CommandName {
type Err = &'static str;

fn from_str(input: &str) -> Result<Self, Self::Err> {
match input {
"compress_textures" => Ok(CommandName::CompressTextures),
"process_skybox" => Ok(CommandName::ProcessSkybox),
_ => Err("Command not recognized"),
}
}
}

enum Command {
Help,
CompressTextures(TextureCompressorArgs),
Expand All @@ -64,41 +86,53 @@ impl Command {
pub fn from_env() -> Result<Self, ArgParseError> {
let mut args = pico_args::Arguments::from_env();

if args.contains("compress_textures") {
if args.contains("--help") {
return Ok(Self::CompressTexturesHelp);
let error_mapper = |err| ArgParseError::Root(format!("{err}"));
let command_result: Result<CommandName, _> =
args.value_from_str("--command").map_err(error_mapper);

match command_result {
Ok(CommandName::CompressTextures) => {
if args.contains("--help") {
return Ok(Self::CompressTexturesHelp);
}

let error_mapper = |err| ArgParseError::CompressTextures(format!("{err}"));
return Ok(Self::CompressTextures(TextureCompressorArgs {
search_folder: args
.value_from_str("--search_folder")
.map_err(error_mapper)?,
threads_per_texture: args
.opt_value_from_str("--threads_per_texture")
.map_err(error_mapper)?,
force: args.contains("--force"),
}));
}

return Ok(Self::CompressTextures(TextureCompressorArgs {
search_folder: args
.value_from_str("--search_folder")
.map_err(|err| ArgParseError::CompressTextures(format!("{err}")))?,
threads_per_texture: args
.opt_value_from_str("--threads_per_texture")
.map_err(|err| ArgParseError::CompressTextures(format!("{err}")))?,
force: args.contains("--force"),
}));
}

if args.contains("process_skybox") {
if args.contains("--help") {
return Ok(Self::ProcessSkyboxHelp);
Ok(CommandName::ProcessSkybox) => {
if args.contains("--help") {
return Ok(Self::ProcessSkyboxHelp);
}

let error_mapper = |err| ArgParseError::ProcessSkybox(format!("{err}"));
return Ok(Self::ProcessSkybox(SkyboxProcessorArgs {
background_path: args
.value_from_str("--background_path")
.map_err(error_mapper)?,
environment_hdr_path: args
.opt_value_from_str("--environment_hdr_path")
.map_err(error_mapper)?,
out_path: args.value_from_str("--out_path").map_err(error_mapper)?,
}));
}

return Ok(Self::ProcessSkybox(SkyboxProcessorArgs {
background_path: args
.value_from_str("--background_path")
.map_err(|err| ArgParseError::ProcessSkybox(format!("{err}")))?,
environment_hdr_path: args
.opt_value_from_str("--environment_hdr_path")
.map_err(|err| ArgParseError::ProcessSkybox(format!("{err}")))?,
}));
}
_ => {}
};

if args.contains("--help") {
return Ok(Self::Help);
}

// only show missing command error if --help is not supplied
command_result?;

Err(ArgParseError::Root(String::from("No command specified")))
}
}
Expand Down
130 changes: 121 additions & 9 deletions clikari/src/skybox_processor.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,130 @@
use std::path::PathBuf;

use ikari::{
renderer::{
BaseRenderer, BindedSkybox, Renderer, SkyboxBackgroundPath, SkyboxHDREnvironmentPath,
},
texture::Texture,
};
use image::{ImageBuffer, Rgba};

const DXC_PATH: &str = "dxc/";

pub struct SkyboxProcessorArgs {
pub background_path: PathBuf,
pub environment_hdr_path: Option<PathBuf>,
pub out_path: PathBuf,
}

pub fn run(args: SkyboxProcessorArgs) {
// let base_render_state = {
// let backends = if cfg!(target_os = "windows") {
// wgpu::Backends::from(wgpu::Backend::Dx12)
// // wgpu::Backends::PRIMARY
// } else {
// wgpu::Backends::PRIMARY
// };
// BaseRenderer::new(&window, backends, wgpu::PresentMode::AutoNoVsync).await
// };
if let Err(err) = ikari::block_on(run_internal(args)) {
log::error!("Error: {err}\n{}", err.backtrace());
}
}

pub async fn run_internal(args: SkyboxProcessorArgs) -> anyhow::Result<()> {
let backends = if cfg!(target_os = "windows") {
wgpu::Backends::from(wgpu::Backend::Dx12)
// wgpu::Backends::PRIMARY
} else {
wgpu::Backends::PRIMARY
};

let base_renderer = BaseRenderer::offscreen(backends, Some(DXC_PATH.into())).await?;
let mut renderer =
Renderer::new(base_renderer, wgpu::TextureFormat::Bgra8Unorm, (1, 1)).await?;

renderer.base.device.start_capture();

let bindable_skybox = ikari::asset_loader::make_bindable_skybox(
SkyboxBackgroundPath::Equirectangular {
image_path: args
.background_path
.to_str()
.expect("background_path was not valid unicode"),
},
args.environment_hdr_path
.as_ref()
.map(
|environment_hdr_path| SkyboxHDREnvironmentPath::Equirectangular {
image_path: environment_hdr_path
.to_str()
.expect("environment_hdr_path was not valid unicode"),
},
),
)
.await?;

let binded_skybox =
ikari::asset_loader::bind_skybox(&renderer.base, &renderer.constant_data, bindable_skybox)?;

let BindedSkybox {
background,
diffuse_environment_map,
specular_environment_map,
} = binded_skybox;

{
let texture = background;
let path = "background.png";

let texture_bytes = texture.to_bytes(&renderer.base).await?;

// TODO: use ikari:: texture compression module to compress it as srgb
// basis_universal doesn't support BC6 at the moment

// let buffer = ImageBuffer::<Rgba<u8>, _>::from_raw(
// texture.size.width,
// texture.size.height * texture.size.depth_or_array_layers,
// texture
// .to_bytes(&renderer.base)
// .await?
// .iter()
// .flatten()
// .copied()
// .collect::<Vec<_>>(),
// )
// .unwrap();
// buffer.save(path).unwrap();
}

renderer.base.device.stop_capture();

/* {
let texture = diffuse_environment_map;
let path = "diffuse_environment_map.png";
let buffer = ImageBuffer::<Rgba<u8>, _>::from_raw(
texture.size.width * texture.size.depth_or_array_layers,
texture.size.height,
texture
.to_bytes(&renderer.base)
.await?
.iter()
.flatten()
.copied()
.collect::<Vec<_>>(),
)
.unwrap();
buffer.save(path).unwrap();
}
{
let texture = specular_environment_map;
let path = "specular_environment_map.png";
let buffer = ImageBuffer::<Rgba<u8>, _>::from_raw(
texture.size.width * texture.size.depth_or_array_layers,
texture.size.height,
texture
.to_bytes(&renderer.base)
.await?
.iter()
.flatten()
.copied()
.collect::<Vec<_>>(),
)
.unwrap();
buffer.save(path).unwrap();
} */

Ok(())
}
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions example_game/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ikari::scene::*;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

const DXC_PATH: &str = "ikari/dxc/";
const DXC_PATH: &str = "dxc/";

async fn start() {
let run_result = async {
Expand Down Expand Up @@ -55,7 +55,7 @@ async fn start() {

let (base_renderer, surface_data) = {
let backends = if cfg!(target_os = "windows") {
wgpu::Backends::from(wgpu::Backend::Dx12)
wgpu::Backends::from(wgpu::Backend::Vulkan)
// wgpu::Backends::PRIMARY
} else {
wgpu::Backends::PRIMARY
Expand Down
1 change: 1 addition & 0 deletions ikari/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ iced_aw = { git = "https://github.com/iced-rs/iced_aw.git", branch = "main", def
"card",
] }
wasm_thread = { version = "0.2.0", features = ["es_modules"] }
futures-intrusive = "0.5.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
basis-universal = "0.3.0"
zstd = "0.12.4"
Expand Down
Loading

0 comments on commit fa18943

Please sign in to comment.