975 lines
26 KiB
C
975 lines
26 KiB
C
/*
|
|
* Copyright (c) 1993-1995 Argonaut Technologies Limited. All rights reserved.
|
|
*
|
|
* $Id: renderer.c 1.3 1997/08/11 14:25:57 jon Exp JON $
|
|
* $Locker: JON $
|
|
*
|
|
* Renderer methods
|
|
*/
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include "drv.h"
|
|
#include "shortcut.h"
|
|
#include "brassert.h"
|
|
|
|
BR_RCS_ID("$Id: renderer.c 1.3 1997/08/11 14:25:57 jon Exp JON $");
|
|
|
|
/*
|
|
* Default dispatch table for renderer (defined at end of file)
|
|
*/
|
|
static const struct br_renderer_dispatch rendererDispatch;
|
|
|
|
/*
|
|
* 0 terminated list of tokens that are used to represent the state for
|
|
* this library
|
|
*/
|
|
const br_token RendererPartsTokens[] = {
|
|
BRT_CULL,
|
|
BRT_SURFACE,
|
|
BRT_MATRIX,
|
|
BRT_ENABLE,
|
|
BRT_LIGHT,
|
|
BRT_CLIP,
|
|
0
|
|
};
|
|
|
|
/*
|
|
* Renderer info. template
|
|
*/
|
|
|
|
/*
|
|
* Return a token list of ourself and that of the primitive library
|
|
*/
|
|
static br_error BR_CALLBACK customPartsQuery(br_uint_32 *pvalue, void **pextra, br_size_t *pextra_size,
|
|
void *block, struct br_tv_template_entry *tep)
|
|
{
|
|
struct br_renderer *self = block;
|
|
int i;
|
|
br_uint_32 dummy;
|
|
br_error r;
|
|
br_token **ppt = (br_token **)pextra;
|
|
|
|
if(pextra == NULL || *pextra == NULL || pextra_size == NULL)
|
|
return BRE_FAIL;
|
|
|
|
*((void **)pvalue) = *pextra;
|
|
|
|
/*
|
|
* Check there is space
|
|
*/
|
|
if(((BR_ASIZE(RendererPartsTokens)-1) * sizeof(br_token)) > *pextra_size)
|
|
return BRE_FAIL;
|
|
|
|
/*
|
|
* Add our own tokens to list
|
|
*/
|
|
for(i=0; i < BR_ASIZE(RendererPartsTokens)-1; i++) {
|
|
*(*ppt)++ = RendererPartsTokens[i];
|
|
*pextra_size -= sizeof(br_token);
|
|
}
|
|
|
|
/*
|
|
* Hand off to primitive library for rest of list
|
|
*/
|
|
r = ObjectQueryBuffer(self->plib, &dummy, *ppt, *pextra_size, BRT_PARTS_TL);
|
|
|
|
if(r != BRE_OK)
|
|
return r;
|
|
|
|
/*
|
|
* Work out how much space was consumed
|
|
*/
|
|
for(i = 0; (*ppt)[i] ; i++)
|
|
*pextra_size -= sizeof(br_token);
|
|
|
|
/*
|
|
* NULL
|
|
*/
|
|
*pextra_size -= sizeof(br_token);
|
|
|
|
return BRE_OK;
|
|
}
|
|
|
|
static br_size_t BR_CALLBACK customPartsExtra(void *block, struct br_tv_template_entry *tep)
|
|
{
|
|
struct br_renderer *self = block;
|
|
br_size_t s;
|
|
br_token_value tv[] = {
|
|
{BRT_PARTS_TL,0},
|
|
{0,0}
|
|
};
|
|
|
|
/*
|
|
* Find out size of primitive's list
|
|
*/
|
|
if(ObjectQueryManySize((br_object *)self->plib, &s, tv) != BRE_OK)
|
|
return 0;
|
|
|
|
/*
|
|
* Add our own contribution
|
|
*/
|
|
return s + (BR_ASIZE(RendererPartsTokens)-1) * sizeof(br_token);
|
|
}
|
|
|
|
static struct br_tv_custom customPartsConv = {
|
|
customPartsQuery,
|
|
NULL,
|
|
customPartsExtra,
|
|
};
|
|
|
|
#define F(f) offsetof(struct br_renderer, f)
|
|
|
|
/*
|
|
* Shortcuts for template flags
|
|
*/
|
|
#define _S BRTV_SET
|
|
#define _Q BRTV_QUERY
|
|
#define _A BRTV_ALL
|
|
|
|
#if BASED_FIXED
|
|
#define _AX BRTV_ALL
|
|
#else
|
|
#define _AX 0
|
|
#endif
|
|
|
|
#if BASED_FLOAT
|
|
#define _AF BRTV_ALL
|
|
#else
|
|
#define _AF 0
|
|
#endif
|
|
|
|
static struct br_tv_template_entry rendererTemplateEntries[] = {
|
|
{BRT(IDENTIFIER_CSTR), F(identifier), _Q | _A, BRTV_CONV_COPY, },
|
|
{BRT(PARTS_TL), 0, _Q | _A, BRTV_CONV_CUSTOM, (br_int_32)&customPartsConv},
|
|
};
|
|
#undef F
|
|
|
|
static HRESULT FAR PASCAL enumTextureFormat(LPDDSURFACEDESC surface_desc, struct br_renderer *renderer);
|
|
static br_boolean betterTextureFormat(br_uint_32 pixel_type, LPDDPIXELFORMAT old_pixel_format, LPDDPIXELFORMAT new_pixel_format);
|
|
|
|
/*
|
|
* Create a new renderer
|
|
*/
|
|
br_renderer *RendererD3DAllocate(br_device *device, struct br_renderer_facility *facility, struct br_device_pixelmap *dest)
|
|
{
|
|
br_renderer *self;
|
|
DDSURFACEDESC surface_desc = { sizeof(DDSURFACEDESC) };
|
|
LPDIRECTDRAWSURFACE target, depth;
|
|
br_boolean attached_depth = BR_FALSE;
|
|
br_uint_32 i;
|
|
|
|
/*
|
|
* Check that destination is valid
|
|
*/
|
|
if (dest == NULL || ObjectDevice(dest) != device)
|
|
return NULL;
|
|
|
|
self = BrResAllocate(facility, sizeof(*self), BR_MEMORY_OBJECT);
|
|
|
|
if (self == NULL)
|
|
return NULL;
|
|
|
|
self->dispatch = (struct br_renderer_dispatch *)&rendererDispatch;
|
|
self->identifier = facility->identifier;
|
|
self->device = device;
|
|
self->renderer_facility = facility;
|
|
|
|
/*
|
|
* Get a valid rendering target from which to create the device, and use the IDirectDrawSurface
|
|
* interface
|
|
*/
|
|
if (IDirectDrawSurface2_GetSurfaceDesc(dest->surface, &surface_desc) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
if (surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE) {
|
|
|
|
/*
|
|
* Use the screen buffer if it is a valid rendering target
|
|
*/
|
|
if (IDirectDrawSurface2_QueryInterface(dest->surface, &IID_IDirectDrawSurface, &target) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
} else if (dest->offscreen_surface != NULL) {
|
|
|
|
/*
|
|
* Use an offscreen buffer matched from the screen, if any
|
|
*/
|
|
if (IDirectDrawSurface2_QueryInterface(dest->offscreen_surface, &IID_IDirectDrawSurface, &target) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Otherwise try to allocate a temporary one
|
|
*
|
|
* Leave the pixel format the same as the screen and make the width and height the same as
|
|
* the screen pixelmap (not the same as the surface if windowed) - should try smaller if
|
|
* the allocation fails (in case the image is intended to be stretched)
|
|
*
|
|
* Should use renderer caps to determine what sort of memory to use
|
|
*/
|
|
surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
|
|
surface_desc.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE;
|
|
surface_desc.dwWidth = dest->pm_width;
|
|
surface_desc.dwHeight = dest->pm_height;
|
|
|
|
if (IDirectDraw2_CreateSurface(dest->output_facility->ddraw.ddraw, &surface_desc, &target, NULL) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get a valid depth target (I understand that this is necessary to ensure that the device is
|
|
* capable of rendering to depth buffers)
|
|
*/
|
|
if (dest->depth_surface != NULL) {
|
|
|
|
/*
|
|
* Use a first depth buffer matched from the screen or an offscreen buffer from the screen, if any
|
|
*/
|
|
if (IDirectDrawSurface2_QueryInterface(dest->depth_surface, &IID_IDirectDrawSurface, &depth) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Otherwise try to allocate a temporary one and attach it to the target
|
|
*
|
|
* Leave the width and height the same as the offscreen buffer and choose a common bit depth (FIX!)
|
|
*
|
|
* Should use renderer caps to determine what sort of memory to use
|
|
*/
|
|
if (IDirectDrawSurface_GetSurfaceDesc(target, &surface_desc) != DD_OK) {
|
|
IDirectDrawSurface_Release(target);
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_ZBUFFERBITDEPTH;
|
|
surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
|
|
surface_desc.dwZBufferBitDepth = 16;
|
|
|
|
if (IDirectDraw2_CreateSurface(dest->output_facility->ddraw.ddraw, &surface_desc, &depth, NULL) == DD_OK) {
|
|
|
|
IDirectDrawSurface2_AddAttachedSurface(target, depth);
|
|
attached_depth = BR_TRUE;
|
|
|
|
} else
|
|
|
|
depth = NULL;
|
|
}
|
|
|
|
/*
|
|
* Create the D3D device
|
|
*/
|
|
if (IDirect3D2_CreateDevice(self->renderer_facility->d3d.d3d, self->renderer_facility->d3d.guid, target, &self->d3d_device) != DD_OK) {
|
|
if (depth != NULL) {
|
|
if (attached_depth)
|
|
IDirectDrawSurface_DeleteAttachedSurface(target, 0, depth);
|
|
IDirectDrawSurface_Release(depth);
|
|
}
|
|
IDirectDrawSurface_Release(target);
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* TEMPORARY - Set the global state up
|
|
*/
|
|
if (SetD3DGlobalState(self) != BRE_OK) {
|
|
if (depth != NULL) {
|
|
if (attached_depth)
|
|
IDirectDrawSurface_DeleteAttachedSurface(target, 0, depth);
|
|
IDirectDrawSurface_Release(depth);
|
|
}
|
|
IDirectDrawSurface_Release(target);
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Compile a list of the best texture format for each BRender pixelmap type
|
|
*/
|
|
for (i = 0; i < BR_ASIZE(self->texture_pixel_type); i++)
|
|
self->texture_pixel_type[i].supported = BR_FALSE;
|
|
|
|
IDirect3DDevice2_EnumTextureFormats(self->d3d_device, enumTextureFormat, self);
|
|
|
|
/*
|
|
* Create the viewport
|
|
*
|
|
* N.B. I may end up keeping a separate viewport with each pixelmap
|
|
*/
|
|
if (IDirect3D2_CreateViewport(self->renderer_facility->d3d.d3d, &self->viewport, NULL) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
if (IDirect3DDevice2_AddViewport(self->d3d_device, self->viewport) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
if (IDirect3DDevice2_SetCurrentViewport(self->d3d_device, self->viewport) != DD_OK) {
|
|
BrResFree(self);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Set up out object list
|
|
*/
|
|
self->object_list = BrObjectListAllocate(self);
|
|
|
|
/*
|
|
* Remember default state
|
|
*/
|
|
self->default_state = &facility->default_state;
|
|
self->state.renderer = self;
|
|
|
|
/*
|
|
* State starts out as default
|
|
*/
|
|
RendererStateDefault(self, (br_uint_32)BR_STATE_ALL);
|
|
|
|
/*
|
|
* Associate renderer with screen pixelmap
|
|
*/
|
|
dest->screen->renderer = self;
|
|
|
|
/*
|
|
* *** TEMPORARY ***
|
|
*
|
|
* Initialise the static brp_block, and the scales and ranges
|
|
*/
|
|
InitBrpBlock(self);
|
|
|
|
ObjectContainerAddFront(facility, (br_object *)self);
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
static HRESULT FAR PASCAL enumTextureFormat(LPDDSURFACEDESC surface_desc, struct br_renderer *renderer)
|
|
{
|
|
br_uint_32 i;
|
|
br_uint_32 type;
|
|
|
|
/*
|
|
* See if this corresponds directly to a BRender pixel type
|
|
*/
|
|
if (DDPixelFormatToPixelType(&type, &surface_desc->ddpfPixelFormat) != BRE_OK)
|
|
type = BR_ASIZE(renderer->texture_pixel_type);
|
|
|
|
/*
|
|
* For each BRender pixel format, see if this texture format is a suitable substitute
|
|
*/
|
|
for (i = 0; i < BR_ASIZE(renderer->texture_pixel_type); i++) {
|
|
|
|
/*
|
|
* If this is the ideal match, use it
|
|
*/
|
|
if (i == type) {
|
|
|
|
if (renderer->texture_pixel_type[i].pixel_format != NULL)
|
|
BrResFree(renderer->texture_pixel_type[i].pixel_format);
|
|
|
|
PixelTypeToDDPixelFormat(&renderer->texture_pixel_type[i].pixel_format, type);
|
|
|
|
renderer->texture_pixel_type[i].supported = BR_TRUE;
|
|
renderer->texture_pixel_type[i].convert = BR_FALSE;
|
|
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* If an ideal match has already been found, ignore
|
|
*/
|
|
if (renderer->texture_pixel_type[i].supported && !renderer->texture_pixel_type[i].convert)
|
|
continue;
|
|
|
|
/*
|
|
* If this a better match than the previous one, use it
|
|
*
|
|
* N.B. Could cache some of the details determined by betterTextureFormat for the conversion
|
|
* code to use
|
|
*/
|
|
if (betterTextureFormat(i, renderer->texture_pixel_type[i].pixel_format, &surface_desc->ddpfPixelFormat)) {
|
|
|
|
/*
|
|
* If a pixel format already exists, it must have been allocated (unless it was ideally
|
|
* matched already in which case it wouldn't reach this code)
|
|
*/
|
|
if (renderer->texture_pixel_type[i].pixel_format == NULL) {
|
|
|
|
renderer->texture_pixel_type[i].pixel_format = BrResAllocate(renderer, sizeof(*renderer->texture_pixel_type[i].pixel_format), BR_MEMORY_OBJECT_DATA);
|
|
if (renderer->texture_pixel_type[i].pixel_format == NULL)
|
|
continue;
|
|
}
|
|
|
|
BrMemCpy(renderer->texture_pixel_type[i].pixel_format, &surface_desc->ddpfPixelFormat, sizeof(*renderer->texture_pixel_type[i].pixel_format));
|
|
|
|
renderer->texture_pixel_type[i].supported = BR_TRUE;
|
|
renderer->texture_pixel_type[i].convert = BR_TRUE;
|
|
}
|
|
}
|
|
|
|
return DDENUMRET_OK;
|
|
}
|
|
|
|
/*
|
|
* Pixel format flags that are significant for comparison purposes for pixel format and channels
|
|
*/
|
|
#define FORMAT_DDPF_MASK (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 |\
|
|
DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXEDTO8 | DDPF_RGB | DDPF_YUV)
|
|
|
|
#define CHANNELS_DDPF_MASK (DDPF_ALPHA | DDPF_ALPHAPIXELS | DDPF_ZBUFFER | DDPF_ZPIXELS)
|
|
|
|
/*
|
|
* Convert the mask for a channel into a number of bits
|
|
*/
|
|
static br_uint_32 ChannelMaskToBits(br_uint_32 mask)
|
|
{
|
|
br_uint_32 bits;
|
|
|
|
/*
|
|
* Count the number of bits in the mask. N.B. Bits don't have to be consecutive (e.g. in Y the
|
|
* case of YUYV pixel formats) - this should be handled by the conversion code
|
|
*/
|
|
bits = 0;
|
|
|
|
while (mask != 0) {
|
|
|
|
if ((mask & 1) != 0)
|
|
bits++;
|
|
|
|
mask >>= 1;
|
|
}
|
|
|
|
return bits;
|
|
}
|
|
|
|
|
|
/*
|
|
* Determine if a particular DirectDraw pixel format is a better match for a BRender pixel format than
|
|
* another
|
|
*/
|
|
static br_boolean betterTextureFormat(br_uint_32 pixel_type, LPDDPIXELFORMAT old_pixel_format, LPDDPIXELFORMAT new_pixel_format)
|
|
{
|
|
LPDDPIXELFORMAT ideal_pixel_format;
|
|
br_int_32 r_bits, g_bits, b_bits, a_bits;
|
|
br_int_32 bits_lost;
|
|
br_uint_32 new_bits_lost, old_bits_lost;
|
|
|
|
/*
|
|
* Get the pixel format for the BRender pixel type
|
|
*
|
|
* If no valid pixel format exists, there isn't going to be a format that can be converted to it
|
|
* as far as I can work out
|
|
*/
|
|
if (PixelTypeToDDPixelFormat(&ideal_pixel_format, pixel_type) != BRE_OK)
|
|
return BR_FALSE;
|
|
|
|
/*
|
|
* If the new format is totally unsuitable, reject
|
|
*
|
|
* Grounds for rejection are:
|
|
*
|
|
* Wrong number of index bits (could this be relaxed to same or higher?)
|
|
* Wrong colour format (including indexedto8)
|
|
* Required colour, alpha or depth channel not supported (unnecessary channels aren't a problem
|
|
* since they can be filled with 1s (alpha and colour) or 0s (depth) during conversion)
|
|
*
|
|
* N.B. Compressed surfaces aren't a problem as we copy into them later
|
|
*/
|
|
if ((ideal_pixel_format->dwFlags & FORMAT_DDPF_MASK) != 0 &&
|
|
(ideal_pixel_format->dwFlags & FORMAT_DDPF_MASK) != (new_pixel_format->dwFlags & FORMAT_DDPF_MASK))
|
|
return BR_FALSE;
|
|
|
|
switch (ideal_pixel_format->dwFlags & CHANNELS_DDPF_MASK) {
|
|
|
|
case 0:
|
|
if ((new_pixel_format->dwFlags & (DDPF_ALPHA | DDPF_ZBUFFER)) != 0)
|
|
return BR_FALSE;
|
|
break;
|
|
|
|
case DDPF_ALPHA:
|
|
|
|
if ((new_pixel_format->dwFlags & (DDPF_ALPHA | DDPF_ALPHAPIXELS)) == 0)
|
|
return BR_FALSE;
|
|
break;
|
|
|
|
case DDPF_ALPHAPIXELS:
|
|
|
|
if ((new_pixel_format->dwFlags & DDPF_ALPHAPIXELS) == 0)
|
|
return BR_FALSE;
|
|
break;
|
|
|
|
case DDPF_ZBUFFER:
|
|
|
|
if ((new_pixel_format->dwFlags & (DDPF_ZBUFFER | DDPF_ZPIXELS)) == 0)
|
|
return BR_FALSE;
|
|
break;
|
|
|
|
case DDPF_ZPIXELS:
|
|
|
|
if ((new_pixel_format->dwFlags & DDPF_ZPIXELS) == 0)
|
|
return BR_FALSE;
|
|
break;
|
|
|
|
default:
|
|
return BR_FALSE;
|
|
}
|
|
|
|
/*
|
|
* If there was an old format, see if the new format is better, and reject if not
|
|
*
|
|
* Criteria for being a better match are:
|
|
*
|
|
* Fewer bits of accuracy dropped, or
|
|
* Fewer bits required
|
|
* Being compressed
|
|
*
|
|
* At the moment bits lost in alpha channel are weighted twice as heavily as bits lost in
|
|
* colour channels
|
|
*/
|
|
if (old_pixel_format != NULL) {
|
|
|
|
/*
|
|
* Determine the number of bits of accuracy lost in total for the new and old formats (could
|
|
* cache value for old format)
|
|
*/
|
|
r_bits = PixelTypeRBits(pixel_type);
|
|
g_bits = PixelTypeGBits(pixel_type);
|
|
b_bits = PixelTypeBBits(pixel_type);
|
|
a_bits = PixelTypeABits(pixel_type);
|
|
|
|
new_bits_lost = 0;
|
|
|
|
bits_lost = r_bits - ChannelMaskToBits(new_pixel_format->dwRBitMask);
|
|
if (bits_lost > 0)
|
|
new_bits_lost += bits_lost;
|
|
|
|
bits_lost = g_bits - ChannelMaskToBits(new_pixel_format->dwGBitMask);
|
|
if (bits_lost > 0)
|
|
new_bits_lost += bits_lost;
|
|
|
|
bits_lost = b_bits - ChannelMaskToBits(new_pixel_format->dwBBitMask);
|
|
if (bits_lost > 0)
|
|
new_bits_lost += bits_lost;
|
|
|
|
bits_lost = a_bits - ChannelMaskToBits(new_pixel_format->dwRGBAlphaBitMask);
|
|
if (bits_lost > 0)
|
|
new_bits_lost += bits_lost * 2;
|
|
|
|
old_bits_lost = 0;
|
|
|
|
bits_lost = r_bits - ChannelMaskToBits(old_pixel_format->dwRBitMask);
|
|
if (bits_lost > 0)
|
|
old_bits_lost += bits_lost;
|
|
|
|
bits_lost = g_bits - ChannelMaskToBits(old_pixel_format->dwGBitMask);
|
|
if (bits_lost > 0)
|
|
old_bits_lost += bits_lost;
|
|
|
|
bits_lost = b_bits - ChannelMaskToBits(old_pixel_format->dwBBitMask);
|
|
if (bits_lost > 0)
|
|
old_bits_lost += bits_lost;
|
|
|
|
bits_lost = a_bits - ChannelMaskToBits(old_pixel_format->dwRGBAlphaBitMask);
|
|
if (bits_lost > 0)
|
|
old_bits_lost += bits_lost * 2;
|
|
|
|
/*
|
|
* If the new format loses more bits of accuracy, it isn't better
|
|
*/
|
|
if (new_bits_lost > old_bits_lost)
|
|
return BR_FALSE;
|
|
|
|
/*
|
|
* If the new format loses the same number bits of accuracy but uses more bits total,
|
|
* it isn't better
|
|
*/
|
|
if (new_bits_lost == old_bits_lost && new_pixel_format->dwRGBBitCount > old_pixel_format->dwRGBBitCount)
|
|
return BR_FALSE;
|
|
|
|
/*
|
|
* If the old format was compressed, it isn't better
|
|
*/
|
|
if (old_pixel_format->dwFlags & DDPF_COMPRESSED)
|
|
return BR_FALSE;
|
|
}
|
|
|
|
/*
|
|
* If all else fails, it must be better!
|
|
*/
|
|
return BR_TRUE;
|
|
}
|
|
|
|
|
|
static void BR_CMETHOD_DECL(br_renderer_d3d, free)(br_renderer *self)
|
|
{
|
|
ObjectContainerRemove(self->renderer_facility, (br_object *)self);
|
|
|
|
/*
|
|
* Free Direct3D device
|
|
*/
|
|
if (self->d3d_device != NULL)
|
|
IDirect3DDevice2_Release(self->d3d_device);
|
|
|
|
self->renderer_facility->num_instances--;
|
|
|
|
BrObjectContainerFree((br_object_container *)self, BR_NULL_TOKEN, NULL, NULL);
|
|
|
|
BrResFreeNoCallback(self);
|
|
}
|
|
|
|
static char *BR_CMETHOD_DECL(br_renderer_d3d, identifier)(br_renderer *self)
|
|
{
|
|
return self->identifier;
|
|
}
|
|
|
|
static br_token BR_CMETHOD_DECL(br_renderer_d3d, type)(br_renderer *self)
|
|
{
|
|
return BRT_RENDERER;
|
|
}
|
|
|
|
static br_boolean BR_CMETHOD_DECL(br_renderer_d3d, isType)(br_renderer *self, br_token t)
|
|
{
|
|
return (t == BRT_RENDERER) || (t == BRT_OBJECT);
|
|
}
|
|
|
|
static struct br_device *BR_CMETHOD_DECL(br_renderer_d3d, device)(br_renderer *self)
|
|
{
|
|
return self->device;
|
|
}
|
|
|
|
static br_int_32 BR_CMETHOD_DECL(br_renderer_d3d, space)(br_renderer *self)
|
|
{
|
|
return sizeof(br_renderer);
|
|
}
|
|
|
|
static struct br_tv_template * BR_CMETHOD_DECL(br_renderer_d3d,templateQuery)
|
|
(br_renderer *self)
|
|
{
|
|
if(self->device->templates.rendererTemplate == NULL)
|
|
self->device->templates.rendererTemplate = BrTVTemplateAllocate(self->device,
|
|
rendererTemplateEntries,
|
|
BR_ASIZE(rendererTemplateEntries));
|
|
|
|
return self->device->templates.rendererTemplate;
|
|
}
|
|
|
|
static void * BR_CMETHOD_DECL(br_renderer_d3d,listQuery)(br_device *self)
|
|
{
|
|
return self->object_list;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d, validDestination)(br_renderer *self, br_boolean *bp, br_object *h)
|
|
{
|
|
return BRE_OK;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d, stateStoredNew)
|
|
(struct br_renderer *self, struct br_renderer_state_stored **pss, br_uint_32 mask, br_token_value *tv)
|
|
{
|
|
br_renderer_state_stored *ss;
|
|
|
|
ss = RendererStateStoredD3DAllocate(self, &self->state, mask, tv);
|
|
|
|
if(ss) {
|
|
*pss = ss;
|
|
return BRE_OK;
|
|
} else
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d, stateStoredAvail)
|
|
(struct br_renderer *self, br_int_32 *psize, br_uint_32 mask, br_token_value *tv)
|
|
{
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d, bufferStoredNew)
|
|
(struct br_renderer *self, struct br_buffer_stored **psm,
|
|
br_token use, struct br_device_pixelmap *pm, br_token_value *tv)
|
|
{
|
|
struct br_buffer_stored *sm;
|
|
|
|
sm = BufferStoredD3DAllocate(self, use, pm, tv);
|
|
|
|
if (sm) {
|
|
*psm = sm;
|
|
return BRE_OK;
|
|
} else
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d, bufferStoredAvail)(
|
|
struct br_renderer *self,
|
|
br_int_32 *space,
|
|
br_token use,
|
|
br_token_value *tv)
|
|
{
|
|
/*
|
|
* Should return free VRAM
|
|
*/
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d, flush)
|
|
(struct br_renderer *self, br_boolean wait)
|
|
{
|
|
br_error r;
|
|
|
|
/*
|
|
* End the scene if necessary.
|
|
*
|
|
* Never any need to wait with Direct3D (I believe)
|
|
*/
|
|
if (self->scene_started) {
|
|
|
|
r = RendererSceneEnd(self);
|
|
|
|
if (r != BRE_OK)
|
|
return r;
|
|
}
|
|
|
|
return BRE_OK;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d, synchronise)
|
|
(struct br_renderer *self, br_token sync_type, br_boolean block)
|
|
{
|
|
switch (sync_type) {
|
|
|
|
case BRT_RENDERER:
|
|
|
|
/*
|
|
* Wait until any drawing has finished
|
|
*
|
|
* *** Don't know how to do this, if it is possible
|
|
*/
|
|
// ....
|
|
break;
|
|
|
|
default:
|
|
|
|
return BRE_UNSUPPORTED;
|
|
}
|
|
|
|
return BRE_OK;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d,commandModeSet)
|
|
(struct br_renderer *self, br_token mode)
|
|
{
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d,commandModeQuery)
|
|
(struct br_renderer *self, br_token *mode)
|
|
{
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d,commandModeDefault)
|
|
(struct br_renderer *self)
|
|
{
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d,commandModePush)
|
|
(struct br_renderer *self)
|
|
{
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
static br_error BR_CMETHOD_DECL(br_renderer_d3d,commandModePop)
|
|
(struct br_renderer *self)
|
|
{
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
br_error BR_CMETHOD_DECL(br_renderer_d3d, sceneBegin)
|
|
(struct br_renderer *self)
|
|
{
|
|
LPDIRECTDRAWSURFACE surface;
|
|
D3DVIEWPORT2 viewport = { sizeof(D3DVIEWPORT2) };
|
|
|
|
/*
|
|
* Check we have a rendering target
|
|
*/
|
|
if (self->state.out.colour == NULL)
|
|
return BRE_FAIL;
|
|
|
|
/*
|
|
* We need the old interface for the destination surface
|
|
*/
|
|
if (IDirectDrawSurface2_QueryInterface(self->state.out.colour->surface, &IID_IDirectDrawSurface, &surface) != DD_OK)
|
|
return BRE_FAIL;
|
|
|
|
/*
|
|
* Set the target for the device
|
|
*/
|
|
if (IDirect3DDevice2_SetRenderTarget(self->d3d_device, surface, 0) != DD_OK) {
|
|
IDirectDrawSurface_Release(surface);
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
/*
|
|
* Update the viewport for the new render target
|
|
*
|
|
* No 3D clipping is done but I still need to give sensible view volume values
|
|
*/
|
|
viewport.dwX = self->state.out.colour->pm_base_x;
|
|
viewport.dwY = self->state.out.colour->pm_base_y;
|
|
viewport.dwWidth = self->state.out.colour->pm_width;
|
|
viewport.dwHeight = self->state.out.colour->pm_height;
|
|
|
|
viewport.dvClipX = -1.0;
|
|
viewport.dvClipY = -1.0;
|
|
viewport.dvClipWidth = 2.0f;
|
|
viewport.dvClipHeight = 2.0f;
|
|
viewport.dvMinZ = 0.0f;
|
|
viewport.dvMaxZ = 1.0f;
|
|
|
|
if (IDirect3DViewport2_SetViewport2(self->viewport, &viewport) != DD_OK) {
|
|
IDirectDrawSurface_Release(surface);
|
|
return BRE_FAIL;
|
|
}
|
|
|
|
IDirectDrawSurface_Release(surface);
|
|
|
|
if (self->state.out.depth != NULL) {
|
|
|
|
/*
|
|
* Ensure that this depth buffer is attached
|
|
*/
|
|
switch (IDirectDrawSurface2_AddAttachedSurface(self->state.out.colour->surface, self->state.out.depth->surface)) {
|
|
|
|
case DD_OK:
|
|
case DDERR_SURFACEALREADYATTACHED:
|
|
break;
|
|
|
|
default:
|
|
return BRE_FAIL;
|
|
}
|
|
}
|
|
|
|
if (IDirect3DDevice2_BeginScene(self->d3d_device) != DD_OK)
|
|
return BRE_FAIL;
|
|
|
|
/*
|
|
* Set various flags to show that rendering is occurring
|
|
*/
|
|
self->state.out.colour->renderer_active = BR_TRUE;
|
|
|
|
if (self->state.out.depth != NULL)
|
|
self->state.out.depth->renderer_active = BR_TRUE;
|
|
|
|
self->scene_started = BR_TRUE;
|
|
|
|
return BRE_OK;
|
|
}
|
|
|
|
br_error BR_CMETHOD_DECL(br_renderer_d3d, sceneEnd)
|
|
(struct br_renderer *self)
|
|
{
|
|
if (IDirect3DDevice2_EndScene(self->d3d_device) != DD_OK)
|
|
return BRE_FAIL;
|
|
|
|
self->scene_started = BR_FALSE;
|
|
|
|
if (self->state.out.colour != NULL)
|
|
self->state.out.colour->renderer_active = BR_FALSE;
|
|
|
|
if (self->state.out.depth != NULL)
|
|
self->state.out.depth->renderer_active = BR_FALSE;
|
|
|
|
return BRE_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
* Default dispatch table for renderer
|
|
*/
|
|
static const struct br_renderer_dispatch rendererDispatch = {
|
|
BR_CMETHOD_REF(br_renderer_d3d, sceneBegin),
|
|
BR_CMETHOD_REF(br_renderer_d3d, sceneEnd),
|
|
NULL,
|
|
NULL,
|
|
BR_CMETHOD_REF(br_renderer_d3d, free),
|
|
BR_CMETHOD_REF(br_renderer_d3d, identifier),
|
|
BR_CMETHOD_REF(br_renderer_d3d, type),
|
|
BR_CMETHOD_REF(br_renderer_d3d, isType),
|
|
BR_CMETHOD_REF(br_renderer_d3d, device),
|
|
BR_CMETHOD_REF(br_renderer_d3d, space),
|
|
BR_CMETHOD_REF(br_renderer_d3d, templateQuery),
|
|
BR_CMETHOD_REF(br_object, query),
|
|
BR_CMETHOD_REF(br_object, queryBuffer),
|
|
BR_CMETHOD_REF(br_object, queryMany),
|
|
BR_CMETHOD_REF(br_object, queryManySize),
|
|
BR_CMETHOD_REF(br_object, queryAll),
|
|
BR_CMETHOD_REF(br_object, queryAllSize),
|
|
BR_CMETHOD_REF(br_renderer_d3d, listQuery),
|
|
BR_CMETHOD_REF(br_object_container, tokensMatchBegin),
|
|
BR_CMETHOD_REF(br_object_container, tokensMatch),
|
|
BR_CMETHOD_REF(br_object_container, tokensMatchEnd),
|
|
BR_CMETHOD_REF(br_object_container, addFront),
|
|
BR_CMETHOD_REF(br_object_container, removeFront),
|
|
BR_CMETHOD_REF(br_object_container, remove),
|
|
BR_CMETHOD_REF(br_object_container, find),
|
|
BR_CMETHOD_REF(br_object_container, findMany),
|
|
BR_CMETHOD_REF(br_object_container, count),
|
|
|
|
BR_CMETHOD_REF(br_renderer_d3d, validDestination),
|
|
BR_CMETHOD_REF(br_renderer_d3d, stateStoredNew),
|
|
BR_CMETHOD_REF(br_renderer_d3d, stateStoredAvail),
|
|
BR_CMETHOD_REF(br_renderer_d3d, bufferStoredNew),
|
|
BR_CMETHOD_REF(br_renderer_d3d, bufferStoredAvail),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partSet),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partSetMany),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partQuery),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partQueryBuffer),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partQueryMany),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partQueryManySize),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partQueryAll),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partQueryAllSize),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partIndexQuery),
|
|
BR_CMETHOD_REF(br_renderer_d3d, modelMulF),
|
|
BR_CMETHOD_REF(br_renderer_d3d, modelMulX),
|
|
BR_CMETHOD_REF(br_renderer_d3d, modelPopPushMulF),
|
|
BR_CMETHOD_REF(br_renderer_d3d, modelPopPushMulX),
|
|
BR_CMETHOD_REF(br_renderer_d3d, modelInvert),
|
|
BR_CMETHOD_REF(br_renderer_d3d, statePush),
|
|
BR_CMETHOD_REF(br_renderer_d3d, statePop),
|
|
BR_CMETHOD_REF(br_renderer_d3d, stateSave),
|
|
BR_CMETHOD_REF(br_renderer_d3d, stateRestore),
|
|
BR_CMETHOD_REF(br_renderer_d3d, stateMask),
|
|
BR_CMETHOD_REF(br_renderer_d3d, stateDefault),
|
|
BR_CMETHOD_REF(br_renderer_d3d, boundsTestF),
|
|
BR_CMETHOD_REF(br_renderer_d3d, boundsTestX),
|
|
BR_CMETHOD_REF(br_renderer_d3d, coverageTestF),
|
|
BR_CMETHOD_REF(br_renderer_d3d, coverageTestX),
|
|
BR_CMETHOD_REF(br_renderer_d3d, viewDistanceF),
|
|
BR_CMETHOD_REF(br_renderer_d3d, viewDistanceX),
|
|
BR_CMETHOD_REF(br_renderer_d3d, commandModeSet),
|
|
BR_CMETHOD_REF(br_renderer_d3d, commandModeQuery),
|
|
BR_CMETHOD_REF(br_renderer_d3d, commandModeDefault),
|
|
BR_CMETHOD_REF(br_renderer_d3d, commandModePush),
|
|
BR_CMETHOD_REF(br_renderer_d3d, commandModePop),
|
|
BR_CMETHOD_REF(br_renderer_d3d, flush),
|
|
BR_CMETHOD_REF(br_renderer_d3d, synchronise),
|
|
BR_CMETHOD_REF(br_renderer_d3d, partQueryCapability),
|
|
BR_CMETHOD_REF(br_renderer_d3d, stateQueryPerformance),
|
|
};
|