Lots of noob questions

SGDK only sub forum

Moderator: Stef

KillaMaaki
Very interested
Posts: 84
Joined: Sat Feb 28, 2015 9:22 pm

Lots of noob questions

Post by KillaMaaki » Sat Mar 07, 2015 10:17 pm

OK, be prepared for a dump of all of the noob questions I've been saving up until my account was activated.

*deep breath in*

Color Palette Management
So, I see that on the Genesis I have four color palettes at my disposal, each with 16 colors. That gives me a maximum of 64 colors I can display at any given time, up to 16 per sprite.
Question is, how exactly do you manage color palettes? Would it make sense to divide color palette by usage? (one for background, one for level, one for player, one for everything else?)

Resource Management
OK, so I've wrapped a lot of SGDK calls in a GameEngine.c file. The game engine currently maintains a list of sprite pointers, and a u32 pointing to the next available sprite index. Then a function call loads a sprite into memory and stores the pointer to it at that index (and returns the index, acting as a sort of "handle" for that sprite instance), and advances the u32 to point to the next one.
Basically, I can load sprites into memory, but the problem is I can't unload them easily. I was thinking about implementing some sort of free list, so that I can essentially request the next available free space to load the sprite into, and then, for instance, if a game entity is destroyed, it frees that slot so that another entity can use it. Does this approach make any sense?

Actually, for that matter, I was thinking of implementing a free-list-like thing for my game entities as well, since GameEngine.c already has an array of entity pointers it runs through and updates every frame, and at the moment when adding a new entity it just iterates through until it finds a NULL pointer (which, obviously, would probably get pretty damn inefficient if there's a lot of entities).

Music XGM issues
Has anybody else had issues when converting VGM over to XGM? Here's how my music *should* sound (exported as a ROM file from DefleMask)

http://www.newgrounds.com/audio/listen/611434

But here's how it *actually* sounds. Close, but something's... I don't know, off? It sounds a little messed up. Actually, I think the percussion's just a little bit off, like maybe it's lagging behind the other instruments a bit.

https://dl.dropboxusercontent.com/u/991 ... ch_XGM.mp3

Also, is there a way to loop XGM music? At the moment, in my game loop I'm manually checking if the music is playing and, if not, restarting it, but there's often a tiny gap if silence when it restarts.

Anyway, sorry to be posting so many questions but I'm just really curious about this stuff.
Any answers appreciated :)

KillaMaaki
Very interested
Posts: 84
Joined: Sat Feb 28, 2015 9:22 pm

Post by KillaMaaki » Sun Mar 08, 2015 5:37 am

Actually, something just occurred to me.
Is it possible to palette swap mid-frame in SGDK? Say, rewrite palette data just before drawing one or more sprites?

EDIT: Actually, been looking around... Looks like my best bet would be do do something like:

- One full 16-color palette for background/level stuff
- One full 16-color palette for main character, maybe a few colors reserved for pickups or effects?
- Remaining two palettes divided into four palettes of 8 colors, used for everything else.
- Additionally, just to give an example, a boss character might load its own full 16-color palette into one of the two remaining ones.

kubilus1
Very interested
Posts: 237
Joined: Thu Aug 16, 2012 2:25 am
Contact:

Post by kubilus1 » Sun Mar 08, 2015 11:33 pm

Good questions but I'm probably not the best to answer all of them.

Color palette management. You can slice this up a few different ways. I've heard of using one palette for background plane A, on for background plane B, and then two for sprites. Then stuff like the status bar may share with one of the other sprites.

One thing to keep in mind, you don't really get 16 colors per palette, one color is the "alpha channel" so in effect you have 15 useable colors per palette.

Resource managment. I wrote a sprite list structure that allows me to add and remove sprites. When adding it searches for an open spot to stick the sprite in. Sounds like what you are suggesting.

Music issues. One thing about the XGM driver is that there may be a slight delay when playing samples. That *could* be what you are hearing. You could try the VGM driver instead and see if that sounds any different. The VGM driver is generally less powerful than the XGM driver, but does not need to buffer sample playback. (Just make sure your samples are @ 8khz for the VGM driver)

KillaMaaki
Very interested
Posts: 84
Joined: Sat Feb 28, 2015 9:22 pm

Post by KillaMaaki » Mon Mar 09, 2015 12:30 am

kubilus1 wrote: One thing to keep in mind, you don't really get 16 colors per palette, one color is the "alpha channel" so in effect you have 15 useable colors per palette.
Oh, duh, yeah you're right.
Guess I'll have to experiment with the color palette thing depending on my needs.
kubilus1 wrote: One thing about the XGM driver is that there may be a slight delay when playing samples. That *could* be what you are hearing. You could try the VGM driver instead
I think I might just accept the sample delay and continue using XGM. Pretty sure I read that XGM is way more efficient than the VGM driver, plus I'm using those three extra channels for sound effects which is fantastically convenient.

kubilus1
Very interested
Posts: 237
Joined: Thu Aug 16, 2012 2:25 am
Contact:

Post by kubilus1 » Mon Mar 09, 2015 1:09 am

Yeah, especially if you are doing a lot of sound effects the XGM driver is better. Uses smaller file sizes since straight VGMs can cometimes be on the large size. This isn't always such a concern though if you use the newer VGM formats.

I wrote the VGM driver a while back and the one advantage is that it should play the sample closer to instantly. Otherwise, the XGM is better. It *may* still be worth trying both just to see if the sound difference is really sample delay, or something else. Sometimes the actual conversion from VGM to XGM can be at fault, not the driver itself.

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Mar 09, 2015 1:46 pm

Actually there was a bug in the latter XGM driver version which indeed can eat some part of the samples when converting from VGM to XGM music :p
The bug was added with the auto enable DAC stuff but I fixed it since sometime, i just need to upload it ! I will do it quite soon and hopefully that will fix your issues ;)
About the sample lag, that is indeed a default of the XGM driver because of the internal circular PCM buffer. I take care of it when converting VGM music to XGM format but i can't fix it when it comes to play SFX through PCM and so you have about 3 frames of delay... hopefully that is not too much hurting for SFX.
For the loop stuff, currently there is no loop option for music play but if the original VGM file has loop information then it will be supported in the XGM music as well, so you can try to tweak a bit the input VGM file to add the loop info.

About the sprite problem, do you use the new sprite engine of SGDK ? I'm pretty sure it can help you in covering your allocation problem.

KillaMaaki
Very interested
Posts: 84
Joined: Sat Feb 28, 2015 9:22 pm

Post by KillaMaaki » Mon Mar 09, 2015 6:22 pm

Stef wrote:Actually there was a bug in the latter XGM driver version which indeed can eat some part of the samples when converting from VGM to XGM music :p
The bug was added with the auto enable DAC stuff but I fixed it since sometime, i just need to upload it ! I will do it quite soon and hopefully that will fix your issues ;)
About the sample lag, that is indeed a default of the XGM driver because of the internal circular PCM buffer. I take care of it when converting VGM music to XGM format but i can't fix it when it comes to play SFX through PCM and so you have about 3 frames of delay... hopefully that is not too much hurting for SFX.
For the loop stuff, currently there is no loop option for music play but if the original VGM file has loop information then it will be supported in the XGM music as well, so you can try to tweak a bit the input VGM file to add the loop info.

About the sprite problem, do you use the new sprite engine of SGDK ? I'm pretty sure it can help you in covering your allocation problem.
1.) Ah. Yeah, I could tell there was a sample delay for sound effects but it's not that bad. Sound effects can afford to be a little late and still sound okay, but drum samples do need to stay synced with the main track.
2.) Ooooh, OK. I don't think DefleMask supports adding loop information to VGM files so I'll have to look into that.
3.) New sprite engine? Not the SPR_initSprite stuff? What I've got now is going to work perfectly fine for me, although if there's a different way to do things I'm a little curious about it (since most of what I know is based on crawling through the header files and the example projects)

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Mar 09, 2015 7:00 pm

1) Yeah of course drum/sample for music need to be perfectly synched so the xgm compiler take care of that. Actually samples are never perfectly in sync but for music there is less that 1 frame of delay and so we can't really heard it ;-)
2) That might be the problem, I could eventually add an option to make the music to loop automatically but s the XGM format support it internally I did not added it for now.
3) SPR_init() is what I call the new sprite engine so if you are already using it you are alright :D I guess you already know about supported features if you dig in the headers ;-)

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Mar 09, 2015 10:28 pm

Ok, i just uploaded a new version of SGDK with the fixed XGM driver =) Just drop me a message if you meet any problem !

KillaMaaki
Very interested
Posts: 84
Joined: Sat Feb 28, 2015 9:22 pm

Post by KillaMaaki » Tue Mar 10, 2015 4:33 am

OK, cool, I'll let you know how that works :)

On a side note, figured I'd post here instead of making a new thread (at least for now).
A little side project of mine which started over the weekend is something I'm sure is really crazy, but I wanted to tackle it nonetheless. Basically, I'm making a custom almost-kinda compiler for a custom-built programming language, with the intent to use it for Sega Genesis homebrew.

It started a long time ago on a completely unrelated thing, and recently while fighting with C's somewhat arcane syntax (I'm more used to higher level languages, can you tell?), I suddenly realized that it should be possible to modify and extend what I'd already done previously, and have it "compile" into C code.

The syntax is somewhere in between maybe ActionScript 3 and C/C++ (albeit highly pared down). So for example (and I actually do have this working), I might have this code:

Code: Select all

include( "genesis.h" );

// structs can store variables, they're like simple containers for data
struct Vector2
{
	var x : fix32;
	var y : fix32;
}

// classes are like structs, but they can also have methods.
// additionally, they are allocated via 'new' syntax, and are allocated on the heap rather than the stack (internally, this is done via MEM_alloc function)
class TestClass
{
	var position : Vector2;
	
	// Initialize game entity
	function virtual Init() : void
	{
		// do stuff
	}
}

// classes can inherit from other classes
class TestSubclass : TestClass
{
	function override Init() : void
	{
		super(); // <-- this is used to call the parent method implementation
		
		this->position.x = 50;
	}
}

// modules look a lot like static classes - you can put fields and functions in here and access them via Module.[..] syntax.
// at the moment, modules are more like classes than namespaces - so for instance you cannot put structs or classes inside of them (only fields and functions).
module SomeModule
{
	var someField : u32;
}

function main() : int
{
	var testSubclass : TestSubclass* = new TestSubclass();
	testSubclass->Init();
	
	// this is how you access module fields and functions
	SomeModule.someField = 42;
	
	while( true )
	{
		VDP_waitVSync();
	}

	return 0;
}
And that "compiles" into the following C code (formatted for readability, the actual output from my compiler has a lot less whitespace):

Code: Select all

#include <genesis.h>

typedef struct Vector2_ 
{
    fix32 x;
    fix32 y;
} Vector2;

typedef struct TestClass_ 
{
    Vector2 position;
    void (*Init) ( struct TestClass_* this );
} TestClass;

void TestClass_Init( TestClass* this )
{
}

void TestClass_AssignFuncPointers( TestClass* this )
{
    this->Init = TestClass_Init;
}

TestClass* new_TestClass()
{
    TestClass* newObj = MEM_alloc( sizeof( TestClass ) );
    TestClass_AssignFuncPointers( newObj );
    return newObj;
}

typedef struct TestSubclass_ 
{
    TestClass base;
} TestSubclass;

void TestSubclass_Init( TestSubclass* this )
{
    TestClass_Init(this);
    this->base.position.x = 50; // <-- note that it automatically inserts "base." when accessing position. The compiler understands and keeps track of inheritance, unlike C.
}

void TestSubclass_AssignFuncPointers( TestSubclass* this )
{
    TestClass_AssignFuncPointers( this );
    this->Init = TestSubclass_Init;
}

TestSubclass* new_TestSubclass()
{
    TestSubclass* newObj = MEM_alloc( sizeof( TestSubclass ) );
    TestSubclass_AssignFuncPointers( newObj );
    return newObj;
}

// "module" was sort of meant to be used as an alternative to naming conventions. So for instance if you were to rewrite the VDP_* functions in this language, instead of, say,
// VDP_waitVSync(), you'd have a module named "VDP", and a function inside "waitVSync()", and you'd call it via "VDP.waitVSync();", which internally just translates to VDP_waitVSync();
u32 SomeModule_someField;

int main(  )
{
    TestSubclass* testSubclass = new_TestSubclass();
    testSubclass->Init(testSubclass);
    SomeModule_someField = 42;
    while( true ){
        VDP_waitVSync();
    }
    return 0;
}
I still plan on adding support for compiling in other code files. Additionally, I'm thinking of adding support for:

- Inline C code, via BEGINC / ENDC statements. For the things that you need to hand-write.
- Similarly, inline assembly, via BEGINASM / ENDASM statements (the SGDK C compiler supports inline assembly, right?). For the things you REALLY need to hand-write.

So what do you think? Am I crazy? ;D

EDIT: Should be noted that although this IS working, the compiler code is incredibly fugly and probably can be totally broken in all sorts of ways I haven't found yet.

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Post by tryphon » Tue Mar 10, 2015 9:26 am

That's not crazy. I'm more or less sure that it's what many high-level languages do : they don't compile directly to asm but go through C in-between (I'm sure it's the case of WEB, the language designed by D.E. Knuth to code the TeX word processor, which went through Pascal, and now go by C).

And I have considered to develop a kind of minimal typed Python that would translate into C with SGDK, to allow less verbose code. But I'm not sure the time invested wouldn't be much more important than coding small projects directly in C.

One thing to note, a "Basic" specially designed to MD was developped. But it seems much less flexible than SGDK.

KillaMaaki
Very interested
Posts: 84
Joined: Sat Feb 28, 2015 9:22 pm

Post by KillaMaaki » Tue Mar 10, 2015 9:32 am

tryphon wrote:That's not crazy. I'm more or less sure that it's what many high-level languages do : they don't compile directly to asm but go through C in-between (I'm sure it's the case of WEB, the language designed by D.E. Knuth to code the TeX word processor, which went through Pascal, and now go by C).
I know that's how C++ compilers used to work (not so much anymore, though).

I already had a good deal of the syntax developed and the parser project sitting there, so it's taken maybe three days to get to where it is now. One of the reasons it didn't take that long to get it pretty much fully functional is because I implemented a Pratt parser - which is an amazing magic thing that nobody should ever write a compiler without because it's just that good. Forget Lexx or Yacc, Pratt parsers are awesome :D

But mostly, I'm actually used to primarily C#, and C++ as well, and I was really missing the nice OOP and polymorphism in those languages. Figured it would be super nice to be able to do OOP and inheritance and all that fun stuff :)

Stef
Very interested
Posts: 3131
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Tue Mar 10, 2015 9:32 am

Haha, yeah you are crazy :D
Actually you are almost writing a C++ compiler with some differences here and there (Module instead of Namespace) but the object concept is the same ! You can get the C++ compiler (g++) to work for Megadrive target but i don't distribute it in SGDK as it requires huge binaries files and IMO abusing of the objects features will add many overhead to your code and make it slightly slower.
But for sure, that is a very interesting project ! Having a good OO compiler would be really handy for developers (for myself as well) but i thing that is also a *big* project and you may experience many issues in getting your compiler to actually work (generate correct C code) and then you will have some hard time in optimizing the C code generation itself (to minimize the object code overhead) ! But if you feel that you can do it, then just go for it ! Again i think many people will love to get something like that =)

tryphon
Very interested
Posts: 316
Joined: Sat Aug 17, 2013 9:38 pm
Location: France

Post by tryphon » Tue Mar 10, 2015 9:52 am

KillaMaaki wrote:I know that's how C++ compilers used to work (not so much anymore, though).
I'm always interested in this kind of stuff (even if it's not my domain of expertise) : how does it work now ?

KillaMaaki
Very interested
Posts: 84
Joined: Sat Feb 28, 2015 9:22 pm

Post by KillaMaaki » Tue Mar 10, 2015 10:02 am

tryphon wrote:
KillaMaaki wrote:I know that's how C++ compilers used to work (not so much anymore, though).
I'm always interested in this kind of stuff (even if it's not my domain of expertise) : how does it work now ?
Now C++ compilers just compile directly to native code.

Post Reply