init
This commit is contained in:
commit
7640a16333
19
.clang-format
Normal file
19
.clang-format
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: WebKit
|
||||||
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 80
|
||||||
|
IndentCaseLabels: true
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|
||||||
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
|
|
||||||
|
BinPackArguments: false
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
|
||||||
|
# BinPackParameters: OnePerLine # llvm >= 20
|
||||||
|
BinPackParameters: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 1000 # abitrary, seems to work
|
||||||
|
|
||||||
|
|
||||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
game
|
||||||
20
Makefile
Normal file
20
Makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
CFLAGS = -std=c23
|
||||||
|
CFLAGS += -fsanitize=address,undefined -g
|
||||||
|
CFLAGS += -Wall -Wextra -Wpedantic -Wconversion -pedantic -pedantic-errors
|
||||||
|
|
||||||
|
LFLAGS = -lm
|
||||||
|
|
||||||
|
CFLAGS += $(shell pkg-config sdl2 --cflags)
|
||||||
|
LFLAGS += $(shell pkg-config sdl2 --libs)
|
||||||
|
|
||||||
|
CFILES = $(shell find . -name "*.c")
|
||||||
|
HFILES = $(shell find . -name "*.h")
|
||||||
|
|
||||||
|
game: $(CFILES) $(HFILES)
|
||||||
|
gcc -o $@ $(CFILES) $(CFLAGS) $(LFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf game
|
||||||
|
|
||||||
|
|
||||||
10
compile_flags.txt
Normal file
10
compile_flags.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
-xc
|
||||||
|
-std=c23
|
||||||
|
-Wall
|
||||||
|
-Wextra
|
||||||
|
-Wpedantic
|
||||||
|
-Wconversion
|
||||||
|
-pedantic
|
||||||
|
-pedantic-errors
|
||||||
|
-Wno-unused-variable
|
||||||
|
|
||||||
33
linalg.c
Normal file
33
linalg.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "linalg.h"
|
||||||
|
|
||||||
|
f2 f2_from_f3(f3 v)
|
||||||
|
{
|
||||||
|
return (f2) { v.x, v.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
i2 i2_from_f2(f2 v)
|
||||||
|
{
|
||||||
|
return (i2) { (int)v.x, (int)v.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 add_f3(f3 l, f3 r)
|
||||||
|
{
|
||||||
|
return (f3) { l.x + r.x, l.y + r.y, l.z + r.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 mul_f2_f2x2(f2 l, f2x2 r)
|
||||||
|
{
|
||||||
|
return (f2) {
|
||||||
|
l.x * r.xx + l.y * r.xy,
|
||||||
|
l.x * r.yx + l.y * r.yy,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 mul_f3_f3x3(f3 l, f3x3 r)
|
||||||
|
{
|
||||||
|
return (f3) {
|
||||||
|
l.x * r.xx + l.y * r.xy + l.z * r.xz,
|
||||||
|
l.x * r.yx + l.y * r.yy + l.z * r.yz,
|
||||||
|
l.x * r.zx + l.y * r.zy + l.z * r.zz,
|
||||||
|
};
|
||||||
|
}
|
||||||
59
linalg.h
Normal file
59
linalg.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef LINALG_H
|
||||||
|
#define LINALG_H
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
} f3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double xx;
|
||||||
|
double xy;
|
||||||
|
double xz;
|
||||||
|
double yx;
|
||||||
|
double yy;
|
||||||
|
double yz;
|
||||||
|
double zx;
|
||||||
|
double zy;
|
||||||
|
double zz;
|
||||||
|
} f3x3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
} f2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double xx;
|
||||||
|
double xy;
|
||||||
|
double yx;
|
||||||
|
double yy;
|
||||||
|
} f2x2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
f2 p0;
|
||||||
|
f2 p1;
|
||||||
|
f2 p2;
|
||||||
|
} f2x3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} i2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
i2 p0;
|
||||||
|
i2 p1;
|
||||||
|
i2 p2;
|
||||||
|
} i2x3;
|
||||||
|
|
||||||
|
f2 f2_from_f3(f3 v);
|
||||||
|
i2 i2_from_f2(f2 v);
|
||||||
|
|
||||||
|
f3 add_f3(f3 l, f3 r);
|
||||||
|
|
||||||
|
f2 mul_f2_f2x2(f2 l, f2x2 r);
|
||||||
|
f3 mul_f3_f3x3(f3 l, f3x3 r);
|
||||||
|
|
||||||
|
#endif
|
||||||
454
main.c
Normal file
454
main.c
Normal file
@ -0,0 +1,454 @@
|
|||||||
|
#include "linalg.h"
|
||||||
|
#include "texture_map.h"
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <SDL2/SDL_blendmode.h>
|
||||||
|
#include <SDL2/SDL_events.h>
|
||||||
|
#include <SDL2/SDL_keycode.h>
|
||||||
|
#include <SDL2/SDL_pixels.h>
|
||||||
|
#include <SDL2/SDL_rect.h>
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
#include <SDL2/SDL_timer.h>
|
||||||
|
#include <SDL2/SDL_video.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
const f3 verts[] = {
|
||||||
|
// clang-format off
|
||||||
|
{ 0, 0, 0 }, // 0 front top left
|
||||||
|
{ 1, 0, 0 }, // 1 front top right
|
||||||
|
{ 0, 1, 0 }, // 2 front bottom left
|
||||||
|
{ 1, 1, 0 }, // 3 front bottom right
|
||||||
|
{ 0, 0, 1 }, // 4 back top left
|
||||||
|
{ 1, 0, 1 }, // 5 back top right
|
||||||
|
{ 0, 1, 1 }, // 6 back bottom left
|
||||||
|
{ 1, 1, 1 }, // 7 back bottom right
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t shapes[][3] = {
|
||||||
|
// back
|
||||||
|
{ 0, 1, 2 },
|
||||||
|
{ 3, 2, 1 },
|
||||||
|
// bottom
|
||||||
|
{ 4, 5, 0 },
|
||||||
|
{ 1, 0, 5 },
|
||||||
|
// left
|
||||||
|
{ 4, 0, 6 },
|
||||||
|
{ 2, 6, 0 },
|
||||||
|
// front
|
||||||
|
{ 5, 4, 7 },
|
||||||
|
{ 6, 7, 4 },
|
||||||
|
// top
|
||||||
|
{ 7, 6, 3 },
|
||||||
|
{ 2, 3, 6 },
|
||||||
|
// right
|
||||||
|
{ 1, 5, 3 },
|
||||||
|
{ 7, 3, 5 },
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr size_t verts_size = sizeof(verts) / sizeof(verts[0]);
|
||||||
|
constexpr size_t shapes_size = sizeof(shapes) / sizeof(shapes[0]);
|
||||||
|
|
||||||
|
constexpr int screen_width = 1024;
|
||||||
|
constexpr int screen_height = 1024;
|
||||||
|
|
||||||
|
constexpr size_t colors_size = 32;
|
||||||
|
uint32_t colors[colors_size] = { 0 };
|
||||||
|
|
||||||
|
constexpr size_t textures_size = 1;
|
||||||
|
uint32_t textures[textures_size][64];
|
||||||
|
|
||||||
|
const f2 verts_uv_map[verts_size] = {
|
||||||
|
// clang-format off
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 1, 0 },
|
||||||
|
{ 0, 1 },
|
||||||
|
{ 1, 1 },
|
||||||
|
{ 0, 0 },
|
||||||
|
{ 1, 0 },
|
||||||
|
{ 0, 1 },
|
||||||
|
{ 1, 1 },
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t shapes_textures_map[shapes_size] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI (3.141529653578)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
double pi(double v)
|
||||||
|
{
|
||||||
|
return v * M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX(L, R) ((L) >= (R) ? (L) : (R))
|
||||||
|
#define MIN(L, R) ((L) < (R) ? (L) : (R))
|
||||||
|
|
||||||
|
void set_px(uint32_t* pixels, int x, int y, uint32_t color)
|
||||||
|
{
|
||||||
|
if ((uint32_t)x >= (size_t)screen_width
|
||||||
|
|| (uint32_t)y >= (size_t)screen_height)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pixels[y * screen_width + x] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_line_impl(
|
||||||
|
uint32_t* pixels, int x0, int y0, int x1, int y1, uint32_t color,
|
||||||
|
bool steep)
|
||||||
|
{
|
||||||
|
if (abs(x0 - x1) < abs(y0 - y1)) {
|
||||||
|
draw_line_impl(pixels, y0, x0, y1, x1, color, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (x0 > x1) {
|
||||||
|
draw_line_impl(pixels, x1, y1, x0, y0, color, steep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int dx = x1 - x0;
|
||||||
|
int dy = y1 - y0;
|
||||||
|
int derror2 = abs(dy) * 2;
|
||||||
|
int error2 = 0;
|
||||||
|
int y = y0;
|
||||||
|
for (int x = x0; x <= x1; ++x) {
|
||||||
|
if (steep) {
|
||||||
|
set_px(pixels, y, x, color);
|
||||||
|
} else {
|
||||||
|
set_px(pixels, x, y, color);
|
||||||
|
}
|
||||||
|
error2 += derror2;
|
||||||
|
if (error2 > dx) {
|
||||||
|
y += y1 > y0 ? 1 : -1;
|
||||||
|
error2 -= dx * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_line(uint32_t* pixels, i2 p0, i2 p1, uint32_t color)
|
||||||
|
{
|
||||||
|
draw_line_impl(pixels, p0.x, p0.y, p1.x, p1.y, color, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_triangle_lines(uint32_t* pixels, i2x3 tri, uint32_t color)
|
||||||
|
{
|
||||||
|
draw_line(pixels, tri.p0, tri.p1, color);
|
||||||
|
draw_line(pixels, tri.p1, tri.p2, color);
|
||||||
|
draw_line(pixels, tri.p2, tri.p0, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
double signed_triangle_area(int x0, int y0, int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
return 0.5
|
||||||
|
* ((y1 - y0) * (x1 + x0) + (y2 - y1) * (x2 + x1)
|
||||||
|
+ (y0 - y2) * (x0 + x2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_triangle_filled(uint32_t* pixels, i2x3 tri, uint32_t color)
|
||||||
|
{
|
||||||
|
int x0 = tri.p0.x;
|
||||||
|
int y0 = tri.p0.y;
|
||||||
|
int x1 = tri.p1.x;
|
||||||
|
int y1 = tri.p1.y;
|
||||||
|
int x2 = tri.p2.x;
|
||||||
|
int y2 = tri.p2.y;
|
||||||
|
|
||||||
|
int rect_x0 = MIN(MIN(x0, x1), x2);
|
||||||
|
int rect_y0 = MIN(MIN(y0, y1), y2);
|
||||||
|
|
||||||
|
int rect_x1 = MAX(MAX(x0, x1), x2);
|
||||||
|
int rect_y1 = MAX(MAX(y0, y1), y2);
|
||||||
|
|
||||||
|
int rect_w = rect_x1 - rect_x0;
|
||||||
|
int rect_h = rect_y1 - rect_y0;
|
||||||
|
|
||||||
|
if (rect_w == 0 || rect_h == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double area = signed_triangle_area(x0, y0, x1, y1, x2, y2);
|
||||||
|
|
||||||
|
for (int y = rect_y0; y <= rect_y1; ++y) {
|
||||||
|
for (int x = rect_x0; x <= rect_x1; ++x) {
|
||||||
|
double a0 = signed_triangle_area(x, y, x1, y1, x2, y2) / area;
|
||||||
|
double a1 = signed_triangle_area(x, y, x2, y2, x0, y0) / area;
|
||||||
|
double a2 = signed_triangle_area(x, y, x0, y0, x1, y1) / area;
|
||||||
|
|
||||||
|
if (a0 < 0 || a1 < 0 || a2 < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
set_px(pixels, x, y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 rotate_x(f3 v, double angle)
|
||||||
|
{
|
||||||
|
f3x3 rotation_mx = {
|
||||||
|
// clang-format off
|
||||||
|
1, 0, 0,
|
||||||
|
0, cos(angle), -sin(angle),
|
||||||
|
0, sin(angle), cos(angle),
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
return mul_f3_f3x3(v, rotation_mx);
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 rotate_y(f3 v, double angle)
|
||||||
|
{
|
||||||
|
f3x3 rotation_mx = {
|
||||||
|
// clang-format off
|
||||||
|
cos(angle), 0, sin(angle),
|
||||||
|
0, 1, 0,
|
||||||
|
-sin(angle), 0, cos(angle),
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
return mul_f3_f3x3(v, rotation_mx);
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 rotate_z(f3 v, double angle)
|
||||||
|
{
|
||||||
|
f3x3 rotation_mx = {
|
||||||
|
// clang-format off
|
||||||
|
cos(angle), -sin(angle), 0,
|
||||||
|
sin(angle), cos(angle), 0,
|
||||||
|
0, 0, 1,
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
return mul_f3_f3x3(v, rotation_mx);
|
||||||
|
}
|
||||||
|
|
||||||
|
f3 translate(f3 v, double x, double y, double z)
|
||||||
|
{
|
||||||
|
return add_f3(v, (f3) { x, y, z });
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 f3_project(f3 v, double focal_length)
|
||||||
|
{
|
||||||
|
focal_length *= -1;
|
||||||
|
return (f2) {
|
||||||
|
(v.x * focal_length) / (v.z + focal_length),
|
||||||
|
(-v.y * focal_length) / (v.z + focal_length),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
i2 f2_to_screen_i2(f2 v)
|
||||||
|
{
|
||||||
|
return (i2) {
|
||||||
|
(int)(v.x * (screen_width / 4.0) + screen_width / 2.0),
|
||||||
|
(int)(v.y * (screen_width / 4.0) + screen_width / 2.0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
f2 f2_to_screen(f2 v)
|
||||||
|
{
|
||||||
|
return (f2) {
|
||||||
|
v.x * (screen_width / 4.0) + screen_width / 2.0,
|
||||||
|
v.y * (screen_width / 4.0) + screen_width / 2.0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_shape(uint32_t* pixels, i2x3 verts, uint32_t color)
|
||||||
|
{
|
||||||
|
double cross_z = (verts.p1.x - verts.p0.x) * (verts.p2.y - verts.p0.y)
|
||||||
|
- (verts.p1.y - verts.p0.y) * (verts.p2.x - verts.p0.x);
|
||||||
|
if (cross_z <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
draw_triangle_filled(pixels, verts, color);
|
||||||
|
// draw_triangle_lines(pixels, verts, 0xff000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
double f2x3_signed_area(f2x3 s)
|
||||||
|
{
|
||||||
|
return 0.5
|
||||||
|
* ((s.p1.y - s.p0.y) * (s.p1.x + s.p0.x)
|
||||||
|
+ (s.p2.y - s.p1.y) * (s.p2.x + s.p1.x)
|
||||||
|
+ (s.p0.y - s.p2.y) * (s.p0.x + s.p2.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_shape_with_texture(uint32_t* pixels, size_t shape_idx, f2x3 s)
|
||||||
|
{
|
||||||
|
double cross_z = (s.p1.x - s.p0.x) * (s.p2.y - s.p0.y)
|
||||||
|
- (s.p1.y - s.p0.y) * (s.p2.x - s.p0.x);
|
||||||
|
if (cross_z <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double rect_x0 = MIN(MIN(s.p0.x, s.p1.x), s.p2.x);
|
||||||
|
double rect_y0 = MIN(MIN(s.p0.y, s.p1.y), s.p2.y);
|
||||||
|
|
||||||
|
double rect_x1 = MAX(MAX(s.p0.x, s.p1.x), s.p2.x);
|
||||||
|
double rect_y1 = MAX(MAX(s.p0.y, s.p1.y), s.p2.y);
|
||||||
|
|
||||||
|
double rect_w = rect_x1 - rect_x0;
|
||||||
|
double rect_h = rect_y1 - rect_y0;
|
||||||
|
|
||||||
|
if (rect_w == 0 || rect_h == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double area = f2x3_signed_area(s);
|
||||||
|
|
||||||
|
for (int y = (int)rect_y0; y <= rect_y1; ++y) {
|
||||||
|
for (int x = (int)rect_x0; x <= rect_x1; ++x) {
|
||||||
|
f2 p = { x, y };
|
||||||
|
double a0 = f2x3_signed_area((f2x3) { p, s.p1, s.p2 }) / area;
|
||||||
|
double a1 = f2x3_signed_area((f2x3) { p, s.p2, s.p0 }) / area;
|
||||||
|
double a2 = f2x3_signed_area((f2x3) { p, s.p0, s.p1 }) / area;
|
||||||
|
|
||||||
|
if (a0 < 0 || a1 < 0 || a2 < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
f2 uv = { x / rect_x1, y / rect_y1 };
|
||||||
|
|
||||||
|
// uint32_t color
|
||||||
|
// = (uint32_t)(0xff * uv.x) << 0 | (uint32_t)(0xff * uv.y) <<
|
||||||
|
// 8;
|
||||||
|
// uint32_t color = colors[shape_idx];
|
||||||
|
uint32_t color
|
||||||
|
= textures[0][MIN((size_t)(uv.y * 8 * 8 + uv.x * 8), 63)];
|
||||||
|
|
||||||
|
set_px(pixels, x, y, 0xff000000 | color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(uint32_t* pixels, uint64_t total_ms)
|
||||||
|
{
|
||||||
|
double time_frac = total_ms % 4000 / 4000.0;
|
||||||
|
|
||||||
|
i2 screen_verts_i2[verts_size];
|
||||||
|
f2 screen_verts[verts_size];
|
||||||
|
for (size_t i = 0; i < verts_size; ++i) {
|
||||||
|
f3 v = verts[i];
|
||||||
|
|
||||||
|
v = translate(v, -0.5, -0.5, -0.5);
|
||||||
|
|
||||||
|
// v = rotate_y(v, pi(2) * time_frac);
|
||||||
|
|
||||||
|
v = rotate_x(v, M_PI * 2 * time_frac);
|
||||||
|
v = rotate_y(v, M_PI * 2 * time_frac);
|
||||||
|
v = rotate_z(v, M_PI * 2 * time_frac);
|
||||||
|
|
||||||
|
v = translate(v, -1, -1, 0);
|
||||||
|
v = translate(v, 10 * time_frac, 10 * time_frac, -20 * time_frac);
|
||||||
|
|
||||||
|
screen_verts_i2[i] = f2_to_screen_i2(f3_project(v, 4.0));
|
||||||
|
screen_verts[i] = f2_to_screen(f3_project(v, 4.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t shape_idx = 0; shape_idx < shapes_size; ++shape_idx) {
|
||||||
|
|
||||||
|
i2x3 shape_verts_i2;
|
||||||
|
f2x3 shape_verts;
|
||||||
|
for (size_t vert_idx = 0; vert_idx < 3; ++vert_idx) {
|
||||||
|
((i2*)&shape_verts_i2)[vert_idx]
|
||||||
|
= screen_verts_i2[shapes[shape_idx][vert_idx]];
|
||||||
|
((f2*)&shape_verts)[vert_idx]
|
||||||
|
= screen_verts[shapes[shape_idx][vert_idx]];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DRAW_TEXTURE
|
||||||
|
draw_shape_with_texture(pixels, shape_idx, shape_verts);
|
||||||
|
#elifdef DRAW_LINES
|
||||||
|
draw_triangle_lines(pixels, shape_verts_i2, 0xffffffff);
|
||||||
|
#else
|
||||||
|
draw_shape(pixels, shape_verts_i2, colors[shape_idx]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
srand((unsigned int)time(nullptr));
|
||||||
|
|
||||||
|
TextureMap* texture_map = texture_map_new("texture_map.tga");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < textures_size; ++i) {
|
||||||
|
texture_map_read_texture(texture_map, textures[i], (int)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
texture_map_free(texture_map);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < colors_size; ++i) {
|
||||||
|
uint32_t color = (uint32_t)((double)rand() / RAND_MAX * 0xffffff);
|
||||||
|
colors[i] = 0xffu << 24 | color;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_VIDEO);
|
||||||
|
|
||||||
|
SDL_Window* window;
|
||||||
|
SDL_Renderer* renderer;
|
||||||
|
|
||||||
|
SDL_CreateWindowAndRenderer(
|
||||||
|
screen_width, screen_height, 0, &window, &renderer);
|
||||||
|
|
||||||
|
SDL_Texture* buffer = SDL_CreateTexture(
|
||||||
|
renderer,
|
||||||
|
SDL_PIXELFORMAT_RGBA32,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
|
screen_width,
|
||||||
|
screen_height);
|
||||||
|
|
||||||
|
SDL_SetTextureBlendMode(buffer, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
uint64_t before = SDL_GetTicks64();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
uint64_t now = SDL_GetTicks64();
|
||||||
|
uint64_t delta = now - before;
|
||||||
|
(void)delta;
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_QUIT:
|
||||||
|
goto exit_game;
|
||||||
|
case SDL_KEYDOWN: {
|
||||||
|
switch (event.key.keysym.sym) {
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
goto exit_game;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
uint32_t* pixels;
|
||||||
|
int row_size;
|
||||||
|
SDL_LockTexture(
|
||||||
|
buffer,
|
||||||
|
&(SDL_Rect) { 0, 0, screen_width, screen_height },
|
||||||
|
(void**)&pixels,
|
||||||
|
&row_size);
|
||||||
|
row_size /= (int)sizeof(uint32_t);
|
||||||
|
|
||||||
|
memset(
|
||||||
|
pixels,
|
||||||
|
0,
|
||||||
|
sizeof(int) * (size_t)screen_width * (size_t)screen_height);
|
||||||
|
|
||||||
|
render(pixels, now);
|
||||||
|
|
||||||
|
SDL_UnlockTexture(buffer);
|
||||||
|
|
||||||
|
SDL_RenderCopy(renderer, buffer, nullptr, nullptr);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
SDL_Delay(16);
|
||||||
|
|
||||||
|
before = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_game:;
|
||||||
|
printf("exitting...\n");
|
||||||
|
|
||||||
|
SDL_DestroyRenderer(renderer);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
144
texture_map.c
Normal file
144
texture_map.c
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#include "texture_map.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct TextureMap {
|
||||||
|
uint32_t* data;
|
||||||
|
size_t width;
|
||||||
|
size_t height;
|
||||||
|
};
|
||||||
|
|
||||||
|
TextureMap* texture_map_new(const char* filename)
|
||||||
|
{
|
||||||
|
TextureMap* result;
|
||||||
|
|
||||||
|
FILE* file = fopen(filename, "rb");
|
||||||
|
if (!file) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"error: could not open texture map file \"%s\": %s\n",
|
||||||
|
filename,
|
||||||
|
strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t header_size = 18;
|
||||||
|
uint8_t header[header_size];
|
||||||
|
size_t header_read = fread(header, 1, 18, file);
|
||||||
|
if (header_read != header_size) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"error: could not read texture map TGA header of file \"%s\"\n",
|
||||||
|
filename);
|
||||||
|
|
||||||
|
result = nullptr;
|
||||||
|
goto exit_close_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* header_iter = header;
|
||||||
|
|
||||||
|
uint8_t id_length = *header_iter++;
|
||||||
|
uint8_t color_map_type = *header_iter++;
|
||||||
|
uint8_t image_type = *header_iter++;
|
||||||
|
uint8_t cm_spec[5];
|
||||||
|
for (size_t i = 0; i < 5; ++i)
|
||||||
|
cm_spec[i] = *header_iter++;
|
||||||
|
uint8_t image_spec[10];
|
||||||
|
for (size_t i = 0; i < 10; ++i)
|
||||||
|
image_spec[i] = *header_iter++;
|
||||||
|
|
||||||
|
uint16_t first_entry_index = (uint16_t)(cm_spec[1] << 8 | cm_spec[0]);
|
||||||
|
uint16_t cm_length = (cm_spec[2] << 8 | cm_spec[3]) & 0xffff;
|
||||||
|
uint8_t cm_entry_size = cm_spec[4];
|
||||||
|
|
||||||
|
uint16_t x_origin = (uint16_t)(image_spec[1] << 8 | image_spec[0]);
|
||||||
|
uint16_t y_origin = (uint16_t)(image_spec[3] << 8 | image_spec[2]);
|
||||||
|
uint16_t image_width = (uint16_t)(image_spec[5] << 8 | image_spec[4]);
|
||||||
|
uint16_t image_height = (uint16_t)(image_spec[7] << 8 | image_spec[6]);
|
||||||
|
uint8_t pixel_depth = image_spec[8];
|
||||||
|
uint8_t image_desc = image_spec[9];
|
||||||
|
|
||||||
|
uint8_t alpha_channel_depth = image_desc & 0b1111;
|
||||||
|
bool right_to_left_ordering = image_desc >> 4 & 0x1;
|
||||||
|
bool top_to_bottom_ordering = image_desc >> 5 & 0x1;
|
||||||
|
|
||||||
|
if (!(id_length == 0 && color_map_type == 0 && image_type == 2
|
||||||
|
&& first_entry_index == 0 && cm_length == 0 && cm_entry_size == 0
|
||||||
|
&& x_origin == 0 && y_origin == 128 && image_width == 128
|
||||||
|
&& image_height == 128 && pixel_depth == 32 && image_desc == 40
|
||||||
|
&& alpha_channel_depth == 8 && right_to_left_ordering == 0
|
||||||
|
&& top_to_bottom_ordering == 1)) {
|
||||||
|
fprintf(stderr, "error: invalid texture map \"%s\"\n", filename);
|
||||||
|
printf("id length: %d\n", id_length);
|
||||||
|
printf("color map type: %d\n", color_map_type);
|
||||||
|
printf("image type: %d\n", image_type);
|
||||||
|
printf("first entry index: %d\n", first_entry_index);
|
||||||
|
printf("color map length: %d\n", cm_length);
|
||||||
|
printf("color map entry size: %d\n", cm_entry_size);
|
||||||
|
printf("x_origin: %d\n", x_origin);
|
||||||
|
printf("y_origin: %d\n", y_origin);
|
||||||
|
printf("image_width: %d\n", image_width);
|
||||||
|
printf("image_height: %d\n", image_height);
|
||||||
|
printf("pixel_depth: %d\n", pixel_depth);
|
||||||
|
printf("image_desc: %d\n", image_desc);
|
||||||
|
printf("alpha_channel_depth: %d\n", alpha_channel_depth);
|
||||||
|
printf("right_to_left_ordering: %d\n", right_to_left_ordering);
|
||||||
|
printf("top_to_bottom_ordering: %d\n", top_to_bottom_ordering);
|
||||||
|
|
||||||
|
result = nullptr;
|
||||||
|
goto exit_close_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t* data = malloc(sizeof(uint32_t) * image_width * image_height);
|
||||||
|
size_t data_read
|
||||||
|
= fread(data, sizeof(uint32_t), image_width * image_height, file);
|
||||||
|
if (data_read != image_width * image_height) {
|
||||||
|
printf("data_bytes_read: %ld\n", data_read);
|
||||||
|
printf(
|
||||||
|
"expected: %ld\n", sizeof(uint32_t) * image_width * image_height);
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"error: could not read texture map TGA data of file \"%s\"\n",
|
||||||
|
filename);
|
||||||
|
|
||||||
|
result = nullptr;
|
||||||
|
goto exit_free_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = malloc(sizeof(TextureMap));
|
||||||
|
*result = (TextureMap) {
|
||||||
|
.data = data,
|
||||||
|
.width = image_width,
|
||||||
|
.height = image_height,
|
||||||
|
};
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
exit_free_data:
|
||||||
|
free(data);
|
||||||
|
exit_close_file:
|
||||||
|
fclose(file);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void texture_map_free(TextureMap* map)
|
||||||
|
{
|
||||||
|
free(map->data);
|
||||||
|
free(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
void texture_map_read_texture(TextureMap* map, uint32_t* data, int id)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < 8; ++y) {
|
||||||
|
for (size_t x = 0; x < 8; ++x) {
|
||||||
|
size_t oy = (size_t)(id / 8) + y;
|
||||||
|
size_t ox = (size_t)(id % 8) + x;
|
||||||
|
data[y * 8 + x] = map->data[oy * map->width + ox];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
texture_map.h
Normal file
14
texture_map.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef TEXTURE_MAP_H
|
||||||
|
#define TEXTURE_MAP_H
|
||||||
|
|
||||||
|
#include "linalg.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct TextureMap TextureMap;
|
||||||
|
|
||||||
|
TextureMap* texture_map_new(const char* filename);
|
||||||
|
void texture_map_free(TextureMap* map);
|
||||||
|
|
||||||
|
void texture_map_read_texture(TextureMap* map, uint32_t* data, int id);
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
texture_map.tga
Normal file
BIN
texture_map.tga
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
Loading…
x
Reference in New Issue
Block a user