Thursday, February 07, 2019

#CSpect 2.2.4

In this version of CSpect, the number of Sprites has increased to 128, and we have the new tilemap engine to play with.


CSpect V2.2.4 changes:
  • Minor update for tilemap indexing when tile size is 16bit.

CSpect V2.2.3 changes

  • Added Tilemap screen mode
  • Upped sprites to 128 as per new hardware (yum!)
  • Added X and Y scrolling to tilemaps
  • Added ULA scrolling using LowRes scroll registers. Note: X currently byte scrolling only.
  • Fixed a couple of bugs in the streaming API.
  • Fixed USL rendering order - was just buggered. (Layer2 demo was broken)
  • Added a "vsync" mode when using "-60 -sound"
  • Bit 4 of nextreg $09 now locks next sprite regs, and port regs together
  • Fixed regs $75-$79 sprite auto inc





Wednesday, January 02, 2019

YoYo Games... The good, the bad, the cake.

Now that I've left YoYo Games, and especially after such a long period of time - almost 10 years in fact, I thought I'd take a little trip down memory lane and reminisce a little. I won't be able to talk about everything here, coz that'd be a book....and I'm not ready to write that yet!

Realtime Worlds non-compete waiver
It all began for me in the summer of 2009 while I was at Realtime Worlds, I had been approached for some freelance work by one Sandy Duncan, someone I remembered vaguely from my Visual Science days as running XBox. Strangely enough, I recommended someone else for the gig, but they didn't want to do it, so I started to think about it myself. I happened to be down in London for a family event so arranged to meet with Sandy at his home on the way back to discuss this simple "porting" gig.

Sandy lives in the back end of no where, where post codes and Satnavs don't get along, but I did eventually find my way there, and Sandy and I chatted about things; my experience - and that of Russell Kay who I had persuaded to help me if it came off, and about what the job entailed. YoYo Games had been going for a couple of years at this point and had already acquired Game Maker (note the space in the name!), and he had already gotten it ported to C++, although to be honest, that's being generous. Sandy wanted to get this onto console, more specifically the PlayStation Portable (PSP), so he needed someone to port it from windows to the PSP. Sounds straight forward enough right?

As it turns out, the initial port was very shoddy - probably because it was left to an Intern who simply didn't have the experience to know any better. It was supposed to be the basis of a cross platform port, yet it was based completely around MFC (Microsoft Foundation Class), making it utterly unportable. So we spent several months removing all this and making it actually portable, and using the a PSP homebrew SDK to get something running. In December 2009, we were able to show Skydiver running on a PSP - Sandy was ecstatic.

From here, Sandy decided to open an office up, either in Dundee or Sheffield. If I was interested, then he would open in Dundee, which I was and so he did. He then hired Russell and Myself to work there. Being from Dundee himself, it allowed him to visit relatives while he was here, so it all worked out pretty well. We continued with the PSP version, but then in what become typical Sandy fashion, decided that iOS would be be a nice target. I spent a month or so porting everything over - our work making it all portable paying off here, and we started to look at making Skydiver our first game. This was closely followed by Russell doing an Android port of the Game Maker runner.

As to the PSP port, we did finally get it out, but due to the Sony submission process etc. it took a loooong time, and in the end we only released 2 games there; Karoshi and Green Tech.

The next thing we looked at doing was an update to Game Maker 8.0. Having done (and quite liked) Pascal in the dim and distant past, I took this on while Russell was trying to finish off GM4Mac, a Game Maker 7 port. GM8.1 had the first zooming room editor which I spent quite a bit of time getting fast enough as it was all software rendered, and the first introduction to having "frozen" D3D models, allowing for much faster - and larger, model submission. There really was a massive amount in it, and so it made for a great first dig into Game Maker IDE itself.

After this, we set our sights on HTML5. In 2011 this was a new and emerging technology, and Sandy reckoned we could jump in early and perhaps make a big splash. The biggest issue was that we needed to port whole runner to Javascript, a language neither Russell or I had ever worked in before.
So while Russell started work on the GML to Javascript compiler, I started with a blank sheet or paper and begin a whole new runner. This wasn't nearly as hard as we thought it would be, and did make us think we should have just written the C++ one from scratch, instead of trying to port it. Oh well, never mind... What was pretty amazing, was that in just 2 weeks, we had a couple of games being exported from GM8.1 and running in HTML5. Simple games to be sure - Poker Squares being one of them, and I think Solitaire being the other. We all headed out to Utrecht to meet with Mark Overmars and discuss and plan things, and to get an idea of just how much work this was going to be. We then jumped in with both feet and finished the port, with Chris and I converting a couple of thousand GML functions to Javascript and making Game Maker HTML5. We then headed off to our first conference, GDC Europe, to show it off.

None of us had really been on stands selling stuff like this before, but it's fairly safe to say we loved every minute of it. The big message we got from everyone was; "Yeah, that's really cool... but we really need to be able to export to iOS and Android as well."  Doh! We had this back in the office of course, as this is what we did to make and sell our own games.

So Sandy decided we needed to get all this into an all in one sell-able bundle, and GameMaker: Studio. You'll notice it was at this point, we decided to drop the space from Game Maker. There were a couple of reasons for this, mainly though because we thought "Game Maker" was more a description, while "GameMaker" more of a product name. 

In September, Sandy sent me to Microsoft's BUILD Conference in Anaheim, LA. This was the first time ever that I'd travelled on my own abroad and I was a little nervous to say the least. I managed to upgrade from Economy to Premium Economy on checkin, and Sandy even refunded me that when I got back! I loved this trip, and it's totally set the travel bug alight in me....

To make GameMaker: Studio a reality, took from August to March to get a working version to show off, just in time for GDC 2012 in San Francisco. We had a nice stand right across from Google, so had lots of foot traffic.


This was the first time I'd ever been to San Francisco, not that I'd see very much of it.... Both Russell and I were stuck in Sandy's hotel suite working on the tutorials we were going to be demoing over the next few days. We got a headset and speakers, and we stood there talking through how to make Veg Ninja - a Fruit Ninja clone in just 15 to 20 minutes. All in all, it went quite well I think, and it certainly us on our marketing course for the next few years; get major features ready for shows, then go and sell it to people.

We did go to Develop in Brighton to show things off as well, and attended the Develop Awards for the first time which was fun. Our little stand was right next to a large Unity one, and it was funny seeing all these 2D games people had spent years on. It never took long to convince them that they could have done it all much faster in GMS. It was usually the case they'd been working on it for 6 to 9 months, and thought they'd have another 3 to to go, then 6 for doing a port. In GMS, they could have gotten some of the games down to a few months, with the ports being almost instantaneous.

Develop was also a nice cheap show to attend, as I could flatten my minivan, load it up, and drive down, stopping by Sandy's on the way back to pick up a large filing cabinet. This was a fun trip - even if the drive back was in monsoon conditions!

Shortly after this, we also got an interesting call from Steam, as they were looking for games to put on their new "apps" store (rather than game store). Sandy had previously told them to Sod Off, but that was soon smoothed over, especially when they found out we had the beginnings of a Linux runner than I had been working on in my spare time. They were keep to get both the app store, and more Linux content, and GameMaker seemed like a perfect fit.
I was given the task of integrating things and getting GMS onto Steam - you can read more about it, and 2012 here, it was quite a ride!

We did then of course go back to GDC Europe in 2012 as well, and I gave a talk on HTML5 Dynamic  WebGL rendering, which was fun.

One thing I have loved over the years with YoYo, was being sent out to shows to give talks, or meet up with folk, or to do stands. From hardly travelling, to travelling a lot, I surprised myself by discovering that I loved it! I can't get enough of it in fact, so I usually jumped at the chance to hope around various shows to do talks.

Over the next year we swapped focus from publishing to making GameMaker, as now that people could publish stuff themselves, there seemed less need for us to spend all our time chasing content. We did still make some things, mainly to test the product, something I still believe was vital, and something I'm sad we weren't allowed to continue doing.

Through this time I added shaders, the new primitive building and custom vertex formats, while Russell added YYC - the YoYo Games compiler, making things more secure and faster. At GDC 2013 we demo'd both shaders and the compiler. This was the great thing about doing your own content, we were able to demo things properly. When you release a complex feature like shaders, it takes the community a few years to catch up and make content you want to demo, and for Press stuff you just can't wait that long.

One thing that we didn't like about stands of course, was the standing! It was actually the very first show where Sandy came up with the rule that you weren't allowed to sit down while at the stand - except when doing a demo. This seems a little harsh, but actually it's definitely the right thing to do. The first show we did at GDC Europe, we had a little walk around the stands, and the smaller ones - like ours, usually had one or two people on them, and 9 times out of 10, they were sitting down, face planted in their phones. This is the most unappealing, and unapproachable way to man a stand. Even if you were interested, you just didn't want to approach them, it was so uninviting! But not sitting, this meant you weren't on your phones, and were standing looking out, and it was a far more welcoming stand than many others because of it. When someone came up to the stand, you'd be there, smiling and chatty. Not sitting ignoring them, looking at your phone.
It's certainly hard work - especially on your feet, but it's by far the best way to man a stand. This was especially hard going when later that year, Stuart and I went back to San Francisco to attend Casual Connect, and this one had a 9 or 10 hour day. Normally expos are open from about 10pm to 5pm, so 7 hours, and you'd get a little time for a break at lunch - and there were usually more people on the stand. But here Sandy and Stuart were doing various meetings as well as being on the stand, but for the most part, I was left to man it. This was a looooong day. Stuart and I went for food at night, and we were both falling asleep waiting on it arriving. Hard going.

2013 was also the "year of travel", which you can read more about here, it was mad, and I loved every second!

GDC Europe was our next show, where only 3 of us attending this time, but it was still great fun. This was probably our nicest stand, and lots of other exhibitors came round after to ask where we go it from.

This was also the trip where I was the drunkest I've ever been.... I blame Kristina Rothe (who was at Microsoft at the time), who took us to a GDC party and got me rat-arsed.... was great fun.
(the next day wasn't....)
Over the next year, YoYo FINALLY got into consoles with GameMaker! Sandy finally managed to get deals with both Sony and Microsoft, although the Microsoft announcement got delayed, so the logos were pulled last minute from the stand. But finally showing GameMaker on the PS4 was awesome! We got a stack of games from developers to show off - and to test the new platform. I wrote the initial PS4 port and got a stack of games running on it. GDC 2014 was our biggest stand, and we took a load of staff with us to help man it, and it was great fun again. This was also our last stand.... although we didn't know it yet, the Playtech acquisition was just around the corner....

Developers were ecstatic, they could finally export to console, quickly and easily, and not have to commission full game ports. When you get right down to it, consoles are all about inspiration. Developers WANT to get to console, for many it's been a lifelong desire to get one of their games, onto a console - any console, and now they had a simple route.

Of course, even though the exports were paid for by Sony and Microsoft, they still had to get approval, and sign up to normal console rules. This was sometimes beyond many devs, especially as in the early days you had to be a company, not an individual. This has improved loads over the years, not least because of people like Shahid Ahmad on Sony, and to a lesser extent, Chris Charla on XBox. Shahid, was pushing the new Indie scene like you wouldn't believe, he was also our champion, and the reason GameMaker finally manged to make that leap onto Sony platforms. Indie devs owe a huge amount to Shahid, even when they've never even heard of him.

YoYo was growing a lot at this point, we'd taken on a load more "core tech" people, and with all the other platforms, we were certainly needing the help.

YoYo Games was bought by Playtech in March of 2015, and although the deal had been ongoing for a few months, it was finally signed at the end of March. This meant we couldn't go out to GDC again, so only Stuart, Sandy and Dan - our new Community manager headed out. I really missed not going out that year...

This was also the year we started to focus work on GMS2.0. I was to concentrate on the IDE, while Russell and his team would look after the runner/compiler side, both with 1.x support and any new GMS2 features. In 2014 we'd decided early on that we wanted to host it inside a browser, that way it could be "cloud ready", a big buzz word in 2014, and so that it could run on basically any platform. I spent a few months getting the basic infrastructure up and running, and I had a basic window system running, however... it just wasn't cutting the mustard. We broke the news to Sandy that browsers were just not going to work. We'd used an off the shelve window system, and while nice to look at, just wasn't fast enough. On top of this, the browser was just getting in the way, and even if we moved to WebGL and did everything ourselves, it would stuttering all over the place.

The decision was taken to start again in C#. One of the major goals of GMS2 was to make the IDE as portable as possible, as we really missed not getting GMS onto Mac or Linux, so we didn't want to have the same issues with GM2

We were able to salvage some of the JavaScript work, taking it over to C#, I also got another coder - Claire, to help out which was great. I wrote the whole GMS2 infrastructure, the rendering engine plugin system, message/event system and input manager etc. while Claire ported the Javascript MVC system to C# and then started work on the GUI itself. While I'd done the basic window in window system using a 9 slice rendering system, which I then also then used for buttons, there were a huge number of GUI elements needed, so she started on those. More folk started to come onto the project to help out, Chris helped with the UI and file IO - and eventually took on the OSX version, while Alan started on the code editor and image editor, with Claire moving onto the room editor later. Even more joined as time went on to help fill out the huge number of features GameMaker has.

GMS2 is a massive project, especially when you consider the whole UI rendering layer had to be written first. I'm especially proud of the work the team did on the whole thing. While there are always going to be usability issues, my plan was to get something we liked first, then bounce it off the community and take feedback.

Our first feedback session was in Utrecht some Game Devs, just after we'd been to Develop in Brighton again, hosted by the Dutch Game Garden - who are a great bunch of folk BTW. I'd gathered about 14 developers under NDA to talk through GMS2 with the help of Jan Willem of Vlambeer, to see what they thought. This went pretty well, and devs were especially interested in the new Room editor - which wasn't a surprise really as it was massively improved.

I also took some time in August to go to Utrecht to get Mark Overmars opinion on things, to see what he thought about our changes - and to visit with him, it's always great catching up with Mark, so any excuse really! 

In September 2015, we were summoned to Playtech in Israel to talk over future GMS2 plans. Having never been there, we were excited to go, so we booked our trip and off we went! Playtech were in 2 separate buildings and out unit manager Orel, took us in for a look and nose around, which was cool.
I was shocked at the level of security throughout Tel Aviv, with actual checkpoints dotted around - very odd. It was only for a couple of days, but it was good fun - aside from the utterly splitting headache I got on the last night. Oh well... Lovely place, and lovely folk.


The next one was just a couple of months later at GDC 2016, I had a suite where I met with developers to talk through what we were up to, and how things were going. Feedback from both groups was generally good, although I kept the proviso that as soon as devs got their hands on it, all bets were off.

2016 saw us crack on with things, with an aim to release a beta at the end of the year - although that of course never happened. It was decided that we needed a compatibility plan. We had been saying for years than at some point, we'd just break things so that we could move on, and GMS2 was going to be this break. Our new Playtech managers however thought we should have a much smoother upgrade plan, allowing users half way though projects to upgrade and carry on. This was definitely the right call, and has helped people massively. I think the key to this was not leaving the features in the runner, but emulating them in GML. This meant we could still break most things, but fix them up in GML code if users use that feature or function. This let users upgrade game code at their own pace, and that's pretty cool.

It was about May 2016, that I also started my "game in a day" tests. Although I couldn't say at the time, these were to test out GMS2, and make sure things were actually usable. I cranked out several retro style games in 10 hours or less! Breakout - which became a demo for GMS2, Pole Position, Pac-Man, TLL, Chimera, Gauntlet and Uridium, all done (mostly) in a few hours. TLL to be fair took a little longer, as I got carried away in the new room editor doing the full TLL map - it was great fun, and the new room editor was a pleasure to use.
I still count all this as a missed PR opportunity that I wasn't able to show me doing these games so quickly, but there was a total blackout on GMS2 work. First, because as a public company, we couldn't just leak new products, and second showing how far along GMS2 was, would kill GMS1.x

2016 also saw us finally getting a new Managing Director in the shape of James Cox. This meant James taking all the Playtech meetings, and letting us get on with things. Playtech like any large organisation has it's bureaucracy, and James was left to navigate that on behalf of us all - something we were all very grateful for!

All these changes added a lot of time, pushing release out a few months, so at GDC2017, I again got a room with a sitting area so I could hold some developer meetings, and show not only what the final one was going to be like, but also that we had a Mac version up and running.

My GDC schedule was again totally jam packed, so I saw very little of San Francisco and the show, although I did reserve a couple of hours for running around the expo...

2017 was a big year for YoYo, the launch of GMS2 for Windows and Mac marked a whole new era for us, we even won an award in 2017! But this is also where things started to change for me. I was gradually being pushed into the background, I was no longer asked to do talks, or give interviews. James had a very different way of doing things, and I started to lose the interaction with developers that I loved about the job.

I carried on at home doing cool little GameMaker projects in my spare time to test the engine out, from making a MOD player completely in GML, to doing more "games in a day" - this time I was allowed to stream them, although still under some restrictions. Manic Miner, StarQuake, JetPac, Boulder Dash, Blood Money, even Lemmings, all remade in 10 hours or less.

I even did some more tech blogs, trying to revive them as they'd kind of died off in the previous couple of years....

But around August/September time people were being transferred onto another internal project, and I was starting to get frustrated with the lack of progress on GMS2. James was demanding more and more new features to help sell it, but not giving me the time, or man power to fix things. This meant over the next 9 or 10 months, GMS2 would get a load of new features, but become increasingly buggy.

This in turn started to make me lose interest at home - for the first time in 8 years, I started doing something else in my spare time. It was about here that the ZX Spectrum Next really got a lot of my attention. At the start of 2018, I even started to do some retro shows and talks with the rest of the Next guys - which I love doing.

In March 2018 we headed off to what was my final YoYo Games GDC, this time in a proper meeting room. I was again stuck in this room for the week as the other headed out for biz dev and press meetings - again, I was removed from all press interaction.

At the start of 2018 things had again changed, and people we starting to get transferred back onto GMS2, so we started to try and finish off some of the outstanding features and move into a stabilisation period. This was mainly bug fixing, although these took months and months to appear, the product was finally getting the stability work I was longing for. We spent a lot of time bringing HTML5 up to spec, again something that's annoyed me - it's been the forgotten child for a long time, but finally we were starting to put some real effort into it. We cleared off hundreds of HTML5 bugs, and ran loads of games through it to make them work and make it even more compatible. 

James left YoYo at the end of September, and I hoped things might improve for me at this point, but alas no... if anything, the plans he clearly set in motion carried on and I was sidelined even more.

A few devs left around this time as well,  and I felt a lot of the fun had gone for me. It was a hard choice, but the time had come to move on. It was great fun, and I've probably done more at YoYo the ANY previous job I've had, it was amazing how much stuff we got through. So... here's a little more reminiscing...

Some of the notable things I did, or was part of, while at YoYo

PSP Runner port
Texture page packer
Batching and Hardware T&L
iOS Runner port
Simply Solitaire
Initial Ad implementation for Simply Solitaire
Game Maker 8.1 update
Static 3D Models
New GUI Layer
HTML5 runner port
DX9 Upgrade
GameMaker: Studio
Linux runner port
GameMaker: Studio on Steam
GameMaker Player on Steam
HTML5 WebGL upgrade
Added GMS Networking API
Added GMS Shader support
Added GMS Primitive builder and custom vertex formats
Added GMS Debugger
Updating the GMS draw events
Application Surface
PS4 Runner Port
GameMaker Studio 2 IDE
A stack of Techblogs, including

  • 2D Shadow tutorial
  • Dynamic Rendering Masks
  • Depth based Mouse Collision
  • Creating a C64 emulator series
  • Writing a ZX Spectrum Emulator
  • Manic Miner Binary files series
  • Shader introduction series
  • Networking introduction
  • Introduction to Binary
  • The Hazards Of Precise Collision Detection
  • Seamless Tile Scaling In GameMaker
  • Fast Platform Collisions
A stack of tech demos and Marketplace assets.
  • Isometric demo
  • Platformer demo
  • 3D Cube test
  • Network platformer demo
  • Your World - GTA 1 Engine
  • C64 emulator
  • ZX Spectrum emulator
  • 3 Raspberry pi games
  • ZX Spectrum Colour Clash demo
  • GML MOD Player
  • Ball Breaker Demo (Arkanoid)
  • GMS2 Dungeon Demo
  • Voxel Landscape
  • Bit Streaming library
  • Ball Blaster game demo (Ballistx)
  • Muncher demo (Pac Man)
  • Full Boost demo (Thrust)
  • TLL Shadow demo
  • Alien Attack (Defender)
  • A load of unreleased things... (shader tilemaps, a load of Raspberry Pi stuff, Lighting engine, loads of "games in a day" source etc)
I'm really was only person in the office who did all these little tests/demos/blogs with GameMaker. This isn't to say no one else uses it, loads of them do, but no one really churns things out, or pushes the edges and tries as many different things as I did. I hope one of them starts doing this kind of thing, because I think it really does help push the product on.

Some things I've regretted....

Not getting a Raspberry Pi version out in some shape or form. I tried for about 5 years, almost manged twice. Just never happened, which is a real shame.

The HTML5 version needed more love, but I was never given the time to give it the attention it deserved until much later. Only doing bits at home was I able to try and bring it up to scratch. I'm pleased that in my final few months, I was able to spend time on it, and make it a lot more robust and usable. It's just a shame it took so long.

I'd have loved to get GameMaker more widely used more internally in Playtech.

Not being able to do more games. It was great doing games, not just because we love doing games, but to test the engine with, and I think we lost a lot by not doing this....

All good things...

I've loved my time at YoYo Games, the people I've worked with have been brilliant, funny and made the time go that much faster. I've also done a massive amount of stuff while there, and I'm particularly proud of bringing such a wonderful education tool into mainstream development, and helping many developers make their dreams come true....

okay.... the cake was a lie.

Monday, December 24, 2018

#CSpect 2.1.4

In this version of CSpect, I have the new sprite engine implemented. You can now have all 64 sprites in a line, except when expanded - which they can not be by 32,64 and 128 pixel sizes. You can also now have 16 colour shapes, allowing double the number of images a sprite can have.

On top of this, is the new L2 pixel priority engine and lighten/darken L2+ULA modes which you can get by setting the SLU order to %110 and %111 respectively.


CSpect V2.1.4 changes

  • Added logging debug command (see readme)
  • Added Layer 2 pixel priority mode - top bit of second colour palette byte (the single bit of blue) specifies over the top of everything.
  • Added Next OS streaming API ( see readme )
  • Added DMA reverse mode (R0 BASE, bit 2)
  • Added BSLA DE,B (ED 28) shift DE left by B places - uses bits 4..0 of B only
  • Added BSRA DE,B (ED 28) arithmetic shift right DE by B places - uses bits 4..0 of B only - bit 15 is replicated to keep sign
  • Added BSRL DE,B (ED 2A) logical shift right DE by B places - uses bits 4..0 of B only
  • Added BSRF DE,B (ED 2B) shift right DE by B places, filling from left with 1s - uses bits 4..0 of B only
  • Added BRLC DE,B (ED 2C) rotate DE left by B places - uses bits 3..0 of B only (to rotate right, use B=16-places)
  • Added JP (C) (ED 98) JP ( IN(C)*64 + PC&$c000 )
  • Added new sprite control byte
  • Added sprite expand on X (16,32,64 or 128)
  • Added sprite expand on Y (16,32,64 or 128)
  • Added 16 colour shape mode
  • Removed 12 sprite limit, limitations still apply when expanding on X (100 16x16s per line ma
  • Sprite pixel wrapping on X and Y (out one side, back in the other)
  • Added "lighten" mode. L2+ULA colours clamped. (selected using SLU layer order of 110)
  • Added "darken" mode. L2+ULA-555 colours clamped. (selected using SLU layer order of 111)

CSpect V2.2.0 updates
  • Fixed reg 0x43 bit 7- disable palette auto increment.
  • Fixed NextReg access for sprites. Was using the wrong index.


SNasm V2.0.15 changes
  • Removed MIRROR DE instruction
  • Added “JP(C)” instruction
  • Added “BSLA DE, B” instruction
  • Added “BSRA DE, B” instruction
  • Added “BSRL DE, B” instruction
  • Added “BSRF DE, B” instruction
  • Added “BRLC DE, B” instruction
  • Fixed error reporting on command like "and a" when a user gives "and a,7" etc.





Saturday, November 10, 2018

#CSpect 2.1.0

In this release I add back in Mouse and Gamepads. I've tested both on Windows, but not on OSX and Linux, so if someone can give that a go and let me know, I'd be grateful.

I've also fixed the bug when esxDOS is trying to save that was crashing things.
EDIT: Also fixed a bug in sprite palettes that was causing a crash

I'll leave the install and running in this post, but it'll vanish next post.


Installing
----------
Windows - You will need the latest .NET, and openAL ( https://www.openal.org/downloads/ )
Linux - You will need the full MONO (on ubuntu do "apt-get install mono-devel" )
OSX - You will need the latest mono from https://www.mono-project.com/


Running
-------
Windows - CSpect.exe [options] game.sna/game.nex
Linux - mono ./CSpect.exe [options] game.sna/game.nex
OSX - mono ./CSpect.exe [options] game.sna/game.nex

There are a few things not yet in/finished for this version.

  • Some esxDOS functions (F_FSTAT, F_STAT, M_GETDATE)
  • 128K SNA files are not currently loading
  • File dialog (F2) will not work on OSX due to windows Forms not working in x64 mode in mono.
  • Due to the way openAL appears to work, things aren't as smooth as i'd like. Disabling audio (using -sound) will smooth out movement for now...



Friday, November 02, 2018

#CSpect 2.0!!

So I'm very pleased to announce the release of #CSpect! A port of CSpect to C#!

This version runs under .NET and so is fully cross platform running under Windows, OSX and Linux using the Mono runtime. So finally Mac and Linux users can have access CSpect for developing ZX Spectrum Next games.

Installing
----------
Windows - You will need the latest .NET, and openAL ( https://www.openal.org/downloads/ )
Linux - You will need the full MONO (on ubuntu do "apt-get install mono-devel" )
OSX - You will need the latest mono from https://www.mono-project.com/


Running
-------
Windows - CSpect.exe [options] game.sna/game.nex
Linux - mono ./CSpect.exe [options] game.sna/game.nex
OSX - mono ./CSpect.exe [options] game.sna/game.nex

There are a few things not yet in/finished for this version.

  • Gamepads
  • Some esxDOS functions (F_FSTAT, F_STAT, M_GETDATE)
  • 128K SNA files are not currently loading
  • File dialog (F2) will not work on OSX due to windows Forms not working in x64 mode in mono.
  • Mouse is not currently implemented.
  • Due to the way openAL appears to work, things aren't as smooth as i'd like. Disabling audio (using -sound) will smooth out movement for now...
  • Probably a few more things....




Tuesday, October 02, 2018

Advanced programming of the ZX Spectrum Next

So while porting Super Crate Box to the NEXT I decided to break with the norm, and use the hardware more fully. While doing so... I realised I'm probably the first to do so - although we all knew about this when the hardware features were being designed, I think I'm the first to take advantage of it. That being so.... I thought I'd write it up so others could also take advantage.

One of the (many) things I loved about the C64, was the 64k of RAM and address space you had, you could fill that machine with your game, banking out ROMs, VIC, Character sets and IO ports etc and use every part of it! This was awesome. I use this when writing Blood Money on the C64, and it was very liberating. :P

When putting the Next together, the team extended the new 8K memory mapping to allow for the same thing - you can now have a full 64k of program space. This means you can now bank RAM into the lower 16k, and even move the screen location. This is incredible, and really helps you make full use of the machine.

So... how did I do it? Actually... it's fairly simple, but it's nice to see it all laid out. Using the new .NEX format file, I simply had to move code around a bit, and have a small "boot" loader somewhere. Here's the memory map I was aiming for...

$0000-$7FFF - Game Code
$8000-$BFFF - Game Data
$C000-$DFFF - Graphics
$E000-$FFFF - ULA/Timex screen

I will use $C000-$FFFF for other things on demand (like Hardware sprite graphics etc), but this is the main layout. As you can see, it's a much better layout, meaning you can have so much more code, and not fill the middle of memory with 16K of screens. The 8K banks also allows the paging of graphics AND the ULA/Timex screen.

Using the Timex screen means I can double buffer the ULA screen without using the ZX128 shadow screen, and it's much easier to control. it's also important to realise that the NEXT will ALWAYS use bank 5 (banks 10 and 11) for the ULA and Timex screen, even if it's not banked in. This is very cool.

Using SNASM and the new segments I can lay this out easily, but I'll be more generic so you can use another assembler if you want.

First, you need to ORG at $8000 so we can write out BOOT loader. This is incredibly simple

  di
  NextReg $50,Code_Bank  ; $0000-$1FFF
  NextReg $51,Code_Bank+1  ; $2000-$3FFF
  NextReg $52,Code_Bank+2  ; $4000-$5FFF
  NextReg $53,Code_Bank+3  ; $6000-$7FFF
  rst $00

StackEnd:       ds      127
StackStart:     db      0

Technically, I only need to bank in the first bank, and then I could do the rest in the main code block, but for me this is fine. I've set code to use banks 12,13,14 and 15 - which maps to the ZX Spectrum 128 banks 6 and 7. Bank 2 (4,5) is my data, and bank 5(10,11) is the ULA/Timex screen.

I've yet to use Bank 0 (0,1)...so it's free to something else - perhaps tables I need to bank in on demand. I can decide that later

So next I need to set bank 6 (8K bank 12) to assemble to (however your assembler does this), then set the target "ASSEMBLE TO" address to $0000. In SNASM you would do this....

                SEG  CODE_SEG,12:0,$0000    ; create segment (bank 12,offset 0. Assemble to location $0000)
                SEG  CODE_SEG               ; set segment


BootUp          di                          ; RST $00 jumps here....
                jp      StartCode
                nop
                nop
                nop
                nop

                ; RST $08
                ret
                nop
                nop
                nop
                nop
                nop
                nop
                nop

                ; RST $10
                ret
                nop
                nop
                nop
                nop
                nop
                nop
                nop

                ; RST $18
                ret
                nop
                nop
                nop
                nop
                nop
                nop
                nop

                ; RST $20
                ret
                nop
                nop
                nop
                nop
                nop
                nop
                nop

                ; RST $28
                ret
                nop
                nop
                nop
                nop
                nop
                nop
                nop

                ; RST $30
                ret
                nop
                nop
                nop
                nop
                nop
                nop
                nop

                ; RST $38
IRQ             ei
                reti
                nop
                nop
                nop
                nop
                nop
                nop

StartCode:
                ; Main game start up....

One interesting side effect of this, is that you no longer have to use IM 2 for interrupts. You have access to the hardware vector, which is handy.
Now when I (say) clear the screen, no matter which it is - Timex or ULA, I just bank in the correct bank (10 or 11) to $E000, and then clear - like this.

; ************************************************************************
; Clear the ULA Screen using DMA
; ************************************************************************
ClearULAScreen:
  ld a,(ULABank)
  NextReg $57,a   ; bank screen into $E000
  
                ld      hl,$e000  ; Get the current buffer we're drawing to
                ld de,$e001
                ld      (hl),0
                ld      bc,6143   ; fill the screen
                jp DMACopy


You'll notice I use DMA instead of LDIR, as it's much faster - but that's just an aside. As you can see, I bank in the current buffer, then always target $E000, it's as simple as that.

The only real gotcha is that using the new opcode pixelad returns an address based on $4000, so we need to OR in $A0 to get the proper address. Fortunately, pixeldn works with any base address - which is cool.

Lastly...the main loop and double buffering is pretty simple, and looks like this...

; *****************************************************************************************************************************
; Flip Buffers
; *****************************************************************************************************************************
FlipBuffers:
                ; Flip ULA/Timex screen (double buffer ULA screen)
                ld      a,(ULABank)             ; Get screen to display this frame
                cp      10
                jr      z,@DisplayTimex

                ld      b,10                    ; set target screen to ULA
                ld      a,1                     ; set CURRENT screen to TIMEX
                jp      @DisplayULA

@DisplayTimex:  ld      b,11                    ; set target screen to TIMEX
                xor     a                       ; set CURRENT screen to ULA
                
@DisplayULA:    out     ($ff),a                 ; Select Timex/ULA screen
                ld      a,b                     ; get bank to render to next frame
                ld      (ULABank),a             ; store...

                jp      ClearULAScreen          ; wipe ULA/Timex screen 


A little aside.... using RST $?? as common functions is very handy, especially as they are smaller than normal calls, and if it's a tiny function, it's also faster than a call by 7 T-States. If Interrupts are disabled, you can also use RST $38 for a larger call, giving you much quicker CALLs to a common function.

So that's the basics. As you can see, it's not that complicated, but the new memory layout is awesome. lots of code without having to bank in overlays, and being able to move the ULA screen AND have it double buffered is just brilliant.



Tuesday, September 25, 2018

Making NEXT Lemmings: Part 5

So between families holidays and work, it was a couple months before I got time to get back to doing anything on Next related, but it was for a good reason - the Next motherboard had finally arrived!


I was hyped, really...REALLY hyped!! I had the extra RAM for it already, and after doing an initial power on I installed it and booted it up.


I spent the evening playing around, trying demos and the like, and much fun was had by all - well, me.
A couple of weeks later, I figured it was time to try and get Lemmings running on it. Needless to say, it didn't just "run". I poked around for a bit, but in the end I had to cut out everything and get some very basic code to run. I then slowly started adding code back in.

If you don't know, this is by far the best debugging method on a system where you've no debugger. Comment stuff out, and if you can, draw to the visible screen or change the border/screen colour as you go, so that when it crashes, you can see how far it got and that'll give you a clue as to where it crashed. Then repeat, moving the colour changes into the new area where it crashed. This is obviously a painful process, but it's utterly reliable, and you will make (very slow) progress.


This image above is actually major progress. I had managed to go from a black screen, to the game loop actually running.  I'd skipped all loading/processing code, and all I was doing was copying the level bitmap to the screen, and copying and panel - or rather where the panel lives in memory.


Next was to get something loading. The panel was the simplest thing as it was just pure data/graphics content, so once that was loading I knew the loading code was good, and could start looking at other things. Next thing I wanted to do, was get interrupts working again, and this is where I hit the issue. Just enabling it didn't work, so I started by creating a very simple handler that just changed the colour, which worked fine. This was odd, as it meant setting up and running the IRQ was totally fine. So I spent a while trying to figure this out then I twigged.... The new NEXTREG instruction wasn't working. So the replacement for this took several instructions to set a value, and the IRQ could happening in the middle of it, and then my IRQ code was then changing it.
So...I had to now remember the current Next Register, and restore it later. Once I'd added this, my IRQs worked fine, and the main code carried on properly, and then I was able to slowly re-enable the rest of the code.


All this took 2 or 3 days to get working, but now it was going, I starting to think that now's the time to start actually doing proper Lemming processing.
I'd been putting this off for a bit because it's....well, boring to code. But a lot of game code is boring, especially when you've done it several times before. Still it had to be done, so I started building a simple state machine for the Lemmings, where it would start out as a Floater, then when it hits the ground either splats, or turns into a walker.


In order to get to this point, I had to define a basic lemming structure like this

;
; lemmings structure
;
                    rsreset
LemType             rb 1
LemX                rw 1
LemY                rb 1
LemDir              rb 1  ; left or right facing
LemFrameBase        rw 1  ; keep base,count and offset together
LemFrameCount       rb 1  ; so "SetAnim" function is quicker
LemFrameOffX        rb 1
LemFrameOffY        rb 1
LemFrame            rb 1
LemSkillMask        rb 1  ; skill mask
LemBombCounter      rb 1
LemBombCounter_Frac rb 1
LemSkillTemp        rb 9
LemStructSize       rb 0
LemDataSize         equ LemStructSize*MAX_LEM

Structure definition like this is a feature of my assembler SNasm, and means I can load the base of the lemming into IX, then offset using the value above like this LD A,(IX+LEMY). Using IX is pretty slow, but in these cases, there's really no alternative. I'd have loved to find a faster way of doing it, but oh well. once I had this defined, I loaded the base address into IX, and looped around 100 Lemmings - that still being my goal. I then set a basic counter and dropped a lemming out somewhere on screen in "Faller" mode, then hoped.

This is where it started to get complicated. I'd originally planned to to store a bitfield collision mask of the whole level - a bitfield mask being 1 bit per pixel, so packing the whole mask down to around 40K, so that moving up/down was very fast. However, this would mean that not only would I need to remove data from the Level Bitmap, but I'd also need an old school sprite masking routine so that I could add/remove pixels from the bitmask screen as well. I toyed with several ideas about how to lay this out in memory, and what would be fastest/simplest, but in the end I decided to do what the Amiga did, and just use the background screen.

This actually works fairly well, although it does still have the bank swapping issue that the rendering has. But aside from that, it's pretty good.

This has the added benefit that I just have to add or remove things from the level bitmap - which you have to do, and then your Lemmings will just automatically walk over it. This keeps things very simple, and stops anything getting out of sync.

Once I had this working, I was able to churn out the 100 Lemmings and see how fast things were going....


This all worked pretty well, and while a little sluggish, I figured I'd get a lot back once I was able to use the copper to display the panel, and didn't have to copy the whole thing each frame. During this time however, the Next team managed to get the speed back up to 14Mhz again (mostly), so this was a great free boost and the above video shows this 100 Lemmings running at 14Mhz.

The next biggest CPU hog - and the next coolest thing to do, would be to explode a Lemming. This introduces several important functions; panel selection, selecting a Lemming, removing the background, the explosion particle system.

First the panel selection was reasonably straight forward, especially as I opted to use a sprite for the selection box which simplified things a lot. While doing the basic clicking on the panel, I also decided to implement the release rate properly. I had up until now just had a simple frame counter, but actually Lemmings doesn't do it this way. In fact, Lemmings release rate is very odd, a fudge that just gives you a nice curve. Basically, it takes the 0-99 number, inverts it (so its a 99-0 delay), divides by 2 - just because 0 to 99 was nicer than 0 to 49. Then comes the "magic". it negates this value,adds 53, negates again and adds 57. Yeah... i don't know why either. This has however stuck in my mind for years, as it's basically sums up game coding in a nutshell; fudge it till it works. No matter what the code looks like or does, as long as it works the way you want, then go with it. You can see this function in my github repository in level.asm/ConvertToDelay.

Next, I had to be able to pick a Lemming. I started out by doing this simply, that being, just looping over all the Lemmings and finding the first one under the cursor. This however doesn't work very well, you end up picking a Lemming who is mostly out from under the cursor, when in fact you really want the one that's mostly central to it. This means I needed to measure the distance to the middle of the cursor and pick the Lemming closest to that. This take a bit more oomph, but works much better, and feels much more natural.


The next step was a big one, removing background pixels. This is one of the key elements of lemmings, so would be good to get this into place. This is basically an inverse sprite routine, removing pixels instead of drawing. Because this goes into the level bitmap (the 2048x160 bitmap) and not the screen (256x160 screen), I copied the bob draw code from the level creation code, and then whenever I was about to draw a pixel, I'd store a 0 (black) instead.


I then defined an egg shaped blob and attached it to the mouse, and hey-presto! We go this. The code was simpler as you only need to clip top and bottom, as the level has lots of space left/right, which is nice.You'll also notice that the Lemmings are walking through the areas I've cut out due to the fact I use the level bitmap to collide with.

Interestingly, we changed this method in Lemmings 2 so we could have pretty backgrounds that you wouldn't walk over or dig away, as simple Black backgrounds are pretty dull really....

In the next post, I'll go through the explosion code and the nuke function...




Sunday, September 16, 2018

CSpect 1.18

Changes to the debugger. This allows you set breakpoints using the physical address, allowing you to set breakpoints in code not yet paged in. This allows for simpler debugging of proper overlay code.
Also, if your using another assembler, you can use the new -16bit command line to use logical addresses only.

CSpect changes
  • added -16bit to use only the logical address of the MAP file
  • Execution Breakpoints are now set in physical address space. A HEX number or SHIFT+F9 will set a logical address breakpoint. This means you can now set breakpoints on code that is not banked in yet.
  • Next mode enabled when loading a .NEX file



Monday, September 10, 2018

CSpect 1.17.1

Minor update to SNasm. 48K SNAs weren't saving out correctly, and labels under $8000 were whacky. This is now fixed.

SNasm changes
  • Fixed labels
  • Fixed SNA saving



Sunday, September 09, 2018

CSpect V1.17

New version  of CSpect and SNasm with some big changes for those using it to dev. You can now specify segments and save out NEX format packages, allowing you to build "large" packages all from within SNasm.
CSpect will now load the new symbol format and correctly display the proper symbol when that bank is paged in, allowing overlays to work more seamlessly.

CSpect changes
  • ULA colours updated to match new core colours. Bright Magenta no longer transparent by default. Now matches with $E7 (not $E3)
  • Fixed debugger bug where "0" is just left blank
  • New MAP format allowing overlays mapped in. Labels in the debugger are now based on physical addresses depending on the MMU
  • You can now specify a bank+offset in the debuggers memory view (M $00:$0000) to display physical addresses. 
  • Numeric Keypad added for debugger use.
  • EQUates are no longer displayed in the debugger, only addresses. This makes the view much cleaner

SNasm changes
  • SEG command added for Segment control on ZX Spectrum Next machines. Banks are 8K in size.
                                    SEG  NAME,BANK:OFFSET,TARGET_PC ; to create

                                    SEG  NAME              ;to use
  • SAVENEX "name",StartPC,[StackSP] added.
  • New MAP format exported for CSpect