Texture test
Texture_test is a basic example plugin. This wiki page is intended as a walkthrough of the code in order to help you better understand the SDK.
This plugin is a test of plugin value textures, essentially a type of procedural.
Contents
Code Walkthrough
Class declaration
class CTestTexture : public CLxImpl_ValueTexture, public CLxImpl_ChannelUI { public: static LXtTagInfoDesc descInfo[]; CTestTexture (); LxResult vtx_SetupChannels (ILxUnknownID addChan); LxResult vtx_LinkChannels (ILxUnknownID eval, ILxUnknownID item); LxResult vtx_ReadChannels (ILxUnknownID attr, void **ppvData); void vtx_Evaluate (ILxUnknownID vector, LXpTextureOutput *tOut, void *data); void vtx_Cleanup (void *data); LxResult cui_Enabled (const char *channelName, ILxUnknownID msg, ILxUnknownID item, ILxUnknownID read); LxResult cui_DependencyCount (const char *channelName, unsigned *count); LxResult cui_DependencyByIndex (const char *channelName, unsigned index, LXtItemType *depItemType, const char **depChannelName); LXtItemType MyType (); CLxUser_PacketService pkt_service; unsigned idx_sat, idx_lo, idx_hi; unsigned tin_offset; LXtItemType my_type; class RendData { public: float f_sat, f_base, f_mult; }; };
This has the basic ValueTexture interface to support simple multi-effect evaluations, plus the ChannelUI interface for enable states. The local RendData struct is used for storing values used for a specific texture evaluation.
Server Tags
LXtTagInfoDesc CTestTexture::descInfo[] = { { LXsSRV_USERNAME, "Test Value Texture" }, { LXsSRV_LOGSUBSYSTEM, "val-texture" }, { 0 } };
The tags here indicate that server has the name Test Value Texture with the internal name of val-texture.
Initialize
void Initialize() { CLxGenericPolymorph *srv; srv = new CLxPolymorph<CTestTexture>; srv->AddInterface (new CLxIfc_ValueTexture<CTestTexture>); srv->AddInterface (new CLxIfc_ChannelUI <CTestTexture>); srv->AddInterface (new CLxIfc_StaticDesc <CTestTexture>); lx::AddServer (SRVs_TEXTURE, srv); }
This function exports a server of the TEXTURE type dependent on the CTestTexture class with the ValueTexture, ChannelUI, and StaticDesc interfaces.
Helper Functions
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) < (b) ? (b) : (a)) #define PI 3.14159265 #define TWOPI (2 * PI) #define _R rgb[0] #define _G rgb[1] #define _B rgb[2] #define _H hsv[0] #define _S hsv[1] #define _V hsv[2] static void RGB2HSV ( const LXtFVector rgb, LXtFVector hsv) { double min, max, delta; min = MIN (MIN (_R, _G), _B); max = MAX (MAX (_R, _G), _B); delta = max - min; _V = max; if (max) _S = delta / max; else { _S = 0.0; _H = 0.0; // black: hue undefined return; } if (delta) { if (_R == max) _H = (_G - _B) / delta; // between yellow & magenta else if (_G == max) _H = (_B - _R) / delta + 2.0; // between cyan & yellow else _H = (_R - _G) / delta + 4.0; // between magenta & cyan } else _H = 0; _H *= (float) (PI / 3.0); if (_H < 0) _H += (float) TWOPI; } static void HSV2RGB ( const LXtFVector hsv, LXtFVector rgb) { double f, p, q, t; int i; if (_S < DBL_EPSILON) { _R = _G = _B = _V; // grey return; } f = _H * 3.0 / PI; while (f < 0.0) f += 6.0; while (f >= 6.0) f -= 6.0; i = floor (f); // sector 0 to 5 f = f - i; // factorial part of Hue p = _V * (1.0 - _S); q = _V * (1.0 - _S * f); t = _V * (1.0 - _S * (1.0 - f)); switch (i) { case 0: _R = _V; _G = t; _B = p; break; case 1: _R = q; _G = _V; _B = p; break; case 2: _R = p; _G = _V; _B = t; break; case 3: _R = p; _G = q; _B = _V; break; case 4: _R = t; _G = p; _B = _V; break; default: _R = _V; _G = p; _B = q; break; } }
Utilities for RGB/HSV conversion.
Implementations
LxResult CTestTexture::vtx_SetupChannels ( ILxUnknownID addChan) { CLxUser_AddChannel ac (addChan); ac.NewChannel (CHANs_SATURATION, "percent"); ac.SetDefault (1.0, 1); ac.NewChannel (CHANs_LOW, "percent"); ac.SetDefault (0.0, 0); ac.NewChannel (CHANs_HIGH, "percent"); ac.SetDefault (1.0, 1); return LXe_OK; }
This function creates the channels for the item type using the methods of an AddChannel object.
LxResult CTestTexture::vtx_LinkChannels ( ILxUnknownID eval, ILxUnknownID item) { CLxUser_Evaluation ev (eval); idx_sat = ev.AddChan (item, CHANs_SATURATION); idx_lo = ev.AddChan (item, CHANs_LOW); idx_hi = ev.AddChan (item, CHANs_HIGH); tin_offset = pkt_service.GetOffset (LXsCATEGORY_SAMPLE, LXsP_TEXTURE_INPUT); return LXe_OK; }
This function attaches the channels to channel evaluation. This gets indices for the channels in attributes through the AddChan method of a User Evaluation object.
LxResult CTestTexture::vtx_ReadChannels ( ILxUnknownID attr, void **ppvData) { CLxUser_Attributes at (attr); RendData *rd = new RendData; rd->f_sat = at.Float (idx_sat); rd->f_base = at.Float (idx_lo); rd->f_mult = at.Float (idx_hi) - rd->f_base; ppvData[0] = rd; return LXe_OK; }
This function reads channel values which may have changed. These are stored in the allocated data for later evaluation.
void CTestTexture::vtx_Evaluate ( ILxUnknownID vector, LXpTextureOutput *tOut, void *data) { RendData *rd = (RendData *) data; LXpTextureInput *tInp; float tPos[2], u, v, iu, iv; LXtFVector hsv, rgb; tInp = (LXpTextureInput *) pkt_service.FastPacket (vector, tin_offset); tPos[0] = (tInp->axis == 0) ? -tInp->tPos[2] : tInp->tPos[0] + 0.5; tPos[1] = (tInp->axis == 1) ? -tInp->tPos[2] : tInp->tPos[1] + 0.5; iu = floor (tPos[0]); iv = floor (tPos[1]); u = tPos[0] - iu - 0.5; v = tPos[1] - iv - 0.5; hsv[0] = iu / 7.7 + iv * 776.315; hsv[1] = 1.0 - u * rd->f_sat; hsv[2] = v * rd->f_mult + rd->f_base; HSV2RGB (hsv, rgb); tOut->direct = 1; tOut->alpha[0] = 1.0; tOut->value[0] = LXx_VLEN (rgb); if (tInp->context == LXi_TFX_COLOR) LXx_VCPY (tOut->color[0], rgb); }
Evaluate the color at a spot using cached values.
void CTestTexture::vtx_Cleanup ( void *data) { RendData *rd = (RendData *) data; delete rd; }
Release the cached state after rendering is complete using the RendData class defined in our CTestTexture class.
LXtItemType CTestTexture::MyType () { if (my_type != LXiTYPE_NONE) return my_type; CLxUser_SceneService svc; my_type = svc.ItemType (SRVs_ITEMTYPE); return my_type; }
Release the cached state after rendering is complete using the SceneService object.
LXtItemType CTestTexture::MyType () { if (my_type != LXiTYPE_NONE) return my_type; CLxUser_SceneService svc; my_type = svc.ItemType (SRVs_ITEMTYPE); return my_type; }
Utility to get the type code for this item type, as needed.
LxResult CTestTexture::cui_Enabled ( const char *channelName, ILxUnknownID msg, ILxUnknownID item, ILxUnknownID read) { if (strcmp (channelName, CHANs_SATURATION)) return LXe_OK; CLxUser_Item src (item); CLxUser_ChannelRead chan (read); if (chan.FValue (src, CHANs_LOW) != 0.0) return LXe_OK; if (chan.FValue (src, CHANs_HIGH) != 0.0) return LXe_OK; CLxUser_Message res (msg); res.SetCode (LXe_CMD_DISABLED); res.SetMsg ("common", 99); res.SetArg (1, "This only applies when High and Low are non-zero."); return LXe_CMD_DISABLED; }
Test if a given channel is enabled. We're going to disable the saturation channel if both the high and low are set to zero. I'm using common message 99, which just repeats its string argument, but normally this would be defined in a dedicated message table.
LxResult CTestTexture::cui_DependencyCount ( const char *channelName, unsigned *count) { if (strcmp (channelName, CHANs_SATURATION) == 0) count[0] = 2; else count[0] = 0; return LXe_OK; } LxResult CTestTexture::cui_DependencyByIndex ( const char *channelName, unsigned index, LXtItemType *depItemType, const char **depChannelName) { if (strcmp (channelName, CHANs_SATURATION)) return LXe_OUTOFBOUNDS; depItemType[0] = MyType (); switch (index) { case 0: depChannelName[0] = CHANs_LOW; return LXe_OK; case 1: depChannelName[0] = CHANs_HIGH; return LXe_OK; default: return LXe_OUTOFBOUNDS; } }
Dependency count/byIndex list the channels that affect a given target channel. In our case the saturation channel is affected by changes to the low and high channels of this same item type.