Vintage Simulator is a (currently 100% FREE) custom libretro front-end (sharing zero code with RetroArch) with the following features:
- Implements most of the libretro API
- Run several emulators at the same time
- Full Lua scripting API
- 3D graphics and sound
- Easily load most 3D models such as 3DS or OBJ
- Bullet Physics engine
- Plugins
- includes LOVE plugin (for UI screens in separate windows or generating textures etc.)
VSIM is a work in progress. VSIM is currently primarily aimed at programmers who are interested in things like emulation, Lua, 3D models, or physics simulation. For example, it can provide a good starting point for creating your own custom front-end for libretro. The hope is that some developers will be interested and will create plugins that add functionality or content that non-programmers can easily access.
| Key | What It Does |
|---|---|
F5 |
Install plugin |
Ctrl-F1 |
Open help in browser |
` |
Toggle Lua console |
1-9 |
Zoom and interact with emulator #N |
F7 |
Put zoomed emulator in full screen mode |
Ctrl-F10 |
Exit |
Currently https://reddit.com/r/vsim is the best place to find plugins or post any you create.
To install a plugin press F5, paste in the plugin URL with Control-V, then hit ENTER. You will need to restart the program before the plugin will be active.
To create a plugin, first make a directory in [VSIM root]/lua/. Plugins can contain files and/or lua code in init.lua. You can test your plugin by adding it to the list in the [VSIM root]/plugins file and restarting VSIM. When it is ready open the console and type plugin_makezip("mydir")[ENTER] where mydir is the subdirectory of [VSIM root]/lua/ (just the folder name, not a full path). It will create a .7z file in [VSIM root]/lua/plugins/forupload which you can upload to your host. Then just share the URL for your plugin.
Run selected emulator (set with emu.core()) with an optional command/rom/binary and options table with emulator variable settings. Note: if there is a cores.cfg file it is parsed by the utils plugin at program start and placed in vsimcorecfg. NOTE: YOU MUST HAVE THE REQUIRED ROM OR OTHER FILES INSTALLED IN THE EXPECTED LOCATIONS. You may run the same core multiple times simultaneously or several different cores depending on system resources.
emu.core('snes9x')
emulatorid = emu.emulate(-1, 'topgear.sfc', vsimcorecfg.snes9x) specify the emulator core to use with emulate() commmands
emu.core("mame") -- needs mame.dllget memory data from emulator; returns a lua string
get size of memory from emulator
change emulator memory data
emuN = 0
bank = 2
offset = 1024 -- C64 screen mem start
str = "123456789"
-- (this was tested on vice-libretro)
emu.setmem(emuN, bank, offset, str)reset emulator machine
specify emulator option
set this emu option to string "true" to pause emulation
set this emu option to string "true" to turn on positional audio from emulator
insert virtual disk into emulator drive
eject disk from virtual emulator drive
delete emulator and node
run emulator in the full window
Rez (instantiate) a 3d model (3ds dae xml x mdl lwo obj mesh bsp md2 md3 stl ply) NOTE: Not all models are compatible. YMMV.
model.rez('mymodel.3ds')local mynodeid = model.rez('myhouse.obj')change selected node which subsequent commands like pos() and rot() affect
(model.put "true"): selected node casts a shadow (does not work on high-poly meshes)
create a sky dome; texturePerc=0..1, spherePerc=0..2
set this variable on any node to change ambient light color of entire scene
put('VSIM_AMBIENT', 255,95, 95, 95)set an attribute on a node or the system
set this attribute on any node to string "true" to show VSIM internal messages in STDOUT
make the selected node a child of nodeid
move the currently selected node
scale the currently selected node
rotate the currently selected node
create a mesh from the specified tables
c = { r=255, g=255, b=255, a=255 }
v = { { pos = {x=0,y=0,z=0}, color=c,
texturecoords = {u=0, v=0},
normal = {x=0,y=1,z=0} },
{ pos = {x=10,y=0,z=0}, color=c,
texturecoords = {u=0, v=1},
normal = {x=0,y=1,z=0} },
{ pos = {x=0,y=0,z=10}, color=c,
texturecoords = {u=0, v=0},
normal = {x=0,y=1,z=0} } }
i = {1,2,3}
meshid=model.mesh(i,v)
id=model.node(meshid)add a scene node based on a mesh
add a point light; rgb 0..1
apply an image as a texture to a node; optional texture num n
add a 3d line with thickness
add a 3d line
get attribute value of selected node
aim the camera at a position
position and look direction of selected node becomes relative to nodeid
animate selected node; loop/repeat string "true" or "false"
wait X milliseconds and then run a function by name
flow.wait(1000, "myFunction")flow.wait(20, "funcRepeats", "repeat")call a handler on event trigger
flow.on("keydown", "mykeyhandler")flow.on("mousedownobj", "mynodeclickhandler")require 'utils'
function menukey(code, char)
if handler ~= nil then handler(char) end
end
function firstMenu()
ui.cls()
ui.palette(2,255,255,255,255)
ui.showscreen(1)
print("Press key to select an option:")
print('1) Option The First')
print('2) Option The Second')
print('3) Cancel')
handler = secondMenu
end
function secondMenu(opt)
if (opt == "3") then
print("Cancel")
handler = nil
return
end
print("You selected "..opt)
print("Press key to select a suboption")
print("1) Option A")
print("2) Option B")
handler = thirdMenu
end
function thirdMenu(opt)
print("You selected suboption "..opt)
print("Thank you for your input.")
handler = nil
end
function menutest()
firstMenu()
end
flow.on('keydown', 'menukey')
menutest()add a force w/dir (fx,fy,fz) and rel. pos (px,py,pz); returns forceid
remove force
remove torque
add a torque around axis tx,ty,tz ; longer vector = greater torque; returns torqueid
apply an impulse given direction and relative position
Enable collisions by setting this attribute
model.put("collision", "gimpact", 5)keys used for movement (0), console (1) or emulator(2+)
wait for UI to process all lua commands
set w/model.put on any node to png filename to change the overlay image
create a new screen or switch to an existing; print() and palette() affect this screen
apply emu or ui screen as a texture to a node
geom = require 'geom'
require 'utils'
i,v = geom.face2(0.5,0.5,1,0,0,0)
screenMesh = model.mesh(i,v)
screen = model.node(screenMesh)
model.pos(0,-5,0)
model.rot(0,0,90)
model.scale(10,10,10)
rtype = emucmd('cores/mamenew', 'rtype2')
model.scale(0.0001, 0.0001, 0.0001)
function emustarted(which)
model.sel(screen)
ui.screenon(rtype)
end
flow.wait(2000, 'emustarted')geom = require 'geom'
i,v = geom.face2(5,5,0,0,0)
labelMesh = model.mesh(i,v)
lblnode = model.node(labelMesh)
ui.screen()
print("Text on node")
flow.waitui()
ui.screenon()
ui.screen(0)change color values at index
show console (1) or hide (0)
Open a file dialog and return the selected filename
f=ui.filedialog('Choose file', "Any file\0*.*\0"add, update or delete draw commands based on Cairo. Commands and arguments separated by spaces. id -1 to append, blank command string to delete. Available commands: font, size, path (start new path), move x y, line x y, sub (new subpath), end (end sub-path), scale x y, trans x y, save (save state), rest (restore state), arc x y radius degreestart degreeend, curve (cubic Bezier) dx1 dy1 dx2 dy2 dx3 dy3, rot deg, rect x y w h, color r g b a (0..1), fill, stroke (fill/stroke required to actually output shapes). See Cairo documentation and the following examples.
f=ui.draw(-1, "font fonts\\Open_Sans.ttf size 20"
ui.draw(f, "font MyFont.ttf size 22")ui.palette(1,0,0,0,0) -- transparent screen (console) background
ui.cls()
ui.draw(-1, "trans 200 200")
ui.draw(-1, "rot 0")
ui.draw(-1, "trans -25 -25")
ui.draw(-1, "move 60 0")
ui.text(-1, "0")
-- note that stroke and/or fill are required to actually show anything
ui.draw(-1, "move -50 0 line 50 0 move 0 -50 line 0 50 stroke")
function dorot()
-- use clock for smoother animation
r = os.clock() * 50
-- modifies the draw command at position 1 (0 is first)
-- note use of substitution with globals table can be useful for constructing
-- dynamic command strings
ui.draw(1, "rot ${r}" % _G)
-- update text which is index 4 in draw command line
ui.text(4, r)
end
-- animate by updating draw command list every 16 ms
flow.wait(16, 'dorot', 'repeat')add,update, or delete a text element at the current x, y coordinate
HTTP GET and return response body to callback function
HTTP GET and save response to fname
run a .cmd that simulates cmd-line for emulator
List files in directory
unzip a file (uses 7-Zip, LGPL, www.7-zip.org)
run a love program from vsimroot/lua/plugindir/main.lua and return the stdout as a string
run a love program from vsimroot/lua/plugindir/main.lua in the background i.e. dont wait for it to finish