Some TVP 10 scripts don't work in TVP 11 Topic is solved

A forum dedicated to George scripting questions
User avatar
Lukas
Posts: 526
Joined: 14 Jan 2011, 11:15
Contact:

Some TVP 10 scripts don't work in TVP 11

Post by Lukas »

I wrote a bunch of George scripts in TVPaint 10 that no longer work in TVPaint 11. Is there a list of changes that I can look into so I know where to start to fix them?
  • Lukas Sketch Panel
  • TVPaint Pro 11.7.3
  • MacBook Pro 2018 macOS Ventura 13.4.1 + PC Windows 10
  • Wacom Cintiq 27QHD + Wacom Intuos4
  • YouTube.com/@ClubBaboo
  • YouTube.com/@FrameOrder
User avatar
Joost
Posts: 439
Joined: 24 Nov 2011, 13:16

Re: Some TVP 10 scripts don't work in TVP 11

Post by Joost »

I always use Lukas' scripts. They work really well and they save me a lot of work.

However, a lot of them are broken now. So any help from the TVP team would be really helpful!

Thanks
Mac OS 13.4.1 , Mac Studio 2023, 32GB RAM, Wacom Cintiq 27 QHD (no touch), Wacom Driver 6.4.2-4.
TVP Pro 11.7.1
User avatar
Thierry
Site Admin
Posts: 2780
Joined: 07 Jan 2013, 08:28

Re: Some TVP 10 scripts don't work in TVP 11

Post by Thierry »

Can you post the scripts (or send them to me via PM if you don't want them to be available to the public), so I can check what's wrong?
Is there a list of changes that I can look into so I know where to start to fix them?
You can check the changelogs: viewtopic.php?f=10&t=9058
I don't think we changed a lot of commands in v11 updates, as we know that it might break already existing scripts, we mainly added new ones.
User avatar
Lukas
Posts: 526
Joined: 14 Jan 2011, 11:15
Contact:

Re: Some TVP 10 scripts don't work in TVP 11

Post by Lukas »

Hi Thierry,
Nothing serious in the changelog that I can imagine is breaking the scripts. For some scripts I can imagine some tool settings have changed, but it might be something else.
Here's an example script that no longer works:

Code: Select all

// Fix multiply stuff from non-pro .tvpp files

Blendingmode[1] = "Color"
Blendingmode[2] = "Behind"
Blendingmode[3] = "Erase"
Blendingmode[4] = "Shade"
Blendingmode[5] = "Light"
Blendingmode[6] = "Colorize"
Blendingmode[7] = "Hue"
Blendingmode[8] = "Add"
Blendingmode[9] = "Sub"
Blendingmode[10] = "Multiply"
Blendingmode[11] = "Screen"
Blendingmode[12] = "Replace"
Blendingmode[13] = "Copy"
Blendingmode[14] = "ReplaceSet"
Blendingmode[15] = "Difference"
Blendingmode[16] = "Divide"
Blendingmode[17] = "Overlay"
Blendingmode[18] = "Light2"
Blendingmode[19] = "Shade2"
Blendingmode[20] = "HardLight"
Blendingmode[21] = "SoftLight"
Blendingmode[22] = "GrainExtract"
Blendingmode[23] = "GrainMerge"
Blendingmode[24] = "Sub2"
Blendingmode[25] = "Darken"
Blendingmode[26] = "Lighten"
Blendingmode[27] = "Saturation"

tv_undoOpenStacktack

tv_LayerCurrentID
Beginlayer = result

layerRun = 1
layerPos = 0
WHILE layerRun	

	tv_LayerGetID layerPos	
	lid = result	
	
	IF CMP(lid,"NONE")==0
		//---START RUN ON LAYER---
		
		//PARSE LAYER INFO
		tv_LayerInfo lid
		PARSE result layerDisplay layerPosition layerOpacity LayerName layerType layerStart layerEnd layerPrelighttable layerPostlighttable layerSelection
		
		//REPLACE SPACES IN LayerName BY UNDERSCORES
		PARSE LayerName LayerName1 LayerName2 LayerName3 LayerName4 Layername5
		IF CMP(Layername5,"")==0
			PRINT "This layername has too many spaces: "LayerName
		END
		IF CMP(LayerName4,"")==0
			LayerName = LayerName1"_"LayerName2"_"LayerName3"_"LayerName4
		ELSE
			IF CMP(LayerName3,"")==0
				LayerName = LayerName1"_"LayerName2"_"LayerName3
			ELSE
				IF CMP(LayerName2,"")==0
					LayerName = LayerName1"_"LayerName2
				END
			END
		END
		
		lastUnderscore = LastPos(LayerName,"_")
		
		strlen = LEN(LayerName)
		LastWord = RightString(LayerName,strlen-lastUnderscore)	
		IF CMP(lastUnderscore,0)
			FirstPart = LayerName
		ELSE
			FirstPart = LeftString(LayerName,lastUnderscore-1)
		END


		FOR i = 2 TO 27
			//CHECK LAYERBLENDING AND SET NAME TO MULTIPLY
			tv_layerblendingmode lid
			IF CMP(result,Blendingmode[i]) && CMP(LastWord,Blendingmode[i])==0
				LastWord = Blendingmode[i]
				LayerName = LayerName"_"LastWord
				tv_LayerRename lid LayerName
			ELSE
				IF CMP(result,Blendingmode[i])
					LastWord = Blendingmode[i]
					LayerName = FirstPart"_"LastWord
					tv_LayerRename lid LayerName
				END
			END
			
			//SET LAYER TO BLENDINGMODE IF NAME IS BLENDINGMODE
			IF CMP(LastWord, Blendingmode[i])
				tv_layerblendingmode lid Blendingmode[i]
			END
			tv_layerblendingmode lid LastWord
		END
		
		//---END RUN ON LAYER---
		layerPos = layerPos+1
	ELSE
		layerRun = 0
	END
END

tv_layerSet Beginlayer

tv_undoCloseStack

#INCLUDE "Include.grg"
The scripts saves a layer's blending mode to the layer name, for example: A layer "Shadow" might become "Shadow_Multiply", so when someone works on the file without TVP Pro (our interns usually work on TVP 11 non-pro), that information doesn't get lost. And when someone with pro opens the file, the script sets the blending mode back to the original state.

Thanks for looking into it :)
  • Lukas Sketch Panel
  • TVPaint Pro 11.7.3
  • MacBook Pro 2018 macOS Ventura 13.4.1 + PC Windows 10
  • Wacom Cintiq 27QHD + Wacom Intuos4
  • YouTube.com/@ClubBaboo
  • YouTube.com/@FrameOrder
User avatar
Thierry
Site Admin
Posts: 2780
Joined: 07 Jan 2013, 08:28

Re: Some TVP 10 scripts don't work in TVP 11

Post by Thierry »

Thanks!
Can you send me the "include.grg" script that is referenced in your script?

Also, if you could post a screenshot of the error message you're getting it would be great :)

