Files
FC1/BinkSDK/dx8rad3d.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1737 lines
49 KiB
C++

//############################################################################
//## ##
//## D3DRAD3D.CPP ##
//## ##
//## API to use Direct3D for video textures ##
//## ##
//## Author: Jeff Roberts ##
//## ##
//############################################################################
//## ##
//## Copyright (C) RAD Game Tools, Inc. ##
//## ##
//## For technical support, contact RAD Game Tools at 425 - 893 - 4300. ##
//## ##
//############################################################################
#define D3D_OVERLOADS
#include <windows.h>
#include <\devel\libs\dx81\include\d3d8.h> // change to your 8.0 or up path
#include "rad3d.h"
//
// Direct3D RAD3D structure.
//
typedef struct RAD3D
{
LPDIRECT3D8 direct_3d;
LPDIRECT3DDEVICE8 direct_3d_device;
HWND window;
D3DFORMAT d3d_alpha_surface;
D3DFORMAT d3d_surface;
u32 alpha_pixel_size;
u32 pixel_size;
s32 rad_alpha_surface;
s32 rad_surface;
// Device can use non-POW2 textures if:
// 1) D3DTEXTURE_ADDRESS is set to CLAMP for this texture's stage
// 2) D3DRS_WRAP(N) is zero for this texture's coordinates
// 3) mip mapping is not enabled (use magnification filter only)
u32 nonpow2_textures_supported;
} RAD3D;
//############################################################################
//## ##
//## Verify that a texture format is compatible with a specific ##
//## back buffer format. ##
//## ##
//############################################################################
inline u32 is_valid_texture_format(LPDIRECT3D8 direct_3d,
D3DFORMAT TextureFormat, D3DFORMAT AdapterFormat )
{
return SUCCEEDED( direct_3d->CheckDeviceFormat( D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, AdapterFormat, 0, D3DRTYPE_TEXTURE, TextureFormat) );
}
//############################################################################
//## ##
//## Return the appropriate texture format given a backbuffer d3dformat. ##
//## ##
//############################################################################
static s32 get_texture_formats(LPDIRECT3D8 direct_3d,
D3DFORMAT adapter_format, HRAD3D rad_3d )
{
struct
{
D3DFORMAT d3d_format;
s32 rad_surface;
u32 pixel_size;
u32 alpha_pixels;
} format_list[] =
{
{ D3DFMT_X8R8G8B8, RAD3DSURFACE32, 4, 0 },
{ D3DFMT_R8G8B8, RAD3DSURFACE24, 3, 0 },
{ D3DFMT_R5G6B5, RAD3DSURFACE565, 2, 0 },
{ D3DFMT_X1R5G5B5, RAD3DSURFACE555, 2, 0 },
{ D3DFMT_A8R8G8B8, RAD3DSURFACE32A, 4, 1 },
{ D3DFMT_A4R4G4B4, RAD3DSURFACE4444, 2, 1 },
{ D3DFMT_A1R5G5B5, RAD3DSURFACE5551, 2, 1 },
};
u32 num_formats = sizeof(format_list) / sizeof(format_list[0]);
u32 format;
//
// Go through the list of texture formats searching for
// the chosen one. Or at least one that works.
//
for ( format = 0; format < num_formats; format++ )
{
if ( is_valid_texture_format(direct_3d,
format_list[format].d3d_format, adapter_format ) )
{
rad_3d->d3d_surface = format_list[format].d3d_format;
rad_3d->rad_surface = format_list[format].rad_surface;
rad_3d->pixel_size = format_list[format].pixel_size;
break;
}
}
if( format == num_formats)
return( 0 );
//
// Go through the list of texture formats searching for
// a supported alpha format.
//
for ( format = 0; format < num_formats; format++ )
{
if ( format_list[format].alpha_pixels )
{
if ( is_valid_texture_format ( direct_3d,
format_list[format].d3d_format, adapter_format ) )
{
rad_3d->d3d_alpha_surface = format_list[format].d3d_format;
rad_3d->rad_alpha_surface = format_list[format].rad_surface;
rad_3d->alpha_pixel_size = format_list[format].pixel_size;
break;
}
}
}
if( format == num_formats)
return( 0 );
return( 1 );
}
//############################################################################
//## ##
//## Call this function to actually open Direct3D. ##
//## ##
//############################################################################
RADCFUNC HRAD3D Open_RAD_3D( HWND window )
{
D3DDISPLAYMODE d3ddm;
D3DPRESENT_PARAMETERS d3dpp = {0};
LPDIRECT3D8 direct_3d;
LPDIRECT3DDEVICE8 direct_3d_device;
HRAD3D rad_3d;
if( !( direct_3d = Direct3DCreate8( D3D_SDK_VERSION ) ) )
{
return( 0 );
}
if( FAILED( direct_3d->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
{
direct_3d->Release();
return( 0 );
}
//
// try to create a RAD3D structure
//
rad_3d = ( HRAD3D ) malloc( sizeof( RAD3D ) );
if ( rad_3d == 0 )
{
direct_3d->Release( );
return( 0 );
}
//
// get the appropriate texture formats
//
if ( !get_texture_formats( direct_3d, d3ddm.Format, rad_3d ) )
{
direct_3d->Release( );
return( 0 );
}
d3dpp.hDeviceWindow = window;
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;
if( FAILED( direct_3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &direct_3d_device ) ) )
{
free( rad_3d );
direct_3d->Release();
return( 0 );
}
//
// Check if linear (non power 2) textures are supported.
//
D3DCAPS8 Caps;
direct_3d_device->GetDeviceCaps(&Caps);
rad_3d->nonpow2_textures_supported = !!(Caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
//
// Now set the structure values.
//
rad_3d->direct_3d = direct_3d;
rad_3d->direct_3d_device = direct_3d_device;
rad_3d->window = window;
//
// And return the handle.
//
return( rad_3d );
}
//############################################################################
//## ##
//## Call this function to close Direct3D. ##
//## ##
//############################################################################
RADCFUNC void Close_RAD_3D( HRAD3D rad_3d )
{
if ( rad_3d )
{
if ( rad_3d->direct_3d )
{
rad_3d->direct_3d->Release( );
rad_3d->direct_3d = 0;
}
if ( rad_3d->direct_3d_device )
{
rad_3d->direct_3d_device->Release( );
rad_3d->direct_3d_device = 0;
}
free( rad_3d );
}
}
//############################################################################
//## ##
//## Return a string describing this 3D provider. ##
//## ##
//############################################################################
RADCFUNC char* Describe_RAD_3D( void )
{
return( "Direct3D8" );
}
//############################################################################
//## ##
//## Begin a D3D frame. ##
//## ##
//############################################################################
RADCFUNC void Start_RAD_3D_frame( HRAD3D rad_3d )
{
if ( rad_3d )
{
//
// Clear the screen.
//
rad_3d->direct_3d_device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
//
// Start the scene
//
rad_3d->direct_3d_device->BeginScene();
}
}
//############################################################################
//## ##
//## End a D3D frame. ##
//## ##
//############################################################################
RADCFUNC void End_RAD_3D_frame( HRAD3D rad_3d )
{
if ( rad_3d )
{
//
// End the rendering.
//
rad_3d->direct_3d_device->EndScene();
rad_3d->direct_3d_device->Present( NULL, NULL, NULL, NULL );
}
}
//############################################################################
//## ##
//## Resize the Direct3D viewport. ##
//## ##
//############################################################################
RADCFUNC void Resize_RAD_3D( HRAD3D rad_3d,
u32 width,
u32 height )
{
//
// Make sure there is at least a pixel.
//
if ( width < 1 )
{
width = 1;
}
if ( height < 1 )
{
height = 1;
}
// Create the viewport
D3DVIEWPORT8 vp = { 0, 0, width, height, 0.0f, 1.0f };
rad_3d->direct_3d_device->SetViewport( &vp );
}
//############################################################################
//## ##
//## Simple function to round up to the next power of 2. ##
//## ##
//############################################################################
static u32 Round_up_to_next_2_power( u32 value )
{
if ( value > 16 )
if ( value > 64 )
if ( value > 128 )
if ( value > 256 )
if ( value > 512 )
return( 1024 );
else
return( 512 );
else
return( 256 );
else
return( 128 );
else
if ( value > 32 )
return( 64 );
else
return( 32 );
else
if ( value > 4 )
if ( value > 8 )
return( 16 );
else
return( 8 );
else
if ( value > 2 )
return( 4 );
return( value );
}
//############################################################################
//## ##
//## Create a new D3D texture. ##
//## ##
//############################################################################
LPDIRECT3DTEXTURE8 Create_texture( LPDIRECT3DDEVICE8 d3d_device,
D3DFORMAT d3d_surface_type,
u32 pitch,
u32 pixel_size,
u32 width,
u32 height )
{
LPDIRECT3DTEXTURE8 texture = NULL;
//
// try to create a dynamic texture first
//
if ( SUCCEEDED( d3d_device->CreateTexture(width, height, 1,
D3DUSAGE_DYNAMIC, d3d_surface_type,
D3DPOOL_DEFAULT,
&texture) ) )
{
goto gotit;
}
//
// if that fails, create a regular texture
//
if ( SUCCEEDED( d3d_device->CreateTexture(width, height, 1,
0, d3d_surface_type,
D3DPOOL_MANAGED,
&texture) ) )
{
D3DLOCKED_RECT locked_rect;
gotit:
//
// Clear the texture to black.
//
if ( SUCCEEDED( texture->LockRect( 0, &locked_rect, NULL, 0 ) ) )
{
//
// Copy over the pixels.
//
u8* dest = ( u8* ) locked_rect.pBits;
u32 bytes = width * pixel_size;
for ( u32 y = 0 ; y < height ; y++ )
{
memset( dest, 0, bytes );
dest += locked_rect.Pitch;
}
//
// Unlock the DirectX texture.
//
texture->UnlockRect( 0 );
}
}
return texture;
}
//############################################################################
//## ##
//## Structure to contain a RAD 3D image. ##
//## ##
//############################################################################
typedef struct RAD3DIMAGE
{
// members used by linear and pow2 routines
LPDIRECT3DDEVICE8 direct_3d_device;
D3DFORMAT d3d_surface_type;
u32 rad_surface_type;
s32 alpha_pixels;
u32 pixel_size;
u32 width;
u32 height;
u32 texture_count;
s32 lin_texture;
// members used by pow2 routines only
u32 pitch;
u32 total_textures;
u32 textures_across;
u32 textures_down;
u32 remnant_width;
u32 remnant_height;
u32 remnant_input_width;
u32 remnant_input_height;
u32 maximum_texture_size;
LPDIRECT3DTEXTURE8* d3d_textures;
// member used by linear routines only
LPDIRECT3DTEXTURE8 texture;
} RAD3DIMAGE;
/*
* Vertex structure
*/
typedef struct _D3DTLVERTEX {
float sx; /* Screen coordinates */
float sy;
float sz;
float rhw; /* Reciprocal of homogeneous w */
D3DCOLOR color; /* Vertex color */
D3DCOLOR specular; /* Specular component of vertex */
float tu; /* Texture coordinates */
float tv;
} D3DTLVERTEX, *LPD3DTLVERTEX;
#define D3DFVF_TLVERTEX ( D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1 )
//############################################################################
//## ##
//## Submit the vertices for one texture. ##
//## ##
//############################################################################
static void Submit_vertices( LPDIRECT3DDEVICE8 d3d_device,
f32 dest_x,
f32 dest_y,
f32 scale_x,
f32 scale_y,
s32 width,
s32 height,
f32 alpha_level )
{
D3DTLVERTEX vertices[ 4 ];
//
// Setup up the vertices.
//
vertices[ 0 ].sx = dest_x;
vertices[ 0 ].sy = dest_y;
vertices[ 0 ].sz = 0.0F;
vertices[ 0 ].rhw = 1.0F;
vertices[ 0 ].color = ( ( s32 ) ( ( alpha_level * 255.0F ) ) << 24 ) | 0xffffff;
vertices[ 0 ].specular = vertices[ 0 ].color;
vertices[ 0 ].tu = 0.0F;
vertices[ 0 ].tv = 0.0F;
vertices[ 1 ] = vertices[ 0 ];
vertices[ 1 ].sx = dest_x + ( scale_x * ( f32 ) width );
vertices[ 1 ].tu = 1.0F;
vertices[ 2 ] = vertices[0];
vertices[ 2 ].sy = dest_y + ( scale_y * ( f32 ) height );
vertices[ 2 ].tv = 1.0F;
vertices[ 3 ] = vertices[ 1 ];
vertices[ 3 ].sy = vertices[ 2 ].sy;
vertices[ 3 ].tv = 1.0F;
//
// Draw the vertices.
//
d3d_device->SetVertexShader(D3DFVF_TLVERTEX);
d3d_device->DrawPrimitiveUP(
D3DPT_TRIANGLESTRIP,
2,
vertices,
sizeof(vertices[0]));
}
//############################################################################
//## ##
//## Submit the lines to outline a texture. ##
//## ##
//############################################################################
static void Submit_lines( LPDIRECT3DDEVICE8 d3d_device,
f32 dest_x,
f32 dest_y,
f32 scale_x,
f32 scale_y,
s32 width,
s32 height )
{
D3DTLVERTEX points[ 12 ];
//
// Setup the line coordinates.
//
points[ 0 ].sx = dest_x;
points[ 0 ].sy = dest_y;
points[ 0 ].sz = 0.0F;
points[ 0 ].rhw = 1.0F;
points[ 0 ].color = 0xffffffff;
points[ 0 ].specular = 0xffffffff;
points[ 0 ].tu = 0.0F;
points[ 0 ].tv = 0.0F;
points[ 1 ] = points[ 0 ];
points[ 1 ].sx = dest_x + ( scale_x * ( f32 ) width );
points[ 1 ].sy = dest_y ;
points[ 2 ] = points[ 1 ];
points[ 3 ] = points[ 1 ];
points[ 3 ].sy = dest_y + ( scale_y * ( f32 ) height );
points[ 4 ] = points[ 3 ];
points[ 5 ] = points[ 3 ];
points[ 5 ].sx = dest_x;
points[ 6 ] = points[ 5 ];
points[ 7 ] = points[ 0 ];
points[ 8 ] = points[ 0 ];
points[ 9 ] = points[ 3 ];
points[ 10 ] = points[ 2 ];
points[ 11 ] = points[ 6 ];
points[ 8 ].color = 0xffff0000;
points[ 8 ].specular = 0xffff0000;
points[ 9 ].color = 0xffff0000;
points[ 9 ].specular = 0xffff0000;
points[ 10 ].color = 0xffff0000;
points[ 10 ].specular = 0xffff0000;
points[ 11 ].color = 0xffff0000;
points[ 11 ].specular = 0xffff0000;
//
// Turn off texturing.
//
d3d_device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
d3d_device->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
//
// Draw the lines.
//
d3d_device->SetVertexShader(D3DFVF_TLVERTEX);
d3d_device->DrawPrimitiveUP(
D3DPT_LINELIST,
6,
points,
sizeof(points[0]));
}
//############################################################################
//## ##
//## Set up the appropriate renderstates for texture. ##
//## ##
//############################################################################
static void Setup_Renderstate( HRAD3DIMAGE rad_image, f32 alpha_level )
{
//
// If alpha is disabled and there is no texture alpha, turn alpha off.
//
if ( ( alpha_level >= (1.0F-0.0001) ) && ( ! rad_image->alpha_pixels ) )
{
rad_image->direct_3d_device->SetRenderState( D3DRS_ALPHABLENDENABLE, 0 );
rad_image->direct_3d_device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
rad_image->direct_3d_device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
rad_image->direct_3d_device->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
}
else
{
rad_image->direct_3d_device->SetRenderState( D3DRS_ALPHABLENDENABLE, 1 );
rad_image->direct_3d_device->SetRenderState( D3DRS_SRCBLEND,D3DBLEND_SRCALPHA );
rad_image->direct_3d_device->SetRenderState( D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA );
rad_image->direct_3d_device->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
rad_image->direct_3d_device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
rad_image->direct_3d_device->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
rad_image->direct_3d_device->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
}
}
/*
* Power 2 routines for devices that only support pow2 textures.
*/
//############################################################################
//## ##
//## Open a RAD 3D image (a data structure to blit an image through D3D). ##
//## ##
//############################################################################
RADCFUNC HRAD3DIMAGE Open_RAD_3D_image_pow2( HRAD3D rad_3d,
u32 width,
u32 height,
s32 alpha_pixels,
u32 maximum_texture_size )
{
HRAD3DIMAGE rad_image;
u32 remnant_width, remnant_height;
u32 buffer_pitch, buffer_height;
u32 pitch, pixel_size;
u32 total_textures;
LPDIRECT3DTEXTURE8* textures;
u32 x, y, i;
//
// Calculate the pixel size and the pitch
//
pixel_size = ( alpha_pixels ) ? rad_3d->alpha_pixel_size : rad_3d->pixel_size;
pitch=( ( width * pixel_size ) + 15 ) & ~15;
//
// Calculate the remnant size (for the width and the height)
//
remnant_width = Round_up_to_next_2_power( width % maximum_texture_size );
remnant_height = Round_up_to_next_2_power( height % maximum_texture_size );
//
// The buffer_pitch is the greater of the remnant size and the input pitch.
//
buffer_pitch = remnant_width * pixel_size;
if ( buffer_pitch < pitch )
{
buffer_pitch = pitch;
}
//
// The buffer_height is the greater of the remnant size and the input height.
//
buffer_height = ( height > remnant_height) ? height : remnant_height;
//
// Calculate the total number of textures we'll need.
//
total_textures = ( ( width + ( maximum_texture_size - 1 ) ) / maximum_texture_size ) *
( ( height + ( maximum_texture_size - 1 ) ) / maximum_texture_size );
//
// Allocate enough memory for a RAD image, a list of textures and a buffer.
//
rad_image = ( HRAD3DIMAGE ) malloc( sizeof( RAD3DIMAGE ) +
( total_textures * 4 ) );
if ( rad_image == 0 )
{
return( 0 );
}
memset( rad_image, 0, sizeof( RAD3DIMAGE ) );
//
// The textures come after the structure.
//
rad_image->d3d_textures = ( LPDIRECT3DTEXTURE8 * ) ( rad_image + 1 );
//
// Set all the variables in our new structure.
//
rad_image->direct_3d_device = rad_3d->direct_3d_device;
rad_image->total_textures = total_textures;
rad_image->pitch = pitch;
rad_image->width = width;
rad_image->height = height;
rad_image->alpha_pixels = alpha_pixels;
rad_image->pixel_size = pixel_size;
rad_image->textures_across = width / maximum_texture_size;
rad_image->textures_down = height / maximum_texture_size;
rad_image->remnant_width = remnant_width;
rad_image->remnant_height = remnant_height;
rad_image->remnant_input_width = width % maximum_texture_size;
rad_image->remnant_input_height = height % maximum_texture_size;
rad_image->maximum_texture_size = maximum_texture_size;
rad_image->rad_surface_type = ( alpha_pixels ) ?
rad_3d->rad_alpha_surface :
rad_3d->rad_surface;
rad_image->d3d_surface_type = ( alpha_pixels ) ?
rad_3d->d3d_alpha_surface :
rad_3d->d3d_surface;
//
// Loop through and init each texture (setting each of their sizes).
//
textures = rad_image->d3d_textures;
for (y = 0; y < rad_image->textures_down ; y++ )
{
for ( x = 0 ; x < rad_image->textures_across ; x++ )
{
//
// Create the texture.
//
*textures++ = Create_texture( rad_3d->direct_3d_device,
rad_image->d3d_surface_type,
rad_image->pitch,
rad_image->pixel_size,
rad_image->maximum_texture_size,
rad_image->maximum_texture_size );
}
//
// Do the rememnant texture at the end of the scanline.
//
if ( rad_image->remnant_width )
{
//
// Create the texture.
//
*textures++ = Create_texture( rad_3d->direct_3d_device,
rad_image->d3d_surface_type,
rad_image->pitch,
rad_image->pixel_size,
rad_image->remnant_width,
rad_image->maximum_texture_size );
}
}
//
// Do the remnants along the bottom edge (if any).
//
if ( rad_image->remnant_height )
{
for ( x = 0 ; x < rad_image->textures_across ; x++ )
{
//
// Create the texture.
//
*textures++ = Create_texture( rad_3d->direct_3d_device,
rad_image->d3d_surface_type,
rad_image->pitch,
rad_image->pixel_size,
rad_image->maximum_texture_size,
rad_image->remnant_height );
}
if ( rad_image->remnant_width )
{
//
// Create the texture.
//
*textures++ = Create_texture( rad_3d->direct_3d_device,
rad_image->d3d_surface_type,
rad_image->pitch,
rad_image->pixel_size,
rad_image->remnant_width,
rad_image->remnant_height );
}
}
//
// Now make sure all of the textures were successfully created,
// if not, just free them all.
//
for ( i = 0 ; i < rad_image->total_textures ; i++ )
{
if ( rad_image->d3d_textures[ i ] == 0 )
{
//
// One of the textures wasn't created, so hose them all.
//
for ( i = 0 ; i < rad_image->total_textures ; i++ )
{
if ( rad_image->d3d_textures[ i ] )
{
rad_image->d3d_textures[ i ]->Release();
rad_image->d3d_textures[ i ] = 0;
}
}
//
// Free our memory and return.
//
free( rad_image );
return( 0 );
}
}
rad_image->lin_texture = 0;
return( rad_image );
}
//############################################################################
//## ##
//## Closes a RAD 3D image (frees textures and memory). ##
//## ##
//############################################################################
RADCFUNC void Close_RAD_3D_image_pow2( HRAD3DIMAGE rad_image )
{
if ( rad_image->d3d_textures )
{
u32 i;
//
// Hose all our textures.
//
for ( i = 0 ; i < rad_image->total_textures ; i++ )
{
if ( rad_image->d3d_textures[ i ] )
{
rad_image->d3d_textures[ i ]->Release();
}
}
rad_image->d3d_textures = 0;
//
// Free our memory.
//
free( rad_image );
}
}
//############################################################################
//## ##
//## Lock a RAD 3D image and return the buffer address and pitch. ##
//## ##
//############################################################################
RADCFUNC s32 Lock_RAD_3D_image_pow2( HRAD3DIMAGE rad_image,
void* out_pixel_buffer,
u32* out_buffer_pitch,
u32* out_surface_type,
u32* src_x,
u32* src_y,
u32* src_w,
u32* src_h )
{
//
// Fill the variables that were requested.
//
D3DLOCKED_RECT locked_rect;
if ( rad_image->texture_count < rad_image->total_textures )
{
//
// Lock the DirectX texture.
//
if ( ! SUCCEEDED( rad_image->d3d_textures[ rad_image->texture_count ]->LockRect( 0, &locked_rect, NULL, 0 ) ) )
{
goto err;
}
if ( out_pixel_buffer )
{
*( void** )out_pixel_buffer = locked_rect.pBits;
}
if ( out_buffer_pitch )
{
*out_buffer_pitch = locked_rect.Pitch;
}
if ( out_surface_type )
{
*out_surface_type = rad_image->rad_surface_type;
}
U32 acc = rad_image->textures_across + ( rad_image->remnant_width ? 1 : 0 );
U32 y = rad_image->texture_count / acc;
U32 x = rad_image->texture_count - ( acc * y );
if ( src_x )
{
*src_x = ( x * rad_image->maximum_texture_size );
}
if ( src_y )
{
*src_y = ( y * rad_image->maximum_texture_size );
}
if ( src_w )
{
*src_w = ( x >= rad_image->textures_across ) ?
rad_image->remnant_width : rad_image->maximum_texture_size;
}
if ( src_h )
{
*src_h = ( y >= rad_image->textures_down ) ?
rad_image->remnant_height : rad_image->maximum_texture_size;
}
++( rad_image->texture_count );
return( 1 );
}
else
{
err:
rad_image->texture_count = 0;
return( 0 );
}
}
//############################################################################
//## ##
//## Unlock a RAD 3D image (mark it for redownloading next frame). ##
//## ##
//############################################################################
RADCFUNC void Unlock_RAD_3D_image_pow2( HRAD3DIMAGE rad_image )
{
//
// Unlock the DirectX texture.
//
rad_image->d3d_textures[ rad_image->texture_count - 1 ]->UnlockRect( 0 );
}
//############################################################################
//## ##
//## Blit a 3D image onto the render target. ##
//## ##
//############################################################################
RADCFUNC void Blit_RAD_3D_image_pow2( HRAD3DIMAGE rad_image,
f32 x_offset,
f32 y_offset,
f32 x_scale,
f32 y_scale,
f32 alpha_level )
{
LPDIRECT3DTEXTURE8* textures;
u8* pixels;
u32 x, y;
f32 dest_x, dest_y;
s32 x_skip, y_skip;
f32 adjust_x, adjust_y;
//
// Setup appropriate texture renderstates.
//
Setup_Renderstate( rad_image, alpha_level );
//
// Now loop through all of our textures, submitting them.
//
textures = rad_image->d3d_textures;
//
// Calculate how many bytes to move to the next texture block in X.
//
x_skip = ( rad_image->maximum_texture_size * rad_image->pixel_size );
//
// Calculate how many bytes to move to the next texture block in Y.
//
y_skip = ( rad_image->pitch *
rad_image->maximum_texture_size ) -
( rad_image->textures_across *
rad_image->maximum_texture_size *
rad_image->pixel_size );
adjust_x = ( x_scale * ( f32 ) rad_image->maximum_texture_size );
adjust_y = ( y_scale * ( f32 ) rad_image->maximum_texture_size );
dest_y = y_offset;
for ( y = 0 ; y < rad_image->textures_down ; y++ )
{
dest_x = x_offset;
for ( x = 0 ; x < rad_image->textures_across ; x++ )
{
//
// Select the proper texture.
//
rad_image->direct_3d_device->SetTexture( 0, *textures );
++textures;
//
// Submit the vertices.
//
Submit_vertices( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->maximum_texture_size,
rad_image->maximum_texture_size,
alpha_level );
dest_x += adjust_x;
pixels += x_skip;
}
//
// Handle the right side remnant (if any).
//
if ( rad_image->remnant_width )
{
//
// Select the proper texture.
//
rad_image->direct_3d_device->SetTexture( 0, *textures );
++textures;
//
// Submit the vertices.
//
Submit_vertices( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->remnant_width,
rad_image->maximum_texture_size,
alpha_level );
}
dest_y += adjust_y;
pixels += y_skip;
}
//
// Handle the bottom row remnants (if any).
//
if ( rad_image->remnant_height )
{
dest_x = x_offset;
for ( x = 0 ; x < rad_image->textures_across ; x++ )
{
//
// Select the proper texture.
//
rad_image->direct_3d_device->SetTexture( 0, *textures );
++textures;
//
// Submit the vertices.
//
Submit_vertices( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->maximum_texture_size,
rad_image->remnant_height,
alpha_level );
dest_x += adjust_x;
pixels += x_skip;
}
if ( rad_image->remnant_width )
{
//
// Select the proper texture.
//
rad_image->direct_3d_device->SetTexture( 0, *textures );
++textures;
//
// Submit the vertices.
//
Submit_vertices( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->remnant_width,
rad_image->remnant_height,
alpha_level );
}
}
}
//############################################################################
//## ##
//## Draw the edges of each texture for debugging purposes. ##
//## ##
//############################################################################
RADCFUNC void Draw_lines_RAD_3D_image_pow2( HRAD3DIMAGE rad_image,
f32 x_offset,
f32 y_offset,
f32 x_scale,
f32 y_scale )
{
u32 x, y;
f32 dest_x, dest_y;
f32 adjust_x, adjust_y;
adjust_x = ( x_scale * ( f32 ) rad_image->maximum_texture_size );
adjust_y = ( y_scale * ( f32 ) rad_image->maximum_texture_size );
dest_y = y_offset;
for ( y = 0 ; y < rad_image->textures_down ; y++ )
{
dest_x = x_offset;
for ( x = 0 ; x < rad_image->textures_across ; x++ )
{
//
// Submit the lines.
//
Submit_lines( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->maximum_texture_size,
rad_image->maximum_texture_size );
dest_x += adjust_x;
}
//
// Handle the right side remnant (if any).
//
if ( rad_image->remnant_width )
{
//
// Submit the lines.
//
Submit_lines( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->remnant_width,
rad_image->maximum_texture_size );
}
dest_y += adjust_y;
}
//
// Handle the bottom row remnants (if any).
//
if ( rad_image->remnant_height )
{
dest_x = x_offset;
for ( x = 0 ; x < rad_image->textures_across ; x++ )
{
//
// Submit the lines.
//
Submit_lines( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->maximum_texture_size,
rad_image->remnant_height );
dest_x += adjust_x;
}
if ( rad_image->remnant_width )
{
//
// Submit the lines.
//
Submit_lines( rad_image->direct_3d_device,
dest_x,
dest_y,
x_scale,
y_scale,
rad_image->remnant_width,
rad_image->remnant_height );
}
}
}
/*
* Linear routines for devices that support non-power 2 textures.
*/
//############################################################################
//## ##
//## Blit a 3D image onto the render target. ##
//## ##
//############################################################################
RADCFUNC void Blit_RAD_3D_image_lin( HRAD3DIMAGE rad_image,
f32 x_offset,
f32 y_offset,
f32 x_scale,
f32 y_scale,
f32 alpha_level )
{
//
// Setup appropriate texture renderstates.
//
Setup_Renderstate( rad_image, alpha_level );
//
// Select our texture.
//
rad_image->direct_3d_device->SetTexture( 0, rad_image->texture );
//
// Submit the vertices.
//
Submit_vertices( rad_image->direct_3d_device,
x_offset,
y_offset,
x_scale,
y_scale,
rad_image->width,
rad_image->height,
alpha_level );
}
//############################################################################
//## ##
//## Draw the edges of the texture for debugging purposes. ##
//## ##
//############################################################################
RADCFUNC void Draw_lines_RAD_3D_image_lin( HRAD3DIMAGE rad_image,
f32 x_offset,
f32 y_offset,
f32 x_scale,
f32 y_scale )
{
//
// Submit the lines.
//
Submit_lines( rad_image->direct_3d_device,
x_offset,
y_offset,
x_scale,
y_scale,
rad_image->width,
rad_image->height );
}
//############################################################################
//## ##
//## Lock a RAD 3D image and return the buffer address and pitch. ##
//## ##
//############################################################################
RADCFUNC s32 Lock_RAD_3D_image_lin( HRAD3DIMAGE rad_image,
void * out_pixel_buffer,
u32 * out_buffer_pitch,
u32 * out_surface_type,
u32 * src_x,
u32 * src_y,
u32 * src_w,
u32 * src_h )
{
//
// Fill the variables that were requested.
//
if ( rad_image->texture_count == 0 )
{
if ( out_pixel_buffer || out_buffer_pitch )
{
D3DLOCKED_RECT locked_rect;
if ( FAILED( rad_image->texture->LockRect( 0, &locked_rect, NULL, 0 ) ) )
{
return 0;
}
if ( out_pixel_buffer )
{
*( void** )out_pixel_buffer = locked_rect.pBits;
}
if ( out_buffer_pitch )
{
*out_buffer_pitch = locked_rect.Pitch;
}
if ( src_x )
{
*src_x = 0;
}
if ( src_y )
{
*src_y = 0;
}
if ( src_w )
{
*src_w = rad_image->width;
}
if ( src_h )
{
*src_h = rad_image->height;
}
}
if ( out_surface_type )
{
*out_surface_type = rad_image->rad_surface_type;
}
rad_image->texture_count = 1;
return( 1 );
}
else
{
rad_image->texture_count = 0;
return( 0 );
}
}
//############################################################################
//## ##
//## Unlock a RAD 3D image (mark it for redownloading next frame). ##
//## ##
//############################################################################
RADCFUNC void Unlock_RAD_3D_image_lin( HRAD3DIMAGE rad_image )
{
//
// Unlock our texture.
//
rad_image->texture->UnlockRect( 0 );
}
//############################################################################
//## ##
//## Open a RAD 3D image (a data structure to blit an image through D3D). ##
//## ##
//############################################################################
RADCFUNC HRAD3DIMAGE Open_RAD_3D_image_lin( HRAD3D rad_3d,
u32 width,
u32 height,
s32 alpha_pixels,
u32 maximum_texture_size )
{
HRAD3DIMAGE rad_image;
u32 pixel_size;
//
// Allocate enough memory for a RAD image.
//
rad_image = ( HRAD3DIMAGE ) malloc( sizeof( RAD3DIMAGE ));
if ( rad_image == 0 )
{
return( 0 );
}
memset( rad_image, 0, sizeof( RAD3DIMAGE ) );
//
// Calculate the pixel size
//
pixel_size = ( alpha_pixels ) ? rad_3d->alpha_pixel_size : rad_3d->pixel_size;
//
// Set all the variables in our new structure.
//
rad_image->direct_3d_device = rad_3d->direct_3d_device;
rad_image->width = width;
rad_image->height = height;
rad_image->alpha_pixels = alpha_pixels;
rad_image->pixel_size = pixel_size;
rad_image->rad_surface_type = ( alpha_pixels ) ?
rad_3d->rad_alpha_surface :
rad_3d->rad_surface;
rad_image->d3d_surface_type = ( alpha_pixels ) ?
rad_3d->d3d_alpha_surface :
rad_3d->d3d_surface;
rad_image->texture_count = 0;
//
// Create the texture.
//
rad_image->texture = Create_texture( rad_3d->direct_3d_device,
rad_image->d3d_surface_type,
rad_image->pitch,
rad_image->pixel_size,
width,
height );
if ( rad_image->texture == 0 )
{
free( rad_image );
rad_image = 0;
}
rad_image->lin_texture = 1;
return rad_image;
}
//############################################################################
//## ##
//## Closes a RAD 3D image (frees textures and memory). ##
//## ##
//############################################################################
RADCFUNC void Close_RAD_3D_image_lin( HRAD3DIMAGE rad_image )
{
if ( rad_image->texture )
{
rad_image->texture->Release();
}
//
// Free our memory.
//
free( rad_image );
}
/*
* Wrapper routines which call the real pow2 or linear functions.
*/
//############################################################################
//## ##
//## Blit a 3D image onto the render target. ##
//## ##
//############################################################################
RADCFUNC void Blit_RAD_3D_image( HRAD3DIMAGE rad_image,
f32 x_offset,
f32 y_offset,
f32 x_scale,
f32 y_scale,
f32 alpha_level )
{
if ( rad_image == 0 )
{
return;
}
if ( rad_image->lin_texture )
{
Blit_RAD_3D_image_lin( rad_image, x_offset, y_offset, x_scale,
y_scale, alpha_level );
}
else
{
Blit_RAD_3D_image_pow2( rad_image, x_offset, y_offset, x_scale,
y_scale, alpha_level );
}
}
//############################################################################
//## ##
//## Draw the edges of the texture for debugging purposes. ##
//## ##
//############################################################################
RADCFUNC void Draw_lines_RAD_3D_image( HRAD3DIMAGE rad_image,
f32 x_offset,
f32 y_offset,
f32 x_scale,
f32 y_scale )
{
if ( rad_image == 0 )
{
return;
}
if ( rad_image->lin_texture )
{
Draw_lines_RAD_3D_image_lin( rad_image, x_offset,
y_offset, x_scale, y_scale );
}
else
{
Draw_lines_RAD_3D_image_pow2( rad_image, x_offset,
y_offset, x_scale, y_scale );
}
}
//############################################################################
//## ##
//## Lock a RAD 3D image and return the buffer address and pitch. ##
//## ##
//############################################################################
RADCFUNC s32 Lock_RAD_3D_image( HRAD3DIMAGE rad_image,
void * out_pixel_buffer,
u32 * out_buffer_pitch,
u32 * out_surface_type,
u32 * src_x,
u32 * src_y,
u32 * src_w,
u32 * src_h )
{
if ( rad_image == 0 )
{
return( 0 );
}
if ( rad_image->lin_texture )
{
return Lock_RAD_3D_image_lin( rad_image, out_pixel_buffer,
out_buffer_pitch, out_surface_type, src_x, src_y, src_w, src_h );
}
else
{
return Lock_RAD_3D_image_pow2( rad_image, out_pixel_buffer,
out_buffer_pitch, out_surface_type, src_x, src_y, src_w, src_h );
}
}
//############################################################################
//## ##
//## Unlock a RAD 3D image (mark it for redownloading next frame). ##
//## ##
//############################################################################
RADCFUNC void Unlock_RAD_3D_image( HRAD3DIMAGE rad_image )
{
if ( rad_image == 0 )
{
return;
}
if ( rad_image->lin_texture )
{
Unlock_RAD_3D_image_lin( rad_image );
}
else
{
Unlock_RAD_3D_image_pow2( rad_image );
}
}
#define is_pow2( val ) ( Round_up_to_next_2_power( val ) == ( val ) )
//############################################################################
//## ##
//## Open a RAD 3D image (a data structure to blit an image through D3D). ##
//## ##
//############################################################################
RADCFUNC HRAD3DIMAGE Open_RAD_3D_image( HRAD3D rad_3d,
u32 width,
u32 height,
s32 alpha_pixels,
u32 maximum_texture_size )
{
if ( ( is_pow2( width ) && is_pow2( height ) ) || ( rad_3d->nonpow2_textures_supported ) )
{
return Open_RAD_3D_image_lin( rad_3d, width, height,
alpha_pixels, maximum_texture_size );
}
else
{
return Open_RAD_3D_image_pow2( rad_3d, width, height,
alpha_pixels, maximum_texture_size );
}
}
//############################################################################
//## ##
//## Closes a RAD 3D image (frees textures and memory). ##
//## ##
//############################################################################
RADCFUNC void Close_RAD_3D_image( HRAD3DIMAGE rad_image )
{
if ( rad_image == 0 )
{
return;
}
if ( rad_image->lin_texture )
{
Close_RAD_3D_image_lin( rad_image );
}
else
{
Close_RAD_3D_image_pow2( rad_image );
}
}
// @cdep pre $requiresbinary(d3d8.lib)