So I've got off the ground.

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

So I've got off the ground.

Post by N64VSNES »

Hey guys I've been looking into dreamcast devving some more and I think I've made a lot of progress. I've learned about PVR, and some KGL as well as how the dreamcast handles things and loads things.

I've gotten a application to load and display some colored polygons nicely but I need to now move on to *gulp* texture mapping.

I've learned a fair bit about it so far but I've had no luck getting it to work. All of the examples seem to use "romdisks" and from what I've heard they are basically just a folder of content that gets initialized and you can just grab stuff from it.

From the examples I see lines like this:

Code: Select all

png_to_texture("'/rd/whatever.png");
I *guess* the "/rd/" means "r- rom, d- disk" so just loading a file directly from the disc would be "/cd/whatever.png"?

So I'm looking at the simplest way I can just load a texture from the disc into memory using PVR. I've looked through examples and stuff and I've looked around this forum for people with similar problems but I still can't get it to work.

Can somebody help me out with understanding how this all works? Do I and can I just grab data from the disc? Do I need to load a romdisk? is the romdisk loaded to memory when initialized? Do I need a pvr_dr_state_t object and write directly to the buffer for this? etc

Thanks and any help is really appreciated.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

First of all: moved to Programming Discussion...
N64VSNES wrote:I've learned a fair bit about it so far but I've had no luck getting it to work. All of the examples seem to use "romdisks" and from what I've heard they are basically just a folder of content that gets initialized and you can just grab stuff from it.
The romdisks in all the examples get linked into the binary at compile time. You can also make romdisks that you can mount and unmount at will at runtime, but that's a different story. That functionality is useful for, for instance, loading a whole level's worth of data in multiple files easily.
From the examples I see lines like this:

Code: Select all

png_to_texture("'/rd/whatever.png");
I *guess* the "/rd/" means "r- rom, d- disk" so just loading a file directly from the disc would be "/cd/whatever.png"?
Yes, if you want the file called "whatever.png" in the root of the CD.
So I'm looking at the simplest way I can just load a texture from the disc into memory using PVR. I've looked through examples and stuff and I've looked around this forum for people with similar problems but I still can't get it to work.

Can somebody help me out with understanding how this all works? Do I and can I just grab data from the disc? Do I need to load a romdisk? is the romdisk loaded to memory when initialized? Do I need a pvr_dr_state_t object and write directly to the buffer for this? etc
Look at the PNG example (kos/examples/dreamcast/png/example.c) that's included with KOS. It should show you everything you need to know to get started. If you need more help than that, ask, and I'm sure someone will be able to help out.

You might want to check out the "Thread links for DC programmers" topic for a wide range of things. That's here: viewtopic.php?f=29&t=100002
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

Apologies for the wrong area, I wasn't sure which it would be.

I'm mainly just trying to cover some stuff I can't deduce from the examples. So what's the difference between the bin and elf file? I noticed the elf is larger and that's the one I normally convert to a scrambled binary. Should I be doing it this way?

Also suppose I have a "Data" romdisk that contains say 100MB- Would this be an issue? I like the idea of the romdisk's but I'm not sure if they get loaded into memory or they're just being prepared to be loaded into memory?

Thanks.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

First of all, on the difference between elf and bin. The elf file is what the compiler outputs. It contains symbol tables and debugging symbols that are quite useful in debugging problems. The bin file is a raw binary image that is exactly what would get loaded into memory. In the end, the "elf2cdi" and other scripts like that end up converting the elf to a bin as a part of the process, since scrambling an elf wouldn't help much at all. The scrambled binaries are simply scrambled versions of the bin file.

With regard to the romdisk size. You cannot have a romdisk that is bigger than the available RAM. The entire thing must fit into memory in order for KOS to use it at all. So, assume your program is 1MB in its raw binary form, and you allocate at most 5 MB of data between malloc/calloc/new and any static allocations. You'd roughly have 10MB left, give or take (other factors come into play, so expect slightly less than that). You only have a total of 16MB of RAM available for general use on the Dreamcast.
User avatar
Neoblast
DC Developer
DC Developer
Posts: 314
Joined: Sat Dec 01, 2007 8:51 am
Has thanked: 3 times
Been thanked: 1 time

Re: So I've got off the ground.

Post by Neoblast »

If your programs fits barely in ram or it crashes ( kernel panic : out of memory ) there's always a last resort option and that's disabling the debug in kos, you can get up to 3-4 MBs this way BUT some memory allocation *might* stop working ( not sure about that last part But I remember reading about it and having some problems in ports when disabling it, but only rare cases )
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

Thanks for the helpful links and supports guys!

I've been exploring all options and I'd like to use the SDL image library for loading images (I believe it actually uses libpng anyway) I've gotten it to compile and link perfectly fine but if I try to load anything it will just crash.

Here is what I've been trying to do:

Code: Select all

void Setup() {
	pvr_init_params_t init_params = {
	{ PVR_BINSIZE_16, PVR_BINSIZE_0, PVR_BINSIZE_16, PVR_BINSIZE_0, PVR_BINSIZE_16 }
		, 512 * 1024
	};
		
	vid_set_mode(DM_640x480,PM_RGB565);
	pvr_init(&init_params);
	
	surf = IMG_Load("/cd/Test.png");
	if ( surf == NULL ) {
		printf("ERROR ALLOCATING TEXTURE!\n");
	}
	else {
		printf("Allocated texture successfully!");
	}
	d_texture = pvr_mem_malloc(surf->w * surf->h * 2);
	pvr_txr_load_ex(surf->pixels, d_texture, surf->w, surf->h, PVR_TXRLOAD_16BPP);
}
Am I doing something wrong or is SDL_image out of the question for dreamcast?

If I comment out this line:

Code: Select all

surf = IMG_Load("/cd/Test.png");
Then it runs fine, I'm sure the "surf" variable isn't getting touched until after this point and I get no output from the if statements so it must be crashing right on that line.

Thanks.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

Why would you want to use SDL_image if you're not using SDL? That's just kinda silly when you have the functionality that you need already in KOS' libpng, if you ask me.

Also, I'd avoid SDL like the plague. It only seemed to cause me more troubles than it was worth in the end on the Dreamcast.
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

I figured since it's a C library and it internally uses libpng it would cut out all the hassle with C file pointers (not used C itself for years)

All this crap you need just to get details about the image such as width, height, color depth, etc. I noticed a lot of people just pass these in by parameter and hardcode it but I like to keep this stuff under a level of abstraction.

If you really think libpng itself is way to go then that's the way I'll go.

I'll post another update later hopefully I'll have gotten it working :grin:

One more question though just to give this post some relevance:
In a emulator the PVR borders don't show at all but on my TV (not flat screen or LCD or HD or anything fancy) only the border to the right of the screen are shown. I tested it on a bigger TV and some of the top and bottom are shown as well, does PVR or the KOS have some sort of functionality to make the buffer "scale" to fit the screen? I guess this is just resolution problems?
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

If you want something to wrap things up nicely in a neat little package (reading in the width/height and all that), all of KOS' PNG loading code will do that for you (assuming you use png_to_img, png_load_texture, or png_to_texture). In addition, the first two of those will give you back the width and height as a part of the loading process in some way. Also, png_to_img acts a lot like SDL_image, returning you a nice wrapped package that has information about the image in a structure that's fairly easy to deal with.

The main reason for not using SDL_image (other than the fact that it relies on SDL, partially) is that it won't convert images by default from 32bpp (what they'll likely be read in as) to 16bpp as you'll need to do for using them as textures. KOS' libpng will handle all that for you automatically.

As for the question about the PVR. You probably don't want to mess with the border areas. You could play with the video init and all that to set register values that'll work for your TV, but don't count on them working right on other people's TVs. As you've seen each TV is different, and there's no way to detect what parts of the border will show on a given TV.
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

Okay I've got another problem it would seem.

I'm trying to make a basic library to handle this stuff behind the scenes just as something to work on instead of a lot of test programs.

I noticed that pvr_poly_hdr_t and pvr_poly_cxt_t need to be declared in the same scope as your infinite loop and be redeclared every frame.

So I can't do:

Code: Select all

bool Loop() {
     pvr_poly_hdr_t hdr;
     pvr_poly_cxt_t cxt;
     // etc
     return true
}
while(Loop()) {
//blah
}
but I can do:

Code: Select all

while(1) {
     pvr_poly_hdr_t hdr;
     pvr_poly_cxt_t cxt;
     // etc
}
I looked further into the problem and it looks like I could use pvr_dr_state_t and write it directly to the buffer? (correct me if I'm wrong)

This works like a treat so far but it crashes when it hits my new rendering code just for a polygon without texturing:

Code: Select all

void VideoSystem::Initialize() {
	// Set up the parameters
	pvr_init_params_t init_params = {
	{ PVR_BINSIZE_16, PVR_BINSIZE_0, PVR_BINSIZE_0, PVR_BINSIZE_0, PVR_BINSIZE_0 }
		, 512 * 1024
	};
	vid_set_mode(DM_640x480,PM_RGB565);
	pvr_init(&init_params);

	pvr_poly_cxt_t cxt;

	pvr_poly_cxt_col(&cxt, PVR_LIST_OP_POLY);
	cxt.gen.shading = PVR_SHADE_FLAT;
	pvr_poly_compile(&hdr, &cxt);

}

bool VideoSystem::Loop() {
	pvr_wait_ready();
	pvr_scene_begin();
	
	pvr_list_begin(PVR_LIST_OP_POLY);
	pvr_prim(&hdr,sizeof(hdr));

	pvr_dr_init(dr_state);
	return true;
}

void VideoSystem::Flip() {
	pvr_list_finish();
	pvr_scene_finish();
}

void VideoSystem::DrawPolygon(Rectangle *p) {

	pvr_vertex_t *vert;

	vert = pvr_dr_target(dr_state);
	vert->flags = PVR_CMD_VERTEX;
	vert->x = p->x;
	vert->y = p->y + p->w;
	vert->z = 1.0f;
	vert->u = vert->v = 0.0f;
	vert->argb = 0xff0000ff;
	vert->oargb = 0;
	pvr_dr_commit(vert);

	vert = pvr_dr_target(dr_state);
	vert->y = p->y;
	vert->x = p->x;
	vert->argb = 0xff00ff00;
	pvr_dr_commit(vert);

	vert = pvr_dr_target(dr_state);
	vert->x = p->x + p->w;
	vert->y = p->y + p->h;
	vert->argb = 0xff000000;
	pvr_dr_commit(vert);

	vert = pvr_dr_target(dr_state);
	vert->flags = PVR_CMD_VERTEX_EOL;
	vert->y = p->y;
	vert->x = p->x + p->w;
	vert->argb = 0xffff0000;
	pvr_dr_commit(vert);
}
As much as I hate posting code I don't want to leave anything out I think may be important.

Here is what I'm doing in my main:
void Program::Run() {
Eternal::Rectangle r;
r.x = r.y = 200;
r.w = r.h = 128;

while(VideoSystem->Loop()) {
VideoSystem->DrawPolygon(&r);
VideoSystem->Flip();
}
}

Forget about it being Program::Run() it's a design that I could get VERY off topic by going into details with.

Thanks.

EDIT:
To be more specific it crashes when I call DrawPolygon()
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

I don't think it should cause a crash, but you haven't filled in part of your vertices (although, I suppose it could screw with the PVR's state, which would in all likelihood look like a crash). When using the dr stuff, you should always fill in all parts of the vertex, even those that do not change from vertex to vertex, since you're switching between the two store queues as you write data.

The pvr_dr_target macro actually modifies the "pointer" passed in to push you over into the next store queue, just so you know.

I would recommend getting something up and running using the normal pvr_prim() stuff rather than the dr stuff for a first pass. Unless you're going to be pushing a whole lot of polygons really quick, there's no real reason to use the dr stuff anyway.

For instance, instead of doing what you're doing with DrawPolygon, try this instead (note, I haven't tried this, but it looks sane enough):

Code: Select all

void VideoSystem::DrawPolygon(Rectangle *p) {
   pvr_vertex_t vert;

   vert.flags = PVR_CMD_VERTEX;
   vert.x = p->x;
   vert.y = p->y + p->w;
   vert.z = 1.0f;
   vert.u = vert.v = 0.0f;
   vert.argb = 0xff0000ff;
   vert.oargb = 0;
   pvr_prim(&vert, sizeof(vert));

   vert.y = p->y;
   vert.x = p->x;
   vert.argb = 0xff00ff00;
   pvr_prim(&vert, sizeof(vert));

   vert.x = p->x + p->w;
   vert.y = p->y + p->h;
   vert.argb = 0xff000000;
   pvr_prim(&vert, sizeof(vert));

   vert.flags = PVR_CMD_VERTEX_EOL;
   vert.y = p->y;
   vert.x = p->x + p->w;
   vert.argb = 0xffff0000;
   pvr_prim(&vert, sizeof(vert));
}
Since this isn't doing the dr stuff, leaving out the extra stuff is fine as it won't change unexpectedly from vertex to vertex.

Also, just as a matter of how I'd do things, I'd store the pvr_poly_hdr_t in your Rectangle class and do the pvr_prim for it in the draw function too. Its safer that way, and extends much more neatly into doing sprites and the like later on.
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

This shizzle is working! :grin:

Thanks guys! Especially you BlueCrab!

EDIT:
One last question: How about color keying? I had to pass a flag for the kos_img which PNG_FULL_ALPHA I guess should be used? So basically how would I go about setting a specific color to full transparency?
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

The easiest way to do it is to set the color to fully transparent in the image data itself. Then use either PNG_MASK_ALPHA (ARGB1555) or PNG_FULL_ALPHA (ARGB4444). If you're just doing either full transparency or full opacity, the first would be better, since you have a larger range of color values left over (15 bits versus 12 bits).

You'll have to put the primitives you draw either in PVR_LIST_TR_POLY or PVR_LIST_PT_POLY if you want the transparencies to work. TR allows full alpha blending, so if you need multiple levels of transparency (i.e, you're going with ARGB4444) use it. PT only does simple all or nothing transparency, so if you're using ARGB1555, use it instead.
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

That all sounds cool apart from:
BlueCrab wrote: set the color to fully transparent in the image data itself
Uh...I don't quite understand. I guess you mean I pass the PVR_MASK_ALPHA or PVR_MASK_FULL_ALPHA and use PVR_LIST_TR_POLY but I'm not sure what you mean about set the color to fully transparent itself.

You mean manually convert all the pixels of that color to have a max alpha value? Because I wouldn't know how that's done in PVR :?
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

N64VSNES wrote:You mean manually convert all the pixels of that color to have a max alpha value? Because I wouldn't know how that's done in PVR :?
Well, you could do it in your image editor (which is the easiest option). Or, you could set up some code to do it when you load the image. I'd recommend the former over the latter though.
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

Ah is it difficult in to do in code? Because I like the idea of having a single color that will automatically be transparent. Some artists prefer this method and it helps when using simple image editing software.

Can't you just loop through each pixel and set its alpha value like that?
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

Yes, you could do that. Everything that you'll get out of KOS' libpng will be 16-bit color, one of RGB565 (PNG_NO_ALPHA), ARGB1555 (PNG_MASK_ALPHA), or ARGB4444 (PNG_FULL_ALPHA). If you're using png_to_img, the data pointer in the kos_img_t structure will be in main RAM, but if you're using either png_to_texture or png_load_texture, it'll be in Video RAM.

Either way, you can modify it where it gets loaded to. Just cast the pointer to a uint16 and then you can set the alpha on each pixel as you see fit. For the PVR, full alpha is opaque, 0 alpha is transparent, so conceptually, you'll have to do something like this (adapt it as needed, completely untested and written off the top of my head):

Code: Select all

void clear_color(void *buf, uint16 color_key, uint16 mask, int w, int h) {
    int i, total = w * h;
    uint16 *ptr = (uint16 *)buf;

    for(i = 0; i < total; ++i, ++ptr) {
        if(*ptr == color_key) {
            *ptr &= mask;
        }
    }
}
In this case, buf would be the pointer to your pixels, color_key would be the value of the color (already changed to the correct color format (ARGB4444 or ARGB1555) with the alpha value set fully, mask would be either 0x7FFF (ARGB1555) or 0x0FFF (ARGB4444), w/h would be the width and height of the image. Note, you can't use this with RGB565, so you still need to load the image with either PNG_MASK_ALPHA or PNG_FULL_ALPHA.

I still have to say, its easier and faster to do it in the image editor. Color keying is something that should've died long ago after we had hardware capable of alpha blending.
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has thanked: 0
Been thanked: 1 time

Re: So I've got off the ground.

Post by BlackAura »

One other thing to be aware of with colour keying - you'll get colour fringing if you distort the image in any way.

For example, your images use magenta as transparent. So, you set all the magenta pixels to transparent (alpha is 0). If you draw the sprite at 2x it's normal size, you'll have this magenta halo around the image, which looks ugly. It's caused by bilinear filtering, which blends adjacent pixels together.

To fix it, you can:

1 - Never rotate or scale your sprites.
2 - Disable bilinear filtering. You can do this by passing the PVR_FILTER_NONE flag to pvr_poly_cxt_txr (instead of PVR_FILTER_BILINEAR or similar), or by changing txr.filter in the pvr_poly_cxt_t struct. It makes the images look kind of pixellated though.
3 - When you set the magenta pixels to transparent, make them black as well.

The last approach is the easiest.
N64VSNES
DCEmu Freak
DCEmu Freak
Posts: 65
Joined: Sun Apr 10, 2011 12:05 pm
Has thanked: 0
Been thanked: 0

Re: So I've got off the ground.

Post by N64VSNES »

That's cool thanks!

When you say the kos_img_t will be in the main RAM, what about when I call kos_load_kimg() will the pvr_ptr_t be stored in the VRAM? :?

I had another problem but I spoke to soon it's fixed! :)

Thanks.
Last edited by N64VSNES on Mon Apr 18, 2011 10:11 am, edited 2 times in total.
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5658
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: So I've got off the ground.

Post by BlueCrab »

Yes, the pvr_ptr_t will be in Video RAM. The only things that are ever returned from any KOS functions as pvr_ptr_t are pointers to Video RAM.
Post Reply