Advertisement
partyboy1a

snes-blinking-sprites-marker-wip1.lua

Sep 9th, 2011
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.80 KB | None | 0 0
  1. -- snes blinking sprites marker
  2. -- to understand what's going on here you must read
  3. -- http://patpend.net/technical/snes/snes.txt
  4.  
  5.  
  6. --[[ HOW TO USE:
  7. - playback a movie file
  8. - start the script when you got to the start of an interesting section
  9. - press numpad+ to see sprite data
  10. --]]
  11. local count = 0
  12.  
  13. oam = {}
  14.  
  15. sprite_size_table = { -- note: width==height
  16.     {8,16},{8,32},{8,64},
  17.     {16,32},{16,64},{32,64}
  18. }
  19.  
  20. bit_select = {[0]=1,[1]=2,[2]=4,[3]=8,[4]=16,[5]=32,[6]=64,[7]=128}
  21. function bit(val,bit)
  22.     return AND(val,bit_select[bit])/bit_select[bit]
  23. end
  24.  
  25. spritedata = {}
  26. spritegroup = {}
  27.  
  28. function parse_oam(frame)
  29.     -- here are still some programming errors left...
  30.  
  31.     spritedata[frame] = {}
  32. --[[
  33. |   0     Byte   0             xxxxxxxx           x: X-location.             |
  34. |         Byte   1             yyyyyyyy           y: Y-location.             |
  35. |         Byte   2             abcdeeeC           a: Vertical flip.          |
  36. |                                                 b: Horizontal flip.        |
  37. |                                                 c: Playfield priority.     |
  38. |                                                 d: Playfield priority.     |
  39. |                                                 e: Pallete #.              |
  40. |         Byte   3             CCCCCCCC           C: Character data.         |
  41. |                                                                            |
  42. |starting at oam byte 512:                                                   |
  43. |2 bits are defined for each OBJ (eg. byte #0 holds the info for OBJ 0, 1, 2,|
  44. |and 3; byte #1 holds the info for OBJ 4, 5, 6, and 7). Therefore, 128/4 is  |
  45. |32 bytes of data for the following table:                                   |
  46. |                                  ab                                        |
  47. |                                  ||____Size toggle bit.                    |
  48. |                                  |_____MSB of X-position bit.              |
  49. |                                                                            |
  50. |So, the 4 bytes/sprites + the block are put into the OAM table by consec-   |
  51. |utive writes to the OAM data register. You first should set the OAM address |
  52. |to $0000, then shove your data into it.                                     |
  53. --]]
  54.     for i=0,31 do for j=0,3 do
  55.         spritedata[frame][4*i+j] = {}
  56.         spritedata[frame][4*i+j].x = oam[frame][4*(4*i+j)] + 256 * bit(oam[frame][512+i],2*j)
  57.        
  58.         temp = oam[frame][4*(4*i+j)+1]
  59.         if temp < 224 then
  60.             spritedata[frame][4*i+j].y = temp
  61.         else
  62.             spritedata[frame][4*i+j].y = temp - 256
  63.         end
  64.         spritedata[frame][4*i+j].width = sprite_size[bit(oam[frame][512+i],2*j+1) + 1]
  65.         if real_x == 256 + 128 then --don't draw this one, it doesn't exist
  66.             spritedata[frame][4*i+j].enabled = false
  67.         else
  68.             spritedata[frame][4*i+j].enabled = true
  69.         end
  70.         spritedata[frame][4*i+j].verticalflip   = (bit(oam[frame][4*(4*i+j)+2], 0) == 1)
  71.         spritedata[frame][4*i+j].horizontalflip = (bit(oam[frame][4*(4*i+j)+2], 1) == 1)
  72.         spritedata[frame][4*i+j].playfieldpriority = 2*bit(oam[frame][4*(4*i+j)+2], 2) + bit(oam[frame][4*(4*i+j)+2], 3)
  73.         spritedata[frame][4*i+j].pallete = 4*bit(oam[frame][4*(4*i+j)+2], 4) + 2*bit(oam[frame][4*(4*i+j)+2], 5) + bit(oam[frame][4*(4*i+j)+2], 6)
  74.         spritedata[frame][4*i+j].characterdata = 256 * bit(oam[frame][4*(4*i+j)+2], 7) + oam[frame][4*(4*i+j)+3]
  75.     end end
  76. end
  77.  
  78. function read_oam()
  79.     b = memory.readword(0x2101)
  80.     name_base = AND(b, 1+2+4) * 4096
  81.     name_bits = AND(b, 8+16)
  82.     sprite_size_bits = AND(b, 32+64+128) / 32
  83.     --sprite_size = {8,16} --should be sprite_size_table[sprite_size_bits + 1]
  84.     sprite_size = {16,32}
  85.    
  86.     oam[cf] = {}
  87.     memory.writeword(0x2102,0)
  88.     for i = 0,512+32-1 do
  89.         --memory.writeword(0x2102,i)
  90.         w = memory.readbyte(0x2138)
  91.         oam[cf][i] = w
  92.         --oam[2*i+1] = w % 256
  93.     end
  94. end
  95. --vram_sprite_offset
  96.  
  97. start = savestate.create()
  98. savestate.save(start)
  99.  
  100. function detectspritegroups(frame)
  101.     spritegroup[frame] = {}
  102.    
  103.     groupcount = 0
  104.     i = 0
  105.     while i < 127 do
  106.         groupcount = groupcount + 1
  107.         spritegroup[frame][groupcount] = {
  108.             min_x = spritedata[frame][i].x,
  109.             max_x = spritedata[frame][i].x,
  110.             min_y = spritedata[frame][i].y,
  111.             max_y = spritedata[frame][i].y,
  112.             numberofsprites = 1,
  113.             first = i
  114.         }
  115.         j = i + 1
  116.         while not spritedata[frame][j].enabled and j < 127 do
  117.             j = j + 1
  118.         end
  119.         while (
  120.             spritedata[frame][i].characterdata == spritedata[frame][j].characterdata and
  121.             math.mod(spritedata[frame][i].x - spritedata[frame][j].x, spritedata[frame][i].width) == 0 and
  122.             math.mod(spritedata[frame][i].y - spritedata[frame][j].y, spritedata[frame][i].width) == 0 ) and
  123.             ( spritedata[frame][i].x == spritedata[frame][j].x or spritedata[frame][i].y == spritedata[frame][j].y)
  124.             do
  125.            
  126.             spritegroup[frame][groupcount].min_x = math.min(spritegroup[frame][groupcount].min_x, spritedata[frame][j].x)
  127.             spritegroup[frame][groupcount].max_x = math.max(spritegroup[frame][groupcount].max_x, spritedata[frame][j].x)
  128.             spritegroup[frame][groupcount].min_y = math.min(spritegroup[frame][groupcount].min_y, spritedata[frame][j].y)
  129.             spritegroup[frame][groupcount].max_y = math.max(spritegroup[frame][groupcount].max_y, spritedata[frame][j].y)
  130.             spritegroup[frame][groupcount].numberofsprites = spritegroup[frame][groupcount].numberofsprites + 1
  131.             j = j + 1
  132.             if j == 128 then break end
  133.            
  134.         end
  135.         i = j
  136.        
  137.     end
  138. end
  139.  
  140. function findblinkingspritegroups(frame, distx, disty)
  141.     if spritegroup[frame] == nil or spritegroup[frame+1] == nil or spritegroup[frame+2] == nil then return end
  142.     for i,group in pairs(spritegroup[frame]) do
  143.         for j,group2 in pairs(spritegroup[frame+1]) do
  144.             if math.abs(group.min_x - group2.min_x) <= distx and
  145.                 math.abs(group.min_y - group2.min_y) <= disty and
  146.                 group.max_x - group.min_x == group2.max_x - group2.min_x and
  147.                 group.max_y - group.min_y == group2.max_y - group2.min_y and
  148.                 group.characterdata == group2.characterdata
  149.                 then
  150.                
  151.                 spritegroup[frame][i].normalmovement = j
  152.             end
  153.         end
  154.         for j,group2 in pairs(spritegroup[frame+2]) do
  155.             if math.abs(group.min_x - group2.min_x) <= 2*distx and
  156.                 math.abs(group.min_y - group2.min_y) <= 2*disty and
  157.                 group.max_x - group.min_x == group2.max_x - group2.min_x and
  158.                 group.max_y - group.min_y == group2.max_y - group2.min_y and
  159.                 group.characterdata == group2.characterdata
  160.                 then
  161.                
  162.                 spritegroup[frame][i].twostepmovement = j
  163.             end
  164.         end
  165.        
  166.         group.blinking = not group.normalmovement and group.twostepmovement
  167.     end
  168. end
  169.  
  170. while(true) do
  171.     snes9x.frameadvance()
  172.     cf = emu.framecount()
  173.     spritedata[cf] = {}
  174.     read_oam()
  175.     parse_oam(cf)
  176.     detectspritegroups(cf)
  177.     keys = input.get()
  178.     if keys["numpad+"] then break end
  179. end
  180.  
  181. function drawspritegroups(frame, color)
  182.     for i,group in pairs(spritegroup[frame]) do
  183.         if group.blinking or not group.normalmovement then
  184.             gui.box(math.max(0,group.min_x), math.max(0,group.min_y), group.max_x + 16, group.max_y + 16, color)
  185.             --gui.text(group.min_x, group.min_y, "BLINKING SPRITE")
  186.         end
  187.         if group.offset_x then
  188.             gui.text(group.max_x, group.max_y, tostring(group.offset_x) .. "|" .. tostring(group.offset_y))
  189.         end
  190.     end
  191. end
  192.  
  193. savestate.load(start)
  194. emu.registerbefore(function()
  195.     if spritegroup[cf - 1] == nil or spritegroup[cf] == nil or spritegroup[cf + 1] == nil then return end
  196.     cf = emu.framecount()
  197.     m = cf - 4 * math.floor(cf/4)
  198.     -- change sprite blinking status on two consecutive frames
  199.     if m == 0 then
  200.         -- don't change anything
  201.     elseif m == 1 then
  202.         -- copy all sprites that blink on the previous frame and the next frame
  203.         for i,group in pairs(spritegroup[cf - 1]) do
  204.             if group.blinking then
  205.                 -- do a linear movement interpolation
  206.                 gn = group.twostepmovement
  207.                 group2 = spritegroup[cf + 1][gn]
  208.                 group.offset_x = (group2.min_x - group.min_x) / 2
  209.                 group.offset_y = (group2.min_y - group.min_y) / 2
  210.             end
  211.         end
  212.     elseif m == 2 then
  213.         -- kill all sprites that blink on the current frame
  214.         for i,group in pairs(spritegroup[cf]) do
  215.             if group.blinking then
  216.                 group.enabled = false
  217.             end
  218.         end
  219.         -- copy all movement mismatched sprites from previous and next frame semi-transparent
  220.         for i,group in pairs(spritegroup[cf - 1]) do
  221.             if not group.normalmovement then
  222.                 -- here we should insert some "copy code"
  223.             end
  224.         end
  225.         for i,group in pairs(spritegroup[cf + 1]) do
  226.             if not group.normalmovement then
  227.                 -- here we should insert some "copy code"
  228.             end
  229.         end
  230.     elseif m == 3 then
  231.         -- do nothing
  232.     end
  233. end)
  234.  
  235. while(true) do
  236.     cf = emu.framecount()
  237.     findblinkingspritegroups(cf, 8, 8)
  238.    
  239.     m = cf - 4 * math.floor(cf/4)
  240.     colors = {[0]="red", [1]="green", [2]="red",[3]="green",[4]="red",[5]="green"}
  241.     if spritedata[cf] ~= nil then drawspritegroups(cf, colors[m]) end
  242.     if spritedata[cf-1] ~= nil then drawspritegroups(cf-1, colors[m+1]) end
  243.    
  244.     snes9x.frameadvance()
  245. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement