Super Mario 64 Source
A Super Mario 64 decompilation, brought to you by a bunch of clever folks.
Data Structures | Macros | Functions | Variables
shadow.c File Reference

This file implements a self-contained subsystem used to draw shadows. More...

#include <ultra64.h>
#include <math.h>
#include "sm64.h"
#include "shadow.h"
#include "area.h"
#include "engine/graph_node.h"
#include "engine/math_util.h"
#include "engine/surface_collision.h"
#include "mario_animation_ids.h"
#include "mario.h"
#include "memory.h"
#include "rendering_graph_node.h"
#include "room.h"
#include "segment2.h"
#include "save_file.h"
#include "geo_misc.h"

Data Structures

struct  Shadow
 Encapsulation of information about a shadow. More...
 
struct  shadowRectangle
 A struct containing info about hardcoded rectangle shadows. More...
 

Macros

#define SHADOW_SOLIDITY_NO_SHADOW   0
 Constant to indicate that a shadow should not be drawn. More...
 
#define SHADOW_SOILDITY_ALREADY_SET   1
 Constant to indicate that a shadow's solidity has been pre-set by a previous function and should not be overwritten. More...
 
#define SHADOW_SOLIDITY_NOT_YET_SET   2
 Constant to indicate that a shadow's solidity has not yet been set. More...
 
#define SHADOW_SHAPE_CIRCLE   10
 Constant to indicate any sort of circular shadow. More...
 
#define SHADOW_SHAPE_SQUARE   20
 Constant to indicate any sort of rectangular shadow. More...
 
#define SHADOW_WITH_9_VERTS   0
 Constant to indicate a shadow consists of 9 vertices. More...
 
#define SHADOW_WITH_4_VERTS   1
 Constant to indicate a shadow consists of 4 vertices. More...
 

Functions

void rotate_rectangle (f32 *newZ, f32 *newX, f32 oldZ, f32 oldX)
 Let (oldZ, oldX) be the relative coordinates of a point on a rectangle, assumed to be centered at the origin on the standard SM64 X-Z plane. More...
 
f32 atan2_deg (f32 a, f32 b)
 Return atan2(a, b) in degrees. More...
 
f32 scale_shadow_with_distance (f32 initial, f32 distFromFloor)
 Shrink a shadow when its parent object is further from the floor, given the initial size of the shadow and the current distance. More...
 
f32 disable_shadow_with_distance (f32 shadowScale, f32 distFromFloor)
 Disable a shadow when its parent object is more than 600 units from the ground. More...
 
u8 dim_shadow_with_distance (u8 solidity, f32 distFromFloor)
 Dim a shadow when its parent object is further from the ground. More...
 
f32 get_water_level_below_shadow (struct Shadow *s)
 Return the water level below a shadow, or 0 if the water level is below -10,000. More...
 
s8 init_shadow (struct Shadow *s, f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 overwriteSolidity)
 Initialize a shadow. More...
 
void get_texture_coords_9_vertices (s8 vertexNum, s16 *textureX, s16 *textureY)
 Given a vertexNum from a shadow with nine vertices, update the texture coordinates corresponding to that vertex. More...
 
void get_texture_coords_4_vertices (s8 vertexNum, s16 *textureX, s16 *textureY)
 Given a vertexNum from a shadow with four vertices, update the texture coordinates corresponding to that vertex. More...
 
void make_shadow_vertex_at_xyz (Vtx *vertices, s8 index, f32 relX, f32 relY, f32 relZ, u8 alpha, s8 shadowVertexType)
 Make a shadow's vertex at a position relative to its parent. More...
 
f32 extrapolate_vertex_y_position (struct Shadow s, f32 vtxX, f32 vtxZ)
 Given an (x, z)-position close to a shadow, extrapolate the y-position according to the floor's normal vector. More...
 
void get_vertex_coords (s8 index, s8 shadowVertexType, s8 *xCoord, s8 *zCoord)
 Given a shadow vertex with the given index, return the corresponding texture coordinates ranging in the square with corners at (-1, -1), (1, -1), (-1, 1), and (1, 1) in the x-z plane. More...
 
