从 IDirect3DTexture9 向后移植后显示 IDirect3DTexture8 的问题

Issue displaying IDirect3DTexture8 after backporting from IDirect3DTexture9

我正在尝试通过 ID 软件将某人的 Quake 1 的 Direct3d9 端口反向移植到 Direct3d8,以便我可以将它移植到原始 Xbox(仅使用 D3D8 API)。

进行更改以使用 Direct3d8 后,它会在屏幕上显示一些看起来像小方块的混合像素:/(参见图片)。

有人知道这里出了什么问题吗?它与 D3D9 完美配合,是否需要一些额外的参数,我缺少 D3D8 的要求,也许是矩形间距?

传入的数据是 Quake 1 .lmp 2d 图像文件。 "It consists of two integers (width and height) followed by a string of width x height bytes, each of which is an index into the Quake palette"

它已传递给 D3D_ResampleTexture() 函数。

如有任何帮助,我们将不胜感激。

Image output using D3D8

Image output using D3D9

代码:

void D3D_ResampleTexture (image_t *src, image_t *dst)
{
    int y, x , srcpos, srcbase,  dstpos;

    unsigned int *dstdata, *srcdata;

    // take an unsigned pointer to the dest data that we'll actually fill
    dstdata = (unsigned int *) dst->data;

    // easier access to src data for 32 bit resampling
    srcdata = (unsigned int *) src->data;

    // nearest neighbour for now
    for (y = 0, dstpos = 0; y < dst->height; y++)
    {
        srcbase = (y * src->height / dst->height) * src->width;

        for (x = 0; x < dst->width; x++, dstpos++)
        {
            srcpos = srcbase + (x * src->width / dst->width);

            if (src->flags & IMAGE_32BIT)
                dstdata[dstpos] = srcdata[srcpos];
            else if (src->palette)
                dstdata[dstpos] = src->palette[src->data[srcpos]];
            else Sys_Error ("D3D_ResampleTexture: !(flags & IMAGE_32BIT) without palette set");
        }
    }
}


void D3D_LoadTextureStage3 (LPDIRECT3DTEXTURE8/*9*/ *tex, image_t *image)
{
    int i;
    image_t scaled;

    D3DLOCKED_RECT LockRect;

    memset (&LockRect, 0, sizeof(D3DLOCKED_RECT));

    // check scaling here first
    for (scaled.width = 1; scaled.width < image->width; scaled.width *= 2);
    for (scaled.height = 1; scaled.height < image->height; scaled.height *= 2);

    // clamp to max texture size
    if (scaled.width > /*d3d_DeviceCaps.MaxTextureWidth*/640) scaled.width = /*d3d_DeviceCaps.MaxTextureWidth*/640;
    if (scaled.height > /*d3d_DeviceCaps.MaxTextureHeight*/480) scaled.height = /*d3d_DeviceCaps.MaxTextureHeight*/480;


    IDirect3DDevice8/*9*/_CreateTexture(d3d_Device, scaled.width, scaled.height,
    (image->flags & IMAGE_MIPMAP) ? 0 : 1,
    /*(image->flags & IMAGE_MIPMAP) ? D3DUSAGE_AUTOGENMIPMAP :*/ 0,
    (image->flags & IMAGE_ALPHA) ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8,
    D3DPOOL_MANAGED,
    tex
    );

    // lock the texture rectangle
    //(*tex)->LockRect (0, &LockRect, NULL, 0);
    IDirect3DTexture8/*9*/_LockRect(*tex, 0, &LockRect, NULL, 0);

    // fill it in - how we do it depends on the scaling
    if (scaled.width == image->width && scaled.height == image->height)
    {
        // no scaling
        for (i = 0; i < (scaled.width * scaled.height); i++)
        {
            unsigned int p;

            // retrieve the correct texel - this will either be direct or a palette lookup
            if (image->flags & IMAGE_32BIT)
                p = ((unsigned *) image->data)[i];
            else if (image->palette)
                p = image->palette[image->data[i]];
            else Sys_Error ("D3D_LoadTexture: !(flags & IMAGE_32BIT) without palette set");
            // store it back
            ((unsigned *) LockRect.pBits)[i] = p;
        }
    }
    else
    {
        // save out lockbits in scaled data pointer
        scaled.data = (byte *) LockRect.pBits;

        // resample data into the texture
        D3D_ResampleTexture (image, &scaled);
    }

    // unlock it
    //(*tex)->UnlockRect (0);
    IDirect3DTexture8/*9*/_UnlockRect(*tex, 0);

    // tell Direct 3D that we're going to be needing to use this managed resource shortly
    //FIXME
    //(*tex)->PreLoad ();
}


LPDIRECT3DTEXTURE8/*9*/ D3D_LoadTextureStage2 (image_t *image)
{
    d3d_texture_t *tex;

    // look for a match

    // create a new one
    tex = (d3d_texture_t *) malloc (sizeof (d3d_texture_t));

    // link it in
    tex->next = d3d_Textures;
    d3d_Textures = tex;

    // fill in the struct
    tex->LastUsage = 0;
    tex->d3d_Texture = NULL;

    // copy the image
    memcpy (&tex->TexImage, image, sizeof (image_t));

    // upload through direct 3d
    D3D_LoadTextureStage3 (&tex->d3d_Texture, image);

    // return the texture we got
    return tex->d3d_Texture;
}


LPDIRECT3DTEXTURE8/*9*/ D3D_LoadTexture (char *identifier, int width, int height, byte *data, /*bool*/qboolean mipmap, /*bool*/qboolean alpha)
{
    image_t image;

    image.data = data;
    image.flags = 0;
    image.height = height;
    image.width = width;
    image.palette = d_8to24table;

    strcpy (image.identifier, identifier);

    if (mipmap) image.flags |= IMAGE_MIPMAP;
    if (alpha) image.flags |= IMAGE_ALPHA;

    return D3D_LoadTextureStage2 (&image);
}

锁定纹理时,必须观察返回的D3DLOCKED_RECT结构的Pitch成员。您的代码假设所有数据都是连续的,但是 Pitch 可以大于扫描线的宽度,以便允许锁定子区域和缓冲区中没有连续像素的其他布局一个扫描线的结尾到下一个扫描线的开头。

查看 Chapter 4 of my book "The Direct3D Graphics Pipeline" 以查看访问表面并正确使用 Pitch 的示例。

对于遇到此问题的任何其他人,这是由于图像加载到 Xbox 内存的方式所致,需要对其进行调整。