The 5th Annual Night in the Woods Longest Night Stream - 12/29/2024, 10:35:27 PM
Via MakerTube -- The Industrious Rabbit
A few days late but that's fine. I play through the supplemental content of Night in the Woods.
Here you’ll find regularly updated posts from the various places where The Industrious Rabbit happens – across the Fediverse, here on this blog, and in the various apps that support the project.
A few days late but that's fine. I play through the supplemental content of Night in the Woods.
5th Annual Night in the Woods Longest Night Stream on now! https://makertube.net/w/p9xvVXCKG2Cvokf7boUuaM #nightinthewoods #indiegame #streaming
Ok I think I will do my Night in the Woods stream tomorrow afternoon around 5PM EST on my PeerTube channel. See you then!
Next piece of the Amiga gamedev puzzle for me was figuring out a good way to fade between arbitrary color palettes. While a fade to/from black is pretty straightforward, I will have some effects that will require moving to/from other full palettes. This was calculated within the assembler code and not pre-calculated, it's fully unit tested so it took way less time to ultimately build, and the module's reusable so I can calculate palettes anywhere, including in the C program running this small demo. #amiga #indiegamedev #retrocomputing
I decided to work on the palette manager, and now I can fade between arbitrary palettes of colors:
The fading algorithm is a slightly tweaked implementation of Bresenham’s line algorithm. I know I built paletete fading code back in the AMOS days, very likely using a ratio approach like this:
m% "start color channel value" + "color channel delta" * ("current step" / "step count") %m
The issue is arbitrary multiplications and divisions on the 68000 processor are expensive. Compare the roughly worst-case cycle time cost of MULU
and DIVU
to MOVE
, LSL
, and ADD
:
MULU
: 70 cyclesDIVU
: 140 cyclesMOVE.L
to/from memory: 8 cyclesLSL.L
: 8 cyclesADD.L
: 12 cycles(Values from MC68000 Instructions Timing)
If you’re efficient, you can do a lot of stuff in the time it takes one division operation to take place!
The Bresenham implementation is all fixed point with no multiplications or divisions, and it’s pretty fast. This is also an algorithm I’m sure I’ll come back to a lot in retro development, so I wanted to get good with it:
The unit testing I alluded to in my last post helped out a lot with implementing this. Being able to write code like this to test out the results of the assembler-based algorithm made it way easier to find bugs and discover issues in my algorithm:
void T_buildColorTransition(CuTest *tc) { uint16_t targetMemory[7] = { 0, 0, 0, 0, 0, 0, 0 }; struct ColorTransition ct = { 0x845, 0xAC0, 0, 6 }; int i; buildColorTransition( targetMemory, &ct ); CuAssertIntEquals(tc, 0x845, targetMemory[0]); CuAssertIntEquals(tc, 0x864, targetMemory[1]); CuAssertIntEquals(tc, 0x983, targetMemory[2]); CuAssertIntEquals(tc, 0x992, targetMemory[3]); CuAssertIntEquals(tc, 0xab1, targetMemory[4]); CuAssertIntEquals(tc, 0xac0, targetMemory[5]); CuAssertIntEquals(tc, 0, targetMemory[6]); }
Additionally writing unit tests forced me to build an interface to the palette manager that was reusable. Lots of structures to manage incoming data, and well-defined inputs and outputs means that reusing this code in future programs, like the demo code above, was trivial.
I’ll be getting back to the head collision physics, and probably implementing more unit tests around that, since hand-testing the collision code requires a lot of setup and me jumping really precisely. Tests should speed up that feedback loop a lot.
Yup, no Night in the Woods stream tonight. I'll do one towards the end of the year. Close enough, right?
Things are pretty busy for me at the moment but I'm still gonna try to do my Night in the Woods Longest Night stream tomorrow. If it doesn't happen then, then it may happen closer to the new year. Stay tuned...
I now have a Sun Ultra 5 all fixed up and ready to serve up some Perl and C CGI scripts to my local machines. The future is now.
All three collision types are now working! (well, mostly working):
I need to do something about that last one, when you are going to go over an edge. I may just have to extend the physics engine a bit more to make that look good. Thankfully, I have a new tool in my retro development toolkit to make that a lot easier to implement.
I have unit tests with CuTest working with assembler code, so I can write tests for some of the more complicated data transformations (like collision physics) rather than using slow and error-prone hand testing:
As I describe on my wiki page about the subject, you have to set the stack up to around 30000 bytes on the Amiga for the test to run. You also have to include the math library. Get those in place, and you can easily run tests against any symbols exported from your assembler code.
Next is fixing that head konk collision ground slide, then implementing a palette manager which can set Copperlist palettes as well as perform transitions between two palette sets, to allow for color fades in and out and other effects.
Doing some drawing to make sure my stream setup is good for a future NITW stream.
Art stream is over, here's the art which includes a crab for @mhzmodels as well as an Adina Astra for my upcoming Night in the Woods Longest Night stream on December 21st. #mastoart #rabbit #crab #nightinthewoods
Streaming some art for a bit: https://makertube.net/w/p9xvVXCKG2Cvokf7boUuaM
Gonna try some art streaming tonight to make sure my streaming setup is ready for my yearly Night in the Woods stream. I'll post a link later. If you have something you want me to try and draw (SFW plz), lemme know.
If you told 16 year old me I'd be writing unit tests for Amiga code, I'd respond, "...what the HECK is a unit test?!?" #amiga #retrocomputing #programming
Trip! #amiga #indiegamedev #retrogaming
I have two of the three collision types working! Well at least the basics of them working:
I also got the tiles background working, though for performance reasons I made the backgrounds 512px wide so it’s easier to do bitwise math for calculations.
Doing both of these things required restructuring a TON of code, and included working out good ways to do unit-ish testing in C of the assembler code I’ve been writing. It’s also helped me focus on ensuring dependencies between areas of the game code are as few and deep as possible.
Next is finishing up the final collision type, the rabbit hitting its head. This will involve the physics necessary to get the rabbit to fall correctly and hit the ground. Then I’ll be doing a few additional frames of animation and moving on to other parts of the game.
Almost 6 hours later and I've completely restructured how sprites are loaded, stored, and referenced by other routines in my Amiga game. As annoying as restructuring is to do in assembler, I'm loving it right now. It's the kind of puzzle my brain needs at this moment.
Thwack! #amiga #indiegamedev
I decided to give up on the data recovery. It would have literally taken days to grab some now-swiss cheese files related to a demo reel I made when I was 22, and some other files I likely have other copies of strewn about elsewhere. I'll survive without it all.
Well I didn't expect to have to recover data from two dozen crappy BD-Rs this weekend but here we are.
One of the most enlightening things about working on this Amiga game in assembler is figuring out the best ways for me to structure this code for the best separation of concerns and testability. Getting from the YOLO stage of coding to a well-organized structure is a lot harder in assembler than it is in higher level languages, that's for sure.
This week was about getting a basic level “editor” working, using a combination of a Ruby script with RMagick and an image from LibreSprite:
The level generation works, and I restructured a ton of code to make dynamic level loading work. However, the more complex levels revealed an issue in collision detection that I need to debug.
To make this easier, I’m finally adding some on-screen debugging to the game:
I needed the ability to write text to the info screen anyway. I also need to tweak the copperlist split screen a bit more (that’s the red glitch), but that can come later.
Next will be fixing that collision detection, then reworking the background art to be two 640px images that are tiled rather than one massive 1000px image and fixing the background rendering pipeline.
Implemented Bresenham line drawing in assembler this morning for more assembler, math, and Amiga Intuition practice. #commodore #amiga
There were many more machines and electronics doo-dads there that I didn't get photos of! #retrocomputing #sharp #ti99 #commodore #amiga #vectrex
Hardcore retro gaming. #retrogaming #retrocomputing #ibmpc #atari #pacman #commodore64
Peak computing. #retrocomputing #windows #zork #atari
I went down to a retro computing meetup @bluewizard@mastodon.sdf.org runs on Sunday! I brought my MiSTer and the current build of Bun Runner 2000, which was a big hit. Next few posts will have more pictures from the event. More details at https://www.bluewizard.net/pages/vintagecomputermeetup/.
#retrocomputing #commodore #amiga #acorn
slowaris
Big thanks to @TMBGdotLOVE for the great show this year! #tmbptmbg #tmbg #internetradio
We have a main menu! It’s very simple, but it also forced me to restructure huge chunks of code in order to allow swapping out the menu and the game code.
This included asset loading code, and this restructuring caused me to find a bug that took a few hours to track down. Symptoms:
What it came down to was this line:
; D0 contains the address to the background art ADD.W #GAME_SCREEN_LAST_WORD_POSITION,D0
I was adding a value to an address and scoping to word boundaries, and it kinda worked, as long as I wasn’t wrapping around a 64k boundary when adding that value to the address. Changing how memory was allocated, as sprite memory was allocated before screen memory, would change the start address of screen memory and make this “work”.
But I have a menu now! Oh and some more animation! The rabbit will angle up and down depending on vertical velocity, and the jetpack has animation now, too!
Next will be changing up some game behaviors, and then on to some fun bits of the game.
Another week of slow progress, but this is mainly due to some really heavy refactoring work. I wanted to use ptplayer for music, and that required having my code in a ready-to-link format. If I was going to do this, I was going to do it right, and so I restructured all of the code using all of the techniques I use when working with higher level languages:
My biggest problem holding me back was that MonAm did not like it as all when I gave it linked code:
Along with all the refactoring, I switched to using BDebug in the Barfly assembler package, and I haven’t looked back. Symbols, source code, proper OS 2.0 windows, full mouse support, command line arguments, and lots and lots of great options.
Along with reworking the game code in this way, I restructured my art compression tool to get more practice. I’ve gotten a lot better at restructing assembler code and figuring out the good places to divide up modules. Once I feel really confident that this is the way to go, I’ll write up an article detailing my approach, if you want to try it out yourself.
Oh, and music playback works!
Not as much progress this week, but some good code cleanups and performance enhancements:
Next will be getting the double buffering to happen independently between the front and back planes, which will allow for smooth backgrounds and foregrounds. Then I’ll work on externalizing some more of the game from the code, moving maps to separate files that can be loaded in and adding some other colors to the output.
Lots of progress this week!
I also fixed up some really stupid bugs and got the game working on my MiSTer and A1200:
Additionally, I tightened up the art pipeline so when I’m creating assets, it’s easy to get them into the game. I will need to figure out the best way to automate more of the XPK compression, too.
Next I’ll be getting the rest of the draw operations for the background into the game and spreading the writes to the double buffer over a few frames.
Going to write up a blog post every week with the progress of my finite-at-first runner for the Amiga. My goals:
I have no timeline to get a WIP out for testing because I’ve never worked in Assembler nor this deeply with the Amiga and AmigaOS before!
This week:
I also learned:
It's time...time for a video on the Commodore Amiga Blitter! Topaz walks through the memory copy capabilities of this feature in the context of a small demo written to exercise the blitter, copper, and sprites.
Thanks to Tyrel (@tyrel@mastodon.social), corb0!
References
Code:
Documentation:
Credits
Music:
SFX:
It’s time…time for a video on the Commodore Amiga Blitter! Topaz walks through the memory copy capabilities of this feature in the context of a small demo written to exercise the blitter, copper, and sprites.
Thanks to Tyrel (@tyrel@mastodon.social), corb0!
Here's my Nandland Go Board (https://nandland.com/the-go-board/) running through some of the exercises from the creator's book and website:
I posted the Verilog source code that I reworked for these examples on my Gitea server: https://code.hackerbun.dev/john/go-board-code
The EGA and VGA video standards share some similarities with how the Amiga did graphics, but the similarities end when it comes to the 256 color graphics that defined 90s PC gaming. Topaz walks you through the basics of how those video modes worked, and what made them get so fast over time.
Thanks to Tyrel (@tyrel@mastodon.social)!
References
3d game source code:
Code on Hackerbun:
2d games and the EGA pipeline:
Why are, like, half these examples id Software games?:
Credits
Music:
The EGA and VGA video standards share some similarities with how the Amiga did graphics, but the similarities end when it comes to the 256 color graphics that defined 90s PC gaming. Topaz walks you through the basics of how those video modes worked, and what made them get so fast over time.
Thanks to Tyrel (@tyrel@mastodon.social)!
Version 1.1.4 of the AMOS Pro BSD Socket extension is out, and it’s a big one. Thanks to both an anonymous contributor and some improved M68K assembler debugging techniques, this version has multiple crash bugs fixed, as well as an issue that prevented the extension from working well on non-emulated Amigas. Upgrading is highly recommended!
Grab it from Hackerbun Gitea or Aminet:
(1.1.3 was an internal release and not published to the public)
Lots of great TV-related stuff in the InfoAge Radio Museum. #VCFEast #television #museum
SCIENCE! #VCFEast #TheSimpsons #museum
Lots of other fun stuff!
* A Nabu set up with a run'n'gun'n'fly game
* A Tandy Color Computer running FujiNet and showing Mastodon toots about Sonic the Hedgehog
* A SGI Personal Iris
* @paulrickards@mastodon.social was pen plotting away
#vcfeast #retrocomputing #nabu #fujinet #silicongraphics
I like little computers and I like BeOS (at least the idea of it and those cool yellow toolbars) so I had a good time at the @ActionRetro@bitbang.social table. #VCFEast #BeOS #HaikuOS #retrocomputing
Lots of Macs, including one I drew Topaz on last year as well! #VCFEast #Apple #Macintosh #retrocomputing #rabbit #furryart #mastoart
I made a joystick! It works on the Amiga and it's real weird. Let's try to play some games with it.
Hot on the heels of 1.1.1 comes even better fixes to string handling in the extension. The issue is that, while the strings returned from the functions were immediately usable, they weren’t being added correctly to the string space AMOS maintains, so you couldn’t do things like concatenate them. I documented the proper usage on the wiki. This fixes up all of the string returning functions in the extension, which means that Socket Recv$
should work as expected now.
Grab it from Hackerbun Gitea or Aminet:
I’ve released version 1.1.1 of my BSD Socket extension for AMOS Professional. It fixes two bugs in Socket Inet Ntoa$
, a crash bug and an issue where the null terminator in the original string was being copied into the AMOS string, causing issues. There was also an issue with the build script where the latest version of the library was appearing in the wrong place in the archive.
Grab it from Hackerbun Gitea or Aminet:
I put up the code and binary for a Smash TV/Robotron-like game I built for DOS and PCs with VGA graphics. It works well enough to be playable.
The code is up on Hackerbun Gitea. It has a bunch of code related to working with the PC and VGA card, and it’s the biggest program I’ve written in C so far. It also has unit tests using CuTest, inline assembler, and compiled sprites built using Ruby.
Take it for a spin if you like. Downloadable files are in the project’s Releases. If you have feedback, send it along. I’m not sure when I’ll get back to working on it because I have a video idea I want to do next, but who knows what the future will bring!
I’ve released version 1.1.0 of my BSD Socket extension for AMOS Professional. It fixes a bug in Dns Get Host Address By Name$
where I was incorrectly handling string termination from AMOS strings. It also adds Socket Herrno
to get error code information from the DNS resolver in the network stack.
Thanks to Allanon on Mastodon for finding the issue and testing out the fix!
Grab it from Hackerbun Gitea or Aminet:
Young Topaz has an IFF ILBM image he wants to show his dad, but his dad's on his PC. Learn about what it takes to write a simple IFF ILBM reader for DOS.
References
Source Code:
IFF Files:
PC Development:
Credits
Music:
Sound Effects:
Young Topaz has an IFF ILBM image he wants to show his dad, but his dad’s on his PC. Learn about what it takes to write a simple IFF ILBM reader for DOS.
For the fourth time I play through the Night in the Woods supplemental games, “Longest Night” and “Lost Constellation”, on the 2023 winter solstice.
For the fourth time I play through the Night in the Woods supplemental games, "Longest Night" and "Lost Constellation", on the 2023 winter solstice.
I play through a bunch of Hop to the Top: Bunny's Revenge and bounce between streaming providers while I get Owncast working. Now that my Twitch- and YouTube-free streaming setup is worked out, expect a full live stream of HttT:BR for realsies!
Download the game and see high scores here: https://rabbit.robsmithdev.co.uk/
RobSmithDev released Hop to the Top: Bunny’s Revenge and posted a video about some of the production process. I did some of the graphics for the game, as well as writing the code for the intro. For the graphics, I ended up writing some custom code to automate some of the process, and it was an opportunity to learn about a popular Amiga image format.
My typical process for making art for retro systems is:
In the case of the Amiga, I’ve used ArtPRO on the Amiga in the past to convert PNG images to whatever format I needed. With all the art I was making, and potentially remaking, I needed a faster process. ArtPRO is good, but clicking buttons on retro machine software to convert images was going to be too slow.
I was also running into an issue with GIMP not preserving the index order of the color map I had created for the game. I think I had Remove Unused and Duplicate Colors from Colormap enabled which was messing up the color indexes, so be sure to disable that if you’re using a similar process.
Due to this, the resulting color map on the output images was all over the place, so I needed to fix that issue.
I had two approaches I could take:
I chose the latter since I preferred separate image banks to start, over hard-wiring in sprite sheet locations, during initial development.
I decided to write a tool in Ruby that converts indexed color PNG images directly to IFF Interleaved Bitmap (ILBM) files, enforcing the order of the palette. It uses RMagick to load the image, and then implements IFF ILBM writer code to create the Amiga-ready files. It even supports run length encoding compression.
Here’s the source code. It drew heavily from the IFF ILBM reference found here, as well as from a lot of examining IFF ILBM files in hex editors. It only supports images up to 32 colors, so no Extra Half Brite or HAM images. If you end up using it, let me know!
I draw your requests on a Quantel Paintbox, specifically a Harriet from the early 90s. Due to streaming issues, I wasn't able to broadcast this live, but I did record the whole stream locally. I made it through three pieces: a rat holding a Quantel RAT (a mouse-like input device), a request from @imrustyok@meow.social for a TV show ad card recreation, and a request from @tyrel@social.tyrel.dev to draw his cat. I thought I was drawing his cat Henry, but it was actually Victor. Oops.
Learn more about the Quantel Paintbox:
Stream music by Nihilore: https://nihilore.com
I uploaded the full Quantel Paintbox live stream, edited a bit to trim out some stream issues and to correct some audio issues. This was my first time not only recording a Paintbox, but also recording away from home, so there were plenty of issues to work around!
Below are the three pieces I produced during the stream. They came out as Targa files from the Paintbox that I converted to JPEG.
Thanks again to Adrian Wilson for providing me access to the Paintbox and giving me lots on instruction on how to use it. Hopefully I’ll get a chance to paint on it again!
Stream music by Nihilore.
A cartoon rat holding a Quantel RAT, an input device for the Paintbox.
A parody of a TV ad card for a show called Mission Bunpossible. This was a request by Rusty Ralston.
A drawing of Tyrel's cat Victor. I thought it was Henry. Oops! Sorry, Victor.
Continued stream go here: https://makertube.net/w/7dyJqokqtdXYJFsURs6tgn
I've taken your requests, as well as a few of my own ideas, and will draw them on a Quantel Paintbox, a Harriet model from the early 90s. Watch and see how digital graphics were made on bespoke art computers long before Photoshop took over the digital art world.
The popular shorthand for digital photo editing is based on the name of software developed in the 90s. However, that activity was already being done by users of a bespoke art computer developed by a British company in the early 80s, and the public could see the output of this machine everywhere. So why is digital photo manipulation not called "being Paintboxed"?
Thanks to DextersTechLab for actual Paintbox footage and technical assistance, Adrian Wilson for lots of feedback and resources!
Chapters
00:00 - Introduction
00:36 - Digital Video History
01:23 - The Quantel Paintbox
02:33 - Music Videos
02:57 - Paintbox Machines
03:23 - Why is it not called being Paintboxed?
References
Quantel Paintbox Resources:
Credits
Music:
My 2021 annual playthrough of the Night in the Woods supplemental games, "Longest Night" and "Lost Constellation".
Join me for my yearly play through of the Night in the Woods supplemental games, "Longest Night" and "Lost Constellation". Jump to 08:46 to skip past all my stream setup stuff.
I did it. I finished the animation. Working with this software is more challenging than I expected. It also didn't help that my tablet was having issues with Weylus after a while. I also learn just what Frisket does, and why it's important to Free the Frisket!
Skip to 2:23:54 if you want to see the finished animation playing!
I'll be taking a break from streaming while I focus on the next video, then I'll pick back up with either DeluxePaint V or True Brilliance as my next Amiga art tool to explore.
Stream music by Nihilore (CC-BY 4.0) - https://nihilore.com
Bamboo figures out how to get code he wrote 23 years ago on the Amiga to work for someone today, and it involves a lot of work with libraries.
Thanks to Piotr Kuchno for contacting me and working through debugging the code, and for the videos of the code in use on real Amiga computers! Thanks also to @ijimkoz on Twitter for valuable feedback!
Note: The project name and URL have changed! Go to theindustriousrabbit.com to learn more!
Resources
Intro:
http://aminet.net/package/dev/amos/BSDSocket - The code I wrote 23 years ago
https://en.wikipedia.org/wiki/AMOS_(programming_language) - AMOS BASIC
https://docs.freebsd.org/en/books/developers-handbook/sockets/ - BSD sockets in general
https://www.youtube.com/watch?v=EVr1AHJaGCk - The Copper Demo video, also written in AMOS, that exercises a bunch of Agnus's features
AMOS Extensions:
Amiga libraries:
Why was my server code not working?
Want to try out gaming on the classic Commodore Amiga computer? Topaz walks you through the basics of this retro computer's hardware, and the things you'll need to look for to get your own setup working.
I currently use these emulators:
If you're on Windows, you can run the venerable WinUAE (https://www.winuae.net/).
You can get Kickstart ROMs from Cloanto and their Amiga Forever pack (get at least the Plus Edition for the more modern Kickstarts) and/or from Hyperion if you want AmigaOS 3.2, a modern AmigaOS for applications.
I leave ADF and WHDLoad archive hunting to the viewer!
Thanks to Meredith, Tyrel, Dave!
Read more at https://theindustriousrabbit.com and subscribe to the channel and RSS feed for future updates!
Credits
I take Digital Creations True Brilliance 2.0 for a spin on my emulated Amiga 1200. I've never used this software before, and I discover it's actually not bad for painting, especially when using my Weylus and Galaxy Tab powered input setup.
Stream music by Nihilore (CC-BY 4.0) - https://nihilore.com
Having trouble getting MiSTerFS to work on the AO486 core? Topaz Rabbit walks you through a workaround you can do on the Linux side of the MiSTer, then describes how that workaround works.
Thanks to Tyrel (@tyrel@social.tyrel.dev), Jim (@ijimkoz@mastodon.social)!
References
Credits
Topaz Rabbit walks us through writing a pizza timer app in C on the Commodore Amiga. Follow along and learn about Intuition, GadTools, devices, message ports, IO, and even signals!
Thanks to Tyrel (@tyrel@social.tyrel.dev)!
Chapters
00:15 - Introduction
00:40 - Intuition
01:17 - Opening a Window
01:50 - GadTools
03:31 - setup and teardown
03:53 - Fonts
04:29 - Timer Logic
05:24 - Amiga code documentation
05:53 - Message Ports
06:34 - Intuition Direct Communication Message Port (IDCMP)
09:06 - Time & timer.device
10:01 - Synchronous & Asynchronous IO
11:40 - Alerting the user with DataTypes audio playback
12:43 - Signals
13:27 - Intuition menus
14:19 - The About window
14:45 - App testing with CodeWatcher and avail
15:25 - Conclusion
References
Amiga documentation and tools:
C tutorials:
Source code:
Credits
Music:
Sound Effects: