Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

133 changed files with 484 additions and 1526 deletions

View file

@ -1,41 +1,28 @@
# ParadiSO - eine minimale 2D-Grafikengine # ParadisSO - eine minimale 2D-Grafikengine
**ParadiSO** wurde als stark abgespeckte 2D-Version meiner `pixwerx`-Engine konzipiert. _ParadiSO_ verfolgt einen minimalistischen Ansatz für 2D-Grafik zu Bildungszwecken. Es verwendet modernes C++ und ein datengetriebenes Design, jedoch keine ECS (Entity Component System). **ParadiSO** wurde als stark abgespeckte 2D-Version meiner `pixwerx`-Engine konzipiert. *ParadiSO* verfolgt einen minimalistischen Ansatz für 2D-Grafik zu Bildungszwecken. Es verwendet modernes C++ und ein datengetriebenes Design, jedoch keine ECS (Entity Component System).
## Bildungszwecke ## Bildungszwecke
Einige Argumente für seinen Bildungsaspekt: Einige Argumente für seinen Bildungsaspekt:
- Kombination verschiedener Konzepte und Paradigmen zur Erstellung ausdrucksstarker, aber knappen Codes - Kombination verschiedener Konzepte und Paradigmen zur Erstellung ausdrucksstarker, aber knappen Codes
- Stark von Rust-Code inspiriert - Stark von Rust-Code inspiriert
- Für den mathematischen Code wird eine sofortige Auswertung verwendet (keine Expression-Templates), jedoch mit der Verwendung von `constexpr`, um eventuelle Performance-Overheads auszugleichen und optimale Vektorisierung zu erreichen. - Für den mathematischen Code wird eine sofortige Auswertung verwendet (keine Expression-Templates), jedoch mit der Verwendung von `constexpr`, um eventuelle Performance-Overheads auszugleichen und optimale Vektorisierung zu erreichen.
- Versteckt alte `C`-APIs hinter einer modernisierten Fassade - Versteckt alte `C`-APIs hinter einer modernisierten Fassade
- Es lehnt sich stark an die STL und ihre Algorithmen an - Es lehnt sich stark an die STL und ihre Algorithmen an
## Minimalistisch ## Minimalistisch
Da diese Engine einige Muster und Designkonzepte zeigen soll, versucht sie, unnötigen Ballast zu vermeiden. Da diese Engine einige Muster und Designkonzepte zeigen soll, versucht sie, unnötigen Ballast zu vermeiden.
## Abhängigkeiten ## Abhängigkeiten
ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hier erwähnt werden: ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hier erwähnt werden:
- [GLFW 3.3.8](https://github.com/glfw/glfw) - [GLFW 3.3.8](https://github.com/glfw/glfw)
- [GLAD](https://github.com/Dav1dde/glad) - [GLAD](https://github.com/Dav1dde/glad)
- [STB image](https://github.com/nothings/stb)
## Toolchains ## Zuarbeiten
ParadiSO kann auf verschiedenen Plattformen gebaut werden * [TimePlex](https://code.technotecture.net/Timeplex)
- Windows (Visual Studio Build Tools 2022)
- MacOS (clang 14 or later)
- Linux (clang 14 or later, gcc 13.2.1)
Andere Kombinationen sind möglich aber nicht getestet.
## Beiträge
- [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build
- [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader
- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone

View file

@ -1,16 +1,16 @@
# ParadiSO - a minimal 2D graphics engine # ParadisSO - a minimal 2D graphics engine
**ParadiSO** was conceived as a heavily stripped down 2D version of my `pixwerx` engine. _ParadiSO_ mimics a minimalistic approach to 2D graphics for educational purposes. It uses modern C++ and a data-driven design, but no ECS. **ParadiSO** was conceived as a heavily stripped down 2D version of my `pixwerx` engine. *ParadiSO* mimics a minimalistic approach to 2D graphics for educational purposes. It uses modern C++ and a data-driven design, but no ECS.
## Educational ## Educational
Some arguments for its educational side: Some arguments for its educational side:
- mix and match of various concepts and paradigms to write expressive but concise code * mix and match of various concepts and paradigms to write expressive but concise code
- heavily inspired by Rust code * heavily inspired by Rust code
- math code is eager evaluation but `constexpr` to compensate overheads * math code is eager evaluation but `constexpr` to compensate overheads
- hides old-style `C` APIs behind a renovated facade * hides old-style `C` APIs behind a renovated facade
- it leans heavily on the STL and its algorithms * it leans heavily on the STL and its algorithms
## Minimal ## Minimal
@ -20,22 +20,9 @@ Because this engine should show some patterns and design concepts it tries to av
ParadiSO comes with batteries included. However, it should be mentioned here: ParadiSO comes with batteries included. However, it should be mentioned here:
- [GLFW 3.3.8](https://github.com/glfw/glfw) * [GLFW 3.3.8](https://github.com/glfw/glfw)
- [GLAD](https://github.com/Dav1dde/glad) * [GLAD](https://github.com/Dav1dde/glad)
- [STB image](https://github.com/nothings/stb)
## Toolchains
ParadiSO is being developed to work on all major desktop systems.
- Windows (Visual Studio Build Tools 2022)
- MacOS (clang 14 or later)
- Linux (clang 14 or later, gcc 13.2.1)
Other combinations might work but are untested.
## Contributors ## Contributors
- [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build * [TimePlex](https://code.technotecture.net/Timeplex)
- [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader
- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone

View file

@ -1,50 +0,0 @@
# Todo
Here some ideas for improving this tiny engine:
## Rendering
- [ ] replace the OpenGL renderer with a Vulkan backend
- [ ] add animatable sprites (access to UV mapping and tiling)
- [ ] add a SDF based renderer (parametric tiles and font rendering)
## Game Support
- [ ] audio!
- [ ] some minimal animation system with tweening with different f-curves
## System Level
- [ ] add a `Asset` handler to load cache and manage assets
- [ ] introspection of file system if we load assset
## Design
- [ ] replace some of the 'unkown source' assets
## Build / Dev Support
- [ ] add a test rig either with Snitch or Catch2
- [ ] write some reasonable testcases
- [ ] add CPU and GPU benchmarks to address various issues
# Issues
```sh
Performance counter stats for 'bin/paradiso_pong':
555,35 msec task-clock:u # 0,042 CPUs utilized
0 context-switches:u # 0,000 /sec
0 cpu-migrations:u # 0,000 /sec
4.072 page-faults:u # 7,332 K/sec
319.484.735 cycles:u # 0,575 GHz
358.165.995 instructions:u # 1,12 insn per cycle
86.037.942 branches:u # 154,926 M/sec
2.469.068 branch-misses:u # 2,87% of all branches
13,092775373 seconds time elapsed
0,311565000 seconds user
0,247491000 seconds sys
```
above run with `perf stat bin/paradiso_pong` shows some really bad performance issues.

View file

@ -1,3 +1,3 @@
add_subdirectory(simple) add_subdirectory(simple)
add_subdirectory(pong) add_subdirectory(pong)
add_subdirectory(quickwings) add_subdirectory(flappy_bird)

View file

@ -0,0 +1,11 @@
file(GLOB_RECURSE flappy_bird_src "*.cpp")
file(GLOB_RECURSE flappy_bird_lib "lib/*.hpp" "lib/*.h")
file(GLOB_RECURSE flappy_bird_assets "assets/*")
add_executable(flappy_bird ${flappy_bird_src} ${flappy_bird_lib})
target_link_libraries(flappy_bird paradiso_core)
add_custom_command(TARGET flappy_bird POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/assets/ $<TARGET_FILE_DIR:flappy_bird>/assets)

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 425 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 427 B

After

Width:  |  Height:  |  Size: 427 B

Before After
Before After

View file

@ -0,0 +1,310 @@
/**
* paradiso - Paradigmen der Softwareentwicklung
*
* (c) Copyright 2023 Hartmut Seichter
*
*/
#include <paradiso/bitmap.hpp>
#include <paradiso/context.hpp>
#include <paradiso/geometry.hpp>
#include <paradiso/renderer.hpp>
#include <paradiso/shader.hpp>
#include <paradiso/sprite.hpp>
#include <paradiso/vector.hpp>
#include <paradiso/window.hpp>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <unordered_map>
#include "lib/image_loader.hpp"
const int frame_rate = 60;
struct Background {
paradiso::Sprite backgroundLeft;
paradiso::Sprite backgroundRight;
paradiso::Sprite grassLeft;
paradiso::Sprite grassRight;
paradiso::Sprite* scrolling[2] = {&backgroundLeft, &backgroundRight};
Background() {
auto backgroundImage =
image_loader::load(std::string("background-day.png"));
backgroundLeft = paradiso::Sprite{
.bitmap = backgroundImage,
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
.scale = paradiso::Vector2<float>::make(1.01f, 1.0f)};
backgroundRight = paradiso::Sprite{
.bitmap = backgroundImage,
.pivot = paradiso::Vector2<float>::make(2.0f, 0.0f),
.scale = paradiso::Vector2<float>::make(1.01f, 1.0f)};
auto grassImage = image_loader::load(std::string("base.png"));
grassLeft = paradiso::Sprite{
.bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(0.0f, -1.0f),
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
grassRight = paradiso::Sprite{
.bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(2.0f, -1.0f),
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
}
void draw(const paradiso::Shader& shader) {
for (auto sprite : scrolling) {
if (sprite->pivot.x() <= -2.0f) {
sprite->pivot.x() += 4.0f;
}
sprite->pivot.x() -= 0.001f;
shader.set_uniform("pivot", sprite->pivot);
shader.set_uniform("scale", sprite->scale);
shader.set_uniform("rotation", sprite->rotation);
renderer.draw(*sprite, shader);
}
}
paradiso::Renderer renderer{};
};
struct Grass {
paradiso::Sprite grassLeft;
paradiso::Sprite grassRight;
paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight};
Grass() {
auto grassImage = image_loader::load(std::string("base.png"));
grassLeft = paradiso::Sprite{
.bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(0.0f, -0.9f),
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
grassRight = paradiso::Sprite{
.bitmap = grassImage,
.pivot = paradiso::Vector2<float>::make(2.0f, -0.9f),
.scale = paradiso::Vector2<float>::make(1.0f, 0.33333f)};
}
void draw(const paradiso::Shader& shader) {
for (auto sprite : scrolling) {
if (sprite->pivot.x() <= -2.0f) {
sprite->pivot.x() += 4.0f;
}
sprite->pivot.x() -= 0.035f;
shader.set_uniform("pivot", sprite->pivot);
shader.set_uniform("scale", sprite->scale);
shader.set_uniform("rotation", sprite->rotation);
renderer.draw(*sprite, shader);
}
}
paradiso::Renderer renderer{};
};
struct FlappyBird {
paradiso::Renderer renderer1{};
paradiso::Renderer renderer2{};
paradiso::Renderer renderer3{};
std::array<paradiso::Sprite, 3> birds;
unsigned int flap = 0;
unsigned int flapSpeed = 15; // How many ticks per flap
unsigned int flapCounter = 0; // How many ticks since last flap
float velocity = 0.0f;
const float max_velocity = 0.05f;
const float gravity = -0.004f;
const float move_up_velocity = 0.0055f;
bool move_up = false;
bool paused = true;
const float max_pos = 0.95f;
const float min_pos = -0.5f;
float pos = 0.0f;
float rotation = 0.0f;
FlappyBird() {
float scaleh = 0.07f;
float scalew = scaleh * 1.416666666666667f;
birds = {
paradiso::Sprite{
.bitmap =
image_loader::load(std::string("yellowbird-downflap.png")),
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
.scale = paradiso::Vector2<float>::make(scalew, scaleh)},
paradiso::Sprite{
.bitmap =
image_loader::load(std::string("yellowbird-midflap.png")),
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
.scale = paradiso::Vector2<float>::make(scalew, scaleh)},
paradiso::Sprite{
.bitmap =
image_loader::load(std::string("yellowbird-upflap.png")),
.pivot = paradiso::Vector2<float>::make(0.0f, 0.0f),
.scale = paradiso::Vector2<float>::make(scalew, scaleh)}};
}
void draw(const paradiso::Shader& shader) {
// Update flap state
if (flapCounter < flapSpeed) {
flapCounter++;
} else {
flapCounter = 0;
flap = (flap + 1) % birds.size();
}
auto bird = birds[flap];
bird.pivot.y() = pos;
bird.rotation = rotation;
shader.set_uniform("pivot", bird.pivot);
shader.set_uniform("scale", bird.scale);
shader.set_uniform("rotation", bird.rotation);
switch (flap) {
case 0:
renderer1.draw(bird, shader);
break;
case 1:
renderer2.draw(bird, shader);
break;
case 2:
renderer3.draw(bird, shader);
break;
}
}
void update() {
// Stop game
if (paused)
return;
// Apply gravity
velocity += gravity;
if (move_up)
velocity += move_up_velocity - gravity;
// Cap velocity
if (velocity > max_velocity)
velocity = max_velocity;
if (velocity < -max_velocity)
velocity = -max_velocity;
// Cap position
pos += velocity;
if (pos < min_pos) {
pos = min_pos;
velocity = 0.0f;
}
if (pos > max_pos) {
pos = max_pos;
velocity = 0.0f;
}
// Update rotation
rotation = velocity * 15.0f;
}
// keyboard handler
void on_keyboard(const paradiso::Window::KeyboardInputStack& input) {
if (input.size()) {
paused = false;
bool pressed_up = input.top().key == ' ' || input.top().key == 'W';
if (input.top().action == 1 && pressed_up) {
move_up = true;
} else if (input.top().action == 0 && pressed_up) {
move_up = false;
}
}
}
};
auto main() -> int {
// Ausgabefenster ... sieht aus als wäre es auf dem Stack
auto window = paradiso::Window();
auto size = paradiso::Size{.width = 500, .height = 700};
/*
window.set_resizecallback([](auto& w) -> void {
w.set_size(paradiso::Size{.width = 405, .height = 720});
});
*/
window
.set_size(size) // ... Grösse
.set_position(paradiso::Point{.x = 100, .y = 100}) // ... Position
.set_title("PardiSO.FlappyBird") // ... Titel
.set_visible(true); // ... und jetzt anzeigen!
// der Fenster Kontext
auto ctx = paradiso::Context{};
// ein Shader (Schattierungsprogramm)
auto shader = paradiso::Shader{};
// wir nutzen einen vorgefertigten shader
shader.load_preset(paradiso::Shader::Preset::Sprite);
// ein viewport stellt die Sicht der Kamera dar, d.h. bei quadratischen
// Pixeln sollte hier auch eine dementsprechende Grösse eingestellt
// werden
ctx.set_viewport(paradiso::Rectangle{
.position = paradiso::Point{.x = 0, .y = 0}, .size = size});
// nothing beats a classic look
ctx.set_clearcolor(paradiso::RGBA::from_rgb(0x00, 0x00, 0x00));
// Load
auto background = Background{};
auto grass = Grass{};
auto flappyBird = FlappyBird{};
// timer
// das update führt den hier mitgegebnen Ausdruck innerhalb der internen
// Updates des Fensters auf. Es wird hier auch explizit ein bool gefordert
// damit das update auch zu jederzeit unterbrochen werden kann
while (window.update([&](paradiso::Window& w) -> bool {
ctx.set_viewport(paradiso::Rectangle{
.position = paradiso::Point{.x = 0, .y = 0}, .size = size});
ctx.clear();
auto t1 = std::chrono::high_resolution_clock::now();
// Keyboard and state change
flappyBird.on_keyboard(w.keyboard_input());
flappyBird.update();
// Draw
background.draw(shader);
grass.draw(shader);
flappyBird.draw(shader);
// wait for frame rate
auto t2 = std::chrono::high_resolution_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
auto wait = std::chrono::microseconds(1000000 / frame_rate) - duration;
std::this_thread::sleep_for(wait);
// Quit
return !(w.keyboard_input().size() &&
w.keyboard_input().top().key == 'Q');
})) {
};
return 0;
}

View file

@ -0,0 +1,72 @@
#include <paradiso/rgba.hpp>
#include <paradiso/sprite.hpp>
#include <fstream>
#include <iostream>
#include <optional>
#include <unordered_map>
// STB image loading
#define STB_IMAGE_IMPLEMENTATION
#include "lib/stb_image.h"
#include "lib/image_loader.hpp"
std::unordered_map<std::string, paradiso::Bitmap> image_loader::image_cache =
std::unordered_map<std::string, paradiso::Bitmap>();
paradiso::Bitmap image_loader::load(const std::string& filename) {
if (image_cache.find(filename) == image_cache.end()) {
std::string path = ASSET_PATH + filename;
std::cout << "Loading " << path << std::endl;
auto data = readBMP(path);
image_cache[filename] = data;
}
return image_cache[filename];
}
paradiso::Bitmap image_loader::readBMP(std::string& filename) {
// Load with stb_image
stbi_set_flip_vertically_on_load(true); // flip y axis for OpenGL
int width, height, channels;
unsigned char* image =
stbi_load(filename.c_str(), &width, &height, &channels, 4);
int size = width * height;
if (!image)
throw std::runtime_error("Error loading image");
// Convert to Vector of RGBA
std::vector<paradiso::RGBA> rgba = std::vector<paradiso::RGBA>(size);
for (int i = 0; i < size; i++) {
// get rgba values
int pos = i * 4;
int r = image[pos + 0];
int g = image[pos + 1];
int b = image[pos + 2];
int a = image[pos + 3];
// bug in from_rgba. it expects bgra, not rgba
auto val = paradiso::RGBA::from_rgba(b, g, r, a);
rgba[i] = val;
}
// rotate image by 90 degrees CW
std::vector<paradiso::RGBA> rotated = std::vector<paradiso::RGBA>(size);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int pos = y * width + x;
int pos_rotated = x * height + (height - y - 1);
rotated[pos_rotated] = rgba[pos];
}
}
// free image
stbi_image_free(image);
return paradiso::Bitmap::from_data(
paradiso::Size{static_cast<unsigned int>(height),
static_cast<unsigned int>(width)},
rotated);
}

View file

@ -0,0 +1,24 @@
#pragma once
#include <paradiso/bitmap.hpp>
#include <optional>
#include <string>
#include <unordered_map>
class image_loader {
public:
/**
* @brief loads an Image from a file
* @param[in] filename path to file
* @return bitmap from file
*/
static paradiso::Bitmap load(const std::string& filename);
private:
static inline const std::string ASSET_PATH = "assets/";
static std::unordered_map<std::string, paradiso::Bitmap> image_cache;
static paradiso::Bitmap readBMP(std::string& filename);
};

View file

@ -1,7 +1,7 @@
/** /**
* paradiso - Paradigmen der Softwareentwicklung * paradiso - Paradigmen der Softwareentwicklung
* *
* (c) Copyright 2023-2024 Hartmut Seichter * (c) Copyright 2023 Hartmut Seichter
* *
*/ */
@ -16,6 +16,7 @@
#include <unordered_map> #include <unordered_map>
#include <iomanip>
#include <iostream> #include <iostream>
struct PongStage { struct PongStage {
@ -85,7 +86,7 @@ struct PongPaddle {
velocity_horizontal *= whoopiness; velocity_horizontal *= whoopiness;
sprite.pivot.x() += velocity_horizontal; sprite.pivot.x() += velocity_horizontal;
sprite.pivot.x() = std::clamp(sprite.pivot.x(), -0.5f, 0.5f); std::clamp(sprite.pivot.x(), -0.5f, 0.5f);
// update shader uniforms // update shader uniforms
shader.set_uniform("pivot", sprite.pivot); shader.set_uniform("pivot", sprite.pivot);
@ -150,7 +151,7 @@ struct PongBall {
void draw(const paradiso::Shader& shader) { void draw(const paradiso::Shader& shader) {
sprite.pivot.x() = std::clamp(sprite.pivot.x(), -0.5f, 0.5f); std::clamp(sprite.pivot.x(), -0.5f, 0.5f);
// update shader uniforms // update shader uniforms
shader.set_uniform("pivot", sprite.pivot); shader.set_uniform("pivot", sprite.pivot);
@ -165,9 +166,6 @@ struct PongBall {
paradiso::Renderer renderer{}; paradiso::Renderer renderer{};
constexpr void push(const auto& impulse) noexcept { velocity += impulse; } constexpr void push(const auto& impulse) noexcept { velocity += impulse; }
constexpr void whoop(const auto& whoopiness) noexcept { velocity *= whoopiness; }
}; };
auto main() -> int { auto main() -> int {
@ -236,19 +234,6 @@ auto main() -> int {
ball.sprite.pivot.x() = 0.0f; ball.sprite.pivot.x() = 0.0f;
ball.sprite.pivot.y() = 0.9f; ball.sprite.pivot.y() = 0.9f;
} }
// speed adjust
if (w.keyboard_input().top().key == 'N') {
std::cout << "Speed Up!\n";
ball.push(paradiso::Vector2<float>::make(0.f,0.01f));
} else if (w.keyboard_input().top().key == 'M') {
ball.push(paradiso::Vector2<float>::make(0.f,-0.01f));
std::cout << "Speed Lower!\n";
}
} }
ball.interact(stage); ball.interact(stage);

View file

@ -1,20 +0,0 @@
set(quickwings_srcs quickwings.cpp)
set(quickwings_assets
assets/background-day.png
assets/base.png
assets/pipe-green.png
assets/yellowbird-downflap.png
assets/yellowbird-midflap.png
assets/yellowbird-upflap.png
)
set_source_files_properties(${quickwings_assets} PROPERTIES HEADER_FILE_ONLY TRUE)
add_executable(quickwings ${quickwings_srcs} ${quickwings_assets})
target_link_libraries(quickwings paradiso_core)
add_custom_command(TARGET quickwings POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/assets/ $<TARGET_FILE_DIR:quickwings>/assets)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Some files were not shown because too many files have changed in this diff Show more