Jump to content



Photo
- - - - -

Displaying ROM Segment Display on a (Flex) DMD


  • Please log in to reply
131 replies to this topic

#1 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 04 October 2021 - 01:05 PM

Here's some quick notes on how to convert a table using a segment backglass score display to a virtual or real DMD via flexDMD. It will probably be of most interest to people reskinning a table using a rom that displays scores on a segment display or for Real DMD users.
 
********* If you're wanting to add FlexDMD scoring to an EM table see @endeemillr's guide here - https://www.vpforums...topic=56053&hl= *********
 
Notes - You need freezy & flexDMD installed, and as i am not a flexDMD or a table script expert there may be a better way to do this that i'm not aware of. If you know of one then please correct me!
 
The code (cut down example for displaying two 7 segment numeric display strips on a DMD)..
 
First things first, add a constant at the top of the table code to control whether or not flex is used;
Const UseFlexDMD = 1    ' 1 is on

Add global variables;

Dim FlexDMD		' the flex dmd display
DIm FlexDMDDict		' a dictionary / lookup to convert segment display hex/int codes to characters
Dim L1Chars, L2Chars	' arrays to hold converted text for displaying. One for each segment strip used by the table (two here)

Add FlexDMD_Init sub (and call it from the top of Table1_Init, with If UseFlexDMD Then FlexDMD_Init)

Sub FlexDMD_Init() 'default/startup values

	' flex dmd variables
	DIm FlexDMDFont
	Dim FlexPath
	Dim FlexDMDScene
	
	'popualte arrays to hold characters to display converted from segment codes with defaults
	'here we assume that each display line has 7 segments
	L1Chars = Array(" "," "," "," "," "," "," ")
	L2Chars = Array(" "," "," "," "," "," "," ")
	
	' populate the lookup dictionary for mapping display characters
	FlexDictionary_Init
	
	'setup flex dmd
	Set FlexDMD = CreateObject("FlexDMD.FlexDMD")
	If Not FlexDMD is Nothing Then
	
		FlexDMD.LockRenderThread

		FlexDMD.RenderMode = 2
		FlexDMD.Width = 128
		FlexDMD.Height = 32
		FlexDMD.Clear = True
		FlexDMD.GameName = cGameName
		FlexDMD.Run = True

		Set FlexDMDScene = FlexDMD.NewGroup("Scene")
		
		'black background
		FlexDMDScene.AddActor FlexDMD.NewImage("Back", "FlexDMD.Resources.dmds.black.png")
		
		'display font
		Set FlexDMDFont = FlexDMD.NewFont("FlexDMD.Resources.teeny_tiny_pixls-5.fnt", vbRed, vbBlue, 0)
		
		' add a label for each line of text to display (i.e. one per segment strip).
		FlexDMDScene.AddActor(FlexDMD.NewLabel("Line1", FlexDMDFont, "       "))
		FlexDMDScene.GetLabel("Line1").SetAlignedPosition  5,5,0
		FlexDMDScene.AddActor(FlexDMD.NewLabel("Line2", FlexDMDFont,  "       "))
		FlexDMDScene.GetLabel("Line2").SetAlignedPosition 5,15,0
	
		FlexDMD.Stage.AddActor FlexDMDScene
		
		FlexDMD.Show = True
		FlexDMD.UnlockRenderThread
		
	End If

End Sub

Add code for to populate the dictionary / lookup (called in FlexDMD_Init). Note that the conversion codes will depend on rom and segement display type, as it may use alphanumeric characters or include . or , characters as part of one segment. For alphanumeric segment displays S and 5, 0 and O etc will be mapped once. If the lookup values for the segment-character mapping aren't known then add the FlexDMDDict.Add lines later.

Sub FlexDictionary_Init

	'add conversion of segment charcters codes to lookup table
	Set FlexDMDDict = CreateObject("Scripting.Dictionary")

	' when the segment hex display value is zero we want to display as a space etc
	FlexDMDDict.Add 0, " "			
	FlexDMDDict.Add 63, "0"
	FlexDMDDict.Add 6, "1"
	FlexDMDDict.Add 91, "2"
	FlexDMDDict.Add 79, "3"
	FlexDMDDict.Add 102, "4"
	FlexDMDDict.Add 109, "5"
	FlexDMDDict.Add 125, "6"
	FlexDMDDict.Add 7, "7"
	FlexDMDDict.Add 127, "8"
	FlexDMDDict.Add 111, "9"

	' add values for a segment that can include a comma	
	FlexDMDDict.Add 191, "0,"
	FlexDMDDict.Add 134, "1,"
	FlexDMDDict.Add 219, "2,"
	FlexDMDDict.Add 207, "3,"
	FlexDMDDict.Add 230, "4,"
	FlexDMDDict.Add 237, "5,"
	FlexDMDDict.Add 253, "6,"
	FlexDMDDict.Add 135, "7,"
	FlexDMDDict.Add 255, "8,"
	FlexDMDDict.Add 239, "9,"

	' add other characters as required to match what is displayed in game
	 
End Sub
Add the code that will use the dictionary to convert to characters and store the dsipaly text in the L1Chars, L2Chars arrays and the code to update the flexDMD display. 
Find the section of code where the LED segment displays are updated (search for Controller.ChangedLEDs. usually in a DisplayTimer_Timer type event), it should have a block of code something like;
Dim ChgLED,ii,num,chg,stat,obj
	ChgLED=Controller.ChangedLEDs  (&Hffffffff, &Hffffffff)
	If Not IsEmpty(ChgLED) Then
		For ii=0 To UBound(chgLED)
			num=chgLED(ii,0):chg=chgLED(ii,1):stat=chgLED(ii,2)
			For Each obj In Digits(num)
				If chg And 1 Then obj.State=stat And 1
				chg=chg\2:stat=stat\2
			Next
		Next
	End If

Insert two lines to track what characters have changed, and then to update flexDMD when all changes are known;

	Dim ChgLED,ii,num,chg,stat,obj
	ChgLED=Controller.ChangedLEDs  (&Hffffffff, &Hffffffff)
	If Not IsEmpty(ChgLED) Then
		For ii=0 To UBound(chgLED)
			num=chgLED(ii,0):chg=chgLED(ii,1):stat=chgLED(ii,2)
			If UseFlexDMD then UpdateFlexChar num, stat
			For Each obj In Digits(num)
				If chg And 1 Then obj.State=stat And 1
				chg=chg\2:stat=stat\2
			Next
		Next
		If UseFlexDMD then FlexDMDUpdate
	End If

Then the subs that are called;

Sub UpdateFlexChar(id, value)
	'map segment code to character in LnChars arrays
	Dim chr
	if FlexDMDDict.Exists (value) then
                chr = FlexDMDDict.Item (value)
		if id < 7 then
			L1Chars(id) = chr
		elseif id < 14 then
			L2Chars(id - 7) = chr
		end if
	else
		''for testing, if lookup values aren't known return the integer value so it can be displayed and added to FlexDMDDict.Add 
		'if id < 7 then
		'	L1Chars(id) = value
		'elseif id < 14 then
		'	L2Chars(id - 7) = value
		'end if
	end if 	
End Sub

Sub FlexDMDUpdate()

	If Not FlexDMD is Nothing Then FlexDMD.LockRenderThread
	
	With FlexDMD.Stage
		' use the Join function to concatenate the LxChars arrays into a string of text and update the labels
		.GetLabel("Line2").Text = Join(L2Chars,"")
		.GetLabel("Line1").Text = Join(L1Chars,"")
	End With

	If Not FlexDMD is Nothing Then FlexDMD.UnlockRenderThread
		
End Sub

At this point the basic code is in place and the flexDMD should work. You may need to add or change character code lookups in the FlexDictionary_Init uncommenting the test code in UpdateFlexChar to help if required. Then you can make things look a bit prettier (check lamp states to display alternate labels or colours, use different fonts, change label positions, add gifs etc).

 

Other than that just add code for a clean exit, so in the Table1_exit routine add;

	If UseFlexDMD then
		If IsObject(FlexDMD) Then 
			If Not FlexDMD is Nothing Then
				FlexDMD.Show = False
				FlexDMD.Run = False
				FlexDMD = NULL
			End If
		End if
	End if 

There will be a small overhead on performance with this, if it's too much for your system then just set the UseFlexDMD flag to 0.

 

