Lighting Engine refactor (up to 10x perf increase) (#1098)
Some checks failed
Build coop / build-linux (push) Has been cancelled
Build coop / build-steamos (push) Has been cancelled
Build coop / build-windows-opengl (push) Has been cancelled
Build coop / build-windows-directx (push) Has been cancelled
Build coop / build-macos-arm (push) Has been cancelled
Build coop / build-macos-intel (push) Has been cancelled

* C++ lighting engine

Runs better using my new system for storing and iterating through lights.

I removed the lighting ctx profiler because after I've realized its very inaccurate and was probably programmed incorrectly from the start. Although I remember it working fine before and not constantly showing 20 ms or higher when I'm in an extremely simple level with extremely simple lights and the FPS is way too high for it to be taking 20 ms.

* Whoops

* Make some optimizations

* Fix small bug with LE inside graphics vertex function

I also brought back the lighting profiler because it's better than nothing.

* Some optimizations

* Cache active lights and 4 lights per vertex limit

Less branching and less iterating with the limit

* Peachy changes
This commit is contained in:
Agent X 2026-02-18 01:43:44 -05:00 committed by GitHub
parent 1680c715fd
commit 0ce4163519
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 513 additions and 392 deletions

View file

@ -3635,7 +3635,7 @@ HUD_DISPLAY_DEFAULT = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_CO
--- | `HUD_DISPLAY_DEFAULT`
--- @type integer
LE_MAX_LIGHTS = 512
LE_MAX_LIGHTS = 1024
LE_MODE_AFFECT_ALL_SHADED_AND_COLORED = 0 --- @type LEMode
LE_MODE_AFFECT_ALL_SHADED = 1 --- @type LEMode

View file

@ -5103,6 +5103,12 @@ function le_set_ambient_color(r, g, b)
-- ...
end
--- @param count integer
--- Sets the max amount of lights that can affect a vertex
function le_set_max_lights_per_vertex(count)
-- ...
end
--- @param pos Vec3f
--- @param out Color
--- @param lightIntensityScalar number

View file

@ -147,6 +147,29 @@ Sets the lighting engine ambient color
<br />
## [le_set_max_lights_per_vertex](#le_set_max_lights_per_vertex)
### Description
Sets the max amount of lights that can affect a vertex
### Lua Example
`le_set_max_lights_per_vertex(count)`
### Parameters
| Field | Type |
| ----- | ---- |
| count | `integer` |
### Returns
- None
### C Prototype
`void le_set_max_lights_per_vertex(u8 count);`
[:arrow_up_small:](#)
<br />
## [le_calculate_lighting_color](#le_calculate_lighting_color)
### Description

View file

@ -976,6 +976,7 @@
- [le_set_tone_mapping](functions-4.md#le_set_tone_mapping)
- [le_get_ambient_color](functions-4.md#le_get_ambient_color)
- [le_set_ambient_color](functions-4.md#le_set_ambient_color)
- [le_set_max_lights_per_vertex](functions-4.md#le_set_max_lights_per_vertex)
- [le_calculate_lighting_color](functions-4.md#le_calculate_lighting_color)
- [le_calculate_lighting_color_with_normal](functions-4.md#le_calculate_lighting_color_with_normal)
- [le_calculate_lighting_dir](functions-4.md#le_calculate_lighting_dir)

View file

@ -1,382 +0,0 @@
#include "lighting_engine.h"
#include "math_util.h"
struct LELight
{
f32 posX;
f32 posY;
f32 posZ;
u8 colorR;
u8 colorG;
u8 colorB;
f32 radius;
f32 intensity;
bool added;
bool useSurfaceNormals;
};
Color gLEAmbientColor = { 127, 127, 127 };
static struct LELight sLights[LE_MAX_LIGHTS] = { 0 };
static enum LEMode sMode = LE_MODE_AFFECT_ALL_SHADED_AND_COLORED;
static enum LEToneMapping sToneMapping = LE_TONE_MAPPING_WEIGHTED;
static bool sEnabled = false;
static inline void color_set(Color color, u8 r, u8 g, u8 b) {
color[0] = r;
color[1] = g;
color[2] = b;
}
static inline void color_copy(Color dest, Color src) {
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
}
bool le_is_enabled(void) {
// this is needed because we don't want to make vanilla darker,
// and we don't want to set the ambient color to { 255, 255, 255 }
// because then no one could see the effect of their lights
return sEnabled;
}
void le_set_mode(enum LEMode mode) {
sMode = mode;
}
enum LEMode le_get_mode(void) {
return sMode;
}
void le_set_tone_mapping(enum LEToneMapping toneMapping) {
sToneMapping = toneMapping;
}
void le_get_ambient_color(VEC_OUT Color out) {
color_copy(out, gLEAmbientColor);
}
void le_set_ambient_color(u8 r, u8 g, u8 b) {
color_set(gLEAmbientColor, r, g, b);
sEnabled = true;
}
static inline void le_tone_map_total_weighted(Color out, Color inAmbient, Vec3f inColor, float weight) {
out[0] = clamp((inAmbient[0] + inColor[0]) / weight, 0, 255);
out[1] = clamp((inAmbient[1] + inColor[1]) / weight, 0, 255);
out[2] = clamp((inAmbient[2] + inColor[2]) / weight, 0, 255);
}
static inline void le_tone_map_weighted(Color out, Color inAmbient, Vec3f inColor, float weight) {
out[0] = clamp(inAmbient[0] + (inColor[0] / weight), 0, 255);
out[1] = clamp(inAmbient[1] + (inColor[1] / weight), 0, 255);
out[2] = clamp(inAmbient[2] + (inColor[2] / weight), 0, 255);
}
static inline void le_tone_map_clamp(Color out, Color inAmbient, Vec3f inColor) {
out[0] = clamp(inAmbient[0] + inColor[0], 0, 255);
out[1] = clamp(inAmbient[1] + inColor[1], 0, 255);
out[2] = clamp(inAmbient[2] + inColor[2], 0, 255);
}
static inline void le_tone_map_reinhard(Color out, Color inAmbient, Vec3f inColor) {
inColor[0] += inAmbient[0];
inColor[1] += inAmbient[1];
inColor[2] += inAmbient[2];
out[0] = clamp((inColor[0] / (inColor[0] + 255.0f)) * 255.0f, 0, 255);
out[1] = clamp((inColor[1] / (inColor[1] + 255.0f)) * 255.0f, 0, 255);
out[2] = clamp((inColor[2] / (inColor[2] + 255.0f)) * 255.0f, 0, 255);
}
static inline void le_tone_map(Color out, Color inAmbient, Vec3f inColor, float weight) {
switch (sToneMapping) {
case LE_TONE_MAPPING_TOTAL_WEIGHTED: le_tone_map_total_weighted(out, inAmbient, inColor, weight); break;
case LE_TONE_MAPPING_WEIGHTED: le_tone_map_weighted(out, inAmbient, inColor, weight); break;
case LE_TONE_MAPPING_CLAMP: le_tone_map_clamp(out, inAmbient, inColor); break;
case LE_TONE_MAPPING_REINHARD: le_tone_map_reinhard(out, inAmbient, inColor); break;
}
}
static inline void le_calculate_light_contribution(struct LELight* light, Vec3f pos, Vec3f normal, f32 lightIntensityScalar, Vec3f out_color, f32* weight) {
// skip 'inactive' lights
if (light->intensity <= 0 || light->radius <= 0) { return; }
// vector to light
f32 diffX = light->posX - pos[0];
f32 diffY = light->posY - pos[1];
f32 diffZ = light->posZ - pos[2];
// squared distance check
f32 dist2 = (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ);
f32 radius2 = light->radius * light->radius;
if (dist2 > radius2 || dist2 <= 0) { return; }
// attenuation & intensity
f32 att = 1.0f - (dist2 / radius2);
f32 brightness = att * light->intensity * lightIntensityScalar;
// normalize diff
f32 invLen = 1.0f / sqrtf(dist2);
diffX *= invLen;
diffY *= invLen;
diffZ *= invLen;
if (light->useSurfaceNormals && normal) {
// lambert term
f32 nl = (normal[0] * diffX) + (normal[1] * diffY) + (normal[2] * diffZ);
if (nl <= 0.0f) { return; }
// modulate by normal
brightness *= nl;
}
// accumulate
out_color[0] += light->colorR * brightness;
out_color[1] += light->colorG * brightness;
out_color[2] += light->colorB * brightness;
*weight += brightness;
}
void le_calculate_vertex_lighting(Vtx_t* v, Vec3f pos, Color out) {
// clear color
Vec3f color = { 0 };
// accumulate lighting
f32 weight = 1.0f;
for (s16 i = 0; i < LE_MAX_LIGHTS; i++) {
struct LELight* light = &sLights[i];
if (!light->added) { continue; }
le_calculate_light_contribution(light, pos, NULL, 1.0f, color, &weight);
}
// tone map and output
Color vtxAmbient = {
v->cn[0] * (gLEAmbientColor[0] / 255.0f),
v->cn[1] * (gLEAmbientColor[1] / 255.0f),
v->cn[2] * (gLEAmbientColor[2] / 255.0f),
};
le_tone_map(out, vtxAmbient, color, weight);
}
void le_calculate_lighting_color(Vec3f pos, Color out, f32 lightIntensityScalar) {
// clear color
Vec3f color = { 0 };
// accumulate lighting
f32 weight = 1.0f;
for (s16 i = 0; i < LE_MAX_LIGHTS; i++) {
struct LELight* light = &sLights[i];
if (!light->added) { continue; }
le_calculate_light_contribution(light, pos, NULL, lightIntensityScalar, color, &weight);
}
// tone map and output
le_tone_map(out, gLEAmbientColor, color, weight);
}
void le_calculate_lighting_color_with_normal(Vec3f pos, Vec3f normal, Color out, f32 lightIntensityScalar) {
// normalize normal
if (normal) { vec3f_normalize(normal); }
// clear color
Vec3f color = { 0 };
// accumulate lighting
f32 weight = 1.0f;
for (s16 i = 0; i < LE_MAX_LIGHTS; i++) {
struct LELight* light = &sLights[i];
if (!light->added) { continue; }
le_calculate_light_contribution(light, pos, normal, lightIntensityScalar, color, &weight);
}
// tone map and output
le_tone_map(out, gLEAmbientColor, color, weight);
}
void le_calculate_lighting_dir(Vec3f pos, Vec3f out) {
Vec3f lightingDir = { 0, 0, 0 };
s16 count = 1;
for (s16 i = 0; i < LE_MAX_LIGHTS; i++) {
struct LELight* light = &sLights[i];
if (!light->added) { continue; }
f32 diffX = light->posX - pos[0];
f32 diffY = light->posY - pos[1];
f32 diffZ = light->posZ - pos[2];
f32 dist = (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ);
f32 radius = light->radius * light->radius;
if (dist > radius) { continue; }
Vec3f dir = {
pos[0] - light->posX,
pos[1] - light->posY,
pos[2] - light->posZ,
};
vec3f_normalize(dir);
f32 intensity = (1 - (dist / radius)) * light->intensity;
lightingDir[0] += dir[0] * intensity;
lightingDir[1] += dir[1] * intensity;
lightingDir[2] += dir[2] * intensity;
count++;
}
out[0] = lightingDir[0] / (f32)(count);
out[1] = lightingDir[1] / (f32)(count);
out[2] = lightingDir[2] / (f32)(count);
vec3f_normalize(out);
}
s16 le_add_light(f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, f32 radius, f32 intensity) {
struct LELight* newLight = NULL;
s16 lightID = -1;
for (s16 i = 0; i < LE_MAX_LIGHTS; i++) {
struct LELight* light = &sLights[i];
if (!light->added) {
newLight = light;
lightID = i;
break;
}
}
if (newLight == NULL) { return -1; }
newLight->posX = x;
newLight->posY = y;
newLight->posZ = z;
newLight->colorR = r;
newLight->colorG = g;
newLight->colorB = b;
newLight->radius = radius;
newLight->intensity = intensity;
newLight->added = true;
newLight->useSurfaceNormals = true;
sEnabled = true;
return lightID;
}
void le_remove_light(s16 id) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
memset(&sLights[id], 0, sizeof(struct LELight));
}
s16 le_get_light_count(void) {
s16 count = 0;
for (s16 i = 0; i < LE_MAX_LIGHTS; i++) {
if (sLights[i].added) { count++; }
}
return count;
}
bool le_light_exists(s16 id) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return false; }
return sLights[id].added;
}
void le_get_light_pos(s16 id, VEC_OUT Vec3f out) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
struct LELight* light = &sLights[id];
if (!light->added) { return; }
vec3f_set(out, light->posX, light->posY, light->posZ);
}
void le_set_light_pos(s16 id, f32 x, f32 y, f32 z) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
struct LELight* light = &sLights[id];
if (!light->added) { return; }
light->posX = x;
light->posY = y;
light->posZ = z;
}
void le_get_light_color(s16 id, VEC_OUT Color out) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
struct LELight* light = &sLights[id];
if (!light->added) { return; }
color_set(out, light->colorR, light->colorG, light->colorB);
}
void le_set_light_color(s16 id, u8 r, u8 g, u8 b) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
struct LELight* light = &sLights[id];
if (!light->added) { return; }
light->colorR = r;
light->colorG = g;
light->colorB = b;
}
f32 le_get_light_radius(s16 id) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return 0.0f; }
struct LELight* light = &sLights[id];
if (!light->added) { return 0.0f; }
return light->radius;
}
void le_set_light_radius(s16 id, f32 radius) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
struct LELight* light = &sLights[id];
if (!light->added) { return; }
light->radius = radius;
}
f32 le_get_light_intensity(s16 id) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return 0.0f; }
struct LELight* light = &sLights[id];
if (!light->added) { return 0.0f; }
return light->intensity;
}
void le_set_light_intensity(s16 id, f32 intensity) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
struct LELight* light = &sLights[id];
if (!light->added) { return; }
light->intensity = intensity;
}
bool le_get_light_use_surface_normals(s16 id) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return false; }
struct LELight* light = &sLights[id];
if (!light->added) { return false; }
return light->useSurfaceNormals;
}
void le_set_light_use_surface_normals(s16 id, bool useSurfaceNormals) {
if (id < 0 || id >= LE_MAX_LIGHTS) { return; }
struct LELight* light = &sLights[id];
if (!light->added) { return; }
light->useSurfaceNormals = useSurfaceNormals;
}
void le_clear(void) {
memset(&sLights, 0, sizeof(struct LELight) * LE_MAX_LIGHTS);
gLEAmbientColor[0] = 127;
gLEAmbientColor[1] = 127;
gLEAmbientColor[2] = 127;
}
void le_shutdown(void) {
sEnabled = false;
sMode = LE_MODE_AFFECT_ALL_SHADED_AND_COLORED;
sToneMapping = LE_TONE_MAPPING_WEIGHTED;
le_clear();
}

View file

@ -0,0 +1,444 @@
#include "lighting_engine.h"
extern "C" {
#include "math_util.h"
#include "pc/lua/smlua.h"
}
#undef clamp
#undef min
#undef max
#include <vector>
#include <algorithm>
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#define C_FIELD extern "C"
struct LELight
{
s16 id;
Vec3f pos;
Color color;
f32 radius;
f32 intensity;
bool useSurfaceNormals;
};
Color gLEAmbientColor = { 127, 127, 127 };
static std::vector<LELight> sLightPool;
static std::vector<LELight*> sActiveLights;
static s16 sLightID = -1;
static enum LEMode sMode = LE_MODE_AFFECT_ALL_SHADED_AND_COLORED;
static enum LEToneMapping sToneMapping = LE_TONE_MAPPING_WEIGHTED;
static bool sEnabled = false;
static u8 sMaxLightsPerVertex = 4;
static inline f32 rsqrt(f32 value) {
#ifdef __SSE__
return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(value)));
#else
return 1.0f / sqrtf(value);
#endif
}
static inline void color_set(Color color, u8 r, u8 g, u8 b) {
color[0] = r;
color[1] = g;
color[2] = b;
}
static inline void color_copy(Color dest, Color src) {
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
}
static inline u8 clamp_u8(f32 value) {
s32 v = (s32)value;
v = v < 0 ? 0 : v;
v = v > 255 ? 255 : v;
return (u8)v;
}
C_FIELD bool le_is_enabled(void) {
// this is needed because we don't want to make vanilla darker,
// and we don't want to set the ambient color to { 255, 255, 255 }
// because then no one could see the effect of their lights
return sEnabled;
}
C_FIELD void le_set_mode(enum LEMode mode) {
sMode = mode;
}
C_FIELD enum LEMode le_get_mode(void) {
return sMode;
}
C_FIELD void le_set_tone_mapping(enum LEToneMapping toneMapping) {
sToneMapping = toneMapping;
}
C_FIELD void le_get_ambient_color(VEC_OUT Color out) {
color_copy(out, gLEAmbientColor);
}
C_FIELD void le_set_ambient_color(u8 r, u8 g, u8 b) {
color_set(gLEAmbientColor, r, g, b);
sEnabled = true;
}
C_FIELD void le_set_max_lights_per_vertex(u8 count) {
sMaxLightsPerVertex = count;
}
static inline void le_tone_map_total_weighted(Color out, Color inAmbient, Vec3f inColor, f32 weight) {
out[0] = clamp_u8((inAmbient[0] + inColor[0]) / weight);
out[1] = clamp_u8((inAmbient[1] + inColor[1]) / weight);
out[2] = clamp_u8((inAmbient[2] + inColor[2]) / weight);
}
static inline void le_tone_map_weighted(Color out, Color inAmbient, Vec3f inColor, f32 weight) {
out[0] = clamp_u8(inAmbient[0] + (inColor[0] / weight));
out[1] = clamp_u8(inAmbient[1] + (inColor[1] / weight));
out[2] = clamp_u8(inAmbient[2] + (inColor[2] / weight));
}
static inline void le_tone_map_clamp(Color out, Color inAmbient, Vec3f inColor) {
out[0] = clamp_u8(inAmbient[0] + inColor[0]);
out[1] = clamp_u8(inAmbient[1] + inColor[1]);
out[2] = clamp_u8(inAmbient[2] + inColor[2]);
}
static inline void le_tone_map_reinhard(Color out, Color inAmbient, Vec3f inColor) {
inColor[0] += inAmbient[0];
inColor[1] += inAmbient[1];
inColor[2] += inAmbient[2];
out[0] = clamp_u8((inColor[0] / (inColor[0] + 255.0f)) * 255.0f);
out[1] = clamp_u8((inColor[1] / (inColor[1] + 255.0f)) * 255.0f);
out[2] = clamp_u8((inColor[2] / (inColor[2] + 255.0f)) * 255.0f);
}
static void le_tone_map(Color out, Color inAmbient, Vec3f inColor, f32 weight) {
switch (sToneMapping) {
case LE_TONE_MAPPING_TOTAL_WEIGHTED: le_tone_map_total_weighted(out, inAmbient, inColor, weight); break;
case LE_TONE_MAPPING_WEIGHTED: le_tone_map_weighted(out, inAmbient, inColor, weight); break;
case LE_TONE_MAPPING_CLAMP: le_tone_map_clamp(out, inAmbient, inColor); break;
case LE_TONE_MAPPING_REINHARD: le_tone_map_reinhard(out, inAmbient, inColor); break;
}
}
static void le_update_active_lights() {
sActiveLights.clear();
for (auto& light : sLightPool) {
if (light.intensity > 0.0f && light.radius > 0.0f) {
sActiveLights.push_back(&light);
}
}
}
static inline OPTIMIZE_O3 void le_calculate_light_contribution(const LELight& light, Vec3f pos, Vec3f normal, f32 lightIntensityScalar, Vec3f outColor, f32& weight, u8& contribution) {
// vector to light
f32 diffX = light.pos[0] - pos[0];
f32 diffY = light.pos[1] - pos[1];
f32 diffZ = light.pos[2] - pos[2];
// squared distance check
f32 dist2 = (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ);
f32 radius2 = light.radius * light.radius;
if (dist2 > radius2 || dist2 <= 0) { return; }
// attenuation & intensity
f32 att = 1.0f - (dist2 / radius2);
f32 brightness = att * light.intensity * lightIntensityScalar;
if (light.useSurfaceNormals && normal) {
// normalize diff
f32 invLen = rsqrt(dist2);
diffX *= invLen;
diffY *= invLen;
diffZ *= invLen;
// lambert term
f32 nl = (normal[0] * diffX) + (normal[1] * diffY) + (normal[2] * diffZ);
if (nl <= 0.0f) { return; }
// modulate by normal
brightness *= nl;
}
// accumulate
outColor[0] += light.color[0] * brightness;
outColor[1] += light.color[1] * brightness;
outColor[2] += light.color[2] * brightness;
weight += brightness;
contribution++;
}
C_FIELD OPTIMIZE_O3 void le_calculate_vertex_lighting(const Vtx_t* v, Vec3f pos, VEC_OUT Color out) {
// clear color
Vec3f color = { 0 };
// accumulate lighting
f32 weight = 1.0f;
u8 contribution = 0;
for (LELight* light : sActiveLights) {
le_calculate_light_contribution(*light, pos, NULL, 1.0f, color, weight, contribution);
if (contribution == sMaxLightsPerVertex) { break; }
}
// tone map and output
Color vtxAmbient = {
(u8)(v->cn[0] * (gLEAmbientColor[0] / 255.0f)),
(u8)(v->cn[1] * (gLEAmbientColor[1] / 255.0f)),
(u8)(v->cn[2] * (gLEAmbientColor[2] / 255.0f)),
};
le_tone_map(out, vtxAmbient, color, weight);
}
C_FIELD OPTIMIZE_O3 void le_calculate_lighting_color(Vec3f pos, VEC_OUT Color out, f32 lightIntensityScalar) {
// clear color
Vec3f color = { 0 };
// accumulate lighting
f32 weight = 1.0f;
u8 contribution = 0;
for (LELight* light : sActiveLights) {
le_calculate_light_contribution(*light, pos, NULL, lightIntensityScalar, color, weight, contribution);
if (contribution == sMaxLightsPerVertex) { break; }
}
// tone map and output
le_tone_map(out, gLEAmbientColor, color, weight);
}
C_FIELD OPTIMIZE_O3 void le_calculate_lighting_color_with_normal(Vec3f pos, Vec3f normal, VEC_OUT Color out, f32 lightIntensityScalar) {
// normalize normal
if (normal) { vec3f_normalize(normal); }
// clear color
Vec3f color = { 0 };
// accumulate lighting
f32 weight = 1.0f;
u8 contribution = 0;
for (LELight* light : sActiveLights) {
le_calculate_light_contribution(*light, pos, normal, lightIntensityScalar, color, weight, contribution);
if (contribution == sMaxLightsPerVertex) { break; }
}
// tone map and output
le_tone_map(out, gLEAmbientColor, color, weight);
}
C_FIELD void le_calculate_lighting_dir(Vec3f pos, VEC_OUT Vec3f out) {
Vec3f lightingDir = { 0, 0, 0 };
s16 count = 1;
for (LELight* light : sActiveLights) {
f32 diffX = light->pos[0] - pos[0];
f32 diffY = light->pos[1] - pos[1];
f32 diffZ = light->pos[2] - pos[2];
f32 dist = (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ);
f32 radius = light->radius * light->radius;
if (dist > radius) { continue; }
Vec3f dir = {
pos[0] - light->pos[0],
pos[1] - light->pos[1],
pos[2] - light->pos[2],
};
vec3f_normalize(dir);
f32 intensity = (1 - (dist / radius)) * light->intensity;
lightingDir[0] += dir[0] * intensity;
lightingDir[1] += dir[1] * intensity;
lightingDir[2] += dir[2] * intensity;
count++;
}
out[0] = lightingDir[0] / (f32)(count);
out[1] = lightingDir[1] / (f32)(count);
out[2] = lightingDir[2] / (f32)(count);
vec3f_normalize(out);
}
C_FIELD s16 le_add_light(f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, f32 radius, f32 intensity) {
if (sLightPool.size() >= LE_MAX_LIGHTS) {
LOG_LUA_LINE("LE light count cannot exceed %d lights!", LE_MAX_LIGHTS);
return -1;
}
LELight newLight;
newLight.id = ++sLightID;
newLight.pos[0] = x;
newLight.pos[1] = y;
newLight.pos[2] = z;
newLight.color[0] = r;
newLight.color[1] = g;
newLight.color[2] = b;
newLight.radius = radius;
newLight.intensity = intensity;
newLight.useSurfaceNormals = true;
sLightPool.push_back(newLight);
le_update_active_lights();
sEnabled = true;
return sLightID;
}
C_FIELD void le_remove_light(s16 id) {
if (id < 0) { return; }
auto it = std::find_if(sLightPool.begin(), sLightPool.end(),
[id](const LELight& light) {
return light.id == id;
}
);
if (it != sLightPool.end()) {
sLightPool.erase(it);
}
le_update_active_lights();
}
C_FIELD s16 le_get_light_count(void) {
return sLightPool.size();
}
C_FIELD bool le_light_exists(s16 id) {
if (id < 0) { return false; }
return std::any_of(sLightPool.begin(), sLightPool.end(),
[id](const LELight& light) {
return light.id == id;
}
);
}
static LELight* le_find_light(s16 id) {
if (id < 0) { return nullptr; }
auto it = std::find_if(sLightPool.begin(), sLightPool.end(),
[id](const LELight& light) {
return light.id == id;
}
);
// kinda cursed syntax but it works
return (it != sLightPool.end()) ? &(*it) : nullptr;
}
C_FIELD void le_get_light_pos(s16 id, VEC_OUT Vec3f out) {
if (id < 0) { return; }
if (auto* light = le_find_light(id)) {
vec3f_set(out, light->pos[0], light->pos[1], light->pos[2]);
}
}
C_FIELD void le_set_light_pos(s16 id, f32 x, f32 y, f32 z) {
if (id < 0) { return; }
if (auto* light = le_find_light(id)) {
light->pos[0] = x;
light->pos[1] = y;
light->pos[2] = z;
}
}
C_FIELD void le_get_light_color(s16 id, VEC_OUT Color out) {
if (id < 0) { return; }
if (auto* light = le_find_light(id)) {
color_set(out, light->color[0], light->color[1], light->color[2]);
}
}
C_FIELD void le_set_light_color(s16 id, u8 r, u8 g, u8 b) {
if (id < 0) { return; }
if (auto* light = le_find_light(id)) {
light->color[0] = r;
light->color[1] = g;
light->color[2] = b;
}
}
C_FIELD f32 le_get_light_radius(s16 id) {
if (id < 0) { return 0.0f; }
if (auto* light = le_find_light(id)) {
return light->radius;
}
return 0.0f;
}
C_FIELD void le_set_light_radius(s16 id, f32 radius) {
if (id < 0) { return; }
if (auto* light = le_find_light(id)) {
light->radius = radius;
}
le_update_active_lights();
}
C_FIELD f32 le_get_light_intensity(s16 id) {
if (id < 0) { return 0.0f; }
if (auto* light = le_find_light(id)) {
return light->intensity;
}
return 0.0f;
}
C_FIELD void le_set_light_intensity(s16 id, f32 intensity) {
if (id < 0) { return; }
if (auto* light = le_find_light(id)) {
light->intensity = intensity;
}
le_update_active_lights();
}
C_FIELD bool le_get_light_use_surface_normals(s16 id) {
if (id < 0) { return false; }
if (auto* light = le_find_light(id)) {
return light->useSurfaceNormals;
}
return false;
}
C_FIELD void le_set_light_use_surface_normals(s16 id, bool useSurfaceNormals) {
if (id < 0) { return; }
if (auto* light = le_find_light(id)) {
light->useSurfaceNormals = useSurfaceNormals;
}
}
void le_clear(void) {
sLightPool.clear();
sLightID = -1;
color_set(gLEAmbientColor, 127, 127, 127);
}
void le_shutdown(void) {
sEnabled = false;
sMode = LE_MODE_AFFECT_ALL_SHADED_AND_COLORED;
sToneMapping = LE_TONE_MAPPING_WEIGHTED;
sMaxLightsPerVertex = 4;
le_clear();
}

View file

@ -1,9 +1,12 @@
#ifndef LIGHTING_ENGINE_H
#define LIGHTING_ENGINE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "types.h"
#define LE_MAX_LIGHTS 512
#define LE_MAX_LIGHTS 1024
enum LEMode {
LE_MODE_AFFECT_ALL_SHADED_AND_COLORED,
@ -32,8 +35,10 @@ void le_set_tone_mapping(enum LEToneMapping toneMapping);
void le_get_ambient_color(VEC_OUT Color out);
/* |description|Sets the lighting engine ambient color|descriptionEnd| */
void le_set_ambient_color(u8 r, u8 g, u8 b);
/* |description|Sets the max amount of lights that can affect a vertex|descriptionEnd| */
void le_set_max_lights_per_vertex(u8 count);
void le_calculate_vertex_lighting(Vtx_t* v, Vec3f pos, VEC_OUT Color out);
void le_calculate_vertex_lighting(const Vtx_t* v, Vec3f pos, VEC_OUT Color out);
/* |description|Calculates the lighting with `lightIntensityScalar` at a position and outputs the color in `out`|descriptionEnd|*/
void le_calculate_lighting_color(Vec3f pos, VEC_OUT Color out, f32 lightIntensityScalar);
/* |description|Calculates the lighting with `lightIntensityScalar` at a position and with a normal and outputs the color in `out`|descriptionEnd|*/
@ -71,4 +76,8 @@ void le_set_light_use_surface_normals(s16 id, bool useSurfaceNormals);
void le_clear(void);
void le_shutdown(void);
#ifdef __cplusplus
}
#endif
#endif // LIGHTING_ENGINE_H

View file

@ -892,13 +892,14 @@ static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, cons
}
// if lighting engine is enabled and either we want to affect all shaded surfaces or the lighting engine geometry mode is on
if (le_is_enabled() && ((le_get_mode() != LE_MODE_AFFECT_ONLY_GEOMETRY_MODE) || (rsp.geometry_mode & G_LIGHTING_ENGINE_EXT))) {
if (le_is_enabled() && luaVertexColor && ((le_get_mode() != LE_MODE_AFFECT_ONLY_GEOMETRY_MODE) || (rsp.geometry_mode & G_LIGHTING_ENGINE_EXT))) {
Color color = { gLEAmbientColor[0], gLEAmbientColor[1], gLEAmbientColor[2] };
CTX_BEGIN(CTX_LIGHTING);
Vec3f vpos = { v->ob[0], v->ob[1], v->ob[2] };
Vec3f vnormal = { nx, ny, nz };
CTX_BEGIN(CTX_LIGHTING);
// transform vpos and vnormal to world space
gfx_local_to_world_space(vpos, vnormal);
@ -913,10 +914,11 @@ static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, cons
// if lighting engine is enabled and we should affect all vertex colored surfaces or the lighting engine geometry mode is on
} else if (le_is_enabled() && !(rsp.geometry_mode & G_LIGHT_MAP_EXT) && (affectAllVertexColored || (rsp.geometry_mode & G_LIGHTING_ENGINE_EXT))) {
Color color = { gLEAmbientColor[0], gLEAmbientColor[1], gLEAmbientColor[2] };
CTX_BEGIN(CTX_LIGHTING);
Vec3f vpos = { v->ob[0], v->ob[1], v->ob[2] };
CTX_BEGIN(CTX_LIGHTING);
// transform vpos to world space
gfx_local_to_world_space(vpos, NULL);
@ -927,7 +929,7 @@ static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, cons
if (affectAllVertexColored && !(rsp.geometry_mode & G_LIGHTING_ENGINE_EXT)) {
le_calculate_lighting_color(vpos, color, 1.0f);
} else {
le_calculate_vertex_lighting((Vtx_t*)v, vpos, color);
le_calculate_vertex_lighting(v, vpos, color);
}
CTX_END(CTX_LIGHTING);

View file

@ -1794,7 +1794,7 @@ char gSmluaConstants[] = ""
"HUD_DISPLAY_FLAG_EMPHASIZE_POWER=0x8000\n"
"HUD_DISPLAY_NONE=0x0000\n"
"HUD_DISPLAY_DEFAULT=HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_COIN_COUNT | HUD_DISPLAY_FLAG_STAR_COUNT | HUD_DISPLAY_FLAG_CAMERA_AND_POWER | HUD_DISPLAY_FLAG_CAMERA | HUD_DISPLAY_FLAG_POWER | HUD_DISPLAY_FLAG_KEYS | HUD_DISPLAY_FLAG_UNKNOWN_0020\n"
"LE_MAX_LIGHTS=512\n"
"LE_MAX_LIGHTS=1024\n"
"LE_MODE_AFFECT_ALL_SHADED_AND_COLORED=0\n"
"LE_MODE_AFFECT_ALL_SHADED=1\n"
"LE_MODE_AFFECT_ONLY_GEOMETRY_MODE=2\n"

View file

@ -15509,6 +15509,23 @@ int smlua_func_le_set_ambient_color(lua_State* L) {
return 1;
}
int smlua_func_le_set_max_lights_per_vertex(lua_State* L) {
if (L == NULL) { return 0; }
int top = lua_gettop(L);
if (top != 1) {
LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "le_set_max_lights_per_vertex", 1, top);
return 0;
}
u8 count = smlua_to_integer(L, 1);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "le_set_max_lights_per_vertex"); return 0; }
le_set_max_lights_per_vertex(count);
return 1;
}
int smlua_func_le_calculate_lighting_color(lua_State* L) {
if (L == NULL) { return 0; }
@ -37539,6 +37556,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "le_set_tone_mapping", smlua_func_le_set_tone_mapping);
smlua_bind_function(L, "le_get_ambient_color", smlua_func_le_get_ambient_color);
smlua_bind_function(L, "le_set_ambient_color", smlua_func_le_set_ambient_color);
smlua_bind_function(L, "le_set_max_lights_per_vertex", smlua_func_le_set_max_lights_per_vertex);
smlua_bind_function(L, "le_calculate_lighting_color", smlua_func_le_calculate_lighting_color);
smlua_bind_function(L, "le_calculate_lighting_color_with_normal", smlua_func_le_calculate_lighting_color_with_normal);
smlua_bind_function(L, "le_calculate_lighting_dir", smlua_func_le_calculate_lighting_dir);

View file

@ -1,11 +1,11 @@
#ifndef MOD_STORAGE_H
#define MOD_STORAGE_H
#include <PR/ultratypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <PR/ultratypes.h>
#include "pc/lua/smlua_utils.h"
#define MAX_KEYS 4096