Hi,

As some of you might know, I am working on a 3D engine. But the engine only runs at a reasonable speed on 15MHz mode, especially when using textures. But the main problem with the 3D engine is that, because it uses 8.8 fixed-points, it quickly runs into accuracy problems. For example rendering a room correctely is, even when it's split up into several wall models, impossible while you are inside it.

So actually to make the engine more useful, it would need a full recode , and I would like to create a full game with it too.

I'm especially looking for someone who can help me with fast math routines and writing optimized code. If someone wants to join for doing something else, that's good too.

For the game, I would prefer an fps, but that can still change. Also, I hope no one would have problems with it being open-source.

Maybe, with the help of the community, this can become a great project.
Hi ben_g! I have never managed to make a working 3D engine, but I have worked on most of the components, code-wise and I have a large collection of routines that I have been optimising more and more over the years. I cannot promise full-time help, but I wouldn't mind having some code to work on in my spare time. For example, if you asked me to write a 16.16 FP multiplication routine, it might take me a while to work through optimising as far as I can (I have a rather dismal stock of FP routines and most of them are rather new, so they haven't had the same years of optimising) Also, high precision trig routines sound rather scary. The fastest and most accurate I've ever done is a signed 8-bit routine using a 64-byte LUT.

Anyways, if you have some routines that you want worked on, feel free to email me or post them. If I see a few I can do right away or if any particularly intrigue me, I'll help Smile
I have a bunch of fast trig routines as well, and I would be happy to contribute any other routines I have or could write relatively quickly. I regret that I won't have the time to be a more substantive partner in the project. I hope you do find people, though!
To be honest, I don't fully know which routines I need yet. For the 3D part, it needs to be signed. And 8.8 was too small because I got overflows. 8 bits of decimal accuracy is enough, so 16.16 might be a bit of overkill.

So I'll have to choose between 16.8 fixed-points or 16-bit floating points. Does anyone know what would be the best for this project? (I do not know anything about the speed of small floating points).

If it helps to make the desision, here's a list of the math that is done in the 3D engine:

-addition
-substraction
-multiplication
-division
-sine (In the current version, I used that together with some math to do cosine and tangent as well)
- square root

All routines accept for the square root have to be signed.

Also, my fixed-point triangle drawing routine looks quite inefficient. Could anyone help with a very fast one based on how lines are drawn? Also, it should have support for full signed 16-bit coordinates.

And thanks to everyone who wants to help.
You're almost definitely best served using fixed-point numbers for a project like this. If 8.8 fixed-point is insufficient, then go for 16.8 fixed-point, I suppose. What sort of overflows were you getting with 8.8 that made it infeasible?
when models ware drawn very big (when you're close), stuff suddenly start to glitch and lines are being drawn incorrectely , drawing to the wrong points or drawing to random locations (only some lines, other parts of the model , which are further away and smaller, were drawn correctely). I can make a screenshot of this if you want.

EDIT to avoid a double-post:
So I decided to go with 16.8 fixed-points. I already have addition and addition:
add hl, de \ adc a, c ;to add cde to ahl
and subtraction:
sub c \ sbc hl, de ;to subtract cde from ahl

I'm not fully sure if they would work with signed numbers too, but I think they will.

Now I still need a signed 16.8 multiplication routine, a signed 16.8 division routine and a 16.8 square root routine. I already have an 8.8 sine routine and it shouldn't be too hard to make it 16.8.
All math routines can have LUT's, as long as I still have around 2Kb RAM free for variables and the engine.
I'm going to try the multiplication, so I was wondering how you wanted to deal with overflow? Maybe return a specific flag if there was overflow, set the result as the highest it can go, or just return it somewhere?
I basically switched to 16.8 to avoid overflows, so if it's the easiest for you, you can just ignore it. But if you like to handle it differently, setting it to the highest sounds like the best option.
oh, okay, I see. I think I will add that in just as an extra precaution.

EDIT: What about using shadow registers? Are you using interrupts?
I'm not using interrupts. I might add some later which will be used to move the player and other objects, so that everything keeps updating at the same speed interdependently of at which speed the engine runs. This would only be done once every X interrupts (I don't know the exact number), so it shouldn't matter if I miss a few.

So if I would once use interrupts, i could just add some DI's and EI's.
I am not sure if this will work for you:

Code:

Signed_AHL_Times_CDE:
;Inputs:
;     AHL, CDE
;Outputs:
;     CDEAHL is the result
     ld b,24
     ld (TempWord1),hl
     ld (TempByte1),a
     xor a
     ld h,a
     ld l,a
Loop:
;Shift the accumulator AHL
     add hl,hl
     rla
;Shift the multiplier CDE
     rl e
     rl d
     rl c
     jr c,Added
       push de
       push bc
       ld de,(TempWord1)
       ld bc,(TempByte1)
       add hl,de
       adc a,c
       pop bc
       pop de
       jr nc,$+3
       inc e
Added:
     djnz Loop
     ret


Since you are using 16.8 format, you will want the EAH part. Overflow on the integer end will be in CD, so you can check for overflow. You can add this before the "ret" to get the result in ELH

Code:

     ld l,a
;ELH
     ld a,c
     xor d             ;If there was no overflow, CD=0000 or FFFF
     jr nz,MaxVal
     xor d
     ret z              ;if it exits, CD=0
     inc d
     ret z              ;if it exits here, CD=-1
MaxVal:              ;If it got here, there was overflow
     ld hl,-1
     ld e,h
     ret

Now the result is in ELH and if there was overflow, it goes with FFFFFF as the result.

(At least, that is how I expect it to work. Hopefully somebody can come along and optimise/fix this up)

*cough* Runer Razz
Thank you for the multiplication routine.

I just completed the sine routine:

Code:

Sin:
  ;calculates the sine of a as a fixed point number
  ;IN: a
  ;OUT: ahl = sin(a)
  ld h, 0
  ld l, a
  add hl, hl
  ld de, Sine_table
  add hl, de
  ld a, (hl)
  inc hl
  ld h, (hl)
  ld l, a
  ld a, 0
  bit 7, h
  ret z
  ld a, $FF
  ret
sine_table:
.dw    0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 62, 68, 74, 80, 86, 92, 98, 104, 109, 115, 121, 126, 132, 137, 142
.dw    147, 152, 157, 162, 167, 172, 177, 181, 185, 190, 194, 198, 202, 206, 209, 213, 216, 220, 223, 226, 229, 231, 234
.dw    237, 239, 241, 243, 245, 247, 248, 250, 251, 252, 253, 254, 255, 255, 256, 256, 256, 256, 256, 255, 255, 254, 253
.dw    252, 251, 250, 248, 247, 245, 243, 241, 239, 237, 234, 231, 229, 226, 223, 220, 216, 213, 209, 206, 202, 198, 194
.dw    190, 185, 181, 177, 172, 167, 162, 157, 152, 147, 142, 137, 132, 126, 121, 115, 109, 104, 98, 92, 86, 80, 74, 68
.dw    62, 56, 50, 44, 38, 31, 25, 19, 13, 6, 0, -6, -13, -19, -25, -31, -38, -44, -50, -56, -62, -68, -74, -80, -86, -92
.dw    -98, -104, -109, -115, -121, -126, -132, -137, -142, -147, -152, -157, -162, -167, -172, -177, -181, -185, -190
.dw    -194, -198, -202, -206, -209, -213, -216, -220, -223, -226, -229, -231, -234, -237, -239, -241, -243, -245, -247
.dw    -248, -250, -251, -252, -253, -254, -255, -255, -256, -256, -256, -256, -256, -255, -255, -254, -253, -252, -251
.dw    -250, -248, -247, -245, -243, -241, -239, -237, -234, -231, -229, -226, -223, -220, -216, -213, -209, -206, -202
.dw    -198, -194, -190, -185, -181, -177, -172, -167, -162, -157, -152, -147, -142, -137, -132, -126, -121, -115, -109
.dw    -104, -98, -92, -86, -80, -74, -68, -62, -56, -50, -44, -38, -31, -25, -19, -13, -6
Ben_g. I'm terrible at math routines, but if you need a beta/alpha tester at any point, you can count me in.
As requested in IRC, negating ahl:

Code:
   neg
   push af
      ld a,h
      cpl
      ld h,a
      ld a,l
      cpl
      ld l,a
      pop af
   ld de,1
   add hl,de
   adc a,d


I welcome any optimizations or functional corrections.
I alse needed a negCDE routine, so I wrote this one based on your code:

