114 lines
3.3 KiB
C
114 lines
3.3 KiB
C
#include "pxl8_lightmap.h"
|
|
#include "pxl8_mem.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
pxl8_lightmap* pxl8_lightmap_create(u32 width, u32 height, u32 scale) {
|
|
pxl8_lightmap* lm = pxl8_calloc(1, sizeof(pxl8_lightmap));
|
|
if (!lm) return NULL;
|
|
|
|
lm->width = width;
|
|
lm->height = height;
|
|
lm->scale = scale;
|
|
lm->data = pxl8_calloc(width * height * 3, sizeof(u8));
|
|
if (!lm->data) {
|
|
pxl8_free(lm);
|
|
return NULL;
|
|
}
|
|
|
|
pxl8_lightmap_clear(lm, PXL8_LIGHTMAP_NEUTRAL, PXL8_LIGHTMAP_NEUTRAL, PXL8_LIGHTMAP_NEUTRAL);
|
|
return lm;
|
|
}
|
|
|
|
void pxl8_lightmap_destroy(pxl8_lightmap* lm) {
|
|
if (!lm) return;
|
|
pxl8_free(lm->data);
|
|
pxl8_free(lm);
|
|
}
|
|
|
|
void pxl8_lightmap_clear(pxl8_lightmap* lm, u8 r, u8 g, u8 b) {
|
|
if (!lm || !lm->data) return;
|
|
u32 count = lm->width * lm->height;
|
|
for (u32 i = 0; i < count; i++) {
|
|
lm->data[i * 3 + 0] = r;
|
|
lm->data[i * 3 + 1] = g;
|
|
lm->data[i * 3 + 2] = b;
|
|
}
|
|
}
|
|
|
|
void pxl8_lightmap_set(pxl8_lightmap* lm, u32 x, u32 y, u8 r, u8 g, u8 b) {
|
|
if (!lm || !lm->data || x >= lm->width || y >= lm->height) return;
|
|
u32 idx = (y * lm->width + x) * 3;
|
|
lm->data[idx + 0] = r;
|
|
lm->data[idx + 1] = g;
|
|
lm->data[idx + 2] = b;
|
|
}
|
|
|
|
void pxl8_lightmap_get(const pxl8_lightmap* lm, u32 x, u32 y, u8* r, u8* g, u8* b) {
|
|
if (!lm || !lm->data || x >= lm->width || y >= lm->height) {
|
|
*r = *g = *b = PXL8_LIGHTMAP_NEUTRAL;
|
|
return;
|
|
}
|
|
u32 idx = (y * lm->width + x) * 3;
|
|
*r = lm->data[idx + 0];
|
|
*g = lm->data[idx + 1];
|
|
*b = lm->data[idx + 2];
|
|
}
|
|
|
|
void pxl8_lightmap_add_point(
|
|
pxl8_lightmap* lm,
|
|
f32 lx, f32 ly,
|
|
u8 r, u8 g, u8 b,
|
|
f32 radius,
|
|
f32 intensity
|
|
) {
|
|
if (!lm || !lm->data || radius <= 0.0f) return;
|
|
|
|
f32 radius_sq = radius * radius;
|
|
f32 inv_radius_sq = 1.0f / radius_sq;
|
|
|
|
i32 cx = (i32)(lx * (f32)lm->width);
|
|
i32 cy = (i32)(ly * (f32)lm->height);
|
|
i32 rad_pixels = (i32)(radius * (f32)lm->width) + 1;
|
|
|
|
i32 x0 = cx - rad_pixels;
|
|
i32 y0 = cy - rad_pixels;
|
|
i32 x1 = cx + rad_pixels;
|
|
i32 y1 = cy + rad_pixels;
|
|
|
|
if (x0 < 0) x0 = 0;
|
|
if (y0 < 0) y0 = 0;
|
|
if (x1 >= (i32)lm->width) x1 = (i32)lm->width - 1;
|
|
if (y1 >= (i32)lm->height) y1 = (i32)lm->height - 1;
|
|
|
|
f32 scale_x = 1.0f / (f32)lm->width;
|
|
f32 scale_y = 1.0f / (f32)lm->height;
|
|
|
|
for (i32 y = y0; y <= y1; y++) {
|
|
f32 dy = ((f32)y * scale_y) - ly;
|
|
for (i32 x = x0; x <= x1; x++) {
|
|
f32 dx = ((f32)x * scale_x) - lx;
|
|
f32 dist_sq = dx * dx + dy * dy;
|
|
|
|
if (dist_sq >= radius_sq) continue;
|
|
|
|
f32 falloff = 1.0f - dist_sq * inv_radius_sq;
|
|
f32 contrib = falloff * falloff * intensity;
|
|
|
|
u32 idx = ((u32)y * lm->width + (u32)x) * 3;
|
|
|
|
i32 nr = (i32)lm->data[idx + 0] + (i32)((f32)(r - 128) * contrib);
|
|
i32 ng = (i32)lm->data[idx + 1] + (i32)((f32)(g - 128) * contrib);
|
|
i32 nb = (i32)lm->data[idx + 2] + (i32)((f32)(b - 128) * contrib);
|
|
|
|
if (nr < 0) nr = 0; if (nr > 255) nr = 255;
|
|
if (ng < 0) ng = 0; if (ng > 255) ng = 255;
|
|
if (nb < 0) nb = 0; if (nb > 255) nb = 255;
|
|
|
|
lm->data[idx + 0] = (u8)nr;
|
|
lm->data[idx + 1] = (u8)ng;
|
|
lm->data[idx + 2] = (u8)nb;
|
|
}
|
|
}
|
|
}
|