remove puppylights (#736)

This commit is contained in:
arthurtilly
2023-12-17 17:26:31 +13:00
committed by GitHub
parent 913cda93b8
commit 6148582f5e
16 changed files with 2 additions and 568 deletions

View File

@@ -36,7 +36,6 @@ Thanks to Frame#5375 and AloXado320 for also helping with silhouette stuff
**Lighting Engine by Wiseguy**
- Lighting Engine is available on a separate branch ([base/lighting-engine](https://github.com/Reonu/HackerSM64/tree/base/lighting-engine)). Instructions on how to use it are in the readme of that branch.
- Alternatively, the main repo has `Puppylights` available, which is a more lightweight, but limited lighting library intended to be used to modify existing light properties. You can look at `puppylights.c` to find out how to use it.
**Puppycam**
- Puppycam is available on the master branch now, you can toggle it in `config/config_camera.h`. *

View File

@@ -5,7 +5,6 @@
#include "level_table.h"
#include "config.h"
#include "game/puppylights.h"
enum LevelCommands {
/*0x00*/ LEVEL_CMD_LOAD_AND_EXECUTE,
@@ -71,9 +70,7 @@ enum LevelCommands {
/*0x3C*/ LEVEL_CMD_GET_OR_SET_VAR,
/*0x3D*/ LEVEL_CMD_PUPPYVOLUME,
/*0x3E*/ LEVEL_CMD_CHANGE_AREA_SKYBOX,
/*0x3F*/ LEVEL_CMD_PUPPYLIGHT_ENVIRONMENT,
/*0x40*/ LEVEL_CMD_PUPPYLIGHT_NODE,
/*0x41*/ LEVEL_CMD_SET_ECHO,
/*0x3F*/ LEVEL_CMD_SET_ECHO,
};
enum LevelActs {

View File

@@ -169,9 +169,6 @@
#define /*0x1BC*/ oAngleToHome OBJECT_FIELD_S32(0x4D)
#define /*0x1C0*/ oFloor OBJECT_FIELD_SURFACE(0x4E)
#define /*0x1C4*/ oDeathSound OBJECT_FIELD_S32(0x4F)
#ifdef PUPPYLIGHTS
#define /*0x1C4*/ oLightID OBJECT_FIELD_S32(0x50)
#endif
/* Pathed (see obj_follow_path) */
#define /*0x0FC*/ oPathedStartWaypoint OBJECT_FIELD_WAYPOINT(0x1D)

View File

@@ -256,27 +256,9 @@ struct ObjectNode {
struct ObjectNode *prev;
};
#ifdef PUPPYLIGHTS
struct PuppyLight {
Vec3t pos[2]; // The location of the light. First index is the absolute position, second index are offsets.
s16 yaw; // Used by cubes. Allows epic rotating of the volume.
RoomData room; // Which room to use. -1 is visible from all rooms.
s8 epicentre; // What percentage inside the volume you'll be before maximum light strength is applied. (E.g: 100 will be full strength always, and 0 will be full strength at the centre.)
u8 flags; // Some stuff to define how the volume is used. Mostly just shape stuff, but can potentially have other uses.
ColorRGBA rgba; // Colour. Go on, take even the tiniest guess as to what this entails.
u8 area; // Which section of the level this light is stored in.
u8 active: 1; // Whether the light will actually work. Mostly intended to be used for objects.
};
#endif
// NOTE: Since ObjectNode is the first member of Object, it is difficult to determine
// whether some of these pointers point to ObjectNode or Object.
#ifdef PUPPYLIGHTS
#define MAX_OBJECT_FIELDS 0x51
#else
#define MAX_OBJECT_FIELDS 0x50
#endif
struct Object {
/*0x000*/ struct ObjectNode header;
@@ -335,9 +317,6 @@ struct Object {
/*0x218*/ void *collisionData;
/*0x21C*/ Mat4 transform;
/*0x25C*/ void *respawnInfo;
#ifdef PUPPYLIGHTS
struct PuppyLight puppylight;
#endif
};
struct ObjectHitbox {

View File

@@ -20,7 +20,6 @@
#include "usb/debug.h"
#endif
#include "game/puppyprint.h"
#include "game/puppylights.h"
#include "game/profiling.h"
#include "game/emutest.h"
@@ -115,9 +114,6 @@ void alloc_pool(void) {
main_pool_init(start, end);
gEffectsMemoryPool = mem_pool_init(EFFECTS_MEMORY_POOL, MEMORY_POOL_LEFT);
#ifdef PUPPYLIGHTS
gLightsPool = mem_pool_init(PUPPYLIGHTS_POOL, MEMORY_POOL_LEFT);
#endif
}
void create_thread(OSThread *thread, OSId id, void (*entry)(void *), void *arg, void *sp, OSPri pri) {

View File

@@ -14,7 +14,6 @@
#include "math_util.h"
#include "graph_node.h"
#include "surface_collision.h"
#include "game/puppylights.h"
// Macros for retrieving arguments from behavior scripts.
#define BHV_CMD_GET_1ST_U8(index) (u8)((gCurBhvCommand[index] >> 24) & 0xFF) // unused
@@ -911,10 +910,6 @@ void cur_obj_update(void) {
}
#endif
#ifdef PUPPYLIGHTS
puppylights_object_emit(o);
#endif
// Handle visibility of object
if (o->oRoom != -1) {
// If the object is in a room, only show it when Mario is in the room.

View File

@@ -28,7 +28,6 @@
#include "string.h"
#include "game/puppycam2.h"
#include "game/puppyprint.h"
#include "game/puppylights.h"
#include "game/emutest.h"
#include "config.h"
@@ -859,52 +858,6 @@ static void level_cmd_puppyvolume(void) {
sCurrentCmd = CMD_NEXT;
}
static void level_cmd_puppylight_environment(void) {
#ifdef PUPPYLIGHTS
Lights1 temp = gdSPDefLights1(CMD_GET(u8, 2), CMD_GET(u8, 3), CMD_GET(u8, 4),
CMD_GET(u8, 5), CMD_GET(u8, 6), CMD_GET(u8, 7),
CMD_GET(u8, 8), CMD_GET(u8, 9), CMD_GET(u8, 10));
memcpy(&gLevelLight, &temp, sizeof(Lights1));
levelAmbient = TRUE;
#endif
sCurrentCmd = CMD_NEXT;
}
static void level_cmd_puppylight_node(void) {
#ifdef PUPPYLIGHTS
gPuppyLights[gNumLights] = mem_pool_alloc(gLightsPool, sizeof(struct PuppyLight));
if (gPuppyLights[gNumLights] == NULL) {
append_puppyprint_log("Puppylight allocation failed.");
sCurrentCmd = CMD_NEXT;
return;
}
vec4_set(gPuppyLights[gNumLights]->rgba, CMD_GET(u8, 2),
CMD_GET(u8, 3),
CMD_GET(u8, 4),
CMD_GET(u8, 5));
vec3s_set(gPuppyLights[gNumLights]->pos[0], CMD_GET(s16, 6),
CMD_GET(s16, 8),
CMD_GET(s16, 10));
vec3s_set(gPuppyLights[gNumLights]->pos[1], CMD_GET(s16, 12),
CMD_GET(s16, 14),
CMD_GET(s16, 16));
gPuppyLights[gNumLights]->yaw = CMD_GET(s16, 18);
gPuppyLights[gNumLights]->epicentre = CMD_GET(u8, 20);
gPuppyLights[gNumLights]->flags = CMD_GET(u8, 21);
gPuppyLights[gNumLights]->active = TRUE;
gPuppyLights[gNumLights]->area = sCurrAreaIndex;
gPuppyLights[gNumLights]->room = CMD_GET(s16, 22);
gNumLights++;
#endif
sCurrentCmd = CMD_NEXT;
}
static void level_cmd_set_echo(void) {
if (sCurrAreaIndex >= 0 && sCurrAreaIndex < AREA_COUNT) {
gAreaData[sCurrAreaIndex].useEchoOverride = TRUE;
@@ -980,8 +933,6 @@ static void (*LevelScriptJumpTable[])(void) = {
/*LEVEL_CMD_GET_OR_SET_VAR */ level_cmd_get_or_set_var,
/*LEVEL_CMD_PUPPYVOLUME */ level_cmd_puppyvolume,
/*LEVEL_CMD_CHANGE_AREA_SKYBOX */ level_cmd_change_area_skybox,
/*LEVEL_CMD_PUPPYLIGHT_ENVIRONMENT */ level_cmd_puppylight_environment,
/*LEVEL_CMD_PUPPYLIGHT_NODE */ level_cmd_puppylight_node,
/*LEVEL_CMD_SET_ECHO */ level_cmd_set_echo,
};

View File

@@ -44,7 +44,6 @@
#include "spawn_object.h"
#include "spawn_sound.h"
#include "rumble_init.h"
#include "puppylights.h"
#include "behaviors/star_door.inc.c"
#include "behaviors/mr_i.inc.c"

View File

@@ -30,7 +30,6 @@
#include "rumble_init.h"
#include "puppycam2.h"
#include "puppyprint.h"
#include "puppylights.h"
#include "level_commands.h"
#include "config.h"
@@ -630,30 +629,16 @@ void initiate_warp(s16 destLevel, s16 destArea, s16 destWarpNode, s32 warpFlags)
sWarpDest.areaIdx = destArea;
sWarpDest.nodeId = destWarpNode;
sWarpDest.arg = warpFlags;
#if defined(PUPPYCAM) || defined(PUPPYLIGHTS)
s32 i = 0;
#endif
#ifdef PUPPYCAM
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL)
{
for (i = 0; i < gPuppyVolumeCount; i++)
for (s32 i = 0; i < gPuppyVolumeCount; i++)
{
mem_pool_free(gPuppyMemoryPool, sPuppyVolumeStack[i]);
}
gPuppyVolumeCount = 0;
}
#endif
#ifdef PUPPYLIGHTS
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL)
{
for (i = 0; i < gNumLights; i++)
{
mem_pool_free(gLightsPool, gPuppyLights[i]);
}
gNumLights = 0;
levelAmbient = FALSE;
}
#endif
}
// From Surface 0xD3 to 0xFC
@@ -992,9 +977,6 @@ void update_hud_values(void) {
void basic_update(void) {
area_update_objects();
update_hud_values();
#ifdef PUPPYLIGHTS
delete_lights();
#endif
if (gCurrentArea != NULL) {
update_camera(gCurrentArea->camera);
@@ -1035,9 +1017,6 @@ s32 play_mode_normal(void) {
area_update_objects();
#endif
update_hud_values();
#ifdef PUPPYLIGHTS
delete_lights();
#endif
if (gCurrentArea != NULL) {
#ifdef PUPPYPRINT_DEBUG
#ifdef BETTER_REVERB
@@ -1318,10 +1297,6 @@ s32 init_level(void) {
sound_banks_disable(SEQ_PLAYER_SFX, SOUND_BANKS_DISABLED_DURING_INTRO_CUTSCENE);
}
#ifdef PUPPYLIGHTS
puppylights_allocate();
#endif
append_puppyprint_log("Level loaded in %d" PP_CYCLE_STRING ".", (s32)(PP_CYCLE_CONV(osGetTime() - first)));
return TRUE;
}

View File

@@ -32,7 +32,6 @@
#include "spawn_object.h"
#include "spawn_sound.h"
#include "rumble_init.h"
#include "puppylights.h"
/**
* @file obj_behaviors.c

View File

@@ -45,7 +45,6 @@
#include "save_file.h"
#include "seq_ids.h"
#include "spawn_sound.h"
#include "puppylights.h"
//! TODO: remove static

View File

@@ -26,7 +26,6 @@
#include "rendering_graph_node.h"
#include "spawn_object.h"
#include "spawn_sound.h"
#include "puppylights.h"
static s32 clear_move_flag(u32 *bitSet, s32 flag);
@@ -878,9 +877,6 @@ s32 cur_obj_clear_interact_status_flag(s32 flag) {
* Mark an object to be unloaded at the end of the frame.
*/
void obj_mark_for_deletion(struct Object *obj) {
#ifdef PUPPYLIGHTS
obj_disable_light(obj);
#endif
//! This clears all activeFlags. Since some of these flags disable behavior,
// setting it to 0 could potentially enable unexpected behavior. After an
// object is marked for deletion, it still updates on that frame (I think),

View File

@@ -20,7 +20,6 @@
#include "platform_displacement.h"
#include "spawn_object.h"
#include "puppyprint.h"
#include "puppylights.h"
#include "profiling.h"
@@ -382,10 +381,6 @@ s32 unload_deactivated_objects_in_list(struct ObjectNode *objList) {
obj = obj->next;
if ((gCurrentObject->activeFlags & ACTIVE_FLAG_ACTIVE) != ACTIVE_FLAG_ACTIVE) {
#ifdef PUPPYLIGHTS
if (gCurrentObject->oLightID != 0xFFFF)
obj_disable_light(gCurrentObject);
#endif
// Prevent object from respawning after exiting and re-entering the
// area
if (!(gCurrentObject->oFlags & OBJ_FLAG_PERSISTENT_RESPAWN)) {

View File

@@ -1,382 +0,0 @@
///Puppylights 2.0 by Fazana. What happened to 1.0? Tragic accident.
/**
Intended for use with manipulating existing Lights1 structs for objects in real time.
Can support static lights that are loaded with the level, or lights created by objects.
Puppylights is generally intended to be used with things that don't directly use lights to colour
themselves. Inside the main function, you can pass through a colour to override the default light
but it will not be affected by environmental tinting. If you wish for an object to emit a light,
simply set the object flag OBJ_FLAG_EMIT_LIGHT and set some values to o->puppylight.
For easy light modification, you can call set_light_properties, so set all the attributes of any
given loaded puppylight struct. Objects will ignore x, y, z, active and room, as it will set all
of these automatically. It will force the PUPPYLIGHT_DYNAMIC flag, too.
If you're introducing a static light in the level script with PUPPYLIGHT_NODE, ensure it's contained
inside the respective area node it's going to be inside, otherwise it will not show up. If you do not
use rooms in your level, or if you wish for this light to be seen from any room, use -1 for that param.
If you have visual debug enabled, light nodes will show up as magenta in the world. They will be
shaped and rotated correctly, for accurate representation of their properties.
**/
#include <ultra64.h>
#include "types.h"
#include "puppylights.h"
#include "area.h"
#include "engine/math_util.h"
#include "string.h"
#include "object_fields.h"
#include "object_constants.h"
#include "camera.h"
#include "memory.h"
#include "print.h"
#include "debug_box.h"
#include "object_list_processor.h"
#include "level_update.h"
#include "engine/surface_collision.h"
#include "surface_terrains.h"
#ifdef PUPPYLIGHTS
Lights1 gLevelLight; // Existing ambient light in the area. Will be set by the level script, though can always be changed afterwards if desired.
u8 levelAmbient = FALSE;
Lights1 *sLightBase; // The base value where lights are written to when worked with.
Lights1 sDefaultLights = gdSPDefLights1(0x7F, 0x7F, 0x7F, 0xFE, 0xFE, 0xFE, 0x28, 0x28, 0x28); // Default lights default lights
u16 gNumLights = 0; // How many lights are loaded.
u16 gDynLightStart = 0; // Where the dynamic lights will start.
struct PuppyLight *gPuppyLights[MAX_LIGHTS]; // This contains all the loaded data.
struct MemoryPool *gLightsPool; // The memory pool where the above is stored.
// Runs after an area load, allocates the dynamic light slots.
void puppylights_allocate(void) {
s32 numAllocate = MIN(MAX_LIGHTS - gNumLights, MAX_LIGHTS_DYNAMIC);
s32 i;
gDynLightStart = gNumLights;
if (numAllocate <= 0) { // If this happens you've allocated too many static lights and therefore cucked dynamic.
return;
}
// Now it has the number it wants, it will allocate this many extra lights, intended for dynamic lights.
for (i = 0; i < numAllocate; i++) {
gPuppyLights[gNumLights] = mem_pool_alloc(gLightsPool, sizeof(struct PuppyLight));
if (gPuppyLights[gNumLights] == NULL) {
return;
}
gPuppyLights[gNumLights]->active = FALSE;
gPuppyLights[gNumLights]->flags = 0;
gNumLights++;
}
}
extern Mat4 gMatStack[32];
// Function that iterates through each light.
void puppylights_iterate(struct PuppyLight *light, Lights1 *src, struct Object *obj, s32 flags) {
Lights1 *tempLight;
s32 lightPos[2];
Vec3i lightRelative;
Vec3i lightDir = {0, 0, 0};
s32 i;
s32 colour;
s32 ambient;
f64 scaleOrig;
f32 scale;
f32 scale2;
f64 scaleVal = 1.0f;
Vec3f debugPos[2];
// Relative positions of the object vs. the centre of the node.
lightRelative[0] = light->pos[0][0] - obj->oPosX;
lightRelative[1] = light->pos[0][1] - obj->oPosY;
lightRelative[2] = light->pos[0][2] - obj->oPosZ;
// If the nodes X and Z values are equal, then a check is made if the angle is a derivative of 90.
// If so, then it will completely skip over the calculation that figures out position from rotation.
// If it's a cylinder, then it ignores that check, simply because an equal sided cylinder will have the
// same result no matter the yaw. If neither is true, then it simply checks if it's 180 degrees, since
// That will just be the same as 0.
if (light->pos[1][0] == light->pos[1][2]) {
if (light->yaw % 0x4000 == 0 || light->flags & PUPPYLIGHT_SHAPE_CYLINDER) {
lightPos[0] = lightRelative[0];
lightPos[1] = lightRelative[2];
goto skippingTrig;
}
} else if (light->yaw % 0x8000 == 0) {
lightPos[0] = lightRelative[0];
lightPos[1] = lightRelative[2];
goto skippingTrig;
}
// Get the position based off the rotation of the box.
lightPos[0] = lightRelative[2] * sins(-light->yaw) + lightRelative[0] * coss(-light->yaw);
lightPos[1] = lightRelative[2] * coss(-light->yaw) - lightRelative[0] * sins(-light->yaw);
skippingTrig:
#ifdef VISUAL_DEBUG
vec3f_set(debugPos[0], light->pos[0][0], light->pos[0][1], light->pos[0][2]);
vec3f_set(debugPos[1], light->pos[1][0], light->pos[1][1], light->pos[1][2]);
debug_box_color(0xFF00FF08);
if (light->flags & PUPPYLIGHT_SHAPE_CYLINDER) {
debug_box_rot(debugPos[0], debugPos[1], light->yaw, DEBUG_SHAPE_CYLINDER | DEBUG_UCODE_DEFAULT);
} else {
debug_box_rot(debugPos[0], debugPos[1], light->yaw, DEBUG_SHAPE_BOX | DEBUG_UCODE_DEFAULT);
}
#endif
// Check if the object is inside the box, after correcting it for rotation.
if (-light->pos[1][0] < lightPos[0] && lightPos[0] < light->pos[1][0] &&
-light->pos[1][1] < lightRelative[1] && lightRelative[1] < light->pos[1][1] &&
-light->pos[1][2] < lightPos[1] && lightPos[1] < light->pos[1][2]) {
// If so, then start making preparations to see how alongside they're in.
// This takes the largest side of the box and multiplies the other axis to match the numbers.
// This way, the colour value will scale correctly, no matter which side is entered.
// Because positions are a vector, and Y is up, it means tempID needs to be multiplied
// By 2 in order to reach the X and Z axis. Thanks SM64.
// It will skip scaling the opposite axis if there's no need to.
// Every axis needs to be the same as Z, so X and Y, if necessary, will be scaled to match it.
// This is done, so that when calculating scale, it's done spherically.
if (light->pos[1][0] != light->pos[1][2]) {
lightPos[0] /= ((f32)light->pos[1][0] / light->pos[1][2]);
}
// Same for Y axis.
if (light->pos[1][1] != light->pos[1][2]) {
lightRelative[1] /= ((f32)light->pos[1][1] / light->pos[1][2]);
}
if (light->flags & PUPPYLIGHT_IGNORE_Y) {
scaleOrig = sqr(lightPos[0]) + sqr(lightPos[1]);
} else {
scaleOrig = sqr(lightPos[0]) + sqr(lightRelative[1]) + sqr(lightPos[1]);
}
scaleVal = (light->pos[1][2]*light->pos[1][2]);
// If it's a cylinder, then bin anything outside it.
if (light->flags & PUPPYLIGHT_SHAPE_CYLINDER) {
if (scaleOrig > scaleVal) {
return;
}
}
}
else
return;
f32 epc = (f32)(light->epicentre/100.0f);
tempLight = segmented_to_virtual(src);
//Now we have a scale value and a scale factor, we can start lighting things up.
// Convert to a percentage.
scale = CLAMP(scaleOrig/scaleVal, 0.0f, 1.0f);
// Reduce scale2 by the epicentre.
scale2 = CLAMP((scale - epc) * (1 + epc), 0.0f, 1.0f);
// Get the direction numbers we want by applying some maths to the relative positions. We use 64 because light directions range from -64 to 63.
// Note: can this be optimised further? Simply squaring lightRelative and then dividing it by preScale doesn't work.
if (light->flags & PUPPYLIGHT_DIRECTIONAL) {
lightDir[0] = ((lightRelative[0]) * 64.0f) / light->pos[1][0];
lightDir[1] = ((lightRelative[1]) * 64.0f) / light->pos[1][1];
lightDir[2] = ((lightRelative[2]) * 64.0f) / light->pos[1][2];
}
//Get direction if applicable.
for (i = 0; i < 3; i++) {
//So it works by starting from the final colour, and then lerping to the original colour, by a factor of the epicentre corrected scale. Light opacity affects this further.
colour = approach_f32_asymptotic(light->rgba[i], tempLight->l[0].l.col[i], scale2 * ((f32)light->rgba[3]/255.0f));
// If it's a directional light, then increase the current ambient by 50%, to give the effect better.
// Otherwise, just normalise the brightness to keep it in line with the current ambient.
// And now to apply the values.
tempLight->l[0].l.col[i] = colour;
tempLight->l[0].l.colc[i] = colour;
// Ambient, too.
if (!(light->flags & PUPPYLIGHT_DIRECTIONAL)) {
ambient = approach_f32_asymptotic(light->rgba[i]/2, tempLight->a.l.col[i], scale*((f32)light->rgba[3] / 255.0f));
tempLight->a.l.col[i] = ambient;
tempLight->a.l.colc[i] = ambient;
}
// A slightly hacky way to offset the ambient lighting in order to prevent directional lighting from having a noticeable change in ambient brightness.
if (flags & LIGHTFLAG_DIRECTIONAL_OFFSET) {
ambient = approach_f32_asymptotic(MIN(tempLight->a.l.col[i] * 2, 0xFF), tempLight->a.l.col[i], scale2*((f32)light->rgba[3] / 255.0f));
tempLight->a.l.col[i] = ambient;
tempLight->a.l.colc[i] = ambient;
}
// Apply direction. It takes the relative positions, and then multiplies them with the perspective matrix to get a correct direction.
// Index 1 of the first dimension of gMatStack is perspective. Note that if you ever decide to cheat your way into rendering things after the game does :^)
if (light->flags & PUPPYLIGHT_DIRECTIONAL) {
tempLight->l->l.dir[i] = approach_f32_asymptotic((s8)(lightDir[0] * gMatStack[1][0][i] + lightDir[1] * gMatStack[1][1][i] + lightDir[2] * gMatStack[1][2][i]), tempLight->l->l.dir[i], scale);
}
}
}
// Main function. Run this in the object you wish to illuminate, and just give it its light, object pointer and any potential flags if you want to use them.
// If the object has multiple lights, then you run this for each light.
void puppylights_run(Lights1 *src, struct Object *obj, s32 flags, u32 baseColour) {
s32 i;
s32 numlights = 0;
s32 offsetPlaced = 0;
s32 lightFlags = flags;
if (gCurrLevelNum < LEVEL_BBH) {
return;
}
// Checks if there's a hardset colour. Colours are only the first 3 bytes, so you can really put whatever you want in the last.
// If there isn't a colour, then it decides whether to apply the ambient lighting, or the default lighting as the baseline.
// Otherwise, it hardsets a colour to begin with. I don't recommend you use this, simply because it's intended to be used
// As a hacky quick-fix for models coloured by lights. Lightcoloured models don't blend nearly as nicely as ones coloured
// By other means.
if (baseColour < 0x100) {
sLightBase = (levelAmbient ? &gLevelLight : &sDefaultLights);
} else {
s32 colour;
sLightBase = (levelAmbient) ? &gLevelLight : &sDefaultLights;
for (i = 0; i < 3; i++) {
colour = (((baseColour >> (24-(i*8)))) & 0xFF);
sLightBase->l[0].l.col[i] = colour;
sLightBase->l[0].l.colc[i] = colour;
sLightBase->a.l.col[i] = colour/2;
sLightBase->a.l.colc[i] = colour/2;
sLightBase->l->l.dir[i] = 0x28;
}
}
memcpy(segmented_to_virtual(src), &sLightBase[0], sizeof(Lights1));
for (i = 0; i < gNumLights; i++) {
if (gPuppyLights[i]->rgba[3] > 0 && gPuppyLights[i]->active == TRUE && gPuppyLights[i]->area == gCurrAreaIndex && (gPuppyLights[i]->room == -1 || gPuppyLights[i]->room == gMarioCurrentRoom)) {
if (gPuppyLights[i]->flags & PUPPYLIGHT_DIRECTIONAL && !offsetPlaced) {
lightFlags |= LIGHTFLAG_DIRECTIONAL_OFFSET;
offsetPlaced = 1;
} else {
lightFlags &= ~LIGHTFLAG_DIRECTIONAL_OFFSET;
}
puppylights_iterate(gPuppyLights[i], src, obj, lightFlags);
numlights++;
}
}
}
// Sets and updates dynamic lights from objects.
// 0xFFFF is essentially the null ID. If the display flag is met, it will find and set an ID, otherwise it frees up the spot.
void puppylights_object_emit(struct Object *obj) {
s32 i;
if (gCurrLevelNum < LEVEL_BBH) {
return;
}
if (obj->oFlags & OBJ_FLAG_EMIT_LIGHT) {
f64 dist = ((obj->oPosX - gMarioState->pos[0]) * (obj->oPosX - gMarioState->pos[0])) +
((obj->oPosY - gMarioState->pos[1]) * (obj->oPosY - gMarioState->pos[1])) +
((obj->oPosZ - gMarioState->pos[2]) * (obj->oPosZ - gMarioState->pos[2]));
f64 lightSize = ((obj->puppylight.pos[1][0]) * (obj->puppylight.pos[1][0])) +
((obj->puppylight.pos[1][1]) * (obj->puppylight.pos[1][1])) +
((obj->puppylight.pos[1][2]) * (obj->puppylight.pos[1][2]));
if (dist > lightSize) {
goto deallocate; // That's right. I used a goto. Eat your heart out xkcd.
}
if (obj->oLightID == 0xFFFF) {
s32 fadingExists = FALSE;
if (ABS(gNumLights - gDynLightStart) < MAX_LIGHTS_DYNAMIC) {
goto deallocate;
}
for (i = gDynLightStart; i < MIN(gDynLightStart+MAX_LIGHTS_DYNAMIC, MAX_LIGHTS); i++) {
if (gPuppyLights[i]->active == TRUE) {
if (gPuppyLights[i]->flags & PUPPYLIGHT_DELETE) {
fadingExists = TRUE;
}
continue;
}
memcpy(gPuppyLights[i], &obj->puppylight, sizeof(struct PuppyLight));
gPuppyLights[i]->active = TRUE;
gPuppyLights[i]->area = gCurrAreaIndex;
gPuppyLights[i]->room = obj->oRoom;
obj->oLightID = i;
goto updatepos;
}
// Go through all the lights again, now this time, ignore the fading light flag and overwrite them.
if (fadingExists) {
for (i = gDynLightStart; i < MIN(gDynLightStart+MAX_LIGHTS_DYNAMIC, MAX_LIGHTS); i++) {
if (gPuppyLights[i]->active == TRUE && !(gPuppyLights[i]->flags & PUPPYLIGHT_DELETE)) {
continue;
}
memcpy(gPuppyLights[i], &obj->puppylight, sizeof(struct PuppyLight));
gPuppyLights[i]->active = TRUE;
gPuppyLights[i]->area = gCurrAreaIndex;
gPuppyLights[i]->room = obj->oRoom;
gPuppyLights[i]->flags &= ~PUPPYLIGHT_DELETE;
obj->oLightID = i;
goto updatepos;
}
}
} else {
updatepos:
gPuppyLights[obj->oLightID]->pos[0][0] = obj->oPosX;
gPuppyLights[obj->oLightID]->pos[0][1] = obj->oPosY;
gPuppyLights[obj->oLightID]->pos[0][2] = obj->oPosZ;
}
} else {
deallocate:
if (obj->oLightID != 0xFFFF) {
gPuppyLights[obj->oLightID]->active = FALSE;
gPuppyLights[obj->oLightID]->flags = 0;
}
obj->oLightID = 0xFFFF;
}
}
// A bit unorthodox, but anything to avoid having to set up data to pass through in the original function.
// Objects will completely ignore X, Y, Z and active though.
void set_light_properties(struct PuppyLight *light, s32 x, s32 y, s32 z, s32 offsetX, s32 offsetY, s32 offsetZ, s32 yaw, s32 epicentre, s32 colour, s32 flags, s32 room, s32 active) {
light->active = active;
light->pos[0][0] = x;
light->pos[0][1] = y;
light->pos[0][2] = z;
light->pos[1][0] = MAX(offsetX, 10);
light->pos[1][1] = MAX(offsetY, 10);
light->pos[1][2] = MAX(offsetZ, 10);
light->rgba[0] = (colour >> 24) & 0xFF;
light->rgba[1] = (colour >> 16) & 0xFF;
light->rgba[2] = (colour >> 8) & 0xFF;
light->rgba[3] = colour & 0xFF;
light->yaw = yaw;
light->area = gCurrAreaIndex;
light->room = room;
light->epicentre = epicentre;
if (!(flags & PUPPYLIGHT_SHAPE_CYLINDER) && flags & PUPPYLIGHT_SHAPE_CUBE)
light->flags |= PUPPYLIGHT_SHAPE_CYLINDER;
light->flags |= flags | PUPPYLIGHT_DYNAMIC;
}
// You can run these in objects to enable or disable their light properties.
void cur_obj_enable_light(void) {
gCurrentObject->oFlags |= OBJ_FLAG_EMIT_LIGHT;
}
void cur_obj_disable_light(void) {
gCurrentObject->oFlags &= ~OBJ_FLAG_EMIT_LIGHT;
if (gPuppyLights[gCurrentObject->oLightID] && gCurrentObject->oLightID != 0xFFFF)
gPuppyLights[gCurrentObject->oLightID]->flags |= PUPPYLIGHT_DELETE;
}
void obj_enable_light(struct Object *obj) {
obj->oFlags |= OBJ_FLAG_EMIT_LIGHT;
}
void obj_disable_light(struct Object *obj) {
obj->oFlags &= ~OBJ_FLAG_EMIT_LIGHT;
if (gPuppyLights[obj->oLightID] && obj->oLightID != 0xFFFF) {
gPuppyLights[obj->oLightID]->flags |= PUPPYLIGHT_DELETE;
}
}
// This is ran during a standard area update
void delete_lights(void) {
s32 i;
for (i = 0; i < gNumLights; i++) {
if (gPuppyLights[i]->active == TRUE && gPuppyLights[i]->flags & PUPPYLIGHT_DELETE) {
gPuppyLights[i]->pos[1][0] = approach_f32_asymptotic(gPuppyLights[i]->pos[1][0], 0, 0.15f);
gPuppyLights[i]->pos[1][1] = approach_f32_asymptotic(gPuppyLights[i]->pos[1][1], 0, 0.15f);
gPuppyLights[i]->pos[1][2] = approach_f32_asymptotic(gPuppyLights[i]->pos[1][2], 0, 0.15f);
if (gPuppyLights[i]->pos[1][0] < 1.0f && gPuppyLights[i]->pos[1][1] < 1.0f && gPuppyLights[i]->pos[1][2] < 1.0f) {
gPuppyLights[i]->flags &= ~ PUPPYLIGHT_DELETE;
gPuppyLights[i]->active = FALSE;
}
}
}
}
#endif

View File

@@ -1,57 +0,0 @@
#ifdef PUPPYLIGHTS
#ifndef PUPPYLIGHTS_H
#define PUPPYLIGHTS_H
#include "types.h"
#include "command_macros_base.h"
// The maximum number of lights that can be loaded at once. Any further lights that attempt to be created past this will simply not spawn.
#define MAX_LIGHTS 32
// The maximum number of dynamic lights available at one time.
#define MAX_LIGHTS_DYNAMIC 8
// Two shapes. Choose your destiny.
#define PUPPYLIGHT_SHAPE_CUBE (1 << 0) // 0x01
#define PUPPYLIGHT_SHAPE_CYLINDER (1 << 1) // 0x02
#define PUPPYLIGHT_DYNAMIC (1 << 2) // 0x04
#define PUPPYLIGHT_DIRECTIONAL (1 << 3) // 0x08
#define PUPPYLIGHT_SHADOW (1 << 4) // 0x10
#define PUPPYLIGHT_WET (1 << 5) // 0x20
#define PUPPYLIGHT_DELETE (1 << 6) // 0x40
#define PUPPYLIGHT_IGNORE_Y (1 << 7) // 0x80
#define LIGHTFLAG_DIRECTIONAL_OFFSET 0x1
#define PUPPYLIGHT_ENVIRONMENT(ambientR, ambientG, ambientB, diffuseR, diffuseG, diffuseB, diffuseX, diffuseY, diffuseZ) \
CMD_BBBB(0x3F, 0x0C, ambientR, ambientG), \
CMD_BBBB(ambientB, diffuseR, diffuseG, diffuseB), \
CMD_BBBB(diffuseX, diffuseY, diffuseZ, 0x0)
#define PUPPYLIGHT_NODE(r, g, b, a, x, y, z, offsetX, offsetY, offsetZ, yaw, epicentre, flags, room) \
CMD_BBBB(0x40, 0x18, r, g), \
CMD_BBH(b, a, x), \
CMD_HH(y, z), \
CMD_HH(offsetX, offsetY), \
CMD_HH(offsetZ, yaw), \
CMD_BBH(epicentre, flags, room)
//How much RAM is allocated to puppylights
#define PUPPYLIGHTS_POOL sizeof(struct PuppyLight) * MAX_LIGHTS
extern Lights1 gLevelLight;
extern u16 gNumLights;
extern u8 levelAmbient;
extern struct PuppyLight *gPuppyLights[MAX_LIGHTS];
extern struct MemoryPool *gLightsPool;
extern void puppylights_run(Lights1 *src, struct Object *obj, s32 flags, u32 baseColour);
extern void puppylights_object_emit(struct Object *obj);
extern void cur_obj_enable_light(void);
extern void cur_obj_disable_light(void);
extern void obj_enable_light(struct Object *obj);
extern void obj_disable_light(struct Object *obj);
extern void set_light_properties(struct PuppyLight *light, s32 x, s32 y, s32 z, s32 offsetX, s32 offsetY, s32 offsetZ, s32 yaw, s32 epicentre, s32 colour, s32 flags, s32 room, s32 active);
extern void puppylights_allocate(void);
extern void delete_lights(void);
#endif
#endif

View File

@@ -12,7 +12,6 @@
#include "object_list_processor.h"
#include "spawn_object.h"
#include "types.h"
#include "puppylights.h"
/**
* Attempt to allocate an object from freeList (singly linked) and append it
@@ -190,9 +189,6 @@ struct Object *allocate_object(struct ObjectNode *objList) {
obj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE;
vec3_same(obj->header.gfx.pos, -10000.0f);
obj->header.gfx.throwMatrix = NULL;
#ifdef PUPPYLIGHTS
obj->oLightID = 0xFFFF;
#endif
return obj;
}