Code:

NegCDE:
  push af   ;1
  xor a
  sub c
  inc c
  ld a,d
  cpl
  ld d,a
  ld a,e
  cpl
  ld c,e
  pop af   ;0
  ret

Will it work?

EDIT: @ACagliano, Once this reaches a playable state, you can be one of the first who will test it, to get rid of most bugs.
Nope, that's still not it. You're incrementing c, but c is the MSB and e is the LSB. To do two's-complement negation, you first flip all bits, then add 1. It would look something like this:


Code:
NegCDE:
   push af
      ld a,d
      cpl
      ld d,a
      ld a,e
      cpl
      ld e,a
      ld hl,1
      add hl,de   ; affects carry
      ex de,hl     ; does not affect condition registers
      ld a,c
      cpl             ; does not affect carry
      adc a,h      ; a + 0 + carry -> a
      ld c,a
      pop af


I think.
Thank you. Now, will this work as a signed multiplication?

Code:

MulFP:
;Inputs:
;     AHL, CDE
;Outputs:
;     CDEAHL is the result

  ;handle sign
  push af      ;1
  xor c
  res 0, (IY+RoutineFlags)
  bit 7, a
  jr nz, ResultPos
  set 0, (IY+RoutineFlags)
ResultPos:
  pop af      ;0
  bit 7, a
  call nz, negAHL
  bit 7, c
  call nz, negCDE


     ld b,24
     ld (TempWord1),hl
     ld (TempByte1),a
     xor a
     ld h,a
     ld l,a
Loop:
;Shift the accumulator AHL
     add hl,hl
     rla
;Shift the multiplier CDE
     rl e
     rl d
     rl c
     jr c,Added
       push de
       push bc
       ld de,(TempWord1)
       ld bc,(TempByte1)
       add hl,de
       adc a,c
       pop bc
       pop de
       jr nc,$+3
       inc e
Added:
     djnz Loop

;handle overflow
     ld l, a
;ELH
     ld a,c
     xor d             ;If there was no overflow, CD=0000 or FFFF
     jr nz,MaxVal
     xor d
     ret z              ;if it exits, CD=0
     inc d
     ret z              ;if it exits here, CD=-1
MaxVal:              ;If it got here, there was overflow
     ld hl,-1
     ld e,h

  ;the result is now in ELH. Move to ahl
  ld a, e
  ld e, h
  ld h, l
  ld l, e

;now fix the sign:
  bit 0, (IY+RoutineFlags)
  call nz, negAHL
  ret


It's basically xeda's routine with some code added at the start and end.

The code at the start to make sure both numbers are positive and save the sign:

Code:

  ;handle sign
  push af      ;1
  xor c
  res 0, (IY+RoutineFlags)
  bit 7, a
  jr nz, ResultPos
  set 0, (IY+RoutineFlags)
ResultPos:
  pop af      ;0
  bit 7, a
  call nz, negAHL
  bit 7, c
  call nz, negCDE


And the code at the end to put the result in ahl and negate if nessicary:

Code:

  ;the result is now in ELH. Move to ahl
  ld a, e
  ld e, h
  ld h, l
  ld l, e

;now fix the sign:
  bit 0, (IY+RoutineFlags)
  call nz, negAHL
  ret
Yep, that looks right, but I can see a slight optimisation:

Code:

  bit 7, a
  jr nz, ResultPos

This can be changed to just:

Code:

  jp p,ResultPos

This is because the "xor c" will have bit 7 (the sign bit) set if only one value was negative, and if that bit is set after a math operation, the plus/minus flag is set.
Okay, couldn't resist on the NegCDE.

Code:
  xor a
  ld h,a
  sub e
  ld e,a
  ld a,h
  sbc a,d
  ld d,a
  ld a,h
  sbc a,c
  ld c,a
And I was just going to post the NegAHL:

Code:

NegAHL:
  push af    ;10
  xor a      ;4
  sub l      ;4
  ld l,a     ;4
  sbc a,a    ;4    ;since c flag will be set, a will be FF
  sub h      ;4
  ld h,a     ;4
  ex (sp),hl ;19
  ld a,-1    ;7
  sub h      ;4
  pop hl     ;11

I hope I didn't make any mistakes :/
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement