Jump to content

Ed Minchau

  • Content Count

  • Joined

  • Last visited

  • Days Won


Ed Minchau last won the day on March 24

Ed Minchau had the most liked content!

Community Reputation

63 Excellent

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. This is astonishing. I get the feeling we've only barely scratched the surface of what this little computer can do.
    This is AWESOME. I can totally see a game like Comanche based on this.
  2. When I did my LOTR video I found I had to put in a delay loop to match the speed of the actual hardware. The emulator loads from file into VERA approximately 50 times faster than the actual hardware.
  3. Video is surprisingly easy to do on this machine. Here's something I put together back in September of 2019, on version 28 of the emulator, but there's no sound; VERA has only gotten better since then. I think I'm going to put together an instructional video showing how to make a much better version of this with sound.
  4. Is 3 RAM chips even going to be an option? My understanding was they'd only be selling 512k, 1M, and 2M variants.
  5. OK, so I got the data tables generated; this will all go in ray.h
  6. Yeah that makes sense. I'll keep digging. BTW I generated the lookup tables for interpolation last night, that was the easy part. I should have the code done in a day or so.
  7. @Jeffrey I'm not just looking at your source code, I'm also looking at the compiled code with the META/L editor. There is a lot of room for improvement in that code; although macros make things easier to read and C makes it easier to write, the compiler produces much longer code than is necessary. For instance, there's a lot of places where the code reads LDX #00 LDA #22 STAA VERA_DAT_0 LDX #00 LDA #22 STAA VERA_DAT_0 over and over again. The second and subsequent LDX and LDA instructions aren't necessary because the value being sent to VERA isn't changing, and each adds two cycles. The sequences like that aren't all the same, some of them include unnecessary LDX#00 and LDY#08 and LDA ($22),Y instructions over and over, or some similar things. A few cycles here, a few cycles there, repeated hundreds of times per column of pixels and it really adds up. If this was all optimized assembly code, then a target FPS of 15 to match the original is definitely achievable.
  8. I've been looking through your code; I think I understand it enough to write some tables and subroutines for you. One thing I noticed in ray.h: That should be 8192, no? Anyhow, I'll generate the data tables and subroutines needed for the interpolation and will post them here soon.
  9. Yes. You'd have to keep track of the map block hit and the side of the block; two rays that hit the same block on different faces can't be interpolated between.
  10. I wanted to illustrate what this shortcut does, so I took the starting screen from Jeffrey's demo and marked it up a bit in Paint. First, there would be four rays cast a using the normal method, marked here in red in the first file below. A is column 0, B is column 256, C is column 288, and D is column 304. Note that the display is only columns 0 to 303 so 304 is not actually displayed, just used for interpolation if possible. The second image shows where the interpolation happens. Ray E is column 128. First, we check the high byte of the distance value array corresponding to this column; these will all be set to FF at the start of a screen and only changed if a ray is calculated. So in this case column E has not already been calculated. We look to the left and right, rays A and B, and see if they point to the same wall. They do not, so we cast the ray for E and move on to the next one, ray F in column 64. Once again we check if this ray is already calculated, nope, and then check to the left and right, A and E. These two are not on the same wall, so we cast ray F and move on to ray G. Ray G, in column 192, has not been calculated yet (its distance high byte is still FF) so it checks to the left and right, rays E and B. These are not pointing to the same wall, so we cast ray G and move on to ray H. Ray H is in column 32. We see that it has not been calculated yet, so we check to the left and right, columns A and F. These two rays are indeed pointing to the same wall, so we can interpolate all the rays in between A and F. Now if we go further down the list and find ourselves at a column that has already been interpolated, such as column 16, the high byte of its distance will no longer be FF, and that entry in the list is skipped. These interpolated pixel columns are marked in yellow in the second image. Eventually ray Y (column 272) will be encountered, and comparing B and C shows that they are on the same wall so columns 257-287 are all interpolated. And when Z comes up on the list, all columns from 289-303 would be interpolated. The third image shows all 39 columns that would have to be raycast as red vertical lines, and the 266 interpolated columns are shown in yellow across the bottom - an 87% reduction in the number of rays cast. Edited to add: this is probably pretty representative of an average. 305/(log(305)/log(2)) ~ 37 startscreensmall2.bmp startscreensmall3.bmp startscreensmall4.bmp
  11. I think I laid out something very similar, except instead of calculating the center of the new range every time, I'd have a precalculated list of which pixel columns to do in which order. You wouldn't be calculating the leftmost column of the face, you'd be interpolating rays between the rays you'd already cast. The column height or distance (however you want to store it, same thing really) is just interpolated between two rays that happen to be on the same face. Likewise, choosing which column of the image that corresponds to (or the xintercept/yintercept, same thing really) is an interpolation between the intercepts/columns. You wouldn't need recursion, just a way of seeing whether the next one in the list has already been mooted by interpolation, and the high byte of the distance variable indicates that. Basically, if you have two rays that hit the same wall, then all the rays between those two are calculated with one multiplication and one addition for the image column choice, and then one multiplication and one addition for the distance. It's pretty much the same number of cycles as you need for just the final step of a raycast; converting the distance into a distance relative to the direction the player faces uses two multiplications, lookups to sin and cosine tables, and an addition. It would indeed be fast, if you were very close to a wall you might only cast five or six rays and just interpolate all the rest. But even if there's lots of walls in view, you'd still probably only have to cast 30 or 40 rays total before the entire screen was filled in. The fastest you can push the data to VERA for the whole image is about 260000 cycles, so 30fps wouldn't leave any time to calculate anything else. 20 fps is 400000 cycles though, and I think you'll be able to hit that easily with this method, with time left over to calculate bad guys and pew pews and sound effects etc.
  12. In the original game the bad guys/ projectiles were all sprites. That's going to take some trickery to make it work here because we can't resize sprites.
  13. It just occurred to me that you wouldn't need a fraction lookup table at all to interpolate 255 pixel columns; the fraction to multiply by would be the column number itself. Also, instead of raycasting column 303 it might work better to cast the imaginary column 304 to make the binary split work better.
  14. Thinking more about interpolation: Suppose pixel column 0 and pixel column 8 are pointing at the same map block and the same face; say both pointing at the north side of map block 0xFE. Suppose further that column 0 is pointing to (group 6) the leftmost column of the image associated with that map block (call it image column 0) and pixel column 8 is pointing to (group 6) an image column about 2/3 of the way to the right, image column 42. And let's say for pixel column 0 the group 7 data is 511 (it's really far away) and for pixel column 8 the group 7 data is 502 (a little closer). So, we've got 7 pixel columns to interpolate, and two ranges: 42-0= 42 for the image column range and 502-511= -9 for the height or distance range. You've already got a macro or subroutine that multiplies a 16 bit number by an 8 bit number representing the range 0/256 to 255/256. So for a 7 point interpolation like this, you'd have a table of 7 numbers to multiply these ranges by 1/8, 2/8, 3/8... 7/8. So you use that macro to multiply the lookup by the range and add the value stored in the leftmost pixel column's group 6/7 values. So pixel column 1's image column would be pixel column 0's image column (0) plus 1/8 times the range (42) = 5 and the height would be 511 + (1/8)(-9) = 510. All the others between pixel column 2 and pixel column 7 would be just that easy, just increment the interpolation pointer as you increment the pixel column pointer. A 15 pixel range would need a table of 15 numbers, a 31 pixel range would need a table of 31 numbers... you could have these multiplication lookup tables for interpolating 1, 3, 7, 15, 31, 63, and 127 pixel columns all in one 256 byte page of RAM. So, total overhead: 10 or 11 bytes for each pixel column; in practical terms you'd have 512 bytes set aside for each variable even though there's only 304 columns. The remaining 192 bytes can remain empty or be used for other purposes such as the linear interpolation tables. So that's 20-22 pages of RAM, 5 to 5.5 kb, depending on whether or not you keep groups 5 and 6 separate. You could use slightly less memory by cramming it together more, at the expense of speed.
  • Create New...

Important Information

Please review our Terms of Use