clean up worldgen and remove verbose logging
This commit is contained in:
parent
4d84122ef3
commit
34e534b6f2
11 changed files with 359 additions and 174 deletions
|
|
@ -18,6 +18,9 @@
|
|||
(local turn-speed 2.0)
|
||||
(local bob-speed 8.0)
|
||||
(local bob-amount 4.0)
|
||||
(local max-pitch 1.5)
|
||||
(local cell-size 64)
|
||||
(local grid-size 32)
|
||||
|
||||
(fn init []
|
||||
(set world (pxl8.world_new))
|
||||
|
|
@ -30,7 +33,37 @@
|
|||
:iterations 4})]
|
||||
(if (< result 0)
|
||||
(pxl8.error (.. "Failed to generate cave - result: " result))
|
||||
(pxl8.info "Generated procedural cave"))))
|
||||
(do
|
||||
(let [floor-tex (pxl8.procgen_tex {:name "floor"
|
||||
:seed 11111
|
||||
:width 64
|
||||
:height 64
|
||||
:base_color 20})
|
||||
ceiling-tex (pxl8.procgen_tex {:name "ceiling"
|
||||
:seed 22222
|
||||
:width 64
|
||||
:height 64
|
||||
:base_color 0})
|
||||
wall-tex (pxl8.procgen_tex {:name "wall"
|
||||
:seed 12345
|
||||
:width 64
|
||||
:height 64
|
||||
:base_color 4})]
|
||||
|
||||
(pxl8.upload_atlas)
|
||||
|
||||
(let [result (pxl8.world_apply_textures world [
|
||||
{:name "floor"
|
||||
:texture_id floor-tex
|
||||
:rule (fn [normal] (> normal.y 0.7))}
|
||||
{:name "ceiling"
|
||||
:texture_id ceiling-tex
|
||||
:rule (fn [normal] (< normal.y -0.7))}
|
||||
{:name "wall"
|
||||
:texture_id wall-tex
|
||||
:rule (fn [normal] (and (<= normal.y 0.7) (>= normal.y -0.7)))}])]
|
||||
(when (< result 0)
|
||||
(pxl8.error (.. "Failed to apply textures - result: " result)))))))))
|
||||
|
||||
(fn update [dt]
|
||||
(set fps-accumulator (+ fps-accumulator dt))
|
||||
|
|
@ -50,36 +83,35 @@
|
|||
forward-z (- (math.cos cam-yaw))
|
||||
right-x (math.cos cam-yaw)
|
||||
right-z (- (math.sin cam-yaw))
|
||||
cell-size 64
|
||||
grid-min 0
|
||||
grid-max (* 32 cell-size)]
|
||||
grid-max (* grid-size cell-size)
|
||||
move-delta (* move-speed dt)]
|
||||
|
||||
(var moving false)
|
||||
(var new-x cam-x)
|
||||
(var new-z cam-z)
|
||||
|
||||
(when (pxl8.key_down "w")
|
||||
(set new-x (+ new-x (* forward-x move-speed dt)))
|
||||
(set new-z (+ new-z (* forward-z move-speed dt)))
|
||||
(set new-x (+ new-x (* forward-x move-delta)))
|
||||
(set new-z (+ new-z (* forward-z move-delta)))
|
||||
(set moving true))
|
||||
|
||||
(when (pxl8.key_down "s")
|
||||
(set new-x (- new-x (* forward-x move-speed dt)))
|
||||
(set new-z (- new-z (* forward-z move-speed dt)))
|
||||
(set new-x (- new-x (* forward-x move-delta)))
|
||||
(set new-z (- new-z (* forward-z move-delta)))
|
||||
(set moving true))
|
||||
|
||||
(when (pxl8.key_down "q")
|
||||
(set new-x (- new-x (* right-x move-speed dt)))
|
||||
(set new-z (- new-z (* right-z move-speed dt)))
|
||||
(set new-x (- new-x (* right-x move-delta)))
|
||||
(set new-z (- new-z (* right-z move-delta)))
|
||||
(set moving true))
|
||||
|
||||
(when (pxl8.key_down "e")
|
||||
(set new-x (+ new-x (* right-x move-speed dt)))
|
||||
(set new-z (+ new-z (* right-z move-speed dt)))
|
||||
(set new-x (+ new-x (* right-x move-delta)))
|
||||
(set new-z (+ new-z (* right-z move-delta)))
|
||||
(set moving true))
|
||||
|
||||
(when (and (>= new-x grid-min) (<= new-x grid-max)
|
||||
(>= new-z grid-min) (<= new-z grid-max))
|
||||
(when (and (>= new-x 0) (<= new-x grid-max)
|
||||
(>= new-z 0) (<= new-z grid-max))
|
||||
(set cam-x new-x)
|
||||
(set cam-z new-z))
|
||||
|
||||
|
|
@ -90,12 +122,10 @@
|
|||
(set cam-yaw (- cam-yaw (* turn-speed dt))))
|
||||
|
||||
(when (pxl8.key_down "up")
|
||||
(set cam-pitch (+ cam-pitch (* turn-speed dt)))
|
||||
(when (> cam-pitch 1.5) (set cam-pitch 1.5)))
|
||||
(set cam-pitch (math.min max-pitch (+ cam-pitch (* turn-speed dt)))))
|
||||
|
||||
(when (pxl8.key_down "down")
|
||||
(set cam-pitch (- cam-pitch (* turn-speed dt)))
|
||||
(when (< cam-pitch -1.5) (set cam-pitch -1.5)))
|
||||
(set cam-pitch (math.max (- max-pitch) (- cam-pitch (* turn-speed dt)))))
|
||||
|
||||
(if moving
|
||||
(set bob-time (+ bob-time (* dt bob-speed)))
|
||||
|
|
@ -134,7 +164,7 @@
|
|||
|
||||
(pxl8.text (.. "Pos: " (string.format "%.0f" cam-x) ","
|
||||
(string.format "%.0f" cam-y) ","
|
||||
(string.format "%.0f" cam-z)) 10 25 12))
|
||||
(string.format "%.0f" cam-z)) 10 25 12)
|
||||
|
||||
(let [new-state (debug-ui.render {:show-debug-ui show-debug-ui
|
||||
:fps fps
|
||||
|
|
@ -144,7 +174,7 @@
|
|||
:use-texture true
|
||||
:affine affine})]
|
||||
(when (not= new-state.show-debug-ui nil) (set show-debug-ui new-state.show-debug-ui))
|
||||
(when (not= new-state.affine nil) (set affine new-state.affine)))))
|
||||
(when (not= new-state.affine nil) (set affine new-state.affine))))))
|
||||
|
||||
{:init init
|
||||
:update update
|
||||
|
|
|
|||
|
|
@ -469,11 +469,64 @@ function pxl8.world_generate(world, params)
|
|||
c_params.density = params.density or 0.45
|
||||
c_params.iterations = params.iterations or 4
|
||||
c_params.type_params = nil
|
||||
return C.pxl8_world_generate(world, c_params)
|
||||
return C.pxl8_world_generate(world, gfx, c_params)
|
||||
end
|
||||
|
||||
pxl8.PROCGEN_CAVE = C.PXL8_PROCGEN_CAVE
|
||||
pxl8.PROCGEN_DUNGEON = C.PXL8_PROCGEN_DUNGEON
|
||||
pxl8.PROCGEN_TERRAIN = C.PXL8_PROCGEN_TERRAIN
|
||||
|
||||
function pxl8.procgen_tex(params)
|
||||
local width = params.width or 64
|
||||
local height = params.height or 64
|
||||
local buffer = ffi.new("u8[?]", width * height)
|
||||
local tex_params = ffi.new("pxl8_procgen_tex_params")
|
||||
|
||||
local name = params.name or ""
|
||||
ffi.copy(tex_params.name, name, math.min(#name, 15))
|
||||
|
||||
tex_params.seed = params.seed or 0
|
||||
tex_params.width = width
|
||||
tex_params.height = height
|
||||
tex_params.scale = params.scale or 1.0
|
||||
tex_params.roughness = params.roughness or 0.0
|
||||
tex_params.base_color = params.base_color or 0
|
||||
tex_params.variation = params.variation or 0
|
||||
|
||||
C.pxl8_procgen_tex(buffer, tex_params)
|
||||
|
||||
local tex_id = C.pxl8_gfx_create_texture(gfx, buffer, width, height)
|
||||
if tex_id < 0 then
|
||||
return nil
|
||||
end
|
||||
return tex_id
|
||||
end
|
||||
|
||||
function pxl8.world_apply_textures(world, texture_defs)
|
||||
local count = #texture_defs
|
||||
local textures = ffi.new("pxl8_world_texture[?]", count)
|
||||
local callbacks = {}
|
||||
|
||||
for i, def in ipairs(texture_defs) do
|
||||
local idx = i - 1
|
||||
ffi.copy(textures[idx].name, def.name or "", math.min(#(def.name or ""), 15))
|
||||
textures[idx].texture_id = def.texture_id or 0
|
||||
|
||||
if def.rule then
|
||||
local cb = ffi.cast("bool (*)(const pxl8_vec3*, const pxl8_bsp_face*, const pxl8_bsp*)",
|
||||
function(normal, face, bsp)
|
||||
return def.rule(normal[0], face, bsp)
|
||||
end)
|
||||
textures[idx].rule = cb
|
||||
callbacks[idx + 1] = cb
|
||||
else
|
||||
textures[idx].rule = nil
|
||||
end
|
||||
end
|
||||
|
||||
local result = C.pxl8_world_apply_textures(world, textures, count)
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
return pxl8
|
||||
|
|
|
|||
|
|
@ -386,17 +386,8 @@ void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 t
|
|||
pxl8_vec3 verts[64];
|
||||
u32 num_verts = 0;
|
||||
|
||||
const pxl8_bsp_plane* plane = &bsp->planes[face->plane_id];
|
||||
|
||||
u32 color;
|
||||
bool use_texture = false;
|
||||
|
||||
if (fabsf(plane->normal.y) > 0.7f) {
|
||||
color = (plane->normal.y > 0) ? 4 : 3;
|
||||
} else {
|
||||
color = 15;
|
||||
use_texture = (texture_id > 0);
|
||||
}
|
||||
u32 color = 15;
|
||||
bool use_texture = (texture_id > 0);
|
||||
|
||||
|
||||
for (u32 i = 0; i < face->num_edges && num_verts < 64; i++) {
|
||||
|
|
@ -446,11 +437,10 @@ void pxl8_bsp_render_face(pxl8_gfx* gfx, const pxl8_bsp* bsp, u32 face_id, u32 t
|
|||
}
|
||||
}
|
||||
|
||||
void pxl8_bsp_render_solid(
|
||||
void pxl8_bsp_render_textured(
|
||||
pxl8_gfx* gfx,
|
||||
const pxl8_bsp* bsp,
|
||||
pxl8_vec3 camera_pos,
|
||||
u32 texture_id
|
||||
pxl8_vec3 camera_pos
|
||||
) {
|
||||
if (!gfx || !bsp || bsp->num_faces == 0) return;
|
||||
|
||||
|
|
@ -488,10 +478,22 @@ void pxl8_bsp_render_solid(
|
|||
|
||||
if (!face_in_frustum(bsp, face_id, frustum)) continue;
|
||||
|
||||
pxl8_bsp_render_face(gfx, bsp, face_id, texture_id);
|
||||
const pxl8_bsp_face* face = &bsp->faces[face_id];
|
||||
u32 texture_id = 0;
|
||||
if (face->texinfo_id < bsp->num_texinfo) {
|
||||
texture_id = bsp->texinfo[face->texinfo_id].miptex;
|
||||
} else {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
pxl8_warn("Face %u has invalid texinfo_id %u (num_texinfo=%u)",
|
||||
face_id, face->texinfo_id, bsp->num_texinfo);
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_bsp_render_face(gfx, bsp, face_id, texture_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_bsp_render_wireframe(
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ typedef struct pxl8_bsp_plane {
|
|||
|
||||
typedef struct pxl8_bsp_texinfo {
|
||||
u32 miptex;
|
||||
char name[16];
|
||||
|
||||
f32 u_offset;
|
||||
pxl8_vec3 u_axis;
|
||||
|
|
@ -121,11 +122,10 @@ void pxl8_bsp_render_face(
|
|||
u32 texture_id
|
||||
);
|
||||
|
||||
void pxl8_bsp_render_solid(
|
||||
void pxl8_bsp_render_textured(
|
||||
pxl8_gfx* gfx,
|
||||
const pxl8_bsp* bsp,
|
||||
pxl8_vec3 camera_pos,
|
||||
u32 texture_id
|
||||
pxl8_vec3 camera_pos
|
||||
);
|
||||
|
||||
void pxl8_bsp_render_wireframe(
|
||||
|
|
|
|||
|
|
@ -992,7 +992,15 @@ static inline u32 pxl8_sample_texture(pxl8_gfx* gfx, u32 texture_id, f32 u, f32
|
|||
if (!gfx->atlas) return 0;
|
||||
|
||||
const pxl8_atlas_entry* entry = pxl8_atlas_get_entry(gfx->atlas, texture_id);
|
||||
if (!entry || !entry->active) return 0;
|
||||
if (!entry || !entry->active) {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
pxl8_warn("Texture sampling failed: texture_id=%u entry=%p active=%d",
|
||||
texture_id, (void*)entry, entry ? entry->active : 0);
|
||||
warned = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = u - floorf(u);
|
||||
v = v - floorf(v);
|
||||
|
|
|
|||
|
|
@ -14,14 +14,6 @@ typedef enum pxl8_blend_mode {
|
|||
PXL8_BLEND_NONE
|
||||
} pxl8_blend_mode;
|
||||
|
||||
typedef struct pxl8_mode7_params {
|
||||
bool active;
|
||||
f32 horizon;
|
||||
f32 offset_x, offset_y;
|
||||
f32 rotation;
|
||||
f32 scale_x, scale_y;
|
||||
} pxl8_mode7_params;
|
||||
|
||||
typedef struct pxl8_palette_cycle {
|
||||
bool active;
|
||||
u8 end_index;
|
||||
|
|
|
|||
|
|
@ -78,19 +78,6 @@ static i32 cave_grid_count_neighbors(const cave_grid* grid, i32 x, i32 y) {
|
|||
return count;
|
||||
}
|
||||
|
||||
static void calculate_texture_axes(const pxl8_vec3 normal, pxl8_vec3* u_axis, pxl8_vec3* v_axis) {
|
||||
if (fabsf(normal.y) > 0.9f) {
|
||||
*u_axis = (pxl8_vec3){1.0f, 0.0f, 0.0f};
|
||||
*v_axis = (pxl8_vec3){0.0f, 0.0f, 1.0f};
|
||||
} else if (fabsf(normal.x) > 0.7f) {
|
||||
*u_axis = (pxl8_vec3){0.0f, 1.0f, 0.0f};
|
||||
*v_axis = (pxl8_vec3){0.0f, 0.0f, 1.0f};
|
||||
} else {
|
||||
*u_axis = (pxl8_vec3){1.0f, 0.0f, 0.0f};
|
||||
*v_axis = (pxl8_vec3){0.0f, 1.0f, 0.0f};
|
||||
}
|
||||
}
|
||||
|
||||
static inline void compute_face_aabb(pxl8_bsp_face* face, const pxl8_bsp_vertex* verts, u32 vert_idx) {
|
||||
face->aabb_min = (pxl8_vec3){1e30f, 1e30f, 1e30f};
|
||||
face->aabb_max = (pxl8_vec3){-1e30f, -1e30f, -1e30f};
|
||||
|
|
@ -159,12 +146,14 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->planes = calloc(face_count, sizeof(pxl8_bsp_plane));
|
||||
bsp->edges = calloc(vertex_count, sizeof(pxl8_bsp_edge));
|
||||
bsp->surfedges = calloc(vertex_count, sizeof(i32));
|
||||
bsp->texinfo = calloc(face_count, sizeof(pxl8_bsp_texinfo));
|
||||
|
||||
if (!bsp->vertices || !bsp->faces || !bsp->planes || !bsp->edges || !bsp->surfedges || !bsp->texinfo) {
|
||||
if (!bsp->vertices || !bsp->faces || !bsp->planes || !bsp->edges || !bsp->surfedges) {
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
bsp->texinfo = NULL;
|
||||
bsp->num_texinfo = 0;
|
||||
|
||||
i32 vert_idx = 0;
|
||||
i32 face_idx = 0;
|
||||
i32 edge_idx = 0;
|
||||
|
|
@ -190,13 +179,7 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->faces[face_idx].plane_id = face_idx;
|
||||
bsp->faces[face_idx].num_edges = 4;
|
||||
bsp->faces[face_idx].first_edge = edge_idx;
|
||||
bsp->faces[face_idx].texinfo_id = face_idx;
|
||||
|
||||
calculate_texture_axes(bsp->planes[face_idx].normal,
|
||||
&bsp->texinfo[face_idx].u_axis,
|
||||
&bsp->texinfo[face_idx].v_axis);
|
||||
bsp->texinfo[face_idx].u_offset = 0.0f;
|
||||
bsp->texinfo[face_idx].v_offset = 0.0f;
|
||||
bsp->faces[face_idx].texinfo_id = 0;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
bsp->edges[edge_idx + i].vertex[0] = vert_idx + i;
|
||||
|
|
@ -223,13 +206,7 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->faces[face_idx].plane_id = face_idx;
|
||||
bsp->faces[face_idx].num_edges = 4;
|
||||
bsp->faces[face_idx].first_edge = edge_idx;
|
||||
bsp->faces[face_idx].texinfo_id = face_idx;
|
||||
|
||||
calculate_texture_axes(bsp->planes[face_idx].normal,
|
||||
&bsp->texinfo[face_idx].u_axis,
|
||||
&bsp->texinfo[face_idx].v_axis);
|
||||
bsp->texinfo[face_idx].u_offset = 0.0f;
|
||||
bsp->texinfo[face_idx].v_offset = 0.0f;
|
||||
bsp->faces[face_idx].texinfo_id = 0;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
bsp->edges[edge_idx + i].vertex[0] = vert_idx + i;
|
||||
|
|
@ -256,13 +233,7 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->faces[face_idx].plane_id = face_idx;
|
||||
bsp->faces[face_idx].num_edges = 4;
|
||||
bsp->faces[face_idx].first_edge = edge_idx;
|
||||
bsp->faces[face_idx].texinfo_id = face_idx;
|
||||
|
||||
calculate_texture_axes(bsp->planes[face_idx].normal,
|
||||
&bsp->texinfo[face_idx].u_axis,
|
||||
&bsp->texinfo[face_idx].v_axis);
|
||||
bsp->texinfo[face_idx].u_offset = 0.0f;
|
||||
bsp->texinfo[face_idx].v_offset = 0.0f;
|
||||
bsp->faces[face_idx].texinfo_id = 0;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
bsp->edges[edge_idx + i].vertex[0] = vert_idx + i;
|
||||
|
|
@ -289,13 +260,7 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->faces[face_idx].plane_id = face_idx;
|
||||
bsp->faces[face_idx].num_edges = 4;
|
||||
bsp->faces[face_idx].first_edge = edge_idx;
|
||||
bsp->faces[face_idx].texinfo_id = face_idx;
|
||||
|
||||
calculate_texture_axes(bsp->planes[face_idx].normal,
|
||||
&bsp->texinfo[face_idx].u_axis,
|
||||
&bsp->texinfo[face_idx].v_axis);
|
||||
bsp->texinfo[face_idx].u_offset = 0.0f;
|
||||
bsp->texinfo[face_idx].v_offset = 0.0f;
|
||||
bsp->faces[face_idx].texinfo_id = 0;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
bsp->edges[edge_idx + i].vertex[0] = vert_idx + i;
|
||||
|
|
@ -330,13 +295,7 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->faces[face_idx].plane_id = face_idx;
|
||||
bsp->faces[face_idx].num_edges = 4;
|
||||
bsp->faces[face_idx].first_edge = edge_idx;
|
||||
bsp->faces[face_idx].texinfo_id = face_idx;
|
||||
|
||||
calculate_texture_axes(bsp->planes[face_idx].normal,
|
||||
&bsp->texinfo[face_idx].u_axis,
|
||||
&bsp->texinfo[face_idx].v_axis);
|
||||
bsp->texinfo[face_idx].u_offset = 0.0f;
|
||||
bsp->texinfo[face_idx].v_offset = 0.0f;
|
||||
bsp->faces[face_idx].texinfo_id = 0;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
bsp->edges[edge_idx + i].vertex[0] = vert_idx + i;
|
||||
|
|
@ -361,13 +320,7 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->faces[face_idx].plane_id = face_idx;
|
||||
bsp->faces[face_idx].num_edges = 4;
|
||||
bsp->faces[face_idx].first_edge = edge_idx;
|
||||
bsp->faces[face_idx].texinfo_id = face_idx;
|
||||
|
||||
calculate_texture_axes(bsp->planes[face_idx].normal,
|
||||
&bsp->texinfo[face_idx].u_axis,
|
||||
&bsp->texinfo[face_idx].v_axis);
|
||||
bsp->texinfo[face_idx].u_offset = 0.0f;
|
||||
bsp->texinfo[face_idx].v_offset = 0.0f;
|
||||
bsp->faces[face_idx].texinfo_id = 0;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
bsp->edges[edge_idx + i].vertex[0] = vert_idx + i;
|
||||
|
|
@ -389,7 +342,6 @@ static pxl8_result cave_to_bsp(pxl8_bsp* bsp, const cave_grid* grid) {
|
|||
bsp->num_planes = face_count;
|
||||
bsp->num_edges = vertex_count;
|
||||
bsp->num_surfedges = vertex_count;
|
||||
bsp->num_texinfo = face_count;
|
||||
|
||||
bsp->leafs = calloc(1, sizeof(pxl8_bsp_leaf));
|
||||
bsp->marksurfaces = calloc(face_count, sizeof(u16));
|
||||
|
|
@ -455,45 +407,99 @@ pxl8_result pxl8_procgen(pxl8_bsp* bsp, const pxl8_procgen_params* params) {
|
|||
}
|
||||
}
|
||||
|
||||
static u32 hash2d(i32 x, i32 y) {
|
||||
u32 h = ((u32)x * 374761393u) + ((u32)y * 668265263u);
|
||||
h ^= h >> 13;
|
||||
h ^= h << 17;
|
||||
h ^= h >> 5;
|
||||
return h;
|
||||
}
|
||||
|
||||
void pxl8_procgen_tex(u8* buffer, const pxl8_procgen_tex_params* params) {
|
||||
if (!buffer || !params) return;
|
||||
|
||||
prng_seed(params->seed);
|
||||
|
||||
u8 min_val = 255, max_val = 0;
|
||||
|
||||
for (i32 y = 0; y < params->height; y++) {
|
||||
for (i32 x = 0; x < params->width; x++) {
|
||||
i32 ix = (i32)((f32)x * params->scale);
|
||||
i32 iy = (i32)((f32)y * params->scale);
|
||||
f32 u = (f32)x / (f32)params->width;
|
||||
f32 v = (f32)y / (f32)params->height;
|
||||
|
||||
u32 block_hash = ((u32)ix * 374761393u + (u32)iy * 668265263u) ^ params->seed;
|
||||
block_hash ^= block_hash >> 13;
|
||||
block_hash ^= block_hash << 17;
|
||||
block_hash ^= block_hash >> 5;
|
||||
u8 color = params->base_color;
|
||||
|
||||
u32 pixel_hash = ((u32)x * 1597334677u + (u32)y * 3812015801u) ^ params->seed;
|
||||
pixel_hash ^= pixel_hash >> 13;
|
||||
pixel_hash ^= pixel_hash << 17;
|
||||
pixel_hash ^= pixel_hash >> 5;
|
||||
// Tile-based pattern (floor style)
|
||||
if (params->seed == 11111) {
|
||||
i32 tile_x = (i32)floorf(u * 8.0f);
|
||||
i32 tile_y = (i32)floorf(v * 8.0f);
|
||||
u32 h = hash2d(tile_x, tile_y);
|
||||
|
||||
u32 combined = (block_hash * 3 + pixel_hash) / 4;
|
||||
f32 pattern = (f32)(h & 0xFF) / 255.0f;
|
||||
i32 quantized = (pattern < 0.3f) ? 0 : (pattern < 0.7f) ? 1 : 2;
|
||||
|
||||
u32 value_range = params->variation + 1;
|
||||
i32 value = params->base_color + (combined % value_range);
|
||||
color = params->base_color + quantized;
|
||||
|
||||
if (value < 0) value = 0;
|
||||
if (value > 15) value = 15;
|
||||
// Checkerboard dither
|
||||
if (((tile_x + tile_y) & 1) == 0 && (h & 0x100)) {
|
||||
color = (color < 15) ? color + 1 : color;
|
||||
}
|
||||
}
|
||||
// Large tile pattern (ceiling style)
|
||||
else if (params->seed == 22222) {
|
||||
i32 coarse_x = (i32)floorf(u * 2.0f);
|
||||
i32 coarse_y = (i32)floorf(v * 2.0f);
|
||||
u32 coarse_h = hash2d(coarse_x, coarse_y);
|
||||
|
||||
u8 final_value = (u8)value;
|
||||
buffer[y * params->width + x] = final_value;
|
||||
i32 subdivision = (coarse_h >> 8) & 0x3;
|
||||
i32 tile_x, tile_y;
|
||||
|
||||
if (final_value < min_val) min_val = final_value;
|
||||
if (final_value > max_val) max_val = final_value;
|
||||
switch (subdivision) {
|
||||
case 0: tile_x = (i32)floorf(u * 3.0f); tile_y = (i32)floorf(v * 3.0f); break;
|
||||
case 1: tile_x = (i32)floorf(u * 5.0f); tile_y = (i32)floorf(v * 5.0f); break;
|
||||
case 2: tile_x = (i32)floorf(u * 2.0f); tile_y = (i32)floorf(v * 4.0f); break;
|
||||
default: tile_x = (i32)floorf(u * 4.0f); tile_y = (i32)floorf(v * 2.0f); break;
|
||||
}
|
||||
|
||||
u32 h = hash2d(tile_x, tile_y);
|
||||
f32 pattern = (f32)(h & 0xFF) / 255.0f;
|
||||
|
||||
if (pattern < 0.25f) color = params->base_color;
|
||||
else if (pattern < 0.50f) color = params->base_color + 1;
|
||||
else if (pattern < 0.75f) color = params->base_color + 2;
|
||||
else color = params->base_color + 1;
|
||||
}
|
||||
// Brick pattern (wall style)
|
||||
else {
|
||||
f32 brick_y = floorf(v * 4.0f);
|
||||
f32 offset = ((i32)brick_y & 1) ? 0.5f : 0.0f;
|
||||
i32 brick_x = (i32)floorf(u * 4.0f + offset);
|
||||
brick_y = (i32)brick_y;
|
||||
|
||||
f32 brick_u = fabsf((u * 4.0f + offset) - floorf(u * 4.0f + offset) - 0.5f);
|
||||
f32 brick_v = fabsf((v * 4.0f) - floorf(v * 4.0f) - 0.5f);
|
||||
|
||||
u32 h = hash2d(brick_x, (i32)brick_y);
|
||||
f32 noise = (f32)(h & 0xFF) / 255.0f;
|
||||
|
||||
// Mortar lines
|
||||
if (brick_u > 0.47f || brick_v > 0.47f) {
|
||||
color = params->base_color - 2;
|
||||
} else {
|
||||
i32 shade = (i32)(noise * 3.0f);
|
||||
color = params->base_color + shade;
|
||||
}
|
||||
}
|
||||
|
||||
pxl8_debug("Generated texture %dx%d: values range %u-%u (base=%u, variation=%u)",
|
||||
params->width, params->height, min_val, max_val,
|
||||
params->base_color, params->variation);
|
||||
if (color > 31) color = 31;
|
||||
buffer[y * params->width + x] = color;
|
||||
}
|
||||
}
|
||||
|
||||
u8 min_color = 255, max_color = 0;
|
||||
u32 color_counts[256] = {0};
|
||||
for (i32 i = 0; i < params->width * params->height; i++) {
|
||||
if (buffer[i] < min_color) min_color = buffer[i];
|
||||
if (buffer[i] > max_color) max_color = buffer[i];
|
||||
color_counts[buffer[i]]++;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ typedef struct pxl8_procgen_dungeon_params {
|
|||
} pxl8_procgen_dungeon_params;
|
||||
|
||||
typedef struct pxl8_procgen_tex_params {
|
||||
char name[16];
|
||||
u32 seed;
|
||||
i32 width;
|
||||
i32 height;
|
||||
|
|
@ -42,6 +43,7 @@ typedef struct pxl8_procgen_tex_params {
|
|||
f32 roughness;
|
||||
u8 base_color;
|
||||
u8 variation;
|
||||
u8 max_color;
|
||||
} pxl8_procgen_tex_params;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -225,10 +225,34 @@ static const char* pxl8_ffi_cdefs =
|
|||
" void* type_params;\n"
|
||||
"} pxl8_procgen_params;\n"
|
||||
"\n"
|
||||
"typedef struct pxl8_procgen_tex_params {\n"
|
||||
" char name[16];\n"
|
||||
" unsigned int seed;\n"
|
||||
" int width;\n"
|
||||
" int height;\n"
|
||||
" float scale;\n"
|
||||
" float roughness;\n"
|
||||
" unsigned char base_color;\n"
|
||||
" unsigned char variation;\n"
|
||||
"} pxl8_procgen_tex_params;\n"
|
||||
"\n"
|
||||
"void pxl8_procgen_tex(u8* buffer, const pxl8_procgen_tex_params* params);\n"
|
||||
"\n"
|
||||
"typedef struct pxl8_bsp pxl8_bsp;\n"
|
||||
"typedef struct pxl8_bsp_face pxl8_bsp_face;\n"
|
||||
"typedef bool (*pxl8_texture_rule)(const pxl8_vec3* normal, const pxl8_bsp_face* face, const pxl8_bsp* bsp);\n"
|
||||
"\n"
|
||||
"typedef struct pxl8_world_texture {\n"
|
||||
" char name[16];\n"
|
||||
" unsigned int texture_id;\n"
|
||||
" pxl8_texture_rule rule;\n"
|
||||
"} pxl8_world_texture;\n"
|
||||
"\n"
|
||||
"typedef struct pxl8_world pxl8_world;\n"
|
||||
"pxl8_world* pxl8_world_create(void);\n"
|
||||
"void pxl8_world_destroy(pxl8_world* world);\n"
|
||||
"int pxl8_world_generate(pxl8_world* world, const pxl8_procgen_params* params);\n"
|
||||
"int pxl8_world_generate(pxl8_world* world, pxl8_gfx* gfx, const pxl8_procgen_params* params);\n"
|
||||
"int pxl8_world_apply_textures(pxl8_world* world, const pxl8_world_texture* textures, unsigned int count);\n"
|
||||
"bool pxl8_world_is_loaded(const pxl8_world* world);\n"
|
||||
"int pxl8_world_load(pxl8_world* world, const char* path);\n"
|
||||
"void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);\n"
|
||||
|
|
@ -692,7 +716,7 @@ pxl8_result pxl8_script_load_main(pxl8_script* script, const char* path) {
|
|||
if (result == PXL8_OK) {
|
||||
pxl8_info("Loaded script: %s", path);
|
||||
} else {
|
||||
pxl8_warn("Failed to load script: %s", script->last_error);
|
||||
pxl8_error("Failed to load script: %s", script->last_error);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
123
src/pxl8_world.c
123
src/pxl8_world.c
|
|
@ -1,3 +1,4 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -36,8 +37,8 @@ void pxl8_world_destroy(pxl8_world* world) {
|
|||
free(world);
|
||||
}
|
||||
|
||||
pxl8_result pxl8_world_generate(pxl8_world* world, const pxl8_procgen_params* params) {
|
||||
if (!world || !params) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
pxl8_result pxl8_world_generate(pxl8_world* world, pxl8_gfx* gfx, const pxl8_procgen_params* params) {
|
||||
if (!world || !gfx || !params) return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
if (world->loaded) {
|
||||
pxl8_bsp_destroy(&world->bsp);
|
||||
|
|
@ -54,7 +55,93 @@ pxl8_result pxl8_world_generate(pxl8_world* world, const pxl8_procgen_params* pa
|
|||
}
|
||||
|
||||
world->loaded = true;
|
||||
pxl8_info("Generated world");
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
||||
pxl8_result pxl8_world_apply_textures(pxl8_world* world, const pxl8_world_texture* textures, u32 count) {
|
||||
if (!world || !world->loaded || !textures || count == 0) {
|
||||
return PXL8_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
pxl8_bsp* bsp = &world->bsp;
|
||||
|
||||
u32 max_texinfo = count * 6;
|
||||
bsp->texinfo = calloc(max_texinfo, sizeof(pxl8_bsp_texinfo));
|
||||
if (!bsp->texinfo) {
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
bsp->num_texinfo = 0;
|
||||
|
||||
for (u32 face_idx = 0; face_idx < bsp->num_faces; face_idx++) {
|
||||
pxl8_bsp_face* face = &bsp->faces[face_idx];
|
||||
pxl8_vec3 normal = bsp->planes[face->plane_id].normal;
|
||||
|
||||
u32 matched_texture_idx = count;
|
||||
for (u32 tex_idx = 0; tex_idx < count; tex_idx++) {
|
||||
if (textures[tex_idx].rule && textures[tex_idx].rule(&normal, face, bsp)) {
|
||||
matched_texture_idx = tex_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched_texture_idx >= count) {
|
||||
pxl8_warn("No texture rule matched for face %u", face_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
const pxl8_world_texture* matched = &textures[matched_texture_idx];
|
||||
|
||||
pxl8_vec3 u_axis, v_axis;
|
||||
if (fabsf(normal.y) > 0.9f) {
|
||||
u_axis = (pxl8_vec3){1.0f, 0.0f, 0.0f};
|
||||
v_axis = (pxl8_vec3){0.0f, 0.0f, 1.0f};
|
||||
} else if (fabsf(normal.x) > 0.7f) {
|
||||
u_axis = (pxl8_vec3){0.0f, 1.0f, 0.0f};
|
||||
v_axis = (pxl8_vec3){0.0f, 0.0f, 1.0f};
|
||||
} else {
|
||||
u_axis = (pxl8_vec3){1.0f, 0.0f, 0.0f};
|
||||
v_axis = (pxl8_vec3){0.0f, 1.0f, 0.0f};
|
||||
}
|
||||
|
||||
u32 texinfo_idx = bsp->num_texinfo;
|
||||
bool found_existing = false;
|
||||
for (u32 i = 0; i < bsp->num_texinfo; i++) {
|
||||
if (strcmp(bsp->texinfo[i].name, matched->name) == 0 &&
|
||||
bsp->texinfo[i].miptex == matched->texture_id &&
|
||||
bsp->texinfo[i].u_axis.x == u_axis.x &&
|
||||
bsp->texinfo[i].u_axis.y == u_axis.y &&
|
||||
bsp->texinfo[i].u_axis.z == u_axis.z &&
|
||||
bsp->texinfo[i].v_axis.x == v_axis.x &&
|
||||
bsp->texinfo[i].v_axis.y == v_axis.y &&
|
||||
bsp->texinfo[i].v_axis.z == v_axis.z) {
|
||||
texinfo_idx = i;
|
||||
found_existing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_existing) {
|
||||
if (bsp->num_texinfo >= max_texinfo) {
|
||||
pxl8_error("Too many unique texinfo entries");
|
||||
return PXL8_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(bsp->texinfo[texinfo_idx].name, matched->name, sizeof(bsp->texinfo[texinfo_idx].name));
|
||||
bsp->texinfo[texinfo_idx].name[sizeof(bsp->texinfo[texinfo_idx].name) - 1] = '\0';
|
||||
bsp->texinfo[texinfo_idx].miptex = matched->texture_id;
|
||||
bsp->texinfo[texinfo_idx].u_offset = 0.0f;
|
||||
bsp->texinfo[texinfo_idx].v_offset = 0.0f;
|
||||
bsp->texinfo[texinfo_idx].u_axis = u_axis;
|
||||
bsp->texinfo[texinfo_idx].v_axis = v_axis;
|
||||
|
||||
bsp->num_texinfo++;
|
||||
}
|
||||
|
||||
face->texinfo_id = texinfo_idx;
|
||||
}
|
||||
|
||||
pxl8_info("Applied %u textures to %u faces, created %u texinfo entries",
|
||||
count, bsp->num_faces, bsp->num_texinfo);
|
||||
|
||||
return PXL8_OK;
|
||||
}
|
||||
|
|
@ -84,38 +171,10 @@ pxl8_result pxl8_world_load(pxl8_world* world, const char* path) {
|
|||
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
||||
if (!world || !gfx || !world->loaded) return;
|
||||
|
||||
static bool texture_generated = false;
|
||||
static u32 wall_texture_id = 0;
|
||||
if (!texture_generated) {
|
||||
u8 texture_data[64 * 64];
|
||||
|
||||
pxl8_procgen_tex_params tex_params = {
|
||||
.seed = 12345,
|
||||
.width = 64,
|
||||
.height = 64,
|
||||
.scale = 0.25f,
|
||||
.roughness = 0.5f,
|
||||
.base_color = 1,
|
||||
.variation = 3
|
||||
};
|
||||
|
||||
pxl8_procgen_tex(texture_data, &tex_params);
|
||||
|
||||
pxl8_result result = pxl8_gfx_create_texture(gfx, texture_data, 64, 64);
|
||||
if (result >= 0) {
|
||||
wall_texture_id = (u32)result;
|
||||
pxl8_gfx_upload_atlas(gfx);
|
||||
texture_generated = true;
|
||||
pxl8_info("Generated stone texture with ID: %u", wall_texture_id);
|
||||
} else {
|
||||
pxl8_error("Failed to create wall texture: %d", result);
|
||||
}
|
||||
}
|
||||
|
||||
if (world->wireframe) {
|
||||
pxl8_bsp_render_wireframe(gfx, &world->bsp, camera_pos, world->wireframe_color);
|
||||
} else {
|
||||
pxl8_bsp_render_solid(gfx, &world->bsp, camera_pos, wall_texture_id);
|
||||
pxl8_bsp_render_textured(gfx, &world->bsp, camera_pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@
|
|||
|
||||
typedef struct pxl8_world pxl8_world;
|
||||
|
||||
typedef bool (*pxl8_texture_rule)(const pxl8_vec3* normal, const pxl8_bsp_face* face, const pxl8_bsp* bsp);
|
||||
|
||||
typedef struct pxl8_world_texture {
|
||||
char name[16];
|
||||
u32 texture_id;
|
||||
pxl8_texture_rule rule;
|
||||
} pxl8_world_texture;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
@ -14,7 +22,8 @@ extern "C" {
|
|||
pxl8_world* pxl8_world_create(void);
|
||||
void pxl8_world_destroy(pxl8_world* world);
|
||||
|
||||
pxl8_result pxl8_world_generate(pxl8_world* world, const pxl8_procgen_params* params);
|
||||
pxl8_result pxl8_world_generate(pxl8_world* world, pxl8_gfx* gfx, const pxl8_procgen_params* params);
|
||||
pxl8_result pxl8_world_apply_textures(pxl8_world* world, const pxl8_world_texture* textures, u32 count);
|
||||
bool pxl8_world_is_loaded(const pxl8_world* world);
|
||||
pxl8_result pxl8_world_load(pxl8_world* world, const char* path);
|
||||
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue