diff --git a/autogen/convert_constants.py b/autogen/convert_constants.py
index 565cc4efb..db338d9fb 100644
--- a/autogen/convert_constants.py
+++ b/autogen/convert_constants.py
@@ -51,6 +51,7 @@ in_files = [
"src/game/player_palette.h",
"src/pc/network/lag_compensation.h",
"src/pc/djui/djui_panel_menu.h",
+ "src/engine/lighting_engine.h",
"include/PR/gbi.h"
]
diff --git a/autogen/lua_definitions/constants.lua b/autogen/lua_definitions/constants.lua
index 285ebe9fb..ceca13102 100644
--- a/autogen/lua_definitions/constants.lua
+++ b/autogen/lua_definitions/constants.lua
@@ -3608,6 +3608,24 @@ HUD_DISPLAY_DEFAULT = HUD_DISPLAY_FLAG_LIVES | HUD_DISPLAY_FLAG_CO
--- | `HUD_DISPLAY_NONE`
--- | `HUD_DISPLAY_DEFAULT`
+LE_MODE_AFFECT_ALL_SHADED = 0 --- @type LEMode
+LE_MODE_AFFECT_ONLY_GEOMETRY_MODE = 1 --- @type LEMode
+
+--- @alias LEMode
+--- | `LE_MODE_AFFECT_ALL_SHADED`
+--- | `LE_MODE_AFFECT_ONLY_GEOMETRY_MODE`
+
+LE_TONE_MAPPING_TOTAL_WEIGHTED = 0 --- @type LEToneMapping
+LE_TONE_MAPPING_WEIGHTED = 1 --- @type LEToneMapping
+LE_TONE_MAPPING_CLAMP = 2 --- @type LEToneMapping
+LE_TONE_MAPPING_REINHARD = 3 --- @type LEToneMapping
+
+--- @alias LEToneMapping
+--- | `LE_TONE_MAPPING_TOTAL_WEIGHTED`
+--- | `LE_TONE_MAPPING_WEIGHTED`
+--- | `LE_TONE_MAPPING_CLAMP`
+--- | `LE_TONE_MAPPING_REINHARD`
+
MARIO_ANIM_SLOW_LEDGE_GRAB = 0 --- @type MarioAnimID
MARIO_ANIM_FALL_OVER_BACKWARDS = 1 --- @type MarioAnimID
MARIO_ANIM_BACKWARD_AIR_KB = 2 --- @type MarioAnimID
diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua
index 72671d418..e9c5d54ff 100644
--- a/autogen/lua_definitions/functions.lua
+++ b/autogen/lua_definitions/functions.lua
@@ -5022,6 +5022,30 @@ function lvl_set_current_level(param, levelNum)
-- ...
end
+--- @param mode LEMode
+--- Sets the lighting engine mode to `mode`
+function le_set_mode(mode)
+ -- ...
+end
+
+--- @return LEMode
+--- Gets the lighting engine mode
+function le_get_mode()
+ -- ...
+end
+
+--- @param toneMapping LEToneMapping
+--- Sets the lighting engine's tone mapping mode to `toneMapping`
+function le_set_tone_mapping(toneMapping)
+ -- ...
+end
+
+--- @return boolean
+--- Gets whether the lighting engine has been enabled or not. It becomes enabled once a light is added.
+function le_is_enabled()
+ -- ...
+end
+
--- @param pos Vec3f
--- @param out Color
--- @param lightIntensityScalar number
@@ -5030,6 +5054,15 @@ function le_calculate_lighting_color(pos, out, lightIntensityScalar)
-- ...
end
+--- @param pos Vec3f
+--- @param normal Vec3f
+--- @param out Color
+--- @param lightIntensityScalar number
+--- Calculates the lighting with `lightIntensityScalar` at a position and with a normal and outputs the color in `out`
+function le_calculate_lighting_color_with_normal(pos, normal, out, lightIntensityScalar)
+ -- ...
+end
+
--- @param pos Vec3f
--- @param out Vec3f
--- Calculates the lighting direction from a position and outputs the result in `out`
@@ -5103,6 +5136,13 @@ function le_set_light_intensity(id, intensity)
-- ...
end
+--- @param id integer
+--- @param useSurfaceNormals boolean
+--- Sets whether a lighting engine point light will use a surface's normals to determine its brightness with `useSurfaceNormals`
+function le_set_light_use_surface_normals(id, useSurfaceNormals)
+ -- ...
+end
+
--- @param m MarioState
--- @return integer
--- Checks if Mario's current animation has reached its final frame (i.e., the last valid frame in the animation). Useful for deciding when to transition out of an animation-driven action
@@ -6589,11 +6629,19 @@ end
--- @param dest Mat4
--- @param src Mat4
---- Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space
+--- Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space. The `src` matrix *must* be affine!
function mtxf_inverse(dest, src)
-- ...
end
+--- @param dest Mat4
+--- @param src Mat4
+--- @return boolean
+--- Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space. Returns `false` if the inversion failed.
+function mtxf_inverse_non_affine(dest, src)
+ -- ...
+end
+
--- @param dest Vec3f
--- @param objMtx Mat4
--- @param camMtx Mat4
diff --git a/developer/compile.sh b/developer/compile.sh
index 85af76929..1dc460bb8 100755
--- a/developer/compile.sh
+++ b/developer/compile.sh
@@ -13,4 +13,4 @@ if [ ! -f "$FILE" ]; then
FILE=./build/us_pc/sm64coopdx
fi
-$FILE &
+$FILE --console --server 7777 &
diff --git a/docs/lua/constants.md b/docs/lua/constants.md
index 5c3b1385e..0cdb90306 100644
--- a/docs/lua/constants.md
+++ b/docs/lua/constants.md
@@ -40,6 +40,9 @@
- [level_update.h](#level_updateh)
- [enum MarioSpawnType](#enum-MarioSpawnType)
- [enum HUDDisplayFlag](#enum-HUDDisplayFlag)
+- [lighting_engine.h](#lighting_engineh)
+ - [enum LEMode](#enum-LEMode)
+ - [enum LEToneMapping](#enum-LEToneMapping)
- [mario_animation_ids.h](#mario_animation_idsh)
- [enum MarioAnimID](#enum-MarioAnimID)
- [enum CharacterAnimID](#enum-CharacterAnimID)
@@ -1619,6 +1622,26 @@
+## [lighting_engine.h](#lighting_engine.h)
+
+### [enum LEMode](#LEMode)
+| Identifier | Value |
+| :--------- | :---- |
+| LE_MODE_AFFECT_ALL_SHADED | 0 |
+| LE_MODE_AFFECT_ONLY_GEOMETRY_MODE | 1 |
+
+### [enum LEToneMapping](#LEToneMapping)
+| Identifier | Value |
+| :--------- | :---- |
+| LE_TONE_MAPPING_TOTAL_WEIGHTED | 0 |
+| LE_TONE_MAPPING_WEIGHTED | 1 |
+| LE_TONE_MAPPING_CLAMP | 2 |
+| LE_TONE_MAPPING_REINHARD | 3 |
+
+[:arrow_up_small:](#)
+
+
+
## [mario_animation_ids.h](#mario_animation_ids.h)
### [enum MarioAnimID](#MarioAnimID)
diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md
index b65f95308..789ab7b81 100644
--- a/docs/lua/functions-3.md
+++ b/docs/lua/functions-3.md
@@ -6633,6 +6633,94 @@ Sets the level number and handles the act select screen. `param` is used for ove
+## [le_set_mode](#le_set_mode)
+
+### Description
+Sets the lighting engine mode to `mode`
+
+### Lua Example
+`le_set_mode(mode)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| mode | [enum LEMode](constants.md#enum-LEMode) |
+
+### Returns
+- None
+
+### C Prototype
+`void le_set_mode(enum LEMode mode);`
+
+[:arrow_up_small:](#)
+
+
+
+## [le_get_mode](#le_get_mode)
+
+### Description
+Gets the lighting engine mode
+
+### Lua Example
+`local enumValue = le_get_mode()`
+
+### Parameters
+- None
+
+### Returns
+[enum LEMode](constants.md#enum-LEMode)
+
+### C Prototype
+`enum LEMode le_get_mode(void);`
+
+[:arrow_up_small:](#)
+
+
+
+## [le_set_tone_mapping](#le_set_tone_mapping)
+
+### Description
+Sets the lighting engine's tone mapping mode to `toneMapping`
+
+### Lua Example
+`le_set_tone_mapping(toneMapping)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| toneMapping | [enum LEToneMapping](constants.md#enum-LEToneMapping) |
+
+### Returns
+- None
+
+### C Prototype
+`void le_set_tone_mapping(enum LEToneMapping toneMapping);`
+
+[:arrow_up_small:](#)
+
+
+
+## [le_is_enabled](#le_is_enabled)
+
+### Description
+Gets whether the lighting engine has been enabled or not. It becomes enabled once a light is added.
+
+### Lua Example
+`local booleanValue = le_is_enabled()`
+
+### Parameters
+- None
+
+### Returns
+- `boolean`
+
+### C Prototype
+`bool le_is_enabled(void);`
+
+[:arrow_up_small:](#)
+
+
+
## [le_calculate_lighting_color](#le_calculate_lighting_color)
### Description
@@ -6658,6 +6746,32 @@ Calculates the lighting with `lightIntensityScalar` at a position and outputs th
+## [le_calculate_lighting_color_with_normal](#le_calculate_lighting_color_with_normal)
+
+### Description
+Calculates the lighting with `lightIntensityScalar` at a position and with a normal and outputs the color in `out`
+
+### Lua Example
+`le_calculate_lighting_color_with_normal(pos, normal, out, lightIntensityScalar)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| pos | [Vec3f](structs.md#Vec3f) |
+| normal | [Vec3f](structs.md#Vec3f) |
+| out | [Color](structs.md#Color) |
+| lightIntensityScalar | `number` |
+
+### Returns
+- None
+
+### C Prototype
+`void le_calculate_lighting_color_with_normal(Vec3f pos, Vec3f normal, OUT Color out, f32 lightIntensityScalar);`
+
+[:arrow_up_small:](#)
+
+
+
## [le_calculate_lighting_dir](#le_calculate_lighting_dir)
### Description
@@ -6879,6 +6993,30 @@ Sets a lighting engine point light's `intensity`
[:arrow_up_small:](#)
+
+
+## [le_set_light_use_surface_normals](#le_set_light_use_surface_normals)
+
+### Description
+Sets whether a lighting engine point light will use a surface's normals to determine its brightness with `useSurfaceNormals`
+
+### Lua Example
+`le_set_light_use_surface_normals(id, useSurfaceNormals)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| id | `integer` |
+| useSurfaceNormals | `boolean` |
+
+### Returns
+- None
+
+### C Prototype
+`void le_set_light_use_surface_normals(s32 id, bool useSurfaceNormals);`
+
+[:arrow_up_small:](#)
+
---
diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md
index e21c1fa09..636e195d5 100644
--- a/docs/lua/functions-4.md
+++ b/docs/lua/functions-4.md
@@ -4803,7 +4803,7 @@ Rotates the matrix `mtx` in the XY plane by the given `angle`. Rotating in the X
## [mtxf_inverse](#mtxf_inverse)
### Description
-Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space
+Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space. The `src` matrix *must* be affine!
### Lua Example
`mtxf_inverse(dest, src)`
@@ -4824,6 +4824,30 @@ Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Ap
+## [mtxf_inverse_non_affine](#mtxf_inverse_non_affine)
+
+### Description
+Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space. Returns `false` if the inversion failed.
+
+### Lua Example
+`local booleanValue = mtxf_inverse_non_affine(dest, src)`
+
+### Parameters
+| Field | Type |
+| ----- | ---- |
+| dest | [Mat4](structs.md#Mat4) |
+| src | [Mat4](structs.md#Mat4) |
+
+### Returns
+- `boolean`
+
+### C Prototype
+`bool mtxf_inverse_non_affine(OUT Mat4 dest, Mat4 src);`
+
+[:arrow_up_small:](#)
+
+
+
## [get_pos_from_transform_mtx](#get_pos_from_transform_mtx)
### Description
diff --git a/docs/lua/functions.md b/docs/lua/functions.md
index 3d4ded489..7ad8bc456 100644
--- a/docs/lua/functions.md
+++ b/docs/lua/functions.md
@@ -964,7 +964,12 @@
- lighting_engine.h
+ - [le_set_mode](functions-3.md#le_set_mode)
+ - [le_get_mode](functions-3.md#le_get_mode)
+ - [le_set_tone_mapping](functions-3.md#le_set_tone_mapping)
+ - [le_is_enabled](functions-3.md#le_is_enabled)
- [le_calculate_lighting_color](functions-3.md#le_calculate_lighting_color)
+ - [le_calculate_lighting_color_with_normal](functions-3.md#le_calculate_lighting_color_with_normal)
- [le_calculate_lighting_dir](functions-3.md#le_calculate_lighting_dir)
- [le_add_light](functions-3.md#le_add_light)
- [le_remove_light](functions-3.md#le_remove_light)
@@ -974,6 +979,7 @@
- [le_set_light_color](functions-3.md#le_set_light_color)
- [le_set_light_radius](functions-3.md#le_set_light_radius)
- [le_set_light_intensity](functions-3.md#le_set_light_intensity)
+ - [le_set_light_use_surface_normals](functions-3.md#le_set_light_use_surface_normals)
@@ -1217,6 +1223,7 @@
- [mtxf_mul_vec3s](functions-4.md#mtxf_mul_vec3s)
- [mtxf_rotate_xy](functions-4.md#mtxf_rotate_xy)
- [mtxf_inverse](functions-4.md#mtxf_inverse)
+ - [mtxf_inverse_non_affine](functions-4.md#mtxf_inverse_non_affine)
- [get_pos_from_transform_mtx](functions-4.md#get_pos_from_transform_mtx)
diff --git a/include/PR/gbi_extension.h b/include/PR/gbi_extension.h
index 2382267e3..fb08a5a0d 100644
--- a/include/PR/gbi_extension.h
+++ b/include/PR/gbi_extension.h
@@ -19,6 +19,8 @@
#define G_TEXADDR_DJUI 0x13
#define G_EXECUTE_DJUI 0xdd
+#define G_MTX_INVERSE_CAMERA_EXT 0x08
+
#define gsSPTextureAddrDjui(c) \
{{ \
(_SHIFTL(G_TEXADDR_DJUI,24,8)|_SHIFTL(~(u32)(c),0,24)),(u32)(0) \
diff --git a/src/engine/lighting_engine.c b/src/engine/lighting_engine.c
index 9c3af3f10..9f7d785f2 100644
--- a/src/engine/lighting_engine.c
+++ b/src/engine/lighting_engine.c
@@ -5,11 +5,13 @@
#include "data/dynos_cmap.cpp.h"
#define LE_MAX_LIGHTS 256
-#define LE_TOTAL_WEIGHTED_LIGHTING
-static Color sAmbientColor;
+static Color sAmbientColor = { 127, 127, 127 };
static void* sLights = NULL;
static s32 sLightID = 0;
+static enum LEMode sMode = LE_MODE_AFFECT_ALL_SHADED;
+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;
@@ -17,82 +19,156 @@ static inline void color_set(Color color, u8 r, u8 g, u8 b) {
color[2] = b;
}
-void le_calculate_vertex_lighting(Vtx_t* v, OUT Color out) {
- if (sLights == NULL) { return; }
+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;
+}
-#ifdef LE_TOTAL_WEIGHTED_LIGHTING
- f32 r = v->cn[0] * (sAmbientColor[0] / 255.0f);
- f32 g = v->cn[1] * (sAmbientColor[1] / 255.0f);
- f32 b = v->cn[2] * (sAmbientColor[2] / 255.0f);
-#else
- f32 r = 0;
- f32 g = 0;
- f32 b = 0;
-#endif
- f32 weight = 1.0f;
- for (struct LELight* light = hmap_begin(sLights); light != NULL; light = hmap_next(sLights)) {
- f32 diffX = light->posX - v->ob[0];
- f32 diffY = light->posY - v->ob[1];
- f32 diffZ = light->posZ - v->ob[2];
- f32 dist = (diffX * diffX) + (diffY * diffY) + (diffZ * diffZ);
- f32 radius = light->radius * light->radius;
- if (dist > radius) { continue; }
+void le_set_mode(enum LEMode mode) {
+ sMode = mode;
+}
- f32 brightness = (1 - (dist / radius)) * light->intensity;
- r += light->colorR * brightness;
- g += light->colorG * brightness;
- b += light->colorB * brightness;
- weight += brightness;
+enum LEMode le_get_mode(void) {
+ return sMode;
+}
+
+void le_set_tone_mapping(enum LEToneMapping toneMapping) {
+ sToneMapping = toneMapping;
+}
+
+static inline void le_tone_map_total_weighted(OUT Color out, Color in_ambient, Vec3f in_color, float weight) {
+ out[0] = clamp((in_ambient[0] + in_color[0]) / weight, 0, 255);
+ out[1] = clamp((in_ambient[1] + in_color[1]) / weight, 0, 255);
+ out[2] = clamp((in_ambient[2] + in_color[2]) / weight, 0, 255);
+}
+
+static inline void le_tone_map_weighted(OUT Color out, Color in_ambient, Vec3f in_color, float weight) {
+ out[0] = clamp(in_ambient[0] + (in_color[0] / weight), 0, 255);
+ out[1] = clamp(in_ambient[1] + (in_color[1] / weight), 0, 255);
+ out[2] = clamp(in_ambient[2] + (in_color[2] / weight), 0, 255);
+}
+
+static inline void le_tone_map_clamp(OUT Color out, Color in_ambient, Vec3f in_color) {
+ out[0] = clamp(in_ambient[0] + in_color[0], 0, 255);
+ out[1] = clamp(in_ambient[1] + in_color[1], 0, 255);
+ out[2] = clamp(in_ambient[2] + in_color[2], 0, 255);
+}
+
+static inline void le_tone_map_reinhard(OUT Color out, Color in_ambient, Vec3f in_color) {
+ in_color[0] += in_ambient[0];
+ in_color[1] += in_ambient[1];
+ in_color[2] += in_ambient[2];
+
+ out[0] = clamp((in_color[0] / (in_color[0] + 255.0f)) * 255.0f, 0, 255);
+ out[1] = clamp((in_color[1] / (in_color[1] + 255.0f)) * 255.0f, 0, 255);
+ out[2] = clamp((in_color[2] / (in_color[2] + 255.0f)) * 255.0f, 0, 255);
+}
+
+static inline void le_tone_map(OUT Color out, Color in_ambient, Vec3f in_color, float weight) {
+ switch (sToneMapping) {
+ case LE_TONE_MAPPING_TOTAL_WEIGHTED: le_tone_map_total_weighted(out, in_ambient, in_color, weight); break;
+ case LE_TONE_MAPPING_WEIGHTED: le_tone_map_weighted(out, in_ambient, in_color, weight); break;
+ case LE_TONE_MAPPING_CLAMP: le_tone_map_clamp(out, in_ambient, in_color); break;
+ case LE_TONE_MAPPING_REINHARD: le_tone_map_reinhard(out, in_ambient, in_color); break;
+ }
+}
+
+static inline void le_calculate_light_contribution(struct LELight* light, Vec3f pos, Vec3f normal, f32 lightIntensityScalar, OUT Vec3f out_color, OUT 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;
}
-#ifdef LE_TOTAL_WEIGHTED_LIGHTING
- out[0] = min(r / weight, 255);
- out[1] = min(g / weight, 255);
- out[2] = min(b / weight, 255);
-#else
- out[0] = min((v->cn[0] * (sAmbientColor[0] / 255.0f)) + (r / weight), 255);
- out[1] = min((v->cn[1] * (sAmbientColor[1] / 255.0f)) + (g / weight), 255);
- out[2] = min((v->cn[2] * (sAmbientColor[2] / 255.0f)) + (b / weight), 255);
-#endif
+ // 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, OUT Color out) {
+ if (sLights == NULL) { return; }
+
+ // clear color
+ Vec3f color = { 0 };
+
+ // accumulate lighting
+ f32 weight = 1.0f;
+ for (struct LELight* light = hmap_begin(sLights); light != NULL; light = hmap_next(sLights)) {
+ le_calculate_light_contribution(light, pos, NULL, 1, color, &weight);
+ }
+
+ // tone map and output
+ Color vtxAmbient = {
+ v->cn[0] * (sAmbientColor[0] / 255.0f),
+ v->cn[1] * (sAmbientColor[1] / 255.0f),
+ v->cn[2] * (sAmbientColor[2] / 255.0f),
+ };
+ le_tone_map(out, vtxAmbient, color, weight);
}
void le_calculate_lighting_color(Vec3f pos, OUT Color out, f32 lightIntensityScalar) {
if (sLights == NULL) { return; }
-#ifdef LE_TOTAL_WEIGHTED_LIGHTING
- f32 r = sAmbientColor[0];
- f32 g = sAmbientColor[1];
- f32 b = sAmbientColor[2];
-#else
- f32 r = 0;
- f32 g = 0;
- f32 b = 0;
-#endif
+ // clear color
+ Vec3f color = { 0 };
+
+ // accumulate lighting
f32 weight = 1.0f;
for (struct LELight* light = hmap_begin(sLights); light != NULL; light = hmap_next(sLights)) {
- 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; }
-
- f32 brightness = (1 - (dist / radius)) * light->intensity * lightIntensityScalar;
- r += light->colorR * brightness;
- g += light->colorG * brightness;
- b += light->colorB * brightness;
- weight += brightness;
+ le_calculate_light_contribution(light, pos, NULL, lightIntensityScalar, color, &weight);
}
-#ifdef LE_TOTAL_WEIGHTED_LIGHTING
- out[0] = min(r / weight, 255);
- out[1] = min(g / weight, 255);
- out[2] = min(b / weight, 255);
-#else
- out[0] = min(sAmbientColor[0] + (r / weight), 255);
- out[1] = min(sAmbientColor[1] + (g / weight), 255);
- out[2] = min(sAmbientColor[2] + (b / weight), 255);
-#endif
+ // tone map and output
+ le_tone_map(out, sAmbientColor, color, weight);
+}
+
+void le_calculate_lighting_color_with_normal(Vec3f pos, Vec3f normal, OUT Color out, f32 lightIntensityScalar) {
+ if (sLights == NULL) { return; }
+
+ // normalize normal
+ if (normal) { vec3f_normalize(normal); }
+
+ // clear color
+ Vec3f color = { 0 };
+
+ // accumulate lighting
+ f32 weight = 1.0f;
+ for (struct LELight* light = hmap_begin(sLights); light != NULL; light = hmap_next(sLights)) {
+ le_calculate_light_contribution(light, pos, normal, lightIntensityScalar, color, &weight);
+ }
+
+ // tone map and output
+ le_tone_map(out, sAmbientColor, color, weight);
}
void le_calculate_lighting_dir(Vec3f pos, OUT Vec3f out) {
@@ -145,7 +221,10 @@ s32 le_add_light(f32 x, f32 y, f32 z, u8 r, u8 g, u8 b, f32 radius, f32 intensit
light->colorB = b;
light->radius = radius;
light->intensity = intensity;
+ light->useSurfaceNormals = true;
hmap_put(sLights, ++sLightID, light);
+
+ sEnabled = true;
return sLightID;
}
@@ -163,6 +242,7 @@ s32 le_get_light_count(void) {
void le_set_ambient_color(u8 r, u8 g, u8 b) {
color_set(sAmbientColor, r, g, b);
+ sEnabled = true;
}
void le_set_light_pos(s32 id, f32 x, f32 y, f32 z) {
@@ -201,6 +281,14 @@ void le_set_light_intensity(s32 id, f32 intensity) {
light->intensity = intensity;
}
+void le_set_light_use_surface_normals(s32 id, bool useSurfaceNormals) {
+ if (sLights == NULL || id <= 0) { return; }
+
+ struct LELight* light = hmap_get(sLights, id);
+ if (light == NULL) { return; }
+ light->useSurfaceNormals = useSurfaceNormals;
+}
+
void le_clear(void) {
if (sLights == NULL) { return; }
@@ -209,14 +297,17 @@ void le_clear(void) {
}
hmap_clear(sLights);
sLightID = 0;
- sAmbientColor[0] = 0;
- sAmbientColor[1] = 0;
- sAmbientColor[2] = 0;
+ sAmbientColor[0] = 127;
+ sAmbientColor[1] = 127;
+ sAmbientColor[2] = 127;
}
void le_shutdown(void) {
if (sLights == NULL) { return; }
+ sEnabled = false;
+ sMode = LE_MODE_AFFECT_ALL_SHADED;
+ sToneMapping = LE_TONE_MAPPING_WEIGHTED;
le_clear();
hmap_destroy(sLights);
sLights = NULL;
diff --git a/src/engine/lighting_engine.h b/src/engine/lighting_engine.h
index 72540cc31..e5cc842b1 100644
--- a/src/engine/lighting_engine.h
+++ b/src/engine/lighting_engine.h
@@ -13,11 +13,35 @@ struct LELight
u8 colorB;
f32 radius;
f32 intensity;
+ bool useSurfaceNormals;
};
-void le_calculate_vertex_lighting(Vtx_t* v, OUT Color out);
+enum LEMode {
+ LE_MODE_AFFECT_ALL_SHADED,
+ LE_MODE_AFFECT_ONLY_GEOMETRY_MODE,
+};
+
+enum LEToneMapping {
+ LE_TONE_MAPPING_TOTAL_WEIGHTED,
+ LE_TONE_MAPPING_WEIGHTED,
+ LE_TONE_MAPPING_CLAMP,
+ LE_TONE_MAPPING_REINHARD,
+};
+
+/* |description|Sets the lighting engine mode to `mode`|descriptionEnd|*/
+void le_set_mode(enum LEMode mode);
+/* |description|Gets the lighting engine mode|descriptionEnd|*/
+enum LEMode le_get_mode(void);
+/* |description|Sets the lighting engine's tone mapping mode to `toneMapping`|descriptionEnd|*/
+void le_set_tone_mapping(enum LEToneMapping toneMapping);
+/* |description|Gets whether the lighting engine has been enabled or not. It becomes enabled once a light is added.|descriptionEnd|*/
+bool le_is_enabled(void);
+
+void le_calculate_vertex_lighting(Vtx_t* v, Vec3f pos, 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, 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|*/
+void le_calculate_lighting_color_with_normal(Vec3f pos, Vec3f normal, OUT Color out, f32 lightIntensityScalar);
/* |description|Calculates the lighting direction from a position and outputs the result in `out`|descriptionEnd| */
void le_calculate_lighting_dir(Vec3f pos, OUT Vec3f out);
/* |description|Adds a lighting engine point light at `x`, `y`, `z` with color `r`, `g`, `b` and `radius` with `intensity`|descriptionEnd| */
@@ -36,6 +60,8 @@ void le_set_light_color(s32 id, u8 r, u8 g, u8 b);
void le_set_light_radius(s32 id, f32 radius);
/* |description|Sets a lighting engine point light's `intensity`|descriptionEnd| */
void le_set_light_intensity(s32 id, f32 intensity);
+/* |description|Sets whether a lighting engine point light will use a surface's normals to determine its brightness with `useSurfaceNormals`|descriptionEnd| */
+void le_set_light_use_surface_normals(s32 id, bool useSurfaceNormals);
void le_clear(void);
void le_shutdown(void);
diff --git a/src/engine/math_util.c b/src/engine/math_util.c
index 0cb6231c6..fc3562799 100644
--- a/src/engine/math_util.c
+++ b/src/engine/math_util.c
@@ -781,6 +781,64 @@ OPTIMIZE_O3 void mtxf_inverse(OUT Mat4 dest, Mat4 src) {
mtxf_copy(dest, buf);
}
+/**
+ * Compute the inverse of 'src' and put it into 'dest' but it can be a non-affine matrix.
+ * Obtains the inverse via Gauss-Jordan elimination.
+ */
+OPTIMIZE_O3 bool mtxf_inverse_non_affine(OUT Mat4 dest, Mat4 src) {
+ // augmented matrix [ src | I ]
+ f32 aug[4][8];
+ for (s32 i = 0; i < 4; i++) {
+ for (s32 j = 0; j < 4; j++) {
+ aug[i][j] = src[i][j];
+ aug[i][j + 4] = (i == j) ? 1.0f : 0.0f;
+ }
+ }
+
+ // forward elimination
+ for (s32 k = 0; k < 4; k++) {
+ // find pivot row
+ s32 piv = k;
+ for (s32 i = k + 1; i < 4; i++) {
+ if (fabsf(aug[i][k]) > fabsf(aug[piv][k])) { piv = i; }
+ }
+
+ if (fabsf(aug[piv][k]) < FLT_EPSILON) { return false; }
+
+ // swap pivot row into place
+ if (piv != k) {
+ for (s32 j = 0; j < 8; j++) {
+ f32 tmp = aug[k][j];
+ aug[k][j] = aug[piv][j];
+ aug[piv][j] = tmp;
+ }
+ }
+
+ // scale pivot row to make pivot = 1
+ f32 inv_p = 1.0f / aug[k][k];
+ for (s32 j = k; j < 8; j++) { aug[k][j] *= inv_p; }
+
+ // eliminate below
+ for (s32 i = k+1; i < 4; i++) {
+ f32 f = aug[i][k];
+ for (s32 j = k; j < 8; j++) { aug[i][j] -= f * aug[k][j]; }
+ }
+ }
+
+ // backward substitution
+ for (s32 k = 3; k >= 0; k--) {
+ for (s32 i = 0; i < k; i++) {
+ f32 f = aug[i][k];
+ for (s32 j = k; j < 8; j++) { aug[i][j] -= f * aug[k][j]; }
+ }
+ }
+
+ // copy right half (the inverse) into dest
+ for (s32 i = 0; i < 4; i++) { memcpy(dest[i], &aug[i][4], 4 * sizeof(f32)); }
+
+ return true;
+}
+
/**
* Extract a position given an object's transformation matrix and a camera matrix.
* This is used for determining the world position of the held object: since objMtx
@@ -800,3 +858,4 @@ OPTIMIZE_O3 Vec3fp get_pos_from_transform_mtx(OUT Vec3f dest, Mat4 objMtx, Mat4
return dest;
}
+
diff --git a/src/engine/math_util.h b/src/engine/math_util.h
index 838fa58ce..72ead474d 100644
--- a/src/engine/math_util.h
+++ b/src/engine/math_util.h
@@ -253,10 +253,15 @@ Rotates the matrix `mtx` in the XY plane by the given `angle`. Rotating in the X
OPTIMIZE_O3 void mtxf_rotate_xy(OUT Mat4 mtx, s16 angle);
/* |description|
-Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space
+Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space. The `src` matrix *must* be affine!
|descriptionEnd| */
OPTIMIZE_O3 void mtxf_inverse(OUT Mat4 dest, Mat4 src);
+/* |description|
+Inverts the 4x4 floating-point matrix `src` and stores the inverse in `dest`. Applying the inverse transformation undoes whatever `src` did, returning points back to their original coordinate space. Returns `false` if the inversion failed.
+|descriptionEnd| */
+OPTIMIZE_O3 bool mtxf_inverse_non_affine(OUT Mat4 dest, Mat4 src);
+
/* |description|
Extracts the position (translation component) from the transformation matrix `objMtx` relative to the coordinate system defined by `camMtx` and stores that 3D position in `dest`. This can be used to get the object's coordinates in camera space
|descriptionEnd| */
diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c
index 8b0749e07..0d71ab204 100644
--- a/src/game/rendering_graph_node.c
+++ b/src/game/rendering_graph_node.c
@@ -2,6 +2,7 @@
#include "area.h"
#include "engine/math_util.h"
+#include "engine/lighting_engine.h"
#include "game_init.h"
#include "gfx_dimensions.h"
#include "main.h"
@@ -403,9 +404,12 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) {
gMtxTbl[gMtxTblSize].displayList = currList->displayList;
gMtxTbl[gMtxTblSize++].usingCamSpace = currList->usingCamSpace;
}
+
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformPrev),
G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
+
gSPDisplayList(gDisplayListHead++, currList->displayList);
+
currList = currList->next;
}
}
@@ -609,6 +613,16 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
mtxf_copy(gCamera->mtx, gMatStack[gMatStackIndex]);
}
+ // compute inverse matrix for lighting engine
+ if (le_is_enabled()) {
+ Mat4 invCameraMatrix;
+ if (mtxf_inverse_non_affine(invCameraMatrix, gCamera->mtx)) {
+ Mtx *invMtx = alloc_display_list(sizeof(Mtx));
+ mtxf_to_mtx(invMtx, invCameraMatrix);
+ gSPMatrix(gDisplayListHead++, invMtx, G_MTX_INVERSE_CAMERA_EXT);
+ }
+ }
+
if (node->fnNode.node.children != 0) {
gCurGraphNodeCamera = node;
sUsingCamSpace = TRUE;
diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c
index 483caff2e..59425e67b 100644
--- a/src/pc/gfx/gfx_pc.c
+++ b/src/pc/gfx/gfx_pc.c
@@ -124,6 +124,10 @@ Color gVertexColor = { 0xFF, 0xFF, 0xFF };
Color gFogColor = { 0xFF, 0xFF, 0xFF };
f32 gFogIntensity = 1;
+// need inverse camera matrix to compute world space for lighting engine
+static Mat4 sInverseCameraMatrix;
+static bool sHasInverseCameraMatrix = false;
+
// 4x4 pink-black checkerboard texture to indicate missing textures
#define MISSING_W 4
#define MISSING_H 4
@@ -627,7 +631,18 @@ static void calculate_normal_dir(const Light_t *light, Vec3f coeffs, bool applyL
}
static void OPTIMIZE_O3 gfx_sp_matrix(uint8_t parameters, const int32_t *addr) {
+
Mat4 matrix;
+
+ // remember inverse camera matrix to use for the lighting engine
+ if (parameters == G_MTX_INVERSE_CAMERA_EXT) {
+ if (addr) {
+ memcpy(sInverseCameraMatrix, addr, sizeof(sInverseCameraMatrix));
+ sHasInverseCameraMatrix = true;
+ }
+ return;
+ }
+
#if 0
// Original code when fixed point matrices were used
for (int32_t i = 0; i < 4; i++) {
@@ -642,6 +657,7 @@ static void OPTIMIZE_O3 gfx_sp_matrix(uint8_t parameters, const int32_t *addr) {
memcpy(matrix, addr, sizeof(matrix));
#endif
+
if (parameters & G_MTX_PROJECTION) {
if (parameters & G_MTX_LOAD) {
mtxf_copy(rsp.P_matrix, matrix);
@@ -678,6 +694,37 @@ static float gfx_adjust_x_for_aspect_ratio(float x) {
return x * gfx_current_dimensions.x_adjust_ratio;
}
+static OPTIMIZE_O3 void gfx_local_to_world_space(OUT Vec3f pos, OUT Vec3f normal) {
+ if (!sHasInverseCameraMatrix) { return; }
+
+ // strip view matrix off of the model-view matrix
+ Mat4 model;
+ mtxf_mul(model, rsp.modelview_matrix_stack[rsp.modelview_matrix_stack_size-1], sInverseCameraMatrix);
+
+ // transform position to world
+ Vec3f worldPos;
+ worldPos[0] = pos[0] * model[0][0] + pos[1] * model[1][0] + pos[2] * model[2][0] + model[3][0];
+ worldPos[1] = pos[0] * model[0][1] + pos[1] * model[1][1] + pos[2] * model[2][1] + model[3][1];
+ worldPos[2] = pos[0] * model[0][2] + pos[1] * model[1][2] + pos[2] * model[2][2] + model[3][2];
+
+ pos[0] = worldPos[0];
+ pos[1] = worldPos[1];
+ pos[2] = worldPos[2];
+
+ // transform normal to world
+ if (normal) {
+ Vec3f worldNormal;
+ worldNormal[0] = normal[0] * model[0][0] + normal[1] * model[1][0] + normal[2] * model[2][0];
+ worldNormal[1] = normal[0] * model[0][1] + normal[1] * model[1][1] + normal[2] * model[2][1];
+ worldNormal[2] = normal[0] * model[0][2] + normal[1] * model[1][2] + normal[2] * model[2][2];
+
+ normal[0] = worldNormal[0];
+ normal[1] = worldNormal[1];
+ normal[2] = worldNormal[2];
+ }
+}
+
+
static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *vertices, bool luaVertexColor) {
if (!vertices) { return; }
@@ -814,21 +861,37 @@ static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, cons
V = (int32_t)((doty / 127.0f + 1.0f) / 4.0f * rsp.texture_scaling_factor.t);
}
- if (rsp.geometry_mode & G_LIGHTING_ENGINE_EXT) {
+ if (le_is_enabled() && ((le_get_mode() == LE_MODE_AFFECT_ALL_SHADED) || (rsp.geometry_mode & G_LIGHTING_ENGINE_EXT))) {
Color color;
CTX_BEGIN(CTX_LIGHTING);
- le_calculate_lighting_color(((Vtx_t*)v)->ob, color, 1.0f);
+
+ Vec3f vpos = { v->ob[0], v->ob[1], v->ob[2] };
+ Vec3f vnormal = { nx, ny, nz };
+
+ // transform vpos and vnormal to world space
+ gfx_local_to_world_space(vpos, vnormal);
+
+ le_calculate_lighting_color_with_normal(vpos, vnormal, color, 1.0f);
+
CTX_END(CTX_LIGHTING);
d->color.r *= color[0] / 255.0f;
d->color.g *= color[1] / 255.0f;
d->color.b *= color[2] / 255.0f;
}
- } else if (rsp.geometry_mode & G_LIGHTING_ENGINE_EXT) {
+ } else if (le_is_enabled() && (rsp.geometry_mode & G_LIGHTING_ENGINE_EXT)) {
Color color;
CTX_BEGIN(CTX_LIGHTING);
- le_calculate_vertex_lighting((Vtx_t*)v, color);
+
+ Vec3f vpos = { v->ob[0], v->ob[1], v->ob[2] };
+
+ // transform vpos to world space
+ gfx_local_to_world_space(vpos, NULL);
+
+ le_calculate_vertex_lighting((Vtx_t*)v, vpos, color);
+
CTX_END(CTX_LIGHTING);
+
if (luaVertexColor) {
d->color.r = color[0] * vertexColorCached[0];
d->color.g = color[1] * vertexColorCached[1];
@@ -1875,6 +1938,8 @@ void gfx_start_frame(void) {
void gfx_run(Gfx *commands) {
gfx_sp_reset();
+ sHasInverseCameraMatrix = false;
+
//puts("New frame");
if (!gfx_wapi->start_frame()) {
diff --git a/src/pc/lua/smlua_constants_autogen.c b/src/pc/lua/smlua_constants_autogen.c
index 10c85cdfb..bbda80aa3 100644
--- a/src/pc/lua/smlua_constants_autogen.c
+++ b/src/pc/lua/smlua_constants_autogen.c
@@ -1777,6 +1777,12 @@ 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_MODE_AFFECT_ALL_SHADED=0\n"
+"LE_MODE_AFFECT_ONLY_GEOMETRY_MODE=1\n"
+"LE_TONE_MAPPING_TOTAL_WEIGHTED=0\n"
+"LE_TONE_MAPPING_WEIGHTED=1\n"
+"LE_TONE_MAPPING_CLAMP=2\n"
+"LE_TONE_MAPPING_REINHARD=3\n"
"MARIO_ANIM_SLOW_LEDGE_GRAB=0\n"
"MARIO_ANIM_FALL_OVER_BACKWARDS=1\n"
"MARIO_ANIM_BACKWARD_AIR_KB=2\n"
diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c
index 18e3d3019..b227a3ce1 100644
--- a/src/pc/lua/smlua_functions_autogen.c
+++ b/src/pc/lua/smlua_functions_autogen.c
@@ -15515,6 +15515,70 @@ int smlua_func_lvl_set_current_level(lua_State* L) {
// lighting_engine.h //
///////////////////////
+int smlua_func_le_set_mode(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_mode", 1, top);
+ return 0;
+ }
+
+ int mode = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "le_set_mode"); return 0; }
+
+ le_set_mode(mode);
+
+ return 1;
+}
+
+int smlua_func_le_get_mode(UNUSED lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 0) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "le_get_mode", 0, top);
+ return 0;
+ }
+
+
+ lua_pushinteger(L, le_get_mode());
+
+ return 1;
+}
+
+int smlua_func_le_set_tone_mapping(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_tone_mapping", 1, top);
+ return 0;
+ }
+
+ int toneMapping = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "le_set_tone_mapping"); return 0; }
+
+ le_set_tone_mapping(toneMapping);
+
+ return 1;
+}
+
+int smlua_func_le_is_enabled(UNUSED lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 0) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "le_is_enabled", 0, top);
+ return 0;
+ }
+
+
+ lua_pushboolean(L, le_is_enabled());
+
+ return 1;
+}
+
int smlua_func_le_calculate_lighting_color(lua_State* L) {
if (L == NULL) { return 0; }
@@ -15542,6 +15606,37 @@ int smlua_func_le_calculate_lighting_color(lua_State* L) {
return 1;
}
+int smlua_func_le_calculate_lighting_color_with_normal(lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 4) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "le_calculate_lighting_color_with_normal", 4, top);
+ return 0;
+ }
+
+
+ Vec3f pos;
+ smlua_get_vec3f(pos, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "le_calculate_lighting_color_with_normal"); return 0; }
+
+ Vec3f normal;
+ smlua_get_vec3f(normal, 2);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "le_calculate_lighting_color_with_normal"); return 0; }
+
+ Color out;
+ smlua_get_color(out, 3);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "le_calculate_lighting_color_with_normal"); return 0; }
+ f32 lightIntensityScalar = smlua_to_number(L, 4);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 4, "le_calculate_lighting_color_with_normal"); return 0; }
+
+ le_calculate_lighting_color_with_normal(pos, normal, out, lightIntensityScalar);
+
+ smlua_push_color(out, 3);
+
+ return 1;
+}
+
int smlua_func_le_calculate_lighting_dir(lua_State* L) {
if (L == NULL) { return 0; }
@@ -15735,6 +15830,25 @@ int smlua_func_le_set_light_intensity(lua_State* L) {
return 1;
}
+int smlua_func_le_set_light_use_surface_normals(lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 2) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "le_set_light_use_surface_normals", 2, top);
+ return 0;
+ }
+
+ s32 id = smlua_to_integer(L, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "le_set_light_use_surface_normals"); return 0; }
+ bool useSurfaceNormals = smlua_to_boolean(L, 2);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "le_set_light_use_surface_normals"); return 0; }
+
+ le_set_light_use_surface_normals(id, useSurfaceNormals);
+
+ return 1;
+}
+
/////////////
// mario.h //
/////////////
@@ -19890,6 +20004,31 @@ int smlua_func_mtxf_inverse(lua_State* L) {
return 1;
}
+int smlua_func_mtxf_inverse_non_affine(lua_State* L) {
+ if (L == NULL) { return 0; }
+
+ int top = lua_gettop(L);
+ if (top != 2) {
+ LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "mtxf_inverse_non_affine", 2, top);
+ return 0;
+ }
+
+
+ Mat4 dest;
+ smlua_get_mat4(dest, 1);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "mtxf_inverse_non_affine"); return 0; }
+
+ Mat4 src;
+ smlua_get_mat4(src, 2);
+ if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "mtxf_inverse_non_affine"); return 0; }
+
+ lua_pushboolean(L, mtxf_inverse_non_affine(dest, src));
+
+ smlua_push_mat4(dest, 1);
+
+ return 1;
+}
+
int smlua_func_get_pos_from_transform_mtx(lua_State* L) {
if (L == NULL) { return 0; }
@@ -36380,7 +36519,12 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "lvl_set_current_level", smlua_func_lvl_set_current_level);
// lighting_engine.h
+ smlua_bind_function(L, "le_set_mode", smlua_func_le_set_mode);
+ smlua_bind_function(L, "le_get_mode", smlua_func_le_get_mode);
+ smlua_bind_function(L, "le_set_tone_mapping", smlua_func_le_set_tone_mapping);
+ smlua_bind_function(L, "le_is_enabled", smlua_func_le_is_enabled);
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);
smlua_bind_function(L, "le_add_light", smlua_func_le_add_light);
smlua_bind_function(L, "le_remove_light", smlua_func_le_remove_light);
@@ -36390,6 +36534,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "le_set_light_color", smlua_func_le_set_light_color);
smlua_bind_function(L, "le_set_light_radius", smlua_func_le_set_light_radius);
smlua_bind_function(L, "le_set_light_intensity", smlua_func_le_set_light_intensity);
+ smlua_bind_function(L, "le_set_light_use_surface_normals", smlua_func_le_set_light_use_surface_normals);
// mario.h
smlua_bind_function(L, "is_anim_at_end", smlua_func_is_anim_at_end);
@@ -36616,6 +36761,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "mtxf_mul_vec3s", smlua_func_mtxf_mul_vec3s);
smlua_bind_function(L, "mtxf_rotate_xy", smlua_func_mtxf_rotate_xy);
smlua_bind_function(L, "mtxf_inverse", smlua_func_mtxf_inverse);
+ smlua_bind_function(L, "mtxf_inverse_non_affine", smlua_func_mtxf_inverse_non_affine);
smlua_bind_function(L, "get_pos_from_transform_mtx", smlua_func_get_pos_from_transform_mtx);
// math_util.inl