summaryrefslogtreecommitdiff
path: root/kon/konsofren.h
diff options
context:
space:
mode:
authorKonAki <konaki@anokonaki.org>2026-10-11 22:16:09 +0800
committerKonAki <konaki@anokonaki.org>2026-10-11 22:16:09 +0800
commita4b7011ac9d5ccf012a99bd8a7769fcd45bac53e (patch)
treeb04f98585b2cd303e7d6e501be6b44ce29e5de49 /kon/konsofren.h
parent20bbe2731a2d04b6dde65e9f893ad360915a889b (diff)
konsofren: kon_lightPass, point and spot lights from the depth buffer
Diffstat (limited to 'kon/konsofren.h')
-rw-r--r--kon/konsofren.h115
1 files changed, 115 insertions, 0 deletions
diff --git a/kon/konsofren.h b/kon/konsofren.h
index 4e29e56..6cca535 100644
--- a/kon/konsofren.h
+++ b/kon/konsofren.h
@@ -249,6 +249,26 @@ void kon_drawMesh(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_mat4_t m
int kon_drawBillboard(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3_t position, float width, float height,
const kon_image *image, kon_rect_t src, float brightness, kon_renderFlags_t flags);
+/*** lights that sit in the world ***/
+
+/* a light with a place. with cone 0 it shines all around, otherwise it is a spot light like a flashlight pointing along direction */
+typedef struct kon_pointLight {
+ kon_vec3_t position;
+ uint32_t color; /* 0xFFRRGGBB, alpha is ignored */
+ float radius; /* it reaches nothing farther than this */
+ float intensity; /* 1 is full strength, more than that lights things brighter than they were drawn */
+ kon_vec3_t direction; /* spot lights only, the way it points */
+ float cone; /* spot lights only, how wide it is from the middle to the edge in radians, 0 for a light that shines all around */
+ float soft; /* spot lights only, 0 to 1, how much of the cone fades out at the edge */
+} kon_pointLight_t;
+
+/* lights what is already drawn, after everything with depth is in and before the screen elements. every pixel that has depth gets
+ color * (ambient + the light of every light that reaches it). draw the scene with light.ambient 1 and intensity 0 so it still has
+ its plain colors, this makes it dark and then lights it. it knows where things are but not which way they face, and it has no
+ shadows: light goes through walls, so keep the radius of a light inside its room. it costs about one pass over the screen plus a bit
+ for every light that is close. needs the depth buffer, so draw with KON_RENDER_DEPTH */
+void kon_lightPass(kon_framebuffer_t *fb, kon_mat4_t viewProjection, const kon_pointLight_t *lights, int count, float ambient);
+
/* cube from -1 to 1 with every face mapped to the whole texture */
extern const kon_mesh_t kon_cubeMesh;
@@ -1652,6 +1672,101 @@ int kon_drawBillboard(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3
return 1;
}
+/*** light pass ***/
+
+typedef struct kon_lightSetup_ {
+ float x, y, z, radius, invRadius, intensity, r, g, b;
+ float dx, dy, dz, cosOuter, cosRange;
+ int spot;
+} kon_lightSetup_t;
+
+void kon_lightPass(kon_framebuffer_t *fb, kon_mat4_t viewProjection, const kon_pointLight_t *lights, int count, float ambient) {
+ enum { MAX_LIGHTS = 32 };
+ kon_lightSetup_t set[MAX_LIGHTS];
+ kon_mat4_t inv;
+ int used = 0, i, ok, px, py;
+ float ndcStepX, ndcStepY;
+
+ if (!fb || !fb->depth || !lights) return;
+ inv = kon_mat4Inverse(viewProjection, &ok);
+ if (!ok) return;
+ if (ambient < 0.0f) ambient = 0.0f;
+
+ for (i = 0; i < count && used < MAX_LIGHTS; i++) {
+ const kon_pointLight_t *l = &lights[i];
+ kon_lightSetup_t *s = &set[used];
+
+ if (l->radius <= 0.0f || l->intensity <= 0.0f) continue;
+ s->x = l->position.x; s->y = l->position.y; s->z = l->position.z;
+ s->radius = l->radius;
+ s->invRadius = 1.0f / l->radius;
+ s->intensity = l->intensity;
+ s->r = (float)((l->color >> 16) & 255) / 255.0f;
+ s->g = (float)((l->color >> 8) & 255) / 255.0f;
+ s->b = (float)(l->color & 255) / 255.0f;
+ s->spot = l->cone > 0.0f;
+ if (s->spot) {
+ float len = sqrtf(l->direction.x * l->direction.x + l->direction.y * l->direction.y + l->direction.z * l->direction.z);
+ float soft = kon_clamp(l->soft, 0.0f, 1.0f), inner = l->cone * (1.0f - soft);
+
+ if (len < 1.0e-6f) continue;
+ s->dx = l->direction.x / len; s->dy = l->direction.y / len; s->dz = l->direction.z / len;
+ s->cosOuter = cosf(l->cone);
+ s->cosRange = cosf(inner) - s->cosOuter;
+ if (s->cosRange < 1.0e-4f) s->cosRange = 1.0e-4f;
+ }
+ used++;
+ }
+
+ ndcStepX = 2.0f / (float)fb->width;
+ ndcStepY = 2.0f / (float)fb->height;
+ for (py = 0; py < fb->height; py++) {
+ float ndcY = 1.0f - ((float)py + 0.5f) * ndcStepY;
+
+ for (px = 0; px < fb->width; px++) {
+ int index = py * fb->width + px;
+ float z = fb->depth[index], ndcX, wx, wy, wz, ww, level[3], inverseW;
+ uint32_t c;
+ int k, r, g, b;
+
+ if (z >= 1.0f) continue;
+ ndcX = ((float)px + 0.5f) * ndcStepX - 1.0f;
+ wx = inv.m[0] * ndcX + inv.m[4] * ndcY + inv.m[8] * z + inv.m[12];
+ wy = inv.m[1] * ndcX + inv.m[5] * ndcY + inv.m[9] * z + inv.m[13];
+ wz = inv.m[2] * ndcX + inv.m[6] * ndcY + inv.m[10] * z + inv.m[14];
+ ww = inv.m[3] * ndcX + inv.m[7] * ndcY + inv.m[11] * z + inv.m[15];
+ inverseW = 1.0f / ww;
+ wx *= inverseW; wy *= inverseW; wz *= inverseW;
+
+ level[0] = level[1] = level[2] = ambient;
+ for (k = 0; k < used; k++) {
+ const kon_lightSetup_t *s = &set[k];
+ float dx = wx - s->x, dy = wy - s->y, dz = wz - s->z, d2 = dx * dx + dy * dy + dz * dz, d, fall, amount;
+
+ if (d2 >= s->radius * s->radius) continue;
+ d = sqrtf(d2);
+ fall = 1.0f - d * s->invRadius;
+ amount = fall * fall * s->intensity;
+ if (s->spot) {
+ float along = d > 1.0e-6f ? (dx * s->dx + dy * s->dy + dz * s->dz) / d : 1.0f, edge = (along - s->cosOuter) / s->cosRange;
+
+ if (edge <= 0.0f) continue;
+ if (edge < 1.0f) amount *= edge * edge * (3.0f - 2.0f * edge);
+ }
+ level[0] += amount * s->r;
+ level[1] += amount * s->g;
+ level[2] += amount * s->b;
+ }
+
+ c = fb->data[index];
+ r = (int)((float)((c >> 16) & 255) * level[0]);
+ g = (int)((float)((c >> 8) & 255) * level[1]);
+ b = (int)((float)(c & 255) * level[2]);
+ fb->data[index] = 0xFF000000u | (uint32_t)(r > 255 ? 255 : r) << 16 | (uint32_t)(g > 255 ? 255 : g) << 8 | (uint32_t)(b > 255 ? 255 : b);
+ }
+ }
+}
+
#endif /* KONSOFREN_3D */
#endif /* end of KONSOFREN_IMPLEMENTATION */