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.
567 lines
16 KiB
567 lines
16 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// rampmat.hpp
|
|
//
|
|
// Declares classes for ramp material handling.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#ifndef _RAMPMAT_HPP_
|
|
#define _RAMPMAT_HPP_
|
|
|
|
/* -*- c++ -*- */
|
|
|
|
#include "rampmap.h"
|
|
#include "palette.h"
|
|
#include "rgbmap.h"
|
|
|
|
struct ExtMaterial;
|
|
struct IntMaterial;
|
|
struct RampMaterial;
|
|
struct RLDDIRampLightingDriver;
|
|
|
|
struct AgeList {
|
|
CIRCLE_QUEUE_MEMBER(AgeList) list;
|
|
LIST_ROOT(alh,IntMaterial) agelist;
|
|
};
|
|
|
|
class RampCommon {
|
|
public:
|
|
|
|
void* operator new(size_t size)
|
|
{
|
|
void* p;
|
|
if (D3DMalloc(&p, size))
|
|
return NULL;
|
|
return p;
|
|
}
|
|
|
|
void operator delete(void *p)
|
|
{
|
|
D3DFree(p);
|
|
}
|
|
};
|
|
|
|
/*
|
|
* An ExtMaterial is the underlying driver object for an LPDIRECT3DMATERIAL.
|
|
* When used, it creates IntMaterials which are distinguished by different
|
|
* ambient light, fog, D3DMATERIAL value etc.
|
|
*
|
|
* The ExtMaterials are kept on a list in the driver and if not explicitly
|
|
* freed, they are cleaned up when the driver is destroyed.
|
|
*
|
|
* The IntMaterials can outlive the ExtMaterial in the case that the
|
|
* ExtMaterial is destroyed right after use. We add these orphans to a list
|
|
* which is emptied at Clear time since after Clear, no pixels are visible
|
|
* which were rendered with the IntMaterial and it can be freed.
|
|
*/
|
|
struct ExtMaterial : public RampCommon {
|
|
friend struct IntMaterial;
|
|
private:
|
|
/*
|
|
* Driver object which owns us.
|
|
*/
|
|
RLDDIRampLightingDriver* driver;
|
|
|
|
/*
|
|
* Current API level material definition.
|
|
*/
|
|
D3DMATERIAL mat;
|
|
|
|
/*
|
|
* List of internal materials derived from us.
|
|
*/
|
|
LIST_ROOT(eml,IntMaterial) intlist;
|
|
|
|
/*
|
|
* Generation count. The generation is incremented each time
|
|
* the material is changed. This allows us to generate a new internal
|
|
* material as needed.
|
|
*/
|
|
int generation;
|
|
|
|
/*
|
|
* This tracks the generation of any texture used by the material. The
|
|
* texture generation is bumped if its palette is changed or it is
|
|
* loaded from another texture.
|
|
*/
|
|
int texture_generation;
|
|
|
|
/*
|
|
* This tracks the underlying texture object represented by the texture
|
|
* handle (if any). If texture handles are swapped, we need to know
|
|
* so that we can make a new internal material for the new texture.
|
|
*/
|
|
PD3DI_SPANTEX texture;
|
|
|
|
/*
|
|
* Increment the generation either because the material was set or
|
|
* because a texture changed.
|
|
*/
|
|
void Age();
|
|
|
|
public:
|
|
/*
|
|
* Chain for list of external materials created by this driver.
|
|
*/
|
|
LIST_MEMBER(ExtMaterial) list;
|
|
|
|
public:
|
|
/*
|
|
* Constructor/Destructor.
|
|
*/
|
|
ExtMaterial(RLDDIRampLightingDriver* driver, D3DMATERIALHANDLE hMat);
|
|
~ExtMaterial();
|
|
|
|
/*
|
|
* Change the API level material.
|
|
*/
|
|
void SetMaterial(D3DMATERIAL* mat);
|
|
|
|
/*
|
|
* Accessor to the current API level material.
|
|
*/
|
|
D3DMATERIAL* GetMaterial() {
|
|
return &mat;
|
|
}
|
|
|
|
/*
|
|
* Find an internal material which corresponds to the current driver
|
|
* object state.
|
|
*/
|
|
IntMaterial* FindIntMaterial();
|
|
|
|
/*
|
|
* 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 FindLightingRange(unsigned long* base,
|
|
unsigned long* size,
|
|
BOOL* specular,
|
|
unsigned long** texture_colors);
|
|
};
|
|
|
|
/*
|
|
* The IntMaterial is derived from an ExtMaterial taking into account the
|
|
* driver state when the ExtMaterial was used. Normally IntMaterials are
|
|
* on a list in their owning ExtMaterial. If the external material is
|
|
* destroyed, any active internal materials which it owned are
|
|
* transferred to an orphans list in the driver. This is cleared out
|
|
* next time Clear is called.
|
|
*
|
|
* The internal material has a list of underlying RampMaterials. For
|
|
* a non-textured material, there is exactly one and for a textured
|
|
* material, there is one per color in the texture's palette. The
|
|
* ramp materials track color sharing between internal materials and
|
|
* handle the details of allocating color resources.
|
|
*
|
|
* Internal materials are also chained onto one of a number of lists
|
|
* based on their age. The age of a material is the number of frames
|
|
* since it was last used to render something. When a material is
|
|
* aged, it is rejuvenated by moving it to the age=0 list. Each
|
|
* frame, the lists are rotated by one notch and materials on the
|
|
* oldest list are reclaimed.
|
|
*
|
|
* A material is either active or inactive. Active materials have
|
|
* color resources and are either on the age=0 list (active this
|
|
* frame) or the age=1 list (active last frame). When an inactive
|
|
* material is used, it allocates color resources by attempting to
|
|
* activate the underlying ramp materials.
|
|
*
|
|
* At the end of the frame, on Update, any active materials on the
|
|
* age=1 list must be materials which were active last frame but were
|
|
* not used this frame. We remove their color resources by
|
|
* deactivating the underlying ramp materials.
|
|
*/
|
|
struct IntMaterial : public RampCommon {
|
|
private:
|
|
/*
|
|
* Driver object which owns us.
|
|
*/
|
|
RLDDIRampLightingDriver* driver;
|
|
|
|
/*
|
|
* External material which created us.
|
|
*/
|
|
ExtMaterial* extmat;
|
|
|
|
public:
|
|
/*
|
|
* Too annoying to have these private.
|
|
*/
|
|
|
|
/*
|
|
* Chain of internal materials created by our external material owner
|
|
* which owns us. The chain is also used to place the material on the
|
|
* driver's orphans list if appropriate.
|
|
*/
|
|
LIST_MEMBER(IntMaterial) list;
|
|
|
|
/*
|
|
* Current ageing list which we are on.
|
|
*/
|
|
AgeList* age;
|
|
LIST_MEMBER(IntMaterial) agelist;
|
|
private:
|
|
|
|
/*
|
|
* D3DMATERIAL which the external material had when it created us.
|
|
*/
|
|
D3DMATERIAL mat;
|
|
|
|
/*
|
|
* TRUE if we are active. We are active if we currently have color
|
|
* allocation resources assigned to us.
|
|
*/
|
|
int active;
|
|
|
|
/*
|
|
* Base values of our color allocation resources. Contents are valid
|
|
* only when active.
|
|
*/
|
|
unsigned long* colors;
|
|
|
|
/*
|
|
* Features which distinguish us from other internal materials owned by
|
|
* our external material.
|
|
*/
|
|
float ambient; // ambient shade
|
|
unsigned long viewport_id; // viewport which owns it
|
|
int fog_enable; // material incorporates fog
|
|
unsigned long fog_color; // the fogging color
|
|
int generation;
|
|
|
|
/*
|
|
* RampMaterials used by this internal material.
|
|
*/
|
|
int ramp_count;
|
|
RampMaterial** ramps;
|
|
|
|
public:
|
|
|
|
/*
|
|
* Constructor/Destructor.
|
|
*/
|
|
IntMaterial(ExtMaterial* extmat);
|
|
~IntMaterial();
|
|
|
|
/*
|
|
* Returns TRUE if we match the current settings of our external material
|
|
* and driver state.
|
|
*/
|
|
int Valid();
|
|
|
|
/*
|
|
* See ExtMaterial
|
|
*/
|
|
HRESULT FindLightingRange(unsigned long* base,
|
|
unsigned long* size,
|
|
BOOL* specular,
|
|
unsigned long** texture_colors);
|
|
|
|
/*
|
|
* Activate the material and allocate color resources for it.
|
|
*/
|
|
HRESULT Activate();
|
|
|
|
/*
|
|
* Deactivate the material, freeing color resources. Always works.
|
|
*/
|
|
void Deactivate();
|
|
|
|
/*
|
|
* Returns TRUE if the material is currently active.
|
|
*/
|
|
int IsActive() {
|
|
return active;
|
|
}
|
|
|
|
/*
|
|
* Add the material to the driver's orphaned material list. Called when
|
|
* the external material is destroyed.
|
|
*/
|
|
void Orphan();
|
|
};
|
|
|
|
/*
|
|
* RampMaterials are used by internal materials to represent ranges of
|
|
* colors. They perform low level color allocation by allocating
|
|
* color ranges (RLDDIRamps) from a rampmap.
|
|
*
|
|
* A textured internal material can use many ramp materials.
|
|
* Several internal materials can use the same ramp material if the
|
|
* colors match. This can happen easily if many textures use the same
|
|
* palette. The ramp material maintains a usage of how many internal
|
|
* materials are using it and is freed when the last one stops.
|
|
*
|
|
* Ramp materials, like internal materials are either active or
|
|
* inactive. Active materials have color resources and inactive
|
|
* materials do not. A ramp material is made active when any of its
|
|
* internal material users are active and inactive when none of then
|
|
* are active. To track this a count of how many active users is
|
|
* maintained.
|
|
*
|
|
* When a material is made active, it attempts to allocate a color
|
|
* range to use. If that is successful, it sets the colors in the
|
|
* range to an appropriate ramp of colors. If is no more space in the
|
|
* colormap for a new range, it finds the closes active ramp material
|
|
* and shares its ramp.
|
|
*
|
|
* To track active materials and sharing materials, the driver has a
|
|
* list of active materials and each material has a list of sharers.
|
|
* The sharers list is only valid for materials which are both active
|
|
* and which own their ramp.
|
|
*/
|
|
struct RampMaterial : public RampCommon {
|
|
private:
|
|
/*
|
|
* Driver object which owns us.
|
|
*/
|
|
RLDDIRampLightingDriver* driver;
|
|
|
|
/*
|
|
* List of materials which have the same hash value.
|
|
*/
|
|
LIST_MEMBER(RampMaterial) hash;
|
|
|
|
/*
|
|
* Materials sharing this ramp. Only valid for active materials
|
|
* with owner == TRUE.
|
|
*/
|
|
LIST_ROOT(name6,RampMaterial) sharers;
|
|
|
|
/*
|
|
* If the material is active, then it is on the drivers rmactive list
|
|
* if it owns the ramp, otherwise it is on the sharers list of the
|
|
* material which does own the ramp. Only valid for active materials.
|
|
*/
|
|
LIST_MEMBER(RampMaterial) list;
|
|
|
|
/*
|
|
* If were sharing a ramp and inherit it from the owner, we need to
|
|
* defer setting the colors until the next frame to avoid possible
|
|
* palette flashing. The driver has a list of materials for which
|
|
* color setting is deferred, chainged through here.
|
|
*
|
|
* We make sure that deferredlist.le_next is NULL unless we are
|
|
* actually on the deferred list so that we can avoid list problems
|
|
* if we are destroyed or passed on to another inheritor before the
|
|
* list is processed.
|
|
*/
|
|
LIST_MEMBER(RampMaterial) deferredlist;
|
|
|
|
/*
|
|
* A count of the number of internal materials which use us.
|
|
*/
|
|
int usage;
|
|
|
|
/*
|
|
* A count of active internal materials which use us.
|
|
*/
|
|
int active;
|
|
|
|
/*
|
|
* If we are active (active > 0), this is the underlying color
|
|
* range for the material.
|
|
*/
|
|
RLDDIRamp* ramp;
|
|
|
|
/*
|
|
* TRUE if we created or inherited the ramp. FALSE if I am merely
|
|
* sharing some other material.
|
|
*/
|
|
int owner;
|
|
|
|
/*
|
|
* Distinguishing features.
|
|
*/
|
|
float ambient; /* ambient shade */
|
|
D3DMATERIAL mat; /* material we represent */
|
|
int fog_enable; /* material incorporates fog */
|
|
unsigned long fog_color; /* the fogging color */
|
|
|
|
private:
|
|
|
|
/*
|
|
* Constructor/Destructor.
|
|
* These are private. Callers should use Find/Release.
|
|
*/
|
|
RampMaterial(RLDDIRampLightingDriver* driver,
|
|
D3DMATERIAL* mat, float ambient);
|
|
~RampMaterial();
|
|
|
|
public:
|
|
/*
|
|
* Find a material which matches the api material and driver state.
|
|
* If no such material exists, make one.
|
|
*/
|
|
static RampMaterial* Find(RLDDIRampLightingDriver* driver,
|
|
D3DMATERIAL* mat);
|
|
|
|
private:
|
|
/*
|
|
* Next functions are implementation detail of Find.
|
|
*/
|
|
|
|
/*
|
|
* Compare two api materials to see if they are identical.
|
|
*/
|
|
static int MaterialSame(D3DMATERIAL* mat1, D3DMATERIAL* mat2);
|
|
|
|
/*
|
|
* Return a measure of how close two rgb colors are in rgb space.
|
|
*/
|
|
static int RGBDist(D3DCOLORVALUE* rgb1, D3DCOLORVALUE* rgb2);
|
|
|
|
/*
|
|
* Return a measure of how close two api materials are.
|
|
*/
|
|
static int CompareMaterials(D3DMATERIAL* mat1, D3DMATERIAL* mat2);
|
|
|
|
public:
|
|
/*
|
|
* Called by a user when it is no longer needed.
|
|
*/
|
|
void Release();
|
|
|
|
/*
|
|
* Called by a user when the material is about to be used.
|
|
*/
|
|
HRESULT Activate();
|
|
|
|
/*
|
|
* Called by a user when the material has not been used this frame.
|
|
*/
|
|
void Deactivate();
|
|
|
|
/*
|
|
* Return the base color of an active material.
|
|
*/
|
|
unsigned long Base();
|
|
|
|
private:
|
|
/*
|
|
* Implementation details of Activate and Deactivate.
|
|
*/
|
|
|
|
/*
|
|
* Allocate a ramp of colors for us to use.
|
|
* May only be called for an inactive material.
|
|
*/
|
|
HRESULT AllocateColors();
|
|
|
|
/*
|
|
* Free our color allocation. May only be called for an active material.
|
|
*/
|
|
void FreeColors();
|
|
|
|
/*
|
|
* Set the color values of our color allocation.
|
|
*/
|
|
private:
|
|
void SetColorsStd();
|
|
void SetColorsFog();
|
|
public:
|
|
void SetColors();
|
|
};
|
|
|
|
///*
|
|
// * Workspace used when evaluating complex lighting models.
|
|
// */
|
|
//struct Workspace {
|
|
// float diffuse;
|
|
// float specular;
|
|
//};
|
|
//
|
|
//struct SpecularTable {
|
|
// LIST_MEMBER(SpecularTable) list;
|
|
// float power; /* shininess power */
|
|
// float table[260]; /* space for overflows */
|
|
//};
|
|
//
|
|
//#define WORKSPACE_SIZE 1024
|
|
|
|
#define HASH_SIZE 257
|
|
/*
|
|
* If the app is rendering at 30fps, this means that a material can survive
|
|
* for about 5 seconds. This seems like enough to cope with stuff moving
|
|
* out of shot and back in again soon after.
|
|
*/
|
|
#define AGE_MAX (30*5) /* age at which unused materials die */
|
|
|
|
typedef struct _RLDDISoftLightingDriver {
|
|
D3DMATERIAL material;
|
|
float ambient;
|
|
D3DFOGMODE fog_mode;
|
|
float fog_start;
|
|
float fog_end;
|
|
float fog_density;
|
|
D3DMATERIALHANDLE hMat;
|
|
D3DCOLORMODEL color_model;
|
|
DWORD ambient_save;
|
|
} RLDDISoftLightingDriver;
|
|
|
|
struct RLDDIRampLightingDriver {
|
|
RLDDISoftLightingDriver driver; /* common fields */
|
|
|
|
/*
|
|
* Colormap
|
|
*/
|
|
RLDDIPalette* palette;
|
|
RLDDIRGBMap* rgbmap;
|
|
unsigned long* pixelmap; /* map color indices to pixels */
|
|
PALETTEENTRY ddpalette[256];
|
|
int paletteChanged;
|
|
|
|
RLDDIRampmap* rampmap;
|
|
unsigned long viewport_id; /* current viewport */
|
|
int fog_enable;
|
|
unsigned long fog_color;
|
|
|
|
/*
|
|
* External materials created by this driver.
|
|
*/
|
|
LIST_ROOT(deml,ExtMaterial) materials;
|
|
|
|
/*
|
|
* Active internal materials orphaned by their owning external material.
|
|
*/
|
|
LIST_ROOT(diml,IntMaterial) orphans;
|
|
|
|
AgeList agelists[AGE_MAX];
|
|
CIRCLE_QUEUE_ROOT(aqh,AgeList) agequeue; /* age sorted queue of lists */
|
|
AgeList* active; /* current active list */
|
|
|
|
/*
|
|
* This is set to TRUE after Clear has advanced the ages one notch and
|
|
* cleared on update. It is used to stop multiple calls to Clear from
|
|
* confusing the aging system
|
|
*/
|
|
int already_aged;
|
|
|
|
LIST_ROOT(name7,RampMaterial) rmactive; /* materials with ramps */
|
|
LIST_ROOT(name8,RampMaterial) rmdeferred;
|
|
LIST_ROOT(name9,RampMaterial) hash[HASH_SIZE]; /* materials hash table */
|
|
|
|
/*
|
|
* Current material.
|
|
*/
|
|
ExtMaterial* current_material;
|
|
};
|
|
|
|
typedef struct _RLDDILookupMaterialData {
|
|
D3DMATERIALHANDLE hMat; /* material to look up */
|
|
unsigned long base; /* base pixel value */
|
|
unsigned long size; /* size of index range */
|
|
unsigned long texture_index; /* texture table for textures */
|
|
} RLDDILookupMaterialData;
|
|
|
|
|
|
#endif // _RAMPMAT_HPP_
|