[jak2,3] Support loading clut blender animated textures to the pool (#3735)
Some checks failed
Build / 🖥️ Windows (push) Waiting to run
Build / 🐧 Linux (push) Waiting to run
Build / 🍎 MacOS (push) Waiting to run
Lint / 📝 Formatting (push) Waiting to run
Lint / 📝 Required Checks (push) Waiting to run
Lint / 📝 Optional Checks (push) Waiting to run
Inform Pages Repo / Generate Documentation (push) Has been cancelled

Animated textures that use the clut blender can now upload them to the
texture pool, so they can get read by the eye renderer. This will also
fix darkjak's eyelids in jak 2.


![image](https://github.com/user-attachments/assets/5edbd20d-53c9-42c6-937d-6263823b8b45)

Co-authored-by: water111 <awaterford1111445@gmail.com>
This commit is contained in:
water111 2024-10-27 09:21:44 -04:00 committed by GitHub
parent 5bc61c5854
commit 1962fbfb51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 127 additions and 124 deletions

View File

@ -736,10 +736,14 @@ void TextureAnimator::copy_private_to_public() {
int TextureAnimator::create_clut_blender_group(const std::vector<std::string>& textures,
const std::string& suffix0,
const std::string& suffix1,
const std::optional<std::string>& dgo) {
const std::optional<std::string>& dgo,
bool add_to_pool) {
int ret = m_clut_blender_groups.size();
m_clut_blender_groups.emplace_back();
add_to_clut_blender_group(ret, textures, suffix0, suffix1, dgo);
if (add_to_pool) {
m_clut_blender_groups.back().move_to_pool = true;
}
return ret;
}
@ -1240,23 +1244,23 @@ void TextureAnimator::handle_texture_anim_data(DmaFollower& dma,
break;
case PcTextureAnimCodesJak2::DARKJAK: {
auto p = scoped_prof("darkjak");
run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx);
run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx, texture_pool);
} break;
case PcTextureAnimCodesJak2::PRISON_JAK: {
auto p = scoped_prof("prisonjak");
run_clut_blender_group(tf, m_jakb_prison_clut_blender_idx, frame_idx);
run_clut_blender_group(tf, m_jakb_prison_clut_blender_idx, frame_idx, texture_pool);
} break;
case PcTextureAnimCodesJak2::ORACLE_JAK: {
auto p = scoped_prof("oraclejak");
run_clut_blender_group(tf, m_jakb_oracle_clut_blender_idx, frame_idx);
run_clut_blender_group(tf, m_jakb_oracle_clut_blender_idx, frame_idx, texture_pool);
} break;
case PcTextureAnimCodesJak2::NEST_JAK: {
auto p = scoped_prof("nestjak");
run_clut_blender_group(tf, m_jakb_nest_clut_blender_idx, frame_idx);
run_clut_blender_group(tf, m_jakb_nest_clut_blender_idx, frame_idx, texture_pool);
} break;
case PcTextureAnimCodesJak2::KOR_TRANSFORM: {
auto p = scoped_prof("kor");
run_clut_blender_group(tf, m_kor_transform_clut_blender_idx, frame_idx);
run_clut_blender_group(tf, m_kor_transform_clut_blender_idx, frame_idx, texture_pool);
} break;
case PcTextureAnimCodesJak2::SKULL_GEM:
case PcTextureAnimCodesJak2::BOMB:
@ -1321,11 +1325,12 @@ void TextureAnimator::handle_texture_anim_data(DmaFollower& dma,
break;
case PcTextureAnimCodesJak3::DARKJAK: {
auto p = scoped_prof("darkjak");
run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx);
run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx, texture_pool);
} break;
case PcTextureAnimCodesJak3::DARKJAK_HIGHRES: {
auto p = scoped_prof("darkjak-highres");
run_clut_blender_group(tf, m_darkjak_highres_clut_blender_idx, frame_idx);
run_clut_blender_group(tf, m_darkjak_highres_clut_blender_idx, frame_idx,
texture_pool);
} break;
case PcTextureAnimCodesJak3::SKULL_GEM:
case PcTextureAnimCodesJak3::DEFAULT_WATER:
@ -1579,15 +1584,48 @@ PcTextureId TextureAnimator::get_id_for_tbp(TexturePool* pool, u64 tbp, u64 othe
}
}
void TextureAnimator::run_clut_blender_group(DmaTransfer& tf, int idx, u64 frame_idx) {
void TextureAnimator::run_clut_blender_group(DmaTransfer& tf,
int idx,
u64 frame_idx,
TexturePool* texture_pool) {
auto& blenders = m_clut_blender_groups.at(idx);
const int tbps_size = sizeof(u32) * 4 * ((blenders.blenders.size() + 3) / 4);
float f;
ASSERT(tf.size_bytes == 16);
ASSERT(tf.size_bytes == 16 + tbps_size);
memcpy(&f, tf.data, sizeof(float));
float weights[2] = {1.f - f, f};
auto& blender = m_clut_blender_groups.at(idx);
blender.last_updated_frame = frame_idx;
for (size_t i = 0; i < blender.blenders.size(); i++) {
m_private_output_slots[blender.outputs[i]] = blender.blenders[i].run(weights);
blenders.last_updated_frame = frame_idx;
for (size_t i = 0; i < blenders.blenders.size(); i++) {
m_private_output_slots[blenders.outputs[i]] = blenders.blenders[i].run(weights);
}
const u32* tbps = (const u32*)(tf.data + 16);
// give to the pool for renderers that don't know how to access this directly
if (blenders.move_to_pool) {
for (size_t i = 0; i < blenders.blenders.size(); i++) {
auto& blender = blenders.blenders[i];
const u32 tbp = tbps[i];
if (tbp == UINT32_MAX) {
continue;
}
ASSERT(tbp < 0x40000);
m_skip_tbps.push_back(tbp); // known to be an output texture.
if (blender.pool_gpu_tex) {
// TODO: handle debug checkbox.
texture_pool->move_existing_to_vram(blender.pool_gpu_tex, tbp);
ASSERT(texture_pool->lookup(tbp).value() == blender.texture());
} else {
TextureInput in;
in.gpu_texture = blender.texture();
in.w = blender.w();
in.h = blender.h();
in.debug_page_name = "PC-ANIM";
in.debug_name = std::to_string(tbp);
in.id = get_id_for_tbp(texture_pool, tbp, idx);
blender.pool_gpu_tex = texture_pool->give_texture_and_load_to_vram(in, tbp);
}
}
}
}

View File

@ -77,6 +77,10 @@ class ClutBlender {
GLuint texture() const { return m_texture; }
bool at_default() const { return m_current_weights[0] == 1.f && m_current_weights[1] == 0.f; }
int w() const { return m_dest->w; }
int h() const { return m_dest->h; }
GpuTexture* pool_gpu_tex = nullptr;
private:
const tfrag3::IndexTexture* m_dest;
std::array<const std::array<math::Vector4<u8>, 256>*, 2> m_cluts;
@ -220,7 +224,6 @@ struct FixedAnim {
std::optional<FramebufferTexturePair> fbt;
int dest_slot;
std::vector<FixedAnimSource> src_textures;
GpuTexture* pool_gpu_tex = nullptr;
};
@ -397,6 +400,7 @@ class TextureAnimator {
std::vector<ClutBlender> blenders;
std::vector<int> outputs;
u64 last_updated_frame = 0;
bool move_to_pool = false;
};
std::vector<ClutBlenderGroup> m_clut_blender_groups;
@ -409,13 +413,14 @@ class TextureAnimator {
int create_clut_blender_group(const std::vector<std::string>& textures,
const std::string& suffix0,
const std::string& suffix1,
const std::optional<std::string>& dgo);
const std::optional<std::string>& dgo,
bool send_to_pool = false);
void add_to_clut_blender_group(int idx,
const std::vector<std::string>& textures,
const std::string& suffix0,
const std::string& suffix1,
const std::optional<std::string>& dgo);
void run_clut_blender_group(DmaTransfer& tf, int idx, u64 frame_idx);
void run_clut_blender_group(DmaTransfer& tf, int idx, u64 frame_idx, TexturePool* texture_pool);
GLint run_clouds(const SkyInput& input, bool hires);
void run_slime(const SlimeInput& input);

View File

@ -21,7 +21,7 @@ void TextureAnimator::setup_texture_anims_jak3() {
"jakchires-facert",
"jakchires-hair",
},
"-norm", "-dark", "MHCTYCST.DGO");
"-norm", "-dark", "MHCTYCST.DGO", true);
// default-water
{
@ -1791,13 +1791,13 @@ void TextureAnimator::setup_texture_anims_jak2() {
// MISSING FINGER
m_jakb_oracle_clut_blender_idx = create_clut_blender_group(
{"jakb-eyebrow", "jakb-eyelid", "jakb-facelft", "jakb-facert", "jakb-hairtrans"}, "-norm",
"-dark", "ORACLE.DGO");
"-dark", "ORACLE.DGO", true);
// NEST
// MISSING FINGER
m_jakb_nest_clut_blender_idx = create_clut_blender_group(
{"jakb-eyebrow", "jakb-eyelid", "jakb-facelft", "jakb-facert", "jakb-hairtrans"}, "-norm",
"-dark", "NEB.DGO");
"-dark", "NEB.DGO", true);
// KOR (doesn't work??)
m_kor_transform_clut_blender_idx = create_clut_blender_group(

View File

@ -777,6 +777,34 @@ struct SlimeInput {
(the int (-> *toxic-slime-texture-anim-array* array-data 8 tex dest 0)))
)
(defun pc-clut-blender ((bucket bucket-id) (id texture-anim-pc) (anim-array texture-anim-array))
(let* ((sz (-> anim-array length))
(qwc (+ 1 (/ (+ 3 sz) 4))))
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag-id id dma-buf :qwc qwc)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(dotimes (i sz)
(let ((tex (-> anim-array array-data i tex)))
(set! (-> (the (pointer uint32) (-> dma-buf base)) i)
(if tex (-> tex dest 0)
-1)
)
)
)
(&+! (-> dma-buf base) (- (* 16 qwc) 16))
(pc-texture-anim-flag finish-anim-array dma-buf)
)
)
(none)
)
(defun update-texture-anim ((bucket bucket-id) (anim-array texture-anim-array))
@ -902,96 +930,23 @@ struct SlimeInput {
(return #f)
)
((= anim-array *darkjak-texture-anim-array*)
;; darkjak is simple, and we reimplemented it in C++.
;; so we just have to send the frame-time value.
;; (format *stdcon* "doing darkjak~%")
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag darkjak dma-buf :qwc 1)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
(pc-clut-blender bucket (texture-anim-pc darkjak) anim-array)
(return #f)
)
((= anim-array *jakb-prison-texture-anim-array*)
;; prison is simple, and we reimplemented it in C++.
;; so we just have to send the frame-time value.
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag prison-jak dma-buf :qwc 1)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
(pc-clut-blender bucket (texture-anim-pc prison-jak) anim-array)
(return #f)
)
((= anim-array *darkjak-hires-texture-anim-array*)
;; oracle is simple, and we reimplemented it in C++.
;; so we just have to send the frame-time value.
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag oracle-jak dma-buf :qwc 1)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
(pc-clut-blender bucket (texture-anim-pc oracle-jak) anim-array)
(return #f)
)
((= anim-array *darkjak-hires-nest-texture-anim-array*)
;; oracle is simple, and we reimplemented it in C++.
;; so we just have to send the frame-time value.
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag nest-jak dma-buf :qwc 1)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
(pc-clut-blender bucket (texture-anim-pc nest-jak) anim-array)
(return #f)
)
((= anim-array *kor-transform-texture-anim-array*)
;; kor is simple, and we reimplemented it in C++.
;; so we just have to send the frame-time value.
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag kor-transform dma-buf :qwc 1)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
(pc-clut-blender bucket (texture-anim-pc kor-transform) anim-array)
(return #f)
)
(else

View File

@ -435,6 +435,35 @@
0
)
(defun pc-clut-blender ((bucket bucket-id) (id texture-anim-pc) (anim-array texture-anim-array))
(let* ((sz (-> anim-array length))
(qwc (+ 1 (/ (+ 3 sz) 4))))
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag-id id dma-buf :qwc qwc)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(dotimes (i sz)
(let ((tex (-> anim-array array-data i tex)))
(set! (-> (the (pointer uint32) (-> dma-buf base)) i)
(if tex (-> tex dest 0)
-1)
)
)
)
(&+! (-> dma-buf base) (- (* 16 qwc) 16))
(pc-texture-anim-flag finish-anim-array dma-buf)
)
)
(none)
)
;; WARN: Function update-texture-anim has a return type of none, but the expression builder found a return statement.
(defun update-texture-anim ((bucket bucket-id) (anim-array texture-anim-array))
(let ((anim-idx 0))
@ -471,35 +500,11 @@
;; (return #f)
)
((*darkjak-texture-anim-array*)
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag darkjak dma-buf :qwc 1)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
(pc-clut-blender bucket (texture-anim-pc darkjak) anim-array)
(return #f)
)
((*darkjak-highres-texture-anim-array*)
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf))
bucket
)
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag darkjak-highres dma-buf :qwc 1)
(let ((morph (-> anim-array array-data 0 frame-time))
(vec (the vector (-> dma-buf base)))
)
(set! (-> vec x) morph)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
(pc-clut-blender bucket (texture-anim-pc darkjak-highres) anim-array)
(return #f)
)
((*skull-gem-texture-anim-array*)