Skip to content

Commit

Permalink
[jak2,3] Support loading clut blender animated textures to the pool (#…
Browse files Browse the repository at this point in the history
…3735)

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 <[email protected]>
  • Loading branch information
water111 and water111 authored Oct 27, 2024
1 parent 5bc61c5 commit 1962fbf
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 124 deletions.
66 changes: 52 additions & 14 deletions game/graphics/opengl_renderer/TextureAnimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
}
}
}
}

Expand Down
11 changes: 8 additions & 3 deletions game/graphics/opengl_renderer/TextureAnimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -220,7 +224,6 @@ struct FixedAnim {
std::optional<FramebufferTexturePair> fbt;
int dest_slot;
std::vector<FixedAnimSource> src_textures;

GpuTexture* pool_gpu_tex = nullptr;
};

Expand Down Expand Up @@ -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;

Expand All @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions game/graphics/opengl_renderer/TextureAnimatorDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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(
Expand Down
111 changes: 33 additions & 78 deletions goal_src/jak2/engine/gfx/texture/texture-anim.gc
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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
Expand Down
57 changes: 31 additions & 26 deletions goal_src/jak3/engine/gfx/texture/texture-anim.gc
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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*)
Expand Down

0 comments on commit 1962fbf

Please sign in to comment.