Closed mithrendal closed 4 years ago
On subsequent visits the user has not to be bothered again as the roms are already in the browsers local storage ...
Sounds good to me. But what happens if the user wants to exchange the current Roms with new ones? He must be capable of opening the Rom dialog manually.
We should have additionally a roms button in the UI, right? There the user can manage its local storage.
to get in touch with the cores API ... I just allowed our current file drop zone to accept .bin files and only added this code to the existing D64/CRT loader
extern "C" void wasm_loadFile(char* name, Uint8 *blob, long len)
{
...
else if (checkFileSuffix(name, ".BIN")|| checkFileSuffix(name, ".bin")) {
printf("isBIN\n");
bool result;
bool wasRunnable = wrapper->c64->isRunnable();
//ROMFile *rom = ROMFile::makeWithFile(name);
ROMFile *rom = ROMFile::makeWithBuffer(blob, len);
if (!rom) {
printf("Failed to read ROM image file %s\n", name);
return;
}
wrapper->c64->suspend();
result = wrapper->c64->flash(rom);
wrapper->c64->resume();
if (result) {
printf("Loaded ROM image %s.\n", name);
} else {
printf("Failed to flash ROM image %s.\n", name);
}
if (!wasRunnable && wrapper->c64->isRunnable())
wrapper->c64->putMessage(MSG_READY_TO_RUN);
then on startup a black screen
constructing C64 ...
adding a listener to C64 message queue...
vC64 message=MSG_PAL, data=0
vC64 message=MSG_VC1541_ATTACHED_SOUND, data=1
vC64 message=MSG_VC1541_ATTACHED, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_MOTOR_OFF, data=1
vC64 message=MSG_VC1541_NO_DISK, data=1
vC64 message=MSG_DISK_SAVED, data=1
vC64 message=MSG_PAL, data=0
vC64 message=MSG_NO_CARTRIDGE, data=0
vC64 message=MSG_CART_SWITCH, data=0
vC64 message=MSG_IEC_BUS_IDLE, data=0
vC64 message=MSG_VC1541_ATTACHED, data=1
vC64 message=MSG_VC1541_RED_LED_OFF, data=1
vC64 message=MSG_VC1541_MOTOR_OFF, data=1
vC64 message=MSG_VC1541_NO_DISK, data=1
vC64 message=MSG_DISK_SAVED, data=1
vC64 message=MSG_VC1541_DETACHED, data=2
vC64 message=MSG_VC1541_RED_LED_OFF, data=2
vC64 message=MSG_VC1541_MOTOR_OFF, data=2
vC64 message=MSG_VC1541_NO_DISK, data=2
vC64 message=MSG_DISK_SAVED, data=2
vC64 message=MSG_VC1530_NO_TAPE, data=0
vC64 message=MSG_VC1530_PROGRESS, data=0
vC64 message=MSG_WARP_OFF, data=0
vC64 message=MSG_ALWAYS_WARP_OFF, data=0
set SID to freq= 44100
can not get hardware accelerated renderer going with software renderer instead...
Size changed: 392, 248
wrapper calls 4x c64->loadRom(...) method
wrapper calls run on c64->run() method
vC64 message=MSG_ROM_MISSING, data=0
after run ...
now I dragged the bin files one after the other into the drop zone (where normally th D64 goes into ...)...
load file=kernal.901227-03.bin len=8192
isBIN
Loaded ROM image kernal.901227-03.bin.
load file=characters.901225-01.bin len=4096
isBIN
Loaded ROM image characters.901225-01.bin.
load file=basic.901226-01.bin len=8192
isBIN
Loaded ROM image basic.901226-01.bin.
load file=1541-II.355640-01.bin len=16384
isBIN
Loaded ROM image 1541-II.355640-01.bin.
vC64 message=MSG_READY_TO_RUN, data=0
and then I just clicked the "halt" button and the "run" button and it gives us this !!!
AWESOMENESS !!! π€€π€€π€€
I mean we could just change the following lines in wasm_loadFile(char name, Uint8 blob, long len)
if (!wasRunnable && wrapper->c64->isRunnable())
wrapper->c64->putMessage(MSG_READY_TO_RUN);
to
if (!wasRunnable && wrapper->c64->isRunnable())
wrapper->c64->run();
and it would start automatical when the 4 files are dragged into the file drop zone ...
confirmed ... after dragging the four files into the drop zone vc64web starts automatically with this code
if (!wasRunnable && wrapper->c64->isRunnable())
wrapper->c64->run();
So now I am getting weak... and need some advice ....
first I thought of a new rom manage dialog ... in which you could upload the roms or delete them
now I see a much simpler alternative plan (without ROM management dialog):
on MISSING_ROMS message and when there is no rom in local storage the user will get an alert popup which tells him to drag the four missing roms files into the drop zone ... then the core starts automatically ... and the rom files are saved to the local storage...
But what happens if the user wants to exchange the current Roms with new ones? He must be capable of opening the Rom dialog manually.
ππ»in this case he just drags the new roms into the drop zone ...
π€ Hmm the question is which is better from user expirience aspect ? The former extra rom managment dialog with extra rom dedicated file upload area or the simple popup message which tells the user to drag the four files into the existing file drop zone ....
I thought about it ... maybe we can implement both ... the simple just drag that stuff into the file drop zone box ... and also additional offer a sophisticated rom dialog with extra file upload for roms? π€
I have trouble to give a decent advice at the moment, because I canβt image yet how this is all going to look in the long run. Overall, itβs a good strategy to add pieces incrementally and to adjust old stuff when new stuff makes it necessary (I am developing myself this way most of the time, itβs the usual agile approach).
Therefore, let me just put in some thoughts for the long term visions:
First, have a look at: https://c64emulator.111mb.de/index.php?site=pp_javascript&lang=de&group=c64
Now, have a look at this popular site we all know: https://www.netflix.com/browse
The first page is just a page (π₯±) whereas the second one is an experience (π). In my mind I imagine VirtualC64web as an experience, because otherwise, itβll be just another emulator in a browser.
So maybe itβs best to build a visual prototype first. I did this with vAmiga and I remember your post where youβve been looking for the Defender of The Crown intro image in memory, but it was just two fake GIFs that were flipped by a timer π .
Just another thought: In vAmiga, I jeopardized my original idea to use Aros as the default OS, because I felt that Aros is not as stable as I thought and because it looked so different than the Amiga I remembered. For a web emulator, a (free) default OS might make sense for other reasons though (i.e., because people expect a web site to work out of the box more than they expect this from an ordinary app).
Interestingly, there is a free C64 Rom replacement written by the Mega65 team:
https://c65gs.blogspot.com/2019/05/free-and-open-source-replacement-roms.html
I was already in contact with them some time ago (I lost contact, because I was very busy at that time):
https://github.com/MEGA65/open-roms/issues/33
Still I an not sure if it makes sense to use those Roms by default, because there are Pros and Cons:
Pros:
Cons:
Those are really just my 2 cents. Yet, I am pretty unsure about the right approach at the moment. I am just clear about the goal: Making VirtualC64web an experience π.
I have trouble to give a decent advice at the moment, because I canβt image yet how this is all going to look in the long run.
so am I π¬... currently we have three unclear front lines ...
I think in this situation the best is as you said ... the incremental approach ... small steps πΆπ» ... but without hesitating to throw already achieved things over board in favour of making VirtualC64web an experience. π
So I first will do the local storage baby ... lets see if we can save to it and restore from it... After that I will do the extra rom dialog like you did it in the MacOS VirtualC64.app ...
- is the choosen underlying technical framework (bootstrap/jquery) sufficient enough for the greatest experience we can get from a browser ... ?
Good question π€. Unfortunately, my knowledge about web technology is kind of limited.
- I don't know how vc64web will look like when it is finally done
It'll be great π.
- but we could always encode binary data to a base64 string I think π...
There might be a limitation to string size. If not, yeah, convert the Rom to a string π, it's 2020.
Anyway, I'm a little anxious right now. Not because of VirtualC64web, because of Moira. I just discovered that I need to increase the program counter at the end of an instruction (during prefetch) and not at the beginning (otherwise, some exception stack frames will be wrong).
This is bad, because it's like removing the lowest brick from this tower π¬.
Soon everything will be in ruins π.
Soon everything will be in ruins π.
The worst case I can think of is that when someone hits the reset button of vc64web that it then resets/deletes the internet instead π Could that be possible π¬?
We should implement an extra big red button and name it βnever push thisβ ... do you think they will push it?
short update ... local storage idea seems to work
localStorage.setItem('file1', ToBase64(byteArray));
var restoredbytearray = Uint8Array.from(FromBase64(localStorage.getItem('file1')));
wasm_loadfile(file.name, restoredbytearray, restoredbytearray.byteLength);
and I can see the file π in the firefox webdev tools -> web storage
and all files have been loaded this way into the core which then started up immediatelyπ
small steps ....
the file dialog detects now the four rom files. If it detects a rom file it automatically stores it into browsers local storage... Yes you can simply replace them by simply loading another rom file into it π
here you see firefox after cold start ... and a visit to VirtualC64web ... the roms are automatically loaded from local storage π...I bet no other web emulator did this before ...
How long does the local storage persist days weeks months years ... I donβt know ...
pushed this version to branch dev
Now we can test whether it works in all modern browsers...
try out here... https://mithrendal.github.io/virtualc64web/vC64.html
Just opened the link on my iPhone and saved the website on its homescreen.π of course on the first homesceen page. loaded the roms into its local storage and vc64 started up.
Next cold started safari. And on click on the vc64 icon on iPhones homescreen π² vC64web starts up with roms from local storage π
Turned out that local storage was a good choice. ππ»Maybe we should use that technique for also storing everything we throw at the file dialog e.g. D64 files or .crt files too ?? And offer an app internal netflix like file browser which browses over the local storage π€€
try out here... https://mithrendal.github.io/virtualc64web/vC64.html
I tried in Chrome and Safari and dragged in all four Roms, but the screen remains black: π€
what did the log say ? (the text area ...) Are the roms being detected when you drag thm into the blue bordered box?
also the roms do have to end with .bin
I tried already safari mac π safari ios π firefox mac π
all working nicely
also the roms do have to end with .bin
Oh, why is that? π³
Adding a .bin suffix did the trick π
Oh, why is that? π³
true ... we will change that ... the reason was that I compare the suffix to know what kind of archive I have to build in wasm_loadFile()
extern "C" const char* wasm_loadFile(char* name, Uint8 *blob, long len)
{
printf("load file=%s len=%ld\n", name, len);
filename=name;
if(wrapper == NULL)
{
return "";
}
if (checkFileSuffix(name, ".D64") || checkFileSuffix(name, ".d64")) {
printf("isD64\n");
changeDisk(D64File::makeWithBuffer(blob, len),8);
}
else if (checkFileSuffix(name, ".G64") || checkFileSuffix(name, ".g64")) {
printf("isG64\n");
changeDisk(G64File::makeWithBuffer(blob, len),8);
}
else if (checkFileSuffix(name, ".PRG") || checkFileSuffix(name, ".prg")) {
printf("isPRG\n");
wrapper->c64->flash(PRGFile::makeWithBuffer(blob, len),0);
}
else if (checkFileSuffix(name, ".CRT")|| checkFileSuffix(name, ".crt")) {
printf("isCRT\n");
wrapper->c64->expansionport.attachCartridge( Cartridge::makeWithCRTFile(wrapper->c64,(CRTFile::makeWithBuffer(blob, len))));
wrapper->c64->reset();
}
else if (checkFileSuffix(name, ".BIN")|| checkFileSuffix(name, ".bin")) {
printf("isBIN\n");
//wrapper->c64->flash(ROMFile::makeWithBuffer(blob, len),0);
bool result;
bool wasRunnable = wrapper->c64->isRunnable();
//ROMFile *rom = ROMFile::makeWithFile(name);
ROMFile *rom = ROMFile::makeWithBuffer(blob, len);
if (!rom) {
printf("Failed to read ROM image file %s\n", name);
return "";
}
wrapper->c64->suspend();
result = wrapper->c64->flash(rom);
wrapper->c64->resume();
if (result) {
printf("Loaded ROM image %s.\n", name);
} else {
printf("Failed to flash ROM image %s.\n", name);
}
if (!wasRunnable && wrapper->c64->isRunnable())
{
wrapper->c64->putMessage(MSG_READY_TO_RUN);
}
const char *rom_type="";
if(rom->isKernalRomBuffer(blob, len))
{
rom_type = "kernal_rom";
}
else if(rom->isVC1541RomBuffer(blob, len))
{
rom_type = "vc1541_rom";
}
else if(rom->isCharRomBuffer(blob, len))
{
rom_type = "char_rom";
}
else if(rom->isBasicRomBuffer(blob, len))
{
rom_type = "basic_rom";
}
printf("detected rom_type=%s.\n", rom_type);
delete rom;
return rom_type;
}
return "";
}
we can impove it and make it independend of the suffix right ?
Adding a .bin suffix did the trick π
Is that picture chrome?
You shouldn't need the custom Rom handling code at all. π€
Just call C64::loadRom(const char *filename)
before doing the suffix checks. If it's a Rom, VirtualC64 will auto-detect its type, install it and return true. If it's not a Rom, it'll return false.
The MSG_READY_TO_RUN
message will be sent from inside loadRom
once all Roms are in place.
C64::loadRom(const char *filename) Is for files only. Local storage is no filesystem. the rom will be pushed into the core as a byte array from the JavaScript side which in turn loads and decodes it from the local storage... all control is on the JavaScript side even the core message listener now forwards to JavaScript message_handler(). When the core reports ready to run then the JavaScript side decides to run()
Also storing to local storage happens on JavaScript side.
Do you remember we decided for the design to keep the wrapper as thin as possible... all control in HTML5
The command sequence is as follows
Mainsdl.cpp tries to load the embedded romfiles.
When there are none the core emits missing rom message
The JavaScript message handler receives it and tries to locate the rons inside the local storage.
When it does not find anything-> black screen
When it finds them it decodes them base64 and pushes them into the core with wasm_loadFile
When all four roms are pushed then wasm_loadfile emits readytorun
The JavaScript message handler receives it and calls wasm_run
C64::loadRom(const char *filename) Is for files only.
You are so right π.
if (checkFileSuffix(name, ".BIN")|| checkFileSuffix(name, ".bin")) {
But you could just skip this test, couldn't you? If the file is nothing else, assume it's a Rom. If it's not a Rom,
ROMFile *rom = ROMFile::makeWithBuffer(blob, len);
will return NULL.
If the file is nothing else, assume it's a Rom.
Yes we will do ...π
Just opened the link on my iPhone and saved the website on its homescreen.
Just did the same. On the first page. Sure thing.
loaded the roms into its local storage and vc64 started up.
How do I do that on my iPhone π?
How do I do that on my iPhone π?
Touch the dropzone ...
Touch the dropzone ...
I'm scared π
OK, if this is the only way, I'll do it...
Woaaa, I can select files. So futuristic.
Yeeees, it worked π
When connecting a bluetooth keyboard you can play ...πππ»
Possibly a bluetooth xbox one controller or ps4 controller works too ... but I have not one π€€
Works on the iPad, too. And I already discovered some bugs π:
T64 is not implemented in the wrapper yet... D64 is implemented ...but somehow the file dialog in iOS wont let you select it ... works in Safari on a Mac so I think it is a restriction in iOS ... have to investigate ...
When I hit 'Z', VC64 displays 'Y' π
a bug will have to correct it in vC64keymap.js ...
iOS file selection repaired ...
before π
<input id="filedialog" name="theFileDialog" type="file" accept=".g64,.d64,.crt,.prg,.bin" style="display:none" >
now ππΌ
<!-- iOS won't work with accept=".g64,.d64,.crt,.prg,.bin" on d64 files -->
<input id="filedialog" name="theFileDialog" type="file" style="display:none" >
strange thing ...π³
now it accepts everything ... also pictures from your camera roll πΆ ... π
maybe they repair it in iOS14 ?
I published the working version in gh-pages π I like the workflow ...
The plan: when roms folder is empty the core will notify the javascript part that it needs roms to start ... the javascript part looks into local storage if it can find the roms there and when it does not find them then it invokes a modal dialog asking the user for help. The user can then select the rom files with the file dialog and the javascript part saves them for later use into the local storage. On subsequent visits the user has not to be bothered again as the roms are already in the browsers local storage ...