Compare commits

...

38 Commits

Author SHA1 Message Date
Annika 3acd7de9a7 minor cleanup 2026-07-25 23:50:05 -07:00
Annika 1c2579148e moved textures into their own classes, better tilemapping 2026-07-25 23:47:54 -07:00
Annika e6ce80ce13 basic tilemapping 2026-07-25 21:53:33 -07:00
Annika 5298e75fdb added origin to mapper parameters 2026-07-24 19:06:14 -07:00
Annika eddbb85256 added mappers to rest of primatives 2026-07-24 18:31:49 -07:00
Annika 78ec985f7a header files, cleanup 2026-07-24 18:10:35 -07:00
Annika a89ef52247 added basic mappers 2026-07-24 18:01:59 -07:00
Annika c7cdfd402e started arc/circle plotting algorithm 2026-07-20 15:03:13 -07:00
Annika ee2c66f97b implemented H and V GradientShaders 2026-07-20 14:31:28 -07:00
Annika 8a00e42f75 completed CRTP shader migration 2026-07-20 02:08:40 -07:00
Annika 90df991e7e CRTP shaders on Lines 2026-07-20 02:08:06 -07:00
Annika 3588a41657 CRTP shaders on Lines 2026-07-20 02:04:17 -07:00
Annika 0f0e352fca shaders headerfile, and added CRTP shader to Point 2026-07-20 01:52:30 -07:00
Annika 444143ced9 implemented CRTP shader on ColorShader and Rectangle 2026-07-20 01:41:10 -07:00
Annika b95022de29 stubbed out CRTP shaders 2026-07-08 22:17:50 -07:00
Annika bb30e2df0b brute forced text support, fixed an off-by one, lots to fix 2026-07-08 19:44:37 -07:00
Annika ee0d43dd75 added gradient shaders to all primatives 2026-07-08 17:13:57 -07:00
Annika 89afdfce9b created buffer shader and added shader logic to rectangle 2026-07-08 16:50:17 -07:00
Annika 43c893984f added gradient shaders to line 2026-07-08 16:15:48 -07:00
Annika 9096b01e19 added gradient shaders to point 2026-07-08 15:17:30 -07:00
Annika 27b7640c85 added gradient shaders to triangle primative 2026-07-08 15:08:48 -07:00
Annika f61e3a8237 added gradient shader logic to trapezoids 2026-07-08 14:34:55 -07:00
Annika b7032c3b8e bit of code cleanup 2026-07-08 14:05:42 -07:00
Annika 04afd9eee0 cache optimized rectangle drawing and made sure the methods could be inlined 2026-07-08 13:33:43 -07:00
Annika 85cfdaab49 added shaders, but ran into performance issues. will need refactor 2026-07-07 17:57:25 -07:00
Annika ad2e84c279 implemented shaders, gradients, and uv mapping 2026-07-07 12:17:32 -07:00
Annika 989cb196ed fixed makefile 2026-07-07 08:13:56 -07:00
Annika f09db214cc organized project directory. makefile broken 2026-07-07 08:09:54 -07:00
Annika 1fce028eea stubbed out shaders 2026-07-07 07:46:27 -07:00
Annika aa49a32ace rewrote example.cpp to use composition 2026-07-07 07:25:49 -07:00
Annika 3907c88f31 refeactoring more primatives into their own classes 2026-07-07 06:47:24 -07:00
Annika 19400ed32e split out main loop from draw class 2026-07-07 03:49:24 -07:00
Annika c9d289f923 added missing files 2026-07-07 03:25:10 -07:00
Annika a3142a6b18 major refactor 2026-07-06 17:33:52 -07:00
Annika 64dbdb670c added exit by escape key -xyious 2026-07-06 12:40:35 -07:00
Annika 95e9e92b40 fixed issue with bresenham high detection 2026-07-06 12:23:06 -07:00
Annika 1d27f6e5d1 fixed issue with vertex sorting leading to segfault 2026-07-05 21:05:15 -07:00
Annika c8db7a8933 added helper function to git 2026-07-05 20:56:28 -07:00
50 changed files with 1211 additions and 562 deletions
+19
View File
@@ -0,0 +1,19 @@
shapes:
triangles:
point
line
solid
gradient
rectangle
solid
gradient
blitter (tilemaps)
triangle
solid
gradient
perspective mapping (3D!!!)
quad
solid
gradient (charts)
blitter (isometric)
affine mapping (sprite rotation and scaling)
+10 -10
View File
@@ -1,5 +1,5 @@
CC ?= gcc
CFLAGS := -Wall -Wextra -O2 $(shell pkg-config --cflags wayland-client 2>/dev/null)
CFLAGS := -Wall -Wextra -O3 $(shell pkg-config --cflags wayland-client 2>/dev/null)
LDFLAGS := $(shell pkg-config --libs wayland-client 2>/dev/null)
# Fallback if pkg-config is unavailable or returns nothing.
@@ -7,27 +7,27 @@ ifeq ($(LDFLAGS),)
LDFLAGS := -lwayland-client -lm
endif
LIB_SRC := waymini.c xdg-shell-client-protocol.c
LIB_SRC := waymini/waymini.c waymini/xdg-shell-client-protocol.c
LIB_OBJ := $(LIB_SRC:.c=.o)
.PHONY: all clean
all: libwaymini.a test waymini
all: waymini/libwaymini.a example waymini
libwaymini.a: $(LIB_OBJ)
waymini/libwaymini.a: $(LIB_OBJ)
ar rcs $@ $^
test: test.cpp libwaymini.a
g++ $(CFLAGS) -o $@ test.cpp -L. -lwaymini $(LDFLAGS)
example: example.cpp waymini/libwaymini.a
g++ $(CFLAGS) -o $@ example.cpp -Lwaymini -lwaymini $(LDFLAGS)
waymini: waymini_standalone.c waymini.c xdg-shell-client-protocol.c
$(CC) $(CFLAGS) -o $@ waymini_standalone.c waymini.c xdg-shell-client-protocol.c $(LDFLAGS)
waymini: waymini/waymini_standalone.c waymini/waymini.c waymini/xdg-shell-client-protocol.c
$(CC) $(CFLAGS) -o $@ waymini/waymini_standalone.c waymini/waymini.c waymini/xdg-shell-client-protocol.c $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f $(LIB_OBJ) libwaymini.a test waymini
rm -f $(LIB_OBJ) waymini/libwaymini.a example waymini/waymini
xdg-shell-client-protocol.c xdg-shell-client-protocol.h: gen-protocols.sh
bash gen-protocols.sh
bash waymini/gen-protocols.sh
+127
View File
@@ -0,0 +1,127 @@
# UwUGL Styleguide
This document describes the coding conventions used in UwUGL, inferred from the existing codebase. It prioritizes readability and simplicity for a small graphics library.
---
## 1. File Organization
- **Single monolithic header**: `uwugl.h` is the public entry point and includes all implementation files.
- **Header-like `.cpp` files**: Every implementation file begins with `#pragma once` and is designed to be `#include`d directly by `uwugl.h` (or by other `.cpp` files). There are no traditional separate `.h`/`.cpp` pairs.
- **No separate headers for internal modules**: Classes and structs are declared and defined directly in `.cpp` files.
- **Exception**: `shaders/shaders.h` is a small aggregator file that includes the shader `.cpp` files.
- **Directory layout**:
- `primatives/` — shape classes (`Line`, `Point`, `Rectangle`, `Trapezoid`, `Triangle`)
- `shaders/` — shader classes and base
- `waymini/` — external Wayland helper library (C)
## 2. Naming Conventions
- **Namespace**: All library code lives in `namespace UwU`.
- **Classes / structs**: PascalCase (`Buffer`, `ColorShader`, `Rectangle`, `Helpers`).
- **Functions / methods**: camelCase (`drawPixel`, `lerpColor`, `bresenham`, `shouldClose`).
- **Member variables**: lowercase with no prefix (`pixels`, `width`, `x0`, `c`).
- **Template parameters**: PascalCase ending in `T` (`ShaderT`).
- **Enums**: PascalCase type name; UPPER_SNAKE_CASE values (`ShaderType`, `COLOR`, `HGRADIENT`, `VGRADIENT`).
- **Constants in code**: prefer lowercase; UPPER_SNAKE_CASE may be used for local compile-time-ish constants in comments or test code.
- **Filenames**: lowercase and descriptive (`buffer.cpp`, `colorshader.cpp`, `line.cpp`).
## 3. Formatting
- **Indentation**: 2 spaces.
- **Brace style**: K&R — opening brace on the same line as the class/function/control statement.
- **Pointer/reference syntax**: attach `*` and `&` to the variable name:
- `uint8_t* pixels`
- `ShaderBase<ShaderT>& shader`
- **Empty parameter lists**: use `()` for default constructors, e.g., `Color() {}`.
- **Spacing around operators**: use spaces around binary operators for readability (`x + y` instead of `x+y`).
- **Explicit `return;` at end of void functions**: Acceptable, but not required.
- **Comments**: use `//` for both inline and block-style comments. Keep them informal and focused on intent or known issues.
## 4. Includes
Include order within a file:
1. `#pragma once`
2. C/C++ standard headers (`<stdint.h>`, `<stdio.h>`, `<algorithm>`)
3. Project implementation files via relative paths (`"../datatypes.cpp"`, `"../buffer.cpp"`)
External C library headers (e.g., `"waymini/waymini.h"`) are included where needed.
## 5. Code Patterns
- **Composition over inheritance**: primitives hold data; shaders are passed into `draw()`.
- **CRTP for shaders**: `ShaderBase<ShaderT>` uses the Curiously Recurring Template Pattern for static polymorphism.
- **Template `draw` methods**: every primitive's `draw()` is templated on `ShaderT` and takes `(Buffer buffer, ShaderBase<ShaderT>& shader)`.
- **Manual memory management**: `new uint8_t[...]` in `Buffer`; no smart pointers.
- **C-style casts**: `(uint16_t)x`, `(uint8_t*)ptr`.
- **Bounds checks**: primitives guard `draw()` with `if (x > buffer.width || y > buffer.height) {return;};`.
- **Unused parameter suppression**: use `(void)param;` to silence warnings.
## 6. C++ Feature Usage
### Used
- Classes and structs
- Namespaces
- Templates (`template <class ShaderT>`)
- CRTP (Curiously Recurring Template Pattern)
- Function overloading (constructors)
- References
- C-style casts
- `new` / `new[]` for dynamic allocation
- Raw pointers
- Stack-allocated arrays
- C standard headers (`<stdint.h>`, `<stdio.h>`, `<stdlib.h>`, `<string.h>`, `<time.h>`, `<algorithm>`)
### Not Used but Allowed
- Smart pointers (`std::unique_ptr`, `std::shared_ptr`)
- Standard containers (`std::vector`, `std::array`, etc.)
- `enum class`
- Exceptions
- `std::string`
- `std::chrono`
- `std::function`
### Not Used
The following features are intentionally not used. This keeps the codebase small, predictable, and easy to reason about.
- `auto`
- Range-based `for` loops
- `nullptr`
- Lambda expressions
- `constexpr` / `consteval`
- `using` type aliases
- Move semantics / rvalue references
- Default member initializers
- Delegating constructors
- `override` / `final`
- Named casts (`static_cast`, `reinterpret_cast`, etc.)
- Structured bindings
- Concepts / `requires` (C++20)
- Virtual functions / runtime polymorphism / abstract base classes
- Operator overloading
- RTTI / `dynamic_cast` / `typeid`
- `<iostream>` (use C-style `printf`/`fflush`)
## 7. Build System
- **Makefile-based**.
- C library (`waymini`) compiled with `gcc`.
- Main example compiled with `g++`.
- Flags: `-Wall -Wextra -O3`, plus Wayland client flags from `pkg-config`.
## 8. Known Inconsistencies and Recommendations
The codebase currently has a few inconsistencies. The following recommendations aim to improve readability without adding complexity:
- **Indentation consistency**: some blocks are not aligned (e.g., `line.cpp` inner loop). Keep all indentation strictly at 2 spaces per level.
- **Spacing consistency**: standardize on spaces around binary operators and after commas.
- **Include consistency**: some primitives include `../shaders/shaders.h` while `rectangle.cpp` also includes `../shaders/shaderbase.cpp` directly. Prefer the aggregator `shaders.h` everywhere.
- **`return;` at end of void functions**: acceptable, but can be omitted when it adds no clarity.
- **Bounds check style**: the pattern `if (...) {return;};` has a redundant semicolon. Prefer `if (...) { return; }`.
---
This guide should evolve with the project. When in doubt, favor simplicity and consistency with the existing code.
+15
View File
@@ -0,0 +1,15 @@
[x] write a monolithic header file
[x] refactor example code using composition
[x] remove draw class entirely
[x] create shader classes with polymorphism
[x] optimize shader/primative performance (repeat myself!)
[x] finish implementing gradient shaders to primatives
[x] implement buffer shader
[ ] implement more primatives
[ ] fix off by one with buffer shader (and probably certain primatives)
[ ] fix memory leak and arrays in stack issue
[ ] fix shader offset limitations and headache
[ ] maybe add blitter primative?
[ ] support for lower color depths
[ ] support for transparency
[ ] 15bpp + dither "shader"
-31
View File
@@ -1,31 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
namespace UwU {
class Bresenham {
private:
int16_t x0;
int16_t y0;
int16_t x1;
int16_t y1;
int16_t d;
int16_t
public:
Bresenham(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
if (abs(y1 - y0) < abs(x1 - x0)) {
if (x0 > x1) {
}
}
}
};
}
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#include <stdint.h>
#include "datatypes.cpp"
#include "helpers.cpp"
// #include "shader.cpp"
namespace UwU {
// Buffer object - can be a wayland surface or a virtual buffer
class Buffer {
public:
Buffer(uint16_t width, uint16_t height) {
this->pixels = new uint8_t[width * height * 4];
this->width = width;
this->height = height;
this->stride = width * 4;
}
// Buffer(uint8_t* pixels, uint16_t width, uint16_t height, uint16_t stride) {
// this->pixels = pixels;
// this->width = width;
// this->height = height;
// this->stride = stride;
// }
Buffer() {}
uint8_t* pixels;
uint16_t width;
uint16_t height;
uint16_t stride;
void drawPixel(uint16_t x, uint16_t y, Color color) {
// if (color.a == 0) {return;}
size_t i = (size_t)y * stride + (size_t)x * 4;
// uint8_t b0 = pixels[i + 0];
// uint8_t g0 = pixels[i + 1];
// uint8_t r0 = pixels[i + 2];
// uint8_t b = Helpers::lerp8(b0, color.b, color.a);
// uint8_t g = Helpers::lerp8(g0, color.g, color.a);
// uint8_t r = Helpers::lerp8(r0, color.r, color.a);
pixels[i + 0] = color.b; // B
pixels[i + 1] = color.g; // G
pixels[i + 2] = color.r; // R
pixels[i + 3] = 0xff; // A
return;
}
};
}
+52 -36
View File
@@ -12,6 +12,12 @@ namespace UwU {
this->g = (hex & 0x00ff0000) >> 16;
this->r = (hex & 0xff000000) >> 24;
}
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
Color() {}
uint8_t r;
uint8_t g;
@@ -21,49 +27,59 @@ namespace UwU {
// Coord2 datatype for xy coordinates, from top-left of surface
struct Coord2 {
Coord2(uint32_t x, uint32_t y) {
Coord2(uint16_t x, uint16_t y) {
this->x = x;
this->y = y;
}
Coord2() {}
uint32_t x;
uint32_t y;
uint16_t x;
uint16_t y;
};
// trapezoid datatype (horizontally constrained)
struct Trapezoid {
Trapezoid(uint16_t y0, uint16_t y1, uint16_t xl0, uint16_t xl1, uint16_t xr0, uint16_t xr1) {
this->y0 = y0;
this->y1 = y1;
this->xl0 = xl0;
this->xl1 = xl1;
this->xr0 = xr0;
this->xr1 = xr1;
}
Trapezoid() {}
uint16_t y0;
uint16_t y1;
uint16_t xl0;
uint16_t xl1;
uint16_t xr0;
uint16_t xr1;
// Vec2 datatype for signed x, y coordinates
// struct Vec2 {
// Vec2(int16_t x, int16_t y) {
// this->x = x;
// this->y = y;
// }
// Vec2() {}
// int16_t x;
// int16_t y;
// };
// // 2x2 matrix, Q15.16 signed fixed point
// struct Matrix4 {
// Matrix4(int32_t xx, int32_t xy, int32_t yx, int32_t yy) {
// this->xx = xx;
// this->xy = xy;
// this->yx = yx;
// this->yy = yy;
// }
// Matrix4() {}
// int32_t xx; // x' = x*xx + y*xy
// int32_t xy;
// int32_t yx; // y' = x*yx + y*yy
// int32_t yy;
// };
// class Mapper {
// public:
// Mapper() {
// }
// uint16_t *xxMap;
// };
enum ShaderType {
COLOR,
HGRADIENT,
VGRADIENT,
BUFFER
};
struct Triangle {
Triangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
this->x2 = x2;
this->y2 = y2;
}
Triangle() {}
uint16_t x0;
uint16_t y0;
uint16_t x1;
uint16_t y1;
uint16_t x2;
uint16_t y2;
enum Direction {
H,
V
};
}
-31
View File
@@ -1,31 +0,0 @@
#include <stdint.h>
namespace UwU {
struct Color {
Color(uint32_t hex);
Color();
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct Coord2 {
Coord2(uint32_t x, uint32_t y);
Coord2();
uint32_t x;
uint32_t y;
};
struct Trapezoid {
Trapezoid(uint16_t y0, uint16_t y1, uint16_t xl0, uint16_t xl1, uint16_t xr0, uint16_t xr1);
Trapezoid();
uint16_t y0;
uint16_t y1;
uint16_t xl0;
uint16_t xl1;
uint16_t xr0;
uint16_t xr1;
};
}
BIN
View File
Binary file not shown.
+111
View File
@@ -0,0 +1,111 @@
// #pragma once
#include "waymini/waymini.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uwugl.h"
#include <time.h>
#include "font.cpp"
static void onKey(void *user, uint32_t keycode, uint32_t state) {
if (keycode == 1) {
exit(1);
}
(void)user;
const char *label = state ? "down" : "up ";
printf("key %s: %u\n", label, keycode);
fflush(stdout);
}
int main(void) {
uint16_t w = 800, h = 480;
UwU::Surface surface = UwU::Surface(w, h, onKey);
// UwU::Color fuchsia = UwU::Color(0xb00b69ff);
UwU::Color red = UwU::Color(0xff0000ff);
UwU::Color green = UwU::Color(0x00ff00ff);
UwU::Color blue = UwU::Color(0x0000ffff);
// UwU::ColorTexture fuchsia = UwU::ColorTexture(UwU::Color(0xb00b69ff));
UwU::HGradientTexture bisexual = UwU::HGradientTexture(180, red, blue);
UwU::OffsetMapper offsetMapper = UwU::OffsetMapper();
UwU::Tilemap myTilemap = UwU::Tilemap();
myTilemap.tilemap[0] = 0x0000;
myTilemap.tilemap[1] = 0x0001;
myTilemap.tilemap[2] = 0x0000;
myTilemap.tilemap[3] = 0x0002;
myTilemap.tilemap[4] = 0x0003;
UwU::Buffer fontBuffer = font();
UwU::TilemapTexture textMap = UwU::TilemapTexture(myTilemap, fontBuffer);
UwU::Rectangle rectangle = UwU::Rectangle(69, 69, 420, 420);
rectangle.draw(surface.buffer, offsetMapper, textMap);
UwU::ColorTexture greenTexture = UwU::ColorTexture(green);
UwU::NullMapper nullMapper = UwU::NullMapper();
UwU::Point point = UwU::Point(187, 37);
point.draw(surface.buffer, nullMapper, greenTexture);
UwU::ColorTexture blueTexture = UwU::ColorTexture(blue);
UwU::Trapezoid trapezoid = UwU::Trapezoid(100, 300, 690, 320, 720, 780);
trapezoid.draw(surface.buffer, nullMapper, blueTexture);
UwU::ColorTexture redTexture = UwU::ColorTexture(red);
UwU::Triangle triangle = UwU::Triangle(140, 140, 60, 400, 240, 240);
triangle.draw(surface.buffer, offsetMapper, bisexual);
// // Benchmarking
// struct timespec start, end;
// const int WARMUP = 100;
// const int BATCH = 1000;
// const int SAMPLES = 10;
// for (int i = 0; i < WARMUP; i++) {
// rectangle.draw(surface.buffer, gradientBuffer);
// }
// long times[SAMPLES];
// for (int s = 0; s < SAMPLES; s++) {
// clock_gettime(CLOCK_MONOTONIC, &start);
// for (int i = 0; i < BATCH; i++) {
// rectangle.draw(surface.buffer, gradientBuffer);
// }
// clock_gettime(CLOCK_MONOTONIC, &end);
// times[s] = (end.tv_sec - start.tv_sec) * 1000000000L + (end.tv_nsec - start.tv_nsec);
// }
// long timeAvg = 0;
// for (int i = 0; i < SAMPLES; i++) {
// timeAvg += times[i];
// }
// timeAvg /= SAMPLES;
// timeAvg /= BATCH;
// printf("Elapsed: %ld ns\n", timeAvg);
UwU::Line lines[8] {
UwU::Line(300, 100, 250, 469),
UwU::Line(250, 100, 300, 469),
UwU::Line(300, 100, 469, 250),
UwU::Line(469, 100, 300, 250),
UwU::Line(100, 300, 250, 469),
UwU::Line(250, 300, 100, 469),
UwU::Line(100, 300, 469, 250),
UwU::Line(469, 300, 100, 250)
};
for (uint16_t i = 0; i < 8; i++) {
lines[i].draw(surface.buffer, nullMapper, blueTexture);
}
surface.present();
while (!surface.shouldClose()) {}
surface.destroy();
return 0;
}
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include <stdint.h>
#include "buffer.cpp"
UwU::Buffer font() {
const uint32_t fontInt[9] = {
0xcc003f00,
0xcc004300,
0xcf33c300,
0xcf33c300,
0xcf33df00,
0xcf33cf00,
0xcf33cf00,
0xcf33cf00,
0x7ffeffe0
};
UwU::Buffer font = UwU::Buffer(32, 9);
uint32_t t;
uint32_t b;
for (uint16_t y = 0; y < 9; y++) {
t = fontInt[y];
for (uint16_t x = 0; x < 32; x++) {
b = t & 0x80000000;
if (b == 0x80000000) {
font.pixels[(y * 128) + (x * 4) + 0] = 0xff;
font.pixels[(y * 128) + (x * 4) + 1] = 0xff;
font.pixels[(y * 128) + (x * 4) + 2] = 0xff;
font.pixels[(y * 128) + (x * 4) + 3] = 0xff;
} else {
font.pixels[(y * 128) + (x * 4) + 0] = 0x00;
font.pixels[(y * 128) + (x * 4) + 1] = 0x00;
font.pixels[(y * 128) + (x * 4) + 2] = 0x00;
font.pixels[(y * 128) + (x * 4) + 3] = 0x00;
}
t = t << 1;
}
}
return font;
}
+6 -2
View File
@@ -79,7 +79,7 @@ namespace UwU {
}
return;
}
if (abs(y1 - y0) <= x1) {
if (abs(y1 - y0) <= abs(x1 - x0)) {
bresenhamLow(x0, y0, x1, y1, LUT);
} else {
if (y0 > y1) {
@@ -90,5 +90,9 @@ namespace UwU {
}
return;
}
// plot a 90 degree arc
static void fastArc(uint16_t radius, uint16_t* LUT) {
}
};
}
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "datatypes.cpp"
#include "helpers.cpp"
namespace UwU {
class Mapper {
public:
Mapper(Vec2 offset, Vec2 origin, Matrix4 transformation) {
this->offset = offset;
this->origin = origin;
this->transformation = transformation;
}
Vec2 offset; // offset (translation)
Vec2 origin; // origin (for rotation, etc)
Matrix4 transformation; // transformation matrix (for rotation, translation, etc)
Coord2 map(Coord2 input) {
int64_t x1 = (int64_t)transformation.xx * ((int64_t)input.x - (int64_t)origin.x);
x1 += (int64_t)transformation.xy * ((int64_t)input.y - (int64_t)origin.y);
x1 = x1 / 65536;
x1 += origin.x;
x1 += offset.x;
int64_t y1 = (int64_t)transformation.yx * ((int64_t)input.x - (int64_t)origin.x);
y1 += (int64_t)transformation.yy * ((int64_t)input.y - (int64_t)origin.y);
y1 = y1 / 65536;
y1 += origin.y;
y1 += offset.y;
return Coord2((uint16_t)x1, (uint16_t)0);
}
};
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
namespace UwU {
template <class MapperT>
class MapperBase {
public:
Coord2 map(uint16_t x0, uint16_t y0, uint16_t x, uint16_t y) {
return static_cast<MapperT*>(this)->map(x0, y0, x, y);
}
};
}
+4
View File
@@ -0,0 +1,4 @@
#include "mapperbase.cpp"
#include "nullmapper.cpp"
#include "offsetmapper.cpp"
// #include "tilemapper.cpp"
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "mapperbase.cpp"
namespace UwU {
class NullMapper : public MapperBase<NullMapper> {
public:
NullMapper() {}
Coord2 map(uint16_t x0, uint16_t y0, uint16_t x, uint16_t y) {
(void)x0;
(void)y0;
return Coord2(x, y);
}
};
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "mapperbase.cpp"
namespace UwU {
class OffsetMapper : public MapperBase<OffsetMapper> {
public:
OffsetMapper() {}
Coord2 map(uint16_t x0, uint16_t y0, uint16_t x, uint16_t y) {
uint16_t u = x -x0;
uint16_t v = y -y0;
return Coord2(u, v);
}
};
}
+108
View File
@@ -0,0 +1,108 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "../mappers/mappers.h"
#include "../textures/textures.h"
namespace UwU {
// line
class Line {
private:
// plot lines if m <= 1
template <class MapperT, class TextureT>
void lineLow(int16_t ix0, int16_t iy0, int16_t ix1, int16_t iy1, Buffer buffer, MapperBase<MapperT>& mapper, TextureBase<TextureT>& texture) {
int16_t dx = ix1 - ix0;
int16_t dy = iy1 - iy0;
int16_t yi = 1;
if (dy < 0) {
yi = -1;
dy = -dy;
}
int16_t d = (2 * dy) - dx;
int16_t y = iy0;
Coord2 uv;
for (int16_t x = ix0; x < ix1; x++) {
uv = mapper.map(ix0, iy0, x, y);
buffer.drawPixel((uint16_t)x, (uint16_t)y, texture.texel(uv.x, uv.y));
if (d > 0) {
y += yi;
d += (2 * (dy - dx));
} else {
d += (2 * dy);
}
}
return;
}
// plot lines if m >1
template <class MapperT, class TextureT>
void lineHigh(int16_t ix0, int16_t iy0, int16_t ix1, int16_t iy1, Buffer buffer, MapperBase<MapperT>& mapper, TextureBase<TextureT>& texture) {
int16_t dx = ix1 - ix0;
int16_t dy = iy1 - iy0;
int16_t xi = 1;
if (dx < 0) {
xi = -1;
dx = -dx;
}
int16_t d = (2 * dx) - dy;
int16_t x = ix0;
Coord2 uv;
for (int16_t y = iy0; y < iy1; y++) {
uv = mapper.map(ix0, iy0, x, y);
buffer.drawPixel((uint16_t)x, (uint16_t)y, texture.texel(uv.x, uv.y));
if (d > 0) {
x += xi;
d += (2 * (dx - dy));
} else {
d += (2 * dx);
}
}
return;
}
public:
Line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
}
Line() {}
uint16_t x0;
uint16_t y0;
uint16_t x1;
uint16_t y1;
// Uses Bresenham's line algorithm to draw line of any slope
template <class MapperT, class TextureT>
void draw (Buffer buffer, MapperBase<MapperT>& mapper, TextureBase<TextureT>& texture) {
if (x0 > buffer.width || y0 > buffer.height || x1 > buffer.width || y1 > buffer.height) {return;};
int16_t ix0 = x0;
int16_t iy0 = y0;
int16_t ix1 = x1;
int16_t iy1 = y1;
if (abs(iy1 - iy0) < abs(ix1 - ix0)) {
if (ix0 > ix1) {
lineLow(ix1, iy1, ix0, iy0, buffer, mapper, texture);
} else {
lineLow(ix0, iy0, ix1, iy1, buffer, mapper, texture);
}
} else {
if (iy0 > iy1) {
lineHigh(ix1, iy1, ix0, iy0, buffer, mapper, texture);
} else {
lineHigh(ix0, iy0, ix1, iy1, buffer, mapper, texture);
}
}
return;
}
};
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "../mappers/mappers.h"
#include "../textures/textures.h"
namespace UwU {
// point
class Point {
public:
Point(uint16_t x, uint16_t y) {
this->x = x;
this->y = y;
}
Point() {}
uint16_t x;
uint16_t y;
// Draw a point
template <class MapperT, class TextureT>
void draw (Buffer buffer, MapperBase<MapperT>& mapper, TextureBase<TextureT>& texture) {
if (x > buffer.width || y > buffer.height) {return;};
Coord2 uv = mapper.map(x, y, x, y);
buffer.drawPixel(x, y, texture.texel(uv.x, uv.y));
return;
}
};
}
+5
View File
@@ -0,0 +1,5 @@
#include "point.cpp"
#include "line.cpp"
#include "rectangle.cpp"
#include "trapezoid.cpp"
#include "triangle.cpp"
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "../mappers/mappers.h"
#include "../textures/textures.h"
namespace UwU {
// rectangle
class Rectangle {
public:
Rectangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
}
Rectangle() {}
uint16_t x0;
uint16_t y0;
uint16_t x1;
uint16_t y1;
// Draw a rectangle
template <class MapperT, class TextureT>
void draw (Buffer buffer, MapperBase<MapperT>& mapper, TextureBase<TextureT>& texture) {
if (x0 > buffer.width || y0 > buffer.height || x1 > buffer.width || y1 > buffer.height) {return;};
for (uint16_t y = y0; y <= y1; y++) {
for (uint16_t x = x0; x <= x1; x++) {
Coord2 uv = mapper.map(x0, y0, x, y);
buffer.drawPixel(x, y, texture.texel(uv.x, uv.y));
}
}
return;
}
};
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <stdint.h>
#include <algorithm>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "../mappers/mappers.h"
#include "../textures/textures.h"
namespace UwU {
// trapezoid (horizontally constrained)
class Trapezoid {
public:
Trapezoid(uint16_t y0, uint16_t y1, uint16_t xl0, uint16_t xl1, uint16_t xr0, uint16_t xr1) {
this->y0 = y0;
this->y1 = y1;
this->xl0 = xl0;
this->xl1 = xl1;
this->xr0 = xr0;
this->xr1 = xr1;
}
Trapezoid() {}
uint16_t y0;
uint16_t y1;
uint16_t xl0;
uint16_t xl1;
uint16_t xr0;
uint16_t xr1;
// Draw a horizontally bounded trapezoid
// y1 >= y0
template <class MapperT, class TextureT>
void draw (Buffer buffer, MapperBase<MapperT>& mapper, TextureBase<TextureT>& texture) {
uint16_t height = 1 + y1 - y0;
int16_t LeftBound[height];
int16_t RightBound[height];
Helpers::bresenham(0, xl0, y1 - y0, xl1, LeftBound);
Helpers::bresenham(0, xr0, y1 - y0, xr1, RightBound);
uint16_t x0 = std::min(xl0, xl1);
for (uint16_t i = 0; i < height; i++) {
for (uint16_t x = LeftBound[i]; x <= RightBound[i]; x++) {
Coord2 uv = mapper.map(x0, y0, x, i + y0);
buffer.drawPixel(x, i + y0, texture.texel(uv.x, uv.y));
}
}
return;
}
};
}
+118
View File
@@ -0,0 +1,118 @@
#pragma once
#include <stdint.h>
#include <algorithm>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "../mappers/mappers.h"
#include "../textures/textures.h"
namespace UwU {
class Triangle {
private:
public:
Triangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
this->x2 = x2;
this->y2 = y2;
}
Triangle() {}
uint16_t x0;
uint16_t y0;
uint16_t x1;
uint16_t y1;
uint16_t x2;
uint16_t y2;
// Draw a triangle
template <class MapperT, class TextureT>
void draw (Buffer buffer, MapperBase<MapperT>& mapper, TextureBase<TextureT>& texture) {
uint16_t topX, topY, midX, midY, btmX, btmY;
// Find top, middle and bottom points of triangle
if (y0 <= y1 && y0 <= y2) {
topX = x0;
topY = y0;
if (y1 < y2) {
midX = x1;
midY = y1;
btmX = x2;
btmY = y2;
} else {
midX = x2;
midY = y2;
btmX = x1;
btmY = y1;
}
} else if (y1 <= y0 && y1 <= y2) {
topX = x1;
topY = y1;
if (y0 < y2) {
midX = x0;
midY = y0;
btmX = x2;
btmY = y2;
} else {
midX = x2;
midY = y2;
btmX = x0;
btmY = y0;
}
} else {
topX = x2;
topY = y2;
if (y0 < y1) {
midY = y0;
midX = x0;
btmX = x1;
btmY = y1;
} else {
midX = x1;
midY = y1;
btmX = x0;
btmY = y0;
}
}
uint16_t height = 1 + btmY - topY;
int16_t longBound[height];
int16_t splitBound[height];
// Calculate LUT for longest vertical line (from top to bottom)
Helpers::bresenham(0, topX, height - 1, btmX, longBound);
// Calculate LUT for short two lines
Helpers::bresenham(0, topX, midY - topY, midX, splitBound);
Helpers::bresenham(midY - topY, midX, height - 1, btmX, splitBound);
Coord2 uv;
uint16_t leftX = std::min(topX, std::min(midX, btmX));
// Left-handed triangle case (midpoint is left of triangle)
if ((int16_t)midX < longBound[midY - topY]) {
for (uint16_t i = 0; i < height; i++) {
for (uint16_t x = (uint16_t)splitBound[i]; x <= (uint16_t)longBound[i]; x++) {
uv = mapper.map(leftX, topY, x, i + (uint16_t)topY);
buffer.drawPixel(x, i + (uint16_t)topY, texture.texel(uv.x, uv.y));
}
}
// Right-handed triangle case (midpoint is right of triangle)
} else {
for (uint16_t i = 0; i < height; i++) {
for (uint16_t x = (uint16_t)longBound[i]; x <= (uint16_t)splitBound[i]; x++) {
uv = mapper.map(leftX, topY, x, i + (uint16_t)topY);
buffer.drawPixel(x, i + (uint16_t)topY, texture.texel(uv.x, uv.y));
}
}
}
return;
}
};
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
namespace UwU {
template <class ShaderT>
class ShaderBase {
public:
Color shade(uint16_t x, uint16_t y) {
return static_cast<ShaderT*>(this)->shade(x, y);
}
};
}
+1
View File
@@ -0,0 +1 @@
#include "shaderbase.cpp"
+81
View File
@@ -0,0 +1,81 @@
#pragma once
#include "waymini/waymini.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "datatypes.cpp"
#include "buffer.cpp"
namespace UwU {
class Surface {
// should probably be a child of buffer
public:
Surface(uint16_t width, uint16_t height, waymini_key_cb onKey) {
this->wm = waymini_create((uint32_t)width, (uint32_t)height, onKey, NULL);
if (!this->wm) exit(1);
// this->buffer = Buffer(
// (uint8_t*)waymini_get_pixels(this->wm),
// waymini_get_width(this->wm),
// waymini_get_height(this->wm),
// waymini_get_stride(this->wm));
this->buffer.pixels = (uint8_t*)waymini_get_pixels(this->wm);
this->buffer.width = waymini_get_width(this->wm);
this->buffer.height = waymini_get_height(this->wm);
this->buffer.stride = waymini_get_stride(this->wm);
printf("surface: %ux%u stride=%u\n", waymini_get_width(this->wm), waymini_get_height(this->wm), waymini_get_stride(this->wm));
if (!this->buffer.pixels) {
waymini_destroy(this->wm);
exit(1);
}
}
class Buffer buffer;
struct waymini* wm;
// get current size of wayland surface and update buffer
void updateSize() {
buffer.width = waymini_get_width(wm);
buffer.height = waymini_get_height(wm);
buffer.stride = waymini_get_stride(wm);
return;
}
uint32_t getWidth() {
updateSize();
return buffer.width;
}
uint32_t getHeight() {
updateSize();
return buffer.height;
}
uint32_t getStride() {
updateSize();
return buffer.stride;
}
void present() {
waymini_present(wm);
return;
}
void destroy() {
waymini_destroy(wm);
return;
}
bool shouldClose() {
if (waymini_should_close(wm) || waymini_dispatch(wm) < 0) {
return true;
} else {
return false;
}
}
};
}
BIN
View File
Binary file not shown.
-425
View File
@@ -1,425 +0,0 @@
/* Example program that links against the waymini library.
* No external dependencies beyond waymini itself and the C standard library.
*/
#include "waymini.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "datatypes.cpp"
#include "helpers.cpp"
// #include "triangle.cpp"
// this should be handled elsewhere, eventually, maybe, probably
static void on_key(void *user, uint32_t keycode, uint32_t state) {
(void)user;
const char *label = state ? "down" : "up ";
printf("key %s: %u\n", label, keycode);
fflush(stdout);
}
namespace UwU {
class Draw {
private:
uint8_t *pixels;
void putPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a = 0xff) {
size_t i = (size_t)y * waymini_get_stride(wm) + (size_t)x * 4;
uint8_t b0 = pixels[i + 0];
uint8_t g0 = pixels[i + 1];
uint8_t r0 = pixels[i + 2];
b = Helpers::lerp8(b0, b, a);
g = Helpers::lerp8(g0, g, a);
r = Helpers::lerp8(r0, r, a);
pixels[i + 0] = b; // B
pixels[i + 1] = g; // G
pixels[i + 2] = r; // R
pixels[i + 3] = 0xff; // A
}
// plot lines if m <= 1
void lineLow(int32_t x0, int32_t y0, int32_t x1, int32_t y1, Color color) {
int32_t dx = x1 - x0;
int32_t dy = y1 - y0;
int32_t yi = 1;
if (dy < 0) {
yi = -1;
dy = -dy;
}
int32_t d = (2 * dy) - dx;
int32_t y = y0;
for (int32_t x = x0; x < x1; x++) {
putPixel(x, y, color.r, color.g, color.b, color.a);
if (d > 0) {
y += yi;
d += (2 * (dy - dx));
} else {
d += (2 * dy);
}
}
return;
}
// plot lines if m >1
void lineHigh(int32_t x0, int32_t y0, int32_t x1, int32_t y1, Color color) {
int32_t dx = x1 - x0;
int32_t dy = y1 - y0;
int32_t xi = 1;
if (dx < 0) {
xi = -1;
dx = -dx;
}
int32_t d = (2 * dx) - dy;
int32_t x = x0;
for (int32_t y = y0; y < y1; y++) {
putPixel(x, y, color.r, color.g, color.b, color.a);
if (d > 0) {
x += xi;
d += (2 * (dx - dy));
} else {
d += (2 * dx);
}
}
return;
}
public:
Draw(uint32_t width, uint32_t height, waymini_key_cb on_key) {
this->wm = waymini_create(width, height, on_key, NULL);
if (!this->wm) exit(1);
// this->width = waymini_get_width(this->wm);
// this->height = waymini_get_height(this->wm);
// this->stride = waymini_get_stride(this->wm);
printf("surface: %ux%u stride=%u\n", waymini_get_width(this->wm), waymini_get_height(this->wm), waymini_get_stride(this->wm));
this->pixels = (uint8_t *)waymini_get_pixels(this->wm);
if (!this->pixels) {
waymini_destroy(this->wm);
exit(1);
}
}
struct waymini* wm;
uint32_t getWidth() {
return waymini_get_width(wm);
}
uint32_t getHeight() {
return waymini_get_height(wm);
}
uint32_t getStride() {
return waymini_get_stride(wm);
}
void present() {
waymini_present(wm);
return;
}
void destroy() {
waymini_destroy(wm);
return;
}
// Draw a rectangle (duh)
void rectangle(Coord2 point0, Coord2 point1, Color color) {
if (point0.x > getWidth() || point0.y > getHeight() || point1.x > getWidth() || point1.y > getHeight()) {return;};
for (uint32_t y = point0.y; y < point1.y; y++) {
for (uint32_t x = point0.x; x < point1.x; x++) {
putPixel(x, y, color.r, color.g, color.b, color.a);
}
}
return;
}
// Draws a rectangle with a 4-point color gradient
void rectangleGradient(Coord2 point0, Coord2 point1, Color colorUL, Color colorUR, Color colorLL, Color colorLR) {
// convert to int32_t and ensure x1>x0 && y1>y0
int32_t x0, y0, x1, y1;
if (point0.x > point1.x) {
x0 = (int32_t)point1.x;
x1 = (int32_t)point0.x;
} else {
x0 = (int32_t)point0.x;
x1 = (int32_t)point1.x;
}
if (point0.y > point1.y) {
y0 = (int32_t)point1.y;
y1 = (int32_t)point0.y;
} else {
y0 = (int32_t)point0.y;
y1 = (int32_t)point1.y;
}
// setup gradient coefficient arrays
int32_t w = x1 - x0 + 1;
int32_t h = y1 - y0 + 1;
int16_t xGrad[w];
int16_t yGrad[h];
// calculate gradient coefficients
Helpers::bresenham(0, 0, w - 1, 255, xGrad);
Helpers::bresenham(0, 0, h - 1, 255, yGrad);
// for each point calculate, alpha blend and print color
Color Lmix = Color();
Color Rmix = Color();
Color Xmix = Color();
for (int32_t y = y0; y <= y1; y++) {
Lmix = Helpers::lerpColor(colorUL, colorLL, (uint8_t)yGrad[y - y0]);
Rmix = Helpers::lerpColor(colorUR, colorLR, (uint8_t)yGrad[y - y0]);
for (int32_t x = x0; x <= x1; x++) {
Xmix = Helpers::lerpColor(Lmix, Rmix, (uint8_t)xGrad[x - x0]);
putPixel(x, y, Xmix.r, Xmix.g, Xmix.b, Xmix.a);
}
}
return;
}
// Fill a simple gradient. Each row is stride bytes.
void rainbow() {
for (uint32_t y = 0; y < getHeight(); y++) {
for (uint32_t x = 0; x < getWidth(); x++) {
size_t i = (size_t)y * getStride() + (size_t)x * 4;
pixels[i + 0] = (uint8_t)(y * 255 / getHeight()); // B
pixels[i + 1] = 0x00; // G
pixels[i + 2] = (uint8_t)(x * 255 / getWidth()); // R
pixels[i + 3] = 0xFF; // A
}
}
}
// Draw a single point
void point (Coord2 point, Color color) {
if (point.x > getWidth() || point.y > getHeight()) {return;};
putPixel(point.x, point.y, color.r, color.g, color.b, color.a);
}
// Uses Bresenham's line algorithm to draw line of any slope
void line (Coord2 point0, Coord2 point1, Color color) {
if (point0.x > getWidth() || point0.y > getHeight() || point1.x > getWidth() || point1.y > getHeight()) {return;};
int32_t x0 = (int32_t)point0.x;
int32_t y0 = (int32_t)point0.y;
int32_t x1 = (int32_t)point1.x;
int32_t y1 = (int32_t)point1.y;
if (abs(y1 - y0) < abs(x1 - x0)) {
if (x0 > x1) {
lineLow(x1, y1, x0, y0, color);
} else {
lineLow(x0, y0, x1, y1, color);
}
} else {
if (y0 > y1) {
lineHigh(x1, y1, x0, y0, color);
} else {
lineHigh(x0, y0, x1, y1, color);
}
}
}
// Draw a horizontally bounded trapezoid
// coords.y1 >= coords.y0
// todo move to private and add public checks
void trapezoid (Trapezoid coords, Color color) {
printf("(%u, %u, %u, %u, %u, %u)", coords.y0, coords.y1, coords.xl0, coords.xl1, coords.xr0, coords.xr1);
uint16_t height = 1 + coords.y1 - coords.y0;
int16_t LeftBound[height];
int16_t RightBound[height];
Helpers::bresenham(0, coords.xl0, coords.y1 - coords.y0, coords.xl1, LeftBound);
Helpers::bresenham(0, coords.xr0, coords.y1 - coords.y0, coords.xr1, RightBound);
printf("leftbound\n");
for (uint16_t i = 0; i < height; i++) {
printf("(%u, %u)\n", i, LeftBound[i]);
}
printf("rightbound\n");
for (uint16_t i = 0; i < height; i++) {
printf("(%u, %u)\n", i, RightBound[i]);
}
for (uint16_t i = 0; i < height; i++) {
for (uint16_t x = LeftBound[i]; x <= RightBound[i]; x++) {
// printf("(%u, %u)", x, i + coords.y0);
putPixel((uint32_t)x, (uint32_t)i + coords.y0, color.r, color.g, color.b, color.a);
}
}
return;
}
// Draw a triangle
void triangle (Triangle coords, Color color) {
Coord2 top = Coord2();
Coord2 mid = Coord2();
Coord2 btm = Coord2();
// cases: flat top, flat bottom, left point, right point
if (coords.y0 < coords.y1 && coords.y0 < coords.y2) {
top.x = coords.x0;
top.y = coords.y0;
if (coords.y1 < coords.y2) {
mid.x = coords.x1;
mid.y = coords.y1;
btm.x = coords.x2;
btm.y = coords.y2;
} else {
mid.x = coords.x2;
mid.y = coords.y2;
btm.x = coords.x1;
btm.y = coords.y1;
}
} else if (coords.y1 < coords.y0 && coords.y1 < coords.y2) {
top.x = coords.x1;
top.y = coords.y1;
if (coords.y0 < coords.y2) {
mid.x = coords.x0;
mid.y = coords.y0;
btm.x = coords.x2;
btm.y = coords.y2;
} else {
mid.x = coords.x2;
mid.y = coords.y2;
btm.x = coords.x0;
btm.y = coords.y0;
}
} else {
top.x = coords.x2;
top.y = coords.y2;
if (coords.y0 < coords.y1) {
mid.x = coords.x0;
mid.y = coords.y0;
btm.x = coords.x1;
btm.y = coords.y1;
} else {
mid.x = coords.x1;
mid.y = coords.y1;
btm.x = coords.x0;
btm.y = coords.y0;
}
}
uint16_t height = 1 + btm.y - top.y;
int16_t longBound[height];
int16_t splitBound[height];
// int16_t rightBound[height];
Helpers::bresenham(0, top.x, height - 1, btm.x, longBound);
if ((int16_t)mid.x < longBound[mid.y - top.y]) {
// left-handed triangle
// rightBound = longBound;
Helpers::bresenham(0, top.x, mid.y - top.y, mid.x, splitBound);
Helpers::bresenham(mid.y - top.y, mid.x, height - 1, btm.x, splitBound);
for (uint32_t i = 0; i < height; i++) {
for (uint32_t x = (uint32_t)splitBound[i]; x <= (uint32_t)longBound[i]; x++) {
putPixel(x, i + (uint32_t)top.y, color.r, color.g, color.b, color.a);
}
}
} else {
// right-handed triangle
// leftBound = longBound;
Helpers::bresenham(0, top.x, mid.y - top.y, mid.x, splitBound);
Helpers::bresenham(mid.y - top.y, mid.x, height - 1, btm.x, splitBound);
for (uint32_t i = 0; i < height; i++) {
for (uint32_t x = (uint32_t)longBound[i]; x <= (uint32_t)splitBound[i]; x++) {
putPixel(x, i + (uint32_t)top.y, color.r, color.g, color.b, color.a);
}
}
}
// // handle case where top or bottom is flat
// if (mid.y == top.y) {
// // flat top
// if (mid.x < top.x) {
// trapezoid(Trapezoid(top.y, btm.y, mid.x, btm.x, top.x, btm.x), color);
// return;
// } else {
// trapezoid(Trapezoid(top.y, btm.y, top.x, btm.x, mid.x, btm.x), color);
// return;
// }
// } else if (mid.y == btm.y) {
// // flat bottom
// if (mid.x < btm.x) {
// trapezoid(Trapezoid(top.y, btm.y, top.x, mid.x, top.x, btm.x), color);
// return;
// } else {
// trapezoid(Trapezoid(top.y, btm.y, top.x, btm.x, top.x, mid.x), color);
// return;
// }
// }
// // calculate midpoint of straight line
// int32_t dy = (int32_t)btm.y - (int32_t)top.y;
// if (dy == 0) {
// return; // shouldn't be possible, should be detected earlier
// }
// int32_t dx = (int32_t)btm.x - (int32_t)top.x;
// dx *= (mid.y - top.y);
// dx /= dy;
// dx += top.x;
// uint16_t oppx = (uint16_t)dx;
// // split triangle into two trapezoids
// if (mid.x < oppx) {
// trapezoid(Trapezoid(top.y, mid.y, top.x, mid.x, top.x, oppx), color);
// trapezoid(Trapezoid(mid.y, btm.y, mid.x, btm.x, oppx, btm.x), color);
// return;
// } else {
// trapezoid(Trapezoid(top.y, mid.y, top.x, oppx, top.x, mid.x), color);
// trapezoid(Trapezoid(mid.y, btm.y, oppx, btm.x, mid.x, btm.x), color);
// return;
// }
return;
}
};
}
int main(void) {
uint32_t w = 800, h = 480;
UwU::Color fuchsia = UwU::Color(0xb00b6940);
UwU::Color red = UwU::Color(0xff0000ff);
UwU::Color green = UwU::Color(0x00ff00ff);
UwU::Color blue = UwU::Color(0x0000ffff);
UwU::Color alpha = UwU::Color(0x00000000);
printf("r: %u, g:%u, b:%u, a:%u\n", fuchsia.r, fuchsia.g, fuchsia.b, fuchsia.a);
// struct waymini *wm = waymini_create(w, h, on_key, NULL);
UwU::Draw draw = UwU::Draw(w, h, on_key);
draw.rainbow();
draw.rectangle(UwU::Coord2(69, 69), UwU::Coord2(420, 420), fuchsia);
draw.rectangleGradient(UwU::Coord2(200, 200), UwU::Coord2(600, 400), red, blue, alpha, red);
draw.trapezoid(UwU::Trapezoid(300, 400, 360, 380, 600, 400), green);
draw.triangle(UwU::Triangle(200, 100, 240, 100, 320, 300), green);
draw.point(UwU::Coord2(387, 43), green);
draw.line(UwU::Coord2(300, 100), UwU::Coord2(250, 469), green);
draw.line(UwU::Coord2(250, 100), UwU::Coord2(300, 469), green);
draw.line(UwU::Coord2(300, 100), UwU::Coord2(469, 250), green);
draw.line(UwU::Coord2(469, 100), UwU::Coord2(300, 250), green);
draw.line(UwU::Coord2(100, 300), UwU::Coord2(250, 469), green);
draw.line(UwU::Coord2(250, 300), UwU::Coord2(100, 469), green);
draw.line(UwU::Coord2(100, 300), UwU::Coord2(469, 250), green);
draw.line(UwU::Coord2(469, 300), UwU::Coord2(100, 250), green);
draw.present();
while (!waymini_should_close(draw.wm)) {
if (waymini_dispatch(draw.wm) < 0) break;
}
draw.destroy();
return 0;
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "texturebase.cpp"
namespace UwU {
class BitmapTexture : public TextureBase<BitmapTexture> {
private:
Buffer buffer;
public:
BitmapTexture(Buffer buffer) {
this->buffer = buffer;
}
Color texel(uint16_t u, uint16_t v) {
uint32_t index = (v * buffer.stride) + (u * 4);
Color c = Color(buffer.pixels[index + 2], buffer.pixels[index + 1], buffer.pixels[index], buffer.pixels[index + 3]);
return c;
}
};
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "texturebase.cpp"
namespace UwU {
class ColorTexture : public TextureBase<ColorTexture> {
private:
Color color;
public:
ColorTexture(Color color) {
this->color = color;
}
Color texel(uint16_t u, uint16_t v) {
(void)u;
(void)v;
return color;
}
};
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "texturebase.cpp"
namespace UwU {
class GradientTexture : public TextureBase<GradientTexture> {
public:
GradientTexture(uint16_t width, Color c0, Color c1) {
this->uScale = 0xffffffff / (1 + (uint32_t)width);
this->c0 = c0;
this->c1 = c1;
}
uint32_t uScale;
Color c0;
Color c1;
Color texel(uint16_t u, uint16_t v) {
(void)v;
uint32_t t = (((uint32_t)u) * uScale) / 0x01000000;
return Helpers::lerpColor(c0, c1, (uint8_t)t);
}
};
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "texturebase.cpp"
namespace UwU {
class HGradientTexture : public TextureBase<HGradientTexture> {
public:
HGradientTexture(uint16_t width, Color c0, Color c1) {
this->uScale = 0xffffffff / (1 + (uint32_t)width);
this->c0 = c0;
this->c1 = c1;
}
uint32_t uScale;
Color c0;
Color c1;
Color texel(uint16_t u, uint16_t v) {
(void)v;
uint32_t t = (((uint32_t)u) * uScale) / 0x01000000;
return Helpers::lerpColor(c0, c1, (uint8_t)t);
}
};
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
namespace UwU {
template <class TextureT>
class TextureBase {
public:
Color texel(uint16_t u, uint16_t v) {
return static_cast<TextureT*>(this)->texel(u, v);
}
};
}
+7
View File
@@ -0,0 +1,7 @@
#include "texturebase.cpp"
#include "colortexture.cpp"
#include "bitmaptexture.cpp"
#include "tilemaptexture.cpp"
#include "hgradienttexture.cpp"
#include "vgradienttexture.cpp"
// #include "gradienttexture.cpp"
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "texturebase.cpp"
#include "../tilemap.cpp"
namespace UwU {
class TilemapTexture : public TextureBase<TilemapTexture> {
private:
Buffer buffer;
Tilemap tilemap;
public:
TilemapTexture(Tilemap tilemap, Buffer buffer) {
this->buffer = buffer;
this->tilemap = tilemap;
}
Color texel(uint16_t u, uint16_t v) {
Coord2 bitmapUV = tilemap.map(u, v);
uint32_t index = (bitmapUV.y * buffer.stride) + (bitmapUV.x * 4);
Color c = Color(buffer.pixels[index + 2], buffer.pixels[index + 1], buffer.pixels[index], buffer.pixels[index + 3]);
return c;
}
};
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include "../datatypes.cpp"
#include "../helpers.cpp"
#include "../buffer.cpp"
#include "texturebase.cpp"
namespace UwU {
class VGradientTexture : public TextureBase<VGradientTexture> {
public:
VGradientTexture(uint16_t height, Color c0, Color c1) {
this->vScale = 0xffffffff / (1 + (uint32_t)height);
this->c0 = c0;
this->c1 = c1;
}
uint32_t vScale;
Color c0;
Color c1;
Color texel(uint16_t u, uint16_t v) {
(void)u;
uint32_t t = (((uint32_t)v) * vScale) / 0x01000000;
return Helpers::lerpColor(c0, c1, (uint8_t)t);
}
};
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include "datatypes.cpp"
#include "helpers.cpp"
namespace UwU {
class Tilemap {
public:
Tilemap() {
this->tilemap = new uint16_t[16384]; // the map of tile positions 128x128 8x8 tiles from a 512x512 bitmap space
}
uint16_t* tilemap;
Coord2 map(uint16_t u, uint16_t v) {
// returns uv coordinates that point to a specific pixel of a specific tile on a tilesheet buffer
uint16_t mapX = (u & 0x03f8) >> 3;
uint16_t mapY = (v & 0x03f8) << 4;
uint16_t tileIndex = tilemap[mapY + mapX];
uint16_t u1 = (tileIndex & 0x003f) << 3;
u1 += (u & 0x0007);
uint16_t v1 = (tileIndex & 0x0fc0) >> 3;
v1 += (v & 0x0007);
return Coord2(u1, v1);
}
};
}
-27
View File
@@ -1,27 +0,0 @@
#pragma once
#include <stdint.h>
#include "datatypes.cpp"
#include "helpers.cpp"
namespace UwU {
class Triangle {
public:
Triangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
this->x0 = x0;
this->y0 = y0;
this->x1 = x1;
this->y1 = y1;
this->x2 = x2;
this->y2 = y2;
}
Triangle() {}
uint16_t x0;
uint16_t y0;
uint16_t x1;
uint16_t y1;
uint16_t x2;
uint16_t y2;
};
}
+9
View File
@@ -0,0 +1,9 @@
#include "datatypes.cpp"
#include "helpers.cpp"
#include "buffer.cpp"
#include "surface.cpp"
#include "primatives/primatives.h"
#include "mappers/mappers.h"
#include "textures/textures.h"
#include "tilemap.cpp"
// #include "shaders/shaders.h"
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
View File
View File
BIN
View File
Binary file not shown.