|
|
|
|
| Welcome, Guest | Home | Search | Login | Register | |
| Author | Mac port of "Attack of the PETSCII Robots"... (Read 39549 times) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
lauland
512 MB ![]() ![]() ![]() ![]() ![]() Posts: 674 Symtes 7 Mewconer! |
Reply #15 on: May 10, 2024, 17:08
Don't be too intimidated by C++...it has become quite a large language, with countless features that are, IMHO, a bit overdesigned and rarely used when the rubber hits the road. ---- That brings up a good point about Object Orientation...and a lot of C++ coders use the language, more than anything, as just an improved C... PETSCII is NOT very object oriented at all! In fact, the only part that really is, is abstracting the platform specifics. You could've expected to see a class for bitmaps, for sounds, a class for tiles on the screen, maybe a font class, a Window/Display class, a player class, an enemy class, etc etc ---- One thing I could've done was to make a PlatformMac that was a superclass of PlatformSDL...it'd inherit everything and only override the parts needed for mac specifics. I didn't do this because it wasn't needed and I wanted to keep things as simple with as few changes as necessary. It also would've been difficult as he doesn't have a class for bitmaps...so I'd have ended up writing a LOT of code that was mostly just "objects for object sake" to get around the fact that I needed to replace the SDL Surfaces with Mac GWorlds. And in the end, it would be slower due to the language overhead...ie instead of just calling SDL Blit on SDL Surfaces and CopyBits for GWorlds, you'd have a bitmap class with a draw method, etc etc. ---- You can argue both ways about this, and which is the "right" way to code in C++ (or any object oriented language), and people do endlessly. But, in the end, implementation, ESPECIALLY for games, doesn't matter in the end...beyond how easy it makes it for the coder to understand (and expand) their own code. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #16 on: May 11, 2024, 08:24
|
Completely agreed on all points, @lauland. I also notice the tendency towards a language getting bloated over the years, and believe it simplifies design and allows better focus when we limit ourselves to use only the relevant subset of all the features of a language. Or SDK. Or anything. Overengineering is also another plague (or, as people love calling it, "anti-pattern") that I see getting worse everywhere. As I like to say it, "less is more". In the case of C#, I made it a point in the company I'm employed by so we limit ourselves to C#7.3 (latest version is C#12 or beyond, I forget, it started getting incremented each year, unlike before), for various reasons, and the more experienced the developers in the company, the more they agree on the reasoning. We can actually enforce this in the IDE/compilers with the following XML in a project file: <langVersion>7.3</langVersion>. This is a very "real world" problem, with "real world" massive benefits when not underestimated. This concept also applies to other "bloated", "misguided" or "misdirected" aspects of the whole of the .NET platform (a platform which I should professionally get away from, since it increasingly clashes more and more with my personal life principles-- oldschool C/C++ FTW!). So back to PETSCII, while object orientation might make it easier to conceptualize in the head of the reader or project newcomer, you have very good and valid reasons for leaving it "the way it was". This is right in my view, especially because part of the scope is to run it on VERY old Macs! And this scope will also be there for my own "Seiken-like" project. I believe I can poke at PETSCII a bit more today (Saturday). I hope I can achieve something here. Let's see. (I will also tend a bit to my other, REALbasicDR1r33 Mini-vMac-related project here and there.) Question: Can we use MPW compilers (MrC/MrCpp and its SCpp counterpart) with CodeWarrior? Out of curiosity.
|
lauland
|
512 MB ![]() ![]() ![]() ![]() ![]() Posts: 674 Symtes 7 Mewconer!
Reply #17 on: May 11, 2024, 22:02
|
During the workday I'm in a different world than yours, but face the same issues...we're a java backend, js frontend all-in-the-cloud shop...but, of course, the exact same problems easily creep up with bloat and using the latest hot features and/or libraries/frameworks. Luckily we're small enough the developers don't have enough time to over-indulge themselves too much! Very glad to hear you've got the experienced people on your side, and can actually enforce the language level! ---- If you do get time to hack around on PETSCII, please do NOT let yourself get stuck on the keyboard to the point where your forehead meets the wall...let me know if you get there! The reason is I don't know personally why the keypresses aren't working...and'd hate to have you get frustrated chasing something bizarre...which is why I suggested hacking on SDLFill(), etc first, since the solution is really simple...and thus easily attained progress and satisfaction...which reinforces more hacking! ---- So, yeah what remains to be finished falls into several categories...from the very clear to the I-have-no-idea... Sound could be tricky...I didn't even touch it, and aren't sure the best approach...luckily the MOD player is all there and should "just work" once we give it somewhere to output. Happily sound effects are already raw, so we don't need to include a .wav reader, etc. But having things play "in the background" may be a challenge. Fixing the colors and/or converting to black and white would be pretty clear. The only changes would be where the art is read in...but if we want to run on a System 6 Mac Plus (because...of course we do!) we'll need to switch away from GWorlds to just raw BitMaps. Depending on how much time you have, we might split it into two versions...one that plays on pretty much whatever the display is currently set to, requiring color quickdraw at minimum (ie what we have now), and another "B+W" version...that was what I did for Arashi. Like Arashi, there'd still be a single code base, with #ifdef's. ---- As far as I know you can't use the MPW compilers (or any others) in the CodeWarrior IDE...but you can the opposite (there are MPW tool versions of the CW compilers). If you're thinking you want to use really old compilers in order to enforce squeezing on ancient hardware, I'd suggest Think/Symantec any day before MPW... I did an earlier abortive attempt at PETSCII with Think/Symantec and ran into goofy C++ language feature issues...none horrible, but the point of using PETSCII was to teach programming to people interested in learning, using a game...not teaching about scary cranky compilers! So, unless there's a compelling reason, I'd say stick with CodeWarrior...at least as far as PETSCII goes... (MPW is on my personal learning TODO list...but there's never been a compelling reason to jump into it...it is VERY alien to pretty much everything else out there...with a very strange take on a "command line" and "makefiles"...not a friendly experience compared to any other IDE...if you can call it an IDE?)
Last Edit: May 11, 2024, 23:16 by lauland
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #18 on: June 13, 2024, 19:22
|
OK, so, little update: I have read up again and again on the ANSI C89 / ISO C90 spec, and got myself familiarized with the C89 world as much as I could in two weeks between short breaks. I built up enough confidence and determination that I started working on my personal project 100% from scratch. (I also tried to be as strictly-compliant to pure ANSI C89 as possible. Because I guess I just like trying to make things "universally portable".) Well, along the way, it turned out I was using a lot of stuff that later on I realized was from the successor, ISO C99, instead. So I successfully avoided things like stdbool.h and created a "polyfill" (term borrowed from JavaScript parlance) that would use my own re-creation of bool, OR #include stdbool.h if the compiler was detected as ISO-C99-compliant. But I realized only later things like stdint.h for guaranteed fixed-sized integer types were part of C99, and CodeWarrior Pro 6 seems to be compliant enough that it had all of it. But now I found some decent workarounds to do something akin to what I did with the bool type, which is currently underway. Anyway... I avoided C++ for the time being, but in my search for learning C, I found a heck of a lot of info on the small little things that differ between the C and C++ specs, so I partially absorbed a lot of C++ along the way just so that I could tell how NOT to do things in strict C. So as I finally started working on my Quickdraw routines, I started noticing... "heck, this is starting to look A LOT like the PETSCII source code!" The main difference is that now I know A LOT better what the heck I'm doing, and what the heck is going on. I will still continue to do work on my own strict C game project, BUT this journey has given and still is giving me a lot of very-much-needed confidence to go back to the PETSCII project and get it moving forward again... Simply for the educational merit, since I'm not really interested in the actual game. So, yeah, just thought I would share these developments. I'm very grateful to @lauland for pushing me as far as he did. It certainly helped with just about everything. I hope what we are writing here can likewise inspire others to keep on going with whatever they are working or want to work on.
Last Edit: June 13, 2024, 19:27 by Jatoba
|
lauland
|
512 MB ![]() ![]() ![]() ![]() ![]() Posts: 674 Symtes 7 Mewconer!
Reply #19 on: June 15, 2024, 21:03
|
That is awesome! Warms my heart to hear you're working on stuff! And it's all good, use PETSCII however it is useful to you. The only reason I did any of it was to inspire people just like you. I hear a lot of talk, and I think, dang, I know they could do it, they just need a little tiny push/help to get REALLY going. Everybody has different learning styles, and programming is like speaking a foreign language...or woodworking...or cooking...or dancing...whatever... Reading about the techniques and different styles will help you know what you're doing, but when the rubber meets the road may be less useful than it seems. I don't know, I probably should shut up, I know my personal style is to just jump and try and do things, see what works, and learn from my (countless!) mistakes. But I guess the point is, planning things never gets me very far because, as they say, "Battle plans never survive contact with the enemy". When I jumped on PETSCII, for example, it didn't occur to me that I'd need to deal with loading the images (Doh!). I thought, "do it the Mac way", resource forks and PICT format at first, but...that way I'd end up spending a LOT of time on conversion and dicing up the image into blocks and/or dealing with Resource Manager limitations. I wanted to only do the absolute bare minimum to show easy a port would be...and instead ended up reading things raw binary. A lot quicker, and easier to understand. What I mean is, really, learning standards, you'll quickly find out nobody is standard. You can't EVER count on header files like stdint.h (or heaven forbid stdbool.h!), being there, or if they are, what is in them. I could bore your ears off on dealing with my tribulations with time.h and sys/time.h with Goliath and Jabbernaut! (Or HFVExplorer and different Visual C++ version's MFC implementations) So, I have mixed feelings about using things like polyfills...where you write to a particular standard, and use additional code to "fill in" the missing parts where they aren't supported on one system or another, can work really well, but can also end up being a crutch of sorts. It can take a lot of work, and be ultimately impossible to try and make something like Think C 5 compliant with ANYTHING...Um...well...this could degenerate into a "religious" discussion, so I think I'll just leave it there...too much my personal opinion, which may or may not be useful at all! The real point is, you sat down and worked on your personal project, and that's the only important thing! Keep on truckin'!
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #20 on: June 16, 2024, 15:05
|
@lauland Actually, you are completely right, as it (unsurprisingly) turns out: after I did my "polyfill" of stdint.h, and started using both bool types and fixed-width integer types around... I noticed a lot of conflicts before things even got off the ground. It turns out there's already a bunch of those definitions in Mac headers, I think in MacTypes.h and/or elsewhere. Then I noticed and learned that the order of inclusion of headers in a file can also affect the outcome... And then, long story short... I ultimately realized the deep truth that... What I was doing was crazy. A noble attempt, for sure, but too crazy to ACTUALLY achieve the goal without having... some sort of 75-headed chimera beast of hell. If even truly achievable, because, again like you said, each compiler seems to do whatever the heck it wants, with partial or no regard for the standards. So then I rethought the whole thing, and forked my own code so that it would follow a TOTAL "less is more" philosophy, meaning now I radically went the opposite route: I will use char, short, int, long etc. to my heart's content, will ALWAYS use 1 and 0 instead of macros or enums of "true" and "false", and, IF one day I want to port this code over to other platforms, fine, I will just use whatever types are appropriate THEN, rather than pre-emptively. Add casts between one type and the other where needed. Etc.. Now it's time I 'fess up my secret idea/project: I hoped to make the code I was making to be "universal" so that I could take most of the effort and port this game of mine... To the Game Boy! Yes, that 160x144px Nintendo device of 4 shades of weird-green. There's something called GBDK, and it's reliant on a C compiler called LCC (Little C Compiler). Guess what, that version of LCC isn't standards-compliant either, since an int is only 8 bits, even though the C89 standard guarantees at least 16 bits minimum. Anyway... back to the basics, and carrying forward my project with dead-simple, straightforward, clean and organized C89... All hail vanilla coding! Goodbye polyfills.
Last Edit: June 16, 2024, 15:07 by Jatoba
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #21 on: June 16, 2024, 18:17
|
@lauland By the way, do you know what the heck is this compiler behavior about? http://macintoshgarden.org/forum/c-compilers-mac-vs-c-standards After I figured this one out, the ship's been sailing smooth with my project, but wow, this was nowhere near as easy to figure out as the cause as that thread makes it seem like.
|
lauland
|
512 MB ![]() ![]() ![]() ![]() ![]() Posts: 674 Symtes 7 Mewconer!
Reply #22 on: June 17, 2024, 01:41
|
God d*mn, I'm proud of you! (Is it ok if I say that?) The last thing I wanted was to discourage you in any way or somehow impose my own (possibly crazy) philosophy, but it took you very little time to figure out the road you were setting down on... Everything you concluded about types/macros is 100% spot on! You are rockin', please don't ever stop! (When you get discouraged, let me know ASAP!) What you were trying was truly noble, but probably a HUGE time grabber, extremely difficult, should be a project unto itself, and likely ultimately impossible. What you should take away is that something like that isn't a bad idea at all, but probably separate, extremely thin, polyfills per each separate compiler version would be the ONLY way to go. (And even then, you might find you'd need different ones for different projects too!) While I've been working on buiding FireFox, I was watching things "./configure" and saw messages about "testing if stdbool is C99 compliant...no" many times. And this was with (relatively recent) versions of clang and llvm...if they aren't compliant, only very recent versions must be. Was going to point this out to you...but now I don't need to! So, learning any particular standard like C99 and trying to REALLY stick with it EVERYWHERE, personally to me, would seem to be opening a world of potential pain. ---- One pitfall programmers fall into all the time is "building tools to build tools". Which is when you end up putting off what you really want to be working on, and spend (waste) so much time just getting the perfect version of "whatever"...or building endless libraries of code that you "just know you'll need"...without actually jumping on the project you're "supposed" to be doing, and just seeing what you actually need NOW. I have been extremely guilty of this, but have gotten better! ---- Your "secret project" is absolutely something you should never give up on...but get it running on ONE system before you get it running on ALL of them! Ha! We will definitely chat and discuss it in the future. I love squeezing code into small systems, and that sounds totally up my alley. (Palm pilot port too maybe?) ---- FYI The working PETSCII code you see is only the last most recent attempt of several, and I think it'll enlighten you to hear about the previous ones because they are very apropos to your recent experience: #1 Was along with a fellow programmer who wanted to use the "Sprite Toolkit" to do things. I did not like this idea because it meant we'd have to learn an obscure, very old, library...and that knowledge may not have been very useful for any other project. There'd also be the overhead and limitations of that toolkit...it might've been too slow and/or not worked at all on very old systems like a System 6 MacPlus, which was the purported target! But, when working on projects with others, compromise is the name of the game... #2 Abandoned the "Sprite Toolkit" and was very close to I ended up doing: Writing extremely basic Mac Toolbox calls. This failed because we were trying to use Symantec C++...which is a very old version of C++. I started tweaking the code to compile, but the other programmer lost interest, and I didn't see any reason to torture myself. It turned out CodeWarrior is ALSO a pretty old version of C++, but MUCH newer than Symantec. I still had to hack out a few things: the sound code uses clever C++ class constructors that CodeWarrior doesn't support...so if anyone ever tries to finish THAT, it'll need some hacking. #3 was an attempt to use the SDL version of PETSCII, and, guess what?!?!, a polyfill!!! This was because PETSCII uses SDL2, but there is no SDL2 for classic MacOS. So I started writing one. I got to the point where I realized I was "building tools to build tools" and getting anything resembling SDL2 on MacOS 9 is a huge project just itself. (I promise I will revisit SDL2 on classic MacOS soonish! I've still got half written, but very limited, shim/polyfill code... I'll start a new topic for it when the time comes...unless YOU would like to talk about it now?!?) This also seemed to be losing sight of the whole reason I was working on PETSCII in the first place: As an example to show how it isn't rocket science to write a Mac classic game...kept as simple and clear as possible. #4, the final one: I ended up just using GWorld's as the equivalent of SDL Surfaces', because I knew the SDL version relied on scaling the bitmaps and I didn't want to have to add separate code for Mac screens with different bit depths. (CopyBits does it ALL, and is fast enough on faster systems). So, as it is, it relies on Color QuickDraw...to get it running on System 6 I think #ifdef's to use BitMap's where there are GWorld's now would work extremely well. I guess the point I'm making is, expect to have to abandon multiple ideas/versions/tries along the way in every thing you do...but every time you'll be learning VERY important lessons in "how not to do it".
Last Edit: June 17, 2024, 02:01 by lauland
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #23 on: June 17, 2024, 15:27
|
@lauland As always, it's very fun and educational hearing your insight, and thank you again for the words of encouragement. They certainly help, especially when I keep hitting my head against the wall of learning these APIs and, right now, 2D drawing concepts (Quickdraw.h)... So a minor update, I got to the point I got a Mac window, and inside it I can draw pixels. I can make the pixel "move around" by simply painting over the pixel's original location with the default background color, then I paint over the window again with the pixel's new position. So it looks as if it is "walking". It does this with arrow keys when pressing them, and when "repeating" them by holding down the given arrow key. All fine and dandy up until that point, except that my pixel is actually a 16x16 rectangle. No issue, I learned to use: PenSize(16, 16); ... as well as Rect and WindowPtr structs. I do the memory management with pointers just fine, as well. I also rely on: MoveTo(x, y); ... where x and y are not the monitor pixel position, but the pixel position of the new Mac window I generated. Cool. Then I effectively draw there with: Line(0, 0); ... And I know I can change those two parameters to serve as the offset for where I want to draw based on what was set with MoveTo(). Working with only two colors, I also set the color of my pixel to be either black (when I want to draw something) or white (when I want to "erase" something), like this: RGBColor rgbWhite; /* Separate declaration and assignment for 1983 K&R C conformity just for the heck of it */ rgbWhite.red = 65535; rgbWhite.green = 65535; rgbWhite.blue = 65535; RGBForeColor(&rgbWhite); ... and: RGBColor rgbBlack; rgbBlack.red = 0; rgbBlack.green = 0; rgbBlack.blue = 0; RGBForeColor(&rgbBlack); So what is my current problem? Well, through a little algorithm I get my 16x16 block to walk "4 pixels" each time it takes a "step". But each time it "walks", no matter the step size, there's a good chance that there will be a tiny, quick visual flicker. I tried to tackle on this flicker. Eventually, after many failed attempts, I figured I might need what is called "double-buffering". And so now I am/was trying to figure out HOW to do that. And I'm stumped honestly. For the time being, I decided to move forward "as is", with the flicker and all, and get the rest of the game "done". Then maybe revisit the flicker issue during a polishing phase... ... But I wish I knew how to pull it off right now. I'm greedy.That's it for the minor update.
Last Edit: June 17, 2024, 15:30 by Jatoba
|
lauland
|
512 MB ![]() ![]() ![]() ![]() ![]() Posts: 674 Symtes 7 Mewconer!
Reply #24 on: June 17, 2024, 17:04
|
Dangit! I'd typed up a nice explanation of double buffering but then system7today went down and ate my comment. Basically: Draw everything offscreen into a buffer (a GWorld, or BitMap for B&W) the size of the window. Copy that buffer to the window for every "frame" to the screen. Never draw directly in a window. There is no flicker because everything is drawn at once. Since QuickDraw calls are always to "the current port" you just SetPort to your offscreen GWorld/BitMap before any drawing. Then CopyBits the entire buffer to the window. Look at the PETSCII code and you'll see it doing this. (It copies the artwork, even the text, from several offscreen buffers). ---- A slightly different method of avoiding flicker is a "display list" where you have a list of everything to draw, in the correct order and go over that for each frame (clearing/erasing what needs to be, using "dirty rectangles"). The difference is there is no offscreen buffer. This is how Arashi, which is all vectors works. It doesn't care about overlap/overdraw because it's fast enough, and it adds to the retro charm!
Last Edit: June 17, 2024, 17:08 by lauland
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #25 on: June 17, 2024, 17:44
|
@lauland Thank you for the tips. I will look into it again to get it working, preferably through the double-buffered way rather than the Arashi way, if I can. I relate to losing a forum post, a lot. Electricity here goes poof at any moment at any point for any reason. I also developed for some years now the habit of Cmd+A Cmd+C (or Ctrl+A Ctrl+C) my writing of a forum post before submitting it, due to all kinds of issues that can happen. If I'm writing something extra long, sometimes I even save the contents in a text file until I publish it...But don't worry, your advice was to the point, educational and put me on track again. So mission complete?
|
cballero
|
1024 MB ![]() ![]() ![]() ![]() ![]() ![]() Posts: 1176 System 7, today and forever
Reply #26 on: June 17, 2024, 22:45
|
Love following along all of these posts as well! ![]() So another trick from those already you mentioned, Jatoba, is I quickly capture text by taking a few screenshots. It does involve retyping if it's actually needed, but it's a super quick (and lazy, I know, lol!) and easy way to snap, and then it can be trashed later once it's no longer needed, so why not?
|
lauland
|
512 MB ![]() ![]() ![]() ![]() ![]() Posts: 674 Symtes 7 Mewconer!
Reply #27 on: June 18, 2024, 04:14
|
One thing to keep in mind is that on slower machines, like the kind we all love here, you may not be able to redraw the entire screen/window each time, and expect get any kind of decent frame rate. Especially using CopyBits, which is truly wonderful...but it is a do-everything solution that scales and clips and handles different bit depths, even different drawing styles, for you. If you limit yourself to a particular screen depth, handle (or don't need) clipping yourself, and have your art pre-scaled to the right size(s), writing your own "blit" routine can be necessary (and nowhere near as hard as it sounds). (This can degenerate into one of those "religious discussions" where some people will tell you to NEVER use CopyBits EVER...but don't listen to them...use it if you at all can!) That is something that a MacPlus version of PETSCII might need, if an attempt is ever made. ---- So, if you aren't redrawing the entire screen, "dirty rectangles" can cut down a LOT on the amount of pixels you're needing to draw. This is when you keep track of what is over drawn or overlapping, and just draw those parts, leaving anything unchanged untouched. Don't count out the "Arashi method" just yet either...I found it was impossible to redraw the whole screen on an SE/30 or '030 powerbook for each frame, so instead I cheated a bit. I redraw the "game grid" often, because every enemy or "bullet" that moves over it leaves tracks, or erases parts of it. But for everything else moving, it actually goes back and erases the lines from the previous frame, before drawing the new one. Just drawing lines is very fast and I optimized it about as far as it could go with pure C. (I didn't want to write any new assembly...very rusty after several decades). ...but that's a whole other subject: Squeezing down into very low end systems and when you get there we can go over it in detail. To get a version of Arashi running at all on a stock m68000 (not even an '020) I only draw half as many stars/bullets/etc, only every other pixel for all the lines (other than text, which is also just vectors, because it was unreadable), made clipping optional, and I simplified the explosions a lot, etc etc. Even then it is just BARELY "playable". Obviously more could be done, but the goal was black and white on low end '030, and it runs very well there. ---- FYI By "clipping" I mean limiting drawing to just the screen/window and/or a particular bitmap/surface/gworld. Thus you aren't trying (or wasting time) to draw pixels off any of the edges, etc. If you are just drawing single pixels, you only need to check the coords...but if a line or bitmap is halfway/partially off an edge, it can be very tricky if you are doing it yourself.
Last Edit: June 18, 2024, 04:24 by lauland
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #28 on: June 18, 2024, 10:57
|
@lauland I was able to implement drawing on what I think is an offscreen grid, then use CopyBits to copy it all to the game window, but there's still a flicker. I am positive I am doing one or multiple things wrong in the steps, hence the flicker, not to mention the "initial state" of my window is now a bunch of "glitchy visuals", rather than pure white. As my 16x16 block "walks around", it cleans the screen back to pure white background. Although it's still flickering. But I'm interested in your considerations for weaker hardware, because I think a Game Boy is weaker than even the earliest 68000 Macs, right? So I'm interested in the "dirty rectangles" approach. I am indeed working with a pre-decided-upon, fixed window size/resolution of 160x144 because it is also the Game Boy resolution. My plan, for the Mac version, is to evenly upscale this, like a magnification feature, meaning it shouldn't involve much rework, but that's for later. I will write a follow-up post shortly with my drawing routine, without the attempt of double-buffering, because I wonder if my original approach already is what is called the "dirty rectangles" approach. And I wonder if I got the flicker because of some of the methods I was using before AND after all the drawing (PenSize, MoveTo, Line) was already done. And also, for a true horror show, I will put here the terror that is my code trying to use double-buffering, as I try to understand what exactly I'm doing... (My attempt was a bunch of copy-paste of method calls and minor adjustments in the ways I thought they were supposed to be... So expect terrible code!)
Last Edit: June 18, 2024, 11:01 by Jatoba
|
Jatoba
|
256 MB ![]() ![]() ![]() ![]() ![]() Posts: 270 System 9 Newcomer!
Reply #29 on: June 18, 2024, 12:23
|
As promised, here's the "important" code so far: ================================================================== Main.c (all clean and nice) ================================================================== #include <stdio.h> #include <stdlib.h> #include <Types.h> #include <Windows.h> #include <Quickdraw.h> #include <Events.h> #include "Drawing.h" int main(void) { Rect* screenRect; Rect* spriteRect; WindowPtr window; EventRecord event; char boolQuit; unsigned long lastKeyTime; screenRect = GetNewRectWithReasonableParameters(90, 90, 160, 144); spriteRect = GetNewRectWithReasonableParameters(72, 64, 16, 16); window = NewCWindow(NULL, screenRect, "\pThe Game Window", 1, documentProc, (WindowPtr)-1, 1, 0); PaintGrid(window, spriteRect, 0); boolQuit = 0; /* Initialize last key press time */ lastKeyTime = TickCount(); while (!boolQuit) { if (WaitNextEvent(everyEvent, &event, 1, NULL)) { switch (event.what) { case keyDown: if ((event.modifiers & cmdKey) && (event.message & charCodeMask) == 'q') { /* Exit the loop when Command + Q is pressed */ boolQuit = 1; } else { switch (event.message & charCodeMask) { case kUpArrowCharCode: MoveSprite(window, spriteRect, 0, -4); break; case kDownArrowCharCode: MoveSprite(window, spriteRect, 0, 4); break; case kLeftArrowCharCode: MoveSprite(window, spriteRect, -4, 0); break; case kRightArrowCharCode: MoveSprite(window, spriteRect, 4, 0); break; } } break; case autoKey: if ((TickCount() - lastKeyTime) >= GetCaretTime()) { switch (event.message & charCodeMask) { case kUpArrowCharCode: MoveSprite(window, spriteRect, 0, -4); break; case kDownArrowCharCode: MoveSprite(window, spriteRect, 0, 4); break; case kLeftArrowCharCode: MoveSprite(window, spriteRect, -4, 0); break; case kRightArrowCharCode: MoveSprite(window, spriteRect, 4, 0); break; } /* Update last key press time */ lastKeyTime = TickCount(); } break; case mouseDown: boolQuit = 1; break; } } } free(spriteRect); free(screenRect); DisposeWindow(window); return EXIT_SUCCESS; } ================================================================== Drawing.c (drawing magic here-- Is this using "dirty rectangles"?) ================================================================== #include <stdio.h> #include <stdlib.h> #include <Types.h> #include <Windows.h> #include <Quickdraw.h> #include <Events.h> /* For debugging only */ #include <SIOUX.h> #include "Drawing.h" Rect* GetNewRectWithReasonableParameters(short startingXPosition, short startingYPosition, short width, short height) { /* Rect* rect = (Rect*)malloc(1 * sizeof(Rect)); */ Rect* rect = (Rect*)malloc(sizeof(Rect)); rect->left = startingXPosition; rect->top = startingYPosition; rect->right = (short)(width + startingXPosition); /* NOTE: short + short = int outcome! WTF! */ rect->bottom = (short)(height + startingYPosition); return rect; } void PaintGrid(WindowPtr window, Rect* spriteRect, char boolErase) { /* TODO: Paint to a buffer of same size of the game window. Then use CopyBits method to put it in window */ FILE* debugf; /* TODO: Remove this debugging-related stuff for the finished game */ GrafPtr savedPort; debugf = stdout; /* Save the current graphics port */ GetPort(&savedPort); /* Set the graphics port to the window's port */ SetPortWindowPort(window); PenSize(16, 16); if (boolErase) { RGBColor rgbWhite; rgbWhite.red = 65535; rgbWhite.green = 65535; rgbWhite.blue = 65535; RGBForeColor(&rgbWhite); } else { RGBColor rgbBlack; rgbBlack.red = 0; rgbBlack.green = 0; rgbBlack.blue = 0; RGBForeColor(&rgbBlack); } /* TODO: else if (2 other cases of grey hues) */ /* MoveTo is based on the SCREEN/WINDOW, not the monitor */ MoveTo(spriteRect->right, spriteRect->bottom); /* Actually draw/paint */ Line(0, 0); fprintf(debugf, "spriteRect->right is %d and spriteRect->bottom is %d.\n", spriteRect->right, spriteRect->bottom); SetPort(savedPort); /* Restore the original graphics port */ } void MoveSprite(WindowPtr window, Rect* spriteRect, short x, short y) { PaintGrid(window, spriteRect, 1); spriteRect->right += x; spriteRect->bottom += y; PaintGrid(window, spriteRect, 0); } ================================================================== Drawing.c (version with double-buffered attempt / horror) ================================================================== #include <stdio.h> #include <stdlib.h> #include <Types.h> #include <Windows.h> #include <Quickdraw.h> #include <Events.h> /* For debugging only */ #include <SIOUX.h> #include "Drawing.h" /* WindowPtr type in QuickDraw properties of interest: 1. **Window Position and Size**: - 'GetWindowBounds': Get the bounding rectangle of the window. - 'SetWindowBounds': Set the position and size of the window. 2. **Window Drawing**: - 'BeginUpdate': Begin updating the window for drawing. - 'EndUpdate': End updating the window after drawing. */ Rect* GetNewRectWithReasonableParameters(short startingXPosition, short startingYPosition, short width, short height) { /* Rect* rect = (Rect*)malloc(1 * sizeof(Rect)); */ Rect* rect = (Rect*)malloc(sizeof(Rect)); rect->left = startingXPosition; rect->top = startingYPosition; rect->right = (short)(width + startingXPosition); /* NOTE: short + short = int outcome! WTF! */ rect->bottom = (short)(height + startingYPosition); return rect; } void PaintGrid(WindowPtr window, Rect* spriteRect, char boolErase) { /* TODO: Paint to a buffer of same size of the game window. Then use CopyBits method to put it in window */ FILE* debugf; /* TODO: Remove this debugging-related stuff for the finished game*/ GrafPtr savedPort; GWorldPtr offscreenGWorld; Rect offscreenRect; PixMapHandle pm; unsigned int bpl; char *dst; char c; unsigned int off; unsigned int sbpl; unsigned int r; unsigned int b; /* PixMapHandle offscreenPixMap; GrafPtr offscreenPort; Rect bounds; */ /* Save the current graphics port */ GetPort(&savedPort); /* Set the graphics port to the window's port */ SetPortWindowPort(window); offscreenRect = window->portRect; /* Use the window's portRect as the offscreen buffer size */ NewGWorld(&offscreenGWorld, 0, &offscreenRect, NULL, NULL, 0); /* /*create the buffer*//* offscreenPixMap = GetPortPixMap(GetWindowPort(window)); GetPortBounds(GetPortWindowPort(GetWindowPort(window)), &bounds); SetRect(&bounds, 0, 0, bounds.right, bounds.bottom); NewGWorld(&offscreenPort, 0, &bounds, NULL, NULL, 0); SetGWorld(offscreenPort, NULL); */ SetGWorld(offscreenGWorld, NULL); pm=GetGWorldPixMap(offscreenGWorld); LockPixels(pm); debugf = stdout; PenSize(16, 16); if (boolErase) { RGBColor rgbWhite; rgbWhite.red = 65535; rgbWhite.green = 65535; rgbWhite.blue = 65535; RGBForeColor(&rgbWhite); } else { RGBColor rgbBlack; rgbBlack.red = 0; rgbBlack.green = 0; rgbBlack.blue = 0; RGBForeColor(&rgbBlack); } /* TODO: else if (2 other cases of grey hues) */ /* Draw on the offscreen buffer here */ /* FrameRect(&bounds); */ /*FrameRect(&offscreenRect);*/ /* MoveTo is based on the SCREEN/WINDOW, not the monitor */ MoveTo(spriteRect->right, spriteRect->bottom); /* Actually draw/paint */ Line(0, 0); bpl=0; /*bpl=GetPixRowBytes(pm);*/ bpl=(unsigned int)((*pm)->rowBytes&0x3fff); dst=GetPixBaseAddr(pm); off=0; sbpl=0; for(r=0;r<0;r++) { for(b=0;b<sbpl;b++) { fread(&c,1,1,0); dst[off+b]=c; } off+=bpl; } UnlockPixels(pm); /* Restore the window's graphics port */ SetGWorld(GetWindowPort(window), NULL); /* CopyBits(GetPortBitMapForCopyBits(offscreenPort), GetPortBitMapForCopyBits(GetWindowPort(window)), &bounds, &bounds, srcCopy, NULL); */ CopyBits((BitMap*)offscreenGWorld->portPixMap, (BitMap*)&window->portBits, &offscreenRect, &offscreenRect, srcCopy, NULL); /* SetGWorld(GetWindowPort(window), NULL);*/ /* DisposeGWorld(offscreenPort); */ /*DisposeGWorld(offscreenGWorld); /* Clean up the offscreen buffer */ fprintf(debugf, "spriteRect->right is %d and spriteRect->bottom is %d.\n", spriteRect->right, spriteRect->bottom); SetPort(savedPort); /* Restore the original graphics port */ } void MoveSprite(WindowPtr window, Rect* spriteRect, short x, short y) { PaintGrid(window, spriteRect, 1); spriteRect->right += x; spriteRect->bottom += y; PaintGrid(window, spriteRect, 0); } ================================================================== Drawing.h (for either version of Drawing.c) ================================================================== #ifndef DRAWING_H #define DRAWING_H #include <Quickdraw.h> Rect* GetNewRectWithReasonableParameters(short startingXPosition, short startingYPosition, short width, short height); void PaintGrid(WindowPtr window, Rect* spriteRect, char boolErase); void MoveSprite(WindowPtr window, Rect* spriteRect, short x, short y); #endif
Last Edit: June 18, 2024, 12:36 by Jatoba
|
|
Pages: 1 [2] 3
|
| |||||||||||||||
|
© 2021 System7Today.com. |


I'm greedy.