NES lookalike graphics

A place for your artistic side. Discuss techniques and tools for pixel art on the NES, GBC, or similar platforms.

Moderator: Moderators

tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: NES lookalike graphics

Post by tepples »

Dendy and other PAL famiclones have the same capability as NES in this respect. Games that draw primitives, such as points, lines, and ellipses, do so by plotting pixels into tiles for the PPU to display.
  • Videomation and CrossPaint are paint programs letting the player draw arbitrary primitives.
  • Qix lets the player draw fences over a playfield, much like an Etch-A-Sketch art toy. When the player divides the floor in two with a fence, the game fills in pixels on the side farther from the enemy.
  • Elite is a space trading game with wireframe vector graphics. The released version relies on PAL NES PPU timing but could be ported to Dendy with little trouble if lead developer David Braben wanted to. Elite co-developer Ian Bell also produced Tank Demo, a tech demo of a Battlezone clone using the same principle as Elite.
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

Thank you so much for the answer! Could you give an example of code that draws a line or at least a dot on the screen? I started studying cc65 for NES but I don't understand yet how to draw a point with certain coordinates. Maybe it needs to be done in assembler?
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: NES lookalike graphics

Post by lidnariq »

The NES, by default, does not provide enough video memory to draw arbitrarily single pixels.

(Math: 256 × 240 pixels × 2 bits per pixel ÷ 8 bits per byte = 15360 bytes)

This is why Elite and Color a Dinosaur have so much empty space: they only have 8192 bytes for all the lines they've drawn, and so they fill most of the screen real estate with blank.

So your options, in order of increasing software complexity, are:
1- Don't draw arbitrary single pixels. Instead, use a fixed library of tiles made up of multiple native pixels, like the Game Genie software does. (The Game Genie's library of tiles is the 16 combinations of 4x4 pixel squares in each corner.)
2- Use extra hardware on the cartridge to permit addressing more video memory, like mappers 13 or 96, or change the interpretation of the video memory to 1bpp, like mapper 371.
3- Dynamically allocate tiles as you draw single pixels, keeping track of both the tilemap and the tiles, and update both. This is what commercial software did, due to the other options being too coarse or too expensive.
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

It means to operate only 4x4 pixels and only ready-made sprites. I am saddened :о(
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

But how so? Only Videomation knows how to do it?
Attachments
draw.jpg
Catyak
Posts: 54
Joined: Mon Apr 25, 2022 4:33 pm

Re: NES lookalike graphics

Post by Catyak »

Cyrix wrote: Sun Dec 25, 2022 8:14 am But how so? Only Videomation knows how to do it?
Because Videomation is one of the exceptions that uses a mapper (in this case, Mapper 13) to increase the amount of VRAM the NES can use.
Videomation uses 16k of additional VRAM in the cartridge, which is then addressed as 4 kilobyte banks (because the NES can only see 8 kilobytes of graphics data from the cartridge at one time, and Videomation uses half of that space to point to a single fixed bank) that are swapped multiple times during display to bypass the NES's limitation of 256 characters in a tile map. (In this case, the tilemap is composed mainly of the 256 tile values repeated multiple times in different sections, and the VRAM banks are swapped so those values point to different tiles for each section of the "virtual" framebuffer)
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

Okay, let's say I invent a NES-CPROM board, how do I program a color dot on the screen?
Catyak
Posts: 54
Joined: Mon Apr 25, 2022 4:33 pm

Re: NES lookalike graphics

Post by Catyak »

Cyrix wrote: Sun Dec 25, 2022 11:25 am Okay, let's say I invent a NES-CPROM board, how do I program a color dot on the screen?
If you wanted to put a dot on screen, you would need to both follow these same steps on almost any other CHR-RAM (CHR-RAM means external graphics VRAM in NESdev lingo) NES board, including modern ones like UNROM-512, and some specialized steps for the NES-CPROM board. This assumes you have code that initializes the system first, before doing this.

You'd set up a palette with the colors and a tile map that contains an entry for the tile you want to write to that is set to the correct palette, and during vertical blank, you'd start by write tile data to the CHR-RAM by first setting up the PPU data address to point to the tile you want to change. (through writing the PPU address register PPUADDR twice, to write two 8 bit halves of the 16 bit PPU address)

Then (still during vertical blank), you would write the graphics data using the PPUDATA register, making sure to write to both of the tile's bit planes.

The unique part for the NES-CPROM board, if you're writing a function that plots a dot anywhere on a screen set up like Videomation, is that before writing the graphics data, you need to write the CHR-RAM mapping register to select the CHR-RAM bank that corresponds with the region of screen you want to draw to.

Keep in mind that, as with all programmable tile map or character map displays, on the NES with any CHR-RAM board you can easily plot a single dot anywhere on screen, but if you want to draw hundreds of dots randomly across the screen you'll likely run into the 256 character limit of the NES (that other early tile/character map systems like the VIC-20 also have) and will need a board that can bypass that limit by banking CHR-RAM, like the NES-CPROM board or the modern UNROM 512 board.
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

How can a tail be rewritten pixel to VRAM? For example: before drawing a sprite from tiles, I change the pixels in an 8x8 tile, save and output the sprite. How to do it?
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: NES lookalike graphics

Post by tokumaru »

Do you mind telling us what exactly you're trying to make for the NES? I'm asking because plotting pixels is not something the NES was designed to do, so it's a very slow process that's hard to integrate into an actual game.

While the basic idea behind it doesn't change much, depending on how fast or dynamic you need things to be, we might have different suggestions on how to approach this task.

Do you know how to use tiles in a normal NES program? A program where you can manipulate the tiles is exactly the same, you still have to setup the name tables, attribute tables, palettes and OAM in order to make the NES draw the tiles, but since you're using CHR-RAM, you can edit the tiles as the program runs. Whenever you modify a tile in the pattern tables, all instances of that tile used in the background or on sprites will automatically change.

If you just want a "blank canvas" to draw pixels on, the first thing to do is to setup the name table to use tiles 0, 1, 2, 3, 4, etc. all the way up to 255. If your "canvas" is bigger than 256 tiles, you're gonna need extra VRAM, and raster effects to swap the patterns mid-screen. Don't forget to also setup the corresponding attribute table to assign palettes to the tiles, and the palette itself.

Once the background is all set up, you can start updating the pattern table to draw pixels. The exact formula to calculate the address of the tile to change will vary depending on the size and position of your "canvas", so I need you to tell me more about your project in order to provide more useful information. The general idea is that you use the higher bits of the pixel's X and Y coordinates to calculate the address of tile that needs to be updated, the 3 lowest bits of the Y coordinate to select a line in that tile, and the 3 lowest bits of the X coordinate to select bitmasks that can be used to manipulate the bits/pixels in that line.
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

The idea is this: I want to create an application with primitive pseudo 3D objects that can be zoomed in, rotated, and zoomed out. Objects should be as primitive as possible, from straight lines. For example, a person draws a rectangle of lines, and the program zooms out or zooms in on this object. It also gives the impression that this is a 3D object, because it can also spin.
Attachments
screen.jpg
NR50.gif
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: NES lookalike graphics

Post by tokumaru »

I see... so it's basically wireframe 3D then, like in Elite? I guess you can prototype it using basic pixel and line drawing code, and optimize later if you need more speed.

In the simplest possible case (no obscure mappers, raster effects or other extra things to worry about), you'd have a 16x16-tile reagion somewhere in the name table, whith tiles numbered 0 through 255, from left to right, top to bottom. This is a 128x128-pixel region, so coordinates will range from 0 to 127, so 7 bits each:

X coordinate: *XXXXxxx
Y coordinate: *YYYYyyy

The upper case bits will be used to locate the tile that needs to be edited, while the lower case bits will be used to locate the pixel.

To calculate the address of the tile, you must shift and combine the bits into the following format: YYYYXXXX0000

NES tiles are 2bpp, and they're stored as 2 consecutive 1bpp tiles, so first you'll see the 8 lines of the first plane, then the 8 lines of the second plane. The yyy bits will tell you which of the 8 lines you have to change. For example, if yyy is %101 (5), you'll have to change 1 bit in the 5th byte of plane 0, and 1 bit in the 5th byte of plane 1, in order to draw a complete pixel.

Here's a straightforward subroutine in assembly that will write a pixel anywhere on a 16x16-tile (128x128-pixel) region:

Code: Select all

DrawPixel:

;X = pixel X (0 to 127)
;Y = pixel Y (0 to 127)
;A = pixel color (0 to 3)

  ;saves the inverted color for later
  eor #$ff
  sta PixelColor

  ;calculates the low byte of the pointer to the tile
  txa
  and #%01111000
  asl
  sta Pointer+0

  ;calculates the high byte of the pointer to the tile
  tya
  and #%01111000
  lsr
  lsr
  lsr
  ora #>PatternBuffer
  sta Pointer+1

  ;gets the position of the line within the tile
  tya
  and #%00000111
  tay

  ;gets the position of the pixel within the line
  txa
  and #%00000111
  tax

  ;creates a byte with bit 0 of the color in the correct position
  lda #$00
  lsr PixelColor
  adc #$ff
  and PositiveMasks, x
  sta PixelPlane0

  ;creates a byte with bit 1 of the color in the correct position
  lda #$00
  lsr PixelColor
  adc #$ff
  and PositiveMasks, x
  sta PixelPlane1

  ;updates the tile's first plane
  lda (Pointer), y
  and NegativeMasks, x
  ora PixelPlane0
  sta (Pointer), y

  ;updates the line index to access the second plane
  tya
  ora #%00001000
  tay

  ;updates the tile's second plane
  lda (Pointer), y
  and NegativeMasks, x
  ora PixelPlane1
  sta (Pointer), y

  ;returns
  rts

PositiveMasks:

  .byte %10000000
  .byte %01000000
  .byte %00100000
  .byte %00010000
  .byte %00001000
  .byte %00000100
  .byte %00000010
  .byte %00000001

NegativeMasks:

  .byte %01111111
  .byte %10111111
  .byte %11011111
  .byte %11101111
  .byte %11110111
  .byte %11111011
  .byte %11111101
  .byte %11111110
Note that this is editing a buffered copy of the tiles in RAM (PatternBuffer), which can be accessed at any time. To actually see the changes you have to upload the buffered data to VRAM during vblank or forced blanking. Updating all 256 tiles takes a lot longer than the duration of vblank, so you will have to spread the update across multiple frames.

Also note that drawing anything with this code will be incredibly slow.
Last edited by tokumaru on Tue Dec 27, 2022 12:15 pm, edited 1 time in total.
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

void main (void) {
All_Off(); // turn off screen
X1 = 0x7f; // starting position of the top left sprite
Y1 = 0x77; // near the middle of screen
Load_Palette();
Reset_Scroll();
All_On(); // turn on screen

while (1){ // infinite loop
while (NMI_flag == 0); // wait till NMI

Code: Select all

//I can't figure out how to insert assembler code here?

NMI_flag = 0;
}
}
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

Code: Select all

lda (Pointer), y
What should be in Pointer?
Cyrix
Posts: 12
Joined: Sat Dec 24, 2022 4:54 pm

Re: NES lookalike graphics

Post by Cyrix »

added #include "nes.h" and error while compiling
"This module may only be used when compiling for the NES!"
Post Reply