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

A forum dedicated to George scripting questions
Svengali
Posts: 1571
Joined: 28 Dec 2006, 10:08

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

Post by Svengali »

Lucas,
In fact, the script IS working well, it just not doing what you want it to do in your new upgrade to TVPaint 11. For instance, assigning the fill layer to the same group as the line layer is your requirement, but not how I originally wrote the script. Likewise, the fill might not be working if the line layer doesn't start on frame one... but that is another one of your requirements, but not how I originally wrote the script... neither of these additional requirements were specifically mentioned earlier in the "bug report"...

The other thing that makes it hard to understand or resolve when an existing script reportedly doesn't "work well" anymore:
When a bunch of action line commands are added before and/or after the script in an attempt to crowbar the script into doing what is needed It can make fixing the script much more difficult...

At any rate, I think this new version fixes the two problems you mention:
1. the Kleur layer is automatically assigned to the same colorgroup assigned to the line layer...
2. the Kleur layer fills properly EVEN IF THE LINE LAYER STARTS ON A LATER FRAME...

test it and let me know if it works now. But be careful when adding more action line commands which might neutralize some part(s) of the new script, itself. :D

EDIT: further testing of this version... each time you run the script, ANOTHER KLEUR LAYER IS CREATED, is that what you wanted? The script can be modified to warn you when multiple copies of the same Kleur layer are being generated... if that's a problem or there is some other problem, let me know. Also, note that when created, each Kleur layer's pre/post behavior is automatically set to NONE. Is that OK?
Attachments
New Fig Fill 2021.tvpx
version .9 of the NewFigFill script.
(96.5 KiB) Downloaded 518 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
Joost
Posts: 439
Joined: 24 Nov 2011, 13:16

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

Post by Joost »

Hello Sven,

Thank you very much for helping us out!
The script is working much better now!

