You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2048 lines
63 KiB
2048 lines
63 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// rmprov.cpp
|
|
//
|
|
// Declares classes for ramp material handling.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
include(`m4hdr.mh')dnl
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
//#define _D3DHAL_H_
|
|
//typedef void* LPD3DHAL_CALLBACKS;
|
|
//typedef void* LPD3DHAL_CALLBACKS2;
|
|
//typedef void* LPD3DHAL_TRANSFORMLIGHTCALLBACKS;
|
|
//typedef void* LPD3DHAL_TEXTURE3CALLBACKS;
|
|
//typedef void* LPD3DHAL_GLOBALDRIVERDATA;
|
|
//typedef void* LPD3DHAL_D3DEXTENDEDCAPS;
|
|
//
|
|
//#include <assert.h>
|
|
//#include <string.h>
|
|
//#include <math.h>
|
|
//
|
|
//extern "C" {
|
|
//#include "driver.h"
|
|
//#include "lightdrv.h"
|
|
//#include "fsqrt.h"
|
|
//#include "lists.h"
|
|
//#include "ramplt.h"
|
|
//#include "rampmap.h"
|
|
//#include "transfm.h"
|
|
//#include "handle.h"
|
|
//#include "gentex.h"
|
|
//#include "dmath.h"
|
|
//#include "ramplti.h"
|
|
//#include "dpf.h"
|
|
//
|
|
//#include <d3di.h>
|
|
//#include "..\include\genras.h"
|
|
//}
|
|
//
|
|
//static void Destroy(RLDDIDriver* drv);
|
|
//static long RampLightingService(RLDDIDriver* drv, RLDDIServiceType type,
|
|
// long arg1, void* arg2);
|
|
//
|
|
//#define SPEC(tab, s) tab->table[QVALTOFXP(s, 8)]
|
|
//#define NEXT_X(type, x, size) ((type*)((char*) (x) + (size)))
|
|
//#define NEXT_ELEMENT(el, size) NEXT_X(D3DLIGHTINGELEMENT, el, size)
|
|
//#define NEXT_COLOR(col, size) NEXT_X(unsigned long, col, size)
|
|
//#define NEXT_VERTEX(v, size) NEXT_X(D3DTLVERTEX, v, size)
|
|
//
|
|
#define CVAL_TO_RGBA(rgb) RGBA_MAKE((int)(255.0 * (rgb)->r), \
|
|
(int)(255.0 * (rgb)->g), \
|
|
(int)(255.0 * (rgb)->b), \
|
|
(int)(255.0 * (rgb)->a))
|
|
|
|
//static HRESULT LitFog(RLDDIRampLightingDriver* driver,
|
|
// int count, D3DTLVERTEX* v, size_t v_size,
|
|
// Workspace* wp);
|
|
static void ReclaimMaterials(RLDDIRampLightingDriver* driver);
|
|
//void vectordvNormalise12(D3DVECTOR* v);
|
|
//
|
|
//static D3DCOLOR cval_to_cola(D3DCOLORVALUE* rgb)
|
|
//{
|
|
// return CVAL_TO_RGBA(rgb);
|
|
//}
|
|
//
|
|
|
|
static int InitRampmap(PD3DI_RASTCTX pCtx, RLDDIRampLightingDriver* driver, RLDDIRampmap** rampmap_return)
|
|
{
|
|
RLDDIColormap* cmap;
|
|
RLDDIRampmap* rampmap;
|
|
RLDDIColorAllocator* alloc;
|
|
LPDDRAWI_DDRAWSURFACE_LCL pLcl =
|
|
((LPDDRAWI_DDRAWSURFACE_INT)(pCtx->pDDS))->lpLcl;
|
|
|
|
if ((pCtx->iSurfaceType == D3DI_SPTFMT_PALETTE4) || (pCtx->iSurfaceType == D3DI_SPTFMT_PALETTE8))
|
|
{
|
|
if (pCtx->iSurfaceType == D3DI_SPTFMT_PALETTE4)
|
|
{
|
|
driver->palette = RLDDICreatePalette(pCtx, 16);
|
|
}
|
|
else
|
|
{
|
|
driver->palette = RLDDICreatePalette(pCtx, 256);
|
|
}
|
|
alloc = &driver->palette->alloc;
|
|
|
|
// Initialize palette
|
|
PALETTEENTRY ddppe[256];
|
|
HRESULT ddrval;
|
|
LPDIRECTDRAWPALETTE lpPal;
|
|
ddrval = pCtx->pDDS->GetPalette(&lpPal);
|
|
ddrval = lpPal->GetEntries(0, 0, 256, ddppe);
|
|
|
|
memset(driver->ddpalette, 0, sizeof(PALETTEENTRY) * 256);
|
|
for (int i = 0; i < 256; i++) {
|
|
DWORD dwFlags = ddppe[i].peFlags & (D3DPAL_FREE | D3DPAL_READONLY | D3DPAL_RESERVED);
|
|
driver->ddpalette[i].peFlags = ddppe[i].peFlags;
|
|
switch (dwFlags) {
|
|
case D3DPAL_FREE:
|
|
D3D_INFO(6, "(Rast) Color %d is free", i);
|
|
RLDDIPaletteFreeColor(driver->palette, i);
|
|
break;
|
|
case D3DPAL_READONLY:
|
|
D3D_INFO(6, "(Rast) Color %d is readonly", i);
|
|
RLDDIPaletteSetColor(driver->palette, i,
|
|
ddppe[i].peRed, ddppe[i].peGreen, ddppe[i].peBlue);
|
|
driver->ddpalette[i].peRed = ddppe[i].peRed;
|
|
driver->ddpalette[i].peGreen = ddppe[i].peGreen;
|
|
driver->ddpalette[i].peBlue = ddppe[i].peBlue;
|
|
break;
|
|
case D3DPAL_RESERVED:
|
|
D3D_INFO(6, "(Rast) Color %d is reserved", i);
|
|
break;
|
|
default:
|
|
D3D_ERR("(Rast) Unknown flag passed in peFlags");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
DWORD dwRMask, dwGMask, dwBMask;
|
|
if (pLcl->dwFlags & DDRAWISURF_HASPIXELFORMAT)
|
|
{
|
|
dwRMask = pLcl->lpGbl->ddpfSurface.dwRBitMask;
|
|
dwGMask = pLcl->lpGbl->ddpfSurface.dwGBitMask;
|
|
dwBMask = pLcl->lpGbl->ddpfSurface.dwBBitMask;
|
|
}
|
|
else
|
|
{
|
|
dwRMask = pLcl->lpGbl->lpDD->vmiData.ddpfDisplay.dwRBitMask;
|
|
dwGMask = pLcl->lpGbl->lpDD->vmiData.ddpfDisplay.dwGBitMask;
|
|
dwBMask = pLcl->lpGbl->lpDD->vmiData.ddpfDisplay.dwBBitMask;
|
|
}
|
|
|
|
driver->rgbmap = RLDDICreateRGBMap(dwRMask,dwGMask,dwBMask);
|
|
alloc = &driver->rgbmap->alloc;
|
|
}
|
|
|
|
cmap = RLDDICreateIndirectColormap(alloc, 32768);
|
|
|
|
if (cmap == NULL || cmap->priv == NULL)
|
|
return DDERR_OUTOFMEMORY;
|
|
|
|
driver->pixelmap = RLDDIIndirectColormapGetMap(cmap);
|
|
pCtx->pRampMap = (PUINT32)driver->pixelmap;
|
|
rampmap = RLDDICreateRampmap(cmap);
|
|
|
|
if (rampmap)
|
|
*rampmap_return = rampmap;
|
|
else
|
|
return DDERR_OUTOFMEMORY;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
static void ReleaseRampmap(RLDDIRampmap* rampmap)
|
|
{
|
|
if (rampmap != NULL)
|
|
{
|
|
RLDDIColormap* cmap = rampmap->cmap;
|
|
|
|
RLDDIDestroyRampmap(rampmap);
|
|
if (cmap != NULL)
|
|
cmap->destroy(cmap);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampCreate
|
|
//
|
|
// Creates the original RLDDIRampLightingDriver with associated lists. The
|
|
// pointer returned is kept in pCtx->pRampDrv.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
RLDDIRampLightingDriver* RLDDIRampCreate(PD3DI_RASTCTX pCtx/*int width, int height, LPDIRECT3DDEVICEI lpD3DDevI*/)
|
|
{
|
|
RLDDIRampLightingDriver* driver;
|
|
RLDDISoftLightingDriver* sdriver;
|
|
int i;
|
|
|
|
if (D3DMalloc((void**) &driver, sizeof(RLDDIRampLightingDriver)))
|
|
return NULL;
|
|
memset(driver, 0, sizeof(RLDDIRampLightingDriver));
|
|
|
|
sdriver = (RLDDISoftLightingDriver*)driver;
|
|
|
|
pCtx->pRampDrv = driver;
|
|
|
|
// sdriver->driver.prev = NULL;
|
|
// sdriver->driver.next = NULL;
|
|
// sdriver->driver.width = width;
|
|
// sdriver->driver.height = height;
|
|
// sdriver->driver.destroy = Destroy;
|
|
// sdriver->driver.service = RampLightingService;
|
|
// sdriver->driver.lpD3DDevI = lpD3DDevI;
|
|
|
|
/*
|
|
* Initialise driver specific fields.
|
|
*/
|
|
// sdriver->count = 0;
|
|
// sdriver->lights = NULL;
|
|
|
|
LIST_INITIALIZE(&driver->materials);
|
|
LIST_INITIALIZE(&driver->orphans);
|
|
|
|
CIRCLE_QUEUE_INITIALIZE(&driver->agequeue,AgeList);
|
|
for (i = 0; i < AGE_MAX; i++)
|
|
{
|
|
LIST_INITIALIZE(&driver->agelists[i].agelist);
|
|
CIRCLE_QUEUE_INSERT_END(&driver->agequeue, AgeList,
|
|
&driver->agelists[i], list);
|
|
}
|
|
driver->active = CIRCLE_QUEUE_FIRST(&driver->agequeue);
|
|
driver->already_aged = FALSE;
|
|
|
|
LIST_INITIALIZE(&driver->rmactive);
|
|
for (i = 0; i < HASH_SIZE; i++)
|
|
LIST_INITIALIZE(&driver->hash[i]);
|
|
|
|
// LIST_INITIALIZE(&driver->specular_tables);
|
|
// driver->specular_table = NULL;
|
|
|
|
driver->fog_enable = FALSE;
|
|
driver->fog_color = FALSE;
|
|
|
|
sdriver->fog_mode = D3DFOG_NONE;
|
|
|
|
if (InitRampmap(pCtx, driver, &driver->rampmap) == S_OK)
|
|
return /*(RLDDIDriver*)*/ driver;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampDestroy
|
|
//
|
|
// Destroys a RLDDIRampLightingDriver with all associated objects and memory.
|
|
// The pCtx->pRampDrv pointer should be set to NULL after this occurs.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RLDDIRampDestroy(RLDDIRampLightingDriver* drv)
|
|
{
|
|
// RLDDISoftLightingDriver* sdriver = (RLDDISoftLightingDriver*)drv;
|
|
RLDDIRampLightingDriver* driver = (RLDDIRampLightingDriver*) drv;
|
|
|
|
// if (sdriver->lights) {
|
|
// D3DFree(sdriver->lights);
|
|
// }
|
|
//
|
|
// {
|
|
// SpecularTable* spec;
|
|
// SpecularTable* spec_next;
|
|
//
|
|
// for (spec = LIST_FIRST(&driver->specular_tables);
|
|
// spec;
|
|
// spec = spec_next) {
|
|
// spec_next = LIST_NEXT(spec,list);
|
|
// D3DFree(spec);
|
|
// }
|
|
// }
|
|
//
|
|
|
|
ReclaimMaterials(driver);
|
|
|
|
ReleaseRampmap(driver->rampmap);
|
|
|
|
RLDDIDestroyRGBMap(driver->rgbmap);
|
|
|
|
// this must be done AFTER ReclaimMaterials
|
|
if (driver->palette)
|
|
{
|
|
RLDDIDestroyPalette(driver->palette);
|
|
}
|
|
|
|
D3DFree(drv);
|
|
}
|
|
|
|
static void ReclaimMaterials(RLDDIRampLightingDriver* driver)
|
|
{
|
|
/*
|
|
* Reclaim materials.
|
|
*/
|
|
for (ExtMaterial* extmat = LIST_FIRST(&driver->materials);
|
|
extmat;
|
|
extmat = LIST_FIRST(&driver->materials))
|
|
{
|
|
delete extmat;
|
|
}
|
|
for (IntMaterial* intmat = LIST_FIRST(&driver->orphans);
|
|
intmat;
|
|
intmat = LIST_FIRST(&driver->orphans))
|
|
{
|
|
delete intmat;
|
|
}
|
|
|
|
/*
|
|
* After destroying all the materials, there should be nothing
|
|
* left in the ramp material hash tables. Lets just make sure.
|
|
*/
|
|
for (int i = 0; i < HASH_SIZE; i++)
|
|
{
|
|
DDASSERT(LIST_FIRST(&driver->hash[i]) == NULL);
|
|
}
|
|
}
|
|
|
|
ExtMaterial::ExtMaterial(RLDDIRampLightingDriver* adriver, D3DMATERIALHANDLE hMat)
|
|
{
|
|
D3D_INFO(7, "(Rast) Making new ExtMaterial(%08x)", this);
|
|
driver = adriver;
|
|
generation = 0;
|
|
texture_generation = 0;
|
|
texture = NULL;
|
|
LIST_INITIALIZE(&intlist);
|
|
}
|
|
|
|
ExtMaterial::~ExtMaterial()
|
|
{
|
|
D3D_INFO(7, "(Rast) Destroying ExtMaterial(%08x)", this);
|
|
|
|
IntMaterial* intmat;
|
|
|
|
/*
|
|
* Transfer active internal materials to the driver's orphans list
|
|
* to be reclaimed after Clear. Free any inactive ones now.
|
|
*/
|
|
while (LIST_FIRST(&intlist))
|
|
{
|
|
intmat = LIST_FIRST(&intlist);
|
|
if (intmat->IsActive())
|
|
{
|
|
D3D_INFO(7, "(Rast) IntMaterial(%08x) is still active, moving to orphan list",
|
|
intmat);
|
|
intmat->Orphan();
|
|
}
|
|
else
|
|
delete intmat;
|
|
}
|
|
|
|
if (driver->current_material == this)
|
|
{
|
|
D3D_WARN(3, "(Rast) Destroying current material, setting to NULL");
|
|
driver->current_material = NULL;
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ExtMaterial::SetMaterial"
|
|
|
|
void ExtMaterial::SetMaterial(D3DMATERIAL* lpMat)
|
|
{
|
|
D3D_INFO(7, "(Rast) Setting value of ExtMaterial(%08x)", this);
|
|
if (!memcmp(&mat, lpMat, sizeof(D3DMATERIAL)))
|
|
{
|
|
D3D_WARN(7, "(Rast) ExtMaterial::SetMaterial: New value is identical to old value, ignoring");
|
|
return;
|
|
}
|
|
mat = *lpMat;
|
|
if (mat.hTexture)
|
|
{
|
|
PD3DI_SPANTEX tex;
|
|
|
|
#ifdef DEBUG
|
|
__try
|
|
{
|
|
#endif
|
|
tex = HANDLE_TO_SPANTEX(mat.hTexture);
|
|
texture_generation = tex->iGeneration;
|
|
texture = tex;
|
|
#ifdef DEBUG
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
D3D_ERR("Invalid texture handle");
|
|
mat.hTexture = 0;
|
|
texture = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
else texture = NULL;
|
|
Age();
|
|
}
|
|
|
|
void ExtMaterial::Age()
|
|
{
|
|
IntMaterial* intmat;
|
|
|
|
/*
|
|
* Transfer active internal materials to the driver's orphans list
|
|
* to be reclaimed after Clear. Free any inactive ones now.
|
|
*/
|
|
while (LIST_FIRST(&intlist))
|
|
{
|
|
intmat = LIST_FIRST(&intlist);
|
|
if (intmat->IsActive())
|
|
{
|
|
D3D_INFO(7, "(Rast) IntMaterial(%08x) is still active, moving to orphan list",
|
|
intmat);
|
|
intmat->Orphan();
|
|
}
|
|
else
|
|
delete intmat;
|
|
}
|
|
|
|
generation++;
|
|
}
|
|
|
|
IntMaterial* ExtMaterial::FindIntMaterial()
|
|
{
|
|
IntMaterial* intmat;
|
|
|
|
if (texture)
|
|
{
|
|
D3D_INFO(7, "(Rast) Checking texture in ExtMaterial(%08x) for new palette or texture swap", this);
|
|
PD3DI_SPANTEX tex;
|
|
tex = HANDLE_TO_SPANTEX(mat.hTexture);
|
|
if (tex != texture)
|
|
{
|
|
D3D_WARN(1, "(Rast) Textures swapped, discarding old materials");
|
|
texture_generation = tex->iGeneration;
|
|
texture = tex;
|
|
Age();
|
|
}
|
|
else if (texture_generation != tex->iGeneration)
|
|
{
|
|
D3D_WARN(1, "(Rast) Texture has changed, discarding old materials");
|
|
texture_generation = tex->iGeneration;
|
|
Age();
|
|
}
|
|
}
|
|
|
|
D3D_INFO(7, "(Rast) Searching ExtMaterial(%08x) for an IntMaterial", this);
|
|
for (intmat = LIST_FIRST(&intlist); intmat; intmat = LIST_NEXT(intmat,list))
|
|
{
|
|
if (intmat->Valid())
|
|
{
|
|
/*
|
|
* Found it. Move to the front of the list to optimise searches.
|
|
*/
|
|
LIST_DELETE(intmat, list);
|
|
LIST_INSERT_ROOT(&intlist, intmat, list);
|
|
D3D_INFO(7, "(Rast) IntMaterial(%08x) found", intmat);
|
|
return intmat;
|
|
}
|
|
}
|
|
D3D_INFO(7, "(Rast) No matching IntMaterial found, creating new one");
|
|
return new IntMaterial(this);
|
|
}
|
|
|
|
/*
|
|
* Find what range of values lighting should take. The base is the
|
|
* pixel value (in fixed point) of the dark end of the material. The
|
|
* shift value is user to convert a 0.16 fixed point shade into the
|
|
* range needed for the material. e.g.
|
|
*
|
|
* pixel = base + (VALTOFX8(shade) << shift);
|
|
*
|
|
*/
|
|
HRESULT ExtMaterial::FindLightingRange(unsigned long* base,
|
|
unsigned long* size,
|
|
BOOL* specular,
|
|
unsigned long** texture_colors)
|
|
{
|
|
IntMaterial* intmat;
|
|
|
|
D3D_INFO(7, "(Rast) Finding color ranges for ExtMaterial(%08x)", this);
|
|
intmat = FindIntMaterial();
|
|
if (intmat == NULL) return DDERR_NOTFOUND;
|
|
|
|
/*
|
|
* Delegate to the internal material.
|
|
*/
|
|
D3D_INFO(7, "(Rast) Using IntMaterial(%08x) for ExtMaterial(%08x)", intmat, this);
|
|
return intmat->FindLightingRange(base, size, specular, texture_colors);
|
|
}
|
|
|
|
IntMaterial::IntMaterial(ExtMaterial* anextmat)
|
|
{
|
|
D3D_INFO(7, "(Rast) Creating new IntMaterial(%08x) for ExtMaterial(%08x)",
|
|
this, extmat);
|
|
/*
|
|
* Remember the driver object.
|
|
*/
|
|
extmat = anextmat;
|
|
driver = extmat->driver;
|
|
|
|
RLDDISoftLightingDriver* sdriver = (RLDDISoftLightingDriver*) driver;
|
|
|
|
/*
|
|
* Initialise stuff so that if we have to abort, the destructor can
|
|
* clean up.
|
|
*/
|
|
active = FALSE;
|
|
ramps = NULL;
|
|
colors = NULL;
|
|
ambient = sdriver->ambient;
|
|
viewport_id = driver->viewport_id;
|
|
fog_enable = driver->fog_enable;
|
|
fog_color = driver->fog_color;
|
|
generation = extmat->generation;
|
|
|
|
/*
|
|
* Put us on the list of internal materials owned by our creator.
|
|
*/
|
|
LIST_INSERT_ROOT(&extmat->intlist, this, list);
|
|
|
|
/*
|
|
* Add to the age=1 list for material use tracking.
|
|
*/
|
|
AgeList* age1 = CIRCLE_QUEUE_NEXT(&driver->agequeue,driver->active,list);
|
|
age = age1;
|
|
LIST_INSERT_ROOT(&age1->agelist, this, agelist);
|
|
|
|
/*
|
|
* Record the current external material's D3DMATERIAL. Note that this
|
|
* can change at any time. We need a snapshot.
|
|
*/
|
|
mat = extmat->mat;
|
|
|
|
PD3DI_SPANTEX tex;
|
|
if (mat.hTexture)
|
|
tex = HANDLE_TO_SPANTEX(mat.hTexture);
|
|
else
|
|
tex = NULL;
|
|
|
|
if (tex == NULL)
|
|
ramp_count = 1;
|
|
else
|
|
ramp_count = tex->iPaletteSize;
|
|
|
|
ramps = new RampMaterial*[ramp_count];
|
|
if (ramps == NULL)
|
|
{
|
|
D3D_ERR("Out of memory creating IntMaterial");
|
|
delete this;
|
|
//this = NULL;
|
|
return;
|
|
}
|
|
colors = new unsigned long[ramp_count];
|
|
|
|
memset(ramps, 0, ramp_count * sizeof(RampMaterial*));
|
|
|
|
D3DMATERIAL tmat;
|
|
tmat = mat;
|
|
tmat.hTexture = 0L;
|
|
LPPALETTEENTRY palette = NULL;
|
|
if (tex)
|
|
palette = (LPPALETTEENTRY)tex->pPalette;
|
|
for (int i = 0; i < ramp_count; i++)
|
|
{
|
|
if (tex)
|
|
{
|
|
tmat.ambient.r = (float)((palette->peRed * mat.ambient.r) / 255.0);
|
|
tmat.ambient.g = (float)((palette->peGreen * mat.ambient.g) / 255.0);
|
|
tmat.ambient.b = (float)((palette->peBlue * mat.ambient.b) / 255.0);
|
|
tmat.ambient.a = mat.ambient.a;
|
|
tmat.diffuse.r = (float)((palette->peRed * mat.diffuse.r) / 255.0);
|
|
tmat.diffuse.g = (float)((palette->peGreen * mat.diffuse.g) / 255.0);
|
|
tmat.diffuse.b = (float)((palette->peBlue * mat.diffuse.b) / 255.0);
|
|
tmat.diffuse.a = mat.diffuse.a;
|
|
palette++;
|
|
}
|
|
ramps[i] = RampMaterial::Find(driver, &tmat);
|
|
if (ramps[i] == NULL)
|
|
{
|
|
D3D_ERR("Can't find RampMaterial for IntMaterial");
|
|
delete this;
|
|
//this = NULL;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
IntMaterial::~IntMaterial()
|
|
{
|
|
D3D_INFO(9, "(Rast) Destroying IntMaterial(%08x)", this);
|
|
|
|
/*
|
|
* Give up our colors.
|
|
*/
|
|
if (active) Deactivate();
|
|
|
|
/*
|
|
* Remove from lists.
|
|
*/
|
|
LIST_DELETE(this, list);
|
|
LIST_DELETE(this, agelist);
|
|
|
|
/*
|
|
* Release underlying ramp materials and memory.
|
|
*/
|
|
if (ramps)
|
|
{
|
|
for (int i = 0; i < ramp_count; i++)
|
|
if (ramps[i])
|
|
ramps[i]->Release();
|
|
delete ramps;
|
|
}
|
|
if (colors)
|
|
delete colors;
|
|
}
|
|
|
|
int IntMaterial::Valid()
|
|
{
|
|
RLDDISoftLightingDriver* sdriver = (RLDDISoftLightingDriver*) driver;
|
|
|
|
/*
|
|
* Ambient only matters for lit materials.
|
|
*/
|
|
if (mat.dwRampSize > 1 && ambient != sdriver->ambient)
|
|
return FALSE;
|
|
|
|
return (viewport_id == driver->viewport_id
|
|
&& fog_enable == driver->fog_enable
|
|
&& fog_color == driver->fog_color
|
|
&& generation == extmat->generation);
|
|
}
|
|
|
|
HRESULT IntMaterial::FindLightingRange(unsigned long* base,
|
|
unsigned long* size,
|
|
BOOL* specular,
|
|
unsigned long** texture_colors)
|
|
{
|
|
HRESULT error;
|
|
|
|
D3D_INFO(7, "(Rast) Finding color ranges for IntMaterial(%08x)", this);
|
|
|
|
/*
|
|
* Make sure the material is active.
|
|
*/
|
|
if ((error = Activate()) != DD_OK)
|
|
{
|
|
D3D_ERR("Can't activate IntMaterial");
|
|
return error;
|
|
}
|
|
|
|
/*
|
|
* For non-textured materials, the base is the start of the
|
|
* color range. For textured materials, the base is zero and
|
|
* texture_colors is set to the array containing the color bases.
|
|
*/
|
|
if (mat.hTexture)
|
|
{
|
|
// until we find a reason to do otherwise, have base
|
|
// be just a plain color index offset (no alpha, and no shift
|
|
// up by 8
|
|
// *base = CI_MAKE((int)(mat.diffuse.a * 255.0), 0, 0);
|
|
*base = 0;
|
|
*texture_colors = colors;
|
|
}
|
|
else
|
|
{
|
|
// *base = CI_MAKE((int)(mat.diffuse.a * 255.0), colors[0], 0);
|
|
*base = colors[0];
|
|
}
|
|
*size = mat.dwRampSize;
|
|
|
|
// same code as in SetColorsStd and SetColorsFog
|
|
if ((*size <= 2) || ((mat.specular.r == 0.0) &&
|
|
(mat.specular.g == 0.0) &&
|
|
(mat.specular.b == 0.0)))
|
|
*specular = FALSE;
|
|
else
|
|
*specular = TRUE;
|
|
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
HRESULT IntMaterial::Activate()
|
|
{
|
|
HRESULT error;
|
|
|
|
/*
|
|
* If we are already active, just make sure we are on the right list.
|
|
*/
|
|
if (active)
|
|
{
|
|
D3D_INFO(7, "(Rast) IntMaterial(%08x) is already active", this);
|
|
if (age != driver->active)
|
|
{
|
|
D3D_INFO(7, "(Rast) Moving IntMaterial(%08x) to list %08x",
|
|
this, driver->active);
|
|
LIST_DELETE(this, agelist);
|
|
LIST_INSERT_ROOT(&driver->active->agelist, this, agelist);
|
|
age = driver->active;
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(7, "(Rast) IntMaterial(%08x) is already on the active list", this);
|
|
}
|
|
return DD_OK;
|
|
}
|
|
|
|
D3D_INFO(6, "(Rast) Activating IntMaterial(%08x)", this);
|
|
|
|
/*
|
|
* Activate all the underlying materials and record their bases.
|
|
*/
|
|
for (int i = 0; i < ramp_count; i++)
|
|
{
|
|
if ((error = ramps[i]->Activate()) != DD_OK)
|
|
{
|
|
D3D_WARN(0, "Failed to activate RampMaterial(%08x) for IntMaterial(%08x)",
|
|
ramps[i], this);
|
|
/*
|
|
* Failed to activate all the underlying RampMaterials.
|
|
* Deactivate any which we did manage.
|
|
*/
|
|
for (int j = 0; j < i; j++)
|
|
ramps[j]->Deactivate();
|
|
return error;
|
|
}
|
|
colors[i] = ramps[i]->Base();
|
|
}
|
|
|
|
/*
|
|
* We are now active, so remember and put us on the age=0 list.
|
|
*/
|
|
D3D_INFO(7, "(Rast) Moving IntMaterial(%08x) to list %08x", this, driver->active);
|
|
active = TRUE;
|
|
LIST_DELETE(this, agelist);
|
|
LIST_INSERT_ROOT(&driver->active->agelist, this, agelist);
|
|
age = driver->active;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
void IntMaterial::Deactivate()
|
|
{
|
|
if (!active) return;
|
|
|
|
D3D_INFO(6, "(Rast) Deactivating IntMaterial(%08x)", this);
|
|
|
|
for (int i = 0; i < ramp_count; i++)
|
|
ramps[i]->Deactivate();
|
|
|
|
active = FALSE;
|
|
}
|
|
|
|
void IntMaterial::Orphan()
|
|
{
|
|
LIST_DELETE(this, list);
|
|
LIST_INSERT_ROOT(&driver->orphans, this, list);
|
|
}
|
|
|
|
RampMaterial::RampMaterial(RLDDIRampLightingDriver* adriver,
|
|
D3DMATERIAL* lpMat,
|
|
float anambient)
|
|
: driver(adriver)
|
|
{
|
|
D3D_INFO(6, "(Rast) Creating new RampMaterial(%08x) color=[%d,%d,%d] size=%d",
|
|
this,
|
|
(int)(255 * lpMat->diffuse.r),
|
|
(int)(255 * lpMat->diffuse.g),
|
|
(int)(255 * lpMat->diffuse.b),
|
|
lpMat->dwRampSize);
|
|
|
|
unsigned int hash = CVAL_TO_RGBA(&lpMat->diffuse) % HASH_SIZE; /* XXX */
|
|
|
|
LIST_INSERT_ROOT(&driver->hash[hash], this, hash);
|
|
LIST_INITIALIZE(&sharers);
|
|
|
|
usage = 1;
|
|
active = 0;
|
|
|
|
ramp = NULL;
|
|
owner = FALSE;
|
|
ambient = anambient;
|
|
mat = *lpMat;
|
|
fog_enable = driver->fog_enable;
|
|
fog_color = driver->fog_color;
|
|
LIST_INITIALIZE_MEMBER(this,deferredlist);
|
|
}
|
|
|
|
RampMaterial::~RampMaterial()
|
|
{
|
|
D3D_INFO(9, "(Rast) Destroying RampMaterial(%08x)", this);
|
|
|
|
DDASSERT(usage == 0); // don't destroy stuff, call Release
|
|
DDASSERT(active == 0); // don't Release an active material
|
|
|
|
LIST_DELETE(this, hash);
|
|
}
|
|
|
|
int RampMaterial::MaterialSame(D3DMATERIAL* mat1, D3DMATERIAL* mat2)
|
|
{
|
|
if (mat1->ambient.r == mat2->ambient.r
|
|
&& mat1->ambient.g == mat2->ambient.g
|
|
&& mat1->ambient.b == mat2->ambient.b
|
|
&& mat1->diffuse.r == mat2->diffuse.r
|
|
&& mat1->diffuse.g == mat2->diffuse.g
|
|
&& mat1->diffuse.b == mat2->diffuse.b
|
|
&& mat1->specular.r == mat2->specular.r
|
|
&& mat1->specular.g == mat2->specular.g
|
|
&& mat1->specular.b == mat2->specular.b
|
|
&& mat1->emissive.r == mat2->emissive.r
|
|
&& mat1->emissive.g == mat2->emissive.g
|
|
&& mat1->emissive.b == mat2->emissive.b
|
|
&& mat1->power == mat2->power
|
|
&& mat1->dwRampSize == mat2->dwRampSize)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
#define ABS(a) ((a) > 0 ? (a) : -(a))
|
|
|
|
int RampMaterial::RGBDist(D3DCOLORVALUE* rgb1, D3DCOLORVALUE* rgb2)
|
|
{
|
|
return ABS((int)(255.0 * (rgb1->r - rgb2->r)))
|
|
+ ABS((int)(255.0 * (rgb1->g - rgb2->g)))
|
|
+ ABS((int)(255.0 * (rgb1->b - rgb2->b)));
|
|
}
|
|
|
|
int RampMaterial::CompareMaterials(D3DMATERIAL* mat1, D3DMATERIAL* mat2)
|
|
{
|
|
return (RGBDist(&mat1->ambient, &mat2->ambient)
|
|
+ RGBDist(&mat1->diffuse, &mat2->diffuse)
|
|
+ RGBDist(&mat1->specular, &mat2->specular)
|
|
+ ABS((int)mat1->power - (int)mat2->power));
|
|
}
|
|
|
|
RampMaterial* RampMaterial::Find(RLDDIRampLightingDriver* driver,
|
|
D3DMATERIAL* mat)
|
|
{
|
|
D3D_INFO(8, "(Rast) Searching for RampMaterial");
|
|
|
|
unsigned int hash = CVAL_TO_RGBA(&mat->diffuse) % HASH_SIZE; /* XXX */
|
|
RLDDISoftLightingDriver* sdriver = (RLDDISoftLightingDriver*)driver;
|
|
RampMaterial* rm = NULL;
|
|
float ambient;
|
|
|
|
if (mat->dwRampSize > 1 && !driver->fog_enable)
|
|
ambient = sdriver->ambient;
|
|
else
|
|
ambient = 0.0f;
|
|
|
|
for (rm = LIST_FIRST(&driver->hash[hash]);
|
|
rm; rm = LIST_NEXT(rm,hash))
|
|
{
|
|
if (MaterialSame(&rm->mat, mat)
|
|
&& rm->ambient == ambient
|
|
&& driver->fog_enable == rm->fog_enable
|
|
&& driver->fog_color == rm->fog_color)
|
|
break;
|
|
}
|
|
if (rm)
|
|
{
|
|
rm->usage++;
|
|
D3D_INFO(7, "(Rast) RampMaterial(%08x) found, usage is now %d",
|
|
rm, rm->usage);
|
|
return rm;
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(7, "(Rast) No matching material found, creating new one");
|
|
return new RampMaterial(driver, mat, ambient);
|
|
}
|
|
}
|
|
|
|
void RampMaterial::Release()
|
|
{
|
|
usage--;
|
|
D3D_INFO(7, "(Rast) Releasing RampMaterial(%08x), usage is now %d", this, usage);
|
|
if (usage == 0)
|
|
delete this;
|
|
}
|
|
|
|
HRESULT RampMaterial::Activate()
|
|
{
|
|
HRESULT error;
|
|
|
|
D3D_INFO(6, "(Rast) Activating RampMaterial(%08x)", this);
|
|
|
|
/*
|
|
* The first time we are activated, allocate some colors.
|
|
*/
|
|
if (active == 0)
|
|
{
|
|
if ((error = AllocateColors()) != DD_OK)
|
|
return error;
|
|
}
|
|
|
|
active++;
|
|
DDASSERT(active <= usage);
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
void RampMaterial::Deactivate()
|
|
{
|
|
D3D_INFO(6, "(Rast) Deactivating RampMaterial(%08x)", this);
|
|
|
|
active--;
|
|
DDASSERT(active >= 0);
|
|
|
|
/*
|
|
* Free our colors if none of our users are active.
|
|
*/
|
|
if (active == 0)
|
|
FreeColors();
|
|
}
|
|
|
|
unsigned long RampMaterial::Base()
|
|
{
|
|
DDASSERT(ramp != NULL);
|
|
D3D_INFO(7, "(Rast) Base pixel for RampMaterial(%08x) is %d", this, ramp->base);
|
|
return ramp->base;
|
|
}
|
|
|
|
HRESULT RampMaterial::AllocateColors()
|
|
{
|
|
D3D_INFO(6, "(Rast) Allocating colors for RampMaterial(%08x)", this);
|
|
|
|
DDASSERT(ramp == NULL);
|
|
|
|
ramp = RLDDIRampmapAllocate(driver->rampmap, mat.dwRampSize);
|
|
|
|
if (ramp)
|
|
{
|
|
D3D_INFO(7, "(Rast) Ramp(%08x) range %d..%d allocated for RampMaterial(%08x)",
|
|
ramp, ramp->base, ramp->base + ramp->size - 1, this);
|
|
|
|
/*
|
|
* We got a ramp, so mark this material as owning the ramp and add
|
|
* it to the active list.
|
|
*/
|
|
owner = TRUE;
|
|
SetColors();
|
|
|
|
/*
|
|
* This material now owns the ramp, so place it on the active list.
|
|
*/
|
|
D3D_INFO(7, "(Rast) Adding RampMaterial(%08x) to active material list", this);
|
|
LIST_INSERT_ROOT(&driver->rmactive, this, list);
|
|
|
|
/*
|
|
* No sharers yet.
|
|
*/
|
|
LIST_INITIALIZE(&sharers);
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(7, "(Rast) No Ramp allocated, searching for closest active material");
|
|
|
|
/*
|
|
* Search the active list for a similar material and share its ramp.
|
|
*/
|
|
RampMaterial *t;
|
|
RampMaterial *best;
|
|
int closeness, c;
|
|
|
|
best = NULL;
|
|
closeness = INT_MAX;
|
|
do
|
|
{
|
|
for (t = LIST_FIRST(&driver->rmactive); t; t = LIST_NEXT(t,list))
|
|
{
|
|
if (t->ramp)
|
|
{
|
|
if (mat.dwRampSize != t->mat.dwRampSize)
|
|
continue;
|
|
|
|
c = CompareMaterials(&mat, &t->mat);
|
|
if (c < closeness)
|
|
{
|
|
best = t;
|
|
closeness = c;
|
|
}
|
|
}
|
|
}
|
|
if (best == NULL)
|
|
{
|
|
t = LIST_FIRST(&driver->rmactive);
|
|
mat.dwRampSize = t->mat.dwRampSize;
|
|
D3D_WARN(2, "(Rast) No matching ramp found in palette");
|
|
D3D_WARN(2, "(Rast) Changing material rampsize to match first list entry");
|
|
}
|
|
} while (!best);
|
|
|
|
DDASSERT(best != NULL);
|
|
|
|
/*
|
|
* Add the material to the list of sharers for the ramp owner. If
|
|
* the owner later stops using the ramp, it will be inherited by the
|
|
* first material on the sharers list.
|
|
*/
|
|
D3D_INFO(7, "(Rast) Adding RampMaterial(%08x) as sharer of RampMaterial(%08x)",
|
|
this, best);
|
|
LIST_INSERT_ROOT(&best->sharers, this, list);
|
|
ramp = best->ramp;
|
|
owner = FALSE;
|
|
}
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
void RampMaterial::FreeColors()
|
|
{
|
|
D3D_INFO(6, "(Rast) Freeing colors for RampMaterial(%08x)", this);
|
|
|
|
DDASSERT(ramp != NULL);
|
|
|
|
/*
|
|
* First remove us from either rmactive or owner->sharers depending on
|
|
* whether we are sharing a ramp.
|
|
*/
|
|
LIST_DELETE(this, list);
|
|
|
|
/*
|
|
* If we were waiting for a deferred call to SetColors, make sure
|
|
* it doesn't happen.
|
|
*/
|
|
if (!LIST_ORPHAN_MEMBER(this,deferredlist))
|
|
{
|
|
D3D_INFO(7, "(Rast) Removing RampMaterial(%08x) from deferred SetColor list",
|
|
this);
|
|
LIST_DELETE(this, deferredlist);
|
|
}
|
|
|
|
/*
|
|
* If we owned the ramp, then either donate it to a sharer or free it
|
|
* as appropriate.
|
|
*/
|
|
if (owner)
|
|
{
|
|
D3D_INFO(7, "(Rast) RampMaterial(%08x) owned Ramp(%08x)", this, ramp);
|
|
if (LIST_FIRST(&sharers))
|
|
{
|
|
/*
|
|
* There were sharers, so donate the ramp to the first one and
|
|
* make the others sharers of the new owner.
|
|
*/
|
|
RampMaterial* new_owner = LIST_FIRST(&sharers);
|
|
RampMaterial* t;
|
|
RampMaterial* tnext;
|
|
|
|
D3D_INFO(7, "(Rast) New owner of Ramp(%08x) is RampMaterial(%08x)",
|
|
ramp, new_owner);
|
|
new_owner->owner = TRUE;
|
|
/*
|
|
* Defer setting the colours until the next frame to avoid
|
|
* palette flashing. Check to see if it is already there.
|
|
*/
|
|
if (LIST_ORPHAN_MEMBER(new_owner,deferredlist))
|
|
{
|
|
D3D_INFO(7, "(Rast) Adding RampMaterial(%08x) to deferred SetColor list",
|
|
this);
|
|
LIST_INSERT_ROOT(&driver->rmdeferred, new_owner, deferredlist);
|
|
}
|
|
|
|
/*
|
|
* Remove from the sharers list and add to the active list.
|
|
* Clear the new owner's sharers list so that we can add
|
|
* the rest of the old sharers to it.
|
|
*/
|
|
D3D_INFO(7, "(Rast) Adding RampMaterial(%08x) to active material list",
|
|
new_owner);
|
|
LIST_DELETE(new_owner, list);
|
|
LIST_INSERT_ROOT(&driver->rmactive, new_owner, list);
|
|
LIST_INITIALIZE(&new_owner->sharers);
|
|
|
|
/*
|
|
* Traverse the rest of the sharers, and add them as
|
|
* sharers of the new owner if they are still using the
|
|
* ramp, otherwise add them to the inactive list.
|
|
*/
|
|
for (t = LIST_FIRST(&sharers); t; t = tnext)
|
|
{
|
|
tnext = LIST_NEXT(t,list);
|
|
D3D_INFO(7, "(Rast) Adding RampMaterial(%08x) as sharer of RampMaterial(%08x)",
|
|
t, new_owner);
|
|
LIST_INSERT_ROOT(&new_owner->sharers, t, list);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
D3D_INFO(7, "(Rast) Freeing Ramp(%08x) for RampMaterial(%08x)", ramp, this);
|
|
|
|
/*
|
|
* XXX maybe we should donate the ramp to a material
|
|
* which is sharing the ramp of a material which does not
|
|
* match its own colors.
|
|
*
|
|
* Set the contents of the ramp to black, which will
|
|
* possibly help out some lower level color allocation.
|
|
*/
|
|
int i;
|
|
RLDDIColormap* cmap = driver->rampmap->cmap;
|
|
|
|
for (i = 0; i < ramp->size; i++)
|
|
cmap->set_color(cmap, ramp->base + i,
|
|
0, 0, 0);
|
|
|
|
RLDDIRampmapFree(driver->rampmap, ramp);
|
|
}
|
|
}
|
|
|
|
ramp = NULL;
|
|
}
|
|
|
|
void RampMaterial::SetColorsStd()
|
|
{
|
|
int base = ramp->base;
|
|
int size = ramp->size;
|
|
int dsize;
|
|
int ssize;
|
|
int i, specular;
|
|
float ambient = (float) VALTOD(this->ambient);
|
|
RLDDIColormap* cmap = driver->rampmap->cmap;
|
|
|
|
if ((size <= 2) || ((mat.specular.r == 0.0) &&
|
|
(mat.specular.g == 0.0) &&
|
|
(mat.specular.b == 0.0)))
|
|
specular = FALSE;
|
|
else
|
|
specular = TRUE;
|
|
|
|
if (ramp->size == 1)
|
|
{
|
|
cmap->set_color(cmap, base, (int)(255.0 * mat.diffuse.r),
|
|
(int)(255.0 * mat.diffuse.g),
|
|
(int)(255.0 * mat.diffuse.b));
|
|
return;
|
|
}
|
|
|
|
if (specular != 0)
|
|
{
|
|
dsize = (3 * ramp->size) / 4;
|
|
ssize = ramp->size / 4;
|
|
}
|
|
else
|
|
{
|
|
dsize = ramp->size;
|
|
ssize = 0;
|
|
}
|
|
for (i = 0; i < dsize; i++)
|
|
{
|
|
float intensity = (1 - ambient) * ((float)i / (dsize - 1));
|
|
float r = (mat.emissive.r
|
|
+ ambient * mat.ambient.r
|
|
+ intensity * mat.diffuse.r);
|
|
float g = (mat.emissive.g
|
|
+ ambient * mat.ambient.g
|
|
+ intensity * mat.diffuse.g);
|
|
float b = (mat.emissive.b
|
|
+ ambient * mat.ambient.b
|
|
+ intensity * mat.diffuse.b);
|
|
if (r > 1.0) r = (float)1.0;
|
|
if (g > 1.0) g = (float)1.0;
|
|
if (b > 1.0) b = (float)1.0;
|
|
cmap->set_color(cmap, base + i, (int)(255.0 * r),
|
|
(int)(255.0 * g),
|
|
(int)(255.0 * b));
|
|
}
|
|
if (ssize)
|
|
{
|
|
float mdr, mdg, mdb; /* Maximum diffuse values */
|
|
float sr, sg, sb;
|
|
|
|
mdr = (mat.emissive.r
|
|
+ ambient * mat.ambient.r
|
|
+ (1 - ambient) * mat.diffuse.r);
|
|
mdg = (mat.emissive.g
|
|
+ ambient * mat.ambient.g
|
|
+ (1 - ambient) * mat.diffuse.g);
|
|
mdb = (mat.emissive.b
|
|
+ ambient * mat.ambient.b
|
|
+ (1 - ambient) * mat.diffuse.b);
|
|
|
|
if (mdr > 1.0) mdr = (float)1.0;
|
|
if (mdg > 1.0) mdg = (float)1.0;
|
|
if (mdb > 1.0) mdb = (float)1.0;
|
|
|
|
sr = mdr + mat.specular.r;
|
|
sg = mdg + mat.specular.g;
|
|
sb = mdb + mat.specular.b;
|
|
|
|
if (sr > 1.0) sr = (float)1.0;
|
|
if (sg > 1.0) sg = (float)1.0;
|
|
if (sb > 1.0) sb = (float)1.0;
|
|
|
|
for (i = 0; i < ssize; i++)
|
|
{
|
|
float s = (float)i / (ssize - 1);
|
|
float r = (1 - s) * mdr + s * sr;
|
|
float g = (1 - s) * mdg + s * sg;
|
|
float b = (1 - s) * mdb + s * sb;
|
|
cmap->set_color(cmap,
|
|
base + dsize + i,
|
|
(int)(255.0 * r),
|
|
(int)(255.0 * g),
|
|
(int)(255.0 * b));
|
|
}
|
|
}
|
|
}
|
|
|
|
void RampMaterial::SetColorsFog()
|
|
{
|
|
int base = ramp->base;
|
|
int size = ramp->size;
|
|
int dsize;
|
|
int ssize;
|
|
int i, specular;
|
|
float ambient = (float) VALTOD(this->ambient);
|
|
RLDDIColormap* cmap = driver->rampmap->cmap;
|
|
float fr, fg, fb;
|
|
|
|
fr = RGBA_GETRED(driver->fog_color) / 255.0f;
|
|
fg = RGBA_GETGREEN(driver->fog_color) / 255.0f;
|
|
fb = RGBA_GETBLUE(driver->fog_color) / 255.0f;
|
|
|
|
if ((size <= 2) || ((mat.specular.r == 0.0) &&
|
|
(mat.specular.g == 0.0) &&
|
|
(mat.specular.b == 0.0)))
|
|
specular = 0;
|
|
|
|
if (ramp->size == 1)
|
|
{
|
|
cmap->set_color(cmap, base, (int)(255.0 * mat.diffuse.r),
|
|
(int)(255.0 * mat.diffuse.g),
|
|
(int)(255.0 * mat.diffuse.b));
|
|
return;
|
|
}
|
|
|
|
if (specular != 0)
|
|
{
|
|
dsize = (3 * ramp->size) / 4;
|
|
ssize = ramp->size / 4;
|
|
}
|
|
else
|
|
{
|
|
dsize = ramp->size;
|
|
ssize = 0;
|
|
}
|
|
for (i = 0; i < dsize; i++)
|
|
{
|
|
float intensity = (1 - ambient) * ((float)i / (dsize - 1));
|
|
float r = (mat.emissive.r
|
|
+ ambient * mat.ambient.r
|
|
+ intensity * mat.diffuse.r);
|
|
float g = (mat.emissive.g
|
|
+ ambient * mat.ambient.g
|
|
+ intensity * mat.diffuse.g);
|
|
float b = (mat.emissive.b
|
|
+ ambient * mat.ambient.b
|
|
+ intensity * mat.diffuse.b);
|
|
r += (1.0f - intensity) * fr;
|
|
g += (1.0f - intensity) * fg;
|
|
b += (1.0f - intensity) * fb;
|
|
if (r > 1.0) r = (float)1.0;
|
|
if (g > 1.0) g = (float)1.0;
|
|
if (b > 1.0) b = (float)1.0;
|
|
cmap->set_color(cmap, base + i, (int)(255.0 * r),
|
|
(int)(255.0 * g),
|
|
(int)(255.0 * b));
|
|
}
|
|
if (ssize)
|
|
{
|
|
float mdr, mdg, mdb; /* Maximum diffuse values */
|
|
float sr, sg, sb;
|
|
|
|
mdr = (mat.emissive.r
|
|
+ ambient * mat.ambient.r
|
|
+ (1 - ambient) * mat.diffuse.r);
|
|
mdg = (mat.emissive.g
|
|
+ ambient * mat.ambient.g
|
|
+ (1 - ambient) * mat.diffuse.g);
|
|
mdb = (mat.emissive.b
|
|
+ ambient * mat.ambient.b
|
|
+ (1 - ambient) * mat.diffuse.b);
|
|
|
|
if (mdr > 1.0) mdr = (float)1.0;
|
|
if (mdg > 1.0) mdg = (float)1.0;
|
|
if (mdb > 1.0) mdb = (float)1.0;
|
|
|
|
sr = mdr + mat.specular.r;
|
|
sg = mdg + mat.specular.g;
|
|
sb = mdb + mat.specular.b;
|
|
|
|
if (sr > 1.0) sr = (float)1.0;
|
|
if (sg > 1.0) sg = (float)1.0;
|
|
if (sb > 1.0) sb = (float)1.0;
|
|
|
|
for (i = 0; i < ssize; i++)
|
|
{
|
|
float s = (float)i / (ssize - 1);
|
|
float r = (1 - s) * mdr + s * sr;
|
|
float g = (1 - s) * mdg + s * sg;
|
|
float b = (1 - s) * mdb + s * sb;
|
|
cmap->set_color(cmap,
|
|
base + dsize + i,
|
|
(int)(255.0 * r),
|
|
(int)(255.0 * g),
|
|
(int)(255.0 * b));
|
|
}
|
|
}
|
|
}
|
|
|
|
void RampMaterial::SetColors()
|
|
{
|
|
if (!LIST_ORPHAN_MEMBER(this, deferredlist))
|
|
{
|
|
LIST_DELETE(this, deferredlist);
|
|
}
|
|
|
|
D3D_INFO(7, "(Rast) Setting colors for RampMaterial(%08x)", this);
|
|
if (fog_enable)
|
|
SetColorsFog();
|
|
else
|
|
SetColorsStd();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampBeginSceneHook
|
|
//
|
|
// Called at clear time to advance material ages and process deferred color
|
|
// setting. Also deletes orphaned IntMaterials.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RLDDIRampBeginSceneHook(RLDDIRampLightingDriver* driver)
|
|
{
|
|
AgeList* oldest;
|
|
|
|
if (driver->already_aged)
|
|
return;
|
|
driver->already_aged = TRUE;
|
|
|
|
D3D_INFO(6, "(Rast) Aging materials in Clear");
|
|
|
|
/*
|
|
* remove the oldest list and make that the new age=0 list.
|
|
*/
|
|
oldest = CIRCLE_QUEUE_LAST(&driver->agequeue);
|
|
DDASSERT(LIST_FIRST(&oldest->agelist) == NULL);
|
|
CIRCLE_QUEUE_DELETE(&driver->agequeue, oldest, list);
|
|
CIRCLE_QUEUE_INSERT_ROOT(&driver->agequeue, AgeList, oldest, list);
|
|
driver->active = oldest;
|
|
D3D_INFO(7, "(Rast) New active list is %08x", driver->active);
|
|
|
|
/*
|
|
* Set the colors of any ramp materials which inherited color
|
|
* resources last frame.
|
|
*/
|
|
for (RampMaterial* rm = LIST_FIRST(&driver->rmdeferred);
|
|
rm; rm = LIST_FIRST(&driver->rmdeferred))
|
|
{
|
|
D3D_INFO(6, "(Rast) Processing deferred SetColor for RampMaterial(%08x)", rm);
|
|
rm->SetColors();
|
|
}
|
|
|
|
/*
|
|
* Any internal materials on the orphans list lost their parents last
|
|
* frame. If they are inactive, reclaim them here instead of waiting
|
|
* for them to die of old age.
|
|
*/
|
|
IntMaterial* intmat;
|
|
IntMaterial* intmat_next;
|
|
for (intmat = LIST_FIRST(&driver->orphans);
|
|
intmat;
|
|
intmat = intmat_next)
|
|
{
|
|
intmat_next = LIST_NEXT(intmat,list);
|
|
if (!intmat->IsActive())
|
|
{
|
|
D3D_INFO(9, "(Rast) Destroying inactive orphan IntMaterial(%08x)", intmat);
|
|
delete intmat;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampEndSceneHook
|
|
//
|
|
// Called at update time to reclaim unused color resources and reclaim
|
|
// memory for old IntMaterials.
|
|
//
|
|
// The age1 list will contain materials which were active last frame
|
|
// and have not been used since the last Clear.
|
|
// We remove their colour resources.
|
|
//
|
|
// The agemax list will contain inactive materials which have not
|
|
// been used for AGE_MAX-1 frames. These are obsolete and we reclaim
|
|
// their memory.
|
|
//
|
|
// NOT CALLING THIS CONSTITUTES A MEMORY LEAK.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RLDDIRampEndSceneHook(RLDDIRampLightingDriver* driver)
|
|
{
|
|
AgeList* age1 = CIRCLE_QUEUE_NEXT(&driver->agequeue,driver->active,list);
|
|
AgeList* agemax = CIRCLE_QUEUE_LAST(&driver->agequeue);
|
|
IntMaterial* intmat;
|
|
|
|
driver->already_aged = FALSE;
|
|
|
|
D3D_INFO(9, "(Rast) Processing materials in Update");
|
|
|
|
/*
|
|
* The age1 list will contain materials which were active last frame
|
|
* and have not been used since the last Clear.
|
|
* We remove their colour resources.
|
|
*/
|
|
D3D_INFO(7, "(Rast) Deactivating any materials on old active list %08x", age1);
|
|
for (intmat = LIST_FIRST(&age1->agelist);
|
|
intmat;
|
|
intmat = LIST_NEXT(intmat,agelist))
|
|
{
|
|
D3D_INFO(6, "(Rast) IntMaterial(%08x) not used this frame, deactivating", intmat);
|
|
intmat->Deactivate();
|
|
}
|
|
|
|
/*
|
|
* The agemax list will contain inactive materials which have not
|
|
* been used for AGE_MAX-1 frames. These are obsolete and we reclaim
|
|
* their memory.
|
|
*/
|
|
for (intmat = LIST_FIRST(&agemax->agelist);
|
|
intmat;
|
|
// this seems wierd, but I think it is O.K. since IntMaterial's destructor
|
|
// removes itself from the agelist
|
|
intmat = LIST_FIRST(&agemax->agelist))
|
|
{
|
|
D3D_INFO(6, "(Rast) IntMaterial(%08x) dying of old age", intmat);
|
|
delete intmat;
|
|
}
|
|
}
|
|
|
|
inline ExtMaterial* MaterialHandleLookup(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat)
|
|
{
|
|
DDASSERT(hMat);
|
|
return (ExtMaterial*)((((D3DFE_MATERIAL*)ULongToPtr(hMat))->pRmMat));
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampMaterialChanged
|
|
//
|
|
// Called when the contents of D3DMATERIAL we have already made a ExtMaterial
|
|
// for changes.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
long RLDDIRampMaterialChanged(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat)
|
|
{
|
|
D3DMATERIAL* lpMat = &((D3DFE_MATERIAL*)ULongToPtr(hMat))->mat;
|
|
ExtMaterial* extmat = MaterialHandleLookup(driver, hMat);
|
|
|
|
// Don't know if MaterialChanged is supposed to unconditionally set the current
|
|
// material or not. In any case, this code seems to make the uvis RM test app
|
|
// work
|
|
if (NULL == driver->current_material)
|
|
{
|
|
driver->current_material = extmat;
|
|
}
|
|
|
|
extmat->SetMaterial(lpMat);
|
|
return DD_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampSetMaterial
|
|
//
|
|
// Called when a D3DLIGHTSTATE_MATERIAL changes, which sets the
|
|
// driver->current_material.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
long RLDDIRampSetMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat)
|
|
|
|
{
|
|
if (hMat == NULL)
|
|
{ // NULL material is legal
|
|
driver->current_material = NULL;
|
|
return D3D_OK;
|
|
}
|
|
ExtMaterial* extmat = MaterialHandleLookup(driver, hMat);
|
|
driver->current_material = extmat;
|
|
|
|
// D3DMATERIALHANDLE hMat = (D3DMATERIALHANDLE)arg;
|
|
// ExtMaterial* extmat;
|
|
// RLDDIRampLightingDriver* driver = (RLDDIRampLightingDriver*)drv;
|
|
// RLDDISoftLightingDriver* sdriver = (RLDDISoftLightingDriver*)drv;
|
|
// LPRLDDIGENRASDRIVER rasDrv = (LPRLDDIGENRASDRIVER)drv->next;
|
|
//
|
|
// if (!extmat) {
|
|
// return DDERR_NOTFOUND;
|
|
// }
|
|
//
|
|
// if (extmat->GetMaterial()->power > 0) {
|
|
// SpecularTable* spec;
|
|
//
|
|
// for (spec = LIST_FIRST(&driver->specular_tables)
|
|
// ; // intentionally left blank
|
|
// spec;
|
|
// spec = LIST_NEXT(spec,list)) {
|
|
// if (spec->power == extmat->GetMaterial()->power)
|
|
// break;
|
|
// }
|
|
// if (spec == NULL) {
|
|
// spec = CreateSpecularTable(extmat->GetMaterial()->power);
|
|
// if (spec == NULL)
|
|
// return DDERR_OUTOFMEMORY;
|
|
// LIST_INSERT_ROOT(&driver->specular_tables, spec, list);
|
|
// }
|
|
// driver->specular_table = spec;
|
|
// } else {
|
|
// driver->specular_table = NULL;
|
|
// }
|
|
//
|
|
// sdriver->hMat = hMat;
|
|
//
|
|
// if (rasDrv->driver.lpD3DDevI->rstates[D3DRENDERSTATE_TEXTUREHANDLE] != extmat->GetMaterial()->hTexture)
|
|
// rasDrv->badRampTex = 1; /* Currently hTex are not matched */
|
|
// else
|
|
// rasDrv->badRampTex = 0;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampCreateMaterial
|
|
//
|
|
// Called to create a new ExtMaterial for a given D3DFE_MATERIAL.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
long RLDDIRampCreateMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat, PD3DI_RASTCTX pCtx)
|
|
{
|
|
D3DMATERIAL* lpMat = &((D3DFE_MATERIAL*)ULongToPtr(hMat))->mat;
|
|
ExtMaterial* extmat;
|
|
|
|
driver->fog_enable = pCtx->pdwRenderState[D3DRENDERSTATE_FOGENABLE];
|
|
driver->fog_color = pCtx->pdwRenderState[D3DRENDERSTATE_FOGCOLOR];
|
|
|
|
extmat = new ExtMaterial(driver, hMat);
|
|
if (extmat == NULL)
|
|
return (long) NULL;
|
|
|
|
LIST_INSERT_ROOT(&driver->materials, extmat, list);
|
|
|
|
extmat->SetMaterial(lpMat);
|
|
|
|
((D3DFE_MATERIAL*)ULongToPtr(hMat))->pRmMat = (LPVOID)extmat;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampDestroyMaterial
|
|
//
|
|
// Called to delete a ExtMaterial and all associated underlying memory and rampmap
|
|
// allocations for a given D3DFE_MATERIAL.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
long RLDDIRampDestroyMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat)
|
|
{
|
|
ExtMaterial* extmat = MaterialHandleLookup(driver, hMat);
|
|
|
|
// take this element off the list before deleting it, so driver->materials
|
|
// gets updated when it should
|
|
LIST_DELETE(extmat, list);
|
|
|
|
delete extmat;
|
|
return DD_OK;
|
|
}
|
|
|
|
static long LookupMaterial(RLDDIRampLightingDriver* driver,
|
|
RLDDILookupMaterialData* data)
|
|
{
|
|
ExtMaterial* extmat = (ExtMaterial*) ULongToPtr(data->hMat);
|
|
unsigned long* texture_colors;
|
|
BOOL specular;
|
|
HRESULT error;
|
|
|
|
if ((error = extmat->FindLightingRange(&data->base, &data->size, &specular,
|
|
&texture_colors)) != DD_OK)
|
|
return error;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampMaterialToPixel
|
|
//
|
|
// Call to convert a previously created material to a color for use in clearing
|
|
// the color buffer, for example.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
unsigned long RLDDIRampMaterialToPixel(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat)
|
|
{
|
|
ExtMaterial* extmat = MaterialHandleLookup(driver, hMat);
|
|
RLDDILookupMaterialData data;
|
|
|
|
data.hMat = (D3DMATERIALHANDLE)((ULONG_PTR)extmat);
|
|
|
|
LookupMaterial(driver, &data);
|
|
|
|
return driver->pixelmap[data.base];
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// RLDDIRampMakePaletteRGB8
|
|
//
|
|
// Call to set up the RGB8 palette and rampmap. This is a palette of 216 (== 6**3)
|
|
// entries of 6 gradations each for r, g, b. Using this palette requires
|
|
// multiplies by 6.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
long RLDDIRampMakePaletteRGB8(RLDDIRampLightingDriver* driver)
|
|
{
|
|
RLDDIColormap* cmap = driver->rampmap->cmap;
|
|
|
|
int r, g, b;
|
|
int i = 0;
|
|
|
|
for (r = 0; r < 6; r++)
|
|
{
|
|
for (g = 0; g < 6; g++)
|
|
{
|
|
for (b = 0; b < 6; b++)
|
|
{
|
|
cmap->set_color(cmap, i, (int)((255.0/5.0) * r),
|
|
(int)((255.0/5.0) * g),
|
|
(int)((255.0/5.0) * b));
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
return DD_OK;
|
|
}
|
|
|
|
long RLDDIRampPaletteChanged(RLDDIRampLightingDriver* driver, D3DTEXTUREHANDLE hTex)
|
|
{
|
|
PD3DI_SPANTEX tex;
|
|
|
|
#ifdef DEBUG
|
|
__try
|
|
{
|
|
#endif
|
|
tex = HANDLE_TO_SPANTEX(hTex);
|
|
tex->iGeneration++;
|
|
LPDDRAWI_DDRAWSURFACE_LCL pLcl = ((LPDDRAWI_DDRAWSURFACE_INT) tex->pSurf[0])->lpLcl;
|
|
// Palette might be changed
|
|
if (tex->Format == D3DI_SPTFMT_PALETTE8 ||
|
|
tex->Format == D3DI_SPTFMT_PALETTE4)
|
|
{
|
|
if (pLcl->lpDDPalette)
|
|
{
|
|
LPDDRAWI_DDRAWPALETTE_GBL pPal = pLcl->lpDDPalette->lpLcl->lpGbl;
|
|
tex->pPalette = (PUINT32)pPal->lpColorTable;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
D3D_ERR("Invalid texture handle");
|
|
}
|
|
#endif
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
//static long RampLightingService(RLDDIDriver* drv, RLDDIServiceType type,
|
|
// long arg1, void* arg2)
|
|
//{
|
|
// RLDDIRampLightingDriver* driver = (RLDDIRampLightingDriver*) drv;
|
|
// RLDDISoftLightingDriver* sdriver = (RLDDISoftLightingDriver*)driver;
|
|
// D3DLIGHTDATA* data;
|
|
// int mustService = FALSE;
|
|
// HRESULT err = DDERR_NOTFOUND;
|
|
//
|
|
// /*
|
|
// * Handle any services which we recognise.
|
|
// */
|
|
// switch (type) {
|
|
// case RLDDIPush:
|
|
// { RLDDIServiceProc *table = (RLDDIServiceProc *) arg2;
|
|
//
|
|
// drv->data->lighting = drv;
|
|
// if ((err = drv->service(drv, RLDDIFindRampmap, 0, &driver->rampmap)) != D3D_OK)
|
|
// return err;
|
|
// table[RLDDIPush] = RampLightingService;
|
|
// table[RLDDIPop] = RampLightingService;
|
|
// table[RLDDIApplyMaterialsUnlit] = serviceUnlight;
|
|
// table[RLDDIApplyMaterialsLit] = RampLightingService;
|
|
// table[RLDDIApplyMaterialShade] = ApplyMaterialShade;
|
|
// table[RLDDISetFogMode] = RampLightingService;
|
|
// table[RLDDISetFogStart] = RampLightingService;
|
|
// table[RLDDISetFogEnd] = RampLightingService;
|
|
// table[RLDDISetFogDensity] = RampLightingService;
|
|
// table[RLDDISetFogColor] = RampLightingService;
|
|
// table[RLDDISetLight] = RampLightingService;
|
|
// table[RLDDISetAmbientLight] = RampLightingService;
|
|
// table[RLDDILookupMaterial] = RampLightingService;
|
|
// table[RLDDISetViewport] = RampLightingService;
|
|
// table[RLDDISetMaterial] = SetMaterial;
|
|
// table[RLDDICreateMaterial] = RampLightingService;
|
|
// table[RLDDIDestroyMaterial] = RampLightingService;
|
|
// table[RLDDIFindMaterial] = RampLightingService;
|
|
// table[RLDDIMaterialChanged] = RampLightingService;
|
|
// table[RLDDISceneCapture] = RampLightingService;
|
|
// table[RLDDIClear] = RampLightingService;
|
|
// table[RLDDIClearZ] = RampLightingService;
|
|
// table[RLDDIClearBoth] = RampLightingService;
|
|
// }
|
|
// return DD_OK;
|
|
//
|
|
// case RLDDIPop:
|
|
// ReclaimMaterials(driver);
|
|
// drv->service(drv, RLDDIReleaseRampmap, 0, driver->rampmap);
|
|
// return DD_OK;
|
|
//
|
|
// case RLDDIApplyMaterialsUnlit:
|
|
// return serviceUnlight(drv, type, arg1, arg2);
|
|
//
|
|
// case RLDDIApplyMaterialsLit:
|
|
// data = (LPD3DLIGHTDATA) arg2;
|
|
// if (driver->current_material == NULL)
|
|
// return DD_OK;
|
|
// if (driver->current_material->GetMaterial()->dwRampSize == 1) {
|
|
// serviceUnlight(drv, type, arg1, arg2);
|
|
// return DD_OK;
|
|
// }
|
|
// if (sdriver->count == 1
|
|
// && (sdriver->lights->type == RLLightDirectional
|
|
// || sdriver->lights->type == RLLightParallelPoint)
|
|
// && sdriver->lights->shade > 0
|
|
// && sdriver->lights->shade <= ITOVALP(1, 8)
|
|
// && !driver->fog_enable && sdriver->lights->version==1)
|
|
// if (driver->specular_table)
|
|
// return Light1DirectionalS(driver, arg1, (LPD3DLIGHTDATA)arg2);
|
|
// else
|
|
// return Light1Directional(driver, arg1, (LPD3DLIGHTDATA)arg2);
|
|
// else
|
|
// if (driver->specular_table)
|
|
// return LightS(driver, arg1, (LPD3DLIGHTDATA)arg2);
|
|
// else
|
|
// return Light(driver, arg1, (LPD3DLIGHTDATA)arg2);
|
|
// break;
|
|
//
|
|
// case RLDDISetLight:
|
|
// {
|
|
// D3DI_LIGHT* newLights;
|
|
//
|
|
// if (arg1 > sdriver->count - 1) {
|
|
// if ((err = D3DMalloc((void**)&newLights,
|
|
// (arg1 + 1) * sizeof(D3DI_LIGHT))) != DD_OK) {
|
|
// return err;
|
|
// }
|
|
// memset(newLights, 0, (arg1 + 1) * sizeof(D3DI_LIGHT));
|
|
// memcpy(newLights, sdriver->lights, sdriver->count * sizeof(D3DI_LIGHT));
|
|
// if (sdriver->lights) {
|
|
// D3DFree(sdriver->lights);
|
|
// }
|
|
// sdriver->lights = newLights;
|
|
// sdriver->count = arg1 + 1;
|
|
// }
|
|
// }
|
|
// memcpy(&sdriver->lights[arg1], arg2, sizeof(D3DI_LIGHT));
|
|
//
|
|
// /*
|
|
// * The light vectors could be out of date.
|
|
// */
|
|
// ((RLDDITransformDriver*)drv->data->transform)->age_world = 1;
|
|
//
|
|
// return DD_OK;
|
|
//
|
|
// case RLDDISetFogMode:
|
|
// {
|
|
// D3DFOGMODE* fog = (D3DFOGMODE*) arg2;
|
|
// sdriver->fog_mode = *fog;
|
|
// driver->fog_enable = sdriver->fog_mode != D3DFOG_NONE;
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// case RLDDISetFogStart:
|
|
// {
|
|
// float* fog = (float*) arg2;
|
|
// sdriver->fog_start = *fog;
|
|
//
|
|
// break;
|
|
// }
|
|
// case RLDDISetFogEnd:
|
|
// {
|
|
// float* fog = (float*) arg2;
|
|
// sdriver->fog_end = *fog;
|
|
//
|
|
// break;
|
|
// }
|
|
// case RLDDISetFogDensity:
|
|
// {
|
|
// float* fog = (float*) arg2;
|
|
// sdriver->fog_density = *fog;
|
|
//
|
|
// break;
|
|
// }
|
|
//
|
|
// case RLDDISetFogColor:
|
|
// {
|
|
// driver->fog_color = arg1;
|
|
// break;
|
|
// }
|
|
//
|
|
// case RLDDIClear:
|
|
// case RLDDIClearZ:
|
|
// case RLDDIClearBoth:
|
|
// BeginSceneHook(driver);
|
|
// goto chain;
|
|
//
|
|
// case RLDDISceneCapture:
|
|
// if (arg1)
|
|
// BeginSceneHook(driver);
|
|
// else
|
|
// EndSceneHook(driver);
|
|
// goto chain;
|
|
//
|
|
// case RLDDISetAmbientLight:
|
|
// sdriver->ambient = INCPREC(FX8TOVAL((unsigned long) arg1 >> 24), 8);
|
|
// sdriver->ambient_save = arg1;
|
|
// break;
|
|
//
|
|
// case RLDDIApplyMaterialShade:
|
|
// return ApplyMaterialShade(drv, type, arg1, arg2);
|
|
//
|
|
// case RLDDILookupMaterial:
|
|
// return LookupMaterial(driver, (RLDDILookupMaterialData*) arg2);
|
|
//
|
|
// case RLDDISetMaterial:
|
|
// return SetMaterial(drv, type, arg1, arg2);
|
|
//
|
|
// case RLDDICreateMaterial:
|
|
// return CreateMaterial(driver, (LPD3DMATERIALHANDLE)arg1, (LPD3DMATERIAL)arg2);
|
|
//
|
|
// case RLDDIDestroyMaterial:
|
|
// return DestroyMaterial(driver, (D3DMATERIALHANDLE)arg1);
|
|
//
|
|
// case RLDDIFindMaterial:
|
|
// {
|
|
// LPD3DMATERIAL* lplpMat = (LPD3DMATERIAL*)arg2;
|
|
// ExtMaterial* extmat = (ExtMaterial*)arg1;
|
|
//
|
|
// *lplpMat = extmat->GetMaterial();
|
|
// }
|
|
// return DD_OK;
|
|
//
|
|
// case RLDDIMaterialChanged:
|
|
// {
|
|
// ExtMaterial* extmat = (ExtMaterial*)arg1;
|
|
//
|
|
// extmat->SetMaterial((LPD3DMATERIAL) arg2);
|
|
//
|
|
// return DD_OK;
|
|
// }
|
|
//
|
|
// case RLDDISetViewport:
|
|
// driver->viewport_id = arg1;
|
|
// /*
|
|
// * Chain to the next driver.
|
|
// */
|
|
// if (drv->next)
|
|
// return drv->next->service(drv->next, type, arg1, arg2);
|
|
// return DD_OK;
|
|
//
|
|
// default: chain:
|
|
// mustService = TRUE;
|
|
// }
|
|
//
|
|
// if (drv->next)
|
|
// err = (HRESULT) drv->next->service(drv->next, type, arg1, arg2);
|
|
//
|
|
// return (mustService || err != DDERR_NOTFOUND)? err : DD_OK;
|
|
//}
|
|
//
|
|
//unsigned long* RLDDIRampFindTexturePixels(RLDDIDriver* drv, D3DMATERIALHANDLE hMat)
|
|
//{
|
|
// RLDDIRampLightingDriver* driver = (RLDDIRampLightingDriver*) drv;
|
|
// ExtMaterial* extmat = (ExtMaterial*) hMat;
|
|
// PD3DI_SPANTEX tex = HANDLE_TO_SPANTEX(extmat->GetMaterial()->hTexture);
|
|
// unsigned long base, size;
|
|
// unsigned long* texture_colors;
|
|
// HRESULT error;
|
|
//
|
|
// if (!tex) {
|
|
// return NULL;
|
|
// }
|
|
// driver = (RLDDIRampLightingDriver*) tex->owner;
|
|
//
|
|
// if (extmat == NULL)
|
|
// return NULL;
|
|
// if ((error = extmat->FindLightingRange(&base, &size, &texture_colors)) != DD_OK)
|
|
// return NULL;
|
|
//
|
|
// return texture_colors;
|
|
//}
|
|
//
|
|
//void*GetMaterialTextureHandle(RLDDIDriver* drv)
|
|
//{
|
|
// RLDDIRampLightingDriver* driver = (RLDDIRampLightingDriver*) drv;
|
|
// ExtMaterial* extmat = driver->current_material;
|
|
// PD3DI_SPANTEX tex = NULL;
|
|
// if(extmat){
|
|
// LPD3DMATERIAL mat = extmat->GetMaterial();
|
|
// if (mat && mat->hTexture)
|
|
// tex = HANDLE_TO_SPANTEX(mat->hTexture);
|
|
// }
|
|
//
|
|
// return tex;
|
|
//}
|
|
|
|
define(`d_Ramp_ScaleImage', `
|
|
dnl
|
|
define(`d_BPP', eval($1/8))dnl
|
|
define(`d_Type', ifelse($1, 8, `UINT8', $1, 16, `UINT16', $1, 24, `UINT8', $1, 32, `UINT32'))dnl
|
|
dnl
|
|
void Ramp_Mono_ScaleImage_$1(PD3DI_RASTCTX pCtx, D3DMATERIALHANDLE hMat, LPD3DRECT pRect)
|
|
{
|
|
RLDDIRampLightingDriver *pLtDriver =
|
|
(RLDDIRampLightingDriver*)pCtx->pRampDrv;
|
|
|
|
RLDDIRampSetMaterial(pLtDriver, hMat);
|
|
PD3DI_SPANTEX pTex;
|
|
pTex = HANDLE_TO_SPANTEX(((D3DFE_MATERIAL*)ULongToPtr(hMat))->mat.hTexture);
|
|
|
|
if (pLtDriver && pLtDriver->current_material)
|
|
{
|
|
DWORD dwBase;
|
|
DWORD dwSize;
|
|
unsigned long* pixels;
|
|
unsigned long* map = (unsigned long*)pCtx->pRampMap;
|
|
BOOL bSpecular;
|
|
|
|
// Update the ramp info. in RastCtx
|
|
pLtDriver->current_material->FindLightingRange(
|
|
&dwBase,
|
|
&dwSize,
|
|
&bSpecular,
|
|
(unsigned long**)&pixels);
|
|
|
|
|
|
// Make sure DD Palette is updated after it gets set by FindLightingRange
|
|
RLDDIRampUpdateDDPalette(pCtx);
|
|
|
|
LPDDRAWI_DDRAWSURFACE_LCL pLcl =
|
|
((LPDDRAWI_DDRAWSURFACE_INT)(pTex->pSurf[0]))->lpLcl;
|
|
int iTexWidth = pLcl->lpGbl->wWidth;
|
|
int iTexHeight = pLcl->lpGbl->wHeight;
|
|
int src_width = pLcl->lpGbl->lPitch;
|
|
pLcl = ((LPDDRAWI_DDRAWSURFACE_INT)(pCtx->pDDS))->lpLcl;
|
|
int iSurfWidth = pLcl->lpGbl->wWidth;
|
|
int iSurfHeight = pLcl->lpGbl->wHeight;
|
|
|
|
int x1 = pRect->x1;
|
|
int y1 = pRect->y1;
|
|
int x2 = pRect->x2;
|
|
int y2 = pRect->y2;
|
|
int width = x2 - x1;
|
|
int height = y2 - y1;
|
|
FLOAT scalex = (FLOAT)iSurfWidth/(FLOAT)iTexWidth;
|
|
FLOAT scaley = (FLOAT)iSurfHeight/(FLOAT)iTexHeight;
|
|
int dstx = x1;
|
|
int dsty = y1;
|
|
|
|
unsigned char* src = pTex->pBits[0];
|
|
int src_skip;
|
|
unsigned char* dst = pCtx->pSurfaceBits + dstx * d_BPP + dsty * pCtx->iSurfaceStride;
|
|
int dst_skip = pCtx->iSurfaceStride - width * d_BPP;
|
|
int i;
|
|
|
|
if ((scalex == 1.0F) && (scaley == 1.0F)) {
|
|
src = src + src_width * y1 + x1;
|
|
src_skip = src_width - width;
|
|
|
|
do {
|
|
i = width;
|
|
do {
|
|
ifelse($1, 24, `
|
|
*(d_Type*)(dst+0) = ((d_Type*)(&map[pixels[*src]]))[0];
|
|
*(d_Type*)(dst+1) = ((d_Type*)(&map[pixels[*src]]))[1];
|
|
*(d_Type*)(dst+2) = ((d_Type*)(&map[pixels[*src++]]))[2];',`
|
|
*(d_Type*)dst = (d_Type)map[pixels[*src++]];')
|
|
dst += d_BPP;
|
|
} while (--i);
|
|
src += src_skip;
|
|
dst += dst_skip;
|
|
} while (--height);
|
|
} else {
|
|
FLOAT mu, mv;
|
|
FLOAT u, v, u_start;
|
|
|
|
/*
|
|
* Turn the scale values into deltas which we can use to
|
|
* interpolate in the texture.
|
|
*/
|
|
mu = 1.0f/scalex;
|
|
mv = 1.0f/scaley;
|
|
|
|
/*
|
|
* Work out the real source address in the unscaled texture.
|
|
* ~.5 offset makes the result stable for even scales which are common.
|
|
*/
|
|
u = ((FLOAT)x1+0.4999f) * mu;
|
|
v = ((FLOAT)y1+0.4999f) * mv;
|
|
|
|
u_start = u;
|
|
do {
|
|
unsigned char* src_line = src + src_width * int(v);
|
|
|
|
u = u_start;
|
|
i = width;
|
|
do {
|
|
ifelse($1, 24, `
|
|
*(d_Type*)(dst+0) = ((d_Type*)(&map[pixels[src_line[int(u)]]]))[0];
|
|
*(d_Type*)(dst+1) = ((d_Type*)(&map[pixels[src_line[int(u)]]]))[1];
|
|
*(d_Type*)(dst+2) = ((d_Type*)(&map[pixels[src_line[int(u)]]]))[2];',`
|
|
*(d_Type*)dst = (d_Type)map[pixels[src_line[int(u)]]];')
|
|
dst += d_BPP;
|
|
u += mu;
|
|
} while (--i);
|
|
v += mv;
|
|
dst += dst_skip;
|
|
} while (--height);
|
|
}
|
|
}
|
|
}
|
|
')dnl
|
|
|
|
d_Ramp_ScaleImage(8)
|
|
d_Ramp_ScaleImage(16)
|
|
d_Ramp_ScaleImage(24)
|
|
d_Ramp_ScaleImage(32)
|
|
|
|
|