Add base editor, with improved UI and support for color codes

This commit is contained in:
Llennpie 2021-10-07 19:53:55 -04:00
parent d1f5da5ca5
commit 37e47e6451
47 changed files with 2054 additions and 165 deletions

View File

@ -123,7 +123,7 @@ endif
# Release (version) flag defs
VERSION_DEF := VERSION_US
TARGET := moon64.$(VERSION)
TARGET := saturn.$(VERSION)
VERSION_CFLAGS := -D$(VERSION_DEF) -D_LANGUAGE_C
VERSION_ASFLAGS := --defsym $(VERSION_DEF)=1
@ -672,8 +672,10 @@ ifeq ($(TARGET_SWITCH),1)
all: $(EXE).nro
endif
ADDONS := addons
ADDONS_PATH := $(BUILD_DIR)/$(ADDONS)/
ADDONS := addons
ADDONS_PATH := $(BUILD_DIR)/$(ADDONS)/
MACHINIMA := machinima
MACHINIMA_PATH := $(BUILD_DIR)/$(MACHINIMA)/
BASEPACK_LST := $(BUILD_DIR)/basepack.lst
# depend on resources as well
@ -721,7 +723,7 @@ $(BUILD_DIR)/src/game/crash_screen.o: $(CRASH_TEXTURE_C_FILES)
$(BUILD_DIR)/lib/rsp.o: $(BUILD_DIR)/rsp/rspboot.bin $(BUILD_DIR)/rsp/fast3d.bin $(BUILD_DIR)/rsp/audio.bin
RSP_DIRS := $(BUILD_DIR)/rsp
ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(GODDARD_SRC_DIRS) $(ULTRA_SRC_DIRS) $(ULTRA_ASM_DIRS) $(ULTRA_BIN_DIRS) $(BIN_DIRS) $(TEXTURE_DIRS) $(SOUND_SAMPLE_DIRS) $(addprefix levels/,$(LEVEL_DIRS)) include) $(MIO0_DIR) $(addprefix $(MIO0_DIR)/,$(VERSION)) $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/sequences/$(VERSION) $(RSP_DIRS) $(ADDONS_PATH)
ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(GODDARD_SRC_DIRS) $(ULTRA_SRC_DIRS) $(ULTRA_ASM_DIRS) $(ULTRA_BIN_DIRS) $(BIN_DIRS) $(TEXTURE_DIRS) $(SOUND_SAMPLE_DIRS) $(addprefix levels/,$(LEVEL_DIRS)) include) $(MIO0_DIR) $(addprefix $(MIO0_DIR)/,$(VERSION)) $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/sequences/$(VERSION) $(RSP_DIRS) $(ADDONS_PATH) $(MACHINIMA_PATH)
# Make sure build directory exists before compiling anything
DUMMY != mkdir -p $(ALL_DIRS)

View File

@ -14,8 +14,8 @@ static const Lights1 mario_red_lights_group = gdSPDefLights1(
// 0x04000030 # solid color white - metal butt & left thigh - normal left & right hand closed & open (with cap too) and all wings - all poly types
static const Lights1 mario_white_lights_group = gdSPDefLights1(
0x7f, 0x7f, 0x7f,
0xff, 0xff, 0xff, 0x28, 0x28, 0x28
0x00, 0x7f, 0x00,
0x00, 0xff, 0x00, 0x28, 0x28, 0x28
);
// 0x04000048 # solid color brown 1 - foot - all poly types

View File

@ -118,6 +118,10 @@ struct GraphNodeObject_sub
/*0x0A 0x42*/ u16 animTimer;
/*0x0C 0x44*/ s32 animFrameAccelAssist;
/*0x10 0x48*/ s32 animAccel;
s16 prevAnimFrame;
s16 prevAnimID;
u32 prevAnimFrameTimestamp;
struct Animation *prevAnimPtr;
};
struct GraphNodeObject
@ -128,11 +132,22 @@ struct GraphNodeObject
/*0x19*/ s8 unk19;
/*0x1A*/ Vec3s angle;
/*0x20*/ Vec3f pos;
Vec3s prevAngle;
Vec3f prevPos;
u32 prevTimestamp;
Vec3f prevShadowPos;
u32 prevShadowPosTimestamp;
/*0x2C*/ Vec3f scale;
Vec3f prevScale;
u32 prevScaleTimestamp;
/*0x38*/ struct GraphNodeObject_sub unk38;
/*0x4C*/ struct SpawnInfo *unk4C;
/*0x50*/ Mat4 *throwMatrix; // matrix ptr
Mat4 prevThrowMatrix;
u32 prevThrowMatrixTimestamp;
Mat4 *throwMatrixInterpolated;
/*0x54*/ Vec3f cameraToObject;
u32 skipInterpolationTimestamp;
};
struct ObjectNode
@ -243,6 +258,10 @@ struct Surface
} normal;
/*0x28*/ f32 originOffset;
/*0x2C*/ struct Object *object;
Vec3s prevVertex1;
Vec3s prevVertex2;
Vec3s prevVertex3;
u32 modifiedTimestamp;
};
struct MarioBodyState

BIN
platform/win/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

18
platform/win/info.rc Normal file
View File

@ -0,0 +1,18 @@
IDI_ICON1 ICON DISCARDABLE "icon.ico"
1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "InternalName", "v64saturn"
VALUE "ProductName", "Saturn"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0
END
END

72
src/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,72 @@
{
"files.associations": {
"random": "c",
"saturn.h": "c",
"achievements.h": "c",
"cheats.h": "c",
"save_file.h": "c",
"saturn_types.h": "c",
"object_list_processor.h": "c",
"typeinfo": "c",
"vector": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"unordered_map": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"ratio": "cpp",
"regex": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"shared_mutex": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"valarray": "cpp",
"compare": "cpp",
"concepts": "cpp",
"ranges": "cpp"
}
}

View File

@ -110,6 +110,8 @@ struct GraphNodePerspective
/*0x1C*/ f32 fov; // horizontal field of view in degrees
/*0x20*/ s16 near; // near clipping plane
/*0x22*/ s16 far; // far clipping plane
f32 prevFov;
f32 prevTimestamp;
};
/** An entry in the master list. It is a linked list of display lists
@ -118,7 +120,9 @@ struct GraphNodePerspective
struct DisplayListNode
{
Mtx *transform;
void *transformInterpolated;
void *displayList;
void *displayListInterpolated;
struct DisplayListNode *next;
};
@ -185,7 +189,11 @@ struct GraphNodeCamera
} config;
/*0x1C*/ Vec3f pos;
/*0x28*/ Vec3f focus;
Vec3f prevPos;
Vec3f prevFocus;
u32 prevTimestamp;
/*0x34*/ Mat4 *matrixPtr; // pointer to look-at matrix of this camera as a Mat4
Mat4 *matrixPtrInterpolated;
/*0x38*/ s16 roll; // roll in look at matrix. Doesn't account for light direction unlike rollScreen.
/*0x3A*/ s16 rollScreen; // rolls screen while keeping the light direction consistent
};
@ -226,7 +234,8 @@ struct GraphNodeRotation
/*0x00*/ struct GraphNode node;
/*0x14*/ void *displayList;
/*0x18*/ Vec3s rotation;
u8 pad1E[2];
Vec3s prevRotation;
u32 prevTimestamp;
};
/** GraphNode part that transforms itself and its children based on animation
@ -323,6 +332,9 @@ struct GraphNodeBackground
/*0x00*/ struct FnGraphNode fnNode;
/*0x18*/ s32 unused;
/*0x1C*/ s32 background; // background ID, or rgba5551 color if fnNode.func is null
Vec3f prevCameraPos;
Vec3f prevCameraFocus;
u32 prevCameraTimestamp;
};
/** Renders the object that Mario is holding.
@ -333,6 +345,8 @@ struct GraphNodeHeldObject
/*0x18*/ s32 playerIndex;
/*0x1C*/ struct Object *objNode;
/*0x20*/ Vec3s translation;
Vec3f prevShadowPos;
u32 prevShadowPosTimestamp;
};
/** A node that allows an object to specify a different culling radius than the

View File

@ -8,6 +8,7 @@
#include "surface_collision.h"
#include "surface_load.h"
#include "math_util.h"
#include "game/game_init.h"
/**************************************************
* WALLS *
@ -394,26 +395,44 @@ f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometr
return floorHeight;
}
u8 gInterpolatingSurfaces;
/**
* Iterate through the list of floors and find the first floor under a given point.
*/
static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) {
register struct Surface *surf;
register s32 x1, z1, x2, z2, x3, z3;
register f32 x1, z1, x2, z2, x3, z3;
f32 nx, ny, nz;
f32 oo;
f32 height;
struct Surface *floor = NULL;
s32 interpolate;
// Iterate through the list of floors until there are no more floors.
while (surfaceNode != NULL) {
surf = surfaceNode->surface;
surfaceNode = surfaceNode->next;
interpolate = gInterpolatingSurfaces && surf->modifiedTimestamp == gGlobalTimer;
x1 = surf->vertex1[0];
z1 = surf->vertex1[2];
x2 = surf->vertex2[0];
z2 = surf->vertex2[2];
if (interpolate) {
f32 diff = (surf->prevVertex1[0] - x1) * (surf->prevVertex1[0] - x1);
diff += (surf->prevVertex1[1] - surf->vertex1[1]) * (surf->prevVertex1[1] - surf->vertex1[1]);
diff += (surf->prevVertex1[2] - z1) * (surf->prevVertex1[2] - z1);
//printf("%f\n", sqrtf(diff));
if (diff > 10000) {
interpolate = FALSE;
} else {
x1 = (surf->prevVertex1[0] + x1) / 2;
z1 = (surf->prevVertex1[2] + z1) / 2;
x2 = (surf->prevVertex2[0] + x2) / 2;
z2 = (surf->prevVertex2[2] + z2) / 2;
}
}
// Check that the point is within the triangle bounds.
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 0) {
@ -423,6 +442,10 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
// To slightly save on computation time, set this later.
x3 = surf->vertex3[0];
z3 = surf->vertex3[2];
if (interpolate) {
x3 = (surf->prevVertex3[0] + x3) / 2;
z3 = (surf->prevVertex3[2] + z3) / 2;
}
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) < 0) {
continue;
@ -442,10 +465,30 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
continue;
}
nx = surf->normal.x;
ny = surf->normal.y;
nz = surf->normal.z;
oo = surf->originOffset;
if (interpolate) {
f32 y1, y2, y3;
f32 mag;
y1 = (surf->prevVertex1[1] + surf->vertex1[1]) / 2;
y2 = (surf->prevVertex2[1] + surf->vertex2[1]) / 2;
y3 = (surf->prevVertex3[1] + surf->vertex3[1]) / 2;
nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2);
ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2);
nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
mag = sqrtf(nx * nx + ny * ny + nz * nz);
if (mag < 0.0001) {
continue;
}
mag = (f32)(1.0 / mag);
nx *= mag;
ny *= mag;
nz *= mag;
oo = -(nx * x1 + ny * y1 + nz * z1);
} else {
nx = surf->normal.x;
ny = surf->normal.y;
nz = surf->normal.z;
oo = surf->originOffset;
}
// If a wall, ignore it. Likely a remnant, should never occur.
if (ny == 0.0f) {
@ -460,6 +503,15 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
}
*pheight = height;
if (interpolate) {
static struct Surface s;
s.type = surf->type;
s.normal.x = nx;
s.normal.y = ny;
s.normal.z = nz;
s.originOffset = oo;
return &s;
}
floor = surf;
break;
}

View File

@ -14,6 +14,7 @@
#include "game/mario.h"
#include "game/object_list_processor.h"
#include "surface_load.h"
#include "game/game_init.h"
s32 unused8038BE90;
@ -354,6 +355,11 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) {
surface = alloc_surface();
vec3s_copy(surface->prevVertex1, surface->vertex1);
vec3s_copy(surface->prevVertex2, surface->vertex2);
vec3s_copy(surface->prevVertex3, surface->vertex3);
surface->modifiedTimestamp = gGlobalTimer;
surface->vertex1[0] = x1;
surface->vertex2[0] = x2;
surface->vertex3[0] = x3;

View File

@ -11617,4 +11617,4 @@ void obj_rotate_towards_point(struct Object *o, Vec3f point, s16 pitchOff, s16 y
#include "behaviors/intro_lakitu.inc.c"
#include "behaviors/end_birds_1.inc.c"
#include "behaviors/end_birds_2.inc.c"
#include "behaviors/intro_scene.inc.c"
#include "behaviors/intro_scene.inc.c"

View File

@ -657,6 +657,8 @@ struct LakituState
/// Mario's action from the previous frame. Only used to determine if Mario just finished a dive.
/*0xB8*/ u32 lastFrameAction;
/*0xBC*/ s16 unused;
u32 skipCameraInterpolationTimestamp;
};
// bss order hack to not affect BSS order. if possible, remove me, but it will be hard to match otherwise
@ -773,4 +775,7 @@ void obj_rotate_towards_point(struct Object *o, Vec3f point, s16 pitchOff, s16 y
Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context);
extern u8 machinimaMode;
extern f32 camVelSpeed;
#endif // CAMERA_H

View File

@ -35,6 +35,20 @@ Vtx_t gBubbleTempVtx[3] = {
{ { 0, 0, 0 }, 0, { -498, 964 }, { 0xFF, 0xFF, 0xFF, 0xFF } },
};
static Gfx sGfxSaved[60 / 5];
static Gfx *sBubbleInterpolatedDisplayListPos[60 / 5];
static Vec3s sPrevBubblePositions[60];
void patch_interpolated_bubble_particles(void) {
s32 i;
for (i = 0; i < 60 / 5; i++) {
if (sBubbleInterpolatedDisplayListPos[i] != NULL) {
*sBubbleInterpolatedDisplayListPos[i] = sGfxSaved[i];
sBubbleInterpolatedDisplayListPos[i] = NULL;
}
}
}
/**
* Check whether the particle with the given index is
* laterally within distance of point (x, z). Used to
@ -241,6 +255,7 @@ void envfx_update_whirlpool(void) {
(gEnvFxBuffer + i)->yPos = (i + gEnvFxBuffer)->bubbleY;
(gEnvFxBuffer + i)->unusedBubbleVar = 0;
(gEnvFxBuffer + i)->isAlive = 1;
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos,
&(gEnvFxBuffer + i)->zPos);
@ -299,6 +314,7 @@ void envfx_update_jetstream(void) {
+ coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1];
(gEnvFxBuffer + i)->yPos =
gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (random_float() * 400.0f - 200.0f);
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
} else {
(gEnvFxBuffer + i)->angleAndDist[1] += 10;
(gEnvFxBuffer + i)->xPos += sins((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f;
@ -506,6 +522,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
Vec3s vertex1;
Vec3s vertex2;
Vec3s vertex3;
Vec3s interpolatedVertices[3];
static Vec3s prevVertex1;
static Vec3s prevVertex2;
static Vec3s prevVertex3;
static u32 prevTimestamp;
Gfx *gfxStart;
@ -521,18 +543,52 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3);
rotate_triangle_vertices(vertex1, vertex2, vertex3, pitch, yaw);
if (gGlobalTimer == prevTimestamp + 1) {
interpolate_vectors_s16(interpolatedVertices[0], prevVertex1, vertex1);
interpolate_vectors_s16(interpolatedVertices[1], prevVertex2, vertex2);
interpolate_vectors_s16(interpolatedVertices[2], prevVertex3, vertex3);
}
vec3s_copy(prevVertex1, vertex1);
vec3s_copy(prevVertex2, vertex2);
vec3s_copy(prevVertex3, vertex3);
prevTimestamp = gGlobalTimer;
gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006D38);
for (i = 0; i < sBubbleParticleMaxCount; i += 5) {
Vtx *interpolatedVertBuf = alloc_display_list(15 * sizeof(Vtx));
s32 j, k;
gDPPipeSync(sGfxCursor++);
envfx_set_bubble_texture(mode, i);
append_bubble_vertex_buffer(sGfxCursor++, i, vertex1, vertex2, vertex3, (Vtx *) gBubbleTempVtx);
sBubbleInterpolatedDisplayListPos[i / 5] = sGfxCursor;
for (j = 0; j < 5; j++) {
for (k = 0; k < 3; k++) {
Vtx *v = &interpolatedVertBuf[j * 3 + k];
v->v = gBubbleTempVtx[k];
if (gGlobalTimer != gEnvFxBuffer[i + j].spawnTimestamp && mode != ENVFX_LAVA_BUBBLES) {
v->v.ob[0] = (sPrevBubblePositions[i + j][0] + gEnvFxBuffer[i + j].xPos) / 2.0f + interpolatedVertices[k][0];
v->v.ob[1] = (sPrevBubblePositions[i + j][1] + gEnvFxBuffer[i + j].yPos) / 2.0f + interpolatedVertices[k][1];
v->v.ob[2] = (sPrevBubblePositions[i + j][2] + gEnvFxBuffer[i + j].zPos) / 2.0f + interpolatedVertices[k][2];
} else {
v->v.ob[0] = gEnvFxBuffer[i + j].xPos + interpolatedVertices[k][0];
v->v.ob[1] = gEnvFxBuffer[i + j].yPos + interpolatedVertices[k][1];
v->v.ob[2] = gEnvFxBuffer[i + j].zPos + interpolatedVertices[k][2];
}
}
}
gSPVertex(sGfxCursor++, VIRTUAL_TO_PHYSICAL(interpolatedVertBuf), 15, 0);
append_bubble_vertex_buffer(&sGfxSaved[i / 5], i, vertex1, vertex2, vertex3, (Vtx *) gBubbleTempVtx);
gSP1Triangle(sGfxCursor++, 0, 1, 2, 0);
gSP1Triangle(sGfxCursor++, 3, 4, 5, 0);
gSP1Triangle(sGfxCursor++, 6, 7, 8, 0);
gSP1Triangle(sGfxCursor++, 9, 10, 11, 0);
gSP1Triangle(sGfxCursor++, 12, 13, 14, 0);
}
for (i = 0; i < sBubbleParticleMaxCount; i++) {
sPrevBubblePositions[i][0] = gEnvFxBuffer[i].xPos;
sPrevBubblePositions[i][1] = gEnvFxBuffer[i].yPos;
sPrevBubblePositions[i][2] = gEnvFxBuffer[i].zPos;
}
gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006AB0);
gSPEndDisplayList(sGfxCursor++);

View File

@ -54,6 +54,26 @@ extern void *tiny_bubble_dl_0B006AB0;
extern void *tiny_bubble_dl_0B006A50;
extern void *tiny_bubble_dl_0B006CD8;
static struct {
Gfx *pos;
Vtx vertices[15];
} sPrevSnowVertices[140 / 5];
static s16 sPrevSnowParticleCount;
static u32 sPrevSnowTimestamp;
void patch_interpolated_snow_particles(void) {
int i;
if (gGlobalTimer != sPrevSnowTimestamp + 1) {
return;
}
for (i = 0; i < sPrevSnowParticleCount; i += 5) {
gSPVertex(sPrevSnowVertices[i / 5].pos,
VIRTUAL_TO_PHYSICAL(sPrevSnowVertices[i / 5].vertices), 15, 0);
}
}
/**
* Initialize snow particles by allocating a buffer for storing their state
* and setting a start amount.
@ -217,6 +237,7 @@ void envfx_update_snow_normal(s32 snowCylinderX, s32 snowCylinderY, s32 snowCyli
400.0f * random_float() - 200.0f + snowCylinderZ + (s16)(deltaZ * 2);
(gEnvFxBuffer + i)->yPos = 200.0f * random_float() + snowCylinderY;
(gEnvFxBuffer + i)->isAlive = 1;
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
} else {
(gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2);
(gEnvFxBuffer + i)->yPos -= 2 -(s16)(deltaY * 0.8);
@ -251,6 +272,7 @@ void envfx_update_snow_blizzard(s32 snowCylinderX, s32 snowCylinderY, s32 snowCy
400.0f * random_float() - 200.0f + snowCylinderZ + (s16)(deltaZ * 2);
(gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY;
(gEnvFxBuffer + i)->isAlive = 1;
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
} else {
(gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2) + 20.0f;
(gEnvFxBuffer + i)->yPos -= 5 -(s16)(deltaY * 0.8);
@ -294,6 +316,7 @@ void envfx_update_snow_water(s32 snowCylinderX, s32 snowCylinderY, s32 snowCylin
(gEnvFxBuffer + i)->zPos = 400.0f * random_float() - 200.0f + snowCylinderZ;
(gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY;
(gEnvFxBuffer + i)->isAlive = 1;
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
}
}
}
@ -346,6 +369,8 @@ void rotate_triangle_vertices(Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, s16 p
void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3) {
s32 i = 0;
Vtx *vertBuf = (Vtx *) alloc_display_list(15 * sizeof(Vtx));
Vtx *vertBufInterpolated = (Vtx *) alloc_display_list(15 * sizeof(Vtx));
Vtx *v;
#ifdef VERSION_EU
Vtx *p;
#endif
@ -395,7 +420,23 @@ void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s ve
#endif
}
gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBuf), 15, 0);
for (i = 0; i < 15; i++) {
v = &sPrevSnowVertices[index / 5].vertices[i];
vertBufInterpolated[i] = gSnowTempVtx[i % 3];
if (index < sPrevSnowParticleCount && gGlobalTimer == sPrevSnowTimestamp + 1 &&
gGlobalTimer != gEnvFxBuffer[index + i / 3].spawnTimestamp) {
vertBufInterpolated[i].v.ob[0] = (v->v.ob[0] + vertBuf[i].v.ob[0]) / 2;
vertBufInterpolated[i].v.ob[1] = (v->v.ob[1] + vertBuf[i].v.ob[1]) / 2;
vertBufInterpolated[i].v.ob[2] = (v->v.ob[2] + vertBuf[i].v.ob[2]) / 2;
} else {
vertBufInterpolated[i].v.ob[0] = vertBuf[i].v.ob[0];
vertBufInterpolated[i].v.ob[1] = vertBuf[i].v.ob[1];
vertBufInterpolated[i].v.ob[2] = vertBuf[i].v.ob[2];
}
*v = vertBuf[i];
}
sPrevSnowVertices[index / 5].pos = gfx;
gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBufInterpolated), 15, 0);
}
/**
@ -479,6 +520,8 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo)
gSP1Triangle(gfx++, 9, 10, 11, 0);
gSP1Triangle(gfx++, 12, 13, 14, 0);
}
sPrevSnowParticleCount = gSnowParticleCount;
sPrevSnowTimestamp = gGlobalTimer;
gSPDisplayList(gfx++, &tiny_bubble_dl_0B006AB0) gSPEndDisplayList(gfx++);

View File

@ -25,7 +25,8 @@ struct EnvFxParticle {
s32 angleAndDist[2]; // for whirpools, [0] = angle from center, [1] = distance from center
s32 unusedBubbleVar; // set to zero for bubbles when respawning, never used elsewhere
s32 bubbleY; // for Bubbles, yPos is always set to this
s8 filler20[56 - 0x20];
//s8 filler20[56 - 0x20];
u32 spawnTimestamp;
};
extern s8 gEnvFxMode;

View File

@ -82,6 +82,20 @@ void render_hud_texture(s32 x, s32 y, u32 w, u32 h, u8 *texture) {
gSPDisplayList(gDisplayListHead++, dl_hud_img_end);
}
static u32 sPowerMeterLastRenderTimestamp;
static s16 sPowerMeterLastY;
static Gfx *sPowerMeterDisplayListPos;
void patch_interpolated_hud(void) {
if (sPowerMeterDisplayListPos != NULL) {
Mtx *mtx = alloc_display_list(sizeof(Mtx));
guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0);
gSPMatrix(sPowerMeterDisplayListPos, VIRTUAL_TO_PHYSICAL(mtx),
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
sPowerMeterDisplayListPos = NULL;
}
}
/**
* Renders a rgba16 16x16 glyph texture from a table list.
*/
@ -134,6 +148,7 @@ void render_power_meter_health_segment(s16 numHealthWedges) {
*/
void render_dl_power_meter(s16 numHealthWedges) {
Mtx *mtx;
f32 interpolatedY;
mtx = alloc_display_list(sizeof(Mtx));
@ -141,7 +156,15 @@ void render_dl_power_meter(s16 numHealthWedges) {
return;
}
guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0);
if (gGlobalTimer == sPowerMeterLastRenderTimestamp + 1) {
interpolatedY = (sPowerMeterLastY + sPowerMeterHUD.y) / 2.0f;
} else {
interpolatedY = sPowerMeterHUD.y;
}
guTranslate(mtx, (f32) sPowerMeterHUD.x, interpolatedY, 0);
sPowerMeterLastY = sPowerMeterHUD.y;
sPowerMeterLastRenderTimestamp = gGlobalTimer;
sPowerMeterDisplayListPos = gDisplayListHead;
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx++),
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);

View File

@ -78,6 +78,47 @@ s8 gLastDialogResponse = 0;
u8 gMenuHoldKeyIndex = 0;
u8 gMenuHoldKeyTimer = 0;
s32 gDialogResponse = 0;
static Gfx *sInterpolatedDialogOffsetPos;
static f32 sInterpolatedDialogOffset;
static Gfx *sInterpolatedDialogRotationPos;
static f32 sInterpolatedDialogScale;
static f32 sInterpolatedDialogRotation;
static Gfx *sInterpolatedDialogZoomPos;
void patch_interpolated_dialog(void) {
Mtx *matrix;
if (sInterpolatedDialogOffsetPos != NULL) {
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
guTranslate(matrix, 0, sInterpolatedDialogOffset, 0);
gSPMatrix(sInterpolatedDialogOffsetPos, VIRTUAL_TO_PHYSICAL(matrix),
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
sInterpolatedDialogOffsetPos = NULL;
}
if (sInterpolatedDialogRotationPos != NULL) {
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f);
gSPMatrix(sInterpolatedDialogRotationPos++, VIRTUAL_TO_PHYSICAL(matrix),
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
guRotate(matrix, sInterpolatedDialogRotation * 4.0f, 0, 0, 1.0f);
gSPMatrix(sInterpolatedDialogRotationPos, VIRTUAL_TO_PHYSICAL(matrix),
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
sInterpolatedDialogRotationPos = NULL;
}
if (sInterpolatedDialogZoomPos != NULL) {
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
guTranslate(matrix, 65.0 - (65.0 / sInterpolatedDialogScale),
(40.0 / sInterpolatedDialogScale) - 40, 0);
gSPMatrix(sInterpolatedDialogZoomPos++, VIRTUAL_TO_PHYSICAL(matrix),
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f);
gSPMatrix(sInterpolatedDialogZoomPos, VIRTUAL_TO_PHYSICAL(matrix),
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
sInterpolatedDialogZoomPos = NULL;
}
}
void create_dl_identity_matrix(void) {
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
@ -541,6 +582,14 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) {
switch (gDialogBoxType) {
case DIALOG_TYPE_ROTATE: // Renders a dialog black box with zoom and rotation
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
sInterpolatedDialogRotationPos = gDisplayListHead;
if (gDialogBoxState == DIALOG_STATE_OPENING) {
sInterpolatedDialogScale = gDialogBoxScale - 2 / 2;
sInterpolatedDialogRotation = gDialogBoxOpenTimer - 7.5f / 2;
} else {
sInterpolatedDialogScale = gDialogBoxScale + 2 / 2;
sInterpolatedDialogRotation = gDialogBoxOpenTimer + 7.5f / 2;
}
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
// convert the speed into angle
create_dl_rotation_matrix(MENU_MTX_NOPUSH, gDialogBoxOpenTimer * 4.0f, 0, 0, 1.0f);
@ -549,6 +598,12 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) {
break;
case DIALOG_TYPE_ZOOM: // Renders a dialog white box with zoom
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
sInterpolatedDialogZoomPos = gDisplayListHead;
if (gDialogBoxState == DIALOG_STATE_OPENING) {
sInterpolatedDialogScale = gDialogBoxScale - 2 / 2;
} else {
sInterpolatedDialogScale = gDialogBoxScale + 2 / 2;
}
create_dl_translation_matrix(MENU_MTX_NOPUSH, 65.0 - (65.0 / gDialogBoxScale),
(40.0 / gDialogBoxScale) - 40, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
@ -659,7 +714,8 @@ u32 ensure_nonnegative(s16 value) {
return value;
}
void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 lowerBound) {
void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 lowerBound)
{
UNUSED s32 pad[2];
u8 strChar;
@ -689,9 +745,11 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
strIdx = gDialogTextPos;
if (gDialogBoxState == DIALOG_STATE_HORIZONTAL)
if (gDialogBoxState == DIALOG_STATE_HORIZONTAL) {
sInterpolatedDialogOffset = gDialogScrollOffsetY + dialog->linesPerBox;
sInterpolatedDialogOffsetPos = gDisplayListHead;
create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, (f32) gDialogScrollOffsetY, 0);
}
create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL3, 2 - lineNum * Y_VAL3, 0);
while (pageState == DIALOG_PAGE_STATE_NONE) {
@ -716,7 +774,6 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l
case DIALOG_CHAR_SPACE:
xMatrix++;
linePos++;
break;
case DIALOG_CHAR_SLASH:
xMatrix += 2;
@ -748,7 +805,6 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l
}
strIdx++;
}
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
if (gDialogBoxState == DIALOG_STATE_VERTICAL) {

View File

@ -34,12 +34,16 @@ Gfx *geo_envfx_main(s32 callContext, struct GraphNode *node, Mat4 mtxf) {
vec3f_to_vec3s(marioPos, gPlayerCameraState->pos);
particleList = envfx_update_particles(snowMode, marioPos, camTo, camFrom);
if (particleList != NULL) {
#if 0
Mtx *mtx = alloc_display_list(sizeof(*mtx));
gfx = alloc_display_list(2 * sizeof(*gfx));
mtxf_to_mtx(mtx, mtxf);
gSPMatrix(&gfx[0], VIRTUAL_TO_PHYSICAL(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
gSPBranchList(&gfx[1], VIRTUAL_TO_PHYSICAL(particleList));
#else
gfx = particleList;
#endif
execNode->fnNode.node.flags = (execNode->fnNode.node.flags & 0xFF) | 0x400;
}
SET_HIGH_U16_OF_32(*params, gAreaUpdateCounter);

View File

@ -1560,15 +1560,19 @@ void update_mario_info_for_cam(struct MarioState *m) {
}
}
int current_cap_state = MARIO_HAS_DEFAULT_CAP_ON;
int current_eye_state = MARIO_EYES_BLINK;
int current_hand_state = MARIO_HAND_FISTS;
/**
* Resets Mario's model, done every time an action is executed.
*/
void mario_reset_bodystate(struct MarioState *m) {
struct MarioBodyState *bodyState = m->marioBodyState;
bodyState->capState = MARIO_HAS_DEFAULT_CAP_OFF;
bodyState->eyeState = MARIO_EYES_BLINK;
bodyState->handState = MARIO_HAND_FISTS;
bodyState->capState = current_cap_state;
bodyState->eyeState = current_eye_state;
bodyState->handState = current_hand_state;
bodyState->modelState = 0;
bodyState->wingFlutter = FALSE;
@ -1669,6 +1673,8 @@ void mario_update_hitbox_and_cap_model(struct MarioState *m) {
}
}
/*
if (flags & MARIO_CAP_IN_HAND) {
if (flags & MARIO_WING_CAP) {
bodyState->handState = MARIO_HAND_HOLDING_WING_CAP;
@ -1685,6 +1691,8 @@ void mario_update_hitbox_and_cap_model(struct MarioState *m) {
}
}
*/
// Short hitbox for crouching/crawling/etc.
if (m->action & ACT_FLAG_SHORT_HITBOX) {
m->marioObj->hitboxHeight = 100.0f;

View File

@ -51,4 +51,8 @@ s32 execute_mario_action(UNUSED struct Object *o);
void init_mario(void);
void init_mario_from_save_file(void);
extern int current_cap_state;
extern int current_eye_state;
extern int current_hand_state;
#endif // MARIO_H

View File

@ -18,6 +18,7 @@
#ifdef BETTERCAMERA
#include "bettercamera.h"
#endif
#include "moon/saturn/saturn_types.h"
void play_flip_sounds(struct MarioState *m, s16 frame1, s16 frame2, s16 frame3) {
s32 animFrame = m->marioObj->header.gfx.unk38.animFrame;
@ -1707,7 +1708,8 @@ s32 act_shot_from_cannon(struct MarioState *m) {
}
if (m->vel[1] > 0.0f) {
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
reset_rumble_timers();
@ -1867,7 +1869,8 @@ s32 act_flying(struct MarioState *m) {
}
if (m->faceAngle[0] > 0x800 && m->forwardVel >= 48.0f) {
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
if (startPitch <= 0 && m->faceAngle[0] > 0 && m->forwardVel >= 48.0f) {

View File

@ -31,6 +31,7 @@
#include "../../include/libc/stdlib.h"
#include "pc/pc_main.h"
#include "moon/achievements/achievements.h"
#include "moon/saturn/saturn_types.h"
// TODO: put this elsewhere
enum SaveOption { SAVE_OPT_SAVE_AND_CONTINUE = 1, SAVE_OPT_SAVE_AND_QUIT, SAVE_OPT_SAVE_EXIT_GAME, SAVE_OPT_CONTINUE_DONT_SAVE };
@ -2152,7 +2153,8 @@ static void end_peach_cutscene_run_to_peach(struct MarioState *m) {
play_step_sound(m, 9, 45);
vec3f_copy(m->marioObj->header.gfx.pos, m->pos);
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
// dialog 1

View File

@ -15,6 +15,7 @@
#include "pc/configfile.h"
#include "pc/cheats.h"
#include "moon/achievements/achievements.h"
#include "moon/saturn/saturn_types.h"
struct LandingAction {
s16 numFrames;
@ -709,7 +710,8 @@ void push_or_sidle_wall(struct MarioState *m, Vec3f startPos) {
if (m->marioObj->header.gfx.unk38.animFrame < 20) {
play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject);
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
m->actionState = 1;
@ -837,7 +839,8 @@ s32 act_walking(struct MarioState *m) {
case GROUND_STEP_NONE:
anim_and_audio_for_walk(m);
if (m->intendedMag - m->forwardVel > 16.0f) {
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
break;
@ -880,7 +883,8 @@ s32 act_move_punching(struct MarioState *m) {
break;
case GROUND_STEP_NONE:
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
break;
}
@ -935,7 +939,8 @@ s32 act_hold_walking(struct MarioState *m) {
anim_and_audio_for_hold_walk(m);
if (0.4f * m->intendedMag - m->forwardVel > 10.0f) {
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
return FALSE;
@ -1005,7 +1010,8 @@ s32 act_turning_around(struct MarioState *m) {
break;
case GROUND_STEP_NONE:
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
break;
}
@ -1070,7 +1076,8 @@ s32 act_braking(struct MarioState *m) {
break;
case GROUND_STEP_NONE:
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
break;
case GROUND_STEP_HIT_WALL:
@ -1132,7 +1139,8 @@ s32 act_decelerating(struct MarioState *m) {
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT);
play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject);
adjust_sound_for_speed(m);
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
} else {
// (Speed Crash) Crashes if speed exceeds 2^17.
if ((val0C = (s32)(m->forwardVel / 4.0f * 0x10000)) < 0x1000) {
@ -1198,7 +1206,8 @@ s32 act_hold_decelerating(struct MarioState *m) {
set_mario_animation(m, MARIO_ANIM_IDLE_WITH_LIGHT_OBJ);
play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject);
adjust_sound_for_speed(m);
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
} else {
//! (Speed Crash) This crashes if Mario has more speed than 2^15 speed.
if ((val0C = (s32)(m->forwardVel * 0x10000)) < 0x1000) {
@ -1391,7 +1400,8 @@ void common_slide_action(struct MarioState *m, u32 endAction, u32 airAction, s32
case GROUND_STEP_NONE:
set_mario_animation(m, animation);
align_with_floor(m);
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
break;
case GROUND_STEP_HIT_WALL:
@ -1523,7 +1533,8 @@ s32 act_slide_kick_slide(struct MarioState *m) {
}
play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject);
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
return FALSE;
}
@ -1746,7 +1757,8 @@ u32 common_landing_action(struct MarioState *m, s16 animation, u32 airAction) {
}
if (m->forwardVel > 16.0f) {
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
set_mario_animation(m, animation);

View File

@ -17,6 +17,7 @@
#include "sound_init.h"
#include "surface_terrains.h"
#include "thread6.h"
#include "moon/saturn/saturn_types.h"
s32 check_common_idle_cancels(struct MarioState *m) {
mario_drop_held_object(m);
@ -133,15 +134,27 @@ s32 act_idle(struct MarioState *m) {
} else {
switch (m->actionState) {
case 0:
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT);
if (enable_head_rotations) {
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT);
} else {
set_mario_animation(m, MARIO_ANIM_FIRST_PERSON);
}
break;
case 1:
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_RIGHT);
if (enable_head_rotations) {
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_RIGHT);
} else {
set_mario_animation(m, MARIO_ANIM_FIRST_PERSON);
}
break;
case 2:
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_CENTER);
if (enable_head_rotations) {
set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_CENTER);
} else {
set_mario_animation(m, MARIO_ANIM_FIRST_PERSON);
}
break;
}

View File

@ -16,6 +16,7 @@
#include "behavior_data.h"
#include "level_table.h"
#include "thread6.h"
#include "moon/saturn/saturn_types.h"
#define MIN_SWIM_STRENGTH 160
#define MIN_SWIM_SPEED 16.0f
@ -1099,7 +1100,8 @@ static void play_metal_water_jumping_sound(struct MarioState *m, u32 landing) {
static void play_metal_water_walking_sound(struct MarioState *m) {
if (is_anim_past_frame(m, 10) || is_anim_past_frame(m, 49)) {
play_sound(SOUND_ACTION_METAL_STEP_WATER, m->marioObj->header.gfx.cameraToObject);
m->particleFlags |= PARTICLE_DUST;
if (enable_dust_particles)
m->particleFlags |= PARTICLE_DUST;
}
}

View File

@ -1550,6 +1550,7 @@ void cur_obj_set_pos_to_home(void) {
o->oPosX = o->oHomeX;
o->oPosY = o->oHomeY;
o->oPosZ = o->oHomeZ;
o->header.gfx.skipInterpolationTimestamp = gGlobalTimer;
}
void cur_obj_set_pos_to_home_and_stop(void) {

View File

@ -189,6 +189,32 @@ struct Painting **sPaintingGroups[] = {
s16 gPaintingUpdateCounter = 1;
s16 gLastPaintingUpdateCounter = 0;
static Vtx sLastVertices[2 * 264 * 3];
static u32 sLastVerticesTimestamp;
static Vtx *sVerticesPtr[2];
static s32 sVerticesCount;
void patch_interpolated_paintings(void) {
if (sVerticesPtr[0] != NULL) {
s32 i;
if (sVerticesPtr[1] != NULL) {
for (i = 0; i < sVerticesCount / 2; i++) {
sVerticesPtr[0][i] = sLastVertices[i];
}
for (; i < sVerticesCount; i++) {
sVerticesPtr[1][i - sVerticesCount / 2] = sLastVertices[i];
}
} else {
for (i = 0; i < sVerticesCount; i++) {
sVerticesPtr[0][i] = sLastVertices[i];
}
}
sVerticesPtr[0] = NULL;
sVerticesPtr[1] = NULL;
sVerticesCount = 0;
}
}
/**
* Stop paintings in paintingGroup from rippling if their id is different from *idptr.
*/
@ -890,6 +916,23 @@ Gfx *render_painting(u8 *img, s16 tWidth, s16 tHeight, s16 *textureMap, s16 mapV
gSP1Triangle(gfx++, group * 3, group * 3 + 1, group * 3 + 2, 0);
}
if (sVerticesCount >= numVtx * 2) {
sVerticesCount = 0;
}
for (map = 0; map < numVtx; map++) {
Vtx v = verts[map];
if (gGlobalTimer == sLastVerticesTimestamp + 1) {
s32 i;
for (i = 0; i < 3; i++) {
verts[map].n.ob[i] = (v.n.ob[i] + sLastVertices[sVerticesCount + map].n.ob[i]) / 2;
verts[map].n.n[i] = (v.n.n[i] + sLastVertices[sVerticesCount + map].n.n[i]) / 2;
}
}
sLastVertices[sVerticesCount + map] = v;
}
sVerticesPtr[sVerticesCount / numVtx] = verts;
sVerticesCount += numVtx;
gSPEndDisplayList(gfx);
return dlist;
}
@ -954,6 +997,7 @@ Gfx *painting_ripple_image(struct Painting *painting) {
meshTris = textureMap[meshVerts * 3 + 1];
gSPDisplayList(gfx++, render_painting(textures[i], tWidth, tHeight, textureMap, meshVerts, meshTris, painting->alpha));
}
sLastVerticesTimestamp = gGlobalTimer;
// Update the ripple, may automatically reset the painting's state.
painting_update_ripple_state(painting);
@ -991,6 +1035,7 @@ Gfx *painting_ripple_env_mapped(struct Painting *painting) {
meshVerts = textureMap[0];
meshTris = textureMap[meshVerts * 3 + 1];
gSPDisplayList(gfx++, render_painting(tArray[0], tWidth, tHeight, textureMap, meshVerts, meshTris, painting->alpha));
sLastVerticesTimestamp = gGlobalTimer;
// Update the ripple, may automatically reset the painting's state.
painting_update_ripple_state(painting);

View File

@ -40,6 +40,8 @@
s16 gMatStackIndex;
Mat4 gMatStack[32];
Mtx *gMatStackFixed[32];
Mat4 gMatStackInterpolated[32];
Mtx *gMatStackInterpolatedFixed[32];
/**
* Animation nodes have state in global variables, so this struct captures
@ -53,6 +55,7 @@ struct GeoAnimState {
/*0x04*/ f32 translationMultiplier;
/*0x08*/ u16 *attribute;
/*0x0C*/ s16 *data;
s16 prevFrame;
};
// For some reason, this is a GeoAnimState struct, but the current state consists
@ -62,6 +65,7 @@ struct GeoAnimState gGeoTempState;
u8 gCurAnimType;
u8 gCurAnimEnabled;
s16 gCurrAnimFrame;
s16 gPrevAnimFrame;
f32 gCurAnimTranslationMultiplier;
u16 *gCurrAnimAttribute;
s16 *gCurAnimData;
@ -130,6 +134,46 @@ u16 gAreaUpdateCounter = 0;
LookAt lookAt;
#endif
static Gfx *sPerspectivePos;
static Mtx *sPerspectiveMtx;
struct {
Gfx *pos;
void *mtx;
void *displayList;
} gMtxTbl[6400];
s32 gMtxTblSize;
static Gfx *sViewportPos;
static Vp sPrevViewport;
void mtx_patch_interpolated(void) {
s32 i;
if (sPerspectivePos != NULL) {
gSPMatrix(sPerspectivePos, VIRTUAL_TO_PHYSICAL(sPerspectiveMtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
}
for (i = 0; i < gMtxTblSize; i++) {
Gfx *pos = gMtxTbl[i].pos;
gSPMatrix(pos++, VIRTUAL_TO_PHYSICAL(gMtxTbl[i].mtx),
G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
gSPDisplayList(pos++, gMtxTbl[i].displayList);
}
if (sViewportPos != NULL) {
Gfx *saved = gDisplayListHead;
gDisplayListHead = sViewportPos;
make_viewport_clip_rect(&sPrevViewport);
gSPViewport(gDisplayListHead, VIRTUAL_TO_PHYSICAL(&sPrevViewport));
gDisplayListHead = saved;
}
gMtxTblSize = 0;
sPerspectivePos = NULL;
sViewportPos = NULL;
}
/**
* Process a master list node.
*/
@ -157,9 +201,14 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) {
if ((currList = node->listHeads[i]) != NULL) {
gDPSetRenderMode(gDisplayListHead++, modeList->modes[i], mode2List->modes[i]);
while (currList != NULL) {
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transform),
if ((u32) gMtxTblSize < sizeof(gMtxTbl) / sizeof(gMtxTbl[0])) {
gMtxTbl[gMtxTblSize].pos = gDisplayListHead;
gMtxTbl[gMtxTblSize].mtx = currList->transform;
gMtxTbl[gMtxTblSize++].displayList = currList->displayList;
}
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformInterpolated),
G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
gSPDisplayList(gDisplayListHead++, currList->displayList);
gSPDisplayList(gDisplayListHead++, currList->displayListInterpolated);
currList = currList->next;
}
}
@ -175,7 +224,7 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) {
* parameter. Look at the RenderModeContainer struct to see the corresponding
* render modes of layers.
*/
static void geo_append_display_list(void *displayList, s16 layer) {
static void geo_append_display_list2(void *displayList, void *displayListInterpolated, s16 layer) {
#ifdef F3DEX_GBI_2
gSPLookAt(gDisplayListHead++, &lookAt);
@ -185,7 +234,9 @@ static void geo_append_display_list(void *displayList, s16 layer) {
alloc_only_pool_alloc(gDisplayListHeap, sizeof(struct DisplayListNode));
listNode->transform = gMatStackFixed[gMatStackIndex];
listNode->transformInterpolated = gMatStackInterpolatedFixed[gMatStackIndex];
listNode->displayList = displayList;
listNode->displayListInterpolated = displayListInterpolated;
listNode->next = 0;
if (gCurGraphNodeMasterList->listHeads[layer] == 0) {
gCurGraphNodeMasterList->listHeads[layer] = listNode;
@ -196,6 +247,10 @@ static void geo_append_display_list(void *displayList, s16 layer) {
}
}
static void geo_append_display_list(void *displayList, s16 layer) {
geo_append_display_list2(displayList, displayList, layer);
}
/**
* Process the master list node.
*/
@ -242,7 +297,9 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {
}
if (node->fnNode.node.children != NULL) {
u16 perspNorm;
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
Mtx *mtx = alloc_display_list(sizeof(*mtx));
f32 fovInterpolated;
#ifdef VERSION_EU
f32 aspect = ((f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height) * 1.1f;
@ -251,9 +308,23 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {
#endif
guPerspective(mtx, &perspNorm, node->fov, aspect, node->near, node->far, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
if (gGlobalTimer == node->prevTimestamp + 1 && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) {
fovInterpolated = (node->prevFov + node->fov) / 2.0f;
guPerspective(mtxInterpolated, &perspNorm, fovInterpolated, aspect, node->near, node->far, 1.0f);
gSPPerspNormalize(gDisplayListHead++, perspNorm);
sPerspectivePos = gDisplayListHead;
sPerspectiveMtx = mtx;
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtxInterpolated),
G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
} else {
gSPPerspNormalize(gDisplayListHead++, perspNorm);
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
}
node->prevFov = node->fov;
node->prevTimestamp = gGlobalTimer;
gCurGraphNodeCamFrustum = node;
geo_process_node_and_siblings(node->fnNode.node.children);
@ -305,6 +376,39 @@ static void geo_process_switch(struct GraphNodeSwitchCase *node) {
}
}
void interpolate_vectors(Vec3f res, Vec3f a, Vec3f b) {
res[0] = (a[0] + b[0]) / 2.0f;
res[1] = (a[1] + b[1]) / 2.0f;
res[2] = (a[2] + b[2]) / 2.0f;
}
void interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b) {
res[0] = (a[0] + b[0]) / 2;
res[1] = (a[1] + b[1]) / 2;
res[2] = (a[2] + b[2]) / 2;
}
static s16 interpolate_angle(s16 a, s16 b) {
s32 absDiff = b - a;
if (absDiff < 0) {
absDiff = -absDiff;
}
if (absDiff >= 0x4000 && absDiff <= 0xC000) {
return b;
}
if (absDiff <= 0x8000) {
return (a + b) / 2;
} else {
return (a + b) / 2 + 0x8000;
}
}
static void interpolate_angles(Vec3s res, Vec3s a, Vec3s b) {
res[0] = interpolate_angle(a[0], b[0]);
res[1] = interpolate_angle(a[1], b[1]);
res[2] = interpolate_angle(a[2], b[2]);
}
/**
* Process a camera node.
*/
@ -312,6 +416,9 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
Mat4 cameraTransform;
Mtx *rollMtx = alloc_display_list(sizeof(*rollMtx));
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
Vec3f posInterpolated;
Vec3f focusInterpolated;
if (node->fnNode.func != NULL) {
node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, gMatStack[gMatStackIndex]);
@ -322,12 +429,40 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
mtxf_lookat(cameraTransform, node->pos, node->focus, node->roll);
mtxf_mul(gMatStack[gMatStackIndex + 1], cameraTransform, gMatStack[gMatStackIndex]);
if (gGlobalTimer == node->prevTimestamp + 1 && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) {
interpolate_vectors(posInterpolated, node->prevPos, node->pos);
interpolate_vectors(focusInterpolated, node->prevFocus, node->focus);
float magnitude = 0;
for (int i = 0; i < 3; i++) {
float diff = node->pos[i] - node->prevPos[i];
magnitude += diff * diff;
}
if (magnitude > 500000) {
// Observed ~479000 in BBH when toggling R camera
// Can get over 3 million in VCUTM though...
vec3f_copy(posInterpolated, node->pos);
vec3f_copy(focusInterpolated, node->focus);
}
} else {
vec3f_copy(posInterpolated, node->pos);
vec3f_copy(focusInterpolated, node->focus);
}
vec3f_copy(node->prevPos, node->pos);
vec3f_copy(node->prevFocus, node->focus);
node->prevTimestamp = gGlobalTimer;
mtxf_lookat(cameraTransform, posInterpolated, focusInterpolated, node->roll);
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], cameraTransform, gMatStackInterpolated[gMatStackIndex]);
gMatStackIndex++;
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->fnNode.node.children != 0) {
gCurGraphNodeCamera = node;
node->matrixPtr = &gMatStack[gMatStackIndex];
node->matrixPtrInterpolated = &gMatStackInterpolated[gMatStackIndex];
geo_process_node_and_siblings(node->fnNode.node.children);
gCurGraphNodeCamera = NULL;
}
@ -344,13 +479,17 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation
Mat4 mtxf;
Vec3f translation;
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
vec3s_to_vec3f(translation, node->translation);
mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation);
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
gMatStackIndex++;
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->displayList != NULL) {
geo_append_display_list(node->displayList, node->node.flags >> 8);
}
@ -369,13 +508,17 @@ static void geo_process_translation(struct GraphNodeTranslation *node) {
Mat4 mtxf;
Vec3f translation;
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
vec3s_to_vec3f(translation, node->translation);
mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero);
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
gMatStackIndex++;
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->displayList != NULL) {
geo_append_display_list(node->displayList, node->node.flags >> 8);
}
@ -393,12 +536,23 @@ static void geo_process_translation(struct GraphNodeTranslation *node) {
static void geo_process_rotation(struct GraphNodeRotation *node) {
Mat4 mtxf;
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
Vec3s rotationInterpolated;
mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation);
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
if (gGlobalTimer == node->prevTimestamp + 1) {
interpolate_angles(rotationInterpolated, node->prevRotation, node->rotation);
mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, rotationInterpolated);
}
vec3s_copy(node->prevRotation, node->rotation);
node->prevTimestamp = gGlobalTimer;
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
gMatStackIndex++;
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->displayList != NULL) {
geo_append_display_list(node->displayList, node->node.flags >> 8);
}
@ -417,12 +571,16 @@ static void geo_process_scale(struct GraphNodeScale *node) {
UNUSED Mat4 transform;
Vec3f scaleVec;
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
vec3f_set(scaleVec, node->scale, node->scale, node->scale);
mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec);
mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex], scaleVec);
gMatStackIndex++;
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->displayList != NULL) {
geo_append_display_list(node->displayList, node->node.flags >> 8);
}
@ -441,21 +599,30 @@ static void geo_process_scale(struct GraphNodeScale *node) {
static void geo_process_billboard(struct GraphNodeBillboard *node) {
Vec3f translation;
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
gMatStackIndex++;
vec3s_to_vec3f(translation, node->translation);
mtxf_billboard(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex - 1], translation,
gCurGraphNodeCamera->roll);
mtxf_billboard(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex - 1], translation,
gCurGraphNodeCamera->roll);
if (gCurGraphNodeHeldObject != NULL) {
mtxf_scale_vec3f(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex],
gCurGraphNodeHeldObject->objNode->header.gfx.scale);
mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex],
gCurGraphNodeHeldObject->objNode->header.gfx.scale);
} else if (gCurGraphNodeObject != NULL) {
mtxf_scale_vec3f(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex],
gCurGraphNodeObject->scale);
mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex],
gCurGraphNodeObject->scale);
}
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->displayList != NULL) {
geo_append_display_list(node->displayList, node->node.flags >> 8);
}
@ -504,13 +671,39 @@ static void geo_process_generated_list(struct GraphNodeGenerated *node) {
*/
static void geo_process_background(struct GraphNodeBackground *node) {
Gfx *list = NULL;
Gfx *listInterpolated = NULL;
if (node->fnNode.func != NULL) {
Vec3f posCopy;
Vec3f focusCopy;
Vec3f posInterpolated;
Vec3f focusInterpolated;
if (gGlobalTimer == node->prevCameraTimestamp + 1 &&
gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) {
interpolate_vectors(posInterpolated, node->prevCameraPos, gLakituState.pos);
interpolate_vectors(focusInterpolated, node->prevCameraFocus, gLakituState.focus);
} else {
vec3f_copy(posInterpolated, gLakituState.pos);
vec3f_copy(focusInterpolated, gLakituState.focus);
}
vec3f_copy(node->prevCameraPos, gLakituState.pos);
vec3f_copy(node->prevCameraFocus, gLakituState.focus);
node->prevCameraTimestamp = gGlobalTimer;
list = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node,
(struct AllocOnlyPool *) gMatStack[gMatStackIndex]);
vec3f_copy(posCopy, gLakituState.pos);
vec3f_copy(focusCopy, gLakituState.focus);
vec3f_copy(gLakituState.pos, posInterpolated);
vec3f_copy(gLakituState.focus, focusInterpolated);
listInterpolated = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, NULL);
vec3f_copy(gLakituState.pos, posCopy);
vec3f_copy(gLakituState.focus, focusCopy);
}
if (list != 0) {
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(list), node->fnNode.node.flags >> 8);
geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(list),
(void *) VIRTUAL_TO_PHYSICAL(listInterpolated), node->fnNode.node.flags >> 8);
} else if (gCurGraphNodeMasterList != NULL) {
#ifndef F3DEX_GBI_2E
Gfx *gfxStart = alloc_display_list(sizeof(Gfx) * 7);
@ -535,6 +728,47 @@ static void geo_process_background(struct GraphNodeBackground *node) {
}
}
static void anim_process(Vec3f translation, Vec3s rotation, u8 *animType, s16 animFrame, u16 **animAttribute) {
if (*animType == ANIM_TYPE_TRANSLATION) {
translation[0] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
* gCurAnimTranslationMultiplier;
translation[1] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
* gCurAnimTranslationMultiplier;
translation[2] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
* gCurAnimTranslationMultiplier;
*animType = ANIM_TYPE_ROTATION;
} else {
if (*animType == ANIM_TYPE_LATERAL_TRANSLATION) {
translation[0] +=
gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
* gCurAnimTranslationMultiplier;
*animAttribute += 2;
translation[2] +=
gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
* gCurAnimTranslationMultiplier;
*animType = ANIM_TYPE_ROTATION;
} else {
if (*animType == ANIM_TYPE_VERTICAL_TRANSLATION) {
*animAttribute += 2;
translation[1] +=
gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
* gCurAnimTranslationMultiplier;
*animAttribute += 2;
*animType = ANIM_TYPE_ROTATION;
} else if (*animType == ANIM_TYPE_NO_TRANSLATION) {
*animAttribute += 6;
*animType = ANIM_TYPE_ROTATION;
}
}
}
if (*animType == ANIM_TYPE_ROTATION) {
rotation[0] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)];
rotation[1] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)];
rotation[2] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)];
}
}
/**
* Render an animated part. The current animation state is not part of the node
* but set in global variables. If an animated part is skipped, everything afterwards desyncs.
@ -543,53 +777,32 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
Mat4 matrix;
Vec3s rotation;
Vec3f translation;
Vec3s rotationInterpolated;
Vec3f translationInterpolated;
Mtx *matrixPtr = alloc_display_list(sizeof(*matrixPtr));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
u16 *animAttribute = gCurrAnimAttribute;
u8 animType = gCurAnimType;
vec3s_copy(rotation, gVec3sZero);
vec3f_set(translation, node->translation[0], node->translation[1], node->translation[2]);
if (gCurAnimType == ANIM_TYPE_TRANSLATION) {
translation[0] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
* gCurAnimTranslationMultiplier;
translation[1] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
* gCurAnimTranslationMultiplier;
translation[2] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
* gCurAnimTranslationMultiplier;
gCurAnimType = ANIM_TYPE_ROTATION;
} else {
if (gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) {
translation[0] +=
gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
* gCurAnimTranslationMultiplier;
gCurrAnimAttribute += 2;
translation[2] +=
gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
* gCurAnimTranslationMultiplier;
gCurAnimType = ANIM_TYPE_ROTATION;
} else {
if (gCurAnimType == ANIM_TYPE_VERTICAL_TRANSLATION) {
gCurrAnimAttribute += 2;
translation[1] +=
gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
* gCurAnimTranslationMultiplier;
gCurrAnimAttribute += 2;
gCurAnimType = ANIM_TYPE_ROTATION;
} else if (gCurAnimType == ANIM_TYPE_NO_TRANSLATION) {
gCurrAnimAttribute += 6;
gCurAnimType = ANIM_TYPE_ROTATION;
}
}
}
vec3s_copy(rotationInterpolated, rotation);
vec3f_copy(translationInterpolated, translation);
anim_process(translationInterpolated, rotationInterpolated, &animType, gPrevAnimFrame, &animAttribute);
anim_process(translation, rotation, &gCurAnimType, gCurrAnimFrame, &gCurrAnimAttribute);
interpolate_vectors(translationInterpolated, translationInterpolated, translation);
interpolate_angles(rotationInterpolated, rotationInterpolated, rotation);
if (gCurAnimType == ANIM_TYPE_ROTATION) {
rotation[0] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)];
rotation[1] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)];
rotation[2] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)];
}
mtxf_rotate_xyz_and_translate(matrix, translation, rotation);
mtxf_mul(gMatStack[gMatStackIndex + 1], matrix, gMatStack[gMatStackIndex]);
mtxf_rotate_xyz_and_translate(matrix, translationInterpolated, rotationInterpolated);
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], matrix, gMatStackInterpolated[gMatStackIndex]);
gMatStackIndex++;
mtxf_to_mtx(matrixPtr, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = matrixPtr;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->displayList != NULL) {
geo_append_display_list(node->displayList, node->node.flags >> 8);
}
@ -621,6 +834,17 @@ void geo_set_animation_globals(struct GraphNodeObject_sub *node, s32 hasAnimatio
}
gCurrAnimFrame = node->animFrame;
if (node->prevAnimPtr == anim && node->prevAnimID == node->animID &&
gGlobalTimer == node->prevAnimFrameTimestamp + 1) {
gPrevAnimFrame = node->prevAnimFrame;
} else {
gPrevAnimFrame = node->animFrame;
}
node->prevAnimPtr = anim;
node->prevAnimID = node->animID;
node->prevAnimFrame = node->animFrame;
node->prevAnimFrameTimestamp = gGlobalTimer;
gCurAnimEnabled = (anim->flags & ANIM_FLAG_5) == 0;
gCurrAnimAttribute = segmented_to_virtual((void *) anim->index);
gCurAnimData = segmented_to_virtual((void *) anim->values);
@ -639,8 +863,10 @@ void geo_set_animation_globals(struct GraphNodeObject_sub *node, s32 hasAnimatio
*/
static void geo_process_shadow(struct GraphNodeShadow *node) {
Gfx *shadowList;
Gfx *shadowListInterpolated;
Mat4 mtxf;
Vec3f shadowPos;
Vec3f shadowPosInterpolated;
Vec3f animOffset;
f32 objScale;
f32 shadowScale;
@ -648,6 +874,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
f32 cosAng;
struct GraphNode *geo;
Mtx *mtx;
Mtx *mtxInterpolated;
if (gCurGraphNodeCamera != NULL && gCurGraphNodeObject != NULL) {
if (gCurGraphNodeHeldObject != NULL) {
@ -686,21 +913,57 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
}
}
if (gCurGraphNodeHeldObject != NULL) {
if (gGlobalTimer == gCurGraphNodeHeldObject->prevShadowPosTimestamp + 1) {
interpolate_vectors(shadowPosInterpolated, gCurGraphNodeHeldObject->prevShadowPos, shadowPos);
} else {
vec3f_copy(shadowPosInterpolated, shadowPos);
}
vec3f_copy(gCurGraphNodeHeldObject->prevShadowPos, shadowPos);
gCurGraphNodeHeldObject->prevShadowPosTimestamp = gGlobalTimer;
} else {
if (gGlobalTimer == gCurGraphNodeObject->prevShadowPosTimestamp + 1 &&
gGlobalTimer != gCurGraphNodeObject->skipInterpolationTimestamp) {
interpolate_vectors(shadowPosInterpolated, gCurGraphNodeObject->prevShadowPos, shadowPos);
} else {
vec3f_copy(shadowPosInterpolated, shadowPos);
}
vec3f_copy(gCurGraphNodeObject->prevShadowPos, shadowPos);
gCurGraphNodeObject->prevShadowPosTimestamp = gGlobalTimer;
}
extern u8 gInterpolatingSurfaces;
gInterpolatingSurfaces = TRUE;
shadowListInterpolated = create_shadow_below_xyz(shadowPosInterpolated[0], shadowPosInterpolated[1],
shadowPosInterpolated[2], shadowScale,
node->shadowSolidity, node->shadowType);
gInterpolatingSurfaces = FALSE;
shadowList = create_shadow_below_xyz(shadowPos[0], shadowPos[1], shadowPos[2], shadowScale,
node->shadowSolidity, node->shadowType);
if (shadowList != NULL) {
if (shadowListInterpolated != NULL && shadowList != NULL) {
mtx = alloc_display_list(sizeof(*mtx));
mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
gMatStackIndex++;
mtxf_translate(mtxf, shadowPos);
mtxf_mul(gMatStack[gMatStackIndex], mtxf, *gCurGraphNodeCamera->matrixPtr);
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_translate(mtxf, shadowPosInterpolated);
mtxf_mul(gMatStackInterpolated[gMatStackIndex], mtxf, *gCurGraphNodeCamera->matrixPtrInterpolated);
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (gShadowAboveWaterOrLava == 1) {
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 4);
geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList),
(void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 4);
} else if (gMarioOnIceOrCarpet == 1) {
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 5);
geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList),
(void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 5);
} else {
geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 6);
geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList),
(void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 6);
}
gMatStackIndex--;
}
@ -797,31 +1060,101 @@ static int obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) {
return TRUE;
}
static void interpolate_matrix(Mat4 result, Mat4 a, Mat4 b) {
s32 i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
result[i][j] = (a[i][j] + b[i][j]) / 2.0f;
}
}
}
/**
* Process an object node.
*/
static void geo_process_object(struct Object *node) {
Mat4 mtxf;
s32 hasAnimation = (node->header.gfx.node.flags & GRAPH_RENDER_HAS_ANIMATION) != 0;
Vec3f scaleInterpolated;
if (node->header.gfx.unk18 == gCurGraphNodeRoot->areaIndex) {
if (node->header.gfx.throwMatrix != NULL) {
mtxf_mul(gMatStack[gMatStackIndex + 1], *node->header.gfx.throwMatrix,
gMatStack[gMatStackIndex]);
if (gGlobalTimer == node->header.gfx.prevThrowMatrixTimestamp + 1 &&
gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
interpolate_matrix(mtxf, *node->header.gfx.throwMatrix, node->header.gfx.prevThrowMatrix);
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf,
gMatStackInterpolated[gMatStackIndex]);
} else {
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], (void *) node->header.gfx.throwMatrix,
gMatStackInterpolated[gMatStackIndex]);
}
mtxf_copy(node->header.gfx.prevThrowMatrix, *node->header.gfx.throwMatrix);
node->header.gfx.prevThrowMatrixTimestamp = gGlobalTimer;
} else if (node->header.gfx.node.flags & GRAPH_RENDER_CYLBOARD) {
Vec3f posInterpolated;
if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 &&
gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos);
} else {
vec3f_copy(posInterpolated, node->header.gfx.pos);
}
vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos);
node->header.gfx.prevTimestamp = gGlobalTimer;
mtxf_cylboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex],
node->header.gfx.pos, gCurGraphNodeCamera->roll);
mtxf_cylboard(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex],
posInterpolated, gCurGraphNodeCamera->roll);
} else if (node->header.gfx.node.flags & GRAPH_RENDER_BILLBOARD) {
Vec3f posInterpolated;
if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 &&
gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos);
} else {
vec3f_copy(posInterpolated, node->header.gfx.pos);
}
vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos);
node->header.gfx.prevTimestamp = gGlobalTimer;
mtxf_billboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex],
node->header.gfx.pos, gCurGraphNodeCamera->roll);
mtxf_billboard(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex],
posInterpolated, gCurGraphNodeCamera->roll);
} else {
Vec3f posInterpolated;
Vec3s angleInterpolated;
if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 &&
gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos);
interpolate_angles(angleInterpolated, node->header.gfx.prevAngle, node->header.gfx.angle);
} else {
vec3f_copy(posInterpolated, node->header.gfx.pos);
vec3s_copy(angleInterpolated, node->header.gfx.angle);
}
vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos);
vec3s_copy(node->header.gfx.prevAngle, node->header.gfx.angle);
node->header.gfx.prevTimestamp = gGlobalTimer;
mtxf_rotate_zxy_and_translate(mtxf, node->header.gfx.pos, node->header.gfx.angle);
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
mtxf_rotate_zxy_and_translate(mtxf, posInterpolated, angleInterpolated);
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
}
if (gGlobalTimer == node->header.gfx.prevScaleTimestamp + 1 &&
gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
interpolate_vectors(scaleInterpolated, node->header.gfx.prevScale, node->header.gfx.scale);
} else {
vec3f_copy(scaleInterpolated, node->header.gfx.scale);
}
vec3f_copy(node->header.gfx.prevScale, node->header.gfx.scale);
node->header.gfx.prevScaleTimestamp = gGlobalTimer;
mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1],
node->header.gfx.scale);
mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex + 1],
scaleInterpolated);
node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex];
node->header.gfx.throwMatrixInterpolated = &gMatStackInterpolated[gMatStackIndex];
node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0];
node->header.gfx.cameraToObject[1] = gMatStack[gMatStackIndex][3][1];
node->header.gfx.cameraToObject[2] = gMatStack[gMatStackIndex][3][2];
@ -832,9 +1165,12 @@ static void geo_process_object(struct Object *node) {
}
if (obj_is_in_view(&node->header.gfx, gMatStack[gMatStackIndex])) {
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
if (node->header.gfx.sharedChild != NULL) {
gCurGraphNodeObject = (struct GraphNodeObject *) node;
node->header.gfx.sharedChild->parent = &node->header.gfx.node;
@ -845,11 +1181,16 @@ static void geo_process_object(struct Object *node) {
if (node->header.gfx.node.children != NULL) {
geo_process_node_and_siblings(node->header.gfx.node.children);
}
} else {
node->header.gfx.prevThrowMatrixTimestamp = 0;
node->header.gfx.prevTimestamp = 0;
node->header.gfx.prevScaleTimestamp = 0;
}
gMatStackIndex--;
gCurAnimType = ANIM_TYPE_NONE;
node->header.gfx.throwMatrix = NULL;
node->header.gfx.throwMatrixInterpolated = NULL;
}
}
@ -876,6 +1217,8 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
Mat4 mat;
Vec3f translation;
Mtx *mtx = alloc_display_list(sizeof(*mtx));
Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
Vec3f scaleInterpolated;
#ifdef F3DEX_GBI_2
gSPLookAt(gDisplayListHead++, &lookAt);
@ -891,6 +1234,14 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
translation[1] = node->translation[1] / 4.0f;
translation[2] = node->translation[2] / 4.0f;
if (gGlobalTimer == node->objNode->header.gfx.prevScaleTimestamp + 1) {
interpolate_vectors(scaleInterpolated, node->objNode->header.gfx.prevScale, node->objNode->header.gfx.scale);
} else {
vec3f_copy(scaleInterpolated, node->objNode->header.gfx.scale);
}
vec3f_copy(node->objNode->header.gfx.prevScale, node->objNode->header.gfx.scale);
node->objNode->header.gfx.prevScaleTimestamp = gGlobalTimer;
mtxf_translate(mat, translation);
mtxf_copy(gMatStack[gMatStackIndex + 1], *gCurGraphNodeObject->throwMatrix);
gMatStack[gMatStackIndex + 1][3][0] = gMatStack[gMatStackIndex][3][0];
@ -899,6 +1250,13 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
mtxf_mul(gMatStack[gMatStackIndex + 1], mat, gMatStack[gMatStackIndex + 1]);
mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1],
node->objNode->header.gfx.scale);
mtxf_copy(gMatStackInterpolated[gMatStackIndex + 1], (void *) gCurGraphNodeObject->throwMatrixInterpolated);
gMatStackInterpolated[gMatStackIndex + 1][3][0] = gMatStackInterpolated[gMatStackIndex][3][0];
gMatStackInterpolated[gMatStackIndex + 1][3][1] = gMatStackInterpolated[gMatStackIndex][3][1];
gMatStackInterpolated[gMatStackIndex + 1][3][2] = gMatStackInterpolated[gMatStackIndex][3][2];
mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mat, gMatStackInterpolated[gMatStackIndex + 1]);
mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex + 1],
scaleInterpolated);
if (node->fnNode.func != NULL) {
node->fnNode.func(GEO_CONTEXT_HELD_OBJ, &node->fnNode.node,
(struct AllocOnlyPool *) gMatStack[gMatStackIndex + 1]);
@ -906,12 +1264,15 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
gMatStackIndex++;
mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = mtx;
mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
gGeoTempState.type = gCurAnimType;
gGeoTempState.enabled = gCurAnimEnabled;
gGeoTempState.frame = gCurrAnimFrame;
gGeoTempState.translationMultiplier = gCurAnimTranslationMultiplier;
gGeoTempState.attribute = gCurrAnimAttribute;
gGeoTempState.data = gCurAnimData;
gGeoTempState.prevFrame = gPrevAnimFrame;
gCurAnimType = 0;
gCurGraphNodeHeldObject = (void *) node;
if (node->objNode->header.gfx.unk38.curAnim != NULL) {
@ -926,6 +1287,7 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
gCurAnimTranslationMultiplier = gGeoTempState.translationMultiplier;
gCurrAnimAttribute = gGeoTempState.attribute;
gCurAnimData = gGeoTempState.data;
gPrevAnimFrame = gGeoTempState.prevFrame;
gMatStackIndex--;
}
@ -1047,6 +1409,7 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor)
if (node->node.flags & GRAPH_RENDER_ACTIVE) {
Mtx *initialMatrix;
Vp *viewport = alloc_display_list(sizeof(*viewport));
Vp *viewportInterpolated = viewport;
gDisplayListHeap = alloc_only_pool_init();
initialMatrix = alloc_display_list(sizeof(*initialMatrix));
@ -1056,7 +1419,12 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor)
vec3s_set(viewport->vp.vscale, node->width * 4, node->height * 4, 511);
if (b != NULL) {
clear_frame_buffer(clearColor);
make_viewport_clip_rect(b);
viewportInterpolated = alloc_display_list(sizeof(*viewportInterpolated));
interpolate_vectors_s16(viewportInterpolated->vp.vtrans, sPrevViewport.vp.vtrans, b->vp.vtrans);
interpolate_vectors_s16(viewportInterpolated->vp.vscale, sPrevViewport.vp.vscale, b->vp.vscale);
sViewportPos = gDisplayListHead;
make_viewport_clip_rect(viewportInterpolated);
*viewport = *b;
}
@ -1064,11 +1432,16 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor)
clear_frame_buffer(clearColor);
make_viewport_clip_rect(c);
}
sPrevViewport = *viewport;
mtxf_identity(gMatStack[gMatStackIndex]);
mtxf_to_mtx(initialMatrix, gMatStack[gMatStackIndex]);
gMatStackFixed[gMatStackIndex] = initialMatrix;
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewport));
mtxf_identity(gMatStackInterpolated[gMatStackIndex]);
gMatStackInterpolatedFixed[gMatStackIndex] = initialMatrix;
gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewportInterpolated));
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(gMatStackFixed[gMatStackIndex]),
G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
gCurGraphNodeRoot = node;

View File

@ -16,6 +16,19 @@
u8 sTransitionColorFadeCount[4] = { 0 };
u16 sTransitionTextureFadeCount[2] = { 0 };
static Gfx *sScreenTransitionVerticesPos[2];
static Vtx *sScreenTransitionVertices;
void patch_screen_transition_interpolated(void) {
if (sScreenTransitionVerticesPos[0] != NULL) {
gSPVertex(sScreenTransitionVerticesPos[0], VIRTUAL_TO_PHYSICAL(sScreenTransitionVertices), 8, 0);
gSPVertex(sScreenTransitionVerticesPos[1], VIRTUAL_TO_PHYSICAL(sScreenTransitionVertices), 4, 0);
sScreenTransitionVerticesPos[0] = NULL;
sScreenTransitionVerticesPos[1] = NULL;
sScreenTransitionVertices = NULL;
}
}
s32 set_and_reset_transition_fade_timer(s8 fadeTimer, u8 transTime) {
s32 reset = FALSE;
@ -85,14 +98,29 @@ s32 render_fade_transition_into_color(s8 fadeTimer, u8 transTime, struct WarpTra
return dl_transition_color(fadeTimer, transTime, transData, alpha);
}
#if 0
s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) {
f32 texRadius = transData->endTexRadius - transData->startTexRadius;
f32 radiusTime = sTransitionColorFadeCount[fadeTimer] * texRadius / (f32)(transTime - 1);
f32 result = transData->startTexRadius + radiusTime;
return (s16)(result + 0.5);;
return (s16)(result + 0.5);
}
#else
s16 calc_tex_transition_radius(s8 fadeTimer, f32 interpolationFraction, s8 transTime, struct WarpTransitionData *transData) {
f32 texRadius = transData->endTexRadius - transData->startTexRadius;
f32 radiusTime = (sTransitionColorFadeCount[fadeTimer] == 0 ? 0 :
sTransitionColorFadeCount[fadeTimer] - 1 + interpolationFraction) * texRadius / (f32)(transTime - 1);
f32 result = transData->startTexRadius + radiusTime;
return (s16)(result + 0.5);
}
#endif
f32 calc_tex_transition_time(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) {
f32 startX = transData->startTexX;
f32 startY = transData->startTexY;
@ -166,6 +194,8 @@ void *sTextureTransitionID[] = {
texture_transition_bowser_half,
};
#if 0
s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) {
f32 texTransTime = calc_tex_transition_time(fadeTimer, transTime, transData);
u16 texTransPos = convert_tex_transition_angle_to_pos(transData);
@ -206,6 +236,56 @@ s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransition
return set_and_reset_transition_fade_timer(fadeTimer, transTime);
}
#else
s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) {
f32 texTransTime = calc_tex_transition_time(fadeTimer, transTime, transData);
u16 texTransPos = convert_tex_transition_angle_to_pos(transData);
s16 centerTransX = center_tex_transition_x(transData, texTransTime, texTransPos);
s16 centerTransY = center_tex_transition_y(transData, texTransTime, texTransPos);
s16 texTransRadius = calc_tex_transition_radius(fadeTimer, 1.0f, transTime, transData);
s16 texTransRadiusInterpolated = calc_tex_transition_radius(fadeTimer, 0.5f, transTime, transData);
Vtx *verts = alloc_display_list(8 * sizeof(*verts));
Vtx *vertsInterpolated = alloc_display_list(8 * sizeof(*vertsInterpolated));
if (verts != NULL && vertsInterpolated != NULL) {
load_tex_transition_vertex(verts, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, transTexType);
load_tex_transition_vertex(vertsInterpolated, fadeTimer, transData, centerTransX, centerTransY, texTransRadiusInterpolated, transTexType);
sScreenTransitionVertices = verts;
gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen)
gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE);
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2);
sScreenTransitionVerticesPos[0] = gDisplayListHead;
gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsInterpolated), 8, 0);
gSPDisplayList(gDisplayListHead++, dl_transition_draw_filled_region);
gDPPipeSync(gDisplayListHead++);
gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA);
gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP);
switch (transTexType) {
case TRANS_TYPE_MIRROR:
gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 32, 64, 0,
G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD);
break;
case TRANS_TYPE_CLAMP:
gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 64, 64, 0,
G_TX_CLAMP, G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD);
break;
}
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
sScreenTransitionVerticesPos[1] = gDisplayListHead;
gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsInterpolated), 4, 0);
gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123);
gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF);
gSPDisplayList(gDisplayListHead++, dl_screen_transition_end);
sTransitionTextureFadeCount[fadeTimer] += transData->texTimer;
} else {
}
return set_and_reset_transition_fade_timer(fadeTimer, transTime);
}
#endif
int render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct WarpTransitionData *transData) {
switch (transType) {
case WARP_TRANSITION_FADE_FROM_COLOR:

View File

@ -12,6 +12,7 @@
#include "segment2.h"
#include "shadow.h"
#include "sm64.h"
#include "moon/saturn/saturn_types.h"
// Avoid Z-fighting
#define find_floor_height_and_data 0.4 + find_floor_height_and_data
@ -851,6 +852,11 @@ Gfx *create_shadow_hardcoded_rectangle(f32 xPos, f32 yPos, f32 zPos, UNUSED s16
*/
Gfx *create_shadow_below_xyz(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 shadowSolidity,
s8 shadowType) {
if (!enable_shadows) {
return NULL;
}
Gfx *displayList = NULL;
struct Surface *pfloor;
find_floor(xPos, yPos, zPos, &pfloor);

View File

@ -1,5 +1,6 @@
#include <PR/ultratypes.h>
#include "engine/math_util.h"
#include "game/memory.h"
#include "game/segment2.h"
#include "game/segment7.h"
@ -146,6 +147,18 @@ Gfx *geo_n64_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
}
static Gfx *sIntroScalePos;
static Vec3f sIntroScale;
void patch_title_screen_scales(void) {
if (sIntroScalePos != NULL) {
Mtx *scaleMat = alloc_display_list(sizeof(*scaleMat));
guScale(scaleMat, sIntroScale[0], sIntroScale[1], sIntroScale[2]);
gSPMatrix(sIntroScalePos, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
sIntroScalePos = NULL;
}
}
Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
struct GraphNode *graphNode; // sp4c
Gfx *displayList; // sp48
@ -156,6 +169,8 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
f32 scaleX; // sp34
f32 scaleY; // sp30
f32 scaleZ; // sp2c
Vec3f scale;
Vec3f scaleInterpolated;
graphNode = sp54;
displayList = NULL;
displayListIter = NULL;
@ -187,6 +202,11 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
scaleZ = 0.0f;
}
guScale(scaleMat, scaleX, scaleY, scaleZ);
vec3f_set(scale, scaleX, scaleY, scaleZ);
interpolate_vectors(scaleInterpolated, sIntroScale, scale);
vec3f_set(sIntroScale, scaleX, scaleY, scaleZ);
guScale(scaleMat, scaleInterpolated[0], scaleInterpolated[1], scaleInterpolated[2]);
sIntroScalePos = displayListIter;
gSPMatrix(displayListIter++, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
gSPDisplayList(displayListIter++, &intro_seg7_dl_0700B3A0);
gSPPopMatrix(displayListIter++, G_MTX_MODELVIEW);

View File

@ -30,7 +30,7 @@ using namespace std;
map<string, Achievement*> registeredAchievements;
map<int, vector<AchievementEntry*>> entries;
bool cheatsGotEnabled = false;
bool cheatsGotEnabled = true;
namespace AchievementList {
/* Star achievements */

View File

@ -12,6 +12,9 @@
#include "moon/mod-engine/hooks/hook.h"
#include "moon/mod-engine/textures/mod-texture.h"
#include "moon/mod-engine/engine.h"
#include "moon/saturn/saturn.h"
#include "moon/saturn/saturn_colors.h"
#include "moon/saturn/saturn_types.h"
#include "icons/IconsForkAwesome.h"
#include "icons/IconsMaterialDesign.h"
#include "moon/utils/moon-env.h"
@ -63,6 +66,8 @@ extern "C" {
extern "C" {
#include "pc/gfx/gfx_pc.h"
#include "pc/pc_main.h"
#include "game/camera.h"
#include "game/mario.h"
}
#include "pc/configfile.h"
@ -133,6 +138,26 @@ namespace MoonInternal {
map<string, ImFont*> fontMap;
// Colors
static ImVec4 uiHatColor = ImVec4(255.0f / 255.0f, 0.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiHatShadeColor = ImVec4(127.0f / 255.0f, 0.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiOverallsColor = ImVec4(0.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiOverallsShadeColor = ImVec4(0.0f / 255.0f, 0.0f / 255.0f, 127.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiGlovesColor = ImVec4(255.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiGlovesShadeColor = ImVec4(127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiShoesColor = ImVec4(114.0f / 255.0f, 28.0f / 255.0f, 14.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiShoesShadeColor = ImVec4(57.0f / 255.0f, 14.0f / 255.0f, 7.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiSkinColor = ImVec4(254.0f / 255.0f, 193.0f / 255.0f, 121.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiSkinShadeColor = ImVec4(127.0f / 255.0f, 96.0f / 255.0f, 60.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiHairColor = ImVec4(115.0f / 255.0f, 6.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f);
static ImVec4 uiHairShadeColor = ImVec4(57.0f / 255.0f, 3.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f);
static char bufname[128] = "Sample";
bool hasChangedFullscreen;
int tempXRes;
int tempYRes;
void setupFonts() {
ImGuiIO& io = ImGui::GetIO();
// for (auto entry = Moon::fonts.begin(); entry != Moon::fonts.end(); entry++){
@ -156,6 +181,45 @@ namespace MoonInternal {
io.Fonts->Build();
}
void apply_cc_from_editor() {
defaultColorHatRLight = (int)(uiHatColor.x * 255);
defaultColorHatGLight = (int)(uiHatColor.y * 255);
defaultColorHatBLight = (int)(uiHatColor.z * 255);
defaultColorHatRDark = (int)(uiHatShadeColor.x * 255);
defaultColorHatGDark = (int)(uiHatShadeColor.y * 255);
defaultColorHatBDark = (int)(uiHatShadeColor.z * 255);
defaultColorOverallsRLight = (int)(uiOverallsColor.x * 255);
defaultColorOverallsGLight = (int)(uiOverallsColor.y * 255);
defaultColorOverallsBLight = (int)(uiOverallsColor.z * 255);
defaultColorOverallsRDark = (int)(uiOverallsShadeColor.x * 255);
defaultColorOverallsGDark = (int)(uiOverallsShadeColor.y * 255);
defaultColorOverallsBDark = (int)(uiOverallsShadeColor.z * 255);
defaultColorGlovesRLight = (int)(uiGlovesColor.x * 255);
defaultColorGlovesGLight = (int)(uiGlovesColor.y * 255);
defaultColorGlovesBLight = (int)(uiGlovesColor.z * 255);
defaultColorGlovesRDark = (int)(uiGlovesShadeColor.x * 255);
defaultColorGlovesGDark = (int)(uiGlovesShadeColor.y * 255);
defaultColorGlovesBDark = (int)(uiGlovesShadeColor.z * 255);
defaultColorShoesRLight = (int)(uiShoesColor.x * 255);
defaultColorShoesGLight = (int)(uiShoesColor.y * 255);
defaultColorShoesBLight = (int)(uiShoesColor.z * 255);
defaultColorShoesRDark = (int)(uiShoesShadeColor.x * 255);
defaultColorShoesGDark = (int)(uiShoesShadeColor.y * 255);
defaultColorShoesBDark = (int)(uiShoesShadeColor.z * 255);
defaultColorSkinRLight = (int)(uiSkinColor.x * 255);
defaultColorSkinGLight = (int)(uiSkinColor.y * 255);
defaultColorSkinBLight = (int)(uiSkinColor.z * 255);
defaultColorSkinRDark = (int)(uiSkinShadeColor.x * 255);
defaultColorSkinGDark = (int)(uiSkinShadeColor.y * 255);
defaultColorSkinBDark = (int)(uiSkinShadeColor.z * 255);
defaultColorHairRLight = (int)(uiHairColor.x * 255);
defaultColorHairGLight = (int)(uiHairColor.y * 255);
defaultColorHairBLight = (int)(uiHairColor.z * 255);
defaultColorHairRDark = (int)(uiHairShadeColor.x * 255);
defaultColorHairGDark = (int)(uiHairShadeColor.y * 255);
defaultColorHairBDark = (int)(uiHairShadeColor.z * 255);
}
void setupImGuiModule(string status) {
MoonInternal::setupWindowHook(status);
if(status == "PreStartup"){
@ -182,6 +246,9 @@ namespace MoonInternal {
ImGui_ImplSDL2_InitForOpenGL(window, call.baseArgs["context"]);
ImGui_ImplOpenGL3_Init(glsl_version);
tempXRes = configWindow.w;
tempYRes = configWindow.h;
#ifdef TARGET_SWITCH
MoonNX::handleVirtualKeyboard("Init");
#endif
@ -227,7 +294,7 @@ namespace MoonInternal {
if (!ImGui::DockBuilderGetNode(dockspace_id)) {
ImGui::DockBuilderRemoveNode(dockspace_id);
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_None);
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_NoTabBar);
ImGui::DockBuilderDockWindow("Game", dockspace_id);
@ -236,24 +303,39 @@ namespace MoonInternal {
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
if (ImGui::BeginMenuBar()) {
TextureData* tmp = forceTextureLoad("mod-icons://Moon64");
if(tmp != nullptr) {
ImGui::SetCursorPos(ImVec2(0, 0));
ImGui::Image((ImTextureID) tmp->texture_id, ImVec2(25.0f, 25.0f));
//if (show_menu_bar) {
if (ImGui::BeginMenuBar()) {
/*
TextureData* tmp = forceTextureLoad("mod-icons://Moon64");
if(tmp != nullptr) {
ImGui::SetCursorPos(ImVec2(0, 0));
ImGui::Image((ImTextureID) tmp->texture_id, ImVec2(25.0f, 25.0f));
ImGui::SameLine();
}
*/
ImGui::Text("Saturn");
ImGui::SameLine();
ImGui::Separator();
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Toggle View (F1)", NULL, &show_menu_bar);
ImGui::MenuItem("N64 Mode", NULL, &configImGui.n64Mode);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("Stats", NULL, &configImGui.moon64);
ImGui::MenuItem("Machinima", NULL, &configImGui.s_machinima);
ImGui::MenuItem("Quick Toggles", NULL, &configImGui.s_toggles);
ImGui::MenuItem("CC Editor", NULL, &configImGui.s_cceditor);
//ImGui::MenuItem("Debug Textures", NULL, &configImGui.texture_debug);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Misc")) {
ImGui::MenuItem("Settings", NULL, &configImGui.s_options);
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
ImGui::Text("Moon64");
ImGui::SameLine();
ImGui::Separator();
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("Moon64", NULL, &configImGui.moon64);
ImGui::MenuItem("Textures", NULL, &configImGui.texture_debug);
ImGui::MenuItem("N64 Mode", NULL, &configImGui.n64Mode);
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
//}
ImGui::End();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); // Set window background to red
@ -264,6 +346,27 @@ namespace MoonInternal {
ImVec2 size = ImGui::GetContentRegionAvail();
ImVec2 pos = ImVec2(0, 0);
if (configWindow.fullscreen) {
if (!hasChangedFullscreen) {
std::cout << "fullscreen test" << std::endl;
tempXRes = configWindow.w;
tempYRes = configWindow.h;
SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM);
configWindow.w = DM.w;
configWindow.h = DM.h;
hasChangedFullscreen = true;
}
} else {
if (hasChangedFullscreen) {
std::cout << "test2 fsd" << std::endl;
configWindow.w = tempXRes;
configWindow.h = tempYRes;
SDL_SetWindowSize(window, tempXRes, tempYRes);
hasChangedFullscreen = false;
}
}
configWindow.internal_w = configImGui.n64Mode ? SM64_WIDTH : size.x;
configWindow.internal_h = configImGui.n64Mode ? SM64_HEIGHT : size.y;
@ -278,27 +381,203 @@ namespace MoonInternal {
ImGui::ImageRotated((ImTextureID) fbuf, pos, size, 180.0f);
ImGui::End();
if (configImGui.moon64){
if (configImGui.moon64 && show_menu_bar){
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Moon64 Game Stats", NULL, ImGuiWindowFlags_None);
ImGui::Begin("Stats", NULL, ImGuiWindowFlags_None);
ImGui::Text("Platform: " PLATFORM " (" RAPI_NAME ")");
ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("View: %.0fx%.0f (%.1f FPS)", configWindow.internal_w * configWindow.multiplier, configWindow.internal_h * configWindow.multiplier, ImGui::GetIO().Framerate);
ImGui::Text("Version: " GIT_BRANCH " " GIT_HASH);
ImGui::Text("Addons: %d\n", Moon::addons.size());
ImGui::Text("Resolution: %.0fx%.0f\n", configWindow.internal_w * configWindow.multiplier, configWindow.internal_h * configWindow.multiplier);
ImGui::Text("Internal Resolution:");
if(!configImGui.n64Mode)
ImGui::SliderFloat("Mul", &configWindow.multiplier, 0.0f, 4.0f);
else
ImGui::SliderInt("Mul", &n64Mul, 1, 8);
ImGui::End();
ImGui::PopStyleColor();
}
if (configImGui.s_toggles && show_menu_bar){
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Quick Toggles", NULL, ImGuiWindowFlags_None);
if (ImGui::BeginTable("quick_toggles", 1))
{
ImGui::TableNextColumn();
ImGui::Checkbox("HUD", &configHUD);
ImGui::TableNextColumn();
ImGui::Checkbox("Head Rotations", &enable_head_rotations);
ImGui::TableNextColumn();
ImGui::Checkbox("Shadows", &enable_shadows);
ImGui::TableNextColumn();
ImGui::Checkbox("Dust Particles", &enable_dust_particles);
ImGui::EndTable();
}
ImGui::End();
ImGui::PopStyleColor();
}
if(configImGui.texture_debug) {
if (configImGui.s_machinima && show_menu_bar) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Machinima", NULL, ImGuiWindowFlags_None);
ImGui::Checkbox("Machinima Camera", &camera_frozen);
if (camera_frozen == true) {
ImGui::SliderFloat("Speed", &camera_speed, 0.0f, 0.3f);
}
ImGui::Dummy(ImVec2(0, 10));
ImGui::Text("Body States");
const char* eyeStates[] = { "Default", "Open", "Half", "Closed", "Left", "Right", "Up", "Down", "Dead" };
ImGui::Combo("Eyes", &current_eye_state, eyeStates, IM_ARRAYSIZE(eyeStates));
const char* handStates[] = { "Fists", "Open", "Peace", "With Cap", "With Wing Cap", "Right Open" };
ImGui::Combo("Hands", &current_hand_state, handStates, IM_ARRAYSIZE(handStates));
const char* capStates[] = { "Cap On", "Cap Off", "Wing Cap" }; // unused "wing cap off" not included
ImGui::Combo("Cap", &current_cap_state, capStates, IM_ARRAYSIZE(capStates));
ImGui::Dummy(ImVec2(0, 10));
ImGui::Text("Select Color Code");
static int current_cc_id = 0;
string cc_name = MoonInternal::cc_array[current_cc_id].substr(0, MoonInternal::cc_array[current_cc_id].size() - 3);
if (ImGui::BeginCombo(".gs", cc_name.c_str()))
{
for (int n = 0; n < MoonInternal::cc_array.size(); n++)
{
const bool is_selected = (current_cc_id == n);
cc_name = MoonInternal::cc_array[n].substr(0, MoonInternal::cc_array[n].size() - 3);
if (ImGui::Selectable(cc_name.c_str(), is_selected)) {
current_cc_id = n;
}
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
if (ImGui::Button("Load")) {
load_cc_file(cc_array[current_cc_id]);
uiHatColor = ImVec4(float(defaultColorHatRLight) / 255.0f, float(defaultColorHatGLight) / 255.0f, float(defaultColorHatBLight) / 255.0f, 255.0f / 255.0f);
uiHatShadeColor = ImVec4(float(defaultColorHatRDark) / 255.0f, float(defaultColorHatGDark) / 255.0f, float(defaultColorHatBDark) / 255.0f, 255.0f / 255.0f);
uiOverallsColor = ImVec4(float(defaultColorOverallsRLight) / 255.0f, float(defaultColorOverallsGLight) / 255.0f, float(defaultColorOverallsBLight) / 255.0f, 255.0f / 255.0f);
uiOverallsShadeColor = ImVec4(float(defaultColorOverallsRDark) / 255.0f, float(defaultColorOverallsGDark) / 255.0f, float(defaultColorOverallsBDark) / 255.0f, 255.0f / 255.0f);
uiGlovesColor = ImVec4(float(defaultColorGlovesRLight) / 255.0f, float(defaultColorGlovesGLight) / 255.0f, float(defaultColorGlovesBLight) / 255.0f, 255.0f / 255.0f);
uiGlovesShadeColor = ImVec4(float(defaultColorGlovesRDark) / 255.0f, float(defaultColorGlovesGDark) / 255.0f, float(defaultColorGlovesBDark) / 255.0f, 255.0f / 255.0f);
uiShoesColor = ImVec4(float(defaultColorShoesRLight) / 255.0f, float(defaultColorShoesGLight) / 255.0f, float(defaultColorShoesBLight) / 255.0f, 255.0f / 255.0f);
uiShoesShadeColor = ImVec4(float(defaultColorShoesRDark) / 255.0f, float(defaultColorShoesGDark) / 255.0f, float(defaultColorShoesBDark) / 255.0f, 255.0f / 255.0f);
uiSkinColor = ImVec4(float(defaultColorSkinRLight) / 255.0f, float(defaultColorSkinGLight) / 255.0f, float(defaultColorSkinBLight) / 255.0f, 255.0f / 255.0f);
uiSkinShadeColor = ImVec4(float(defaultColorSkinRDark) / 255.0f, float(defaultColorSkinGDark) / 255.0f, float(defaultColorSkinBDark) / 255.0f, 255.0f / 255.0f);
uiHairColor = ImVec4(float(defaultColorHairRLight) / 255.0f, float(defaultColorHairGLight) / 255.0f, float(defaultColorHairBLight) / 255.0f, 255.0f / 255.0f);
uiHairShadeColor = ImVec4(float(defaultColorHairRDark) / 255.0f, float(defaultColorHairGDark) / 255.0f, float(defaultColorHairBDark) / 255.0f, 255.0f / 255.0f);
// We never want to use the name "Mario" when saving/loading a CC, as it will cause file issues.
if (cc_name == "Mario") {
strcpy(bufname, "Sample");
} else {
strcpy(bufname, cc_name.c_str());
}
}
ImGui::End();
ImGui::PopStyleColor();
}
if (configImGui.s_cceditor && show_menu_bar) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("CC Editor", NULL, ImGuiWindowFlags_None);
ImGui::Text("Shirt/Cap");
ImGui::ColorEdit4("Hat Main", (float*)&uiHatColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::ColorEdit4("Hat Shade", (float*)&uiHatShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::Text("Overalls");
ImGui::ColorEdit4("Overalls Main", (float*)&uiOverallsColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::ColorEdit4("Overalls Shade", (float*)&uiOverallsShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::Text("Gloves");
ImGui::ColorEdit4("Gloves Main", (float*)&uiGlovesColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::ColorEdit4("Gloves Shade", (float*)&uiGlovesShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::Text("Shoes");
ImGui::ColorEdit4("Shoes Main", (float*)&uiShoesColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::ColorEdit4("Shoes Shade", (float*)&uiShoesShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::Text("Skin");
ImGui::ColorEdit4("Skin Main", (float*)&uiSkinColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::ColorEdit4("Skin Shade", (float*)&uiSkinShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::Text("Hair");
ImGui::ColorEdit4("Hair Main", (float*)&uiHairColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::ColorEdit4("Hair Shade", (float*)&uiHairShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel);
ImGui::Dummy(ImVec2(0, 5));
if (ImGui::Button("Load")) {
apply_cc_from_editor();
}
ImGui::Dummy(ImVec2(0, 5));
ImGui::InputText(".gs", bufname, IM_ARRAYSIZE(bufname));
if (ImGui::Button("Save")) {
apply_cc_from_editor();
std::string cc_name = bufname;
// We don't want to save a CC named "Mario", as it may cause file issues.
if (cc_name != "Mario") {
save_cc_file(cc_name);
} else {
strcpy(bufname, "Sample");
save_cc_file("Sample");
}
load_cc_directory();
}
ImGui::End();
ImGui::PopStyleColor();
}
//ImGui::ShowDemoWindow();
if (configImGui.s_options && show_menu_bar) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Settings", NULL, ImGuiWindowFlags_None);
if (ImGui::CollapsingHeader("Graphics")) {
if (ImGui::Button("Toggle Fullscreen")) {
configWindow.fullscreen = !configWindow.fullscreen;
configWindow.settings_changed = true;
}
if (!configWindow.fullscreen) {
if (ImGui::Button("Reset Window Size")) {
configWindow.w = 1280;
configWindow.h = 768; // 720 + 48 for the top bar
SDL_SetWindowSize(window, 1280, 768);
}
}
ImGui::Checkbox("VSync", &configWindow.vsync);
ImGui::Text("Graphics Quality");
const char* lod_modes[] = { "Auto", "Low", "High" };
ImGui::Combo("###lod_modes", (int*)&configLODMode, lod_modes, IM_ARRAYSIZE(lod_modes));
ImGui::Text("Texture Filtering");
const char* texture_filters[] = { "Nearest", "Linear", "Three-point" };
ImGui::Combo("###texture_filters", (int*)&configFiltering, texture_filters, IM_ARRAYSIZE(texture_filters));
}
if (ImGui::CollapsingHeader("Audio")) {
ImGui::Text("Volume");
ImGui::SliderInt("Master", (int*)&configMasterVolume, 0, MAX_VOLUME);
ImGui::SliderInt("SFX", (int*)&configSfxVolume, 0, MAX_VOLUME);
ImGui::SliderInt("Music", (int*)&configMusicVolume, 0, MAX_VOLUME);
ImGui::SliderInt("Environment", (int*)&configEnvVolume, 0, MAX_VOLUME);
}
if (ImGui::CollapsingHeader("Gameplay")) {
ImGui::Text("Rumble Strength");
ImGui::SliderInt("###rumble_strength", (int*)&configRumbleStrength, 0, 50);
ImGui::Checkbox("Skip Intro", &configSkipIntro);
#ifdef DISCORDRPC
ImGui::Checkbox("Discord Activity Status", &configDiscordRPC);
#endif
}
ImGui::End();
ImGui::PopStyleColor();
}
if(configImGui.texture_debug && show_menu_bar) {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Loaded textures", NULL, ImGuiWindowFlags_None);

View File

@ -8,6 +8,7 @@
#include "moon/utils/moon-env.h"
#include "moon/mod-engine/engine.h"
#include "moon/mod-engine/test.h"
#include "moon/saturn/saturn.h"
#include "moon/io/moon-io.h"
#include "moon/imgui/imgui_impl.h"
@ -28,6 +29,7 @@ void moon_setup(char *state){
MoonInternal::setupImGuiModule(string(state));
// MoonRenderer::setupSkyboxRenderer(string(state));
// MoonInternal::setupSoundModule(string(state));
MoonInternal::setupSaturnModule(string(state));
}
/*

130
src/moon/saturn/saturn.cpp Normal file
View File

@ -0,0 +1,130 @@
#include "saturn.h"
#include "moon/mod-engine/hooks/hook.h"
#include "moon/utils/moon-env.h"
#include "moon/fs/moonfs.h"
#include "pc/configfile.h"
#include "saturn_colors.h"
#include <SDL2/SDL.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include <dirent.h>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
extern "C" {
#include "game/camera.h"
#include "game/level_update.h"
#include "game/mario.h"
#include "sm64.h"
}
bool camera_frozen;
bool enable_head_rotations;
bool enable_shadows;
bool enable_dust_particles;
bool show_menu_bar;
float camera_speed = 0.0f;
namespace MoonInternal {
// Machinima
void freeze_camera() {
camera_frozen = !camera_frozen;
//camVelSpeed = 1.0f;
}
void cycle_eye_state(int cycle) {
current_eye_state += cycle;
}
// Setup Module
void setupSaturnModule(string status){
if(status == "PreStartup"){
Moon::registerHookListener({.hookName = WINDOW_API_INIT, .callback = [&](HookCall call){
camera_frozen = false;
enable_shadows = true;
current_eye_state = 0;
show_menu_bar = false;
MoonInternal::load_cc_directory();
}});
Moon::registerHookListener({.hookName = WINDOW_API_HANDLE_EVENTS, .callback = [&](HookCall call){
SDL_Event* ev = (SDL_Event*) call.baseArgs["event"];
switch (ev->type){
case SDL_KEYDOWN:
if(ev->key.keysym.sym == SDLK_f){
freeze_camera();
}
if(ev->key.keysym.sym == SDLK_x){
cycle_eye_state(1);
}
if(ev->key.keysym.sym == SDLK_z){
cycle_eye_state(-1);
}
if(ev->key.keysym.sym == SDLK_F1){
show_menu_bar = !show_menu_bar;
}
case SDL_CONTROLLERBUTTONDOWN:
if (ev->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
freeze_camera();
}
if (ev->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
cycle_eye_state(1);
}
if (ev->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
cycle_eye_state(-1);
}
if(ev->cbutton.button == SDL_CONTROLLER_BUTTON_BACK){
show_menu_bar = !show_menu_bar;
}
break;
}
}});
Moon::registerHookListener({.hookName = GFX_PRE_START_FRAME, .callback = [&](HookCall call){
// Machinima Camera
if (camera_frozen == true) {
if (set_cam_angle(0) != CAM_ANGLE_MARIO) {
gLakituState.focVSpeed = camera_speed;
gLakituState.focHSpeed = camera_speed;
}
gLakituState.posVSpeed = camera_speed;
gLakituState.posHSpeed = camera_speed;
gCamera->nextYaw = calculate_yaw(gLakituState.focus, gLakituState.pos);
gCamera->yaw = gCamera->nextYaw;
gCameraMovementFlags &= ~CAM_MOVE_FIX_IN_PLACE;
}
// Body States
if (current_cap_state >= 3) {
current_cap_state = 0;
}
if (current_eye_state >= 9) {
current_eye_state = 0;
} else if (current_eye_state <= -1) {
current_eye_state = 8;
}
if (current_hand_state >= 6) {
current_hand_state = 0;
}
}});
}
}
}

19
src/moon/saturn/saturn.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef MoonSaturnEngine
#define MoonSaturnEngine
#include <string>
#include <vector>
namespace MoonInternal {
void setupSaturnModule(std::string status);
void freeze_camera();
}
extern bool camera_frozen;
#include "saturn_types.h"
extern bool show_menu_bar;
extern float camera_speed;
#endif

View File

@ -0,0 +1,343 @@
#include "saturn_colors.h"
#include "saturn.h"
#include "moon/mod-engine/hooks/hook.h"
#include "moon/utils/moon-env.h"
#include "moon/fs/moonfs.h"
#include "pc/configfile.h"
#include "moon/imgui/imgui_impl.h"
#include "moon/libs/imgui/imgui.h"
#include "moon/libs/imgui/imgui_internal.h"
#include "moon/libs/imgui/imgui_impl_sdl.h"
#include <SDL2/SDL.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include <dirent.h>
#include <filesystem>
#include <fstream>
namespace fs = std::filesystem;
extern "C" {
#include "game/camera.h"
#include "game/level_update.h"
#include "sm64.h"
}
unsigned int defaultColorHatRLight = 255;
unsigned int defaultColorHatRDark = 127;
unsigned int defaultColorHatGLight = 0;
unsigned int defaultColorHatGDark = 0;
unsigned int defaultColorHatBLight = 0;
unsigned int defaultColorHatBDark = 0;
unsigned int defaultColorOverallsRLight = 0;
unsigned int defaultColorOverallsRDark = 0;
unsigned int defaultColorOverallsGLight = 0;
unsigned int defaultColorOverallsGDark = 0;
unsigned int defaultColorOverallsBLight = 255;
unsigned int defaultColorOverallsBDark = 127;
unsigned int defaultColorGlovesRLight = 255;
unsigned int defaultColorGlovesRDark = 127;
unsigned int defaultColorGlovesGLight = 255;
unsigned int defaultColorGlovesGDark = 127;
unsigned int defaultColorGlovesBLight = 255;
unsigned int defaultColorGlovesBDark = 127;
unsigned int defaultColorShoesRLight = 114;
unsigned int defaultColorShoesRDark = 57;
unsigned int defaultColorShoesGLight = 28;
unsigned int defaultColorShoesGDark = 14;
unsigned int defaultColorShoesBLight = 14;
unsigned int defaultColorShoesBDark = 7;
unsigned int defaultColorSkinRLight = 254;
unsigned int defaultColorSkinRDark = 127;
unsigned int defaultColorSkinGLight = 193;
unsigned int defaultColorSkinGDark = 96;
unsigned int defaultColorSkinBLight = 121;
unsigned int defaultColorSkinBDark = 60;
unsigned int defaultColorHairRLight = 115;
unsigned int defaultColorHairRDark = 57;
unsigned int defaultColorHairGLight = 6;
unsigned int defaultColorHairGDark = 3;
unsigned int defaultColorHairBLight = 0;
unsigned int defaultColorHairBDark = 0;
// Color Codes
namespace MoonInternal {
std::vector<string> cc_array;
string colorCodeDir;
void load_cc_directory() {
cc_array.clear();
cc_array.push_back("Mario.gs");
string cwd = MoonInternal::getEnvironmentVar("MOON_CWD");
#ifdef __MINGW32__
// Windows moment
colorCodeDir = cwd.substr(0, cwd.find_last_of("/\\")) + "\\machinima\\colorcodes\\";
#else
colorCodeDir = cwd.substr(0, cwd.find_last_of("/\\")) + "/machinima/colorcodes/";
#endif
for (const auto & entry : fs::directory_iterator(colorCodeDir))
cc_array.push_back(entry.path().filename().u8string());
//std::cout << cc_array[0] << std::endl;
}
void reset_cc_colors() {
defaultColorHatRLight = 255;
defaultColorHatRDark = 127;
defaultColorHatGLight = 0;
defaultColorHatGDark = 0;
defaultColorHatBLight = 0;
defaultColorHatBDark = 0;
defaultColorOverallsRLight = 0;
defaultColorOverallsRDark = 0;
defaultColorOverallsGLight = 0;
defaultColorOverallsGDark = 0;
defaultColorOverallsBLight = 255;
defaultColorOverallsBDark = 127;
defaultColorGlovesRLight = 255;
defaultColorGlovesRDark = 127;
defaultColorGlovesGLight = 255;
defaultColorGlovesGDark = 127;
defaultColorGlovesBLight = 255;
defaultColorGlovesBDark = 127;
defaultColorShoesRLight = 114;
defaultColorShoesRDark = 57;
defaultColorShoesGLight = 28;
defaultColorShoesGDark = 14;
defaultColorShoesBLight = 14;
defaultColorShoesBDark = 7;
defaultColorSkinRLight = 254;
defaultColorSkinRDark = 127;
defaultColorSkinGLight = 193;
defaultColorSkinGDark = 96;
defaultColorSkinBLight = 121;
defaultColorSkinBDark = 60;
defaultColorHairRLight = 115;
defaultColorHairRDark = 57;
defaultColorHairGLight = 6;
defaultColorHairGDark = 3;
defaultColorHairBLight = 0;
defaultColorHairBDark = 0;
}
void load_cc_file(string cc_filename) {
if (cc_filename == "Mario.gs") {
reset_cc_colors();
return;
}
std::ifstream file(colorCodeDir + cc_filename, std::ios::in | std::ios::binary);
// If the color code was previously deleted, reload the list and cancel.
if (!file.good()) {
load_cc_directory();
return;
}
const std::size_t& size = std::filesystem::file_size(colorCodeDir + cc_filename);
std::string content(size, '\0');
file.read(content.data(), size);
file.close();
std::istringstream f(content);
std::string line;
while (std::getline(f, line)) {
std::string address = line.substr(2, 6);
int value1 = std::stoi(line.substr(9, 2), 0, 16);
int value2 = std::stoi(line.substr(11, 2), 0, 16);
// Hat
if (address == "07EC40") {
defaultColorHatRLight = value1;
defaultColorHatGLight = value2;
}
if (address == "07EC42") {
defaultColorHatBLight = value1;
}
if (address == "07EC38") {
defaultColorHatRDark = value1;
defaultColorHatGDark = value2;
}
if (address == "07EC3A") {
defaultColorHatBDark = value1;
}
// Overalls
if (address == "07EC28") {
defaultColorOverallsRLight = value1;
defaultColorOverallsGLight = value2;
}
if (address == "07EC2A") {
defaultColorOverallsBLight = value1;
}
if (address == "07EC20") {
defaultColorOverallsRDark = value1;
defaultColorOverallsGDark = value2;
}
if (address == "07EC22") {
defaultColorOverallsBDark = value1;
}
// Gloves
if (address == "07EC58") {
defaultColorGlovesRLight = value1;
defaultColorGlovesGLight = value2;
}
if (address == "07EC5A") {
defaultColorGlovesBLight = value1;
}
if (address == "07EC50") {
defaultColorGlovesRDark = value1;
defaultColorGlovesGDark = value2;
}
if (address == "07EC52") {
defaultColorGlovesBDark = value1;
}
// Shoes
if (address == "07EC70") {
defaultColorShoesRLight = value1;
defaultColorShoesGLight = value2;
}
if (address == "07EC72") {
defaultColorShoesBLight = value1;
}
if (address == "07EC68") {
defaultColorShoesRDark = value1;
defaultColorShoesGDark = value2;
}
if (address == "07EC6A") {
defaultColorShoesBDark = value1;
}
// Skin
if (address == "07EC88") {
defaultColorSkinRLight = value1;
defaultColorSkinGLight = value2;
}
if (address == "07EC8A") {
defaultColorSkinBLight = value1;
}
if (address == "07EC80") {
defaultColorSkinRDark = value1;
defaultColorSkinGDark = value2;
}
if (address == "07EC82") {
defaultColorSkinBDark = value1;
}
// Hair
if (address == "07ECA0") {
defaultColorHairRLight = value1;
defaultColorHairGLight = value2;
}
if (address == "07ECA2") {
defaultColorHairBLight = value1;
}
if (address == "07EC98") {
defaultColorHairRDark = value1;
defaultColorHairGDark = value2;
}
if (address == "07EC9A") {
defaultColorHairBDark = value1;
}
//std::cout << address << std::endl;
}
}
void save_cc_file(std::string name) {
std::string gameshark;
char col1char[64];
ImFormatString(col1char, IM_ARRAYSIZE(col1char), "%02X%02X%02X", ImClamp((int)defaultColorHatRLight, 0, 255), ImClamp((int)defaultColorHatGLight, 0, 255), ImClamp((int)defaultColorHatBLight, 0, 255));
std::string col1 = col1char;
char col2char[64];
ImFormatString(col2char, IM_ARRAYSIZE(col2char), "%02X%02X%02X", ImClamp((int)defaultColorHatRDark, 0, 255), ImClamp((int)defaultColorHatGDark, 0, 255), ImClamp((int)defaultColorHatBDark, 0, 255));
std::string col2 = col2char;
char col3char[64];
ImFormatString(col3char, IM_ARRAYSIZE(col3char), "%02X%02X%02X", ImClamp((int)defaultColorOverallsRLight, 0, 255), ImClamp((int)defaultColorOverallsGLight, 0, 255), ImClamp((int)defaultColorOverallsBLight, 0, 255));
std::string col3 = col3char;
char col4char[64];
ImFormatString(col4char, IM_ARRAYSIZE(col4char), "%02X%02X%02X", ImClamp((int)defaultColorOverallsRDark, 0, 255), ImClamp((int)defaultColorOverallsGDark, 0, 255), ImClamp((int)defaultColorOverallsBDark, 0, 255));
std::string col4 = col4char;
char col5char[64];
ImFormatString(col5char, IM_ARRAYSIZE(col5char), "%02X%02X%02X", ImClamp((int)defaultColorGlovesRLight, 0, 255), ImClamp((int)defaultColorGlovesGLight, 0, 255), ImClamp((int)defaultColorGlovesBLight, 0, 255));
std::string col5 = col5char;
char col6char[64];
ImFormatString(col6char, IM_ARRAYSIZE(col6char), "%02X%02X%02X", ImClamp((int)defaultColorGlovesRDark, 0, 255), ImClamp((int)defaultColorGlovesGDark, 0, 255), ImClamp((int)defaultColorGlovesBDark, 0, 255));
std::string col6 = col6char;
char col7char[64];
ImFormatString(col7char, IM_ARRAYSIZE(col7char), "%02X%02X%02X", ImClamp((int)defaultColorShoesRLight, 0, 255), ImClamp((int)defaultColorShoesGLight, 0, 255), ImClamp((int)defaultColorShoesBLight, 0, 255));
std::string col7 = col7char;
char col8char[64];
ImFormatString(col8char, IM_ARRAYSIZE(col8char), "%02X%02X%02X", ImClamp((int)defaultColorShoesRDark, 0, 255), ImClamp((int)defaultColorShoesGDark, 0, 255), ImClamp((int)defaultColorShoesBDark, 0, 255));
std::string col8 = col8char;
char col9char[64];
ImFormatString(col9char, IM_ARRAYSIZE(col9char), "%02X%02X%02X", ImClamp((int)defaultColorSkinRLight, 0, 255), ImClamp((int)defaultColorSkinGLight, 0, 255), ImClamp((int)defaultColorSkinBLight, 0, 255));
std::string col9 = col9char;
char col10char[64];
ImFormatString(col10char, IM_ARRAYSIZE(col10char), "%02X%02X%02X", ImClamp((int)defaultColorSkinRDark, 0, 255), ImClamp((int)defaultColorSkinGDark, 0, 255), ImClamp((int)defaultColorSkinBDark, 0, 255));
std::string col10 = col10char;
char col11char[64];
ImFormatString(col11char, IM_ARRAYSIZE(col11char), "%02X%02X%02X", ImClamp((int)defaultColorHairRLight, 0, 255), ImClamp((int)defaultColorHairGLight, 0, 255), ImClamp((int)defaultColorHairBLight, 0, 255));
std::string col11 = col11char;
char col12char[64];
ImFormatString(col12char, IM_ARRAYSIZE(col12char), "%02X%02X%02X", ImClamp((int)defaultColorHairRDark, 0, 255), ImClamp((int)defaultColorHairGDark, 0, 255), ImClamp((int)defaultColorHairBDark, 0, 255));
std::string col12 = col12char;
gameshark += "8107EC40 " + col1.substr(0, 2) + col1.substr(2, 2) + "\n";
gameshark += "8107EC42 " + col1.substr(4, 2) + "00\n";
gameshark += "8107EC38 " + col2.substr(0, 2) + col2.substr(2, 2) + "\n";
gameshark += "8107EC3A " + col2.substr(4, 2) + "00\n";
gameshark += "8107EC28 " + col3.substr(0, 2) + col3.substr(2, 2) + "\n";
gameshark += "8107EC2A " + col3.substr(4, 2) + "00\n";
gameshark += "8107EC20 " + col4.substr(0, 2) + col4.substr(2, 2) + "\n";
gameshark += "8107EC22 " + col4.substr(4, 2) + "00\n";
gameshark += "8107EC58 " + col5.substr(0, 2) + col5.substr(2, 2) + "\n";
gameshark += "8107EC5A " + col5.substr(4, 2) + "00\n";
gameshark += "8107EC50 " + col6.substr(0, 2) + col6.substr(2, 2) + "\n";
gameshark += "8107EC52 " + col6.substr(4, 2) + "00\n";
gameshark += "8107EC70 " + col7.substr(0, 2) + col7.substr(2, 2) + "\n";
gameshark += "8107EC72 " + col7.substr(4, 2) + "00\n";
gameshark += "8107EC68 " + col8.substr(0, 2) + col8.substr(2, 2) + "\n";
gameshark += "8107EC6A " + col8.substr(4, 2) + "00\n";
gameshark += "8107EC88 " + col9.substr(0, 2) + col9.substr(2, 2) + "\n";
gameshark += "8107EC8A " + col9.substr(4, 2) + "00\n";
gameshark += "8107EC80 " + col10.substr(0, 2) + col10.substr(2, 2) + "\n";
gameshark += "8107EC82 " + col10.substr(4, 2) + "00\n";
gameshark += "8107ECA0 " + col11.substr(0, 2) + col11.substr(2, 2) + "\n";
gameshark += "8107ECA2 " + col11.substr(4, 2) + "00\n";
gameshark += "8107EC98 " + col12.substr(0, 2) + col12.substr(2, 2) + "\n";
gameshark += "8107EC9A " + col12.substr(4, 2) + "00";
//std::cout << gameshark << std::endl;
#ifdef __MINGW32__
std::ofstream file("machinima\\colorcodes\\" + name + ".gs");
#else
std::ofstream file("machinima/colorcodes/" + name + ".gs");
#endif
file << gameshark;
}
}

View File

@ -0,0 +1,14 @@
#ifndef SaturnColors
#define SaturnColors
#include <string>
#include <vector>
namespace MoonInternal {
extern std::vector<std::string> cc_array;
void load_cc_directory(void);
void load_cc_file(std::string cc_path);
void save_cc_file(std::string name);
}
#endif

View File

@ -0,0 +1,54 @@
#ifndef MoonSaturnTypes
#define MoonSaturnTypes
#include <stdbool.h>
extern bool enable_head_rotations;
extern bool enable_shadows;
extern bool enable_dust_particles;
// Color Codes
extern unsigned int defaultColorHatRLight;
extern unsigned int defaultColorHatRDark;
extern unsigned int defaultColorHatGLight;
extern unsigned int defaultColorHatGDark;
extern unsigned int defaultColorHatBLight;
extern unsigned int defaultColorHatBDark;
extern unsigned int defaultColorOverallsRLight;
extern unsigned int defaultColorOverallsRDark;
extern unsigned int defaultColorOverallsGLight;
extern unsigned int defaultColorOverallsGDark;
extern unsigned int defaultColorOverallsBLight;
extern unsigned int defaultColorOverallsBDark;
extern unsigned int defaultColorGlovesRLight;
extern unsigned int defaultColorGlovesRDark;
extern unsigned int defaultColorGlovesGLight;
extern unsigned int defaultColorGlovesGDark;
extern unsigned int defaultColorGlovesBLight;
extern unsigned int defaultColorGlovesBDark;
extern unsigned int defaultColorShoesRLight;
extern unsigned int defaultColorShoesRDark;
extern unsigned int defaultColorShoesGLight;
extern unsigned int defaultColorShoesGDark;
extern unsigned int defaultColorShoesBLight;
extern unsigned int defaultColorShoesBDark;
extern unsigned int defaultColorSkinRLight;
extern unsigned int defaultColorSkinRDark;
extern unsigned int defaultColorSkinGLight;
extern unsigned int defaultColorSkinGDark;
extern unsigned int defaultColorSkinBLight;
extern unsigned int defaultColorSkinBDark;
extern unsigned int defaultColorHairRLight;
extern unsigned int defaultColorHairRDark;
extern unsigned int defaultColorHairGLight;
extern unsigned int defaultColorHairGDark;
extern unsigned int defaultColorHairBLight;
extern unsigned int defaultColorHairBDark;
#endif

View File

@ -54,11 +54,13 @@ void MoonChangeUI(int index){
}
void MoonHandleToggle(){
/*
if(gPlayer1Controller->buttonPressed & toggle){
currentScreen = 0;
isOpen = !isOpen;
MoonUpdateStatus();
}
*/
}
void MoonUpdateStatus() {

View File

@ -153,7 +153,7 @@ extern "C" {
basePath.append(stickAnim ? "stick-down.rgba16" : "stick-up.rgba16");
MoonDrawButton(5, GetScreenHeight() - 24, "Move", basePath, 16, 0, false, false);
MoonDrawButton(7, GetScreenHeight() - 24, "Open settings", "textures/moon/controller/r-btn.rgba16", 10, 4, true, false);
//MoonDrawButton(7, GetScreenHeight() - 24, "Open settings", "textures/moon/controller/r-btn.rgba16", 10, 4, true, false);
}
}

View File

@ -58,6 +58,10 @@ ConfigWindow configWindow = {
ImGuiConfig configImGui = {
.moon64 = false,
.texture_debug = false,
.s_toggles = false,
.s_machinima = false,
.s_cceditor = false,
.s_options = false,
.n64Mode = false
};
@ -71,7 +75,7 @@ bool configPrecacheRes = true;
unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point
unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME
unsigned int configMusicVolume = MAX_VOLUME;
unsigned int configMusicVolume = 0;
unsigned int configSfxVolume = MAX_VOLUME;
unsigned int configEnvVolume = MAX_VOLUME;
@ -105,8 +109,8 @@ bool configEnableCamera = false;
bool configCameraAnalog = true;
bool configCameraMouse = false;
#endif
bool configSkipIntro = 0;
bool configHUD = true;
bool configSkipIntro = 1;
bool configHUD = false;
#ifdef DISCORDRPC
bool configDiscordRPC = true;
#endif
@ -117,7 +121,7 @@ bool configDiscordRPC = true;
################################
*/
unsigned int configLODMode = 0;
unsigned int configLODMode = 2;
static const struct ConfigOption options[] = {
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen},
@ -177,6 +181,10 @@ static const struct ConfigOption options[] = {
{.name = "moon64_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.moon64},
{.name = "texture_debug_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.texture_debug},
{.name = "s_toggles_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_toggles},
{.name = "s_machinima", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_machinima},
{.name = "s_cceditor_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_cceditor},
{.name = "s_options_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_options},
{.name = "n64Mode", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.n64Mode}
};

View File

@ -23,6 +23,10 @@ typedef struct {
typedef struct {
bool moon64;
bool s_toggles;
bool s_machinima;
bool s_cceditor;
bool s_options;
bool texture_debug;
bool n64Mode;
} ImGuiConfig;

View File

@ -42,7 +42,7 @@ extern "C" {
#endif
#define DISCORDLIB DISCORDLIBFILE DISCORDLIBEXT
#define DISCORD_APP_ID "856717153431453716"
#define DISCORD_APP_ID "895788060518793226"
#define DISCORD_UPDATE_RATE 3
using namespace std;
@ -228,35 +228,22 @@ string getLevelLogo(){
}
void set_logo(void) {
discordRichPresence.largeImageKey = sys_strdup(getLevelLogo().data());
discordRichPresence.largeImageKey = "saturn-logo-star-bg";
discordRichPresence.largeImageText = "https://github.com/Llennpie/Saturn";
}
void DiscordReloadPresence() {
reloadRPC = true;
}
void set_health(){
if(gCurrCourseNum == 0) return;
if(lastHealth != gHudDisplay.wedges){
lastHealth = gHudDisplay.wedges;
string new_health_icon = "health-"+to_string(lastHealth);
string new_health_text = to_string(gHudDisplay.lives) + " Lives";
discordRichPresence.smallImageKey = sys_strdup(new_health_icon.data());
discordRichPresence.smallImageText = sys_strdup(new_health_text.data());
}
}
void set_image_key(){
if(gCurrCourseNum == 0) return;
int size = entries[gCurrSaveFileNum - 1].size();
if(lastAchievements != size || lastStarAmount != gHudDisplay.stars){
lastAchievements = size;
lastStarAmount = gHudDisplay.stars;
string new_text = to_string(lastStarAmount) + "/120 Stars - " + to_string(lastAchievements) + "/" + to_string(registeredAchievements.size()) + " Achievements";
discordRichPresence.largeImageText = sys_strdup(new_text.data());
}
void set_platform(){
#ifdef __MINGW32__
discordRichPresence.smallImageKey = "windows";
discordRichPresence.smallImageText = "Windows";
#else
discordRichPresence.smallImageKey = "linux";
discordRichPresence.smallImageText = "Linux";
#endif
}
void DiscordUpdatePresence(){
@ -268,8 +255,7 @@ void DiscordUpdatePresence(){
set_state();
set_details();
set_logo();
set_health();
set_image_key();
set_platform();
discordUpdatePresence(&discordRichPresence);
reloadRPC = false;
}
@ -306,8 +292,8 @@ void discord_init(void) {
discordUpdatePresence = (Discord_UpdatePresence) dlsym(handle, "Discord_UpdatePresence");
init_discord();
discordRichPresence.details = stage;
discordRichPresence.state = act;
discordRichPresence.details = "Making Machinima";
discordRichPresence.state = stage;
lastUpdatedTime = 0;
}

View File

@ -24,6 +24,7 @@
#include "../fs/fs.h"
#include "moon/moon64.h"
#include "moon/mod-engine/hooks/hook.h"
#include "moon/saturn/saturn_types.h"
#define SUPPORT_CHECK(x) assert(x)
@ -447,6 +448,48 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti
int g = rsp.current_lights[rsp.current_num_lights - 1].col[1];
int b = rsp.current_lights[rsp.current_num_lights - 1].col[2];
// sm64plus saves the day...
// Detect if these are one of Mario's colors
bool mario_hat = (r == 0x7f && g == 0x00 && b == 0x00);
bool mario_overalls = (r == 0x00 && g == 0x00 && b == 0x7f);
bool mario_gloves = (r == 0x00 && g == 0x7f && b == 0x00);
bool mario_shoes = (r == 0x39 && g == 0x0e && b == 0x07);
bool mario_skin = (r == 0x7f && g == 0x60 && b == 0x3c);
bool mario_hair = (r == 0x39 && g == 0x03 && b == 0x00);
// Override them lazily
if (mario_hat) {
r = defaultColorHatRDark;
g = defaultColorHatGDark;
b = defaultColorHatBDark;
}
if (mario_overalls) {
r = defaultColorOverallsRDark;
g = defaultColorOverallsGDark;
b = defaultColorOverallsBDark;
}
if (mario_gloves) {
r = defaultColorGlovesRDark;
g = defaultColorGlovesGDark;
b = defaultColorGlovesBDark;
}
if (mario_shoes) {
r = defaultColorShoesRDark;
g = defaultColorShoesGDark;
b = defaultColorShoesBDark;
}
if (mario_skin) {
r = defaultColorSkinRDark;
g = defaultColorSkinGDark;
b = defaultColorSkinBDark;
}
if (mario_hair) {
r = defaultColorHairRDark;
g = defaultColorHairGDark;
b = defaultColorHairBDark;
}
for (int i = 0; i < rsp.current_num_lights - 1; i++) {
float intensity = 0;
intensity += vn->n[0] * rsp.current_lights_coeffs[i][0];
@ -454,9 +497,47 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti
intensity += vn->n[2] * rsp.current_lights_coeffs[i][2];
intensity /= 127.0f;
if (intensity > 0.0f) {
r += intensity * rsp.current_lights[i].col[0];
g += intensity * rsp.current_lights[i].col[1];
b += intensity * rsp.current_lights[i].col[2];
// Light colors
int lightr = rsp.current_lights[i].col[0];
int lightg = rsp.current_lights[i].col[1];
int lightb = rsp.current_lights[i].col[2];
// Override these too
if (mario_hat) {
r += intensity * defaultColorHatRLight;
g += intensity * defaultColorHatGLight;
b += intensity * defaultColorHatBLight;
}
else if (mario_overalls) {
r += intensity * defaultColorOverallsRLight;
g += intensity * defaultColorOverallsGLight;
b += intensity * defaultColorOverallsBLight;
}
else if (mario_gloves) {
r += intensity * defaultColorGlovesRLight;
g += intensity * defaultColorGlovesGLight;
b += intensity * defaultColorGlovesBLight;
}
else if (mario_shoes) {
r += intensity * defaultColorShoesRLight;
g += intensity * defaultColorShoesGLight;
b += intensity * defaultColorShoesBLight;
}
else if (mario_skin) {
r += intensity * defaultColorSkinRLight;
g += intensity * defaultColorSkinGLight;
b += intensity * defaultColorSkinBLight;
}
else if (mario_hair) {
r += intensity * defaultColorHairRLight;
g += intensity * defaultColorHairGLight;
b += intensity * defaultColorHairBLight;
}
else {
r += intensity * lightr;
g += intensity * lightg;
b += intensity * lightb;
}
}
}

View File

@ -1,7 +1,7 @@
#ifndef GFX_SCREEN_CONFIG_H
#define GFX_SCREEN_CONFIG_H
#define DESIRED_SCREEN_WIDTH 640
#define DESIRED_SCREEN_HEIGHT 480
#define DESIRED_SCREEN_WIDTH 1280
#define DESIRED_SCREEN_HEIGHT 768
#endif

View File

@ -62,7 +62,7 @@ static void (*kb_all_keys_up)(void) = NULL;
// whether to use timer for frame control
static bool use_timer = true;
// time between consequtive game frames
static const int frame_time = 1000 / FRAMERATE;
static const int frame_time = 1000 / (2 * FRAMERATE);
const SDL_Scancode windows_scancode_table[] = {
/* 0 1 2 3 4 5 6 7 */
@ -149,13 +149,17 @@ int test_vsync(void) {
static inline void gfx_sdl_set_vsync(const bool enabled) {
#ifdef TARGET_SWITCH
SDL_GL_SetSwapInterval(2);
SDL_GL_SetSwapInterval(1);
use_timer = false;
#else
if (enabled) {
// try to detect refresh rate
SDL_GL_SetSwapInterval(1);
const int vblanks = test_vsync();
int vblanks = test_vsync();
if (vblanks & 1)
vblanks = 0; // not divisible by 60, fuck that
else
vblanks /= 2;
if (vblanks) {
printf("determined swap interval: %d\n", vblanks);
SDL_GL_SetSwapInterval(vblanks);

View File

@ -86,6 +86,25 @@ void send_display_list(struct SPTask *spTask) {
#define SAMPLES_LOW 528
#endif
static inline void patch_interpolations(void) {
extern void mtx_patch_interpolated(void);
extern void patch_screen_transition_interpolated(void);
extern void patch_title_screen_scales(void);
extern void patch_interpolated_dialog(void);
extern void patch_interpolated_hud(void);
extern void patch_interpolated_paintings(void);
extern void patch_interpolated_bubble_particles(void);
extern void patch_interpolated_snow_particles(void);
mtx_patch_interpolated();
patch_screen_transition_interpolated();
patch_title_screen_scales();
patch_interpolated_dialog();
patch_interpolated_hud();
patch_interpolated_paintings();
patch_interpolated_bubble_particles();
patch_interpolated_snow_particles();
}
void produce_one_frame(void) {
moon_setup("Update");
gfx_start_frame();
@ -114,6 +133,11 @@ void produce_one_frame(void) {
}
//printf("Audio samples before submitting: %d\n", audio_api->buffered());
gfx_start_frame();
patch_interpolations();
send_display_list(gGfxSPTask);
gfx_end_frame();
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
gfx_end_frame();
@ -211,8 +235,7 @@ void main_func(char *argv[]) {
# define RAPI_NAME "OpenGL"
# endif
char window_title[96] =
"Super Mario 64 - Moon64 (" RAPI_NAME ")";
char window_title[96] = "Saturn";
gfx_init(wm_api, rendering_api, window_title);
wm_api->set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up);