Issue displaying IDirect3DTexture8 after backporting from IDirect3DTexture9

175 Views Asked by At

I'm trying to backport someones Direct3d9 port of Quake 1 by ID software to Direct3d8 so I can port it to the original Xbox (only uses the D3D8 API).

After making the changes to use Direct3d8 it displays some mashed up pixels on the screen that appear to be in little squares :/ (see pictures).

Does anyone know whats gone wrong here? It works flawlessly with D3D9, is there some extra arguments required that I'm missing require for D3D8, rect pitch maybe?

The data been passed in is a Quake 1 .lmp 2d image file. "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"

Its been passed to the D3D_ResampleTexture() function.

Any help would be much appreciated.

Image output using D3D8

Image output using D3D9

The code:

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);
}
2

There are 2 best solutions below

0
On BEST ANSWER

For anyone else that comes across this issue, it was due to the way the image was been loaded into the Xbox's memory, it needed to be swizzled.

0
On

When you lock the texture, you have to observe the returned Pitch member of the D3DLOCKED_RECT structure. Your code is assuming that all the data is contiguous, but the Pitch can be larger than the width of a scanline in order to allow for locking a subregion and other layouts of the buffer that don't have contiguous pixels at the end of one scanline to the beginning of the next.

Look at Chapter 4 of my book "The Direct3D Graphics Pipeline" to see an example of accessing a surface and using the Pitch properly.