don't click here

S2:AE update topic/ rika needs help topic

Discussion in 'Engineering & Reverse Engineering' started by Rika Chou, May 4, 2006.

Thread Status:
Not open for further replies.
  1. muteKi

    muteKi

    Fuck it Member
    7,851
    131
    43
  2. Puto

    Puto

    Shin'ichi Kudō, detective. Tech Member
    2,013
    0
    16
    Portugal, Oeiras
    Part of Team Megamix, but haven't done any actual work in ages.
    What do I have to do with any of this?
     
  3. muteKi

    muteKi

    Fuck it Member
    7,851
    131
    43
    Fuck, I've got you and Nineko confused again.


    Well, that's one brilliant pun down the drain.
     
  4. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    Having most of my new background in ROM, I'm realizing that I need some new deformation to go with it. I have no idea how to do this. ;)


    Does anyone here know how to program new deformation scrolling? I need something that is 624 pixels tall and 4 128x128 tiles wide (before it repeats itself.), and scrolls like this:

    [​IMG]

    RED = Slow
    GREEN = A little faster
    PURPLE = Fastest
     
  5. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    No one knows how to do this? Or maybe, no one wants to help me with it. ;)
     
  6. JoseTB

    JoseTB

    Tech Member
    716
    59
    28
    I don't have time to write the code for you but, the basic idea is that you can simply modify the H Scroll table mirror in your own background deformation sub (well virtually you can modify it at anytime, but you get the idea) to get whatever scrolling effect you want, you might have to check for the y position and modify accordingly since the bg is taller than the whole plane, but it shouldn't still take too much to code.
     
  7. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    What do you mean here? The Backgrounds can be 16 chunks tall while mine is only slightly less than 5. Either way though, I really have no idea how to do that, I suck when it comes to programing. :rolleyes:
     
  8. jman2050

    jman2050

    Teh Sonik Haker Tech Member
    634
    4
    18
    Deformation scrolling! I can be useful!

    That deformation for what you want in particular is extremely simply, so it shouldn't be a problem to do relatively quickly when I have time.
     
  9. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    :(

    That will be awesome, thanks a lot!
     
  10. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    You still up to doing it? (not wanting to bug you or be pushy or anything!)
     
  11. Write a guide plz? =P I'd like to learn how to do deformation as well, it can be a bitch to work with.
     
  12. qiuu

    qiuu

    Tech Member
    144
    9
    18
    Blue Ball & Blocks
    First of all, I'm pretty inexperienced regarding ASM and the Sonic Engine, and the following is just my observation from messing around with the parallax scrolling routines. Therefore the following content is not necessarily correct, but at least it appears to work that way for me. Anyone with better knowledge is encouraged to correct mistakes and explain missing things. While the general concept of parallax scrolling is rather simple to grasp, some sub-routines are still beyond my understanding.

    I've been using Xenowhirl's 2007 Sonic 2 disassembly, and the following code is extracted from it.

    The parallax scrolling array stores for both background and foreground the amount of pixels the gfx data is shifted in each horizontal line on the screen. The address of this array is $FFFFE000, in the assembly it is referenced as Horiz_Scroll_Buf. According to the wiki, it takes $400 bytes thus allowing data for 256 lines being stored even though only 224 appear to be needed. The entry for each line in the array is 4 bytes, I.e. a longword; the upper word of it stores the foreground shift, the lower word the background shift.

    For each zone there is a specific routine that is executed every frame updating the data in the parallax scrolling array. A jump table that is labeled JmpTbl_SwScrlMgr determines which rountine is to be executed.

    In the following I altered the routine of MCZ hopefully to fit rika_chou's needs.

    The MCZ routine is labeled SwScrl_MCZ (loc_CD2C).

    The position of the foreground camera is stored at address $FFFFEE04 labeled Camera_Y_pos; the value stored at address $FFFFEE0C appears to be the vertical camera background position, so I labeled it Camera_Bg_Y_pos.

    Code (ASM):
    1. ; loc_CD2C:
    2. SwScrl_MCZ:
    3.     ;   Two-Player Test from MCZ removed
    4.     move.w  (Camera_Y_pos).w,d0 ;   foreground Y
    5.     tst.b   (Current_Act).w
    6.     bne.s   loc_CD4C
    7.     divu.w  #3,d0       ;   act 1: original code from MCZ
    8.     subi.w  #$140,d0    ;   modify for your needs
    9.     bra.s   loc_CD54
    10.  
    11. loc_CD4C:
    12.     divu.w  #6,d0       ;   act 2: original code from MCZ
    13.     subi.w  #$10,d0     ;   modify for your needs
    14.  
    15. loc_CD54:
    16.     move.l  (Camera_Bg_Y_pos).w,d3  ;   background Y
    17.     swap    d0
    18.     moveq   #6,d6
    19.     bsr.w   Vertical_Bg_Deformation2    ;   loc_D940
    20.     move.w  (Camera_Bg_Y_pos).w,($FFFFF618).w
    21.     moveq   #0,d2
    The background camera y-position is stored in d3 as it will be needed in the subroutine I labeled Vertical_Bg_Deformation2, formerly labeled loc_D940. I'm not quite sure what that routine actually does apart from assigning the value of d0 to Camera_Bg_Y_pos. Anyways, for each act you can set d0, preferably depending on the Camera_Y_pos; d0 will determine Camera_Bg_Y_pos then.
    In the original code, d0 = Camera_Y_pos/3 - $140 and d0 = Camera_Y_pos/6 - $10 for each act respectively. So Camera_Bg_Y_pos could be negative theoretically which would cause nothing (or possibly even garbled crap) to be displayed, however Sonic cannot reach high enough in MCZ for the Camera_Y_pos to be low enough to make Camera_Bg_Y_pos negative.
    So let's say e.g. your foreground is set up of 8 128*128 chunks = 1024 pixels, so the highest possible value for Camera_Y_pos is 1024 - 224 = 800, the lowest 0. Your background has a height of 624 pixels, so the highest Camera_Bg_Y_pos should be 624 - 224 = 400, the lowest 0 again. Then you have to divide Camera_Y_pos by (800/400)=2 in order to get d0=Camera_Bg_Y_pos.

    So replace
    Code (ASM):
    1.     divu.w  #3,d0       ;   act 1: original code from MCZ
    2.     subi.w  #$140,d0    ;   modify for your needs
    by
    Code (ASM):
    1.     asr.w   #1,d0       ;   divide by 2
    in that case, or to whatever fits.

    I don't quite know what the Vertical_Bg_Deformation2 routine does, but it might set some bits at byte $FFFFEE52 depending on d6. For some values of d6 the background will be garbled. $FFFFEE52 is somewhere else or.b'ed with $FFFFEE54 to $FFFFEE56, but I can't find out what either of these does. Neither do I know what $FFFFF618 means.

    Now on to the actual parallax scrolling. In the original code there is a short segment for shaking the screen, but I removed this here.
    Now, in the original code the scrolling shift values for the respective layers are stored to $FFFFA800 onwards, and that happenes in various parallax scrolling routines (I.e. also for other zones), while according to the wiki these addresses belong to the 'Block Table'. I'm not sure whether this might cause an interference (for me it doesn't), but in case it does, a different address might be used. Alternatively, this could also be modified not to use any other memory, it would have to be directly integrated into the loops that store the layer deformation data in Horiz_Scroll_Buf.

    Code (ASM):
    1.     lea ($FFFFA800).w,a2    ;   the future scrolling shift array
    2.     move.w  (Camera_X_pos).w,d0
    3.     ext.l   d0
    4.     asl.l   #6,d0
    5.     asl.l   #8,d0   ;   the Camera_X_pos multiplied by $400, adjust to your needs
    6.     move.l  d0,d1
    7.     swap    d1
    8.     move.w  d1,(a2)+    ;   basic shift
    9.     move.w  d1,(a2)+    ;   basic shift
    10.     swap    d1
    11.     add.l   d0,d1
    12.     swap    d1
    13.     move.w  d1,(a2)+    ;   2*basic shift
    14.     swap    d1
    15.     add.l   d0,d1
    16.     swap    d1
    17.     move.w  d1,(a2)+    ;   3*basic shift
    18.     lea (MCZ_Deformation_Data).l,a3
    19.     lea ($FFFFA800).w,a2    ;   scrolling speed array
    20.     move.w  (Camera_Bg_Y_pos).w,d1
    21.     moveq   #0,d0
    In order to avoid mul and div commands, d0 will be a basic scrolling shift, I.e. the amount of pixels for the layer to be offset. d1 will have various multiples of the basic shift d0 as values.
    In the code above, the Camera_X_pos is stored in d0 and multiplied by $400. You can choose any other value as well use mul and div commands. In the example code the upper word of d0 now contains the Camera_X_pos divided by 4, the lower word the fractions left from the division. Calculation using fractions will allow for a smoother scrolling.
    The value of d0 is now stored in d1, and d1 is swapped (I.e. upper and lower word exchanged) that the lower word now contains the integer part of the scrolling shift. This value is moved to the scrolling shift array. d1 is swapped again, d0 added, and so on. Later on we get two more layers, one scrolling twice as fast as the first one, one scrolling three times as fast.
    Essentially one can put anything into the scrolling shift array, depending on the Camera position, current frame number, static or onything else I guess.

    Now we've got an array of scrolling shifts, and we also have a fixed array of layer widths at MCZ_Deformation_Data, formerly labeled byte_CE6C. The routine above can easily be altered to use an arbitrary amount of layers.
    However, this is the data starting from the top of the background, if the Camera_Bg_Y_pos is larger than 0, some of this data will be irrelevant and has to be skipped. This is done in the first section of the following routine:

    Code (ASM):
    1. loc_CE3E:
    2.     move.b  (a3)+,d0    ;   data from shift width list
    3.     addq.w  #2,a2   ;   next entry in scrolling shift list
    4.     sub.w   d0,d1   ;   d1=(Camera_Bg_Y_pos)
    5.     bcc.s   loc_CE3E    ;   skip until affected layers, i.e. d1 < d0
    6.  
    7.     neg.w   d1
    8.     subq.w  #2,a2   ;   one entry back
    9.     move.w  (Camera_X_pos).w,d0
    10.     neg.w   d0
    11.     swap    d0  ;   negated Camera_X_pos in upper word (foreground)
    12.     move.w  (a2)+,d0   
    13.     neg.w   d0  ;   negated data from scrolling shift array in lower word (background)
    14.  
    15. ;   loop to enter data into Horiz_Scroll_Buf
    16.     lea (Horiz_Scroll_Buf).w,a1
    17.     move.w  #bytesToLcnt($380),d2   ;   #bytesToLcnt($380) = 223
    18. -   move.l  d0,(a1)+
    19.     subq.w  #1,d1   ;   decrease remaining width of layer
    20.     bne.s   +   ;   as long as some lines of the layer left, don't change scrolling shift
    21.     move.b  (a3)+,d1    ;   width of next layer
    22.     move.w  (a2)+,d0
    23.     neg.w   d0  ;   negated new scrolling shift value
    24. +   dbf d2,-
    25.     rts
    The final part of the routine uses a nested loop to store the data finally into the Horiz_Scroll_Buf. The foreground scrolling shift always keeps the same, Camera_X_Pos, as the upper word is not affected by the other instructions, the lower word is the data from the scrolling shift array.

    And finally the layer width array at the end:

    Code (ASM):
    1. ;   byte_CE6C:
    2. MCZ_Deformation_Data:
    3.     dc.b $FF    ;   0
    4.     dc.b $AD    ;   1 (428)
    5.     dc.b $47    ;   2 (71)
    6.     dc.b $7D    ;   3 (125)
    The layer of width 428 is split up into two layers, scrolling shift value is added twice to the array in the respective section of the routine.

    It is also possible to make the scrolling not dependant on the camera position but continuous, I.e. increasing the shift each frame, like in HTZ (clouds) and DEZ (stars).

    One thing that seems weird is that after 4 chunks that background simply starts off again from the beginning. However, some zones like CPZ appear to overcome that limitation. Maybe that weird value of $FFFFEE56 has something to do with it?
    I hope this works not just for me and that my explanations are of use to somebody, as they appear somewhat messy to me...
    Questions, corrections et al. are always welcome.
     
  13. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    WOW! That is one awesome first post! Thanks a lot of taking the time to help me with this.


    It seems to work, almost. I don't quite understand how to set the Y size of the level so that the background dosen't scroll below the last layer. (My level is going to be 16 128x128 chunks tall in both acts.) The scrolling works and everything, but the background goes a bit too far down, so you can see the nothingness below it. It doesn't scroll or anything, just follows along with the camera. Also, I'm not sure how to change how fast each layer moves.

    Everything else seems like it's working like it should.
     
  14. qiuu

    qiuu

    Tech Member
    144
    9
    18
    Blue Ball & Blocks
    Nice to know that it could be of use to you.

    As for the vertical scrolling, well, if Sonic is standing at the top of the level, the Camera_Y_pos will be 0. As your level's height is 2048, the maximal Camery_Y_pos is one screen height less, I.e. 2048 - 224 = 1824. For the background Camera, the lowest value should be 0 and the highest 624 - 224 = 400.
    The quota of these values is 400/1824, I.e. when the foreground Camera scrolls 1824 pixels, the background camera scrolls 400. In order to have to use a div or mul command only once, I approximate what value with 16/73. The difference between 400/1824 and 16/73 is small enough to only account for one pixel difference effectively, I.e. only the 624th line of your background will never be displayed.

    Code (ASM):
    1. SwScrl_MCZ:
    2.     move.w  (Camera_Y_pos).w,d0 ;   foreground Y
    3.     ext.l   d0  ;   not sure whether this is exactly necessary
    4.     asl.l   #4,d0
    5.     divu.w  #$49,d0 ;   multiplied by 16 and divided by $49 = 73 decimal
    If you replace the first two paragraphs from my first asm tag by this, the vertical scrolling should work as intended.

    The layers scrolling 'speeds', or actually shifts, are stored in the array starting at $FFFFA800. Essentially I had the first layer scroll at a speed 1/4 of the foreground scrolling speed, the sceond layer at 2/4 and the third at 3/4. It looks more complicated than it is as the use of mul has been avoided, and swapping commands on longwords are used to keep the precision. Some explanation on the latter: say we have $0123|9000 stored in d0. Swapping will cause d0 to be $9000|0123. $0123 is stored in the scrolling shift array. Swapped again, it is $0123|9000. Now we mulitply it by 2 (asl.l #1,d0), the value is $0247|2000. If we had just operated on the integer part, that value would have been $0246, it could never be $247 then, therefore the scrolling would be sloppy always jumping two pixel that way.
    Ok, so first you move the Camera_X_pos to d0, it is only the size of a word, so extend it to a longword. The value stored in d0 which I will call ShiftValue henceforce is the background shift multiplied by $10000, I.e. if it is $01234000, the background shift is $123.4, the upper word of the ShiftValue is the integer part, the lower word the fraction; the foreground Camera value is equivalent to the foreground shift, so dividing the ShiftValue by Camera_X_pos would result in the speed that layer moves compared to the foreground, e.g. if the Camra_X_pos is $48D and the background shift $123.4, $123.4/$48D is 1/4, I.e. the background layer scrolls 1/4 as fast as the foreground.
    So essentially, backgroundScrollSpeed/foregroundScrollSpeed = ShiftValue/(Camera_X_Pos*$10000), I.e. ShiftValue = backgroundScrollSpeed/foregroundScrollSpeed * (Camera_X_Pos*$10000). Using that formula, you can easily assign the desired scrolling speeds. To store the ShiftValue into the array that is addressed with $FFFFA800, you first have to swap it, as the integer part of it is stored in the upper word, but you need it in the lower word to put it into the array.

    There are many ways to calculate the the shift values; let's say we want to scroll the first layer at speed 1/7, the second at 2/7, and the third at 4/7:

    Code (ASM):
    1.     lea ($FFFFA800).w,a2
    2.     move.w  (Camera_X_pos).w,d0
    3.     ext.l   d0
    4.     asl.l   #4,d0
    5.     divu.w  #$7,d0
    6.     asl.l   #4,d0
    7.     asl.l   #8,d0   ;   $10000/7*Camera_X_pos, i.e. 1/7 scrolling speed
    8.     swap    d0
    9.     move.w  d0,(a2)+
    10.     move.w  d0,(a2)+
    11.     swap    d0
    12.     asl.l   #1,d0   ;   2/7 scrolling speed
    13.     swap    d0
    14.     move.w  d0,(a2)+
    15.     swap    d0
    16.     asl.l   #1,d0   ;   4/7 scrolling speed
    17.     swap    d0
    18.     move.w  d0,(a2)+
    19.     lea (MCZ_Deformation_Data).l,a3
    20.     lea ($FFFFA800).w,a2    ;   shift array
    21.     move.w  (Camera_Bg_Y_pos).w,d1
    22.     moveq   #0,d0
    I know I suck at explaining stuff, but I hope it is at least remotely understandable.
     
  15. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    Awesome, it's working now. I had to read through it a million times, but I think I understand it. I really suck at understanding this kind of stuff. :P

    Thanks!
     
  16. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    Nother problem!

    I have an object that I want to be flippable by setting the third object value in soned. I know that #1,$22(a0) and #1,$1(a0) have something to do with this, but I just can't figure out how to change these values according to that third value in soned.

    Also, how would I make an object hurt sonic only when he touches it from the top or the bottom according to how the object is flipped. (like the spikes...)

    I know that has got to be simple, but I couldn't figure it out by looking at other objects.
     
  17. jman2050

    jman2050

    Teh Sonik Haker Tech Member
    634
    4
    18
    Crap, I completely forgot about doing this deformation. You should've badgered me more :P

    Sorry bout that though. Lots of things going on, you know? >_>
     
  18. At object loading, the upper 3 bits of the object Y position are treated as special - upmost bit (bit #15) being set indicates an object for which respawn state should be remembered, the bit below that (bit #14) is the Y flip flag, and the bit below that (bit #13) is the X flip flag (these two bits become the bit #1 and bit #0 (respectively) of the render flags and status bitfields). While SonED doesn't allow setting these directly, I think you can press 9 to switch between different flip modes (normal, X flip, Y flip, X+Y flip).

    As far as I can see, the spikes call SolidObject with the appropriate parameters and then check the return values and call Touch_ChkHurt2 appropriately - in case of the upright spikes, they check the character standing on platform bits in the status bitfield, and in case of the Y-flipped spikes, they manipulate d6 in some way. You'll probably have to combine both if you want the object to hurt Sonic from the top and bottom simultaneously.
     
  19. Rika Chou

    Rika Chou

    Tech Member
    5,276
    169
    43
    I know this already. My problem is that when I change my object to be y flipped using the first bit of the Y position, it doesn't actually appear y flipped in game.
     
  20. :S I think that's pretty impossible, since flipping is handled by the VDP itself. Just for testing purposes, try putting a:
    Code (ASM):
    1.     bset #1,status(a0) ; set Y-flip bit
    2.     or.b  #6,render_flags(a0) ; set level-coordinate and Y-flip flags
    at the beginning of the object code. If it still doesn't flip, I have no idea what's wrong.

    Also, if by first bit you mean upmost bit, it's not the first bit, it's the second. (In other words, you need to add 4000 to the Y position for Y flip, not 8000)
     
Thread Status:
Not open for further replies.