diff --git a/audit/history.jsonl b/audit/history.jsonl index a92ee584..69996b5e 100644 --- a/audit/history.jsonl +++ b/audit/history.jsonl @@ -625,3 +625,9 @@ {"date": "2026-09-30", "unit": "EterImageLib/Image.cpp", "action": "port", "evidence": "verbatim; port.eter_image"} {"date": "2026-09-30", "unit": "EterImageLib/TGAImage.cpp", "action": "port", "evidence": "verbatim; raw save/load flips (desc 0x08), RLE load; port.eter_image"} {"date": "2026-09-30", "unit": "EterImageLib/DXTCImage.cpp", "action": "port", "evidence": "verbatim + DWORD_PTR casts + ddraw shim; -fno-strict-aliasing for MSVC type punning; port.eter_image"} +{"date": "2026-09-30", "unit": "EterLib/GrpTexture.cpp", "action": "port", "evidence": "verbatim except the handle release; SetTextureStage now binds through STATEMANAGER (SnowEnvironment); port.grp_resource"} +{"date": "2026-09-30", "unit": "EterLib/GrpImage.cpp", "action": "port", "evidence": "verbatim; port.grp_resource"} +{"date": "2026-09-30", "unit": "EterLib/GrpSubImage.cpp", "action": "port", "evidence": "verbatim (resource names use '\\\\', so the 2.0 path split matches); port.grp_resource"} +{"date": "2026-09-30", "unit": "EterLib/GrpImageTexture.cpp", "action": "port", "evidence": "40250 flow: pack reload in CreateDeviceObjects, CDXTCImage header check + CreateDDSTexture size/mip bias, CreateFromDiskFile; handles stay platform textures; port.grp_resource"} +{"date": "2026-09-30", "unit": "EterLib/GrpIndexBuffer.cpp", "action": "port", "evidence": "CPU buffers, bodies otherwise 40250; port.grp_resource"} +{"date": "2026-09-30", "unit": "EterLib/GrpVertexBuffer.cpp", "action": "port", "evidence": "CPU buffers, bodies otherwise 40250; port.grp_resource"} diff --git a/audit/port-map/EterLib/GrpImage.cpp.json b/audit/port-map/EterLib/GrpImage.cpp.json new file mode 100644 index 00000000..5bae8bdc --- /dev/null +++ b/audit/port-map/EterLib/GrpImage.cpp.json @@ -0,0 +1,134 @@ +{ + "reference": "EterLib/GrpImage.cpp", + "reference_sha256": "1966e1d5eaf45ad2391a1e71e42e3c7c30408aed246a1dc79be428396382837d", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicImage::CGraphicImage": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::CGraphicImage" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::~CGraphicImage": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::~CGraphicImage" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::CreateDeviceObjects": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::CreateDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::DestroyDeviceObjects": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::DestroyDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::Type": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::Type" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::OnIsType": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::OnIsType" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::GetWidth": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::GetWidth" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::GetHeight": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::GetHeight" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::GetTextureReference": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::GetTextureReference" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::GetTexturePointer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::GetTexturePointer" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::GetRectReference": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::GetRectReference" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::OnLoad": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::OnLoad" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::OnClear": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::OnClear" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicImage::OnIsEmpty": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImage.cpp:CGraphicImage::OnIsEmpty" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + } + } +} diff --git a/audit/port-map/EterLib/GrpImageTexture.cpp.json b/audit/port-map/EterLib/GrpImageTexture.cpp.json index c19151f4..0e85693d 100644 --- a/audit/port-map/EterLib/GrpImageTexture.cpp.json +++ b/audit/port-map/EterLib/GrpImageTexture.cpp.json @@ -5,56 +5,127 @@ "contracts": [], "functions": { "CGraphicImageTexture::Lock": { - "status": "TODO" + "status": "ADAPTED", + "note": "40250: LockRect on the D3D texture. Port: the memory texture's native bytes in its own format, pitch = width*bpp. Invariant: the font pages write the same A4R4G4B4 words.", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::Lock" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::Unlock": { - "status": "TODO" + "status": "ADAPTED", + "note": "40250: UnlockRect. Port: converts the native pixels to ARGB32 and bumps the revision in the handle name. Invariant: the canvas sees the written pixels after Unlock.", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::Unlock" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::Initialize": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::Initialize" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::Destroy": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::Destroy" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::CreateDeviceObjects": { - "status": "TODO" + "status": "ADAPTED", + "note": "40250: CreateTexture (font) / pack Get + CreateFromMemoryFile. Port: the empty-name branch makes a memory texture; the file branch is verbatim. Invariant: same success/failure and size.", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::CreateDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::Create": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::Create" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::CreateFromTexturePointer": { - "status": "TODO" + "status": "ADAPTED", + "note": "40250: shares the source D3D texture with AddRef. Port: handles are not reference counted, so the copy gets its own handle naming the source's pack path. Invariant: the sub image draws the source file with the source size.", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::CreateFromTexturePointer" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::CreateDDSTexture": { "status": "ADAPTED", "impl": [ - "src/host/dxt.cpp:decode", - "src/host/vk_textures.cpp:get_gpu_texture", - "src/host/vk_textures.cpp:upload_texture" + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::CreateDDSTexture" ], - "test": "tests/port/dxt_decode_test.cpp", - "note": "The platform CreateDDSTexture member is a stub; its level logic lives in the texture decode/upload the renderer does. mipmapCount = max(1, min(dwMipMapCount, MAX_MIPLEVELS=12)), level i read at sum(dwLinearSize>>2k) with CDXTCImage::Copy's dwLinearSize>>2i bytes (the rest zero, uninitialised in 40250), decoded to RGBA8 (no GPU DXT) and uploaded as file levels, not regenerated. Divergence: without DDSD_MIPMAPCOUNT, or with DDSD_PITCH, 40250 creates the extra levels uninitialised; here that is one level. IsLowTextureMemory's uTexBias level skip is not applied (the port's ms_isLowTextureMemory is false). The far-terrain look NEEDS_LIVE." + "test": [ + "tests/port/port_grp_resource_test.cpp" + ], + "note": "40250: D3DXCreateTexture + per-level LockRect/Copy (and an A4R4G4B4/A1R5G5B5 copy without DXT support). Port: a file handle; the renderers decode the .dds. Invariant: the size, including the low-texture-memory top-mip skip, is 40250's." }, "CGraphicImageTexture::CreateFromMemoryFile": { "status": "ADAPTED", "impl": [ - "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::CreateFromMemoryFile", - "src/host/vk_textures.cpp:get_gpu_texture" + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::CreateFromMemoryFile" ], - "test": "tests/port/dxt_decode_test.cpp", - "note": "The platform body records only the size and file name; the renderer decodes the bytes. 40250 dispatch is kept: a DXT DDS takes the CreateDDSTexture levels, anything else takes D3DXCreateTextureFromFileInMemoryEx(MipLevels=D3DX_DEFAULT), i.e. a full generated chain (vkCmdBlitImage linear, instead of D3DX's box filter). The invented is_ui_tex rule (no mips for icon/, ui/, locale/ and textures <=128px) was removed. Memory textures (mem:, 40250 CreateTexture levels=1) get one level. GRAPHICS_CAPS_HALF_SIZE_IMAGE/low-memory A4R4G4B4 re-encode is not applied." + "test": [ + "tests/port/port_grp_resource_test.cpp" + ], + "note": "40250: LoadHeaderFromMemory → CreateDDSTexture, else D3DXCreateTextureFromFileInMemoryEx. Port: same DDS check (only when the buffer holds 128 bytes), else the size is read from the DDS/PNG/JPEG/BMP/TGA header and the canvas decodes. Invariant: same width/height and failure on undecodable bytes." }, "CGraphicImageTexture::SetFileName": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::SetFileName" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::CreateFromDiskFile": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::CreateFromDiskFile" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::CGraphicImageTexture": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::CGraphicImageTexture" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] }, "CGraphicImageTexture::~CGraphicImageTexture": { - "status": "TODO" + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpImageTexture.cpp:CGraphicImageTexture::~CGraphicImageTexture" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] } } } diff --git a/audit/port-map/EterLib/GrpIndexBuffer.cpp.json b/audit/port-map/EterLib/GrpIndexBuffer.cpp.json new file mode 100644 index 00000000..07a43c41 --- /dev/null +++ b/audit/port-map/EterLib/GrpIndexBuffer.cpp.json @@ -0,0 +1,123 @@ +{ + "reference": "EterLib/GrpIndexBuffer.cpp", + "reference_sha256": "ef734b7d12aa0da8881bdb55d9356f932bbfe528c445504c81c816ba004201af", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicIndexBuffer::GetD3DIndexBuffer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::GetD3DIndexBuffer" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::SetIndices": { + "status": "ADAPTED", + "note": "40250: D3D8 index buffer Lock/Unlock/CreateIndexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::SetIndices" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::Lock": { + "status": "ADAPTED", + "note": "40250: D3D8 index buffer Lock/Unlock/CreateIndexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::Lock" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::Unlock": { + "status": "ADAPTED", + "note": "40250: D3D8 index buffer Lock/Unlock/CreateIndexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::Unlock" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::Copy": { + "status": "ADAPTED", + "note": "40250: D3D8 index buffer Lock/Unlock/CreateIndexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::Copy" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::Create": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::Create" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::CreateDeviceObjects": { + "status": "ADAPTED", + "note": "40250: D3D8 index buffer Lock/Unlock/CreateIndexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::CreateDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::DestroyDeviceObjects": { + "status": "ADAPTED", + "note": "40250: D3D8 index buffer Lock/Unlock/CreateIndexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::DestroyDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::Destroy": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::Destroy" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::Initialize": { + "status": "ADAPTED", + "note": "40250: leaves m_iidxCount/m_dwBufferSize unset. Port: zeroes them. Invariant: every 40250 reader runs after Create, which sets both.", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::Initialize" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::CGraphicIndexBuffer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::CGraphicIndexBuffer" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicIndexBuffer::~CGraphicIndexBuffer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpIndexBuffer.cpp:CGraphicIndexBuffer::~CGraphicIndexBuffer" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + } + } +} diff --git a/audit/port-map/EterLib/GrpSubImage.cpp.json b/audit/port-map/EterLib/GrpSubImage.cpp.json new file mode 100644 index 00000000..06e4c1ef --- /dev/null +++ b/audit/port-map/EterLib/GrpSubImage.cpp.json @@ -0,0 +1,125 @@ +{ + "reference": "EterLib/GrpSubImage.cpp", + "reference_sha256": "b0fd32d1c7cd5b11d932acfda8caaa44db8cb222ba68d834950db5f15870103b", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicSubImage::Type": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::Type" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::CGraphicSubImage": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::CGraphicSubImage" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::~CGraphicSubImage": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::~CGraphicSubImage" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::CreateDeviceObjects": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::CreateDeviceObjects" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::SetImagePointer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::SetImagePointer" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::SetImageFileName": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::SetImageFileName" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::SetRectPosition": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::SetRectPosition" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::SetRectReference": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::SetRectReference" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::SetSearchPath": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::SetSearchPath" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::OnLoad": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::OnLoad" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::OnClear": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::OnClear" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::OnIsEmpty": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::OnIsEmpty" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + }, + "CGraphicSubImage::OnIsType": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpSubImage.cpp:CGraphicSubImage::OnIsType" + ], + "test": [ + "build/native/src/host/mt_native_render --live-client (UI sub images)" + ] + } + } +} diff --git a/audit/port-map/EterLib/GrpTexture.cpp.json b/audit/port-map/EterLib/GrpTexture.cpp.json new file mode 100644 index 00000000..36c44b11 --- /dev/null +++ b/audit/port-map/EterLib/GrpTexture.cpp.json @@ -0,0 +1,99 @@ +{ + "reference": "EterLib/GrpTexture.cpp", + "reference_sha256": "82f803e743bc476e87eaff32919cc9d8e77bf09cf5aff90b093f3e041f42a8d2", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicTexture::DestroyDeviceObjects": { + "status": "ADAPTED", + "note": "40250: safe_release(m_lpd3dTexture). Port: UIRenderReleaseMemoryTexture frees the platform handle. Invariant: the handle is gone and m_lpd3dTexture is NULL.", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::DestroyDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::Destroy": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::Destroy" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::Initialize": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::Initialize" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::IsEmpty": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::IsEmpty" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::SetTextureStage": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::SetTextureStage" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::GetD3DTexture": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::GetD3DTexture" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::GetWidth": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::GetWidth" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::GetHeight": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::GetHeight" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::CGraphicTexture": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::CGraphicTexture" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicTexture::~CGraphicTexture": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpTexture.cpp:CGraphicTexture::~CGraphicTexture" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + } + } +} diff --git a/audit/port-map/EterLib/GrpVertexBuffer.cpp.json b/audit/port-map/EterLib/GrpVertexBuffer.cpp.json new file mode 100644 index 00000000..f23f498d --- /dev/null +++ b/audit/port-map/EterLib/GrpVertexBuffer.cpp.json @@ -0,0 +1,171 @@ +{ + "reference": "EterLib/GrpVertexBuffer.cpp", + "reference_sha256": "0c6f3f6331b7e837f4a38f4b4a9993a158081dcd80d7f4f8a84f947a4fbe49fd", + "priority": "P4", + "contracts": [], + "functions": { + "CGraphicVertexBuffer::GetVertexStride": { + "status": "ADAPTED", + "note": "40250: D3DXGetFVFVertexSize. Port: mt_fvf_vertex_size, the same D3D8 FVF size rule. Invariant: equal stride for every FVF.", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::GetVertexStride" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::GetFlexibleVertexFormat": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::GetFlexibleVertexFormat" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::GetVertexCount": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::GetVertexCount" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::SetStream": { + "status": "ADAPTED", + "note": "40250: assert(ms_lpd3dDevice) + STATEMANAGER.SetStreamSource. Port: without the assert (CPU buffers exist without a device). Invariant: same stream binding.", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::SetStream" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::LockRange": { + "status": "ADAPTED", + "note": "40250: D3D8 vertex buffer Lock/Unlock/CreateVertexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::LockRange" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::Lock": { + "status": "ADAPTED", + "note": "40250: D3D8 vertex buffer Lock/Unlock/CreateVertexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::Lock" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::Unlock": { + "status": "ADAPTED", + "note": "40250: D3D8 vertex buffer Lock/Unlock/CreateVertexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::Unlock" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::IsEmpty": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::IsEmpty" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::LockDynamic": { + "status": "ADAPTED", + "note": "40250: D3D8 vertex buffer Lock/Unlock/CreateVertexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::LockDynamic" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::Copy": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::Copy" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::CreateDeviceObjects": { + "status": "ADAPTED", + "note": "40250: D3D8 vertex buffer Lock/Unlock/CreateVertexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::CreateDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::DestroyDeviceObjects": { + "status": "ADAPTED", + "note": "40250: D3D8 vertex buffer Lock/Unlock/CreateVertexBuffer/Release. Port: CPU memory (CpuBuffer.h MtCpu*Buffer); Lock hands out the bytes, Unlock bumps the revision the renderer re-uploads on. Invariant: the same bytes and sizes reach the draw; no device needed (Granny loader thread).", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::DestroyDeviceObjects" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::Create": { + "status": "ADAPTED", + "note": "40250: D3DXGetFVFVertexSize(fvf)*count, assert(device). Port: mt_fvf_vertex_size, no device assert (CPU buffers). Invariant: same buffer size.", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::Create" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::Destroy": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::Destroy" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::Initialize": { + "status": "ADAPTED", + "note": "40250: leaves m_dwFVF unset. Port: zeroes it. Invariant: every 40250 reader runs after Create, which sets it.", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::Initialize" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::CGraphicVertexBuffer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::CGraphicVertexBuffer" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + }, + "CGraphicVertexBuffer::~CGraphicVertexBuffer": { + "status": "PORTED", + "impl": [ + "src/platform/EterLib/GrpVertexBuffer.cpp:CGraphicVertexBuffer::~CGraphicVertexBuffer" + ], + "test": [ + "tests/port/port_grp_resource_test.cpp" + ] + } + } +} diff --git a/src/platform/EterLib/GrpImage.cpp b/src/platform/EterLib/GrpImage.cpp index 15553856..ff339fcc 100644 --- a/src/platform/EterLib/GrpImage.cpp +++ b/src/platform/EterLib/GrpImage.cpp @@ -1,82 +1,93 @@ -// Platform skeleton for EterLib/GrpImage.h (40250 EterLib/GrpImage.cpp), generated by platform_stub.py. -// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation. +// 40250 EterLib/GrpImage.cpp, verbatim. #include "EterLib/StdAfx.h" #include "EterLib/GrpImage.h" -#include "../PlatformStub.h" - -auto CGraphicImage::Type() -> TType +CGraphicImage::CGraphicImage(const char * c_szFileName, DWORD dwFilter) : +CResource(c_szFileName), +m_dwFilter(dwFilter) { - static TType type = StringToType("CGraphicImage"); - return type; -} - -CGraphicImage::CGraphicImage(const char * c_szFileName, DWORD dwFilter) : CResource(c_szFileName), m_dwFilter(dwFilter) // initializers as in 40250 -{ - m_rect = {0, 0, 0, 0}; + m_rect.bottom = m_rect.right = m_rect.top = m_rect.left = 0; } CGraphicImage::~CGraphicImage() { - MT_PLATFORM_STUB(); } -auto CGraphicImage::CreateDeviceObjects() -> bool +bool CGraphicImage::CreateDeviceObjects() { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + return m_imageTexture.CreateDeviceObjects(); } -auto CGraphicImage::DestroyDeviceObjects() -> void +void CGraphicImage::DestroyDeviceObjects() { - MT_PLATFORM_STUB(); + m_imageTexture.DestroyDeviceObjects(); } -auto CGraphicImage::GetWidth() const -> int +CGraphicImage::TType CGraphicImage::Type() +{ + static TType s_type = StringToType("CGraphicImage"); + return s_type; +} + +bool CGraphicImage::OnIsType(TType type) +{ + if (CGraphicImage::Type() == type) + return true; + + return CResource::OnIsType(type); +} + +int CGraphicImage::GetWidth() const { return m_rect.right - m_rect.left; } -auto CGraphicImage::GetHeight() const -> int +int CGraphicImage::GetHeight() const { return m_rect.bottom - m_rect.top; } -auto CGraphicImage::GetRectReference() const -> const RECT & -{ - return m_rect; -} - -auto CGraphicImage::GetTextureReference() const -> const CGraphicTexture & +const CGraphicTexture& CGraphicImage::GetTextureReference() const { return m_imageTexture; } -auto CGraphicImage::GetTexturePointer() -> CGraphicTexture * +CGraphicTexture* CGraphicImage::GetTexturePointer() { return &m_imageTexture; } -auto CGraphicImage::OnLoad(int size, const void *data) -> bool +const RECT& CGraphicImage::GetRectReference() const { - m_imageTexture.SetFileName(GetFileName()); - if (!m_imageTexture.CreateFromMemoryFile(size, data, D3DFMT_UNKNOWN, m_dwFilter)) return false; - m_rect = {0, 0, m_imageTexture.GetWidth(), m_imageTexture.GetHeight()}; + return m_rect; +} + +bool CGraphicImage::OnLoad(int iSize, const void * c_pvBuf) +{ + if (!c_pvBuf) + return false; + + m_imageTexture.SetFileName(CResource::GetFileName()); + + // 특정 컴퓨터에서 Unknown으로 '안'하면 튕기는 현상이 있음-_-; -비엽 + if (!m_imageTexture.CreateFromMemoryFile(iSize, c_pvBuf, D3DFMT_UNKNOWN, m_dwFilter)) + return false; + + m_rect.left = 0; + m_rect.top = 0; + m_rect.right = m_imageTexture.GetWidth(); + m_rect.bottom = m_imageTexture.GetHeight(); return true; } -auto CGraphicImage::OnClear() -> void +void CGraphicImage::OnClear() { +// Tracef("Image Destroy : %s\n", m_pszFileName); m_imageTexture.Destroy(); - m_rect = {0, 0, 0, 0}; + memset(&m_rect, 0, sizeof(m_rect)); } -auto CGraphicImage::OnIsEmpty() const -> bool +bool CGraphicImage::OnIsEmpty() const { return m_imageTexture.IsEmpty(); } - -auto CGraphicImage::OnIsType(TType type) -> bool -{ - return type == Type() || CResource::OnIsType(type); -} diff --git a/src/platform/EterLib/GrpImageTexture.cpp b/src/platform/EterLib/GrpImageTexture.cpp index e2370873..5ee10a4e 100644 --- a/src/platform/EterLib/GrpImageTexture.cpp +++ b/src/platform/EterLib/GrpImageTexture.cpp @@ -1,9 +1,13 @@ -// Platform skeleton for EterLib/GrpImageTexture.h (40250 EterLib/GrpImageTexture.cpp), generated by platform_stub.py. -// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation. +// 40250 EterLib/GrpImageTexture.cpp. The control flow (pack lookup, the DDS header check, the +// DXT/low-texture-memory mip bias) is 40250's; the D3D8 texture objects become platform handles: +// a memory texture (Create: the font pages, Lock/Unlock) or a file texture that carries the pack path, +// decoded by the canvas and the 3D renderer themselves (D3DXCreateTexture*/LockRect/LoadSurface). #include "EterLib/StdAfx.h" #include "EterLib/GrpImageTexture.h" +#include "EterBase/MappedFile.h" +#include "EterPack/EterPackManager.h" +#include "EterImageLib/DXTCImage.h" -#include "../PlatformStub.h" #include "UIRenderCommands.h" #include @@ -183,6 +187,7 @@ auto CGraphicImageTexture::Destroy() -> void auto CGraphicImageTexture::Create(UINT width, UINT height, D3DFORMAT d3dFmt, DWORD dwFilter) -> bool { + assert(ms_lpd3dDevice != NULL); Destroy(); m_width = width; @@ -216,9 +221,13 @@ auto CGraphicImageTexture::CreateDeviceObjects() -> bool } else { - // PORT: file textures are decoded by the canvas from the pack path; only their size is read here - // (CreateFromMemoryFile), so there is no device object to recreate. - return !m_bEmpty; + CMappedFile mappedFile; + LPCVOID c_pvMap; + + if (!CEterPackManager::Instance().Get(mappedFile, m_stFileName.c_str(), &c_pvMap)) + return false; + + return CreateFromMemoryFile(mappedFile.Size(), c_pvMap, m_d3dFmt, m_dwFilter); } m_bEmpty = false; @@ -241,15 +250,31 @@ auto CGraphicImageTexture::CreateFromTexturePointer(const CGraphicTexture *sourc m_lpd3dTexture = new_file_texture(m_stFileName); } -auto CGraphicImageTexture::CreateFromDiskFile(const char *, D3DFORMAT, DWORD) -> bool +auto CGraphicImageTexture::CreateFromDiskFile(const char * c_szFileName, D3DFORMAT d3dFmt, DWORD dwFilter) -> bool { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + Destroy(); + + SetFileName(c_szFileName); + + m_d3dFmt = d3dFmt; + m_dwFilter = dwFilter; + return CreateDeviceObjects(); } auto CGraphicImageTexture::CreateFromMemoryFile(UINT size, const void *bytes, D3DFORMAT, DWORD) -> bool { + assert(ms_lpd3dDevice != NULL); if (!bytes) return false; + + static CDXTCImage image; + + // PORT: the size check; 40250 reads the 128-byte DDS header (magic + DDSURFACEDESC2) from any buffer. + if (size >= 128 && image.LoadHeaderFromMemory((const BYTE *) bytes)) // DDS인가 확인 + { + return (CreateDDSTexture(image, (const BYTE *) bytes)); + } + + // PORT: D3DXCreateTextureFromFileInMemoryEx — only the image size is read here (the canvas decodes the file). const auto* data = static_cast(bytes); unsigned width = 0, height = 0; if (size >= 20 && std::memcmp(data, "DDS ", 4) == 0) { @@ -272,15 +297,38 @@ auto CGraphicImageTexture::CreateFromMemoryFile(UINT size, const void *bytes, D3 return true; } -auto CGraphicImageTexture::CreateDDSTexture(CDXTCImage &, const BYTE *) -> bool +// PORT: D3DXCreateTexture + LockRect/Copy per level; the renderers decode the .dds from the pack path. +// The size (and the low-texture-memory top-mip skip it implies) is 40250's. +auto CGraphicImageTexture::CreateDDSTexture(CDXTCImage & image, const BYTE * /*c_pbBuf*/) -> bool { - MT_PLATFORM_STUB(); - return mt_platform_stub_return(); + int mipmapCount = image.m_dwMipMapCount == 0 ? 1 : image.m_dwMipMapCount; + + UINT uTexBias=0; + if (IsLowTextureMemory()) + uTexBias=1; + + if (uTexBias>0) + { + if (mipmapCount>uTexBias) + { + image.m_nWidth>>=uTexBias; + image.m_nHeight>>=uTexBias; + } + } + + DestroyDeviceObjects(); + m_lpd3dTexture = new_file_texture(m_stFileName); + + m_width = image.m_nWidth; + m_height = image.m_nHeight; + m_bEmpty = false; + + return true; } auto CGraphicImageTexture::SetFileName(const char *name) -> void { - m_stFileName = name ? name : ""; + m_stFileName=name; } // PORT: where 40250 binds pTexture->GetD3DTexture(), the canvas gets the pack path of the file the diff --git a/src/platform/EterLib/GrpSubImage.cpp b/src/platform/EterLib/GrpSubImage.cpp index c0acbf45..45f058cc 100644 --- a/src/platform/EterLib/GrpSubImage.cpp +++ b/src/platform/EterLib/GrpSubImage.cpp @@ -1,100 +1,157 @@ +// 40250 EterLib/GrpSubImage.cpp, verbatim. #include "EterLib/StdAfx.h" +#include "EterBase/Stl.h" +#include "EterBase/FileLoader.h" #include "EterLib/GrpSubImage.h" #include "EterLib/ResourceManager.h" -#include -#include -#include -#include -#include -#include -#include - char CGraphicSubImage::m_SearchPath[256] = "D:/Ymir Work/UI/"; -auto CGraphicSubImage::Type() -> TType +CGraphicSubImage::TType CGraphicSubImage::Type() { - static TType type = StringToType("CGraphicSubImage"); - return type; + static TType s_type = StringToType("CGraphicSubImage"); + return s_type; } -CGraphicSubImage::CGraphicSubImage(const char* name) : CGraphicImage(name) {} -CGraphicSubImage::~CGraphicSubImage() { m_roImage.Clear(); } +CGraphicSubImage::CGraphicSubImage(const char* c_szFileName) : CGraphicImage(c_szFileName) +{ +} + +CGraphicSubImage::~CGraphicSubImage() +{ + m_roImage = NULL; +} bool CGraphicSubImage::CreateDeviceObjects() { - if (m_roImage.IsNull()) return false; m_imageTexture.CreateFromTexturePointer(m_roImage->GetTexturePointer()); return true; } -void CGraphicSubImage::SetImagePointer(CGraphicImage* image) +void CGraphicSubImage::SetImagePointer(CGraphicImage* pImage) { - m_roImage.SetPointer(image); + m_roImage = pImage; CreateDeviceObjects(); } -bool CGraphicSubImage::SetImageFileName(const char* name) +bool CGraphicSubImage::SetImageFileName(const char* c_szFileName) { - CResource* resource = CResourceManager::Instance().GetResourcePointer(name); - if (!resource || !resource->IsType(CGraphicImage::Type())) return false; - SetImagePointer(static_cast(resource)); + CResource* pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName); + + if (!pResource->IsType(CGraphicImage::Type())) + return false; + + SetImagePointer(static_cast(pResource)); return true; } void CGraphicSubImage::SetRectPosition(int left, int top, int right, int bottom) { - m_rect = {left, top, right, bottom}; + m_rect.left = left; + m_rect.top = top; + m_rect.right = right; + m_rect.bottom = bottom; } -void CGraphicSubImage::SetRectReference(const RECT& rect) { m_rect = rect; } - -void CGraphicSubImage::SetSearchPath(const char* path) +void CGraphicSubImage::SetRectReference(const RECT& c_rRect) { - if (!path) return; - std::strncpy(m_SearchPath, path, sizeof(m_SearchPath) - 1); - m_SearchPath[sizeof(m_SearchPath) - 1] = 0; + m_rect = c_rRect; } -bool CGraphicSubImage::OnLoad(int size, const void* bytes) +void CGraphicSubImage::SetSearchPath(const char * c_szFileName) { - if (!bytes || size <= 0) return false; - std::istringstream input(std::string(static_cast(bytes), static_cast(size))); - std::map tokens; - std::string line; - while (std::getline(input, line)) { - std::istringstream fields(line); - std::string key, value; - if (!(fields >> key >> value)) continue; - if (!value.empty() && value.front() == '"') { - value.erase(0, 1); - if (!value.empty() && value.back() == '"') value.pop_back(); + strncpy(m_SearchPath, c_szFileName, sizeof(m_SearchPath)-1); +} + +bool CGraphicSubImage::OnLoad(int iSize, const void* c_pvBuf) +{ + if (!c_pvBuf) + return false; + + CTokenVector stTokenVector; + std::map stTokenMap; + + CMemoryTextFileLoader textFileLoader; + + textFileLoader.Bind(iSize, c_pvBuf); + + for (DWORD i = 0; i < textFileLoader.GetLineCount(); ++i) + { + if (!textFileLoader.SplitLine(i, &stTokenVector)) + continue; + + if (stTokenVector.size() != 2) + return false; + + stl_lowers(stTokenVector[0]); + stl_lowers(stTokenVector[1]); + + stTokenMap[stTokenVector[0]] = stTokenVector[1]; + } + + const std::string& c_rstTitle = stTokenMap["title"]; + const std::string& c_rstVersion = stTokenMap["version"]; + const std::string& c_rstImage = stTokenMap["image"]; + const std::string& c_rstLeft = stTokenMap["left"]; + const std::string& c_rstTop = stTokenMap["top"]; + const std::string& c_rstRight = stTokenMap["right"]; + const std::string& c_rstBottom = stTokenMap["bottom"]; + + if (c_rstTitle != "subimage") + return false; + + char szFileName[256]; + if ("2.0"==c_rstVersion) + { + const std::string& c_rstSubFileName=GetFileNameString(); + int nPos=c_rstSubFileName.find_last_of('\\', -1); + if (nPos>=0) + { + nPos++; + memcpy(szFileName, c_rstSubFileName.c_str(), nPos); + szFileName[nPos]='\0'; + memcpy(szFileName+nPos, c_rstImage.c_str(), c_rstImage.length()); + szFileName[nPos+c_rstImage.length()]='\0'; + } + else + { + memcpy(szFileName, c_rstImage.c_str(), c_rstImage.length()); } - std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c) { return std::tolower(c); }); - std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return std::tolower(c); }); - tokens[key] = value; } - if (tokens["title"] != "subimage" || tokens["image"].empty()) return false; - std::string image_path; - if (tokens["version"] == "2.0") { - const std::string parent = GetFileNameString(); - const auto slash = parent.find_last_of("\\/"); - image_path = slash == std::string::npos ? tokens["image"] : parent.substr(0, slash + 1) + tokens["image"]; - } else { - image_path = std::string(m_SearchPath) + tokens["image"]; + else + { + _snprintf(szFileName, sizeof(szFileName), "%s%s", m_SearchPath, c_rstImage.c_str()); } - if (!SetImageFileName(image_path.c_str())) return false; - SetRectPosition(std::atoi(tokens["left"].c_str()), std::atoi(tokens["top"].c_str()), - std::atoi(tokens["right"].c_str()), std::atoi(tokens["bottom"].c_str())); + + SetImageFileName(szFileName); + + SetRectPosition(atoi(c_rstLeft.c_str()), + atoi(c_rstTop.c_str()), + atoi(c_rstRight.c_str()), + atoi(c_rstBottom.c_str())); + return true; } void CGraphicSubImage::OnClear() { - m_roImage.Clear(); - m_imageTexture.Destroy(); - m_rect = {0, 0, 0, 0}; + m_roImage = NULL; + memset(&m_rect, 0, sizeof(m_rect)); } -bool CGraphicSubImage::OnIsEmpty() const { return m_roImage.IsNull() || m_roImage->IsEmpty(); } -bool CGraphicSubImage::OnIsType(TType type) { return type == Type() || CGraphicImage::OnIsType(type); } +bool CGraphicSubImage::OnIsEmpty() const +{ + if (!m_roImage.IsNull()) + if (!m_roImage->IsEmpty()) + return false; + + return true; +} + +bool CGraphicSubImage::OnIsType(TType type) +{ + if (CGraphicSubImage::Type() == type) + return true; + + return CGraphicImage::OnIsType(type); +} diff --git a/src/platform/EterLib/GrpTexture.cpp b/src/platform/EterLib/GrpTexture.cpp index 746d304e..ec362ca6 100644 --- a/src/platform/EterLib/GrpTexture.cpp +++ b/src/platform/EterLib/GrpTexture.cpp @@ -1,9 +1,9 @@ -// Platform skeleton for EterLib/GrpTexture.h (40250 EterLib/GrpTexture.cpp), generated by platform_stub.py. -// Every MT_PLATFORM_STUB() body is unimplemented: replace it with the platform implementation. +// 40250 EterLib/GrpTexture.cpp. m_lpd3dTexture is a platform texture handle: RecordingDevice resolves +// it by name (UIRenderTextureNameFromHandle), and UIRenderReleaseMemoryTexture frees it. #include "EterLib/StdAfx.h" #include "EterLib/GrpTexture.h" -#include "../PlatformStub.h" +#include "EterLib/StateManager.h" #include "UIRenderCommands.h" auto CGraphicTexture::IsEmpty() const -> bool @@ -21,9 +21,10 @@ auto CGraphicTexture::GetHeight() const -> int return m_height; } -auto CGraphicTexture::SetTextureStage(int) const -> void +auto CGraphicTexture::SetTextureStage(int stage) const -> void { - MT_PLATFORM_STUB(); + assert(ms_lpd3dDevice != NULL); + STATEMANAGER.SetTexture(stage, m_lpd3dTexture); } auto CGraphicTexture::GetD3DTexture() const -> LPDIRECT3DTEXTURE8 diff --git a/src/port/CMakeLists.txt b/src/port/CMakeLists.txt index 8b308b4e..54597d2c 100644 --- a/src/port/CMakeLists.txt +++ b/src/port/CMakeLists.txt @@ -214,6 +214,9 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) add_executable(port_eter_image_test ${PROJECT_SOURCE_DIR}/tests/port/port_eter_image_test.cpp) target_link_libraries(port_eter_image_test PRIVATE port_platform) add_test(NAME port.eter_image COMMAND $) + add_executable(port_grp_resource_test ${PROJECT_SOURCE_DIR}/tests/port/port_grp_resource_test.cpp) + target_link_libraries(port_grp_resource_test PRIVATE port_platform) + add_test(NAME port.grp_resource COMMAND $) # MilesLib: the 40250 sound managers over the Miles emulation (platform/MilesLib/MilesAil.cpp). add_executable(port_miles_test ${PROJECT_SOURCE_DIR}/tests/port/port_miles_test.cpp) diff --git a/tests/port/port_grp_resource_test.cpp b/tests/port/port_grp_resource_test.cpp new file mode 100644 index 00000000..14337cf4 --- /dev/null +++ b/tests/port/port_grp_resource_test.cpp @@ -0,0 +1,158 @@ +// 40250 EterLib texture/image/buffer resources on the platform: CGraphicImageTexture (the DDS header check +// and its low-texture-memory mip bias, memory textures), CGraphicImage, CGraphicVertexBuffer/IndexBuffer. +#include "EterLib/StdAfx.h" +#include "EterLib/GrpImage.h" +#include "EterLib/GrpImageTexture.h" +#include "EterLib/GrpIndexBuffer.h" +#include "EterLib/GrpVertexBuffer.h" +#include "../../src/platform/EterLib/CpuBuffer.h" +#include "../../src/platform/EterLib/RecordingDevice.h" +#include "../../src/platform/EterLib/UIRenderCommands.h" + +#include +#include +#include + +namespace { +int g_failures = 0; +void check(bool ok, const char* name) +{ + if (!ok) { + std::fprintf(stderr, "FAIL %s\n", name); + ++g_failures; + } +} + +struct BaseAccess : CGraphicBase +{ + static void SetDevice(IDirect3DDevice8* device) { ms_lpd3dDevice = device; } + static void SetLowTextureMemory(bool low) { ms_isLowTextureMemory = low; } +}; + +// "DDS " + DDSURFACEDESC2 (LINEARSIZE, MIPMAPCOUNT) + the DXT1 levels of a width x height texture. +std::vector MakeDDS(DWORD width, DWORD height, DWORD mips) +{ + std::vector dds(128, 0); + memcpy(&dds[0], "DDS ", 4); + DWORD* h = reinterpret_cast(&dds[4]); + h[0] = 124; + h[1] = 0x1 | 0x2 | 0x4 | 0x1000 | 0x20000 | 0x80000; + h[2] = height; + h[3] = width; + h[4] = width * height / 2; + h[6] = mips; + h[18] = 32; + h[19] = 0x4; + memcpy(&h[20], "DXT1", 4); + for (DWORD size = width * height / 2, i = 0; i < mips; ++i, size >>= 2) + dds.resize(dds.size() + std::max(size, 8), 0); + return dds; +} + +struct ImageAccess : CGraphicImage +{ + ImageAccess(const char* name) : CGraphicImage(name) {} + bool Load(int size, const void* data) { return OnLoad(size, data); } +}; + +std::vector MakePNGHeader(DWORD width, DWORD height) +{ + std::vector png = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n', 0, 0, 0, 13, 'I', 'H', 'D', 'R'}; + for (DWORD v : {width, height}) + for (int shift = 24; shift >= 0; shift -= 8) + png.push_back(BYTE(v >> shift)); + png.resize(160, 0); // past the 128 bytes the DDS header check reads + return png; +} +} + +int main() +{ + IDirect3DDevice8* device = MtCreateRecordingDevice(800, 600); + BaseAccess::SetDevice(device); + BaseAccess::SetLowTextureMemory(false); + + // A DXT .dds goes through CDXTCImage::LoadHeaderFromMemory + CreateDDSTexture; the handle names the file. + { + std::vector dds = MakeDDS(64, 32, 3); + CGraphicImageTexture texture; + texture.SetFileName("d:\\ymir work\\ui\\a.dds"); + check(texture.CreateFromMemoryFile(UINT(dds.size()), dds.data(), D3DFMT_UNKNOWN, 0), "DDS create"); + check(!texture.IsEmpty() && texture.GetWidth() == 64 && texture.GetHeight() == 32, "DDS size"); + check(UIRenderTextureNameFromHandle(texture.GetD3DTexture()) == "d:\\ymir work\\ui\\a.dds", "DDS handle name"); + } + + // Low texture memory skips the top mip of a mipmapped .dds (40250 halves the reported size) ... + BaseAccess::SetLowTextureMemory(true); + { + std::vector dds = MakeDDS(64, 32, 3); + CGraphicImageTexture texture; + texture.SetFileName("b.dds"); + check(texture.CreateFromMemoryFile(UINT(dds.size()), dds.data(), D3DFMT_UNKNOWN, 0), "low-memory DDS create"); + check(texture.GetWidth() == 32 && texture.GetHeight() == 16, "low-memory DDS half size"); + } + // ... but not one with a single level. + { + std::vector dds = MakeDDS(64, 32, 1); + CGraphicImageTexture texture; + texture.SetFileName("c.dds"); + check(texture.CreateFromMemoryFile(UINT(dds.size()), dds.data(), D3DFMT_UNKNOWN, 0) && texture.GetWidth() == 64, + "low-memory single-level DDS keeps its size"); + } + BaseAccess::SetLowTextureMemory(false); + + // Other formats (D3DXCreateTextureFromFileInMemoryEx): the size comes from the file header. + { + std::vector png = MakePNGHeader(300, 200); + CGraphicImageTexture texture; + texture.SetFileName("d.png"); + check(texture.CreateFromMemoryFile(UINT(png.size()), png.data(), D3DFMT_UNKNOWN, 0), "PNG create"); + check(texture.GetWidth() == 300 && texture.GetHeight() == 200, "PNG size"); + check(!texture.CreateFromMemoryFile(4, "junk", D3DFMT_UNKNOWN, 0), "unknown bytes refused"); + } + + // CGraphicImage::OnLoad (CResource::Load with the pack bytes) sets the rect from the texture; Clear empties it. + { + std::vector png = MakePNGHeader(40, 24); + ImageAccess image("e.png"); + check(image.Load(int(png.size()), png.data()), "CGraphicImage OnLoad"); + check(image.GetWidth() == 40 && image.GetHeight() == 24 && image.GetRectReference().right == 40, "CGraphicImage rect"); + image.Clear(); + check(image.IsEmpty() && image.GetRectReference().right == 0, "CGraphicImage Clear"); + } + + // A memory texture (font page): Lock hands out A4R4G4B4 words, Unlock republishes them as ARGB32. + { + CGraphicImageTexture texture; + check(texture.Create(4, 2, D3DFMT_A4R4G4B4, 0) && !texture.IsEmpty(), "memory texture create"); + int pitch = 0; + void* pixels = NULL; + check(texture.Lock(&pitch, &pixels) && pitch == 8, "memory texture lock"); + static_cast(pixels)[5] = 0xF84C; + texture.Unlock(); + UIMemoryTexture out; + const std::string name = UIRenderTextureName(&texture); + check(UIRenderMemoryTexture(name, &out) && out.width == 4 && out.argb[5] == 0xFF8844CC, "memory texture pixels"); + check(name.find("@1") != std::string::npos, "Unlock bumps the revision"); + } + + // Vertex and index buffers keep their bytes in memory; Unlock bumps the revision the renderer checks. + { + CGraphicVertexBuffer vb; + check(vb.Create(3, D3DFVF_XYZ | D3DFVF_DIFFUSE, 0, D3DPOOL_MANAGED) && vb.GetVertexStride() == 16 && vb.GetVertexCount() == 3, + "vertex buffer create"); + const float data[12] = {1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9, 0}; + check(vb.Copy(sizeof(data), data), "vertex buffer copy"); + auto* cpu = static_cast(vb.GetD3DVertexBuffer()); + check(memcmp(cpu->bytes.data(), data, sizeof(data)) == 0 && cpu->revision == 1, "vertex bytes"); + + CGraphicIndexBuffer ib; + TFace faces[2] = {{{0, 1, 2}}, {{2, 1, 3}}}; + check(ib.Create(2, faces) && ib.GetIndexCount() == 6, "index buffer from faces"); + auto* idx = static_cast(ib.GetD3DIndexBuffer()); + const WORD* w = reinterpret_cast(idx->bytes.data()); + check(w[3] == 2 && w[5] == 3 && idx->format == D3DFMT_INDEX16, "index words"); + } + + return g_failures ? 1 : 0; +}