I'll do a worked example for Bone Busters in a follow up post, but here's some previous ones;
 
 
 
elvirale.gif
 
 
mst3k1.gif
 
 
aliens.gif
 
 
pacman0.gif
 
 
 
Big thanks to Vincent Bousquet the flexdmd author !!
 
 
Notes - for real DMD users if you have enabled alphanumeric segments in dmddevice (freezy) this can prevent a real dmd from initialising with the table and therefore the flexdmd from displaying. Amend in dmddevice.ini.
Later examples include code to turn off External DMD in vpinmame options for a rom when running the the table, but for earlier examples you may need to do this manually to prevent flashing between flexdmd and the default external dmd displays.
 
 

Edited by scutters, 06 October 2025 - 09:17 PM.


#2 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 04 October 2021 - 09:37 PM

Dont forget the table_exit sub

need to exit flex DMD when the table exits

 

If Not FlexDMD is Nothing Then FlexDMD.UnlockRenderThread
    FlexDMD.Run = False

*Graphics Not Included


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#3 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 05 October 2021 - 06:14 AM

Dont forget the table_exit sub

need to exit flex DMD when the table exits

 

Dammit, knew i'd forget something. Thanks weisshund, post amended

 

Edit - fixed a couple of other things too


Edited by scutters, 05 October 2021 - 11:19 AM.


#4 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 06 October 2021 - 11:39 AM

Bone Busters Segment Display Conversion to Flex

 

For Aubrel V1.6 table  https://www.vpforums...&showfile=16079. This one is mainly for the Real DMD guys to get something nice on the DMD in game that fits the 128*32 display (virtual dmd users can just use the pinmame DMD on an LCD screen if they want)

 
From a quick look at the game the segment displays it's two strips of twenty 14+1 segment displays (+1 is for a comma), so we'll need to amend the stock code above to handle 20 segments in the two line arrays of text. As the segment display is pretty large and with plenty happening all we'll do is mirror the segment display to flexDMD (no gifs or extra lamp checks to display additional images/text etc)
 
So in the example code adjust the array and initial flexdmd label lengths in FlexDMD_Init to match the segment display sizes;
	L1Chars = Array(" "," "," "," "," "," "," ")
	L2Chars = Array(" "," "," "," "," "," "," ")

and

		FlexDMDScene.AddActor(FlexDMD.NewLabel("Line1", FlexDMDFont, "       "))
		FlexDMDScene.GetLabel("Line1").SetAlignedPosition  5,5,0
		FlexDMDScene.AddActor(FlexDMD.NewLabel("Line2", FlexDMDFont,  "       "))
		FlexDMDScene.GetLabel("Line2").SetAlignedPosition 5,15,0

which become

	'20 segments
	L1Chars = Array(" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ")
	L2Chars = Array(" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," ")

and

		FlexDMDScene.AddActor(FlexDMD.NewLabel("Line1", FlexDMDFont, "                    "))
		FlexDMDScene.GetLabel("Line1").SetAlignedPosition  5,2,0
		FlexDMDScene.AddActor(FlexDMD.NewLabel("Line2", FlexDMDFont,  "                    "))
		FlexDMDScene.GetLabel("Line2").SetAlignedPosition 5,16,0
(i've also changed the aligned position slightly)
 
Also update UpdateFlexChar sub to account for the new array offsets (7 and 14 become 20 and 40), e.g.;
		if id < 20 then
			L1Chars(id) = chr
		elseif id < 40 then
			L2Chars(id - 20) = chr
		end if
The code to call the update the flex DMD is also slightly different, as this tables DisplayTimer_Timer event includes a check on ShowDT (desktop), i guess maybe all tables should do this but it appears not (and as i've tried to do minimal changes to the existing table code i haven't added it to other scripts).
 
Existing table script is;
Sub DisplayTimer_Timer
	Dim ChgLED, ii, jj, num, chg, stat, obj, b, x
    ChgLED=Controller.ChangedLEDs(&Hffffffff, &Hffffffff)
    If Not IsEmpty(ChgLED)Then
		If Table1.ShowDT = true Then
			For ii=0 To UBound(chgLED)
				num=chgLED(ii, 0) : chg=chgLED(ii, 1) : stat=chgLED(ii, 2)
				if (num < 40) then
					For Each obj In Digits(num)
						If chg And 1 Then obj.State=stat And 1
						chg=chg\2 : stat=stat\2
					Next
				else
			    end if
			Next
		End if
	End If
 End Sub

and we change it to;

Sub DisplayTimer_Timer
	Dim ChgLED, ii, jj, num, chg, stat, obj, b, x
    ChgLED=Controller.ChangedLEDs(&Hffffffff, &Hffffffff)
    If Not IsEmpty(ChgLED)Then
		If Table1.ShowDT = true or UseFlexDMD Then
			For ii=0 To UBound(chgLED)
				num=chgLED(ii, 0) : chg=chgLED(ii, 1) : stat=chgLED(ii, 2)
				If UseFlexDMD then UpdateFlexChar num, stat
				if (num < 40) and Table1.ShowDT = true then
					For Each obj In Digits(num)
						If chg And 1 Then obj.State=stat And 1
						chg=chg\2 : stat=stat\2
					Next
				else
			    end if
			Next
			If UseFlexDMD then FlexDMDUpdate
		End if
	End If
 End Sub
After adding the rest of the 'stock' code basic tests quickly show that we need to update the lookup dictionary mapping codes for segment to character conversion for the 14+1 segment display type. Comment out the existing FlexDMDDict.Add lines in FlexDictionary_Init and uncomment the test code in UpdateFlexChar, then launch the game and try and map the integer values displayed to characters (it's a pain!). Add the new character conversions to the lookup.
 
FlexDictionary_Init sub then becomes;
Sub FlexDictionary_Init

	Set FlexDMDDict = CreateObject("Scripting.Dictionary")

	FlexDMDDict.Add 0, " "
	FlexDMDDict.Add 63, "0"
	FlexDMDDict.Add 8704, "1"
	FlexDMDDict.Add 2139, "2"
	FlexDMDDict.Add 2127, "3"
	FlexDMDDict.Add 2150, "4"
	FlexDMDDict.Add 2157, "5"
	FlexDMDDict.Add 2173, "6"
	FlexDMDDict.Add 7, "7"
	FlexDMDDict.Add 2175, "8"
	FlexDMDDict.Add 2159, "9"
	
	 FlexDMDDict.Add 191, "0,"
	 FlexDMDDict.Add 8832, "1,"
	 FlexDMDDict.Add 2267, "2,"
	 FlexDMDDict.Add 2255, "3,"
	 FlexDMDDict.Add 2278, "4,"
	 FlexDMDDict.Add 2285, "5,"
	 FlexDMDDict.Add 2301, "6,"
	 FlexDMDDict.Add 135, "7,"
	 FlexDMDDict.Add 2303, "8,"
	 FlexDMDDict.Add 2287, "9,"
	
	FlexDMDDict.Add 2167, "A"
	FlexDMDDict.Add 10767, "B"
	FlexDMDDict.Add 57, "C"
	FlexDMDDict.Add 8719, "D"
	FlexDMDDict.Add 121, "E"
	FlexDMDDict.Add 113, "F"
	FlexDMDDict.Add 2109, "G"
	FlexDMDDict.Add 2166, "H"
	FlexDMDDict.Add 8713, "I"
	FlexDMDDict.Add 30, "J"
	FlexDMDDict.Add 5232, "K"
	FlexDMDDict.Add 56, "L"
	FlexDMDDict.Add 1334, "M"
	FlexDMDDict.Add 4406, "N"
	' "O" = 0
	FlexDMDDict.Add 2163, "P"
	FlexDMDDict.Add 4159, "Q"
	FlexDMDDict.Add 6259, "R"
	 ' "S" = 5
	FlexDMDDict.Add 8705, "T"
	FlexDMDDict.Add 62, "U"
	FlexDMDDict.Add 17456, "V"
	FlexDMDDict.Add 20534, "W"
	FlexDMDDict.Add 21760, "X"
	FlexDMDDict.Add 9472, "Y"
	FlexDMDDict.Add 17417, "Z"
	
	FlexDMDDict.Add &h400, "'"
	FlexDMDDict.Add 16640, ")"
	FlexDMDDict.Add 5120, "("
	FlexDMDDict.Add 2120, "="
	FlexDMDDict.Add 10275, "?"
	FlexDMDDict.Add 2112, "-"
	FlexDMDDict.Add 10861, "$"
	FlexDMDDict.Add 6144, "<"
	FlexDMDDict.Add 65535, "#"
	FlexDMDDict.Add 32576, "*"
	FlexDMDDict.Add 10816, "+"
	
End sub
Note that we only map uppercase A-Z and that we also need to map codes for numeric values followed by commas (i never saw a comma displayed following an A-Z character so couldn't map those, but probably didn't need to).
 
Now what to do with the other 'transitional' characters displayed on the LED's (when the text is moving right to left and pseudo random segments are lit)?.. For that we revisit the UpdateFlexChar sub and amend the test code block and just force a " " (space) to be returned for unknown/unmapped segment display values;
Sub UpdateFlexChar(id, value)
	'map segment code to character in LnChars arrays
	Dim chr
	
	if FlexDMDDict.Exists (value) then
		chr = FlexDMDDict.Item (value)
		if id < 20 then
			L1Chars(id) = chr
		elseif id < 40 then
			L2Chars(id - 20) = chr
		end if
	else
		chr = " " ' unrecognised transitioning characters just replace with a space
		if id < 20 then
			L1Chars(id) = chr
		elseif id < 40 then
			L2Chars(id - 20) = chr
		end if
	end if 	
End Sub

The flexDMD now mirrors the LED segment displays but it doesn't look pretty at all so we need to find a better font to fill the space. There's a problem though, if we use a font width of 5 (+ 1 for a spacer between characters) we fill 6*20=120 of the 128 available pixels/dots which is fine until you remember the commas -  the inbuilt flexDMD fonts are fixed width so the comma is a full width character (using another 6 pixel width for each comma displayed). So we need a custom font, and to fit the comma in make it appear zero width by placing it in the 'spacer' area between other characters and drop it down a pixel so it stands out.

 

e.g. offset the commas so something like this
 
commaspace.png
 
would look like
 
commanospace.png
 
If we're creating a custom font we may as well increase the height too to fill the dmd area while we're at it, 5x10 seems a good size for most characters
 
Like this;
 
sys80white.png
 
We then need to create a custom .fnt text file to match the font image .png file. This is just a lookup table telling it where to find the character in the image, what width etc to use, but also includes x and y offset values (change these change where the comma is displayed) and xadvance (which controls the width used before the next character, so set to 0 for the comma to have no impact on spacing of the other characters).
 
For a comma, chr(44), the .fnt file entry for the offsets looks like;
char id=44      x=206  y=10   width=2    height=14    xoffset=-2   yoffset=11    xadvance=0    page=0    chnl=0 
Nearly there now! Just need to amend the code in FlexDMD_Init sub to use the custom font .png and .fnt files, let's call the font files 'sys80' (make sure the name for the png file is reflected at the top of the .fnt file) and place them in a 'bonebstr.FlexDMD' folder in the VP tables folder (the folder name can be anything, i've use romname.FlexDMD here but you could call it Sys80.FlexDMD if you wanted to reuse the same folder for other tables).
 
FlexDMD_Init sub code change to use the custom font, from;
		'display font
		Set FlexDMDFont = FlexDMD.NewFont("FlexDMD.Resources.teeny_tiny_pixls-5.fnt", vbRed, vbBlue, 0)

to

		Dim fso,curdir
		Set fso = CreateObject("Scripting.FileSystemObject")
		curDir = fso.GetAbsolutePathName(".")
		FlexPath = curDir & "\bonebstr.FlexDMD\"
		
		'display font
		Set FlexDMDFont = FlexDMD.NewFont(FlexPath & "sys80.fnt", vbWhite, vbBlue, 0)
(i also changed the colour to white)
 
And then one final step, add a colour gradient to the sys80.png file so that the displayed text uses the Bone Busters logo colours. Don't ask me why but adding a Blue-Cyan gradient will display as Red-Yellow when the FlexDMDFont colour is set to white (might be something to do with colour complements? dunno, ask someone into graphics!) 
 
So sys80.png now looks like this
 
sys80gradpng.png
 
which when the table is run gives
 
bb.gif
 
and it's done!
 
Finished table script and files here;
 
 
Copy it all into your VP tables folder and rename the script to match the filename of the table. You can just paste the vbs code into the table script if you want but copying the vbs file means you just have to delete or rename it to rollback.
 
Only use the script with with the correct version of the table!. Link at top of this post.
 
 

Edited by scutters, 06 October 2021 - 12:05 PM.


#5 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 14 October 2021 - 10:05 AM

Logan's Run Segment Display Conversion to Flex

 

So, i thought i'd try adding a flex DMD to another system 80 table, Logan's Run (which is a reskin and uses the rom of Gottlieb's Arena 1987) as a reskin the result may be of interest to users outside the real DMD owners group too (there's no need to stick to segment displays for stuff that isn't an authentic recreation is there?!). 
 
As a system 80 rom so we already have the code the dictionary/lookup for segment display codes to character conversions with a font file we can use, but this time i wanted to try and add the code to the table embedding all the FlexDMD dependencies within the vpx table file itself (so no external folder dependencies for font files etc in the VPX table folder). 
 
As we can't embed a .fnt file within VPX this presents a few issues with the standard code, instead of dealing with the display as two lines of 20 characters which we pass as two strings to flex dmd to display using a font file we need to deal with the display as 40 distinct locations for characters on screen, and use changing character images in each one (with the images stored in the VPX file). This will introduce more overhead to the table script as the work won't be just palmed straight off to FlexDMD to deal with in it's own thread, and it'll need a bit more work in the table script (but luckily JP has already done something similar for Deadpool so i knew it could be done!).
 
First step build a load of small images for each character that will be displayed. Basic maths tells us a 6x11 image for 40 locations on a 128x32 screen and should give us a few pixels free.  Lot's of images to build... A-Z, 0-9, a few symbols and then 0-9 repeated with a dot included (it's a system 80, see last post re dot spacing), most character images will use the top left 5x10 pixels of the 6x11 with the bottom right pixel reserved for the dot.
 
e.g.
 
number.png
 

etc..
 
Link to complete set here
 
Then import to the table file;
 
imagemanager.png
 

With the characters all built and imported it should be just a copy and paste of the standard code now with a few tweaks here and there so that instead of dealing with the display as two lines of text for flexDMD it's dealt with as 40 images instead.
 
Add constants for each character image added to the table file. When passed to flexDMD the "VPX." prefix tells it to use the iamge in the table file (rather than a path);
 

'flexdmd image constants
Const DMD_A = "VPX.DMD_A"
Const DMD_B = "VPX.DMD_B"
Const DMD_C = "VPX.DMD_C"
Const DMD_D = "VPX.DMD_D"
Const DMD_E = "VPX.DMD_E"
Const DMD_F = "VPX.DMD_F"
Const DMD_G = "VPX.DMD_G"
Const DMD_H = "VPX.DMD_H"
Const DMD_I = "VPX.DMD_I"
Const DMD_J = "VPX.DMD_J"
Const DMD_K = "VPX.DMD_K"
Const DMD_L = "VPX.DMD_L"
Const DMD_M = "VPX.DMD_M"
Const DMD_N = "VPX.DMD_N"
Const DMD_O = "VPX.DMD_O"
Const DMD_P = "VPX.DMD_P"
Const DMD_Q = "VPX.DMD_Q"
Const DMD_R = "VPX.DMD_R"
Const DMD_S = "VPX.DMD_S"
Const DMD_T = "VPX.DMD_T"
Const DMD_U = "VPX.DMD_U"
Const DMD_V = "VPX.DMD_V"
Const DMD_W = "VPX.DMD_W"
Const DMD_X = "VPX.DMD_X"
Const DMD_Y = "VPX.DMD_Y"
Const DMD_Z = "VPX.DMD_Z"

Const DMD_1 = "VPX.DMD_1"
Const DMD_2 = "VPX.DMD_2"
Const DMD_3 = "VPX.DMD_3"
Const DMD_4 = "VPX.DMD_4"
Const DMD_6 = "VPX.DMD_6"
Const DMD_7 = "VPX.DMD_7"
Const DMD_8 = "VPX.DMD_8"
Const DMD_9 = "VPX.DMD_9"

Const DMD_1dot = "VPX.DMD_1dot"
Const DMD_2dot = "VPX.DMD_2dot"
Const DMD_3dot = "VPX.DMD_3dot"
Const DMD_4dot = "VPX.DMD_4dot"
Const DMD_6dot = "VPX.DMD_6dot"
Const DMD_7dot = "VPX.DMD_7dot"
Const DMD_8dot = "VPX.DMD_8dot"
Const DMD_9dot = "VPX.DMD_9dot"

Const DMD_Odot = "VPX.DMD_Odot"
Const DMD_Sdot = "VPX.DMD_Sdot"

Const DMD_Space = "VPX.DMD_Space"
Const DMD_SpaceDot = "VPX.DMD_SpaceDot"

Const DMD_Ampersand = "VPX.DMD_Ampersand"
Const DMD_Asterick = "VPX.DMD_Asterick"
Const DMD_BSlash = "VPX.DMD_BSlash"
Const DMD_CloseBracket = "VPX.DMD_CloseBracket"
Const DMD_Colon = "VPX.DMD_Colon"
Const DMD_Dollar = "VPX.DMD_Dollar"
Const DMD_Equals = "VPX.DMD_Equals"
Const DMD_Exclamation = "VPX.DMD_Exclamation"
Const DMD_FSlash = "VPX.DMD_FSlash"
Const DMD_GreaterThan = "VPX.DMD_GreaterThan"
Const DMD_Hash = "VPX.DMD_Hash"
Const DMD_LessThan = "VPX.DMD_LessThan"
Const DMD_Minus = "VPX.DMD_Minus"
Const DMD_OpenBracket = "VPX.DMD_OpenBracket"
Const DMD_Percent = "VPX.DMD_Percent"
Const DMD_Plus = "VPX.DMD_Plus"
Const DMD_Question = "VPX.DMD_Question"
Const DMD_Quote = "VPX.DMD_Quote"
Const DMD_SemiColon = "VPX.DMD_SemiColon"
Const DMD_SingleQuote = "VPX.DMD_SingleQuote"

Declare the flex objects and the toggle on/off flag in the script;


Const UseFlexDMD = 0	' 1 is on
Dim FlexDMD
DIm FlexDMDDict
Dim FlexDMDScene
Then create the routines
 
Sub FlexDMD_Init (add a call to this from table_init) needs updating to populate the 40 image locations (seg 0-39) with flex images (using spaces/blanks initially), and to set the .TableFile property first so flexdmd knows what table file to use;

Sub FlexDMD_Init() 'default/startup values

	' flex dmd variables
	DIm FlexDMDFont
	Dim FlexPath

	' populate the lookup dictionary for mapping display characters
	FlexDictionary_Init

	'setup flex dmd
	Set FlexDMD = CreateObject("FlexDMD.FlexDMD")
	If Not FlexDMD is Nothing Then
	
		
		FlexDMD.GameName = cGameName
		FlexDMD.TableFile = Table1.Filename & ".vpx"
		FlexDMD.RenderMode = 2
		FlexDMD.Width = 128
		FlexDMD.Height = 32
		FlexDMD.Clear = True
		FlexDMD.Run = True

		FlexDMD.LockRenderThread

		Set FlexDMDScene = FlexDMD.NewGroup("Scene")
		

		With FlexDMDScene
			'populate blank display
			.AddActor FlexDMD.NewImage("Back", "VPX.DMD_Background")
			'40 segment display holders
			.AddActor FlexDMD.NewImage("Seg0", DMD_Space)
			.GetImage("Seg0").SetAlignedPosition 4,0,0
			.AddActor FlexDMD.NewImage("Seg1", DMD_Space)
			.GetImage("Seg1").SetAlignedPosition 10,0,0
			.AddActor FlexDMD.NewImage("Seg2", DMD_Space)
			.GetImage("Seg2").SetAlignedPosition 16,0,0
			.AddActor FlexDMD.NewImage("Seg3", DMD_Space)
			.GetImage("Seg3").SetAlignedPosition 22,0,0
			.AddActor FlexDMD.NewImage("Seg4", DMD_Space)
			.GetImage("Seg4").SetAlignedPosition 28,0,0
			.AddActor FlexDMD.NewImage("Seg5", DMD_Space)
			.GetImage("Seg5").SetAlignedPosition 34,0,0
			.AddActor FlexDMD.NewImage("Seg6", DMD_Space)
			.GetImage("Seg6").SetAlignedPosition 40,0,0
			.AddActor FlexDMD.NewImage("Seg7", DMD_Space)
			.GetImage("Seg7").SetAlignedPosition 46,0,0
			.AddActor FlexDMD.NewImage("Seg8", DMD_Space)
			.GetImage("Seg8").SetAlignedPosition 52,0,0
			.AddActor FlexDMD.NewImage("Seg9", DMD_Space)
			.GetImage("Seg9").SetAlignedPosition 58,0,0
			.AddActor FlexDMD.NewImage("Seg10", DMD_Space)
			.GetImage("Seg10").SetAlignedPosition 64,0,0
			.AddActor FlexDMD.NewImage("Seg11", DMD_Space)
			.GetImage("Seg11").SetAlignedPosition 70,0,0
			.AddActor FlexDMD.NewImage("Seg12", DMD_Space)
			.GetImage("Seg12").SetAlignedPosition 76,0,0
			.AddActor FlexDMD.NewImage("Seg13", DMD_Space)
			.GetImage("Seg13").SetAlignedPosition 82,0,0
			.AddActor FlexDMD.NewImage("Seg14", DMD_Space)
			.GetImage("Seg14").SetAlignedPosition 88,0,0
			.AddActor FlexDMD.NewImage("Seg15", DMD_Space)
			.GetImage("Seg15").SetAlignedPosition 94,0,0
			.AddActor FlexDMD.NewImage("Seg16", DMD_Space)
			.GetImage("Seg16").SetAlignedPosition 100,0,0
			.AddActor FlexDMD.NewImage("Seg17", DMD_Space)
			.GetImage("Seg17").SetAlignedPosition 106,0,0
			.AddActor FlexDMD.NewImage("Seg18", DMD_Space)
			.GetImage("Seg18").SetAlignedPosition 112,0,0
			.AddActor FlexDMD.NewImage("Seg19", DMD_Space)
			.GetImage("Seg19").SetAlignedPosition 118,0,0

			.AddActor FlexDMD.NewImage("Seg20", DMD_Space)
			.GetImage("Seg20").SetAlignedPosition 4,16,0
			.AddActor FlexDMD.NewImage("Seg21", DMD_Space)
			.GetImage("Seg21").SetAlignedPosition 10,16,0
			.AddActor FlexDMD.NewImage("Seg22", DMD_Space)
			.GetImage("Seg22").SetAlignedPosition 16,16,0
			.AddActor FlexDMD.NewImage("Seg23", DMD_Space)
			.GetImage("Seg23").SetAlignedPosition 22,16,0
			.AddActor FlexDMD.NewImage("Seg24", DMD_Space)
			.GetImage("Seg24").SetAlignedPosition 28,16,0
			.AddActor FlexDMD.NewImage("Seg25", DMD_Space)
			.GetImage("Seg25").SetAlignedPosition 34,16,0
			.AddActor FlexDMD.NewImage("Seg26", DMD_Space)
			.GetImage("Seg26").SetAlignedPosition 40,16,0
			.AddActor FlexDMD.NewImage("Seg27", DMD_Space)
			.GetImage("Seg27").SetAlignedPosition 46,16,0
			.AddActor FlexDMD.NewImage("Seg28", DMD_Space)
			.GetImage("Seg28").SetAlignedPosition 52,16,0
			.AddActor FlexDMD.NewImage("Seg29", DMD_Space)
			.GetImage("Seg29").SetAlignedPosition 58,16,0
			.AddActor FlexDMD.NewImage("Seg30", DMD_Space)
			.GetImage("Seg30").SetAlignedPosition 64,16,0
			.AddActor FlexDMD.NewImage("Seg31", DMD_Space)
			.GetImage("Seg31").SetAlignedPosition 70,16,0
			.AddActor FlexDMD.NewImage("Seg32", DMD_Space)
			.GetImage("Seg32").SetAlignedPosition 76,16,0
			.AddActor FlexDMD.NewImage("Seg33", DMD_Space)
			.GetImage("Seg33").SetAlignedPosition 82,16,0
			.AddActor FlexDMD.NewImage("Seg34", DMD_Space)
			.GetImage("Seg34").SetAlignedPosition 88,16,0
			.AddActor FlexDMD.NewImage("Seg35", DMD_Space)
			.GetImage("Seg35").SetAlignedPosition 94,16,0
			.AddActor FlexDMD.NewImage("Seg36", DMD_Space)
			.GetImage("Seg36").SetAlignedPosition 100,16,0
			.AddActor FlexDMD.NewImage("Seg37", DMD_Space)
			.GetImage("Seg37").SetAlignedPosition 106,16,0
			.AddActor FlexDMD.NewImage("Seg38", DMD_Space)
			.GetImage("Seg38").SetAlignedPosition 112,16,0
			.AddActor FlexDMD.NewImage("Seg39", DMD_Space)
			.GetImage("Seg39").SetAlignedPosition 118,16,0

		End With
	
		FlexDMD.Stage.AddActor FlexDMDScene
		
		FlexDMD.Show = True
		FlexDMD.UnlockRenderThread

	End If

End Sub
Yeah i know... maybe i could have done all the .AddActors & .GetImage lines in a loop, but this is more readable and obvious what is happening (to me anyway)
 
Then in the FlexDictionary_Init change the dictionary lookup to use the VPX. image constants rather than characters;

Sub FlexDictionary_Init

	Set FlexDMDDict = CreateObject("Scripting.Dictionary")

	FlexDMDDict.Add 0, DMD_Space
	FlexDMDDict.Add 63, DMD_O
	FlexDMDDict.Add 8704, DMD_1
	FlexDMDDict.Add 2139, DMD_2
	FlexDMDDict.Add 2127, DMD_3
	FlexDMDDict.Add 2150, DMD_4
	FlexDMDDict.Add 2157, DMD_S
	FlexDMDDict.Add 2173, DMD_6
	FlexDMDDict.Add 7, DMD_7
	FlexDMDDict.Add 2175,DMD_8
	FlexDMDDict.Add 2159,DMD_9
	
	FlexDMDDict.Add 191,DMD_Odot
	FlexDMDDict.Add 8832, DMD_1dot
	FlexDMDDict.Add 2267, DMD_2dot
	FlexDMDDict.Add 2255, DMD_3dot
	FlexDMDDict.Add 2278, DMD_4dot
	FlexDMDDict.Add 2285, DMD_Sdot
	FlexDMDDict.Add 2301, DMD_6dot
	FlexDMDDict.Add 135, DMD_7dot
	FlexDMDDict.Add 2303, DMD_8dot
	FlexDMDDict.Add 2287, DMD_9dot
	
	FlexDMDDict.Add 2167, DMD_A
	FlexDMDDict.Add 10767, DMD_B
	FlexDMDDict.Add 57, DMD_C
	FlexDMDDict.Add 8719, DMD_D
	FlexDMDDict.Add 121, DMD_E
	FlexDMDDict.Add 113, DMD_F
	FlexDMDDict.Add 2109, DMD_G
	FlexDMDDict.Add 2166, DMD_H
	FlexDMDDict.Add 8713, DMD_I
	FlexDMDDict.Add 30, DMD_J
	FlexDMDDict.Add 5232, DMD_K
	FlexDMDDict.Add 56, DMD_L
	FlexDMDDict.Add 1334, DMD_M
	FlexDMDDict.Add 4406, DMD_N
	' "O" = 0
	FlexDMDDict.Add 2163, DMD_P
	FlexDMDDict.Add 4159, DMD_Q
	FlexDMDDict.Add 6259, DMD_R
	 ' "S" = 5
	FlexDMDDict.Add 8705, DMD_T
	FlexDMDDict.Add 62, DMD_U
	FlexDMDDict.Add 17456, DMD_V
	FlexDMDDict.Add 20534, DMD_W
	FlexDMDDict.Add 21760, DMD_X
	FlexDMDDict.Add 9472, DMD_Y
	FlexDMDDict.Add 17417, DMD_Z
	
	FlexDMDDict.Add &h400,DMD_SingleQuote
	FlexDMDDict.Add 16640, DMD_CloseBracket
	FlexDMDDict.Add 5120, DMD_OpenBracket
	FlexDMDDict.Add 2120, DMD_Equals
	FlexDMDDict.Add 10275, DMD_Question
	FlexDMDDict.Add 2112, DMD_Minus
	FlexDMDDict.Add 10861, DMD_Dollar
	FlexDMDDict.Add 6144, DMD_GreaterThan
	FlexDMDDict.Add 65535, DMD_Hash
	FlexDMDDict.Add 32576, DMD_Asterick
	FlexDMDDict.Add 10816, DMD_Plus
	
End sub
The base table doesn't have a desktop segment score display so there is no existing DisplayTimer_Timer event with a call to ChangedLEDs to use, so add a timer to the the table and a cut down version of the DisplayTimer_Timer code (as no need to loop through individual segments for desktop scoring like in most cases). 

Sub DisplayTimer_Timer

	If UseFlexDMD then 
		Dim ChgLED, ii, num, stat
		ChgLED=Controller.ChangedLEDs(&Hffffffff, &Hffffffff)

		If Not IsEmpty(ChgLED)Then
			If Not FlexDMD is Nothing Then FlexDMD.LockRenderThread
			For ii=0 To UBound(chgLED)
				num=chgLED(ii, 0) : stat=chgLED(ii, 2)
				UpdateFlexChar num, stat
			Next
			If Not FlexDMD is Nothing Then FlexDMD.UnlockRenderThread
		End if
		
	Else
		DisplayTimer.Enabled = False
	End If
 End Sub
Note that the flexdmd render thread is locked/unlocked in the DisplayTimer_Timer event as well now instead of in a FlexDMDUpdate sub (as we don't need to concatanate strings for flexDMD to use with a font file, a FlexDMDUpdate sub won't be used in this code). 
 
Last add the code translation sub, to map the segment display id and value from the rom to an image location on the dmd and the characters image for flex to use;

Sub UpdateFlexChar(id, value)

	If id < 40 Then
		if FlexDMDDict.Exists (value) then
			FlexDMDScene.GetImage("Seg" & id).Bitmap = FlexDMD.NewImage("", FlexDMDDict.Item (value)).Bitmap
		Else
			FlexDMDScene.GetImage("Seg" & id).Bitmap = FlexDMD.NewImage("", DMD_Space).Bitmap
		end if
	End If

End Sub

Add the usual code to cleanup flexdmd objects on table_exit

Sub Table1_Exit()
	Controller.Pause = False
	Controller.Stop
	If UseFlexDMD then
		If Not FlexDMD is Nothing Then 
			FlexDMD.Show = False
			FlexDMD.Run = False
			FlexDMD = NULL
		End if
	End if
End Sub

and the result when UseFlexDMD is set to 1 (with the default freezy display on top for comparison) gives;

 

logans.gif

 

In the final version i also added some checks and extra images to be used as overlay to add some Logan's Run game specific text instead of Arena game text (e.g. 'PREMIER WARRIORS' is overlayed with 'PREMIER RUNNERS'), i won't describe them here, but you should be able to see the differences where used in the final code below compared with the code above

 

Dim FlexDMD
DIm FlexDMDDict
Dim FlexDMDScene
Dim PremierFlag, BottomLine(19)

Sub FlexDMD_Init() 'default/startup values

	' flex dmd variables
	DIm FlexDMDFont
	Dim FlexPath

	' populate the lookup dictionary for mapping display characters
	FlexDictionary_Init

	dim i
	for i = 0 to 19
		BottomLine(i) = 0
	next
	PremierFlag = False
	
	'setup flex dmd
	Set FlexDMD = CreateObject("FlexDMD.FlexDMD")
	If Not FlexDMD is Nothing Then
	
		
		FlexDMD.GameName = cGameName
		FlexDMD.TableFile = Table1.Filename & ".vpx"
		FlexDMD.RenderMode = 2
		FlexDMD.Width = 128
		FlexDMD.Height = 32
		FlexDMD.Clear = True
		FlexDMD.Run = True

		FlexDMD.LockRenderThread

		Set FlexDMDScene = FlexDMD.NewGroup("Scene")
		

		With FlexDMDScene
			'populate blank display
			.AddActor FlexDMD.NewImage("Back", "VPX.DMD_Background")
			'40 segment display holders
			.AddActor FlexDMD.NewImage("Seg0", DMD_Space)
			.GetImage("Seg0").SetAlignedPosition 4,0,0
			.AddActor FlexDMD.NewImage("Seg1", DMD_Space)
			.GetImage("Seg1").SetAlignedPosition 10,0,0
			.AddActor FlexDMD.NewImage("Seg2", DMD_Space)
			.GetImage("Seg2").SetAlignedPosition 16,0,0
			.AddActor FlexDMD.NewImage("Seg3", DMD_Space)
			.GetImage("Seg3").SetAlignedPosition 22,0,0
			.AddActor FlexDMD.NewImage("Seg4", DMD_Space)
			.GetImage("Seg4").SetAlignedPosition 28,0,0
			.AddActor FlexDMD.NewImage("Seg5", DMD_Space)
			.GetImage("Seg5").SetAlignedPosition 34,0,0
			.AddActor FlexDMD.NewImage("Seg6", DMD_Space)
			.GetImage("Seg6").SetAlignedPosition 40,0,0
			.AddActor FlexDMD.NewImage("Seg7", DMD_Space)
			.GetImage("Seg7").SetAlignedPosition 46,0,0
			.AddActor FlexDMD.NewImage("Seg8", DMD_Space)
			.GetImage("Seg8").SetAlignedPosition 52,0,0
			.AddActor FlexDMD.NewImage("Seg9", DMD_Space)
			.GetImage("Seg9").SetAlignedPosition 58,0,0
			.AddActor FlexDMD.NewImage("Seg10", DMD_Space)
			.GetImage("Seg10").SetAlignedPosition 64,0,0
			.AddActor FlexDMD.NewImage("Seg11", DMD_Space)
			.GetImage("Seg11").SetAlignedPosition 70,0,0
			.AddActor FlexDMD.NewImage("Seg12", DMD_Space)
			.GetImage("Seg12").SetAlignedPosition 76,0,0
			.AddActor FlexDMD.NewImage("Seg13", DMD_Space)
			.GetImage("Seg13").SetAlignedPosition 82,0,0
			.AddActor FlexDMD.NewImage("Seg14", DMD_Space)
			.GetImage("Seg14").SetAlignedPosition 88,0,0
			.AddActor FlexDMD.NewImage("Seg15", DMD_Space)
			.GetImage("Seg15").SetAlignedPosition 94,0,0
			.AddActor FlexDMD.NewImage("Seg16", DMD_Space)
			.GetImage("Seg16").SetAlignedPosition 100,0,0
			.AddActor FlexDMD.NewImage("Seg17", DMD_Space)
			.GetImage("Seg17").SetAlignedPosition 106,0,0
			.AddActor FlexDMD.NewImage("Seg18", DMD_Space)
			.GetImage("Seg18").SetAlignedPosition 112,0,0
			.AddActor FlexDMD.NewImage("Seg19", DMD_Space)
			.GetImage("Seg19").SetAlignedPosition 118,0,0

			.AddActor FlexDMD.NewImage("Seg20", DMD_Space)
			.GetImage("Seg20").SetAlignedPosition 4,16,0
			.AddActor FlexDMD.NewImage("Seg21", DMD_Space)
			.GetImage("Seg21").SetAlignedPosition 10,16,0
			.AddActor FlexDMD.NewImage("Seg22", DMD_Space)
			.GetImage("Seg22").SetAlignedPosition 16,16,0
			.AddActor FlexDMD.NewImage("Seg23", DMD_Space)
			.GetImage("Seg23").SetAlignedPosition 22,16,0
			.AddActor FlexDMD.NewImage("Seg24", DMD_Space)
			.GetImage("Seg24").SetAlignedPosition 28,16,0
			.AddActor FlexDMD.NewImage("Seg25", DMD_Space)
			.GetImage("Seg25").SetAlignedPosition 34,16,0
			.AddActor FlexDMD.NewImage("Seg26", DMD_Space)
			.GetImage("Seg26").SetAlignedPosition 40,16,0
			.AddActor FlexDMD.NewImage("Seg27", DMD_Space)
			.GetImage("Seg27").SetAlignedPosition 46,16,0
			.AddActor FlexDMD.NewImage("Seg28", DMD_Space)
			.GetImage("Seg28").SetAlignedPosition 52,16,0
			.AddActor FlexDMD.NewImage("Seg29", DMD_Space)
			.GetImage("Seg29").SetAlignedPosition 58,16,0
			.AddActor FlexDMD.NewImage("Seg30", DMD_Space)
			.GetImage("Seg30").SetAlignedPosition 64,16,0
			.AddActor FlexDMD.NewImage("Seg31", DMD_Space)
			.GetImage("Seg31").SetAlignedPosition 70,16,0
			.AddActor FlexDMD.NewImage("Seg32", DMD_Space)
			.GetImage("Seg32").SetAlignedPosition 76,16,0
			.AddActor FlexDMD.NewImage("Seg33", DMD_Space)
			.GetImage("Seg33").SetAlignedPosition 82,16,0
			.AddActor FlexDMD.NewImage("Seg34", DMD_Space)
			.GetImage("Seg34").SetAlignedPosition 88,16,0
			.AddActor FlexDMD.NewImage("Seg35", DMD_Space)
			.GetImage("Seg35").SetAlignedPosition 94,16,0
			.AddActor FlexDMD.NewImage("Seg36", DMD_Space)
			.GetImage("Seg36").SetAlignedPosition 100,16,0
			.AddActor FlexDMD.NewImage("Seg37", DMD_Space)
			.GetImage("Seg37").SetAlignedPosition 106,16,0
			.AddActor FlexDMD.NewImage("Seg38", DMD_Space)
			.GetImage("Seg38").SetAlignedPosition 112,16,0
			.AddActor FlexDMD.NewImage("Seg39", DMD_Space)
			.GetImage("Seg39").SetAlignedPosition 118,16,0

			'score text overlays last
			.AddActor FlexDMD.NewImage("PremierRunners", "VPX.DMD_PremierRunners")
			.GetImage("PremierRunners").Visible = False
			.AddActor FlexDMD.NewImage("LogansRun", "VPX.DMD_LogansRunLogo")
			.GetImage("LogansRun").Visible = False
		
		End With
	
		FlexDMD.Stage.AddActor FlexDMDScene
		
		FlexDMD.Show = True
		FlexDMD.UnlockRenderThread

	End If

End Sub


Sub FlexDictionary_Init

	Set FlexDMDDict = CreateObject("Scripting.Dictionary")

	FlexDMDDict.Add 0, DMD_Space
	FlexDMDDict.Add 63, DMD_O
	FlexDMDDict.Add 8704, DMD_1
	FlexDMDDict.Add 2139, DMD_2
	FlexDMDDict.Add 2127, DMD_3
	FlexDMDDict.Add 2150, DMD_4
	FlexDMDDict.Add 2157, DMD_S
	FlexDMDDict.Add 2173, DMD_6
	FlexDMDDict.Add 7, DMD_7
	FlexDMDDict.Add 2175,DMD_8
	FlexDMDDict.Add 2159,DMD_9
	
	FlexDMDDict.Add 191,DMD_Odot
	FlexDMDDict.Add 8832, DMD_1dot
	FlexDMDDict.Add 2267, DMD_2dot
	FlexDMDDict.Add 2255, DMD_3dot
	FlexDMDDict.Add 2278, DMD_4dot
	FlexDMDDict.Add 2285, DMD_Sdot
	FlexDMDDict.Add 2301, DMD_6dot
	FlexDMDDict.Add 135, DMD_7dot
	FlexDMDDict.Add 2303, DMD_8dot
	FlexDMDDict.Add 2287, DMD_9dot
	
	FlexDMDDict.Add 2167, DMD_A
	FlexDMDDict.Add 10767, DMD_B
	FlexDMDDict.Add 57, DMD_C
	FlexDMDDict.Add 8719, DMD_D
	FlexDMDDict.Add 121, DMD_E
	FlexDMDDict.Add 113, DMD_F
	FlexDMDDict.Add 2109, DMD_G
	FlexDMDDict.Add 2166, DMD_H
	FlexDMDDict.Add 8713, DMD_I
	FlexDMDDict.Add 30, DMD_J
	FlexDMDDict.Add 5232, DMD_K
	FlexDMDDict.Add 56, DMD_L
	FlexDMDDict.Add 1334, DMD_M
	FlexDMDDict.Add 4406, DMD_N
	' "O" = 0
	FlexDMDDict.Add 2163, DMD_P
	FlexDMDDict.Add 4159, DMD_Q
	FlexDMDDict.Add 6259, DMD_R
	 ' "S" = 5
	FlexDMDDict.Add 8705, DMD_T
	FlexDMDDict.Add 62, DMD_U
	FlexDMDDict.Add 17456, DMD_V
	FlexDMDDict.Add 20534, DMD_W
	FlexDMDDict.Add 21760, DMD_X
	FlexDMDDict.Add 9472, DMD_Y
	FlexDMDDict.Add 17417, DMD_Z
	
	FlexDMDDict.Add &h400,DMD_SingleQuote
	FlexDMDDict.Add 16640, DMD_CloseBracket
	FlexDMDDict.Add 5120, DMD_OpenBracket
	FlexDMDDict.Add 2120, DMD_Equals
	FlexDMDDict.Add 10275, DMD_Question
	FlexDMDDict.Add 2112, DMD_Minus
	FlexDMDDict.Add 10861, DMD_Dollar
	FlexDMDDict.Add 6144, DMD_GreaterThan
	FlexDMDDict.Add 65535, DMD_Hash
	FlexDMDDict.Add 32576, DMD_Asterick
	FlexDMDDict.Add 10816, DMD_Plus
	
End sub

Sub UpdateFlexChar(id, value)

	If id < 40 Then
		if FlexDMDDict.Exists (value) then
			FlexDMDScene.GetImage("Seg" & id).Bitmap = FlexDMD.NewImage("", FlexDMDDict.Item (value)).Bitmap
		Else
			FlexDMDScene.GetImage("Seg" & id).Bitmap = FlexDMD.NewImage("", DMD_Space).Bitmap
		end if
		'basic text tracking
		if id =2 then
			if value = 2163 Then
				PremierFlag = True
			Else	
				PremierFlag = False
			end if
		End if
		if id > 19 Then
			BottomLine(id - 20) = value
		end if
	End If
	If Controller.Solenoid(10) = True Then
		'ball in play. Hide premier runners / logans run text
		FlexDMDScene.GetImage("LogansRun").Visible = False
		FlexDMDScene.GetImage("PremierRunners").Visible = False
	
	Else
		'overwrite text with image checks
		if PremierFlag = True Then
			FlexDMDScene.GetImage("LogansRun").Visible = False
			FlexDMDScene.GetImage("PremierRunners").Visible = True
		elseif join(BottomLine,"") = 0 Then
			FlexDMDScene.GetImage("LogansRun").Visible = True
			FlexDMDScene.GetImage("PremierRunners").Visible = False
		Else
			'in game
			FlexDMDScene.GetImage("LogansRun").Visible = False
			FlexDMDScene.GetImage("PremierRunners").Visible = False
		End If
	End if
	

End Sub

Sub DisplayTimer_Timer

	If UseFlexDMD then 
		Dim ChgLED, ii, num, stat
		ChgLED=Controller.ChangedLEDs(&Hffffffff, &Hffffffff)

		If Not IsEmpty(ChgLED)Then
			If Not FlexDMD is Nothing Then FlexDMD.LockRenderThread
			For ii=0 To UBound(chgLED)
				num=chgLED(ii, 0) : stat=chgLED(ii, 2)
				UpdateFlexChar num, stat
			Next
			If Not FlexDMD is Nothing Then FlexDMD.UnlockRenderThread
		End if
		
	Else
		DisplayTimer.Enabled = False
	End If
 End Sub

Note - as i've updated the table.vpx file rather than just add a .vbs script and external files i now count this as a 'table mod'. It will be up to the table author if he wants to release it (he has a copy), i won't post a link to the table here other than the main table download page.


Edited by scutters, 20 October 2021 - 05:44 PM.


#6 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 14 October 2021 - 05:21 PM

you forgot to post a link to a zip of the font images to import?


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#7 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 14 October 2021 - 09:07 PM

you forgot to post a link to a zip of the font images to import?

 

Well done weisshund!, spotted deliberate omission no.2 as well. Was just checking you were reading  ;) . Link now added..



#8 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 14 October 2021 - 10:39 PM

 

you forgot to post a link to a zip of the font images to import?

 

Well done weisshund!, spotted deliberate omission no.2 as well. Was just checking you were reading  ;) . Link now added..

 

 

now to paint all characters Pink


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#9 jpsalas

jpsalas

    Grand Schtroumpf

  • VIP
  • 7,300 posts
  • Location:I'm Spanish, but I live in Oslo (Norway)

  • Flag: Norway

  • Favorite Pinball: I like both new and old, but I guess I prefer modern tables with some rules and goals to achieve.



Posted 15 October 2021 - 02:01 AM

Nice!  :otvclap:  :tup:


If you want to check my latest uploads then click on the image below:

 

vp.jpg

 

Next table? A tribute table to Stern's Foo Fighters


#10 Mike DA Spike

Mike DA Spike

    Pinball Fan

  • Platinum Supporter
  • 1,279 posts
  • Location:Hoofddorp

  • Flag: Netherlands

  • Favorite Pinball: Too many to mention

Posted 15 October 2021 - 05:52 AM

How can we get the table creators to a point, that they can implement this in the tables ?
So the scripting is there, font's etc in the VPX embedded and that a lazy end user (like me  :tongue3:  )  only needs to enable or disabled the feature in the script ?


331ddabcc742f0ba74791e946eb0f791.gif Try PinballX Database manager as a replacement of PinballX's game list manager
With special thanks to Scutters 


#11 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 15 October 2021 - 08:02 AM

How can we get the table creators to a point, that they can implement this in the tables ?
So the scripting is there, font's etc in the VPX embedded and that a lazy end user (like me  :tongue3:  )  only needs to enable or disabled the feature in the script ?

 mostly just make the timer enabled and flexDMD ini based on if user option = Yes

 

