port: Grp texture/image/buffer units toward 40250 (+ port.grp_resource)
GrpImage/GrpSubImage verbatim; GrpImageTexture DDS path through CDXTCImage header + low-texture-memory mip bias, CreateDeviceObjects/CreateFromDiskFile verbatim; GrpTexture::SetTextureStage via STATEMANAGER. Port-map entries for GrpTexture/Image/SubImage/ImageTexture/IndexBuffer/VertexBuffer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7e385f827b
commit
010e99f070
@@ -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 <cstdio>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
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<BYTE> MakeDDS(DWORD width, DWORD height, DWORD mips)
|
||||
{
|
||||
std::vector<BYTE> dds(128, 0);
|
||||
memcpy(&dds[0], "DDS ", 4);
|
||||
DWORD* h = reinterpret_cast<DWORD*>(&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<DWORD>(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<BYTE> MakePNGHeader(DWORD width, DWORD height)
|
||||
{
|
||||
std::vector<BYTE> 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<BYTE> 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<BYTE> 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<BYTE> 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<BYTE> 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<BYTE> 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<WORD*>(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<MtCpuVertexBuffer*>(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<MtCpuIndexBuffer*>(ib.GetD3DIndexBuffer());
|
||||
const WORD* w = reinterpret_cast<const WORD*>(idx->bytes.data());
|
||||
check(w[3] == 2 && w[5] == 3 && idx->format == D3DFMT_INDEX16, "index words");
|
||||
}
|
||||
|
||||
return g_failures ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user