|
Post by gtoal on Jul 26, 2024 13:19:18 GMT -5
You actually have to replace those lines with: jsr >Read_Btns
- thanks, that worked but I did have to remove the '>' marker.
|
|
|
Post by gtoal on Jul 26, 2024 19:36:22 GMT -5
3. In the TAB below switch to "Imager3d" - Then you will be able to watch all 3d imager settings. This also lets you chose/edit wheels! You can also switch the output mode of the imager to "BW" or to "anaglyphic" - That's pretty good, I must find my red/cyan glasses! Haven't used them in 10 years!
|
|
|
Post by gtoal on Jul 26, 2024 23:00:36 GMT -5
I just realised... if we get this to work, my 3D X's and O's ( gtoal.com/vectrex/xandoz/xandoz.c.html ) is the ideal game to make into 3D... (although I'm thinking of a conversion of Sundance to 3D as well)
|
|
|
Post by Peer on Jul 27, 2024 7:04:01 GMT -5
I only had the time to take a very quick glance at the C code. I have not yet compiled it and looked at the generated asm code, but here is what I noticed:
In your code, one single array element has a size of 3 bytes. That is unfavorable in terms of efficiency. Let array a be defined as:
element_type a;
Then each array access
a[i]
translates to
&a + i * sizeof(element_type)
"Take the base address of a, and add i multiplied by the number of bytes required for one array element".
Here, the multiplication is the crucial part. If the size of the element_type is a power of 2, then the compiler will use shifts (fast), otherwise it will use true multiplication (slow). So it is advisable to always have array elements which require a number of bytes which is a power of 2.
For the same reason, when using multi-dimensional arrays, it is advisable to also have powers of 2 for the sizes of the "inner" array dimensions (which is the case in your code).
Also, for the same reasons as above, when indexing an array twice in the very same way, like in
y = screen[z0][y0][x0].y; x = screen[z0][y0][x0].x;
it is much more favorable to use a pointer and to compute the effective low-level index [z0][y0][x0] only once, and then use it in both assignments of y and x. gcc6809 has a very hard job in doing such optimizations by itself as the number of CPU registers of the 6809 is so limited. My personal policy is to avoid relying on compiler optimizations.
Hope this helps.
Peer
|
|
|
Post by Malban on Jul 27, 2024 9:35:06 GMT -5
(Again in response to Grahams email - but if other read and want to try - this is important!)
Reminder to myself - never post advice you did not try first.
clr Vec_Misc_Count ; Disable joystick approximation jsr Joy_Digital
If you enable these lines you also MUST remove the ">" sign. The comments are from the other assembler (assi) not from the C-Assembler.
The ">" sign has nearly the opposite meaning! So everything went awry when you just uncomment those lines.
Another reminder - something I saw in your code. With the right Eye - the pulse may still be on and must be switch off'able. Therefor after ever "lengthy" operation you should once call
checkPWMOutput(); The output should be more stable.
-> your right eye should look something like: for (i = 0; i < next_free_line; i++) { x0 = line[i].x0; x1 = line[i].x1; y0 = line[i].y0; y1 = line[i].y1; z0 = line[i].z0; z1 = line[i].z1;
ZeroPen_3d(); y = (screen[z0][y0][x0].y SCALED); x = (screen[z0][y0][x0].xright SCALED); Moveto_d_3d(x, y); checkPWMOutput(); // Subtract last coord from this coord to get delta move value dy = (screen[z1][y1][x1].y SCALED) - y; dx = (screen[z1][y1][x1].xright SCALED) - x;
Draw_Line_d(dy, dx); checkPWMOutput(); }
I added a "debug" feature in my code - each time your "display round" takes longer then allowed - a variable "missCounter" is increased. If a "missed" is counted, it means the T2 Timer has reached zero and an interrupt occured during code you wanted to run. As it is - the missed is always in the joystick code. Probably nothing too bad will happen. But if a "missed" occurs at the wrong time - the code WILL crash!
When you have a miss - the display also gets a bit garbled - looks like you lost a frame or so.
Considering this - on my vectrex everything looks fine now... actually really much the same as the emulator except one thing: - On a real Vectrex the "cross" starts only moving after several seconds - some uninitialized value on a real vectrex?
I have no clue what causes that...
---
In Vide you can configure how to emulate the motor of the imager. In configuration "Emulator" (first TAB) - there is a checkBox "imager auto mode on default"
If it is unchecked - the motor automatically spins in the speed of the wheel that is configured - nothing will ever change the speed.
If it is checked - then a actual pulse width modulation is done - and the speed of the motor is regulated by the vectrex. The real vectrex though "spins up" in less then a second... the emulation needs about 5-6 seconds - so the screen is blank, while the motor spins up. You can watch this via "Joyi"...
Malban
|
|
|
Post by gtoal on Jul 27, 2024 12:21:03 GMT -5
clr Vec_Misc_Count ; Disable joystick approximation jsr Joy_Digital
If you enable these lines you also MUST remove the ">" sign.
Thanks - that was the bug that stopped it working. I had spotted the first occurrence of that problem but not this one. One more question re your demo example: what's the easiest way to fall back to passing control to a different procedure if there's no 3D imager attached? (I don't care about detecting one being reconnected later). I'ld like to write my code so that if there's no 3D imager, it gives a choice of mono or cross-/wall-eyed viewing as per the first example I uploaded. I'm off now to assemble some monochrome wheels for the Madtronix viewer, from the clear discs that Tony Lindstrom gave out last year. Sorry I can't do the same for an original viewer. G
|
|
|
Post by gtoal on Jul 27, 2024 12:49:33 GMT -5
Considering this - on my vectrex everything looks fine now... actually really much the same as the emulator except one thing: - On a real Vectrex the "cross" starts only moving after several seconds - some uninitialized value on a real vectrex?
I have no clue what causes that...
I'm betting it is related to the spin-up and synch time of the wheel. Which if it is the case, is easily fixed by having a 5-second intro screen with fewer vectors on it, to give the wheel time to spin up. It's not so much that it's the movement of those vectors that's the factor, it's that they're the last ones to be drawn. A related observation - when my nose bumped against the wheel and slowed it down, the same behaviour happened again. A separate issue is that one vector - and I believe it is the *first* vector to be drawn - is sometimes being drawn in the right eye's slot rather than the left. But I think I know the reason - it may be a consequence of where the white sticker is placed that signals the timing to the headset - I moved it from the center of the black area about 1/8th of a rotation anti-clockwise and the problem reduced (but didn't go away entirely). I'll try a few more positions until I find the best one by trial and error. (btw this was with the 50% clear / 50% black monocolour wheel that I just built). I did note that the two colour wheels that came with the Madtronix imager have their index marks in totally different positions, which surprised me a little. G
|
|
|
Post by Malban on Jul 28, 2024 5:55:04 GMT -5
Graham,
you also asked how to "exit" the spinner or switch it off/on. It is both easy - and "not nice".
The function in main() that you call "imagerCInit()" is not a function but can rather be seen as a goto statement. It will never "return" - the stack is rebuilt and internally the following game loop is done by setting a certain timer to T2 and when that timer reaches Zero an interrupt is invoked.
The interrupt handler resets the stack and initiates a new round.... and so forth.
To exit that "loop" you also need a "goto" statement - one that returns you to the main function. That can not be done in "C" - as you can not goto somewhere outside your own scope.
But with a few lines of inline assembler it is possible... So - use this as a the main function:
(NOTE: Do not use local variables in the main function!!!)
int main(void)
{
startAgain:
imagerCInit();
__asm (
"_mainLabel:\n"
"orcc #0x10\n" // disable 6809 interrupts
"ldd #0x0EFF\n" // ensure motor is switched off
"jsr 0xF256\n" // Sound_Byte
"ldb 0xC845\n" // Vec_Music_Wk_7 restore port direction
"andb #0xBF\n"
"lda #0x07\n"
"jsr 0xF25B\n" // Sound_Byte_raw
"ldd #0x3075\n" // set refresh rate to $30000
"std 0xC83D\n"
"lds #0xCBEA\n" // correct stack frame
);
while (1)
{
Wait_Recal();
Intensity_5F();
Print_Str_d(0,-50,"HELLO GRAHAM!\x80");
check_buttons();
if (button_1_1_pressed()) goto startAgain;
}
// if return value is <= 0, then a warm reset will be performed,
// otherwise a cold reset will be performed
return 0;
}
Then in your right eye function - or anywhere else:
if (button_1_4_pressed())
{
__asm (" jmp _mainLabel\n");
}
With this you can then "jump" back to the main function.
The example jumps back and forth from imager to non - imager display using buttons 1 and 4. (also include controller.h)
ATTENTION! Vide does for whatever reason not support switching the imager off!
I have to look at that - right now in Vide you will not be able to switch back and forth!
Cheers Malban
|
|
|
Post by Peer on Jul 28, 2024 8:14:19 GMT -5
... To exit that "loop" you also need a "goto" statement - one that returns you to the main function. That can not be done in "C" - as you can not goto somewhere outside your own scope. Hehe, at least not in ANSI C. But of course there is a dirty way to do this
gcc6809 supports "computed gotos", which are a gcc-specific compiler extension and a nice and very efficient way to implement jump tables.
The destination of such a goto statement is computed at runtime. It is usually taken from a static array, which contains the addresses of local labels. However, this extension can be abused, as technically any address is allowed here. There is no way to reference the address of an out-of-scope label, but using the address of a function works:
goto *(&main);
This will take you from anywhere right to the (beginning of the) main() function. It compiles to a jump to the start of the respective function without cleaning the stack, so you have to take care of that yourself.
Cheers, Peer
|
|
|
Post by Peer on Jul 28, 2024 8:21:42 GMT -5
Here is the link to the documentation:
|
|
|
Post by gtoal on Jul 28, 2024 9:48:44 GMT -5
To exit that "loop" you also need a "goto" statement - one that returns you to the main function. That can not be done in "C" - as you can not goto somewhere outside your own scope. Not even with setjmp() and longjmp()? Not that I mind which hack is used, but setjmp/longjmp are marginally cleaner, if they work. you also asked how to "exit" the spinner or switch it off/on. Actually, no, what I meant was when the program starts, if there is no imager connected, I want to execute alternative code. I.e. I don't want people without an imager to try running the rom and getting a black screen. I want it to work as a normal program by default but magically work in 3D if you have an imager attached. Actually I'm a little surprised that they didn't write all the original 3D programs that way back in the 80's. G
|
|
|
Post by Peer on Jul 28, 2024 11:30:52 GMT -5
... I want it to work as a normal program by default but magically work in 3D if you have an imager attached. Actually I'm a little surprised that they didn't write all the original 3D programs that way back in the 80's. Likely because of the few KB limited and expensive cartridge ROM space they had to work with?
|
|