Jump to content

Texture Change HUD Button with multiple textures


You are about to reply to a thread that has been inactive for 83 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I am trying to make a Texture change HUD button that has multiple textures assigned to one button, that when the button is clicked, assigns the first texture to a single face in the object, and when the button is clicked again, it assigns the second texture in the list to the object, then the third, and so on, until we reach the end of the texture list, and it starts over. I want this button to be able to have multiple texture UUIDs in a list to grab from, to assign to the object, but so far I have only found ways to make scripts that only offer one texture to apply, and that is not good considering I wish to use my script for changing facial expressions on a robotic head. I want to have a variety of different eye types, for example, assigned to one button.. Think of it like turning pages in a magazine.


If possible I would also like to know if it is possible to read UUIDs from a notecard and add them to a list, so that users of my product may add their own textures to the HUD applier.

 

 

To clarify, I do not want one texture per button, that requires too many buttons and a buttload of scripts.

Edited by Techwolf77
Link to post
Share on other sites

That's easy enough to do. for each button you have a global integer that you increment which acts as the index into a list of textures. when the integer is greater than or equal to the number of textures in the list, set the integer back to zero.

You can indeed read texture uuids from a notecard, but reading from a notecard is slow (1 second per line in the notecard) and a somewhat intermediate programming challenge. I might recommend just using textures that are in the prim's inventory.

 

integer gTextureIndex;
uSetTexture(string texture)
{ /*apply the texture here*/ }

default
{
	touch_start(integer i)
	{
		uSetTexture(llGetInventoryName(INVENTORY_TEXTURE,gTextureIndex++));
		if(gTextureIndex>=llGetInventoryNumber(INVENTORY_TEXTURE))
			gTextureIndex=0;
	}
}

I didn't test this but that should do roughly what you want. Following is an example with how to do the same thing, but reading the textures from a notecard (also untested):

string	gNotecardName="";
integer gNotecardLine=0; // set this to the number of lines to ignore before expecting every line to be a texture UUID or name.
key		gNotecardRequestKey;

integer	gTextureIndex;
list	gTextures=[]; // you can add some specific textures here.

uSetTexture(string texture)
{ /*apply the texture here*/ }

default
{
	state_entry()
	{
		gNotecardName=llGetInventoryName(INVENTORY_NOTECARD,0); //comment out if using hardcoded notecard name.
		gNotecardRequestKey=llGetNotecardLine(gNotecardName,gNotecardLine);
	}
	touch_start(integer i)
	{
		uSetTexture(llList2String(gTextures,gTextureIndex++);
		if(gTextureIndex>=llGetListLength(gTextures))
			gTextureIndex=0;
	}
	dataserver(key ID,string data)
	{	if(ID==gNotecardRequestKey)
		{
			if(data!=EOF)
			{
				gTextures+=data;
				gNotecardRequestKey=llGetNotecardLine(gNotecardName,++gNotecardLine);
			}
		}
	}
}

if there are a lot of textures to read, and no textures listed in gTextures, you might want/need to add some code to stop the user from trying to set the texture before all the textures are loaded in from the notecard, possibly by moving touch_start() to a separate state that you transition to from the dataserver even when data==EOF.

Edited by Quistessa
added notecard example.
  • Like 1
  • Thanks 1
Link to post
Share on other sites

In addition to either using textures in the prim's inventory or reading from a notecard, you can also create a list with texture keys directly in the script; this is faster than reading from a notecard, which can indeed be somewhat slow, as @Quistessarightly noted.  However, this is only recommended if the textures are a fixed set, since you'd need to edit the script each time you'd want to add, remove, or otherwise change a texture.

  • Like 1
  • Thanks 1
Link to post
Share on other sites
  • 2 weeks later...

thank you for this useful information. I believe I want to go with an inventory-based texture application now.

One concern I have is how to separate the different textures by type? I want to have different sets of eyes, mouths, and blushes for the head I'm making, and I want the scripts to be able to tell which textures go for what part of the head by face number if that makes sense. so that eye textures only apply to the eye face, and all that.

Can I make it so there's a naming format for the textures for the scripts to read, so that for example, a texture named EYE_1 is recognized as an eye texture by the prefix?

Link to post
Share on other sites

You could certainly use a naming format. You'll need some way of storing data on which texture is of which type, and an implementation of some naming convention. to parse the texture names, you might use either llParseString2List() or llGetSubString() to separate the name of the texture into meaningful chunks. for storing the data on what texture is which type, you'll want to use either several lists for each type, or a big strided list. there are pros and cons for each, but I'd say if you want each kind of texture to go together as a set (EYE_1 FACE_1 BODY_1 all grouped together as set one for example) I think it might be easier to manage a strided list, but if all of your things are separate (you have more eye options than face options for example) then separate lists would e the way to go.

You'll probably want to organize the texture names in both state_entry() and changed() events, so a global function to do the organizing would probably be prudent.

Using separate lists, a parsing function might look something like this:

list gFaceList;
list gEyeList;

uParseTextureNames()
{
  list gFaceList=[];
  list gEyeList=[]; // good safety to clear the lists first to avoid filling them with duplicates.
  integer index = llGetInventoryNumber(INVENTORY_TEXTURE);
  while(--index>0)
  {
    string name = llGetInventoryName(INVENTORY_TEXTURE,index);
    string subname = llGetSubString(name,0,2); // first 3 letters of name
    if(subname=="FAC")
      gFaceList+=name;
    if(subname=="EYE")
      gEyeList+=name;
    else
      llSay(0,"Bad texture Name: "+name);
  }
}

 

Link to post
Share on other sites
On 3/7/2021 at 9:07 PM, Techwolf77 said:

To clarify, I do not want one texture per button, that requires too many buttons and a buttload of scripts.

FWIW you would only need one script for all your buttons, using llDetectedLinkNumber() and llDetectedTouchFace() to determine which button was pressed.

  • Like 1
Link to post
Share on other sites
Posted (edited)
On 3/19/2021 at 9:30 PM, Quistessa said:

You could certainly use a naming format. You'll need some way of storing data on which texture is of which type, and an implementation of some naming convention. to parse the texture names, you might use either llParseString2List() or llGetSubString() to separate the name of the texture into meaningful chunks. for storing the data on what texture is which type, you'll want to use either several lists for each type, or a big strided list. there are pros and cons for each, but I'd say if you want each kind of texture to go together as a set (EYE_1 FACE_1 BODY_1 all grouped together as set one for example) I think it might be easier to manage a strided list, but if all of your things are separate (you have more eye options than face options for example) then separate lists would e the way to go.

You'll probably want to organize the texture names in both state_entry() and changed() events, so a global function to do the organizing would probably be prudent.

Using separate lists, a parsing function might look something like this:



list gFaceList;
list gEyeList;

uParseTextureNames()
{
  list gFaceList=[];
  list gEyeList=[]; // good safety to clear the lists first to avoid filling them with duplicates.
  integer index = llGetInventoryNumber(INVENTORY_TEXTURE);
  while(--index>0)
  {
    string name = llGetInventoryName(INVENTORY_TEXTURE,index);
    string subname = llGetSubString(name,0,2); // first 3 letters of name
    if(subname=="FAC")
      gFaceList+=name;
    if(subname=="EYE")
      gEyeList+=name;
    else
      llSay(0,"Bad texture Name: "+name);
  }
}

 

I added this piece of code to my current HUD button hoping to integrate it in to what I already have, but the Texture Name thing seems to not be working.
I changed my Texture names to EYE_x but I get an output saying "INVALID TEXTURE NAME" 3 times for all textures in the inventory.

I need a second pair of eyes to see what I did wrong. I'll attach my code here.

 

integer numberoftextures;//number of textures in inventory
integer currenttexture;//inventory number of current texture
integer channel = (Omitted); // Channel for comms (Must be same as reciever).
 list protoEyeList; // List of Eye Textures in HUD inventory
   integer link = LINK_SET;  // Link number to apply the texture to (LINK_SET for all links).
   integer face = 1; // Face number to apply the texture to (ALL_SIDES for all faces).

string SR = "*"; // Seperator to use in the list, must be the same
                 // as the seperator to be used within the reviever
                 // script.

////////////////////////////////////////////////////////////////////
uParseTextureNames()
{
    integer counter;
    string texture = llList2String(protoEyeList,currenttexture);
  currenttexture = 0;
  list protoEyeList=[];
  integer index = llGetInventoryNumber(INVENTORY_TEXTURE);
  while(index>0)
  {
    string name = llGetInventoryName(INVENTORY_TEXTURE,index);
    string subname = llGetSubString(name,0,2);
    if(subname=="EYE")
      protoEyeList+=name;
    else
      llSay(0,"Invalid texture Name: "+name);
  }
}


default
{
    touch_start(integer total_number) // When object is touched.
    {
        numberoftextures = llGetListLength(protoEyeList);//speed hack here
        string texture = llList2String(protoEyeList,currenttexture);
        ++currenttexture;
            if(currenttexture == numberoftextures)//if current texture = number of textures, reset counter
                currenttexture = 0;
                uParseTextureNames();
        // Say each texture property with the seperator inbetween so the reciever can parse it.
        llRegionSay(channel,texture+SR+(string)link+SR+(string)face);
    }
}


Keep in mind this is a frankenstein of several pieces of code as well.

Messed around a little bit more and it seems the code is not actually getting the names of the inventory textures at all!

 

Edited by Techwolf77
Link to post
Share on other sites

in the

44 minutes ago, Techwolf77 said:

Messed around a little bit more and it seems the code is not actually getting the names of the inventory textures at all!

 

in uParseTexturesNames()

 

index needs to be decrement

(index > 0) should be (--index >= 0)

best also to look at the flow of the code

for example call uParseTextureNames() one time in state_entry event (remove the call in touch_start event)

then in touch_start event, step thru protoEyeList

  • Thanks 1
Link to post
Share on other sites
You are about to reply to a thread that has been inactive for 83 days.

Please take a moment to consider if this thread is worth bumping.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...