mirror of
https://github.com/open-goal/jak-project
synced 2026-06-17 07:08:17 -04:00
[jak2] Support Japanese Subtitles (#2914)

This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user