mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
[jak 2] ETIE (#2326)
Definitely needs a clean up pass, but I think the functionality is very close. There's a few "hacks" still: - I am using the emerc logic for environment mapping, which doesn't care about the length of the normals. I can't figure out how the normal scaling worked in etie. I want to do a little bit more experimentation with this before merging. - There is some part about adgifs for TIE and ETIE that I don't understand. The clearly correct behavior of TIE/ETIE is that the alpha settings from the adgif shader are overwritten by the settings from the renderer. But I can't figure out how this happens in all cases. - Fade out is completely disabled. I think this is fine because the performance difference isn't bad. But if you are comparing screenshots with PCSX2, it will make things look a tiny bit different.
This commit is contained in:
parent
6670124296
commit
2fa4a23ea1
|
@ -72,6 +72,104 @@ void TfragTree::serialize(Serializer& ser) {
|
|||
ser.from_ptr(&use_strips);
|
||||
}
|
||||
|
||||
math::Vector3f vopmula(math::Vector3f a, math::Vector3f b) {
|
||||
return math::Vector3f(a.y() * b.z(), a.z() * b.x(), a.x() * b.y());
|
||||
}
|
||||
|
||||
math::Vector3f vopmsub(math::Vector3f acc, math::Vector3f a, math::Vector3f b) {
|
||||
return acc - vopmula(a, b);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Compute the normal transformation for a TIE from the TIE matrix.
|
||||
* Note that this isn't identical to the original game - we're missing the vf14 scaling factor
|
||||
* For now, I just set this to 1, then normalize in the shader. Though I think we could avoid
|
||||
* this by figuring out the value of vf14 here (I am just too lazy right now).
|
||||
*/
|
||||
std::array<math::Vector3f, 3> tie_normal_transform_v2(const std::array<math::Vector4f, 4>& m) {
|
||||
// let:
|
||||
// vf10, vf11, vf12, vf13 be the input matrix m
|
||||
std::array<math::Vector3f, 3> result;
|
||||
auto& vf10 = m[0];
|
||||
auto& vf11 = m[1];
|
||||
// auto& vf12 = m[2];
|
||||
|
||||
// vmulx.xyz vf16, vf10, vf14
|
||||
math::Vector3f vf16 = vf10.xyz() * 1.0; // TODO VF14
|
||||
|
||||
// vopmula.xyz acc, vf11, vf16
|
||||
math::Vector3f acc = vopmula(vf11.xyz(), vf16);
|
||||
|
||||
// vopmsub.xyz vf17, vf16, vf11
|
||||
math::Vector3f vf17 = vopmsub(acc, vf16, vf11.xyz());
|
||||
|
||||
// vopmula.xyz acc, vf16, vf17
|
||||
acc = vopmula(vf16, vf17);
|
||||
|
||||
// vopmsub.xyz vf17, vf17, vf16
|
||||
vf17 = vopmsub(acc, vf17, vf16);
|
||||
|
||||
// vmul.xyz vf14, vf17, vf17
|
||||
math::Vector3f vf14 = vf17.elementwise_multiply(vf17);
|
||||
|
||||
// vmulax.w acc, vf0, vf14
|
||||
// vmadday.w acc, vf0, vf14
|
||||
// vmaddz.w vf14, vf0, vf14
|
||||
float sum = vf14.x() + vf14.y() + vf14.z();
|
||||
|
||||
// vrsqrt Q, vf0.w, vf14.w
|
||||
float Q = 1.f / std::sqrt(sum);
|
||||
|
||||
// vmulax.xyzw acc, vf24, vf16
|
||||
// vmadday.xyzw acc, vf25, vf16
|
||||
// vmaddz.xyzw vf10, vf26, vf16
|
||||
// vf10 = vf16; // assume cam is identity here.
|
||||
result[0] = vf16;
|
||||
|
||||
// vwaitq
|
||||
// vmulq.xyz vf17, vf17, Q
|
||||
vf17 *= Q;
|
||||
|
||||
// vopmula.xyz acc, vf16, vf17
|
||||
acc = vopmula(vf16, vf17);
|
||||
// vopmsub.xyz vf18, vf17, vf16
|
||||
math::Vector3f vf18 = vopmsub(acc, vf17, vf16);
|
||||
|
||||
// vmulax.xyzw acc, vf24, vf17
|
||||
// vmadday.xyzw acc, vf25, vf17
|
||||
// vmaddz.xyzw vf11, vf26, vf17
|
||||
result[1] = vf17;
|
||||
|
||||
// vmulax.xyzw acc, vf24, vf18
|
||||
// vmadday.xyzw acc, vf25, vf18
|
||||
// vmaddz.xyzw vf12, vf26, vf18
|
||||
result[2] = vf18;
|
||||
return result;
|
||||
//
|
||||
// sqc2 vf10, -112(t8)
|
||||
// sqc2 vf11, -96(t8)
|
||||
// sqc2 vf12, -80(t8)
|
||||
}
|
||||
|
||||
/*!
|
||||
* Unpack tie normal by transforming and converting to s16 for OpenGL.
|
||||
*/
|
||||
math::Vector<s16, 3> unpack_tie_normal(const std::array<math::Vector3f, 3>& mat,
|
||||
s8 nx,
|
||||
s8 ny,
|
||||
s8 nz) {
|
||||
// rotate the normal
|
||||
math::Vector3f nrm = math::Vector3f::zero();
|
||||
nrm += mat[0] * nx;
|
||||
nrm += mat[1] * ny;
|
||||
nrm += mat[2] * nz;
|
||||
// convert to s16 for OpenGL renderer
|
||||
nrm *= 0.0078125; // number from EE asm
|
||||
nrm *= 256.f * 128.f; // for normalize s16 -> float conversion by OpenGL.
|
||||
|
||||
return nrm.cast<s16>();
|
||||
}
|
||||
|
||||
void TieTree::unpack() {
|
||||
unpacked.vertices.resize(packed_vertices.color_indices.size());
|
||||
size_t i = 0;
|
||||
|
@ -84,13 +182,21 @@ void TieTree::unpack() {
|
|||
vtx.x = proto_vtx.x;
|
||||
vtx.y = proto_vtx.y;
|
||||
vtx.z = proto_vtx.z;
|
||||
vtx.q_unused = 1.f;
|
||||
vtx.s = proto_vtx.s;
|
||||
vtx.t = proto_vtx.t;
|
||||
vtx.nx = proto_vtx.nx << 8;
|
||||
vtx.ny = proto_vtx.ny << 8;
|
||||
vtx.nz = proto_vtx.nz << 8;
|
||||
vtx.r = proto_vtx.r;
|
||||
vtx.g = proto_vtx.g;
|
||||
vtx.b = proto_vtx.b;
|
||||
vtx.a = proto_vtx.a;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
const auto& mat = packed_vertices.matrices[grp.matrix_idx];
|
||||
auto nmat = tie_normal_transform_v2(mat);
|
||||
|
||||
for (u32 src_idx = grp.start_vert; src_idx < grp.end_vert; src_idx++) {
|
||||
auto& vtx = unpacked.vertices[i];
|
||||
vtx.color_index = packed_vertices.color_indices[i];
|
||||
|
@ -99,9 +205,16 @@ void TieTree::unpack() {
|
|||
vtx.x = temp.x();
|
||||
vtx.y = temp.y();
|
||||
vtx.z = temp.z();
|
||||
vtx.q_unused = 1.f;
|
||||
vtx.s = proto_vtx.s;
|
||||
vtx.t = proto_vtx.t;
|
||||
auto nrm = unpack_tie_normal(nmat, proto_vtx.nx, proto_vtx.ny, proto_vtx.nz);
|
||||
vtx.nx = nrm.x();
|
||||
vtx.ny = nrm.y();
|
||||
vtx.nz = nrm.z();
|
||||
vtx.r = proto_vtx.r;
|
||||
vtx.g = proto_vtx.g;
|
||||
vtx.b = proto_vtx.b;
|
||||
vtx.a = proto_vtx.a;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +272,6 @@ void TfragTree::unpack() {
|
|||
o.z = cz + in.zoff * rescale;
|
||||
o.s = in.s / (1024.f);
|
||||
o.t = in.t / (1024.f);
|
||||
o.q_unused = 1.f;
|
||||
o.color_index = in.color_index;
|
||||
}
|
||||
|
||||
|
@ -188,6 +300,8 @@ void TieTree::serialize(Serializer& ser) {
|
|||
draw.serialize(ser);
|
||||
}
|
||||
|
||||
ser.from_ptr(&category_draw_indices);
|
||||
|
||||
if (ser.is_saving()) {
|
||||
ser.save<size_t>(instanced_wind_draws.size());
|
||||
} else {
|
||||
|
|
|
@ -73,17 +73,22 @@ struct MemoryUsageTracker {
|
|||
void add(MemoryUsageCategory category, u32 size_bytes) { data[category] += size_bytes; }
|
||||
};
|
||||
|
||||
constexpr int TFRAG3_VERSION = 27;
|
||||
constexpr int TFRAG3_VERSION = 28;
|
||||
|
||||
// These vertices should be uploaded to the GPU at load time and don't change
|
||||
struct PreloadedVertex {
|
||||
// the vertex position
|
||||
float x, y, z;
|
||||
float x = 0, y = 0, z = 0;
|
||||
// texture coordinates
|
||||
float s, t, q_unused;
|
||||
float s = 0, t = 0;
|
||||
|
||||
u8 r = 0, g = 0, b = 0, a = 0; // envmap tint color, not used in == or hash.
|
||||
|
||||
// color table index
|
||||
u16 color_index;
|
||||
u16 pad[3];
|
||||
u16 color_index = 0;
|
||||
|
||||
// not used in == or hash!!
|
||||
s16 nx = 0, ny = 0, nz = 0;
|
||||
|
||||
struct hash {
|
||||
std::size_t operator()(const PreloadedVertex& x) const;
|
||||
|
@ -100,6 +105,8 @@ struct PackedTieVertices {
|
|||
struct Vertex {
|
||||
float x, y, z;
|
||||
float s, t;
|
||||
s8 nx, ny, nz;
|
||||
u8 r, g, b, a;
|
||||
};
|
||||
|
||||
struct MatrixGroup {
|
||||
|
@ -313,10 +320,66 @@ struct TieWindInstance {
|
|||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
// Tie draws are split into categories.
|
||||
enum class TieCategory {
|
||||
// normal tie buckets
|
||||
NORMAL,
|
||||
TRANS, // also called alpha
|
||||
WATER,
|
||||
|
||||
// first draw (normal base draw) for envmapped stuff
|
||||
NORMAL_ENVMAP,
|
||||
TRANS_ENVMAP,
|
||||
WATER_ENVMAP,
|
||||
|
||||
// second draw (shiny) for envmapped ties.
|
||||
NORMAL_ENVMAP_SECOND_DRAW,
|
||||
TRANS_ENVMAP_SECOND_DRAW,
|
||||
WATER_ENVMAP_SECOND_DRAW,
|
||||
};
|
||||
constexpr int kNumTieCategories = 9;
|
||||
|
||||
constexpr bool is_envmap_first_draw_category(tfrag3::TieCategory category) {
|
||||
switch (category) {
|
||||
case tfrag3::TieCategory::NORMAL_ENVMAP:
|
||||
case tfrag3::TieCategory::WATER_ENVMAP:
|
||||
case tfrag3::TieCategory::TRANS_ENVMAP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool is_envmap_second_draw_category(tfrag3::TieCategory category) {
|
||||
switch (category) {
|
||||
case tfrag3::TieCategory::NORMAL_ENVMAP_SECOND_DRAW:
|
||||
case tfrag3::TieCategory::WATER_ENVMAP_SECOND_DRAW:
|
||||
case tfrag3::TieCategory::TRANS_ENVMAP_SECOND_DRAW:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr TieCategory get_second_draw_category(tfrag3::TieCategory category) {
|
||||
switch (category) {
|
||||
case TieCategory::NORMAL_ENVMAP:
|
||||
return TieCategory::NORMAL_ENVMAP_SECOND_DRAW;
|
||||
case TieCategory::TRANS_ENVMAP:
|
||||
return TieCategory::TRANS_ENVMAP_SECOND_DRAW;
|
||||
case TieCategory::WATER_ENVMAP:
|
||||
return TieCategory::WATER_ENVMAP_SECOND_DRAW;
|
||||
default:
|
||||
return TieCategory::NORMAL_ENVMAP;
|
||||
}
|
||||
}
|
||||
|
||||
// A tie model
|
||||
struct TieTree {
|
||||
BVH bvh;
|
||||
std::vector<StripDraw> static_draws; // the actual topology and settings
|
||||
std::vector<StripDraw> static_draws;
|
||||
// Category n uses draws: static_draws[cdi[n]] to static_draws[cdi[n + 1]]
|
||||
std::array<u32, kNumTieCategories + 1> category_draw_indices;
|
||||
|
||||
PackedTieVertices packed_vertices;
|
||||
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
|
||||
|
|
|
@ -225,6 +225,8 @@ VuDisassembler::VuDisassembler(VuKind kind) : m_kind(kind) {
|
|||
add_op(VuInstrK::SQRT, "sqrt").fsf_zero().ftf_0().vis_zero().dst_q().src_vft();
|
||||
add_op(VuInstrK::SQD, "sqd").dst_mask().src_vfs().src_vit();
|
||||
add_op(VuInstrK::ERLENG, "erleng").dst_mask().vft_zero().src_vfs().dst_p();
|
||||
add_op(VuInstrK::ESUM, "esum").dst_mask().vft_zero().src_vfs().dst_p();
|
||||
add_op(VuInstrK::ESADD, "esadd").dst_mask().vft_zero().src_vfs().dst_p();
|
||||
add_op(VuInstrK::ELENG, "eleng").dst_mask().vft_zero().src_vfs().dst_p();
|
||||
add_op(VuInstrK::MFP, "mfp").dst_mask().dst_vft().src_p();
|
||||
}
|
||||
|
@ -294,10 +296,14 @@ VuInstrK VuDisassembler::lower_kind(u32 in) {
|
|||
return VuInstrK::XTOP;
|
||||
case 0b11011'1111'00:
|
||||
return VuInstrK::XGKICK;
|
||||
case 0b11100'1111'00:
|
||||
return VuInstrK::ESADD;
|
||||
case 0b11100'1111'10:
|
||||
return VuInstrK::ELENG;
|
||||
case 0b11100'1111'11:
|
||||
return VuInstrK::ERLENG;
|
||||
case 0b11101'1111'10:
|
||||
return VuInstrK::ESUM;
|
||||
case 0b11110'1111'11:
|
||||
return VuInstrK::WAITP;
|
||||
}
|
||||
|
|
|
@ -126,13 +126,13 @@ enum class VuInstrK {
|
|||
JALR,
|
||||
MFP,
|
||||
WAITP,
|
||||
// ESADD,
|
||||
ESADD,
|
||||
// ERSADD,
|
||||
ELENG,
|
||||
ERLENG,
|
||||
// EATANxy,
|
||||
// EATANxz,
|
||||
// ESUM,
|
||||
ESUM,
|
||||
// ERCPR,
|
||||
// ESQRT,
|
||||
// ERSQRT,
|
||||
|
|
|
@ -24991,13 +24991,14 @@
|
|||
;; etie-vu1 ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
#|
|
||||
(deftype etie-consts (structure)
|
||||
((gifbufs qword :inline :offset-assert 0)
|
||||
(adgif qword :inline :offset-assert 16)
|
||||
(alpha qword :inline :offset-assert 32)
|
||||
(strgif qword :inline :offset-assert 48)
|
||||
(envgif qword :inline :offset-assert 64)
|
||||
;(adgif qword :inline :offset-assert 16)
|
||||
(adgif gs-gif-tag :inline :offset-assert 16)
|
||||
;;(alpha qword :inline :offset-assert 32)
|
||||
(alpah gs-adcmd :inline)
|
||||
(strgif gs-gif-tag :inline :offset-assert 48)
|
||||
(envgif gs-gif-tag :inline :offset-assert 64)
|
||||
(envmap adgif-shader :inline :offset-assert 80)
|
||||
(pers0 vector :inline :offset-assert 160)
|
||||
(pers1 vector :inline :offset-assert 176)
|
||||
|
@ -25006,27 +25007,24 @@
|
|||
:size-assert #xc0
|
||||
:flag-assert #x9000000c0
|
||||
)
|
||||
|#
|
||||
|
||||
#|
|
||||
(deftype etie-matrix (structure)
|
||||
((rmtx matrix :inline :offset-assert 0)
|
||||
(nmtx matrix3 :inline :offset-assert 64)
|
||||
(morph float :offset-assert 76)
|
||||
(fog float :offset-assert 92)
|
||||
(fade uint32 :offset-assert 108)
|
||||
(morph float :offset 76)
|
||||
(fog float :offset 92)
|
||||
(fade uint32 :offset 108)
|
||||
(tint qword :inline :offset-assert 112)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x80
|
||||
:flag-assert #x900000080
|
||||
)
|
||||
|#
|
||||
|
||||
;; (define-extern etie-vu1-block object)
|
||||
;; (define-extern etie-magic function)
|
||||
;; (define-extern etie-init-consts function)
|
||||
(define-extern etie-init-engine (function dma-buffer none))
|
||||
(define-extern etie-vu1-block vu-function)
|
||||
(define-extern etie-magic (function int int))
|
||||
(define-extern etie-init-consts (function etie-consts gs-alpha none))
|
||||
(define-extern etie-init-engine (function dma-buffer gs-alpha gs-test none))
|
||||
(define-extern etie-end-buffer (function dma-buffer none))
|
||||
;; (define-extern etie-float-reg-bp function)
|
||||
;; (define-extern etie-float-reg function)
|
||||
|
@ -25201,7 +25199,7 @@
|
|||
(define-extern draw-drawable-tree-instance-tie (function drawable-tree-instance-tie level none))
|
||||
(define-extern tie-init-scissor-buf (function bucket-id gs-alpha gs-test gs-test none))
|
||||
(define-extern tie-init-buf (function bucket-id gs-alpha gs-test gs-test none))
|
||||
(define-extern tie-init-envmap-buf (function bucket-id gs-alpha int int none))
|
||||
(define-extern tie-init-envmap-buf (function bucket-id gs-alpha gs-test none))
|
||||
(define-extern tie-init-envmap-scissor-buf (function bucket-id gs-alpha int int none))
|
||||
(define-extern *tie-init-table* (inline-array tie-init-data))
|
||||
(define-extern tie-vu1-init-buffers (function none))
|
||||
|
|
|
@ -11005,5 +11005,17 @@
|
|||
"(method 98 gun-buoy)": [
|
||||
[46, "v1", "collide-shape-moving"],
|
||||
[76, "v1", "collide-shape-moving"]
|
||||
],
|
||||
"etie-init-engine": [
|
||||
[[3, 10], "a0", "dma-packet"],
|
||||
[[12, 19], "a0", "gs-gif-tag"],
|
||||
[24, "a0", "(pointer gs-reg64)"],
|
||||
[[34, 48], "a0", "dma-packet"],
|
||||
[[58, 66], "a0", "dma-packet"],
|
||||
[[68, 75], "a0", "dma-packet"],
|
||||
[[79, 86], "a0", "(pointer uint32)"],
|
||||
[[87, 94], "a0", "(pointer vif-tag)"]
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ void TextureDB::add_texture(u32 tpage,
|
|||
u16 h,
|
||||
const std::string& tex_name,
|
||||
const std::string& tpage_name,
|
||||
const std::vector<std::string>& level_names) {
|
||||
const std::vector<std::string>& level_names,
|
||||
u32 num_mips) {
|
||||
auto existing_tpage_name = tpage_names.find(tpage);
|
||||
if (existing_tpage_name == tpage_names.end()) {
|
||||
tpage_names[tpage] = tpage_name;
|
||||
|
@ -32,6 +33,7 @@ void TextureDB::add_texture(u32 tpage,
|
|||
ASSERT(existing_tex->second.h == h);
|
||||
ASSERT(existing_tex->second.rgba_bytes == data);
|
||||
ASSERT(existing_tex->second.page == tpage);
|
||||
ASSERT(existing_tex->second.num_mips == num_mips);
|
||||
} else {
|
||||
auto& new_tex = textures[combo_id];
|
||||
new_tex.rgba_bytes = data;
|
||||
|
@ -39,6 +41,7 @@ void TextureDB::add_texture(u32 tpage,
|
|||
new_tex.w = w;
|
||||
new_tex.h = h;
|
||||
new_tex.page = tpage;
|
||||
new_tex.num_mips = num_mips;
|
||||
}
|
||||
for (const auto& level_name : level_names) {
|
||||
texture_ids_per_level[level_name].insert(combo_id);
|
||||
|
|
|
@ -15,6 +15,7 @@ struct TextureDB {
|
|||
std::string name;
|
||||
u32 page;
|
||||
std::vector<u32> rgba_bytes;
|
||||
u32 num_mips = -1;
|
||||
};
|
||||
|
||||
std::unordered_map<u32, TextureData> textures;
|
||||
|
@ -28,7 +29,8 @@ struct TextureDB {
|
|||
u16 h,
|
||||
const std::string& tex_name,
|
||||
const std::string& tpage_name,
|
||||
const std::vector<std::string>& level_names);
|
||||
const std::vector<std::string>& level_names,
|
||||
u32 num_mips);
|
||||
|
||||
void replace_textures(const fs::path& path);
|
||||
};
|
||||
|
|
|
@ -537,7 +537,7 @@ TPageResultStats process_tpage(ObjectFileData& data,
|
|||
file_util::write_rgba_png(texture_dump_dir / fmt::format("{}.png", tex.name), out.data(),
|
||||
tex.w, tex.h);
|
||||
texture_db.add_texture(texture_page.id, tex_id, out, tex.w, tex.h, tex.name,
|
||||
texture_page.name, level_names);
|
||||
texture_page.name, level_names, tex.num_mips);
|
||||
stats.successful_textures++;
|
||||
} else if (tex.psm == int(PSM::PSMT8) && tex.clutpsm == int(CPSM::PSMCT16)) {
|
||||
// will store output pixels, rgba (8888)
|
||||
|
@ -580,7 +580,7 @@ TPageResultStats process_tpage(ObjectFileData& data,
|
|||
file_util::write_rgba_png(texture_dump_dir / fmt::format("{}.png", tex.name), out.data(),
|
||||
tex.w, tex.h);
|
||||
texture_db.add_texture(texture_page.id, tex_id, out, tex.w, tex.h, tex.name,
|
||||
texture_page.name, level_names);
|
||||
texture_page.name, level_names, tex.num_mips);
|
||||
stats.successful_textures++;
|
||||
} else if (tex.psm == int(PSM::PSMCT16) && tex.clutpsm == 0) {
|
||||
// not a clut.
|
||||
|
@ -605,7 +605,7 @@ TPageResultStats process_tpage(ObjectFileData& data,
|
|||
file_util::write_rgba_png(texture_dump_dir / fmt::format("{}.png", tex.name), out.data(),
|
||||
tex.w, tex.h);
|
||||
texture_db.add_texture(texture_page.id, tex_id, out, tex.w, tex.h, tex.name,
|
||||
texture_page.name, level_names);
|
||||
texture_page.name, level_names, tex.num_mips);
|
||||
stats.successful_textures++;
|
||||
} else if (tex.psm == int(PSM::PSMT4) && tex.clutpsm == int(CPSM::PSMCT16)) {
|
||||
// will store output pixels, rgba (8888)
|
||||
|
@ -646,7 +646,7 @@ TPageResultStats process_tpage(ObjectFileData& data,
|
|||
file_util::write_rgba_png(texture_dump_dir / fmt::format("{}.png", tex.name), out.data(),
|
||||
tex.w, tex.h);
|
||||
texture_db.add_texture(texture_page.id, tex_id, out, tex.w, tex.h, tex.name,
|
||||
texture_page.name, level_names);
|
||||
texture_page.name, level_names, tex.num_mips);
|
||||
stats.successful_textures++;
|
||||
} else if (tex.psm == int(PSM::PSMT4) && tex.clutpsm == int(CPSM::PSMCT32)) {
|
||||
// will store output pixels, rgba (8888)
|
||||
|
@ -687,7 +687,7 @@ TPageResultStats process_tpage(ObjectFileData& data,
|
|||
file_util::write_rgba_png(texture_dump_dir / fmt::format("{}.png", tex.name), out.data(),
|
||||
tex.w, tex.h);
|
||||
texture_db.add_texture(texture_page.id, tex_id, out, tex.w, tex.h, tex.name,
|
||||
texture_page.name, level_names);
|
||||
texture_page.name, level_names, tex.num_mips);
|
||||
stats.successful_textures++;
|
||||
} else if (tex.psm == int(PSM::PSMCT32) && tex.clutpsm == 0) {
|
||||
// not a clut.
|
||||
|
@ -712,7 +712,7 @@ TPageResultStats process_tpage(ObjectFileData& data,
|
|||
file_util::write_rgba_png(texture_dump_dir / fmt::format("{}.png", tex.name), out.data(),
|
||||
tex.w, tex.h);
|
||||
texture_db.add_texture(texture_page.id, tex_id, out, tex.w, tex.h, tex.name,
|
||||
texture_page.name, level_names);
|
||||
texture_page.name, level_names, tex.num_mips);
|
||||
stats.successful_textures++;
|
||||
}
|
||||
|
||||
|
|
|
@ -445,6 +445,15 @@ std::string TFragment::print(const PrintSettings& settings, int indent) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void memcpy_plain_data(u8* dst, const Ref& ref, size_t size_bytes) {
|
||||
const auto& words = ref.data->words_by_seg.at(ref.seg);
|
||||
for (size_t i = 0; i < size_bytes; i++) {
|
||||
size_t byte_offset = ref.byte_offset + i;
|
||||
u8 byte = words.at(byte_offset / 4).get_byte(byte_offset % 4);
|
||||
memcpy(dst + i, &byte, sizeof(u8));
|
||||
}
|
||||
}
|
||||
|
||||
void TieFragment::read_from_file(TypedRef ref,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
DrawStats* stats,
|
||||
|
@ -492,6 +501,15 @@ void TieFragment::read_from_file(TypedRef ref,
|
|||
}
|
||||
|
||||
stats->total_tie_prototype_tris += num_tris;
|
||||
|
||||
if (version > GameVersion::Jak1) {
|
||||
u16 normals_qwc = read_plain_data_field<u16>(ref, "normal-count", dts);
|
||||
if (normals_qwc) {
|
||||
normals.resize(16 * normals_qwc);
|
||||
auto normals_data_ref = deref_label(get_field_ref(ref, "normal-ref", dts));
|
||||
memcpy_plain_data((u8*)normals.data(), normals_data_ref, normals_qwc * 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string TieFragment::print(const PrintSettings& /*settings*/, int indent) const {
|
||||
|
@ -1037,6 +1055,24 @@ void PrototypeBucketTie::read_from_file(TypedRef ref,
|
|||
for (int i = 0; i < int(8 * time_of_day.height); i++) {
|
||||
time_of_day.colors.push_back(deref_u32(palette, 3 + i));
|
||||
}
|
||||
|
||||
if (version > GameVersion::Jak1) {
|
||||
auto fr = get_field_ref(ref, "envmap-shader", dts);
|
||||
const auto& word = fr.data->words_by_seg.at(fr.seg).at(fr.byte_offset / 4);
|
||||
if (word.kind() == decompiler::LinkedWord::PTR) {
|
||||
has_envmap_shader = true;
|
||||
Ref envmap_shader_ref(deref_label(fr));
|
||||
for (int i = 0; i < 5 * 16; i++) {
|
||||
int byte = envmap_shader_ref.byte_offset + i;
|
||||
u8 val =
|
||||
ref.ref.data->words_by_seg.at(envmap_shader_ref.seg).at(byte / 4).get_byte(byte % 4);
|
||||
envmap_shader[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
u32 tint = read_plain_data_field<u32>(ref, "tint-color", dts);
|
||||
memcpy(tint_color.data(), &tint, 4);
|
||||
}
|
||||
}
|
||||
|
||||
std::string PrototypeBucketTie::print(const PrintSettings& settings, int indent) const {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/math/Vector.h"
|
||||
#include "common/versions.h"
|
||||
|
||||
#include "decompiler/level_extractor/common_formats.h"
|
||||
|
@ -406,6 +407,8 @@ struct TieFragment : public Drawable {
|
|||
|
||||
std::string debug_label_name;
|
||||
|
||||
std::vector<s8> normals;
|
||||
|
||||
// todo, lots more
|
||||
};
|
||||
|
||||
|
@ -479,7 +482,9 @@ struct PrototypeBucketTie {
|
|||
|
||||
TimeOfDayPalette time_of_day;
|
||||
|
||||
// todo envmap shader
|
||||
bool has_envmap_shader = false;
|
||||
u8 envmap_shader[5 * 16]; // jak 2 only
|
||||
math::Vector<u8, 4> tint_color;
|
||||
// todo collide-frag
|
||||
DrawableInlineArrayCollideFragment collide_frag;
|
||||
// todo tie-colors
|
||||
|
|
|
@ -2070,9 +2070,8 @@ void make_tfrag3_data(std::map<u32, std::vector<GroupedDraw>>& draws,
|
|||
vtx.z = vert.pre_cam_trans_pos.z();
|
||||
vtx.s = vert.stq.x();
|
||||
vtx.t = vert.stq.y();
|
||||
vtx.q_unused = vert.stq.z();
|
||||
// if this is true, we can remove a divide in the shader
|
||||
ASSERT(vtx.q_unused == 1.f);
|
||||
// because this is true, we can remove a divide in the shader
|
||||
ASSERT(vert.stq.z() == 1.f);
|
||||
vtx.color_index = vert.rgba / 4;
|
||||
// ASSERT((vert.rgba >> 2) < 1024); spider cave has 2048?
|
||||
ASSERT((vert.rgba & 3) == 0);
|
||||
|
|
File diff suppressed because it is too large
Load diff
2520
docs/progress-notes/jak2/etie.md
Normal file
2520
docs/progress-notes/jak2/etie.md
Normal file
File diff suppressed because it is too large
Load diff
|
@ -48,7 +48,15 @@ struct SharedRenderState {
|
|||
LevelVis occlusion_vis[6];
|
||||
|
||||
math::Vector4f camera_planes[4];
|
||||
|
||||
// including transformation, rotation, perspective
|
||||
math::Vector4f camera_matrix[4];
|
||||
|
||||
// including transformation, rotation
|
||||
math::Vector4f camera_no_persp[4];
|
||||
|
||||
// just the perspective
|
||||
math::Vector4f camera_persp[4];
|
||||
math::Vector4f camera_hvdf_off;
|
||||
math::Vector4f camera_fog;
|
||||
math::Vector4f camera_pos;
|
||||
|
@ -78,6 +86,7 @@ struct SharedRenderState {
|
|||
int bucket_for_vis_copy = 0;
|
||||
int num_vis_to_copy = 0;
|
||||
GameVersion version;
|
||||
u64 frame_idx = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -99,7 +99,7 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
init_bucket_renderer<OceanMidAndFar>("ocean-mid-far", BucketCategory::OCEAN,
|
||||
BucketId::OCEAN_MID_FAR);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
#define GET_BUCKET_ID_FOR_LIST(bkt1, bkt2, idx) ((int)bkt1 + ((int)bkt2 - (int)bkt1) * idx)
|
||||
#define GET_BUCKET_ID_FOR_LIST(bkt1, bkt2, idx) ((int)(bkt1) + ((int)(bkt2) - (int)(bkt1)) * (idx))
|
||||
init_bucket_renderer<TextureUploadHandler>(
|
||||
fmt::format("tex-l{}-tfrag", i), BucketCategory::TEX,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TEX_L0_TFRAG, BucketId::TEX_L1_TFRAG, i));
|
||||
|
@ -107,9 +107,13 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
fmt::format("tfrag-l{}-tfrag", i), BucketCategory::TFRAG,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TFRAG_L0_TFRAG, BucketId::TFRAG_L1_TFRAG, i),
|
||||
std::vector{tfrag3::TFragmentTreeKind::NORMAL}, false, i);
|
||||
init_bucket_renderer<Tie3>(
|
||||
Tie3* tie = init_bucket_renderer<Tie3>(
|
||||
fmt::format("tie-l{}-tfrag", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TIE_L0_TFRAG, BucketId::TIE_L1_TFRAG, i), i);
|
||||
init_bucket_renderer<Tie3AnotherCategory>(
|
||||
fmt::format("etie-l{}-tfrag", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_L0_TFRAG, BucketId::ETIE_L1_TFRAG, i), tie,
|
||||
tfrag3::TieCategory::NORMAL_ENVMAP);
|
||||
init_bucket_renderer<Merc2>(
|
||||
fmt::format("merc-l{}-tfrag", i), BucketCategory::MERC,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::MERC_L0_TFRAG, BucketId::MERC_L1_TFRAG, i));
|
||||
|
@ -131,6 +135,14 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
fmt::format("tfrag-t-l{}-alpha", i), BucketCategory::TFRAG,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TFRAG_T_L0_ALPHA, BucketId::TFRAG_T_L1_ALPHA, i),
|
||||
std::vector{tfrag3::TFragmentTreeKind::TRANS}, false, i);
|
||||
init_bucket_renderer<Tie3AnotherCategory>(
|
||||
fmt::format("tie-t-l{}-alpha", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TIE_T_L0_ALPHA, BucketId::TIE_T_L1_ALPHA, i), tie,
|
||||
tfrag3::TieCategory::TRANS);
|
||||
init_bucket_renderer<Tie3AnotherCategory>(
|
||||
fmt::format("etie-t-l{}-alpha", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_T_L0_ALPHA, BucketId::ETIE_T_L1_ALPHA, i), tie,
|
||||
tfrag3::TieCategory::TRANS_ENVMAP);
|
||||
|
||||
init_bucket_renderer<TextureUploadHandler>(
|
||||
fmt::format("tex-l{}-pris", i), BucketCategory::TEX,
|
||||
|
@ -156,6 +168,14 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
|
|||
fmt::format("tfrag-w-l{}-alpha", i), BucketCategory::TFRAG,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TFRAG_W_L0_WATER, BucketId::TFRAG_W_L1_WATER, i),
|
||||
std::vector{tfrag3::TFragmentTreeKind::WATER}, false, i);
|
||||
init_bucket_renderer<Tie3AnotherCategory>(
|
||||
fmt::format("tie-w-l{}-water", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::TIE_W_L0_WATER, BucketId::TIE_W_L1_WATER, i), tie,
|
||||
tfrag3::TieCategory::WATER);
|
||||
init_bucket_renderer<Tie3AnotherCategory>(
|
||||
fmt::format("etie-w-l{}-water", i), BucketCategory::TIE,
|
||||
GET_BUCKET_ID_FOR_LIST(BucketId::ETIE_W_L0_WATER, BucketId::ETIE_W_L1_WATER, i), tie,
|
||||
tfrag3::TieCategory::WATER_ENVMAP);
|
||||
#undef GET_BUCKET_ID_FOR_LIST
|
||||
}
|
||||
// 180
|
||||
|
@ -911,6 +931,7 @@ void OpenGLRenderer::dispatch_buckets(DmaFollower dma,
|
|||
ScopedProfilerNode& prof,
|
||||
bool sync_after_buckets) {
|
||||
m_render_state.version = m_version;
|
||||
m_render_state.frame_idx++;
|
||||
switch (m_version) {
|
||||
case GameVersion::Jak1:
|
||||
dispatch_buckets_jak1(dma, prof, sync_after_buckets);
|
||||
|
|
|
@ -104,6 +104,8 @@ ShaderLibrary::ShaderLibrary(GameVersion version) {
|
|||
at(ShaderId::GLOW_PROBE_READ_DEBUG) = {"glow_probe_read_debug", version};
|
||||
at(ShaderId::GLOW_PROBE_DOWNSAMPLE) = {"glow_probe_downsample", version};
|
||||
at(ShaderId::GLOW_DRAW) = {"glow_draw", version};
|
||||
at(ShaderId::ETIE_BASE) = {"etie_base", version};
|
||||
at(ShaderId::ETIE) = {"etie", version};
|
||||
|
||||
for (auto& shader : m_shaders) {
|
||||
ASSERT_MSG(shader.okay(), "error compiling shader");
|
||||
|
|
|
@ -54,6 +54,8 @@ enum class ShaderId {
|
|||
GLOW_PROBE_READ_DEBUG = 27,
|
||||
GLOW_PROBE_DOWNSAMPLE = 28,
|
||||
GLOW_DRAW = 29,
|
||||
ETIE_BASE = 30,
|
||||
ETIE = 31,
|
||||
MAX_SHADERS
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,27 +19,58 @@ struct TieProtoVisibility {
|
|||
bool all_visible = true;
|
||||
};
|
||||
|
||||
struct EtieUniforms {
|
||||
GLuint persp0, persp1, cam_no_persp, envmap_tod_tint, decal;
|
||||
};
|
||||
|
||||
class Tie3 : public BucketRenderer {
|
||||
public:
|
||||
Tie3(const std::string& name, int my_id, int level_id);
|
||||
// by default, only render the specified category on the call to render.
|
||||
// to render the other categories, use the Tie3AnotherCategory renderer below.
|
||||
Tie3(const std::string& name,
|
||||
int my_id,
|
||||
int level_id,
|
||||
tfrag3::TieCategory category = tfrag3::TieCategory::NORMAL);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
void init_shaders(ShaderLibrary& shaders) override;
|
||||
~Tie3();
|
||||
|
||||
void render_all_trees(int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size);
|
||||
void render_tree(int idx,
|
||||
int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size);
|
||||
bool setup_for_level(const std::string& str, SharedRenderState* render_state);
|
||||
bool set_up_common_data_from_dma(DmaFollower& dma, SharedRenderState* render_state);
|
||||
|
||||
void setup_all_trees(int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size,
|
||||
bool use_multidraw,
|
||||
ScopedProfilerNode& prof);
|
||||
|
||||
void setup_tree(int idx,
|
||||
int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
const u8* proto_vis_data,
|
||||
size_t proto_vis_data_size,
|
||||
bool use_multidraw,
|
||||
ScopedProfilerNode& prof);
|
||||
|
||||
void draw_matching_draws_for_all_trees(int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
tfrag3::TieCategory category);
|
||||
|
||||
void draw_matching_draws_for_tree(int idx,
|
||||
int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
tfrag3::TieCategory category);
|
||||
|
||||
bool try_loading_level(const std::string& str, SharedRenderState* render_state);
|
||||
|
||||
void render_from_another(SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
tfrag3::TieCategory category);
|
||||
|
||||
struct WindWork {
|
||||
u32 paused;
|
||||
|
@ -55,7 +86,7 @@ class Tie3 : public BucketRenderer {
|
|||
int lod() const { return Gfx::g_global_settings.lod_tie; }
|
||||
|
||||
private:
|
||||
void update_load(const LevelData* loader_data);
|
||||
void load_from_fr3_data(const LevelData* loader_data);
|
||||
void discard_tree_cache();
|
||||
void render_tree_wind(int idx,
|
||||
int geom,
|
||||
|
@ -63,13 +94,22 @@ class Tie3 : public BucketRenderer {
|
|||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof);
|
||||
|
||||
struct CommonData {
|
||||
// data that the AnotherCategory renderers can use.
|
||||
TfragRenderSettings settings;
|
||||
const u8* proto_vis_data = nullptr;
|
||||
u32 proto_vis_data_size = 0;
|
||||
math::Vector4f envmap_color;
|
||||
u64 frame_idx = -1;
|
||||
} m_common_data;
|
||||
|
||||
struct Tree {
|
||||
GLuint vertex_buffer;
|
||||
GLuint index_buffer;
|
||||
GLuint single_draw_index_buffer;
|
||||
GLuint time_of_day_texture;
|
||||
GLuint vao;
|
||||
u32 vert_count;
|
||||
std::array<u32, tfrag3::kNumTieCategories + 1> category_draw_indices;
|
||||
const std::vector<tfrag3::StripDraw>* draws = nullptr;
|
||||
const std::vector<tfrag3::InstancedStripDraw>* wind_draws = nullptr;
|
||||
const std::vector<tfrag3::TieWindInstance>* instance_info = nullptr;
|
||||
|
@ -77,56 +117,39 @@ class Tie3 : public BucketRenderer {
|
|||
const tfrag3::BVH* vis = nullptr;
|
||||
const u32* index_data = nullptr;
|
||||
SwizzledTimeOfDay tod_cache;
|
||||
|
||||
std::vector<std::array<math::Vector4f, 4>> wind_matrix_cache;
|
||||
|
||||
bool has_wind = false;
|
||||
GLuint wind_vertex_index_buffer;
|
||||
std::vector<u32> wind_vertex_index_offsets;
|
||||
|
||||
bool has_proto_visibility = false;
|
||||
TieProtoVisibility proto_visibility;
|
||||
|
||||
struct {
|
||||
u32 draws = 0;
|
||||
u32 wind_draws = 0;
|
||||
Filtered<float> cull_time;
|
||||
Filtered<float> index_time;
|
||||
Filtered<float> tod_time;
|
||||
Filtered<float> proto_vis_time;
|
||||
Filtered<float> setup_time;
|
||||
Filtered<float> draw_time;
|
||||
Filtered<float> tree_time;
|
||||
} perf;
|
||||
};
|
||||
|
||||
std::array<std::vector<Tree>, 4> m_trees; // includes 4 lods!
|
||||
std::string m_level_name;
|
||||
const std::vector<GLuint>* m_textures;
|
||||
u64 m_load_id = -1;
|
||||
|
||||
struct Cache {
|
||||
std::vector<std::pair<int, int>> draw_idx_temp;
|
||||
std::vector<u32> index_temp;
|
||||
std::vector<u8> vis_temp;
|
||||
std::vector<std::pair<int, int>> multidraw_offset_per_stripdraw;
|
||||
std::vector<GLsizei> multidraw_count_buffer;
|
||||
std::vector<void*> multidraw_index_offset_buffer;
|
||||
} m_cache;
|
||||
};
|
||||
|
||||
void envmap_second_pass_draw(const Tree& tree,
|
||||
const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof,
|
||||
tfrag3::TieCategory category);
|
||||
|
||||
std::array<std::vector<Tree>, 4> m_trees; // includes 4 lods!
|
||||
std::string m_level_name;
|
||||
const std::vector<GLuint>* m_textures;
|
||||
u64 m_load_id = -1;
|
||||
|
||||
std::vector<math::Vector<u8, 4>> m_color_result;
|
||||
|
||||
static constexpr int TIME_OF_DAY_COLOR_COUNT = 8192;
|
||||
|
||||
bool m_has_level = false;
|
||||
char m_user_level[255] = "vi1";
|
||||
std::optional<std::string> m_pending_user_level = std::nullopt;
|
||||
bool m_override_level = false;
|
||||
bool m_use_fast_time_of_day = true;
|
||||
bool m_debug_wireframe = false;
|
||||
bool m_debug_all_visible = false;
|
||||
bool m_hide_wind = false;
|
||||
Filtered<float> m_all_tree_time;
|
||||
|
||||
TfragPcPortData m_pc_port_data;
|
||||
|
||||
|
@ -136,5 +159,27 @@ class Tie3 : public BucketRenderer {
|
|||
|
||||
int m_level_id;
|
||||
|
||||
tfrag3::TieCategory m_default_category;
|
||||
|
||||
struct {
|
||||
GLuint decal;
|
||||
} m_uniforms;
|
||||
|
||||
EtieUniforms m_etie_uniforms, m_etie_base_uniforms;
|
||||
|
||||
static_assert(sizeof(WindWork) == 84 * 16);
|
||||
};
|
||||
|
||||
class Tie3AnotherCategory : public BucketRenderer {
|
||||
public:
|
||||
Tie3AnotherCategory(const std::string& name,
|
||||
int my_id,
|
||||
Tie3* parent,
|
||||
tfrag3::TieCategory category);
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
|
||||
void draw_debug_window() override;
|
||||
|
||||
private:
|
||||
Tie3* m_parent;
|
||||
tfrag3::TieCategory m_category;
|
||||
};
|
|
@ -36,9 +36,14 @@ DoubleDraw setup_opengl_from_draw_mode(DrawMode mode, u32 tex_unit, bool mipmap)
|
|||
|
||||
DoubleDraw double_draw;
|
||||
|
||||
bool should_enable_blend = false;
|
||||
if (mode.get_ab_enable() && mode.get_alpha_blend() != DrawMode::AlphaBlend::DISABLED) {
|
||||
glEnable(GL_BLEND);
|
||||
should_enable_blend = true;
|
||||
switch (mode.get_alpha_blend()) {
|
||||
case DrawMode::AlphaBlend::SRC_SRC_SRC_SRC:
|
||||
should_enable_blend = false;
|
||||
// (SRC - SRC) * alpha + SRC = SRC, no blend.
|
||||
break;
|
||||
case DrawMode::AlphaBlend::SRC_DST_SRC_DST:
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||
|
@ -71,6 +76,12 @@ DoubleDraw setup_opengl_from_draw_mode(DrawMode mode, u32 tex_unit, bool mipmap)
|
|||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
} else {
|
||||
should_enable_blend = false;
|
||||
}
|
||||
|
||||
if (should_enable_blend) {
|
||||
glEnable(GL_BLEND);
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
@ -159,6 +170,8 @@ void first_tfrag_draw_setup(const TfragRenderSettings& settings,
|
|||
sh.activate();
|
||||
auto id = sh.id();
|
||||
glUniform1i(glGetUniformLocation(id, "gfx_hack_no_tex"), Gfx::g_global_settings.hack_no_tex);
|
||||
glUniform1i(glGetUniformLocation(id, "decal"), false);
|
||||
|
||||
glUniform1i(glGetUniformLocation(id, "tex_T0"), 0);
|
||||
glUniformMatrix4fv(glGetUniformLocation(id, "camera"), 1, GL_FALSE, settings.math_camera.data());
|
||||
glUniform4f(glGetUniformLocation(id, "hvdf_offset"), settings.hvdf_offset[0],
|
||||
|
@ -752,6 +765,8 @@ void update_render_state_from_pc_settings(SharedRenderState* state, const TfragP
|
|||
for (int i = 0; i < 4; i++) {
|
||||
state->camera_planes[i] = data.planes[i];
|
||||
state->camera_matrix[i] = data.camera[i];
|
||||
state->camera_no_persp[i] = data.camera_rot[i];
|
||||
state->camera_persp[i] = data.camera_perspective[i];
|
||||
}
|
||||
state->camera_pos = data.cam_trans;
|
||||
state->camera_hvdf_off = data.hvdf_off;
|
||||
|
|
|
@ -13,8 +13,13 @@ struct TfragPcPortData {
|
|||
math::Vector4f hvdf_off;
|
||||
math::Vector4f fog;
|
||||
math::Vector4f cam_trans;
|
||||
|
||||
math::Vector4f camera_rot[4];
|
||||
math::Vector4f camera_perspective[4];
|
||||
|
||||
char level_name[16];
|
||||
};
|
||||
static_assert(sizeof(TfragPcPortData) == 16 * 24);
|
||||
|
||||
// inputs to background renderers.
|
||||
struct TfragRenderSettings {
|
||||
|
|
|
@ -104,9 +104,7 @@ void main() {
|
|||
|
||||
// this is required to make jak 1's envmapping look right
|
||||
// otherwise it behaves like the envmap texture is mirrored.
|
||||
// TODO: see if this is right for jak 2 or not.
|
||||
// It _might_ make sense that this exists because we skip the multiply by Q
|
||||
// below, and Q is negative (no idea how that works out with clamp).
|
||||
// this is because we flip vtx_pos above with a negative sign.
|
||||
st_mod.x = 1 - vf10.x;
|
||||
st_mod.y = 1 - vf10.y;
|
||||
|
||||
|
|
31
game/graphics/opengl_renderer/shaders/etie.frag
Normal file
31
game/graphics/opengl_renderer/shaders/etie.frag
Normal file
|
@ -0,0 +1,31 @@
|
|||
#version 430 core
|
||||
|
||||
out vec4 color;
|
||||
|
||||
in vec4 fragment_color;
|
||||
in vec3 tex_coord;
|
||||
in float fogginess;
|
||||
uniform sampler2D tex_T0;
|
||||
|
||||
uniform float alpha_min;
|
||||
uniform float alpha_max;
|
||||
uniform vec4 fog_color;
|
||||
|
||||
uniform int gfx_hack_no_tex;
|
||||
|
||||
|
||||
void main() {
|
||||
if (gfx_hack_no_tex == 0) {
|
||||
//vec4 T0 = texture(tex_T0, tex_coord);
|
||||
vec4 T0 = texture(tex_T0, tex_coord.xy);
|
||||
color = fragment_color * T0;
|
||||
} else {
|
||||
color = fragment_color/2;
|
||||
}
|
||||
|
||||
if (color.a < alpha_min || color.a > alpha_max) {
|
||||
discard;
|
||||
}
|
||||
|
||||
color.rgb = mix(color.rgb, fog_color.rgb, clamp(fogginess * fog_color.a, 0, 1));
|
||||
}
|
165
game/graphics/opengl_renderer/shaders/etie.vert
Normal file
165
game/graphics/opengl_renderer/shaders/etie.vert
Normal file
|
@ -0,0 +1,165 @@
|
|||
#version 430 core
|
||||
|
||||
layout (location = 0) in vec3 position_in;
|
||||
layout (location = 1) in vec3 tex_coord_in;
|
||||
layout (location = 2) in int time_of_day_index;
|
||||
layout (location = 3) in vec3 normal;
|
||||
layout (location = 4) in vec4 proto_tint;
|
||||
|
||||
uniform vec4 hvdf_offset;
|
||||
uniform mat4 camera;
|
||||
uniform float fog_constant;
|
||||
uniform float fog_min;
|
||||
uniform float fog_max;
|
||||
uniform vec4 envmap_tod_tint;
|
||||
layout (binding = 10) uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose.
|
||||
uniform int decal;
|
||||
|
||||
out vec4 fragment_color;
|
||||
out vec3 tex_coord;
|
||||
out float fogginess;
|
||||
|
||||
// etie stuff
|
||||
uniform vec4 persp0;
|
||||
uniform vec4 persp1;
|
||||
uniform mat4 cam_no_persp;
|
||||
|
||||
void main() {
|
||||
|
||||
// maybe we could do fog faster using intermediate results from below, but it doesn't seem significant.
|
||||
float fog1 = camera[3].w + camera[0].w * position_in.x + camera[1].w * position_in.y + camera[2].w * position_in.z;
|
||||
fogginess = 255 - clamp(fog1 + hvdf_offset.w, fog_min, fog_max);
|
||||
|
||||
// rotate the normal
|
||||
vec3 nrm_vf23 = cam_no_persp[0].xyz * normal.x
|
||||
+ cam_no_persp[1].xyz * normal.y
|
||||
+ cam_no_persp[2].xyz * normal.z;
|
||||
vec3 r_nrm = nrm_vf23;
|
||||
|
||||
// transform the point
|
||||
vec4 vf17 = cam_no_persp[3];
|
||||
vf17 += cam_no_persp[0] * position_in.x;
|
||||
vf17 += cam_no_persp[1] * position_in.y;
|
||||
vf17 += cam_no_persp[2] * position_in.z;
|
||||
|
||||
/*
|
||||
// This is the ETIE math.
|
||||
// It seems right only if the nrm_vf23 is normalized first
|
||||
// (and in this case it's identical the emerc math below)
|
||||
// There is no reason to prefer the emerc version over etie - they are identical.
|
||||
// likely on PS2, their normal transformation matrix was scaled correctly.
|
||||
// ours isn't. (yes, the camera matrix is a pure rotation and that doesn't matter, but the
|
||||
// instance matrix used to de-instance the mesh needs the correction, and we don't have it)
|
||||
if (use_emerc_math == 0) {
|
||||
nrm_vf23 = nrm_vf23;
|
||||
// nrm.z -= 1
|
||||
//subw.z vf23, vf23, vf00
|
||||
nrm_vf23.z -= 1.f;
|
||||
|
||||
// dot = nrm.xyz * pt.xyz
|
||||
//mul.xyz vf13, vf17, vf23
|
||||
//esum.xyzw P, vf13
|
||||
//mfp.x vf13, P
|
||||
float nrm_dot = dot(vf17.xyz, nrm_vf23);
|
||||
|
||||
// rfl = pt.xzy * nrm.z
|
||||
//mulz.xyz vf14, vf17, vf23
|
||||
vec3 rfl_vf14 = vf17.xyz * nrm_vf23.z;
|
||||
|
||||
//;; Q_envmap = vf02.w / norm(rfl.xyz)
|
||||
//esadd.xyz P, vf14
|
||||
//mfp.x vf30, P
|
||||
//rsqrt Q, vf02.w, vf30.x
|
||||
float Q_envmap = -0.5 / length(rfl_vf14);
|
||||
|
||||
//
|
||||
//;; nrm.xy *= dot.x
|
||||
//mulx.xy vf23, vf23, vf13
|
||||
nrm_vf23.xy *= nrm_dot;
|
||||
|
||||
//
|
||||
//;; nrm.xy += rfl.xy
|
||||
//add.xy vf23, vf23, vf14
|
||||
nrm_vf23.xy += rfl_vf14.xy;
|
||||
//
|
||||
//;; nrm.z = 1.0
|
||||
//addw.z vf23, vf00, vf00
|
||||
nrm_vf23.z = 1.0;
|
||||
//
|
||||
//;; nrm.xy *= Q_envmap
|
||||
//mul.xy vf23, vf23, Q
|
||||
nrm_vf23.xy *= Q_envmap;
|
||||
//
|
||||
|
||||
//
|
||||
//;; nrm.xy += vf03.w
|
||||
//addw.xy vf23, vf23, vf03
|
||||
nrm_vf23.xy += 0.5;
|
||||
tex_coord = nrm_vf23;
|
||||
}*/
|
||||
|
||||
//;; perspective transform
|
||||
//mula.xy ACC, vf10, vf17 ;; acc build 1
|
||||
//mulaw.zw ACC, vf10, vf00 ;; acc build 2
|
||||
vec4 p_proj = vec4(persp1.x * vf17.x, persp1.y * vf17.y, persp1.z, persp1.w);
|
||||
|
||||
//maddz.xyzw vf18, vf09, vf17 ;; acc star
|
||||
p_proj += persp0 * vf17.z;
|
||||
|
||||
//;; perspective divide
|
||||
//div Q, vf00.w, vf18.w
|
||||
float pQ = 1.f / p_proj.w;
|
||||
|
||||
// EMERC version of the math
|
||||
{
|
||||
// emerc hack
|
||||
vec3 vf10 = normalize(r_nrm);
|
||||
//subw.z vf10, vf10, vf00 ;; subtract 1 from z
|
||||
vf10.z -= 1;
|
||||
//addw.z vf09, vf00, vf09 ;; xyww the unperspected thing
|
||||
vec4 vf09 = vf17;
|
||||
//mul.xyz vf15, vf09, vf10 ;;
|
||||
vec3 vf15 = vf09.xyz * vf10.xyz;
|
||||
//adday.xyzw vf15, vf15
|
||||
//maddz.x vf15, vf21, vf15
|
||||
float vf15_x = vf15.x + vf15.y + vf15.z;
|
||||
//div Q, vf15.x, vf10.z
|
||||
float qq = vf15_x / vf10.z;
|
||||
//mulaw.xyzw ACC, vf09, vf00
|
||||
vec3 ACC = vf09.xyz;
|
||||
//madd.xyzw vf10, vf10, Q
|
||||
vf10 = ACC + vf10 * qq;
|
||||
//eleng.xyz P, vf10
|
||||
float P = length(vf10.xyz);
|
||||
//mfp.w vf10, P
|
||||
//div Q, vf23.z, vf10.w
|
||||
float qqq = 0.5 / P;
|
||||
//addaz.xyzw vf00, vf23
|
||||
ACC = vec3(0.5, 0.5, 0.5);
|
||||
//madd.xyzw vf10, vf10, Q
|
||||
vf10 = ACC + vf10 * qqq;
|
||||
tex_coord = vf10.xyz;
|
||||
}
|
||||
|
||||
|
||||
vec4 transformed = p_proj * pQ;
|
||||
transformed.w = p_proj.w;
|
||||
|
||||
// correct xy offset
|
||||
transformed.xy -= (2048.);
|
||||
// correct z scale
|
||||
transformed.z /= (8388608);
|
||||
transformed.z -= 1;
|
||||
// correct xy scale
|
||||
transformed.x /= (256);
|
||||
transformed.y /= -(128);
|
||||
// hack
|
||||
transformed.xyz *= transformed.w;
|
||||
// scissoring area adjust
|
||||
transformed.y *= SCISSOR_ADJUST * HEIGHT_SCALE;
|
||||
gl_Position = transformed;
|
||||
|
||||
|
||||
fragment_color = proto_tint * envmap_tod_tint;
|
||||
|
||||
}
|
32
game/graphics/opengl_renderer/shaders/etie_base.frag
Normal file
32
game/graphics/opengl_renderer/shaders/etie_base.frag
Normal file
|
@ -0,0 +1,32 @@
|
|||
#version 430 core
|
||||
|
||||
out vec4 color;
|
||||
|
||||
in vec4 fragment_color;
|
||||
in vec3 tex_coord;
|
||||
in float fogginess;
|
||||
uniform sampler2D tex_T0;
|
||||
|
||||
uniform float alpha_min;
|
||||
uniform float alpha_max;
|
||||
uniform vec4 fog_color;
|
||||
|
||||
uniform int gfx_hack_no_tex;
|
||||
|
||||
|
||||
void main() {
|
||||
if (gfx_hack_no_tex == 0) {
|
||||
//vec4 T0 = texture(tex_T0, tex_coord);
|
||||
vec4 T0 = texture(tex_T0, tex_coord.xy);
|
||||
color = fragment_color * T0;
|
||||
} else {
|
||||
color = fragment_color/2;
|
||||
}
|
||||
|
||||
if (color.a < alpha_min || color.a > alpha_max) {
|
||||
discard;
|
||||
}
|
||||
|
||||
color.rgb = mix(color.rgb, fog_color.rgb, clamp(fogginess * fog_color.a, 0, 1));
|
||||
|
||||
}
|
70
game/graphics/opengl_renderer/shaders/etie_base.vert
Normal file
70
game/graphics/opengl_renderer/shaders/etie_base.vert
Normal file
|
@ -0,0 +1,70 @@
|
|||
#version 430 core
|
||||
|
||||
layout (location = 0) in vec3 position_in;
|
||||
layout (location = 1) in vec3 tex_coord_in;
|
||||
layout (location = 2) in int time_of_day_index;
|
||||
|
||||
uniform vec4 hvdf_offset;
|
||||
uniform mat4 camera;
|
||||
uniform float fog_constant;
|
||||
uniform float fog_min;
|
||||
uniform float fog_max;
|
||||
layout (binding = 10) uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose.
|
||||
uniform int decal;
|
||||
|
||||
out vec4 fragment_color;
|
||||
out vec3 tex_coord;
|
||||
out float fogginess;
|
||||
|
||||
// etie stuff
|
||||
uniform vec4 persp0;
|
||||
uniform vec4 persp1;
|
||||
uniform mat4 cam_no_persp;
|
||||
|
||||
void main() {
|
||||
float fog1 = camera[3].w + camera[0].w * position_in.x + camera[1].w * position_in.y + camera[2].w * position_in.z;
|
||||
fogginess = 255 - clamp(fog1 + hvdf_offset.w, fog_min, fog_max);
|
||||
vec4 vf17 = cam_no_persp[3];
|
||||
vf17 += cam_no_persp[0] * position_in.x;
|
||||
vf17 += cam_no_persp[1] * position_in.y;
|
||||
vf17 += cam_no_persp[2] * position_in.z;
|
||||
vec4 p_proj = vec4(persp1.x * vf17.x, persp1.y * vf17.y, persp1.z, persp1.w);
|
||||
p_proj += persp0 * vf17.z;
|
||||
|
||||
float pQ = 1.f / p_proj.w;
|
||||
vec4 transformed = p_proj * pQ;
|
||||
transformed.w = p_proj.w;
|
||||
|
||||
// correct xy offset
|
||||
transformed.xy -= (2048.);
|
||||
// correct z scale
|
||||
transformed.z /= (8388608);
|
||||
transformed.z -= 1;
|
||||
// correct xy scale
|
||||
transformed.x /= (256);
|
||||
transformed.y /= -(128);
|
||||
// hack
|
||||
transformed.xyz *= transformed.w;
|
||||
// scissoring area adjust
|
||||
transformed.y *= SCISSOR_ADJUST * HEIGHT_SCALE;
|
||||
gl_Position = transformed;
|
||||
|
||||
|
||||
|
||||
if (decal == 1) {
|
||||
fragment_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
} else {
|
||||
// time of day lookup
|
||||
fragment_color = texelFetch(tex_T1, time_of_day_index, 0);
|
||||
// color adjustment
|
||||
fragment_color *= 2;
|
||||
fragment_color.a *= 2;
|
||||
}
|
||||
|
||||
// fog hack
|
||||
if (fragment_color.r < 0.005 && fragment_color.g < 0.005 && fragment_color.b < 0.005) {
|
||||
fogginess = 0;
|
||||
}
|
||||
|
||||
tex_coord = tex_coord_in;
|
||||
}
|
|
@ -13,6 +13,7 @@ uniform vec4 fog_color;
|
|||
|
||||
uniform int gfx_hack_no_tex;
|
||||
|
||||
|
||||
void main() {
|
||||
if (gfx_hack_no_tex == 0) {
|
||||
//vec4 T0 = texture(tex_T0, tex_coord);
|
||||
|
|
|
@ -10,6 +10,7 @@ uniform float fog_constant;
|
|||
uniform float fog_min;
|
||||
uniform float fog_max;
|
||||
layout (binding = 10) uniform sampler1D tex_T1; // note, sampled in the vertex shader on purpose.
|
||||
uniform int decal;
|
||||
|
||||
out vec4 fragment_color;
|
||||
out vec3 tex_coord;
|
||||
|
@ -62,12 +63,15 @@ void main() {
|
|||
transformed.y *= SCISSOR_ADJUST * HEIGHT_SCALE;
|
||||
gl_Position = transformed;
|
||||
|
||||
// time of day lookup
|
||||
fragment_color = texelFetch(tex_T1, time_of_day_index, 0);
|
||||
|
||||
// color adjustment
|
||||
fragment_color *= 2;
|
||||
fragment_color.a *= 2;
|
||||
if (decal == 1) {
|
||||
fragment_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
} else {
|
||||
// time of day lookup
|
||||
fragment_color = texelFetch(tex_T1, time_of_day_index, 0);
|
||||
// color adjustment
|
||||
fragment_color *= 2;
|
||||
fragment_color.a *= 2;
|
||||
}
|
||||
|
||||
// fog hack
|
||||
if (fragment_color.r < 0.005 && fragment_color.g < 0.005 && fragment_color.b < 0.005) {
|
||||
|
|
|
@ -91,8 +91,8 @@ int main(int argc, char** argv) {
|
|||
//
|
||||
// Only handling args the launcher provides, all others can be changed
|
||||
// in this repo at the time of merge.
|
||||
std::vector<char*> adjusted_argv_vals;
|
||||
std::vector<char*> adjusted_argv_vals_passthru;
|
||||
std::vector<const char*> adjusted_argv_vals;
|
||||
std::vector<const char*> adjusted_argv_vals_passthru;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
const auto& val = std::string(argv[i]);
|
||||
// Handle all args that aren't passed through
|
||||
|
@ -117,7 +117,7 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<char*> new_argv;
|
||||
std::vector<const char*> new_argv;
|
||||
if (!adjusted_argv_vals.empty() || !adjusted_argv_vals_passthru.empty()) {
|
||||
new_argv.push_back(argv[0]);
|
||||
for (const auto& arg : adjusted_argv_vals) {
|
||||
|
@ -129,7 +129,7 @@ int main(int argc, char** argv) {
|
|||
new_argv.push_back(arg);
|
||||
}
|
||||
}
|
||||
argv = new_argv.data();
|
||||
argv = (char**)new_argv.data();
|
||||
argc = new_argv.size();
|
||||
}
|
||||
// --- END temporary shim
|
||||
|
@ -209,7 +209,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
bool force_debug_next_time = false;
|
||||
// always start with an empty arg, as internally kmachine starts at `1` not `0`
|
||||
std::vector<char*> arg_ptrs = {""};
|
||||
std::vector<const char*> arg_ptrs = {""};
|
||||
for (auto& str : game_args) {
|
||||
arg_ptrs.push_back(str.data());
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ GameVersion g_game_version = GameVersion::Jak1;
|
|||
namespace {
|
||||
|
||||
int g_argc = 0;
|
||||
char** g_argv = nullptr;
|
||||
const char** g_argv = nullptr;
|
||||
|
||||
/*!
|
||||
* SystemThread function for running the DECI2 communication with the GOAL compiler.
|
||||
|
@ -310,7 +310,7 @@ void dmac_runner(SystemThreadInterface& iface) {
|
|||
* Main function to launch the runtime.
|
||||
* GOAL kernel arguments are currently ignored.
|
||||
*/
|
||||
RuntimeExitStatus exec_runtime(GameLaunchOptions game_options, int argc, char** argv) {
|
||||
RuntimeExitStatus exec_runtime(GameLaunchOptions game_options, int argc, const char** argv) {
|
||||
g_argc = argc;
|
||||
g_argv = argv;
|
||||
g_main_thread_id = std::this_thread::get_id();
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
extern u8* g_ee_main_mem;
|
||||
extern GameVersion g_game_version;
|
||||
|
||||
RuntimeExitStatus exec_runtime(GameLaunchOptions game_options, int argc, char** argv);
|
||||
RuntimeExitStatus exec_runtime(GameLaunchOptions game_options, int argc, const char** argv);
|
||||
|
||||
extern std::thread::id g_main_thread_id;
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
(defmethod mem-usage tfragment ((obj tfragment) (arg0 memory-usage-block) (arg1 int))
|
||||
"Compute the memory usage of a tfragment"
|
||||
|
||||
|
||||
;; seems like this flag does colors?
|
||||
(when (logtest? arg1 2)
|
||||
(+! (-> arg0 data 19 count) 1)
|
||||
|
@ -47,18 +47,18 @@
|
|||
)
|
||||
(return obj)
|
||||
)
|
||||
|
||||
|
||||
(let ((s4-0 1))
|
||||
(set! (-> arg0 length) (max (-> arg0 length) (+ s4-0 8)))
|
||||
(set! (-> arg0 data s4-0 name) (symbol->string 'tfragment))
|
||||
(+! (-> arg0 data s4-0 count) 1)
|
||||
|
||||
|
||||
;; the size of the actual tfragment
|
||||
(let ((v1-22 (asize-of obj)))
|
||||
(+! (-> arg0 data s4-0 used) v1-22)
|
||||
(+! (-> arg0 data s4-0 total) (logand -16 (+ v1-22 15)))
|
||||
)
|
||||
|
||||
|
||||
;; the size of the "base" DMA
|
||||
(set! (-> arg0 data (+ s4-0 1) name) "tfragment-base")
|
||||
(+! (-> arg0 data (+ s4-0 1) count) 1)
|
||||
|
@ -66,7 +66,7 @@
|
|||
(+! (-> arg0 data (+ s4-0 1) used) v1-33)
|
||||
(+! (-> arg0 data (+ s4-0 1) total) v1-33)
|
||||
)
|
||||
|
||||
|
||||
;; the size of the "common" DMA
|
||||
(set! (-> arg0 data (+ s4-0 2) name) "tfragment-common")
|
||||
(+! (-> arg0 data (+ s4-0 2) count) 1)
|
||||
|
@ -74,7 +74,7 @@
|
|||
(+! (-> arg0 data (+ s4-0 2) used) v1-43)
|
||||
(+! (-> arg0 data (+ s4-0 2) total) v1-43)
|
||||
)
|
||||
|
||||
|
||||
;; the size of the "level0" DMA
|
||||
(set! (-> arg0 data (+ s4-0 3) name) "tfragment-level0")
|
||||
(when (nonzero? (-> obj num-level0-colors))
|
||||
|
@ -84,7 +84,7 @@
|
|||
(+! (-> arg0 data (+ s4-0 3) total) v1-55)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; The size of the "level0" DMA. Note that the dma chains can overlap, so this is a bit weird.
|
||||
(set! (-> arg0 data (+ s4-0 4) name) "tfragment-level1")
|
||||
(when (not (or (= (-> obj dma-level-1) (-> obj dma-common))
|
||||
|
@ -104,7 +104,7 @@
|
|||
(+! (-> arg0 data (+ s4-0 4) total) v1-70)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; colors
|
||||
(set! (-> arg0 data (+ s4-0 5) name) "tfragment-color")
|
||||
(+! (-> arg0 data (+ s4-0 5) count) 1)
|
||||
|
@ -117,11 +117,11 @@
|
|||
(+! (-> arg0 data (+ s4-0 5) used) v1-79)
|
||||
(+! (-> arg0 data (+ s4-0 5) total) (logand -16 (+ v1-79 15)))
|
||||
)
|
||||
|
||||
|
||||
;; debug (unused)
|
||||
(set! (-> arg0 data (+ s4-0 6) name) "tfragment-debug")
|
||||
)
|
||||
|
||||
|
||||
obj
|
||||
)
|
||||
|
||||
|
@ -322,12 +322,12 @@
|
|||
(defun add-pc-tfrag3-data ((dma-buf dma-buffer) (lev level))
|
||||
"Add PC-port specific tfrag data"
|
||||
(let ((packet (the-as dma-packet (-> dma-buf base))))
|
||||
(set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc 16))
|
||||
(set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc 24))
|
||||
(set! (-> packet vif0) (new 'static 'vif-tag))
|
||||
(set! (-> packet vif1) (new 'static 'vif-tag :cmd (vif-cmd pc-port)))
|
||||
(set! (-> dma-buf base) (the pointer (&+ packet 16)))
|
||||
)
|
||||
|
||||
|
||||
;; first 4 quadwords are planes, then itimes
|
||||
(let ((data-ptr (the-as (pointer uint128) (-> dma-buf base))))
|
||||
(set! (-> data-ptr 0) (-> *math-camera* plane 0 quad))
|
||||
|
@ -349,9 +349,18 @@
|
|||
(set! (-> vec z) (-> *math-camera* fog-max))
|
||||
)
|
||||
(set! (-> data-ptr 14) (-> (math-camera-pos) quad))
|
||||
(charp<-string (the (pointer uint8) (&-> data-ptr 15)) (symbol->string (-> lev nickname)))
|
||||
(set! (-> data-ptr 15) (-> *math-camera* camera-rot vector 0 quad))
|
||||
(set! (-> data-ptr 16) (-> *math-camera* camera-rot vector 1 quad))
|
||||
(set! (-> data-ptr 17) (-> *math-camera* camera-rot vector 2 quad))
|
||||
(set! (-> data-ptr 18) (-> *math-camera* camera-rot vector 3 quad))
|
||||
|
||||
(set! (-> data-ptr 19) (-> *math-camera* perspective vector 0 quad))
|
||||
(set! (-> data-ptr 20) (-> *math-camera* perspective vector 1 quad))
|
||||
(set! (-> data-ptr 21) (-> *math-camera* perspective vector 2 quad))
|
||||
(set! (-> data-ptr 22) (-> *math-camera* perspective vector 3 quad))
|
||||
(charp<-string (the (pointer uint8) (&-> data-ptr 23)) (symbol->string (-> lev nickname)))
|
||||
)
|
||||
(&+! (-> dma-buf base) (* 16 16))
|
||||
(&+! (-> dma-buf base) (* 16 24))
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -607,7 +607,7 @@
|
|||
(defun add-pc-tfrag3-data ((dma-buf dma-buffer) (lev level))
|
||||
"Add PC-port specific tfrag data"
|
||||
(let ((packet (the-as dma-packet (-> dma-buf base))))
|
||||
(set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc 16))
|
||||
(set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc 24))
|
||||
(set! (-> packet vif0) (new 'static 'vif-tag))
|
||||
(set! (-> packet vif1) (new 'static 'vif-tag :cmd (vif-cmd pc-port)))
|
||||
(set! (-> dma-buf base) (the pointer (&+ packet 16)))
|
||||
|
@ -638,6 +638,17 @@
|
|||
(set! (-> vec z) (-> *math-camera* fog-max))
|
||||
)
|
||||
(set! (-> data-ptr 14) (-> *math-camera* trans-other quad))
|
||||
|
||||
(set! (-> data-ptr 15) (-> *math-camera* camera-rot-other vector 0 quad))
|
||||
(set! (-> data-ptr 16) (-> *math-camera* camera-rot-other vector 1 quad))
|
||||
(set! (-> data-ptr 17) (-> *math-camera* camera-rot-other vector 2 quad))
|
||||
(set! (-> data-ptr 18) (-> *math-camera* camera-rot-other vector 3 quad))
|
||||
|
||||
(set! (-> data-ptr 19) (-> *math-camera* perspective vector 0 quad))
|
||||
(set! (-> data-ptr 20) (-> *math-camera* perspective vector 1 quad))
|
||||
(set! (-> data-ptr 21) (-> *math-camera* perspective vector 2 quad))
|
||||
(set! (-> data-ptr 22) (-> *math-camera* perspective vector 3 quad))
|
||||
|
||||
)
|
||||
(else
|
||||
(set! (-> data-ptr 0) (-> *math-camera* plane 0 quad))
|
||||
|
@ -659,10 +670,20 @@
|
|||
(set! (-> vec z) (-> *math-camera* fog-max))
|
||||
)
|
||||
(set! (-> data-ptr 14) (-> *math-camera* trans quad))
|
||||
|
||||
(set! (-> data-ptr 15) (-> *math-camera* camera-rot vector 0 quad))
|
||||
(set! (-> data-ptr 16) (-> *math-camera* camera-rot vector 1 quad))
|
||||
(set! (-> data-ptr 17) (-> *math-camera* camera-rot vector 2 quad))
|
||||
(set! (-> data-ptr 18) (-> *math-camera* camera-rot vector 3 quad))
|
||||
|
||||
(set! (-> data-ptr 19) (-> *math-camera* perspective vector 0 quad))
|
||||
(set! (-> data-ptr 20) (-> *math-camera* perspective vector 1 quad))
|
||||
(set! (-> data-ptr 21) (-> *math-camera* perspective vector 2 quad))
|
||||
(set! (-> data-ptr 22) (-> *math-camera* perspective vector 3 quad))
|
||||
)
|
||||
)
|
||||
|
||||
(charp<-string (the (pointer uint8) (&-> data-ptr 15)) (symbol->string (-> lev nickname)))
|
||||
(charp<-string (the (pointer uint8) (&-> data-ptr 23)) (symbol->string (-> lev nickname)))
|
||||
)
|
||||
(&+! (-> dma-buf base) (* 16 16))
|
||||
(&+! (-> dma-buf base) (* 16 24))
|
||||
)
|
||||
|
|
|
@ -110,6 +110,23 @@
|
|||
)
|
||||
)
|
||||
|
||||
(defun pc-add-tie-envmap-info ((dma-buf dma-buffer))
|
||||
(let ((packet (the-as dma-packet (-> dma-buf base))))
|
||||
(set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc 1))
|
||||
(set! (-> packet vif0) (new 'static 'vif-tag))
|
||||
(set! (-> packet vif1) (new 'static 'vif-tag :cmd (vif-cmd pc-port)))
|
||||
(set! (-> dma-buf base) (the pointer (&+ packet 16)))
|
||||
(set! (-> (the (pointer uint128) (-> dma-buf base)))
|
||||
(if (and *time-of-day-context*
|
||||
(nonzero? *time-of-day-context*))
|
||||
(-> *time-of-day-context* current-env-color quad)
|
||||
(the uint128 0)
|
||||
)
|
||||
)
|
||||
(set! (-> dma-buf base) (the pointer (&+ packet 32)))
|
||||
)
|
||||
)
|
||||
|
||||
(defun instance-tie-patch-buckets ((arg0 dma-buffer) (arg1 level))
|
||||
; (when (logtest? (-> *display* vu1-enable-user) (vu1-renderer-mask tie))
|
||||
; (when (nonzero? (-> *prototype-tie-work* scissor-count))
|
||||
|
@ -220,6 +237,7 @@
|
|||
; (&+! (-> v1-42 base) 16)
|
||||
(add-pc-tfrag3-data v1-42 arg1)
|
||||
(pc-add-tie-vis-mask arg1 v1-42)
|
||||
(pc-add-tie-envmap-info v1-42)
|
||||
(let ((a3-16 (-> v1-42 base)))
|
||||
(let ((a0-20 (the-as dma-packet (-> v1-42 base))))
|
||||
(set! (-> a0-20 dma) (new 'static 'dma-tag :id (dma-tag-id next)))
|
||||
|
@ -1442,14 +1460,14 @@
|
|||
(none)
|
||||
)
|
||||
|
||||
(defun tie-init-envmap-buf ((arg0 bucket-id) (arg1 gs-alpha) (arg2 int) (arg3 int))
|
||||
;; nothing yet
|
||||
(defun tie-init-envmap-buf ((arg0 bucket-id) (arg1 gs-alpha) (arg2 gs-test))
|
||||
;; PC doesn't need this, skip it.
|
||||
; (let ((s5-0 (-> *display* frames (-> *display* on-screen) bucket-group arg0)))
|
||||
; (when (!= s5-0 (-> s5-0 last))
|
||||
; (let* ((s4-0 (-> *display* frames (-> *display* on-screen) global-buf))
|
||||
; (s3-1 (-> s4-0 base))
|
||||
; )
|
||||
; (etie-init-engine s4-0)
|
||||
; (etie-init-engine s4-0 arg1 arg2)
|
||||
; (let ((v1-12 (the-as dma-packet (-> s4-0 base))))
|
||||
; (set! (-> v1-12 dma) (new 'static 'dma-tag :id (dma-tag-id next) :addr (-> s5-0 next)))
|
||||
; (set! (-> v1-12 vif0) (new 'static 'vif-tag))
|
||||
|
@ -1632,7 +1650,11 @@
|
|||
(a3-1 #x50000)
|
||||
)
|
||||
(t9-1 a0-3 (the-as gs-alpha a1-2) (the-as gs-test a2-1) (the-as gs-test a3-1))
|
||||
(tie-init-envmap-buf (-> s2-0 tie-envmap-bucket) (the-as gs-alpha gp-0) #x50000 a3-1)
|
||||
(tie-init-envmap-buf
|
||||
(-> s2-0 tie-envmap-bucket)
|
||||
(the-as gs-alpha gp-0)
|
||||
(new 'static 'gs-test :zte #x1 :ztst (gs-ztest greater-equal))
|
||||
)
|
||||
(tie-init-envmap-scissor-buf (-> s2-0 tie-envmap-scissor-bucket) (the-as gs-alpha gp-0) #x50000 a3-1)
|
||||
)
|
||||
(tie-init-buf
|
||||
|
@ -1666,7 +1688,11 @@
|
|||
(a3-4 #x50000)
|
||||
)
|
||||
(t9-6 a0-8 (the-as gs-alpha a1-7) (the-as gs-test a2-6) (the-as gs-test a3-4))
|
||||
(tie-init-envmap-buf (-> s2-0 tie-envmap-trans-bucket) (the-as gs-alpha s4-0) #x50000 a3-4)
|
||||
(tie-init-envmap-buf
|
||||
(-> s2-0 tie-envmap-trans-bucket)
|
||||
(the-as gs-alpha s4-0)
|
||||
(new 'static 'gs-test :zte #x1 :ztst (gs-ztest greater-equal))
|
||||
)
|
||||
(tie-init-envmap-scissor-buf (-> s2-0 tie-envmap-scissor-trans-bucket) (the-as gs-alpha s4-0) #x50000 a3-4)
|
||||
)
|
||||
(tie-init-buf
|
||||
|
@ -1682,7 +1708,11 @@
|
|||
(a3-6 #x51001)
|
||||
)
|
||||
(t9-10 a0-12 (the-as gs-alpha a1-11) (the-as gs-test a2-10) (the-as gs-test a3-6))
|
||||
(tie-init-envmap-buf (-> s2-0 tie-envmap-water-bucket) (the-as gs-alpha s4-0) #x51001 a3-6)
|
||||
(tie-init-envmap-buf
|
||||
(-> s2-0 tie-envmap-water-bucket)
|
||||
(the-as gs-alpha s4-0)
|
||||
(new 'static 'gs-test :ate #x1 :afail #x1 :zte #x1 :ztst (gs-ztest greater-equal))
|
||||
)
|
||||
(tie-init-envmap-scissor-buf (-> s2-0 tie-envmap-scissor-water-bucket) (the-as gs-alpha s4-0) #x51001 a3-6)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -77,6 +77,7 @@ bool run_build_level(const std::string& input_file,
|
|||
add_ambients_from_json(level_json.at("ambients"), ambients, level_json.value("base_id", 12345));
|
||||
file.ambients = std::move(ambients);
|
||||
auto& ambient_drawable_tree = file.drawable_trees.ambients.emplace_back();
|
||||
(void)ambient_drawable_tree;
|
||||
// cameras
|
||||
// nodes
|
||||
// boxes
|
||||
|
|
|
@ -241,11 +241,6 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
|
|||
v.s = 0;
|
||||
v.t = 0;
|
||||
}
|
||||
|
||||
v.q_unused = 0;
|
||||
v.pad[0] = 0;
|
||||
v.pad[1] = 0;
|
||||
v.pad[2] = 0;
|
||||
}
|
||||
// TODO: other properties
|
||||
return {result, vtx_colors, normals};
|
||||
|
|
|
@ -107,6 +107,13 @@ TEST(VuDisasm, Tie_Jak2) {
|
|||
EXPECT_EQ(disasm.to_string(prog), get_expected("jak2/tie"));
|
||||
}
|
||||
|
||||
TEST(VuDisasm, etie_Jak2) {
|
||||
auto data = get_test_data("jak2/etie-vu1");
|
||||
VuDisassembler disasm(VuDisassembler::VuKind::VU1);
|
||||
auto prog = disasm.disassemble(data.data(), data.size() * 4, false);
|
||||
EXPECT_EQ(disasm.to_string(prog), get_expected("jak2/etie-vu1"));
|
||||
}
|
||||
|
||||
TEST(VuDisasm, SpriteDistort) {
|
||||
auto data = get_test_data("sprite-distort");
|
||||
VuDisassembler disasm(VuDisassembler::VuKind::VU1);
|
||||
|
@ -146,7 +153,6 @@ TEST(VuDisasm, ForegroundVu0_Jak2) {
|
|||
auto data = get_test_data("jak2/foreground-vu0");
|
||||
VuDisassembler disasm(VuDisassembler::VuKind::VU0);
|
||||
auto prog = disasm.disassemble(data.data(), data.size() * 4, false);
|
||||
// fmt::print("{}\n", disasm.to_string(prog));
|
||||
EXPECT_EQ(disasm.to_string(prog), get_expected("jak2/foreground-vu0"));
|
||||
}
|
||||
|
||||
|
|
1535
test/decompiler/vu_reference/jak2/etie-vu1-result.txt
Normal file
1535
test/decompiler/vu_reference/jak2/etie-vu1-result.txt
Normal file
File diff suppressed because it is too large
Load diff
2992
test/decompiler/vu_reference/jak2/etie-vu1.txt
Normal file
2992
test/decompiler/vu_reference/jak2/etie-vu1.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -111,7 +111,7 @@ void runtime_no_kernel_jak1() {
|
|||
const char* argv[argc] = {"", "-fakeiso", "-debug", "-nokernel", "-nosound"};
|
||||
GameLaunchOptions game_options;
|
||||
game_options.disable_display = true;
|
||||
exec_runtime(game_options, argc, const_cast<char**>(argv));
|
||||
exec_runtime(game_options, argc, argv);
|
||||
}
|
||||
|
||||
void runtime_no_kernel_jak2() {
|
||||
|
@ -120,7 +120,7 @@ void runtime_no_kernel_jak2() {
|
|||
GameLaunchOptions game_options;
|
||||
game_options.disable_display = true;
|
||||
game_options.game_version = GameVersion::Jak2;
|
||||
exec_runtime(game_options, argc, const_cast<char**>(argv));
|
||||
exec_runtime(game_options, argc, argv);
|
||||
}
|
||||
|
||||
void runtime_with_kernel_jak1() {
|
||||
|
@ -128,7 +128,7 @@ void runtime_with_kernel_jak1() {
|
|||
const char* argv[argc] = {"", "-fakeiso", "-debug", "-nosound"};
|
||||
GameLaunchOptions game_options;
|
||||
game_options.disable_display = true;
|
||||
exec_runtime(game_options, argc, const_cast<char**>(argv));
|
||||
exec_runtime(game_options, argc, argv);
|
||||
}
|
||||
|
||||
void runtime_with_kernel_jak2() {
|
||||
|
@ -137,7 +137,7 @@ void runtime_with_kernel_jak2() {
|
|||
GameLaunchOptions game_options;
|
||||
game_options.disable_display = true;
|
||||
game_options.game_version = GameVersion::Jak2;
|
||||
exec_runtime(game_options, argc, const_cast<char**>(argv));
|
||||
exec_runtime(game_options, argc, argv);
|
||||
}
|
||||
|
||||
void runtime_with_kernel_no_debug_segment() {
|
||||
|
@ -145,7 +145,7 @@ void runtime_with_kernel_no_debug_segment() {
|
|||
const char* argv[argc] = {"", "-fakeiso", "-debug-mem", "-nosound"};
|
||||
GameLaunchOptions game_options;
|
||||
game_options.disable_display = true;
|
||||
exec_runtime(game_options, argc, const_cast<char**>(argv));
|
||||
exec_runtime(game_options, argc, argv);
|
||||
}
|
||||
|
||||
void createDirIfAbsent(const std::string& path) {
|
||||
|
|
Loading…
Reference in a new issue