Let me explain our situation: I work at the same studio as Lukas. A couple of years ago Lukas came with this TVP action that did the following:
-It created a layer that was exactly the same as the line art layer (including post- and pre behaviour, label color and "repeat images". An exact copy of the layer. Then it turned off the visibility all other layers, it created a color frame (paint bucket) on every frame of the new layer, and then it erased (paint bucket- erase) everything outside the line art by picking a point in the upper left corner wit the "bucket erase" option. Or at least that is what I think it did.
This was an easy way to create a "ground-colour" layer of an animation layer. An important aspect about this action, is that all other layers visibility is turned off, otherwise the color will be affected by other line art layers above the layer I want to color.

The reason I like this method of colouring my animation is that the whole animation layer now has a color layer without any holes in it. You only have to remove some paint between the legs of a character, or small thing like that. With this layer it's very easy to color the rest of your animation.

I don't use this action just for one character, I use it for everything. Both animation and creating backgrounds, and small objects. I always have used this action in TVPaint 10 without any problems, and it also worked perfectly on the TVP11 windows computers out interns are working on. All other methods of colouring my animations where a to slower, and I really prefer this method. It suits my style of animation. But only when I started working on TVPaint 11.5.1 recently, the action suddenly didn't work anymore.

When Lukas came with this "action" years ago, I didn't know you, Sven, wrote the script for it. In the meanwhile I tweaked the action a little bit, just for my own preferences. Lately Lukas is not using TVPaint anymore since his version (TVP10) is not running on OS Big Sur. And I know nothing about scripting for TVPaint. I'm always asking Lukas for his help, but since he is working at home without TVPaint, it's hard for him to help me out. That's maybe why this conversation is a bit confusing. Sorry for that!

Do you understand the way I use this "action" in combination with your script now?
If I use your script, it's almost what I'm looking for. The only thin I'm missing" is the pre-post behaviour of a layer and "repeat images" within a layer. It would be nice to have an EXACT copy of the line art layer.

(And I had to add the commands: "Swap A/B colors", "Hide all layers, show current layer visibility",then "swap A\B colors" after your script ", to make sure only the layer I want to color is affected.)


Best,

Joost
Screenshot 2021-04-21 at 08.46.32.png
Screenshot 2021-04-21 at 08.46.32.png (31.69 KiB) Viewed 11233 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
Svengali
Posts: 1571
Joined: 28 Dec 2006, 10:08

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

Post by Svengali »

I'll look at it and see if I can visualize your workflow.

sven
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
Svengali
Posts: 1571
Joined: 28 Dec 2006, 10:08

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

Post by Svengali »

Joost,

This version should do everything you described:
1. Warns user as to the name of the layer currently to be used as the source line art layer so that the user can choose to continue or exit
2. Creates a matching color-fill layer beneath, with exactly the same parameters as the line art layer (same layer name, same pre & post behavior, same color-index group, duplicate instance-head frame images to match line art layer, An exact copy of the layer)
3. Hides the visibility of all other layers at start
4. On the new color layer, generates matching frames of filled shape(s) for each instance-head frame of outlined shape(s) on original layer
5. When complete, reselects first frame of line art layer (and makes first frame visible in timeline)
6. Turns on the visibility of all other hidden layers again at end

NOTE: the entire FigFill Process can be immediately undone with a single UNDO

test please and let me know if it works as expected...

sven

p.s. added another icon "Toggle Layers 3 ways" which lets you toggle-loop between:
1. all layers @100%
2. all layers @ 35% and current @ 100%
3. all layers @ 0% and current @ 100%.
might come in handy.
Attachments
New Fig Fill 2021 Updated.tvpx
(175.5 KiB) Downloaded 498 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
Joost
Posts: 439
Joined: 24 Nov 2011, 13:16

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

Post by Joost »

Wow, thank you so much!

If there is anything I can do to help you out, let me know. :)
(I doubt it because I'm really bad at scripting...)

I only have one request if possible:
I never rename any layer, so for me it's no problem if layer has the same name. So the warning popup is not necessary. It only slows me down.
Could this "warning popup" function be removed from the script?


Thanks!

Joost
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
Svengali
Posts: 1571
Joined: 28 Dec 2006, 10:08

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

Post by Svengali »

Joost wrote: 26 Apr 2021, 10:34 I only have one request if possible:
I never rename any layer, so for me it's no problem if layer has the same name. So the warning popup is not necessary. It only slows me down.
Could this "warning popup" function be removed from the script?
The layer name confirmation is there because the script can't know if you (or some other user of the script) are on correct layer for processing. If I take it out the results could be unpredictable so it was the easiest scripting solution. So see if you can live with that for now.

sven
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
Joost
Posts: 439
Joined: 24 Nov 2011, 13:16

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

Post by Joost »

Ah I see.

I can live with it :)


Thanks again!
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
NathanOtano
Posts: 1208
Joined: 01 Apr 2014, 07:07
Location: Biarritz, France
Contact:

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

Post by NathanOtano »

I'm searching for a script to export precise .psd files from tvpaint and sort them in an edl/xml file or any format readable by premiere to update editing
Is it something that exists?

Is this an xml exporter Lukas? :D
Lukas wrote: 01 Apr 2021, 09:19
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
Working on Windows 10
Creator of Disnosc, providing storyboard, animation and design for 2D realistic pictural animation: https://www.disnosc.fr/ - nathanotano@disnosc.fr
Highly interested in animation workflows, I'm open to scripting new TVP functions for individuals and studios.
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 »

NathanOtano wrote: 05 Aug 2021, 18:03Is this an xml exporter Lukas? :D
Sorry, only saw the quote-notification just now. Yes it is! It writes an XML file you can import into Premiere keeping TVPaint's timing intact (without rendering duplicate frames). It also labels each clip in alternating colors so you can easily define your shots in Premiere. I use it for storyboarding. It works with JPG and PNG. Do you want to use .PSD because of its layers? It can't handle that (My script can't, not sure about Premiere). As flat images it might work though, can't test it at the moment, because my TVPaint version doesn't work on my macOS version.
  • 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
NathanOtano
Posts: 1208
Joined: 01 Apr 2014, 07:07
Location: Biarritz, France
Contact:

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

Post by NathanOtano »

Awesome!
Well I managed two things with my last script, I export .psd files with structure and right naming and I have been able to write a .bridgesort file so I see the shots in a given order in bridge even if the naming isn't alphabetical (so I have clip IDs kind of). For now I havn't managed to write an xml succesfully and havn't been able to use your script as is, would you share a panel with it maybe and explain how to us it (withotu coding anything new, I can modify myself if needed)? I am really interested in it

Py own script is shared in my ONTANO storyboard tools if you're curious (not the last version yet but still!)
Best,
Working on Windows 10
Creator of Disnosc, providing storyboard, animation and design for 2D realistic pictural animation: https://www.disnosc.fr/ - nathanotano@disnosc.fr
Highly interested in animation workflows, I'm open to scripting new TVP functions for individuals and studios.
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 »

NathanOtano wrote: 30 Sep 2021, 14:31 [...] For now I havn't managed to write an xml succesfully and havn't been able to use your script as is, would you share a panel with it maybe and explain how to us it (withotu coding anything new, I can modify myself if needed)? I am really interested in it [...]
I'm going to update my XML export (to import in Adobe Premiere) to work with the latest TVPaint and will share it when it's done :)
  • 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
NathanOtano
Posts: 1208
Joined: 01 Apr 2014, 07:07
Location: Biarritz, France
Contact:

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

Post by NathanOtano »

Awesome :)
Working on Windows 10
Creator of Disnosc, providing storyboard, animation and design for 2D realistic pictural animation: https://www.disnosc.fr/ - nathanotano@disnosc.fr
Highly interested in animation workflows, I'm open to scripting new TVP functions for individuals and studios.
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 »

Lukas wrote: 10 Jan 2022, 15:24I'm going to update my XML export (to import in Adobe Premiere) to work with the latest TVPaint and will share it when it's done :)
A very belated update, but the export to XML (to be imported in Adobe Premiere) scripts have been working for me so far on TVP 11 Pro / MacOs. (Not sure about standard TVP and Windows).

There's 2 XML buttons in Lukas Sketch Panel v2.1
  • 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
NathanOtano
Posts: 1208
Joined: 01 Apr 2014, 07:07
Location: Biarritz, France
Contact:

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

Post by NathanOtano »

Thank you for sharing it :)
Working on Windows 10
Creator of Disnosc, providing storyboard, animation and design for 2D realistic pictural animation: https://www.disnosc.fr/ - nathanotano@disnosc.fr
Highly interested in animation workflows, I'm open to scripting new TVP functions for individuals and studios.
Post Reply