From what I've seen so far, it seems you're missing the two Blending Modes we've added in v11: Overlay2 (in v11.0.3), and Alpha Diff in (v11.0.9). This might affect the loop at line 78 (FOR i = 2 TO 27).
User avatar
Lukas
Posts: 526
Joined: 14 Jan 2011, 11:15
Contact:

Re: Some TVP 10 scripts don't work in TVP 11

Post by Lukas »

Thierry wrote: 31 Mar 2021, 12:32 Thanks!
Can you send me the "include.grg" script that is referenced in your script?
Oh, of course, I didn't realise it was being included:

Code: Select all

// ************************************************************************************************
// *** FIRST PART ARE FUNCTIONS BY LUKAS KREPEL (FRAME ORDER)									***
// *** THE REST OF THE FILE IS MADS JUUL'S INCLUDE FILE WITH ALL BASIC/ADVANCED/USER FUNCTIONS  ***
// ************************************************************************************************

// ********************************************************************************
// *** Hide storyboard and overlay layers
// *** Wordt in geen enkel script gebruikt, voor backup purposes staat ie hier.
// ********************************************************************************
FUNCTION HideStoryboardAndOverlayLayers()
	tv_layercolor hide Display 12 // Hide Storyboard layer before rendering
	tv_layercolor hide Display 11 // Hide Overlay layer before rendering
END

// ***********************
// *** Render images and save XML
// ***********************
FUNCTION ExportImagesAndXML(saveDir, clipName, inpoint, outpoint, clipOffset)
	renderStart = inpoint
	renderEnd = outpoint
	offsetSTART= renderStart - inpoint + 1
	offsetEND = renderEnd - inpoint + 1
	// *** Get info
	//todo
	//tv_clipname ClipID
	//renderName = result
	//
	ClipXMLfile = saveDir"/"clipName".xml" //!!!!!!!!!!!!!!!!!!
	sequenceIn = inpoint + 1
	sequenceOut = outpoint + 1
	// *** Write info
	XMLbegin(ClipXMLfile, clipName, sequenceIn, sequenceOut, projectFramerate)
	// *** Start saving image files
	curImage = renderStart
	WHILE curImage <= renderEnd
		tv_layerImage curImage
		offsetImage = curImage - inpoint + 1
		frame = offsetImage + renderStart
		prefixedFrame = addZeros("_",frame,5)
		fileName = clipName""prefixedFrame""ext
		filePath = saveDir"/"fileName
		//Show message
		Message = CONCAT("Rendering all clips with XML file | ", (filePath))
		tv_lockdisplay Message
		//
		frameEnd = frame + 1 //todo
		OffsetFrame = frame + clipOffset
		filePathWithQuotes = '"' filePath '"'  //Enclose path-filename with (single quote double quote singlequotes)
		//Save image file
		tv_ProjectSaveSequence filePathWithQuotes CAMERA OffsetFrame OffsetFrame		
		frameStart = frame
		tv_exposureNext //Goes to next exposure
		curImage = result
		// *** Find next frame
		tv_layerImage curImage
		offsetImage = curImage - inpoint + 1
		frame = offsetImage + renderStart
		frameEnd = frame
		// *** Check if we reached the last frame
		tv_exposureinfo curImage
		PARSE result type rest
		XMLimage(ClipXMLfile, fileName, filePath, frameStart, frameEnd, projectWidth, projectHeight, 0) //todo moet ClipXMLfile een parameter zijn?
		XMLimage(TotalXMLfile, fileName, filePath, frameStart, frameEnd, projectWidth, projectHeight, addsomeframes) //todo TotalXMLfile bestaat niet altijd, alleen als je meerdere clips rendert, checken op null?
		IF CMP(type,"Head")==0 || curImage >= sequenceOut //todo OF ALS we verder zijn dan outpointje
			addSomeFrames = addSomeFrames - inpoint - 1 + frameEnd
			curImage = renderEnd + 1
		END
	END
	XMLend(ClipXMLfile)
END

// *********************************************************************************************
// *** Set layers named "*_Multiply" to multiply. And name all multiplied layers "*_Multiply"
// *********************************************************************************************
FUNCTION FixMultiply()
	Zoekwoord = Multiply
	tv_LayerCurrentID
	beginLayer = result
	layerRun = 1
	layerPos = 0
	WHILE layerRun
		tv_LayerGetID layerPos
		layerID = result
		IF CMP(layerID,"NONE")==0
			// START RUN ON LAYER
			tv_LayerInfo layerID
			PARSE result layerDisplay layerPosition layerOpacity layerName layerType layerStart layerEnd layerPrelighttable layerPostlighttable layerSelection
	        last = LastPos(layerName,"_")
	        strlen = LEN(layerName)
	        IF CMP(last,0)
                Eerstewoord = layerName
            ELSE
  		        Eerstewoord = LeftString(layerName,last-1)
            END
            Tweedewoord = RightString(layerName,strlen-last)
			IF CMP(Tweedewoord, Zoekwoord)
				tv_layerblendingmode layerID Multiply
			END
            tv_layerblendingmode layerID
	        IF CMP(result,Multiply)
                Multiplylayername = Eerstewoord"_Multiply"
                tv_LayerRename layerID Multiplylayername
	        END
			// END RUN ON LAYER
			layerPos = layerPos+1	
		ELSE		
			layerRun = 0
		END
	END
	tv_layerSet beginLayer
END



// **************************************************************************************
// *** Add a prefix and extra zeros to a number, to turn "2" into "_00002" for example (Different than Mads Juul's version, can't remember why)
// **************************************************************************************
FUNCTION addZeros(prefix,number,digits)
	LOCAL current i
	current = LEN(number)
	digits = digits - 1
	FOR i = current TO digits
		prefix = prefix"0"
	END
	prefix = prefix""number
	RETURN prefix
END

