|
|
//----------------------------------------------------------------------------
//
// 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_
|