Difference between revisions of "Texture test"

From The Foundry MODO SDK wiki
Jump to: navigation, search
Line 6: Line 6:
  
 
===Class declaration===
 
===Class declaration===
 +
 +
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.
  
 
  class CTestTexture :
 
  class CTestTexture :
Line 38: Line 40:
 
         };
 
         };
 
  };
 
  };
 
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|Server Tags]]===
 
===[[Server_Tags|Server Tags]]===
 +
 +
The tags here indicate that server has the name Test Value Texture with the internal name of val-texture.
  
 
  LXtTagInfoDesc CTestTexture::descInfo[] = {
 
  LXtTagInfoDesc CTestTexture::descInfo[] = {
Line 48: Line 50:
 
         { 0 }
 
         { 0 }
 
  };
 
  };
 
The tags here indicate that server has the name Test Value Texture with the internal name of val-texture.
 
  
 
===[[Initialize_(index)|Initialize]]===
 
===[[Initialize_(index)|Initialize]]===
 +
 +
This function exports a server of the TEXTURE type dependent on the CTestTexture class with the ValueTexture, ChannelUI, and StaticDesc interfaces.
  
 
  void
 
  void
Line 64: Line 66:
 
         lx::AddServer (SRVs_TEXTURE, srv);
 
         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===
 
===Helper Functions===
 +
 +
Utilities for RGB/HSV conversion.
  
 
  #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
  #define MIN(a,b) ((a) < (b) ? (a) : (b))
Line 180: Line 182:
 
         }
 
         }
 
  }
 
  }
 
Utilities for RGB/HSV conversion.
 
  
 
===Implementations===
 
===Implementations===
 +
 +
This function creates the channels for the item type using the methods of an [[Package_(lx-package.hpp)#.2815.29_SDK:_ILxAddChannel_interface method|AddChannel]] object.
  
 
  LxResult
 
  LxResult
Line 203: Line 205:
 
  }
 
  }
  
This function creates the channels for the item type using the methods of an [[Package_(lx-package.hpp)#.2815.29_SDK:_ILxAddChannel_interface method|AddChannel]] object.
+
This function attaches the channels to channel evaluation. This gets indices for the channels in attributes through the AddChan method of a [[Action_(lx-action.hpp)#.2822.29_User_Class:_Evaluation_method|User Evaluation]] object.
  
 
  LxResult
 
  LxResult
Line 221: Line 223:
 
  }
 
  }
  
This function attaches the channels to channel evaluation. This gets indices for the channels in attributes through the AddChan method of a [[Action_(lx-action.hpp)#.2822.29_User_Class:_Evaluation_method|User Evaluation]] object.
+
This function reads channel values which may have changed. These are stored in the allocated data for later evaluation.
  
 
         LxResult
 
         LxResult
Line 239: Line 241:
 
  }
 
  }
  
This function reads channel values which may have changed. These are stored in the allocated data for later evaluation.
+
Evaluate the color at a spot using cached values.
  
 
  void
 
  void
Line 274: Line 276:
 
  }
 
  }
  
Evaluate the color at a spot using cached values.
+
Release the cached state after rendering is complete using the RendData class defined in our CTestTexture class.
  
 
  void
 
  void
Line 285: Line 287:
 
  }
 
  }
  
Release the cached state after rendering is complete using the RendData class defined in our CTestTexture class.
+
Release the cached state after rendering is complete using the [[LXa_SCENESERVICE_(index)#Item_Types|SceneService]] object.
  
 
         LXtItemType
 
         LXtItemType
Line 299: Line 301:
 
  }
 
  }
  
Release the cached state after rendering is complete using the [[LXa_SCENESERVICE_(index)#Item_Types|SceneService]] object.
+
Utility to get the type code for this item type, as needed.
  
 
  LXtItemType
 
  LXtItemType
Line 313: Line 315:
 
  }
 
  }
  
Utility to get the type code for this item type, as needed.
+
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
 
  LxResult
Line 342: Line 344:
 
  }
 
  }
  
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.
+
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.
  
 
  LxResult
 
  LxResult
Line 381: Line 383:
 
         }
 
         }
 
  }
 
  }
 
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.
 

Revision as of 20:58, 10 September 2013

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.

Code Walkthrough

Class declaration

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.

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;
       };
};

Server Tags

The tags here indicate that server has the name Test Value Texture with the internal name of val-texture.

LXtTagInfoDesc	 CTestTexture::descInfo[] = {
       { LXsSRV_USERNAME,	"Test Value Texture" },
       { LXsSRV_LOGSUBSYSTEM,	"val-texture"	},
       { 0 }
};

Initialize

This function exports a server of the TEXTURE type dependent on the CTestTexture class with the ValueTexture, ChannelUI, and StaticDesc interfaces.

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);
}

Helper Functions

Utilities for RGB/HSV conversion.

#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;
       }
}

Implementations

This function creates the channels for the item type using the methods of an AddChannel object.

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 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_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 reads channel values which may have changed. These are stored in the allocated data for later evaluation.

       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;
}

Evaluate the color at a spot using cached values.

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);
}

Release the cached state after rendering is complete using the RendData class defined in our CTestTexture class.

void
CTestTexture::vtx_Cleanup (
        void			*data)
{
       RendData		*rd = (RendData *) data;

       delete rd;
}

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.

LXtItemType
CTestTexture::MyType ()
{
       if (my_type != LXiTYPE_NONE)
               return my_type;

       CLxUser_SceneService	 svc;

       my_type = svc.ItemType (SRVs_ITEMTYPE);
       return my_type;
}

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_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;
}

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.

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;
       }
}