// ******************************
// *** Write start of XML file
// ******************************
FUNCTION XMLbegin(XMLfile, sequenceName, sequenceIn, sequenceOut, projectFramerate)
	tv_WriteTextFile "Create" '"'XMLfile'"' "<xmeml version="'"4"'">" //klopt
	sequenceNameWithQuotes = '"'sequenceName'"'
  	tv_WriteTextFile "Append" '"'XMLfile'"' "<sequence id="sequenceNameWithQuotes">" //SEQUENCE NAME (moet tussen quotes?)
	tv_WriteTextFile "Append" '"'XMLfile'"' "<uuid>69b229de-c9e4-410e-869c-c77e560b4e18</uuid>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<name>"renderName"</name>" //SEQUENCE NAME
   	tv_WriteTextFile "Append" '"'XMLfile'"' "<duration>0</duration>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<timebase>"projectFramerate"</timebase>" //FRAMERATE
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<ntsc>false</ntsc>"
 	tv_WriteTextFile "Append" '"'XMLfile'"' "</rate>"
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<in>"sequenceIn"</in>" //IN
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<out>"sequenceOut"</out>" //OUT
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<timecode>"
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<string>00:00:00:00</string>"
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<frame>0</frame>"
  	tv_WriteTextFile "Append" '"'XMLfile'"' "<displayformat>NDF</displayformat>"
  	tv_WriteTextFile "Append" '"'XMLfile'"' "<rate>"
  	tv_WriteTextFile "Append" '"'XMLfile'"' "<timebase>"projectFramerate"</timebase>" //FRAMERATE
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<ntsc>false</ntsc>"
 	tv_WriteTextFile "Append" '"'XMLfile'"' "</rate>"
  	tv_WriteTextFile "Append" '"'XMLfile'"' "</timecode>"
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<media>"
 	tv_WriteTextFile "Append" '"'XMLfile'"' "<video>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<format>"
   	tv_WriteTextFile "Append" '"'XMLfile'"' "<samplecharacteristics>"
   	tv_WriteTextFile "Append" '"'XMLfile'"' "<width>"projectWidth"</width>" //PROJECT WIDTH
	tv_WriteTextFile "Append" '"'XMLfile'"' "<height>"projectHeight"</height>" //PROJECT HEIGHT
	tv_WriteTextFile "Append" '"'XMLfile'"' "<rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<timebase>"projectFramerate"</timebase>" //FRAMERATE
	tv_WriteTextFile "Append" '"'XMLfile'"' "<ntsc>false</ntsc>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<pixelaspectratio>square</pixelaspectratio>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<anamorphic>false</anamorphic>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</samplecharacteristics>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</format>"
   	tv_WriteTextFile "Append" '"'XMLfile'"' "<track MZ.TrackName="'"video"'">"
   	tv_WriteTextFile "Append" '"'XMLfile'"' "<enabled>true</enabled>"
   	tv_WriteTextFile "Append" '"'XMLfile'"' "<locked>false</locked>"
end

// ****************************************************
// *** Write middle part of XML file, for each image
// ****************************************************
FUNCTION XMLimage(XMLfile, fileName, filePath, frameStart, frameEnd, width, height, addsomeframes)
	frameStart = frameStart - inpoint - 1 + addSomeFrames
	frameEnd = frameEnd - inpoint - 1 + addSomeFrames
	fileNameWithQuotes = '"'fileName'"'
	tv_WriteTextFile "Append" '"'XMLfile'"' "<clipitem id="fileNameWithQuotes">" //FILENAAM (moet tussen quotes?)
	tv_WriteTextFile "Append" '"'XMLfile'"' "<masterclipid>"fileName"</masterclipid>" //FILENAAM
	tv_WriteTextFile "Append" '"'XMLfile'"' "<name>"fileName"</name>" //FILENAAM
	tv_WriteTextFile "Append" '"'XMLfile'"' "<enabled>true</enabled>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<duration>25</duration>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<timebase>25</timebase>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<ntsc>false</ntsc>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<start>"frameStart"</start>" //STARTFRAME
	tv_WriteTextFile "Append" '"'XMLfile'"' "<end>"frameEnd"</end>" //EINDFRAME
	tv_WriteTextFile "Append" '"'XMLfile'"' "<in>0</in>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<out>25.0</out>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<alphatype/>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<pixelaspectratio/>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<anamorphic/>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<file id="fileNameWithQuotes">" //FILENAAM (moet tussen quotes?)
	tv_WriteTextFile "Append" '"'XMLfile'"' "<name/>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<pathurl>"filePath"</pathurl>" //filePath
	tv_WriteTextFile "Append" '"'XMLfile'"' "<rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<timebase>25</timebase>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<ntsc>false</ntsc>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<timecode>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<string>00:00:00:00</string>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<frame>0</frame>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<displayformat>NDF</displayformat>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<timebase>"projectFramerate"</timebase>" //FRAMERATE
	tv_WriteTextFile "Append" '"'XMLfile'"' "<ntsc>false</ntsc>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</timecode>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<media>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<video>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<samplecharacteristics>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<width>"projectWidth"</width>" //RESOLUTIE.X
	tv_WriteTextFile "Append" '"'XMLfile'"' "<height>"projectHeight"</height>" //RESOLUTIE.Y
	tv_WriteTextFile "Append" '"'XMLfile'"' "<rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<timebase>25</timebase>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<ntsc>false</ntsc>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</rate>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<pixelaspectratio>square</pixelaspectratio>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<anamorphic>false</anamorphic>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</samplecharacteristics>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</video>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</media>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</file>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<labels>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "<labels/>"
	tv_WriteTextFile "Append" '"'XMLfile'"'  "<label2>"colorLabel"</label2>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</labels>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</clipitem>"
END

// ******************************
// *** Write end of XML file
// ******************************
FUNCTION XMLend(XMLfile)
	tv_WriteTextFile "Append" '"'XMLfile'"' "</track>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</video>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</media>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</labels>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</sequence>"
	tv_WriteTextFile "Append" '"'XMLfile'"' "</xmeml>"
END

// *********************************************************************************************
// *** Delete all invisible layers (necessary before merging, otherwise they won't be merged)
// *********************************************************************************************
FUNCTION DeleteInvisibleLayers()
	tv_LayerCurrentID
	beginLayer = result
	layerRun = 1
	layerPos = 0
	WHILE layerRun
		tv_LayerGetID layerPos
		layerID = result
		IF CMP(layerID,"NONE")==0
			// START RUN ON LAYER
			tv_LayerInfo layerID
			PARSE result layerDisplay layerPosition layerOpacity layerName layerType layerStart layerEnd layerPrelighttable layerPostlighttable layerSelection
			IF CMP(layerdisplay, "OFF")
				tv_layerKill layerID
				layerPos = layerPos-1 //Layer has been deleted, so we need to make sure the next layer does not get skipped.
			END
			// END RUN ON LAYER
			layerPos = layerPos+1	
		ELSE		
			layerRun = 0
		END
	END
	tv_layerSet beginLayer
END

// ***************************************************
// *** BELOW THIS PART IS MADS JUUL'S INCLUDE FILE ***
// ***************************************************








// Mads Juul INCLUDE file includes the functions from the basic.grg and the advanged.geg George files as well as the proceduresmade by users found in the wiki
// http://wiki.tvpaint.fr/index.php?title=George_Command_Reference
// Use at your own risk!

//{{{ BASIC
//{{{ Find(string,car,start)
//------------------------------------------
//
//	Find
//
//	Function: find a character into a string
//            from a specified start position
//
//	Call: Find(string,car,start)
//
//	Arguments:
//		string = characters string
//		car    = character to look for
//		start  = start position in string
//
//	Return: position of character
//			0 if character does not exist
//			into string
//			-1 if invalid position
//			(negative, null or higher
//			 than string length)
//
//------------------------------------------

FUNCTION Find(string,car,start)
	LOCAL i size
	i = start
	size = LEN(string)
	
	IF ((start <= 0) || (start > size) || (CMP(car,"") == 1))
		RETURN -1
	END
	DO
		IF (CMP(CHAR(string,i),car) == 1)
			RETURN i
		END
	UNTIL ((i=i+1) > size)
	RETURN 0