void calculate_vertex_xyz (s8 index, struct Shadow s, f32 *xPosVtx, f32 *yPosVtx, f32 *zPosVtx, s8 shadowVertexType)
 Populate xPosVtx, yPosVtx, and zPosVtx with the (x, y, z) position of the shadow vertex with the given index. More...
 
s16 floor_local_tilt (struct Shadow s, f32 vtxX, f32 vtxY, f32 vtxZ)
 Given a vertex's location, return the dot product of the position of that vertex (relative to the shadow's center) with the floor normal (at the shadow's center). More...
 
void make_shadow_vertex (Vtx *vertices, s8 index, struct Shadow s, s8 shadowVertexType)
 Make a particular vertex from a shadow, calculating its position and solidity. More...
 
void add_shadow_to_display_list (Gfx *displayListHead, Vtx *verts, s8 shadowVertexType, s8 shadowShape)
 Add a shadow to the given display list. More...
 
void linearly_interpolate_solidity_positive (struct Shadow *s, u8 finalSolidity, s16 curr, s16 start, s16 end)
 Linearly interpolate a shadow's solidity between zero and finalSolidity depending on curr's relation to start and end. More...
 
void linearly_interpolate_solidity_negative (struct Shadow *s, u8 initialSolidity, s16 curr, s16 start, s16 end)
 Linearly interpolate a shadow's solidity between initialSolidity and zero depending on curr's relation to start and end. More...
 
s8 correct_shadow_solidity_for_animations (s32 isLuigi, u8 initialSolidity, struct Shadow *shadow)
 Change a shadow's solidity based on the player's current animation frame. More...
 
void correct_lava_shadow_height (struct Shadow *s)
 Slightly change the height of a shadow in levels with lava. More...
 
Gfxcreate_shadow_player (f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 solidity, s32 isLuigi)
 Create a shadow under a player, correcting that shadow's opacity during appropriate animations and other states. More...
 
Gfxcreate_shadow_circle_9_verts (f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 solidity)
 Create a circular shadow composed of 9 vertices. More...
 
Gfxcreate_shadow_circle_4_verts (f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 solidity)
 Create a circular shadow composed of 4 vertices. More...
 
Gfxcreate_shadow_circle_assuming_flat_ground (f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 solidity)
 Create a circular shadow composed of 4 vertices and assume that the ground underneath it is totally flat. More...
 
Gfxcreate_shadow_rectangle (f32 halfWidth, f32 halfLength, f32 relY, u8 solidity)
 Create a rectangular shadow composed of 4 vertices. More...
 
s32 get_shadow_height_solidity (f32 xPos, f32 yPos, f32 zPos, f32 *shadowHeight, u8 *solidity)
 Populate shadowHeight and solidity appropriately; the default solidity value is 200. More...
 
Gfxcreate_shadow_square (f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 solidity, s8 shadowType)
 Create a square shadow composed of 4 vertices. More...
 
Gfxcreate_shadow_hardcoded_rectangle (f32 xPos, f32 yPos, f32 zPos, UNUSED s16 shadowScale, u8 solidity, s8 shadowType)
 Create a rectangular shadow whose parameters have been hardcoded in the rectangles array. More...
 
Gfxcreate_shadow_below_xyz (f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 shadowSolidity, s8 shadowType)
 Create a shadow at the absolute position given, with the given parameters. More...
 

Variables

shadowRectangle rectangles [2]
 An array consisting of all the hardcoded rectangle shadows in the game. More...
 
s8 sMarioOnFlyingCarpet
 Flag for if Mario is on a flying carpet. More...
 
s16 sSurfaceTypeBelowShadow
 The surface type below the current shadow. More...
 
s8 gShadowAboveWaterOrLava
 Flag for if the current shadow is above water or lava. More...
 
s8 gMarioOnIceOrCarpet
 Flag for if Mario is on ice or a flying carpet. More...
 

Detailed Description

This file implements a self-contained subsystem used to draw shadows.

Macro Definition Documentation

◆ SHADOW_SHAPE_CIRCLE

#define SHADOW_SHAPE_CIRCLE   10

Constant to indicate any sort of circular shadow.

◆ SHADOW_SHAPE_SQUARE

#define SHADOW_SHAPE_SQUARE   20

Constant to indicate any sort of rectangular shadow.

◆ SHADOW_SOILDITY_ALREADY_SET

#define SHADOW_SOILDITY_ALREADY_SET   1

Constant to indicate that a shadow's solidity has been pre-set by a previous function and should not be overwritten.

◆ SHADOW_SOLIDITY_NO_SHADOW

#define SHADOW_SOLIDITY_NO_SHADOW   0

Constant to indicate that a shadow should not be drawn.

This is used to disable shadows during specific frames of Mario's animations.

◆ SHADOW_SOLIDITY_NOT_YET_SET

#define SHADOW_SOLIDITY_NOT_YET_SET   2

Constant to indicate that a shadow's solidity has not yet been set.

◆ SHADOW_WITH_4_VERTS

#define SHADOW_WITH_4_VERTS   1

Constant to indicate a shadow consists of 4 vertices.

◆ SHADOW_WITH_9_VERTS

#define SHADOW_WITH_9_VERTS   0

Constant to indicate a shadow consists of 9 vertices.

Function Documentation

◆ add_shadow_to_display_list()

void add_shadow_to_display_list ( Gfx displayListHead,
Vtx verts,
s8  shadowVertexType,
s8  shadowShape 
)

Add a shadow to the given display list.

◆ atan2_deg()

f32 atan2_deg ( f32  a,
f32  b 
)

Return atan2(a, b) in degrees.

Note that the argument order is swapped from the standard atan2.

◆ calculate_vertex_xyz()

void calculate_vertex_xyz ( s8  index,
struct Shadow  s,
f32 xPosVtx,
f32 yPosVtx,
f32 zPosVtx,
s8  shadowVertexType 
)

Populate xPosVtx, yPosVtx, and zPosVtx with the (x, y, z) position of the shadow vertex with the given index.

If the shadow is to have 9 vertices, then each of those vertices is clamped down to the floor below it. Otherwise, in the 4 vertex case, the vertex positions are extrapolated from the center of the shadow.

In practice, due to the if-statement in make_shadow_vertex(), the 9 vertex and 4 vertex cases are identical, and the above-described clamping behavior is overwritten.

Note that this dichotomy is later overwritten in make_shadow_vertex().

◆ correct_lava_shadow_height()

void correct_lava_shadow_height ( struct Shadow s)

Slightly change the height of a shadow in levels with lava.

◆ correct_shadow_solidity_for_animations()

s8 correct_shadow_solidity_for_animations ( s32  isLuigi,
u8  initialSolidity,
struct Shadow shadow 
)

Change a shadow's solidity based on the player's current animation frame.

This is evidence of a removed second player, likely Luigi. This variable lies in memory just after the gMarioObject and has the same type of shadow that Mario does. The isLuigi variable is never 1 in the game. Note that since this was a switch-case, not an if-statement, the programmers possibly intended there to be even more than 2 characters.

◆ create_shadow_below_xyz()

Gfx* create_shadow_below_xyz ( f32  xPos,
f32  yPos,
f32  zPos,
s16  shadowScale,
u8  shadowSolidity,
s8  shadowType 
)

Create a shadow at the absolute position given, with the given parameters.

Given the (x, y, z) location of an object, create a shadow below that object with the given initial solidity and "shadowType" (described above).

Return a pointer to the display list representing the shadow.

◆ create_shadow_circle_4_verts()

Gfx* create_shadow_circle_4_verts ( f32  xPos,
f32  yPos,
f32  zPos,
s16  shadowScale,
u8  solidity 
)

Create a circular shadow composed of 4 vertices.

◆ create_shadow_circle_9_verts()

Gfx* create_shadow_circle_9_verts ( f32  xPos,
f32  yPos,
f32  zPos,
s16  shadowScale,
u8  solidity 
)

Create a circular shadow composed of 9 vertices.

◆ create_shadow_circle_assuming_flat_ground()

Gfx* create_shadow_circle_assuming_flat_ground ( f32  xPos,
f32  yPos,
f32  zPos,
s16  shadowScale,
u8  solidity 
)

Create a circular shadow composed of 4 vertices and assume that the ground underneath it is totally flat.

◆ create_shadow_hardcoded_rectangle()

Gfx* create_shadow_hardcoded_rectangle ( f32  xPos,
f32  yPos,
f32  zPos,
UNUSED s16  shadowScale,
u8  solidity,
s8  shadowType 
)

Create a rectangular shadow whose parameters have been hardcoded in the rectangles array.

Note that idx could be negative or otherwise out of the bounds of the rectangles array. In practice, it never is, because this was only used twice.

◆ create_shadow_player()

Gfx* create_shadow_player ( f32  xPos,
f32  yPos,
f32  zPos,
s16  shadowScale,
u8  solidity,
s32  isLuigi 
)

Create a shadow under a player, correcting that shadow's opacity during appropriate animations and other states.

◆ create_shadow_rectangle()

Gfx* create_shadow_rectangle ( f32  halfWidth,
f32  halfLength,
f32  relY,
u8  solidity 
)

Create a rectangular shadow composed of 4 vertices.

This assumes the ground underneath the shadow is totally flat.

◆ create_shadow_square()

Gfx* create_shadow_square ( f32  xPos,
f32  yPos,
f32  zPos,
s16  shadowScale,
u8  solidity,
s8  shadowType 
)

Create a square shadow composed of 4 vertices.

◆ dim_shadow_with_distance()

u8 dim_shadow_with_distance ( u8  solidity,
f32  distFromFloor 
)

Dim a shadow when its parent object is further from the ground.

◆ disable_shadow_with_distance()

f32 disable_shadow_with_distance ( f32  shadowScale,
f32  distFromFloor 
)

Disable a shadow when its parent object is more than 600 units from the ground.

◆ extrapolate_vertex_y_position()

f32 extrapolate_vertex_y_position ( struct Shadow  s,
f32  vtxX,
f32  vtxZ 
)

Given an (x, z)-position close to a shadow, extrapolate the y-position according to the floor's normal vector.

◆ floor_local_tilt()

s16 floor_local_tilt ( struct Shadow  s,
f32  vtxX,
f32  vtxY,
f32  vtxZ 
)

Given a vertex's location, return the dot product of the position of that vertex (relative to the shadow's center) with the floor normal (at the shadow's center).

Since it is a dot product, this returns 0 if these two vectors are perpendicular, meaning the ground is locally flat. It returns nonzero in most cases where vtxY is on a different floor triangle from the center vertex, as in the case with SHADOW_WITH_9_VERTS, which sets the y-value from find_floor_height_and_data. (See the bottom of calculate_vertex_xyz.)

◆ get_shadow_height_solidity()

s32 get_shadow_height_solidity ( f32  xPos,
f32  yPos,
f32  zPos,
f32 shadowHeight,
u8 solidity 
)

Populate shadowHeight and solidity appropriately; the default solidity value is 200.

Return 0 if a shadow should be drawn, 1 if not.

◆ get_texture_coords_4_vertices()

void get_texture_coords_4_vertices ( s8  vertexNum,
s16 textureX,
s16 textureY 
)

Given a vertexNum from a shadow with four vertices, update the texture coordinates corresponding to that vertex.

That is: 0 = (-15, -15) 1 = (15, -15) 2 = (-15, 15) 3 = (15, 15)

◆ get_texture_coords_9_vertices()

void get_texture_coords_9_vertices ( s8  vertexNum,
s16 textureX,
s16 textureY 
)

Given a vertexNum from a shadow with nine vertices, update the texture coordinates corresponding to that vertex.

That is: 0 = (-15, -15) 1 = (0, -15) 2 = (15, -15) 3 = (-15, 0) 4 = (0, 0) 5 = (15, 0) 6 = (-15, 15) 7 = (0, 15) 8 = (15, 15)

◆ get_vertex_coords()

void get_vertex_coords ( s8  index,
s8  shadowVertexType,
s8 xCoord,
s8 zCoord 
)

Given a shadow vertex with the given index, return the corresponding texture coordinates ranging in the square with corners at (-1, -1), (1, -1), (-1, 1), and (1, 1) in the x-z plane.

See get_texture_coords_9_vertices() and get_texture_coords_4_vertices(), which have similar functionality, but return 15 times these values.

◆ get_water_level_below_shadow()

f32 get_water_level_below_shadow ( struct Shadow s)

Return the water level below a shadow, or 0 if the water level is below -10,000.

Bug:
Missing return statement. This compiles to return waterLevel incidentally.

◆ init_shadow()

s8 init_shadow ( struct Shadow s,
f32  xPos,
f32  yPos,
f32  zPos,
s16  shadowScale,
u8  overwriteSolidity 
)

Initialize a shadow.

Return 0 on success, 1 on failure.

Parameters
xPos,yPos,zPosPosition of the parent object (not the shadow)
shadowScaleDiameter of the shadow
overwriteSolidityFlag for whether the existing shadow solidity should be dimmed based on its distance to the floor
Bug:
Use of potentially undefined variable waterLevel

◆ linearly_interpolate_solidity_negative()

void linearly_interpolate_solidity_negative ( struct Shadow s,
u8  initialSolidity,
s16  curr,
s16  start,
s16  end 
)

Linearly interpolate a shadow's solidity between initialSolidity and zero depending on curr's relation to start and end.

Note that if curr < start, the solidity will be zero.

◆ linearly_interpolate_solidity_positive()

void linearly_interpolate_solidity_positive ( struct Shadow s,
u8  finalSolidity,
s16  curr,
s16  start,
s16  end 
)

Linearly interpolate a shadow's solidity between zero and finalSolidity depending on curr's relation to start and end.

◆ make_shadow_vertex()

void make_shadow_vertex ( Vtx vertices,
s8  index,
struct Shadow  s,
s8  shadowVertexType 
)

Make a particular vertex from a shadow, calculating its position and solidity.

This is the hack that makes "SHADOW_WITH_9_VERTS" act identically to "SHADOW_WITH_4_VERTS" in the game; this same hack is disabled by the GameShark code in this video: https://youtu.be/MSIh4rtNGF0. The code in the video makes extrapolate_vertex_y_position return the same value as the last-called function that returns a float; in this case, that's find_floor_height_and_data, which this if-statement was designed to overwrite in the first place. Thus, this if-statement is disabled by that code.

The last condition here means the y-position calculated previously was probably on a different floor triangle from the center vertex. The gShadowAboveWaterOrLava check is redundant, since floor_local_tilt will always be 0 over water or lava (since they are always flat).

◆ make_shadow_vertex_at_xyz()

void make_shadow_vertex_at_xyz ( Vtx vertices,
s8  index,
f32  relX,
f32  relY,
f32  relZ,
u8  alpha,
s8  shadowVertexType 
)

Make a shadow's vertex at a position relative to its parent.

Parameters
verticesA preallocated display list for vertices
indexIndex into vertices to insert the vertex
relX,relY,relZVertex position relative to its parent object
alphaOpacity of the vertex
shadowVertexTypeOne of SHADOW_WITH_9_VERTS or SHADOW_WITH_4_VERTS

◆ rotate_rectangle()

void rotate_rectangle ( f32 newZ,
f32 newX,
f32  oldZ,
f32  oldX 
)

Let (oldZ, oldX) be the relative coordinates of a point on a rectangle, assumed to be centered at the origin on the standard SM64 X-Z plane.

This function will update (newZ, newX) to equal the new coordinates of that point after a rotation equal to the yaw of the current graph node object.

◆ scale_shadow_with_distance()

f32 scale_shadow_with_distance ( f32  initial,
f32  distFromFloor 
)

Shrink a shadow when its parent object is further from the floor, given the initial size of the shadow and the current distance.

Variable Documentation

◆ gMarioOnIceOrCarpet

s8 gMarioOnIceOrCarpet

Flag for if Mario is on ice or a flying carpet.

◆ gShadowAboveWaterOrLava

s8 gShadowAboveWaterOrLava

Flag for if the current shadow is above water or lava.

◆ rectangles

shadowRectangle rectangles[2]
Initial value:
= {
{ 360.0f, 230.0f, TRUE },
{ 200.0f, 180.0f, TRUE }
}
#define TRUE
Definition: ultratypes.h:8

An array consisting of all the hardcoded rectangle shadows in the game.

◆ sMarioOnFlyingCarpet

s8 sMarioOnFlyingCarpet

Flag for if Mario is on a flying carpet.

◆ sSurfaceTypeBelowShadow

s16 sSurfaceTypeBelowShadow

The surface type below the current shadow.