|
Post by gtoal on Jul 23, 2024 18:44:43 GMT -5
I've been mulling an idea for a Vectrex program to design/draw 3D wireframe objects:
The world is a 16 X 16 X 16 cube. A point in this space can be stored in 4+4+4 = 12 bits (1.5 bytes).
Initially, you would use the joystick to select an X,Y point in a 16 by 16 X,Y grid. The nearest point to the cursor will be highlighted. Pressing the 'D' button will switch from X,Y mode to Z mode and allow you to indicate the depth of your point using the joystick, at which point pressing the 'A' button will either start drawing a line from that point, or will extend the path you are already creating by adding a line segment from the previous point to this point.
Pressing the 'B' button instead will tell it to stop extending the path after this line segment is added, and put you back in the mode where you can move around to select the start of a new path.
And if you haven't guessed by now, all of the above is done while viewing with the 3D imager! However the code should still work if no imager is present - either by just displaying one image, or by drawing side-by-side images for cross-eyed or wall-eyed viewing.
Pressing 'C' puts you in a selection mode where instead of choosing points in the 16x16x16 grid. you use the joystick to select a line segment, which then remains highlighted as you select from one of four options with one of the four buttons - delete the segment, or colour it red, green, or blue. The code would advise the user if the number of lines in any specific colour was beyond the capability of the selected colour wheel.
Holding the 'D' button down for an extended time indicates that your design is complete, and one of two things can happen: if your cartridge supports it, the object can either be saved to the cartridge or saved externally somehow; if the cartridge does not have appropriate hardware support, a concise textual representation of the model's coordinates will be displayed on screen, a few lines at a time, which you can scroll through and copy to a file manually and then use in your own programs. It would be wise to include a checksum character with each line to reduce the chance of typos.
RAM storage for the points is 1.5 bytes per point, from the 4+4+4 bits needed to identify a point in the 16x16x16 coordinate space, so a reasonably large model of 100 line segments would require between 100*1.5 and 200*1.5 bytes, which is well within Vectrex capabilities - so the limiting factor will be how many lines can be displayed, not how many can be stored.
Because the 16x16x16 point array is fixed, the 3D perspective calculations for each eye can be pre-computed and stored in the rom. It would require a lookup table of: 2 (eyes) * (2 bytes for screen X,Y) * 16 * 16 * 16 which would come to 16K bytes leaving lots of space for code in a 32K Eprom.
This is doable... But it's an idea for the future though, at least if I do it. Anyone else is of course welcome to implement this first because my queue of things to work on is quite long already and I won't be taking this on in the near future.
G
|
|
|
Post by gtoal on Jul 24, 2024 22:25:15 GMT -5
Well, I got bored and decided to see how much of this I could prototype - just the critical part to see how it would perform rather than the actual object editor... gtoal.com/vectrex/3deditor/main.c (and gtoal.com/vectrex/3deditor/perspective.h ) implements the basic algorithm... and compiling with -O handles a mere 20 line segments in the requisite 30000 cycles. Not super impressive but actually ballpark for objects such as Battlezone tanks etc and Tailgunner ships. And it doesn't actually drive a 3D imager. I think I'm going to need a little help from Malban for that part - not to mention handling the three colours of a colour wheel. (This prototype would only make sense with a 50% black and 50% clear wheel...) Also every line segment is treated as an independent object and gets a Reset0Ref() call, so a more complex program that understood connected paths would gain a little more speed. And this is before tackling any low level optimisations. So I think as a proof of concept, it passes the test. But whether it'll be useful to people writing games or whether they'ld be better off prototyping objects under Windows or Linux rather than the Vectrex itself remains to be seen. A few hours later: here's a bin to play with: www.gtoal.com/vectrex/3deditor/3deditor.bin - it'll let you view in 3D if you can do either cross-eyed or wall-eyed viewing of stereo pairs. It also shows mono, and an approximation to stereo from the 3D imager, but there's no synchronisation so it won't actually work with a real 3D imager - it's just there to confirm that there's enough CPU to actually do it. Sources are in the same directory. G
|
|
|
Post by Malban on Jul 25, 2024 2:58:23 GMT -5
Hi Graham, while I always am in awe of you enthusiasm and the ideas you come up with.
I just need to ask the question: Why?
Why do this on a Vectrex?
In almost all conceivable ways the editing of 3d objects will be easier when done on a computer with a modern interface. Even Vide (which is not great at editing 3d-objects) can probably do better. Yes - if you would be able to use the 3d-Imager for editing it would be a "gimmick" - but nothing more at best. You'll soon tire of it.
Wouldn't it be more "productive" to create: - a standard format for (vectrex) 3d objects - build a framework to easily display them on a vectrex (with 3d-imager support)
- have an editor to create these objects, with advanced features like: display the count of cylces needed to display an object?
Interlude:
See, the way a vectrex programs draws objects for each color/eye is like the following.
You decide the Herz you want one display round to last... all imager games are comparably slow - so for the example let's say one round is displayed in 25Hz - this would give you 60000 cycles per "round".
This gives you 30000 per "eye".
Depending on the color wheel you then have to divide that time in the colors you want to display: Per eye you have 180° Lets say red takes the first 120°, blue 40° and green 20°.
For the first eye red: you will have to display the object in the first ~20000 cycles For the first eye blue: you will have to display the object in the next ~6600 cycles For the first eye green: you will have to display the object in the next ~3300 cycles
Then the same for the next eye...
Interlude end
If your editor can give you the timing needed for the objects - then you could place them fitting to the color in the correspronding "draw" section.
If you really want to program 3d-Imager programs - THAT would be a feature that really would be useful. I can hardly imagine your editor tool would be able to do.
hmmm... thinking while writing here...
... It WOULD be a cool feature of your program do have a "demo" mode, where the objects could be displayed using the imager in that mode - to determine if they really fit into the time frame...
Gee...
Haha - I guess a combination of both would be perfect...
Keeping my mouth shut for now...
Cheers Malban
|
|
|
Post by Malban on Jul 25, 2024 8:19:26 GMT -5
Something for you to play with - if inclined.
This is a Vide C-Project that utilizes the 3d-imager. To use it in your own project you have to copy the two files: 3dImager.h
3dImager.s
To your project - include the "*.h" file... and Go. Well - the structure of you program differs...
The main() function now just looks like this:
int main(void) { imagerCInit(); return 0; }
The imager is initialized and calls back 6 functions that you must provide:
void drawRightColor1() void drawRightColor2() void drawRightColor3()
void drawLeftColor1() void drawLeftColor2() void drawLeftColor3()
As an example in the project these are implemented as:
void drawRightColor1() { VIA_t1_cnt_lo = 0x7f;
Print_Str_d_3d(0x30,0xb0, "RIGHT\x80") checkPWMOutput(); // call this AFTER every "figure"
Moveto_d_3d(10,100); Draw_VLp((void* const)starVlist); ZeroPen_3d(); checkPWMOutput(); // call this AFTER every "figure"
return; } void drawRightColor2() { Print_Str_d_3d(0x30,0x00, "RIGHT\x80") checkPWMOutput(); return; } void drawRightColor3() { Print_Str_d_3d(0x30,0x50, "RIGHT\x80") checkPWMOutput(); return; }
// for the left eye checkPWMOutput(); // is probably not needed anymore void drawLeftColor1() { Print_Str_d_3d(0xb0,0xb0, "LEFT\x80") Moveto_d_3d(-10,100); Draw_VLp((void* const)starVlist); ZeroPen_3d(); return; } void drawLeftColor2() { Print_Str_d_3d(0xb0,0x00, "LEFT\x80") return; } void drawLeftColor3() { Print_Str_d_3d(0xb0,0x50, "LEFT\x80") return; } You MUST NOT use Bios functions that change the CIA_CNTL register.
Mostly that means - you are not allowed to use functions that influence the Zeroing or Unzeroing.
A couple of "helper" functions are provided - see the include file.
The "3dimager.s" is one assembler file, which provides all functions needed.
The only things you might want to change might be the "values" of the disk. These are kept in constant definitions:
T2_VALUE = 0xe000 ; value for the wheel update frequency -> 1/(1/1500000 * 0xe000) = 26,1579241 Hz BLUE_ANGLE = 60 ; values for the angles "Crazy Coaster" / "narrow Escape" GREEN_ANGLE = 64 ; I use the angles to calculate in relation to the above timer value RED_ANGLE = 56 ; the compare values, when the actual eye/color combination is drawn in the ; timeframe of one main round
Following values for the actual timing "might be" calculated correctly (hahaha).
The output looks like:
Notes: BAD! Things may happen, if the overall timing goes out of whack! If the final timing interrupt is called - and the main program is not finished - the program may crash.
Housekeeping... reacting to joystick etc... must be done in one of those callbacks (or spread across). It depends on how much time you have got in each "eye-color"...
Malban
PS I hacked this together in an hour at work - this has only been tested in Vide - not with the real thing!
|
|
|
Post by gtoal on Jul 25, 2024 9:18:09 GMT -5
> I just need to ask the question: Why?
> Why do this on a Vectrex?
because it's the first step in all those things you mentioned... (and I forgot to explain - the primary reason being that you get to see the object you're creating in 3D as you create it. The way we currently do these things is with pencil and paper and copying down coordinates into an array by hand!)
|
|
|
Post by gtoal on Jul 25, 2024 9:23:19 GMT -5
> Something for you to play with - if inclined.
> This is a Vide C-Project that utilizes the 3d-imager
Oh yes, I'm inclined :-) Thanks, that's the missing bits I needed and couldn't do myself.
I'll see what I can do with it.
Hey, were you able to see the stereo effect with the stereo pairs? Some people find it difficult, others see it right away.
G
|
|
|
Post by Malban on Jul 25, 2024 10:20:48 GMT -5
I just saw... In the example I do not check buttons/Joystick. In the *.s Source code it is mentioned that either the joytick should be checked BEFORE the PULSE to the imager starts - The you should comment out the lines (460 - 461): ; the first thing we should do here is check the joystick ports (buttons!) ; so they do not interfere later with PWM pulses ; however - for the example ; there is no joystick polling required, so - for the sake of ; lazyness, I just leave that out! ; PSG_PORT_A_INPUT ; jsr >Read_Btns Or probably to the "checking" starting with the first left Eye - since the Pulse will most probably be finished by then...
See also the lines 528/529 in the same file... But you can also do this last in "last" eye... :-)
|
|
|
Post by Malban on Jul 26, 2024 1:46:32 GMT -5
Graham, I answer your question here rather than per email - since it touches the code I posted. If anyone else wants to fiddle around with it - this might be information needed to do so.
First - I said I hacked the code together in about an hour - that is one of the reasons why it is a bit "clumsy".
It is 98% based on the code that I did years ago and is part of Vide. The assembler sources can be found in the codelib that comes with Vide.
The thing is - the assembler used in "C" has a different syntax than the assembler Vide usually uses - so you can not use "normal" assembler sources out of the box with C programs.
In the editor that comes with Vide you have in the lower right corner an ominous TAB called "Assi -> C". Using that (and some background knowledge) you can translate the "Vide"-Assi assembler code to "C"-compatible assembler code with a button click in a second.
One thing that is decidedly different is the handling of macros. Therefore one of the things the button does is to replace all macros with the actual code.
When I told you to uncomment the "PSG_PORT_A_INPUT" I forgot to mention this - so yes, that produces errors. The original macro definition is:
PSG_PORT_A_INPUT macro
ldb >Vec_Music_Wk_7 ; Get current I/O enable setting
andb #$BF
lda #$07
jsr >Sound_Byte_raw ; Config Port A as an input
endm
That means, when I said: remove the comments from:
; PSG_PORT_A_INPUT
; jsr >Read_Btns
You actually have to replace those lines with:
ldb Vec_Music_Wk_7 ; Get current I/O enable setting
andb #0xBF
lda #0x07
jsr Sound_Byte_raw ; Config Port A as an input
jsr >Read_Btns
Sorry for the confusion.
Malban
|
|
|
Post by Malban on Jul 26, 2024 1:53:03 GMT -5
To remove the "GOGGLE" in Vide...
Go to the configuration... On the first TAB there is a checkbox item called "display mode text". Uncheck it - and the text should be gone.
|
|
|
Post by Malban on Jul 26, 2024 2:10:13 GMT -5
PS. For your tests / tries... You might want to use some little known features of Vide. When you are in the debugger you can type "JOYI" - this opens a window that allows you to inspect devices that are connected to the joystick port (e.g. The Imager). 1. You should enable the "camera" icon in the TOP LEFT of that windows - a little green check should then be visible. This means, that the window gets updated upon changes. 2. Use the adjacent comboBox to switch to port 1 (default is port 0) 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" See following images: vectrex.malban.de/tmp/3d-bw.pngvectrex.malban.de/tmp/3d_ana.png
|
|
|
Post by Malban on Jul 26, 2024 2:14:59 GMT -5
PPS Since you have nearly 30000 cycles for each eye - you should be able to draw way, way more then 10 vectors.
- it certainly depends on what sort of other calculation you do of course.
Also the code can be hugely optimized. Using $ff scale for everything is a "killer"...
|
|
|
Post by Malban on Jul 26, 2024 5:14:46 GMT -5
Ok... Last one for today :-)! vectrex.malban.de/tmp/Profile3d.pngI analyzed your code a bit and put the Vide Profiler to use - see image! Basically you draw 19 vectors and position 19 vectors for each eye. That means ((19+19)*2) * 255 = ~20000 cycles pure drawing and move time. That means each "eye" uses about 10000 cycles to move and draw (... ok a few cycles more because of the overhead of the functions themselves). The rest of the cycles (right eye ~12000, left eye ~16000 cycles) is purely housekeeping. Frankly - accessing arrays in a loop is killing "C"-Performance. It is way more "ugly" but if you convert these to pointer accesses - you can probably save 10000 cycles :-): ... and of course the scale factor is also "bad" ... @peer Is the "C" - optimization guy though. Cheers Malban
|
|
|
Post by D-Type on Jul 26, 2024 5:25:07 GMT -5
I'd like to make my development work in 50Hz colour (not bothered so much about 3D), so using the VIDE tools and syncing to the wheel are really interesting to me.
I'm just sad that more 3D colour imagers aren't available. /Shrug/
|
|
|
Post by Peer on Jul 26, 2024 6:11:23 GMT -5
… Frankly - accessing arrays in a loop is killing "C"-Performance. It is way more "ugly" but if you convert these to pointer accesses - you can probably save 10000 cycles :-): ... and of course the scale factor is also "bad" ... @peer Is the "C" - optimization guy though. It heavily depends on how the arrays are used inside the loop. After all, for the C compiler, arrays are nothing but pointers to the first array element. But yes, in general, using pointers right away results in more efficient code. And again yes, ugly and dirty C code is often much better I will happily take a look at the respective C code. Where can I find it?
|
|
|
Post by gtoal on Jul 26, 2024 12:48:59 GMT -5
It heavily depends on how the arrays are used inside the loop. After all, for the C compiler, arrays are nothing but pointers to the first array element. But yes, in general, using pointers right away results in more efficient code. And again yes, ugly and dirty C code is often much better I will happily take a look at the respective C code. Where can I find it? Project zip file is in gtoal.com/vectrex/3dtest/Interestingly I had *deliberately* used 3D indexing (eg array[z][y][x]) rather than locating the element from shifting and adding the 4-bit indices because I had rather foolishly assumed that GCC would be able to optimise array accesses better than the programmer could. Note that stepping through pointers is not helpful as the array accesses are arbitrary and not sequential. (the point of the code being that it supports arbitrary vectors in a 16x16x16 coordinate space. Which are then mapped to x,y screen addresses via a 16x16x16 lookup table. Though in hindsight I realised that the 3d array was overkill as mapping the x coordinate doesn't involve the y coordinate and vice-versa, but I decided to keep that for now as there is enough rom space and it is faster than the alternative) Thanks, Malban (& Peer) for all the comments and advice above! (I only just now found it, I had been checking my email regularly for a reply from Malban to an email, I didn't realise he had replied here!) Ignore the random colouring in Vide for the 3D - it's essentially planned for a 50% clear 50% black wheel (that I'll be creating for myself to test with this weekend) Graham
|
|