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