END
//}}}

//{{{ FirstPos(string,car)
//------------------------------------------
//
//	FirstPos
//
//	Function: find first occurence of a
//			  character into a string
//
//	Call: FirstPos(string,car)
//
//	Arguments:
//		string = characters string
//		car    = character to look for
//
//	Return: position of character
//			or 0 id character does not
//			exist into string.
//
//------------------------------------------

FUNCTION FirstPos(string,car)
	RETURN Find(string,car,1)
END
//}}}

//{{{ LastPos(string,car)
//------------------------------------------
//
//	LastPos
//
//	Function: find last occurence of a
//			  character into a string
//
//	Call: LastPos(string,car)
//
//	Arguments:
//		string = characters string
//		car    = character to look for
//
//	Return: position of character
//			or 0 if character does not
//			exist into string.
//
//------------------------------------------

FUNCTION LastPos(string,car)
	LOCAL loop  myChar 
	pos = LEN(string)
	loop = 1
	WHILE loop
		myChar = CHAR(string,pos)
		
		IF CMP(myChar,car) == 1
			loop =0
		ELSE
			pos = pos-1
		END
		IF pos<1
			loop=0
		END
	END
	RETURN pos
END
//}}}

//{{{ FindString(string,search,start)
//------------------------------------------
//
//	FindString
//
//	Function: find a substring into a string
//             from a specified start position
//
//	Call: FindString(string,search,start)
//
//	Arguments:
//		string = characters string
//		search = substring to look for
//		start  = start position in string
//
//	Return: start position of substring
//			0 if substring does not exist
//			into string
//			-1 if invalid start position
//			(negative, null or higher
//			than string length) or if
//          substring is empty
//
//------------------------------------------

FUNCTION FindString(string,search,start)
	LOCAL found j pos lastpos lstr lsrch
	found = 0
	lastpos = start
	lstr = LEN(string)
	lsrch = LEN(search)
	
	IF (CMP(search,"") == 1)
		RETURN -1
	END
	WHILE ((pos = Find(string,CHAR(search,1),lastpos)) > 0)
		j = 1
		found = 1
		IF (j == lsrch)
			RETURN pos
		END
		WHILE ((j < lsrch) && (found == 1))
			IF ((pos+j) > lstr)
				RETURN 0
			ELSE
				IF (CMP(CHAR(search,j+1),CHAR(string,pos+j)) == 0)
					lastpos = pos+j
					found = 0
				END
			END
			j = j+1
		END
		IF (found == 1)
			RETURN pos
		END
	END
	RETURN pos
END
//}}}

//{{{ LeftString(string,number)
//------------------------------------------
//
//	LeftString
//
//	Function: extract a substring beginning
//            at the start of a string
//			   
//	Call: LeftString(string,number)
//
//	Arguments:
//		string  = characters string
//		number  = number of character to
//			      extract from string
//
//	Return: result substring
//			or 0 if number is negative
//          or null.
//
//------------------------------------------

FUNCTION LeftString(string,number)
	LOCAL size
	size = LEN(string)
	
	IF (number > 0)
		IF (number > size)
			number = size
		END
		RETURN CUT(string,1,number)
	END
	RETURN 0
END
//}}}

//{{{ RightString(string,number)
//------------------------------------------
//
//	RightString
//
//	Function: extract a substring ending
//            at the end of a string
//
//	Call: RightString(string,number)
//
//	Arguments:
//		string  = characters string
//		number  = number of character to
//			      extract from string
//
//	Return: result substring
//			or 0 if number is negative
//          or null.
//
//------------------------------------------

FUNCTION RightString(string,number)
	LOCAL size
	size = LEN(string)
	
	IF (number > 0)
		IF (number > size)
			number = size
		END
		RETURN CUT(string,size-number+1,size)
	END
	RETURN 0
END
//}}}

//{{{ MidString(string,first,size)
//------------------------------------------
//
//	MidString
//
//	Function: extract a substring from a
//			  string
//
//	Call: MidString(string,first,size)
//
//	Arguments:
//		string  = characters string
//		first   = start position in string
//				  cha�ne
//		size    = number of characters
//
//	Return: result substring
//			or 0 if number or first are
//          negatives or null.
//
//------------------------------------------

FUNCTION MidString(string,first,size)
	LOCAL ln
	ln = LEN(string)
	
	IF ((first > 0) && (size > 0))
		IF ((first+size-1) > ln)
			size = ln-first+1
		END
		RETURN CUT(string,first,first+size-1)
	END
	RETURN 0
END
//}}}

//{{{ InsertAtPos(string,insert,pos)
//------------------------------------------
//
//	InsertAtPos
//
//	Function: insert a string in another
//            string at a specified position
//
//	Call: InsertAtPos(string,insert,pos)
//
//	Arguments:
//		string  = characters string 
//		insert  = string to insert
//		pos     = start position for insertion
//
//	Return: result string after insertion
//			or 0 if start position is
//			invalid (negative, null or
//			higher than string length)
//
//------------------------------------------

FUNCTION InsertAtPos(string,insert,pos)
	LOCAL workstr str1 size
	size = LEN(string)

	IF ((pos < 0) || (pos > size))
		RETURN 0
	END
	IF (pos == 0)
		RETURN insert""string
	END
	IF (pos == size)
		RETURN string""insert
	END
	workstr = CUT(string,1,pos)
	IF (pos < size)
		str1 = CUT(string,pos+1,size)
		RETURN workstr""insert""str1
	ELSE
		RETURN workstr""insert
	END
END
//}}}
//}}}

//{{{ ADVANCED
//{{{ InsertAfter(string,insert,search)
//------------------------------------------
//
//	InsertAfter
//
//	Function: insert a string after each
//			  occurence of a character or
//            a set of characters into
//            another string
//
//	Call: InsertAfter(string,insert,search)
//
//	Arguments:
//		string  = characters string
//		insert  = string to insert
//		search  = character or substring
//                to look for
//
//	Return: result string after insertion
//
//------------------------------------------

FUNCTION InsertAfter(string,insert,search)
	LOCAL pos workstr size
	pos = 1
	workstr = string
	size = LEN(search)
	
	WHILE ((pos = FindString(workstr,search,pos)) > 0)
		workstr = InsertStringAtPos(workstr,insert,pos+size-1)
		pos = pos+size+LEN(insert)
	END
	RETURN workstr
END
//}}}

//{{{ InsertBefore(string,insert,search)
//------------------------------------------
//
//	InsertBefore
//
//	Function: insert a string before each
//			  occurence of a character or
//            a set of characters into
//            another string
//
//	Call: InsertBefore(string,insert,search)
//
//	Arguments:
//		string  = characters string
//		insert  = string to insert
//		search  = character or substring
//                to look for
//
//	Return: result string after insertion
//
//------------------------------------------

FUNCTION InsertBefore(string,insert,search)
	LOCAL pos workstr
	pos = 1
	workstr = string
	
	WHILE ((pos = FindString(workstr,search,pos)) > 0)
		workstr = InsertStringAtPos(workstr,insert,pos-1)
		pos = pos+LEN(search)+LEN(insert)
	END
	RETURN workstr
END
//}}}

//{{{ Delete(string,search)
//------------------------------------------
//
//	Delete
//
//	Function: delete all occurences of a
//            substring into a string
//
//	Call: Delete(string,search)
//
//	Arguments:
//		string  = characters string
//		search  = substring to delete
//
//	Return: result string after deletion
//
//------------------------------------------

FUNCTION Delete(string,search)
	LOCAL workstr str1 str2 pos size
	workstr = string
	pos = 1
	size = LEN(search)
	
	WHILE ((pos = FindString(workstr,search,1)) > 0)
		IF ((pos != 1) && ((pos+size) < LEN(workstr)))
			str1 = CUT(workstr,1,pos-1)
			str2 = CUT(workstr,pos+size,LEN(workstr))
			workstr = str1""str2
		ELSE
			IF (pos == 1)
				IF ((size+1) < LEN(workstr))
					workstr = CUT(workstr,size+1,LEN(workstr))
				ELSE
					workstr = ""
				END
			ELSE
				workstr = CUT(workstr,1,pos-1)
			END
		END
	END
	RETURN workstr
END
//}}}}

//{{{ Replace(string,search,repl)
//------------------------------------------
//
//	Replace
//
//	Function: replace each occurence of a
//            substring into a string with
//            another string
//
//	Call: Replace(string,search,repl)
//
//	Arguments:
//		string  = characters string
//		search  = substring to look for
//		repl    = replacement substring
//
//	Return: result string after replacement
//
//------------------------------------------

FUNCTION Replace(string,search,repl)
	LOCAL pos workstr str1 str2 size
	pos = 1
	workstr = string
	size = LEN(search)
	
	WHILE ((pos = FindString(workstr,search,pos)) > 0)
		IF (pos == 1)
			str1 = CUT(workstr,size+1,LEN(workstr))
			workstr = repl""str1
			pos = 0
		ELSE
			str1 = CUT(workstr,1,pos-1)
			IF ((pos+size) < LEN(workstr))
				str2 = CUT(workstr,pos+size,LEN(workstr))
				workstr = str1""repl""str2
			ELSE
				workstr = str1""repl
			END
		END
		pos = pos+LEN(repl)
	END
	RETURN workstr
END
//}}}

//{{{ NewParse(string,divider)
//------------------------------------------
//
//	NewParse
//
//	Function: cut a string into several parts and
//            store each part into a variable.
//            The string is cut before each
//            occurence of a specified character.
//
//	Call: NewParse(string,divider)
//
//	Arguments:
//		string  = characters string
//		divider = character used as a separator
//                between each part of the string
//
//	Return: number of variables created.
//          This function create global variables
//			named var(1), var(2)...var(N), where
//          N is the value returned by the function.
//
//  Note: if the string contained two or more
//        successive separators, no variable is
//        created for these parts of the string.
//        For example, if you call the NewParse
//        function for "First;;Second" with
//        divider=";", only two variables are
//        created (var(1)="First" and
//        var(2)="Second").
//
//------------------------------------------

FUNCTION NewParse(string,divider)
	LOCAL pos i workstr size
	i = 0
	pos = 1
	workstr = string
	
	IF ((CMP(workstr,"") == 0) && (CMP(divider,"") == 0) && (CMP(workstr,divider) == 0))
		WHILE ((pos = Find(workstr,divider,1)) > 0)
			IF ((pos != 1) && (pos != LEN(workstr)))
				i = i+1
				var(i) = CUT(workstr,1,pos-1)
				workstr = CUT(workstr,pos+1,LEN(workstr))
			ELSE
				IF (pos == 1)
					IF (pos != LEN(workstr))
						workstr = CUT(workstr,2,LEN(workstr))
					ELSE
						workstr = ""
					END
				ELSE
					workstr = CUT(workstr,pos,LEN(workstr))
				END
			END
		END
		if (CMP(workstr,0) == 0)
			i = i+1
			var(i) = workstr
		END
	END
	RETURN i
END
//}}}}

//{{{ FileRequester(title,path,file,pattern)
//------------------------------------------
//
//	FileRequester
//
//	Function: open a file requester
//
//	Call: FileRequester(title,path,file,pattern)
//
//	Arguments:
//		title   = requester title
//		path    = default directory
//      file    = default filename
//      pattern = default pattern
//
//	Return: 0 if user clicks on Cancel
//          1 if user chooses a file. This
//          function creates three global
//          variables: pathname (path
//          to choosen file), filename
//          (name of choosen file without
//          extension) and extension
//          (extension of choosen file)
//
//------------------------------------------

