diff --git a/.gitignore b/.gitignore
index 8f3e5b8..eac14e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,6 @@ tools/vtf2png
skelatool64/*.zip*
src/controls/controller-data.h
+
+
+log.txt
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index fa2edd4..5b59c92 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -7,14 +7,16 @@ ENV PATH /opt/crashsdk/bin:$PATH
ENV PATH /root/.local/bin:$PATH
ENV ROOT /etc/n64
-RUN apt update -y && \
- DEBIAN_FRONTEND=noninteractive apt install -y \
+RUN apt-get update -y
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y \
+ apt-utils 2>/dev/null
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y \
ca-certificates
RUN echo "deb [trusted=yes] https://lambertjamesd.github.io/apt/ ./" | tee /etc/apt/sources.list.d/lambertjamesd.list && \
echo "deb [trusted=yes] https://crashoveride95.github.io/apt/ ./" | tee /etc/apt/sources.list.d/n64sdk.list
-RUN apt update -y && \
+RUN apt-get update -y && \
dpkg --add-architecture i386 && \
- DEBIAN_FRONTEND=noninteractive apt install -y \
+ DEBIAN_FRONTEND=noninteractive apt-get install -y \
binutils-mips-n64 \
gcc-mips-n64 \
n64sdk \
@@ -58,5 +60,5 @@ RUN rm /opt/blender/blender-3.6.1-linux-x64.tar.xz
ENV BLENDER_3_6 /opt/blender/blender-3.6.1-linux-x64/blender
-RUN pipx ensurepath
+RUN pipx ensurepath --force
RUN pipx install vpk
diff --git a/Makefile b/Makefile
index ae641c7..d2c877c 100644
--- a/Makefile
+++ b/Makefile
@@ -8,14 +8,13 @@
# --------------------------------------------------------------------
include /usr/include/n64/make/PRdefs
-
SKELATOOL64:=skelatool64/skeletool64
VTF2PNG:=vtf2png
SFZ2N64:=sfz2n64
$(SKELATOOL64):
skelatool64/setup_dependencies.sh
- make -C skelatool64
+ @$(MAKE) -C skelatool64
OPTIMIZER := -Os
LCDEFS := -DDEBUG -g -Isrc/ -I/usr/include/n64/nustd -Werror -Wall
@@ -67,6 +66,7 @@ LDFLAGS = -L/usr/lib/n64 $(N64LIB) -L$(N64_LIBGCCDIR) -lgcc
default: english_audio
english_audio: build/src/audio/subtitles.h portal_pak_dir
+ @$(MAKE) -C skelatool64
@$(MAKE) buildgame
all_languages: build/src/audio/subtitles.h portal_pak_dir german_audio french_audio russian_audio spanish_audio
@@ -359,6 +359,7 @@ build/src/scene/security_camera.o: build/src/audio/clips.h build/assets/models/p
build/src/scene/signage.o: $(MODEL_HEADERS)
build/src/scene/switch.o: build/assets/models/props/switch001.h build/assets/materials/static.h build/assets/models/dynamic_animated_model_list.h
build/src/util/dynamic_asset_data.o: build/assets/models/dynamic_model_list_data.h
+build/src/util/dynamic_animated_asset_data.o: build/assets/models/dynamic_animated_model_list_data.h
build/src/util/dynamic_asset_loader.o: build/assets/models/dynamic_model_list.h build/assets/models/dynamic_animated_model_list.h
build/src/menu/audio_options.o: build/src/audio/subtitles.h
build/src/menu/video_options.o: build/src/audio/subtitles.h
@@ -572,7 +573,8 @@ clean:
rm -rf build
rm -rf portal_pak_dir
rm -rf portal_pak_modified
- rm -rf assets/locales/
+ rm -rf assets/locales
+ @$(MAKE) -C skelatool64 clean
clean-src:
rm -rf build/src
diff --git a/Makefile.docker b/Makefile.docker
index 9632368..c1c606c 100644
--- a/Makefile.docker
+++ b/Makefile.docker
@@ -1,38 +1,35 @@
all:
- docker run -v $$PWD:/usr/src/app -it portal64 make
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make
debug:
docker run -v $$PWD:/usr/src/app -it PORTAL64_WITH_GFX_VALIDATOR=1 portal64 make
convert_all_png:
- docker run -v $$PWD:/usr/src/app -it portal64 make convert_all_png
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make convert_all_png
image:
docker build -t portal64 .
bash:
- docker run -v $$PWD:/usr/src/app -it portal64 bash
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 bash
clean:
- sudo rm -rf build
- sudo rm -rf portal_pak_dir
- sudo rm -rf portal_pak_modified
- sudo rm -rf assets/locales/
+ sudo make clean
english_audio:
- docker run -v $$PWD:/usr/src/app -it portal64 make english_audio
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make english_audio
all_languages:
- docker run -v $$PWD:/usr/src/app -it portal64 make all_languages
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make all_languages
german_audio:
- docker run -v $$PWD:/usr/src/app -it portal64 make german_audio
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make german_audio
french_audio:
- docker run -v $$PWD:/usr/src/app -it portal64 make french_audio
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make french_audio
russian_audio:
- docker run -v $$PWD:/usr/src/app -it portal64 make russian_audio
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make russian_audio
spanish_audio:
- docker run -v $$PWD:/usr/src/app -it portal64 make spanish_audio
+ docker run --rm -v $$PWD:/usr/src/app -it portal64 make spanish_audio
diff --git a/README.md b/README.md
index e7185e0..41a412c 100644
--- a/README.md
+++ b/README.md
@@ -68,6 +68,13 @@ pipx install vpk
+Clone the Portal64 repo or download the zip.
+
+```sh
+sudo apt install git
+git clone https://github.com/lambertjamesd/portal64.git
+cd portal64
+```
Setup and install dependencies for `skeletool64`
```sh
@@ -104,13 +111,6 @@ sudo apt install nodejs
```
-Clone the Portal64 repo or download the zip.
-
-```sh
-sudo apt install git
-git clone https://github.com/lambertjamesd/portal64.git
-cd portal64
-```
You then need to add the following files from where Portal is installed to the folder `vpk/` OR create a symbolic link to the `Portal` folder there (see [vpk/add_vpk_here.md](./vpk/add_vpk_here.md) for more details!).
You can add multiple languages if desired.
diff --git a/asm/rom_header.s b/asm/rom_header.s
index 07dd3be..5445939 100644
--- a/asm/rom_header.s
+++ b/asm/rom_header.s
@@ -14,10 +14,10 @@
.word 0x00000000 /* Checksum 2 (OVERWRITTEN BY MAKEMASK)*/
.word 0x00000000 /* Unknown */
.word 0x00000000 /* Unknown */
-.ascii " " /* Internal ROM name (Max 20 characters) */
-.word 0x01000000 /* Advanced_Homebrew_ROM_Header (controller config) */
-/* Game ID (EXAMPLE: NSME) Begins here */
-.word 0x0000004E /* Cartridge Type (N)*/
-.ascii "ED" /* Cartridge ID (SM)*/
-.ascii " " /* Region (E)*/
-.byte 0x30 /* Version */
+.ascii "Portal 64 " /* Internal ROM name (Max 20 characters) */
+
+.word 0x01000000 /* Unused officially / Advanced homebrew ROM header controller config */
+.word 0x0000004E /* Cartridge Type (N; cart)*/
+.ascii "ED" /* Cartridge ID (ED) / Advanced homebrew ROM header magic value */
+.byte 0x41 /* Region (A; All)*/
+.byte 0x32 /* Version / Advanced homebrew ROM header misc. (region-free + 256K SRAM) */
diff --git a/assets/materials/ui.skm.yaml b/assets/materials/ui.skm.yaml
index b508be8..6ad75a6 100644
--- a/assets/materials/ui.skm.yaml
+++ b/assets/materials/ui.skm.yaml
@@ -150,6 +150,10 @@ materials:
filename: "../../portal_pak_modified/materials/gamepadui/portal_logo.png"
siz: G_IM_SIZ_4b
fmt: G_IM_FMT_I
+ s:
+ wrap: false
+ t:
+ wrap: false
gDPSetCombineMode:
color: ["0", "0", "0", ENVIRONMENT]
alpha: [TEXEL0, "0", ENVIRONMENT, "0"]
diff --git a/assets/models/signage/clock_digits.blend b/assets/models/signage/clock_digits.blend
index aca5e94..17ba51f 100644
Binary files a/assets/models/signage/clock_digits.blend and b/assets/models/signage/clock_digits.blend differ
diff --git a/assets/test_chambers/test_chamber_00/test_chamber_00.blend b/assets/test_chambers/test_chamber_00/test_chamber_00.blend
index c724eb3..2cf77f7 100644
Binary files a/assets/test_chambers/test_chamber_00/test_chamber_00.blend and b/assets/test_chambers/test_chamber_00/test_chamber_00.blend differ
diff --git a/assets/test_chambers/test_chamber_01/test_chamber_01.blend b/assets/test_chambers/test_chamber_01/test_chamber_01.blend
index fe89f72..0fbea0d 100644
Binary files a/assets/test_chambers/test_chamber_01/test_chamber_01.blend and b/assets/test_chambers/test_chamber_01/test_chamber_01.blend differ
diff --git a/assets/test_chambers/test_chamber_02/test_chamber_02.blend b/assets/test_chambers/test_chamber_02/test_chamber_02.blend
index 6d8950e..a07a35a 100644
Binary files a/assets/test_chambers/test_chamber_02/test_chamber_02.blend and b/assets/test_chambers/test_chamber_02/test_chamber_02.blend differ
diff --git a/assets/test_chambers/test_chamber_03/test_chamber_03.blend b/assets/test_chambers/test_chamber_03/test_chamber_03.blend
index 7ebd001..0fd8683 100644
Binary files a/assets/test_chambers/test_chamber_03/test_chamber_03.blend and b/assets/test_chambers/test_chamber_03/test_chamber_03.blend differ
diff --git a/assets/test_chambers/test_chamber_04/test_chamber_04.blend b/assets/test_chambers/test_chamber_04/test_chamber_04.blend
index 5da8f81..73269df 100644
Binary files a/assets/test_chambers/test_chamber_04/test_chamber_04.blend and b/assets/test_chambers/test_chamber_04/test_chamber_04.blend differ
diff --git a/assets/test_chambers/test_chamber_06/test_chamber_06.blend b/assets/test_chambers/test_chamber_06/test_chamber_06.blend
index 573dcfe..7853e49 100644
Binary files a/assets/test_chambers/test_chamber_06/test_chamber_06.blend and b/assets/test_chambers/test_chamber_06/test_chamber_06.blend differ
diff --git a/assets/test_chambers/test_chamber_07/test_chamber_07.blend b/assets/test_chambers/test_chamber_07/test_chamber_07.blend
index 1b73794..eaac7ed 100644
Binary files a/assets/test_chambers/test_chamber_07/test_chamber_07.blend and b/assets/test_chambers/test_chamber_07/test_chamber_07.blend differ
diff --git a/skelatool64/makefile b/skelatool64/makefile
index 9f30098..8cc2c54 100644
--- a/skelatool64/makefile
+++ b/skelatool64/makefile
@@ -32,7 +32,9 @@ skeletool64: $(OBJ_FILES) $(LUA_OBJ_FILES)
g++ -g -o skeletool64 $(OBJ_FILES) $(LUA_OBJ_FILES) $(LINKER_FLAGS)
clean:
- rm -r build/
+ rm -rf build/
+ rm -f skeletool64
+ rm -f CImg_*
init:
@@ -48,4 +50,4 @@ build/skeletool.deb: skeletool64 control
dpkg-deb --build build/skeletool
docs:
- ldoc .
\ No newline at end of file
+ ldoc .
diff --git a/skelatool64/src/BoneHierarchy.cpp b/skelatool64/src/BoneHierarchy.cpp
index 67fd8bc..3a0143f 100644
--- a/skelatool64/src/BoneHierarchy.cpp
+++ b/skelatool64/src/BoneHierarchy.cpp
@@ -28,7 +28,7 @@ Bone* Bone::GetParent() {
return mParent;
}
-std::unique_ptr Bone::GenerateRestPosiitonData() {
+std::unique_ptr Bone::GenerateRestPositionData() {
std::unique_ptr result(new StructureDataChunk());
result->Add(std::unique_ptr(new StructureDataChunk(mRestPosition)));
@@ -190,13 +190,14 @@ Bone* BoneHierarchy::BoneForName(std::string name) {
}
}
-void BoneHierarchy::GenerateRestPosiitonData(CFileDefinition& fileDef, const std::string& variableName) {
+void BoneHierarchy::GenerateRestPositionData(CFileDefinition& fileDef, const std::string& variableName) {
if (mBones.size() == 0) return;
std::unique_ptr transformData(new StructureDataChunk());
for (unsigned int boneIndex = 0; boneIndex < mBones.size(); ++boneIndex) {
- transformData->Add(std::move(mBones[boneIndex]->GenerateRestPosiitonData()));
+ auto restPositionData = mBones[boneIndex]->GenerateRestPositionData();
+ transformData->Add(std::move(restPositionData));
std::string boneName = fileDef.GetUniqueName(mBones[boneIndex]->GetName() + "_BONE");
std::transform(boneName.begin(), boneName.end(), boneName.begin(), ::toupper);
@@ -215,4 +216,4 @@ bool BoneHierarchy::HasData() const {
unsigned int BoneHierarchy::GetBoneCount() const {
return mBones.size();
-}
\ No newline at end of file
+}
diff --git a/skelatool64/src/BoneHierarchy.h b/skelatool64/src/BoneHierarchy.h
index 411576c..ec78beb 100644
--- a/skelatool64/src/BoneHierarchy.h
+++ b/skelatool64/src/BoneHierarchy.h
@@ -36,7 +36,7 @@ public:
const std::string& GetName();
Bone* GetParent();
- std::unique_ptr GenerateRestPosiitonData();
+ std::unique_ptr GenerateRestPositionData();
static Bone* FindCommonAncestor(Bone* a, Bone* b);
/**
@@ -72,7 +72,7 @@ public:
bool HasData() const;
unsigned int GetBoneCount() const;
- void GenerateRestPosiitonData(CFileDefinition& fileDef, const std::string& variableName);
+ void GenerateRestPositionData(CFileDefinition& fileDef, const std::string& variableName);
private:
std::vector> mBones;
std::map mBoneByName;
diff --git a/skelatool64/src/DisplayList.cpp b/skelatool64/src/DisplayList.cpp
index 9433b4b..60010d1 100644
--- a/skelatool64/src/DisplayList.cpp
+++ b/skelatool64/src/DisplayList.cpp
@@ -212,7 +212,8 @@ DisplayList::DisplayList(std::string name):
}
void DisplayList::AddCommand(std::unique_ptr command) {
- mDataChunk->Add(std::move(command->GenerateCommand()));
+ auto generatedCommand = command->GenerateCommand();
+ mDataChunk->Add(std::move(generatedCommand));
}
StructureDataChunk& DisplayList::GetDataChunk() {
@@ -237,4 +238,4 @@ std::unique_ptr DisplayList::Generate(const std::string& fileSuf
result->AddTypeHeader("");
return result;
-}
\ No newline at end of file
+}
diff --git a/skelatool64/src/MeshWriter.cpp b/skelatool64/src/MeshWriter.cpp
index 713c4b3..51fbbd7 100644
--- a/skelatool64/src/MeshWriter.cpp
+++ b/skelatool64/src/MeshWriter.cpp
@@ -15,8 +15,8 @@ void useTexture(std::set>& usedTextures, std:
}
usedTextures.insert(texture);
-
- fileDefinition.AddDefinition(std::move(texture->GenerateDefinition(fileDefinition.GetUniqueName(texture->Name()), fileSuffix)));
+ auto textureDefinition = texture->GenerateDefinition(fileDefinition.GetUniqueName(texture->Name()), fileSuffix);
+ fileDefinition.AddDefinition(std::move(textureDefinition));
std::shared_ptr pallete = texture->GetPallete();
if (!pallete || usedPalletes.find(pallete) != usedPalletes.end()) {
@@ -24,7 +24,8 @@ void useTexture(std::set>& usedTextures, std:
}
usedPalletes.insert(pallete);
- fileDefinition.AddDefinition(std::move(pallete->GenerateDefinition(fileDefinition.GetUniqueName(pallete->Name()), fileSuffix)));
+ auto palleteDefinition = pallete->GenerateDefinition(fileDefinition.GetUniqueName(pallete->Name()), fileSuffix);
+ fileDefinition.AddDefinition(std::move(palleteDefinition));
}
void MaterialCollector::UseMaterial(const std::string& material, DisplayListSettings& settings) {
@@ -150,4 +151,4 @@ std::string generateMesh(const aiScene* scene, CFileDefinition& fileDefinition,
fileDefinition.AddDefinition(std::move(dlResult));
return displayList.GetName();
-}
\ No newline at end of file
+}
diff --git a/skelatool64/src/definition_generator/AnimationGenerator.cpp b/skelatool64/src/definition_generator/AnimationGenerator.cpp
index fe3178c..d09f4fe 100644
--- a/skelatool64/src/definition_generator/AnimationGenerator.cpp
+++ b/skelatool64/src/definition_generator/AnimationGenerator.cpp
@@ -266,7 +266,7 @@ AnimationResults generateAnimationForScene(const aiScene* scene, CFileDefinition
std::string bonesName = fileDefinition.GetUniqueName("default_bones");
std::string boneParentName = fileDefinition.GetUniqueName("bone_parent");
- bones.GenerateRestPosiitonData(fileDefinition, bonesName);
+ bones.GenerateRestPositionData(fileDefinition, bonesName);
std::string boneCountName = bonesName + "_COUNT";
std::transform(boneCountName.begin(), boneCountName.end(), boneCountName.begin(), ::toupper);
fileDefinition.AddMacro(boneCountName, std::to_string(bones.GetBoneCount()));
diff --git a/skelatool64/src/definition_generator/CollisionGenerator.cpp b/skelatool64/src/definition_generator/CollisionGenerator.cpp
index 6e010d9..2b68749 100644
--- a/skelatool64/src/definition_generator/CollisionGenerator.cpp
+++ b/skelatool64/src/definition_generator/CollisionGenerator.cpp
@@ -83,8 +83,9 @@ std::shared_ptr generateCollision(const aiScene* scene
if (namedEntry != "") {
fileDefinition.AddMacro(fileDefinition.GetMacroName(namedEntry + "_COLLISION_INDEX"), std::to_string(output->quads.size()));
}
-
- collidersChunk->Add(std::move(collider.Generate()));
+
+ auto generatedCollider = collider.Generate();
+ collidersChunk->Add(std::move(generatedCollider));
std::unique_ptr colliderType(new StructureDataChunk());
colliderType->AddPrimitive("CollisionShapeTypeQuad");
@@ -174,4 +175,4 @@ void generateMeshCollider(CFileDefinition& fileDefinition, CollisionGeneratorOut
std::unique_ptr definition(new DataFileDefinition("struct MeshCollider", colliderName, false, "_geo", std::move(meshColliderChunk)));
definition->AddTypeHeader("\"physics/mesh_collider.h\"");
fileDefinition.AddDefinition(std::move(definition));
-}
\ No newline at end of file
+}
diff --git a/skelatool64/src/definition_generator/MaterialGenerator.cpp b/skelatool64/src/definition_generator/MaterialGenerator.cpp
index b95a046..77acfd5 100644
--- a/skelatool64/src/definition_generator/MaterialGenerator.cpp
+++ b/skelatool64/src/definition_generator/MaterialGenerator.cpp
@@ -54,11 +54,13 @@ void MaterialGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinitio
}
for (auto& texture : textures) {
- fileDefinition.AddDefinition(std::move(texture->GenerateDefinition(fileDefinition.GetUniqueName(texture->Name()), "_mat")));
+ auto textureDefinition = texture->GenerateDefinition(fileDefinition.GetUniqueName(texture->Name()), "_mat");
+ fileDefinition.AddDefinition(std::move(textureDefinition));
}
for (auto& pallete : palletes) {
- fileDefinition.AddDefinition(std::move(pallete->GenerateDefinition(fileDefinition.GetUniqueName(pallete->Name()), "_mat")));
+ auto palleteDefinition = pallete->GenerateDefinition(fileDefinition.GetUniqueName(pallete->Name()), "_mat");
+ fileDefinition.AddDefinition(std::move(palleteDefinition));
}
int index = 0;
@@ -130,4 +132,4 @@ std::string MaterialGenerator::MaterialIndexMacroName(const std::string& materia
std::transform(materialName.begin(), materialName.end(), result.begin(), ::toupper);
makeCCompatible(result);
return result + "_INDEX";
-}
\ No newline at end of file
+}
diff --git a/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp b/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp
index 664a1d8..026fdd0 100644
--- a/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp
+++ b/skelatool64/src/lua_generator/LuaDefinitionWriter.cpp
@@ -20,7 +20,8 @@ std::unique_ptr buildMacroChunk(lua_State* L) {
lua_pushnil(L); /* first key */
while (lua_next(L, args) != 0) {
- result->Add(std::move(buildDataChunk(L)));
+ auto dataChunk = buildDataChunk(L);
+ result->Add(std::move(dataChunk));
lua_pop(L, 1);
}
lua_pop(L, 1);
@@ -39,7 +40,8 @@ std::unique_ptr buildStructureChunk(lua_State* L) {
while (lua_next(L, topStart) != 0) {
int keyType = lua_type(L, -2);
if (keyType == LUA_TNUMBER) {
- result->Add(std::move(buildDataChunk(L)));
+ auto dataChunk = buildDataChunk(L);
+ result->Add(std::move(dataChunk));
} else if (keyType == LUA_TSTRING) {
namedEntries.push_back(std::pair>(
lua_tostring(L, -2),
@@ -308,4 +310,4 @@ int luaDefinitonWriterAppend(lua_State* L) {
void populateLuaDefinitionWrite(lua_State* L, CFileDefinition& fileDef) {
lua_pushlightuserdata(L, &fileDef);
luaChainModuleLoader(L, "sk_definition_writer", luaDefinitonWriterAppend, 1);
-}
\ No newline at end of file
+}
diff --git a/skelatool64/src/materials/MaterialState.cpp b/skelatool64/src/materials/MaterialState.cpp
index 8b9bfdf..9d14054 100644
--- a/skelatool64/src/materials/MaterialState.cpp
+++ b/skelatool64/src/materials/MaterialState.cpp
@@ -601,17 +601,20 @@ void generateMaterial(CFileDefinition& fileDef, const MaterialState& from, const
generateEnumMacro((int)from.alphaCompare, (int)to.alphaCompare, "gsDPSetAlphaCompare", gAlphaCompareNames, output);
generateEnumMacro((int)from.depthSource, (int)to.depthSource, "gsDPSetDepthSource", gDepthSourceNames, output);
- std::unique_ptr geometryModes = std::move(generateGeometryModes(from, to));
+ auto generatedGeometryModes = generateGeometryModes(from, to);
+ std::unique_ptr geometryModes = std::move(generatedGeometryModes);
if (geometryModes) {
output.Add(std::move(geometryModes));
}
- std::unique_ptr combineMode = std::move(generateCombineMode(from, to));
+ auto generatedCombineMode = generateCombineMode(from, to);
+ std::unique_ptr combineMode = std::move(generatedCombineMode);
if (combineMode) {
output.Add(std::move(combineMode));
}
- std::unique_ptr renderMode = std::move(generateRenderMode(from, to));
+ auto generatedRenderMode = generateRenderMode(from, to);
+ std::unique_ptr renderMode = std::move(generatedRenderMode);
if (renderMode) {
output.Add(std::move(renderMode));
}
@@ -869,4 +872,4 @@ double materialTransitionTime(const MaterialState& from, const MaterialState& to
}
return result;
-}
\ No newline at end of file
+}
diff --git a/src/decor/decor_object_list.c b/src/decor/decor_object_list.c
index 65f4fbc..d60b39d 100644
--- a/src/decor/decor_object_list.c
+++ b/src/decor/decor_object_list.c
@@ -122,7 +122,7 @@ struct DecorObjectDefinition gDecorObjectDefinitions[] = {
NULL,
},
0.0f,
- 1.0f,
+ 1.3f,
PROPS_LIGHT_RAIL_ENDCAP_DYNAMIC_MODEL,
.materialIndex = LIGHT_RAIL_ENDCAP_INDEX,
.soundClipId = -1,
diff --git a/src/defs.h b/src/defs.h
index eef9648..5952237 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -15,6 +15,7 @@
#define CONTROLLER_PRIORITY 11
#define AUDIO_PRIORITY 12
#define SCHEDULER_PRIORITY 13
+#define RSP_PROFILE_PRIORITY 14
#define NUM_FIELDS 1
#define LEVEL_SEGMENT 2
diff --git a/src/font/font.c b/src/font/font.c
index de40597..a79fdba 100644
--- a/src/font/font.c
+++ b/src/font/font.c
@@ -47,107 +47,6 @@ struct FontSymbol* fontFindSymbol(struct Font* font, short id) {
return NULL;
}
-Gfx* fontRender(struct Font* font, char* message, int x, int y, Gfx* dl) {
- int startX = x;
- char prev = 0;
-
- for (; *message; prev = *message, ++message) {
- char curr = *message;
-
- if (curr == '\n') {
- y += font->charHeight;
- x = startX;
- continue;
- }
-
- // TODO utf-8 decode
- struct FontSymbol* symbol = fontFindSymbol(font, (short)curr);
-
- if (!symbol) {
- continue;
- }
-
- x += fontDetermineKerning(font, prev, curr);
-
- int finalX = x + symbol->xoffset;
- int finalY = y + symbol->yoffset;
-
- gSPTextureRectangle(
- dl++,
- finalX << 2, finalY << 2,
- (finalX + symbol->width) << 2,
- (finalY + symbol->height) << 2,
- G_TX_RENDERTILE,
- symbol->x << 5, symbol->y << 5,
- 0x400, 0x400
- );
-
- x += symbol->xadvance;
- }
-
- return dl;
-}
-
-int fontCountGfx(struct Font* font, char* message) {
- int result = 0;
-
- for (; *message; ++message) {
- char curr = *message;
-
- if (curr == '\n') {
- continue;
- }
-
- // TODO utf-8 decode
- struct FontSymbol* symbol = fontFindSymbol(font, (short)curr);
-
- if (!symbol) {
- continue;
- }
-
- result += 3;
- }
-
- return result;
-}
-
-struct Vector2s16 fontMeasure(struct Font* font, char* message) {
- int startX = 0;
- char prev = 0;
- int x = 0;
- int y = 0;
-
- struct Vector2s16 result;
-
- result.x = 0;
-
- for (; *message; prev = *message, ++message) {
- char curr = *message;
-
- if (curr == '\n') {
- y += font->charHeight;
- x = startX;
- continue;
- }
-
- // TODO utf-8 decode
- struct FontSymbol* symbol = fontFindSymbol(font, (short)curr);
-
- if (!symbol) {
- continue;
- }
-
- x += fontDetermineKerning(font, prev, curr);
- x += symbol->xadvance;
-
- result.x = MAX(result.x, x);
- }
-
- result.y = y + font->charHeight;
-
- return result;
-}
-
short fontNextUtf8Character(char** strPtr) {
char* curr = *strPtr;
diff --git a/src/font/font.h b/src/font/font.h
index cb6a0fd..c2abb69 100644
--- a/src/font/font.h
+++ b/src/font/font.h
@@ -35,11 +35,6 @@ struct Font {
unsigned short kerningMaxCollisions;
};
-// legacy methods for a font that fits into a single page
-Gfx* fontRender(struct Font* font, char* message, int x, int y, Gfx* dl);
-int fontCountGfx(struct Font* font, char* message);
-struct Vector2s16 fontMeasure(struct Font* font, char* message);
-
struct SymbolLocation {
short x;
short y;
diff --git a/src/graphics/profile_task.c b/src/graphics/profile_task.c
new file mode 100644
index 0000000..9dfb1ee
--- /dev/null
+++ b/src/graphics/profile_task.c
@@ -0,0 +1,143 @@
+#include "profile_task.h"
+
+#include "../defs.h"
+
+
+#ifdef PORTAL64_WITH_DEBUGGER
+#include "../debugger/serial.h"
+#endif
+
+#include
+
+#define VIDEO_MSG 666
+#define RSP_DONE_MSG 667
+#define RDP_DONE_MSG 668
+
+#define SAMPLES_PER_STEP 10
+
+void copyGfx(Gfx* from, Gfx* to, int count) {
+ Gfx* max = from + count;
+
+ while (from < max) {
+ *to++ = *from++;
+ }
+}
+
+void profileTask(OSSched* scheduler, OSThread* currentThread, OSTask* task) {
+ // block scheduler thread
+ osSetThreadPri(currentThread, RSP_PROFILE_PRIORITY);
+
+ // wait for DP to be available
+ while (IO_READ(DPC_STATUS_REG) & (DPC_STATUS_DMA_BUSY | DPC_STATUS_END_VALID | DPC_STATUS_START_VALID));
+
+ OSMesgQueue messageQueue;
+ OSMesg messages[4];
+
+ osCreateMesgQueue(&messageQueue, messages, 4);
+
+ // take over event queues
+ osSetEventMesg(OS_EVENT_SP, &messageQueue, (OSMesg)RSP_DONE_MSG);
+ osSetEventMesg(OS_EVENT_DP, &messageQueue, (OSMesg)RDP_DONE_MSG);
+ osViSetEvent(&messageQueue, (OSMesg)VIDEO_MSG, 1);
+
+ Gfx* curr = (Gfx*)task->t.data_ptr;
+
+ Gfx* end = curr;
+
+ while (end[1].words.w0 != _SHIFTL(G_RDPFULLSYNC, 24, 8)) {
+ ++end;
+ }
+
+#ifdef PORTAL64_WITH_DEBUGGER
+ int total = end - curr;
+#endif
+
+ Gfx tmp[3];
+
+ while (curr <= end) {
+ for (int sample = 0; sample < SAMPLES_PER_STEP; ++sample) {
+ // wait for DP to be available
+ while (IO_READ(DPC_STATUS_REG) & (DPC_STATUS_DMA_BUSY | DPC_STATUS_END_VALID | DPC_STATUS_START_VALID));
+
+ copyGfx(curr, tmp, 3);
+
+ Gfx* dl = curr;
+ gDPPipeSync(dl++);
+ gDPFullSync(dl++);
+ gSPEndDisplayList(dl++);
+
+ // not very precise, but it seems to work
+ osWritebackDCacheAll();
+
+#ifdef PORTAL64_WITH_DEBUGGER
+ OSTime start = osGetTime();
+#endif
+ osSpTaskStart(task);
+ OSMesg recv;
+
+ do {
+ (void)osRecvMesg(&messageQueue, &recv, OS_MESG_BLOCK);
+ } while ((int)recv != RDP_DONE_MSG);
+
+#ifdef PORTAL64_WITH_DEBUGGER
+ OSTime result = osGetTime() - start;
+
+ u64 us = OS_CYCLES_TO_NSEC(result);
+#endif
+
+ // wait for DP to be available
+ while (IO_READ(DPC_STATUS_REG) & (DPC_STATUS_DMA_BUSY | DPC_STATUS_END_VALID | DPC_STATUS_START_VALID));
+
+ copyGfx(tmp, curr, 3);
+
+ osWritebackDCacheAll();
+
+#ifdef PORTAL64_WITH_DEBUGGER
+ char message[64];
+ int messageLen = sprintf(
+ message,
+ "%d/%d 0x%08x%08x ms %d.%d",
+ curr - (Gfx*)task->t.data_ptr,
+ total,
+ curr->words.w0,
+ curr->words.w1,
+ (int)(us / 1000000),
+ (int)(us % 1000000)
+ );
+ gdbSendMessage(GDBDataTypeText, message, messageLen);
+#endif
+ }
+
+ ++curr;
+ }
+
+
+ osSetEventMesg(OS_EVENT_SP, &scheduler->interruptQ, (OSMesg)RSP_DONE_MSG);
+ osSetEventMesg(OS_EVENT_DP, &scheduler->interruptQ, (OSMesg)RDP_DONE_MSG);
+ osViSetEvent(&scheduler->interruptQ, (OSMesg)VIDEO_MSG, 1);
+ osSetThreadPri(currentThread, GAME_PRIORITY);
+}
+
+void profileMapAddress(void* original, void* ramAddress) {
+#ifdef PORTAL64_WITH_DEBUGGER
+ char message[64];
+ int messageLen = sprintf(
+ message,
+ "addr 0x%08x -> 0x%08x",
+ (int)original,
+ (int)ramAddress
+ );
+ gdbSendMessage(GDBDataTypeText, message, messageLen);
+#endif
+}
+
+void profileClearAddressMap() {
+#ifdef PORTAL64_WITH_DEBUGGER
+ char message[64];
+ int messageLen = sprintf(
+ message,
+ "addr clearall"
+ );
+ gdbSendMessage(GDBDataTypeText, message, messageLen);
+#endif
+}
\ No newline at end of file
diff --git a/src/graphics/profile_task.h b/src/graphics/profile_task.h
new file mode 100644
index 0000000..ca92f2a
--- /dev/null
+++ b/src/graphics/profile_task.h
@@ -0,0 +1,11 @@
+#ifndef __PROFILE_TASK_H__
+#define __PROFILE_TASK_H__
+
+#include
+#include
+
+void profileTask(OSSched* scheduler, OSThread* currentThread, OSTask* task);
+void profileMapAddress(void* original, void* ramAddress);
+void profileClearAddressMap();
+
+#endif
\ No newline at end of file
diff --git a/src/levels/static_render.c b/src/levels/static_render.c
index 5d5398e..f1231de 100644
--- a/src/levels/static_render.c
+++ b/src/levels/static_render.c
@@ -65,14 +65,16 @@ void staticRenderPopulateRooms(struct FrustrumCullingInformation* cullingInfo, M
struct RotatedBox rotatedBox;
- rotatedBoxTransform(&staticTransforms[staticElement->transformIndex], animatedBox, &rotatedBox);
+ struct Transform* transform = &staticTransforms[staticElement->transformIndex];
+
+ rotatedBoxTransform(transform, animatedBox, &rotatedBox);
if (isRotatedBoxOutsideFrustrum(cullingInfo, &rotatedBox)) {
continue;
}
struct Vector3 center;
- vector3Scale(&rotatedBox.origin, ¢er, 1.0f / SCENE_SCALE);
+ vector3AddScaled(&staticElement->center, &transform->position, 1.0f / SCENE_SCALE, ¢er);
renderSceneAdd(
renderScene,
diff --git a/src/main.c b/src/main.c
index cd94749..4b73f5a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,6 +25,7 @@
#include "util/profile.h"
#include "util/rom.h"
#include "util/time.h"
+#include "graphics/profile_task.h"
#include "levels/levels.h"
#include "savefile/checkpoint.h"
@@ -182,6 +183,7 @@ int updateSchedulerModeAndGetFPS(int interlacedMode) {
schedulerMode = HIGH_RES ? (interlacedMode ? OS_VI_MPAL_HPF1 : OS_VI_MPAL_HPN1) : (interlacedMode ? OS_VI_MPAL_LPF1 : OS_VI_MPAL_LPN1);
break;
}
+
return fps;
}
@@ -253,6 +255,7 @@ static void gameProc(void* arg) {
controllersInit();
rumblePakClipInit();
initAudio(fps);
+ timeSetFrameRate(fps);
soundPlayerInit();
translationsLoad(gSaveData.controls.subtitleLanguage);
skSetSegmentLocation(CHARACTER_ANIMATION_SEGMENT, (unsigned)_animation_segmentSegmentRomStart);
@@ -281,6 +284,7 @@ static void gameProc(void* arg) {
portalSurfaceRevert(0);
portalSurfaceCleanupQueueInit();
heapInit(_heapStart, memoryEnd);
+ profileClearAddressMap();
translationsLoad(gSaveData.controls.subtitleLanguage);
levelLoadWithCallbacks(levelGetQueued());
rumblePakClipInit();
@@ -325,6 +329,14 @@ static void gameProc(void* arg) {
profileEnd(updateStart, 0);
drawingEnabled = 1;
}
+
+#if PORTAL64_WITH_RSP_PROFILER
+ if (controllerGetButtonDown(2, START_BUTTON)) {
+ struct GraphicsTask* task = &gGraphicsTasks[drawBufferIndex];
+ zeroMemory(task->framebuffer, sizeof(u16) * SCREEN_WD * SCREEN_HT);
+ profileTask(&scheduler, &gameThread, &task->task.list);
+ }
+#endif
timeUpdateDelta();
soundPlayerUpdate();
controllersSavePreviousState();
diff --git a/src/menu/main_menu.c b/src/menu/main_menu.c
index ed46068..021875d 100644
--- a/src/menu/main_menu.c
+++ b/src/menu/main_menu.c
@@ -44,8 +44,9 @@ void mainMenuInit(struct GameMenu* gameMenu) {
mainMenuPlayAmbientSound();
- for (int i = 0; i < gScene.signageCount; ++i) {
- signageActivate(&gScene.signage[i]);
+ for (int i = 0; i < gScene.clockCount; ++i) {
+ // this shows the pause time for the main menu
+ gScene.clocks[i].timeLeft = -1.0f;
}
}
@@ -67,6 +68,12 @@ void mainMenuUpdate(struct GameMenu* gameMenu) {
mainMenuPlayAmbientSound();
+ if (gScene.animator.animators[0].currentTime > 5.0f) {
+ for (int i = 0; i < gScene.signageCount; ++i) {
+ signageActivate(&gScene.signage[i]);
+ }
+ }
+
for (int i = 0; i < gScene.signageCount; ++i) {
signageUpdate(&gScene.signage[i]);
}
diff --git a/src/menu/menu.c b/src/menu/menu.c
index e4f97e8..ae7842e 100644
--- a/src/menu/menu.c
+++ b/src/menu/menu.c
@@ -16,16 +16,6 @@ struct PrerenderedText* menuBuildPrerenderedText(struct Font* font, char* messag
return result;
}
-Gfx* menuBuildText(struct Font* font, char* message, int x, int y) {
- Gfx* result = malloc(sizeof(Gfx) * (fontCountGfx(font, message) + 1));
- Gfx* dl = result;
-
- dl = fontRender(font, message, x, y, dl);
- gSPEndDisplayList(dl++);
-
- return result;
-}
-
Gfx* menuBuildBorder(int x, int y, int width, int height) {
Gfx* result = malloc(sizeof(Gfx) * 7 * 3 + 1);
Gfx* dl = result;
@@ -211,7 +201,7 @@ void menuSetRenderColor(struct RenderState* renderState, int isSelected, struct
}
}
-struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, int y, int shouldUsePrerendered) {
+struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, int y) {
struct MenuCheckbox result;
result.x = x;
@@ -227,12 +217,7 @@ struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, i
dl = menuRenderOutline(x, y, CHECKBOX_SIZE, CHECKBOX_SIZE, 1, dl);
gSPEndDisplayList(dl++);
- if (shouldUsePrerendered) {
- result.prerenderedText = menuBuildPrerenderedText(font, message, x + CHECKBOX_SIZE + 6, y, SCREEN_WD);
- } else {
- result.text = menuBuildText(font, message, x + CHECKBOX_SIZE + 6, y);
- }
-
+ result.prerenderedText = menuBuildPrerenderedText(font, message, x + CHECKBOX_SIZE + 6, y, SCREEN_WD);
result.checked = 0;
return result;
diff --git a/src/menu/menu.h b/src/menu/menu.h
index 92d4d74..75f0157 100644
--- a/src/menu/menu.h
+++ b/src/menu/menu.h
@@ -17,10 +17,7 @@ struct MenuButton {
struct MenuCheckbox {
Gfx* outline;
- union {
- Gfx* text;
- struct PrerenderedText* prerenderedText;
- };
+ struct PrerenderedText* prerenderedText;
Gfx* checkedIndicator;
short x, y;
short checked;
@@ -48,7 +45,6 @@ extern struct Coloru8 gSelectionGray;
extern struct Coloru8 gBorderHighlight;
extern struct Coloru8 gBorderDark;
-Gfx* menuBuildText(struct Font* font, char* message, int x, int y);
struct PrerenderedText* menuBuildPrerenderedText(struct Font* font, char* message, int x, int y, int maxWidth);
Gfx* menuBuildBorder(int x, int y, int width, int height);
@@ -61,7 +57,7 @@ struct MenuButton menuBuildButton(struct Font* font, char* message, int x, int y
void menuSetRenderColor(struct RenderState* renderState, int isSelected, struct Coloru8* selected, struct Coloru8* defaultColor);
void menuRebuildButtonText(struct MenuButton* button, struct Font* font, char* message, int rightAlign);
-struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, int y, int shouldUsePrerendered);
+struct MenuCheckbox menuBuildCheckbox(struct Font* font, char* message, int x, int y);
Gfx* menuCheckboxRender(struct MenuCheckbox* checkbox, Gfx* dl);
struct MenuSlider menuBuildSlider(int x, int y, int w, int tickCount);
diff --git a/src/menu/menu_builder.c b/src/menu/menu_builder.c
index e6ab222..ce3ef72 100644
--- a/src/menu/menu_builder.c
+++ b/src/menu/menu_builder.c
@@ -44,8 +44,7 @@ void checkboxMenuItemInit(struct MenuBuilderElement* element) {
element->params->params.checkbox.font,
translationsGet(element->params->params.checkbox.messageId),
element->params->x,
- element->params->y,
- 1
+ element->params->y
);
element->data = checkbox;
}
diff --git a/src/menu/options_menu.c b/src/menu/options_menu.c
index ce21379..baf4888 100644
--- a/src/menu/options_menu.c
+++ b/src/menu/options_menu.c
@@ -41,8 +41,6 @@ struct Tab gOptionTabs[] = {
void optionsMenuInit(struct OptionsMenu* options) {
options->menuOutline = menuBuildBorder(MENU_LEFT, MENU_TOP, MENU_WIDTH, MENU_HEIGHT);
- options->optionsText = menuBuildText(&gDejaVuSansFont, "OPTIONS", 48, 48);
-
tabsInit(
&options->tabs,
gOptionTabs,
diff --git a/src/menu/options_menu.h b/src/menu/options_menu.h
index d5f787e..f645950 100644
--- a/src/menu/options_menu.h
+++ b/src/menu/options_menu.h
@@ -22,7 +22,6 @@ enum OptionsMenuTabs {
struct OptionsMenu {
Gfx* menuOutline;
- Gfx* optionsText;
struct Tabs tabs;
diff --git a/src/physics/epa.c b/src/physics/epa.c
index 9fe38aa..87245eb 100644
--- a/src/physics/epa.c
+++ b/src/physics/epa.c
@@ -570,7 +570,7 @@ int epaSolveSwept(struct Simplex* startingSimplex, void* objectA, MinkowsiSum ob
vector3Scale(&raycastDir, &planePos, distance);
float moveOffset = vector3DistSqrd(bStart, bEnd);
- if (distance * distance > moveOffset + 0.1f) {
+ if (distance * distance >= moveOffset + 0.01f) {
goto error;
}
diff --git a/src/savefile/scene_serialize.c b/src/savefile/scene_serialize.c
index 3a6f6a7..e068de9 100644
--- a/src/savefile/scene_serialize.c
+++ b/src/savefile/scene_serialize.c
@@ -525,5 +525,6 @@ void sceneDeserialize(struct Serializer* serializer, struct Scene* scene) {
if (scene->player.flags & (PlayerHasFirstPortalGun | PlayerHasSecondPortalGun)) {
scene->portalGun.portalGunVisible = 1;
+ scene->portalGun.rotation = scene->player.lookTransform.rotation;
}
}
diff --git a/src/scene/clock.c b/src/scene/clock.c
index 4364fad..f1f0b3d 100644
--- a/src/scene/clock.c
+++ b/src/scene/clock.c
@@ -19,8 +19,10 @@
#define DIGIT_WIDTH 512
-u8 gCurrentClockDigits[5];
+u8 gCurrentClockDigits[7];
Vtx* gClockDigits[] = {
+ signage_clock_digits_clock_digits_hour_01_color,
+ signage_clock_digits_clock_digits_minute_10_color,
signage_clock_digits_clock_digits_minute_01_color,
signage_clock_digits_clock_digits_second_10_color,
signage_clock_digits_clock_digits_second_01_color,
@@ -45,31 +47,34 @@ void clockSetDigit(int digitIndex, int currDigit) {
}
void clockSetTime(float timeInSeconds) {
+ clockSetDigit(0, 0);
+ clockSetDigit(1, 0);
+
float minutes = floor(timeInSeconds * (1.0f / 60.0f));
- clockSetDigit(0, (int)minutes);
+ clockSetDigit(2, (int)minutes);
timeInSeconds -= minutes *= 60.0f;
float tenSeconds = floor(timeInSeconds * 0.1f);
- clockSetDigit(1, (int)tenSeconds);
+ clockSetDigit(3, (int)tenSeconds);
timeInSeconds -= tenSeconds * 10.0f;
float seconds = floor(timeInSeconds);
- clockSetDigit(2, (int)seconds);
+ clockSetDigit(4, (int)seconds);
timeInSeconds -= seconds;
float tenthsOfSecond = floor(timeInSeconds * 10.0f);
- clockSetDigit(3, (int)tenthsOfSecond);
+ clockSetDigit(5, (int)tenthsOfSecond);
timeInSeconds -= tenthsOfSecond * 0.1f;
- clockSetDigit(4, (int)floor(timeInSeconds * 100.0f));
+ clockSetDigit(6, (int)floor(timeInSeconds * 100.0f));
}
void clockRenderRender(void* data, struct DynamicRenderDataList* renderList, struct RenderState* renderState) {
@@ -81,7 +86,18 @@ void clockRenderRender(void* data, struct DynamicRenderDataList* renderList, str
return;
}
- clockSetTime(clock->timeLeft);
+ // main menu clock time
+ if (clock->timeLeft == -1.0f) {
+ clockSetDigit(0, 1);
+ clockSetDigit(1, 5);
+ clockSetDigit(2, 9);
+ clockSetDigit(3, 5);
+ clockSetDigit(4, 0);
+ clockSetDigit(5, 0);
+ clockSetDigit(6, 0);
+ } else {
+ clockSetTime(clock->timeLeft);
+ }
transformToMatrixL(&clock->transform, matrix, SCENE_SCALE);
diff --git a/src/scene/fizzler.c b/src/scene/fizzler.c
index 06f38d8..76cc9b0 100644
--- a/src/scene/fizzler.c
+++ b/src/scene/fizzler.c
@@ -216,4 +216,6 @@ void fizzlerUpdate(struct Fizzler* fizzler) {
fizzler->oldestParticleIndex = 0;
}
}
+
+ osWritebackDCache(fizzler->modelVertices, sizeof(Vtx) * maxVertex);
}
\ No newline at end of file
diff --git a/src/scene/portal_gun.c b/src/scene/portal_gun.c
index 4445625..fe1c815 100644
--- a/src/scene/portal_gun.c
+++ b/src/scene/portal_gun.c
@@ -49,6 +49,9 @@ void portalGunInit(struct PortalGun* portalGun, struct Transform* at, int isFres
if (isFreshStart) {
skAnimatorRunClip(&portalGun->animator, &portal_gun_v_portalgun_Armature_draw_clip, 0.0f, 0);
+ // the first time the scene renders, the animation clip hasn't started yet
+ // this just hides the gun offscreen so it doesn't show up for a single frame
+ portalGun->armature.pose[0].position.y = -1.0f;
} else {
skAnimatorRunClip(&portalGun->animator, &portal_gun_v_portalgun_Armature_idle_clip, 0.0f, 0);
}
diff --git a/src/scene/portal_surface.c b/src/scene/portal_surface.c
index 6018e14..cf43bdc 100644
--- a/src/scene/portal_surface.c
+++ b/src/scene/portal_surface.c
@@ -272,7 +272,8 @@ int portalSurfaceAdjustPosition(struct PortalSurface* surface, struct Transform*
for (iteration = 0; iteration < MAX_POS_ADJUST_ITERATIONS; ++iteration) {
int minOverlap = PORTAL_SURFACE_OVERLAP;
- struct Vector2s16 minOverlapOffset;
+ int minIsOutside = 0;
+ struct Vector2s16 minOverlapOffset = {{{0, 0}}};
struct Vector2s16 portalMin;
portalMin.x = output->x - halfSize.x;
@@ -310,40 +311,49 @@ int portalSurfaceAdjustPosition(struct PortalSurface* surface, struct Transform*
vector2s16Sub(&b, &a, &edgeDir);
struct Vector2s16 offset;
- int distance = edgeDir.y >= 0 ? portalMax.x - edgeMin.x : PORTAL_SURFACE_OVERLAP;
+ int distance = portalMax.x - edgeMin.x;
+ int isOutside = edgeDir.y < 0;
offset.x = -distance;
offset.y = 0;
int distanceCheck = edgeMax.x - portalMin.x;
- if (distanceCheck < distance && edgeDir.y <= 0) {
+ if (distanceCheck < distance) {
distance = distanceCheck;
offset.x = distance;
offset.y = 0;
+ isOutside = edgeDir.y > 0;
}
distanceCheck = portalMax.y - edgeMin.y;
- if (distanceCheck < distance && edgeDir.x <= 0) {
+ if (distanceCheck < distance) {
distance = distanceCheck;
offset.x = 0;
offset.y = -distance;
+ isOutside = edgeDir.x > 0;
}
distanceCheck = edgeMax.y - portalMin.y;
- if (distanceCheck < distance && edgeDir.x >= 0) {
+ if (distanceCheck < distance) {
distance = distanceCheck;
offset.x = 0;
offset.y = distance;
+ isOutside = edgeDir.x < 0;
}
if (distance < minOverlap) {
minOverlap = distance;
+ minIsOutside = isOutside;
minOverlapOffset = offset;
}
}
+ if (minIsOutside) {
+ return 0;
+ }
+
if (minOverlap == PORTAL_SURFACE_OVERLAP) {
break;
}
diff --git a/src/scene/scene.c b/src/scene/scene.c
index 16c902d..ea218bd 100644
--- a/src/scene/scene.c
+++ b/src/scene/scene.c
@@ -326,12 +326,13 @@ void sceneRender(struct Scene* scene, struct RenderState* renderState, struct Gr
gDPSetRenderMode(renderState->dl++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
gSPGeometryMode(renderState->dl++, G_ZBUFFER | G_LIGHTING | G_CULL_BOTH, G_SHADE);
+ if (gGameMenu.state == GameMenuStateResumeGame || scene->hud.fadeInTimer > 0.0f) {
+ hudRender(&scene->hud, &scene->player, renderState);
+ }
+
if (gGameMenu.state != GameMenuStateResumeGame) {
gameMenuRender(&gGameMenu, renderState, task);
}
- else{
- hudRender(&scene->hud, &scene->player, renderState);
- }
// sceneRenderPerformanceMetrics(scene, renderState, task);
diff --git a/src/scene/signage.c b/src/scene/signage.c
index a4ade79..b632174 100644
--- a/src/scene/signage.c
+++ b/src/scene/signage.c
@@ -250,5 +250,7 @@ void signageUpdate(struct Signage* signage) {
}
void signageActivate(struct Signage* signage) {
- signage->currentFrame = 0;
+ if (signage->currentFrame == -1) {
+ signage->currentFrame = 0;
+ }
}
\ No newline at end of file
diff --git a/src/util/dynamic_asset_loader.c b/src/util/dynamic_asset_loader.c
index ffd1341..3b8afa7 100644
--- a/src/util/dynamic_asset_loader.c
+++ b/src/util/dynamic_asset_loader.c
@@ -1,6 +1,7 @@
#include "dynamic_asset_loader.h"
#include "memory.h"
#include "rom.h"
+#include "../graphics/profile_task.h"
#include "../build/assets/models/dynamic_model_list.h"
#include "../build/assets/models/dynamic_animated_model_list.h"
@@ -92,6 +93,8 @@ Gfx* dynamicAssetLoadModel(struct DynamicAssetModel* model, u32* pointerOffset)
*pointerOffset = 0;
}
+ profileMapAddress(model->model, result);
+
return result;
}
@@ -114,6 +117,8 @@ void dynamicAssetLoadAnimatedModel(struct DynamicAnimatedAssetModel* model, stru
}
result->clipCount = model->clipCount;
+
+ profileMapAddress(result->armature->displayList, result->armature->displayList);
}
void dynamicAssetModelPreload(int index) {
diff --git a/src/util/time.c b/src/util/time.c
index df4d1fe..b1870ed 100644
--- a/src/util/time.c
+++ b/src/util/time.c
@@ -3,9 +3,14 @@
float gTimePassed = 0.0f;
int gCurrentFrame = 0;
+float gFixedDeltaTime = ((1.0f + FRAME_SKIP) / 60.0f);
void timeUpdateDelta() {
OSTime currTime = osGetTime();
gTimePassed = (float)OS_CYCLES_TO_USEC(currTime) / 1000000.0f;
++gCurrentFrame;
+}
+
+void timeSetFrameRate(int fps) {
+ gFixedDeltaTime = ((1.0f + FRAME_SKIP) / (float)fps);
}
\ No newline at end of file
diff --git a/src/util/time.h b/src/util/time.h
index 8c1eca2..7fbad7e 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -6,10 +6,12 @@
extern float gTimePassed;
extern OSTime gLastTime;
extern int gCurrentFrame;
+extern float gFixedDeltaTime;
#define FRAME_SKIP 1
-#define FIXED_DELTA_TIME ((1.0f + FRAME_SKIP) / 60.0f)
+#define FIXED_DELTA_TIME gFixedDeltaTime
void timeUpdateDelta();
+void timeSetFrameRate(int fps);
#endif
\ No newline at end of file
diff --git a/tools/profile_parser.js b/tools/profile_parser.js
new file mode 100644
index 0000000..191ff35
--- /dev/null
+++ b/tools/profile_parser.js
@@ -0,0 +1,171 @@
+const fs = require('fs');
+
+const lines = fs.readFileSync(process.argv[2], 'utf-8').split('\n');
+
+const symbolMapLines = fs.readFileSync(process.argv[3], 'utf-8').split('\n');
+
+const lineParserRegexp = /(\d+)\/\d+ 0x([a-f0-9]{2})([a-f0-9]{6})([a-f0-9]{8}) ms (\d+\.\d+)/
+
+const lineMappingRegexp = /addr 0x([a-f0-9]{8}) -> 0x([a-f0-9]{8})/
+
+const symbolParserRegexp = /0x([a-f0-9]{16})\s+(\w+)/
+
+function parseLine(line) {
+ const match = lineParserRegexp.exec(line);
+
+ if (!match) {
+ return null;
+ }
+
+ return {
+ index: parseInt(match[1]),
+ command: match[2],
+ w0: match[3],
+ w1: match[4],
+ startTime: parseFloat(match[5]),
+ }
+}
+
+function parseSymbolLine(line) {
+ const match = symbolParserRegexp.exec(line);
+
+ if (!match) {
+ return null;
+ }
+
+ return {
+ address: match[1].substring(8),
+ name: match[2],
+ };
+}
+
+const memoryMapping = new Map();
+const profileBatches = [];
+let lastIndex = -1;
+
+for (const line of lines) {
+ const parsedLine = parseLine(line);
+
+ if (parsedLine) {
+ if (lastIndex != 0 && parsedLine.index == 0) {
+ profileBatches.push({
+ memoryMapping: new Map(memoryMapping),
+ lines: [],
+ })
+ }
+
+ const latestBatch = profileBatches[profileBatches.length - 1];
+ latestBatch.lines.push(parsedLine);
+
+ lastIndex = parsedLine.index;
+ continue
+ }
+
+ if (line.trim() == 'addr clearall') {
+ memoryMapping.clear();
+ }
+
+ const addrMatch = lineMappingRegexp.exec(line);
+
+ if (addrMatch) {
+ memoryMapping.set(addrMatch[2], addrMatch[1]);
+ }
+}
+
+const symbolAddressMapping = new Map();
+
+for (const symbolLine of symbolMapLines) {
+ const parsedLine = parseSymbolLine(symbolLine);
+
+ if (!parsedLine) {
+ continue;
+ }
+
+ if (symbolAddressMapping.has(parsedLine.address)) {
+ symbolAddressMapping.set(parsedLine.address, symbolAddressMapping.get(parsedLine.address) + ',' + parsedLine.name);
+ } else {
+ symbolAddressMapping.set(parsedLine.address, parsedLine.name);
+ }
+}
+
+function calculateAverage(batch) {
+ const combinedCommands = [];
+
+ for (const parsedLine of batch.lines) {
+ const existing = combinedCommands[parsedLine.index];
+
+ if (existing) {
+ existing.startTime += parsedLine.startTime;
+ existing.total += 1;
+ } else {
+ combinedCommands[parsedLine.index] = {
+ ...parsedLine,
+ total: 1,
+ };
+ }
+ }
+
+ for (let i = 0; i < combinedCommands.length; ++i) {
+ const current = combinedCommands[i];
+
+ if (current) {
+ current.startTime /= current.total;
+ }
+ }
+
+ for (let i = 0; i + 1 < combinedCommands.length; ++i) {
+ const current = combinedCommands[i];
+ const next = combinedCommands[i + 1];
+
+ current.elapsedTime = next.startTime - current.startTime;
+ }
+
+ // the last command is always a pipe sync we dont care about
+ combinedCommands.pop();
+
+ combinedCommands.sort((a, b) => b.elapsedTime - a.elapsedTime);
+
+ batch.combinedCommands = combinedCommands;
+}
+
+profileBatches.forEach(calculateAverage);
+
+function formatAddress(address, batch) {
+ if (batch.memoryMapping.has(address)) {
+ address = batch.memoryMapping.get(address);
+ }
+
+ return symbolAddressMapping.get(address) || `0x${address}`;
+}
+
+function formatCommandName(command, batch) {
+ switch (command.command) {
+ case 'db':
+ {
+ const segment = parseInt(command.w0.substring(4), 16) / 4;
+ return `gsSPSegment(0x${segment}, 0x${command.w1})`;
+ }
+ case 'de':
+ return `gsSPDisplayList(${formatAddress(command.w1, batch)})`;
+ case 'f6':
+ return `gsDPFillRectangle`;
+ case 'd8':
+ return `gsSPPopMatrix`;
+ case 'da':
+ return `gsSPMatrix`;
+ default:
+ return `unknown 0x${command.command} 0x${command.w0}${command.w1}`;
+ }
+}
+
+function formatCommand(command, batch) {
+ return `${command.elapsedTime} ${formatCommandName(command, batch)}`;
+}
+
+for (const batch of profileBatches) {
+ console.log('start of batch');
+ for (const command of batch.combinedCommands) {
+ console.log(formatCommand(command, batch));
+ }
+ console.log('end of batch');
+}
\ No newline at end of file