RoadMap Discussion

Could Libnds Use More Abstraction

No! I only work in Binary!
4
5%
Its perfect just the way it.
18
24%
Maybe a touch more Abstraction.
45
59%
Give me PALIB reincarnate!
9
12%
 
Total votes: 76

dovoto
Developer
Posts: 43
Joined: Fri Aug 12, 2005 10:01 pm
Contact:

RoadMap Discussion

Post by dovoto » Thu Nov 15, 2007 1:19 am

I have been working a bit on a new abstraction layer for background control. Currently I have the beginnings of an interface and some example usage. Feedback and concerns would be much appreciated.

Interface:

Code: Select all

//Internal state of registers is not tracked other than background scroll.
 
//currently the only direct register access which interferes with the following
//functions is writing to the background scroll registers and rotation registers...
//this will result in the bgRotate() and bgScroll() being invalid (bgSetRotate() and SetScroll()
//will still function as expected )
 
 
//Current design calls for the following assertions to enforce background creation rules
//	range check layer, mapBase, tileBase
//  Verify the type is consistend with the display mode and the layer chosen
//  verify height and width are consistent with the type
//  passed in ids are checked
//  bpp for color mode is checked to ensure color mode is supported by the background
//  others as they arise
 
 
//current design requires only the following enumeration be exposed to the user 
//although they can still set the control bits manually using the libnds defines
typedef enum
{
	BgType_Text,
	BgType_Rotation,
	BgType_ExRotation,
	BgType_Bmp8,
	BgType_Bmp16
 
}BgType;
 
//creates and enables the appropriate background with the supplied attributes
//returns an id which must be supplied to the remainder of the background functions
int bgCreateMain(int layer, BgType type, int width, int height, int mapBase, int tileBase); 
int bgCreateSub(int layer, BgType type, int width, int height, int mapBase, int tileBase); 
 
//allows direct access to background control for the chosen layer
void bgSetControlBits(int id, u16 bits);
 
//inlines for setting attributes
void bgSetPriority(int id, int priority);
void bgSetColorMode(int id, int bpp);
void bgSetMapBase(int id, int base);
void bgSetTileBase(int id, int base);
void bgSetScroll(int id, int x, int y);
 
//inlines for getting attributes
int bgGetPriority(int id);
int bgGetColorMode(int id);
int bgGetMapBase(int id);
int bgGetTileBase(int id);
 
//inlines for grabing a pointer to the map and gfx
void* bgGetMapPtr(int id);
void* bgGetGfxPtr(int id);
void* bgGetPalette(int id, int paletteId);
 
//relative scroll functionality
void bgScroll(int id, int dx, int dy);
 
//modifies display control registers as necessary
void bgShow(int id);
void bgHide(int id);
 
//rotates the background to the supplied angle
void bgSetRotate(int id, int angle);
void bgSetCenter(int id, int x, int y);
 
//rotates the background to: current rotation + supplied angle
void bgRotate(int id, int angle);
 
//sets the scale for the supplied background
void bgSetScale(int id, fixed_8 sx, fixed_8 sy);
 
//scales the background by the supplied value
void bgScale(int id, fixed_8 sx, fixed_8 sy);
 
/////////////////higher (slightly) level functionality/////////////////////
 
//loads a background palette into the backgrounds palette (Smart enough to use extended palette if selected)
void bgLoadPalette(int id, u16* pal, int paletteId, int colorCount);
 
//load gfx for a background at the supplied offset 
void bgLoadGfx(int id, u16* gfx, int size);
 
//handles loading of a map into the current background at the supplied offset (relative to the supplied map) 
void bgLoadMap(int id, u16* mapData, int width, int height, int offx, int offy));
 
//this will scroll the loaded map using the allready provided background
void bgScrollMap(int id, int dx, int dy);
 
//sets the map offset to the absolute coordinates supplied
void bgSetScrollMap(int id, int x, int y);
Sample Usage

Code: Select all

//---------------------------------------------------------------------------------
int main(void) {
//---------------------------------------------------------------------------------
 
	int bg0;
	int bg1;
 
	int ix, iy;
 
	int scrollx = 0;
	int scrolly = 0;
 
	consoleDemoInit();
 
	irqInit();
	irqEnable(IRQ_VBLANK);
 
	videoSetMode(MODE_0_2D);
 
	vramSetBankA(VRAM_A_MAIN_BG);	
 
	bg0 = bgCreateMain(0, BgType_Text, 64, 32, 2, 1);
	bg1 = bgCreateMain(1, BgType_Text, 64, 32, 0, 1);
 
	bgLoadPalette(bg0,Map_1Pal, 256);
	bgLoadGfx(bg0, Map_1Tiles, Map1TileLen);
	bgLoadMap(bg0, Layer_1Map, 64, 64, 0, 0);
 
	//dont need to load tile graphics or pal for bg1 because these resources are shared with bg0
	//we dont need to load the map because we do bg1 manually for illistration
 
	while(1) 
	{
		u16* bg1map = (u16*)bgGetMapPtr(bg1);
 
		scanKeys();
 
		u32 keys = keysHeld();
 
		//use high level to scroll bg0
		if(keys & KEY_UP)    {bgScrollMap(bg0, 0,-1)}
		if(keys & KEY_DOWN)  {bgScrollMap(bg0, 0, 1)}
		if(keys & KEY_RIGHT) {bgScrollMap(bg0, 1, 0)}
		if(keys & KEY_LEFT)  {bgScrollMap(bg0,-1, 0)}
 
 
		//user our own scrolling logic to scroll bg1
		if(keys & KEY_UP)    {scrolly--;}
		if(keys & KEY_DOWN)  {scrolly++;}
		if(keys & KEY_RIGHT) {scrollx--;}
		if(keys & KEY_LEFT)  {scrollx++;}
 
		bgSetScroll(bg1, scrollx & 7, scrolly & 7);
 
		//a simple (unhealthy) redraw everything scroll engine:
		for(iy = 0; iy < 32; iy++)
		{
			for(ix = 0; ix < 33; ix++)
			{
				int mx = (ix + (scrollx / 8)) % (64);
				int my = (iy + (scrolly / 8)) % (64);
 
				if(ix != 32)					
					bg1map[ix + iy * 32] = 	Layer_2Map[my * width + mx];
				else
					bg1map[32*32 + iy * 32] = 	Layer_2Map[my * width + mx];
			}
		}
	}
 
	return 0;
}

Orkie
Posts: 10
Joined: Thu Oct 25, 2007 11:54 pm
Location: UK

Re: RoadMap Discussion

Post by Orkie » Thu Nov 15, 2007 5:10 pm

I'm for a bit more if it won't (and I know it won't) affect me, though I do wonder if there is a point where you have to be "cruel to be kind" and have to just force people to learn how to do something rather than just making it ever easier.
<Erant> If you wipe your ass with a piece of paper with GPLed sourcecode on it, you have to make your poo public domain.

Quirky
Posts: 19
Joined: Thu Nov 15, 2007 8:45 pm

Re: RoadMap Discussion

Post by Quirky » Thu Nov 15, 2007 9:14 pm

I think if done right this would be a good idea.

I imagine that most libnds users end up rolling their own versions of all of those at some point anyway (I know I have, mostly based on GBA experience). Having debugged versions would be a bonus since I know there are things I'm missing or that may be buggy. Ah, and take care with the licensing. i.e. not the usual homebrew "roll my own GPL-incompatible licence", i.e. something like LGPL + static linking clause, MIT, BSD, etc. It would have to not link in code that didn't use it, of course to keep the "bloat" critics quiet. i.e. plenty of .o files.

Other stuff that would have their uses: alpha blending, sleep mode, sprite stuff; copyOam, moveSprite, rotateSprite, scaling, mosaic... Release early, release often remember. So when's the first release? :-)

dovoto
Developer
Posts: 43
Joined: Fri Aug 12, 2005 10:01 pm
Contact:

Re: RoadMap Discussion

Post by dovoto » Thu Nov 15, 2007 11:19 pm

...and take care with the licensing
This will be part of libnds and as such will fall under its licensing scheme.
of course to keep the "bloat" critics quiet. i.e. plenty of .o files.
Much (most I would hope) of this functionality will be implemented via static inline functions. What is not will be separated by affected area (background control is the only section currently but might later include other systems)
Other stuff that would have their uses: alpha blending, sleep mode, sprite stuff; copyOam, moveSprite, rotateSprite, scaling, mosaic...
This current iteration is dealing strictly with background control and as such the sprite stuff will have to wait...sprites are very tricky to do in a generic manner while maintaining the flexibility of the DS hardware. Mosaic and alpha effects on backgrounds would be good additions (scaling of backgrounds is already included).
So when's the first release? :-)
Implementation of the interface is rather trivial for the most part, however I am not yet certain this is the best approach or even significantly better than the current bit define approach being employed. Once I have a bit more feedback, (assuming that feedback is not compellingly negative nor suggests a drastically different and better approach) I will implement and release. My hope is to have something rolled into the library in the next week.
though I do wonder if there is a point where you have to be "cruel to be kind" and have to just force people to learn how to do something rather than just making it ever easier.
I imagine this will be the main argument against a higher level approach and as such I would love to hear a few more responses along this line. If anyone is willing to expound upon how the current more challenging way is a better approach to low level programming than one which abstracts the hardware I think it would add much to the discussion.

Personally, I feel the approach I am working on has the following advantages/disadvantages over the current direct register access via bit defines:

Advantages
--more readable
--easier to remember (I wrote most of the libnds bit defines and I still can't do much with a background without looking up each define in the headers)
--easier to document
--easier to teach in a tutorial
--Not as much knowledge about backgrounds is needed to get started.
--A bit more friendly to auto code-completing IDEs

Disadvantages:
--Some of the detail will be hidden behind the API (such as background rotation, alpha blending, scrolling)
--Some functionality might be unseemly to implement with this method and require direct register access.
--It might lead to a lack of understanding of how DS hardware is controlled as it hides the direct register access from the user

To answer some of the disadvantages:
--Most of the functionality boils down to little more than macros which wrap register access. Very little high level code will be employed and in situations such as rotation and scaling of backgrounds where it makes sense to do things behind the scenes we can document the process.
--Nothing really comes to mind which might be suitable for enumeration in the interface but difficult to implement. This is not going to be a very high level API such as PALIB
--I am not sure how important it is for a person to realize exactly which bits of which registers are being manipulated in order to understand how things work. As long as they understand there ARE registers which control the system they should be able to reference the tech documents (gbatek or libnds header files).

For those individuals who are very new to console development seeing code which works via direct register access will be of little use unless some one or some document explains the process. Without some level of documentation of how the library works people will be left without a good understanding of how the hardware works.

Coming from the perspective of someone who has written a few tutorials on the matter, having an approach which is easier to document and which results in easier to read code will hopefully result in a more understandable description of operation and should lead to a better understanding of the hardware. This is assuming the interface corresponds directly to the operation of the hardware which is my goal.

Orkie
Posts: 10
Joined: Thu Oct 25, 2007 11:54 pm
Location: UK

Re: RoadMap Discussion

Post by Orkie » Fri Nov 16, 2007 12:59 am

I do agree that for a beginner, using functions is certainly much easier to understand since it's what their book teaches. The concept of using a 'variable' (which is how they will see it) as a function will be a mystery, and the same for bitwise operators. However, should an absolute beginner be learning to program on the DS? It's hardly a 'standard' platform. I think it would be a good to have some abstraction to get people into the swing of things and getting a general feel for the way things tend work on the DS, and then documentation of some kind to help understand using the registers directly.

People who really aren't capable of understanding the registers could carry on writing reasonably complex things using the functions, but for the others they'll learn a useful skill and be able to move on. Like I said before, I don't feel something like the DS is a suitable platform for somebody starting out in C - only those who are reasonably competent already should be trying something so different from the norm, and these are people who I would hope are mostly ready to move forward a step.

"--more readable"
I think that's more down to preference, I find functions quite ugly :D.

"--easier to remember"
True.

"--easier to document"
The registers are already documented so that's a bit of a non-issue in my mind. It probably is much easier to teach functions in a tutorial then registers, as I have said above.

"--Some of the detail will be hidden behind the API (such as background rotation, alpha blending, scrolling)"
I don't see this as a problem really if I'm understanding your right. Most of the little odds and ends ignored by the API will only be needed by more advanced code, in which case they can just use a couple of registers to do the rest.

"--Some functionality might be unseemly to implement with this method and require direct register access."
Nothing you can do about that. It's certainly not worth worrying about :).

"--It might lead to a lack of understanding of how DS hardware is controlled as it hides the direct register access from the user"
I don't think total beginners will really care, and anybody else should be able to get at least an overview which can't be a bad thing. I used to use SDL on the GP2X - it got me used to the way of working so I could start doing things for myself a bit later.
<Erant> If you wipe your ass with a piece of paper with GPLed sourcecode on it, you have to make your poo public domain.

DesktopMan
Developer
Posts: 4
Joined: Fri Aug 12, 2005 2:01 pm

Re: RoadMap Discussion

Post by DesktopMan » Sat Nov 24, 2007 5:32 am

Hey Dovoto. I haven't been around for a long time, might be more active in the upcoming months.

Your access interface seems simple and to the point, but I'm wondering how you will handle illegal values for size etc? With such specific hardware limitations it might be difficult to provide the user with enough information about what is possible and not. (assuming they don't read the docs, which they don't)

dovoto
Developer
Posts: 43
Joined: Fri Aug 12, 2005 10:01 pm
Contact:

Re: RoadMap Discussion

Post by dovoto » Sat Nov 24, 2007 9:37 pm

Actually, if debug is enabled all values are currently range checked and asserted on error. If the user attempts something impossible a description of why pops up and the program exits.

Is this what you had in mind or were you looking for something else?

DesktopMan
Developer
Posts: 4
Joined: Fri Aug 12, 2005 2:01 pm

Re: RoadMap Discussion

Post by DesktopMan » Sat Nov 24, 2007 9:41 pm

Yes, I'm curious on how wrong use of the library will be handled now that libnds moves from low to middle level functionality. I don't have a strong opinion how it should be done, only wishing that it's consistent across all functionality and well documented.

TeenDev
Posts: 3
Joined: Sat Mar 15, 2008 9:16 pm

Re: RoadMap Discussion

Post by TeenDev » Sat Mar 15, 2008 9:27 pm

This actually makes me want to use libnds again. The only reason I switched to PA_lib was I hated the complicated graphics system in libnds. IF you do this right DS Dev will become much easier.

RaiDesu
Posts: 1
Joined: Sun Mar 16, 2008 3:32 am

Re: RoadMap Discussion

Post by RaiDesu » Sun Mar 16, 2008 3:40 am

Adding a little more might be good. Personally, I wouldn't want to use PA_Lib at all, since it always seems to break my devkitARM install.

Post Reply

Who is online

Users browsing this forum: Google [Bot] and 4 guests