Skip to content

Commit 350315a

Browse files
authored
Merge pull request #1769 from HarbourMasters/develop-zhora
zhora -> dev
2 parents 4ef7151 + dd6a8b5 commit 350315a

File tree

11 files changed

+114
-60
lines changed

11 files changed

+114
-60
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
77
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE)
88

99
project(Ship LANGUAGES C CXX
10-
VERSION 4.0.2)
11-
set(PROJECT_BUILD_NAME "ZHORA CHARLIE" CACHE STRING "")
10+
VERSION 4.0.3)
11+
set(PROJECT_BUILD_NAME "ZHORA DELTA" CACHE STRING "")
1212
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
1313

1414
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh)

libultraship/libultraship/Lib/Fast3D/gfx_direct3d_common.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,13 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
253253
append_line(buf, &len, "[RootSignature(RS)]");
254254
}
255255
append_line(buf, &len, "float4 PSMain(PSInput input, float4 screenSpace : SV_Position) : SV_TARGET {");
256+
257+
// Reference approach to color wrapping as per GLideN64
258+
// Return wrapped value of x in interval [low, high)
259+
// Mod implementation of GLSL sourced from https://registry.khronos.org/OpenGL-Refpages/gl4/html/mod.xhtml
260+
append_line(buf, &len, "#define MOD(x, y) ((x) - (y) * floor((x)/(y)))");
261+
append_line(buf, &len, "#define WRAP(x, low, high) MOD((x)-(low), (high)-(low)) + (low)");
262+
256263
for (int i = 0; i < 2; i++) {
257264
if (cc_features.used_textures[i]) {
258265
len += sprintf(buf + len, " float2 tc%d = input.uv%d;\r\n", i, i);
@@ -294,11 +301,18 @@ void gfx_direct3d_common_build_shader(char buf[4096], size_t& len, size_t& num_f
294301
append_formula(buf, &len, cc_features.c[c], cc_features.do_single[c][0], cc_features.do_multiply[c][0], cc_features.do_mix[c][0], cc_features.opt_alpha, false, cc_features.opt_alpha);
295302
}
296303
append_line(buf, &len, ";");
304+
305+
if (c == 0) {
306+
append_str(buf, &len, "texel = WRAP(texel, -1.01, 1.01);");
307+
}
297308
}
298309

299310
if (cc_features.opt_texture_edge && cc_features.opt_alpha) {
300311
append_line(buf, &len, " if (texel.a > 0.19) texel.a = 1.0; else discard;");
301312
}
313+
314+
append_str(buf, &len, "texel = WRAP(texel, -0.51, 1.51);");
315+
append_str(buf, &len, "texel = clamp(texel, 0.0, 1.0);");
302316
// TODO discard if alpha is 0?
303317
if (cc_features.opt_fog) {
304318
if (cc_features.opt_alpha) {

libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,10 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
414414

415415
append_line(fs_buf, &fs_len, "void main() {");
416416

417+
// Reference approach to color wrapping as per GLideN64
418+
// Return wrapped value of x in interval [low, high)
419+
append_line(fs_buf, &fs_len, "#define WRAP(x, low, high) mod((x)-(low), (high)-(low)) + (low)");
420+
417421
for (int i = 0; i < 2; i++) {
418422
if (cc_features.used_textures[i]) {
419423
bool s = cc_features.clamp[i][0], t = cc_features.clamp[i][1];
@@ -448,7 +452,14 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad
448452
append_formula(fs_buf, &fs_len, cc_features.c[c], cc_features.do_single[c][0], cc_features.do_multiply[c][0], cc_features.do_mix[c][0], cc_features.opt_alpha, false, cc_features.opt_alpha);
449453
}
450454
append_line(fs_buf, &fs_len, ";");
455+
456+
if (c == 0) {
457+
append_str(fs_buf, &fs_len, "texel = WRAP(texel, -1.01, 1.01);");
458+
}
451459
}
460+
461+
append_str(fs_buf, &fs_len, "texel = WRAP(texel, -0.51, 1.51);");
462+
append_str(fs_buf, &fs_len, "texel = clamp(texel, 0.0, 1.0);");
452463
// TODO discard if alpha is 0?
453464
if (cc_features.opt_fog)
454465
{

libultraship/libultraship/Window.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ namespace Ship {
480480
WmApi = &gfx_dxgi_api;
481481
#endif
482482
#ifdef ENABLE_DX11
483-
RenderingApi = &gfx_direct3d11_api;
483+
RenderingApi = &gfx_direct3d11_api;
484484
WmApi = &gfx_dxgi_api;
485485
#endif
486486
#ifdef __WIIU__

soh/soh/GameMenuBar.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ namespace GameMenuBar {
298298
CVar_SetS32("gCrouchStabHammerFix", 0);
299299
// Fix all crouch stab
300300
CVar_SetS32("gCrouchStabFix", 0);
301+
// Fix Gerudo Warrior's clothing colors
302+
CVar_SetS32("gGerudoWarriorClothingFix", 0);
301303

302304
// Red Ganon blood
303305
CVar_SetS32("gRedGanonBlood", 0);
@@ -1084,6 +1086,8 @@ namespace GameMenuBar {
10841086
UIWidgets::PaddedEnhancementCheckbox("Remove power crouch stab", "gCrouchStabFix", true, false);
10851087
UIWidgets::Tooltip("Make crouch stabbing always do the same damage as a regular slash");
10861088
}
1089+
UIWidgets::PaddedEnhancementCheckbox("Fix Gerudo Warrior's clothing colors", "gGerudoWarriorClothingFix", true, false);
1090+
UIWidgets::Tooltip("Prevent the Gerudo Warrior's clothes changing color when changing Link's tunic or using bombs in front of her");
10871091

10881092
ImGui::EndMenu();
10891093
}

soh/src/code/z_parameter.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2502,13 +2502,6 @@ u8 Item_CheckObtainability(u8 item) {
25022502
} else {
25032503
return ITEM_NONE;
25042504
}
2505-
} else if ( gSaveContext.n64ddFlag &&
2506-
((item >= RG_GERUDO_FORTRESS_SMALL_KEY) && (item <= RG_GANONS_CASTLE_SMALL_KEY) ||
2507-
(item >= RG_FOREST_TEMPLE_BOSS_KEY) && (item <= RG_GANONS_CASTLE_BOSS_KEY) ||
2508-
(item >= RG_DEKU_TREE_MAP) && (item <= RG_ICE_CAVERN_MAP) ||
2509-
(item >= RG_DEKU_TREE_COMPASS) && (item <= RG_ICE_CAVERN_COMPASS))
2510-
) {
2511-
return ITEM_NONE;
25122505
} else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) {
25132506
return ITEM_NONE;
25142507
} else if (item == ITEM_KEY_SMALL) {

soh/src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,14 @@ void func_808FD5F4(BossGanon2* this, GlobalContext* globalCtx) {
577577
BossGanon2_SetObjectSegment(this, globalCtx, OBJECT_GANON_ANIME3, false);
578578
func_8002DF54(globalCtx, &this->actor, 0x54);
579579
this->unk_314 = 3;
580+
581+
// At this point, the actor has Ganon's skeleton but is still playing an animation for Ganondorf. This
582+
// causes issues when trying to access the limb posotions as Ganon has more limbs than Ganondorf. When
583+
// animating, data from past the end of the animation data is accessed. This is a hack solution so
584+
// that we are at least playing an animation meant for Ganon. There is no visible change since Ganon is
585+
// off-screen. There is actually 1 frame where he is visible, and in the vanilla game he is an
586+
// explosion of limbs since half of them are in random positions from the junk data accessed.
587+
Animation_PlayOnce(&this->skelAnime, &gGanonUncurlAndFlailAnim);
580588
}
581589
// fake, tricks the compiler into using stack the way we need it to
582590
if (zero) {

soh/src/overlays/actors/ovl_En_Ge3/z_en_ge3.c

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -249,28 +249,30 @@ s32 EnGe3_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList,
249249
case GELDB_LIMB_HEAD:
250250
rot->x += this->headRot.y;
251251

252-
// This is a hack to fix the color-changing clothes this Gerudo has on N64 versions
253252
default:
254-
OPEN_DISPS(globalCtx->state.gfxCtx);
255-
switch (limbIndex) {
256-
case GELDB_LIMB_NECK:
257-
break;
258-
case GELDB_LIMB_HEAD:
259-
gDPPipeSync(POLY_OPA_DISP++);
260-
gDPSetEnvColor(POLY_OPA_DISP++, 80, 60, 10, 255);
261-
break;
262-
case GELDB_LIMB_R_SWORD:
263-
case GELDB_LIMB_L_SWORD:
264-
gDPPipeSync(POLY_OPA_DISP++);
265-
gDPSetEnvColor(POLY_OPA_DISP++, 140, 170, 230, 255);
266-
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
267-
break;
268-
default:
269-
gDPPipeSync(POLY_OPA_DISP++);
270-
gDPSetEnvColor(POLY_OPA_DISP++, 140, 0, 0, 255);
271-
break;
253+
if (CVar_GetS32("gGerudoWarriorClothingFix", 0)) {
254+
// This is a hack to fix the color-changing clothes this Gerudo has on N64 versions
255+
OPEN_DISPS(globalCtx->state.gfxCtx);
256+
switch (limbIndex) {
257+
case GELDB_LIMB_NECK:
258+
break;
259+
case GELDB_LIMB_HEAD:
260+
gDPPipeSync(POLY_OPA_DISP++);
261+
gDPSetEnvColor(POLY_OPA_DISP++, 80, 60, 10, 255);
262+
break;
263+
case GELDB_LIMB_R_SWORD:
264+
case GELDB_LIMB_L_SWORD:
265+
gDPPipeSync(POLY_OPA_DISP++);
266+
gDPSetEnvColor(POLY_OPA_DISP++, 140, 170, 230, 255);
267+
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
268+
break;
269+
default:
270+
gDPPipeSync(POLY_OPA_DISP++);
271+
gDPSetEnvColor(POLY_OPA_DISP++, 140, 0, 0, 255);
272+
break;
273+
}
274+
CLOSE_DISPS(globalCtx->state.gfxCtx);
272275
}
273-
CLOSE_DISPS(globalCtx->state.gfxCtx);
274276
break;
275277
}
276278
return false;

soh/src/overlays/actors/ovl_En_Niw_Lady/z_en_niw_lady.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ void func_80ABA9B8(EnNiwLady* this, GlobalContext* globalCtx) {
401401
} else {
402402
// TODO: get-item-rework Adult trade sequence
403403
this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_ANJU_AS_ADULT, GI_POCKET_EGG);
404-
GiveItemEntryFromActor(&this->actor, globalCtx, this->getItemEntry, 200.0f, 100.0f);
404+
gSaveContext.itemGetInf[2] |= 0x1000;
405405
}
406406

407407
this->actionFunc = func_80ABAC00;
@@ -431,7 +431,14 @@ void func_80ABAB08(EnNiwLady* this, GlobalContext* globalCtx) {
431431
case 0:
432432
Message_CloseTextbox(globalCtx);
433433
this->actor.parent = NULL;
434-
func_8002F434(&this->actor, globalCtx, GI_COJIRO, 200.0f, 100.0f);
434+
if (!gSaveContext.n64ddFlag) {
435+
func_8002F434(&this->actor, globalCtx, GI_COJIRO, 200.0f, 100.0f);
436+
} else {
437+
// TODO: get-item-rework Adult trade sequence
438+
this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_TRADE_POCKET_CUCCO, GI_COJIRO);
439+
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_POCKET_CUCCO);
440+
gSaveContext.itemGetInf[2] |= 0x4000;
441+
}
435442
this->actionFunc = func_80ABAC00;
436443
break;
437444
case 1:
@@ -455,18 +462,14 @@ void func_80ABAC00(EnNiwLady* this, GlobalContext* globalCtx) {
455462
} else {
456463
getItemId = this->getItemId;
457464
if (LINK_IS_ADULT) {
458-
getItemId = !(gSaveContext.itemGetInf[2] & 0x1000) ? GI_POCKET_EGG : GI_COJIRO;
459-
460-
if (gSaveContext.n64ddFlag) {
461-
if (getItemId == GI_POCKET_EGG) {
462-
// TODO: get-item-rework Adult trade sequence
463-
this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_ANJU_AS_ADULT, GI_POCKET_EGG);
464-
GiveItemEntryFromActor(&this->actor, globalCtx, this->getItemEntry, 200.0f, 100.0f);
465-
} else {
466-
this->getItemEntry = Randomizer_GetItemFromKnownCheck(RC_KAK_TRADE_POCKET_CUCCO, GI_COJIRO);
467-
Randomizer_ConsumeAdultTradeItem(globalCtx, ITEM_POCKET_CUCCO);
468-
GiveItemEntryFromActor(&this->actor, globalCtx, this->getItemEntry, 200.0f, 100.0f);
469-
}
465+
if (!gSaveContext.n64ddFlag) {
466+
getItemId = !(gSaveContext.itemGetInf[2] & 0x1000) ? GI_POCKET_EGG : GI_COJIRO;
467+
} else {
468+
// TODO: get-item-rework Adult trade sequence
469+
getItemId = this->getItemEntry.getItemId;
470+
GiveItemEntryFromActor(&this->actor, globalCtx, this->getItemEntry, 200.0f, 100.0f);
471+
// Skip setting item flags because that was done earlier
472+
this->actionFunc = func_80ABA778;
470473
}
471474
}
472475
if (this->getItemEntry.getItemId == GI_NONE) {

soh/src/overlays/actors/ovl_En_Ru2/z_en_ru2.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,19 @@ void func_80AF3F20(EnRu2* this, GlobalContext* globalCtx) {
820820
void EnRu2_Draw(Actor* thisx, GlobalContext* globalCtx) {
821821
EnRu2* this = (EnRu2*)thisx;
822822

823+
// FAST3D: This is a hack for the issue of both TEXEL0 and TEXEL1 using the same texture with different settings.
824+
// Ruto's earring uses both TEXEL0 and TEXEL1 to render. The issue is that it never loads anything into TEXEL1, so
825+
// it reuses whatever happens to be there, which is the water temple brick texture. It just so happens that the
826+
// earring texture loads into the same place in tmem as the brick texture, so when it comes to rendering, TEXEL1
827+
// uses the earring texture with diffrent clamp settings, and it displays without noticeable error. However, both
828+
// texel samplers are not intended to be used for the same texture with different settings, so this misuse confuses
829+
// our texture cache, and we load the wrong settings for the earrings texture. This patch is a hack that replaces
830+
// TEXEL1 with TEXEL0, which is most likely the original intention, and all is well.
831+
Gfx* gfx = ResourceMgr_LoadGfxByName(gAdultRutoHeadDL);
832+
Gfx patch = gsDPSetCombineLERP(TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, TEXEL0, 0,
833+
PRIM_LOD_FRAC, COMBINED);
834+
gfx[0xA2] = patch;
835+
823836
if ((this->drawConfig < 0) || (this->drawConfig >= ARRAY_COUNT(sDrawFuncs)) ||
824837
(sDrawFuncs[this->drawConfig] == 0)) {
825838
// "Draw Mode is improper!"

0 commit comments

Comments
 (0)