| Main > Project Announcements |
| Vectorising an arcade game: VectorKong is Completed |
| << < (3/11) > >> |
| 10yard:
--- Quote from: Xiaou2 on April 17, 2022, 09:57:56 pm --- But just an FYI about Vector drawing, with real hardware: Due to how a vector monitor draws (like a "Plotter", OR CNC cutter), and due to the limits on how much it can draw.. the programmers would probably highly Optimize how things were drawn. A vector, is drawn by a single electron beam... from one point to another. When moving from one object to another... the electron beam voltage is reduced so that there is no visible line between them. BUT.. if you Crank a vector monitors voltage up... you can actually see that all of the picture is a Continuous line. Visible Lines: A----B----C D--E---------F Actual Drawing: A----B----C-----D--E---------F As such... your Oil Barrel, would probably be drawn as a single line object.. instead of several boxes stacked on top of each other. This would also eliminate the issue that you are seeing.. where two edge lines do not match up. Maybe something like this: eA--------B F--------G - - - - I--------H D--------C That said.. Im just guessing about the way they would have drawn it. They may have had to test a few different versions to see which were faster, and most optimal. --- End quote --- Hey Xiaou2, thank you for your detailed information and examples. I've recently optimised the polyline draw function to allow continuous line drawing. The function now recognises breaks in the line object allowing for a connecting line to be effectively skipped - similar to your description of the low intensity vectors. A bonus of this optimisation is that line objects can be easily stored into a library for easy programmatic retrieval. See the entries for oilcan, hammer and barrel below. The numbers are a list of X,Y endpoints in pairs. "BR" represents a break in the continuous line. When BR,BR is encountered the connecting line is hidden. Now there are NO overlaps in the line drawing at all. --- Code: --- vector_lib["oilcan"] = {1,1,15,1,BR,BR,1,15,15,15,BR,BR,5,1,5,15,BR,BR,12,1,12,15,BR,BR,7,4,10,4,10,7,7,7,7,4,BR,BR,7,9,10,9,BR,BR,7,13,7,11,10,11,BR,BR,15,0,16,0,16,16,15,16,15,0,BR,BR,1,0,0,0,0,16,1,16,1,0} vector_lib["hammer"] = {5,0,7,0,8,1,8,8,7,9,5,9,4,8,4,1,5,0,BR,BR,4,4,0,4,0,5,4,5,BR,BR,8,4,9,4,9,5,8,5} vector_lib["barrel"] = {3,0,12,0,15,2,15,7,12,9,3,9,0,7,0,7,0,2,3,0,BR,BR,1,2,1,7,BR,BR,14,2,14,7,BR,BR,2,3,13,3,BR,BR,2,6,13,6} --- End code --- --- Quote from: Xiaou2 on April 17, 2022, 09:57:56 pm --- Also, Vectors can have different brightness levels. Part of this is probably programmed.. but part of it may be due to them utilizing Time-Delays as well as drawing certain things a few more times in the same area, to create much greater brightness effects. I believe you can turn up the values in mame, to see the entire vector path, including the "Invisible" lines. That should help in figuring out how the programmers drew them. --- End quote --- I have a function to vary the line intensity. At the moment, the intensity is randomised. I will likely adjust the function later to vary brightness of the background and emphasis sprites. I may add splashes of colour. --- Quote from: Xiaou2 on April 17, 2022, 09:57:56 pm --- As for the Vector Kong art.. Its cool, but a bit basic. Id suggest adding Zig-Zags in the Girders, to give it that same familiar raster look. (At very least, close the ends of each Girder) --- End quote --- I intentionally made the girders simple to keep the vector count down to a minimum. You made me rethink things, the zig-zag girders are very familiar to DK. I did some tests with added zig-zags. I also closed the girder ends as you recommended. 1) Full zig-zags = 579 vectors for background 2) Half zig-zags = 415 vectors for background 3) Big zig-zags - 415 vectors for background 4) Spaced zig-zags = 415 vectors for background I really like 4. In other news, I've made really good progress with character/font sprites and will have an update out very soon. |
| 10yard:
Here's another variation of the girder zig-zags. The zig-zags have a slightly increased height. I'm also showing a sneak preview here of the work that i've done with vectorising the DK character/fonts. This explains why the vector count is increased. For comparison with above this would be 415 vectors for the background. 5) spaced zig-zags variation I'd be interested to know what is your favourite option 1-5? |
| 10yard:
In this part 2, I'm going to be vectorising the character/fonts that are used by the game. The Donkey Kong rom includes 2 graphics banks. Bank 1 includes 256 characters which are sized at 8 x 8 pixels. Bank 2 includes 128 sprites which are sized at 16 x 16 pixels. We'll be working with bank 1. The characters in this bank comprise mostly of numbers, letters and punctuation. The Donkey Kong game outputs characters from bank 1 to the screen by utilising video RAM. The video RAM is located in RAM memory from address 7440 to 77ff. We can see video RAM in the MAME debugger. --- Code: ---mame dkong -debug --- End code --- In the debugger, open a new memory window, increase the byte width from 16 to 32 bytes (by pressing Ctrl+P 16 times), enter 7440 into the box and select "Run" from the menu. *The 32 bytes correspond to the height of the screen in DK i.e. 32 characters x 8 pixels = 256 pixel high. Address 7440 relates to the top-right corner of the screen. The video ram appears rotated when viewed in the debugger. I've annotated the debugger to show how we can determine characters that are output to the screen. The character chart below can be used to translate each of the hexadecimal values to a specific character graphic. For example, the wording for "HIGH SCORE" is made up from hex values: 18,19,17,18,10,23,13,1F,22,15. In the chart, "H" is found at 10 + 8 = 18. "I" is found at 10 + 9 = 19 etc. For reference, the video ram is showing the content of the name registration screen. It's perfect for our test because it contains the full alphabet of characters. I fleshed out a function to iterate through all of the 896 characters (32 x 28 characters) in video ram. We're getting ahead of ourselves so we'll come back to this function later when we've figured out how to draw characters from bank 1 as vectors. --- Code: ---function draw_vector_characters() -- Output vector characters based on contents of video ram ($7440-77ff) local _addr = 0x7440 for _x=223, 0, -8 do -- 32 characters for _y=255, 0, -8 do -- 28 characters -- <<<< FIGURE OUT HOW TO DRAW VECTOR CHARACTER AT y, x POSITION >>>> _addr = _addr + 1 end end end --- End code --- Ok, so now we can look into vectorising the pixel characters from bank 1. We may as well start with zero, the first character in the bank. The image below shows how I can draw a vector outline by joining all of the points with 8 lines. The points are relative to 0,0 at the bottom-left corner. So our y, x points forming the zero character are: 0,2 - 0,4 - 2,6 - 4,6 - 6,4 - 6,2 - 4,0 - 2,0 - 0,2 This can be plotted to the screen using our existing polyline function as follows. --- Code: ---polyline{0,2,0,4,2,6,4,6,6,4,6,2,4,0,2,0,0,2} --- End code --- I took on the tedious task of vectorising all of the characters we're going to need and stored the results into a vector library. This will give us convenient access in our LUA program. The ID in the vector library e.g. [0x00] matches with the hexadecimal value in our character lookup table above. --- Code: --- vector_lib[0x00] = {0,2,0,4,2,6,4,6,6,4,6,2,4,0,2,0,0,2} -- 0 vector_lib[0x01] = {0,0,0,6,BR,BR,0,3,6,3,5, 1} -- 1 vector_lib[0x02] = {0,6,0,0,5,6,6,3,5,0} -- 2 vector_lib[0x03] = {1,0,0,1,0,5,1,6,2,6,3,5,3,2,6,6,6,1} -- 3 vector_lib[0x04] = {0,5,6,5,2,0,2,7} -- 4 vector_lib[0x05] = {1,0,0,1,0,5,2,6,4,5,4,0,6,0,6,5} -- 5 vector_lib[0x06] = {3,0,1,0,0,1,0,5,1,6,2,6,3,5,3,0,6,2,6,5} -- 6 vector_lib[0x07] = {6,0,6,6,0,2} -- 7 vector_lib[0x08] = {2,0,0,1,0,5,2,6,5,0,6,1,6,4,5,5,2,0} -- 8 vector_lib[0x09] = {0,1,0,4,2,6,5,6,6,5,6,1,5,0,4,0,3,1,3,6} -- 9 vector_lib[0x11] = {0,0,4,0,6,3,4,6,0,6,BR,BR,2,6,2,0} -- A vector_lib[0x12] = {0,0,6,0,6,5,5,6,4,6,3,5,2,6,1,6,0,5,0,0,BR,BR,3,0,3,4} -- B vector_lib[0x13] = {1,6,0,5,0,2,2,0,4,0,6,2,6,5,5,6} -- C vector_lib[0x14] = {0,0,6,0,6,4,4,6,2,6,0,4,0,0} -- D vector_lib[0x15] = {0,5,0,0,6,0,6,5,BR,BR,3,0,3,4} -- E vector_lib[0x16] = {0,0,6,0,6,6,BR,BR,3,0,3,5} -- F vector_lib[0x17] = {3,4,3,6,0,6,0,2,2,0,4,0,6,2,6,6} -- G vector_lib[0x18] = {0,0,6,0,BR,BR,3,0,3,6,BR,BR,0,6,6,6} -- H vector_lib[0x19] = {0,0,0,6,BR,BR,0,3,6,3,BR,BR,6,0,6,6} -- I vector_lib[0x1a] = {1,0,0,1,0,5,1,6,6,6} -- J vector_lib[0x1b] = {0,0,6,0,BR,BR,3,0,0,6,BR,BR,3,0,6,6} -- K vector_lib[0x1c] = {6,0,0,0,0,5} -- L vector_lib[0x1d] = {0,0,6,0,2,3,6,6,0,6} -- M vector_lib[0x1e] = {0,0,6,0,0,6,6,6} -- N vector_lib[0x1f] = {1,0,5,0,6,1,6,5,5,6,1,6,0,5,0,1,1,0} -- O vector_lib[0x20] = {0,0,6,0,6,5,5,6,3,6,2,5,2,0} -- P vector_lib[0x21] = {1,0,5,0,6,1,6,5,5,6,2,6,0,4,0,1,1,0,BR,BR,0,6,2,3} -- Q vector_lib[0x22] = {0,0,6,0,6,5,5,6,4,6,2,3,2,0,2,3,0,6} -- R vector_lib[0x23] = {1,0,0,1,0,5,1,6,2,6,4,0,5,0,6,1,6,4,5,5} -- S vector_lib[0x24] = {6,0,6,6,BR,BR,6,3,0,3} -- T vector_lib[0x25] = {6,0,1,0,0,1,0,5,1,6,6,6} -- U vector_lib[0x26] = {6,0,3,0,0,3,3,6,6,6} -- V vector_lib[0x27] = {6,0,2,0,0,1,4,3,0,5,2,6,6,6} -- W vector_lib[0x28] = {0,0,6,6,3,3,6,0,0,6} -- X vector_lib[0x29] = {6,0,3,3,6,6,BR,BR,3,3,0,3} -- Y vector_lib[0x2a] = {6,0,6,6,0,0,0,6} -- Z vector_lib[0x2b] = {0,0,1,0,1,1,0,1,0,0} -- dot vector_lib[0x2c] = {3,0,3,5} -- dash vector_lib[0x2d] = {5,0,5,6} -- underscore vector_lib[0x2e] = {4,3,4,3,BR,BR,2,3,2,3} -- colon vector_lib[0x2f] = {5,0,5,6} -- Alt underscore vector_lib[0x34] = {2,0,2,5,BR,BR,4,0,4,5} -- equals vector_lib[0x35] = {3,0,3,5} -- dash vector_lib[0x44] = {0,5,4,5,4,7,2,7,0,8,BR,BR,2,5,2,7,BR,BR,4,10,1,10,0,11,0,12,1,13,4,13,BR,BR,0,15,4,15,4,17,2,17,2,18,0,18,0,15,BR,BR,2,15,2,17,BR,BR,0,23,0,21,4,21,4,23,BR,BR,2,21,2,22,BR,BR,0,25,4,25,0,28,4,28,BR,BR,0,30,4,30,4,32,3,33,1,33,0,32,0,30} -- rub / end vector_lib[0x49] = {0,4,2,2,5,2,7,4,7,8,5,10,2,10,0,8,0,4,BR,BR,2,7,2,5,5,5,5,7} -- copyright vector_lib[0x6c] = {2,0,2,4,3,5,4,4,5,5,6,4,6,0,2,0,BR,BR,4,4,4,0,BR,BR,3,7,2,8,2,11,3,12,5,12,6,11,6,8,5,7,3,7,BR,BR,2,14,6,14,2,19,6,19,BR,BR,6,21,3,21,2,22,2,25,3,26,6,26,BR,BR,2,28,2,31,4,31,4,28,5,28,6,29,6,31, B,BR,6,-2,6,-5,-12,-5,-12,36,6,36,6,33,BR,BR,0,-3,-10,-3,-10,34,0,34,0,-3} -- bonus vector_lib[0x9f] = {2,0,0,2,0,13,2,15,5,15,7,13,7,2,5,0,2,0,BR,BR,5,3,5,7,BR,BR,5,5,2,5,BR,BR,2,8,5,8,4,10,5,12,2,12} -- TM vector_lib[0xb0] = {0,0,0,8,BR,BR,1,0,1,8,BR,BR,7,0,7,8,BR,BR,6,0,6,8} -- Block vector_lib[0xb1] = {0,0,7,0,7,7,0,7,0,0} -- Box vector_lib[0xb7] = {0,1,1,1,1,2,6,2,6,1,7,1,7,3,6,3,6,5,7,5,7,7,6,7,6,6,1,6,1,7,0,7,0,1} -- Rivet vector_lib[0xdd] = {0,0,7,0,BR,BR,4,0,4,4,BR,BR,1,4,7,4,BR,BR,2,9,1,6,7,6,7,9,BR,BR,5,6,5,9,BR,BR,7,11,2,11,3,14,BR,BR,3,16,7,16,7,18,6,19,5,18,5,16,BR,BR,7,22,5,21,BR,BR,3,21,3,21} -- Help (big H) vector_lib[0xed] = {7,0,5,0,BR,BR,6,0,6,4,BR,BR,7,4,4,4,BR,BR,7,9,7,6,4,6,3,9,BR,BR,5,6,5,9,BR,BR,7,11,3,11,2,14,BR,BR,1,16,7,16,7,19,3,19,3,16,BR,BR,7,22,2,21,BR,BR,0,20,0,21} -- Help (little H) vector_lib[0xfb] = {5,1,6,2,6,5,5,6,4,6,2,3,BR,BR,0,3,0,3} -- question mark vector_lib[0xfd] = {-1,0,7,0} -- vertical line vector_lib[0xfe] = {0,0,7,0,7,7,0,7,0,0} -- cross vector_lib[0xff] = {5,2,7,2,7,4,5,4,5,2,BR,BR,5,3,2,3,0,1,BR,BR,2,3,0,5,BR,BR,4,0,3,1,3,5,4,6} -- jumpman / stick man --- End code --- Some entries in the table are more complex than others e.g. [0x6c] is the bonus box, it is comprised of multiple characters as it is convenient for us to link them together. We can now complete the work on our vector drawing function we fleshed out earlier and visualise the results in MAME. --- Code: ---function draw_vector_characters() -- Output vector characters based on contents of video ram ($7400-77ff) local _addr = 0x7440 for _x=223, 0, -8 do for _y=255, 0, -8 do polyline(vector_lib[mem:read_u8(_addr)], _y - 6, _x - 6) _addr = _addr + 1 end end end --- End code --- Here's what the name registration screen looks like now: and the DK title screen: and here's a gameplay video showing our progress. Note that I've hacked the game for now so that we will only play on the barrel stage. This function gets called at the end of the stage. --- Code: ---local STAGE, LEVEL = 0x6227, 0x6229 function debug_stay_on_girders() mem:write_u8(STAGE, 1); mem:write_u8(LEVEL, mem:read_u8(LEVEL) + 1) end --- End code --- |
| zeorangr:
This is really cool! |
| Gilrock:
Cool work. Not sure I could stare at that "wobble" very long. Maybe tone down how many vectors wobble per frame. |
| Navigation |
| Message Index |
| Next page |
| Previous page |