rename from libretrogd to ggdt
i'll admit i never totally liked the name "libretrogd"
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"libretrogd",
|
||||
"ggdt",
|
||||
"examples/*",
|
||||
]
|
||||
|
|
23
README.md
|
@ -1,17 +1,14 @@
|
|||
# libretrogd
|
||||
# ggdt: Gered's Game Dev Tools
|
||||
|
||||
Rust library / mini-framework for "retro-style" games development.
|
||||
This is a purely for-fun project of mine. It's a personal set of retro-like/inspired game development tools for
|
||||
use in my own projects.
|
||||
|
||||
This is a not-so-serious project of mine for hobbyist game dev efforts of my own with some silly DOS-inspired
|
||||
limitations built in. The major one being that graphics are limited to 256 colours, like DOS VGA mode 13h, with a
|
||||
similar low-resolution.
|
||||
It started with a focus on DOS "VGA mode 13h"-style limitations, but is not going to be limited to just that
|
||||
into the future and will be expanded on as I need it to do other things. It should be noted that in this project I will
|
||||
do a lot of (poor) reinventing of the wheel ... because it's fun. Stringing together existing libraries all the time
|
||||
is dull after a while.
|
||||
|
||||
I'm not an expert in Rust and am probably still doing a great many things unidiomatically. But I'm learning, and
|
||||
that is at least half the point of this project in the first place.
|
||||
|
||||
See the `/examples` directory for some demo apps. These will be added to over time.
|
||||
|
||||
---
|
||||
|
||||
**This is FAR from finished and is not really what I'd consider "production-ready" ... and it probably won't be at any
|
||||
point in the near future.**
|
||||
|
||||
This project is one I started working on to help teach myself Rust and to get more comfortable working with it. As such,
|
||||
there is almost certainly a lot of bad code in here!
|
||||
|
|
|
@ -5,4 +5,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "=1.0.55"
|
||||
libretrogd = { path = "../../libretrogd" }
|
||||
ggdt = { path = "../../ggdt" }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# libretrogd - Audio Playback Example
|
||||
# ggdt - Audio Playback Example
|
||||
|
||||
Simple example of playing back one or more sounds loaded from WAV files simultaneously.
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::path::Path;
|
|||
|
||||
use anyhow::Result;
|
||||
|
||||
use libretrogd::audio::*;
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::system::*;
|
||||
use libretrogd::utils::rnd_value;
|
||||
use ggdt::audio::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::system::*;
|
||||
use ggdt::utils::rnd_value;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct AudioChannelStatus {
|
||||
|
|
|
@ -5,4 +5,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "=1.0.55"
|
||||
libretrogd = { path = "../../libretrogd" }
|
||||
ggdt = { path = "../../ggdt" }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# libretrogd - 'Flying Balls' Demo
|
||||
# ggdt - 'Flying Balls' Demo
|
||||
|
||||
Just a silly demo. Very minimal.
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@ use std::path::Path;
|
|||
|
||||
use anyhow::Result;
|
||||
|
||||
use libretrogd::*;
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::math::*;
|
||||
use libretrogd::system::*;
|
||||
use libretrogd::utils::*;
|
||||
use ggdt::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::math::*;
|
||||
use ggdt::system::*;
|
||||
use ggdt::utils::*;
|
||||
|
||||
const NUM_BALLS: usize = 128;
|
||||
const NUM_BALL_SPRITES: usize = 16;
|
||||
|
|
|
@ -5,4 +5,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "=1.0.55"
|
||||
libretrogd = { path = "../../libretrogd", features = [] }
|
||||
ggdt = { path = "../../ggdt", features = [] }
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# libretrogd - 'Flying Balls' Demo v2
|
||||
# ggdt - 'Flying Balls' Demo v2
|
||||
|
||||
Extension of the original 'Flying Balls' demo found in this repository under `/examples/balls`. This one is re-done
|
||||
with some more effects, but with the major difference being utilization of the entity, events, and states support from
|
||||
libretrogd.
|
||||
ggdt.
|
||||
|
||||
Simply do `cargo run` from this directory to try it out.
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use libretrogd::*;
|
||||
use libretrogd::entities::*;
|
||||
use libretrogd::events::*;
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::math::*;
|
||||
use libretrogd::utils::*;
|
||||
use ggdt::*;
|
||||
use ggdt::entities::*;
|
||||
use ggdt::events::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::math::*;
|
||||
use ggdt::utils::*;
|
||||
|
||||
use crate::states::*;
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::path::Path;
|
|||
|
||||
use anyhow::Result;
|
||||
|
||||
use libretrogd::states::*;
|
||||
use libretrogd::system::*;
|
||||
use ggdt::states::*;
|
||||
use ggdt::system::*;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::states::*;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use libretrogd::entities::*;
|
||||
use libretrogd::events::*;
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::math::*;
|
||||
use libretrogd::states::*;
|
||||
use libretrogd::system::*;
|
||||
use ggdt::entities::*;
|
||||
use ggdt::events::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::math::*;
|
||||
use ggdt::states::*;
|
||||
use ggdt::system::*;
|
||||
|
||||
use crate::*;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "=1.0.55"
|
||||
libretrogd = { path = "../../libretrogd", features = [] }
|
||||
ggdt = { path = "../../ggdt", features = [] }
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
serde_json = "1.0.79"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# libretrogd - 'Slime Stabbing Simulator' Demo
|
||||
# ggdt - 'Slime Stabbing Simulator' Demo
|
||||
|
||||
A fairly more involved demo which was originally written to test out and learn how good/bad libretrogd's entity,
|
||||
A fairly more involved demo which was originally written to test out and learn how good/bad ggdt's entity,
|
||||
events and state management support is to use in practice. I learnt a lot from it, and have many ideas to improve
|
||||
things now.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use libretrogd::entities::*;
|
||||
use libretrogd::events::*;
|
||||
use ggdt::entities::*;
|
||||
use ggdt::events::*;
|
||||
|
||||
use crate::Core;
|
||||
use crate::entities::*;
|
||||
|
|
|
@ -2,10 +2,10 @@ use std::collections::HashMap;
|
|||
use std::path::Path;
|
||||
use std::rc::Rc;
|
||||
|
||||
use libretrogd::entities::*;
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::math::*;
|
||||
use libretrogd::utils::rnd_value;
|
||||
use ggdt::entities::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::math::*;
|
||||
use ggdt::utils::rnd_value;
|
||||
|
||||
use crate::{Core, Game, TILE_HEIGHT, TILE_WIDTH, TileMap};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use libretrogd::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||
use libretrogd::entities::*;
|
||||
use libretrogd::math::*;
|
||||
use ggdt::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||
use ggdt::entities::*;
|
||||
use ggdt::math::*;
|
||||
|
||||
use crate::{Core, TILE_HEIGHT, TILE_WIDTH};
|
||||
use crate::entities::*;
|
||||
|
|
|
@ -6,12 +6,12 @@ use std::rc::Rc;
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use libretrogd::base::*;
|
||||
use libretrogd::entities::*;
|
||||
use libretrogd::events::*;
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::math::*;
|
||||
use libretrogd::system::*;
|
||||
use ggdt::base::*;
|
||||
use ggdt::entities::*;
|
||||
use ggdt::events::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::math::*;
|
||||
use ggdt::system::*;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::states::*;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::path::Path;
|
||||
|
||||
use libretrogd::base::*;
|
||||
use libretrogd::entities::*;
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::states::*;
|
||||
use libretrogd::system::*;
|
||||
use ggdt::base::*;
|
||||
use ggdt::entities::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::states::*;
|
||||
use ggdt::system::*;
|
||||
|
||||
use crate::entities::*;
|
||||
use crate::Game;
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::path::Path;
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::states::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::states::*;
|
||||
|
||||
use crate::{Game, TILE_HEIGHT, TILE_WIDTH};
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ use std::path::Path;
|
|||
use anyhow::{Context, Result};
|
||||
use serde::Deserialize;
|
||||
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::math::*;
|
||||
use libretrogd::utils::rnd_value;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::math::*;
|
||||
use ggdt::utils::rnd_value;
|
||||
|
||||
use crate::{TILE_HEIGHT, TILE_WIDTH};
|
||||
|
||||
|
|
|
@ -5,4 +5,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "=1.0.55"
|
||||
libretrogd = { path = "../../libretrogd" }
|
||||
ggdt = { path = "../../ggdt" }
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# libretrogd - Complicated Template/Example
|
||||
# ggdt - Complicated Template/Example
|
||||
|
||||
A more complicated usage example that can also serve as a new project template to get started using libretrogd.
|
||||
A more complicated usage example that can also serve as a new project template to get started using ggdt.
|
||||
|
||||
This example project shows a relatively simple set up of using libretrogd's entity, events and state management
|
||||
This example project shows a relatively simple set up of using ggdt's entity, events and state management
|
||||
systems all together.
|
||||
|
||||
Run `cargo run` from this directory to try it out.
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use anyhow::{Context, Result};
|
||||
|
||||
use libretrogd::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||
use libretrogd::base::*;
|
||||
use libretrogd::entities::*;
|
||||
use libretrogd::events::*;
|
||||
use libretrogd::math::*;
|
||||
use libretrogd::states::*;
|
||||
use libretrogd::system::*;
|
||||
use libretrogd::utils::rnd_value;
|
||||
use ggdt::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||
use ggdt::base::*;
|
||||
use ggdt::entities::*;
|
||||
use ggdt::events::*;
|
||||
use ggdt::math::*;
|
||||
use ggdt::states::*;
|
||||
use ggdt::system::*;
|
||||
use ggdt::utils::rnd_value;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -5,4 +5,4 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "=1.0.55"
|
||||
libretrogd = { path = "../../libretrogd" }
|
||||
ggdt = { path = "../../ggdt" }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# libretrogd - Minimal Template/Example
|
||||
# ggdt - Minimal Template/Example
|
||||
|
||||
A very minimal usage example that can also serve as a new project template to get started using libretrogd.
|
||||
A very minimal usage example that can also serve as a new project template to get started using ggdt.
|
||||
|
||||
Run `cargo run` from this directory to try it out.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use libretrogd::{SCREEN_BOTTOM, SCREEN_RIGHT};
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::system::*;
|
||||
use libretrogd::utils::rnd_value;
|
||||
use ggdt::{SCREEN_BOTTOM, SCREEN_RIGHT};
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::system::*;
|
||||
use ggdt::utils::rnd_value;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut system = SystemBuilder::new().window_title("Minimal Template").vsync(true).build()?;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "libretrogd"
|
||||
description = "A 'retro'-like game development library, for funsies."
|
||||
name = "ggdt"
|
||||
description = "Gered's Game Dev Tools. A strictly for-fun, retro-style game dev set of tools and other code to help with my own projects."
|
||||
version = "0.1.0"
|
||||
authors = ["Gered King <gered@blarg.ca>"]
|
||||
edition = "2021"
|
|
@ -1,7 +1,7 @@
|
|||
use criterion::{black_box, Criterion, criterion_group, criterion_main};
|
||||
|
||||
use libretrogd::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||
use libretrogd::graphics::*;
|
||||
use ggdt::{SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||
use ggdt::graphics::*;
|
||||
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut source = Bitmap::new(SCREEN_WIDTH, SCREEN_HEIGHT).unwrap();
|
|
@ -2,8 +2,8 @@ use std::path::Path;
|
|||
|
||||
use criterion::{black_box, Criterion, criterion_group, criterion_main};
|
||||
|
||||
use libretrogd::graphics::*;
|
||||
use libretrogd::math::*;
|
||||
use ggdt::graphics::*;
|
||||
use ggdt::math::*;
|
||||
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut framebuffer = Bitmap::new(320, 240).unwrap();
|
|
@ -2,7 +2,7 @@ use std::io::Cursor;
|
|||
|
||||
use criterion::{black_box, Criterion, criterion_group, criterion_main};
|
||||
|
||||
use libretrogd::graphics::*;
|
||||
use ggdt::graphics::*;
|
||||
|
||||
pub static SMALL_GIF_FILE_BYTES: &[u8] = include_bytes!("../test-assets/test.gif");
|
||||
pub static LARGE_GIF_FILE_BYTES: &[u8] = include_bytes!("../test-assets/test_image.gif");
|
|
@ -5,10 +5,10 @@
|
|||
//! way for a long while yet. And, truthfully, I suspect I may rip this out eventually. Maybe.
|
||||
//!
|
||||
//! The very-long-winded rationale here is that as I've started building more and more things with
|
||||
//! libretrogd, I started implementing games/apps using a particular pattern which I was largely
|
||||
//! ggdt, I started implementing games/apps using a particular pattern which I was largely
|
||||
//! pushed towards due to the Rust borrow-checker (as is often the case with Rust). My games/apps
|
||||
//! needed to keep their state (for clarity, the word 'state' here is being used very broadly to
|
||||
//! refer to all game/app state, and not just referring to the stuff inside `libretrogd::states`)
|
||||
//! refer to all game/app state, and not just referring to the stuff inside `ggdt::states`)
|
||||
//! somewhere and my needs were a bit complicated since my game/app state often included things
|
||||
//! which needed to get passed other things from inside that same "bag" of state.
|
||||
//!
|
||||
|
@ -19,11 +19,11 @@
|
|||
//! pub enum Event { /* .. various events here .. */ }
|
||||
//! struct App {
|
||||
//! pub delta: f32,
|
||||
//! pub system: libretrogd::system::System,
|
||||
//! pub entities: libretrogd::entities::Entities,
|
||||
//! pub component_systems: libretrogd::entities::ComponentSystems<App, App>, // oh no! :'(
|
||||
//! pub event_publisher: libretrogd::events::EventPublisher<Event>,
|
||||
//! pub event_listeners: libretrogd::events::EventListeners<Event, App>, // oh no again! :'(
|
||||
//! pub system: ggdt::system::System,
|
||||
//! pub entities: ggdt::entities::Entities,
|
||||
//! pub component_systems: ggdt::entities::ComponentSystems<App, App>, // oh no! :'(
|
||||
//! pub event_publisher: ggdt::events::EventPublisher<Event>,
|
||||
//! pub event_listeners: ggdt::events::EventListeners<Event, App>, // oh no again! :'(
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
@ -42,21 +42,21 @@
|
|||
//! // "core" because what the heck else do i call this? "InnerContext"? "InnerApp"? ...
|
||||
//! struct Core {
|
||||
//! pub delta: f32,
|
||||
//! pub system: libretrogd::system::System,
|
||||
//! pub entities: libretrogd::entities::Entities,
|
||||
//! pub event_publisher: libretrogd::events::EventPublisher<Event>,
|
||||
//! pub system: ggdt::system::System,
|
||||
//! pub entities: ggdt::entities::Entities,
|
||||
//! pub event_publisher: ggdt::events::EventPublisher<Event>,
|
||||
//! }
|
||||
//!
|
||||
//! // i guess this is a bit more obvious what to call it, but still ... doesn't sit right with me
|
||||
//! struct App {
|
||||
//! pub core: Core,
|
||||
//! pub component_systems: libretrogd::entities::ComponentSystems<Core, Core>,
|
||||
//! pub event_listeners: libretrogd::events::EventListeners<Event, Core>,
|
||||
//! pub component_systems: ggdt::entities::ComponentSystems<Core, Core>,
|
||||
//! pub event_listeners: ggdt::events::EventListeners<Event, Core>,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This structure seemed to work generally well and I've gotten pretty far with it. Keeping the
|
||||
//! main `libretrogd::states::States` instance _separate_ was also key, and never really a problem
|
||||
//! main `ggdt::states::States` instance _separate_ was also key, and never really a problem
|
||||
//! since that can (and should) just live at the top in your main loop. Easy.
|
||||
//!
|
||||
//! I ended up with some common bits of code that I'd always add to projects using this structure,
|
||||
|
@ -81,16 +81,16 @@
|
|||
//! // with. you'd probably want to put your game/app resources/assets on this struct too.
|
||||
//! struct Core {
|
||||
//! pub delta: f32,
|
||||
//! pub system: libretrogd::system::System,
|
||||
//! pub entities: libretrogd::entities::Entities,
|
||||
//! pub event_publisher: libretrogd::events::EventPublisher<Event>,
|
||||
//! pub system: ggdt::system::System,
|
||||
//! pub entities: ggdt::entities::Entities,
|
||||
//! pub event_publisher: ggdt::events::EventPublisher<Event>,
|
||||
//! }
|
||||
//!
|
||||
//! // "Support" because it contains things that support the main/core game state?
|
||||
//! // kinda grasping at straws here maybe ...
|
||||
//! struct Support {
|
||||
//! pub component_systems: libretrogd::entities::ComponentSystems<Core, Core>,
|
||||
//! pub event_listeners: libretrogd::events::EventListeners<Event, Core>,
|
||||
//! pub component_systems: ggdt::entities::ComponentSystems<Core, Core>,
|
||||
//! pub event_listeners: ggdt::events::EventListeners<Event, Core>,
|
||||
//! }
|
||||
//!
|
||||
//! // better, maybe?
|
||||
|
@ -103,7 +103,7 @@
|
|||
//! Even though it's another struct being added, I do like this more, despite the naming
|
||||
//! uncertainty.
|
||||
//!
|
||||
//! So, with this being my current preferred way to architect a libretrogd-using project, I created
|
||||
//! So, with this being my current preferred way to architect a ggdt-using project, I created
|
||||
//! some traits here in this module to formalize this all a bit more. `CoreState` and (optionally)
|
||||
//! `CoreStateWithEvents` are what you'd make your project's `Core` struct (as shown in the above
|
||||
//! example code) implement, while `SupportSystems` and (optionally) `SupportSystemsWithEvents`
|
||||
|
@ -112,7 +112,7 @@
|
|||
//!
|
||||
//! Once you have all this (which ironically ends up being _more_ code than if you'd not used these
|
||||
//! traits ... heh), you can now optionally use the `main_loop` function to get a ready-to-use
|
||||
//! main loop which is set up to use a `libretrogd::states::State` state manager.
|
||||
//! main loop which is set up to use a `ggdt::states::State` state manager.
|
||||
//!
|
||||
//! Having said all of this ... again, I will reiterate that I don't believe any of this has reached
|
||||
//! anything resembling a "good design" ... yet. There may be a good design hidden somewhere in
|
|
@ -2,9 +2,9 @@
|
|||
// us to *not* expose SDL2 types back to applications, thus preventing them
|
||||
// from being required to explicitly add SDL2 as a dependency even if they
|
||||
// never call into SDL2 directly anywhere (the SDL2 dependency can just be
|
||||
// provided automatically by libretrogd).
|
||||
// provided automatically by ggdt).
|
||||
//
|
||||
// Also note, that with the intended use-cases (for now) that I have for libretrogd,
|
||||
// Also note, that with the intended use-cases (for now) that I have for ggdt,
|
||||
// I don't really care about all possible SDL2 events that could be raised. Thus,
|
||||
// I only map the SDL2 events which I care about here. I will extend this in the
|
||||
// future should I require it.
|
|
@ -477,7 +477,7 @@ impl System {
|
|||
/// should quit. Otherwise, returns false.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use libretrogd::system::*;
|
||||
/// use ggdt::system::*;
|
||||
///
|
||||
/// let mut system = SystemBuilder::new().window_title("Example").build().unwrap();
|
||||
///
|
||||
|
@ -491,7 +491,7 @@ impl System {
|
|||
/// main loop. For example:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use libretrogd::system::*;
|
||||
/// use ggdt::system::*;
|
||||
///
|
||||
/// let mut system = SystemBuilder::new().window_title("Example").build().unwrap();
|
||||
///
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 919 B |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |