It is currently Sat Dec 16, 2017 4:25 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 30 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Sun Jun 19, 2016 3:24 pm 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2983
Location: Tampere, Finland
Dwedit wrote:
The imagineering games also used DxROM instead of MMC3 since they didn't need IRQs.

Definitely not all of them. Bart vs the World (at least) uses IRQs to blank the bottom of the screen.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
PostPosted: Sun Jun 19, 2016 4:29 pm 
Offline

Joined: Tue Sep 27, 2011 8:20 pm
Posts: 23
One of the things that trips me up from a pc dev perspective is how much of nes scrolling is hardware and which parts are software. For example, in the case of games that can scroll horizontally in both directions, how does the game know which columns and which tilemap to restore the nametable with when it gets overwritten? Is that hardware or software? If it's software, does the program have some sort of column register to keep track of which column is being drawn?


Top
 Profile  
 
PostPosted: Sun Jun 19, 2016 4:38 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19348
Location: NE Indiana, USA (NTSC)
It's the same as on PC. A game has a "camera" object that tells how far the screen has scrolled. The game notices when the camera has moved by a certain number of pixels, writes the newly revealed area of the map to video memory, and then tells the PPU where in video memory to start drawing the map based on the camera's position.

Image
The process looks like this


Which 2D API are you familiar with from PC game programming? Allegro, SDL, something else? Or is it all OpenGL all the time?


Top
 Profile  
 
PostPosted: Sun Jun 19, 2016 5:05 pm 
Offline

Joined: Tue Sep 27, 2011 8:20 pm
Posts: 23
Currently, I'm working with Allegro 4, so basically, I'm trying to build skyscrapers with sticks and stones. Scrolling on the nes is as simple as setting a register; the console has innate knowledge of what nametables are because its built into the 2C02. With a library like Allegro, you basically get access to keyboard, mouse, graphics card, and sound card, but that's it; nothing more is given. I have to build up to what the nes already knows how to do.


Last edited by xgamer on Sun Jun 19, 2016 6:36 pm, edited 2 times in total.

Top
 Profile  
 
PostPosted: Sun Jun 19, 2016 5:29 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10165
Location: Rio de Janeiro - Brazil
What the NES offers is still pretty low level. It's just a grid of tiles (name tables) and sprites, things you can easily simulate with bitmaps in Allegro or whatever. You can create a bitmap and call it a "name table", and your scroll registers are nothing more than the position of the screen where you draw the bitmap. If you draw it at (0, 0), the scroll is 0. Draw it at (-1, 0) and you have scrolled one pixel to the right. Just maintain a pair of variables for X and Y offsets and those will be your scroll registers. To handle mirroring, just have the offsets wrap around when they're larger than the name table's width/height, and draw 4 copies of the name table. As for sprites, those are nothing more than bitmaps drawn on top of (or below, if you're doing priorities) the name table. You can even easily implement multiple scroll planes this way, each one being a bitmap and its respective set of scroll offsets.

EDIT: A basic rendering loop could look like this:

Code:
clear screen using the background color;
draw background at (-ScrollX, -ScrollY);
draw background at (-ScrollX + BackgroundWidth, -ScrollY);
draw background at (-ScrollX, -ScrollY + BackgroundHeight);
draw background at (-ScrollX + BackgroundWidth, -ScrollY + BackgroundHeight);
for each sprite:
   draw sprite at (SpriteX, SpriteY);

And a system with sprite and background priorities could work like this:

Code:
clear screen using the background color;
for each level of priority:
   for each background with this priority:
      draw background at (-ScrollX, -ScrollY);
      draw background at (-ScrollX + BackgroundWidth, -ScrollY);
      draw background at (-ScrollX, -ScrollY + BackgroundHeight);
      draw background at (-ScrollX + BackgroundWidth, -ScrollY + BackgroundHeight);
   for each sprite with this priority:
      draw sprite at (SpriteX, SpriteY);

When setting/updating the scroll, just make sure the values are withing the range of a name table:

Code:
ScrollX = ScrollX % BackgroundWidth;
ScrollY = ScrollY % BackgroundHeight;


Top
 Profile  
 
PostPosted: Sun Jun 19, 2016 6:00 pm 
Offline

Joined: Tue Sep 27, 2011 8:20 pm
Posts: 23
For anyone interested, here is the link to a demo of what I have working so far. I can scroll either horizontally or vertically, but not both (or at least not in a way that looks consistent); that's what I'm working on now.

And because I like to put the cart before the horse, I even have horizontal parallax scrolling.

Sorry for the sampling rate, but it does run at (about) 60fps.


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 9:58 am 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 221
You do not (and should not) have to copy how the NES does scrolling when making games for the PC.

On the NES, all graphics are represented as mutable state in VRAM which is persistent across frames, but on the PC, there is absolutely no need to make your video buffers persistent or mutable. Clear your buffers each frame and start anew; frames should not depend on the state of the previous frame. Do not bother trying to update individual columns of tiles offscreen as the NES does; that's bad design on modern PCs with all of their computing power.


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 10:04 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19348
Location: NE Indiana, USA (NTSC)
pubby wrote:
You do not (and should not) have to copy how the NES does scrolling when making games for the PC.

Not even if you are trying to ensure 100 percent consistent logic between an NES game and its PC port?

Quote:
[Caching the composited tile map is] bad design on modern PCs with all of their computing power.

By "PC" do you mean x86-64 desktops and full-size laptops with a Core i series CPU, x86 tablets and netbooks with an Atom CPU, or also ARM devices such as Raspberry Pi? Would it be better to make 1000+ draw calls each frame, one for each tile on the screen?


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 10:33 am 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 221
tepples wrote:
Not even if you are trying to ensure 100 percent consistent logic between an NES game and its PC port

I guess if you're doing what rainwarrior does and coding a C++ version side-by-side with a NES version, then sure, it could make sense. But I don't think many people are doing this.

Quote:
By "PC" do you mean x86-64 desktops and full-size laptops with a Core i series CPU, x86 tablets and netbooks with an Atom CPU, or also ARM devices such as Raspberry Pi? Would it be better to make 1000+ draw calls each frame, one for each tile on the screen?

The Raspberry Pi seems way faster than needed for this. I don't understand where that 1000+ number is coming from. It only takes one glBufferSubData call to update the screen.

That first post of mine had some strongly worded opinions in it. I woke up in a bad mood today so sorry if I came off as standoffish.


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 10:35 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10165
Location: Rio de Janeiro - Brazil
pubby wrote:
I don't understand where that 1000+ number is coming from.

The number of tiles visible on the screen.


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 11:09 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7317
Location: Chexbres, VD, Switzerland
pubby wrote:
You do not (and should not) have to copy how the NES does scrolling when making games for the PC.

On the NES, all graphics are represented as mutable state in VRAM which is persistent across frames, but on the PC, there is absolutely no need to make your video buffers persistent or mutable. Clear your buffers each frame and start anew; frames should not depend on the state of the previous frame. Do not bother trying to update individual columns of tiles offscreen as the NES does; that's bad design on modern PCs with all of their computing power.

As a side not, this is also how sprites should properly be rendered on the NES. Too bad many newbies tends to uses the shadow OAM as part of the game state.

Quote:
I have coded a number of 8-way scrolling engines, and based on previous experience, I'd guess this is because of handling one axis entirely before doing the other.

It is quite possible that this is indeed the problem I have, I do not know. I do not need 8-directional scrolling for any of the games I'm planning to develop right now, so I don't really care at this point.


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 11:21 am 
Offline

Joined: Thu Aug 12, 2010 3:43 am
Posts: 1589
pubby wrote:
On the NES, all graphics are represented as mutable state in VRAM which is persistent across frames, but on the PC, there is absolutely no need to make your video buffers persistent or mutable. Clear your buffers each frame and start anew; frames should not depend on the state of the previous frame. Do not bother trying to update individual columns of tiles offscreen as the NES does; that's bad design on modern PCs with all of their computing power.

This is the common wisdom, but it gets me thinking that for 2D games with tilemaps, it may be better to simulate a nametable by rendering tiles to a texture and only updating it while needed. You're already going to need this if you want to avoid all the seam issues that would come from rendering separate quads (especially when tiles get scaled, which they will because you can't predict the output resolution), and you're also going to want it to reduce the amount of draw calls (only draw a few tiles instead of all of them).

But then again a lot of modern 2D games aren't even using tilemaps but instead everything is an object with an arbitrary shape (avoiding the issue altogether).


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 11:30 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19348
Location: NE Indiana, USA (NTSC)
pubby wrote:
tepples wrote:
Would it be better to make 1000+ draw calls each frame, one for each tile on the screen?

I don't understand where that 1000+ number is coming from.

Tokumaru is right: 33 * 31 = 1023 entries in the tilemap that are at least partially visible. Even if you assume nominal NTSC overscan, that's still 33 * 29 = 957 entries. And before you say a modern game would use metatile-sized tiles instead of tiles the size of individual NES nametable entries, many newer platformers such as New Super Mario Bros. Wii tend to be zoomed out to levels that, if applied on NES or Super NES, would be reminiscent of Super Mario Land.

pubby wrote:
It only takes one glBufferSubData call to update the screen.

The manual states that this function "updates a subset of a buffer object's data store". Wouldn't one have to update pieces of the nametable through this call? Or are you recommending abandoning incremental updates and re-decoding the entire section of the map that falls within the camera's boundaries during every frame that the coarse scroll (X coordinate mod tile width and Y coordinate mod tile height) has changed from the previous frame?


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 11:59 am 
Offline
User avatar

Joined: Thu Mar 31, 2016 11:15 am
Posts: 221
tepples wrote:
Or are you recommending abandoning incremental updates and re-decoding the entire section of the map that falls within the camera's boundaries during every frame that the coarse scroll (X coordinate mod tile width and Y coordinate mod tile height) has changed from the previous frame?

Yep! That's what I was trying to convey.

tepples wrote:
The manual states that this function "updates a subset of a buffer object's data store".

It's like OAM DMA on the NES. Each frame you prepare a buffer of your vertex data in the CPU's address space, then use a single glBufferSubData to transfer it all to the GPU. The buffers will be rebuilt from scratch each frame.


Top
 Profile  
 
PostPosted: Mon Jun 20, 2016 12:21 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19348
Location: NE Indiana, USA (NTSC)
The difference is that OAM has 64 objects, while a nametable has an order of magnitude more.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 30 posts ]  Go to page Previous  1, 2

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot] and 5 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