[jak2] Support Japanese Subtitles (#2914)

![image](https://github.com/open-goal/jak-project/assets/48171810/7b5edd00-4193-47ab-92f6-8f270edbcafe)
This commit is contained in:
water111
2023-08-17 19:40:02 -04:00
committed by GitHub
parent f3f8ccc9ff
commit b16daae310
7 changed files with 121 additions and 34 deletions
@@ -94,7 +94,6 @@ void DirectRenderer::render(DmaFollower& dma,
pre_render();
// if we're rendering from a bucket, we should start off we a totally reset state:
reset_state();
setup_common_state(render_state);
// just dump the DMA data into the other the render function
while (dma.current_tag_offset() != render_state->next_bucket) {
@@ -562,10 +561,6 @@ void DirectRenderer::update_gl_test() {
}
}
void DirectRenderer::setup_common_state(SharedRenderState* /*render_state*/) {
// todo texture clamp.
}
namespace {
/*!
* If it's a direct, returns the qwc.
@@ -50,11 +50,6 @@ class DirectRenderer : public BucketRenderer {
void reset_state();
/*!
* If you don't use the render interface, call this first to set up OpenGL.
*/
void setup_common_state(SharedRenderState* render_state);
/*!
* If you don't use the render interface, call this at the very end.
*/
@@ -292,8 +292,8 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
0x1000);
init_bucket_renderer<DirectRenderer>("screen-filter", BucketCategory::OTHER,
BucketId::SCREEN_FILTER, 256);
init_bucket_renderer<DirectRenderer>("subtitle", BucketCategory::OTHER, BucketId::SUBTITLE,
0x1000);
init_bucket_renderer<TextureUploadHandler>("subtitle", BucketCategory::OTHER, BucketId::SUBTITLE,
m_texture_animator, true);
init_bucket_renderer<DirectRenderer>("debug2", BucketCategory::OTHER, BucketId::DEBUG2, 0x8000);
init_bucket_renderer<DirectRenderer>("debug-no-zbuf2", BucketCategory::OTHER,
BucketId::DEBUG_NO_ZBUF2, 0x8000);
@@ -96,9 +96,20 @@ OpenGLTexturePool::~OpenGLTexturePool() {
* Get a preallocated texture with the given size, or fatal error if we are out.
*/
GLuint OpenGLTexturePool::allocate(u64 w, u64 h) {
const auto& it = textures.find((w << 32) | h);
const u64 key = (w << 32) | h;
const auto& it = textures.find(key);
if (it == textures.end()) {
lg::die("OpenGLTexturePool needs entries for {} x {}", w, h);
// Note: this is a bit of an abuse to support both Japanese subtitles (variable size), and the
// "emulated" cloud textures (preallocated to avoid the performance issue described at the top
// of the file). For now, warn when this happens, just so we don't miss a case of this getting
// spammed during normal gameplay (bad for performance). Note that all of this can get massively
// simplified once clouds are moved to C++. This is just a hack to keep the current clouds
// working. (they are wrong and slow, but look better than nothing)
lg::warn("OpenGLTexturePool creating texture for {} x {}", w, h);
GLuint slot;
glGenTextures(1, &slot);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
return slot;
}
if (it->second.empty()) {
@@ -858,6 +869,32 @@ void TextureAnimator::force_to_gpu(int tbp) {
glBindTexture(GL_TEXTURE_2D, 0);
entry.kind = VramEntry::Kind::GPU;
} break;
case VramEntry::Kind::GENERIC_PSMT4: {
int tw = entry.tex_width;
int th = entry.tex_height;
std::vector<u32> rgba_data(tw * th);
{
auto p = scoped_prof("convert");
// for psmt4, we don't use the special 16x16 case
const auto& clut_lookup = m_textures.find(entry.cbp);
ASSERT(clut_lookup != m_textures.end());
ASSERT(clut_lookup->second.kind == VramEntry::Kind::GENERIC_PSM32);
auto* clut = (const u32*)clut_lookup->second.data.data();
for (int px = 0; px < (int)rgba_data.size(); ++px) {
u8 val = entry.data[px / 2];
int idx = px & 1 ? val >> 4 : val & 0xf;
// no m_index_to_clut_addr mapping for the 4-bit index.
rgba_data[px] = clut[idx];
}
}
setup_vram_entry_for_gpu_texture(tw, th, tbp);
glBindTexture(GL_TEXTURE_2D, entry.tex.value().texture());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
rgba_data.data());
glBindTexture(GL_TEXTURE_2D, 0);
entry.kind = VramEntry::Kind::GPU;
} break;
}
}
@@ -1084,6 +1121,9 @@ void TextureAnimator::handle_generic_upload(const DmaTransfer& tf, const u8* ee_
vram.tex_width = upload->width;
vram.tex_height = upload->height;
memcpy(vram.data.data(), ee_mem + upload->data, vram.data.size());
if (m_tex_looking_for_clut) {
m_tex_looking_for_clut->cbp = upload->dest;
}
m_tex_looking_for_clut = nullptr;
if (upload->force_to_gpu) {
m_erased_on_this_frame.insert(upload->dest);
@@ -1100,6 +1140,17 @@ void TextureAnimator::handle_generic_upload(const DmaTransfer& tf, const u8* ee_
m_erased_on_this_frame.insert(upload->dest);
}
break;
case (int)GsTex0::PSM::PSMT4:
vram.kind = VramEntry::Kind::GENERIC_PSMT4;
vram.data.resize(upload->width * upload->height);
vram.tex_width = upload->width;
vram.tex_height = upload->height;
memcpy(vram.data.data(), ee_mem + upload->data, vram.data.size());
m_tex_looking_for_clut = &vram;
if (upload->force_to_gpu) {
m_erased_on_this_frame.insert(upload->dest);
}
break;
default:
fmt::print("Unhandled format: {}\n", upload->format);
ASSERT_NOT_REACHED();
@@ -20,7 +20,14 @@
struct GpuTexture;
struct VramEntry {
enum class Kind { CLUT16_16_IN_PSM32, GENERIC_PSM32, GENERIC_PSMT8, GPU, INVALID } kind;
enum class Kind {
CLUT16_16_IN_PSM32,
GENERIC_PSM32,
GENERIC_PSMT8,
GENERIC_PSMT4,
GPU,
INVALID
} kind;
std::vector<u8> data;
int tex_width = 0;
@@ -26,6 +26,9 @@ void TextureUploadHandler::render(DmaFollower& dma,
// this is the data we get from the PC Port modification.
m_upload_count = 0;
std::vector<TextureUpload> uploads;
if (m_direct) {
m_direct->reset_state();
}
// loop through all data, grabbing buckets
while (dma.current_tag_offset() != render_state->next_bucket) {
auto dma_tag = dma.current_tag();
+55 -19
View File
@@ -584,6 +584,33 @@
)
)
(defun pc-upload-subtitle-texture ((dma-buf dma-buffer) (image-data pointer) (clut-data pointer) (width int) (height int) (tbp int) (cbp int))
"Added PC-port function to send a mt4 texture."
(pc-texture-anim-flag start-anim-array dma-buf)
(pc-texture-anim-flag upload-generic-vram dma-buf :qwc 1)
(let ((upload-record (the texture-anim-pc-upload (-> dma-buf base))))
(set! (-> upload-record data) clut-data)
(set! (-> upload-record width) 2)
(set! (-> upload-record height) 8)
(set! (-> upload-record dest) cbp)
(set! (-> upload-record format) (gs-psm ct32))
(set! (-> upload-record force-to-gpu) 0)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag upload-generic-vram dma-buf :qwc 1)
(let ((upload-record (the texture-anim-pc-upload (-> dma-buf base))))
(set! (-> upload-record data) image-data)
(set! (-> upload-record width) width)
(set! (-> upload-record height) height)
(set! (-> upload-record dest) tbp)
(set! (-> upload-record format) (gs-psm mt4))
(set! (-> upload-record force-to-gpu) 1)
)
(&+! (-> dma-buf base) 16)
(pc-texture-anim-flag finish-anim-array dma-buf)
)
;; WARN: Return type mismatch pointer vs none.
(defun draw-subtitle-image ((arg0 subtitle-image) (arg1 font-context))
(local-vars (sv-16 pointer) (sv-32 int))
@@ -598,29 +625,39 @@
(with-dma-buffer-add-bucket ((s3-0 (-> *display* frames (-> *display* on-screen) global-buf))
(bucket-id subtitle)
)
(upload-vram-data s3-0 0 (-> arg0 palette) 2 8)
;; (upload-vram-data s3-0 0 (-> arg0 palette) 2 8)
(let ((s0-0 20))
(dma-buffer-add-gs-set s3-0
(bitbltbuf (new 'static 'gs-bitbltbuf :dbp #x1 :dbw (shr gp-0 6) :dpsm s0-0))
(trxpos (new 'static 'gs-trxpos))
(trxreg (new 'static 'gs-trxreg :rrw gp-0 :rrh s5-0))
(trxdir (new 'static 'gs-trxdir))
)
(let ((t9-2 dma-buffer-add-ref-texture)
(a0-13 s3-0)
(a2-8 gp-0)
(a3-1 s5-0)
(t0-1 s0-0)
)
(t9-2 a0-13 sv-16 (the-as int a2-8) (the-as int a3-1) (the-as gs-psm t0-1))
(pc-upload-subtitle-texture
s3-0 ;; dma-buf
sv-16 ;; image data
(-> arg0 palette) ;; clut data
(the int (-> arg0 width))
(the int (-> arg0 height))
1 ;; tbp
0 ;; cbp
)
; (dma-buffer-add-gs-set s3-0
; (bitbltbuf (new 'static 'gs-bitbltbuf :dbp #x1 :dbw (shr gp-0 6) :dpsm s0-0))
; (trxpos (new 'static 'gs-trxpos))
; (trxreg (new 'static 'gs-trxreg :rrw gp-0 :rrh s5-0))
; (trxdir (new 'static 'gs-trxdir))
; )
; (let ((t9-2 dma-buffer-add-ref-texture)
; (a0-13 s3-0)
; (a2-8 gp-0)
; (a3-1 s5-0)
; (t0-1 s0-0)
; )
; (t9-2 a0-13 sv-16 (the-as int a2-8) (the-as int a3-1) (the-as gs-psm t0-1))
; )
(set! sv-32 (+ (log2 (the-as int (+ gp-0 -1))) 1))
(let ((v1-17 (+ (log2 (the-as int (+ s5-0 -1))) 1)))
(dma-buffer-add-gs-set s3-0
(test-1 (new 'static 'gs-test :ate #x1 :afail #x3 :zte #x1 :ztst (gs-ztest always)))
(alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1))
(tex0-1 (new 'static 'gs-tex0 :tbp0 #x1 :tcc #x1 :cld #x1 :psm s0-0 :th v1-17 :tw sv-32 :tbw (shr gp-0 6)))
(tex1-1 (new 'static 'gs-tex1))
;; added texture filtering for PC-port here:
(tex1-1 (new 'static 'gs-tex1 :mmag 1 :mmin 1))
(clamp-1 (new 'static 'gs-clamp :wms (gs-tex-wrap-mode clamp) :wmt (gs-tex-wrap-mode clamp)))
(texflush 0)
)
@@ -737,10 +774,9 @@
(new 'static 'sound-id)
)
)
;; TODO - crashes the game
;; ((subtitle-image)
;; (draw-subtitle-image (the-as subtitle-image s3-0) s2-0)
;; )
((subtitle-image)
(draw-subtitle-image (the-as subtitle-image s3-0) s2-0)
)
(else
(if *debug-segment*
(format *stdcon* "unknown message ~A~%" s3-0)