might be a few other things, i would have to look over it more, but really nothing more than that


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#12 Mike DA Spike

Mike DA Spike

    Pinball Fan

  • Platinum Supporter
  • 1,279 posts
  • Location:Hoofddorp

  • Flag: Netherlands

  • Favorite Pinball: Too many to mention

Posted 15 October 2021 - 02:03 PM


How can we get the table creators to a point, that they can implement this in the tables ?
So the scripting is there, font's etc in the VPX embedded and that a lazy end user (like me  :tongue3:  )  only needs to enable or disabled the feature in the script ?

 mostly just make the timer enabled and flexDMD ini based on if user option = Yes
 
might be a few other things, i would have to look over it more, but really nothing more than that
Nothing more than that ?@scutters did a hell of a job, and you said it is easy ?
Jk mate.
Some dmd's like the aliens 2.0, mr and ms pacman looks pretty cool with special (animated) background and fonts that are the theme of the table.
Little bit more work, but brings my real dmd to a higher level.

Thanks scutters

Edited by Mike DA Spike, 15 October 2021 - 02:05 PM.

331ddabcc742f0ba74791e946eb0f791.gif Try PinballX Database manager as a replacement of PinballX's game list manager
With special thanks to Scutters 


#13 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 15 October 2021 - 06:10 PM

 

 

Nothing more than that ?@scutters did a hell of a job, and you said it is easy ?
Jk mate.
Some dmd's like the aliens 2.0, mr and ms pacman looks pretty cool with special (animated) background and fonts that are the theme of the table.
Little bit more work, but brings my real dmd to a higher level.

Thanks scutters

 

 

Well you asked

 

 

 

 that a lazy end user (like me   :tongue3:  )  only needs to enable or disabled the feature in the script ?

so that is how you could have it in the script and just have a lazy person chose to enable or disable


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#14 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 16 October 2021 - 04:13 AM

@Scutters

 

You may want to put the "Usual" table_exit sub in the post

as a lot of people do not know what the "usual" is, i still run into tables with no exit sub

 

now for more tutorials

for others

I wish i knew how to determine the segment values (what you are calling a dictionary)

well i mean i know how obviously because i am doing it, but in a much different more complicated manner that is longer in the table script than this entire thread will be

 

this works with other things besides flexDMD

if you equate the dict value to a character string, you can also output to text boxes

which some may find useful


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#15 LynnInDenver

LynnInDenver

    Pinball Fan

  • Members
  • PipPipPipPip
  • 570 posts
  • Location:Denver

  • Flag: United States of America

  • Favorite Pinball: Genie

Posted 16 October 2021 - 12:23 PM