FUNCTION FileRequester(title,path,file,pattern)
	LOCAL fullname point slash size titre
	
	pathname = ""
	filename = ""
	extension = ""
	
	IF (CMP(pattern,0) == 1)
		titre = "|"
	ELSE
		titre = "|"pattern
	END
	IF (CMP(file,0) == 1)
		titre = "|"titre
	ELSE
		titre = "|"file""titre
	END
	IF (CMP(path,0) == 1)
		titre = "|"titre
	ELSE
		titre = "|"path""titre
	END
	IF (CMP(title,0) == 1)
		titre = "Choose a file"titre
	ELSE
		titre = title""titre
	END

	tv_ReqFile titre
	fullname = Result
	size = LEN(fullname)
	
	IF (CMP(fullname,"Cancel") == 1)
		RETURN 0
	ELSE
		IF ((point = LastPos(fullname,".")) != 0)
			extension = CUT(fullname,point+1,size)
			size = point-1
			fullname = CUT(fullname,1,size)
		END
		IF ((slash = LastPos(fullname,"\")) != 0)
			filename = CUT(fullname,slash+1,size)
			size = slash-1
			pathname = CUT(fullname,1,size)
		END
		RETURN 1
	END
END
//}}}
//}}}

//{{{ MADS JUUL PROCEDURES

//{{{{TVP

//{{{ tvp_canWrite()
//Check if the TVpaint can read and write the file system else you have to restart TVP
//RETURNS : Boolean 
//DEPENDS : project_getPath()
FUNCTION tvp_canWrite()
	LOCAL projectpath rest project canWrite
	projectpath =  project_getPath()
	tv_writetextfile "Exists" projectpath
	IF CMP(result,"Forbidden")==1
		canWrite = 0
	ELSE
		canWrite = 1
	END
	result = canWrite
	RETURN result
END
//}}}}

//{{{ tvp_getSlash()
//Returns the path seperater of the OS
//RETURN : "/" or "\"
FUNCTION tvp_getSlash()
	LOCAL mySlash

	tv_version "ComputerOS"

	IF CMP(result,"WIN32")==1 || CMP(result,"WIN64")==1 
		mySlash = "\"
	ELSE
		mySlash = "/"
	END
	result = mySlash
	RETURN result
END
//}}}}

//}}}}

//{{{{PROJECT

//{{{ project_getPath()
//Returns complete path of current project
FUNCTION project_getPath()
       LOCAL rest
	tv_ProjectInfo 0
	PARSE result result rest
	RETURN result
END
//}}}}

//{{{ project_isSaved()
//Returns a Boolean to tell if current Project is saved or not
//DEPEND on project_getPath()
FUNCTION project_isSaved()
	LOCAL projectpath exists slash myResult
	projectpath =  project_getPath()
	tv_writetextfile "Exists" projectpath
	exists = projectpath 
	slash = tvp_getSlash()
	IF CMP(exists,projectpath)!=1||CMP(exists,slash )
		myResult = 0
	ELSE
		myResult = 1
	END
	result = myResult 
	RETURN result
END
//}}}}

//{{{  project_getParent()
FUNCTION project_getParent()
	project_getPath()
	file_getParent(result)
	RETURN result
END
//}}}}

//{{{ project_getName()
FUNCTION project_getName()
	project_getPath()
	file_getName(result)
	RETURN result
END
//}}}}

//{{{ project_getBaseName()
FUNCTION project_getBaseName()
	LOCAL projectName strlen last projectbase
	projectName = project_getName()
	IF CMP(projectName,"-1")==1
		result = -1
	ELSE
		strlen = LEN(projectname)
		last = LastPos(projectname,".")
		IF CMP(last,"0")==1
			projectbase = projectname
		ELSE
			projectbase = LeftString(projectname,last-1)
		END
		result = projectbase
	END
	RETURN result
END
//}}}}

//{{{ project_getBound()
FUNCTION project_getBound()
	LOCAL x2 y2
	tv_getWidth
	x2= result
	x2=x2-1
	tv_getHeight 
	y2 = result
	y2=y2-1
	result = "0 0 "x2" "y2
	RETURN result
END
//}}}}

//{{{ project_getAspect()
FUNCTION project_getAspect()
	LOCAL height width aspect
	myResult = -1
	tv_GetHeight
	height = result
	tv_GetWidth
	width = result
	
	aspect = width/height
	myResult = aspect
END
//}}}}

//{{{ project_incrementalSave(divider,part,ask,minimumDigitLength)
//Saves an Incremental file of current TVPP project in the same folder as the currentProject.
//Find the Part of the current file name with the "divider" and the "part" variabled passed to the function

//lets say we have a file called thefox_Q002_S002_v02.tvpp
//And we want to increment the "v02" part. We would calle the function like this
//project_incrementalSave("_",4,1)
FUNCTION project_incrementalSave(divider,part,ask,minimumDigitLength)
	LOCAL name slash dir newName myReturn
	//CHANGELOG
	//2014-11-11 project name can start with a number like "0001_v01.tvpp" without the leading zeros disappear when saving
	project_isSaved()
	IF CMP(result,"1")1==1
		name = project_getName()
		slash = tvp_getSlash()
		name="/"name
		dir = project_getParent()
		string_incrementalPart(name,divider,part,minimumDigitLength)
		newName = dir""result
		IF CMP(ask,"1")==1
			tv_Request "Increment and save : "newName" |Save|CANCEL"
			IF result
				tv_SaveProject newName
			END
		ELSE
			tv_SaveProject newName
		END
		myReturn = newName
	ELSE
		myReturn = 0
	END
	
	result = myReturn
	RETURN result
END
//}}}}

//}}}}

//{{{{STRING

//{{{ string_addZeros(prefix,string,length)
FUNCTION string_addZeros(prefix,string,length)
	LOCAL stringPrefix digit stringPostfix cur i
	// CHANGELOG
	//2014-11-11 Second parameter can be a string instead of an integer with letters before and after string
	stringPrefix = string_getPrefix(string)
	digit = string_getDigit(string)
	PARSE digit digit rest
	stringPostfix = string_getPostfix(string)
	prefix=prefix""stringPrefix
	length=length*1
	digit=digit*1
	cur = LEN(digit)
	length=length-1
	FOR i=cur TO length
		prefix=prefix"0"
	END
	result = prefix""digit""stringPostfix
	RETURN result
END
//}}}}

//{{{ char_isDigit(char)
FUNCTION char_isDigit(char)
	LOCAL myResult
	myResult = 0
	IF CMP('"0"',char)==1
		myResult = 1
	END
	IF CMP('"1"',char)==1
		myResult = 1
	END
	IF CMP('"2"',char)==1
		myResult = 1
	END
	IF CMP('"3"',char)==1
		myResult = 1
	END
	IF CMP('"4"',char)==1
		myResult = 1
	END
	IF CMP('"5"',char)==1
		myResult = 1
	END
	IF CMP('"6"',char)==1
		myResult = 1
	END
	IF CMP('"7"',char)==1
		myResult = 1
	END
	IF CMP('"8"',char)==1
		myResult = 1
	END
	IF CMP('"9"',char)==1
		myResult = 1
	END
	IF CMP('" "',char)==1
		myResult = 0
	END
	result = myResult
	RETURN result
END
//}}}}

//{{{ string_getPrefix(string)
FUNCTION string_getPrefix(string)
	LOCAL myLen pos prefix all loop cur test
	myLen = LEN(string)
	pos = 1
	myResult=""
	loop=1
	WHILE pos<=myLen && loop ==1
		cur = CHAR(string,pos)
		test = '"'cur'"'
		char_isDigit(test)
		IF result==1
			loop=0
		ELSE
			 myResult=myResult""cur
		END
		pos=pos+1
	END
	RETURN myResult
END
//}}}}

//{{{ string_getDigit(string)
FUNCTION string_getDigit(string)
	LOCAL myLen pos number loop cur test length
	myLen = LEN(string)
	pos = 1
	number="0"
	loop=1
	length=0
	WHILE pos<=myLen && loop ==1
		cur = CHAR(string,pos)
		test = '"'cur'"'
		char_isDigit(test)
		IF result==1
			number=number""cur
			length=length+1
		ELSE
			IF length>0
				loop=0
			END
		END
		pos=pos+1
	END
	result = number" "length
	RETURN result
END
//}}}}

//{{{ string_getPostfix(string)
FUNCTION string_getPostfix(string)
	LOCAL myLen pos part cur test
	myLen = LEN(string)
	pos = 1
	myResult=""
	part=0
	WHILE pos<=myLen
		cur = CHAR(string,pos)
		test = '"'cur'"'
		char_isDigit(test)
		IF result==1
			IF part==0
				part=1
			END
		ELSE
			IF part==1
				part=2
			END
		END
		IF part==2
			 myResult=myResult""cur
		END
		pos=pos+1
	END

	RETURN myResult
END
//}}}}

//{{{ string_increment(divider,string,minimumDigitLength)
FUNCTION string_increment(divider,string,minimumDigitLength)
	LOCAL prefix  digit length postfix
	prefix = string_getPrefix(string)
	prefix = divider""prefix 
	string_getDigit(string)
	PARSE result digit length
	digit=digit*1
	digit=digit+1
	IF length<minimumDigitLength
		length=minimumDigitLength
	END
	postfix = string_getPostfix(string)
	string_addZeros(prefix,digit,length)
	result = result""postfix
	RETURN result
END
//}}}}

//{{{ string_incrementalPart(string,divider,part,minimumDigitLength)
FUNCTION string_incrementalPart(string,divider,part,minimumDigitLength)
	LOCAL length myPart increment all i 
	length = newPARSE(string,divider)
	myPart = var(part)
	string_increment(divider,myPart,minimumDigitLength)
	increment = result
	all=""
	FOR i=1 TO length
		iF i==part
			all=all""increment
		ELSE
			myPart=var(i)
			IF i==1
				all=all""myPart
			ELSE
				all=all""divider""myPart
			END
		END
	END
	result=all
	RETURN result
END
//}}}}

//}}}}

//{{{{FILES

//{{{ file_getExt(path)
FUNCTION file_getExt(path)
	newParse(path,".")
	result = var(2)
	RETURN result
END
//}}}}

//{{{ file_getParent(path)
FUNCTION file_getParent(path)
	LOCAL strlen last 
	path = Replace(path,'\','/')
	strlen = LEN(path)
	last = LastPos(path,"/")
	path = LeftString(path,last-1)
	IF CMP(last,strlen)==1
		strlen = LEN(path)
		last = LastPos(path,"/")
		path = LeftString(path,last-1)
	END
	result = path
	RETURN result
END
//}}}}

//{{{ file_exists(path)
FUNCTION file_exists(path)
	LOCAL exists
	IF CMP(path,"0")==1
		exists = 0
	ELSE
		tv_WriteTextFile "Exists" path
		exists=result
		if CMP(exists,path)==1
			exists = 1
		ELSE
			exists = 0
		END
	END
	result = exists
	RETURN result
END
//}}}}

//{{{ file_getName(path)
FUNCTION file_getName(path)
	LOCAL  fileName strlen last
	IF CMP(path,"/")==1 || CMP(path,"\")==1
		fileName = -1
	ELSE
		path = Replace(path,'\','/')
		strlen = LEN(path)
		last = LastPos(path,'/')
		fileName = RightString(path,strlen-last)
		
	END
	result = fileName
	RETURN result
END
//}}}}

//{{{ file_readTextFile(textFilePath)
FUNCTION file_readTextFile(textFilePath)
	LOCAL myReturn fileExists i line text
	myReturn = 0
	tv_WriteTextFile "Exists" textFilePath
	fileExists = result
	
	IF CMP(fileExists,textFilePath)==1
		loop = 1
		i=0
		WHILE loop==1
			tv_readtextfile  i textFilePath
			PARSE result line text
			
			IF CMP( line, "EOF"  ) == 1
				loop=0
			ELSE
			
			
				length = LEN(text)
				length=length-2
				text = CUT(text,1,length)
				IF i==0
					myReturn=text
				ELSE
					myReturn=myReturn"\n"text
				END
		
			END
			i=i+1
	
		END
	END
	result= myReturn
	RETURN result
END
//}}}}

//}}}}

//}}}}
Thierry wrote: 31 Mar 2021, 12:32Also, if you could post a screenshot of the error message you're getting it would be great :)
I am still on TVP 10, but according to Joost there is no error at all.
Thierry wrote: 31 Mar 2021, 12:32 From what I've seen so far, it seems you're missing the two Blending Modes we've added in v11: Overlay2 (in v11.0.3), and Alpha Diff in (v11.0.9). This might affect the loop at line 78 (FOR i = 2 TO 27).
Oh nice, that makes sense. I'll include those and see if that fixes this script. Thanks!

The other button that Joost uses a lot is based on Svengali's FigureFill script (with some added pre-/post-actions) that no longer works: viewtopic.php?f=11&t=5690&hilit=figure+fill&start=45
  • Lukas Sketch Panel
  • TVPaint Pro 11.7.3
  • MacBook Pro 2018 macOS Ventura 13.4.1 + PC Windows 10
  • Wacom Cintiq 27QHD + Wacom Intuos4
  • YouTube.com/@ClubBaboo
  • YouTube.com/@FrameOrder
User avatar
D.T. Nethery
Posts: 4225
Joined: 27 Sep 2006, 19:19

Re: Some TVP 10 scripts don't work in TVP 11

Post by D.T. Nethery »

Lukas wrote: 01 Apr 2021, 09:19 The other button that Joost uses a lot is based on Svengali's FigureFill script (with some added pre-/post-actions) that no longer works: viewtopic.php?f=11&t=5690&hilit=figure+fill&start=45
Switching to TVPaint 11 should make the FigureFill script unnecessary . The function is built-in to TVPaint 11. Of course, the added pre-/post- actions may be what he still wants to use ?

Svengali's own advice regarding his FigureFill script:
Svengali wrote: 12 Oct 2015, 01:48
Changes in TVPaint 11 have made FigureFill obsolete.

Instead, choose Filled-Stroke and make sure to check the box labeled FILL INSIDE. Then simply circle the shapes you want to have filled with the APen color. It's much easier to use and much more sophisticated a solution for individual shape filling.

Sven

Image

Animator, TVPaint Beta-Tester, Animation Educator and Consultant.
MacOS 12.7.1 Monterey , Mac Mini (2018) , 3.2 GHz 6-Core Intel Core i7,
16 GB RAM , TVPaint PRO 11.7.1 - 64bit , Wacom Cintiq 21UX 2nd Gen.
,Wacom Intuos Pro 5 , Wacom driver version 6.3.39-1
User avatar
Lukas
Posts: 526
Joined: 14 Jan 2011, 11:15
Contact:

Re: Some TVP 10 scripts don't work in TVP 11

Post by Lukas »

Thanks D.T. Nethery 🙂

The pre-/post- behaviour was simply putting a color layer below the current line-art layer with the same length etc and fill the line art on that new layer on all frames with 1 color with the 'above' function while excluding foreground items. If there's a way to do that with the new system, that's fine too!

Joost tried the new way, but mentioned it was more work and had worse results. Hopefully the results can simply be improved by adjusting the tool settings. Maybe he can share a screenshot of the issue.
  • Lukas Sketch Panel
  • TVPaint Pro 11.7.3
  • MacBook Pro 2018 macOS Ventura 13.4.1 + PC Windows 10
  • Wacom Cintiq 27QHD + Wacom Intuos4
  • YouTube.com/@ClubBaboo
  • YouTube.com/@FrameOrder
User avatar
Joost
Posts: 439
Joined: 24 Nov 2011, 13:16

Re: Some TVP 10 scripts don't work in TVP 11

Post by Joost »

This is one of the examples from the new tool. It sometimes draws outside of the line art. And some spaces are kept empty when I would like to have them filled.
With the previous tool from Lukas this never happened....

I will try to post more pictures about it.
Screenshot 2021-04-02 at 13.17.15.png
Screenshot 2021-04-02 at 13.17.15.png (29.1 KiB) Viewed 16931 times
Mac OS 13.4.1 , Mac Studio 2023, 32GB RAM, Wacom Cintiq 27 QHD (no touch), Wacom Driver 6.4.2-4.
TVP Pro 11.7.1
User avatar
Joost
Posts: 439
Joined: 24 Nov 2011, 13:16

Re: Some TVP 10 scripts don't work in TVP 11

Post by Joost »

This is an example from a gap within a drawing...(maybe it's not easy to see but its a pencil)
Attachments
Screenshot 2021-04-02 at 13.25.42.png
Screenshot 2021-04-02 at 13.25.42.png (33.47 KiB) Viewed 16931 times
Mac OS 13.4.1 , Mac Studio 2023, 32GB RAM, Wacom Cintiq 27 QHD (no touch), Wacom Driver 6.4.2-4.
TVP Pro 11.7.1
User avatar
Joost
Posts: 439
Joined: 24 Nov 2011, 13:16

Re: Some TVP 10 scripts don't work in TVP 11

Post by Joost »

And some more. All in one simple drawing.

I tried to tweak the numbers from the tool a bit, but the result wasn't much better...
Attachments
Screenshot 2021-04-02 at 13.32.00.png
Screenshot 2021-04-02 at 13.32.00.png (69.93 KiB) Viewed 16931 times
Mac OS 13.4.1 , Mac Studio 2023, 32GB RAM, Wacom Cintiq 27 QHD (no touch), Wacom Driver 6.4.2-4.
TVP Pro 11.7.1
User avatar
Peter Wassink
Posts: 4436
Joined: 17 Feb 2006, 15:38
Location: Amsterdam
Contact:

Re: Some TVP 10 scripts don't work in TVP 11

Post by Peter Wassink »

Hey Joost,
Those artifacts in your posts look like gap closer roundings, these usually appear in sharp corners.
Because you always have neatly closed shapes the Gap Closer value can be left at zero, which should minimize them.
Then the color Range can also be set pretty high because your lines are always nicely black.
And you could set an Expand on the fill, since you have quite thick lines you could safely set the expand to a value between 2 and 4.
Expand will result in the color filling
halfway under your lines, eliminating those little holes.
Peter Wassink - 2D animator
• PC: Win11/64 Pro - AMD Ryzen 9 5900X 12-Core - 64Gb RAM
• laptop: Win10/64 Pro - i7-4600@2.1 GHz - 16Gb RAM
User avatar
D.T. Nethery
Posts: 4225
Joined: 27 Sep 2006, 19:19

Re: Some TVP 10 scripts don't work in TVP 11

Post by D.T. Nethery »

I also wonder if instead of Fill Inside (filled stroke) adding fill colors using CTG method may suit your purposes better ? (in TVPaint 10 , you might know CTG as "LazyBrush") . CTG fills are fast and precise. (*UPDATE: see my post below responding to Svengali's new version of his FigFill script. Svengali's script is faster for filling a character with a single color. The reason I mentioned CTG for doing the color fills was because I saw that a few of your sample frames had more than one color. )

https://www.tvpaint.com/doc/tvp11/index ... l-concepts

https://www.youtube.com/watch?v=FDjQNvbgzmw



The downside of using CTG layers is if you need to share the file with people who do not have TVPaint 11 PRO (for example TVPaint 11 Standard or TVPaint 10 Pro/Standard) then CTG layers will be invisible to them if you share your .tvpp file with them. The workaround is to duplicate the project , convert all CTG layers to regular ANIM layers, then you can share it with someone using TVPaint 11 Standard or TVPaint 10 Pro or Standard and they will be able to see the color fill layers when they open the file.
Convert_CTG_to_ANIM_layer.png
Convert_CTG_to_ANIM_layer.png (71.82 KiB) Viewed 16915 times
Last edited by D.T. Nethery on 04 Apr 2021, 21:13, edited 1 time in total.

Animator, TVPaint Beta-Tester, Animation Educator and Consultant.
MacOS 12.7.1 Monterey , Mac Mini (2018) , 3.2 GHz 6-Core Intel Core i7,
16 GB RAM , TVPaint PRO 11.7.1 - 64bit , Wacom Cintiq 21UX 2nd Gen.
,Wacom Intuos Pro 5 , Wacom driver version 6.3.39-1
Svengali
Posts: 1571
Joined: 28 Dec 2006, 10:08

Re: Some TVP 10 scripts don't work in TVP 11

Post by Svengali »

This needs to be tested in 11.5, if someone has a few minutes. It seems to work for me in 11.0.10. 64bit.
Go to the line layer and press the New Fig Fill Button. The script is embedded.

NEW FIG FILL BUTTON
This New Fig Fill button is an update of the original FIG FILL button from years ago, but it specifically incorporates the adaption that Lukas posted back then. The updated features:
1. The color fill layer is automatically generated under the existing outline layer.
2. The color filled frames on the color layer are auto-generated beneath the Instances (head) frames of the line layer.
3. The entire color layer and frame-filling process (new fill layer and automatic instances with color) is immediately undo-able by pressing a single Ctrl-Z.

I have to say I was surprised anyone was still using this script from 2012, but I downloaded the Lukas version from the old thread to see what had been added, then updated the script to incorporate those tweaks in the new script I'm posting here.

sven
Attachments
New Fig Fill 2021.tvpx
(95.5 KiB) Downloaded 551 times
TVP Pro 11.0.10-64bit Win10 - 64GB ram -2TB HHD - 256GB SSD - Wacom Cintiq 16, driver 6.3.41-1
Android Tablet: rel. 11, Samsung Galaxy Note10.1 - 32GB with microSD 32GB
Android Tablet: rel. 11.5, Samsung Galaxy Tab S7plus - 128GB with microSD 64GB
User avatar
D.T. Nethery
Posts: 4225
Joined: 27 Sep 2006, 19:19

Re: Some TVP 10 scripts don't work in TVP 11

Post by D.T. Nethery »

Svengali wrote: 04 Apr 2021, 18:49 This needs to be tested in 11.5, if someone has a few minutes.
The script works great in 11.5.1 ! The script works much faster for filling a character with a single color that using CTG as I had suggested in a previous post.

Animator, TVPaint Beta-Tester, Animation Educator and Consultant.
MacOS 12.7.1 Monterey , Mac Mini (2018) , 3.2 GHz 6-Core Intel Core i7,
16 GB RAM , TVPaint PRO 11.7.1 - 64bit , Wacom Cintiq 21UX 2nd Gen.
,Wacom Intuos Pro 5 , Wacom driver version 6.3.39-1
Post Reply