Is it possible to have more than 8 sprites in a rasterline on a real Commodore 64 (not on an emulator)?
the sprites don't need to be different.
Short answer: yes.
Long answer: yes, but there are some caveats:
VICII (the video chip) reads in 3 bytes of sprite data per rasterfor each of the maximum 8 hardware sprite, and the buffered data is meant to be displayed on the next raster.
If you display a hardware sprite a second time on a given raster that buffer will be empty the next raster, so on the following raster you'll end up with a transparent stripe in the sprite.
Also the sprite data fetches happen at around the end of the current raster/start of the next one, so you are pretty much limited to duplicate sprite #0 (because its data is fetched first), and even then the CRT-beam is so far on the right of the screen that you'd have to remove the sideborder to able to see the duplicate sprite visible.
Yes it is possible using assembly in interrupts. The interrupt would be aligned to the raster of the video chip. After the first sprite has been rendered by the video chip (using NOP to wait for the necessary time), its position and shape are changed further to the right. Then the interrupt waits again until the sprite has been rendered to reset it to its original place because the nest raster needs to "see" it there.
Using this technique you can have more than 8 sprites in one raster line. The technique is similar to showing sprites in the border for the case of For sprites in the left/right borders. Instead of changing the register to make the screen less width, you need to change the x-position of the sprite.
Related
I am working in a game project that features a large amout of assets. The character animations are very detailed and that require a lot of frames to happen.
At first, I created large spritesheets containing all the animations for a specific character. It was working well on my PC but when I tested it on an Android tablet, I noticed it ecceeded the maximum texture dimension of its GPU. My solution was to break down the big spritesheet into individual frames (the worst case is 180 frames) and upload them individually to the GPU. Things now seem to be working everywhere I need it to work.
Right now, the largest animation I have been working with is a character with 180 frames with 407x725 pixels of width and height. However, as I couldn't find any orientation on the web regarding how to properly render 2D animations using OpenGL, I would like to ask if there is a problem with this approach. Is there a maximum number of textures that can be uploaded to the GPU? Can I exceed the amout of RAM of the GPU?
The most efficient method for the GPU is to pass the entire sprite sheet to opengl as a single texture, and select which frame you want by adjusting the texture coordinates when you draw. You should also pack the sprites into, ideally, a square texture. Reducing the overall amount of memory used by the GPU is very good for performance esp. on phones and tablets.
You want to avoid if possible frequently changing which texture is bound. Ideally you want to bind a single texture and then render bits and pieces of it to the screen until you don't need it anymore, then bind a different texture and continue.
The reason for this is that the GPU will try hard to optimize the operation of the pipeline it creates to handle the geometry you feed it, and the shaders you select. But when you make big changes to the configuration like changing what texture is bound or what shader is bound, that's necessarily going to be somewhat opaque to optimization. Feeding it more vertices and texture coordinates at a time is better because they basically can all get done in a batch without unloading and reloading resources etc.
However depending what cards you are targetting, you should keep in mind that there may be a maximum of 8192 x 8192 size of textures or something like this. So depending on what assets you have you may be forced to split them up across several textures.
In the last days, while I'm working on a project, I was introduced to the sprite - Byte Array.
Unfortunately, I didnt find out any kond of information about the sprite which can tell me mote about what is this and how it's works.
I really be pleased if you can give me some information and examples for sprite.
A sprite is basically an image with a transparent background color or alpha channel which can be positioned on the screen and moved (usually involving redraw the background over the old position). In the case of an animated sprite, the sprite may consist of several actual images making up the frames of the animation. The format of the image depends entirely on the hardware and/or technology being used to draw or render it. For speed, the dimensions are usually powers of two (8,16,32,64 etc) but this may not be necessary for modern hardware.
Traditionally (read: back in my day), you might have a 320x200x256 screen resolution and a 16x16x256 sprite with color 0 being transparent. Each refresh of the screen would begin with redrawing the background under the sprites, taking a copy of the background under their new position and then redrawing only the visible colors of every sprite in their new position.
With modern hardware, however, it is more efficient to pass data in a format that the driver can handle (hopefully in the graphics accelerator) rather than do everything by hand.
Hey guys I am programming for a primitive type board using some assembly and C, consider the board to be aKin to the old school black and white gameboy.
I am running into a problem while writing a game in that there is no backbuffer. when I clear the screen it draws directly to the screen so that the screen truly is cleared, and thus makes anything I draw invisible, because it is immediately cleared in the next pass. So instead of replacing a drawn screen with a new drawn screen, it clears the screen then draws it.
I came up with a hackish solution in where I Limited the rendering to 10 frames per second.
The way I do this is by clearing the screen, drawing the shape, and then burning a loop for however long remains in the 1/10th second. This way whatever is drawn will stay there longer, and be visible longer, allowing the user to see it before it is immediately erased.
i.e.
while (1)
{
doRender = 1;
screen_clear();
draw_circle(x,y,20,1);
while(doRender)
{
// a interrupt will set doRender to 0, thus ending the loop
}
}
This works!! sort of, it creates a flicker, not horrible, but noticeable to be sure. My game does not require incredible framerates, 10/sec will do.
Does anyone have a better solution to my issue?
Your solution is good. Try optimize it by clearing only the area where the circle has been drawn.
You can also use XOR rendering. E.g: you XOR your sprite to the screen to render it, then on the next frame XOR it again at the same place to remove it and XOR it in its new place.
Can you wait for the vsync? If your drawing is fast enough, you may be able to do it during the vertical blank interval, removing any remaining flicker.
I've got a paint program I've been working on, and I've started to tackle opacity. I'm at a point now where I compare the background color to the brush color, average the two based on their alphas, and then set a new pixel. I just need to cache a portion of what I'm drawing off to the side so that it doesn't continuously sample what is continuously changing while the mouse is down. I figured I would fix this by throwing 50 pixels into a stack or queue that starts changing pixels on screen once it's full and completely empties all it's contents onto the screen on mouse up. What I'd like to know is what would be more efficient, two stacks (one of coordinates and one of colors) or one stack of strings that I parse into coordinates and colors.
TLDR: What's more efficient, two stacks of different data types, or one string stack that I parse into two data types.
Your question seems longer and more confusing than it needs to be, but I think what you're asking is:
I'm designing a paint program. If the user is painting 50%-opaque black pixels on a white background, I want them to show up as gray. My problem is that if the user draws a curve that crosses itself, or just leaves the mouse cursor in the same place for a while, the repeated pixels become darker and darker: 50% black, then 75%, then 87.5%... I don't want this. As long as the mouse button is down, no pixel should be "painted" twice, no matter how many times the curve crosses itself.
This question answers itself. The only way to keep pixels from being painted twice is to keep track of which pixels have been painted since the last time the mouse button was up. Replace
image[mouse.x][mouse.y] = alpha_average(image[mouse.x][mouse.y], current_color, current_alpha);
with
if (not already_painted[mouse.x][mouse.y]) {
image[mouse.x][mouse.y] = alpha_average(image[mouse.x][mouse.y], current_color, current_alpha);
already_painted[mouse.x][mouse.y] = true;
}
handle(mouse_up) {
already_painted[*][*] = false;
}
Problem solved, right?
But to answer another implied question: If you're trying to choose between a bunch of parallel arrays and a bunch of data stuffed into strings, you're probably doing it wrong. All Unity3D languages (Python, C#, Javascript) support struct/class/dict types and tuples, either of which would be a better idea than parallel arrays or everything-is-a-string-ism.
I have this curiosity for 25 years and I would love to understand the trick.
In the Commodore 64 the border was not addressable by the 6569 VIC. All you could do was to draw pixels in the central area, the one where the cursor moved. The border was always uniform, although you could change its color with poke 53280,color if i remember correctly.
Nevertheless I clearly remember games intros where the border was featured with graphics, like it was fully addressable. I tried to understand how it worked but never got to the point. legends say it was a clever use of sprites, which could, under some circumstances, be drawn on the border, but I don't know if it's an urban legend.
edit: just read this from one of the provided links
Sprites were multiplexed across
vertical raster lines (over 8 sprites,
sometimes up to 120 sprites). Until
the Group Crest released Krestage 3 in
May 2007 there was the common
perception that no more than 8 sprites
could appear at one raster line, but
assigning new Y coordinates made it
reappear further down the screen.
This is evil.... you beat the raster and reposition the sprite before it gets there...
Firstly only sprites can be displayed in the border area or a repeating 8 bit pattern (8 pixels wide) which is read from the last byte of the video bank, usually $3fff. Note you can only see these sprites or 8 bit pattern when you trick the VIC chip into "not displaying" the borders. See below.
The borders have a higher priority than sprites, so normally when a sprite is drawn in a border area the border covers the sprite. With a bit of VIC chip trickery you can turn the borders off.
You can turn the top and bottom borders off quite easily (I'll explain below), and the side borders off with very critical timing.
Firstly a little bit of info on how the VIC chip works on a c64.
The VIC chip draws the screen from the top left to the top right, then down a line, and from left to right again until the entire screen is drawn. It performs this redraw 50 times a second (for PAL units) or 60 times a second for (NTSC units).
There is an 8-bit VIC register that contains the vertical position of the raster at any given time. $d012. Actually there are more than 255 possible positions, so the 9th bit is stored in bit 7 (highest bit) or register $d011. So at any point you can read these registers and find out the vertical position of the raster. There is no available register to read the x position of the raster.
Another cool feature of the VIC chip was used to fix a problem when using hardware scrolling. Basic vertical scrolling was achieved by using a hardware register to move the screen 0-7 pixels vertically. Once you reached limit (0 or 7 depending on the direction of the scroll) you would move each character block (8x8 pixel) one block vertically and draw the new data to be displayed at the top (or bottom depending direction). This works very well, except that every 8 pixels of scrolling you would see data "pop" onto the screen. To remedy this, you could make the border area grow by 8 pixels vertically by clearing bit 3 in register $d011. This is called 24 row mode. By default the screen was set to 25 rows of 8x8 pixel characters. In 24 row mode, you could still draw characters to the bottom row, they would just be hidden by the border.
So the trick to turning off the top and bottom borders is to:
1) Set the screen to 25 row mode
2) wait for the raster to reach a vertical position between $f2 and $fa (the 8 pixels between where the border starts in both 24 row mode and 25 row mode).
3) Set the screen to 24 row mode... moving the vertical start of the border above the current raster position
4) Wait until after vertical raster position ($fa)
5) Repeat each frame
Step 3) tricks the VIC chip into thinking that it has already started drawing the border, so it never starts drawing it. Voila, the top and bottom borders are open.
Regarding side borders you can do the same thing with different registers, but as the horizontal movement of the raster is a lot quicker than the vertical movement, the timing needs to be much tighter. And there is another issue to take into account called jitter. <-which I won't explain here. Search the web for "Stable Raster C64" for an in depth explanation of that issue.
Note that what Krestage 3 did (as mentioned in the question) is different.
One level of the trick is to mess with the border when the bottom of the "paper" (work-area rectangle, the thing inside the border) is just being drawn. This lets you have sprites in the upper and lower border.
A higher level is to mess with it at the right-hand edge of the paper, in every raster line, all as explained in JohnD's answer above. This lets you have sprites in the left and right border.
None of this lets you have more than 8 sprites in one line. That's just Krest magic.
By far the best resource (I know of) for the VIC chip is "The MOS 6567/6569 video controller (VIC-II) and its application in the Commodore 64" by Christian Bauer and a useful addendum is "The memory accesses of the MOS 6569 VIC-II and MOS 8566 VIC-IIe Video Interface Controller" by Marko Mäkelä.
Caveat lector: these are somewhat technical, and you might find them easier to understand after you've programmed some VIC effects yourself.
If the links ever die, just google up the articles by title, they're endlessly replicated.
You can open upper and lower borders with a simple BASIC program:
1 poke56334,0:poke53266,212:poke53265,27:poke16383,0
2 h=53265:i=53273:h1=19:h2=27:i1=1
3 pokei,i1:waiti,i1:pokeh,h1:pokeh,h2:goto3
Im going to take a stab in the dark here (havent done this myself). I found this on wikipedia.
The c64demo section explains that:
Effects thought impossible were
achieved in demos, mostly due to
undocumented side-effects pertaining
to the MOS Technology VIC-II chip.
Some examples for VIC-trickery:
One of the mentioned hacks was:
Sprite scrollers were placed in the
border. By tricking the hardware not
to draw the border around the screen,
sprites could be moved into this area
and displayed.
Of course, the interesting part of the question is how its done. I would suggest looking in some demo database which includes source code in search for a demo that employs the hack.
The Microsoft flight simulator drew on the border. For one, we can achieve border drawing effects by changing the border color at the right time. LOGO for example had a split screen mode for the Turtle graphics, where the screen was switched between HiRes graphics above and a few lines of text below. The frame was also differently colored. So it is easy to do a horizon effect, green pastures below and blue sky above (as in the Flight Simulator) which effect extends to the frame.
When you run the wild frame flicker program, like
C000 LDX #00
STX D020
INX
STX D020
DEX
BEQ C002
then you get the color to change at every 10-20 pixels or so. That's the fastest change you can get, I think. So you can draw a horizontal line on the border.
And you can time this by using the same vertical line register in the VIC at $D012 and the bit 7 of $D011, You can read the current scan line from that register. But if you write to it, and you enable the low bit in the register $D01A then the VIC will signal and IRQ when the scan hits that line. So that's how the split screen effect is accomplished.
Here is an example. First I set up my interrupt routine:
C000 SEI ; disable interrupt
LDA #1F ; set interrupt routine to C01F
STA 0314 ; set low byte
LDA #C0 ; high byte
STA 0315 ; set
LDA #C0 ; raster position for horizon
STA D012 ; set to raster position interrupt
LDA D011 ; and for the high bit of the raster position
AND #7F ; clear the high bit
STA D011 ; and set the cleared high bit
LDA #F1 ; enable the raster interrupt
STA D01A ; in the appropriate register
CLI ; allow interrupt
RTS ; return from subroutine
And here is my actual interrupt routine now:
C01F LDA D019 ; load VIC interrupt register
STA D019 ; and clear it
BMI C02E ; if highest bit is set, go to our routine
LDA DC0D ; else disable CIA interrupt
CLI ; enable interrupt
JMP EA31 ; continue with normal system interrupt routine
C02E LDA D012 ; load current vertical scan line
CMP #01 ; is it just about the first line?
BCS C042 ; if not jump to bottom part
LDA #03 ; cyan
STA D020 ; set border color (sky)
LDA #C0 ; horizon level
STA D012 ; set vertical scan interrupt to occur at horizon
JMP EA81 ; continue with normal interrupt minus cursor blink
C042 LDA #00 ; black to draw a piece of horizontal line on the horizon
STA D020 ; set border color
LDX #08 ; a short busy loop
C049 DEX
BNE C049
LDA #01 ; white to draw on the right side horizon
STA D020 ; set border color
LDX #02 ; very short busy loop
C053 DEX
BNE C053
LDA #05 ; finally green as the grass
STA D020 ; set border color
LDA #00 ; next scan line interrupt at top of screen
STA DO12 ; set scan line interrupt
JMP EA81 ; continue normal interrupt sans cursor blink
With the following glorious result:
PRINT "IT WAS 53280, DUDE."
From what I understand, this is only possible for sprites.
Sprites are allowed to be in the border area, and the border gets drawn overtop. Through some trickery, the border can be removed.
Graphics in border: Either sprites OR using the $3FFF effect (which is actually NOT sprites at all). To go into in detail needs much more space and time than I have available here.
You can also get sprites to border in basic: BASIC Sprites in Border
iirc, there was also some way to confuse the video chip so, that it draws 26th line of text.