@Scutters

 

You may want to put the "Usual" table_exit sub in the post

as a lot of people do not know what the "usual" is, i still run into tables with no exit sub

 

now for more tutorials

for others

I wish i knew how to determine the segment values (what you are calling a dictionary)

well i mean i know how obviously because i am doing it, but in a much different more complicated manner that is longer in the table script than this entire thread will be

 

this works with other things besides flexDMD

if you equate the dict value to a character string, you can also output to text boxes

which some may find useful

I found such things useful in terms of decoding for PinUp Player... although I'm only really using it on two Atari tables right now to get the apron display on my FullDMD. Ironically, not for streaming, although it's been useful for that, but more for when we have guests over so that they can see scores without crowding.



#16 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 20 October 2021 - 06:25 PM

@Scutters

 

You may want to put the "Usual" table_exit sub in the post

as a lot of people do not know what the "usual" is, i still run into tables with no exit sub

 

now for more tutorials

for others

I wish i knew how to determine the segment values (what you are calling a dictionary)

well i mean i know how obviously because i am doing it, but in a much different more complicated manner that is longer in the table script than this entire thread will be

 

this works with other things besides flexDMD

if you equate the dict value to a character string, you can also output to text boxes

which some may find useful

 

Table_Exit - fair point, added  ;)

 

 

For the lookup/dictionary mapping values;

 

The easiest way is if an existing script conversion FlexDictionary_Init for a 'similar' rom exists, then copy and paste that init.

 

If that doesn't exist then maybe the best way is to map the dictionary values first before adding the flexdmd code. Using a table you're familiar with (LTD Time Machine);

 

You already have a LED(30) array for the display LED's, add another array of the same size, lets say LEDMAPPING(30)

 

Then in sub DisplayTimer_Timer add a code line LEDMAPPING(num) = num & vbtab & stat so it becomes;

Sub DisplayTimer_Timer
Dim ChgLED, ii, num, chg, stat, obj
	ChgLED = Controller.ChangedLEDs (&Hffffffff, &Hffffffff)
	If Not IsEmpty (ChgLED) Then
		For ii = 0 To UBound (chgLED)
			num = chgLED (ii, 0) : chg = chgLED (ii, 1) : stat = chgLED (ii, 2)
			LEDMAPPING(num) = num & vbtab & stat
			For Each obj In LED (num)
			If chg And 1 Then obj.State = stat And 1
			chg = chg \ 2 : stat = stat \ 2
			Next
		Next
	End If
End Sub	

num is the segment display number and stat is the integer/hex value representing the segments lit. The LEDMAPPING array will now track changes to segments and their values.

 

In Table1_KeyDown sub add code to display that in a msgbox, i used left magna save by adding;

if Keycode = LeftMagnaSave then
	msgbox Join(LEDMAPPING, vbCrlf)
end if 

When any unknown display characters are shown press left magna

 

ltdtm0.png

 

So segment value for position one is 63 which maps to a character display value of 0 in the score display, position 3 (the 4th position) is 109 which would map to 5 etc.  Make a note of the mappings (roms displaying 0-9 and blanks only don't take long [all you have to do is add a credit at a time], but alphanumerics can take a while) and you should be able to build the code for FlexDictionary_Init sub, for the 63 and 109 values they'd map as;

	FlexDMDDict.Add 63, "0"
	FlexDMDDict.Add 109, "5"

I think it is safe to assume that a value of 0 will always map as a character display value of " ".

 

Once all mappings are complete remove all references to LEDMAPPINGS in the code and add code for flexDMD, textboxes or whatever.

 

Hope that helps..  i looked around hoping to find existing lookup tables to use for all the mappings but couldn't find any. I think this way is easier and more portable than the original method i'd used which was displaying all values not mapped in as numeric values in the flexdmd labels anyway.



#17 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 20 October 2021 - 07:15 PM

easy code wise

a bit long and tedious in dictionary building, but no way around that i suppose.

 

Heavy Metal's ROM goes through an attract mode sequence where all the LED arrays cycles through all of

the possible characters they can display

Which if i made your pop up also pause VPM, would be great for doing that ROM

as you would get the value for all digits in each array

cause they will cycle the same character in each digit of each player's array

 

so you get

 

000000
000000
000000
000000

111111
111111
111111
111111

 

and so on.
Now i wish ALL ROMs did that LOL

 

Not sure if you you have heavy metal
if not, look at it just for the code aspect
You will see the functional but terribly long drawn out way i did it
which is hard for a low end PC to do, since sometimes low end PC's have trouble keeping fast timers going.

 

At some point i would like to try to revisit it and see if i can not streamline the process using your way
and see if it does not run better maybe.

 

Not to mention, this is much easier to pretend change a ROM
since you can look for a word and say if display = this word, then show another word instead.

Makes using a ROM to drive an otherwise totally different table with different theme and layout a lot nicer
Then you dont have the DMD on Mad Max: Road Warrior saying Get that Wabbit!

All numeric ROMs are a non issue obviously, but the later LED displays that showed wording, well they just look wonky
when a totally out of theme phrase comes up on a rethemed table LOL


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#18 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 20 October 2021 - 09:44 PM

Sorry, don't have Heavy Metal (nothing to do with your table - just not my style). I'll download and have a look though, sounds interesting!

 

The problem on the segment alpha numeric displays is where the rom likes to play transitions across the screen before the final text is formed, so the characters displayed don't always map to alphanumeric characters (triangles formed in the segments etc), and is tricky to form a match to replace words without waiting for the scrolling to finish (which might look a bit weird). I did manage to it for a couple of places in Logans Run so it can be done though. And yeah, all numeric displays are definitely easier, there you can just overlay text where required when lamp states or whatever change if you want too.

 

Edit - just had a quick look at the HM code... Wow!, i think i get what you're doing, must have been hell to do that. Pure dedication man!


Edited by scutters, 20 October 2021 - 09:53 PM.


#19 wiesshund

wiesshund

    VPF Legend

  • Members
  • PipPipPipPipPipPipPip
  • 11,859 posts

  • Flag: United States of America

  • Favorite Pinball: How many can i have?

Posted 21 October 2021 - 12:51 AM

basically i have the ROM controlling the laps for the desktop backdrop score, same as everyone has been doing for years
if they are not wanted/needed they are hidden but still run

 

Then i am looking at every single digit, at what segments are lit

 

and then there is a shit load of
if segment1 is on and segment 2 is on and segment 3 is off and segment 4 is on and segment 5 is on and segment 6 is off and segment 7 is on then number = 2

for every digit of every array for 2 player arrays and a coin array and a ball array

 

and that is a ton of looking really fast

add to that, the fact that the damned displays blink, and not only is this being used to determine what the DMD should display as far as scores go
But also to determine how many players are in the game, which one is playing, what ball are they on etc.

Not for the table logic, the ROM controls that as normal
but to properly operate the DMD and some of the sounds
Mind you that table was never meant to have a DMD or music or those sounds or the hell balls or the insanity mode physics etc.

 

But yea, i would like to try and simply some of that giant blob of stuff and see if it helps on low end machines
as a lot of people with low end machines can not keep all those high speed timers running together
They can play in stock mode 0, but not with the DMD etc running, it may not help given that the DMD is actually 720x404 and even downscaled to 128 x 32 pixels
(and it will run as 720x404, but you need a lot of spare CPU cycles) it adds a lot of CPU load rendering the DMD content

 

Looks neat, but you can see it killing the CPU here, screwing the timers all up and events drift out of sync



So i dont want to make it run like that
but i do want to see if this way could simplify it to be a bit less CPU intensive, maybe not but worth a shot


If you feel the need to empty your wallet in my direction, i don't have any way to receive it anyways

Spend it on Hookers and Blow


#20 scutters

scutters

    Pinball Fan

  • Members
  • PipPipPipPip
  • 539 posts

  • Flag: England

  • Favorite Pinball: Addams Family

Posted 21 October 2021 - 07:50 AM

Impressive stuff!. Changing to use a dictionary lookup and holding arrays with the character text would definitely be less code in the script than all the checks on what segments are lit, would it be any quicker? hard to say but my guess is it should be.

Give me a shout if you need a hand.