Carny_Priest Posted June 27, 2015 Share Posted June 27, 2015 Hi, following up on this thread, http://www.gameex.info/forums/topic/15882-visual-pinball-mini-dmd-screen-3-b2s-for-apron/ , I've added a new feature: a flash viewer that displays instruction and score cards associated with the table. Requires ffmpeg and Adobe flashplayer http://ffmpeg.zeranoe.com/builds/ https://get.adobe.com/flashplayer/ As a demo, here's a crappy phone video https://www.dropbox.com/s/nrgpig9azh1b28b/afm.MOV?dl=0 This is a kludgy solution requiring multiple scripts, but it supports swf and png formats (same as PBX) including animated instruction cards. The downside is that all of the instruction card media that is available on the FTP or at VPForums are oriented for viewing on the BG screen which is usually configured for landscape. VP Cabinet tables are rotated in the program to be viewed in portrait but the screen back buffer is still oriented in landscape. This means that the media that I want to display on the apron must also be rotated. Sadly, I found a high percentage of the media could not be directly converted and rotated. So, I could not just simply convert files from the PBX Instruction Cards folder on-the-fly. I had to do screen caps and rotate the resulting images and store them in a folder prior to running the script. I have a batch script that will be included in this post. The output will need to be stored in a separate folder, and secondary score or price cards should be stored in a new folder named "Score Cards". By default I scale the images using the aspect ratio for Stern and latter day Williams/Bally as reference here: http://www.pinballrebel.com/pinball/cards/Card_sizes.htm It is possible to properly scale and display all the rotated images by manufacturer, but that might be a future update. Similar to the previous script, the correct media is displayed based on matching file names to entries in VisualPinball.xml. Matching images for the table are presented in a loop until VP is closed. I've attached a generic Instructions card and a Score card which I display at the beginning of the loop. In my collection, I have an instruction card for every table installed. So, between the generic card and the card associated with the table, I always expect that there will be multiple images to loop. Instruction cards are displayed on the left side of the apron. I don't have score or price cards for most tables, so the generic price card would be all that there is to loop. Rather than loop the same image, I have some code to check the number of files in the loop and if it is just 1 image then the program will not loop. Score cards are displayed on the right side of the apron. The script assumes the playfield aspect ratio is 1920x1080. If your screen is something different then the script must be tweaked to properly scale the images. I have not tested against all tables, but hopefully the images are not covering any play areas. The X,Y coordinates for displaying the images are user configurable. Consider where the instruction and score card images will be displayed, and leave room for the mini-DMD which will be automatically placed below the instruction and score card. The scaling of images is automated based on the the width of DMD defined in the VPM registry or in screenres.txt along with the Filter setting in the User Input section at the top of the script, so that the card images will be lined up directly over the mini-DMD. Card_Width is a failsafe setting in case there happens to be a table installed that does not use VPM and B2S is set to False in the xml. I haven't tested it. I'm not sure I have that situation in my install. The amount of time each images will be displayed before looping to the next is also user configurable at the top of the script. This is definitely for advanced users. This requires a custom xml as explained in the thread for the previous script. I may also be using different VP executables, so the script may require tweaking to fit another install. Spoiler #NoEnv #SingleInstance force ; http://www.gameex.info/forums/topic/14632-multiple-exe-for-vp/#entry137471 - Thanks horseyhorsey #Include, %A_ScriptDir%\xpath.ahk SetTitleMatchMode, 2 DetectHiddenWindows, On ; USER INPUTS PinballX_Path=c:\PinballX FFMPEG_Path=c:\ffmpeg\bin CARD_Path=%A_ScriptDir%\Instruction Cards SCORE_Path=%A_ScriptDir%\Score Cards Nudge991=300 NudgePM=75 Filter="scale=iw*(1/3):-1,transpose=3" Mirror1PosX=1675 Mirror1PosY=767 Mirror2PosX=1675 Mirror2PosY=127 CardWidth=768 DisplayCardTime=15000 ; array code adapted from Gilrock - http://www.gameex.info/forums/topic/15083-improved-pinball-fx2-script Thanks ; roms for lowest latency but possibly with artifacts arrayf:=["mb_106b", "tz_92", "taf_l7", "frankst"] ; *********************************************** Table=%1% ;Table filename SplitPath, Table,,,, XTable, ; Read description tag from xml - Thanks horseyhorsey - http://www.gameex.info/forums/topic/14632-multiple-exe-for-vp/#entry129111 databaseFile=%PinballX_Path%\Databases\Visual Pinball\Visual Pinball.xml xpath_load(dbXML, databaseFile ) ; need to read the existing xml otherwise xpath deletes all existing nodes exe:= XPath(dbXML, "/menu/game[@name= . XTable . ]/exe/text()") rom:= XPath(dbXML, "/menu/game[@name= . XTable . ]/rom/text()") B2S:= XPath(dbXML, "/menu/game[@name= . XTable . ]/B2S/text()") description:= XPath(dbXML, "/menu/game[@name= . XTable . ]/description/text()") If exe=vpinball-9.9.1-plunger-mods { RegWrite, REG_DWORD,HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainY, %Nudge991% RegWrite, REG_DWORD,HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainX, %Nudge991% } If exe=VP_physmod2 { RegWrite, REG_DWORD, HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainY, %NudgePM% RegWrite, REG_DWORD, HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainX, %NudgePM% } IniRead, TablePath, %PinballX_Path%\Config\PinballX.ini, VisualPinball, TablePath StringReplace, XTablePath, TablePath, \Tables RegRead, XDMD_width, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_width RegRead, XDMD_height, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_height RegRead, DMD_X, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_pos_x RegRead, XDMD_Y, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_pos_y DMD_width:=XDMD_width-3 DMD_height:=XDMD_height+3 DMD_Y:=XDMD_Y-2 ; Hardcode If rom=simpprty { DMD_width:=768 DMD_height:=300 DMD_X:=3840 DMD_Y:=123 } If rom=ripleys { DMD_width:=768 DMD_height:=300 DMD_X:=3840 DMD_Y:=123 } If rom=wpt_140a { DMD_width:=768 DMD_height:=300 DMD_X:=3840 DMD_Y:=123 } If rom=taf_l7 { DMD_width:=768 DMD_height:=244 DMD_X:=3840 DMD_Y:=198 } If B2S=True { FileReadLine, BG_width, %TablePath%\ScreenRes.txt, 3 FileReadLine, DMD_width, %TablePath%\ScreenRes.txt, 8 FileReadLine, XDMD_height, %TablePath%\ScreenRes.txt, 9 FileReadLine, XDMD_X, %TablePath%\ScreenRes.txt, 10 FileReadLine, XDMD_Y, %TablePath%\ScreenRes.txt, 11 DMD_height:=XDMD_height+6 DMD_X:=BG_width+XDMD_X ;Reference to Top Left of Playfield screen DMD_Y:=XDMD_Y-2 } ; Have the information we need to run Card splash screens Run, %A_ScriptDir%\DisplayCard1.exe "%CARD_Path%" "%Filter%" %Mirror1PosX% %Mirror1PosY% %Mirror2PosX% %Mirror2PosY% "%description%" "%XTable%" %DMD_width% %CardWidth% %DisplayCardTime% Run, %A_ScriptDir%\DisplayCard2.exe "%SCORE_Path%" "%Filter%" %Mirror1PosX% %Mirror1PosY% %Mirror2PosX% %Mirror2PosY% "%description%" "%XTable%" %DMD_width% %CardWidth% %DisplayCardTime% StringGetPos, pos, Filter, ) Scale:=SubStr(Filter, 12, pos-11) StringGetPos, pos1, Scale, / If ErrorLevel=0 { Num:=SubStr(Scale, 1, pos1) Denom:=SubStr(Scale, pos1+2) Num1:=Num Denom1:=Denom Scale:=Num1/Denom1 } ; DMD/B2S border BOX1_width:=Floor(DMD_width*Scale+23*2) BOX1_height:=Floor(DMD_height*Scale+4*2) BOX2_width:=BOX1_width-21 BOX2_height:=BOX1_height-4 ; Card border - want to retain the same width and scale the height to preserve the aspect ratio ; a common size is 700px x 382px http://www.pinballrebel.com/pinball/cards/Card_sizes.htm If DMD_width>0 CARD1_height:=Floor(DMD_width*Scale*382/700+4*2) Else CARD1_height:=Floor(CardWidth*Scale*382/700+4*2) ; Position DMD/B2S adjacent to Card border Mirror3PosX:=Mirror1PosX+Card1_height Mirror4PosX:=Mirror2PosX+Card1_height ; *********************************************** ; Disable Aero if Enabled RegRead, DWMComp, HKCU, Software\Microsoft\Windows\DWM, Composition Aero=%DWMComp% If Aero=1 Run, sc stop uxsms ;Run, dc2.exe -configure="%A_ScriptDir%\dc2config\VPMSettings.xml" ; Mirror and flip DMD for apron If DMD_width>0 { Loop % arrayf.MaxIndex() { l_table = % arrayf[A_Index] if( "X" l_table = "X" rom ) { streamx264=1 break } } If streamx264=1 { Run, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v libx264 -preset ultrafast -tune zerolatency -qp 0 -f mpegts -threads 8 udp://localhost:1234,, Hide Run, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v libx264 -preset ultrafast -tune zerolatency -qp 0 -f mpegts -threads 8 udp://localhost:5678,, Hide } Else { Run, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v mpeg4 -qscale:v 1 -f mpegts -threads 8 udp://localhost:1234,, Hide Run, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v mpeg4 -qscale:v 1 -f mpegts -threads 8 udp://localhost:5678,, Hide } Sleep, 1000 Run, %FFMPEG_Path%\ffplay -an -sn -i -fflags nobuffer udp://localhost:1234?listen,, Hide Run, %FFMPEG_Path%\ffplay -an -sn -i -fflags nobuffer udp://localhost:5678?listen,, Hide Loop, 2 { checkwindowagain1: IfWinExist, udp://localhost:1234?listen WinMove, udp://localhost:1234?listen,, %Mirror3PosX%, %Mirror1PosY% Else Goto, checkwindowagain1 } Loop, 2 { checkwindowagain2: IfWinExist, udp://localhost:5678?listen WinMove, udp://localhost:5678?listen,, %Mirror4PosX%, %Mirror2PosY% Else Goto, checkwindowagain2 } } Run, %XTablePath%\%exe%.exe -play "%TablePath%\%Table%" WinWaitActive, ahk_class VPPlayer Sleep, 1000 WinSet, AlwaysOnTop,, udp://localhost:1234?listen WinSet, AlwaysOnTop,, udp://localhost:5678?listen If DMD_width>0 { ; draw a black border to hide the window borders for the mirror Gui, 1: +LastFound +AlwaysOnTop -Caption +ToolWindow Gui, 1: Color, 000000 WinSet, Region, 0-0 %BOX1_height%-0 %BOX1_height%-%BOX1_width% 0-%BOX1_width% 0-0 4-24 %BOX2_height%-24 %BOX2_height%-%BOX2_width% 4-%BOX2_width% 4-24 Gui, 1: Show, W%BOX1_height% H%BOX1_width% X%Mirror3PosX% Y%Mirror1PosY% NoActivate Gui, 2: +LastFound +AlwaysOnTop -Caption +ToolWindow Gui, 2: Color, 000000 WinSet, Region, 0-0 %BOX1_height%-0 %BOX1_height%-%BOX1_width% 0-%BOX1_width% 0-0 4-24 %BOX2_height%-24 %BOX2_height%-%BOX2_width% 4-%BOX2_width% 4-24 Gui, 2: Show, W%BOX1_height% H%BOX1_width% X%Mirror4PosX% Y%Mirror2PosY% NoActivate } ; *********************************************** checkVPPlayer: IfWinNotExist, Visual Pinball { Run, taskkill /IM ffplay.exe Run, taskkill /IM ffmpeg.exe /F If DMD_width>0 { Gui, 1: Destroy Gui, 2: Destroy } Process, Close, DisplayCard1.exe Process, Close, DisplayCard2.exe ;Run, dc2.exe -configure="%A_ScriptDir%\dc2config\4KSettings.xml" ; Enable Aero if Enabled at the start of script execution If Aero=1 Run, sc start uxsms } else { Sleep, 1000 Goto, checkVPPlayer } ExitApp ; *********************************************** ; CloseVP from FPLaunch CloseVP: ;toLog("CloseVP Called") ;Hotkey, %exitScriptKey%, Off GoSub rosveClose ;GoSub bigbossClose ; change loops completely, put all data in xml !!! too slow ;Visual Pinball must be closed this way instead of killing process ;or it wil not save your last game information.i.e score/credtis ;DetectHiddenWindows on ;Or next line will not work ;Loop, 4 ;Gui, %A_Index%: Destroy ;This line fixes where the VP Window flashes real quick ;when closing the window for a cleaner exit ; win hide removed cause vp should be minimized, not hidden ;WinHide, ahk_class VPinball ;WinShow, ahk_class VPinball WinMinimize, ahk_class VPinball WinClose, ahk_class VPinball WinWaitClose ahk_class VPinball ; bigbossclose won't get executed cause main thread will exit ;GoSub bigbossClose ; there's no need for exitscript cause main thread will do it ;Goto ExitScript return rosveClose: ;toLog("rosveClose Called") ; rosve ; -------------------------------------------------------------- ; --- Close the animated backglass ----------------------- ; -------------------------------------------------------------- ; b2s close bug fix StringRight, ending, XTable, 3 if (ending = "B2S") { WinKill, Form1 } return ; *********************************************** #IfWinActive ahk_class VPPlayer ; Interlock Switch Joy7:: Send {End} SetTimer, WaitForJoy7, 10 Return WaitForJoy7: if GetKeyState("Joy7") return Send {End} SetTimer, WaitForJoy7, off Return ; Exit Table Joy8:: Gosub CloseVP Return #IfWinActive This is a secondary script for looping instruction cards. It must be compiled and named DisplayCard1.exe Spoiler #NoEnv #SingleInstance force SetTitleMatchMode, 2 DetectHiddenWindows, On CARD_Path=%1% Filter=%2% Mirror1PosX=%3% Mirror1PosY=%4% Mirror2PosX=%5% Mirror2PosY=%6% description=%7% XTable=%8% DMD_width=%9% CardWidth=%10% DisplayCardTime=%11% IfExist, %CARD_Path%\%description%* cardmatch:=1 IfExist, %CARD_Path%\%XTable%* cardmatch:=1 If cardmatch=1 { StringGetPos, pos, Filter, ) Scale:=SubStr(Filter, 11, pos-10) StringGetPos, pos1, Scale, / If ErrorLevel=0 { Num:=SubStr(Scale, 1, pos1) Denom:=SubStr(Scale, pos1+2) Num1:=Num Denom1:=Denom Scale:=Num1/Denom1 } ; Card border - want to retain the same width and scale the height to preserve the aspect ratio ; a common size is 700px x 382px http://www.pinballrebel.com/pinball/cards/Card_sizes.htm If !(DMD_width>0) DMD_width:=CardWidth CARD1_width:=Floor(DMD_width*Scale+23*2) CARD1_height:=Floor(DMD_width*Scale*382/700+4*2) CARD2_width:=CARD1_width-23 CARD2_height:=CARD1_height-4 GUI4W:=CARD2_width-23 GUI4H:=CARD2_height-4 GUI4X:=Mirror1PosX+4 GUI4Y:=Mirror1PosY+23 ; Show instruction cards ; http://www.autohotkey.com/board/topic/56987-com-object-reference-autohotkey-v11/page-13 Gui, 3: +LastFound -Caption +AlwaysOnTop -SysMenu GUI3_ID:=WinExist() Gui, 3: Color, 000000 WinSet, Region, 0-0 %CARD1_height%-0 %CARD1_height%-%CARD1_width% 0-%CARD1_width% 0-0 4-24 %CARD2_height%-24 %CARD2_height%-%CARD2_width% 4-%CARD2_width% 4-24 CardList1=%CARD_Path%\Instructions.png`n Loop, Files, %CARD_Path%\%description%* CardList1=%CardList1%%A_LoopFileFullPath%`n Loop, Files, %CARD_Path%\%XTable%* CardList1=%CardList1%%A_LoopFileFullPath%`n WinWaitActive, ahk_class VPPlayer Loop { Loop, Parse, CardList1, `n { If A_LoopField= ; Ignore the blank item. Continue getSwfFromDisk=%A_LoopField% GoSub DisplayCard } } } ExitApp ; *********************************************** DisplayCard: Gui, 4: +LastFound -Caption +AlwaysOnTop -SysMenu GUI4_ID:=WinExist() Gui, 4: Color, 000000 Gui, 3: Show, W%CARD1_height% H%CARD1_width% X%Mirror1PosX% Y%Mirror1PosY% NoActivate Hide Gui, 4: Show, W%GUI4H% H%GUI4W% X%GUI4X% Y%GUI4Y% NoActivate Hide Gui, 4: Margin, 0 ,0 DllCall("AnimateWindow","UInt",GUI3_ID,"Int",1,"UInt","0xa0000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",1000,"UInt","0xa0000") Gui, 4: Add, ActiveX, W%GUI4H% H%GUI4W% vpwb, ShockwaveFlash.ShockwaveFlash pwb.Movie := "file:///" . getSwfFromDisk pwb.Scale := "exactfit" Sleep, %DisplayCardTime% Control, Hide,, MacromediaFlashPlayerActiveX1, ahk_id %GUI2_ID% DllCall("AnimateWindow","UInt",GUI3_ID,"Int",750,"UInt","0x90000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",750,"UInt","0x90000") Gui, 4: Destroy Return This is a secondary script for looping score cards. It must be compiled and named DisplayCard2.exe Spoiler #NoEnv #SingleInstance force SetTitleMatchMode, 2 DetectHiddenWindows, On SCORE_Path=%1% Filter=%2% Mirror1PosX=%3% Mirror1PosY=%4% Mirror2PosX=%5% Mirror2PosY=%6% description=%7% XTable=%8% DMD_width=%9% CardWidth=%10% DisplayCardTime=%11% IfExist, %SCORE_Path%\%description%* cardmatch:=1 IfExist, %SCORE_Path%\%XTable%* cardmatch:=1 IfExist, %SCORE_Path%\Score.png cardmatch:=1 If cardmatch=1 { StringGetPos, pos, Filter, ) Scale:=SubStr(Filter, 11, pos-10) StringGetPos, pos1, Scale, / If ErrorLevel=0 { Num:=SubStr(Scale, 1, pos1) Denom:=SubStr(Scale, pos1+2) Num1:=Num Denom1:=Denom Scale:=Num1/Denom1 } ; Card border - want to retain the same width and scale the height to preserve the aspect ratio ; a common size is 700px x 382px http://www.pinballrebel.com/pinball/cards/Card_sizes.htm If !(DMD_width>0) DMD_width:=CardWidth CARD1_width:=Floor(DMD_width*Scale+23*2) CARD1_height:=Floor(DMD_width*Scale*382/700+4*2) CARD2_width:=CARD1_width-23 CARD2_height:=CARD1_height-4 GUI4W:=CARD2_width-23 GUI4H:=CARD2_height-4 GUI4X:=Mirror2PosX+4 GUI4Y:=Mirror2PosY+23 ; Show instruction cards ; http://www.autohotkey.com/board/topic/56987-com-object-reference-autohotkey-v11/page-13 Gui, 3: +LastFound -Caption +AlwaysOnTop -SysMenu GUI3_ID:=WinExist() Gui, 3: Color, 000000 WinSet, Region, 0-0 %CARD1_height%-0 %CARD1_height%-%CARD1_width% 0-%CARD1_width% 0-0 4-24 %CARD2_height%-24 %CARD2_height%-%CARD2_width% 4-%CARD2_width% 4-24 CardList1=%SCORE_Path%\Score.png`n Loop, Files, %SCORE_Path%\%description%* CardList1=%CardList1%%A_LoopFileFullPath%`n Loop, Files, %SCORE_Path%\%XTable%* CardList1=%CardList1%%A_LoopFileFullPath%`n CntFile=0 Loop, Parse, CardList1, `n { If A_LoopField= ; Ignore the blank item. Continue CntFile:=CntFile+1 } If CntFile=1 DisplayCardTime=2147483647 WinWaitActive, ahk_class VPPlayer Loop { Loop, Parse, CardList1, `n { If A_LoopField= ; Ignore the blank item. Continue getSwfFromDisk=%A_LoopField% GoSub DisplayCard } } } ExitApp ; *********************************************** DisplayCard: Gui, 4: +LastFound -Caption +AlwaysOnTop -SysMenu GUI4_ID:=WinExist() Gui, 4: Color, 000000 Gui, 3: Show, W%CARD1_height% H%CARD1_width% X%Mirror2PosX% Y%Mirror2PosY% NoActivate Hide Gui, 4: Show, W%GUI4H% H%GUI4W% X%GUI4X% Y%GUI4Y% NoActivate Hide Gui, 4: Margin, 0 ,0 DllCall("AnimateWindow","UInt",GUI3_ID,"Int",1,"UInt","0xa0000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",1000,"UInt","0xa0000") Gui, 4: Add, ActiveX, W%GUI4H% H%GUI4W% vpwb, ShockwaveFlash.ShockwaveFlash pwb.Movie := "file:///" . getSwfFromDisk pwb.Scale := "exactfit" Sleep, %DisplayCardTime% Control, Hide,, MacromediaFlashPlayerActiveX1, ahk_id %GUI2_ID% DllCall("AnimateWindow","UInt",GUI3_ID,"Int",750,"UInt","0x90000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",750,"UInt","0x90000") Gui, 4: Destroy Return And here is the ffmpeg batch converter for rotating instruction cards for use in the viewer. You define where the source images are and the script will convert and save the images in %A_ScriptDir%\rotate. arrayc is where you define any animated instruction cards. There are not many at all that I could find. STAT at VPF created the two I put into the array. When the script encounters these files during processing ffmpeg will make a 30 second capture, rotate, and save as an swf file. Spoiler #NoEnv #SingleInstance force ; USER INPUTS FFMPEG_Path=c:\ffmpeg\bin CARD_Path=c:\PinballX\Media\Instruction Cards ; array code adapted from Gilrock - http://www.gameex.info/forums/topic/15083-improved-pinball-fx2-script Thanks ; rotated animated instruction cards must be located in the same folder as this script/executable arrayc:=["Attack from Mars (Bally 1995) 3.swf", "Torpedo Alley (Data East 1988).swf"] CardList1= ; Initialize to be blank. Loop, Files, %CARD_Path%\*.* CardList1=%CardList1%%A_LoopFileFullPath%`n Loop, Parse, CardList1, `n { If A_LoopField= ; Ignore the blank item. Continue SplitPath, A_LoopField, XCardfullname,, ext, XCard, AniMatch=0 Loop % arrayc.MaxIndex() { l_card = % arrayc[A_Index] If( "X" l_card = "X" XCardfullname ) { Gui, 2: +LastFound -Caption +AlwaysOnTop -SysMenu Gui, 2: Show, W700 H382 X0 Y0 Gui, 2: Margin, 0 ,0 Gui, 2: Add, ActiveX, W700 H382 vpwb, ShockwaveFlash.ShockwaveFlash getSwfFromDisk=%CARD_Path%\%XCardfullname% pwb.Movie := "file:///" . getSwfFromDisk pwb.Scale := "exactfit" Run, %FFMPEG_Path%\ffmpeg -t 30 -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 700x382 -i desktop -c:v libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\IC.mkv",, Hide Process, WaitClose, ffmpeg.exe, 40 Process, Close, %ErrorLevel% Gui, 2: Destroy Run, %FFMPEG_Path%\ffmpeg -y -i "%A_ScriptDir%\IC.mkv" -vf "transpose=2" "%A_ScriptDir%\rotate\%XCardfullname%" Process, WaitClose, ffmpeg.exe, 60 Process, Close, %ErrorLevel% FileDelete, %A_ScriptDir%\IC.mkv AniMatch=1 Break } } If AniMatch=0 { Gui, 2: +LastFound -Caption +AlwaysOnTop -SysMenu Gui, 2: Show, W700 H382 X0 Y0 Gui, 2: Margin, 0 ,0 Gui, 2: Add, ActiveX, W700 H382 vpwb, ShockwaveFlash.ShockwaveFlash getSwfFromDisk=%A_LoopField% pwb.Movie := "file:///" . getSwfFromDisk pwb.Scale := "exactfit" Run, %FFMPEG_Path%\ffmpeg -t 1 -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 700x382 -i desktop -c:v libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\IC.mkv",, Hide Process, WaitClose, ffmpeg.exe, 5 Process, Close, %ErrorLevel% Gui, 2: Destroy Run, %FFMPEG_Path%\ffmpeg -y -i "%A_ScriptDir%\IC.mkv" -ss 00:00:00.500 -vf "transpose=2" -vframes 1 "%A_ScriptDir%\rotate\%XCard%.png" Process, WaitClose, ffmpeg.exe, 5 Process, Close, %ErrorLevel% FileDelete, %A_ScriptDir%\IC.mkv } } Gui, 2: Destroy ; Clean up FileDelete, %A_ScriptDir%\IC.mkv ExitApp I originally pursued this solution hoping that the text on the instruction card images would be more legible than what VP tends to render. But I have a standard width table and a 39" screen. It's still a pretty small area, so I don't think it looks much better or clearer than what VP was already doing. But since any sort of video or image content can be displayed, it becomes another creative platform for people to do interesting mods. I hope to see more animated cards or custom backgrounds for the mirrored DMD/B2S: This would be possible with some tweaking to the main script: https://pinside.com/pinball/forum/topic/watch-that-dmd#post-1043384 https://pinside.com/pinball/forum/topic/dmd-extender/page/2#post-754826 Cheers! 3 Quote Link to comment Share on other sites More sharing options...
Draco1962 Posted June 27, 2015 Share Posted June 27, 2015 Thanks for sharing this! I am sure it will help quite a few! I hope you don't mind but I moved this to the User Projects subform with a link from the General forum. Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted July 21, 2015 Author Share Posted July 21, 2015 Bug fixes -Can now match on tables with commas in the description tagNo more missing arguments in launching the DisplayCard scriptsChanged window for instruction cards and score cards to 700x400. Images displayed in "default" mode which retains the aspect ratio of the source image.Re-scaled the initial Instruction.png card. Added a Table Info.png card. Score cards now loop after an initial Table Info card in displayed. Both are zipped in attached archive. The file also includes some price cards that I pulled from Stern and Inkochnito. I colored the Stern cards to match their spec.Did a little tweaking to the exit routine. But it basically functions the same way as before.There some customizations for my own setup. I'm running VP in 4K and downsampling using NVidia DSR.I call the first script VPLaunch#NoEnv #SingleInstance force; http://www.gameex.info/forums/topic/14632-multiple-exe-for-vp/#entry137471 - Thanks horseyhorsey #Include, %A_ScriptDir%\xpath.ahkSetTitleMatchMode, 2DetectHiddenWindows, On ; USER INPUTSPinballX_Path=c:\PinballXantimicro_Path=c:\antimicroFFMPEG_Path=c:\ffmpeg\binCARD_Path=%A_ScriptDir%\Instruction CardsSCORE_Path=%A_ScriptDir%\Score CardsNudge991=300NudgePM=75Filter="scale=iw*(2/3):-1,transpose=3"Mirror1PosX=3370Mirror1PosY=1534Mirror2PosX=3370Mirror2PosY=254DisplayCardTime=15000 ; array code adapted from Gilrock - http://www.gameex.info/forums/topic/15083-improved-pinball-fx2-script Thanks ; roms for lowest latency but possibly with artifactsarrayf:=["mb_106b", "tz_92", "taf_l7", "frankst"] ; *********************************************** Table=%1% ;Table filename SplitPath, Table,,,, XTable, ; Read description tag from xml - Thanks horseyhorsey - http://www.gameex.info/forums/topic/14632-multiple-exe-for-vp/#entry129111databaseFile=%PinballX_Path%\Databases\Visual Pinball\Visual Pinball.xmlxpath_load(dbXML, databaseFile ) ; need to read the existing xml otherwise xpath deletes all existing nodesexe:= XPath(dbXML, "/menu/game[@name= . XTable . ]/exe/text()")rom:= XPath(dbXML, "/menu/game[@name= . XTable . ]/rom/text()")B2S:= XPath(dbXML, "/menu/game[@name= . XTable . ]/B2S/text()")description:= XPath(dbXML, "/menu/game[@name= . XTable . ]/description/text()")StringReplace, description, description,,,`,, If exe=vpinball991{RegWrite, REG_DWORD,HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainY, %Nudge991%RegWrite, REG_DWORD,HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainX, %Nudge991%}If exe=vpinball-9.9.1-plunger-mods{RegWrite, REG_DWORD,HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainY, %Nudge991%RegWrite, REG_DWORD,HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainX, %Nudge991%}If exe=VP_physmod2{RegWrite, REG_DWORD, HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainY, %NudgePM%RegWrite, REG_DWORD, HKCU, Software\Visual Pinball\DX9\Player, PBWAccelGainX, %NudgePM%} IniRead, TablePath, %PinballX_Path%\Config\PinballX.ini, VisualPinball, TablePathStringReplace, XTablePath, TablePath, \Tables RegRead, XDMD_width, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_widthRegRead, XDMD_height, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_heightRegRead, DMD_X, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_pos_xRegRead, XDMD_Y, HKCU, Software\Freeware\Visual PinMame\%rom%, dmd_pos_yDMD_width:=XDMD_width-3DMD_height:=XDMD_height+3DMD_Y:=XDMD_Y-2; HardcodeIf rom=hirolcas{DMD_width:=768DMD_height:=300DMD_X:=7680DMD_Y:=123} If rom=simpprty{DMD_width:=768DMD_height:=300DMD_X:=7680DMD_Y:=123} If rom=ripleys{DMD_width:=768DMD_height:=300DMD_X:=7680DMD_Y:=123} If rom=wpt_140a{DMD_width:=768DMD_height:=300DMD_X:=7680DMD_Y:=123} If rom=taf_l7{DMD_width:=768DMD_height:=244DMD_X:=7680DMD_Y:=198} If B2S=True{FileReadLine, BG_width, %TablePath%\ScreenRes.txt, 3FileReadLine, DMD_width, %TablePath%\ScreenRes.txt, 8FileReadLine, XDMD_height, %TablePath%\ScreenRes.txt, 9FileReadLine, XDMD_X, %TablePath%\ScreenRes.txt, 10FileReadLine, XDMD_Y, %TablePath%\ScreenRes.txt, 11DMD_height:=XDMD_height+6DMD_X:=BG_width+XDMD_X ;Reference to Top Left of Playfield screenDMD_Y:=XDMD_Y-2} FileReadLine, CardWidth, %TablePath%\ScreenRes.txt, 8If !(DMD_width>0) DMD_width:=0 ; Have the information we need to run Card splash screensRun, %A_ScriptDir%\DisplayCard1.exe "%CARD_Path%" "%Filter%" %Mirror1PosX% %Mirror1PosY% %Mirror2PosX% %Mirror2PosY% "%description%" "%XTable%" %DMD_width% %CardWidth% %DisplayCardTime%Run, %A_ScriptDir%\DisplayCard2.exe "%SCORE_Path%" "%Filter%" %Mirror1PosX% %Mirror1PosY% %Mirror2PosX% %Mirror2PosY% "%description%" "%XTable%" %DMD_width% %CardWidth% %DisplayCardTime% StringGetPos, pos, Filter, )Scale:=SubStr(Filter, 12, pos-11)StringGetPos, pos1, Scale, /If ErrorLevel=0{Num:=SubStr(Scale, 1, pos1)Denom:=SubStr(Scale, pos1+2)Num1:=NumDenom1:=DenomScale:=Num1/Denom1} ; DMD/B2S borderBOX1_width:=Floor(DMD_width*Scale+23*2)BOX1_height:=Floor(DMD_height*Scale+4*2)BOX2_width:=BOX1_width-23BOX2_height:=BOX1_height-4 ; Card border - want to retain the same width and scale the height to preserve the aspect ratio; a common size is 700px x 382px http://www.pinballrebel.com/pinball/cards/Card_sizes.htm; we'll see how 700px x 400px goesIf DMD_width>0 CARD1_height:=Floor(DMD_width*Scale*400/700+4*2)Else CARD1_height:=Floor(CardWidth*Scale*400/700+4*2) ; Position DMD/B2S adjacent to Card borderMirror3PosX:=Mirror1PosX+Card1_heightMirror4PosX:=Mirror2PosX+Card1_height ; *********************************************** Run, %antimicro_Path%\antimicro --no-tray --hidden --profile "%antimicro_Path%\profiles\VP.joystick.amgp" ; Disable Aero if EnabledRegRead, DWMComp, HKCU, Software\Microsoft\Windows\DWM, CompositionAero=%DWMComp%If Aero=1Run, sc stop uxsms,, Hide Run, dc2.exe -configure="%A_ScriptDir%\dc2config\VPMSettings.xml",, Hide ; Mirror and flip DMD for apronIf DMD_width>0{Loop % arrayf.MaxIndex(){l_table = % arrayf[A_Index]if( "X" l_table = "X" rom ){streamx264=1break}}If streamx264=1{Run, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v libx264 -preset ultrafast -tune zerolatency -qp 0 -f mpegts -threads 8 udp://localhost:1234,, HideRun, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v libx264 -preset ultrafast -tune zerolatency -qp 0 -f mpegts -threads 8 udp://localhost:5678,, Hide}Else{Run, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v mpeg4 -qscale:v 1 -f mpegts -threads 8 udp://localhost:1234,, HideRun, %FFMPEG_Path%\ffmpeg -f gdigrab -framerate 150 -offset_x %DMD_X% -offset_y %DMD_Y% -video_size %DMD_width%x%DMD_height% -i desktop -vf %Filter% -c:v mpeg4 -qscale:v 1 -f mpegts -threads 8 udp://localhost:5678,, Hide}Sleep, 1000Run, %FFMPEG_Path%\ffplay -an -sn -i -fflags nobuffer udp://localhost:1234?listen,, HideRun, %FFMPEG_Path%\ffplay -an -sn -i -fflags nobuffer udp://localhost:5678?listen,, HideLoop, 2{checkwindowagain1:IfWinExist, udp://localhost:1234?listenWinMove, udp://localhost:1234?listen,, %Mirror3PosX%, %Mirror1PosY%ElseGoto, checkwindowagain1}Loop, 2{checkwindowagain2:IfWinExist, udp://localhost:5678?listenWinMove, udp://localhost:5678?listen,, %Mirror4PosX%, %Mirror2PosY%ElseGoto, checkwindowagain2}} Run, %XTablePath%\%exe%.exe -play "%TablePath%\%Table%",, MinWinWaitActive, ahk_class VPPlayerSleep, 1000WinSet, AlwaysOnTop,, udp://localhost:1234?listenWinSet, AlwaysOnTop,, udp://localhost:5678?listen If DMD_width>0{; draw a black border to hide the window borders for the mirror Gui, 1: +LastFound +AlwaysOnTop -Caption +ToolWindowGui, 1: Color, 000000WinSet, Region, 0-0 %BOX1_height%-0 %BOX1_height%-%BOX1_width% 0-%BOX1_width% 0-0 4-24 %BOX2_height%-24 %BOX2_height%-%BOX2_width% 4-%BOX2_width% 4-24Gui, 1: Show, W%BOX1_height% H%BOX1_width% X%Mirror3PosX% Y%Mirror1PosY% NoActivate Gui, 2: +LastFound +AlwaysOnTop -Caption +ToolWindowGui, 2: Color, 000000WinSet, Region, 0-0 %BOX1_height%-0 %BOX1_height%-%BOX1_width% 0-%BOX1_width% 0-0 4-24 %BOX2_height%-24 %BOX2_height%-%BOX2_width% 4-%BOX2_width% 4-24Gui, 2: Show, W%BOX1_height% H%BOX1_width% X%Mirror4PosX% Y%Mirror2PosY% NoActivate} ; *********************************************** checkVPPlayer:IfWinNotExist, Visual Pinball{ Run, taskkill /im ffplay.exe,, HideRun, taskkill /im ffmpeg.exe /f,, Hide If DMD_width>0 { Gui, 1: Destroy Gui, 2: Destroy } Process, Close, DisplayCard1.exe If ErrorLevel Process, Close, %ErrorLevel% Process, Close, DisplayCard2.exe If ErrorLevel Process, Close, %ErrorLevel%Run, dc2.exe -configure="%A_ScriptDir%\dc2config\4KSettings.xml"; Enable Aero if Enabled at the start of script executionIf Aero=1Run, sc start uxsmsRun, taskkill /im antimicro.exe /f,, Hide}else{Sleep, 1000Goto, checkVPPlayer} ExitApp ; *********************************************** ; CloseVP from FPLaunchCloseVP:;toLog("CloseVP Called");Hotkey, %exitScriptKey%, OffGoSub rosveClose;GoSub bigbossClose ; change loops completely, put all data in xml !!! too slow;Visual Pinball must be closed this way instead of killing process ;or it wil not save your last game information.i.e score/credtis;DetectHiddenWindows on ;Or next line will not work;Loop, 4;Gui, %A_Index%: Destroy;This line fixes where the VP Window flashes real quick;when closing the window for a cleaner exit; win hide removed cause vp should be minimized, not hidden;WinHide, ahk_class VPinball;WinShow, ahk_class VPinballWinMinimize, ahk_class VPinballWinClose, ahk_class VPinballWinWaitClose ahk_class VPinball; bigbossclose won't get executed cause main thread will exit;GoSub bigbossClose; there's no need for exitscript cause main thread will do it;Goto ExitScriptreturn rosveClose:;toLog("rosveClose Called"); rosve; --------------------------------------------------------------; --- Close the animated backglass -----------------------; --------------------------------------------------------------; b2s close bug fixStringRight, ending, XTable, 3if (ending = "B2S"){WinKill, Form1}return ; *********************************************** #IfWinActive ahk_class VPPlayer ; Interlock Switchi::Send {End}SetTimer, WaitForJoy7, 10Return WaitForJoy7:if GetKeyState("Joy7")returnSend {End}SetTimer, WaitForJoy7, offReturn ; Exit Tablee:: Gosub CloseVPReturn #IfWinActive DisplayCard1 #NoEnv #SingleInstance forceSetTitleMatchMode, 2DetectHiddenWindows, On CARD_Path=%1%Filter=%2%Mirror1PosX=%3%Mirror1PosY=%4%Mirror2PosX=%5%Mirror2PosY=%6%description=%7%XTable=%8%DMD_width=%9%CardWidth=%10%DisplayCardTime=%11% IfExist, %CARD_Path%\%description%* cardmatch:=1IfExist, %CARD_Path%\%XTable%* cardmatch:=1If cardmatch=1 { StringGetPos, pos, Filter, ) Scale:=SubStr(Filter, 11, pos-10) StringGetPos, pos1, Scale, / If ErrorLevel=0 { Num:=SubStr(Scale, 1, pos1) Denom:=SubStr(Scale, pos1+2) Num1:=Num Denom1:=Denom Scale:=Num1/Denom1 } ; Card border - want to retain the same width and scale the height to preserve the aspect ratio; a common size is 700px x 382px http://www.pinballrebel.com/pinball/cards/Card_sizes.htm; we'll see how 700px x 400px goes If !(DMD_width>0) DMD_width:=CardWidth CARD1_width:=Floor(DMD_width*Scale+23*2) CARD1_height:=Floor(DMD_width*Scale*400/700+4*2) CARD2_width:=CARD1_width-23 CARD2_height:=CARD1_height-4 GUI4W:=CARD2_width-23 GUI4H:=CARD2_height-4 GUI4X:=Mirror1PosX+4 GUI4Y:=Mirror1PosY+23 ; Show instruction cards; http://www.autohotkey.com/board/topic/56987-com-object-reference-autohotkey-v11/page-13 Gui, 3: +LastFound -Caption +AlwaysOnTop -SysMenu GUI3_ID:=WinExist() Gui, 3: Color, 000000 WinSet, Region, 0-0 %CARD1_height%-0 %CARD1_height%-%CARD1_width% 0-%CARD1_width% 0-0 4-24 %CARD2_height%-24 %CARD2_height%-%CARD2_width% 4-%CARD2_width% 4-24 CardList1=%CARD_Path%\Instructions.png`n Loop, Files, %CARD_Path%\%description%* CardList1=%CardList1%%A_LoopFileFullPath%`n Loop, Files, %CARD_Path%\%XTable%* CardList1=%CardList1%%A_LoopFileFullPath%`n WinWaitActive, ahk_class VPPlayer Loop { Loop, Parse, CardList1, `n { If A_LoopField= ; Ignore the blank item. Continue getSwfFromDisk=%A_LoopField% GoSub DisplayCard } } } ExitApp ; *********************************************** DisplayCard: Gui, 4: +LastFound -Caption +AlwaysOnTop -SysMenu GUI4_ID:=WinExist() Gui, 4: Color, 000000 Gui, 3: Show, W%CARD1_height% H%CARD1_width% X%Mirror1PosX% Y%Mirror1PosY% NoActivate Hide Gui, 4: Show, W%GUI4H% H%GUI4W% X%GUI4X% Y%GUI4Y% NoActivate Hide Gui, 4: Margin, 0 ,0 DllCall("AnimateWindow","UInt",GUI3_ID,"Int",1,"UInt","0xa0000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",1000,"UInt","0xa0000") Gui, 4: Add, ActiveX, W%GUI4H% H%GUI4W% vpwb, ShockwaveFlash.ShockwaveFlash pwb.movie := "file:///" . getSwfFromDisk pwb.bgcolor := "#000000" pwb.scale := "default" ;noborder/default/exactfit/noscale ;pwb.wmode := "direct" ;window/opaque/direct/transparent/gpu Sleep, %DisplayCardTime% Control, Hide,, MacromediaFlashPlayerActiveX1, ahk_id %GUI2_ID% DllCall("AnimateWindow","UInt",GUI3_ID,"Int",750,"UInt","0x90000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",750,"UInt","0x90000") Gui, 4: DestroyReturn DisplayCard2 #NoEnv #SingleInstance forceSetTitleMatchMode, 2DetectHiddenWindows, On SCORE_Path=%1%Filter=%2%Mirror1PosX=%3%Mirror1PosY=%4%Mirror2PosX=%5%Mirror2PosY=%6%description=%7%XTable=%8%DMD_width=%9%CardWidth=%10%DisplayCardTime=%11% IfExist, %SCORE_Path%\%description%* cardmatch:=1IfExist, %SCORE_Path%\%XTable%* cardmatch:=1If cardmatch=1 { StringGetPos, pos, Filter, ) Scale:=SubStr(Filter, 11, pos-10) StringGetPos, pos1, Scale, / If ErrorLevel=0 { Num:=SubStr(Scale, 1, pos1) Denom:=SubStr(Scale, pos1+2) Num1:=Num Denom1:=Denom Scale:=Num1/Denom1 } ; Card border - want to retain the same width and scale the height to preserve the aspect ratio; a common size is 700px x 382px http://www.pinballrebel.com/pinball/cards/Card_sizes.htm; we'll see how 700px x 400px goes If !(DMD_width>0) DMD_width:=CardWidth CARD1_width:=Floor(DMD_width*Scale+23*2) CARD1_height:=Floor(DMD_width*Scale*400/700+4*2) CARD2_width:=CARD1_width-23 CARD2_height:=CARD1_height-4 GUI4W:=CARD2_width-23 GUI4H:=CARD2_height-4 GUI4X:=Mirror2PosX+4 GUI4Y:=Mirror2PosY+23 ; Show instruction cards; http://www.autohotkey.com/board/topic/56987-com-object-reference-autohotkey-v11/page-13 Gui, 3: +LastFound -Caption +AlwaysOnTop -SysMenu GUI3_ID:=WinExist() Gui, 3: Color, 000000 WinSet, Region, 0-0 %CARD1_height%-0 %CARD1_height%-%CARD1_width% 0-%CARD1_width% 0-0 4-24 %CARD2_height%-24 %CARD2_height%-%CARD2_width% 4-%CARD2_width% 4-24 CardList1=%SCORE_Path%\Table Info.png`n Loop, Files, %SCORE_Path%\%description%* CardList1=%CardList1%%A_LoopFileFullPath%`n Loop, Files, %SCORE_Path%\%XTable%* CardList1=%CardList1%%A_LoopFileFullPath%`n WinWaitActive, ahk_class VPPlayer Loop { Loop, Parse, CardList1, `n { If A_LoopField= ; Ignore the blank item. Continue getSwfFromDisk=%A_LoopField% GoSub DisplayCard } } } ExitApp ; *********************************************** DisplayCard: Gui, 4: +LastFound -Caption +AlwaysOnTop -SysMenu GUI4_ID:=WinExist() Gui, 4: Color, 000000 Gui, 3: Show, W%CARD1_height% H%CARD1_width% X%Mirror2PosX% Y%Mirror2PosY% NoActivate Hide Gui, 4: Show, W%GUI4H% H%GUI4W% X%GUI4X% Y%GUI4Y% NoActivate Hide Gui, 4: Margin, 0 ,0 DllCall("AnimateWindow","UInt",GUI3_ID,"Int",1,"UInt","0xa0000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",1000,"UInt","0xa0000") Gui, 4: Add, ActiveX, W%GUI4H% H%GUI4W% vpwb, ShockwaveFlash.ShockwaveFlash pwb.movie := "file:///" . getSwfFromDisk pwb.bgcolor := "#000000" pwb.scale := "default" ;noborder/default/exactfit/noscale ;pwb.wmode := "direct" ;window/opaque/direct/transparent/gpu Sleep, %DisplayCardTime% Control, Hide,, MacromediaFlashPlayerActiveX1, ahk_id %GUI2_ID% DllCall("AnimateWindow","UInt",GUI3_ID,"Int",750,"UInt","0x90000") DllCall("AnimateWindow","UInt",GUI4_ID,"Int",750,"UInt","0x90000") Gui, 4: DestroyReturn I have a workflow for creating media from custom cards that people publish on the Internet. I try to obtain or produce media with very high quality, and it is do-able here but with limitations. I was pleasantly surprised that the majority of images that I have worked with so far do have dimensions consistent with the manufacturer documented dimensions found here under Card Sizes: http://www.pinballre.../pinball/cards/ So, producing images although still a manual process is pretty quick and easy. I use GIMP 2. It will open just about all image types and import from PDF. Open an image or import a PDF page with images. I just drag and drop and select what I need in dialog windows. Tools/Selection Tools/Rectangle Select. Use the default settings in the Tool Options dialog. Use the mouse/cursor to draw a rectangle roughly around the image. Image/Crop to Selection Then Autocrop Image. In a small portion of cases, the resulting image might require some additional cropping (if the image includes cut guides or was specifically providing larger borders for trimming printed reproductions. Use the mouse/cursor to draw a rectangle, and the size of the crop area can be fine tuned with the Position and Size options in the Tool Options dialog After cropping, check Image/Print Size... the dimensions should be consistent with a real card from that manufacturer. Most of the time it is. Sometimes you have to change the X/Y resolution. To retain the aspect ratio of the cropped image make sure the chain symbol is linked. Change the resolution until the print size is consistent with a real card. Click OK File/Export As... Choose a name. Select File Type. Use PNG image. Click Export. You will get a dialog where there are settings that can be toggled on/off. Just use the default as it appears and click Export. The file is ready for PinballX with no loss in quality. You could take the output to a printer. You'd probably still want to take the source file to the printer rather than the output though. You could use the SWF files from the FTP. But they would still need to be rotated for use by the script. The batch converter I wrote can do it but it does it by taking a screen grab. There is some loss in quality. Probably better off just taking a high quality scan or reproduction and generating a PNG from the source and using that image rather than the SWF. I have updated the batch converter. ffmpeg captures for SWF media are now processed at the highest quality settings to minimize image degradation. PNG images are rorated losslessly, The script uses convert.exe from ImageMagick http://www.imagemagick.org/script/index.php There are a number of other tools that can be used as well. #NoEnv #SingleInstance force ; USER INPUTSFFMPEG_Path=c:\Users\MeltonE\Downloads\ffmpeg-20150606-git-f073764-win64-static\binCARD_Path=c:\Users\MeltonE\Downloads\ic2ImageMagick_Path=c:\Users\MeltonE\Downloads\ImageMagick-6.9.1-Q16; array code adapted from Gilrock - http://www.gameex.info/forums/topic/15083-improved-pinball-fx2-script Thanks ; rotated animated instruction cards must be located in the same folder as this script/executablearrayc:=["Attack from Mars (Bally 1995) 5.swf", "Torpedo Alley (Data East 1988).swf"] CardList1= ; Initialize to be blank.Loop, Files, %CARD_Path%\*.* CardList1=%CardList1%%A_LoopFileFullPath%`n Loop, Parse, CardList1, `n { If A_LoopField= ; Ignore the blank item. Continue SplitPath, A_LoopField, XCardfullname,, ext, XCard, AniMatch=0 Loop % arrayc.MaxIndex() { l_card = % arrayc[A_Index] If( "X" l_card = "X" XCardfullname ) { Gui, 2: +LastFound -Caption +AlwaysOnTop -SysMenu Gui, 2: Show, W700 H400 X0 Y0 Gui, 2: Margin, 0 ,0 Gui, 2: Add, ActiveX, W700 H400 vpwb, ShockwaveFlash.ShockwaveFlash getSwfFromDisk=%CARD_Path%\%XCardfullname% pwb.movie := "file:///" . getSwfFromDisk pwb.scale := "default" Run, %FFMPEG_Path%\ffmpeg -t 30 -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 700x400 -i desktop -c:v libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\IC.mkv",, Hide Process, WaitClose, ffmpeg.exe, 40 Process, Close, %ErrorLevel% Gui, 2: Destroy Run, %FFMPEG_Path%\ffmpeg -y -i "%A_ScriptDir%\IC.mkv" -vf "transpose=2" -qscale:v 1 "%A_ScriptDir%\rotate\%XCardfullname%" Process, WaitClose, ffmpeg.exe, 60 Process, Close, %ErrorLevel% FileDelete, %A_ScriptDir%\IC.mkv AniMatch=1 Break } } If AniMatch=0 If ext=swf { Gui, 2: +LastFound -Caption +AlwaysOnTop -SysMenu Gui, 2: Show, W700 H400 X0 Y0 Gui, 2: Margin, 0 ,0 Gui, 2: Add, ActiveX, W700 H400 vpwb, ShockwaveFlash.ShockwaveFlash getSwfFromDisk=%A_LoopField% pwb.movie := "file:///" . getSwfFromDisk pwb.scale := "default" Run, %FFMPEG_Path%\ffmpeg -t 1 -f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 700x400 -i desktop -c:v libx264 -preset ultrafast -qp 0 -threads 8 "%A_ScriptDir%\IC.mkv",, Hide Process, WaitClose, ffmpeg.exe, 5 Process, Close, %ErrorLevel% Gui, 2: Destroy Run, %FFMPEG_Path%\ffmpeg -y -i "%A_ScriptDir%\IC.mkv" -ss 00:00:00.500 -vf "transpose=2" -vframes 1 -crf 0 "%A_ScriptDir%\rotate\%XCard%.png" Process, WaitClose, ffmpeg.exe, 5 Process, Close, %ErrorLevel% FileDelete, %A_ScriptDir%\IC.mkv } If ext=png { Run, %ImageMagick_Path%\convert -rotate 270 -background transparent "%CARD_Path%\%XCardfullname%" "%A_ScriptDir%\rotate\%XCardfullname%" Process, WaitClose, convert.exe, 5 } } ExitApp In the end, I'm very happy with how this turned out. Sadly, though generating two DMD mirrors and looping through images using two embedded ActiveX Flash controls is a little too much for my system when I am also doing 4K downsampling. Getting some stutter, sticky flippers, and sound doubling up. It looks like I've found the limit to what this machine can do. I'll probably walk it back a little bit and may just display on one side of the apron rather than both sides. cards.zip 1 Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted August 6, 2015 Author Share Posted August 6, 2015 Hi, I completed generating media for my apron miniDMD and flash player project. This primarily involved using GIMP to trim images out of source files and making sure they are scaled close to the correct manufacturer dimensions so that they will be displayed correctly by the player. Again, the player loops through lists of instruction cards and coin/score cards that are associated with a specific table and displays them on the apron on either side of the table.In the same way you can get PinballX to loop through sequences of cards by adding a number to the card's filename (Ex. Centaur.swf, Centaur 1.swf, Centaur 2.swf, etc.). You do the same thing here with series of images associated with a table. I arrange my cards so that every instruction card has some sort of coin card paired with it. For custom cards that are matched pairs, I make sure that their filenames end in the same number so that the player will display the set together at the same time.I've uploaded some of my work on the FTP Other Uploads/Carny/MiniDMD and flash player. These are images of the stock factory cards. In pairing coin cards to instruction cards, I checked for accuracy largely by observing the ROM when I begin a table. I always just use the default factory settings. For Stern Pinball tables I tried to confirm using shot maps or flyers if available. Otherwise, if I can't figure it out I simply look and see what the table author chose to use.Most files still require rotating for use in a cabinet. Use the batch converter script in the previous post. Some files are already rotated because they were rotated in the source that I captured them from.I'm only including the stock factory cards here. The source is primarily Inkochnito's reproduction cards and Stern Pinball who provided a lot of reproductions for the Sega and Data East properties that they acquired. I processed a lot of custom cards as well, but the sources tend to ask people not to re-distribute and I will respect that. Otherwise, the content is freely available. http://pinballcards.blogspot.com.au/http://www.pinballcards.com/http://www.pinballrebel.com/game/pins/instruction/index.htmPeople post custom cards at Pinside as well.For coin cards and my generic "Instructions" and "Table Info" cards, I've copied up the source files for the work 1 Quote Link to comment Share on other sites More sharing options...
tthurman Posted August 6, 2015 Share Posted August 6, 2015 I just now got to checking into this, but it looks fantastic!I'm almost afraid to ask, what system specs is this hitting limits on? Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted August 6, 2015 Author Share Posted August 6, 2015 Intel i5 3570k @ 3.4 GHz8 Gb DDR3 RAMNVidia GTX660Samsung SSD 840 SeriesI'm running VP using NVidia DSR technology downsampling from 4K. All cores get close to maxing out. I tried some CPU affinity settings to try to manage the load manually, but I don't see that I am getting better performance. I do get stutter and timing issues with flippers depending on the sum of textures that need to be rendered on the table, so I know I'll have to dial something back. Either go back to HD or mirror on one side of the apron and not both sides. 1 Quote Link to comment Share on other sites More sharing options...
Fulltilt Posted August 14, 2015 Share Posted August 14, 2015 Reading threads trying to catch up on things a bit when i saw this and wow, now that's a cool idea! Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted April 1, 2016 Author Share Posted April 1, 2016 The fine Dozer version of Cirqus Voltaire shows that it is very doable to have VPX render a mirrored display with flashers. It would require modding the tables and scripts for this feature. Not a high priority for me at the moment. But very cool. Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted October 5, 2016 Author Share Posted October 5, 2016 Update: Modified to work and look better for Win10 (using a basic or non-Aero theme) Because of changes made to automate Visual Pinball, I can no longer use this launcher with PinballX's integrated Visual Pinball support. I run this launcher as a custom system with a custom system type. Start up and exit code is more reliable Tested with a recent static build release of ffmpeg (2016-09-29) and Nvidia driver (372.90) running on Windows 10 Anniversary Edition Can be modified for VPX windowed full screen support Display of Instruction cards and Score cards are better synchronized via cheap process cross-communication using a temporary ini file written to disc. Launches VPX True Full Screen and automatically brings focus to Visual Pinball Player (no support for mirrored DMD or splash viewer with true full screen, however) I've fixed all cards for use with the splash viewer. On the FTP, Other Uploads/Carny/Z20160604/MiniDMDFlash Edit: Update LaunchVP attachment PinballX.ini - don't need to monitor for any other executables LaunchVP1mirror.ahk - fix bugs Notes: I still run an Intel i5 3570k, 8Gb RAM, with an NVidia GTX 660, 2GB VRAM. With my configuration, the overhead of running all of the extra processes to display everything on both sides of the apron is a little much for VP9 and too much for VPX. Based on the executable, the script runs the mirrors and splash viewer for VP9. And for the performance benefit, the script runs VPX with its Video Options set to use True Full Screen mode. I've included a version of the script where the DMD mirror and splash viewer on the right hand side of the apron are disabled. That should be less of a performance hit if running on both sides of the apron causes slowdown or "sticky flippers" while in-game. Because True Full Screen locks out all other processes that try to use the screen there is no way this solution will work (not on the playfield screen anyway). Weird thing - If a dB2S is really large and/or takes a long time to load, such as the one released with Fire! or the big fantasy one for Monster Bash, there winds up being some sort of a conflict with PinballX where B2SBackglassServerEXE.exe is shutdown or crashes. I don't know if it is a timing issue or resource conflict. But if Task Manager is running at the same time, then dB2S backglasses always load successfully. It's hacky, but without knowing what else to do at this point, I programmatically start Task Manager before launching Visual Pinball and then close it down when quitting the table. No assumptions are made about the dimensions required to capture the DMD. If the table is VPM, the dimensions are pulled from the registry folder for VPinMAME for the specific rom the table uses. If the table is UltraDMD, the dimensions are pulled from the registry folder for UltraDMD. If the table uses a third screen dB2S or older B2S, the dimensions are pulled from screenres.txt. Capture dimensions can otherwise be customized in the script. Information that tells the script if the table is VPM or B2S is stored in a custom xml that uses the standard rom and exe tags and adds a B2S tag. I've included my xml as an example. For me, latency on the DMD mirror was better with Win 7 than with Win 10. This is probably the last update for this project. These days, I only install VPX tables. With my hardware, VPX runs great but not so good with DMD mirror and the splash viewer. As I replace the VP9 and Phymod5 versions of my favorites with shiny, new VPX versions I can see phasing this project out. I'd expect that a cab with powerful hardware could still use a variation of this script to run a mirror and/or splash viewer using a fourth screen. Somebody had asked about routing something like this to fourth and fifth mini screens mounted on a false apron. Possible, I guess, if the hardware is state of the art. LaunchVP.zip Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted December 17, 2016 Author Share Posted December 17, 2016 Hi, I am quitting the splash viewer part of this project for now. The solution is not compatible with true full screen VPX plus I'm simply running out of drive space on my cabinet. Moving the media off gives me more storage space for tables! Media will still be available on the FTP, Other Uploads/Carny/Z20160604 Inkochnito is responsible for pretty much all of the heavy lifting. Please support and donate to his site. He provides a great service: http://www.pinballrebel.com/pinball/cards/ The work I've put into cutting and redrawing on Data East/Sega/Stern Pinball cards are free to use by the community without attribution. All sources are trademarks/copyrights of their respective owners to be privately used in PinballX or for other non-commercial (or at least non-profit) pinball-related applications. I hold no responsibility for their misuse. I will at least continue to provide redraws of media for the Media/Instruction Cards folder as I add them to my machine, but at this rate I don't expect to be adding very frequently. Quote Link to comment Share on other sites More sharing options...
koolywiz Posted February 28, 2017 Share Posted February 28, 2017 This is really cool. Didn't find out about it until now. Going to get it working in my cab, thanks for creating them. Quote Link to comment Share on other sites More sharing options...
gtxjoe Posted April 19, 2017 Share Posted April 19, 2017 Thanks for sharing this project. will try it out this weekend Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted April 19, 2017 Author Share Posted April 19, 2017 It was too resource hungry to run with VPX on my system, but I still use it for VP9. I have not been publishing updates to my script. Any changes are largely in response to VPX updates as I use the one script to launch all tables for all versions of VP. I'll post it if you want it. Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted May 10, 2017 Author Share Posted May 10, 2017 Latest launch scripts, per request LaunchVP.zip Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted March 19, 2018 Author Share Posted March 19, 2018 Hi, I rely pretty heavily on Inkochnito's reproductions to create the factory instruction cards used in this project. I recently found that Acrobat was automatically substituting fonts when they were not embedded in the source PDF file. Usually the substitution was Arial for Helvetica. Arial is close, but Arial is not Helvetica! And the output does not appear as accurately as intended. This occurs even with some of the true manufacturer PDFs hosted at Inkochnito's. I went through and fixed nearly 200 cards. Hopefully, that's all of them. Basically, all of the cards (at least for tables I have installed) are still available on the FTP: Other Uploads/Carny/Z20160604 Not on the FTP are some cards that required quite a bit more sweat to create. Most of them are for the newer Stern releases for which the manufacturer never published any PDFs for people to use for replacements (Ghostbusters, The Walking Dead, Star Trek, etc.) I've been building table specific media packs centered on these cards. They are published at VPUniverse. Check 'em out! http://vpuniverse.com/forums/files/category/9-hyperpin-media-packs/ Enjoy! Quote Link to comment Share on other sites More sharing options...
slydog43 Posted April 26, 2018 Share Posted April 26, 2018 Can you post another video of this in action. I'm getting a 404. I think I want something very similar to this for a new project. Thanks Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted April 27, 2018 Author Share Posted April 27, 2018 On 4/26/2018 at 6:14 AM, slydog43 said: Can you post another video of this in action. I'm getting a 404. I think I want something very similar to this for a new project. Thanks Updated the link to the old afm demo in the original post. Quote Link to comment Share on other sites More sharing options...
PcTeknic Posted July 27, 2020 Share Posted July 27, 2020 I am trying to make a script for Future Pinball that will open Future DMD if there is a video.mp4 in DMD Videos or open Image_Monitor_View with the corresponding image if what it finds is an image.png in DMD Images. I have not succeeded. Nor have I managed to do it directly by name. Even if I had to put as many lines as tables, some with the command for Future DMD and some with the command for Image_Monitor_View, it wouldn't be a problem, but I can't get it to work. I think it should be simple and I do something wrong, that's for sure, but I can't solve it. I've reviewed your files, but I still can't. Quote Link to comment Share on other sites More sharing options...
Carny_Priest Posted July 31, 2020 Author Share Posted July 31, 2020 Yeah, I don't think this project has anything to do with what you are describing. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.