refactor atlas implementation
This commit is contained in:
parent
6008ebf5ed
commit
10fe609edc
12 changed files with 868 additions and 303 deletions
|
|
@ -8,6 +8,17 @@
|
|||
(var wireframe true)
|
||||
(var time 0)
|
||||
(var zoom 5.0)
|
||||
(var texture-id nil)
|
||||
(var use-texture false)
|
||||
(var affine false)
|
||||
(var texture-initialized false)
|
||||
|
||||
(fn init-texture []
|
||||
(when (not texture-initialized)
|
||||
(pxl8.load_palette "sprites/pxl8_logo.ase")
|
||||
(set texture-id (pxl8.load_sprite "sprites/pxl8_logo.ase"))
|
||||
(pxl8.upload_atlas)
|
||||
(set texture-initialized true)))
|
||||
|
||||
(fn make-cube-vertices []
|
||||
[[-1 -1 -1] [1 -1 -1] [1 1 -1] [-1 1 -1]
|
||||
|
|
@ -21,6 +32,20 @@
|
|||
[3 2 6] [3 6 7]
|
||||
[4 5 1] [4 1 0]])
|
||||
|
||||
(fn make-cube-faces-with-uvs []
|
||||
[{:tri [0 1 2] :uvs [[0 0] [1 0] [1 1]]}
|
||||
{:tri [0 2 3] :uvs [[0 0] [1 1] [0 1]]}
|
||||
{:tri [1 5 6] :uvs [[0 0] [1 0] [1 1]]}
|
||||
{:tri [1 6 2] :uvs [[0 0] [1 1] [0 1]]}
|
||||
{:tri [5 4 7] :uvs [[0 0] [1 0] [1 1]]}
|
||||
{:tri [5 7 6] :uvs [[0 0] [1 1] [0 1]]}
|
||||
{:tri [4 0 3] :uvs [[0 0] [1 0] [1 1]]}
|
||||
{:tri [4 3 7] :uvs [[0 0] [1 1] [0 1]]}
|
||||
{:tri [3 2 6] :uvs [[0 0] [1 0] [1 1]]}
|
||||
{:tri [3 6 7] :uvs [[0 0] [1 1] [0 1]]}
|
||||
{:tri [4 5 1] :uvs [[0 0] [1 0] [1 1]]}
|
||||
{:tri [4 1 0] :uvs [[0 0] [1 1] [0 1]]}])
|
||||
|
||||
(fn get-face-color [face-idx]
|
||||
(let [colors [12 22 30 16 28 20]]
|
||||
(. colors (+ 1 (% face-idx 6)))))
|
||||
|
|
@ -43,10 +68,16 @@
|
|||
|
||||
(when (pxl8.key_pressed " ")
|
||||
(set wireframe (not wireframe)))
|
||||
(when (pxl8.key_pressed "r")
|
||||
(set auto-rotate (not auto-rotate)))
|
||||
(when (pxl8.key_pressed "f")
|
||||
(set affine (not affine)))
|
||||
(when (pxl8.key_pressed "p")
|
||||
(set orthographic (not orthographic)))
|
||||
(when (pxl8.key_pressed "r")
|
||||
(set auto-rotate (not auto-rotate)))
|
||||
(when (pxl8.key_pressed "t")
|
||||
(set use-texture (not use-texture))
|
||||
(when use-texture
|
||||
(init-texture)))
|
||||
|
||||
(when (pxl8.key_down "=")
|
||||
(set zoom (- zoom (* dt 2.0))))
|
||||
|
|
@ -63,8 +94,9 @@
|
|||
(pxl8.clr 0)
|
||||
|
||||
(pxl8.clear_zbuffer)
|
||||
(pxl8.set_wireframe wireframe)
|
||||
(pxl8.set_affine_textures affine)
|
||||
(pxl8.set_backface_culling true)
|
||||
(pxl8.set_wireframe wireframe)
|
||||
|
||||
(if orthographic
|
||||
(let [size (* 2.5 (/ zoom 5.0))
|
||||
|
|
@ -84,15 +116,36 @@
|
|||
(pxl8.mat4_multiply (pxl8.mat4_rotate_z angle-z)))]
|
||||
(pxl8.set_model model))
|
||||
|
||||
(let [vertices (make-cube-vertices)
|
||||
faces (make-cube-faces)]
|
||||
(each [i face (ipairs faces)]
|
||||
(let [[i0 i1 i2] face
|
||||
v0 (. vertices (+ 1 i0))
|
||||
v1 (. vertices (+ 1 i1))
|
||||
v2 (. vertices (+ 1 i2))
|
||||
color (get-face-color (math.floor (/ (- i 1) 2)))]
|
||||
(pxl8.draw_triangle_3d v0 v1 v2 color)))))
|
||||
(let [vertices (make-cube-vertices)]
|
||||
(if (and use-texture texture-id)
|
||||
(let [faces (make-cube-faces-with-uvs)]
|
||||
(each [i face-data (ipairs faces)]
|
||||
(let [tri-indices face-data.tri
|
||||
tri-uvs face-data.uvs
|
||||
v0 (. vertices (+ 1 (. tri-indices 1)))
|
||||
v1 (. vertices (+ 1 (. tri-indices 2)))
|
||||
v2 (. vertices (+ 1 (. tri-indices 3)))
|
||||
uv0 (. tri-uvs 1)
|
||||
uv1 (. tri-uvs 2)
|
||||
uv2 (. tri-uvs 3)]
|
||||
(pxl8.draw_triangle_3d_textured
|
||||
v0 v1 v2
|
||||
uv0 uv1 uv2
|
||||
texture-id))))
|
||||
(let [faces (make-cube-faces)]
|
||||
(each [i face (ipairs faces)]
|
||||
(let [[i0 i1 i2] face
|
||||
v0 (. vertices (+ 1 i0))
|
||||
v1 (. vertices (+ 1 i1))
|
||||
v2 (. vertices (+ 1 i2))
|
||||
color (get-face-color (math.floor (/ (- i 1) 2)))]
|
||||
(pxl8.draw_triangle_3d v0 v1 v2 color))))))
|
||||
|
||||
(pxl8.text "WASD/QE: Rotate | +/-: Zoom | Space: Wire | R: Auto | P: Proj" 5 5 15)
|
||||
(pxl8.text (.. "T: Texture | F: Affine | Mode: "
|
||||
(if wireframe "Wire" "Fill")
|
||||
" | Texture: " (if use-texture "On" "Off")
|
||||
" | Mapping: " (if affine "Affine" "Persp")) 5 15 15))
|
||||
|
||||
{:update cube-update
|
||||
:frame cube-frame}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
(var fire-init false)
|
||||
(var rain-init false)
|
||||
(var snow-init false)
|
||||
(var use-nes-palette false)
|
||||
|
||||
(var logo-x 256)
|
||||
(var logo-y 148)
|
||||
|
|
@ -15,7 +16,7 @@
|
|||
(var logo-sprite nil)
|
||||
|
||||
(global init (fn []
|
||||
(pxl8.load_palette "palettes/gruvbox.ase")
|
||||
(pxl8.load_palette "sprites/pxl8_logo.ase")
|
||||
(set logo-sprite (pxl8.load_sprite "sprites/pxl8_logo.ase"))
|
||||
(set particles (pxl8.particles_new 1000))))
|
||||
|
||||
|
|
@ -41,6 +42,12 @@
|
|||
(set snow-init false))
|
||||
(when (pxl8.key_pressed "8")
|
||||
(set current-effect 8))
|
||||
(when (pxl8.key_pressed "9")
|
||||
(set use-nes-palette (not use-nes-palette))
|
||||
(local palette-path (if use-nes-palette "palettes/nes.ase" "sprites/pxl8_logo.ase"))
|
||||
(print (.. "Switching to palette: " palette-path))
|
||||
(pxl8.load_palette palette-path)
|
||||
(print "Palette loaded"))
|
||||
|
||||
(case current-effect
|
||||
1 (do
|
||||
|
|
@ -63,15 +70,15 @@
|
|||
(when logo-sprite
|
||||
(pxl8.sprite logo-sprite logo-x logo-y 128 64)))
|
||||
|
||||
2 (pxl8.vfx_plasma time 0.10 0.04 0)
|
||||
2 (pxl8.vfx_plasma time 0.10 0.04 1)
|
||||
|
||||
3 (pxl8.vfx_tunnel time 2.0 0.25)
|
||||
|
||||
4 (do
|
||||
(pxl8.clr 0)
|
||||
(local bars [{:base_y 60 :amplitude 30 :height 16 :speed 2.0 :phase 0 :color 20 :fade_color 10}
|
||||
{:base_y 180 :amplitude 35 :height 16 :speed 1.8 :phase 2.0 :color 26 :fade_color 10}
|
||||
{:base_y 300 :amplitude 25 :height 16 :speed 2.2 :phase 4.0 :color 14 :fade_color 10}])
|
||||
(local bars [{:base_y 60 :amplitude 30 :height 16 :speed 2.0 :phase 0 :color 1 :fade_color 18}
|
||||
{:base_y 180 :amplitude 35 :height 16 :speed 1.8 :phase 2.0 :color 1 :fade_color 27}
|
||||
{:base_y 300 :amplitude 25 :height 16 :speed 2.2 :phase 4.0 :color 1 :fade_color 24}])
|
||||
(pxl8.vfx_raster_bars bars time))
|
||||
|
||||
5 (do
|
||||
|
|
|
|||
BIN
demo/palettes/nes.ase
Normal file
BIN
demo/palettes/nes.ase
Normal file
Binary file not shown.
|
|
@ -69,6 +69,22 @@ function pxl8.load_sprite(filepath)
|
|||
end
|
||||
end
|
||||
|
||||
function pxl8.create_texture(pixels, width, height)
|
||||
local pixel_data = ffi.new("u8[?]", width * height)
|
||||
for i = 0, width * height - 1 do
|
||||
pixel_data[i] = pixels[i + 1] or 0
|
||||
end
|
||||
local result = C.pxl8_gfx_create_texture(gfx, pixel_data, width, height)
|
||||
if result < 0 then
|
||||
return nil
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function pxl8.upload_atlas()
|
||||
C.pxl8_gfx_upload_atlas(gfx)
|
||||
end
|
||||
|
||||
-- log
|
||||
function pxl8.info(msg)
|
||||
C.pxl8_lua_info(msg)
|
||||
|
|
@ -267,6 +283,10 @@ function pxl8.set_wireframe(wireframe)
|
|||
C.pxl8_3d_set_wireframe(gfx, wireframe)
|
||||
end
|
||||
|
||||
function pxl8.set_affine_textures(affine)
|
||||
C.pxl8_3d_set_affine_textures(gfx, affine)
|
||||
end
|
||||
|
||||
function pxl8.set_backface_culling(culling)
|
||||
C.pxl8_3d_set_backface_culling(gfx, culling)
|
||||
end
|
||||
|
|
@ -278,6 +298,14 @@ function pxl8.draw_triangle_3d(v0, v1, v2, color)
|
|||
C.pxl8_3d_draw_triangle_raw(gfx, vec0, vec1, vec2, color)
|
||||
end
|
||||
|
||||
function pxl8.draw_triangle_3d_textured(v0, v1, v2, uv0, uv1, uv2, texture_id)
|
||||
local vec0 = ffi.new("pxl8_vec3", {x = v0[1], y = v0[2], z = v0[3]})
|
||||
local vec1 = ffi.new("pxl8_vec3", {x = v1[1], y = v1[2], z = v1[3]})
|
||||
local vec2 = ffi.new("pxl8_vec3", {x = v2[1], y = v2[2], z = v2[3]})
|
||||
C.pxl8_3d_draw_triangle_textured(gfx, vec0, vec1, vec2,
|
||||
uv0[1], uv0[2], uv1[1], uv1[2], uv2[1], uv2[2], texture_id)
|
||||
end
|
||||
|
||||
function pxl8.draw_line_3d(p0, p1, color)
|
||||
local vec0 = ffi.new("pxl8_vec3", {x = p0[1], y = p0[2], z = p0[3]})
|
||||
local vec1 = ffi.new("pxl8_vec3", {x = p1[1], y = p1[2], z = p1[3]})
|
||||
|
|
|
|||
|
|
@ -245,11 +245,6 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
|
|||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
if (pxl8_gfx_init_atlas(app.gfx, 1024, 1024) != PXL8_OK) {
|
||||
pxl8_error("Failed to initialize sprite atlas");
|
||||
return SDL_APP_FAILURE;
|
||||
}
|
||||
|
||||
app.ui = pxl8_ui_create(app.gfx);
|
||||
if (!app.ui) {
|
||||
pxl8_error("Failed to create UI");
|
||||
|
|
|
|||
|
|
@ -260,16 +260,11 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
|||
chunk_header.chunk_type = read_u16_le(chunk_data + 4);
|
||||
|
||||
const u8* chunk_payload = chunk_data + 6;
|
||||
|
||||
pxl8_debug("Found chunk: type=0x%04X, size=%d", chunk_header.chunk_type, chunk_header.chunk_size);
|
||||
|
||||
switch (chunk_header.chunk_type) {
|
||||
case PXL8_ASE_CHUNK_OLD_PALETTE: // 0x0004
|
||||
if (!ase_file->palette.colors) {
|
||||
result = parse_old_palette_chunk(chunk_payload, &ase_file->palette);
|
||||
pxl8_debug("Parsed old palette: %d colors, indices %d-%d",
|
||||
ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
|
||||
} else {
|
||||
pxl8_debug("Ignoring old palette (0x0004) - new palette (0x2019) already loaded");
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -284,11 +279,6 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
|||
|
||||
result = parse_layer_chunk(chunk_payload, &ase_file->layers[ase_file->layer_count]);
|
||||
if (result == PXL8_OK) {
|
||||
pxl8_debug("Parsed layer %d: '%s', blend_mode=%d, opacity=%d",
|
||||
ase_file->layer_count,
|
||||
ase_file->layers[ase_file->layer_count].name ? ase_file->layers[ase_file->layer_count].name : "(unnamed)",
|
||||
ase_file->layers[ase_file->layer_count].blend_mode,
|
||||
ase_file->layers[ase_file->layer_count].opacity);
|
||||
ase_file->layer_count++;
|
||||
}
|
||||
break;
|
||||
|
|
@ -296,14 +286,11 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
|||
|
||||
case PXL8_ASE_CHUNK_CEL: { // 0x2005
|
||||
pxl8_ase_cel cel = {0};
|
||||
pxl8_debug("Found CEL chunk: size=%d", chunk_header.chunk_size - 6);
|
||||
result = parse_cel_chunk(chunk_payload, chunk_header.chunk_size - 6, &cel);
|
||||
if (result == PXL8_OK && cel.pixel_data) {
|
||||
pxl8_debug("CEL data loaded: %dx%d, type=%d, first pixel = %d", cel.width, cel.height, cel.cel_type, cel.pixel_data[0]);
|
||||
u32 copy_width = (cel.width < frame->width) ? cel.width : frame->width;
|
||||
u32 copy_height = (cel.height < frame->height) ? cel.height : frame->height;
|
||||
|
||||
pxl8_debug("Copying cel to frame: cel_pos=(%d,%d), copy_size=%dx%d", cel.x, cel.y, copy_width, copy_height);
|
||||
|
||||
for (u32 y = 0; y < copy_height; y++) {
|
||||
u32 src_offset = y * cel.width;
|
||||
u32 dst_offset = (y + cel.y) * frame->width + cel.x;
|
||||
|
|
@ -311,20 +298,16 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
|||
for (u32 x = 0; x < copy_width; x++) {
|
||||
u8 src_pixel = cel.pixel_data[src_offset + x];
|
||||
bool is_transparent = false;
|
||||
|
||||
|
||||
if (src_pixel < ase_file->palette.entry_count && ase_file->palette.colors) {
|
||||
u32 color = ase_file->palette.colors[src_pixel];
|
||||
is_transparent = ((color >> 24) & 0xFF) == 0;
|
||||
}
|
||||
|
||||
|
||||
if (!is_transparent) {
|
||||
frame->pixels[dst_offset + x] = src_pixel;
|
||||
}
|
||||
}
|
||||
if (y < 3) {
|
||||
pxl8_debug("Row %d: cel[%d]=%d, frame[%d]=%d",
|
||||
y, src_offset, cel.pixel_data[src_offset], dst_offset, frame->pixels[dst_offset]);
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_free(cel.pixel_data);
|
||||
|
|
@ -337,8 +320,6 @@ pxl8_result pxl8_ase_load(const char* filepath, pxl8_ase_file* ase_file) {
|
|||
SDL_free(ase_file->palette.colors);
|
||||
}
|
||||
result = parse_palette_chunk(chunk_payload, &ase_file->palette);
|
||||
pxl8_debug("Parsed new palette: %d colors, indices %d-%d",
|
||||
ase_file->palette.entry_count, ase_file->palette.first_color, ase_file->palette.last_color);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
868
src/pxl8_gfx.c
868
src/pxl8_gfx.c
File diff suppressed because it is too large
Load diff
|
|
@ -3,6 +3,7 @@
|
|||
#include "pxl8_math.h"
|
||||
#include "pxl8_types.h"
|
||||
|
||||
typedef struct pxl8_atlas pxl8_atlas;
|
||||
typedef struct pxl8_gfx pxl8_gfx;
|
||||
|
||||
typedef enum pxl8_blend_mode {
|
||||
|
|
@ -48,6 +49,7 @@ typedef struct pxl8_effects {
|
|||
|
||||
typedef struct pxl8_triangle {
|
||||
pxl8_vertex v[3];
|
||||
u32 texture_id;
|
||||
} pxl8_triangle;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -61,12 +63,13 @@ pxl8_bounds pxl8_gfx_get_bounds(pxl8_gfx* gfx);
|
|||
pxl8_color_mode pxl8_gfx_get_color_mode(pxl8_gfx* gfx);
|
||||
u8* pxl8_gfx_get_framebuffer(pxl8_gfx* gfx);
|
||||
i32 pxl8_gfx_get_height(const pxl8_gfx* gfx);
|
||||
u32 pxl8_gfx_get_palette_size(const pxl8_gfx* gfx);
|
||||
void pxl8_gfx_get_resolution_dimensions(pxl8_resolution resolution, i32* width, i32* height);
|
||||
i32 pxl8_gfx_get_width(const pxl8_gfx* gfx);
|
||||
pxl8_result pxl8_gfx_init_atlas(pxl8_gfx* gfx, u32 width, u32 height);
|
||||
pxl8_result pxl8_gfx_load_font_atlas(pxl8_gfx* gfx);
|
||||
pxl8_result pxl8_gfx_load_palette(pxl8_gfx* gfx, const char* path);
|
||||
pxl8_result pxl8_gfx_load_sprite(pxl8_gfx* gfx, const char* path);
|
||||
pxl8_result pxl8_gfx_create_texture(pxl8_gfx* gfx, const u8* pixels, u32 width, u32 height);
|
||||
void pxl8_gfx_present(pxl8_gfx* gfx);
|
||||
void pxl8_gfx_project(pxl8_gfx* gfx, f32 left, f32 right, f32 top, f32 bottom);
|
||||
void pxl8_gfx_upload_atlas(pxl8_gfx* gfx);
|
||||
|
|
@ -96,6 +99,8 @@ void pxl8_3d_clear_zbuffer(pxl8_gfx* gfx);
|
|||
void pxl8_3d_draw_line_3d(pxl8_gfx* gfx, pxl8_vec3 p0, pxl8_vec3 p1, u32 color);
|
||||
void pxl8_3d_draw_triangle(pxl8_gfx* gfx, pxl8_triangle tri);
|
||||
void pxl8_3d_draw_triangle_raw(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, u32 color);
|
||||
void pxl8_3d_draw_triangle_textured(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, f32 u0, f32 v0f, f32 u1, f32 v1f, f32 u2, f32 v2f, u32 texture_id);
|
||||
void pxl8_3d_set_affine_textures(pxl8_gfx* gfx, bool affine);
|
||||
void pxl8_3d_set_backface_culling(pxl8_gfx* gfx, bool culling);
|
||||
void pxl8_3d_set_model(pxl8_gfx* gfx, pxl8_mat4 mat);
|
||||
void pxl8_3d_set_projection(pxl8_gfx* gfx, pxl8_mat4 mat);
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@
|
|||
#include "pxl8_simd.h"
|
||||
|
||||
pxl8_vec2 pxl8_vec2_add(pxl8_vec2 a, pxl8_vec2 b) {
|
||||
return (pxl8_vec2) {
|
||||
return (pxl8_vec2){
|
||||
.x = a.x + b.x,
|
||||
.y = a.y + b.y,
|
||||
};
|
||||
}
|
||||
|
||||
pxl8_vec2 pxl8_vec2_sub(pxl8_vec2 a, pxl8_vec2 b) {
|
||||
return (pxl8_vec2) {
|
||||
return (pxl8_vec2){
|
||||
.x = a.x - b.x,
|
||||
.y = a.y - b.y,
|
||||
};
|
||||
}
|
||||
|
||||
pxl8_vec2 pxl8_vec2_scale(pxl8_vec2 v, f32 s) {
|
||||
return (pxl8_vec2) {
|
||||
return (pxl8_vec2){
|
||||
.x = v.x * s,
|
||||
.y = v.y * s,
|
||||
};
|
||||
|
|
@ -34,7 +34,9 @@ f32 pxl8_vec2_length(pxl8_vec2 v) {
|
|||
|
||||
pxl8_vec2 pxl8_vec2_normalize(pxl8_vec2 v) {
|
||||
f32 len = pxl8_vec2_length(v);
|
||||
|
||||
if (len < 1e-6f) return (pxl8_vec2){0};
|
||||
|
||||
return pxl8_vec2_scale(v, 1.0f / len);
|
||||
}
|
||||
|
||||
|
|
@ -43,7 +45,7 @@ pxl8_vec3 pxl8_vec3_add(pxl8_vec3 a, pxl8_vec3 b) {
|
|||
pxl8_simd_vec_f32 vb = pxl8_simd_set_f32(b.x, b.y, b.z, 0);
|
||||
pxl8_simd_vec_f32 result = pxl8_simd_add_f32(va, vb);
|
||||
|
||||
return (pxl8_vec3) {
|
||||
return (pxl8_vec3){
|
||||
.x = result.f32_array[0],
|
||||
.y = result.f32_array[1],
|
||||
.z = result.f32_array[2],
|
||||
|
|
@ -55,7 +57,7 @@ pxl8_vec3 pxl8_vec3_sub(pxl8_vec3 a, pxl8_vec3 b) {
|
|||
pxl8_simd_vec_f32 vb = pxl8_simd_set_f32(b.x, b.y, b.z, 0);
|
||||
pxl8_simd_vec_f32 result = pxl8_simd_sub_f32(va, vb);
|
||||
|
||||
return (pxl8_vec3) {
|
||||
return (pxl8_vec3){
|
||||
.x = result.f32_array[0],
|
||||
.y = result.f32_array[1],
|
||||
.z = result.f32_array[2],
|
||||
|
|
@ -66,7 +68,7 @@ pxl8_vec3 pxl8_vec3_scale(pxl8_vec3 v, f32 s) {
|
|||
pxl8_simd_vec_f32 vv = pxl8_simd_set_f32(v.x, v.y, v.z, 0);
|
||||
pxl8_simd_vec_f32 result = pxl8_simd_scale_f32(vv, s);
|
||||
|
||||
return (pxl8_vec3) {
|
||||
return (pxl8_vec3){
|
||||
.x = result.f32_array[0],
|
||||
.y = result.f32_array[1],
|
||||
.z = result.f32_array[2],
|
||||
|
|
@ -76,11 +78,12 @@ pxl8_vec3 pxl8_vec3_scale(pxl8_vec3 v, f32 s) {
|
|||
f32 pxl8_vec3_dot(pxl8_vec3 a, pxl8_vec3 b) {
|
||||
pxl8_simd_vec_f32 va = pxl8_simd_set_f32(a.x, a.y, a.z, 0);
|
||||
pxl8_simd_vec_f32 vb = pxl8_simd_set_f32(b.x, b.y, b.z, 0);
|
||||
|
||||
return pxl8_simd_dot3_f32(va, vb);
|
||||
}
|
||||
|
||||
pxl8_vec3 pxl8_vec3_cross(pxl8_vec3 a, pxl8_vec3 b) {
|
||||
return (pxl8_vec3) {
|
||||
return (pxl8_vec3){
|
||||
.x = a.y * b.z - a.z * b.y,
|
||||
.y = a.z * b.x - a.x * b.z,
|
||||
.z = a.x * b.y - a.y * b.x,
|
||||
|
|
@ -93,18 +96,23 @@ f32 pxl8_vec3_length(pxl8_vec3 v) {
|
|||
|
||||
pxl8_vec3 pxl8_vec3_normalize(pxl8_vec3 v) {
|
||||
f32 len = pxl8_vec3_length(v);
|
||||
|
||||
if (len < 1e-6f) return (pxl8_vec3){0};
|
||||
|
||||
return pxl8_vec3_scale(v, 1.0f / len);
|
||||
}
|
||||
|
||||
pxl8_mat4 pxl8_mat4_identity(void) {
|
||||
pxl8_mat4 mat = {0};
|
||||
|
||||
mat.m[0] = mat.m[5] = mat.m[10] = mat.m[15] = 1.0f;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
|
||||
pxl8_mat4 result = {0};
|
||||
pxl8_mat4 mat = {0};
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
for (i32 j = 0; j < 4; j++) {
|
||||
pxl8_simd_vec_f32 row = pxl8_simd_set_f32(
|
||||
|
|
@ -113,34 +121,35 @@ pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
|
|||
pxl8_simd_vec_f32 col = pxl8_simd_set_f32(
|
||||
b.m[0 * 4 + j], b.m[1 * 4 + j], b.m[2 * 4 + j], b.m[3 * 4 + j]
|
||||
);
|
||||
result.m[i * 4 + j] = pxl8_simd_dot4_f32(row, col);
|
||||
mat.m[i * 4 + j] = pxl8_simd_dot4_f32(row, col);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v) {
|
||||
pxl8_simd_vec_f32 vec = pxl8_simd_set_f32(v.x, v.y, v.z, v.w);
|
||||
pxl8_vec4 result;
|
||||
|
||||
pxl8_simd_vec_f32 row0 = pxl8_simd_set_f32(m.m[0], m.m[1], m.m[2], m.m[3]);
|
||||
pxl8_simd_vec_f32 row1 = pxl8_simd_set_f32(m.m[4], m.m[5], m.m[6], m.m[7]);
|
||||
pxl8_simd_vec_f32 row2 = pxl8_simd_set_f32(m.m[8], m.m[9], m.m[10], m.m[11]);
|
||||
pxl8_simd_vec_f32 row3 = pxl8_simd_set_f32(m.m[12], m.m[13], m.m[14], m.m[15]);
|
||||
pxl8_simd_vec_f32 vec = pxl8_simd_set_f32(v.x, v.y, v.z, v.w);
|
||||
|
||||
result.x = pxl8_simd_dot4_f32(row0, vec);
|
||||
result.y = pxl8_simd_dot4_f32(row1, vec);
|
||||
result.z = pxl8_simd_dot4_f32(row2, vec);
|
||||
result.w = pxl8_simd_dot4_f32(row3, vec);
|
||||
|
||||
return result;
|
||||
return (pxl8_vec4){
|
||||
.x = pxl8_simd_dot4_f32(row0, vec),
|
||||
.y = pxl8_simd_dot4_f32(row1, vec),
|
||||
.z = pxl8_simd_dot4_f32(row2, vec),
|
||||
.w = pxl8_simd_dot4_f32(row3, vec),
|
||||
};
|
||||
}
|
||||
|
||||
pxl8_mat4 pxl8_mat4_translate(f32 x, f32 y, f32 z) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
|
||||
mat.m[3] = x;
|
||||
mat.m[7] = y;
|
||||
mat.m[11] = z;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
|
@ -148,10 +157,12 @@ pxl8_mat4 pxl8_mat4_rotate_x(f32 angle) {
|
|||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
f32 c = cosf(angle);
|
||||
f32 s = sinf(angle);
|
||||
|
||||
mat.m[5] = c;
|
||||
mat.m[6] = -s;
|
||||
mat.m[9] = s;
|
||||
mat.m[10] = c;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
|
@ -159,10 +170,12 @@ pxl8_mat4 pxl8_mat4_rotate_y(f32 angle) {
|
|||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
f32 c = cosf(angle);
|
||||
f32 s = sinf(angle);
|
||||
|
||||
mat.m[0] = c;
|
||||
mat.m[2] = s;
|
||||
mat.m[8] = -s;
|
||||
mat.m[10] = c;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
|
@ -170,18 +183,22 @@ pxl8_mat4 pxl8_mat4_rotate_z(f32 angle) {
|
|||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
f32 c = cosf(angle);
|
||||
f32 s = sinf(angle);
|
||||
|
||||
mat.m[0] = c;
|
||||
mat.m[1] = -s;
|
||||
mat.m[4] = s;
|
||||
mat.m[5] = c;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
pxl8_mat4 pxl8_mat4_scale(f32 x, f32 y, f32 z) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
|
||||
mat.m[0] = x;
|
||||
mat.m[5] = y;
|
||||
mat.m[10] = z;
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
|
|
@ -213,11 +230,11 @@ pxl8_mat4 pxl8_mat4_perspective(f32 fov, f32 aspect, f32 near, f32 far) {
|
|||
}
|
||||
|
||||
pxl8_mat4 pxl8_mat4_lookat(pxl8_vec3 eye, pxl8_vec3 center, pxl8_vec3 up) {
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
pxl8_vec3 f = pxl8_vec3_normalize(pxl8_vec3_sub(center, eye));
|
||||
pxl8_vec3 s = pxl8_vec3_normalize(pxl8_vec3_cross(f, up));
|
||||
pxl8_vec3 u = pxl8_vec3_cross(s, f);
|
||||
|
||||
pxl8_mat4 mat = pxl8_mat4_identity();
|
||||
mat.m[0] = s.x;
|
||||
mat.m[1] = s.y;
|
||||
mat.m[2] = s.z;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ static const char* pxl8_ffi_cdefs =
|
|||
"void pxl8_gfx_fade_palette(pxl8_gfx* ctx, u8 start, u8 count, f32 amount, u32 target_color);\n"
|
||||
"i32 pxl8_gfx_load_palette(pxl8_gfx* ctx, const char* filepath);\n"
|
||||
"i32 pxl8_gfx_load_sprite(pxl8_gfx* ctx, const char* filepath, u32* sprite_id);\n"
|
||||
"i32 pxl8_gfx_create_texture(pxl8_gfx* ctx, const u8* pixels, u32 width, u32 height);\n"
|
||||
"void pxl8_gfx_upload_atlas(pxl8_gfx* ctx);\n"
|
||||
"typedef struct pxl8_input_state pxl8_input_state;\n"
|
||||
"bool pxl8_key_down(const pxl8_input_state* input, i32 key);\n"
|
||||
"bool pxl8_key_pressed(const pxl8_input_state* input, i32 key);\n"
|
||||
|
|
@ -133,6 +135,8 @@ static const char* pxl8_ffi_cdefs =
|
|||
"void pxl8_3d_clear_zbuffer(pxl8_gfx* gfx);\n"
|
||||
"void pxl8_3d_draw_line_3d(pxl8_gfx* gfx, pxl8_vec3 p0, pxl8_vec3 p1, u32 color);\n"
|
||||
"void pxl8_3d_draw_triangle_raw(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, u32 color);\n"
|
||||
"void pxl8_3d_draw_triangle_textured(pxl8_gfx* gfx, pxl8_vec3 v0, pxl8_vec3 v1, pxl8_vec3 v2, f32 u0, f32 v0, f32 u1, f32 v1, f32 u2, f32 v2, u32 texture_id);\n"
|
||||
"void pxl8_3d_set_affine_textures(pxl8_gfx* gfx, bool affine);\n"
|
||||
"void pxl8_3d_set_backface_culling(pxl8_gfx* gfx, bool culling);\n"
|
||||
"void pxl8_3d_set_model(pxl8_gfx* gfx, pxl8_mat4 mat);\n"
|
||||
"void pxl8_3d_set_projection(pxl8_gfx* gfx, pxl8_mat4 mat);\n"
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ struct pxl8_particles {
|
|||
void* userdata;
|
||||
};
|
||||
|
||||
void pxl8_vfx_plasma(pxl8_gfx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset) {
|
||||
if (!ctx || !pxl8_gfx_get_framebuffer(ctx)) return;
|
||||
|
||||
for (i32 y = 0; y < pxl8_gfx_get_height(ctx); y++) {
|
||||
for (i32 x = 0; x < pxl8_gfx_get_width(ctx); x++) {
|
||||
void pxl8_vfx_plasma(pxl8_gfx* gfx, f32 time, f32 scale1, f32 scale2, u8 palette_offset) {
|
||||
if (!gfx || !pxl8_gfx_get_framebuffer(gfx)) return;
|
||||
|
||||
for (i32 y = 0; y < pxl8_gfx_get_height(gfx); y++) {
|
||||
for (i32 x = 0; x < pxl8_gfx_get_width(gfx); x++) {
|
||||
f32 v1 = sinf(x * scale1 + time);
|
||||
f32 v2 = sinf(y * scale1 + time * 0.7f);
|
||||
f32 v3 = sinf((x + y) * scale2 + time * 1.3f);
|
||||
|
|
@ -44,13 +44,13 @@ void pxl8_vfx_plasma(pxl8_gfx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette
|
|||
if (normalized > 1.0f) normalized = 1.0f;
|
||||
u8 color = palette_offset + (u8)(15.0f * normalized);
|
||||
|
||||
pxl8_pixel(ctx, x, y, color);
|
||||
pxl8_pixel(gfx, x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_vfx_raster_bars(pxl8_gfx* ctx, pxl8_raster_bar* bars, u32 bar_count, f32 time) {
|
||||
if (!ctx || !bars) return;
|
||||
void pxl8_vfx_raster_bars(pxl8_gfx* gfx, pxl8_raster_bar* bars, u32 bar_count, f32 time) {
|
||||
if (!gfx || !bars) return;
|
||||
|
||||
for (u32 i = 0; i < bar_count; i++) {
|
||||
pxl8_raster_bar* bar = &bars[i];
|
||||
|
|
@ -72,24 +72,24 @@ void pxl8_vfx_raster_bars(pxl8_gfx* ctx, pxl8_raster_bar* bars, u32 bar_count, f
|
|||
color_idx = bar->color - 1;
|
||||
}
|
||||
|
||||
pxl8_rect_fill(ctx, 0, y_int + dy, pxl8_gfx_get_width(ctx), 1, color_idx);
|
||||
pxl8_rect_fill(gfx, 0, y_int + dy, pxl8_gfx_get_width(gfx), 1, color_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
|
||||
if (!ctx || !pxl8_gfx_get_framebuffer(ctx)) return;
|
||||
void pxl8_vfx_rotozoom(pxl8_gfx* gfx, f32 angle, f32 zoom, i32 cx, i32 cy) {
|
||||
if (!gfx || !pxl8_gfx_get_framebuffer(gfx)) return;
|
||||
|
||||
f32 cos_a = cosf(angle);
|
||||
f32 sin_a = sinf(angle);
|
||||
|
||||
u8* temp_buffer = (u8*)SDL_malloc(pxl8_gfx_get_width(ctx) * pxl8_gfx_get_height(ctx));
|
||||
u8* temp_buffer = (u8*)SDL_malloc(pxl8_gfx_get_width(gfx) * pxl8_gfx_get_height(gfx));
|
||||
if (!temp_buffer) return;
|
||||
|
||||
SDL_memcpy(temp_buffer, pxl8_gfx_get_framebuffer(ctx), pxl8_gfx_get_width(ctx) * pxl8_gfx_get_height(ctx));
|
||||
SDL_memcpy(temp_buffer, pxl8_gfx_get_framebuffer(gfx), pxl8_gfx_get_width(gfx) * pxl8_gfx_get_height(gfx));
|
||||
|
||||
for (i32 y = 0; y < pxl8_gfx_get_height(ctx); y++) {
|
||||
for (i32 x = 0; x < pxl8_gfx_get_width(ctx); x++) {
|
||||
for (i32 y = 0; y < pxl8_gfx_get_height(gfx); y++) {
|
||||
for (i32 x = 0; x < pxl8_gfx_get_width(gfx); x++) {
|
||||
f32 dx = x - cx;
|
||||
f32 dy = y - cy;
|
||||
|
||||
|
|
@ -99,8 +99,8 @@ void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
|
|||
i32 sx = (i32)src_x;
|
||||
i32 sy = (i32)src_y;
|
||||
|
||||
if (sx >= 0 && sx < pxl8_gfx_get_width(ctx) && sy >= 0 && sy < pxl8_gfx_get_height(ctx)) {
|
||||
pxl8_gfx_get_framebuffer(ctx)[y * pxl8_gfx_get_width(ctx) + x] = temp_buffer[sy * pxl8_gfx_get_width(ctx) + sx];
|
||||
if (sx >= 0 && sx < pxl8_gfx_get_width(gfx) && sy >= 0 && sy < pxl8_gfx_get_height(gfx)) {
|
||||
pxl8_gfx_get_framebuffer(gfx)[y * pxl8_gfx_get_width(gfx) + x] = temp_buffer[sy * pxl8_gfx_get_width(gfx) + sx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,38 +108,41 @@ void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy) {
|
|||
SDL_free(temp_buffer);
|
||||
}
|
||||
|
||||
void pxl8_vfx_tunnel(pxl8_gfx* ctx, f32 time, f32 speed, f32 twist) {
|
||||
if (!ctx || !pxl8_gfx_get_framebuffer(ctx)) return;
|
||||
|
||||
f32 cx = pxl8_gfx_get_width(ctx) / 2.0f;
|
||||
f32 cy = pxl8_gfx_get_height(ctx) / 2.0f;
|
||||
|
||||
for (i32 y = 0; y < pxl8_gfx_get_height(ctx); y++) {
|
||||
for (i32 x = 0; x < pxl8_gfx_get_width(ctx); x++) {
|
||||
void pxl8_vfx_tunnel(pxl8_gfx* gfx, f32 time, f32 speed, f32 twist) {
|
||||
if (!gfx || !pxl8_gfx_get_framebuffer(gfx)) return;
|
||||
|
||||
f32 cx = pxl8_gfx_get_width(gfx) / 2.0f;
|
||||
f32 cy = pxl8_gfx_get_height(gfx) / 2.0f;
|
||||
u32 palette_size = pxl8_gfx_get_palette_size(gfx);
|
||||
if (palette_size == 0) palette_size = 256;
|
||||
|
||||
for (i32 y = 0; y < pxl8_gfx_get_height(gfx); y++) {
|
||||
for (i32 x = 0; x < pxl8_gfx_get_width(gfx); x++) {
|
||||
f32 dx = x - cx;
|
||||
f32 dy = y - cy;
|
||||
f32 dist = sqrtf(dx * dx + dy * dy);
|
||||
|
||||
|
||||
if (dist > 1.0f) {
|
||||
f32 angle = atan2f(dy, dx);
|
||||
f32 u = angle * 0.159f + twist * sinf(time * 0.5f);
|
||||
f32 v = 256.0f / dist + time * speed;
|
||||
|
||||
|
||||
u8 tx = (u8)((i32)(u * 256.0f) & 0xFF);
|
||||
u8 ty = (u8)((i32)(v * 256.0f) & 0xFF);
|
||||
u8 color = tx ^ ty;
|
||||
|
||||
pxl8_pixel(ctx, x, y, color);
|
||||
u8 pattern = tx ^ ty;
|
||||
u8 color = (pattern / 8) % palette_size;
|
||||
|
||||
pxl8_pixel(gfx, x, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_vfx_water_ripple(pxl8_gfx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping) {
|
||||
if (!ctx || !height_map) return;
|
||||
void pxl8_vfx_water_ripple(pxl8_gfx* gfx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping) {
|
||||
if (!gfx || !height_map) return;
|
||||
|
||||
i32 w = pxl8_gfx_get_width(ctx);
|
||||
i32 h = pxl8_gfx_get_height(ctx);
|
||||
i32 w = pxl8_gfx_get_width(gfx);
|
||||
i32 h = pxl8_gfx_get_height(gfx);
|
||||
|
||||
static f32* prev_height = NULL;
|
||||
if (!prev_height) {
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ void pxl8_vfx_snow(pxl8_particles* particles, i32 width, f32 wind);
|
|||
void pxl8_vfx_sparks(pxl8_particles* particles, i32 x, i32 y, u32 color);
|
||||
void pxl8_vfx_starfield(pxl8_particles* particles, f32 speed, f32 spread);
|
||||
|
||||
void pxl8_vfx_plasma(pxl8_gfx* ctx, f32 time, f32 scale1, f32 scale2, u8 palette_offset);
|
||||
void pxl8_vfx_raster_bars(pxl8_gfx* ctx, pxl8_raster_bar* bars, u32 bar_count, f32 time);
|
||||
void pxl8_vfx_rotozoom(pxl8_gfx* ctx, f32 angle, f32 zoom, i32 cx, i32 cy);
|
||||
void pxl8_vfx_tunnel(pxl8_gfx* ctx, f32 time, f32 speed, f32 twist);
|
||||
void pxl8_vfx_water_ripple(pxl8_gfx* ctx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);
|
||||
void pxl8_vfx_plasma(pxl8_gfx* gfx, f32 time, f32 scale1, f32 scale2, u8 palette_offset);
|
||||
void pxl8_vfx_raster_bars(pxl8_gfx* gfx, pxl8_raster_bar* bars, u32 bar_count, f32 time);
|
||||
void pxl8_vfx_rotozoom(pxl8_gfx* gfx, f32 angle, f32 zoom, i32 cx, i32 cy);
|
||||
void pxl8_vfx_tunnel(pxl8_gfx* gfx, f32 time, f32 speed, f32 twist);
|
||||
void pxl8_vfx_water_ripple(pxl8_gfx* gfx, f32* height_map, i32 drop_x, i32 drop_y, f32 damping);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue