It is currently Fri Apr 28, 2017 7:05 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Sat Dec 31, 2016 1:00 pm 
Offline

Joined: Sun Dec 18, 2016 1:11 pm
Posts: 20
What I (think I) understand about the basic CHR format, not counting setting colors, for the standard 2BPP NES format, from hex viewing:
Each byte acts like a vertical bitflag, e.g. 0 = nothing there, 1 = pixel on 1st row, 2 = pixel on 2nd row, 3 = pixel on 1st and 2nd row etc...

And it is repeated for each color every 8(???) bytes. Something like that. But I'm NOT interested in color right now, I just want the shape to be right!

I am attempting to load CHR with this code:
Using the default rotation: 270.

Code:
unsigned char _bit[9];
   _bit[0] = 0x00;
   _bit[1] = 0x01;
   _bit[2] = 0x02;
   _bit[3] = 0x04;
   _bit[4] = 0x08;
   _bit[5] = 0x10;
   _bit[6] = 0x20;
   _bit[7] = 0x40;
   _bit[8] = 0x80;

int _i = 0;

// ...

while (chr.read(&_b, 1)) {
   if (_i <= imgw) {

      std::cout << "#" << _i << ";\n";

      bool bPixel = false;

      for (int _ii=1; _ii<8; ++_ii) {
         bool bPixel = (_bit[_ii] &_b != 0);
         if (bPixel) {
            tile[_ii-1][_i][_b] = 255; // TESTING PURPOSES NO COLOR YET
         }
      }

      std::cout << "\n";

      _i = _i + 1;
   }
}


Works great. For the first row.
Otherwise I just get garbage that is very vaguely reminiscent of a messed up version of the tile.

Can someone clear up a few things on the CHR format? How should I really be loading this? And yes, I know my code is probably horribly written...

I really hope this is the right place to post it. CHR info is kind of scarce.


Top
 Profile  
 
PostPosted: Sat Dec 31, 2016 1:15 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 998
There's a page on the wiki that describes it pretty well, I think.

https://wiki.nesdev.com/w/index.php/PPU_pattern_tables

Each byte represents a row, each bit represents a column. Each tile is 16 bytes.

If a color for a pixel is %XY (two bits)
Bytes 0-7 are the low bit of the color (The Y bit above) for each row/column.
Bytes 8-15 are the high bit of the color (The X bit above).

If you have byte 0 as this: 0 1 0 0 1 1 1 1
If you have byte 8 as this: 0 0 0 1 0 1 0 1

The first row of the tile is: 00 01 00 10 01 11 01 11
or color 0, 1, 0, 2, 1, 3, 1, 3

Then you read byte 1 and and byte 9 to get the second row.
at byte 16, it's a new tile.
Edit:
My code looks a bit like this:
Code:
int decode_chr(int byte1, int byte2, int andvalue){//andvalue is the bitmask
   if(byte1&andvalue){
      if(byte2&andvalue){
         return 3;
      }else{
         return 1;
      }
   }else{
      if(byte2&andvalue){
         return 2;
      }else{
         return 0;
      }
   }
}//Verfied

      for(int x = 0; x < 16; x++){
         for(int y = 0; y < 16; y++){
            bufferpos = x * 16+y*256;
            for(int row = 0; row < 8; row++){
               chrarray[x*8+0][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x80);
               chrarray[x*8+1][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x40);
               chrarray[x*8+2][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x20);
               chrarray[x*8+3][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x10);
               chrarray[x*8+4][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x08);
               chrarray[x*8+5][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x04);
               chrarray[x*8+6][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x02);
               chrarray[x*8+7][y*8+row] = decode_chr(buffer[bufferpos], buffer[bufferpos+8], 0x01);

               bufferpos++;
            }
            
         }
      }


It assumes the CHR is 256 tiles arranged in a grid of 16x16 tiles. Each tile is 16 bytes, so x (column) is multiplied by 16, y is multiplied by 256 (16 columns skips a row of tiles) to set bufferpos, which is the first byte of the tile at the X, Y position. Then it feeds the byte at that location, and the byte 8 bytes ahead to decode chr to get the color, which is placed in an array.

Edit2: I would name your variables things that aren't i and such.
Anyway, this isn't a clever way to do it, and I know it could be condensed. But it does work.

Edit3: Fixed a small error in the explanation.


Last edited by Kasumi on Sat Dec 31, 2016 2:01 pm, edited 3 times in total.

Top
 Profile  
 
PostPosted: Sat Dec 31, 2016 1:30 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
What isn't immediately apparent (because it's hard to depict in ASCII -- but the very top of the wiki page linked there DOES explain it) is that the two "bit planes" are essentially "overlayed" (for lack of better term -- I like to think of them as OR'd when just referring to raw black and white (pixel on, pixel off)) which is what ends up making the colour range from 0-4 (2 bits per pixel, one from each "plane").

The numbers in the "Pixel Pattern" depict what colour to use, ranging from 0 to 3 (again: 2 bits per pixel).

The attribute table (not going to discuss that in depth right now, but just noting this for clarity) is what holds the "remaining" 2 bits, thus making the pixel colour essentially 4 bits, hence values 0 to 15.

Trust me: once you see it/get it, it'll suddenly click and make a whole ton of sense and you'll be thrilled.


Top
 Profile  
 
PostPosted: Sat Dec 31, 2016 2:04 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 9542
Location: Rio de Janeiro - Brazil
ittyBittyByte wrote:
Each byte acts like a vertical bitflag, e.g. 0 = nothing there, 1 = pixel on 1st row, 2 = pixel on 2nd row, 3 = pixel on 1st and 2nd row etc...

And it is repeated for each color every 8(???) bytes.

Where did you get this information from? That doesn't sound anything like NES patterns. Maybe you were reading about the compression format used by an NES game and mistook it for the format the PPU itself uses? If that's the case, you don't have to worry about game-specific compression formats, because the games themselves will take care of decompressing them to the format the PPU expects.

Quote:
CHR info is kind of scarce.

You probably won't find much information about it because the format is pretty straightforward and well documented. There's just not much to say about it.


Top
 Profile  
 
PostPosted: Sat Dec 31, 2016 2:37 pm 
Offline

Joined: Sun Dec 18, 2016 1:11 pm
Posts: 20
I got that information by using a hex editor, messing in YY-CHR, and saving over and over. Because on a blank CHR when I set pixel 0,0 to color 1 the first byte became 01, when I set pixel 0,1 to color 1 the first byte became 2, and when I set 0,0 and 0,1 to color 1 it became 3. Then I figured out that setting only 0,8 to color 1 made the first byte the hex equivelant 127 (or maybe it was 128, dont remember). And setting all pixels from 0,0 to 0,8 in a column of pixels to color 1 gave me FF for the first byte. So I assumed it worked like some sort of bit flag thing. I knew it was probably wrong though...


Top
 Profile  
 
PostPosted: Sat Dec 31, 2016 3:38 pm 
Offline
User avatar

Joined: Mon Feb 07, 2011 12:46 pm
Posts: 882
This is part of a program I wrote which can do this. The value of "parameter" needs to be 8 for use with NES/Famicom.
Code:
static int initpixel_F2(void) {
  if(!parameter) parameter=1;
  buf=calloc(2,curbyte=parameter);
  return !buf;
}

static int getpixel_F2(void) {
  int i;
  if(curbyte==parameter) {
    curbyte=rowpos=0;
    fread(buf,2,parameter,stdin);
  }
  i=buf[curbyte]&128?1:0;
  i|=buf[parameter+curbyte]&128?2:0;
  buf[curbyte]<<=1;
  buf[parameter+curbyte]<<=1;
  if(++rowpos==8) {
    rowpos=0;
    curbyte++;
  }
  return i;
}

_________________
.


Top
 Profile  
 
PostPosted: Tue Jan 03, 2017 1:55 pm 
Offline

Joined: Sun Dec 18, 2016 1:11 pm
Posts: 20
Thanks guys, I got it to work by messing with Kasumi's code for 7 hours... :P


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group